diff --git a/doc/BUILD_DOCS.sh b/doc/BUILD_DOCS.sh index e18de3b3..2ad09e3a 100755 --- a/doc/BUILD_DOCS.sh +++ b/doc/BUILD_DOCS.sh @@ -1,13 +1,22 @@ #!/bin/sh # Copyright (C) 2009 The Trustees of Indiana University. +# Copyright (C) 2010 Daniel Trebbien. # Use, modification and distribution is subject to 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) -# Authors: Jeremiah Willcock, Andrew Lumsdaine +# Authors: Jeremiah Willcock, Daniel Trebbien, Andrew Lumsdaine for i in read_graphml read_graphviz write_graphml; do rst2html.py -gdt --link-stylesheet --traceback --trim-footnote-reference-space --footnote-references=superscript --stylesheet=../../../rst.css $i.rst > $i.html done # Also see grid_graph_export_png.sh for figure conversions + +# Stoer-Wagner images from Daniel Trebbien +fdp -s -n -Tgif -ostoer_wagner_imgs/digraph1.gif stoer_wagner_imgs/digraph1.dot +fdp -s -n -Tgif -ostoer_wagner_imgs/digraph1-min-cut.gif stoer_wagner_imgs/digraph1-min-cut.dot +fdp -s -n -Tgif -ostoer_wagner_imgs/stoer_wagner-example.gif stoer_wagner_imgs/stoer_wagner-example.dot +fdp -s -n -Tgif -ostoer_wagner_imgs/stoer_wagner-example-c1.gif stoer_wagner_imgs/stoer_wagner-example-c1.dot +fdp -s -n -Tgif -ostoer_wagner_imgs/stoer_wagner-example-min-cut.gif stoer_wagner_imgs/stoer_wagner-example-min-cut.dot +dot -Tgif -ostoer_wagner_imgs/stoer_wagner.cpp.gif stoer_wagner_imgs/stoer_wagner.cpp.dot diff --git a/doc/KeyedUpdatableQueue.html b/doc/KeyedUpdatableQueue.html new file mode 100644 index 00000000..6d5ecaf0 --- /dev/null +++ b/doc/KeyedUpdatableQueue.html @@ -0,0 +1,99 @@ + + + + +KeyedUpdatableQueue + + +C++ Boost + +

KeyedUpdatableQueue

+ +

A KeyedUpdatableQueue is a refinement of the UpdatableQueue concept. +It requires that models order the contained values by their keys, to which +values are mapped via a read/write key map. + +

Notation

+ + + + +
Q is a type that models KeyedUpdatableQueue.
T is the value type of Q.
+ + +

Members

+ +For a type to model the KeyedUpdatableQueue concept it must have the following members +in addition to the members that are required of types that model UpdatableQueue: + +

+ + + + + + + + + + + + + + + + + +
Member Description
key_type The type of keys that are associated with values
key_map The key property map type. This type must model Read/Write Property Map.
key_map keys() const Returns the key map
+ +

Concept Checking Class

+ +

boost/graph/buffer_concepts.hpp + +

+  template <class Q>
+  struct KeyedUpdatableQueueConcept
+  {
+    typedef typename Q::key_type key_type;
+    typedef typename Q::key_map key_map;
+    
+    void constraints() {
+      function_requires< UpdatableQueue<Q> >();
+      function_requires< ReadWritePropertyMap< key_map, typename Buffer<Q>::value_type > >();
+    }
+    
+    void const_constraints(const Q& cq) {
+      km = cq.keys();
+      k = get(km, g_ct);
+    }
+    
+    static const typename Buffer<Q>::value_type g_ct;
+    key_type k;
+    key_map km;
+    Q q;
+  };
+
+ +

Models

+ + + +
+
+ + + + + +
Copyright © 2010Daniel Trebbien (dtrebbien@gmail.com) +
+ + + \ No newline at end of file diff --git a/doc/UpdatableQueue.html b/doc/UpdatableQueue.html new file mode 100644 index 00000000..a91c69cf --- /dev/null +++ b/doc/UpdatableQueue.html @@ -0,0 +1,100 @@ + + + + +UpdatableQueue + + +C++ Boost + +

UpdatableQueue

+ +

An UpdatableQueue is a refinement of the Buffer concept that additionally requires that the Buffer be updatable. + +

Implicit in the definition is an ordering of values. Though access to the order is not required, types that model UpdatableQueue must document how an object of the type orders values so that a program may change the position of a given value in the ordering. For example, an UpdatableQueue may choose to order values by using a property map, and a value v1 is considered less than a value v2 if get(pm, v1) < get(pm, v2). A program can update the properties of values, thus changing the order of values in the UpdatableQueue, and notify the UpdatableQueue of the specific values that have a different position in the ordering by calling the update member of the UpdatableQueue on each. + +

A program that modifies the order must notify the UpdatableQueue of values that may have different positions in the ordering since they were inserted or last updated. + +

Notation

+ + + + +
Q is a type that models UpdatableQueue.
T is the value type of Q.
+ + +

Members

+ +For a type to model the UpdatableQueue concept it must have the following members +in addition to the members that are required of types that model Buffer: + +

+ + + + + + + + + + + + + +
Member Description
void update(const T& t) Informs the UpdatableQueue that the program has modified the position of t in the ordering
unspecified-bool-type contains(const T& t) const Returns whether the queue contains t
+ +

Concept Checking Class

+ +

boost/graph/buffer_concepts.hpp + +

+  template <class Q>
+  struct UpdatableQueueConcept
+  {
+    void constraints() {
+      function_requires< Buffer<Q> >();
+      
+      q.update(g_ct);
+    }
+    
+    void const_constraints(const Q& cq) {
+      if (cq.contains(g_ct));
+    }
+    
+    static const typename Buffer<Q>::value_type g_ct;
+    Q q;
+  };
+
+ +

Futher Refinements

+ + + +

UpdatablePriorityQueue

+

An UpdatablePriorityQueue is a slight refinement of UpdatableQueue +that imposes the requirement that a program may not increase the position of a value that is held in the queue. That is, +if a value v had position n in the ordering, a program may update the position of v only to 0, 1, ..., n - 1, or n, where 0 is the top of the queue. + +

The behavior when a program attempts to increase a value's position in the ordering is undefined. + +
+


+ + + + + +
Copyright © 2010Daniel Trebbien (dtrebbien@gmail.com) +
+ + + \ No newline at end of file diff --git a/doc/graph_theory_review.html b/doc/graph_theory_review.html index 687315fb..e811d297 100644 --- a/doc/graph_theory_review.html +++ b/doc/graph_theory_review.html @@ -1,6 +1,7 @@ -Boost Graph Library: read_dimacs_max_flow +Boost Graph Library: read_dimacs_max_flow and read_dimacs_min_cut //reads a graph with attached edge_capacity properties from an std::istream template <class Graph, class CapacityMap, class ReverseEdgeMap> -int read_dimacs_max_flow(Graph& g, +int read_dimacs_max_flow(Graph& g, CapacityMap capacity, ReverseEdgeMap reverse_edge, - typename graph_traits::vertex_descriptor& src, - typename graph_traits::vertex_descriptor& sink, - std::istream& in=std::cin) + typename graph_traits::vertex_descriptor& src, + typename graph_traits::vertex_descriptor& sink, + std::istream& in=std::cin) + +//reads a graph with attached edge_capacity properties from an std::istream +template <class Graph, class CapacityMap, class ReverseEdgeMap> +int read_dimacs_min_cut(Graph& g, + CapacityMap capacity, + ReverseEdgeMap reverse_edge, + std::istream& in=std::cin)

-This method reads a BGL graph object from a max-flow problem description in extended dimacs format. (see Goldbergs site for more information). For each edge found in the -file an additional reverse_edge is added and set in the reverse_edge map. Source- and sink-vertex-descriptors are set according to the dimacs file. +These functions read a BGL graph object from a max-flow or min-cut problem description in extended dimacs format. (see Goldberg's site for more information). For each edge found in the +file an additional reverse_edge is added and set in the reverse_edge map. For +max-flow problems, source and sink vertex descriptors are set according to the +dimacs file.

Where Defined

@@ -81,6 +91,16 @@ file an additional reverse_edge is added and set in the reverse_edge map. Source A property map that models mutable Lvalue Property Map whose key and value type is the edge descriptor of the graph. This map stores the corresponding reverse edge for each each in Graph g.
+ OUT: vertex_descriptor& src +
+ A graph vertex that will be set to the source of a max-flow problem. +
+ + OUT: vertex_descriptor& sink +
+ A graph vertex that will be set to the sink of a max-flow problem. +
+ IN: std::istream& in
A standard std::istream object.
diff --git a/doc/stoer_wagner_imgs/6e4.gif b/doc/stoer_wagner_imgs/6e4.gif new file mode 100644 index 00000000..5f0cd1c1 Binary files /dev/null and b/doc/stoer_wagner_imgs/6e4.gif differ diff --git a/doc/stoer_wagner_imgs/8b7.gif b/doc/stoer_wagner_imgs/8b7.gif new file mode 100644 index 00000000..7420a27d Binary files /dev/null and b/doc/stoer_wagner_imgs/8b7.gif differ diff --git a/doc/stoer_wagner_imgs/digraph1-min-cut.dot b/doc/stoer_wagner_imgs/digraph1-min-cut.dot new file mode 100644 index 00000000..6fa3414d --- /dev/null +++ b/doc/stoer_wagner_imgs/digraph1-min-cut.dot @@ -0,0 +1,13 @@ +digraph { + edge [ len=1.8 ]; + 0 [ pos="148,246z" ]; + 1 [ pos="255,30", style="filled", fillcolor=gray ]; + 2 [ pos="148,138", style="filled", fillcolor=gray ]; + 3 [ pos="41,138", style="filled", fillcolor=gray ]; + 1 -> 0 [ label="5" ]; + 1 -> 2 [ label="3" ]; + 2 -> 3 [ label="8" ]; + 3 -> 0 [ headlabel="3", labeldistance=4.5, labelangle=0.2854 ]; + 0 -> 3 [ headlabel="1", labeldistance=4.5, labelangle=-0.2854, color=red, fontcolor=red, style=dotted ]; + 3 -> 1 [ label="2", len=2.8 ]; +} \ No newline at end of file diff --git a/doc/stoer_wagner_imgs/digraph1-min-cut.gif b/doc/stoer_wagner_imgs/digraph1-min-cut.gif new file mode 100644 index 00000000..083a3b66 Binary files /dev/null and b/doc/stoer_wagner_imgs/digraph1-min-cut.gif differ diff --git a/doc/stoer_wagner_imgs/digraph1.dot b/doc/stoer_wagner_imgs/digraph1.dot new file mode 100644 index 00000000..e3fd0e09 --- /dev/null +++ b/doc/stoer_wagner_imgs/digraph1.dot @@ -0,0 +1,13 @@ +digraph { + edge [ len=1.8 ]; + 0 [ pos="148,246z" ]; + 1 [ pos="255,30" ]; + 2 [ pos="148,138" ]; + 3 [ pos="41,138" ]; + 1 -> 0 [ label="5" ]; + 1 -> 2 [ label="3" ]; + 2 -> 3 [ label="8" ]; + 3 -> 0 [ headlabel="3", labeldistance=4.5, labelangle=0.2854 ]; + 0 -> 3 [ headlabel="1", labeldistance=4.5, labelangle=-0.2854 ]; + 3 -> 1 [ label="2", len=2.8 ]; +} \ No newline at end of file diff --git a/doc/stoer_wagner_imgs/digraph1.gif b/doc/stoer_wagner_imgs/digraph1.gif new file mode 100644 index 00000000..db8804c8 Binary files /dev/null and b/doc/stoer_wagner_imgs/digraph1.gif differ diff --git a/doc/stoer_wagner_imgs/f79.gif b/doc/stoer_wagner_imgs/f79.gif new file mode 100644 index 00000000..cc47b4d3 Binary files /dev/null and b/doc/stoer_wagner_imgs/f79.gif differ diff --git a/doc/stoer_wagner_imgs/stoer_wagner-example-c1.dot b/doc/stoer_wagner_imgs/stoer_wagner-example-c1.dot new file mode 100644 index 00000000..1fce5233 --- /dev/null +++ b/doc/stoer_wagner_imgs/stoer_wagner-example-c1.dot @@ -0,0 +1,23 @@ +graph { + edge [ len=1.2 ]; + 0 [ pos="42,73", style="filled", fillcolor="#333399", fontcolor=white ]; + 1 [ pos="96,139", style="filled", fillcolor="#9999ff" ]; + 2 [ pos="113,209", style="filled", fillcolor="#9999ff" ]; + 3 [ pos="179,279", style="filled", fillcolor="#9999ff" ]; + 4 [ pos="143,30", style="filled", fillcolor="#9999ff" ]; + 5 [ pos="211,100", style="filled", fillcolor="#9999ff" ]; + 6 [ pos="228,175", style="filled", fillcolor="#333399", fontcolor=white ]; + 7 [ pos="282,241", style="filled", fillcolor="#9999ff" ]; + 0 -- 1 [ label="2", color=red, fontcolor=red, style=dotted ]; + 1 -- 2 [ label="3", len=1 ]; + 2 -- 3 [ label="4" ]; + 0 -- 4 [ label="3", color=red, fontcolor=red, style=dotted ]; + 1 -- 4 [ label="2", len=1.3 ]; + 1 -- 5 [ label="2" ]; + 2 -- 6 [ label="2", color=red, fontcolor=red, style=dotted ]; + 3 -- 6 [ label="2", len=1.3, color=red, fontcolor=red, style=dotted ]; + 3 -- 7 [ label="2" ]; + 4 -- 5 [ label="3" ]; + 5 -- 6 [ label="1", len=1.1, color=red, fontcolor=red, style=dotted ]; + 6 -- 7 [ label="3", color=red, fontcolor=red, style=dotted ]; +} \ No newline at end of file diff --git a/doc/stoer_wagner_imgs/stoer_wagner-example-c1.gif b/doc/stoer_wagner_imgs/stoer_wagner-example-c1.gif new file mode 100644 index 00000000..a67e344b Binary files /dev/null and b/doc/stoer_wagner_imgs/stoer_wagner-example-c1.gif differ diff --git a/doc/stoer_wagner_imgs/stoer_wagner-example-min-cut.dot b/doc/stoer_wagner_imgs/stoer_wagner-example-min-cut.dot new file mode 100644 index 00000000..889324ad --- /dev/null +++ b/doc/stoer_wagner_imgs/stoer_wagner-example-min-cut.dot @@ -0,0 +1,23 @@ +graph { + edge [ len=1.2 ]; + 0 [ pos="42,73", style="filled", fillcolor="#333399", fontcolor=white ]; + 1 [ pos="96,139", style="filled", fillcolor="#333399", fontcolor=white ]; + 2 [ pos="113,209", style="filled", fillcolor="#9999ff" ]; + 3 [ pos="179,279", style="filled", fillcolor="#9999ff" ]; + 4 [ pos="143,30", style="filled", fillcolor="#333399", fontcolor=white ]; + 5 [ pos="211,100", style="filled", fillcolor="#333399", fontcolor=white ]; + 6 [ pos="228,175", style="filled", fillcolor="#9999ff" ]; + 7 [ pos="282,241", style="filled", fillcolor="#9999ff" ]; + 0 -- 1 [ label="2" ]; + 1 -- 2 [ label="3", len=1, color=red, fontcolor=red, style=dotted ]; + 2 -- 3 [ label="4" ]; + 0 -- 4 [ label="3" ]; + 1 -- 4 [ label="2", len=1.3 ]; + 1 -- 5 [ label="2" ]; + 2 -- 6 [ label="2" ]; + 3 -- 6 [ label="2", len=1.3 ]; + 3 -- 7 [ label="2" ]; + 4 -- 5 [ label="3" ]; + 5 -- 6 [ label="1", len=1.1, color=red, fontcolor=red, style=dotted ]; + 6 -- 7 [ label="3" ]; +} \ No newline at end of file diff --git a/doc/stoer_wagner_imgs/stoer_wagner-example-min-cut.gif b/doc/stoer_wagner_imgs/stoer_wagner-example-min-cut.gif new file mode 100644 index 00000000..403e2363 Binary files /dev/null and b/doc/stoer_wagner_imgs/stoer_wagner-example-min-cut.gif differ diff --git a/doc/stoer_wagner_imgs/stoer_wagner-example.dot b/doc/stoer_wagner_imgs/stoer_wagner-example.dot new file mode 100644 index 00000000..a4261a53 --- /dev/null +++ b/doc/stoer_wagner_imgs/stoer_wagner-example.dot @@ -0,0 +1,23 @@ +graph { + edge [ len=1.2 ]; + 0 [ pos="42,73" ]; + 1 [ pos="96,139" ]; + 2 [ pos="113,209" ]; + 3 [ pos="179,279" ]; + 4 [ pos="143,30" ]; + 5 [ pos="211,100" ]; + 6 [ pos="228,175" ]; + 7 [ pos="282,241" ]; + 0 -- 1 [ label="2" ]; + 1 -- 2 [ label="3", len=1 ]; + 2 -- 3 [ label="4" ]; + 0 -- 4 [ label="3" ]; + 1 -- 4 [ label="2", len=1.3 ]; + 1 -- 5 [ label="2" ]; + 2 -- 6 [ label="2" ]; + 3 -- 6 [ label="2", len=1.3 ]; + 3 -- 7 [ label="2" ]; + 4 -- 5 [ label="3" ]; + 5 -- 6 [ label="1", len=1.1 ]; + 6 -- 7 [ label="3" ]; +} \ No newline at end of file diff --git a/doc/stoer_wagner_imgs/stoer_wagner-example.gif b/doc/stoer_wagner_imgs/stoer_wagner-example.gif new file mode 100644 index 00000000..7f7e14bc Binary files /dev/null and b/doc/stoer_wagner_imgs/stoer_wagner-example.gif differ diff --git a/doc/stoer_wagner_imgs/stoer_wagner.cpp.dot b/doc/stoer_wagner_imgs/stoer_wagner.cpp.dot new file mode 100644 index 00000000..bec8ad22 --- /dev/null +++ b/doc/stoer_wagner_imgs/stoer_wagner.cpp.dot @@ -0,0 +1,25 @@ +graph { + 0 [ style="filled", fillcolor="#9999ff" ]; + 1 [ style="filled", fillcolor="#333399", fontcolor=white ]; + 2 [ style="filled", fillcolor="#9999ff" ]; + 3 [ style="filled", fillcolor="#9999ff" ]; + 4 [ style="filled", fillcolor="#9999ff" ]; + 5 [ style="filled", fillcolor="#333399", fontcolor=white ]; + 6 [ style="filled", fillcolor="#9999ff" ]; + 7 [ style="filled", fillcolor="#9999ff" ]; + 3 -- 4 [ taillabel="4" ]; + 3 -- 6 [ taillabel="3" ]; + 3 -- 5 [ taillabel="1" ]; + 0 -- 4 [ taillabel="3" ]; + 0 -- 1 [ taillabel="1" ]; + 0 -- 6 [ taillabel="2" ]; + 0 -- 7 [ taillabel="6" ]; + 0 -- 5 [ taillabel="1" ]; + 0 -- 2 [ taillabel="8" ]; + 4 -- 1 [ label="1" ]; + 1 -- 6 [ label="1" ]; + 1 -- 5 [ label="80", len=4 ]; + 6 -- 7 [ label="2" ]; + 7 -- 5 [ label="1" ]; + 5 -- 2 [ label="1" ]; +} \ No newline at end of file diff --git a/doc/stoer_wagner_imgs/stoer_wagner.cpp.gif b/doc/stoer_wagner_imgs/stoer_wagner.cpp.gif new file mode 100644 index 00000000..1c07c841 Binary files /dev/null and b/doc/stoer_wagner_imgs/stoer_wagner.cpp.gif differ diff --git a/doc/stoer_wagner_min_cut.html b/doc/stoer_wagner_min_cut.html new file mode 100644 index 00000000..2eeabb0f --- /dev/null +++ b/doc/stoer_wagner_min_cut.html @@ -0,0 +1,166 @@ + + + + +Boost Graph Library: Stoer–Wagner Min-Cut + + +C++ Boost + +

stoer_wagner_min_cut

+ + + +
A min-cut of a weighted graph
having min-cut weight 4
+
+template <class UndirectedGraph, class WeightMap, class P, class T, class R>
+weight_type
+stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights,
+    const bgl_named_params<P, T, R>& params = all defaults);
+
+ +

The stoer_wagner_min_cut function determines a min-cut and the min-cut weight of a connected, undirected graph. + +

A cut of a graph G is a partition of the vertices into two, non-empty sets. The weight of such a partition is the number of edges between the two sets if G is unweighted, or the sum of the weights of all edges between the two sets if G is weighted. A min-cut is a cut having the least weight. + +

Sometimes a graph has multiple min-cuts, but all have the same weight. The stoer_wagner_min_cut function determines exactly one of the min-cuts as well as its weight. + +

Where Defined

+

boost/graph/stoer_wagner_min_cut.hpp + +

Parameters

+ +

IN: const UndirectedGraph& g +

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

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. +
+ +

Named Parameters

+ +

OUT: parity_map(ParityMap parities) +

+ The algorithm computes a min-cut, which divides the set of vertices into two, + non-empty sets. The stoer_wagner_min_cut function records which of + the two sets that each vertex belongs to by setting the parity to true + (representing one set) or false (for the other). ParityMap + must be a model of a Writable + Property Map and its value type should be a bool type. The + key type must be the graph's vertex descriptor type.
+ Default: boost::dummy_property_map +
+ +

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) +
+ +

UTIL: 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

+

The weight of the min-cut + +

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(V·E + V2 log V). + +

Example

+ +

The file examples/stoer_wagner.cpp contains an example of calculating a min-cut of a weighted, undirected graph and its min-cut weight. + +

References

+ + +
+
+ + + + + +
Copyright © 2010Daniel Trebbien (dtrebbien@gmail.com) +
+ + + diff --git a/doc/table_of_contents.html b/doc/table_of_contents.html index 86b5311e..8c0783f9 100644 --- a/doc/table_of_contents.html +++ b/doc/table_of_contents.html @@ -208,6 +208,7 @@
  • boykov_kolmogorov_max_flow
  • edmonds_maximum_cardinality_matching +
  • stoer_wagner_min_cut
  • Sparse Matrix Ordering Algorithms @@ -286,7 +287,7 @@
  • Graph Input/Output
    1. AT&T Graphviz: read_graphviz, write_graphviz
    2. -
    3. DIMACS Max-flow: read_dimacs_max_flow, write_dimacs_max_flow
    4. +
    5. DIMACS Max-flow: read_dimacs_max_flow and read_dimacs_min_cut, write_dimacs_max_flow
    6. GraphML: read_graphml and write_graphml
  • diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 48dcc1ae..c85df0ca 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -27,3 +27,6 @@ exe components_on_edgelist : components_on_edgelist.cpp ; exe boykov_kolmogorov-eg : boykov_kolmogorov-eg.cpp ; exe ospf-example : ospf-example.cpp ../build//boost_graph ; # exe cc-internet : cc-internet.cpp ../build//boost_graph ; +exe implicit_graph : implicit_graph.cpp ; +exe astar_maze : astar_maze.cpp ; +exe stoer_wagner : stoer_wagner.cpp ; diff --git a/example/astar_maze.cpp b/example/astar_maze.cpp new file mode 100644 index 00000000..20cff4fd --- /dev/null +++ b/example/astar_maze.cpp @@ -0,0 +1,311 @@ + +// Copyright W.P. McNeill 2010. +// 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) + + +// This program uses the A-star search algorithm in the Boost Graph Library to +// solve a maze. It is an example of how to apply Boost Graph Library +// algorithms to implicit graphs. +// +// This program generates a random maze and then tries to find the shortest +// path from the lower left-hand corner to the upper right-hand corner. Mazes +// are represented by two-dimensional grids where a cell in the grid may +// contain a barrier. You may move up, down, right, or left to any adjacent +// cell that does not contain a barrier. +// +// Once a maze solution has been attempted, the maze is printed. If a +// solution was found it will be shown in the maze printout and its length +// will be returned. Note that not all mazes have solutions. +// +// The default maze size is 20x10, though different dimensions may be +// specified on the command line. + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +boost::mt19937 random_generator; + +// Distance traveled in the maze +typedef double distance; + +#define GRID_RANK 2 +typedef boost::grid_graph grid; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::vertices_size_type vertices_size_type; + +// A hash function for vertices. +struct vertex_hash:std::unary_function { + std::size_t operator()(vertex_descriptor const& u) const { + std::size_t seed = 0; + boost::hash_combine(seed, u[0]); + boost::hash_combine(seed, u[1]); + return seed; + } +}; + +typedef boost::unordered_set vertex_set; +typedef boost::vertex_subset_complement_filter::type + filtered_grid; + +// A searchable maze +// +// The maze is grid of locations which can either be empty or contain a +// barrier. You can move to an adjacent location in the grid by going up, +// down, left and right. Moving onto a barrier is not allowed. The maze can +// be solved by finding a path from the lower-left-hand corner to the +// upper-right-hand corner. If no open path exists between these two +// locations, the maze is unsolvable. +// +// The maze is implemented as a filtered grid graph where locations are +// vertices. Barrier vertices are filtered out of the graph. +// +// A-star search is used to find a path through the maze. Each edge has a +// weight of one, so the total path length is equal to the number of edges +// traversed. +class maze { +public: + friend std::ostream& operator<<(std::ostream&, const maze&); + friend maze random_maze(std::size_t, std::size_t); + + maze():m_grid(create_grid(0, 0)),m_barrier_grid(create_barrier_grid()) {}; + maze(std::size_t x, std::size_t y):m_grid(create_grid(x, y)), + m_barrier_grid(create_barrier_grid()) {}; + + // The length of the maze along the specified dimension. + vertices_size_type length(std::size_t d) const {return m_grid.length(d);} + + bool has_barrier(vertex_descriptor u) const { + return m_barriers.find(u) != m_barriers.end(); + } + + // Try to find a path from the lower-left-hand corner source (0,0) to the + // upper-right-hand corner goal (x-1, y-1). + vertex_descriptor source() const {return vertex(0, m_grid);} + vertex_descriptor goal() const { + return vertex(num_vertices(m_grid)-1, m_grid); + } + + bool solve(); + bool solved() const {return !m_solution.empty();} + bool solution_contains(vertex_descriptor u) const { + return m_solution.find(u) != m_solution.end(); + } + +private: + // Create the underlying rank-2 grid with the specified dimensions. + grid create_grid(std::size_t x, std::size_t y) { + boost::array lengths = { {x, y} }; + return grid(lengths); + } + + // Filter the barrier vertices out of the underlying grid. + filtered_grid create_barrier_grid() { + return boost::make_vertex_subset_complement_filter(m_grid, m_barriers); + } + + // The grid underlying the maze + grid m_grid; + // The underlying maze grid with barrier vertices filtered out + filtered_grid m_barrier_grid; + // The barriers in the maze + vertex_set m_barriers; + // The vertices on a solution path through the maze + vertex_set m_solution; + // The length of the solution path + distance m_solution_length; +}; + + +// Euclidean heuristic for a grid +// +// This calculates the Euclidean distance between a vertex and a goal +// vertex. +class euclidean_heuristic: + public boost::astar_heuristic +{ +public: + euclidean_heuristic(vertex_descriptor goal):m_goal(goal) {}; + + double operator()(vertex_descriptor v) { + return sqrt(pow(m_goal[0] - v[0], 2) + pow(m_goal[1] - v[1], 2)); + } + +private: + vertex_descriptor m_goal; +}; + +// Exception thrown when the goal vertex is found +struct found_goal {}; + +// Visitor that terminates when we find the goal vertex +struct astar_goal_visitor:public boost::default_astar_visitor { + astar_goal_visitor(vertex_descriptor goal):m_goal(goal) {}; + + void examine_vertex(vertex_descriptor u, const filtered_grid&) { + if (u == m_goal) + throw found_goal(); + } + +private: + vertex_descriptor m_goal; +}; + +// Solve the maze using A-star search. Return true if a solution was found. +bool maze::solve() { + boost::static_property_map weight(1); + // The predecessor map is a vertex-to-vertex mapping. + typedef boost::unordered_map pred_map; + pred_map predecessor; + boost::associative_property_map pred_pmap(predecessor); + // The distance map is a vertex-to-distance mapping. + typedef boost::unordered_map dist_map; + dist_map distance; + boost::associative_property_map dist_pmap(distance); + + vertex_descriptor s = source(); + vertex_descriptor g = goal(); + euclidean_heuristic heuristic(g); + astar_goal_visitor visitor(g); + + try { + astar_search(m_barrier_grid, s, heuristic, + boost::weight_map(weight). + predecessor_map(pred_pmap). + distance_map(dist_pmap). + visitor(visitor) ); + } catch(found_goal fg) { + // Walk backwards from the goal through the predecessor chain adding + // vertices to the solution path. + for (vertex_descriptor u = g; u != s; u = predecessor[u]) + m_solution.insert(u); + m_solution.insert(s); + m_solution_length = distance[g]; + return true; + } + + return false; +} + + +#define BARRIER "#" +// Print the maze as an ASCII map. +std::ostream& operator<<(std::ostream& output, const maze& m) { + // Header + for (vertices_size_type i = 0; i < m.length(0)+2; i++) + output << BARRIER; + output << std::endl; + // Body + for (int y = m.length(1)-1; y >= 0; y--) { + // Enumerate rows in reverse order and columns in regular order so that + // (0,0) appears in the lower left-hand corner. This requires that y be + // int and not the unsigned vertices_size_type because the loop exit + // condition is y==-1. + for (vertices_size_type x = 0; x < m.length(0); x++) { + // Put a barrier on the left-hand side. + if (x == 0) + output << BARRIER; + // Put the character representing this point in the maze grid. + vertex_descriptor u = {{x, y}}; + if (m.solution_contains(u)) + output << "."; + else if (m.has_barrier(u)) + output << BARRIER; + else + output << " "; + // Put a barrier on the right-hand side. + if (x == m.length(0)-1) + output << BARRIER; + } + // Put a newline after every row except the last one. + output << std::endl; + } + // Footer + for (vertices_size_type i = 0; i < m.length(0)+2; i++) + output << BARRIER; + if (m.solved()) + output << std::endl << "Solution length " << m.m_solution_length; + return output; +} + +// Return a random integer in the interval [a, b]. +std::size_t random_int(std::size_t a, std::size_t b) { + if (b < a) + b = a; + boost::uniform_int<> dist(a, b); + boost::variate_generator > + generate(random_generator, dist); + return generate(); +} + +// Generate a maze with a random assignment of barriers. +maze random_maze(std::size_t x, std::size_t y) { + maze m(x, y); + vertices_size_type n = num_vertices(m.m_grid); + vertex_descriptor s = m.source(); + vertex_descriptor g = m.goal(); + // One quarter of the cells in the maze should be barriers. + int barriers = n/4; + while (barriers > 0) { + // Choose horizontal or vertical direction. + std::size_t direction = random_int(0, 1); + // Walls range up to one quarter the dimension length in this direction. + vertices_size_type wall = random_int(1, m.length(direction)/4); + // Create the wall while decrementing the total barrier count. + vertex_descriptor u = vertex(random_int(0, n-1), m.m_grid); + while (wall) { + // Start and goal spaces should never be barriers. + if (u != s && u != g) { + wall--; + if (!m.has_barrier(u)) { + m.m_barriers.insert(u); + barriers--; + } + } + vertex_descriptor v = m.m_grid.next(u, direction); + // Stop creating this wall if we reached the maze's edge. + if (u == v) + break; + u = v; + } + } + return m; +} + + +int main (int argc, char const *argv[]) { + // The default maze size is 20x10. A different size may be specified on + // the command line. + std::size_t x = 20; + std::size_t y = 10; + + if (argc == 3) { + x = boost::lexical_cast(argv[1]); + y = boost::lexical_cast(argv[2]); + } + + random_generator.seed(std::time(0)); + maze m = random_maze(x, y); + + if (m.solve()) + std::cout << "Solved the maze." << std::endl; + else + std::cout << "The maze is not solvable." << std::endl; + std::cout << m << std::endl; + return 0; +} diff --git a/example/implicit_graph.cpp b/example/implicit_graph.cpp new file mode 100644 index 00000000..adac9a38 --- /dev/null +++ b/example/implicit_graph.cpp @@ -0,0 +1,544 @@ + +// Copyright W.P. McNeill 2010. +// 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) + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* +This file defines a simple example of a read-only implicit weighted graph +built using the Boost Graph Library. It can be used as a starting point for +developers creating their own implicit graphs. + +The graph models the following concepts: + Graph + IncidenceGraph + BidirectionalGraph + AdjacencyGraph + VertexListGraph + EdgeListGraph + AdjacencyMatrix + ReadablePropertyGraph + +The graph defined here is a ring graph, a graph whose vertices are arranged in +a ring so that each vertex has exactly two neighbors. For example, here is a +ring graph with five nodes. + + 0 + / \ + 4 1 + | | + 3 ---- 2 + +The edges of this graph are undirected and each has a weight that is a +function of its position in the graph. + +The vertices indexed are by integer and arranged sequentially so that each +vertex i is adjacent to i-1 for i>0 and i+1 for i + This tells Boost to associate the edges of the ring graph with the edge + weight map. + +Along with these classes, the graph concepts are modeled by various valid +expression functions defined below. This example also defines a +get(boost::vertex_index_t, const ring_graph&) function which isn’t part of a +graph concept, but is used for Dijkstra search. + +Apart from graph, client code should not instantiate the model classes +directly. Instead it should access them and their properties via +graph_traits<...> and property_traits<...> lookups. For convenience, +this example defines short names for all these properties that client code can +use. +*/ + +// Forward declarations +class ring_graph; +class ring_incident_edge_iterator; +class ring_adjacency_iterator; +class ring_edge_iterator; +struct edge_weight_map; + +// ReadablePropertyGraph associated types +namespace boost { + template<> + struct property_map< ring_graph, edge_weight_t > { + typedef edge_weight_map type; + typedef edge_weight_map const_type; + }; +} + +// Tag values that specify the traversal type in graph::traversal_category. +struct ring_traversal_catetory: + virtual public boost::bidirectional_graph_tag, + virtual public boost::adjacency_graph_tag, + virtual public boost::vertex_list_graph_tag, + virtual public boost::edge_list_graph_tag + {}; + + +/* +Undirected graph of vertices arranged in a ring shape. + +Vertices are indexed by integer, and edges connect vertices with consecutive +indices. Vertex 0 is also adjacent to the vertex n-1. +*/ +class ring_graph { +public: + // Graph associated types + typedef std::size_t vertex_descriptor; + typedef boost::undirected_tag directed_category; + typedef boost::disallow_parallel_edge_tag edge_parallel_category; + typedef ring_traversal_catetory traversal_category; + + // IncidenceGraph associated types + typedef std::pair edge_descriptor; + typedef ring_incident_edge_iterator out_edge_iterator; + typedef std::size_t degree_size_type; + + // BidirectionalGraph associated types + // Note that undirected graphs make no distinction between in- and out- + // edges. + typedef ring_incident_edge_iterator in_edge_iterator; + + // AdjacencyGraph associated types + typedef ring_adjacency_iterator adjacency_iterator; + + // VertexListGraph associated types + typedef boost::counting_iterator vertex_iterator; + typedef std::size_t vertices_size_type; + + // EdgeListGraph associated types + typedef ring_edge_iterator edge_iterator; + typedef std::size_t edges_size_type; + + // This type is not part of a graph concept, but is used to return the + // default vertex index map used by the Dijkstra search algorithm. + typedef vertex_descriptor vertex_property_type; + + ring_graph(std::size_t n):m_n(n) {}; + std::size_t n() const {return m_n;} +private: + // The number of vertices in the graph. + std::size_t m_n; +}; + +// Use these graph_traits parameterizations to refer to the associated +// graph types. +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::edge_descriptor edge_descriptor; +typedef boost::graph_traits::out_edge_iterator out_edge_iterator; +typedef boost::graph_traits::in_edge_iterator in_edge_iterator; +typedef boost::graph_traits::adjacency_iterator adjacency_iterator; +typedef boost::graph_traits::degree_size_type degree_size_type; +typedef boost::graph_traits::vertex_iterator vertex_iterator; +typedef boost::graph_traits::vertices_size_type vertices_size_type; +typedef boost::graph_traits::edge_iterator edge_iterator; +typedef boost::graph_traits::edges_size_type edges_size_type; + + +// Tag values passed to an iterator constructor to specify whether it should +// be created at the start or the end of its range. +struct iterator_position {}; +struct iterator_start:virtual public iterator_position {}; +struct iterator_end:virtual public iterator_position {}; + +/* +Iterator over edges incident on a vertex in a ring graph. + +For vertex i, this returns edge (i, i+1) and then edge (i, i-1), wrapping +around the end of the ring as needed. + +Because this is an undirected graph, the edge is equivalent to . +For clarity's sake, however, this iterator always returns an edge descriptor +with the smaller vertex index first. + +It is implemented with the boost::iterator_adaptor class, adapting an +offset into the dereference::ring_offset array. +*/ +class ring_incident_edge_iterator:public boost::iterator_adaptor < + ring_incident_edge_iterator, + boost::counting_iterator, + edge_descriptor, + boost::use_default, + edge_descriptor > { +public: + ring_incident_edge_iterator(): + ring_incident_edge_iterator::iterator_adaptor_(0),m_n(0),m_u(0) {}; + explicit ring_incident_edge_iterator(const ring_graph& g, + vertex_descriptor u, + iterator_start): + ring_incident_edge_iterator::iterator_adaptor_(0), + m_n(g.n()),m_u(u) {}; + explicit ring_incident_edge_iterator(const ring_graph& g, + vertex_descriptor u, + iterator_end): + // A graph with one vertex only has a single self-loop. A graph with + // two vertices has a single edge between them. All other graphs have + // two edges per vertex. + ring_incident_edge_iterator::iterator_adaptor_(g.n() > 2 ? 2:1), + m_n(g.n()),m_u(u) {}; + +private: + friend class boost::iterator_core_access; + + edge_descriptor dereference() const { + static const int ring_offset[] = {1, -1}; + vertex_descriptor v; + + std::size_t p = *this->base_reference(); + if (m_u == 0 && p == 1) + v = m_n-1; // Vertex n-1 precedes vertex 0. + else + v = (m_u+ring_offset[p]) % m_n; + return edge_descriptor(m_u, v); + } + + std::size_t m_n; // Size of the graph + vertex_descriptor m_u; // Vertex whose out edges are iterated +}; + + +// IncidenceGraph valid expressions +vertex_descriptor source(edge_descriptor e, const ring_graph&) { + // The first vertex in the edge pair is the source. + return e.first; +} + + +vertex_descriptor target(edge_descriptor e, const ring_graph&) { + // The second vertex in the edge pair is the target. + return e.second; +} + +std::pair +out_edges(vertex_descriptor u, const ring_graph& g) { + return std::pair( + out_edge_iterator(g, u, iterator_start()), + out_edge_iterator(g, u, iterator_end()) ); +} + + +degree_size_type out_degree(vertex_descriptor, const ring_graph&) { + // All vertices in a ring graph have two neighbors. + return 2; +} + + +// BidirectionalGraph valid expressions +std::pair +in_edges(vertex_descriptor u, const ring_graph& g) { + // The in-edges and out-edges are the same in an undirected graph. + return out_edges(u, g); +} + +degree_size_type in_degree(vertex_descriptor u, const ring_graph& g) { + // The in-degree and out-degree are both equal to the number of incident + // edges in an undirected graph. + return out_degree(u, g); +} + +degree_size_type degree(vertex_descriptor u, const ring_graph& g) { + // The in-degree and out-degree are both equal to the number of incident + // edges in an undirected graph. + return out_degree(u, g); +} + + +/* +Iterator over vertices adjacent to a given vertex. + +This iterates over the target vertices of all the incident edges. +*/ +class ring_adjacency_iterator:public boost::adjacency_iterator_generator< + ring_graph, + vertex_descriptor, + out_edge_iterator>::type { + // The parent class is an iterator_adpator that turns an iterator over + // out edges into an iterator over adjacent vertices. + typedef boost::adjacency_iterator_generator< + ring_graph, + vertex_descriptor, + out_edge_iterator>::type parent_class; +public: + ring_adjacency_iterator() {}; + ring_adjacency_iterator(vertex_descriptor u, + const ring_graph& g, + iterator_start): + parent_class(out_edge_iterator(g, u, iterator_start()), &g) {}; + ring_adjacency_iterator(vertex_descriptor u, + const ring_graph& g, + iterator_end): + parent_class(out_edge_iterator(g, u, iterator_end()), &g) {}; +}; + + +// AdjacencyGraph valid expressions +std::pair +adjacent_vertices(vertex_descriptor u, const ring_graph& g) { + return std::pair( + adjacency_iterator(u, g, iterator_start()), + adjacency_iterator(u, g, iterator_end())); +} + + +// VertexListGraph valid expressions +vertices_size_type num_vertices(const ring_graph& g) { + return g.n(); +}; + +std::pair vertices(const ring_graph& g) { + return std::pair( + vertex_iterator(0), // The first iterator position + vertex_iterator(num_vertices(g)) ); // The last iterator position +} + + +/* +Iterator over edges in a ring graph. + +This object iterates over all the vertices in the graph, then for each +vertex returns its first outgoing edge. + +It is implemented with the boost::iterator_adaptor class, because it is +essentially a vertex_iterator with a customized deference operation. +*/ +class ring_edge_iterator:public boost::iterator_adaptor< + ring_edge_iterator, + vertex_iterator, + edge_descriptor, + boost::use_default, + edge_descriptor > { +public: + ring_edge_iterator(): + ring_edge_iterator::iterator_adaptor_(0),m_g(NULL) {}; + explicit ring_edge_iterator(const ring_graph& g, iterator_start): + ring_edge_iterator::iterator_adaptor_(vertices(g).first),m_g(&g) {}; + explicit ring_edge_iterator(const ring_graph& g, iterator_end): + ring_edge_iterator::iterator_adaptor_( + // Size 2 graphs have a single edge connecting the two vertices. + g.n() == 2 ? ++(vertices(g).first) : vertices(g).second ), + m_g(&g) {}; + +private: + friend class boost::iterator_core_access; + + edge_descriptor dereference() const { + // The first element in the incident edge list of the current vertex. + return *(out_edges(*this->base_reference(), *m_g).first); + } + + // The graph being iterated over + const ring_graph *m_g; +}; + +// EdgeListGraph valid expressions +std::pair edges(const ring_graph& g) { + return std::pair( + ring_edge_iterator(g, iterator_start()), + ring_edge_iterator(g, iterator_end()) ); +} + +edges_size_type num_edges(const ring_graph& g) { + // There are as many edges as there are vertices, except for size 2 + // graphs, which have a single edge connecting the two vertices. + return g.n() == 2 ? 1:g.n(); +} + + +// AdjacencyMatrix valid expressions +std::pair +edge(vertex_descriptor u, vertex_descriptor v, const ring_graph& g) { + if (abs(u-v) == 1 && + u >= 0 && u < num_vertices(g) && v >= 0 && v < num_vertices(g)) + return std::pair(edge_descriptor(u, v), true); + else + return std::pair(edge_descriptor(), false); +} + + +/* +Map from edges to weight values +*/ +struct edge_weight_map { + typedef double value_type; + typedef value_type reference; + typedef edge_descriptor key_type; + typedef boost::readable_property_map_tag category; + + // Edges have a weight equal to the average of their endpoint indexes. + reference operator[](key_type e) const { + return (e.first + e.second)/2.0; + } +}; + +// Use these propety_map and property_traits parameterizations to refer to +// the associated property map types. +typedef boost::property_map::const_type + const_edge_weight_map; +typedef boost::property_traits::reference + edge_weight_map_value_type; +typedef boost::property_traits::key_type + edge_weight_map_key; + +// PropertyMap valid expressions +edge_weight_map_value_type +get(const_edge_weight_map pmap, edge_weight_map_key e) { + return pmap[e]; +} + + +// ReadablePropertyGraph valid expressions +const_edge_weight_map get(boost::edge_weight_t, const ring_graph&) { + return const_edge_weight_map(); +} + +edge_weight_map_value_type get(boost::edge_weight_t tag, + const ring_graph& g, + edge_weight_map_key e) { + return get(tag, g)[e]; +} + + +// This expression is not part of a graph concept, but is used to return the +// default vertex index map used by the Dijkstra search algorithm. +boost::identity_property_map get(boost::vertex_index_t, const ring_graph&) { + // The vertex descriptors are already unsigned integer indices, so just + // return an identity map. + return boost::identity_property_map(); +} + + +int main (int argc, char const *argv[]) { + using namespace boost; + // Check the concepts that graph models. This is included to demonstrate + // how concept checking works, but is not required for a working program + // since Boost algorithms do their own concept checking. + function_requires< BidirectionalGraphConcept >(); + function_requires< AdjacencyGraphConcept >(); + function_requires< VertexListGraphConcept >(); + function_requires< EdgeListGraphConcept >(); + function_requires< AdjacencyMatrixConcept >(); + function_requires< + ReadablePropertyMapConcept >(); + function_requires< + ReadablePropertyGraphConcept >(); + + // Specify the size of the graph on the command line, or use a default size + // of 5. + std::size_t n = argc == 2 ? boost::lexical_cast(argv[1]) : 5; + + // Create a small ring graph. + ring_graph g(n); + const_edge_weight_map m = get(edge_weight, g); + + // Print the outgoing edges of all the vertices. For n=5 this will print: + // + // Vertices, outgoing edges, and adjacent vertices + // Vertex 0: <0, 1> <0, 4> Adjacent vertices 1 4 + // Vertex 1: <1, 2> <1, 0> Adjacent vertices 2 0 + // Vertex 2: <2, 3> <2, 1> Adjacent vertices 3 1 + // Vertex 3: <3, 4> <3, 2> Adjacent vertices 4 2 + // Vertex 4: <4, 0> <4, 3> Adjacent vertices 0 3 + // 5 vertices + std::cout << "Vertices, outgoing edges, and adjacent vertices" << std::endl; + vertex_iterator vi, vi_end; + for (tie(vi, vi_end) = vertices(g); vi != vi_end; vi++) { + vertex_descriptor u = *vi; + std::cout << "Vertex " << u << ": "; + // Adjacenct edges + out_edge_iterator ei, ei_end; + for (tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ei++) { + edge_descriptor e = *ei; + std::cout << "<" << e.first << ", " << e.second << ">" << " "; + } + std::cout << " Adjacent vertices "; + // Adjacent vertices + // Here we want our adjacency_iterator and not boost::adjacency_iterator. + ::adjacency_iterator ai, ai_end; + for (tie(ai, ai_end) = adjacent_vertices(u, g); ai != ai_end; ai++) { + std::cout << *ai << " "; + } + std::cout << std::endl; + } + std::cout << num_vertices(g) << " vertices" << std::endl << std::endl; + + // Print all the edges in the graph along with their weights. For n=5 this + // will print: + // + // Edges and weights + // <0, 1> weight 0.5 + // <1, 2> weight 1.5 + // <2, 3> weight 2.5 + // <3, 4> weight 3.5 + // <4, 0> weight 2 + // 5 edges + std::cout << "Edges and weights" << std::endl; + edge_iterator ei, ei_end; + for (tie(ei, ei_end) = edges(g); ei != ei_end; ei++) { + edge_descriptor e = *ei; + std::cout << "<" << e.first << ", " << e.second << ">" + << " weight " << get(edge_weight, g, e) << std::endl; + } + std::cout << num_edges(g) << " edges" << std::endl; + + if (n>0) { + std::cout << std::endl; + // Do a Dijkstra search from vertex 0. For n=5 this will print: + // + // Dijkstra search from vertex 0 + // Vertex 0: parent 0, distance 0 + // Vertex 1: parent 0, distance 0.5 + // Vertex 2: parent 1, distance 2 + // Vertex 3: parent 2, distance 4.5 + // Vertex 4: parent 0, distance 2 + vertex_descriptor source = 0; + std::vector pred(num_vertices(g)); + std::vector dist(num_vertices(g)); + + dijkstra_shortest_paths(g, source, + predecessor_map(&pred[0]). + distance_map(&dist[0]) ); + + std::cout << "Dijkstra search from vertex " << source << std::endl; + for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { + vertex_descriptor u = *vi; + std::cout << "Vertex " << u << ": " + << "parent "<< pred[*vi] << ", " + << "distance " << dist[u] + << std::endl; + } + } + + return 0; +} diff --git a/example/stoer_wagner.cpp b/example/stoer_wagner.cpp new file mode 100644 index 00000000..792ee208 --- /dev/null +++ b/example/stoer_wagner.cpp @@ -0,0 +1,71 @@ +// Copyright Daniel Trebbien 2010. +// 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 + +struct edge_t +{ + unsigned long first; + unsigned long second; +}; + +// A graphic of the min-cut is available at +int main() +{ + using namespace std; + + typedef boost::adjacency_list > undirected_graph; + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef boost::property_map::type weight_map_type; + typedef boost::property_traits::value_type weight_type; + + // define the 16 edges of the graph. {3, 4} means an undirected edge between vertices 3 and 4. + edge_t edges[] = {{3, 4}, {3, 6}, {3, 5}, {0, 4}, {0, 1}, {0, 6}, {0, 7}, + {0, 5}, {0, 2}, {4, 1}, {1, 6}, {1, 5}, {6, 7}, {7, 5}, {5, 2}, {3, 4}}; + + // for each of the 16 edges, define the associated edge weight. ws[i] is the weight for the edge + // that is described by edges[i]. + weight_type ws[] = {0, 3, 1, 3, 1, 2, 6, 1, 8, 1, 1, 80, 2, 1, 1, 4}; + + // construct the graph object. 8 is the number of vertices, which are numbered from 0 + // through 7, and 16 is the number of edges. + undirected_graph g(edges, edges + 16, ws, 8, 16); + + // define a property map, `parities`, that will store a boolean value for each vertex. + // Vertices that have the same parity after `stoer_wagner_min_cut` runs are on the same side of the min-cut. + BOOST_AUTO(parities, boost::make_one_bit_color_map(num_vertices(g), get(boost::vertex_index, g))); + + // run the Stoer-Wagner algorithm to obtain the min-cut weight. `parities` is also filled in. + int w = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g), boost::parity_map(parities)); + + cout << "The min-cut weight of G is " << w << ".\n" << endl; + assert(w == 7); + + cout << "One set of vertices consists of:" << endl; + size_t i; + for (i = 0; i < num_vertices(g); ++i) { + if (get(parities, i)) + cout << i << endl; + } + cout << endl; + + cout << "The other set of vertices consists of:" << endl; + for (i = 0; i < num_vertices(g); ++i) { + if (!get(parities, i)) + cout << i << endl; + } + cout << endl; + + return EXIT_SUCCESS; +} diff --git a/include/boost/graph/buffer_concepts.hpp b/include/boost/graph/buffer_concepts.hpp new file mode 100644 index 00000000..2bad8af3 --- /dev/null +++ b/include/boost/graph/buffer_concepts.hpp @@ -0,0 +1,91 @@ +// Copyright Daniel Trebbien 2010. +// 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) + +#ifndef BOOST_GRAPH_BUFFER_CONCEPTS_HPP +#define BOOST_GRAPH_BUFFER_CONCEPTS_HPP 1 +#include +#include +#include +#include +#include +#include +#include + +namespace boost { + + BOOST_concept(Buffer, (B)) + { + typedef typename B::value_type value_type; + typedef typename B::size_type size_type; + + BOOST_CONCEPT_USAGE(Buffer) { + typedef typename boost::add_reference::type reference; + + BOOST_CONCEPT_ASSERT((Assignable)); + + buf.push(g_ct); + buf.pop(); + reference t = buf.top(); + boost::ignore_unused_variable_warning(t); + } + + void const_constraints(const B& cbuf) { + typedef typename boost::add_const::type>::type& const_reference; + + const_reference ct = cbuf.top(); + s = cbuf.size(); + if (cbuf.empty()) + dummy = __LINE__; + } + + int dummy; + + static const value_type g_ct; + size_type s; + B buf; + }; + + BOOST_concept(UpdatableQueue, (Q)) + : Buffer + { + BOOST_CONCEPT_USAGE(UpdatableQueue) { + q.update(g_ct); + } + + void const_constraints(const Q& cq) { + if (cq.contains(g_ct)) + dummy = __LINE__; + } + + int dummy; + + static const typename Buffer::value_type g_ct; + Q q; + }; + + BOOST_concept(KeyedUpdatableQueue, (Q)) + : UpdatableQueue + { + typedef typename Q::key_type key_type; + typedef typename Q::key_map key_map; + + BOOST_CONCEPT_USAGE(KeyedUpdatableQueue) { + BOOST_CONCEPT_ASSERT((boost::ReadWritePropertyMapConcept::value_type>)); + } + + void const_constraints(const Q& cq) { + km = cq.keys(); + k = get(km, g_ct); + } + + static const typename Buffer::value_type g_ct; + key_type k; + key_map km; + Q q; + }; + +} // end `namespace boost` + +#endif // !BOOST_GRAPH_BUFFER_CONCEPTS_HPP diff --git a/include/boost/graph/detail/d_ary_heap.hpp b/include/boost/graph/detail/d_ary_heap.hpp index 2ec716d3..c3b3ef7f 100644 --- a/include/boost/graph/detail/d_ary_heap.hpp +++ b/include/boost/graph/detail/d_ary_heap.hpp @@ -92,6 +92,8 @@ namespace boost { public: typedef typename Container::size_type size_type; typedef Value value_type; + typedef typename boost::property_traits::value_type key_type; + typedef DistanceMap key_map; d_ary_heap_indirect(DistanceMap distance, IndexInHeapPropertyMap index_in_heap, @@ -164,6 +166,10 @@ namespace boost { verify_heap(); } + DistanceMap keys() const { + return distance; + } + private: Compare compare; Container data; diff --git a/include/boost/graph/graph_concepts.hpp b/include/boost/graph/graph_concepts.hpp index 4cf5e63d..7c2b2795 100644 --- a/include/boost/graph/graph_concepts.hpp +++ b/include/boost/graph/graph_concepts.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -493,28 +494,6 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); Graph g; }; - // This needs to move out of the graph library - BOOST_concept(Buffer,(B)) - { - BOOST_CONCEPT_USAGE(Buffer) { - b.push(t); - b.pop(); - typename B::value_type& v = b.top(); - const_constraints(b); - ignore_unused_variable_warning(v); - } - void const_constraints(const B& cb) { - const typename B::value_type& v = cb.top(); - n = cb.size(); - bool e = cb.empty(); - ignore_unused_variable_warning(v); - ignore_unused_variable_warning(e); - } - typename B::size_type n; - typename B::value_type t; - B b; - }; - BOOST_concept(ColorValue,(C)) : EqualityComparable , DefaultConstructible @@ -614,7 +593,6 @@ using boost::concepts::VertexIndexGraphConcept; using boost::concepts::EdgeIndexGraphConcept; // Utility concepts -using boost::concepts::BufferConcept; using boost::concepts::ColorValueConcept; using boost::concepts::BasicMatrixConcept; using boost::concepts::NumericValueConcept; diff --git a/include/boost/graph/named_function_params.hpp b/include/boost/graph/named_function_params.hpp index d3be9f22..47535fbd 100644 --- a/include/boost/graph/named_function_params.hpp +++ b/include/boost/graph/named_function_params.hpp @@ -10,19 +10,23 @@ #ifndef BOOST_GRAPH_NAMED_FUNCTION_PARAMS_HPP #define BOOST_GRAPH_NAMED_FUNCTION_PARAMS_HPP -#include +#include +#include #include #include #include #include #include #include -#include +#include +#include #include #include namespace boost { + struct parity_map_t { }; + struct vertex_assignment_map_t { }; struct distance_compare_t { }; struct distance_combine_t { }; struct distance_inf_t { }; @@ -51,6 +55,8 @@ namespace boost { struct learning_constant_range_t { }; struct vertices_equivalent_t { }; struct edges_equivalent_t { }; + struct index_in_heap_map_t { }; + struct max_priority_queue_t { }; #define BOOST_BGL_DECLARE_NAMED_PARAMS \ BOOST_BGL_ONE_PARAM_CREF(weight_map, edge_weight) \ @@ -62,6 +68,7 @@ namespace boost { BOOST_BGL_ONE_PARAM_CREF(root_vertex, root_vertex) \ BOOST_BGL_ONE_PARAM_CREF(edge_centrality_map, edge_centrality) \ BOOST_BGL_ONE_PARAM_CREF(centrality_map, vertex_centrality) \ + BOOST_BGL_ONE_PARAM_CREF(parity_map, parity_map) \ BOOST_BGL_ONE_PARAM_CREF(color_map, vertex_color) \ BOOST_BGL_ONE_PARAM_CREF(edge_color_map, edge_color) \ BOOST_BGL_ONE_PARAM_CREF(capacity_map, edge_capacity) \ @@ -72,6 +79,7 @@ namespace boost { BOOST_BGL_ONE_PARAM_CREF(vertex_index_map, vertex_index) \ BOOST_BGL_ONE_PARAM_CREF(vertex_index1_map, vertex_index1) \ BOOST_BGL_ONE_PARAM_CREF(vertex_index2_map, vertex_index2) \ + BOOST_BGL_ONE_PARAM_CREF(vertex_assignment_map, vertex_assignment_map) \ BOOST_BGL_ONE_PARAM_CREF(visitor, graph_visitor) \ BOOST_BGL_ONE_PARAM_CREF(distance_compare, distance_compare) \ BOOST_BGL_ONE_PARAM_CREF(distance_combine, distance_combine) \ @@ -98,7 +106,9 @@ namespace boost { BOOST_BGL_ONE_PARAM_CREF(diameter_range, diameter_range) \ BOOST_BGL_ONE_PARAM_CREF(learning_constant_range, learning_constant_range) \ BOOST_BGL_ONE_PARAM_CREF(vertices_equivalent, vertices_equivalent) \ - BOOST_BGL_ONE_PARAM_CREF(edges_equivalent, edges_equivalent) + BOOST_BGL_ONE_PARAM_CREF(edges_equivalent, edges_equivalent) \ + BOOST_BGL_ONE_PARAM_CREF(index_in_heap_map, index_in_heap_map) \ + BOOST_BGL_ONE_PARAM_REF(max_priority_queue, max_priority_queue) template struct bgl_named_params : public Base @@ -541,7 +551,68 @@ BOOST_BGL_DECLARE_NAMED_PARAMS boost::graph::keywords::tag::color_map, default_color_type> make_color_map_from_arg_pack(white_color); - } + + template + struct priority_queue_maker_helper { + typedef Q priority_queue_type; + + static priority_queue_type + make_queue(const Graph& g, const ArgPack& ap, KeyT defaultKey, const Q& q) { + return q; + } + }; + + template + struct priority_queue_maker_helper { + typedef typename std::vector::size_type default_index_in_heap_type; + typedef typename map_maker::helper::map_type index_in_heap_map; + typedef boost::d_ary_heap_indirect::helper::map_type, Compare> priority_queue_type; + + static priority_queue_type + make_queue(const Graph& g, const ArgPack& ap, KeyT defaultKey, const Q& q) { + return priority_queue_type( + map_maker::make_map(g, ap, defaultKey), + map_maker::make_map(g, ap, typename boost::property_traits::value_type(-1)) + ); + } + }; + + template + struct priority_queue_maker { + BOOST_STATIC_CONSTANT( + bool, + g_hasQ = + (parameter_exists + ::value)); + typedef priority_queue_maker_helper + >::type::type + >::type> helper; + typedef typename helper::priority_queue_type priority_queue_type; + + static priority_queue_type make_queue(const Graph& g, const ArgPack& ap, KeyT defaultKey) { + return helper::make_queue(g, ap, defaultKey, ap[::boost::parameter::keyword::instance | 0]); + } + }; + + template , class KeyMapTag = boost::graph::keywords::tag::distance_map, class IndexInHeapMapTag = boost::graph::keywords::tag::index_in_heap_map> + struct make_priority_queue_from_arg_pack_gen { + KeyT defaultKey; + + make_priority_queue_from_arg_pack_gen(KeyT defaultKey_) : defaultKey(defaultKey_) { } + + template + typename priority_queue_maker::priority_queue_type + operator()(const Graph& g, const ArgPack& ap) const { + return priority_queue_maker::make_queue(g, ap, defaultKey); + } + }; + + } // namespace detail } // namespace boost diff --git a/include/boost/graph/read_dimacs.hpp b/include/boost/graph/read_dimacs.hpp index 0fedbfae..b19c8139 100644 --- a/include/boost/graph/read_dimacs.hpp +++ b/include/boost/graph/read_dimacs.hpp @@ -28,19 +28,22 @@ namespace boost { + namespace detail { + template -int read_dimacs_max_flow(Graph& g, - CapacityMap capacity, - ReverseEdgeMap reverse_edge, - typename graph_traits::vertex_descriptor& src, - typename graph_traits::vertex_descriptor& sink, - std::istream& in = std::cin) +int read_dimacs_max_flow_internal(Graph& g, + CapacityMap capacity, + ReverseEdgeMap reverse_edge, + typename graph_traits::vertex_descriptor& src, + typename graph_traits::vertex_descriptor& sink, + std::istream& in, + bool require_source_and_sink, + const std::string& problem_type) { // const int MAXLINE = 100; /* max line length in the input file */ const int ARC_FIELDS = 3; /* no of fields in arc line */ const int NODE_FIELDS = 2; /* no of fields in node line */ const int P_FIELDS = 3; /* no of fields in problem line */ - const char* PROBLEM_TYPE = "max"; /* name of problem type*/ typedef typename graph_traits::vertices_size_type vertices_size_type; typedef typename graph_traits::vertex_descriptor vertex_descriptor; @@ -145,7 +148,7 @@ int read_dimacs_max_flow(Graph& g, /*wrong number of parameters in the problem line*/ { err_no = EN2; goto error; } - if ( std::strcmp ( pr_type, PROBLEM_TYPE ) ) + if ( pr_type != problem_type ) /*wrong problem type*/ { err_no = EN3; goto error; } @@ -203,7 +206,7 @@ int read_dimacs_max_flow(Graph& g, break; case 'a': /* arc description */ - if ( no_nslines == 0 || no_nklines == 0 ) + if ( require_source_and_sink && (no_nslines == 0 || no_nklines == 0) ) /* there was not source and sink description above */ { err_no = EN14; goto error; } @@ -264,7 +267,8 @@ int read_dimacs_max_flow(Graph& g, if ( no_alines < m ) /* not enough arcs */ { err_no = EN19; goto error; } - if ( out_degree(src, g) == 0 || out_degree(sink, g) == 0 ) + if ( require_source_and_sink && + (out_degree(src, g) == 0 || out_degree(sink, g) == 0) ) /* no arc goes out of the source */ { err_no = EN20; goto error; } @@ -282,6 +286,27 @@ int read_dimacs_max_flow(Graph& g, } /* -------------------- end of parser -------------------*/ + } // namespace detail + +template +int read_dimacs_max_flow(Graph& g, + CapacityMap capacity, + ReverseEdgeMap reverse_edge, + typename graph_traits::vertex_descriptor& src, + typename graph_traits::vertex_descriptor& sink, + std::istream& in = std::cin) { + return detail::read_dimacs_max_flow_internal(g, capacity, reverse_edge, src, sink, in, true, "max"); +} + +template +int read_dimacs_min_cut(Graph& g, + CapacityMap capacity, + ReverseEdgeMap reverse_edge, + std::istream& in = std::cin) { + typename graph_traits::vertex_descriptor dummy_src, dummy_sink; // Not filled in + return detail::read_dimacs_max_flow_internal(g, capacity, reverse_edge, dummy_src, dummy_sink, in, false, "cut"); +} + } // namespace boost #endif // BOOST_GRAPH_READ_DIMACS_HPP diff --git a/include/boost/graph/stoer_wagner_min_cut.hpp b/include/boost/graph/stoer_wagner_min_cut.hpp new file mode 100644 index 00000000..9cd2d0da --- /dev/null +++ b/include/boost/graph/stoer_wagner_min_cut.hpp @@ -0,0 +1,240 @@ +// Copyright Daniel Trebbien 2010. +// 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) + +#ifndef BOOST_GRAPH_STOER_WAGNER_MIN_CUT_HPP +#define BOOST_GRAPH_STOER_WAGNER_MIN_CUT_HPP 1 + +#include +#include +#include +#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; + typedef typename boost::property_traits::value_type weight_type; + + 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); + } + } + + assert(pq.size() >= 2); + + 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); + 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); + } + } + } + } + } + + return boost::make_tuple(s, t, w); + } + + /** + * \brief Computes a min-cut of the input graph + * + * Computes a min-cut of the input graph using the Stoer-Wagner algorithm. + * + * \pre \p g is a connected, undirected graph + * \pre pq.empty() + * \param[in] g the input graph + * \param[in] weights a readable property map from each edge to its weight (a non-negative value) + * \param[out] parities a writable property map from each vertex to a bool type object for + * distinguishing the two vertex sets of the min-cut + * \param[out] assignments a read/write property map from each vertex to a \c vertex_descriptor object. This + * map serves as work space, and no particular meaning should be derived from property values + * after completion of the algorithm. + * \param[out] pq a keyed, updatable max-priority queue + * \returns the cut weight of the min-cut + * \see http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.114.6687&rep=rep1&type=pdf + * \see http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.31.614&rep=rep1&type=pdf + * + * \author Daniel Trebbien + * \date 2010-09-11 + */ + template + typename boost::property_traits::value_type + stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, 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_CONCEPT_ASSERT((boost::WritablePropertyMapConcept)); + typedef typename boost::property_traits::value_type parity_type; + 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); + 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); + 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); + } + + assert(pq.empty()); + + return bestW; + } + + } // 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) + + BOOST_AUTO(pq, (boost::detail::make_priority_queue_from_arg_pack_gen >(choose_param(get_param(params, boost::distance_zero_t()), weight_type(0)))(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 + ); + } + + 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))); + } + +} // end `namespace boost` + +#include + +#endif // !BOOST_GRAPH_STOER_WAGNER_MIN_CUT_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e3dd2850..5e01a4e3 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -9,6 +9,8 @@ import modules ; +path-constant TEST_DIR : . ; + path-constant PLANAR_INPUT_FILES : ./planar_input_graphs ; path-constant CYCLE_RATIO_INPUT_FILE : ./cycle_ratio_s382.90.dot ; @@ -118,6 +120,7 @@ test-suite graph_test : [ run incremental_components_test.cpp ] [ run random_spanning_tree_test.cpp ../build//boost_graph ] [ run graphml_test.cpp ../build//boost_graph : : "graphml_test.xml" ] + [ run stoer_wagner_test.cpp ../../test/build : $(TEST_DIR) ] ; # Run SDB tests only when -sSDB= is set. diff --git a/test/prgen_input_graphs/prgen_20_70_2.net b/test/prgen_input_graphs/prgen_20_70_2.net new file mode 100644 index 00000000..b21607ce --- /dev/null +++ b/test/prgen_input_graphs/prgen_20_70_2.net @@ -0,0 +1,137 @@ +c NOIGEN min-cut problem +p cut 20 135 +a 1 2 180 +a 1 6 880 +a 1 7 1640 +a 1 9 1620 +a 1 10 80 +a 1 11 98 +a 1 12 31 +a 1 13 60 +a 1 16 91 +a 1 17 9 +a 1 18 48 +a 1 19 91 +a 1 20 41 +a 2 3 1300 +a 2 4 620 +a 2 5 1540 +a 2 8 1000 +a 2 9 1100 +a 2 10 620 +a 2 11 68 +a 2 15 64 +a 2 16 55 +a 2 17 31 +a 2 19 29 +a 2 20 98 +a 3 4 1540 +a 3 6 1100 +a 3 8 1340 +a 3 9 1840 +a 3 10 840 +a 3 14 48 +a 3 15 88 +a 3 17 81 +a 3 18 42 +a 3 19 98 +a 3 20 70 +a 4 5 200 +a 4 6 560 +a 4 7 1800 +a 4 9 1220 +a 4 10 1640 +a 4 11 62 +a 4 12 75 +a 4 14 31 +a 4 16 44 +a 4 17 54 +a 4 19 39 +a 5 6 1460 +a 5 8 1020 +a 5 10 1340 +a 5 11 12 +a 5 12 21 +a 5 13 72 +a 5 14 68 +a 5 15 2 +a 5 16 12 +a 5 17 28 +a 5 18 87 +a 6 7 640 +a 6 8 380 +a 6 9 940 +a 6 10 1140 +a 6 12 21 +a 6 13 17 +a 6 15 54 +a 6 17 92 +a 6 18 5 +a 6 19 34 +a 6 20 47 +a 7 8 1980 +a 7 9 1340 +a 7 10 820 +a 7 12 68 +a 7 13 54 +a 7 14 4 +a 7 15 32 +a 7 17 54 +a 7 20 18 +a 8 9 500 +a 8 11 55 +a 8 12 100 +a 8 13 35 +a 8 14 65 +a 8 15 78 +a 8 17 48 +a 8 18 11 +a 8 19 14 +a 8 20 2 +a 9 10 180 +a 9 13 92 +a 9 14 39 +a 9 15 17 +a 9 16 2 +a 9 17 57 +a 9 19 72 +a 10 11 8 +a 10 12 65 +a 10 14 97 +a 10 15 1 +a 10 16 78 +a 10 17 94 +a 10 19 28 +a 10 20 1 +a 11 12 1520 +a 11 13 1300 +a 11 15 940 +a 11 16 1400 +a 11 17 1600 +a 11 18 100 +a 11 20 100 +a 12 13 1320 +a 12 15 780 +a 12 17 160 +a 12 18 1680 +a 12 19 560 +a 12 20 540 +a 13 14 1220 +a 13 18 580 +a 13 19 180 +a 14 15 1580 +a 14 16 1220 +a 14 17 940 +a 14 18 840 +a 15 16 920 +a 15 17 300 +a 15 19 1820 +a 16 17 1020 +a 16 19 1200 +a 16 20 280 +a 17 18 520 +a 17 19 20 +a 17 20 540 +a 18 19 1980 +a 18 20 1420 +a 19 20 300 diff --git a/test/prgen_input_graphs/prgen_50_40_2.net b/test/prgen_input_graphs/prgen_50_40_2.net new file mode 100644 index 00000000..826e7f5c --- /dev/null +++ b/test/prgen_input_graphs/prgen_50_40_2.net @@ -0,0 +1,517 @@ +c NOIGEN min-cut problem +p cut 50 515 +a 1 2 450 +a 1 6 3850 +a 1 10 350 +a 1 12 2750 +a 1 17 850 +a 1 18 4200 +a 1 20 3600 +a 1 21 4350 +a 1 22 2750 +a 1 26 87 +a 1 27 97 +a 1 28 55 +a 1 34 97 +a 1 35 55 +a 1 37 52 +a 1 39 57 +a 1 41 97 +a 1 45 75 +a 1 49 84 +a 2 3 450 +a 2 5 3750 +a 2 9 2450 +a 2 17 2750 +a 2 19 3850 +a 2 20 4750 +a 2 22 3450 +a 2 24 3350 +a 2 26 90 +a 2 29 22 +a 2 30 37 +a 2 33 4 +a 2 34 22 +a 2 35 49 +a 2 40 34 +a 2 41 82 +a 2 42 99 +a 2 44 37 +a 2 45 30 +a 2 47 95 +a 2 50 10 +a 3 4 3800 +a 3 5 4100 +a 3 6 100 +a 3 8 3600 +a 3 11 4750 +a 3 12 350 +a 3 13 2850 +a 3 15 4750 +a 3 18 1600 +a 3 21 4850 +a 3 23 3100 +a 3 27 84 +a 3 28 19 +a 3 29 25 +a 3 30 4 +a 3 35 69 +a 3 36 30 +a 3 37 4 +a 3 38 99 +a 3 46 2 +a 3 50 49 +a 4 5 4950 +a 4 6 3000 +a 4 9 4100 +a 4 12 500 +a 4 14 500 +a 4 15 4200 +a 4 17 3450 +a 4 19 750 +a 4 21 2450 +a 4 22 2350 +a 4 23 4850 +a 4 27 52 +a 4 28 17 +a 4 30 52 +a 4 32 82 +a 4 33 75 +a 4 37 27 +a 4 44 25 +a 4 46 2 +a 4 47 47 +a 4 48 2 +a 5 6 1350 +a 5 12 200 +a 5 13 2850 +a 5 16 1250 +a 5 17 4950 +a 5 19 3750 +a 5 21 2100 +a 5 22 2350 +a 5 23 3250 +a 5 26 57 +a 5 30 4 +a 5 33 65 +a 5 36 55 +a 5 41 69 +a 5 43 32 +a 5 47 87 +a 5 48 75 +a 5 49 62 +a 5 50 25 +a 6 7 1900 +a 6 8 4750 +a 6 15 950 +a 6 16 2850 +a 6 22 950 +a 6 26 60 +a 6 27 72 +a 6 29 49 +a 6 32 32 +a 6 33 97 +a 6 36 97 +a 6 37 75 +a 6 41 60 +a 6 42 42 +a 6 43 34 +a 6 45 72 +a 6 46 27 +a 7 8 150 +a 7 11 3600 +a 7 12 3850 +a 7 16 3750 +a 7 18 2000 +a 7 19 500 +a 7 24 4100 +a 7 25 600 +a 7 26 90 +a 7 27 67 +a 7 29 10 +a 7 30 67 +a 7 31 90 +a 7 32 10 +a 7 33 12 +a 7 34 77 +a 7 38 17 +a 7 39 49 +a 7 40 19 +a 7 41 67 +a 7 42 67 +a 7 43 62 +a 7 44 52 +a 7 46 10 +a 7 47 52 +a 7 49 22 +a 8 9 2050 +a 8 15 1250 +a 8 16 600 +a 8 18 1850 +a 8 21 4200 +a 8 22 4750 +a 8 27 69 +a 8 28 40 +a 8 32 40 +a 8 37 82 +a 8 38 65 +a 8 39 99 +a 8 41 65 +a 8 43 22 +a 8 50 19 +a 9 10 2600 +a 9 16 4000 +a 9 19 3100 +a 9 31 2 +a 9 32 62 +a 9 34 62 +a 9 36 40 +a 9 39 80 +a 9 40 69 +a 9 41 25 +a 9 42 22 +a 9 48 82 +a 9 50 97 +a 10 11 4400 +a 10 12 4100 +a 10 17 4200 +a 10 18 4850 +a 10 19 2000 +a 10 20 4750 +a 10 23 1600 +a 10 28 30 +a 10 29 82 +a 10 34 97 +a 10 38 34 +a 10 40 47 +a 10 46 90 +a 10 49 65 +a 11 12 4200 +a 11 13 3750 +a 11 19 850 +a 11 20 3000 +a 11 21 2250 +a 11 23 1700 +a 11 26 82 +a 11 27 67 +a 11 30 4 +a 11 31 19 +a 11 32 27 +a 11 35 62 +a 11 36 19 +a 11 37 75 +a 11 38 95 +a 11 39 49 +a 11 40 7 +a 11 41 77 +a 11 42 77 +a 11 43 40 +a 11 44 82 +a 11 47 12 +a 11 49 45 +a 12 13 4500 +a 12 18 4500 +a 12 19 1600 +a 12 20 3750 +a 12 21 350 +a 12 22 4200 +a 12 24 1100 +a 12 27 57 +a 12 30 55 +a 12 33 82 +a 12 34 67 +a 12 36 90 +a 12 39 75 +a 12 41 52 +a 12 45 84 +a 12 46 55 +a 12 48 34 +a 12 49 34 +a 12 50 19 +a 13 14 600 +a 13 15 3600 +a 13 19 2450 +a 13 22 350 +a 13 25 3350 +a 13 27 37 +a 13 29 37 +a 13 31 15 +a 13 33 19 +a 13 36 57 +a 13 37 15 +a 13 38 80 +a 13 40 52 +a 13 45 25 +a 13 50 37 +a 14 15 2100 +a 14 16 2350 +a 14 21 3000 +a 14 22 2100 +a 14 25 1500 +a 14 26 65 +a 14 28 34 +a 14 32 87 +a 14 33 22 +a 14 34 52 +a 14 35 32 +a 14 37 2 +a 14 40 60 +a 14 41 62 +a 14 42 62 +a 14 43 62 +a 14 44 55 +a 14 46 32 +a 14 50 84 +a 15 16 1850 +a 15 17 3750 +a 15 18 4600 +a 15 20 4100 +a 15 21 4600 +a 15 22 4600 +a 15 23 1100 +a 15 24 2600 +a 15 28 60 +a 15 31 30 +a 15 32 84 +a 15 37 65 +a 15 39 12 +a 15 41 87 +a 15 42 72 +a 15 44 97 +a 15 45 25 +a 15 46 82 +a 15 47 4 +a 16 17 3900 +a 16 18 350 +a 16 19 4600 +a 16 24 4000 +a 16 25 4100 +a 16 30 67 +a 16 31 57 +a 16 36 49 +a 16 37 47 +a 16 43 40 +a 16 45 57 +a 16 47 82 +a 16 48 92 +a 16 50 22 +a 17 18 1100 +a 17 19 4000 +a 17 23 4350 +a 17 24 3600 +a 17 31 17 +a 17 33 10 +a 17 34 4 +a 17 37 7 +a 17 38 57 +a 17 40 95 +a 17 43 45 +a 17 45 45 +a 17 49 92 +a 18 19 1850 +a 18 20 3250 +a 18 32 30 +a 18 34 17 +a 18 39 95 +a 18 40 95 +a 18 41 10 +a 18 45 69 +a 18 47 2 +a 18 48 77 +a 18 49 25 +a 18 50 37 +a 19 20 2550 +a 19 21 600 +a 19 28 69 +a 19 30 19 +a 19 31 99 +a 19 36 90 +a 19 37 97 +a 19 38 60 +a 19 40 52 +a 19 41 95 +a 19 42 2 +a 19 44 55 +a 19 45 45 +a 19 47 4 +a 20 21 4250 +a 20 23 2000 +a 20 25 2600 +a 20 27 72 +a 20 31 84 +a 20 32 60 +a 20 34 84 +a 20 36 52 +a 20 37 95 +a 20 38 25 +a 20 40 84 +a 20 45 42 +a 20 46 42 +a 20 48 67 +a 20 49 52 +a 21 22 400 +a 21 30 77 +a 21 31 40 +a 21 32 69 +a 21 33 4 +a 21 35 40 +a 21 37 19 +a 21 39 40 +a 21 41 72 +a 21 48 10 +a 22 23 2050 +a 22 24 4950 +a 22 25 2750 +a 22 30 60 +a 22 34 62 +a 22 36 84 +a 22 40 99 +a 22 45 82 +a 22 47 55 +a 22 49 75 +a 23 24 4150 +a 23 27 15 +a 23 29 84 +a 23 30 84 +a 23 33 87 +a 23 38 99 +a 23 44 12 +a 24 25 3050 +a 24 26 10 +a 24 28 12 +a 24 31 84 +a 24 32 82 +a 24 36 4 +a 24 40 69 +a 24 41 37 +a 24 42 97 +a 25 26 6 +a 25 30 57 +a 25 32 34 +a 25 35 65 +a 25 36 69 +a 25 38 82 +a 25 40 92 +a 25 42 34 +a 25 43 55 +a 25 44 10 +a 26 27 2450 +a 26 29 200 +a 26 30 2350 +a 26 33 950 +a 26 39 3000 +a 26 42 1250 +a 26 46 4000 +a 26 47 3100 +a 26 48 950 +a 27 28 2300 +a 27 30 3100 +a 27 31 1500 +a 27 32 4750 +a 27 34 3850 +a 27 44 3350 +a 27 46 3350 +a 27 47 2600 +a 27 50 3750 +a 28 29 4150 +a 28 38 1850 +a 28 47 4100 +a 29 30 3150 +a 29 31 4200 +a 29 34 3850 +a 29 37 750 +a 29 39 2850 +a 29 46 2450 +a 29 48 4850 +a 30 31 1350 +a 30 34 950 +a 30 35 200 +a 30 36 3350 +a 30 39 4600 +a 30 40 2100 +a 30 41 100 +a 30 42 100 +a 30 43 3750 +a 30 45 3100 +a 30 46 4950 +a 30 48 1850 +a 31 32 4950 +a 31 33 850 +a 31 37 2000 +a 31 41 4350 +a 31 44 850 +a 31 50 3000 +a 32 33 350 +a 32 37 2450 +a 32 40 4750 +a 32 44 750 +a 32 46 3000 +a 32 50 2600 +a 33 34 2600 +a 33 36 2350 +a 33 42 1100 +a 33 43 1850 +a 33 46 3850 +a 33 48 3600 +a 34 35 3250 +a 34 36 1500 +a 34 38 1600 +a 34 42 2750 +a 34 43 3600 +a 34 44 3350 +a 35 36 750 +a 35 37 1700 +a 35 42 2100 +a 35 43 4350 +a 35 46 200 +a 35 47 1700 +a 35 48 3750 +a 36 37 2150 +a 36 39 4000 +a 36 42 3100 +a 36 45 4350 +a 37 38 4800 +a 37 42 1850 +a 37 43 1350 +a 37 48 2750 +a 37 50 2850 +a 38 39 750 +a 38 41 1600 +a 38 43 500 +a 38 46 3100 +a 38 47 3250 +a 38 49 2100 +a 39 40 4250 +a 39 42 3450 +a 39 43 1700 +a 39 44 4600 +a 39 50 3250 +a 40 41 300 +a 40 42 2600 +a 40 44 1350 +a 40 45 500 +a 40 49 2100 +a 41 42 800 +a 41 43 3100 +a 41 46 3850 +a 41 47 100 +a 41 48 1500 +a 41 49 1700 +a 42 43 4700 +a 42 47 4950 +a 43 44 3450 +a 43 49 1600 +a 43 50 1100 +a 44 45 1600 +a 44 46 750 +a 44 48 1600 +a 44 50 200 +a 45 46 1450 +a 45 50 200 +a 46 47 3550 +a 46 50 750 +a 47 48 4350 +a 47 50 1500 +a 48 49 1350 +a 48 50 4850 +a 49 50 650 diff --git a/test/prgen_input_graphs/prgen_50_70_2.net b/test/prgen_input_graphs/prgen_50_70_2.net new file mode 100644 index 00000000..0352a0a8 --- /dev/null +++ b/test/prgen_input_graphs/prgen_50_70_2.net @@ -0,0 +1,858 @@ +c NOIGEN min-cut problem +p cut 50 856 +a 1 2 450 +a 1 6 2200 +a 1 7 4100 +a 1 9 4050 +a 1 10 200 +a 1 11 4900 +a 1 12 1550 +a 1 13 3000 +a 1 16 4550 +a 1 17 450 +a 1 18 2400 +a 1 19 4550 +a 1 20 2050 +a 1 21 2500 +a 1 22 1550 +a 1 23 3850 +a 1 26 50 +a 1 27 55 +a 1 28 31 +a 1 29 68 +a 1 33 64 +a 1 34 55 +a 1 35 31 +a 1 37 29 +a 1 38 98 +a 1 39 32 +a 1 41 55 +a 1 43 67 +a 1 44 92 +a 1 45 42 +a 1 49 48 +a 1 50 88 +a 2 3 450 +a 2 4 4050 +a 2 5 2100 +a 2 6 4900 +a 2 7 3500 +a 2 9 1400 +a 2 10 4500 +a 2 12 3050 +a 2 13 4100 +a 2 14 3100 +a 2 15 3750 +a 2 17 1550 +a 2 19 2200 +a 2 20 2700 +a 2 22 1950 +a 2 24 1900 +a 2 26 51 +a 2 28 67 +a 2 29 12 +a 2 30 21 +a 2 31 72 +a 2 32 68 +a 2 33 2 +a 2 34 12 +a 2 35 28 +a 2 36 87 +a 2 39 97 +a 2 40 19 +a 2 41 47 +a 2 42 57 +a 2 44 21 +a 2 45 17 +a 2 47 54 +a 2 49 92 +a 2 50 5 +a 3 4 3800 +a 3 5 2350 +a 3 6 50 +a 3 7 3350 +a 3 8 2050 +a 3 10 3400 +a 3 11 2700 +a 3 12 200 +a 3 13 1600 +a 3 15 2700 +a 3 18 900 +a 3 21 2750 +a 3 22 5000 +a 3 23 1750 +a 3 24 3250 +a 3 25 3900 +a 3 27 48 +a 3 28 11 +a 3 29 14 +a 3 30 2 +a 3 34 92 +a 3 35 39 +a 3 36 17 +a 3 37 2 +a 3 38 57 +a 3 40 72 +a 3 43 65 +a 3 45 97 +a 3 46 1 +a 3 47 78 +a 3 48 94 +a 3 50 28 +a 4 5 4950 +a 4 6 1700 +a 4 7 3250 +a 4 9 2350 +a 4 10 3500 +a 4 11 4000 +a 4 12 250 +a 4 14 250 +a 4 15 2400 +a 4 17 1950 +a 4 19 400 +a 4 20 4200 +a 4 21 1400 +a 4 22 1350 +a 4 23 2750 +a 4 27 29 +a 4 28 9 +a 4 30 29 +a 4 31 61 +a 4 32 47 +a 4 33 42 +a 4 36 77 +a 4 37 15 +a 4 39 91 +a 4 41 70 +a 4 43 60 +a 4 44 14 +a 4 46 1 +a 4 47 27 +a 4 48 1 +a 4 49 71 +a 5 6 1350 +a 5 7 3700 +a 5 8 4600 +a 5 9 4000 +a 5 12 100 +a 5 13 1600 +a 5 15 4350 +a 5 16 700 +a 5 17 2850 +a 5 18 3700 +a 5 19 2100 +a 5 21 1200 +a 5 22 1350 +a 5 23 1850 +a 5 26 32 +a 5 29 75 +a 5 30 2 +a 5 31 85 +a 5 32 58 +a 5 33 37 +a 5 36 31 +a 5 37 92 +a 5 38 91 +a 5 40 68 +a 5 41 39 +a 5 42 82 +a 5 43 18 +a 5 45 74 +a 5 47 50 +a 5 48 42 +a 5 49 35 +a 5 50 14 +a 6 7 1900 +a 6 8 2700 +a 6 9 2900 +a 6 10 4350 +a 6 11 3000 +a 6 12 4250 +a 6 14 4100 +a 6 15 550 +a 6 16 1600 +a 6 17 3050 +a 6 19 3400 +a 6 20 3700 +a 6 21 4600 +a 6 22 550 +a 6 23 4600 +a 6 26 34 +a 6 27 41 +a 6 29 28 +a 6 31 60 +a 6 32 18 +a 6 33 55 +a 6 34 90 +a 6 36 55 +a 6 37 42 +a 6 38 90 +a 6 40 94 +a 6 41 34 +a 6 42 24 +a 6 43 19 +a 6 45 41 +a 6 46 15 +a 6 50 98 +a 7 8 150 +a 7 11 2050 +a 7 12 2200 +a 7 16 2100 +a 7 18 1100 +a 7 19 250 +a 7 21 4750 +a 7 23 4900 +a 7 24 2350 +a 7 25 350 +a 7 26 51 +a 7 27 38 +a 7 28 70 +a 7 29 5 +a 7 30 38 +a 7 31 51 +a 7 32 5 +a 7 33 7 +a 7 34 44 +a 7 35 90 +a 7 38 9 +a 7 39 28 +a 7 40 11 +a 7 41 38 +a 7 42 38 +a 7 43 35 +a 7 44 29 +a 7 45 78 +a 7 46 5 +a 7 47 29 +a 7 49 12 +a 8 9 2050 +a 8 10 4550 +a 8 11 4900 +a 8 12 4500 +a 8 15 700 +a 8 16 350 +a 8 17 4000 +a 8 18 1050 +a 8 20 4500 +a 8 21 2400 +a 8 22 2700 +a 8 26 68 +a 8 27 39 +a 8 28 22 +a 8 29 95 +a 8 30 64 +a 8 32 22 +a 8 37 47 +a 8 38 37 +a 8 39 57 +a 8 40 97 +a 8 41 37 +a 8 42 88 +a 8 43 12 +a 8 44 97 +a 8 46 87 +a 8 48 81 +a 8 49 77 +a 8 50 11 +a 9 10 2600 +a 9 13 4100 +a 9 14 3850 +a 9 15 3550 +a 9 16 2250 +a 9 17 4500 +a 9 18 4100 +a 9 19 1750 +a 9 20 3900 +a 9 22 4250 +a 9 23 3500 +a 9 26 81 +a 9 27 95 +a 9 29 65 +a 9 30 95 +a 9 31 1 +a 9 32 35 +a 9 33 87 +a 9 34 35 +a 9 36 22 +a 9 38 60 +a 9 39 45 +a 9 40 39 +a 9 41 14 +a 9 42 12 +a 9 43 81 +a 9 45 62 +a 9 48 47 +a 9 50 55 +a 10 11 4400 +a 10 12 2350 +a 10 17 2400 +a 10 18 2750 +a 10 19 1100 +a 10 20 2700 +a 10 21 4750 +a 10 23 900 +a 10 24 4400 +a 10 26 68 +a 10 27 81 +a 10 28 17 +a 10 29 47 +a 10 30 80 +a 10 32 58 +a 10 33 68 +a 10 34 55 +a 10 35 60 +a 10 37 82 +a 10 38 19 +a 10 40 27 +a 10 42 75 +a 10 44 71 +a 10 46 51 +a 10 48 77 +a 10 49 37 +a 11 12 4200 +a 11 13 2100 +a 11 15 4550 +a 11 19 450 +a 11 20 1700 +a 11 21 1250 +a 11 22 3350 +a 11 23 950 +a 11 24 3550 +a 11 25 3550 +a 11 26 47 +a 11 27 38 +a 11 28 58 +a 11 29 84 +a 11 30 2 +a 11 31 11 +a 11 32 15 +a 11 33 77 +a 11 34 91 +a 11 35 35 +a 11 36 11 +a 11 37 42 +a 11 38 54 +a 11 39 28 +a 11 40 4 +a 11 41 44 +a 11 42 44 +a 11 43 22 +a 11 44 47 +a 11 47 7 +a 11 49 25 +a 11 50 60 +a 12 13 4500 +a 12 17 3200 +a 12 18 2550 +a 12 19 900 +a 12 20 2100 +a 12 21 200 +a 12 22 2400 +a 12 24 600 +a 12 25 2900 +a 12 26 90 +a 12 27 32 +a 12 30 31 +a 12 31 95 +a 12 32 70 +a 12 33 47 +a 12 34 38 +a 12 35 81 +a 12 36 51 +a 12 37 90 +a 12 39 42 +a 12 40 80 +a 12 41 29 +a 12 42 84 +a 12 44 94 +a 12 45 48 +a 12 46 31 +a 12 47 67 +a 12 48 19 +a 12 49 19 +a 12 50 11 +a 13 14 600 +a 13 15 2050 +a 13 16 3900 +a 13 17 3900 +a 13 19 1400 +a 13 22 200 +a 13 24 4550 +a 13 25 1900 +a 13 26 62 +a 13 27 21 +a 13 28 97 +a 13 29 21 +a 13 31 8 +a 13 33 11 +a 13 36 32 +a 13 37 8 +a 13 38 45 +a 13 39 84 +a 13 40 29 +a 13 41 94 +a 13 44 84 +a 13 45 14 +a 13 46 74 +a 13 47 78 +a 13 50 21 +a 14 15 2100 +a 14 16 1350 +a 14 17 4700 +a 14 18 3600 +a 14 19 3100 +a 14 21 1700 +a 14 22 1200 +a 14 25 850 +a 14 26 37 +a 14 28 19 +a 14 32 50 +a 14 33 12 +a 14 34 29 +a 14 35 18 +a 14 36 87 +a 14 37 1 +a 14 39 85 +a 14 40 34 +a 14 41 35 +a 14 42 35 +a 14 43 35 +a 14 44 31 +a 14 46 18 +a 14 47 77 +a 14 50 48 +a 15 16 1850 +a 15 17 2100 +a 15 18 2600 +a 15 20 2350 +a 15 21 2600 +a 15 22 2600 +a 15 23 600 +a 15 24 1450 +a 15 25 4600 +a 15 28 34 +a 15 31 17 +a 15 32 48 +a 15 33 80 +a 15 34 94 +a 15 36 100 +a 15 37 37 +a 15 38 61 +a 15 39 7 +a 15 41 50 +a 15 42 41 +a 15 43 67 +a 15 44 55 +a 15 45 14 +a 15 46 47 +a 15 47 2 +a 15 48 70 +a 16 17 3900 +a 16 18 200 +a 16 19 2600 +a 16 20 3550 +a 16 23 3200 +a 16 24 2250 +a 16 25 2350 +a 16 28 72 +a 16 29 71 +a 16 30 38 +a 16 31 32 +a 16 32 67 +a 16 34 67 +a 16 35 70 +a 16 36 28 +a 16 37 27 +a 16 40 100 +a 16 43 22 +a 16 45 32 +a 16 47 47 +a 16 48 52 +a 16 49 67 +a 16 50 12 +a 17 18 1100 +a 17 19 2250 +a 17 23 2500 +a 17 24 2050 +a 17 26 92 +a 17 28 87 +a 17 29 58 +a 17 30 85 +a 17 31 9 +a 17 32 58 +a 17 33 5 +a 17 34 2 +a 17 35 84 +a 17 36 74 +a 17 37 4 +a 17 38 32 +a 17 39 82 +a 17 40 54 +a 17 41 70 +a 17 43 25 +a 17 45 25 +a 17 46 70 +a 17 47 75 +a 17 49 52 +a 18 19 1850 +a 18 20 1850 +a 18 22 4200 +a 18 26 80 +a 18 28 98 +a 18 32 17 +a 18 34 9 +a 18 35 98 +a 18 36 74 +a 18 38 98 +a 18 39 54 +a 18 40 54 +a 18 41 5 +a 18 44 94 +a 18 45 39 +a 18 47 1 +a 18 48 44 +a 18 49 14 +a 18 50 21 +a 19 20 2550 +a 19 21 350 +a 19 23 4350 +a 19 24 4400 +a 19 25 4850 +a 19 26 71 +a 19 28 39 +a 19 29 100 +a 19 30 11 +a 19 31 57 +a 19 34 58 +a 19 36 51 +a 19 37 55 +a 19 38 34 +a 19 39 72 +a 19 40 29 +a 19 41 54 +a 19 42 1 +a 19 44 31 +a 19 45 25 +a 19 47 2 +a 19 48 94 +a 19 50 91 +a 20 21 4250 +a 20 23 1100 +a 20 25 1450 +a 20 26 70 +a 20 27 41 +a 20 31 48 +a 20 32 34 +a 20 34 48 +a 20 36 29 +a 20 37 54 +a 20 38 14 +a 20 40 48 +a 20 41 98 +a 20 42 92 +a 20 43 100 +a 20 44 67 +a 20 45 24 +a 20 46 24 +a 20 47 98 +a 20 48 38 +a 20 49 29 +a 21 22 400 +a 21 23 4100 +a 21 24 3400 +a 21 26 87 +a 21 27 81 +a 21 29 82 +a 21 30 44 +a 21 31 22 +a 21 32 39 +a 21 33 2 +a 21 35 22 +a 21 37 11 +a 21 39 22 +a 21 41 41 +a 21 42 58 +a 21 43 61 +a 21 44 77 +a 21 45 67 +a 21 46 100 +a 21 48 5 +a 21 49 65 +a 22 23 2050 +a 22 24 2850 +a 22 25 1550 +a 22 27 94 +a 22 28 60 +a 22 29 58 +a 22 30 34 +a 22 31 77 +a 22 32 67 +a 22 34 35 +a 22 35 100 +a 22 36 48 +a 22 40 57 +a 22 42 77 +a 22 45 47 +a 22 46 64 +a 22 47 31 +a 22 49 42 +a 23 24 4150 +a 23 25 3500 +a 23 26 62 +a 23 27 8 +a 23 28 91 +a 23 29 48 +a 23 30 48 +a 23 32 71 +a 23 33 50 +a 23 35 65 +a 23 36 95 +a 23 38 57 +a 23 39 70 +a 23 41 95 +a 23 43 67 +a 23 44 7 +a 23 47 61 +a 23 49 87 +a 24 25 3050 +a 24 26 5 +a 24 28 7 +a 24 31 48 +a 24 32 47 +a 24 33 92 +a 24 34 60 +a 24 36 2 +a 24 37 72 +a 24 39 98 +a 24 40 39 +a 24 41 21 +a 24 42 55 +a 24 46 84 +a 24 47 71 +a 24 49 92 +a 24 50 82 +a 25 26 6 +a 25 29 62 +a 25 30 32 +a 25 32 19 +a 25 33 91 +a 25 34 88 +a 25 35 37 +a 25 36 39 +a 25 38 47 +a 25 40 52 +a 25 41 98 +a 25 42 19 +a 25 43 31 +a 25 44 5 +a 25 46 88 +a 25 48 87 +a 25 49 78 +a 26 27 2450 +a 26 28 3250 +a 26 29 100 +a 26 30 1350 +a 26 32 4700 +a 26 33 550 +a 26 35 3250 +a 26 37 4200 +a 26 39 1700 +a 26 40 3750 +a 26 41 4200 +a 26 42 700 +a 26 44 3000 +a 26 45 4550 +a 26 46 2250 +a 26 47 1750 +a 26 48 550 +a 26 50 4200 +a 27 28 2300 +a 27 30 1750 +a 27 31 850 +a 27 32 2700 +a 27 34 2200 +a 27 39 2900 +a 27 40 3900 +a 27 41 3550 +a 27 44 1900 +a 27 45 3900 +a 27 46 1900 +a 27 47 1450 +a 27 48 3050 +a 27 50 2100 +a 28 29 4150 +a 28 30 3550 +a 28 32 2900 +a 28 33 4250 +a 28 38 1050 +a 28 39 4750 +a 28 40 2900 +a 28 46 3600 +a 28 47 2350 +a 29 30 3150 +a 29 31 2400 +a 29 32 3550 +a 29 34 2200 +a 29 36 4050 +a 29 37 400 +a 29 39 1600 +a 29 40 3750 +a 29 41 3900 +a 29 46 1400 +a 29 48 2750 +a 29 49 3400 +a 29 50 3600 +a 30 31 1350 +a 30 33 4400 +a 30 34 550 +a 30 35 100 +a 30 36 1900 +a 30 37 4100 +a 30 38 3600 +a 30 39 2600 +a 30 40 1200 +a 30 41 50 +a 30 42 50 +a 30 43 2100 +a 30 44 3750 +a 30 45 1750 +a 30 46 2850 +a 30 47 5000 +a 30 48 1050 +a 30 50 3100 +a 31 32 4950 +a 31 33 450 +a 31 35 3250 +a 31 36 2900 +a 31 37 1100 +a 31 38 3050 +a 31 39 4900 +a 31 40 4550 +a 31 41 2500 +a 31 44 450 +a 31 47 3900 +a 31 49 3350 +a 31 50 1700 +a 32 33 350 +a 32 35 3050 +a 32 37 1400 +a 32 39 3550 +a 32 40 2700 +a 32 41 3600 +a 32 42 4400 +a 32 44 400 +a 32 45 4600 +a 32 46 1700 +a 32 47 3550 +a 32 48 4750 +a 32 50 1450 +a 33 34 2600 +a 33 36 1350 +a 33 37 4500 +a 33 39 4750 +a 33 41 3100 +a 33 42 600 +a 33 43 1050 +a 33 46 2200 +a 33 48 2050 +a 34 35 3250 +a 34 36 850 +a 34 38 900 +a 34 40 4100 +a 34 42 1550 +a 34 43 2050 +a 34 44 1900 +a 34 45 4250 +a 34 47 5000 +a 34 49 4600 +a 35 36 750 +a 35 37 950 +a 35 40 3500 +a 35 41 3700 +a 35 42 1200 +a 35 43 2500 +a 35 44 4850 +a 35 45 3600 +a 35 46 100 +a 35 47 950 +a 35 48 2100 +a 35 49 2900 +a 35 50 4100 +a 36 37 2150 +a 36 38 3000 +a 36 39 2250 +a 36 41 4200 +a 36 42 1750 +a 36 45 2500 +a 36 47 4850 +a 36 48 3500 +a 37 38 4800 +a 37 39 3750 +a 37 40 4000 +a 37 41 4500 +a 37 42 1050 +a 37 43 750 +a 37 48 1550 +a 37 49 4100 +a 37 50 1600 +a 38 39 750 +a 38 41 900 +a 38 43 250 +a 38 44 4250 +a 38 45 5000 +a 38 46 1750 +a 38 47 1850 +a 38 49 1200 +a 38 50 3000 +a 39 40 4250 +a 39 42 1950 +a 39 43 950 +a 39 44 2600 +a 39 45 3000 +a 39 47 3900 +a 39 50 1850 +a 40 41 300 +a 40 42 1450 +a 40 43 2900 +a 40 44 750 +a 40 45 250 +a 40 46 3900 +a 40 47 3250 +a 40 49 1200 +a 41 42 800 +a 41 43 1750 +a 41 44 4400 +a 41 45 4350 +a 41 46 2200 +a 41 47 50 +a 41 48 850 +a 41 49 950 +a 42 43 4700 +a 42 45 4750 +a 42 46 3200 +a 42 47 2850 +a 43 44 3450 +a 43 45 4850 +a 43 46 3550 +a 43 47 3900 +a 43 49 900 +a 43 50 600 +a 44 45 1600 +a 44 46 400 +a 44 47 3900 +a 44 48 900 +a 44 49 2900 +a 44 50 100 +a 45 46 1450 +a 45 47 4200 +a 45 49 2900 +a 45 50 100 +a 46 47 3550 +a 46 49 3850 +a 46 50 400 +a 47 48 4350 +a 47 49 3000 +a 47 50 850 +a 48 49 1350 +a 48 50 2750 +a 49 50 650 diff --git a/test/stoer_wagner_test.cpp b/test/stoer_wagner_test.cpp new file mode 100644 index 00000000..1fc4332b --- /dev/null +++ b/test/stoer_wagner_test.cpp @@ -0,0 +1,253 @@ +// Copyright Daniel Trebbien 2010. +// 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 +#define BOOST_TEST_DYN_LINK 1 +#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; +}; + +// the example from Stoer & Wagner (1997) +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 parity; + boost::associative_property_map > parities(parity); + int w = boost::stoer_wagner_min_cut(g, weights, boost::parity_map(parities)); + BOOST_CHECK_EQUAL(w, 4); + const bool parity0 = get(parities, 0); + BOOST_CHECK_EQUAL(parity0, get(parities, 1)); + BOOST_CHECK_EQUAL(parity0, get(parities, 4)); + BOOST_CHECK_EQUAL(parity0, get(parities, 5)); + const bool parity2 = get(parities, 2); + BOOST_CHECK_NE(parity0, parity2); + BOOST_CHECK_EQUAL(parity2, get(parities, 3)); + BOOST_CHECK_EQUAL(parity2, get(parities, 6)); + BOOST_CHECK_EQUAL(parity2, get(parities, 7)); +} + +BOOST_AUTO_TEST_CASE(test1) +{ + { // if only one vertex, can't run `boost::stoer_wagner_min_cut` + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef boost::graph_traits::edge_descriptor edge_descriptor; + + undirected_graph g; + add_vertex(g); + + BOOST_CHECK_THROW(boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g)), boost::bad_graph); + }{ // three vertices with one multi-edge + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef boost::graph_traits::edge_descriptor edge_descriptor; + + edge_t edges[] = {{0, 1}, {1, 2}, {1, 2}, {2, 0}}; + weight_type ws[] = {3, 1, 1, 1}; + undirected_graph g(edges, edges + 4, ws, 3, 4); + + weight_map_type weights = get(boost::edge_weight, g); + std::map parity; + boost::associative_property_map > parities(parity); + std::map assignment; + boost::associative_property_map > assignments(assignment); + int w = boost::stoer_wagner_min_cut(g, weights, boost::parity_map(parities).vertex_assignment_map(assignments)); + BOOST_CHECK_EQUAL(w, 3); + const bool parity2 = get(parities, 2), + parity0 = get(parities, 0); + BOOST_CHECK_NE(parity2, parity0); + BOOST_CHECK_EQUAL(parity0, get(parities, 1)); + } +} + +// example by Daniel Trebbien +BOOST_AUTO_TEST_CASE(test2) +{ + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef boost::graph_traits::edge_descriptor edge_descriptor; + + edge_t edges[] = {{5, 2}, {0, 6}, {5, 6}, + {3, 1}, {0, 1}, {6, 3}, {4, 6}, {2, 4}, {5, 3}}; + weight_type ws[] = {1, 3, 4, 6, 4, 1, 2, 5, 2}; + undirected_graph g(edges, edges + 9, ws, 7, 9); + + std::map parity; + boost::associative_property_map > parities(parity); + int w = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g), boost::parity_map(parities)); + BOOST_CHECK_EQUAL(w, 3); + const bool parity2 = get(parities, 2); + BOOST_CHECK_EQUAL(parity2, get(parities, 4)); + const bool parity5 = get(parities, 5); + BOOST_CHECK_NE(parity2, parity5); + BOOST_CHECK_EQUAL(parity5, get(parities, 3)); + BOOST_CHECK_EQUAL(parity5, get(parities, 6)); + BOOST_CHECK_EQUAL(parity5, get(parities, 1)); + BOOST_CHECK_EQUAL(parity5, get(parities, 0)); +} + +// example by Daniel Trebbien +BOOST_AUTO_TEST_CASE(test3) +{ + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef boost::graph_traits::edge_descriptor edge_descriptor; + + edge_t edges[] = {{3, 4}, {3, 6}, {3, 5}, {0, 4}, {0, 1}, {0, 6}, {0, 7}, + {0, 5}, {0, 2}, {4, 1}, {1, 6}, {1, 5}, {6, 7}, {7, 5}, {5, 2}, {3, 4}}; + weight_type ws[] = {0, 3, 1, 3, 1, 2, 6, 1, 8, 1, 1, 80, 2, 1, 1, 4}; + undirected_graph g(edges, edges + 16, ws, 8, 16); + + weight_map_type weights = get(boost::edge_weight, g); + std::map parity; + boost::associative_property_map > parities(parity); + int w = boost::stoer_wagner_min_cut(g, weights, boost::parity_map(parities)); + BOOST_CHECK_EQUAL(w, 7); + const bool parity1 = get(parities, 1); + BOOST_CHECK_EQUAL(parity1, get(parities, 5)); + const bool parity0 = get(parities, 0); + BOOST_CHECK_NE(parity1, parity0); + BOOST_CHECK_EQUAL(parity0, get(parities, 2)); + BOOST_CHECK_EQUAL(parity0, get(parities, 3)); + BOOST_CHECK_EQUAL(parity0, get(parities, 4)); + BOOST_CHECK_EQUAL(parity0, get(parities, 6)); + BOOST_CHECK_EQUAL(parity0, get(parities, 7)); +} + +BOOST_AUTO_TEST_CASE(test4) +{ + 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}, + {0, 4}, {6, 7}}; + undirected_unweighted_graph g(edges, edges + 14, 8); + + std::map parity; + boost::associative_property_map > parities(parity); + std::map assignment; + boost::associative_property_map > assignments(assignment); + int w = boost::stoer_wagner_min_cut(g, boost::make_constant_property(weight_type(1)), boost::vertex_assignment_map(assignments).parity_map(parities)); + BOOST_CHECK_EQUAL(w, 2); + const bool parity0 = get(parities, 0); + BOOST_CHECK_EQUAL(parity0, get(parities, 1)); + BOOST_CHECK_EQUAL(parity0, get(parities, 4)); + BOOST_CHECK_EQUAL(parity0, get(parities, 5)); + const bool parity2 = get(parities, 2); + BOOST_CHECK_NE(parity0, parity2); + BOOST_CHECK_EQUAL(parity2, get(parities, 3)); + BOOST_CHECK_EQUAL(parity2, get(parities, 6)); + BOOST_CHECK_EQUAL(parity2, get(parities, 7)); +} + +// The input for the `test_prgen` family of tests comes from a program, named +// `prgen`, that comes with a package of min-cut solvers by Chandra Chekuri, +// Andrew Goldberg, David Karger, Matthew Levine, and Cliff Stein. `prgen` was +// used to generate input graphs and the solvers were used to verify the return +// value of `boost::stoer_wagner_min_cut` on the input graphs. +// +// http://www.columbia.edu/~cs2035/code.html +// +// Note that it is somewhat more difficult to verify the parities because +// "`prgen` graphs" often have several min-cuts. This is why only the cut +// weight of the min-cut is verified. + +// 3 min-cuts +BOOST_AUTO_TEST_CASE(test_prgen_20_70_2) +{ + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef boost::graph_traits::edge_descriptor edge_descriptor; + + std::ifstream ifs((test_dir + "/prgen_input_graphs/prgen_20_70_2.net").c_str()); + undirected_graph g; + boost::read_dimacs_min_cut(g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs); + + std::map component; + boost::associative_property_map > components(component); + BOOST_CHECK_EQUAL(boost::connected_components(g, components), 1U); // verify the connectedness assumption + + BOOST_AUTO(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; + BOOST_AUTO(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); + + int w = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g), boost::max_priority_queue(pq)); + BOOST_CHECK_EQUAL(w, 3407); +} + +// 7 min-cuts +BOOST_AUTO_TEST_CASE(test_prgen_50_40_2) +{ + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef boost::graph_traits::edge_descriptor edge_descriptor; + + std::ifstream ifs((test_dir + "/prgen_input_graphs/prgen_50_40_2.net").c_str()); + undirected_graph g; + boost::read_dimacs_min_cut(g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs); + + std::map component; + boost::associative_property_map > components(component); + BOOST_CHECK_EQUAL(boost::connected_components(g, components), 1U); // verify the connectedness assumption + + int w = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g)); + BOOST_CHECK_EQUAL(w, 10056); +} + +// 6 min-cuts +BOOST_AUTO_TEST_CASE(test_prgen_50_70_2) +{ + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef boost::graph_traits::edge_descriptor edge_descriptor; + + std::ifstream ifs((test_dir + "/prgen_input_graphs/prgen_50_70_2.net").c_str()); + undirected_graph g; + boost::read_dimacs_min_cut(g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs); + + std::map component; + boost::associative_property_map > components(component); + BOOST_CHECK_EQUAL(boost::connected_components(g, components), 1U); // verify the connectedness assumption + + int w = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g)); + BOOST_CHECK_EQUAL(w, 21755); +}