From 30e9f22af49e950ce2a2f886a6c85bb655ffa87b Mon Sep 17 00:00:00 2001 From: Jeremiah Willcock Date: Tue, 29 Mar 2011 18:56:56 +0000 Subject: [PATCH] Merged r67703-67704,68155,69263,69629,69726 from trunk [SVN r70703] --- doc/kolmogorov_max_flow.html | 407 ---------- doc/table_of_contents.html | 5 - include/boost/graph/detail/is_same.hpp | 48 -- include/boost/graph/graph_concepts.hpp | 4 +- include/boost/graph/graph_traits.hpp | 1 + include/boost/graph/kolmogorov_max_flow.hpp | 814 -------------------- test/astar_search_test.cpp | 1 + 7 files changed, 4 insertions(+), 1276 deletions(-) delete mode 100644 doc/kolmogorov_max_flow.html delete mode 100644 include/boost/graph/detail/is_same.hpp delete mode 100644 include/boost/graph/kolmogorov_max_flow.hpp diff --git a/doc/kolmogorov_max_flow.html b/doc/kolmogorov_max_flow.html deleted file mode 100644 index fad87452..00000000 --- a/doc/kolmogorov_max_flow.html +++ /dev/null @@ -1,407 +0,0 @@ - - - - - Boost Graph Library: Boykov-Kolmogorov Maximum Flow - - - - - - - - - -

-C++ Boost -

- - - - - - -
- Warning! This header and its contents are deprecated and - will be removed in a future release. Please update your program to use - boykov_kolmogorov_max_flow - instead. Note that only the name of the algorithm has changed. The template - and function parameters will remain the same. -
- - -

kolmogorov_max_flow -

-
// named parameter version
-template <class Graph, class P, class T, class R>
-typename property_traits<typename property_map<Graph, edge_capacity_t>::const_type>::value_type
-kolmogorov_max_flow(Graph& g,
-   typename graph_traits<Graph>::vertex_descriptor src,
-   typename graph_traits<Graph>::vertex_descriptor sink,
-   const bgl_named_params<P, T, R>& params = all defaults)
-
-// non-named parameter version
-template <class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap, class ReverseEdgeMap,
-          class PredecessorMap, class ColorMap, class DistanceMap, class IndexMap>
-typename property_traits<CapacityEdgeMap>::value_type
-kolmogorov_max_flow(Graph& g,
-       CapacityEdgeMap cap,
-       ResidualCapacityEdgeMap res_cap,
-       ReverseEdgeMap rev_map,
-       PredecessorMap pre_map,
-       ColorMap color,
-       DistanceMap dist,
-       IndexMap idx,
-       typename graph_traits <Graph>::vertex_descriptor src,
-       typename graph_traits <Graph >::vertex_descriptor sink)

-Additional overloaded versions for non-named parameters -are provided (without DistanceMap/ColorMap/DistanceMap; for those -iterator_property_maps with the provided index map are used)

-

The kolmogorov_max_flow() function calculates the maximum -flow of a network. See Section Network -Flow Algorithms for a description of maximum flow. The calculated -maximum flow will be the return value of the function. The function -also calculates the flow values f(u,v) for all (u,v) in -E, which are returned in the form of the residual capacity -r(u,v) = c(u,v) - f(u,v). -

-

Requirements:
The directed graph G=(V,E) that -represents the network must include a reverse edge for every edge in -E. That is, the input graph should be Gin = -(V,{E U ET}). The ReverseEdgeMap argument rev -must map each edge in the original graph to its reverse edge, that is -(u,v) -> (v,u) for all (u,v) in E. -

-

Remarks: While the push-relabel method states that each edge in ET -has to have capacity of 0, the reverse edges for this algorithm ARE -allowed to carry capacities. If there are already reverse edges in -the input Graph G, -those can be used. This can halve the amount of edges and will -noticeably increase the performance.

Algorithm -description:
Kolmogorov's algorithm is a variety of the -augmenting-path algorithm. Standard augmenting path algorithms find -shortest paths from source to sink vertex and augment them by -substracting the bottleneck capacity found on that path from the -residual capacities of each edge and adding it to the total flow. -Additionally the minimum capacity is added to the residual capacity -of the reverse edges. If no more paths in the residual-edge tree are -found, the algorithm terminates. Instead of finding a new shortest -path from source to sink in the graph in each iteration, Kolmogorov's -version keeps the already found paths as follows:

-

The algorithm builds up two search trees, a source-tree and a -sink-tree. Each vertex has a label (stored in ColorMap) to -which tree it belongs and a status-flag if this vertex is active or -passive. In the beginning of the algorithm only the source and the -sink are colored (source==black, sink==white) and have active status. -All other vertices are colored gray. The algorithm consists of three -phases:

-

grow-phase: In this phase active vertices are allowed to -acquire neighbor vertices that are connected through an edge that has -a capacity-value greater than zero. Acquiring means that those vertices -become active and belong now to the search tree of the current -active vertex. If there are no more valid connections to neighbor -vertices, the current vertex becomes passive and the grow phase -continues with the next active vertex. The grow phase terminates if -there are no more active vertices left or a vertex discovers a vertex -from the other search tree through an unsaturated edge. In this case -a path from source to sink is found.

-

augment-phase: This phase augments the path that was found -in the grow phase. First it finds the bottleneck capacity of the -found path, and then it updates the residual-capacity of the edges -from this path by substracting the bottleneck capacity from the -residual capacity. Furthermore the residual capacity of the reverse -edges are updated by adding the bottleneck capacity. This phase can -destroy the built up search trees, as it creates at least one -saturated edge. That means, that the search trees collapse to -forests, because a condition for the search trees is, that each -vertex in them has a valid (=non-saturated) connection to a terminal.

-

adoption-phase: Here the search trees are reconstructed. A -simple solution would be to mark all vertices coming after the first -orphan in the found path free vertices (gray). A more sophisticated -solution is to give those orphans new parents: The neighbor vertices -are checked if they have a valid connection to the same terminal like -this vertex had (a path with unsaturated edges). If there is one, -this vertex becomes the new parent of the current orphan and this -forest is re-included into the search tree. If no new valid parent is -found, this vertex becomes a free vertex (marked gray), and it's -children become orphans. The adoption phase terminates if there are -no more orphans.

-


Details:

- -


Implementation notes:

-

The algorithm is mainly implemented as described in the PhD thesis -of Kolmogorov. Few changes were made for increasing performance:

- -

This algorithm [68, 69] was developed by Boykov and Kolmogorov. -

-

Where Defined

-

boost/graph/kolmogorov_max_flow.hpp -

-

Parameters

-

IN: Graph& g -

-
A directed graph. The graph's type must be a model of -Vertex List Graph, Edge -List Graph and Incidence Graph. -For each edge (u,v) in the graph, the reverse edge (v,u) -must also be in the graph. Performance of the algorithm will be slightly -improved if the graph type also models Adjacency -Matrix. -
-

IN: vertex_descriptor src -

-
The source vertex for the flow network graph. -
-

IN: vertex_descriptor sink -

-
The sink vertex for the flow network graph. -
-

Named Parameters

-

IN: edge_capacity(EdgeCapacityMap cap) -

-
The edge capacity property map. The type must be a model -of a constant Lvalue -Property Map. The key type of the map must be the graph's edge -descriptor type.
Default: get(edge_capacity, g) -
-

OUT: edge_residual_capacity(ResidualCapacityEdgeMap res) -

-
The edge residual capacity property map. The type must be -a model of a mutable Lvalue -Property Map. The key type of the map must be the graph's edge -descriptor type.
Default: get(edge_residual_capacity, -g) -
-

IN: edge_reverse(ReverseEdgeMap rev) -

-
An edge property map that maps every edge (u,v) in -the graph to the reverse edge (v,u). The map must be a model -of constant Lvalue -Property Map. The key type of the map must be the graph's edge -descriptor type.
Default: get(edge_reverse, g) -
-

UTIL: vertex_predecessor(PredecessorMap pre_map) -

-
A vertex property map that stores the edge to the vertex' -predecessor. The map must be a model of mutable Lvalue -Property Map. The key type of the map must be the graph's vertex -descriptor type.
Default: get(vertex_predecessor, g) -
-

OUT/UTIL: vertex_color(ColorMap color) -

-
A vertex property map that stores a color for edge -vertex. If the color of a vertex after running the algorithm is black -the vertex belongs to the source tree else it belongs to the -sink-tree (used for minimum cuts). The map must be a model of mutable -Lvalue Property -Map. The key type of the map must be the graph's vertex -descriptor type.
Default: get(vertex_color, g) -
-

UTIL: vertex_distance(DistanceMap dist) -

-
A vertex property map that stores the distance to the -corresponding terminal. It's a utility-map for speeding up the -algorithm. The map must be a model of mutable Lvalue -Property Map. The key type of the map must be the graph's vertex -descriptor type.
Default: get(vertex_distance, g) -
-

IN: vertex_index(VertexIndexMap index_map) -

-
Maps each vertex of the graph to a unique integer in the -range [0, num_vertices(g)). The map must be a model of -constant LvaluePropertyMap. -The key type of the map must be the graph's vertex descriptor -type.
Default: get(vertex_index, g) -
-

Example

-

This reads an example maximum flow problem (a graph with edge -capacities) from a file in the DIMACS format (example/max_flow.dat). -The source for this example can be found in -example/boykov_kolmogorov-eg.cpp. -

-
#include <boost/config.hpp>
-#include <iostream>
-#include <string>
-#include <boost/graph/kolmogorov_max_flow.hpp>
-#include <boost/graph/adjacency_list.hpp>
-#include <boost/graph/read_dimacs.hpp>
-#include <boost/graph/graph_utility.hpp>
-
-int
-main()
-{
-  using namespace boost;
-
-  typedef adjacency_list_traits < vecS, vecS, directedS > Traits;
-  typedef adjacency_list < vecS, vecS, directedS,
-    property < vertex_name_t, std::string,
-    property < vertex_index_t, long,
-    property < vertex_color_t, boost::default_color_type,
-    property < vertex_distance_t, long,
-    property < vertex_predecessor_t, Traits::edge_descriptor > > > > >,
-
-    property < edge_capacity_t, long,
-    property < edge_residual_capacity_t, long,
-    property < edge_reverse_t, Traits::edge_descriptor > > > > Graph;
-
-  Graph g;
-  property_map < Graph, edge_capacity_t >::type
-      capacity = get(edge_capacity, g);
-  property_map < Graph, edge_residual_capacity_t >::type
-      residual_capacity = get(edge_residual_capacity, g);
-  property_map < Graph, edge_reverse_t >::type rev = get(edge_reverse, g);
-  Traits::vertex_descriptor s, t;
-  read_dimacs_max_flow(g, capacity, rev, s, t);
-
-  std::vector<default_color_type> color(num_vertices(g));
-  std::vector<long> distance(num_vertices(g));
-  long flow = kolmogorov_max_flow(g ,s, t);
-
-  std::cout << "c  The total flow:" << std::endl;
-  std::cout << "s " << flow << std::endl << std::endl;
-
-  std::cout << "c flow values:" << std::endl;
-  graph_traits < Graph >::vertex_iterator u_iter, u_end;
-  graph_traits < Graph >::out_edge_iterator ei, e_end;
-  for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter)
-    for (tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei)
-      if (capacity[*ei] > 0)
-        std::cout << "f " << *u_iter << " " << target(*ei, g) << " "
-          << (capacity[*ei] - residual_capacity[*ei]) << std::endl;
-
-  return EXIT_SUCCESS;
-}

-The output is: -

-
c  The total flow:
-s 13
-
-c flow values:
-f 0 6 3
-f 0 1 0
-f 0 2 10
-f 1 5 1
-f 1 0 0
-f 1 3 0
-f 2 4 4
-f 2 3 6
-f 2 0 0
-f 3 7 5
-f 3 2 0
-f 3 1 1
-f 4 5 4
-f 4 6 0
-f 5 4 0
-f 5 7 5
-f 6 7 3
-f 6 4 0
-f 7 6 0
-f 7 5 0

-See Also

-

edmonds_karp_max_flow(),
push_relabel_max_flow(). -

-
- - - - - -
-

Copyright © 2006

-
-

Stephan Diederich, University - Mannheim(diederich@ti.uni-manheim.de)

-
-



-

- - diff --git a/doc/table_of_contents.html b/doc/table_of_contents.html index da03f48e..db02575c 100644 --- a/doc/table_of_contents.html +++ b/doc/table_of_contents.html @@ -201,11 +201,6 @@
  1. edmonds_karp_max_flow
  2. push_relabel_max_flow -
  3. - kolmogorov_max_flow (Deprecated. - Use boykov_kolmogorov_max_flow - instead.) -
  4. boykov_kolmogorov_max_flow
  5. edmonds_maximum_cardinality_matching
diff --git a/include/boost/graph/detail/is_same.hpp b/include/boost/graph/detail/is_same.hpp deleted file mode 100644 index 07330d30..00000000 --- a/include/boost/graph/detail/is_same.hpp +++ /dev/null @@ -1,48 +0,0 @@ -//======================================================================= -// Copyright 1997, 1998, 1999, 2000 University of Notre Dame. -// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek -// -// 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) -//======================================================================= -#ifndef BOOST_GRAPH_DETAIL_IS_SAME_HPP -#define BOOST_GRAPH_DETAIL_IS_SAME_HPP - -// Deprecate the use of this header. -// TODO: Remove this file from trunk/release in 1.41/1.42. -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__) -# pragma message ("Warning: This header is deprecated. Please use: boost/type_traits/is_same.hpp") -#elif defined(__GNUC__) || defined(__HP_aCC) || defined(__SUNPRO_CC) || defined(__IBMCPP__) -# warning "This header is deprecated. Please use: boost/type_traits/is_same.hpp" -#endif - -#include - -namespace boost { - struct false_tag; - struct true_tag; - - namespace graph_detail { - -#if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template - struct is_same { - typedef boost::false_tag is_same_tag; - }; - template - struct is_same { - typedef boost::true_tag is_same_tag; - }; -#else - template - struct is_same { - enum { Unum = U::num, Vnum = V::num }; - typedef typename mpl::if_c< (Unum == Vnum), - boost::true_tag, boost::false_tag>::type is_same_tag; - }; -#endif - } // namespace graph_detail -} // namespace boost - -#endif diff --git a/include/boost/graph/graph_concepts.hpp b/include/boost/graph/graph_concepts.hpp index 7c2b2795..f382edf7 100644 --- a/include/boost/graph/graph_concepts.hpp +++ b/include/boost/graph/graph_concepts.hpp @@ -342,7 +342,7 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); } G g; typename graph_traits::vertex_descriptor v; - typename vertex_property::type vp; + typename vertex_property_type::type vp; }; BOOST_concept(EdgeMutablePropertyGraph,(G)) @@ -356,7 +356,7 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); G g; std::pair p; typename graph_traits::vertex_descriptor u, v; - typename edge_property::type ep; + typename edge_property_type::type ep; }; BOOST_concept(AdjacencyMatrix,(G)) diff --git a/include/boost/graph/graph_traits.hpp b/include/boost/graph/graph_traits.hpp index 257438f5..fad82f9d 100644 --- a/include/boost/graph/graph_traits.hpp +++ b/include/boost/graph/graph_traits.hpp @@ -12,6 +12,7 @@ #include #include +#include /* Primarily for std::pair */ #include #include #include diff --git a/include/boost/graph/kolmogorov_max_flow.hpp b/include/boost/graph/kolmogorov_max_flow.hpp deleted file mode 100644 index 035a60ea..00000000 --- a/include/boost/graph/kolmogorov_max_flow.hpp +++ /dev/null @@ -1,814 +0,0 @@ -// Copyright (c) 2006, Stephan Diederich -// -// This code may be used under either of the following two licences: -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE. -// -// Or: -// -// 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) - -#ifndef BOOST_KOLMOGOROV_MAX_FLOW_HPP -#define BOOST_KOLMOGOROV_MAX_FLOW_HPP - -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__) -# pragma message ("The kolmogorov_max_flow.hpp header is deprecated and will be removed in Boost 1.47. Use boykov_kolmogorov_max_flow.hpp instead.") -#elif defined(__GNUC__) || defined(__HP_aCC) || defined(__SUNPRO_CC) || defined(__IBMCPP__) -# warning "The kolmogorov_max_flow.hpp header is deprecated and will be removed in Boost 1.47. Use boykov_kolmogorov_max_flow.hpp instead." -#endif - -#include -#include -#include -#include -#include -#include -#include // for std::min and std::max - -#include -#include -#include -#include -#include -#include -#include - -namespace boost { - namespace detail { - - template - class kolmogorov{ - typedef typename property_traits::value_type tEdgeVal; - typedef graph_traits tGraphTraits; - typedef typename tGraphTraits::vertex_iterator vertex_iterator; - typedef typename tGraphTraits::vertex_descriptor vertex_descriptor; - typedef typename tGraphTraits::edge_descriptor edge_descriptor; - typedef typename tGraphTraits::edge_iterator edge_iterator; - typedef typename tGraphTraits::out_edge_iterator out_edge_iterator; - typedef boost::queue tQueue; //queue of vertices, used in adoption-stage - typedef typename property_traits::value_type tColorValue; - typedef color_traits tColorTraits; - typedef typename property_traits::value_type tDistanceVal; - - public: - kolmogorov(Graph& g, - EdgeCapacityMap cap, - ResidualCapacityEdgeMap res, - ReverseEdgeMap rev, - PredecessorMap pre, - ColorMap color, - DistanceMap dist, - IndexMap idx, - vertex_descriptor src, - vertex_descriptor sink): - m_g(g), - m_index_map(idx), - m_cap_map(cap), - m_res_cap_map(res), - m_rev_edge_map(rev), - m_pre_map(pre), - m_tree_map(color), - m_dist_map(dist), - m_source(src), - m_sink(sink), - m_active_nodes(), - m_in_active_list_vec(num_vertices(g), false), - m_in_active_list_map(make_iterator_property_map(m_in_active_list_vec.begin(), m_index_map)), - m_has_parent_vec(num_vertices(g), false), - m_has_parent_map(make_iterator_property_map(m_has_parent_vec.begin(), m_index_map)), - m_time_vec(num_vertices(g), 0), - m_time_map(make_iterator_property_map(m_time_vec.begin(), m_index_map)), - m_flow(0), - m_time(1), - m_last_grow_vertex(graph_traits::null_vertex()){ - // initialize the color-map with gray-values - vertex_iterator vi, v_end; - for(boost::tie(vi, v_end) = vertices(m_g); vi != v_end; ++vi){ - set_tree(*vi, tColorTraits::gray()); - } - // Initialize flow to zero which means initializing - // the residual capacity equal to the capacity - edge_iterator ei, e_end; - for(boost::tie(ei, e_end) = edges(m_g); ei != e_end; ++ei) { - m_res_cap_map[*ei] = m_cap_map[*ei]; - assert(m_rev_edge_map[m_rev_edge_map[*ei]] == *ei); //check if the reverse edge map is build up properly - } - //init the search trees with the two terminals - set_tree(m_source, tColorTraits::black()); - set_tree(m_sink, tColorTraits::white()); - m_time_map[m_source] = 1; - m_time_map[m_sink] = 1; - } - - ~kolmogorov(){} - - tEdgeVal max_flow(){ - //augment direct paths from SOURCE->SINK and SOURCE->VERTEX->SINK - augment_direct_paths(); - //start the main-loop - while(true){ - bool path_found; - edge_descriptor connecting_edge; - boost::tie(connecting_edge, path_found) = grow(); //find a path from source to sink - if(!path_found){ - //we're finished, no more paths were found - break; - } - ++m_time; - augment(connecting_edge); //augment that path - adopt(); //rebuild search tree structure - } - return m_flow; - } - - //the complete class is protected, as we want access to members in derived test-class (see $(BOOST_ROOT)/libs/graph/test/kolmogorov_max_flow_test.cpp) - protected: - void augment_direct_paths(){ - //in a first step, we augment all direct paths from source->NODE->sink - //and additionally paths from source->sink - //this improves especially graphcuts for segmentation, as most of the nodes have source/sink connects - //but shouldn't have an impact on other maxflow problems (this is done in grow() anyway) - out_edge_iterator ei, e_end; - for(boost::tie(ei, e_end) = out_edges(m_source, m_g); ei != e_end; ++ei){ - edge_descriptor from_source = *ei; - vertex_descriptor current_node = target(from_source, m_g); - if(current_node == m_sink){ - tEdgeVal cap = m_res_cap_map[from_source]; - m_res_cap_map[from_source] = 0; - m_flow += cap; - continue; - } - edge_descriptor to_sink; - bool is_there; - boost::tie(to_sink, is_there) = lookup_edge(current_node, m_sink, m_g); - if(is_there){ - tEdgeVal cap_from_source = m_res_cap_map[from_source]; - tEdgeVal cap_to_sink = m_res_cap_map[to_sink]; - if(cap_from_source > cap_to_sink){ - set_tree(current_node, tColorTraits::black()); - add_active_node(current_node); - set_edge_to_parent(current_node, from_source); - m_dist_map[current_node] = 1; - m_time_map[current_node] = 1; - //add stuff to flow and update residuals - //we dont need to update reverse_edges, as incoming/outgoing edges to/from source/sink don't count for max-flow - m_res_cap_map[from_source] -= cap_to_sink; - m_res_cap_map[to_sink] = 0; - m_flow += cap_to_sink; - } else if(cap_to_sink > 0){ - set_tree(current_node, tColorTraits::white()); - add_active_node(current_node); - set_edge_to_parent(current_node, to_sink); - m_dist_map[current_node] = 1; - m_time_map[current_node] = 1; - //add stuff to flow and update residuals - //we dont need to update reverse_edges, as incoming/outgoing edges to/from source/sink don't count for max-flow - m_res_cap_map[to_sink] -= cap_from_source; - m_res_cap_map[from_source] = 0; - m_flow += cap_from_source; - } - } else if(m_res_cap_map[from_source]){ - //there is no sink connect, so we can't augment this path - //but to avoid adding m_source to the active nodes, we just activate this node and set the approciate things - set_tree(current_node, tColorTraits::black()); - set_edge_to_parent(current_node, from_source); - m_dist_map[current_node] = 1; - m_time_map[current_node] = 1; - add_active_node(current_node); - } - } - for(boost::tie(ei, e_end) = out_edges(m_sink, m_g); ei != e_end; ++ei){ - edge_descriptor to_sink = m_rev_edge_map[*ei]; - vertex_descriptor current_node = source(to_sink, m_g); - if(m_res_cap_map[to_sink]){ - set_tree(current_node, tColorTraits::white()); - set_edge_to_parent(current_node, to_sink); - m_dist_map[current_node] = 1; - m_time_map[current_node] = 1; - add_active_node(current_node); - } - } - } - - /** - * returns a pair of an edge and a boolean. if the bool is true, the edge is a connection of a found path from s->t , read "the link" and - * source(returnVal, m_g) is the end of the path found in the source-tree - * target(returnVal, m_g) is the beginning of the path found in the sink-tree - */ - std::pair grow(){ - assert(m_orphans.empty()); - vertex_descriptor current_node; - while((current_node = get_next_active_node()) != graph_traits::null_vertex()){ //if there is one - assert(get_tree(current_node) != tColorTraits::gray() && (has_parent(current_node) || current_node==m_source || current_node==m_sink)); - if(get_tree(current_node) == tColorTraits::black()){ - //source tree growing - out_edge_iterator ei, e_end; - if(current_node != m_last_grow_vertex){ - m_last_grow_vertex = current_node; - boost::tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g); - } - for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it){ - edge_descriptor out_edge = *m_last_grow_edge_it; - if(m_res_cap_map[out_edge] > 0){ //check if we have capacity left on this edge - vertex_descriptor other_node = target(out_edge, m_g); - if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node - set_tree(other_node, tColorTraits::black()); //aquire other node to our search tree - set_edge_to_parent(other_node, out_edge); //set us as parent - m_dist_map[other_node] = m_dist_map[current_node] + 1; //and update the distance-heuristic - m_time_map[other_node] = m_time_map[current_node]; - add_active_node(other_node); - } else if(get_tree(other_node) == tColorTraits::black()){ - if(is_closer_to_terminal(current_node, other_node)){ //we do this to get shorter paths. check if we are nearer to the source as its parent is - set_edge_to_parent(other_node, out_edge); - m_dist_map[other_node] = m_dist_map[current_node] + 1; - m_time_map[other_node] = m_time_map[current_node]; - } - } else{ - assert(get_tree(other_node)==tColorTraits::white()); - //kewl, found a path from one to the other search tree, return the connecting edge in src->sink dir - return std::make_pair(out_edge, true); - } - } - } //for all out-edges - } //source-tree-growing - else{ - assert(get_tree(current_node) == tColorTraits::white()); - out_edge_iterator ei, e_end; - if(current_node != m_last_grow_vertex){ - m_last_grow_vertex = current_node; - boost::tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g); - } - for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it){ - edge_descriptor in_edge = m_rev_edge_map[*m_last_grow_edge_it]; - if(m_res_cap_map[in_edge] > 0){ //check if there is capacity left - vertex_descriptor other_node = source(in_edge, m_g); - if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node - set_tree(other_node, tColorTraits::white()); //aquire that node to our search tree - set_edge_to_parent(other_node, in_edge); //set us as parent - add_active_node(other_node); //activate that node - m_dist_map[other_node] = m_dist_map[current_node] + 1; //set its distance - m_time_map[other_node] = m_time_map[current_node]; //and time - } else if(get_tree(other_node) == tColorTraits::white()){ - if(is_closer_to_terminal(current_node, other_node)){ - //we are closer to the sink than its parent is, so we "adopt" him - set_edge_to_parent(other_node, in_edge); - m_dist_map[other_node] = m_dist_map[current_node] + 1; - m_time_map[other_node] = m_time_map[current_node]; - } - } else{ - assert(get_tree(other_node)==tColorTraits::black()); - //kewl, found a path from one to the other search tree, return the connecting edge in src->sink dir - return std::make_pair(in_edge, true); - } - } - } //for all out-edges - } //sink-tree growing - //all edges of that node are processed, and no more paths were found. so remove if from the front of the active queue - finish_node(current_node); - } //while active_nodes not empty - return std::make_pair(edge_descriptor(), false); //no active nodes anymore and no path found, we're done - } - - /** - * augments path from s->t and updates residual graph - * source(e, m_g) is the end of the path found in the source-tree - * target(e, m_g) is the beginning of the path found in the sink-tree - * this phase generates orphans on satured edges, if the attached verts are from different search-trees - * orphans are ordered in distance to sink/source. first the farest from the source are front_inserted into the orphans list, - * and after that the sink-tree-orphans are front_inserted. when going to adoption stage the orphans are popped_front, and so we process the nearest - * verts to the terminals first - */ - void augment(edge_descriptor e){ - assert(get_tree(target(e, m_g)) == tColorTraits::white()); - assert(get_tree(source(e, m_g)) == tColorTraits::black()); - assert(m_orphans.empty()); - - const tEdgeVal bottleneck = find_bottleneck(e); - //now we push the found flow through the path - //for each edge we saturate we have to look for the verts that belong to that edge, one of them becomes an orphans - //now process the connecting edge - m_res_cap_map[e] -= bottleneck; - assert(m_res_cap_map[e] >= 0); - m_res_cap_map[m_rev_edge_map[e]] += bottleneck; - - //now we follow the path back to the source - vertex_descriptor current_node = source(e, m_g); - while(current_node != m_source){ - edge_descriptor pred = get_edge_to_parent(current_node); - m_res_cap_map[pred] -= bottleneck; - assert(m_res_cap_map[pred] >= 0); - m_res_cap_map[m_rev_edge_map[pred]] += bottleneck; - if(m_res_cap_map[pred] == 0){ - set_no_parent(current_node); - m_orphans.push_front(current_node); - } - current_node = source(pred, m_g); - } - //then go forward in the sink-tree - current_node = target(e, m_g); - while(current_node != m_sink){ - edge_descriptor pred = get_edge_to_parent(current_node); - m_res_cap_map[pred] -= bottleneck; - assert(m_res_cap_map[pred] >= 0); - m_res_cap_map[m_rev_edge_map[pred]] += bottleneck; - if(m_res_cap_map[pred] == 0){ - set_no_parent(current_node); - m_orphans.push_front(current_node); - } - current_node = target(pred, m_g); - } - //and add it to the max-flow - m_flow += bottleneck; - } - - /** - * returns the bottleneck of a s->t path (end_of_path is last vertex in source-tree, begin_of_path is first vertex in sink-tree) - */ - inline tEdgeVal find_bottleneck(edge_descriptor e){ - BOOST_USING_STD_MIN(); - tEdgeVal minimum_cap = m_res_cap_map[e]; - vertex_descriptor current_node = source(e, m_g); - //first go back in the source tree - while(current_node != m_source){ - edge_descriptor pred = get_edge_to_parent(current_node); - minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, m_res_cap_map[pred]); - current_node = source(pred, m_g); - } - //then go forward in the sink-tree - current_node = target(e, m_g); - while(current_node != m_sink){ - edge_descriptor pred = get_edge_to_parent(current_node); - minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, m_res_cap_map[pred]); - current_node = target(pred, m_g); - } - return minimum_cap; - } - - /** - * rebuild search trees - * empty the queue of orphans, and find new parents for them or just drop them from the search trees - */ - void adopt(){ - while(!m_orphans.empty() || !m_child_orphans.empty()){ - vertex_descriptor current_node; - if(m_child_orphans.empty()){ - //get the next orphan from the main-queue and remove it - current_node = m_orphans.front(); - m_orphans.pop_front(); - } else{ - current_node = m_child_orphans.front(); - m_child_orphans.pop(); - } - if(get_tree(current_node) == tColorTraits::black()){ - //we're in the source-tree - tDistanceVal min_distance = (std::numeric_limits::max)(); - edge_descriptor new_parent_edge; - out_edge_iterator ei, e_end; - for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){ - const edge_descriptor in_edge = m_rev_edge_map[*ei]; - assert(target(in_edge, m_g) == current_node); //we should be the target of this edge - if(m_res_cap_map[in_edge] > 0){ - vertex_descriptor other_node = source(in_edge, m_g); - if(get_tree(other_node) == tColorTraits::black() && has_source_connect(other_node)){ - if(m_dist_map[other_node] < min_distance){ - min_distance = m_dist_map[other_node]; - new_parent_edge = in_edge; - } - } - } - } - if(min_distance != (std::numeric_limits::max)()){ - set_edge_to_parent(current_node, new_parent_edge); - m_dist_map[current_node] = min_distance + 1; - m_time_map[current_node] = m_time; - } else{ - m_time_map[current_node] = 0; - for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){ - edge_descriptor in_edge = m_rev_edge_map[*ei]; - vertex_descriptor other_node = source(in_edge, m_g); - if(get_tree(other_node) == tColorTraits::black() && has_parent(other_node)){ - if(m_res_cap_map[in_edge] > 0){ - add_active_node(other_node); - } - if(source(get_edge_to_parent(other_node), m_g) == current_node){ - //we are the parent of that node - //it has to find a new parent, too - set_no_parent(other_node); - m_child_orphans.push(other_node); - } - } - } - set_tree(current_node, tColorTraits::gray()); - } //no parent found - } //source-tree-adoption - else{ - //now we should be in the sink-tree, check that... - assert(get_tree(current_node) == tColorTraits::white()); - out_edge_iterator ei, e_end; - edge_descriptor new_parent_edge; - tDistanceVal min_distance = (std::numeric_limits::max)(); - for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){ - const edge_descriptor out_edge = *ei; - if(m_res_cap_map[out_edge] > 0){ - const vertex_descriptor other_node = target(out_edge, m_g); - if(get_tree(other_node) == tColorTraits::white() && has_sink_connect(other_node)) - if(m_dist_map[other_node] < min_distance){ - min_distance = m_dist_map[other_node]; - new_parent_edge = out_edge; - } - } - } - if(min_distance != (std::numeric_limits::max)()){ - set_edge_to_parent(current_node, new_parent_edge); - m_dist_map[current_node] = min_distance + 1; - m_time_map[current_node] = m_time; - } else{ - m_time_map[current_node] = 0; - for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){ - const edge_descriptor out_edge = *ei; - const vertex_descriptor other_node = target(out_edge, m_g); - if(get_tree(other_node) == tColorTraits::white() && has_parent(other_node)){ - if(m_res_cap_map[out_edge] > 0){ - add_active_node(other_node); - } - if(target(get_edge_to_parent(other_node), m_g) == current_node){ - //we were it's parent, so it has to find a new one, too - set_no_parent(other_node); - m_child_orphans.push(other_node); - } - } - } - set_tree(current_node, tColorTraits::gray()); - } //no parent found - } //sink-tree adoption - } //while !orphans.empty() - } //adopt - - /** - * return next active vertex if there is one, otherwise a null_vertex - */ - inline vertex_descriptor get_next_active_node(){ - while(true){ - if(m_active_nodes.empty()) - return graph_traits::null_vertex(); - vertex_descriptor v = m_active_nodes.front(); - - if(!has_parent(v) && v != m_source && v != m_sink){ //if it has no parent, this node can't be active(if its not source or sink) - m_active_nodes.pop(); - m_in_active_list_map[v] = false; - } else{ - assert(get_tree(v) == tColorTraits::black() || get_tree(v) == tColorTraits::white()); - return v; - } - } - } - - /** - * adds v as an active vertex, but only if its not in the list already - */ - inline void add_active_node(vertex_descriptor v){ - assert(get_tree(v) != tColorTraits::gray()); - if(m_in_active_list_map[v]){ - return; - } else{ - m_in_active_list_map[v] = true; - m_active_nodes.push(v); - } - } - - /** - * finish_node removes a node from the front of the active queue (its called in grow phase, if no more paths can be found using this node) - */ - inline void finish_node(vertex_descriptor v){ - assert(m_active_nodes.front() == v); - m_active_nodes.pop(); - m_in_active_list_map[v] = false; - m_last_grow_vertex = graph_traits::null_vertex(); - } - - /** - * removes a vertex from the queue of active nodes (actually this does nothing, - * but checks if this node has no parent edge, as this is the criteria for beeing no more active) - */ - inline void remove_active_node(vertex_descriptor v){ - assert(!has_parent(v)); - } - - /** - * returns the search tree of v; tColorValue::black() for source tree, white() for sink tree, gray() for no tree - */ - inline tColorValue get_tree(vertex_descriptor v) const { - return m_tree_map[v]; - } - - /** - * sets search tree of v; tColorValue::black() for source tree, white() for sink tree, gray() for no tree - */ - inline void set_tree(vertex_descriptor v, tColorValue t){ - m_tree_map[v] = t; - } - - /** - * returns edge to parent vertex of v; - */ - inline edge_descriptor get_edge_to_parent(vertex_descriptor v) const{ - return m_pre_map[v]; - } - - /** - * returns true if the edge stored in m_pre_map[v] is a valid entry - */ - inline bool has_parent(vertex_descriptor v) const{ - return m_has_parent_map[v]; - } - - /** - * sets edge to parent vertex of v; - */ - inline void set_edge_to_parent(vertex_descriptor v, edge_descriptor f_edge_to_parent){ - assert(m_res_cap_map[f_edge_to_parent] > 0); - m_pre_map[v] = f_edge_to_parent; - m_has_parent_map[v] = true; - } - - /** - * removes the edge to parent of v (this is done by invalidating the entry an additional map) - */ - inline void set_no_parent(vertex_descriptor v){ - m_has_parent_map[v] = false; - } - - /** - * checks if vertex v has a connect to the sink-vertex (@var m_sink) - * @param v the vertex which is checked - * @return true if a path to the sink was found, false if not - */ - inline bool has_sink_connect(vertex_descriptor v){ - tDistanceVal current_distance = 0; - vertex_descriptor current_vertex = v; - while(true){ - if(m_time_map[current_vertex] == m_time){ - //we found a node which was already checked this round. use it for distance calculations - current_distance += m_dist_map[current_vertex]; - break; - } - if(current_vertex == m_sink){ - m_time_map[m_sink] = m_time; - break; - } - if(has_parent(current_vertex)){ - //it has a parent, so get it - current_vertex = target(get_edge_to_parent(current_vertex), m_g); - ++current_distance; - } else{ - //no path found - return false; - } - } - current_vertex=v; - while(m_time_map[current_vertex] != m_time){ - m_dist_map[current_vertex] = current_distance--; - m_time_map[current_vertex] = m_time; - current_vertex = target(get_edge_to_parent(current_vertex), m_g); - } - return true; - } - - /** - * checks if vertex v has a connect to the source-vertex (@var m_source) - * @param v the vertex which is checked - * @return true if a path to the source was found, false if not - */ - inline bool has_source_connect(vertex_descriptor v){ - tDistanceVal current_distance = 0; - vertex_descriptor current_vertex = v; - while(true){ - if(m_time_map[current_vertex] == m_time){ - //we found a node which was already checked this round. use it for distance calculations - current_distance += m_dist_map[current_vertex]; - break; - } - if(current_vertex == m_source){ - m_time_map[m_source] = m_time; - break; - } - if(has_parent(current_vertex)){ - //it has a parent, so get it - current_vertex = source(get_edge_to_parent(current_vertex), m_g); - ++current_distance; - } else{ - //no path found - return false; - } - } - current_vertex=v; - while(m_time_map[current_vertex] != m_time){ - m_dist_map[current_vertex] = current_distance-- ; - m_time_map[current_vertex] = m_time; - current_vertex = source(get_edge_to_parent(current_vertex), m_g); - } - return true; - } - - /** - * returns true, if p is closer to a terminal than q - */ - inline bool is_closer_to_terminal(vertex_descriptor p, vertex_descriptor q){ - //checks the timestamps first, to build no cycles, and after that the real distance - return (m_time_map[q] <= m_time_map[p] && m_dist_map[q] > m_dist_map[p]+1); - } - - //////// - // member vars - //////// - Graph& m_g; - IndexMap m_index_map; - EdgeCapacityMap m_cap_map; - ResidualCapacityEdgeMap m_res_cap_map; - ReverseEdgeMap m_rev_edge_map; - PredecessorMap m_pre_map; //stores paths found in the growth stage - ColorMap m_tree_map; //maps each vertex into one of the two search tree or none (gray()) - DistanceMap m_dist_map; //stores distance to source/sink nodes - vertex_descriptor m_source; - vertex_descriptor m_sink; - - tQueue m_active_nodes; - std::vector m_in_active_list_vec; - iterator_property_map::iterator, IndexMap> m_in_active_list_map; - - std::list m_orphans; - tQueue m_child_orphans; // we use a second queuqe for child orphans, as they are FIFO processed - - std::vector m_has_parent_vec; - iterator_property_map::iterator, IndexMap> m_has_parent_map; - - std::vector m_time_vec; //timestamp of each node, used for sink/source-path calculations - iterator_property_map::iterator, IndexMap> m_time_map; - tEdgeVal m_flow; - long m_time; - vertex_descriptor m_last_grow_vertex; - out_edge_iterator m_last_grow_edge_it; - out_edge_iterator m_last_grow_edge_end; - }; - } //namespace detail - - /** - * non-named-parameter version, given everything - * this is the catch all version - */ - template - typename property_traits::value_type - kolmogorov_max_flow - (Graph& g, - CapacityEdgeMap cap, - ResidualCapacityEdgeMap res_cap, - ReverseEdgeMap rev_map, - PredecessorMap pre_map, - ColorMap color, - DistanceMap dist, - IndexMap idx, - typename graph_traits::vertex_descriptor src, - typename graph_traits::vertex_descriptor sink - ) - { - typedef typename graph_traits::vertex_descriptor vertex_descriptor; - typedef typename graph_traits::edge_descriptor edge_descriptor; - //as this method is the last one before we instantiate the solver, we do the concept checks here - function_requires >(); //to have vertices(), num_vertices(), - function_requires >(); //to have edges() - function_requires >(); //to have source(), target() and out_edges() - function_requires >(); //read flow-values from edges - function_requires >(); //write flow-values to residuals - function_requires >(); //read out reverse edges - function_requires >(); //store predecessor there - function_requires >(); //write corresponding tree - function_requires >(); //write distance to source/sink - function_requires >(); //get index 0...|V|-1 - assert(num_vertices(g) >= 2 && src != sink); - detail::kolmogorov - algo(g, cap, res_cap, rev_map, pre_map, color, dist, idx, src, sink); - return algo.max_flow(); - } - - /** - * non-named-parameter version, given: capacity, residucal_capacity, reverse_edges, and an index map. - */ - template - typename property_traits::value_type - kolmogorov_max_flow - (Graph& g, - CapacityEdgeMap cap, - ResidualCapacityEdgeMap res_cap, - ReverseEdgeMap rev, - IndexMap idx, - typename graph_traits::vertex_descriptor src, - typename graph_traits::vertex_descriptor sink) - { - typename graph_traits::vertices_size_type n_verts = num_vertices(g); - std::vector::edge_descriptor> predecessor_vec(n_verts); - std::vector color_vec(n_verts); - std::vector::vertices_size_type> distance_vec(n_verts); - return kolmogorov_max_flow - (g, cap, res_cap, rev, - make_iterator_property_map(predecessor_vec.begin(), idx), - make_iterator_property_map(color_vec.begin(), idx), - make_iterator_property_map(distance_vec.begin(), idx), - idx, src, sink); - } - - /** - * non-named-parameter version, some given: capacity, residual_capacity, reverse_edges, color_map and an index map. - * Use this if you are interested in the minimum cut, as the color map provides that info - */ - template - typename property_traits::value_type - kolmogorov_max_flow - (Graph& g, - CapacityEdgeMap cap, - ResidualCapacityEdgeMap res_cap, - ReverseEdgeMap rev, - ColorMap color, - IndexMap idx, - typename graph_traits::vertex_descriptor src, - typename graph_traits::vertex_descriptor sink) - { - typename graph_traits::vertices_size_type n_verts = num_vertices(g); - std::vector::edge_descriptor> predecessor_vec(n_verts); - std::vector::vertices_size_type> distance_vec(n_verts); - - return kolmogorov_max_flow - (g, cap, res_cap, rev, - make_iterator_property_map(predecessor_vec.begin(), idx), - color, - make_iterator_property_map(distance_vec.begin(), idx), - idx, src, sink); - } - - /** - * named-parameter version, some given - */ - template - typename property_traits::const_type>::value_type - kolmogorov_max_flow - (Graph& g, - typename graph_traits::vertex_descriptor src, - typename graph_traits::vertex_descriptor sink, - const bgl_named_params& params) - { - return kolmogorov_max_flow(g, - choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity), - choose_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity), - choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse), - choose_pmap(get_param(params, vertex_predecessor), g, vertex_predecessor), - choose_pmap(get_param(params, vertex_color), g, vertex_color), - choose_pmap(get_param(params, vertex_distance), g, vertex_distance), - choose_const_pmap(get_param(params, vertex_index), g, vertex_index), - src, sink); - } - - /** - * named-parameter version, none given - */ - template - typename property_traits::const_type>::value_type - kolmogorov_max_flow - (Graph& g, - typename graph_traits::vertex_descriptor src, - typename graph_traits::vertex_descriptor sink) - { - bgl_named_params params(0); // bogus empty param - return kolmogorov_max_flow(g, src, sink, params); - } -} // namespace boost - -#endif // BOOST_KOLMOGOROV_MAX_FLOW_HPP - diff --git a/test/astar_search_test.cpp b/test/astar_search_test.cpp index 36fb0a47..b108bcb2 100644 --- a/test/astar_search_test.cpp +++ b/test/astar_search_test.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include