Commit aeaadabc authored by Tiago Peixoto's avatar Tiago Peixoto

Implement the similarity() function

parent 95470ff4
......@@ -15,19 +15,21 @@ libgraph_tool_topology_la_LIBADD = $(MOD_LIBADD)
libgraph_tool_topology_la_LDFLAGS = $(MOD_LDFLAGS)
libgraph_tool_topology_la_SOURCES = \
graph_topology.cc \
graph_all_distances.cc \
graph_components.cc \
graph_distance.cc \
graph_dominator_tree.cc \
graph_isomorphism.cc \
graph_subgraph_isomorphism.cc \
graph_minimum_spanning_tree.cc \
graph_dominator_tree.cc \
graph_planar.cc \
graph_similarity.cc \
graph_subgraph_isomorphism.cc \
graph_topological_sort.cc \
graph_transitive_closure.cc \
graph_components.cc \
graph_distance.cc \
graph_all_distances.cc \
graph_planar.cc
graph_topology.cc \
graph_transitive_closure.cc
libgraph_tool_topology_la_include_HEADERS = \
graph_components.hh \
graph_similarity.hh \
graph_subgraph_isomorphism.hh
\ No newline at end of file
// Copyright (C) 2008 Tiago de Paula Peixoto <tiago@skewed.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "graph.hh"
#include "graph_filtering.hh"
#include "graph_properties.hh"
#include "graph_selectors.hh"
#include "graph_similarity.hh"
#include <boost/python.hpp>
using namespace std;
using namespace boost;
using namespace graph_tool;
struct get_pointers
{
template <class List>
struct apply
{
typedef typename mpl::transform<List,
mpl::quote1<add_pointer> >::type type;
};
};
size_t similarity(GraphInterface& gi1, GraphInterface& gi2, boost::any label1,
boost::any label2)
{
size_t s = 0;
run_action<>()
(gi1, bind<void>(get_similarity(), _1, _2, _3, label2, ref(s)),
get_pointers::apply<graph_tool::detail::all_graph_views>::type(),
vertex_scalar_properties())(gi2.GetGraphView(), label1);
return s;
}
void export_similarity()
{
python::def("similarity", &similarity);
};
// Copyright (C) 2008 Tiago de Paula Peixoto <tiago@skewed.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef GRAPH_SIMILARITY_HH
#define GRAPH_SIMILARITY_HH
#if (GCC_VERSION >= 40400)
# include <tr1/unordered_set>
#else
# include <boost/tr1/unordered_set.hpp>
#endif
namespace graph_tool
{
using namespace std;
using namespace boost;
template <class Keys, class Set>
size_t intersection_size(Keys& ks, Set& s1, Set& s2)
{
size_t s = 0;
for (typeof(ks.begin()) k = ks.begin(); k != ks.end(); ++k)
{
int c1 = s1.count(*k);
int c2 = s2.count(*k);
s += max(c1, c2) - abs(c1 - c2);
}
return s;
}
struct get_similarity
{
template <class Graph1, class Graph2, class LabelMap>
void operator()(const Graph1& g1, const Graph2* g2p, LabelMap l1,
any l2a, size_t& s) const
{
LabelMap l2 = any_cast<LabelMap>(l2a);
const Graph2& g2 = *g2p;
typedef typename property_traits<LabelMap>::value_type label_t;
tr1::unordered_map<label_t, typename graph_traits<Graph1>::vertex_descriptor>
lmap1;
tr1::unordered_map<label_t, typename graph_traits<Graph2>::vertex_descriptor>
lmap2;
typename graph_traits<Graph1>::vertex_iterator v1, v1_end;
for (tie(v1, v1_end) = vertices(g1); v1 != v1_end; ++v1)
lmap1[get(l1, *v1)] = *v1;
typename graph_traits<Graph2>::vertex_iterator v2, v2_end;
for (tie(v2, v2_end) = vertices(g2); v2 != v2_end; ++v2)
lmap2[get(l2, *v2)] = *v2;
s = 0;
for (typeof(lmap1.begin()) li = lmap1.begin(); li != lmap1.end(); ++li)
{
typename graph_traits<Graph1>::vertex_descriptor v1 = li->second;
typeof(lmap2.begin()) li2 = lmap2.find(li->first);
if (li2 == lmap2.end())
continue;
typename graph_traits<Graph2>::vertex_descriptor v2 = li2->second;
tr1::unordered_set<label_t> keys;
tr1::unordered_multiset<label_t> adj1;
tr1::unordered_multiset<label_t> adj2;
typename graph_traits<Graph1>::adjacency_iterator a1, a1_end;
for(tie(a1, a1_end) = adjacent_vertices(v1, g1); a1 != a1_end; ++a1)
{
adj1.insert(get(l1, *a1));
keys.insert(get(l1, *a1));
}
typename graph_traits<Graph2>::adjacency_iterator a2, a2_end;
for(tie(a2, a2_end) = adjacent_vertices(v2, g2); a2 != a2_end; ++a2)
{
adj2.insert(get(l2, *a2));
keys.insert(get(l2, *a2));
}
s += intersection_size(keys, adj1, adj2);
}
}
};
} // graph_tool namespace
#endif // GRAPH_SIMILARITY_HH
......@@ -39,6 +39,7 @@ void subgraph_isomorphism(GraphInterface& gi1, GraphInterface& gi2,
size_t n_max, size_t seed);
void export_components();
void export_similarity();
void export_dists();
void export_all_dists();
......@@ -53,6 +54,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_topology)
def("transitive_closure", &transitive_closure);
def("is_planar", &is_planar);
export_components();
export_similarity();
export_dists();
export_all_dists();
}
......@@ -57,7 +57,69 @@ __all__ = ["isomorphism", "subgraph_isomorphism", "mark_subgraph",
"min_spanning_tree", "dominator_tree", "topological_sort",
"transitive_closure", "label_components", "label_largest_component",
"label_biconnected_components", "shortest_distance",
"shortest_path", "is_planar"]
"shortest_path", "is_planar", "similarity"]
def similarity(g1, g2, label1=None, label2=None, norm=True):
r"""Return the adjacency similarity between the two graphs.
Parameters
----------
g1 : :class:`~graph_tool.Graph`
First graph to be compared.
g2 : :class:`~graph_tool.Graph`
second graph to be compared.
label1 : :class:`~graph_tool.PropertyMap` (optional, default: ``None``)
Vertex labels for the first graph to be used in comparison. If not
supplied, the vertex indexes are used.
label2 : :class:`~graph_tool.PropertyMap` (optional, default: ``None``)
Vertex labels for the second graph to be used in comparison. If not
supplied, the vertex indexes are used.
norm : bool (optional, default: ``True``)
If ``True``, the returned value is normalized by the total number of
edges.
Returns
-------
similarity : float
Adjacency similarity value.
Notes
-----
The adjacency similarity is the sum of equal entries in the adjacency
matrix, given a vertex ordering determined by the vertex labels. In other
words it counts the number of edges which have the same source and target
labels in both graphs.
The algorithm runs with complexity :math:`O(E_1 + V_1 + E_2 + V_2)`.
Examples
--------
>>> from numpy.random import seed
>>> seed(42)
>>> g = gt.random_graph(100, lambda: (3,3))
>>> u = g.copy()
>>> gt.similarity(u, g)
1.0
>>> gt.random_rewire(u);
>>> gt.similarity(u, g)
0.03333333333333333
"""
if label1 is None:
label1 = g1.vertex_index
if label2 is None:
label2 = g2.vertex_index
if label1.value_type() != label2.value_type():
raise ValueError("label property maps must be of the same type")
s = libgraph_tool_topology.\
similarity(g1._Graph__graph, g2._Graph__graph,
_prop("v", g1, label1), _prop("v", g1, label2))
if not g1.is_directed() or not g2.is_directed():
s /= 2
if norm:
s /= float(max(g1.num_edges(), g2.num_edges()))
return s
def isomorphism(g1, g2, isomap=False):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment