Commit 53c936d8 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

* move distance stuff to src/graph/graph_distance.cc

* average distances now accept weights
* added DynamicPropertyMapWrap


git-svn-id: https://svn.forked.de/graph-tool/trunk@17 d4600afd-f417-0410-95de-beed9576f240
parent 9a7b7361
......@@ -92,8 +92,8 @@ statistics.add_option("--number-of-edges", action="callback", callback=push_opti
statistics.add_option("--vertex-histogram", action="callback", callback=push_option, type="string", metavar="DEGREE|FILE", help="get the vertex degree/property histogram")
statistics.add_option("--edge-histogram", action="callback", callback=push_option, type="string", metavar="PROPERTY|FILE", help="get the edge property histogram")
statistics.add_option("--combined-degree-histogram", action="callback", callback=push_option, type="string", metavar="FILE", help="get the combined (in,out)-degree histogram")
statistics.add_option("--average-distance", action="callback", callback=push_option, type="string", metavar="FILE", help="get the averarge distance")
statistics.add_option("--average-harmonic-distance", action="callback", callback=push_option, type="string", metavar="FILE", help="get the averarge harmonic distance")
statistics.add_option("--average-distance", action="callback", callback=push_option, type="string", metavar="[WEIGHT|]FILE", help="get the averarge distance")
statistics.add_option("--average-harmonic-distance", action="callback", callback=push_option, type="string", metavar="[WEIGHT|]FILE", help="get the averarge harmonic distance")
statistics.add_option("--component-size-histogram", action="callback", callback=push_option, type="string", metavar="FILE", help="get the component size histogram")
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")
......@@ -246,13 +246,27 @@ def parse_option(opt, just_file=False):
return opt.value
return (graph.GetCombinedDegreeHistogram(), opt.value)
elif opt.name == "average-distance":
values = parse_values(opt.value)
if len(values) > 2 or len(values) < 1:
raise OptionError(opt.name, "invalid value '%s'" % opt.value)
file_name, weight = values[0],""
if len(values) > 1:
weight = values[0]
file_name = values[1]
if just_file:
return opt.value
return (graph.GetAverageDistance(), opt.value)
return file_name
return (graph.GetAverageDistance(weight), file_name)
elif opt.name == "average-harmonic-distance":
values = parse_values(opt.value)
if len(values) > 2 or len(values) < 1:
raise OptionError(opt.name, "invalid value '%s'" % opt.value)
file_name, weight = values[0],""
if len(values) > 1:
weight = values[0]
file_name = values[1]
if just_file:
return opt.value
return (graph.GetAverageHarmonicDistance(), opt.value)
return file_name
return (graph.GetAverageHarmonicDistance(weight), file_name)
elif opt.name == "component-size-histogram":
if just_file:
return opt.value
......
......@@ -29,6 +29,7 @@ libgraph_tool_la_SOURCES = \
graph_assortativity.cc\
graph_clustering.cc\
graph_generation.cc\
graph_distance.cc\
graph_io.cc\
graph_bind.cc\
graphml_io.hh\
......
......@@ -321,107 +321,6 @@ GraphInterface::hist_t GraphInterface::GetEdgeHistogram(string property) const
return hist;
}
//==============================================================================
// bfs_distance_sum_visitor
// This event visitor will record and sum all the distances during a BFS.
//==============================================================================
struct normal_distance
{
double operator()(double d) const { return d; }
};
struct harmonic_distance
{
double operator()(double d) const { return 1.0/d; }
};
template <class DistanceSelector, class DistanceMap, class Graph>
class bfs_distance_sum_visitor: public default_bfs_visitor
{
public:
bfs_distance_sum_visitor(DistanceMap distance_map, double &sum)
:_distmap(distance_map), _distsum(sum) { }
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
void tree_edge(edge_t e, const Graph & g)
{
size_t d = _distmap[source(e,g)] + 1;
_distmap[target(e,g)] = d; // record distance
_distsum += _distance(double(d));
}
void initialize_vertex(vertex_t u, const Graph &g)
{
_distmap[u] = 0;
}
private:
DistanceMap _distmap;
double &_distsum;
DistanceSelector _distance;
};
//==============================================================================
// GetAverageDistance()
// retrieves the average vertex-vertex distance
//==============================================================================
template <class DistanceSelector>
struct get_average_distance
{
template <class Graph, class IndexMap>
void operator()(const Graph &g, IndexMap index_map, double &dist) const
{
typedef DescriptorHash<typename graph_traits<Graph>::vertex_descriptor,IndexMap> hashfc_t;
typedef tr1::unordered_map<typename graph_traits<Graph>::vertex_descriptor, size_t, hashfc_t> map_t;
hashfc_t hasher(index_map);
map_t vertex_to_dist(0,hasher);
typedef associative_property_map<map_t> dist_map_t;
dist_map_t dist_map(vertex_to_dist);
double distsum = 0;
size_t n = 0;
// this visitor will sum all harmonic distances (twice) to distsum
bfs_distance_sum_visitor<DistanceSelector, dist_map_t, Graph> bfs_sum_dists(dist_map, distsum);
typename graph_traits<Graph>::vertex_iterator v, v_begin, v_end;
tie(v_begin, v_end) = vertices(g);
for(v = v_begin; v != v_end; ++v)
{
breadth_first_search(g,*v, visitor(bfs_sum_dists));
n++;
}
dist = n<2?0.0:_distance(distsum/(n*(n+1)));
}
DistanceSelector _distance;
};
double GraphInterface::GetAverageDistance() const
{
double avg_dist = 0;
check_filter(*this, bind<void>(get_average_distance<normal_distance>(), _1, _vertex_index, var(avg_dist)),
reverse_check(), directed_check());
return avg_dist;
}
//==============================================================================
// GetAverageHarmonicDistance()
// retrieves the average vertex-vertex harmonic distance
//==============================================================================
double GraphInterface::GetAverageHarmonicDistance() const
{
double avg_dist = 0;
check_filter(*this, bind<void>(get_average_distance<harmonic_distance>(), _1, _vertex_index, var(avg_dist)),
reverse_check(), directed_check());
return avg_dist;
}
//==============================================================================
// GetComponentSizeHistogram()
//==============================================================================
......
......@@ -89,8 +89,8 @@ public:
// other
hist_t GetComponentSizeHistogram() const;
double GetAverageDistance() const;
double GetAverageHarmonicDistance() const;
double GetAverageDistance(std::string weight) const;
double GetAverageHarmonicDistance(std::string weight) const;
// filtering
void SetDirected(bool directed) {_directed = directed;}
......
// 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 <algorithm>
#include <tr1/unordered_set>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/lambda/bind.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;
//==============================================================================
// bfs_distance_sum_visitor
// This event visitor will record and sum all the distances during a BFS.
//==============================================================================
struct normal_distance
{
double operator()(double d) const { return d; }
};
struct harmonic_distance
{
double operator()(double d) const { return 1.0/d; }
};
template <class DistanceSelector, class DistanceMap, class Graph>
class bfs_distance_sum_visitor: public default_bfs_visitor
{
public:
bfs_distance_sum_visitor(DistanceMap distance_map, double &sum)
:_distmap(distance_map), _distsum(sum) { }
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
void tree_edge(edge_t e, const Graph & g)
{
double d = _distmap[source(e,g)] + 1.0;
_distmap[target(e,g)] = d; // record distance
_distsum += _distance(d);
}
void initialize_vertex(vertex_t u, const Graph &g)
{
_distmap[u] = 0.0;
}
private:
DistanceMap _distmap;
double &_distsum;
DistanceSelector _distance;
};
//==============================================================================
// GetAverageDistance()
// retrieves the average vertex-vertex distance
//==============================================================================
struct no_weightS {};
template <class DistanceSelector>
struct get_average_distance
{
template <class Graph, class IndexMap, class WeightMap>
void operator()(const Graph &g, IndexMap index_map, WeightMap weights, double &dist) const
{
typedef DescriptorHash<typename graph_traits<Graph>::vertex_descriptor,IndexMap> hashfc_t;
typedef tr1::unordered_map<typename graph_traits<Graph>::vertex_descriptor, double, hashfc_t> map_t;
hashfc_t hasher(index_map);
map_t vertex_to_dist(0,hasher);
typedef associative_property_map<map_t> dist_map_t;
dist_map_t dist_map(vertex_to_dist);
double distsum = 0;
size_t n = 0;
// select get_sum_vertex_dists based on the existence of weights
typedef typename mpl::if_<is_same<WeightMap, no_weightS>,
get_sum_dists_bfs,
get_sum_dists_djk>::type get_sum_vertex_dists;
get_sum_vertex_dists get_sum_dists;
typename graph_traits<Graph>::vertex_iterator v, v_begin, v_end;
tie(v_begin, v_end) = vertices(g);
for(v = v_begin; v != v_end; ++v)
{
distsum += get_sum_dists(g, *v, index_map, dist_map, weights);
n++;
}
DistanceSelector distance;
dist = n<2?0.0:distance(distsum/(n*(n-1)));
}
// weighted version. Use dijkstra_shortest_paths()
struct get_sum_dists_djk
{
template <class Graph, class Vertex, class IndexMap, class DistanceMap, class WeightMap>
double operator()(const Graph& g, Vertex s, IndexMap index_map, DistanceMap dist_map, WeightMap weights) const
{
double distsum = 0.0;
dijkstra_shortest_paths(g, s, vertex_index_map(index_map).weight_map(weights).distance_map(dist_map));
DistanceSelector get_dist;
typename graph_traits<Graph>::vertex_iterator v, v_begin, v_end;
tie(v_begin, v_end) = vertices(g);
for(v = v_begin; v != v_end; ++v)
if (dist_map[*v] != std::numeric_limits<double>::max() && *v != s)
distsum += get_dist(dist_map[*v]);
return distsum;
}
};
// unweighted version. Use BFS.
struct get_sum_dists_bfs
{
template <class Graph, class Vertex, class IndexMap, class DistanceMap>
double operator()(const Graph& g, Vertex s, IndexMap index_map, DistanceMap dist_map, no_weightS) const
{
double distsum = 0.0;
bfs_distance_sum_visitor<DistanceSelector,DistanceMap,Graph> bfs_sum_dists(dist_map, distsum);
breadth_first_search(g, s, visitor(bfs_sum_dists));
return distsum;
}
};
};
double GraphInterface::GetAverageDistance(string weight) const
{
double avg_dist = 0;
if (weight == "")
{
check_filter(*this, bind<void>(get_average_distance<normal_distance>(), _1, _vertex_index, no_weightS(), var(avg_dist)),
reverse_check(), directed_check());
}
else
{
try
{
dynamic_property_map& weight_prop = find_property_map(_properties, weight, typeid(graph_traits<multigraph_t>::edge_descriptor));
try
{
vector_property_map<double, edge_index_map_t> weight_map;
weight_map = get_static_property_map<vector_property_map<double, edge_index_map_t> >(weight_prop);
check_filter(*this, bind<void>(get_average_distance<normal_distance>(), _1, _vertex_index, weight_map, var(avg_dist)),
reverse_check(), directed_check());
}
catch (bad_cast)
{
DynamicPropertyMapWrap<double, graph_traits<multigraph_t>::edge_descriptor> weight_map(weight_prop);
check_filter(*this, bind<void>(get_average_distance<normal_distance>(), _1, _vertex_index, weight_map, var(avg_dist)),
reverse_check(), directed_check());
}
}
catch (property_not_found& e)
{
throw GraphException("error getting scalar property: " + string(e.what()));
}
}
return avg_dist;
}
//==============================================================================
// GetAverageHarmonicDistance()
// retrieves the average vertex-vertex harmonic distance
//==============================================================================
double GraphInterface::GetAverageHarmonicDistance(string weight) const
{
double avg_dist = 0;
if (weight == "")
{
check_filter(*this, bind<void>(get_average_distance<harmonic_distance>(), _1, _vertex_index, no_weightS(), var(avg_dist)),
reverse_check(), directed_check());
}
else
{
try
{
dynamic_property_map& weight_prop = find_property_map(_properties, weight, typeid(graph_traits<multigraph_t>::edge_descriptor));
try
{
vector_property_map<double, edge_index_map_t> weight_map;
weight_map = get_static_property_map<vector_property_map<double, edge_index_map_t> >(weight_prop);
check_filter(*this, bind<void>(get_average_distance<harmonic_distance>(), _1, _vertex_index, weight_map, var(avg_dist)),
reverse_check(), directed_check());
}
catch (bad_cast)
{
DynamicPropertyMapWrap<double, graph_traits<multigraph_t>::edge_descriptor> weight_map(weight_prop);
check_filter(*this, bind<void>(get_average_distance<harmonic_distance>(), _1, _vertex_index, weight_map, var(avg_dist)),
reverse_check(), directed_check());
}
}
catch (property_not_found& e)
{
throw GraphException("error getting scalar property: " + string(e.what()));
}
}
return avg_dist;
}
......@@ -21,6 +21,8 @@
#include <string>
#include <boost/dynamic_property_map.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>
namespace graph_tool
{
......@@ -29,14 +31,32 @@ namespace graph_tool
// Property Map Utility Functions
//==============================================================================
//==============================================================================
// get_static_property_map(map)
// gets the "static" property map behind the dynamic property map, or throws
// bad_cast if it doesn't match
//==============================================================================
template <class PropertyMap>
PropertyMap& get_static_property_map(boost::dynamic_property_map& map)
{
return dynamic_cast<boost::detail::dynamic_property_map_adaptor<PropertyMap>&>(map).base();
}
//==============================================================================
// find_property_map(dp, name, key_type)
// gets the dynamic property map inside dp which matches the given name and
// key type
//==============================================================================
boost::dynamic_property_map& find_property_map(const boost::dynamic_properties& dp, std::string name, const std::type_info& key_type);
//==============================================================================
// dynamic_properties_copy
// contains a copy of a property map, which does not delete its members when it
// deconstructs
//==============================================================================
struct dynamic_properties_copy: public boost::dynamic_properties
{
dynamic_properties_copy() {}
......@@ -46,10 +66,120 @@ struct dynamic_properties_copy: public boost::dynamic_properties
~dynamic_properties_copy()
{
for (typeof(this->begin()) iter = this->begin(); iter != this->end(); ++iter)
iter->second = 0; // will be deleted when dp deconstructs
iter->second = 0; // will be deleted when original dp deconstructs
}
};
//==============================================================================
// template<ConvertedType,Key>
// get_converted_scalar_value(map, key)
// gets the value in the map corresponding to key, converted to ConvertedType,
// or throws bad_lexical_cast.
//==============================================================================
template <class T>
struct AttemptAnyConversion; // forward declaration
template <class ConvertedType, class Key>
ConvertedType get_converted_scalar_value(boost::dynamic_property_map& dmap, const Key& key)
{
typedef typename boost::mpl::vector<long double, double, float, unsigned long long, long long,
unsigned long, long, unsigned int, int, unsigned short, short,
unsigned char, char, std::string>::type scalar_types;
ConvertedType target;
const boost::any& source = dmap.get(key);
bool success;
if (dmap.value() == typeid(ConvertedType))
{
target = boost::any_cast<ConvertedType>(dmap.get(key));
success = true;
}
else
{
boost::mpl::for_each<scalar_types>(AttemptAnyConversion<ConvertedType>(target, source, success));
}
if (!success)
throw boost::bad_lexical_cast();
return target;
}
template <class T>
struct AttemptAnyConversion
{
AttemptAnyConversion(T& value, const boost::any& source, bool& success)
:_value(value), _source(source), _success(success)
{
_success = false;
}
template <class Source>
void operator()(Source)
{
try
{
_value = boost::lexical_cast<T>(boost::any_cast<Source>(_source));
_success = true;
}
catch (boost::bad_any_cast){}
catch (boost::bad_lexical_cast){}
}
T& _value;
const boost::any& _source;
bool& _success;
};
//==============================================================================
// DynamicPropertyMapWrap
// wraps a dynamic_property_map, so it can be used as a regular property map
//==============================================================================
template <class Value, class Key>
class DynamicPropertyMapWrap
{
public:
typedef Value value_type;
typedef Value reference;
typedef Key key_type;
typedef boost::read_write_property_map_tag category;
DynamicPropertyMapWrap(boost::dynamic_property_map& dmap):_dmap(dmap) {}
// DynamicPropertyMapWrap(DynamicPropertyMapWrap& c):_dmap(c._dmap) {}
Value get(const Key& k) const
{
return get_converted_scalar_value<Value>(_dmap, k);
}
void put(const Key& k, const Value& val)
{
_dmap.put(k, val);
}
private:
boost::dynamic_property_map& _dmap;
};
} // namespace graph_tool
namespace boost {
using namespace graph_tool;
template <class Value, class Key>
Value get(DynamicPropertyMapWrap<Value,Key> pmap, typename property_traits<DynamicPropertyMapWrap<Value,Key> >::key_type k)
{
return pmap.get(k);
}
template <class Value, class Key>
void put(DynamicPropertyMapWrap<Value,Key> pmap, typename property_traits<DynamicPropertyMapWrap<Value,Key> >::key_type k,
typename property_traits<DynamicPropertyMapWrap<Value,Key> >::value_type val)
{
pmap.put(k,val);
}
} // namespace boost
#endif
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