2
0
mirror of https://github.com/boostorg/graph.git synced 2026-02-01 08:32:11 +00:00

Importing exterior_property framework and associated property map helpers.

Integrating closeness_centrality algorithm.


[SVN r51097]
This commit is contained in:
Andrew Sutton
2009-02-08 15:28:31 +00:00
parent 4f9ff68348
commit 6a7fc39328
9 changed files with 682 additions and 4 deletions

View File

@@ -4,8 +4,8 @@
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_CLIQUE_HXX
#define BOOST_GRAPH_CLIQUE_HXX
#ifndef BOOST_GRAPH_CLIQUE_HPP
#define BOOST_GRAPH_CLIQUE_HPP
#include <vector>
#include <deque>

View File

@@ -0,0 +1,157 @@
// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_CLOSENESS_CENTRALITY_HPP
#define BOOST_GRAPH_CLOSENESS_CENTRALITY_HPP
#include <boost/graph/detail/geodesic.hpp>
#include <boost/graph/exterior_property.hpp>
namespace boost
{
template <typename Graph,
typename DistanceType,
typename ResultType,
typename Reciprocal = detail::reciprocal<ResultType> >
struct closeness_measure
: public geodesic_measure<Graph, DistanceType, ResultType>
{
typedef geodesic_measure< Graph, DistanceType, ResultType> base_type;
typedef typename base_type::distance_type distance_type;
typedef typename base_type::result_type result_type;
result_type operator ()(distance_type d, const Graph&)
{
function_requires< NumericValueConcept<DistanceType> >();
function_requires< NumericValueConcept<ResultType> >();
function_requires< AdaptableUnaryFunctionConcept<Reciprocal,ResultType,ResultType> >();
return (d == base_type::infinite_distance())
? base_type::zero_result()
: rec(result_type(d));
}
Reciprocal rec;
};
template <typename Graph, typename DistanceMap>
inline closeness_measure<
Graph, typename property_traits<DistanceMap>::value_type, double,
detail::reciprocal<double> >
measure_closeness(const Graph&, DistanceMap)
{
typedef typename property_traits<DistanceMap>::value_type Distance;
return closeness_measure<Graph, Distance, double, detail::reciprocal<double> >();
}
template <typename T, typename Graph, typename DistanceMap>
inline closeness_measure<
Graph, typename property_traits<DistanceMap>::value_type, T,
detail::reciprocal<T> >
measure_closeness(const Graph&, DistanceMap)
{
typedef typename property_traits<DistanceMap>::value_type Distance;
return closeness_measure<Graph, Distance, T, detail::reciprocal<T> >();
}
template <typename T, typename Graph, typename DistanceMap, typename Reciprocal>
inline closeness_measure<
Graph, typename property_traits<DistanceMap>::value_type, T,
Reciprocal>
measure_closeness(const Graph&, DistanceMap)
{
typedef typename property_traits<DistanceMap>::value_type Distance;
return closeness_measure<Graph, Distance, T, Reciprocal>();
}
template <typename Graph,
typename DistanceMap,
typename Measure,
typename Combinator>
inline typename Measure::result_type
closeness_centrality(const Graph& g,
DistanceMap dist,
Measure measure,
Combinator combine)
{
function_requires< VertexListGraphConcept<Graph> >();
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
function_requires< ReadablePropertyMapConcept<DistanceMap,Vertex> >();
typedef typename property_traits<DistanceMap>::value_type Distance;
function_requires< NumericValueConcept<Distance> >();
function_requires< DistanceMeasureConcept<Measure,Graph> >();
Distance n = detail::combine_distances(g, dist, combine, Distance(0));
return measure(n, g);
}
template <typename Graph, typename DistanceMap, typename Measure>
inline typename Measure::result_type
closeness_centrality(const Graph& g, DistanceMap dist, Measure measure)
{
function_requires< GraphConcept<Graph> >();
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
function_requires< ReadablePropertyMapConcept<DistanceMap,Vertex> >();
typedef typename property_traits<DistanceMap>::value_type Distance;
return closeness_centrality(g, dist, measure, std::plus<Distance>());
}
template <typename Graph, typename DistanceMap>
inline double closeness_centrality(const Graph& g, DistanceMap dist)
{ return closeness_centrality(g, dist, measure_closeness(g, dist)); }
template <typename T, typename Graph, typename DistanceMap>
inline T closeness_centrality(const Graph& g, DistanceMap dist)
{ return closeness_centrality(g, dist, measure_closeness<T>(g, dist)); }
template <typename Graph,
typename DistanceMatrixMap,
typename CentralityMap,
typename Measure>
inline void
all_closeness_centralities(const Graph& g,
DistanceMatrixMap dist,
CentralityMap cent,
Measure measure)
{
function_requires< VertexListGraphConcept<Graph> >();
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
function_requires< ReadablePropertyMapConcept<DistanceMatrixMap,Vertex> >();
typedef typename property_traits<DistanceMatrixMap>::value_type DistanceMap;
function_requires< ReadablePropertyMapConcept<DistanceMap,Vertex> >();
function_requires< WritablePropertyMapConcept<CentralityMap,Vertex> >();
typedef typename property_traits<DistanceMap>::value_type Distance;
typedef typename property_traits<CentralityMap>::value_type Centrality;
typename graph_traits<Graph>::vertex_iterator i, end;
for(tie(i, end) = vertices(g); i != end; ++i) {
DistanceMap dm = get(dist, *i);
Centrality c = closeness_centrality(g, dm, measure);
put(cent, *i, c);
}
}
template <typename Graph,
typename DistanceMatrixMap,
typename CentralityMap>
inline void
all_closeness_centralities(const Graph& g,
DistanceMatrixMap dist,
CentralityMap cent)
{
function_requires< GraphConcept<Graph> >();
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
function_requires< ReadablePropertyMapConcept<DistanceMatrixMap,Vertex> >();
typedef typename property_traits<DistanceMatrixMap>::value_type DistanceMap;
function_requires< ReadablePropertyMapConcept<DistanceMap,Vertex> >();
typedef typename property_traits<DistanceMap>::value_type Distance;
typedef typename property_traits<CentralityMap>::value_type Result;
all_closeness_centralities(g, dist, cent, measure_closeness<Result>(g, DistanceMap()));
}
} /* namespace boost */
#endif

View File

@@ -0,0 +1,129 @@
// (C) Copyright 2007 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_DETAIL_GEODESIC_HPP
#define BOOST_GRAPH_DETAIL_GEODESIC_HPP
#include <functional>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/numeric_values.hpp>
// TODO: Should this really be in detail?
namespace boost
{
// This is a very good discussion on centrality measures. While I can't
// say that this has been the motivating factor for the design and
// implementation of ths centrality framework, it does provide a single
// point of reference for defining things like degree and closeness
// centrality. Plus, the bibliography seems fairly complete.
//
// @article{citeulike:1144245,
// author = {Borgatti, Stephen P. and Everett, Martin G.},
// citeulike-article-id = {1144245},
// doi = {10.1016/j.socnet.2005.11.005},
// journal = {Social Networks},
// month = {October},
// number = {4},
// pages = {466--484},
// priority = {0},
// title = {A Graph-theoretic perspective on centrality},
// url = {http://dx.doi.org/10.1016/j.socnet.2005.11.005},
// volume = {28},
// year = {2006}
// }
// }
namespace detail {
// Note that this assumes T == property_traits<DistanceMap>::value_type
// and that the args and return of combine are also T.
template <typename Graph,
typename DistanceMap,
typename Combinator,
typename Distance>
inline Distance
combine_distances(const Graph& g,
DistanceMap dist,
Combinator combine,
Distance init)
{
function_requires< VertexListGraphConcept<Graph> >();
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::vertex_iterator VertexIterator;
function_requires< ReadablePropertyMapConcept<DistanceMap,Vertex> >();
function_requires< NumericValueConcept<Distance> >();
typedef numeric_values<Distance> DistanceNumbers;
function_requires< AdaptableBinaryFunction<Combinator,Distance,Distance,Distance> >();
// If there's ever an infinite distance, then we simply return
// infinity. Note that this /will/ include the a non-zero
// distance-to-self in the combined values. However, this is usually
// zero, so it shouldn't be too problematic.
Distance ret = init;
VertexIterator i, end;
for(tie(i, end) = vertices(g); i != end; ++i) {
Vertex v = *i;
if(get(dist, v) != DistanceNumbers::infinity()) {
ret = combine(ret, get(dist, v));
}
else {
ret = DistanceNumbers::infinity();
break;
}
}
return ret;
}
// Similar to std::plus<T>, but maximizes parameters
// rather than adding them.
template <typename T>
struct maximize : public std::binary_function<T, T, T>
{
T operator ()(T x, T y) const
{ return std::max(x, y); }
};
// Another helper, like maximize() to help abstract functional
// concepts. This is trivially instantiated for builtin numeric
// types, but should be specialized for those types that have
// discrete notions of reciprocals.
template <typename T>
struct reciprocal : public std::unary_function<T, T>
{
typedef std::unary_function<T, T> function_type;
typedef typename function_type::result_type result_type;
typedef typename function_type::argument_type argument_type;
T operator ()(T t)
{ return T(1) / t; }
};
} /* namespace detail */
// This type defines the basic facilities used for computing values
// based on the geodesic distances between vertices. Examples include
// closeness centrality and mean geodesic distance.
template <typename Graph, typename DistanceType, typename ResultType>
struct geodesic_measure
{
typedef DistanceType distance_type;
typedef ResultType result_type;
typedef typename graph_traits<Graph>::vertices_size_type size_type;
typedef numeric_values<distance_type> distance_values;
typedef numeric_values<result_type> result_values;
static inline distance_type infinite_distance()
{ return distance_values::infinity(); }
static inline result_type infinite_result()
{ return result_values::infinity(); }
static inline result_type zero_result()
{ return result_values::zero(); }
};
} /* namespace boost */
#endif

View File

@@ -0,0 +1,74 @@
// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_DETAIL_INDEX_HPP
#define BOOST_GRAPH_DETAIL_INDEX_HPP
#include <boost/graph/graph_traits.hpp>
// The structures in this module are responsible for selecting and defining
// types for accessing a builting index map. Note that the selection of these
// types requires the Graph parameter to model either VertexIndexGraph or
// EdgeIndexGraph.
namespace boost
{
namespace detail
{
template <typename Graph>
struct vertex_indexer
{
typedef vertex_index_t index_type;
typedef typename property_map<Graph, vertex_index_t>::type map_type;
typedef typename property_map<Graph, vertex_index_t>::const_type const_map_type;
typedef typename property_traits<map_type>::value_type value_type;
typedef typename graph_traits<Graph>::vertex_descriptor key_type;
static const_map_type index_map(const Graph& g)
{ return get(vertex_index, g); }
static map_type index_map(Graph& g)
{ return get(vertex_index, g); }
static value_type index(key_type k, const Graph& g)
{ return get(vertex_index, g, k); }
};
template <typename Graph>
struct edge_indexer
{
typedef edge_index_t index_type;
typedef typename property_map<Graph, edge_index_t>::type map_type;
typedef typename property_map<Graph, edge_index_t>::const_type const_map_type;
typedef typename property_traits<map_type>::value_type value_type;
typedef typename graph_traits<Graph>::edge_descriptor key_type;
static const_map_type index_map(const Graph& g)
{ return get(edge_index, g); }
static map_type index_map(Graph& g)
{ return get(edge_index, g); }
static value_type index(key_type k, const Graph& g)
{ return get(edge_index, g, k); }
};
// NOTE: The Graph parameter MUST be a model of VertexIndexGraph or
// VertexEdgeGraph - whichever type Key is selecting.
template <typename Graph, typename Key>
struct choose_indexer
{
typedef typename mpl::if_<
is_same<Key, typename graph_traits<Graph>::vertex_descriptor>,
vertex_indexer<Graph>,
edge_indexer<Graph>
>::type indexer_type;
typedef typename indexer_type::index_type index_type;
};
}
}
#endif

View File

@@ -0,0 +1,117 @@
// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_EXTERIOR_PROPERTY_HPP
#define BOOST_GRAPH_EXTERIOR_PROPERTY_HPP
#include <vector>
#include <boost/graph/property_maps/container_property_map.hpp>
#include <boost/graph/property_maps/matrix_property_map.hpp>
namespace boost {
namespace detail {
// The vector matrix provides a little abstraction over vector
// types that makes matrices easier to work with. Note that it's
// non-copyable, meaning you should be passing it by value.
template <typename Value>
struct vector_matrix
{
typedef std::vector<Value> container_type;
typedef std::vector<container_type> matrix_type;
typedef container_type value_type;
typedef container_type& reference;
typedef const container_type const_reference;
typedef container_type* pointer;
typedef typename matrix_type::size_type size_type;
// Instantiate the matrix over n elements (creates an nxn matrix).
// The graph has to be passed in order to ensure the index maps
// are constructed correctly when returning indexible elements.
inline vector_matrix(size_type n)
: m_matrix(n, container_type(n))
{ }
inline reference operator [](size_type n)
{ return m_matrix[n]; }
inline const_reference operator [](size_type n) const
{ return m_matrix[n]; }
matrix_type m_matrix;
};
} /* namespace detail */
/**
* The exterior_property metafunction defines an appropriate set of types for
* creating an exterior property. An exterior property is comprised of a both
* a container and a property map that acts as its abstraction. An extension
* of this metafunction will select an appropriate "matrix" property that
* records values for pairs of vertices.
*
* @todo This does not currently support the ability to define exterior
* properties for graph types that do not model the IndexGraph concepts. A
* solution should not be especially difficult, but will require an extension
* of type traits to affect the type selection.
*/
template <typename Graph, typename Key, typename Value>
struct exterior_property
{
typedef Key key_type;
typedef Value value_type;
typedef std::vector<Value> container_type;
typedef container_property_map<Graph, Key, container_type> map_type;
typedef detail::vector_matrix<Value> matrix_type;
typedef matrix_property_map<Graph, Key, matrix_type> matrix_map_type;
private:
exterior_property() { }
exterior_property(const exterior_property&) { }
};
/**
* Define a the container and property map types requried to create an exterior
* vertex property for the given value type. The Graph parameter is required to
* model the VertexIndexGraph concept.
*/
template <typename Graph, typename Value>
struct exterior_vertex_property
{
typedef exterior_property<
Graph, typename graph_traits<Graph>::vertex_descriptor, Value
> property_type;
typedef typename property_type::key_type key_type;
typedef typename property_type::value_type value_type;
typedef typename property_type::container_type container_type;
typedef typename property_type::map_type map_type;
typedef typename property_type::matrix_type matrix_type;
typedef typename property_type::matrix_map_type matrix_map_type;
};
/**
* Define a the container and property map types requried to create an exterior
* edge property for the given value type. The Graph parameter is required to
* model the EdgeIndexGraph concept.
*/
template <typename Graph, typename Value>
struct exterior_edge_property
{
typedef exterior_property<
Graph, typename graph_traits<Graph>::edge_descriptor, Value
> property_type;
typedef typename property_type::key_type key_type;
typedef typename property_type::value_type value_type;
typedef typename property_type::container_type container_type;
typedef typename property_type::map_type map_type;
typedef typename property_type::matrix_type matrix_type;
typedef typename property_type::matrix_map_type matrix_map_type;
};
} /* namespace boost */
#endif

View File

@@ -0,0 +1,59 @@
// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_CONSTANT_PROPERTY_HPP
#define BOOST_GRAPH_CONSTANT_PROPERTY_HPP
#include <boost/property_map.hpp>
// TODO: This should really be part of the property maps library rather than
// the Boost.Graph library.
namespace boost {
/**
* A constant property is one, that regardless of the edge or vertex given,
* will always return a constant value.
*/
template <typename Key, typename Value>
struct constant_property_map
: public boost::put_get_helper<
const Value&,
constant_property_map<Key, Value>
>
{
typedef Key key_type;
typedef Value value_type;
typedef const Value& reference;
typedef boost::readable_property_map_tag category;
constant_property_map()
: m_value()
{ }
constant_property_map(const value_type &value)
: m_value(value)
{ }
constant_property_map(const constant_property_map& copy)
: m_value(copy.m_value)
{ }
inline reference operator [](const key_type& v) const
{ return m_value; }
value_type m_value;
};
template <typename Key, typename Value>
inline constant_property_map<Key, Value>
make_constant_property(const Value& value)
{ return constant_property_map<Key, Value>(value); }
} /* namespace boost */
#endif

View File

@@ -0,0 +1,75 @@
// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_CONTAINER_PROPERTY_MAP_HPP
#define BOOST_GRAPH_CONTAINER_PROPERTY_MAP_HPP
#include <boost/graph/detail/index.hpp>
#include <boost/property_map.hpp>
namespace boost
{
// This is an adapter built over the iterator property map with
// more useful uniform construction semantics. Specifically, this
// requires the container rather than the iterator and the graph
// rather than the optional index map.
template <typename Graph, typename Key, typename Container>
struct container_property_map
: public boost::put_get_helper<
typename iterator_property_map<
typename Container::iterator,
typename property_map<
Graph,
typename detail::choose_indexer<Graph, Key>::index_type
>::type
>::reference,
container_property_map<Graph, Key, Container>
>
{
typedef typename detail::choose_indexer<Graph, Key>::indexer_type indexer_type;
typedef typename indexer_type::index_type index_type;
typedef iterator_property_map<
typename Container::iterator,
typename property_map<Graph, index_type>::type
> map_type;
typedef typename map_type::key_type key_type;
typedef typename map_type::value_type value_type;
typedef typename map_type::reference reference;
typedef typename map_type::category category;
// The default constructor will *probably* crash if its actually
// used for referencing vertices since the underlying iterator
// map points past the end of an unknown container.
inline container_property_map()
: m_map()
{ }
// This is the preferred constructor. It is invoked over the container
// and the graph explicitly. This requires that the underlying iterator
// map use the indices of the vertices in g rather than the default
// identity map.
//
// Note the const-cast this ensures the reference type of the
// vertex index map is non-const, which happens to be an
// artifact of passing const graph references.
inline container_property_map(Container& c, const Graph& g)
: m_map(c.begin(), indexer_type::index_map(const_cast<Graph&>(g)))
{ }
// Typical copy constructor.
inline container_property_map(const container_property_map& x)
: m_map(x.m_map)
{ }
// The [] operator delegates to the underlying map/
inline reference operator [](const key_type& k) const
{ return m_map[k]; }
map_type m_map;
};
}
#endif

View File

@@ -0,0 +1,67 @@
// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_MATRIX_PROPERTY_MAP_HPP
#define BOOST_GRAPH_MATRIX_PROPERTY_MAP_HPP
#include <boost/graph/property_maps/container_property_map.hpp>
namespace boost
{
// This property map is built specifically for property maps over
// matrices. Like the basic property map over a container, this builds
// the property abstraction over a matrix (usually a vector of vectors)
// and returns property maps over the nested containers.
template <typename Graph, typename Key, typename Matrix>
struct matrix_property_map
: boost::put_get_helper<
container_property_map<Graph, Key, typename Matrix::value_type>,
matrix_property_map<Graph, Key, Matrix> >
{
// abstract the indexing keys
typedef typename detail::choose_indexer<Graph, Key>::indexer_type indexer_type;
// aliases for the nested container and its corresponding map
typedef typename Matrix::value_type container_type;
typedef container_property_map<Graph, Key, container_type> map_type;
typedef Key key_type;
// This property map doesn't really provide access to nested containers,
// but returns property maps over them. Since property maps are all
// copy-constructible (or should be anyways), we never return references.
// As such, this property is only readable, but not writable. Curiously,
// the inner property map is actually an lvalue pmap.
typedef map_type value_type;
typedef map_type reference;
typedef readable_property_map_tag category;
matrix_property_map()
: m_matrix(0), m_graph(0)
{ }
matrix_property_map(Matrix& m, const Graph& g)
: m_matrix(&m), m_graph(const_cast<Graph*>(&g))
{ }
matrix_property_map(const matrix_property_map& x)
: m_matrix(x.m_matrix), m_graph(x.m_graph)
{ }
inline reference operator [](key_type k) const
{
typedef typename indexer_type::value_type Index;
Index x = indexer_type::index(k, *m_graph);
return map_type((*m_matrix)[x], *m_graph);
}
private:
mutable Matrix* m_matrix;
mutable Graph* m_graph;
};
}
#endif

View File

@@ -4,8 +4,8 @@
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_CYCLE_HXX
#define BOOST_GRAPH_CYCLE_HXX
#ifndef BOOST_GRAPH_CYCLE_HPP
#define BOOST_GRAPH_CYCLE_HPP
#include <vector>