Commit 6b0e1705 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Implement label_largest_component() and return label histogram in label_components()

parent 5cbf8593
...@@ -20,29 +20,34 @@ ...@@ -20,29 +20,34 @@
#include "graph_components.hh" #include "graph_components.hh"
#include "numpy_bind.hh"
#include <boost/python.hpp> #include <boost/python.hpp>
using namespace std; using namespace std;
using namespace boost; using namespace boost;
using namespace graph_tool; using namespace graph_tool;
void do_label_components(GraphInterface& gi, boost::any prop) python::object do_label_components(GraphInterface& gi, boost::any prop)
{ {
run_action<>()(gi, label_components(), vector<size_t> hist;
run_action<>()(gi, bind<void>(label_components(), _1, _2, ref(hist)),
writable_vertex_scalar_properties())(prop); writable_vertex_scalar_properties())(prop);
return wrap_vector_owned(hist);
} }
size_t do_label_biconnected_components(GraphInterface& gi, boost::any comp, python::object
boost::any art) do_label_biconnected_components(GraphInterface& gi, boost::any comp,
boost::any art)
{ {
size_t nc; vector<size_t> hist;
run_action<graph_tool::detail::never_directed>() run_action<graph_tool::detail::never_directed>()
(gi, bind<void>(label_biconnected_components(), _1, _2, _3, (gi, bind<void>(label_biconnected_components(), _1, _2, _3,
ref(nc)), ref(hist)),
writable_edge_scalar_properties(), writable_edge_scalar_properties(),
writable_vertex_scalar_properties()) writable_vertex_scalar_properties())
(comp, art); (comp, art);
return nc; return wrap_vector_owned(hist);
} }
void export_components() void export_components()
......
...@@ -20,22 +20,93 @@ ...@@ -20,22 +20,93 @@
#include <boost/graph/strong_components.hpp> #include <boost/graph/strong_components.hpp>
#include <boost/graph/biconnected_components.hpp> #include <boost/graph/biconnected_components.hpp>
namespace graph_tool
{
template <class PropertyMap>
class HistogramPropertyMap;
}
namespace boost
{
template <class PropertyMap>
struct property_traits<HistogramPropertyMap<PropertyMap> >:
public property_traits<PropertyMap> {};
}
namespace graph_tool namespace graph_tool
{ {
using namespace std; using namespace std;
using namespace boost; using namespace boost;
// this wraps an existing property map, and makes a simple histogram of the
// values (assumed to be an integer type)
template <class PropertyMap>
class HistogramPropertyMap
{
public:
typedef typename property_traits<PropertyMap>::value_type value_type;
typedef typename property_traits<PropertyMap>::key_type key_type;
typedef typename property_traits<PropertyMap>::category category;
HistogramPropertyMap(PropertyMap base_map, size_t max, vector<size_t>& hist)
: _base_map(base_map), _max(max), _hist(hist) {}
HistogramPropertyMap(){}
value_type get(const key_type& k) const
{
return boost::get(_base_map, k);
}
void put(const key_type& k, const value_type& v)
{
boost::put(_base_map, k, v);
vector<size_t>& h = _hist;
size_t bin = v;
if (bin > _max)
return;
if (bin >= h.size())
h.resize(bin + 1);
++h[bin];
}
private:
PropertyMap _base_map;
size_t _max;
boost::reference_wrapper<vector<size_t> > _hist;
};
template <class PropertyMap>
typename property_traits<PropertyMap>::value_type
get(const HistogramPropertyMap<PropertyMap>& pmap,
const typename property_traits<PropertyMap>::key_type& k)
{
return pmap.get(k);
}
template <class PropertyMap>
void put(HistogramPropertyMap<PropertyMap> pmap,
const typename property_traits<PropertyMap>::key_type& k,
const typename property_traits<PropertyMap>::value_type& val)
{
pmap.put(k, val);
}
// this will label the components of a graph to a given vertex property, from // this will label the components of a graph to a given vertex property, from
// [0, number of components - 1]. If the graph is directed the strong // [0, number of components - 1], and keep an histogram. If the graph is
// components are used. // directed the strong components are used.
struct label_components struct label_components
{ {
template <class Graph, class CompMap> template <class Graph, class CompMap>
void operator()(const Graph& g, CompMap comp_map) const void operator()(const Graph& g, CompMap comp_map, vector<size_t>& hist)
const
{ {
typedef typename graph_traits<Graph>::directed_category typedef typename graph_traits<Graph>::directed_category
directed_category; directed_category;
get_components(g, comp_map, HistogramPropertyMap<CompMap> cm(comp_map, num_vertices(g), hist);
get_components(g, cm,
typename is_convertible<directed_category, typename is_convertible<directed_category,
directed_tag>::type()); directed_tag>::type());
} }
...@@ -80,10 +151,11 @@ struct label_biconnected_components ...@@ -80,10 +151,11 @@ struct label_biconnected_components
template <class Graph, class CompMap, class ArtMap> template <class Graph, class CompMap, class ArtMap>
void operator()(const Graph& g, CompMap comp_map, ArtMap art_map, void operator()(const Graph& g, CompMap comp_map, ArtMap art_map,
size_t& nc) const vector<size_t>& hist) const
{ {
nc = biconnected_components(g, comp_map, HistogramPropertyMap<CompMap> cm(comp_map, num_edges(g), hist);
vertex_inserter<ArtMap>(art_map)).first; biconnected_components(g, cm,
vertex_inserter<ArtMap>(art_map)).first;
} }
}; };
......
...@@ -50,11 +50,11 @@ from .. dl_import import dl_import ...@@ -50,11 +50,11 @@ from .. dl_import import dl_import
dl_import("import libgraph_tool_topology") dl_import("import libgraph_tool_topology")
from .. import _prop, Vector_int32_t, _check_prop_writable, \ from .. import _prop, Vector_int32_t, _check_prop_writable, \
_check_prop_scalar, _check_prop_vector, Graph, PropertyMap _check_prop_scalar, _check_prop_vector, Graph, PropertyMap, GraphView
import random, sys, numpy, weakref import random, sys, numpy, weakref
__all__ = ["isomorphism", "subgraph_isomorphism", "mark_subgraph", __all__ = ["isomorphism", "subgraph_isomorphism", "mark_subgraph",
"min_spanning_tree", "dominator_tree", "topological_sort", "min_spanning_tree", "dominator_tree", "topological_sort",
"transitive_closure", "label_components", "transitive_closure", "label_components", "label_largest_component",
"label_biconnected_components", "shortest_distance", "label_biconnected_components", "shortest_distance",
"shortest_path", "is_planar"] "shortest_path", "is_planar"]
...@@ -422,15 +422,16 @@ def label_components(g, vprop=None, directed=None): ...@@ -422,15 +422,16 @@ def label_components(g, vprop=None, directed=None):
Label the components to which each vertex in the graph belongs. If the Label the components to which each vertex in the graph belongs. If the
graph is directed, it finds the strongly connected components. graph is directed, it finds the strongly connected components.
A property map with the component labels is returned, together with an
histogram of component labels.
Parameters Parameters
---------- ----------
g : :class:`~graph_tool.Graph` g : :class:`~graph_tool.Graph`
Graph to be used. Graph to be used.
vprop : :class:`~graph_tool.PropertyMap` (optional, default: None) vprop : :class:`~graph_tool.PropertyMap` (optional, default: None)
Vertex property to store the component labels. If none is supplied, one Vertex property to store the component labels. If none is supplied, one
is created. is created.
directed : bool (optional, default:None) directed : bool (optional, default:None)
Treat graph as directed or not, independently of its actual Treat graph as directed or not, independently of its actual
directionality. directionality.
...@@ -439,6 +440,8 @@ def label_components(g, vprop=None, directed=None): ...@@ -439,6 +440,8 @@ def label_components(g, vprop=None, directed=None):
------- -------
comp : :class:`~graph_tool.PropertyMap` comp : :class:`~graph_tool.PropertyMap`
Vertex property map with component labels. Vertex property map with component labels.
hist : :class:`~numpy.ndarray`
Histogram of component labels.
Notes Notes
----- -----
...@@ -452,11 +455,13 @@ def label_components(g, vprop=None, directed=None): ...@@ -452,11 +455,13 @@ def label_components(g, vprop=None, directed=None):
>>> from numpy.random import seed >>> from numpy.random import seed
>>> seed(43) >>> seed(43)
>>> g = gt.random_graph(100, lambda: (1, 1)) >>> g = gt.random_graph(100, lambda: (1, 1))
>>> comp = gt.label_components(g) >>> comp, hist = gt.label_components(g)
>>> print comp.get_array() >>> print comp.get_array()
[0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 2 0 0 0 1 0 0 0 0 1 1 0 2 0 1 1 0 0 0 0 1 0 [0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 2 0 0 0 1 0 0 0 0 1 1 0 2 0 1 1 0 0 0 0 1 0
0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 2 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 2 0 0 0 0 1 0 0 0 0 0 1 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0] 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0]
>>> print hist
[81 15 4]
""" """
if vprop is None: if vprop is None:
...@@ -465,17 +470,57 @@ def label_components(g, vprop=None, directed=None): ...@@ -465,17 +470,57 @@ def label_components(g, vprop=None, directed=None):
_check_prop_writable(vprop, name="vprop") _check_prop_writable(vprop, name="vprop")
_check_prop_scalar(vprop, name="vprop") _check_prop_scalar(vprop, name="vprop")
try: if directed is not None:
if directed is not None: g = GraphView(g, directed=directed)
g.stash_filter(directed=True)
g.set_directed(directed)
libgraph_tool_topology.\ hist = libgraph_tool_topology.\
label_components(g._Graph__graph, _prop("v", g, vprop)) label_components(g._Graph__graph, _prop("v", g, vprop))
finally: return vprop, hist
if directed is not None:
g.pop_filter(directed=True)
return vprop def label_largest_component(g, directed=None):
"""
Label the largest component in the graph. If the graph is directed, it
labels the largest strongly connected components.
A property map with a boolean label is returned.
Parameters
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
directed : bool (optional, default:None)
Treat graph as directed or not, independently of its actual
directionality.
Returns
-------
comp : :class:`~graph_tool.PropertyMap`
Vertex property map which labels the largest component with value 1.
Notes
-----
The algorithm runs in :math:`O(V + E)` time.
Examples
--------
>>> from numpy.random import seed, poisson
>>> seed(43)
>>> g = gt.random_graph(100, lambda: poisson(1), directed=False)
>>> l = gt.label_largest_component(g)
>>> print l.a
[1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0
0 0 1 1 0 0 1 0 0 1 0 0 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 1
0 0 0 0 1 0 0 1 0 1 1 0 1 1 0 0 0 0 0 0 1 1 0 0 0 0]
>>> u = gt.GraphView(g, vfilt=l) # extract the largest component as a graph
>>> print u.num_vertices()
26
"""
label = g.new_vertex_property("bool")
c, h = label_components(g, directed=directed)
label.a = c.a == h.argmax()
return label
def label_biconnected_components(g, eprop=None, vprop=None): def label_biconnected_components(g, eprop=None, vprop=None):
...@@ -483,6 +528,10 @@ def label_biconnected_components(g, eprop=None, vprop=None): ...@@ -483,6 +528,10 @@ def label_biconnected_components(g, eprop=None, vprop=None):
Label the edges of biconnected components, and the vertices which are Label the edges of biconnected components, and the vertices which are
articulation points. articulation points.
An edge property map with the component labels is returned, together a
boolean vertex map marking the articulation points, and an histogram of
component labels.
Parameters Parameters
---------- ----------
g : :class:`~graph_tool.Graph` g : :class:`~graph_tool.Graph`
...@@ -529,7 +578,7 @@ def label_biconnected_components(g, eprop=None, vprop=None): ...@@ -529,7 +578,7 @@ def label_biconnected_components(g, eprop=None, vprop=None):
>>> from numpy.random import seed >>> from numpy.random import seed
>>> seed(43) >>> seed(43)
>>> g = gt.random_graph(100, lambda: 2, directed=False) >>> g = gt.random_graph(100, lambda: 2, directed=False)
>>> comp, art, nc = gt.label_biconnected_components(g) >>> comp, art, hist = gt.label_biconnected_components(g)
>>> print comp.a >>> print comp.a
[1 0 0 0 2 0 1 0 0 0 0 0 1 0 0 3 0 0 0 0 0 0 0 0 2 0 0 0 0 0 1 1 0 0 0 0 0 [1 0 0 0 2 0 1 0 0 0 0 0 1 0 0 3 0 0 0 0 0 0 0 0 2 0 0 0 0 0 1 1 0 0 0 0 0
1 0 1 3 0 2 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 3 0 0 0 0 0 0 0 0 0 1 0 1 0 1 3 0 2 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 3 0 0 0 0 0 0 0 0 0 1 0
...@@ -538,8 +587,8 @@ def label_biconnected_components(g, eprop=None, vprop=None): ...@@ -538,8 +587,8 @@ def label_biconnected_components(g, eprop=None, vprop=None):
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
>>> print nc >>> print hist
4 [77 13 6 4]
""" """
...@@ -553,15 +602,11 @@ def label_biconnected_components(g, eprop=None, vprop=None): ...@@ -553,15 +602,11 @@ def label_biconnected_components(g, eprop=None, vprop=None):
_check_prop_writable(eprop, name="eprop") _check_prop_writable(eprop, name="eprop")
_check_prop_scalar(eprop, name="eprop") _check_prop_scalar(eprop, name="eprop")
g.stash_filter(directed=True) g = GraphView(g, directed=False)
try: hist = libgraph_tool_topology.\
g.set_directed(False)
nc = libgraph_tool_topology.\
label_biconnected_components(g._Graph__graph, _prop("e", g, eprop), label_biconnected_components(g._Graph__graph, _prop("e", g, eprop),
_prop("v", g, vprop)) _prop("v", g, vprop))
finally: return eprop, vprop, hist
g.pop_filter(directed=True)
return eprop, vprop, nc
def shortest_distance(g, source=None, weights=None, max_dist=None, def shortest_distance(g, source=None, weights=None, max_dist=None,
......
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