123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860 |
- //=======================================================================
- // Copyright 2000 University of Notre Dame.
- // Authors: Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee
- //
- // 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_PUSH_RELABEL_MAX_FLOW_HPP
- #define BOOST_PUSH_RELABEL_MAX_FLOW_HPP
- #include <boost/config.hpp>
- #include <boost/assert.hpp>
- #include <vector>
- #include <list>
- #include <iosfwd>
- #include <algorithm> // for std::min and std::max
- #include <boost/pending/queue.hpp>
- #include <boost/limits.hpp>
- #include <boost/graph/graph_concepts.hpp>
- #include <boost/graph/named_function_params.hpp>
- namespace boost
- {
- namespace detail
- {
- // This implementation is based on Goldberg's
- // "On Implementing Push-Relabel Method for the Maximum Flow Problem"
- // by B.V. Cherkassky and A.V. Goldberg, IPCO '95, pp. 157--171
- // and on the h_prf.c and hi_pr.c code written by the above authors.
- // This implements the highest-label version of the push-relabel method
- // with the global relabeling and gap relabeling heuristics.
- // The terms "rank", "distance", "height" are synonyms in
- // Goldberg's implementation, paper and in the CLR. A "layer" is a
- // group of vertices with the same distance. The vertices in each
- // layer are categorized as active or inactive. An active vertex
- // has positive excess flow and its distance is less than n (it is
- // not blocked).
- template < class Vertex > struct preflow_layer
- {
- std::list< Vertex > active_vertices;
- std::list< Vertex > inactive_vertices;
- };
- template < class Graph,
- class EdgeCapacityMap, // integer value type
- class ResidualCapacityEdgeMap, class ReverseEdgeMap,
- class VertexIndexMap, // vertex_descriptor -> integer
- class FlowValue >
- class push_relabel
- {
- public:
- typedef graph_traits< Graph > Traits;
- typedef typename Traits::vertex_descriptor vertex_descriptor;
- typedef typename Traits::edge_descriptor edge_descriptor;
- typedef typename Traits::vertex_iterator vertex_iterator;
- typedef typename Traits::out_edge_iterator out_edge_iterator;
- typedef typename Traits::vertices_size_type vertices_size_type;
- typedef typename Traits::edges_size_type edges_size_type;
- typedef preflow_layer< vertex_descriptor > Layer;
- typedef std::vector< Layer > LayerArray;
- typedef typename LayerArray::iterator layer_iterator;
- typedef typename LayerArray::size_type distance_size_type;
- typedef color_traits< default_color_type > ColorTraits;
- //=======================================================================
- // Some helper predicates
- inline bool is_admissible(vertex_descriptor u, vertex_descriptor v)
- {
- return get(distance, u) == get(distance, v) + 1;
- }
- inline bool is_residual_edge(edge_descriptor a)
- {
- return 0 < get(residual_capacity, a);
- }
- inline bool is_saturated(edge_descriptor a)
- {
- return get(residual_capacity, a) == 0;
- }
- //=======================================================================
- // Layer List Management Functions
- typedef typename std::list< vertex_descriptor >::iterator list_iterator;
- void add_to_active_list(vertex_descriptor u, Layer& layer)
- {
- BOOST_USING_STD_MIN();
- BOOST_USING_STD_MAX();
- layer.active_vertices.push_front(u);
- max_active = max BOOST_PREVENT_MACRO_SUBSTITUTION(
- get(distance, u), max_active);
- min_active = min BOOST_PREVENT_MACRO_SUBSTITUTION(
- get(distance, u), min_active);
- layer_list_ptr[u] = layer.active_vertices.begin();
- }
- void remove_from_active_list(vertex_descriptor u)
- {
- layers[get(distance, u)].active_vertices.erase(layer_list_ptr[u]);
- }
- void add_to_inactive_list(vertex_descriptor u, Layer& layer)
- {
- layer.inactive_vertices.push_front(u);
- layer_list_ptr[u] = layer.inactive_vertices.begin();
- }
- void remove_from_inactive_list(vertex_descriptor u)
- {
- layers[get(distance, u)].inactive_vertices.erase(layer_list_ptr[u]);
- }
- //=======================================================================
- // initialization
- push_relabel(Graph& g_, EdgeCapacityMap cap,
- ResidualCapacityEdgeMap res, ReverseEdgeMap rev,
- vertex_descriptor src_, vertex_descriptor sink_, VertexIndexMap idx)
- : g(g_)
- , n(num_vertices(g_))
- , capacity(cap)
- , src(src_)
- , sink(sink_)
- , index(idx)
- , excess_flow_data(num_vertices(g_))
- , excess_flow(excess_flow_data.begin(), idx)
- , current_data(num_vertices(g_), out_edges(*vertices(g_).first, g_))
- , current(current_data.begin(), idx)
- , distance_data(num_vertices(g_))
- , distance(distance_data.begin(), idx)
- , color_data(num_vertices(g_))
- , color(color_data.begin(), idx)
- , reverse_edge(rev)
- , residual_capacity(res)
- , layers(num_vertices(g_))
- , layer_list_ptr_data(
- num_vertices(g_), layers.front().inactive_vertices.end())
- , layer_list_ptr(layer_list_ptr_data.begin(), idx)
- , push_count(0)
- , update_count(0)
- , relabel_count(0)
- , gap_count(0)
- , gap_node_count(0)
- , work_since_last_update(0)
- {
- vertex_iterator u_iter, u_end;
- // Don't count the reverse edges
- edges_size_type m = num_edges(g) / 2;
- nm = alpha() * n + m;
- // Initialize flow to zero which means initializing
- // the residual capacity to equal the capacity.
- out_edge_iterator ei, e_end;
- for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
- ++u_iter)
- for (boost::tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end;
- ++ei)
- {
- put(residual_capacity, *ei, get(capacity, *ei));
- }
- for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
- ++u_iter)
- {
- vertex_descriptor u = *u_iter;
- put(excess_flow, u, 0);
- current[u] = out_edges(u, g);
- }
- bool overflow_detected = false;
- FlowValue test_excess = 0;
- out_edge_iterator a_iter, a_end;
- for (boost::tie(a_iter, a_end) = out_edges(src, g); a_iter != a_end;
- ++a_iter)
- if (target(*a_iter, g) != src)
- test_excess += get(residual_capacity, *a_iter);
- if (test_excess > (std::numeric_limits< FlowValue >::max)())
- overflow_detected = true;
- if (overflow_detected)
- put(excess_flow, src,
- (std::numeric_limits< FlowValue >::max)());
- else
- {
- put(excess_flow, src, 0);
- for (boost::tie(a_iter, a_end) = out_edges(src, g);
- a_iter != a_end; ++a_iter)
- {
- edge_descriptor a = *a_iter;
- vertex_descriptor tgt = target(a, g);
- if (tgt != src)
- {
- ++push_count;
- FlowValue delta = get(residual_capacity, a);
- put(residual_capacity, a,
- get(residual_capacity, a) - delta);
- edge_descriptor rev = get(reverse_edge, a);
- put(residual_capacity, rev,
- get(residual_capacity, rev) + delta);
- put(excess_flow, tgt, get(excess_flow, tgt) + delta);
- }
- }
- }
- max_distance = num_vertices(g) - 1;
- max_active = 0;
- min_active = n;
- for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
- ++u_iter)
- {
- vertex_descriptor u = *u_iter;
- if (u == sink)
- {
- put(distance, u, 0);
- continue;
- }
- else if (u == src && !overflow_detected)
- put(distance, u, n);
- else
- put(distance, u, 1);
- if (get(excess_flow, u) > 0)
- add_to_active_list(u, layers[1]);
- else if (get(distance, u) < n)
- add_to_inactive_list(u, layers[1]);
- }
- } // push_relabel constructor
- //=======================================================================
- // This is a breadth-first search over the residual graph
- // (well, actually the reverse of the residual graph).
- // Would be cool to have a graph view adaptor for hiding certain
- // edges, like the saturated (non-residual) edges in this case.
- // Goldberg's implementation abused "distance" for the coloring.
- void global_distance_update()
- {
- BOOST_USING_STD_MAX();
- ++update_count;
- vertex_iterator u_iter, u_end;
- for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
- ++u_iter)
- {
- put(color, *u_iter, ColorTraits::white());
- put(distance, *u_iter, n);
- }
- put(color, sink, ColorTraits::gray());
- put(distance, sink, 0);
- for (distance_size_type l = 0; l <= max_distance; ++l)
- {
- layers[l].active_vertices.clear();
- layers[l].inactive_vertices.clear();
- }
- max_distance = max_active = 0;
- min_active = n;
- Q.push(sink);
- while (!Q.empty())
- {
- vertex_descriptor u = Q.top();
- Q.pop();
- distance_size_type d_v = get(distance, u) + 1;
- out_edge_iterator ai, a_end;
- for (boost::tie(ai, a_end) = out_edges(u, g); ai != a_end; ++ai)
- {
- edge_descriptor a = *ai;
- vertex_descriptor v = target(a, g);
- if (get(color, v) == ColorTraits::white()
- && is_residual_edge(get(reverse_edge, a)))
- {
- put(distance, v, d_v);
- put(color, v, ColorTraits::gray());
- current[v] = out_edges(v, g);
- max_distance = max BOOST_PREVENT_MACRO_SUBSTITUTION(
- d_v, max_distance);
- if (get(excess_flow, v) > 0)
- add_to_active_list(v, layers[d_v]);
- else
- add_to_inactive_list(v, layers[d_v]);
- Q.push(v);
- }
- }
- }
- } // global_distance_update()
- //=======================================================================
- // This function is called "push" in Goldberg's h_prf implementation,
- // but it is called "discharge" in the paper and in hi_pr.c.
- void discharge(vertex_descriptor u)
- {
- BOOST_ASSERT(get(excess_flow, u) > 0);
- while (1)
- {
- out_edge_iterator ai, ai_end;
- for (boost::tie(ai, ai_end) = current[u]; ai != ai_end; ++ai)
- {
- edge_descriptor a = *ai;
- if (is_residual_edge(a))
- {
- vertex_descriptor v = target(a, g);
- if (is_admissible(u, v))
- {
- ++push_count;
- if (v != sink && get(excess_flow, v) == 0)
- {
- remove_from_inactive_list(v);
- add_to_active_list(v, layers[get(distance, v)]);
- }
- push_flow(a);
- if (get(excess_flow, u) == 0)
- break;
- }
- }
- } // for out_edges of i starting from current
- Layer& layer = layers[get(distance, u)];
- distance_size_type du = get(distance, u);
- if (ai == ai_end)
- { // i must be relabeled
- relabel_distance(u);
- if (layer.active_vertices.empty()
- && layer.inactive_vertices.empty())
- gap(du);
- if (get(distance, u) == n)
- break;
- }
- else
- { // i is no longer active
- current[u].first = ai;
- add_to_inactive_list(u, layer);
- break;
- }
- } // while (1)
- } // discharge()
- //=======================================================================
- // This corresponds to the "push" update operation of the paper,
- // not the "push" function in Goldberg's h_prf.c implementation.
- // The idea is to push the excess flow from from vertex u to v.
- void push_flow(edge_descriptor u_v)
- {
- vertex_descriptor u = source(u_v, g), v = target(u_v, g);
- BOOST_USING_STD_MIN();
- FlowValue flow_delta = min BOOST_PREVENT_MACRO_SUBSTITUTION(
- get(excess_flow, u), get(residual_capacity, u_v));
- put(residual_capacity, u_v,
- get(residual_capacity, u_v) - flow_delta);
- edge_descriptor rev = get(reverse_edge, u_v);
- put(residual_capacity, rev,
- get(residual_capacity, rev) + flow_delta);
- put(excess_flow, u, get(excess_flow, u) - flow_delta);
- put(excess_flow, v, get(excess_flow, v) + flow_delta);
- } // push_flow()
- //=======================================================================
- // The main purpose of this routine is to set distance[v]
- // to the smallest value allowed by the valid labeling constraints,
- // which are:
- // distance[t] = 0
- // distance[u] <= distance[v] + 1 for every residual edge (u,v)
- //
- distance_size_type relabel_distance(vertex_descriptor u)
- {
- BOOST_USING_STD_MAX();
- ++relabel_count;
- work_since_last_update += beta();
- distance_size_type min_distance = num_vertices(g);
- put(distance, u, min_distance);
- // Examine the residual out-edges of vertex i, choosing the
- // edge whose target vertex has the minimal distance.
- out_edge_iterator ai, a_end, min_edge_iter;
- for (boost::tie(ai, a_end) = out_edges(u, g); ai != a_end; ++ai)
- {
- ++work_since_last_update;
- edge_descriptor a = *ai;
- vertex_descriptor v = target(a, g);
- if (is_residual_edge(a) && get(distance, v) < min_distance)
- {
- min_distance = get(distance, v);
- min_edge_iter = ai;
- }
- }
- ++min_distance;
- if (min_distance < n)
- {
- put(distance, u, min_distance); // this is the main action
- current[u].first = min_edge_iter;
- max_distance = max BOOST_PREVENT_MACRO_SUBSTITUTION(
- min_distance, max_distance);
- }
- return min_distance;
- } // relabel_distance()
- //=======================================================================
- // cleanup beyond the gap
- void gap(distance_size_type empty_distance)
- {
- ++gap_count;
- distance_size_type r; // distance of layer before the current layer
- r = empty_distance - 1;
- // Set the distance for the vertices beyond the gap to "infinity".
- for (layer_iterator l = layers.begin() + empty_distance + 1;
- l < layers.begin() + max_distance; ++l)
- {
- list_iterator i;
- for (i = l->inactive_vertices.begin();
- i != l->inactive_vertices.end(); ++i)
- {
- put(distance, *i, n);
- ++gap_node_count;
- }
- l->inactive_vertices.clear();
- }
- max_distance = r;
- max_active = r;
- }
- //=======================================================================
- // This is the core part of the algorithm, "phase one".
- FlowValue maximum_preflow()
- {
- work_since_last_update = 0;
- while (max_active >= min_active)
- { // "main" loop
- Layer& layer = layers[max_active];
- list_iterator u_iter = layer.active_vertices.begin();
- if (u_iter == layer.active_vertices.end())
- --max_active;
- else
- {
- vertex_descriptor u = *u_iter;
- remove_from_active_list(u);
- discharge(u);
- if (work_since_last_update * global_update_frequency() > nm)
- {
- global_distance_update();
- work_since_last_update = 0;
- }
- }
- } // while (max_active >= min_active)
- return get(excess_flow, sink);
- } // maximum_preflow()
- //=======================================================================
- // remove excess flow, the "second phase"
- // This does a DFS on the reverse flow graph of nodes with excess flow.
- // If a cycle is found, cancel it.
- // Return the nodes with excess flow in topological order.
- //
- // Unlike the prefl_to_flow() implementation, we use
- // "color" instead of "distance" for the DFS labels
- // "parent" instead of nl_prev for the DFS tree
- // "topo_next" instead of nl_next for the topological ordering
- void convert_preflow_to_flow()
- {
- vertex_iterator u_iter, u_end;
- out_edge_iterator ai, a_end;
- vertex_descriptor r, restart, u;
- std::vector< vertex_descriptor > parent(n);
- std::vector< vertex_descriptor > topo_next(n);
- vertex_descriptor tos(parent[0]),
- bos(parent[0]); // bogus initialization, just to avoid warning
- bool bos_null = true;
- // handle self-loops
- for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
- ++u_iter)
- for (boost::tie(ai, a_end) = out_edges(*u_iter, g); ai != a_end;
- ++ai)
- if (target(*ai, g) == *u_iter)
- put(residual_capacity, *ai, get(capacity, *ai));
- // initialize
- for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
- ++u_iter)
- {
- u = *u_iter;
- put(color, u, ColorTraits::white());
- parent[get(index, u)] = u;
- current[u] = out_edges(u, g);
- }
- // eliminate flow cycles and topologically order the vertices
- for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
- ++u_iter)
- {
- u = *u_iter;
- if (get(color, u) == ColorTraits::white()
- && get(excess_flow, u) > 0 && u != src && u != sink)
- {
- r = u;
- put(color, r, ColorTraits::gray());
- while (1)
- {
- for (; current[u].first != current[u].second;
- ++current[u].first)
- {
- edge_descriptor a = *current[u].first;
- if (get(capacity, a) == 0 && is_residual_edge(a))
- {
- vertex_descriptor v = target(a, g);
- if (get(color, v) == ColorTraits::white())
- {
- put(color, v, ColorTraits::gray());
- parent[get(index, v)] = u;
- u = v;
- break;
- }
- else if (get(color, v) == ColorTraits::gray())
- {
- // find minimum flow on the cycle
- FlowValue delta = get(residual_capacity, a);
- while (1)
- {
- BOOST_USING_STD_MIN();
- delta = min
- BOOST_PREVENT_MACRO_SUBSTITUTION(
- delta,
- get(residual_capacity,
- *current[v].first));
- if (v == u)
- break;
- else
- v = target(*current[v].first, g);
- }
- // remove delta flow units
- v = u;
- while (1)
- {
- a = *current[v].first;
- put(residual_capacity, a,
- get(residual_capacity, a) - delta);
- edge_descriptor rev
- = get(reverse_edge, a);
- put(residual_capacity, rev,
- get(residual_capacity, rev)
- + delta);
- v = target(a, g);
- if (v == u)
- break;
- }
- // back-out of DFS to the first saturated
- // edge
- restart = u;
- for (v = target(*current[u].first, g);
- v != u; v = target(a, g))
- {
- a = *current[v].first;
- if (get(color, v)
- == ColorTraits::white()
- || is_saturated(a))
- {
- put(color,
- target(*current[v].first, g),
- ColorTraits::white());
- if (get(color, v)
- != ColorTraits::white())
- restart = v;
- }
- }
- if (restart != u)
- {
- u = restart;
- ++current[u].first;
- break;
- }
- } // else if (color[v] == ColorTraits::gray())
- } // if (get(capacity, a) == 0 ...
- } // for out_edges(u, g) (though "u" changes during
- // loop)
- if (current[u].first == current[u].second)
- {
- // scan of i is complete
- put(color, u, ColorTraits::black());
- if (u != src)
- {
- if (bos_null)
- {
- bos = u;
- bos_null = false;
- tos = u;
- }
- else
- {
- topo_next[get(index, u)] = tos;
- tos = u;
- }
- }
- if (u != r)
- {
- u = parent[get(index, u)];
- ++current[u].first;
- }
- else
- break;
- }
- } // while (1)
- } // if (color[u] == white && excess_flow[u] > 0 & ...)
- } // for all vertices in g
- // return excess flows
- // note that the sink is not on the stack
- if (!bos_null)
- {
- for (u = tos; u != bos; u = topo_next[get(index, u)])
- {
- boost::tie(ai, a_end) = out_edges(u, g);
- while (get(excess_flow, u) > 0 && ai != a_end)
- {
- if (get(capacity, *ai) == 0 && is_residual_edge(*ai))
- push_flow(*ai);
- ++ai;
- }
- }
- // do the bottom
- u = bos;
- boost::tie(ai, a_end) = out_edges(u, g);
- while (get(excess_flow, u) > 0 && ai != a_end)
- {
- if (get(capacity, *ai) == 0 && is_residual_edge(*ai))
- push_flow(*ai);
- ++ai;
- }
- }
- } // convert_preflow_to_flow()
- //=======================================================================
- inline bool is_flow()
- {
- vertex_iterator u_iter, u_end;
- out_edge_iterator ai, a_end;
- // check edge flow values
- for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
- ++u_iter)
- {
- for (boost::tie(ai, a_end) = out_edges(*u_iter, g); ai != a_end;
- ++ai)
- {
- edge_descriptor a = *ai;
- if (get(capacity, a) > 0)
- if ((get(residual_capacity, a)
- + get(
- residual_capacity, get(reverse_edge, a))
- != get(capacity, a)
- + get(capacity, get(reverse_edge, a)))
- || (get(residual_capacity, a) < 0)
- || (get(residual_capacity, get(reverse_edge, a))
- < 0))
- return false;
- }
- }
- // check conservation
- FlowValue sum;
- for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
- ++u_iter)
- {
- vertex_descriptor u = *u_iter;
- if (u != src && u != sink)
- {
- if (get(excess_flow, u) != 0)
- return false;
- sum = 0;
- for (boost::tie(ai, a_end) = out_edges(u, g); ai != a_end;
- ++ai)
- if (get(capacity, *ai) > 0)
- sum -= get(capacity, *ai)
- - get(residual_capacity, *ai);
- else
- sum += get(residual_capacity, *ai);
- if (get(excess_flow, u) != sum)
- return false;
- }
- }
- return true;
- } // is_flow()
- bool is_optimal()
- {
- // check if mincut is saturated...
- global_distance_update();
- return get(distance, src) >= n;
- }
- void print_statistics(std::ostream& os) const
- {
- os << "pushes: " << push_count << std::endl
- << "relabels: " << relabel_count << std::endl
- << "updates: " << update_count << std::endl
- << "gaps: " << gap_count << std::endl
- << "gap nodes: " << gap_node_count << std::endl
- << std::endl;
- }
- void print_flow_values(std::ostream& os) const
- {
- os << "flow values" << std::endl;
- vertex_iterator u_iter, u_end;
- out_edge_iterator ei, e_end;
- for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
- ++u_iter)
- for (boost::tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end;
- ++ei)
- if (get(capacity, *ei) > 0)
- os << *u_iter << " " << target(*ei, g) << " "
- << (get(capacity, *ei) - get(residual_capacity, *ei))
- << std::endl;
- os << std::endl;
- }
- //=======================================================================
- Graph& g;
- vertices_size_type n;
- vertices_size_type nm;
- EdgeCapacityMap capacity;
- vertex_descriptor src;
- vertex_descriptor sink;
- VertexIndexMap index;
- // will need to use random_access_property_map with these
- std::vector< FlowValue > excess_flow_data;
- iterator_property_map< typename std::vector< FlowValue >::iterator,
- VertexIndexMap >
- excess_flow;
- std::vector< std::pair< out_edge_iterator, out_edge_iterator > >
- current_data;
- iterator_property_map<
- typename std::vector<
- std::pair< out_edge_iterator, out_edge_iterator > >::iterator,
- VertexIndexMap >
- current;
- std::vector< distance_size_type > distance_data;
- iterator_property_map<
- typename std::vector< distance_size_type >::iterator,
- VertexIndexMap >
- distance;
- std::vector< default_color_type > color_data;
- iterator_property_map< std::vector< default_color_type >::iterator,
- VertexIndexMap >
- color;
- // Edge Property Maps that must be interior to the graph
- ReverseEdgeMap reverse_edge;
- ResidualCapacityEdgeMap residual_capacity;
- LayerArray layers;
- std::vector< list_iterator > layer_list_ptr_data;
- iterator_property_map< typename std::vector< list_iterator >::iterator,
- VertexIndexMap >
- layer_list_ptr;
- distance_size_type max_distance; // maximal distance
- distance_size_type max_active; // maximal distance with active node
- distance_size_type min_active; // minimal distance with active node
- boost::queue< vertex_descriptor > Q;
- // Statistics counters
- long push_count;
- long update_count;
- long relabel_count;
- long gap_count;
- long gap_node_count;
- inline double global_update_frequency() { return 0.5; }
- inline vertices_size_type alpha() { return 6; }
- inline long beta() { return 12; }
- long work_since_last_update;
- };
- } // namespace detail
- template < class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap,
- class ReverseEdgeMap, class VertexIndexMap >
- typename property_traits< CapacityEdgeMap >::value_type push_relabel_max_flow(
- Graph& g, typename graph_traits< Graph >::vertex_descriptor src,
- typename graph_traits< Graph >::vertex_descriptor sink, CapacityEdgeMap cap,
- ResidualCapacityEdgeMap res, ReverseEdgeMap rev, VertexIndexMap index_map)
- {
- typedef typename property_traits< CapacityEdgeMap >::value_type FlowValue;
- detail::push_relabel< Graph, CapacityEdgeMap, ResidualCapacityEdgeMap,
- ReverseEdgeMap, VertexIndexMap, FlowValue >
- algo(g, cap, res, rev, src, sink, index_map);
- FlowValue flow = algo.maximum_preflow();
- algo.convert_preflow_to_flow();
- BOOST_ASSERT(algo.is_flow());
- BOOST_ASSERT(algo.is_optimal());
- return flow;
- } // push_relabel_max_flow()
- template < class Graph, class P, class T, class R >
- typename detail::edge_capacity_value< Graph, P, T, R >::type
- push_relabel_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)
- {
- return push_relabel_max_flow(g, src, sink,
- 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_const_pmap(get_param(params, vertex_index), g, vertex_index));
- }
- template < class Graph >
- typename property_traits<
- typename property_map< Graph, edge_capacity_t >::const_type >::value_type
- push_relabel_max_flow(Graph& g,
- typename graph_traits< Graph >::vertex_descriptor src,
- typename graph_traits< Graph >::vertex_descriptor sink)
- {
- bgl_named_params< int, buffer_param_t > params(0); // bogus empty param
- return push_relabel_max_flow(g, src, sink, params);
- }
- } // namespace boost
- #endif // BOOST_PUSH_RELABEL_MAX_FLOW_HPP
|