Commit c759f2f3 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

* Added minimum spanning tree support

* Range filters now support all kinds of scalar properties without falling back to python code


git-svn-id: https://svn.forked.de/graph-tool/trunk@46 d4600afd-f417-0410-95de-beed9576f240
parent 3266b079
......@@ -106,6 +106,7 @@ statistics.add_option("--component-size-histogram", action="callback", callback=
statistics.add_option("--average-vertex-property", action="callback", callback=push_option, type="string", metavar="PROPERTY|FILE", help="get the average of the vertex property")
statistics.add_option("--average-edge-property", action="callback", callback=push_option, type="string", metavar="PROPERTY|FILE", help="get the average of the edge property")
statistics.add_option("--reciprocity", action="callback", callback=push_option, type="string", metavar="FILE", help="get the edge reciprocity")
statistics.add_option("--minimum-spanning-tree", action="callback", callback=push_option, type="string", metavar="[WEIGHT|]PROPERTY", help="mark the minimum spanning tree edges in PROPERTY")
correlations = parser.add_option_group("Correlations")
correlations.add_option("--average-combined-vertex-correlation", action="callback", callback=push_option, type="string", metavar="DEGREE1|DEGREE2|FILE", help="get the average of DEGREE2 in function of DEGREE1. Scalar properties are also accepted as DEGREE1 or DEGREE2")
......@@ -412,6 +413,17 @@ def parse_option(opt, just_file=False):
if just_file:
return opt.value
return (graph.GetReciprocity(), opt.value)
elif opt.name == "minimum-spanning-tree":
values = parse_values(opt.value)
if len(values) > 2 or len(values) < 1:
raise OptionError(opt.name, "invalid value '%s'" % opt.value)
if just_file:
return None
prop, weight = values[0],""
if len(values) > 1:
weight = values[0]
prop = values[1]
graph.GetMinimumSpanningTree(weight,prop)
elif opt.name == "vertex-correlation-histogram":
values = parse_values(opt.value)
if len(values) != 3:
......
......@@ -35,6 +35,7 @@ libgraph_tool_la_SOURCES = \
graph_distance.cc\
graph_distance_sampled.cc\
graph_reciprocity.cc\
graph_minimum_spanning_tree.cc\
graph_io.cc\
graph_bind.cc\
graphml.hpp\
......
......@@ -89,30 +89,28 @@ GraphInterface::~GraphInterface()
// SetVertexFilter()
//==============================================================================
python::object python_range_filter(python::object variables, const string& filter_property, pair<double,double> range)
{
bool accept = true;
if (python::extract<double>(variables[filter_property]()) < range.first || python::extract<double>(variables[filter_property]()) > range.second)
accept = false;
return python::object(accept);
}
void GraphInterface::SetVertexFilterProperty(string property)
{
_vertex_filter_property = property;
if (property != "")
{
try
try
{
_vertex_filter_map = get_static_property_map<vertex_filter_map_t>(find_property_map(_properties, property,
typeid(graph_traits<multigraph_t>::vertex_descriptor)));
}
catch (bad_cast)
{
// set generic vertex filter instead
function<python::object(python::object)> filter = bind<python::object>(python_range_filter, _1, property, _vertex_range);
SetGenericVertexFilter(python::make_function(filter, python::default_call_policies(), mpl::vector<python::object,python::object>::type()));
dynamic_property_map& pmap = find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::vertex_descriptor));
if (get_static_property_map<vector_property_map<double,vertex_index_map_t> >(&pmap))
_vertex_filter_map = get_static_property_map<vector_property_map<double,vertex_index_map_t> >(pmap);
else if (get_static_property_map<HashedDescriptorMap<vertex_index_map_t,double> >(&pmap))
_vertex_filter_map = get_static_property_map<HashedDescriptorMap<vertex_index_map_t,double> >(pmap);
else if (get_static_property_map<vector_property_map<size_t,vertex_index_map_t> >(&pmap))
_vertex_filter_map = get_static_property_map<vector_property_map<size_t,vertex_index_map_t> >(pmap);
else if (get_static_property_map<HashedDescriptorMap<vertex_index_map_t,size_t> >(&pmap))
_vertex_filter_map = get_static_property_map<HashedDescriptorMap<vertex_index_map_t,size_t> >(pmap);
else if (get_static_property_map<vertex_index_map_t>(&pmap))
_vertex_filter_map = get_static_property_map<vertex_index_map_t>(pmap);
else
_vertex_filter_map = DynamicPropertyMapWrap<double, graph_traits<multigraph_t>::vertex_descriptor>(pmap);
}
catch (property_not_found)
{
......@@ -131,14 +129,20 @@ void GraphInterface::SetEdgeFilterProperty(string property)
{
try
{
_edge_filter_map = get_static_property_map<edge_filter_map_t>(find_property_map(_properties, property,
typeid(graph_traits<multigraph_t>::edge_descriptor)));
}
catch (bad_cast)
{
// set generic edge filter instead
function<python::object(python::object)> filter = bind<python::object>(python_range_filter, _1, property, _edge_range);
SetGenericEdgeFilter(python::make_function(filter, python::default_call_policies(), mpl::vector<python::object,python::object>::type()));
dynamic_property_map& pmap = find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::edge_descriptor));
if (get_static_property_map<vector_property_map<double,edge_index_map_t> >(&pmap))
_edge_filter_map = get_static_property_map<vector_property_map<double,edge_index_map_t> >(pmap);
else if (get_static_property_map<HashedDescriptorMap<edge_index_map_t,double> >(&pmap))
_edge_filter_map = get_static_property_map<HashedDescriptorMap<edge_index_map_t,double> >(pmap);
else if (get_static_property_map<vector_property_map<size_t,edge_index_map_t> >(&pmap))
_edge_filter_map = get_static_property_map<vector_property_map<size_t,edge_index_map_t> >(pmap);
else if (get_static_property_map<HashedDescriptorMap<edge_index_map_t,size_t> >(&pmap))
_edge_filter_map = get_static_property_map<HashedDescriptorMap<edge_index_map_t,size_t> >(pmap);
else if (get_static_property_map<edge_index_map_t>(&pmap))
_edge_filter_map = get_static_property_map<edge_index_map_t>(pmap);
else
_edge_filter_map = DynamicPropertyMapWrap<double, graph_traits<multigraph_t>::edge_descriptor>(pmap);
}
catch (property_not_found)
{
......
......@@ -28,6 +28,7 @@
#include <boost/python/object.hpp>
#include "histogram.hh"
#include "config.h"
#include "graph_properties.hh"
namespace graph_tool
{
......@@ -93,6 +94,7 @@ public:
hist_t GetDistanceHistogram(std::string weight) const;
hist_t GetSampledDistanceHistogram(std::string weight, size_t samples, size_t seed) const;
double GetReciprocity() const;
void GetMinimumSpanningTree(std::string weight, std::string property);
// filtering
void SetDirected(bool directed) {_directed = directed;}
......@@ -171,14 +173,24 @@ private:
// vertex filter
std::string _vertex_filter_property;
typedef boost::vector_property_map<double, vertex_index_map_t> vertex_filter_map_t;
typedef boost::variant<boost::vector_property_map<double, vertex_index_map_t>,
HashedDescriptorMap<vertex_index_map_t,double>,
boost::vector_property_map<size_t, vertex_index_map_t>,
HashedDescriptorMap<vertex_index_map_t, size_t>,
vertex_index_map_t,
DynamicPropertyMapWrap<double, boost::graph_traits<multigraph_t>::vertex_descriptor> > vertex_filter_map_t;
vertex_filter_map_t _vertex_filter_map;
std::pair<double,double> _vertex_range;
boost::python::object _vertex_python_filter;
// edge filter
std::string _edge_filter_property;
typedef boost::vector_property_map<double, edge_index_map_t> edge_filter_map_t;
typedef boost::variant<boost::vector_property_map<double, edge_index_map_t>,
HashedDescriptorMap<edge_index_map_t, double>,
boost::vector_property_map<size_t, edge_index_map_t>,
HashedDescriptorMap<edge_index_map_t, size_t>,
edge_index_map_t,
DynamicPropertyMapWrap<double, boost::graph_traits<multigraph_t>::edge_descriptor> > edge_filter_map_t;
edge_filter_map_t _edge_filter_map;
std::pair<double,double> _edge_range;
boost::python::object _edge_python_filter;
......
......@@ -49,9 +49,17 @@ template <class Graph> class UndirectedAdaptor
public:
UndirectedAdaptor(const Graph &g):_g(const_cast<Graph &>(g)){}
typedef typename Graph::vertex_property_type vertex_property_type;
typedef typename Graph::edge_property_type edge_property_type;
typedef typename Graph::graph_tag graph_tag;
typedef typename Graph::graph_type graph_type;
class EdgeDescriptor;
typedef typename graph_traits<UndirectedAdaptor<Graph> >::vertex_descriptor vertex_descriptor_t;
typedef Graph original_graph_t;
typedef typename graph_traits<UndirectedAdaptor<Graph> >::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<UndirectedAdaptor<Graph> >::vertex_descriptor edge_descriptor;
#ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES
// Bundled properties support
......
......@@ -229,6 +229,7 @@ BOOST_PYTHON_MODULE(libgraph_tool)
.def("GetDistanceHistogram", &GraphInterfaceWrap::GetDistanceHistogram)
.def("GetSampledDistanceHistogram", &GraphInterfaceWrap::GetSampledDistanceHistogram)
.def("GetReciprocity", &GraphInterfaceWrap::GetReciprocity)
.def("GetMinimumSpanningTree", &GraphInterfaceWrap::GetMinimumSpanningTree)
.def("SetDirected", &GraphInterfaceWrap::SetDirected)
.def("GetDirected", &GraphInterfaceWrap::GetDirected)
.def("SetReversed", &GraphInterfaceWrap::SetReversed)
......
......@@ -101,21 +101,39 @@ class RangeFilter
{
public:
RangeFilter(){}
typedef typename property_traits<FilteredPropertyMap>::value_type value_type;
typedef typename property_traits<FilteredPropertyMap>::key_type key_type;
RangeFilter(FilteredPropertyMap filtered_property, std::pair<value_type, value_type> range)
RangeFilter(FilteredPropertyMap filtered_property, std::pair<double, double> range)
: _filtered_property(filtered_property), _range(range) {}
template <class VertexOrEdge>
bool operator() (VertexOrEdge e) const
{
// ignore if outside allowed range
if ( _filtered_property[e] < _range.first || _filtered_property[e] > _range.second)
return false;
return true;
bool retval;
map_visitor<VertexOrEdge> visitor(e, _range, retval);
apply_visitor(visitor, _filtered_property);
return retval;
}
private:
template <class VertexOrEdge>
class map_visitor: public static_visitor<void>
{
public:
map_visitor(const VertexOrEdge& descriptor, const std::pair<double, double>& range, bool& retval)
: _descriptor(descriptor), _range(range), _retval(retval) {}
template <class MapType>
void operator()(MapType& filter_prop)
{
// ignore if outside allowed range
_retval = !(double(get(filter_prop, _descriptor)) < _range.first || double(get(filter_prop, _descriptor)) > _range.second);
}
private:
const VertexOrEdge& _descriptor;
const std::pair<double, double>& _range;
bool& _retval;
};
FilteredPropertyMap _filtered_property;
std::pair<value_type, value_type> _range;
std::pair<double, double> _range;
};
typedef mpl::vector<mpl::bool_<true>, mpl::bool_<false> > reverse_check;
......
......@@ -105,6 +105,11 @@ struct GraphEdgeIndexWrap
Graph &_g;
EdgeIndexMap _edge_index_map;
size_t _n_edges;
typedef typename Graph::vertex_property_type vertex_property_type;
typedef typename Graph::edge_property_type edge_property_type;
typedef typename Graph::graph_tag graph_tag;
typedef typename Graph::graph_type graph_type;
};
template <class Graph, class EdgeIndexMap>
......
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2006 Tiago de Paula Peixoto <tiago@forked.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 2
// 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/graph/kruskal_min_spanning_tree.hpp>
#include "graph.hh"
#include "histogram.hh"
#include "graph_filtering.hh"
#include "graph_selectors.hh"
#include "graph_properties.hh"
using namespace std;
using namespace boost;
using namespace boost::lambda;
using namespace graph_tool;
struct get_kruskal_min_span_tree
{
template <class Graph, class IndexMap, class WeightMap, class TreePropMap>
void operator()(Graph& g, IndexMap vertex_index, WeightMap weights, TreePropMap tree_map) const
{
typedef vector<typename graph_traits<Graph>::edge_descriptor> tree_edges_t;
tree_edges_t tree_edges;
back_insert_iterator<tree_edges_t> tree_inserter(tree_edges);
HashedDescriptorMap<IndexMap, size_t> ranks(vertex_index);
HashedDescriptorMap<IndexMap, typename graph_traits<Graph>::vertex_descriptor> preds(vertex_index);
kruskal_minimum_spanning_tree(g, tree_inserter, weight_map(weights).rank_map(ranks).predecessor_map(preds));
typename graph_traits<Graph>::edge_iterator e, e_end;
for(tie(e, e_end) = edges(g); e != e_end; ++e)
tree_map[*e] = 0;
for(typeof(tree_edges.begin()) te = tree_edges.begin(); te != tree_edges.end(); ++te)
tree_map[*te] = 1;
}
};
void GraphInterface::GetMinimumSpanningTree(string weight, string property)
{
typedef HashedDescriptorMap<edge_index_map_t,size_t> tree_map_t;
tree_map_t tree_map(_edge_index);
bool directed = _directed;
_directed = false;
if(weight != "")
{
dynamic_property_map& weight_prop = find_property_map(_properties, weight, typeid(graph_traits<multigraph_t>::edge_descriptor));
if (get_static_property_map<vector_property_map<double,edge_index_map_t> >(&weight_prop))
{
vector_property_map<double,edge_index_map_t> weight_map = get_static_property_map<vector_property_map<double,edge_index_map_t> >(weight_prop);
check_filter(*this, bind<void>(get_kruskal_min_span_tree(), _1, var(_vertex_index),var(weight_map),var(tree_map)),
reverse_check(), always_undirected());
}
else
{
DynamicPropertyMapWrap<double,graph_traits<multigraph_t>::edge_descriptor> weight_map(weight_prop);
check_filter(*this, bind<void>(get_kruskal_min_span_tree(), _1, var(_vertex_index),var(weight_map),var(tree_map)),
reverse_check(), always_undirected());
}
}
else
{
ConstantPropertyMap<double,graph_traits<multigraph_t>::edge_descriptor> weight_map(1.0);
check_filter(*this, bind<void>(get_kruskal_min_span_tree(), _1, var(_vertex_index),var(weight_map),var(tree_map)),
reverse_check(), always_undirected());
}
_directed = directed;
try
{
find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::edge_descriptor));
RemoveVertexProperty(property);
}
catch (property_not_found) {}
_properties.property(property, tree_map);
}
......@@ -47,6 +47,18 @@ PropertyMap& get_static_property_map(boost::dynamic_property_map& map)
return dynamic_cast<boost::detail::dynamic_property_map_adaptor<PropertyMap>&>(map).base();
}
template <class PropertyMap>
PropertyMap* get_static_property_map(boost::dynamic_property_map* map)
{
boost::detail::dynamic_property_map_adaptor<PropertyMap>* adaptor =
dynamic_cast<boost::detail::dynamic_property_map_adaptor<PropertyMap>*>(map);
if (adaptor)
return &adaptor->base();
else
return 0;
}
//==============================================================================
// find_property_map(dp, name, key_type)
// gets the dynamic property map inside dp which matches the given name and
......@@ -273,6 +285,34 @@ private:
value_type _default;
};
//==============================================================================
// ConstantPropertyMap
// a property map which returns a constant value
//==============================================================================
template <class Value, class Key>
class ConstantPropertyMap
: public boost::put_get_helper<Value, ConstantPropertyMap<Value,Key> >
{
public:
typedef Value value_type;
typedef value_type& reference;
typedef Key key_type;
typedef boost::read_write_property_map_tag category;
ConstantPropertyMap(value_type c): _c(c) {}
ConstantPropertyMap(){}
const value_type& operator[](const key_type& k) const
{
return _c;
}
private:
value_type _c;
};
} // graph_tool namespace
......
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