diff --git a/doc/johnson_all_pairs_shortest.html b/doc/johnson_all_pairs_shortest.html index 8e95b05a..716bf576 100644 --- a/doc/johnson_all_pairs_shortest.html +++ b/doc/johnson_all_pairs_shortest.html @@ -15,7 +15,7 @@
-

+

johnson_all_pairs_shortest_paths

@@ -75,10 +75,12 @@ and Incidence Graph. OUT: DistanceMatrix& D
The length of the shortest path between each pair of vertices -u,v in the graph is stored in D[u][v]. The set of -types {DistanceMatrix, vertices_size_type, D} must be a model +u,v in the graph is stored in D[u][v]. The tuple of +types (DistanceMatrix, vertices_size_type, D) must be a model of BasicMatrix where D is the -value type of the DistanceMap. +value type of the DistanceMap. There must be implicit conversions +between the value type of the distance matrix and the value type of the weight +map.
@@ -86,12 +88,11 @@ value type of the DistanceMap. IN: weight_map(WeightMap w_map)
- The weight or ``length'' of each edge in the graph. + The weight or "length" of each edge in the graph. The type WeightMap must be a model of Readable Property Map. The edge descriptor type of the graph needs to be usable as the key type for the weight - map. The value type for the map must be - Addable with the value type of the distance map.
+ map. The value type of the weight map must support a subtraction operation.
Default: get(edge_weight, g)
@@ -112,7 +113,7 @@ IN: vertex_index_map(VertexIndexMap i_map) Default: get(vertex_index, g) Note: if you use this default, make sure your graph has an internal vertex_index property. For example, - adjacenty_list with VertexList=listS does + adjacency_list with VertexList=listS does not have an internal vertex_index property.
@@ -128,7 +129,8 @@ IN: distance_compare(CompareFunction cmp) This function is use to compare distances to determine which vertex is closer to the source vertex. The CompareFunction type must be a model of - \stlconcept{BinaryPredicate} and have argument types that + Binary Predicate + and have argument types that match the value type of the WeightMap property map.
Default: std::less<DT> with DT=typename property_traits<WeightMap>::value_type @@ -139,11 +141,8 @@ IN: distance_combine(CombineFunction cmb) This function is used to combine distances to compute the distance of a path. The CombineFunction type must be a model of Binary - Function. The first argument type of the binary function must - match the value type of the DistanceMap property map and - the second argument type must match the value type of the - WeightMap property map. The result type must be the same - type as the distance value type.
+ Function. Both argument types and the return type of the binary function + must match the value type of the WeightMap property map. This operation is required to act as the sum operation for the weight type; in particular, it must be the inverse of the binary - operator on that type.
Default: std::plus<DT> with DT=typename property_traits<WeightMap>::value_type @@ -152,7 +151,7 @@ IN: distance_inf(DT inf)
This value is used to initialize the distance for each vertex before the start of the algorithm. - The type DT must be the value type of the WeigthMap.
+ The type DT must be the value type of the WeightMap.
Default: std::numeric_limits::max()
@@ -160,7 +159,7 @@ IN: distance_zero(DT zero)
This value is used to initialize the distance for the source vertex before the start of the algorithm. The type DT - must be the value type of the WeigthMap.
+ must be the value type of the WeightMap.
Default: 0
diff --git a/doc/maximum_adjacency_search.html b/doc/maximum_adjacency_search.html new file mode 100644 index 00000000..d2aa9e80 --- /dev/null +++ b/doc/maximum_adjacency_search.html @@ -0,0 +1,284 @@ + + + +Boost Graph Library: Maximum Adjacency Search + +C++ Boost + +

+maximum_adjacency_search +

+ +

+

+// named parameter versions
+template <class Graph, class class P, class T, class R>
+void
+maximum_adjacency_search(const Graph& g,
+       const bgl_named_params<P, T, R>& params);
+
+// non-named parameter versions
+template <class Graph, class WeightMap, class MASVisitor>
+void
+maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis,
+       const typename graph_traits<Graph>::vertex_descriptor start);
+
+
+ +

+The maximum_adjacency_search() function performs a traversal +of the vertices in an undirected graph. The next vertex visited is the +vertex that has the most visited neighbors at any time. In the case of +an unweighted, undirected graph, the number of visited neighbors of the +very last vertex visited in the graph is also the number of edge-disjoint +paths between that vertex and the next-to-last vertex visited. These can be +retrieved from a visitor, an example of which is in the test harness +mas_test.cpp. +

+ +

+The maximum_adjacency_search() function invokes user-defined +actions at certain event-points within the algorithm. This provides a +mechanism for adapting the generic MAS algorithm to the many situations +in which it can be used. In the pseudo-code below, the event points +for MAS are the labels on the right. The user-defined actions must be +provided in the form of a visitor object, that is, an object whose type +meets the requirements for a MAS Visitor. +

+ + + + + + +
+
+MAS(G)
+  for each vertex u in V 
+    reach_count[u] := 0
+  end for
+  // for the starting vertex s
+  reach_count[s] := 1
+  for each unvisited vertex u in V
+    call MAS-VISIT(G, u)
+    remove u from the list on unvisited vertices
+    for each out edge from u to t
+       if t has not yet been visited
+         increment reach_count[t]
+       end if
+    end for each out edge
+    call MAS-VISIT(G, u)
+  end for each unvisited vertex
+
+
+
+-
+-
+initialize vertex u
+-
+-
+-
+-
+examine vertex u
+-
+examine edge (u,t)
+-
+-
+-
+-
+finish vertex u
+-
+
+
+ +

Where Defined

+ +

+boost/graph/maximum_adjacency_search.hpp

+ +

Parameters

+ +IN: const UndirectedGraph& g

+
+ A connected, directed graph. The graph type must + be a model of Incidence Graph + and Vertex List Graph.
+
+ +

Named Parameters

+ +

IN: WeightMap weights

+
+ The weight or length of each edge in the graph. The + WeightMap type must be a model of + Readable + Property Map and its value type must be + Less Than Comparable and summable. The key type of this map + needs to be the graph's edge descriptor type. + Default: get(edge_weight, g)
+
+ +IN: visitor(MASVisitor vis)

+
+ A visitor object that is invoked inside the algorithm at the + event-points specified by the MAS Visitor concept. The visitor + object is passed by value [1].
+ Default: mas_visitor<null_visitor>
+
+ +IN: root_vertex(typename +graph_traits<VertexListGraph>::vertex_descriptor start)

+
+ This specifies the vertex that the depth-first search should + originate from. The type is the type of a vertex descriptor for the + given graph.
+ Default: *vertices(g).first
+
+ +

Expert Parameters

+ +

IN: vertex_index_map(VertexIndexMap vertexIndices)

+
+ This maps each vertex to an integer in the range + [0, num_vertices(g)). This is only necessary if the default is + used for the assignment, index-in-heap, or distance maps. + VertexIndexMap must be a model of Readable Property + Map. The value type of the map must be an integer type. The + key type must be the graph's vertex descriptor type.
+ Default: get(boost::vertex_index, g) + Note: if you use this default, make sure your graph has + an internal vertex_index property. For example, + adjacency_list with VertexList=listS does + not have an internal vertex_index property. +
+ +

UTIL: vertex_assignment_map(AssignmentMap assignments)

+
+ AssignmentMap must be a model of Read/Write Property + Map. The key and value types must be the graph's vertex descriptor + type.
+ Default: A boost::iterator_property_map using a + std::vector of num_vertices(g) vertex descriptors and + vertexIndices for the index map. +
+ +

UTIL: max_priority_queue(MaxPriorityQueue& pq)

+
+ MaxPriorityQueue must be a model of Keyed Updatable Queue and a + max- + Updatable Priority Queue. The value type must be the graph's vertex + descriptor and the key type must be the weight type. + Default: A boost::d_ary_heap_indirect using a default + index-in-heap and distance map. +
+ +

UTIL: index_in_heap_map(IndexInHeapMap indicesInHeap)

+
+ This parameter only has an effect when the default max-priority queue is used.
+ IndexInHeapMap must be a model of Read/Write Property + Map. The key type must be the graph's vertex descriptor type. The + value type must be a size type + (typename std::vector<vertex_descriptor>::size_type).
+ Default: A boost::iterator_property_map using a + std::vector of num_vertices(g) size type objects and + vertexIndices for the index map. +
+ +

UTIL: distance_map(DistanceMap wAs)

+
+ This parameter only has an effect when the default max-priority queue is used.
+ DistanceMap must be a model of Read/Write Property + Map. The key type must be the graph's vertex descriptor type. The + value type must be the weight type + (typename boost::property_traits<WeightMap>::value_type). +
+ Default: A boost::iterator_property_map using a + std::vector of num_vertices(g) weight type objects + and vertexIndices for the index map. +
+ +

Returns

+

void

+ +

Throws

+ +

bad_graph +

+ If num_vertices(g) is less than 2 +

+ +

std::invalid_argument +

+ If a max-priority queue is given as an argument and it is not empty +
. + +

+Complexity +

+ +

+The time complexity is O(E + V). +

+ +

References

+ + +

Visitor Event Points

+ + + +

Notes

+ +

[1] + Since the visitor parameter is passed by value, if your visitor + contains state then any changes to the state during the algorithm + will be made to a copy of the visitor object, not the visitor object + passed in. Therefore you may want the visitor to hold this state by + pointer or reference.

+ +
+ + +
Copyright © 2012 +Fernando Vilas +
+ + + diff --git a/doc/r_c_shortest_paths.html b/doc/r_c_shortest_paths.html index f33f8acc..069d4c71 100755 --- a/doc/r_c_shortest_paths.html +++ b/doc/r_c_shortest_paths.html @@ -466,7 +466,7 @@ A function object or fun IN: Label_Allocator la
-An object of type Label_Allocator specifying a strategy for the memory management of the labels. It must offer the same interface as std::allocator. There is a default type default_r_c_shortest_paths_allocator for this parameter using the STL standard allocator. If the third or the fourth overload of the function is used, an object of this type is used as Label_Allocator parameter. If the first or the second overload is used, one must specify both a Label_Allocator and a Visitor parameter. If one wants to develop a user-defined type only for Visitor, one can use default_r_c_shortest_paths_allocator as Label_Allocator parameter. If one wants to use a specialized allocator, one can specify an arbitrary type as template parameter for the value type to the allocator; it is rebound to the correct type. +An object of type Label_Allocator specifying a strategy for the memory management of the labels. It must offer the same interface as std::allocator<r_c_shortest_paths_label<Graph, Resource_Container> >. There is a default type default_r_c_shortest_paths_allocator for this parameter using the STL standard allocator. If the third or the fourth overload of the function is used, an object of this type is used as Label_Allocator parameter. If the first or the second overload is used, one must specify both a Label_Allocator and a Visitor parameter. If one wants to develop a user-defined type only for Visitor, one can use default_r_c_shortest_paths_allocator as Label_Allocator parameter. If one wants to use a specialized allocator, one can specify an arbitrary type as template parameter for the value type to the allocator; it is rebound to the correct type.
IN: Visitor vis
diff --git a/doc/table_of_contents.html b/doc/table_of_contents.html index 3bf18523..0fd36e8e 100644 --- a/doc/table_of_contents.html +++ b/doc/table_of_contents.html @@ -287,6 +287,7 @@
  • sequential_vertex_coloring
  • is_bipartite (including two-coloring of bipartite graphs)
  • find_odd_cycle +
  • maximum_adjacency_search
  • diff --git a/doc/vf2_sub_graph_iso.html b/doc/vf2_sub_graph_iso.html index ae24e908..95ea9496 100755 --- a/doc/vf2_sub_graph_iso.html +++ b/doc/vf2_sub_graph_iso.html @@ -87,13 +87,16 @@ bool vf2_subgraph_iso(const GraphSmall& graph_small, graph that preserves the edge structure of the graphs. M is said to be a graph-subgraph isomorphism if and only if M is an isomorphism between G1 and a subgraph of G2. + An induced subgraph of a graph G = (V, E) is a normal subgraph + G' = (V', E') with the extra condition that all edges of G + which have both endpoints in V' are in E'.

    - This function finds all graph-subgraph isomorphism mappings between + This function finds all induced subgraph isomorphisms between graphs graph_small and graph_large and outputs them to user_callback. It continues until user_callback - returns true or the search space has been fully explored. vf2_subgraph_iso + returns false or the search space has been fully explored. vf2_subgraph_iso returns true if a graph-subgraph isomorphism exists and false otherwise. EdgeEquivalencePredicate and VertexEquivalencePredicate predicates are used to test whether @@ -182,8 +185,8 @@ bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1 g) const and CorresondenceMap2To1 types are models of Readable Property Map and map equivalent vertices across the two - graphs given to vf2_subgraph_iso (or vf2_graph_iso). For - instance, if v is + graphs given to vf2_subgraph_iso (or vf2_graph_iso or + vf2_subgraph_mono). For instance, if v is from graph_small, w is from graph_large, and the vertices can be considered equivalent, then get(f, v) will be w and get(g, w) @@ -279,13 +282,22 @@ bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1 g) const function

    vf2_graph_iso(...)

    +

    vf2_subgraph_mono(...)

    - for isomorphism testing take the same parameters as the corresponding - functions vf2_subgraph_iso for subgraph isomorphism testing. - The algorithm finds all isomorphism mappings between graphs - graph1 and graph2 and outputs them to - user_callback. It continues until user_callback - returns true or the search space has been fully explored. As before, + for isomorphism and (not necessarily induced) subgraph isomorphism testing, + taking the same parameters as the corresponding functions vf2_subgraph_iso + for induced subgraph isomorphism testing. + For vf2_graph_iso the algorithm finds all isomorphism mappings between + graphs graph1 and graph2 and outputs them to + user_callback. + For vf2_graph_mono the algorithm finds all mappings of graph_small + to subgraphs of graph_large. + Note that, as opposed to vf2_subgraph_iso, + these subgraphs need not to be induced subgraphs. +

    +

    + Both algorithms continues until user_callback + returns false or the search space has been fully explored. As before, EdgeEquivalencePredicate and VertexEquivalencePredicate predicates are used to test whether edges and vertices are equivalent. By default @@ -511,7 +523,9 @@ vf2_subgraph_iso(graph1, graph2, callback, vertex_order_by_mult(graph1),


    Copyright © 2012, Flavio De Lorenzi - (fdlorenzi@gmail.com) + (fdlorenzi@gmail.com)
    + Copyright © 2013, Jakob Lykke Andersen, University of Southern Denmark + (jlandersen@imada.sdu.dk)

    diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 6d7d62f6..ce155c67 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -35,6 +35,9 @@ exe stoer_wagner : stoer_wagner.cpp ; exe bfs-example : bfs-example.cpp ; exe bfs-example2 : bfs-example2.cpp ; exe dfs-example : dfs-example.cpp ; +exe dijkstra-example : dijkstra-example.cpp ; +exe dijkstra-example-listS : dijkstra-example-listS.cpp ; +exe dijkstra-no-color-map-example : dijkstra-no-color-map-example.cpp ; exe adjacency_list_io : adjacency_list_io.cpp ; exe undirected_adjacency_list : undirected_adjacency_list.cpp ; exe directed_graph : directed_graph.cpp ; @@ -46,4 +49,5 @@ exe subgraph : subgraph.cpp ; exe subgraph_properties : subgraph_properties.cpp ; exe vf2_sub_graph_iso_example : vf2_sub_graph_iso_example.cpp ; exe vf2_sub_graph_iso_multi_example : vf2_sub_graph_iso_multi_example.cpp ; +exe sloan_ordering : sloan_ordering.cpp ; diff --git a/example/astar-cities.cpp b/example/astar-cities.cpp index c594afa7..c18cd41e 100644 --- a/example/astar-cities.cpp +++ b/example/astar-cities.cpp @@ -171,7 +171,7 @@ int main(int argc, char **argv) // pick random start/goal - mt19937 gen(time(0)); + boost::mt19937 gen(time(0)); vertex start = random_vertex(g, gen); vertex goal = random_vertex(g, gen); diff --git a/example/dijkstra-example-listS.cpp b/example/dijkstra-example-listS.cpp index 1c934207..d02e9347 100644 --- a/example/dijkstra-example-listS.cpp +++ b/example/dijkstra-example-listS.cpp @@ -38,25 +38,8 @@ main(int, char *[]) int num_arcs = sizeof(edge_array) / sizeof(Edge); graph_traits::vertex_iterator i, iend; -#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 - graph_t g(num_nodes); - property_map::type weightmap = get(edge_weight, g); - - std::vector msvc_vertices; - for (boost::tie(i, iend) = vertices(g); i != iend; ++i) - msvc_vertices.push_back(*i); - - for (std::size_t j = 0; j < num_arcs; ++j) { - edge_descriptor e; bool inserted; - boost::tie(e, inserted) = add_edge(msvc_vertices[edge_array[j].first], - msvc_vertices[edge_array[j].second], g); - weightmap[e] = weights[j]; - } - -#else graph_t g(edge_array, edge_array + num_arcs, weights, num_nodes); property_map::type weightmap = get(edge_weight, g); -#endif // Manually intialize the vertex index and name maps property_map::type indexmap = get(vertex_index, g); @@ -73,16 +56,7 @@ main(int, char *[]) d = get(vertex_distance, g); property_map::type p = get(vertex_predecessor, g); -#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 - // VC++ has trouble with the named parameters mechanism - property_map::type indexmap = get(vertex_index, g); - dijkstra_shortest_paths(g, s, p, d, weightmap, indexmap, - std::less(), closed_plus(), - (std::numeric_limits::max)(), 0, - default_dijkstra_visitor()); -#else dijkstra_shortest_paths(g, s, predecessor_map(p).distance_map(d)); -#endif std::cout << "distances and parents:" << std::endl; graph_traits < graph_t >::vertex_iterator vi, vend; diff --git a/example/dijkstra-example.cpp b/example/dijkstra-example.cpp index 6a77dded..5f1ef4bd 100644 --- a/example/dijkstra-example.cpp +++ b/example/dijkstra-example.cpp @@ -12,6 +12,7 @@ #include #include #include +#include using namespace boost; @@ -32,32 +33,15 @@ main(int, char *[]) }; int weights[] = { 1, 2, 1, 2, 7, 3, 1, 1, 1 }; int num_arcs = sizeof(edge_array) / sizeof(Edge); -#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 - graph_t g(num_nodes); - property_map::type weightmap = get(edge_weight, g); - for (std::size_t j = 0; j < num_arcs; ++j) { - edge_descriptor e; bool inserted; - boost::tie(e, inserted) = add_edge(edge_array[j].first, edge_array[j].second, g); - weightmap[e] = weights[j]; - } -#else graph_t g(edge_array, edge_array + num_arcs, weights, num_nodes); property_map::type weightmap = get(edge_weight, g); -#endif std::vector p(num_vertices(g)); std::vector d(num_vertices(g)); vertex_descriptor s = vertex(A, g); -#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 - // VC++ has trouble with the named parameters mechanism - property_map::type indexmap = get(vertex_index, g); - dijkstra_shortest_paths(g, s, &p[0], &d[0], weightmap, indexmap, - std::less(), closed_plus(), - (std::numeric_limits::max)(), 0, - default_dijkstra_visitor()); -#else - dijkstra_shortest_paths(g, s, predecessor_map(&p[0]).distance_map(&d[0])); -#endif + dijkstra_shortest_paths(g, s, + predecessor_map(boost::make_iterator_property_map(p.begin(), get(boost::vertex_index, g))). + distance_map(boost::make_iterator_property_map(d.begin(), get(boost::vertex_index, g)))); std::cout << "distances and parents:" << std::endl; graph_traits < graph_t >::vertex_iterator vi, vend; diff --git a/example/dijkstra-no-color-map-example.cpp b/example/dijkstra-no-color-map-example.cpp index cc89ab4f..9a1a1c3e 100644 --- a/example/dijkstra-no-color-map-example.cpp +++ b/example/dijkstra-no-color-map-example.cpp @@ -16,6 +16,7 @@ #include #include #include +#include using namespace boost; @@ -36,33 +37,15 @@ main(int, char *[]) }; int weights[] = { 1, 2, 1, 2, 7, 3, 1, 1, 1 }; int num_arcs = sizeof(edge_array) / sizeof(Edge); -#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 - graph_t g(num_nodes); - property_map::type weightmap = get(edge_weight, g); - for (std::size_t j = 0; j < num_arcs; ++j) { - edge_descriptor e; bool inserted; - boost::tie(e, inserted) = add_edge(edge_array[j].first, edge_array[j].second, g); - weightmap[e] = weights[j]; - } -#else graph_t g(edge_array, edge_array + num_arcs, weights, num_nodes); property_map::type weightmap = get(edge_weight, g); -#endif std::vector p(num_vertices(g)); std::vector d(num_vertices(g)); vertex_descriptor s = vertex(A, g); -#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 - // VC++ has trouble with the named parameters mechanism - property_map::type indexmap = get(vertex_index, g); - dijkstra_shortest_paths_no_color_map(g, s, &p[0], &d[0], weightmap, - indexmap, std::less(), - closed_plus(), - (std::numeric_limits::max)(), 0, - default_dijkstra_visitor()); -#else - dijkstra_shortest_paths_no_color_map(g, s, predecessor_map(&p[0]).distance_map(&d[0])); -#endif + dijkstra_shortest_paths_no_color_map(g, s, + predecessor_map(boost::make_iterator_property_map(p.begin(), get(boost::vertex_index, g))). + distance_map(boost::make_iterator_property_map(d.begin(), get(boost::vertex_index, g)))); std::cout << "distances and parents:" << std::endl; graph_traits < graph_t >::vertex_iterator vi, vend; diff --git a/example/matching_example.cpp b/example/matching_example.cpp index 704f1df1..de39f57c 100644 --- a/example/matching_example.cpp +++ b/example/matching_example.cpp @@ -44,6 +44,7 @@ int main() // our vertices are stored in a vector, so we can refer to vertices // by integers in the range 0..15 + add_edge(1,2,g); add_edge(0,4,g); add_edge(1,5,g); add_edge(2,6,g); diff --git a/include/boost/graph/astar_search.hpp b/include/boost/graph/astar_search.hpp index 7d6da7c3..435ccf03 100644 --- a/include/boost/graph/astar_search.hpp +++ b/include/boost/graph/astar_search.hpp @@ -438,7 +438,7 @@ namespace boost { typename detail::map_maker::map_type distance_map_type; typedef typename boost::property_traits::value_type D; - const D inf = arg_pack[_distance_inf | (std::numeric_limits::max)()]; + const D inf = arg_pack[_distance_inf || detail::get_max()]; astar_search (g, s, h, @@ -480,7 +480,7 @@ namespace boost { typename detail::map_maker::map_type distance_map_type; typedef typename boost::property_traits::value_type D; - const D inf = arg_pack[_distance_inf | (std::numeric_limits::max)()]; + const D inf = arg_pack[_distance_inf || detail::get_max()]; astar_search_tree (g, s, h, @@ -512,7 +512,7 @@ namespace boost { arg_pack_type, tag::weight_map, edge_weight_t, VertexListGraph>::type weight_map_type; typedef typename boost::property_traits::value_type D; - const D inf = arg_pack[_distance_inf | (std::numeric_limits::max)()]; + const D inf = arg_pack[_distance_inf || detail::get_max()]; astar_search_no_init (g, s, h, arg_pack[_visitor | make_astar_visitor(null_visitor())], @@ -545,7 +545,7 @@ namespace boost { arg_pack_type, tag::weight_map, edge_weight_t, VertexListGraph>::type weight_map_type; typedef typename boost::property_traits::value_type D; - const D inf = arg_pack[_distance_inf | (std::numeric_limits::max)()]; + const D inf = arg_pack[_distance_inf || detail::get_max()]; astar_search_no_init_tree (g, s, h, arg_pack[_visitor | make_astar_visitor(null_visitor())], diff --git a/include/boost/graph/detail/adjacency_list.hpp b/include/boost/graph/detail/adjacency_list.hpp index 61959367..f6d79481 100644 --- a/include/boost/graph/detail/adjacency_list.hpp +++ b/include/boost/graph/detail/adjacency_list.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1903,7 +1904,7 @@ namespace boost { { typedef typename Config::stored_vertex stored_vertex; Derived& g = static_cast(g_); - g.removing_vertex(u); + g.removing_vertex(u, boost::graph_detail::iterator_stability(g_.m_vertices)); stored_vertex* su = (stored_vertex*)u; g.m_vertices.erase(su->m_position); delete su; @@ -2203,7 +2204,7 @@ namespace boost { { typedef typename Config::directed_category Cat; Graph& g = static_cast(g_); - g.removing_vertex(v); + g.removing_vertex(v, boost::graph_detail::iterator_stability(g_.m_vertices)); detail::remove_vertex_dispatch(g, v, Cat()); } // O(1) diff --git a/include/boost/graph/detail/histogram_sort.hpp b/include/boost/graph/detail/histogram_sort.hpp index ca6266a5..54d4449e 100644 --- a/include/boost/graph/detail/histogram_sort.hpp +++ b/include/boost/graph/detail/histogram_sort.hpp @@ -69,7 +69,7 @@ count_starts // m_rowstart EdgeIndex start_of_this_row = 0; starts[0] = start_of_this_row; - for (vertices_size_type i = 1; i <= numkeys; ++i) { + for (vertices_size_type i = 1; i < numkeys + 1; ++i) { start_of_this_row += starts[i]; starts[i] = start_of_this_row; } diff --git a/include/boost/graph/dijkstra_shortest_paths.hpp b/include/boost/graph/dijkstra_shortest_paths.hpp index be0f97ea..45bac7df 100644 --- a/include/boost/graph/dijkstra_shortest_paths.hpp +++ b/include/boost/graph/dijkstra_shortest_paths.hpp @@ -159,7 +159,11 @@ namespace boost { void examine_vertex(Vertex u, Graph& g) { m_vis.examine_vertex(u, g); } template void examine_edge(Edge e, Graph& g) { - if (m_compare(get(m_weight, e), m_zero)) + // Comparison needs to be more complicated because distance and weight + // types may not be the same; see bug 8398 + // (https://svn.boost.org/trac/boost/ticket/8398) + D source_dist = get(m_distance, source(e, g)); + if (m_compare(m_combine(source_dist, get(m_weight, e)), source_dist)) boost::throw_exception(negative_edge()); m_vis.examine_edge(e, g); } diff --git a/include/boost/graph/isomorphism.hpp b/include/boost/graph/isomorphism.hpp index 99055f35..225cd205 100644 --- a/include/boost/graph/isomorphism.hpp +++ b/include/boost/graph/isomorphism.hpp @@ -222,7 +222,7 @@ namespace boost { recur: if (iter != ordered_edges.end()) { i = source(*iter, G1); - j = target(*iter, G2); + j = target(*iter, G1); if (dfs_num[i] > dfs_num_k) { G2_verts = vertices(G2); while (G2_verts.first != G2_verts.second) { @@ -310,8 +310,8 @@ fi_adj_loop_k:++fi_adj.first; if (k.empty()) return false; const match_continuation& this_k = k.back(); switch (this_k.position) { - case match_continuation::pos_G2_vertex_loop: {G2_verts = this_k.G2_verts; iter = this_k.iter; dfs_num_k = this_k.dfs_num_k; k.pop_back(); in_S[*G2_verts.first] = false; i = source(*iter, G1); j = target(*iter, G2); goto G2_loop_k;} - case match_continuation::pos_fi_adj_loop: {fi_adj = this_k.fi_adj; iter = this_k.iter; dfs_num_k = this_k.dfs_num_k; k.pop_back(); in_S[*fi_adj.first] = false; i = source(*iter, G1); j = target(*iter, G2); goto fi_adj_loop_k;} + case match_continuation::pos_G2_vertex_loop: {G2_verts = this_k.G2_verts; iter = this_k.iter; dfs_num_k = this_k.dfs_num_k; k.pop_back(); in_S[*G2_verts.first] = false; i = source(*iter, G1); j = target(*iter, G1); goto G2_loop_k;} + case match_continuation::pos_fi_adj_loop: {fi_adj = this_k.fi_adj; iter = this_k.iter; dfs_num_k = this_k.dfs_num_k; k.pop_back(); in_S[*fi_adj.first] = false; i = source(*iter, G1); j = target(*iter, G1); goto fi_adj_loop_k;} case match_continuation::pos_dfs_num: {k.pop_back(); goto return_point_false;} default: { BOOST_ASSERT(!"Bad position"); @@ -378,6 +378,14 @@ fi_adj_loop_k:++fi_adj.first; const Graph& m_g; }; + // Count actual number of vertices, even in filtered graphs. + template + size_t count_vertices(const Graph& g) + { + size_t n = 0; + BGL_FORALL_VERTICES_T(v, g, Graph) {(void)v; ++n;} + return n; + } template )); BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept )); BOOST_CONCEPT_ASSERT(( VertexListGraphConcept )); - BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept )); + //BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept )); typedef typename graph_traits::vertex_descriptor vertex1_t; typedef typename graph_traits::vertex_descriptor vertex2_t; @@ -407,7 +415,7 @@ fi_adj_loop_k:++fi_adj.first; // Property map requirements BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept )); typedef typename property_traits::value_type IsoMappingValue; - BOOST_STATIC_ASSERT((is_same::value)); + BOOST_STATIC_ASSERT((is_convertible::value)); BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept )); typedef typename property_traits::value_type IndexMap1Value; @@ -417,9 +425,9 @@ fi_adj_loop_k:++fi_adj.first; typedef typename property_traits::value_type IndexMap2Value; BOOST_STATIC_ASSERT((is_convertible::value)); - if (num_vertices(G1) != num_vertices(G2)) + if (count_vertices(G1) != count_vertices(G2)) return false; - if (num_vertices(G1) == 0 && num_vertices(G2) == 0) + if (count_vertices(G1) == 0 && count_vertices(G2) == 0) return true; detail::isomorphism_algo dvis; @@ -121,7 +121,7 @@ namespace boost { (g2, *u, pred, d, w_hat, id2, compare, combine, inf, zero,dvis); for (boost::tie(v, v_end) = vertices(g2); v != v_end; ++v) { if (*u != s && *v != s) { - D[get(id2, *u)-1][get(id2, *v)-1] = combine(get(d, *v), (get(h, *v) - get(h, *u))); + D[get(id2, *u)-1][get(id2, *v)-1] = combine((get(h, *v) - get(h, *u)), get(d, *v)); } } } diff --git a/include/boost/graph/maximum_adjacency_search.hpp b/include/boost/graph/maximum_adjacency_search.hpp new file mode 100644 index 00000000..a87c90de --- /dev/null +++ b/include/boost/graph/maximum_adjacency_search.hpp @@ -0,0 +1,321 @@ +// +//======================================================================= +// Copyright 2012 Fernando Vilas +// 2010 Daniel Trebbien +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= +// + +// The maximum adjacency search algorithm was originally part of the +// Stoer-Wagner min cut implementation by Daniel Trebbien. It has been +// broken out into its own file to be a public search algorithm, with +// visitor concepts. +#ifndef BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H +#define BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H + +/** + * This is an implementation of the maximum adjacency search on an + * undirected graph. It allows a visitor object to perform some + * operation on each vertex as that vertex is visited. + * + * The algorithm runs as follows: + * + * Initialize all nodes to be unvisited (reach count = 0) + * and call vis.initialize_vertex + * For i = number of nodes in graph downto 1 + * Select the unvisited node with the highest reach count + * The user provides the starting node to break the first tie, + * but future ties are broken arbitrarily + * Visit the node by calling vis.start_vertex + * Increment the reach count for all unvisited neighbors + * and call vis.examine_edge for each of these edges + * Mark the node as visited and call vis.finish_vertex + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { + template + struct MASVisitorConcept { + void constraints() { + boost::function_requires< boost::CopyConstructibleConcept >(); + vis.initialize_vertex(u, g); + vis.start_vertex(u, g); + vis.examine_edge(e, g); + vis.finish_vertex(u, g); + } + Visitor vis; + Graph g; + typename boost::graph_traits::vertex_descriptor u; + typename boost::graph_traits::edge_descriptor e; + }; + + template + class mas_visitor { + public: + mas_visitor() { } + mas_visitor(Visitors vis) : m_vis(vis) { } + + template + void + initialize_vertex(Vertex u, Graph& g) + { + invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex()); + } + + template + void + start_vertex(Vertex u, Graph& g) + { + invoke_visitors(m_vis, u, g, ::boost::on_start_vertex()); + } + + template + void + examine_edge(Edge e, Graph& g) + { + invoke_visitors(m_vis, e, g, ::boost::on_examine_edge()); + } + + template + void + finish_vertex(Vertex u, Graph& g) + { + invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex()); + } + + BOOST_GRAPH_EVENT_STUB(on_initialize_vertex,mas) + BOOST_GRAPH_EVENT_STUB(on_start_vertex,mas) + BOOST_GRAPH_EVENT_STUB(on_examine_edge,mas) + BOOST_GRAPH_EVENT_STUB(on_finish_vertex,mas) + + protected: + Visitors m_vis; + }; + template + mas_visitor + make_mas_visitor(Visitors vis) { + return mas_visitor(vis); + } + typedef mas_visitor<> default_mas_visitor; + + namespace detail { + template + void + maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis, const typename boost::graph_traits::vertex_descriptor start, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq) { + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::vertices_size_type vertices_size_type; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef typename boost::property_traits::value_type weight_type; + + std::set assignedVertices; + + // initialize `assignments` (all vertices are initially + // assigned to themselves) + BGL_FORALL_VERTICES_T(v, g, Graph) { + put(assignments, v, v); + } + + typename KeyedUpdatablePriorityQueue::key_map keys = pq.keys(); + + // set number of visited neighbors for all vertices to 0 + BGL_FORALL_VERTICES_T(v, g, Graph) { + if (v == get(assignments, v)) { // foreach u \in V do + put(keys, v, weight_type(0)); vis.initialize_vertex(v, g); + + pq.push(v); + } + } + BOOST_ASSERT(pq.size() >= 2); + + // Give the starting vertex high priority + put(keys, start, get(keys, start) + num_vertices(g) + 1); + pq.update(start); + + // start traversing the graph + //vertex_descriptor s, t; + weight_type w; + while (!pq.empty()) { // while PQ \neq {} do + const vertex_descriptor u = pq.top(); // u = extractmax(PQ) + w = get(keys, u); vis.start_vertex(u, g); + pq.pop(); // vis.start_vertex(u, g); + + BGL_FORALL_OUTEDGES_T(u, e, g, Graph) { // foreach (u, v) \in E do + vis.examine_edge(e, g); + + const vertex_descriptor v = get(assignments, target(e, g)); + + if (pq.contains(v)) { // if v \in PQ then + put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, wA(v) + w(u, v)) + pq.update(v); + } + } + + typename std::set::const_iterator assignedVertexIt, assignedVertexEnd = assignedVertices.end(); + for (assignedVertexIt = assignedVertices.begin(); assignedVertexIt != assignedVertexEnd; ++assignedVertexIt) { + const vertex_descriptor uPrime = *assignedVertexIt; + + if (get(assignments, uPrime) == u) { + BGL_FORALL_OUTEDGES_T(uPrime, e, g, Graph) { // foreach (u, v) \in E do + vis.examine_edge(e, g); + + const vertex_descriptor v = get(assignments, target(e, g)); + + if (pq.contains(v)) { // if v \in PQ then + put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, wA(v) + w(u, v)) + pq.update(v); + } + } + } + } + vis.finish_vertex(u, g); + } + } + } // end namespace detail + + template + void +maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis, const typename boost::graph_traits::vertex_descriptor start, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq) { + BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept)); + BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept)); + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::vertices_size_type vertices_size_type; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + BOOST_CONCEPT_ASSERT((boost::Convertible::directed_category, boost::undirected_tag>)); + BOOST_CONCEPT_ASSERT((boost::ReadablePropertyMapConcept)); + typedef typename boost::property_traits::value_type weight_type; + boost::function_requires< MASVisitorConcept >(); + BOOST_CONCEPT_ASSERT((boost::ReadWritePropertyMapConcept)); + BOOST_CONCEPT_ASSERT((boost::Convertible::value_type>)); + BOOST_CONCEPT_ASSERT((boost::KeyedUpdatableQueueConcept)); + + vertices_size_type n = num_vertices(g); + if (n < 2) + throw boost::bad_graph("the input graph must have at least two vertices."); + else if (!pq.empty()) + throw std::invalid_argument("the max-priority queue must be empty initially."); + + detail::maximum_adjacency_search(g, weights, + vis, start, + assignments, pq); + } + + namespace graph { + namespace detail { + template + struct mas_dispatch { + typedef void result_type; + template + static result_type apply(const Graph& g, + //const bgl_named_params& params, + const ArgPack& params, + WeightMap w) { + + using namespace boost::graph::keywords; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename WeightMap::value_type weight_type; + + typedef boost::detail::make_priority_queue_from_arg_pack_gen > default_pq_gen_type; + + default_pq_gen_type pq_gen(choose_param(get_param(params, boost::distance_zero_t()), weight_type(0))); + + typename boost::result_of::type pq = pq_gen(g, params); + + boost::maximum_adjacency_search + (g, + w, + params [ _visitor | make_mas_visitor(null_visitor())], + params [ _root_vertex | *vertices(g).first], + params [ _vertex_assignment_map | boost::detail::make_property_map_from_arg_pack_gen(vertex_descriptor())(g, params)], + pq + ); + } + }; + + template <> + struct mas_dispatch { + typedef void result_type; + + template + static result_type apply(const Graph& g, + const ArgPack& params, + param_not_found) { + + using namespace boost::graph::keywords; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + // get edge_weight_t as the weight type + typedef typename boost::property_map WeightMap; + typedef typename WeightMap::value_type weight_type; + + typedef boost::detail::make_priority_queue_from_arg_pack_gen > default_pq_gen_type; + + default_pq_gen_type pq_gen(choose_param(get_param(params, boost::distance_zero_t()), weight_type(0))); + + typename boost::result_of::type pq = pq_gen(g, params); + + boost::maximum_adjacency_search + (g, + get(edge_weight, g), + params [ _visitor | make_mas_visitor(null_visitor())], + params [ _root_vertex | *vertices(g).first], + params [ _vertex_assignment_map | boost::detail::make_property_map_from_arg_pack_gen(vertex_descriptor())(g, params)], + pq + ); + } + }; + } // end namespace detail + } // end namespace graph + + // Named parameter interface + //BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(maximum_adjacency_search, 1) + template + void + maximum_adjacency_search (const Graph& g, + const bgl_named_params& params) { + + typedef bgl_named_params params_type; + BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params) + + // do the dispatch based on WeightMap + typedef typename get_param_type >::type W; + graph::detail::mas_dispatch::apply(g, arg_pack, get_param(params, edge_weight)); + } + + namespace graph { + namespace detail { + template + struct maximum_adjacency_search_impl { + typedef void result_type; + + template + void + operator() (const Graph& g, const ArgPack arg_pack) const { + // call the function that does the dispatching + typedef typename get_param_type::type W; + graph::detail::mas_dispatch::apply(g, arg_pack, get_param(arg_pack, edge_weight)); + } + }; + } // end namespace detail + BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(maximum_adjacency_search,1,5) + } // end namespace graph + +} // end namespace boost + +#include + +#endif // BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H diff --git a/include/boost/graph/named_function_params.hpp b/include/boost/graph/named_function_params.hpp index 3dd1a136..4ab24f63 100644 --- a/include/boost/graph/named_function_params.hpp +++ b/include/boost/graph/named_function_params.hpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -718,6 +719,15 @@ BOOST_BGL_DECLARE_NAMED_PARAMS result_type operator()() const {return get_default_starting_vertex(g);} }; + // Wrapper to avoid instantiating numeric_limits when users provide distance_inf value manually + template + struct get_max { + T operator()() const { + return (std::numeric_limits::max)(); + } + typedef T result_type; + }; + } // namespace detail } // namespace boost diff --git a/include/boost/graph/named_graph.hpp b/include/boost/graph/named_graph.hpp index 4c687a08..d82807f3 100644 --- a/include/boost/graph/named_graph.hpp +++ b/include/boost/graph/named_graph.hpp @@ -11,6 +11,7 @@ #define BOOST_GRAPH_NAMED_GRAPH_HPP #include +#include #include #include #include @@ -19,9 +20,11 @@ #include #include #include // for boost::lookup_one_property +#include #include #include // for boost::make_tuple #include +#include #include #include #include @@ -253,7 +256,8 @@ public: /// Notify the named_graph that we are removing the given /// vertex. The name of the vertex will be removed from the mapping. - void removing_vertex(Vertex vertex); + template + void removing_vertex(Vertex vertex, VertexIterStability); /// Notify the named_graph that we are clearing the graph. /// This will clear out all of the name->vertex mappings @@ -308,8 +312,10 @@ inline void BGL_NAMED_GRAPH::added_vertex(Vertex vertex) } template -inline void BGL_NAMED_GRAPH::removing_vertex(Vertex vertex) +template +inline void BGL_NAMED_GRAPH::removing_vertex(Vertex vertex, VertexIterStability) { + BOOST_STATIC_ASSERT_MSG ((boost::is_base_of::value), "Named graphs cannot use vecS as vertex container and remove vertices; the lack of vertex descriptor stability (which iterator stability is a proxy for) means that the name -> vertex mapping would need to be completely rebuilt after each deletion. See https://svn.boost.org/trac/boost/ticket/7863 for more information and a test case."); typedef typename BGL_NAMED_GRAPH::vertex_name_type vertex_name_type; const vertex_name_type& vertex_name = extract_name(derived()[vertex]); named_vertices.erase(vertex_name); @@ -486,7 +492,8 @@ struct maybe_named_graph /// Notify the named_graph that we are removing the given /// vertex. This is a no-op. - void removing_vertex(Vertex) { } + template + void removing_vertex(Vertex, VertexIterStability) { } /// Notify the named_graph that we are clearing the graph. This is a /// no-op. @@ -517,7 +524,8 @@ struct maybe_named_graph /// Notify the named_graph that we are removing the given /// vertex. This is a no-op. - void removing_vertex(Vertex) { } + template + void removing_vertex(Vertex, VertexIterStability) { } /// Notify the named_graph that we are clearing the graph. This is a /// no-op. diff --git a/include/boost/graph/r_c_shortest_paths.hpp b/include/boost/graph/r_c_shortest_paths.hpp index 9d395799..28755d87 100644 --- a/include/boost/graph/r_c_shortest_paths.hpp +++ b/include/boost/graph/r_c_shortest_paths.hpp @@ -222,7 +222,7 @@ void r_c_shortest_paths_dispatch std::vector vec_last_valid_index_for_dominance( num_vertices( g ), 0 ); std::vector b_vec_vertex_already_checked_for_dominance( num_vertices( g ), false ); - while( unprocessed_labels.size() ) + while( !unprocessed_labels.empty() && vis.on_enter_loop(unprocessed_labels, g) ) { Splabel cur_label = unprocessed_labels.top(); unprocessed_labels.pop(); @@ -409,7 +409,7 @@ void r_c_shortest_paths_dispatch typename std::list::const_iterator csi = dsplabels.begin(); typename std::list::const_iterator csi_end = dsplabels.end(); // if d could be reached from o - if( dsplabels.size() ) + if( !dsplabels.empty() ) { for( ; csi != csi_end; ++csi ) { @@ -458,6 +458,8 @@ struct default_r_c_shortest_paths_visitor void on_label_dominated( const Label&, const Graph& ) {} template void on_label_not_dominated( const Label&, const Graph& ) {} + template + bool on_enter_loop(const Queue& queue, const Graph& graph) {return true;} }; // default_r_c_shortest_paths_visitor diff --git a/include/boost/graph/reverse_graph.hpp b/include/boost/graph/reverse_graph.hpp index 7985e97f..e9027e3c 100644 --- a/include/boost/graph/reverse_graph.hpp +++ b/include/boost/graph/reverse_graph.hpp @@ -109,6 +109,8 @@ class reverse_graph { // Constructor reverse_graph(GraphRef g) : m_g(g) {} + // Conversion from reverse_graph on non-const reference to one on const reference + reverse_graph(const reverse_graph& o): m_g(o.m_g) {} // Graph requirements typedef typename Traits::vertex_descriptor vertex_descriptor; @@ -364,7 +366,12 @@ namespace detail { template struct property_map, Property> { typedef boost::is_same::type, edge_property_tag> is_edge_prop; - typedef typename property_map::type orig_type; + typedef boost::is_const::type> is_ref_const; + typedef typename boost::mpl::if_< + is_ref_const, + typename property_map::const_type, + typename property_map::type>::type + orig_type; typedef typename property_map::const_type orig_const_type; typedef typename boost::mpl::if_, orig_type>::type type; typedef typename boost::mpl::if_, orig_const_type>::type const_type; diff --git a/include/boost/graph/rmat_graph_generator.hpp b/include/boost/graph/rmat_graph_generator.hpp index 4256d7a8..f083fc55 100644 --- a/include/boost/graph/rmat_graph_generator.hpp +++ b/include/boost/graph/rmat_graph_generator.hpp @@ -22,7 +22,7 @@ #include #include #include -#include +// #include using boost::shared_ptr; using boost::uniform_01; @@ -139,7 +139,7 @@ namespace boost { typedef std::pair value_type; typedef const value_type& reference; typedef const value_type* pointer; - typedef void difference_type; + typedef std::ptrdiff_t difference_type; // Not used // No argument constructor, set to terminating condition rmat_iterator() @@ -156,7 +156,7 @@ namespace boost { { this->gen.reset(new uniform_01(gen)); - BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + d, 1., boost::test_tools::fraction_tolerance(1.e-5))); + // BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + d, 1., 1.e-5)); if (permute_vertices) generate_permutation_vector(gen, vertexPermutation, n); @@ -250,7 +250,7 @@ namespace boost { typedef std::pair value_type; typedef const value_type& reference; typedef const value_type* pointer; - typedef void difference_type; + typedef std::ptrdiff_t difference_type; // Not used // No argument constructor, set to terminating condition sorted_rmat_iterator() @@ -266,7 +266,7 @@ namespace boost { values(sort_pair()), done(false) { - BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + d, 1., boost::test_tools::fraction_tolerance(1.e-5))); + // BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + d, 1., 1.e-5)); this->gen.reset(new uniform_01(gen)); @@ -352,7 +352,7 @@ namespace boost { typedef std::pair value_type; typedef const value_type& reference; typedef const value_type* pointer; - typedef void difference_type; + typedef std::ptrdiff_t difference_type; // Not used // No argument constructor, set to terminating condition unique_rmat_iterator() @@ -367,7 +367,7 @@ namespace boost { : gen(), done(false) { - BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + d, 1., boost::test_tools::fraction_tolerance(1.e-5))); + // BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + d, 1., 1.e-5)); this->gen.reset(new uniform_01(gen)); @@ -464,7 +464,7 @@ namespace boost { typedef std::pair value_type; typedef const value_type& reference; typedef const value_type* pointer; - typedef void difference_type; + typedef std::ptrdiff_t difference_type; // Not used // No argument constructor, set to terminating condition sorted_unique_rmat_iterator() @@ -480,7 +480,7 @@ namespace boost { values(sort_pair()), done(false) { - BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + d, 1., boost::test_tools::fraction_tolerance(1.e-5))); + // BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + d, 1., 1.e-5)); this->gen.reset(new uniform_01(gen)); diff --git a/include/boost/graph/sloan_ordering.hpp b/include/boost/graph/sloan_ordering.hpp index 781e9c9f..88ad1b29 100644 --- a/include/boost/graph/sloan_ordering.hpp +++ b/include/boost/graph/sloan_ordering.hpp @@ -46,9 +46,9 @@ namespace boost { // ///////////////////////////////////////////////////////////////////////// template - unsigned RLS_depth(Distance& d) + typename Distance::value_type RLS_depth(Distance& d) { - unsigned h_s = 0; + typename Distance::value_type h_s = 0; typename Distance::iterator iter; for (iter = d.begin(); iter != d.end(); ++iter) @@ -70,14 +70,16 @@ namespace boost { // ///////////////////////////////////////////////////////////////////////// template - unsigned RLS_max_width(Distance& d, my_int depth) + typename Distance::value_type RLS_max_width(Distance& d, my_int depth) { + + typedef typename Distance::value_type Degree; //Searching for the maximum width of a level - std::vector dummy_width(depth+1, 0); - std::vector::iterator my_it; + std::vector dummy_width(depth+1, 0); + typename std::vector::iterator my_it; typename Distance::iterator iter; - unsigned w_max = 0; + Degree w_max = 0; for (iter = d.begin(); iter != d.end(); ++iter) { @@ -117,10 +119,10 @@ namespace boost { s = *(vertices(G).first); Vertex e = s; Vertex i; - unsigned my_degree = get(degree, s ); - unsigned dummy, h_i, h_s, w_i, w_e; + Degree my_degree = get(degree, s ); + Degree dummy, h_i, h_s, w_i, w_e; bool new_start = true; - unsigned maximum_degree = 0; + Degree maximum_degree = 0; //Creating a std-vector for storing the distance from the start vertex in dist std::vector::vertices_size_type> dist(num_vertices(G), 0); @@ -196,7 +198,7 @@ namespace boost { // step 5 // Initializing w - w_e = (std::numeric_limits::max)(); + w_e = (std::numeric_limits::max)(); //end 5 @@ -290,7 +292,7 @@ namespace boost { typename property_map::type index_map = get(vertex_index, g); //Sets the color and priority to their initial status - unsigned cdeg; + Degree cdeg; typename graph_traits::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { diff --git a/include/boost/graph/stoer_wagner_min_cut.hpp b/include/boost/graph/stoer_wagner_min_cut.hpp index 060f51b4..c868c0c8 100644 --- a/include/boost/graph/stoer_wagner_min_cut.hpp +++ b/include/boost/graph/stoer_wagner_min_cut.hpp @@ -15,104 +15,96 @@ #include #include #include -#include +#include #include +#include #include #include #include #include +#include namespace boost { - + namespace detail { - - /** - * \brief Performs a phase of the Stoer-Wagner min-cut algorithm - * - * Performs a phase of the Stoer-Wagner min-cut algorithm. - * - * As described by Stoer & Wagner (1997), a phase is simply a maximum adjacency search - * (also called a maximum cardinality search), which results in the selection of two vertices - * \em s and \em t, and, as a side product, a minimum s-t cut of - * the input graph. Here, the input graph is basically \p g, but some vertices are virtually - * assigned to others as a way of viewing \p g as a graph with some sets of - * vertices merged together. - * - * This implementation is a translation of pseudocode by Professor Uri Zwick, - * School of Computer Science, Tel Aviv University. - * - * \pre \p g is a connected, undirected graph - * \param[in] g the input graph - * \param[in] assignments a read/write property map from each vertex to the vertex that it is assigned to - * \param[in] assignedVertices a list of vertices that are assigned to others - * \param[in] weights a readable property map from each edge to its weight (a non-negative value) - * \param[out] pq a keyed, updatable max-priority queue - * \returns a tuple (\em s, \em t, \em w) of the "s" and "t" - * of the minimum s-t cut and the cut weight \em w - * of the minimum s-t cut. - * \see http://www.cs.tau.ac.il/~zwick/grad-algo-08/gmc.pdf - * - * \author Daniel Trebbien - * \date 2010-09-11 - */ - template - boost::tuple::vertex_descriptor, typename boost::graph_traits::vertex_descriptor, typename boost::property_traits::value_type> - stoer_wagner_phase(const UndirectedGraph& g, VertexAssignmentMap assignments, const std::set::vertex_descriptor>& assignedVertices, WeightMap weights, KeyedUpdatablePriorityQueue& pq) { - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + template < typename ParityMap, typename WeightMap, typename IndexMap > + class mas_min_cut_visitor : public boost::default_mas_visitor { + typedef one_bit_color_map InternalParityMap; typedef typename boost::property_traits::value_type weight_type; - - BOOST_ASSERT(pq.empty()); - typename KeyedUpdatablePriorityQueue::key_map keys = pq.keys(); - - BGL_FORALL_VERTICES_T(v, g, UndirectedGraph) { - if (v == get(assignments, v)) { // foreach u \in V do - put(keys, v, weight_type(0)); - - pq.push(v); + public: + template < typename Graph > + mas_min_cut_visitor(const Graph& g, + ParityMap parity, + weight_type& cutweight, + WeightMap weight_map, + IndexMap index_map) + : m_bestParity(parity), + m_parity(make_one_bit_color_map(num_vertices(g), index_map)), + m_bestWeight(cutweight), + m_cutweight(0), + m_visited(0), + m_weightMap(weight_map) + { + // set here since the init list sets the reference + m_bestWeight = (std::numeric_limits::max)(); + } + + template < typename Vertex, typename Graph > + void initialize_vertex(Vertex u, const Graph & g) + { + typedef typename boost::property_traits::value_type parity_type; + typedef typename boost::property_traits::value_type internal_parity_type; + + put(m_parity, u, internal_parity_type(0)); + put(m_bestParity, u, parity_type(0)); + } + + template < typename Edge, typename Graph > + void examine_edge(Edge e, const Graph & g) + { + weight_type w = get(m_weightMap, e); + + // if the target of e is already marked then decrease cutweight + // otherwise, increase it + if (get(m_parity, boost::target(e, g))) { + m_cutweight -= w; + } else { + m_cutweight += w; } } - - BOOST_ASSERT(pq.size() >= 2); - - vertex_descriptor s = boost::graph_traits::null_vertex(); - vertex_descriptor t = boost::graph_traits::null_vertex(); - weight_type w; - while (!pq.empty()) { // while PQ \neq {} do - const vertex_descriptor u = pq.top(); // u = extractmax(PQ) - w = get(keys, u); - pq.pop(); - - s = t; t = u; - - BGL_FORALL_OUTEDGES_T(u, e, g, UndirectedGraph) { // foreach (u, v) \in E do - const vertex_descriptor v = get(assignments, target(e, g)); - - if (pq.contains(v)) { // if v \in PQ then - put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, wA(v) + w(u, v)) - pq.update(v); - } - } - - typename std::set::const_iterator assignedVertexIt, assignedVertexEnd = assignedVertices.end(); - for (assignedVertexIt = assignedVertices.begin(); assignedVertexIt != assignedVertexEnd; ++assignedVertexIt) { - const vertex_descriptor uPrime = *assignedVertexIt; - - if (get(assignments, uPrime) == u) { - BGL_FORALL_OUTEDGES_T(uPrime, e, g, UndirectedGraph) { // foreach (u, v) \in E do - const vertex_descriptor v = get(assignments, target(e, g)); - - if (pq.contains(v)) { // if v \in PQ then - put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, wA(v) + w(u, v)) - pq.update(v); - } - } + + template < typename Vertex, typename Graph > + void finish_vertex(Vertex u, const Graph & g) + { + typedef typename boost::property_traits::value_type parity_type; + typedef typename boost::property_traits::value_type internal_parity_type; + + ++m_visited; + put(m_parity, u, internal_parity_type(1)); + + if (m_cutweight < m_bestWeight && m_visited < num_vertices(g)) { + m_bestWeight = m_cutweight; + BGL_FORALL_VERTICES_T(i, g, Graph) { + put(m_bestParity,i, get(m_parity,i)); } } } - - return boost::make_tuple(s, t, w); - } - + + inline void clear() { + m_bestWeight = (std::numeric_limits::max)(); + m_visited = 0; + m_cutweight = 0; + } + + private: + ParityMap m_bestParity; + InternalParityMap m_parity; + weight_type& m_bestWeight; + weight_type m_cutweight; + unsigned m_visited; + const WeightMap& m_weightMap; + }; + /** * \brief Computes a min-cut of the input graph * @@ -135,9 +127,57 @@ namespace boost { * \author Daniel Trebbien * \date 2010-09-11 */ - template + template typename boost::property_traits::value_type - stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq) { + stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq, IndexMap index_map) { + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::vertices_size_type vertices_size_type; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef typename boost::property_traits::value_type weight_type; + typedef typename boost::property_traits::value_type parity_type; + + typename graph_traits::vertex_iterator u_iter, u_end; + + weight_type bestW = (std::numeric_limits::max)(); + weight_type bestThisTime = (std::numeric_limits::max)(); + vertex_descriptor bestStart; + + detail::mas_min_cut_visitor + vis(g, parities, bestThisTime, weights, index_map); + + // for each node in the graph, + for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) { + // run the MAS and find the min cut + vis.clear(); + boost::maximum_adjacency_search(g, + boost::weight_map(weights). + visitor(vis). + root_vertex(*u_iter). + vertex_assignment_map(assignments). + max_priority_queue(pq)); + if (bestThisTime < bestW) { + bestW = bestThisTime; + bestStart = *u_iter; + } + } + + // Run one more time, starting from the best start location, to + // ensure the visitor has the best values. + vis.clear(); + boost::maximum_adjacency_search(g, + boost::vertex_assignment_map(assignments). + weight_map(weights). + visitor(vis). + root_vertex(bestStart). + max_priority_queue(pq)); + + return bestW; + } + } // end `namespace detail` within `namespace boost` + + template + typename boost::property_traits::value_type + stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq, IndexMap index_map) { BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept)); BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept)); typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; @@ -151,91 +191,62 @@ namespace boost { BOOST_CONCEPT_ASSERT((boost::ReadWritePropertyMapConcept)); BOOST_CONCEPT_ASSERT((boost::Convertible::value_type>)); BOOST_CONCEPT_ASSERT((boost::KeyedUpdatableQueueConcept)); - + vertices_size_type n = num_vertices(g); if (n < 2) throw boost::bad_graph("the input graph must have at least two vertices."); else if (!pq.empty()) throw std::invalid_argument("the max-priority queue must be empty initially."); - - std::set assignedVertices; - - // initialize `assignments` (all vertices are initially assigned to themselves) - BGL_FORALL_VERTICES_T(v, g, UndirectedGraph) { - put(assignments, v, v); - } - - vertex_descriptor s, t; - weight_type bestW; - - boost::tie(s, t, bestW) = boost::detail::stoer_wagner_phase(g, assignments, assignedVertices, weights, pq); - BOOST_ASSERT(s != t); - BGL_FORALL_VERTICES_T(v, g, UndirectedGraph) { - put(parities, v, parity_type(v == t ? 1 : 0)); - } - put(assignments, t, s); - assignedVertices.insert(t); - --n; - - for (; n >= 2; --n) { - weight_type w; - boost::tie(s, t, w) = boost::detail::stoer_wagner_phase(g, assignments, assignedVertices, weights, pq); - BOOST_ASSERT(s != t); - - if (w < bestW) { - BGL_FORALL_VERTICES_T(v, g, UndirectedGraph) { - put(parities, v, parity_type(get(assignments, v) == t ? 1 : 0)); - - if (get(assignments, v) == t) // all vertices that were assigned to t are now assigned to s - put(assignments, v, s); - } - - bestW = w; - } else { - BGL_FORALL_VERTICES_T(v, g, UndirectedGraph) { - if (get(assignments, v) == t) // all vertices that were assigned to t are now assigned to s - put(assignments, v, s); - } - } - put(assignments, t, s); - assignedVertices.insert(t); - } - - BOOST_ASSERT(pq.empty()); - - return bestW; + + return detail::stoer_wagner_min_cut(g, weights, + parities, assignments, pq, index_map); } - - } // end `namespace detail` within `namespace boost` - - template - inline typename boost::property_traits::value_type - stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, const boost::bgl_named_params& params) { - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename std::vector::size_type heap_container_size_type; - typedef typename boost::property_traits::value_type weight_type; - - typedef boost::bgl_named_params params_type; - BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params) - - typedef boost::detail::make_priority_queue_from_arg_pack_gen > gen_type; - gen_type gen(choose_param(get_param(params, boost::distance_zero_t()), weight_type(0))); - typename boost::result_of::type pq = gen(g, arg_pack); - - return boost::detail::stoer_wagner_min_cut(g, - weights, - choose_param(get_param(params, boost::parity_map_t()), boost::dummy_property_map()), - boost::detail::make_property_map_from_arg_pack_gen(vertex_descriptor())(g, arg_pack), - pq - ); + +namespace graph { + namespace detail { + template + struct stoer_wagner_min_cut_impl { + typedef typename boost::property_traits::value_type result_type; + template + result_type operator() (const UndirectedGraph& g, WeightMap weights, const ArgPack& arg_pack) const { + using namespace boost::graph::keywords; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::property_traits::value_type weight_type; + + typedef typename boost::detail::make_priority_queue_from_arg_pack_gen > gen_type; + + gen_type gen(choose_param(get_param(arg_pack, boost::distance_zero_t()), weight_type(0))); + + typename boost::result_of::type pq = gen(g, arg_pack); + + return boost::stoer_wagner_min_cut(g, + weights, + arg_pack [_parity_map | boost::dummy_property_map()], + boost::detail::make_property_map_from_arg_pack_gen(vertex_descriptor())(g, arg_pack), + pq, + boost::detail::override_const_property(arg_pack, _vertex_index_map, g, vertex_index) + ); + } + }; } - - template - inline typename boost::property_traits::value_type - stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights) { - return boost::stoer_wagner_min_cut(g, weights, boost::vertex_index_map(get(boost::vertex_index, g))); - } - + BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(stoer_wagner_min_cut,2,4) +} + + // Named parameter interface + BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(stoer_wagner_min_cut, 2) +namespace graph { + // version without IndexMap kept for backwards compatibility + // (but requires vertex_index_t to be defined in the graph) + // Place after the macro to avoid compilation errors + template + typename boost::property_traits::value_type + stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq) { + + return stoer_wagner_min_cut(g, weights, + parities, assignments, pq, + get(vertex_index, g)); + } +} // end `namespace graph` } // end `namespace boost` #include diff --git a/include/boost/graph/vf2_sub_graph_iso.hpp b/include/boost/graph/vf2_sub_graph_iso.hpp index 89784dfe..a316f781 100755 --- a/include/boost/graph/vf2_sub_graph_iso.hpp +++ b/include/boost/graph/vf2_sub_graph_iso.hpp @@ -1,5 +1,6 @@ //======================================================================= // Copyright (C) 2012 Flavio De Lorenzi (fdlorenzi@gmail.com) +// Copyright (C) 2013 Jakob Lykke Andersen, University of Southern Denmark (jlandersen@imada.sdu.dk) // // The algorithm implemented here is derived from original ideas by // Pasquale Foggia and colaborators. For further information see @@ -10,6 +11,9 @@ // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= +// Revision History: +// 8 April 2013: Fixed a typo in vf2_print_callback. (Flavio De Lorenzi) + #ifndef BOOST_VF2_SUB_GRAPH_ISO_HPP #define BOOST_VF2_SUB_GRAPH_ISO_HPP @@ -54,7 +58,7 @@ namespace boost { // Print (sub)graph isomorphism map BGL_FORALL_VERTICES_T(v, graph1_, Graph1) std::cout << '(' << get(vertex_index_t(), graph1_, v) << ", " - << get(vertex_index_t(), graph1_, get(f, v)) << ") "; + << get(vertex_index_t(), graph2_, get(f, v)) << ") "; std::cout << std::endl; @@ -372,7 +376,7 @@ namespace boost { }; - enum problem_selector { subgraph_iso, isomorphism }; + enum problem_selector {subgraph_mono, subgraph_iso, isomorphism }; // The actual state associated with both graphs template state1_; base_state state2_; - // Two helper functions used in Feasibility and Valid functions to test + // Three helper functions used in Feasibility and Valid functions to test // terminal set counts when testing for: + // - graph sub-graph monomorphism, or + inline bool comp_term_sets(graph1_size_type a, + graph2_size_type b, + boost::mpl::int_) const { + return a <= b; + } + // - graph sub-graph isomorphism, or inline bool comp_term_sets(graph1_size_type a, graph2_size_type b, @@ -519,15 +530,16 @@ namespace boost { BGL_FORALL_INEDGES_T(w_new, e2, graph2_, Graph2) { vertex2_type w = source(e2, graph2_); if (state2_.in_core(w) || (w == w_new)) { - vertex1_type v = v_new; - if (w != w_new) - v = state2_.core(w); - - if (!edge1_exists(v, v_new, - edge1_predicate(edge_comp_, e2), - graph1_)) - return false; + if (problem_selection != subgraph_mono) { + vertex1_type v = v_new; + if (w != w_new) + v = state2_.core(w); + if (!edge1_exists(v, v_new, + edge1_predicate(edge_comp_, e2), + graph1_)) + return false; + } } else { if (0 < state2_.in_depth(w)) ++term_in2_count; @@ -545,15 +557,16 @@ namespace boost { BGL_FORALL_OUTEDGES_T(w_new, e2, graph2_, Graph2) { vertex2_type w = target(e2, graph2_); if (state2_.in_core(w) || (w == w_new)) { - vertex1_type v = v_new; - if (w != w_new) - v = state2_.core(w); - - if (!edge1_exists(v_new, v, - edge1_predicate(edge_comp_, e2), - graph1_)) - return false; + if (problem_selection != subgraph_mono) { + vertex1_type v = v_new; + if (w != w_new) + v = state2_.core(w); + if (!edge1_exists(v_new, v, + edge1_predicate(edge_comp_, e2), + graph1_)) + return false; + } } else { if (0 < state2_.in_depth(w)) ++term_in2_count; @@ -564,13 +577,23 @@ namespace boost { } } } - - return comp_term_sets(term_in1_count, term_in2_count, - boost::mpl::int_()) && - comp_term_sets(term_out1_count, term_out2_count, - boost::mpl::int_()) && - comp_term_sets(rest1_count, rest2_count, - boost::mpl::int_()); + + if (problem_selection != subgraph_mono) { // subgraph_iso and isomorphism + return comp_term_sets(term_in1_count, term_in2_count, + boost::mpl::int_()) && + comp_term_sets(term_out1_count, term_out2_count, + boost::mpl::int_()) && + comp_term_sets(rest1_count, rest2_count, + boost::mpl::int_()); + } else { // subgraph_mono + return comp_term_sets(term_in1_count, term_in2_count, + boost::mpl::int_()) && + comp_term_sets(term_out1_count, term_out2_count, + boost::mpl::int_()) && + comp_term_sets(term_in1_count + term_out1_count + rest1_count, + term_in2_count + term_out2_count + rest2_count, + boost::mpl::int_()); + } } // Returns true if vertex v in graph1 is a possible candidate to @@ -790,6 +813,91 @@ namespace boost { } + // Enumerates all graph sub-graph mono-/iso-morphism mappings between graphs + // graph_small and graph_large. Continues until user_callback returns true or the + // search space has been fully explored. + template + bool vf2_subgraph_morphism(const GraphSmall& graph_small, const GraphLarge& graph_large, + SubGraphIsoMapCallback user_callback, + IndexMapSmall index_map_small, IndexMapLarge index_map_large, + const VertexOrderSmall& vertex_order_small, + EdgeEquivalencePredicate edge_comp, + VertexEquivalencePredicate vertex_comp) { + + // Graph requirements + BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept )); + BOOST_CONCEPT_ASSERT(( VertexListGraphConcept )); + BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept )); + BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept )); + + BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept )); + BOOST_CONCEPT_ASSERT(( VertexListGraphConcept )); + BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept )); + BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept )); + + typedef typename graph_traits::vertex_descriptor vertex_small_type; + typedef typename graph_traits::vertex_descriptor vertex_large_type; + + typedef typename graph_traits::vertices_size_type size_type_small; + typedef typename graph_traits::vertices_size_type size_type_large; + + // Property map requirements + BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept )); + typedef typename property_traits::value_type IndexMapSmallValue; + BOOST_STATIC_ASSERT(( is_convertible::value )); + + BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept )); + typedef typename property_traits::value_type IndexMapLargeValue; + BOOST_STATIC_ASSERT(( is_convertible::value )); + + // Edge & vertex requirements + typedef typename graph_traits::edge_descriptor edge_small_type; + typedef typename graph_traits::edge_descriptor edge_large_type; + + BOOST_CONCEPT_ASSERT(( BinaryPredicateConcept )); + + BOOST_CONCEPT_ASSERT(( BinaryPredicateConcept )); + + // Vertex order requirements + BOOST_CONCEPT_ASSERT(( ContainerConcept )); + typedef typename VertexOrderSmall::value_type order_value_type; + BOOST_STATIC_ASSERT(( is_same::value )); + BOOST_ASSERT( num_vertices(graph_small) == vertex_order_small.size() ); + + if (num_vertices(graph_small) > num_vertices(graph_large)) + return false; + + typename graph_traits::edges_size_type num_edges_small = num_edges(graph_small); + typename graph_traits::edges_size_type num_edges_large = num_edges(graph_large); + + // Double the number of edges for undirected graphs: each edge counts as + // in-edge and out-edge + if (is_undirected(graph_small)) num_edges_small *= 2; + if (is_undirected(graph_large)) num_edges_large *= 2; + if (num_edges_small > num_edges_large) + return false; + + if ((num_vertices(graph_small) == 0) && (num_vertices(graph_large) == 0)) + return true; + + detail::state + s(graph_small, graph_large, index_map_small, index_map_large, edge_comp, vertex_comp); + + return detail::match(graph_small, graph_large, user_callback, vertex_order_small, s); + } + } // namespace detail @@ -805,6 +913,72 @@ namespace boost { return vertex_order; } + + // Enumerates all graph sub-graph monomorphism mappings between graphs + // graph_small and graph_large. Continues until user_callback returns true or the + // search space has been fully explored. + template + bool vf2_subgraph_mono(const GraphSmall& graph_small, const GraphLarge& graph_large, + SubGraphIsoMapCallback user_callback, + IndexMapSmall index_map_small, IndexMapLarge index_map_large, + const VertexOrderSmall& vertex_order_small, + EdgeEquivalencePredicate edge_comp, + VertexEquivalencePredicate vertex_comp) { + return detail::vf2_subgraph_morphism + (graph_small, graph_large, + user_callback, + index_map_small, index_map_large, + vertex_order_small, + edge_comp, + vertex_comp); + } + + + // All default interface for vf2_subgraph_iso + template + bool vf2_subgraph_mono(const GraphSmall& graph_small, const GraphLarge& graph_large, + SubGraphIsoMapCallback user_callback) { + return vf2_subgraph_mono(graph_small, graph_large, user_callback, + get(vertex_index, graph_small), get(vertex_index, graph_large), + vertex_order_by_mult(graph_small), + always_equivalent(), always_equivalent()); + } + + + // Named parameter interface of vf2_subgraph_iso + template + bool vf2_subgraph_mono(const GraphSmall& graph_small, const GraphLarge& graph_large, + SubGraphIsoMapCallback user_callback, + const VertexOrderSmall& vertex_order_small, + const bgl_named_params& params) { + return vf2_subgraph_mono(graph_small, graph_large, user_callback, + choose_const_pmap(get_param(params, vertex_index1), + graph_small, vertex_index), + choose_const_pmap(get_param(params, vertex_index2), + graph_large, vertex_index), + vertex_order_small, + choose_param(get_param(params, edges_equivalent_t()), + always_equivalent()), + choose_param(get_param(params, vertices_equivalent_t()), + always_equivalent()) + ); + } + // Enumerates all graph sub-graph isomorphism mappings between graphs // graph_small and graph_large. Continues until user_callback returns true or the @@ -823,71 +997,13 @@ namespace boost { const VertexOrderSmall& vertex_order_small, EdgeEquivalencePredicate edge_comp, VertexEquivalencePredicate vertex_comp) { - - // Graph requirements - BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept )); - BOOST_CONCEPT_ASSERT(( VertexListGraphConcept )); - BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept )); - BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept )); - - BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept )); - BOOST_CONCEPT_ASSERT(( VertexListGraphConcept )); - BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept )); - BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept )); - - typedef typename graph_traits::vertex_descriptor vertex_small_type; - typedef typename graph_traits::vertex_descriptor vertex_large_type; - - typedef typename graph_traits::vertices_size_type size_type_small; - typedef typename graph_traits::vertices_size_type size_type_large; - - // Property map requirements - BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept )); - typedef typename property_traits::value_type IndexMapSmallValue; - BOOST_STATIC_ASSERT(( is_convertible::value )); - - BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept )); - typedef typename property_traits::value_type IndexMapLargeValue; - BOOST_STATIC_ASSERT(( is_convertible::value )); - - // Edge & vertex requirements - typedef typename graph_traits::edge_descriptor edge_small_type; - typedef typename graph_traits::edge_descriptor edge_large_type; - - BOOST_CONCEPT_ASSERT(( BinaryPredicateConcept )); - - BOOST_CONCEPT_ASSERT(( BinaryPredicateConcept )); - - // Vertex order requirements - BOOST_CONCEPT_ASSERT(( ContainerConcept )); - typedef typename VertexOrderSmall::value_type order_value_type; - BOOST_STATIC_ASSERT(( is_same::value )); - BOOST_ASSERT( num_vertices(graph_small) == vertex_order_small.size() ); - - if (num_vertices(graph_small) > num_vertices(graph_large)) - return false; - - typename graph_traits::edges_size_type num_edges_small = num_edges(graph_small); - typename graph_traits::edges_size_type num_edges_large = num_edges(graph_large); - - // Double the number of edges for undirected graphs: each edge counts as - // in-edge and out-edge - if (is_undirected(graph_small)) num_edges_small *= 2; - if (is_undirected(graph_large)) num_edges_large *= 2; - if (num_edges_small > num_edges_large) - return false; - - if ((num_vertices(graph_small) == 0) && (num_vertices(graph_large) == 0)) - return true; - - detail::state - s(graph_small, graph_large, index_map_small, index_map_large, edge_comp, vertex_comp); - - return detail::match(graph_small, graph_large, user_callback, vertex_order_small, s); + return detail::vf2_subgraph_morphism + (graph_small, graph_large, + user_callback, + index_map_small, index_map_large, + vertex_order_small, + edge_comp, + vertex_comp); } diff --git a/src/graphml.cpp b/src/graphml.cpp index 30c58fe7..76ef0a29 100644 --- a/src/graphml.cpp +++ b/src/graphml.cpp @@ -71,6 +71,7 @@ public: else if (for_ == "port") kind = port_key; else if (for_ == "endpoint") kind = endpoint_key; else if (for_ == "all") kind = all_key; + else if (for_ == "graphml") kind = graphml_key; else {BOOST_THROW_EXCEPTION(parse_error("Attribute for is not valid: " + for_));} m_keys[id] = kind; m_key_name[id] = name; @@ -132,7 +133,8 @@ private: hyperedge_key, port_key, endpoint_key, - all_key + all_key, + graphml_key }; void diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 72d58cff..fe0b4849 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -122,6 +122,7 @@ test-suite graph_test : [ run two_graphs_common_spanning_trees_test.cpp ] [ run random_spanning_tree_test.cpp ../build//boost_graph ] [ run graphml_test.cpp ../build//boost_graph : : "graphml_test.xml" ] + [ run mas_test.cpp ../../test/build//boost_unit_test_framework/static : $(TEST_DIR) ] [ run stoer_wagner_test.cpp ../../test/build//boost_unit_test_framework/static : $(TEST_DIR) ] [ compile filtered_graph_properties_dijkstra.cpp ] [ run vf2_sub_graph_iso_test.cpp ] diff --git a/test/astar_search_test.cpp b/test/astar_search_test.cpp index b108bcb2..d72b91f0 100644 --- a/test/astar_search_test.cpp +++ b/test/astar_search_test.cpp @@ -31,7 +31,12 @@ struct location { float y, x; // lat, long }; -typedef float cost; +struct my_float {float v; explicit my_float(float v = float()): v(v) {}}; +typedef my_float cost; +ostream& operator<<(ostream& o, my_float f) {return o << f.v;} +my_float operator+(my_float a, my_float b) {return my_float(a.v + b.v);} +bool operator==(my_float a, my_float b) {return a.v == b.v;} +bool operator<(my_float a, my_float b) {return a.v < b.v;} template class city_writer { @@ -80,9 +85,9 @@ public: : m_location(l), m_goal(goal) {} CostType operator()(Vertex u) { - CostType dx = m_location[m_goal].x - m_location[u].x; - CostType dy = m_location[m_goal].y - m_location[u].y; - return ::sqrt(dx * dx + dy * dy); + float dx = m_location[m_goal].x - m_location[u].x; + float dy = m_location[m_goal].y - m_location[u].y; + return CostType(::sqrt(dx * dx + dy * dy)); } private: LocMap m_location; @@ -153,8 +158,8 @@ int main(int, char **) }; unsigned int num_edges = sizeof(edge_array) / sizeof(edge); cost weights[] = { // estimated travel time (mins) - 96, 134, 143, 65, 115, 133, 117, 116, 74, 56, - 84, 73, 69, 70, 116, 147, 173, 183, 74, 71, 124 + my_float(96), my_float(134), my_float(143), my_float(65), my_float(115), my_float(133), my_float(117), my_float(116), my_float(74), my_float(56), + my_float(84), my_float(73), my_float(69), my_float(70), my_float(116), my_float(147), my_float(173), my_float(183), my_float(74), my_float(71), my_float(124) }; @@ -187,7 +192,7 @@ int main(int, char **) distance_heuristic (locations, goal), predecessor_map(&p[0]).distance_map(&d[0]). - visitor(astar_goal_visitor(goal))); + visitor(astar_goal_visitor(goal)).distance_inf(my_float((std::numeric_limits::max)()))); } catch(found_goal fg) { // found a path to the goal diff --git a/test/mas_test.cpp b/test/mas_test.cpp new file mode 100644 index 00000000..3553d65f --- /dev/null +++ b/test/mas_test.cpp @@ -0,0 +1,227 @@ +// Copyright Fernando Vilas 2012. +// Based on stoer_wagner_test.cpp by Daniel Trebbien. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or the copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef boost::adjacency_list > undirected_graph; +typedef boost::property_map::type weight_map_type; +typedef boost::property_traits::value_type weight_type; + +typedef boost::adjacency_list undirected_unweighted_graph; + +std::string test_dir; + +boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) { + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " path-to-libs-graph-test" << std::endl; + throw boost::unit_test::framework::setup_error("Invalid command line arguments"); + } + test_dir = argv[1]; + return 0; +} + +struct edge_t +{ + unsigned long first; + unsigned long second; +}; + +template +class mas_edge_connectivity_visitor : public boost::default_mas_visitor { + public: + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename KeyedUpdatablePriorityQueue::key_type weight_type; +#if 0 + mas_edge_connectivity_visitor(const mas_edge_connectivity_visitor& r) + : m_pq(r.m_pq), m_curr(r.m_curr), m_prev(r.m_prev), + m_reach_weight(r.m_reach_weight) { + BOOST_TEST_MESSAGE( "COPY CTOR" ); + } +#endif + explicit mas_edge_connectivity_visitor(KeyedUpdatablePriorityQueue& pq) + : m_pq(pq), + m_curr(new vertex_descriptor(0)), m_prev(new vertex_descriptor(0)), + m_reach_weight(new weight_type(0)) { + // BOOST_TEST_MESSAGE( "CTOR" ); + } + + void clear() { + *m_curr = 0; + *m_prev = 0; + *m_reach_weight = 0; + } + + //template //, typename Graph> + //void start_vertex(Vertex u, const Graph& g) { + void start_vertex(vertex_descriptor u, const Graph& g) { + *m_prev = *m_curr; + *m_curr = u; + //BOOST_TEST_MESSAGE( "Initializing Vertex(weight): " << u << "(" << *m_reach_weight << ")" ); + *m_reach_weight = get(m_pq.keys(), u); + } + + vertex_descriptor curr() const { return *m_curr; } + vertex_descriptor prev() const { return *m_prev; } + weight_type reach_weight() const { return *m_reach_weight; } + + private: + + const KeyedUpdatablePriorityQueue& m_pq; + boost::shared_ptr m_curr, m_prev; + boost::shared_ptr m_reach_weight; +}; + + +// the example from Stoer & Wagner (1997) +// Check various implementations of the ArgPack where +// the weights are provided in it, and one case where +// they are not. +BOOST_AUTO_TEST_CASE(test0) +{ + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef boost::graph_traits::edge_descriptor edge_descriptor; + + edge_t edges[] = {{0, 1}, {1, 2}, {2, 3}, + {0, 4}, {1, 4}, {1, 5}, {2, 6}, {3, 6}, {3, 7}, {4, 5}, {5, 6}, {6, 7}}; + weight_type ws[] = {2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 1, 3}; + undirected_graph g(edges, edges + 12, ws, 8, 12); + + weight_map_type weights = get(boost::edge_weight, g); + + std::map assignment; + boost::associative_property_map > assignments(assignment); + + typedef boost::shared_array_property_map::const_type> distances_type; + distances_type distances = boost::make_shared_array_property_map(num_vertices(g), weight_type(0), get(boost::vertex_index, g)); + typedef std::vector::size_type index_in_heap_type; + typedef boost::shared_array_property_map::const_type> indicesInHeap_type; + indicesInHeap_type indicesInHeap = boost::make_shared_array_property_map(num_vertices(g), index_in_heap_type(-1), get(boost::vertex_index, g)); + boost::d_ary_heap_indirect > pq(distances, indicesInHeap); + + mas_edge_connectivity_visitor > > test_vis(pq); + + boost::maximum_adjacency_search(g, + boost::weight_map(weights). + visitor(test_vis). + root_vertex(*vertices(g).first). + vertex_assignment_map(assignments). + max_priority_queue(pq)); + + BOOST_CHECK_EQUAL(test_vis.curr(), vertex_descriptor(7)); + BOOST_CHECK_EQUAL(test_vis.prev(), vertex_descriptor(6)); + BOOST_CHECK_EQUAL(test_vis.reach_weight(), 5); + + test_vis.clear(); + boost::maximum_adjacency_search(g, + boost::weight_map(weights). + visitor(test_vis). + root_vertex(*vertices(g).first). + max_priority_queue(pq)); + + BOOST_CHECK_EQUAL(test_vis.curr(), vertex_descriptor(7)); + BOOST_CHECK_EQUAL(test_vis.prev(), vertex_descriptor(6)); + BOOST_CHECK_EQUAL(test_vis.reach_weight(), 5); + + test_vis.clear(); + boost::maximum_adjacency_search(g, + boost::weight_map(weights). + visitor(test_vis). + max_priority_queue(pq)); + + BOOST_CHECK_EQUAL(test_vis.curr(), vertex_descriptor(7)); + BOOST_CHECK_EQUAL(test_vis.prev(), vertex_descriptor(6)); + BOOST_CHECK_EQUAL(test_vis.reach_weight(), 5); + + boost::maximum_adjacency_search(g, + boost::weight_map(weights). + visitor(boost::make_mas_visitor(boost::null_visitor()))); + + boost::maximum_adjacency_search(g, + boost::weight_map(weights)); + + boost::maximum_adjacency_search(g, + boost::root_vertex(*vertices(g).first)); + + test_vis.clear(); + boost::maximum_adjacency_search(g, + boost::weight_map(boost::make_constant_property(weight_type(1))). + visitor(test_vis). + max_priority_queue(pq)); + BOOST_CHECK_EQUAL(test_vis.curr(), vertex_descriptor(7)); + BOOST_CHECK_EQUAL(test_vis.prev(), vertex_descriptor(3)); + BOOST_CHECK_EQUAL(test_vis.reach_weight(), 2); + +} + +// Check the unweighted case +// with and without providing a weight_map +BOOST_AUTO_TEST_CASE(test1) +{ + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef boost::graph_traits::edge_descriptor edge_descriptor; + + edge_t edge_list[] = {{0, 1}, {1, 2}, {2, 3}, + {0, 4}, {1, 4}, {1, 5}, {2, 6}, {3, 6}, {3, 7}, {4, 5}, {5, 6}, {6, 7}}; + undirected_unweighted_graph g(edge_list, edge_list + 12, 8); + + std::map assignment; + boost::associative_property_map > assignments(assignment); + + typedef unsigned weight_type; + typedef boost::shared_array_property_map::const_type> distances_type; + distances_type distances = boost::make_shared_array_property_map(num_vertices(g), weight_type(0), get(boost::vertex_index, g)); + typedef std::vector::size_type index_in_heap_type; + typedef boost::shared_array_property_map::const_type> indicesInHeap_type; + indicesInHeap_type indicesInHeap = boost::make_shared_array_property_map(num_vertices(g), index_in_heap_type(-1), get(boost::vertex_index, g)); + boost::d_ary_heap_indirect > pq(distances, indicesInHeap); + + mas_edge_connectivity_visitor > > test_vis(pq); + + boost::maximum_adjacency_search(g, + boost::weight_map(boost::make_constant_property(weight_type(1))).visitor(test_vis).max_priority_queue(pq)); + + BOOST_CHECK_EQUAL(test_vis.curr(), vertex_descriptor(7)); + BOOST_CHECK_EQUAL(test_vis.prev(), vertex_descriptor(3)); + BOOST_CHECK_EQUAL(test_vis.reach_weight(), weight_type(2)); + + weight_type ws[] = {2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 1, 3}; + std::map wm; + + weight_type i = 0; + BGL_FORALL_EDGES(e, g, undirected_unweighted_graph) { + wm[e] = ws[i]; + ++i; + } + boost::associative_property_map > ws_map(wm); + + boost::maximum_adjacency_search(g, boost::weight_map(ws_map).visitor(test_vis).max_priority_queue(pq)); + BOOST_CHECK_EQUAL(test_vis.curr(), vertex_descriptor(7)); + BOOST_CHECK_EQUAL(test_vis.prev(), vertex_descriptor(6)); + BOOST_CHECK_EQUAL(test_vis.reach_weight(), weight_type(5)); + +} + +#include + diff --git a/test/vf2_sub_graph_iso_test.cpp b/test/vf2_sub_graph_iso_test.cpp index 7ad653e8..21ef97ee 100644 --- a/test/vf2_sub_graph_iso_test.cpp +++ b/test/vf2_sub_graph_iso_test.cpp @@ -9,6 +9,9 @@ // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= +// Revision History: +// 8 April 2013: Fixed a typo in random_functor. (Flavio De Lorenzi) + #include #include #include @@ -36,7 +39,7 @@ struct random_functor { random_functor(Generator& g) : g(g) { } std::size_t operator()(std::size_t n) { boost::uniform_int distrib(0, n-1); - boost::variate_generator > + boost::variate_generator > x(g, distrib); return x(); }