diff --git a/src/graph/topology/Makefile.am b/src/graph/topology/Makefile.am index f6e2fedbc91f691b988e636887aa7ff81c2239c1..674d23deec9c3ef0728cfbf9ad9a2ce44314ae1d 100644 --- a/src/graph/topology/Makefile.am +++ b/src/graph/topology/Makefile.am @@ -25,6 +25,7 @@ libgraph_tool_topology_la_SOURCES = \ graph_minimum_spanning_tree.cc \ graph_planar.cc \ graph_random_matching.cc \ + graph_reciprocity.cc \ graph_similarity.cc \ graph_subgraph_isomorphism.cc \ graph_topological_sort.cc \ diff --git a/src/graph/topology/graph_reciprocity.cc b/src/graph/topology/graph_reciprocity.cc index 11ad137fcbdb4ca9b1ac5976d4b3df245164d9b6..8b726ce5b33f933ff353f9b906f2a2b58a8bd2f2 100644 --- a/src/graph/topology/graph_reciprocity.cc +++ b/src/graph/topology/graph_reciprocity.cc @@ -28,11 +28,9 @@ using namespace graph_tool; struct get_reciprocity { template - void operator()(const Graph* gp, double& reciprocity) const + void operator()(const Graph& g, double& reciprocity) const { - const Graph& g = *gp; - size_t L = 0; - double Lbd = 0.0; + size_t L = 0, Lbd = 0; int i, NV = num_vertices(g); #pragma omp parallel for default(shared) private(i) reduction(+:L,Lbd) \ @@ -47,44 +45,28 @@ struct get_reciprocity tie(e_begin,e_end) = out_edges(v,g); for(e = e_begin; e != e_end; ++e) { - typename graph_traits::vertex_descriptor s,t; - s = v; - t = target(*e,g); + typename graph_traits::vertex_descriptor t; + t = target(*e, g); - size_t o = 0; typename graph_traits::adjacency_iterator a, a_end; - for (tie(a,a_end) = adjacent_vertices(s, g); a != a_end; ++a) - if (*a == t) - o++; - - size_t j = 0; for (tie(a, a_end) = adjacent_vertices(t, g); a != a_end; ++a) - if (*a == s) - j++; - - Lbd += min(j/double(o),1.0); + if (*a == v) + { + Lbd += 1; + break; + } L++; } } - if(is_convertible::directed_category, - undirected_tag>::value) - { - L /= 2; - Lbd /= 2; - } - - size_t N = HardNumVertices()(&g); - double a = L/double(N*(N-1)); - - reciprocity = (Lbd/L - a)/(1-a); + reciprocity = Lbd / double(L); } }; -double GraphInterface::GetReciprocity() const +double reciprocity(GraphInterface& gi) { double reciprocity; - run_action<>()(*this, bind(get_reciprocity(), _1, - var(reciprocity)))(); + run_action<>()(gi, bind(get_reciprocity(), _1, + ref(reciprocity)))(); return reciprocity; } diff --git a/src/graph/topology/graph_topology.cc b/src/graph/topology/graph_topology.cc index aaa55bbe9a6b356317547e9da2843d11e2da9a08..66875eb043a8ce48443a25a32ec659b56371ab09 100644 --- a/src/graph/topology/graph_topology.cc +++ b/src/graph/topology/graph_topology.cc @@ -37,6 +37,7 @@ void subgraph_isomorphism(GraphInterface& gi1, GraphInterface& gi2, boost::any edge_label1, boost::any edge_label2, python::list vmapping, python::list emapping, size_t n_max, size_t seed); +double reciprocity(GraphInterface& gi); void export_components(); void export_similarity(); @@ -57,6 +58,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_topology) def("dominator_tree", &dominator_tree); def("transitive_closure", &transitive_closure); def("is_planar", &is_planar); + def("reciprocity", &reciprocity); export_components(); export_similarity(); export_dists(); diff --git a/src/graph_tool/topology/__init__.py b/src/graph_tool/topology/__init__.py index 25a59aed7ae8e2ba5ee5c8d181d13a9fd0bf6de4..1e4d042531269044bc95189e82e796535d90888b 100644 --- a/src/graph_tool/topology/__init__.py +++ b/src/graph_tool/topology/__init__.py @@ -45,6 +45,7 @@ Summary label_biconnected_components label_largest_component is_planar + edge_reciprocity Contents ++++++++ @@ -63,7 +64,7 @@ __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", - "pseudo_diameter", "is_planar", "similarity"] + "pseudo_diameter", "is_planar", "similarity", "edge_reciprocity"] def similarity(g1, g2, label1=None, label2=None, norm=True): @@ -1249,3 +1250,56 @@ def max_independent_vertex_set(g, high_deg=False, mivs=None): seed) mivs = g.own_property(mivs) return mivs + + +def edge_reciprocity(g): + r"""Calculate the edge reciprocity of the graph. + + Parameters + ---------- + g : :class:`~graph_tool.Graph` + Graph to be used + edges. + + Returns + ------- + reciprocity : float + The reciprocity value. + + Notes + ----- + + The edge [reciprocity]_ is defined as :math:`E^\leftrightarrow/E`, where + :math:`E^\leftrightarrow` and :math:`E` are the number of bidirectional and + all edges in the graph, respectively. + + The algorithm runs with complexity :math:`O(E + V)`. + + Examples + -------- + + >>> g = gt.Graph() + >>> g.add_vertex(2) + [, + ] + >>> g.add_edge(g.vertex(0), g.vertex(1)) + + >>> gt.edge_reciprocity(g) + 0.0 + >>> g.add_edge(g.vertex(1), g.vertex(0)) + + >>> gt.edge_reciprocity(g) + 1.0 + + References + ---------- + .. [reciprocity] S. Wasserman and K. Faust, "Social Network Analysis". + (Cambridge University Press, Cambridge, 1994) + .. [lopez_reciprocity_2007] Gorka Zamora-López, Vinko Zlatić, Changsong Zhou, Hrvoje Štefančić, and Jürgen Kurths + "Reciprocity of networks with degree correlations and arbitrary degree sequences", Phys. Rev. E 77, 016106 (2008) + :doi:`10.1103/PhysRevE.77.016106`, :arxiv:`0706.3372` + + """ + + r = libgraph_tool_topology.reciprocity(g._Graph__graph) + return r