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
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-  |
-
- 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:
-
- Marking heuristics: A timestamp is stored for each vertex
- which shows in which iteration of the algorithm the distance to the
- corresponding terminal was calculated.
-
-
- This distance is used and gets calculated in the
- adoption-phase. In order to find a valid new parent for an orphan,
- the possible parent is checked for a connection to the terminal to
- which tree it belongs. If there is such a connection, the path is
- tagged with the current time-stamp, and the distance value. If
- another orphan has to find a parent and it comes across a vertex
- with a current timestamp, this information is used.
- The distance is also used in the grow-phase. If a vertex
- comes across another vertex of the same tree while searching for
- new vertices, the other's distance is compared to its distance. If
- it is smaller, that other vertex becomes the new parent of the
- current. This can decrease the length of the search paths, and so
- amount of adoptions.
-
- Ordering of orphans: As described above, the augment-phase
- and the adoption phase can create orphans. The orphans the
- augment-phase generates, are ordered according to their distance to
- the terminals (smallest first). This combined with the
- distance/timestamp heuristics results in the possibility for not
- having to recheck terminal-connections too often. New orphans which
- are generated in adoption phase are processed before orphans from
- the main queue for the same reason.
-
-
Implementation notes:
-The algorithm is mainly implemented as described in the PhD thesis
-of Kolmogorov. Few changes were made for increasing performance:
-
- initialization: the algorithm first augments all paths from
- source->sink and all paths from source->VERTEX->sink. This
- improves especially graph-cuts used in image vision where nearly
- each vertex has a source and sink connect. During this step, all
- vertices that have an unsaturated connection from source are added
- to the active vertex list and so the source is not.
-
- active vertices: Kolmogorov uses two lists for active nodes
- and states that new active vertices are added to the rear of the
- second. Fetching an active vertex is done from the beginning of the
- first list. If the first list is empty, it is exchanged by the
- second. This implementation uses just one list.
- grow-phase: In the grow phase the first vertex in the
- active-list is taken and all outgoing edges are checked if they are
- unsaturated. This decreases performance for graphs with high-edge
- density. This implementation stores the last accessed edge and
- continues with it, if the first vertex in the active-list is the
- same one as during the last grow-phase.
-
-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().
-
-
-
-
-
-
-
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 @@
- edmonds_karp_max_flow
- push_relabel_max_flow
-
-
- kolmogorov_max_flow (Deprecated.
- Use boykov_kolmogorov_max_flow
- instead.)
-
- boykov_kolmogorov_max_flow
- 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