/* -*- C++ -*- * * This file is a part of LEMON, a generic C++ optimization library * * Copyright (C) 2003-2007 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * * Permission to use, modify and distribute this software is granted * provided that this copyright notice appears in all copies. For * precise terms see the accompanying LICENSE file. * * This software is provided "AS IS" with no warranty of any kind, * express or implied, and with no claim as to its suitability for any * purpose. * */ #ifndef LEMON_NETWORK_SIMPLEX_H #define LEMON_NETWORK_SIMPLEX_H /// \ingroup min_cost_flow /// /// \file /// \brief The network simplex algorithm for finding a minimum cost /// flow. #include #include #include /// \brief The pivot rule used in the algorithm. //#define FIRST_ELIGIBLE_PIVOT //#define BEST_ELIGIBLE_PIVOT #define EDGE_BLOCK_PIVOT //#define CANDIDATE_LIST_PIVOT //#define SORTED_LIST_PIVOT //#define _DEBUG_ITER_ /// \brief State constant for edges at their lower bounds. #define LOWER 1 /// \brief State constant for edges in the spanning tree. #define TREE 0 /// \brief State constant for edges at their upper bounds. #define UPPER -1 #ifdef EDGE_BLOCK_PIVOT /// \brief Number of blocks for the "Edge Block" pivot rule. #define BLOCK_NUM 100 /// \brief Lower bound for the size of blocks. #define MIN_BLOCK_SIZE 10 #endif #ifdef CANDIDATE_LIST_PIVOT #include /// \brief The maximum length of the edge list for the /// "Candidate List" pivot rule. #define LIST_LENGTH 100 /// \brief The maximum number of minor iterations between two major /// itarations. #define MINOR_LIMIT 10 #endif #ifdef SORTED_LIST_PIVOT #include #include /// \brief The maximum length of the edge list for the /// "Sorted List" pivot rule. #define LIST_LENGTH 500 #define LOWER_DIV 3 #endif namespace lemon { /// \addtogroup min_cost_flow /// @{ /// \brief Implementation of the network simplex algorithm for /// finding a minimum cost flow. /// /// \ref lemon::NetworkSimplex "NetworkSimplex" implements the /// network simplex algorithm for finding a minimum cost flow. /// /// \param Graph The directed graph type the algorithm runs on. /// \param LowerMap The type of the lower bound map. /// \param CapacityMap The type of the capacity (upper bound) map. /// \param CostMap The type of the cost (length) map. /// \param SupplyMap The type of the supply map. /// /// \warning /// - Edge capacities and costs should be nonnegative integers. /// However \c CostMap::Value should be signed type. /// - Supply values should be integers. /// - \c LowerMap::Value must be convertible to /// \c CapacityMap::Value and \c CapacityMap::Value must be /// convertible to \c SupplyMap::Value. /// /// \author Peter Kovacs template < typename Graph, typename LowerMap = typename Graph::template EdgeMap, typename CapacityMap = LowerMap, typename CostMap = typename Graph::template EdgeMap, typename SupplyMap = typename Graph::template NodeMap > class NetworkSimplex { typedef typename LowerMap::Value Lower; typedef typename CapacityMap::Value Capacity; typedef typename CostMap::Value Cost; typedef typename SupplyMap::Value Supply; typedef SmartGraph SGraph; typedef typename SGraph::Node Node; typedef typename SGraph::NodeIt NodeIt; typedef typename SGraph::Edge Edge; typedef typename SGraph::EdgeIt EdgeIt; typedef typename SGraph::InEdgeIt InEdgeIt; typedef typename SGraph::OutEdgeIt OutEdgeIt; typedef typename SGraph::template EdgeMap SLowerMap; typedef typename SGraph::template EdgeMap SCapacityMap; typedef typename SGraph::template EdgeMap SCostMap; typedef typename SGraph::template NodeMap SSupplyMap; typedef typename SGraph::template NodeMap SPotentialMap; typedef typename SGraph::template NodeMap IntNodeMap; typedef typename SGraph::template NodeMap BoolNodeMap; typedef typename SGraph::template NodeMap NodeNodeMap; typedef typename SGraph::template NodeMap EdgeNodeMap; typedef typename SGraph::template EdgeMap IntEdgeMap; typedef typename Graph::template NodeMap NodeRefMap; typedef typename Graph::template EdgeMap EdgeRefMap; public: /// \brief The type of the flow map. typedef typename Graph::template EdgeMap FlowMap; /// \brief The type of the potential map. typedef typename Graph::template NodeMap PotentialMap; protected: /// \brief Map adaptor class for handling reduced edge costs. class ReducedCostMap : public MapBase { private: const SGraph &gr; const SCostMap &cost_map; const SPotentialMap &pot_map; public: typedef typename MapBase::Value Value; typedef typename MapBase::Key Key; ReducedCostMap( const SGraph &_gr, const SCostMap &_cm, const SPotentialMap &_pm ) : gr(_gr), cost_map(_cm), pot_map(_pm) {} Value operator[](const Key &e) const { return cost_map[e] - pot_map[gr.source(e)] + pot_map[gr.target(e)]; } }; //class ReducedCostMap protected: /// \brief The directed graph the algorithm runs on. SGraph graph; /// \brief The original graph. const Graph &graph_ref; /// \brief The original lower bound map. const LowerMap *lower; /// \brief The capacity map. SCapacityMap capacity; /// \brief The cost map. SCostMap cost; /// \brief The supply map. SSupplyMap supply; /// \brief The reduced cost map. ReducedCostMap red_cost; /// \brief The sum of supply values equals zero. bool valid_supply; /// \brief The edge map of the current flow. SCapacityMap flow; /// \brief The edge map of the found flow on the original graph. FlowMap flow_result; /// \brief The potential node map. SPotentialMap potential; /// \brief The potential node map on the original graph. PotentialMap potential_result; /// \brief Node reference for the original graph. NodeRefMap node_ref; /// \brief Edge reference for the original graph. EdgeRefMap edge_ref; /// \brief The depth node map of the spanning tree structure. IntNodeMap depth; /// \brief The parent node map of the spanning tree structure. NodeNodeMap parent; /// \brief The pred_edge node map of the spanning tree structure. EdgeNodeMap pred_edge; /// \brief The thread node map of the spanning tree structure. NodeNodeMap thread; /// \brief The forward node map of the spanning tree structure. BoolNodeMap forward; /// \brief The state edge map. IntEdgeMap state; #ifdef EDGE_BLOCK_PIVOT /// \brief The size of blocks for the "Edge Block" pivot rule. int block_size; #endif #ifdef CANDIDATE_LIST_PIVOT /// \brief The list of candidate edges for the "Candidate List" /// pivot rule. std::list candidates; /// \brief The number of minor iterations. int minor_count; #endif #ifdef SORTED_LIST_PIVOT /// \brief The list of candidate edges for the "Sorted List" /// pivot rule. std::deque candidates; #endif // Root node of the starting spanning tree. Node root; // The entering edge of the current pivot iteration. Edge in_edge; // Temporary nodes used in the current pivot iteration. Node join, u_in, v_in, u_out, v_out; Node right, first, second, last; Node stem, par_stem, new_stem; // The maximum augment amount along the cycle in the current pivot // iteration. Capacity delta; public : /// \brief General constructor of the class (with lower bounds). /// /// General constructor of the class (with lower bounds). /// /// \param _graph The directed graph the algorithm runs on. /// \param _lower The lower bounds of the edges. /// \param _capacity The capacities (upper bounds) of the edges. /// \param _cost The cost (length) values of the edges. /// \param _supply The supply values of the nodes (signed). NetworkSimplex( const Graph &_graph, const LowerMap &_lower, const CapacityMap &_capacity, const CostMap &_cost, const SupplyMap &_supply ) : graph_ref(_graph), lower(&_lower), capacity(graph), cost(graph), supply(graph), flow(graph), flow_result(_graph), potential(graph), potential_result(_graph), depth(graph), parent(graph), pred_edge(graph), thread(graph), forward(graph), state(graph), node_ref(graph_ref), edge_ref(graph_ref), red_cost(graph, cost, potential) { // Checking the sum of supply values Supply sum = 0; for (typename Graph::NodeIt n(graph_ref); n != INVALID; ++n) sum += _supply[n]; if (!(valid_supply = sum == 0)) return; // Copying graph_ref to graph copyGraph(graph, graph_ref) .edgeMap(cost, _cost) .nodeRef(node_ref) .edgeRef(edge_ref) .run(); // Removing nonzero lower bounds for (typename Graph::EdgeIt e(graph_ref); e != INVALID; ++e) { capacity[edge_ref[e]] = _capacity[e] - _lower[e]; } for (typename Graph::NodeIt n(graph_ref); n != INVALID; ++n) { Supply s = _supply[n]; for (typename Graph::InEdgeIt e(graph_ref, n); e != INVALID; ++e) s += _lower[e]; for (typename Graph::OutEdgeIt e(graph_ref, n); e != INVALID; ++e) s -= _lower[e]; supply[node_ref[n]] = s; } } /// \brief General constructor of the class (without lower bounds). /// /// General constructor of the class (without lower bounds). /// /// \param _graph The directed graph the algorithm runs on. /// \param _capacity The capacities (upper bounds) of the edges. /// \param _cost The cost (length) values of the edges. /// \param _supply The supply values of the nodes (signed). NetworkSimplex( const Graph &_graph, const CapacityMap &_capacity, const CostMap &_cost, const SupplyMap &_supply ) : graph_ref(_graph), lower(NULL), capacity(graph), cost(graph), supply(graph), flow(graph), flow_result(_graph), potential(graph), potential_result(_graph), depth(graph), parent(graph), pred_edge(graph), thread(graph), forward(graph), state(graph), node_ref(graph_ref), edge_ref(graph_ref), red_cost(graph, cost, potential) { // Checking the sum of supply values Supply sum = 0; for (typename Graph::NodeIt n(graph_ref); n != INVALID; ++n) sum += _supply[n]; if (!(valid_supply = sum == 0)) return; // Copying graph_ref to graph copyGraph(graph, graph_ref) .edgeMap(capacity, _capacity) .edgeMap(cost, _cost) .nodeMap(supply, _supply) .nodeRef(node_ref) .edgeRef(edge_ref) .run(); } /// \brief Simple constructor of the class (with lower bounds). /// /// Simple constructor of the class (with lower bounds). /// /// \param _graph The directed graph the algorithm runs on. /// \param _lower The lower bounds of the edges. /// \param _capacity The capacities (upper bounds) of the edges. /// \param _cost The cost (length) values of the edges. /// \param _s The source node. /// \param _t The target node. /// \param _flow_value The required amount of flow from node \c _s /// to node \c _t (i.e. the supply of \c _s and the demand of /// \c _t). NetworkSimplex( const Graph &_graph, const LowerMap &_lower, const CapacityMap &_capacity, const CostMap &_cost, typename Graph::Node _s, typename Graph::Node _t, typename SupplyMap::Value _flow_value ) : graph_ref(_graph), lower(&_lower), capacity(graph), cost(graph), supply(graph), flow(graph), flow_result(_graph), potential(graph), potential_result(_graph), depth(graph), parent(graph), pred_edge(graph), thread(graph), forward(graph), state(graph), node_ref(graph_ref), edge_ref(graph_ref), red_cost(graph, cost, potential) { // Copying graph_ref to graph copyGraph(graph, graph_ref) .edgeMap(cost, _cost) .nodeRef(node_ref) .edgeRef(edge_ref) .run(); // Removing nonzero lower bounds for (typename Graph::EdgeIt e(graph_ref); e != INVALID; ++e) { capacity[edge_ref[e]] = _capacity[e] - _lower[e]; } for (typename Graph::NodeIt n(graph_ref); n != INVALID; ++n) { Supply s = 0; if (n == _s) s = _flow_value; if (n == _t) s = -_flow_value; for (typename Graph::InEdgeIt e(graph_ref, n); e != INVALID; ++e) s += _lower[e]; for (typename Graph::OutEdgeIt e(graph_ref, n); e != INVALID; ++e) s -= _lower[e]; supply[node_ref[n]] = s; } valid_supply = true; } /// \brief Simple constructor of the class (without lower bounds). /// /// Simple constructor of the class (without lower bounds). /// /// \param _graph The directed graph the algorithm runs on. /// \param _capacity The capacities (upper bounds) of the edges. /// \param _cost The cost (length) values of the edges. /// \param _s The source node. /// \param _t The target node. /// \param _flow_value The required amount of flow from node \c _s /// to node \c _t (i.e. the supply of \c _s and the demand of /// \c _t). NetworkSimplex( const Graph &_graph, const CapacityMap &_capacity, const CostMap &_cost, typename Graph::Node _s, typename Graph::Node _t, typename SupplyMap::Value _flow_value ) : graph_ref(_graph), lower(NULL), capacity(graph), cost(graph), supply(graph, 0), flow(graph), flow_result(_graph), potential(graph), potential_result(_graph), depth(graph), parent(graph), pred_edge(graph), thread(graph), forward(graph), state(graph), node_ref(graph_ref), edge_ref(graph_ref), red_cost(graph, cost, potential) { // Copying graph_ref to graph copyGraph(graph, graph_ref) .edgeMap(capacity, _capacity) .edgeMap(cost, _cost) .nodeRef(node_ref) .edgeRef(edge_ref) .run(); supply[node_ref[_s]] = _flow_value; supply[node_ref[_t]] = -_flow_value; valid_supply = true; } /// \brief Returns a const reference to the flow map. /// /// Returns a const reference to the flow map. /// /// \pre \ref run() must be called before using this function. const FlowMap& flowMap() const { return flow_result; } /// \brief Returns a const reference to the potential map (the dual /// solution). /// /// Returns a const reference to the potential map (the dual /// solution). /// /// \pre \ref run() must be called before using this function. const PotentialMap& potentialMap() const { return potential_result; } /// \brief Returns the total cost of the found flow. /// /// Returns the total cost of the found flow. The complexity of the /// function is \f$ O(e) \f$. /// /// \pre \ref run() must be called before using this function. Cost totalCost() const { Cost c = 0; for (typename Graph::EdgeIt e(graph_ref); e != INVALID; ++e) c += flow_result[e] * cost[edge_ref[e]]; return c; } /// \brief Runs the algorithm. /// /// Runs the algorithm. /// /// \return \c true if a feasible flow can be found. bool run() { return init() && start(); } protected: /// \brief Extends the underlaying graph and initializes all the /// node and edge maps. bool init() { if (!valid_supply) return false; // Initializing state and flow maps for (EdgeIt e(graph); e != INVALID; ++e) { flow[e] = 0; state[e] = LOWER; } // Adding an artificial root node to the graph root = graph.addNode(); parent[root] = INVALID; pred_edge[root] = INVALID; depth[root] = supply[root] = potential[root] = 0; // Adding artificial edges to the graph and initializing the node // maps of the spanning tree data structure Supply sum = 0; Node last = root; Edge e; Cost max_cost = std::numeric_limits::max() / 4; for (NodeIt u(graph); u != INVALID; ++u) { if (u == root) continue; thread[last] = u; last = u; parent[u] = root; depth[u] = 1; sum += supply[u]; if (supply[u] >= 0) { e = graph.addEdge(u, root); flow[e] = supply[u]; forward[u] = true; potential[u] = max_cost; } else { e = graph.addEdge(root, u); flow[e] = -supply[u]; forward[u] = false; potential[u] = -max_cost; } cost[e] = max_cost; capacity[e] = std::numeric_limits::max(); state[e] = TREE; pred_edge[u] = e; } thread[last] = root; #ifdef EDGE_BLOCK_PIVOT // Initializing block_size for the edge block pivot rule int edge_num = countEdges(graph); block_size = edge_num >= BLOCK_NUM * MIN_BLOCK_SIZE ? edge_num / BLOCK_NUM : MIN_BLOCK_SIZE; #endif #ifdef CANDIDATE_LIST_PIVOT minor_count = 0; #endif return sum == 0; } #ifdef FIRST_ELIGIBLE_PIVOT /// \brief Finds entering edge according to the "First Eligible" /// pivot rule. bool findEnteringEdge(EdgeIt &next_edge) { for (EdgeIt e = next_edge; e != INVALID; ++e) { if (state[e] * red_cost[e] < 0) { in_edge = e; next_edge = ++e; return true; } } for (EdgeIt e(graph); e != next_edge; ++e) { if (state[e] * red_cost[e] < 0) { in_edge = e; next_edge = ++e; return true; } } return false; } #endif #ifdef BEST_ELIGIBLE_PIVOT /// \brief Finds entering edge according to the "Best Eligible" /// pivot rule. bool findEnteringEdge() { Cost min = 0; for (EdgeIt e(graph); e != INVALID; ++e) { if (state[e] * red_cost[e] < min) { min = state[e] * red_cost[e]; in_edge = e; } } return min < 0; } #endif #ifdef EDGE_BLOCK_PIVOT /// \brief Finds entering edge according to the "Edge Block" /// pivot rule. bool findEnteringEdge(EdgeIt &next_edge) { // Performing edge block selection Cost curr, min = 0; EdgeIt min_edge(graph); int cnt = 0; for (EdgeIt e = next_edge; e != INVALID; ++e) { if ((curr = state[e] * red_cost[e]) < min) { min = curr; min_edge = e; } if (++cnt == block_size) { if (min < 0) break; cnt = 0; } } if (!(min < 0)) { for (EdgeIt e(graph); e != next_edge; ++e) { if ((curr = state[e] * red_cost[e]) < min) { min = curr; min_edge = e; } if (++cnt == block_size) { if (min < 0) break; cnt = 0; } } } in_edge = min_edge; if ((next_edge = ++min_edge) == INVALID) next_edge = EdgeIt(graph); return min < 0; } #endif #ifdef CANDIDATE_LIST_PIVOT /// \brief Functor class for removing non-eligible edges from the /// candidate list. class RemoveFunc { private: const IntEdgeMap &st; const ReducedCostMap &rc; public: RemoveFunc(const IntEdgeMap &_st, const ReducedCostMap &_rc) : st(_st), rc(_rc) {} bool operator()(const Edge &e) { return st[e] * rc[e] >= 0; } }; /// \brief Finds entering edge according to the "Candidate List" /// pivot rule. bool findEnteringEdge() { static RemoveFunc remove_func(state, red_cost); typedef typename std::list::iterator ListIt; candidates.remove_if(remove_func); if (minor_count >= MINOR_LIMIT || candidates.size() == 0) { // Major iteration for (EdgeIt e(graph); e != INVALID; ++e) { if (state[e] * red_cost[e] < 0) { candidates.push_back(e); if (candidates.size() == LIST_LENGTH) break; } } if (candidates.size() == 0) return false; } // Minor iteration ++minor_count; Cost min = 0; for (ListIt it = candidates.begin(); it != candidates.end(); ++it) { if (state[*it] * red_cost[*it] < min) { min = state[*it] * red_cost[*it]; in_edge = *it; } } return true; } #endif #ifdef SORTED_LIST_PIVOT /// \brief Functor class to compare edges during sort of the /// candidate list. class SortFunc { private: const IntEdgeMap &st; const ReducedCostMap &rc; public: SortFunc(const IntEdgeMap &_st, const ReducedCostMap &_rc) : st(_st), rc(_rc) {} bool operator()(const Edge &e1, const Edge &e2) { return st[e1] * rc[e1] < st[e2] * rc[e2]; } }; /// \brief Finds entering edge according to the "Sorted List" /// pivot rule. bool findEnteringEdge() { static SortFunc sort_func(state, red_cost); // Minor iteration while (candidates.size() > 0) { in_edge = candidates.front(); candidates.pop_front(); if (state[in_edge] * red_cost[in_edge] < 0) return true; } // Major iteration Cost curr, min = 0; for (EdgeIt e(graph); e != INVALID; ++e) { if ((curr = state[e] * red_cost[e]) < min / LOWER_DIV) { candidates.push_back(e); if (curr < min) min = curr; if (candidates.size() == LIST_LENGTH) break; } } if (candidates.size() == 0) return false; sort(candidates.begin(), candidates.end(), sort_func); in_edge = candidates.front(); candidates.pop_front(); return true; } #endif /// \brief Finds the join node. Node findJoinNode() { // Finding the join node Node u = graph.source(in_edge); Node v = graph.target(in_edge); while (u != v) { if (depth[u] == depth[v]) { u = parent[u]; v = parent[v]; } else if (depth[u] > depth[v]) u = parent[u]; else v = parent[v]; } return u; } /// \brief Finds the leaving edge of the cycle. Returns \c true if /// the leaving edge is not the same as the entering edge. bool findLeavingEdge() { // Initializing first and second nodes according to the direction // of the cycle if (state[in_edge] == LOWER) { first = graph.source(in_edge); second = graph.target(in_edge); } else { first = graph.target(in_edge); second = graph.source(in_edge); } delta = capacity[in_edge]; bool result = false; Capacity d; Edge e; // Searching the cycle along the path form the first node to the // root node for (Node u = first; u != join; u = parent[u]) { e = pred_edge[u]; d = forward[u] ? flow[e] : capacity[e] - flow[e]; if (d < delta) { delta = d; u_out = u; u_in = first; v_in = second; result = true; } } // Searching the cycle along the path form the second node to the // root node for (Node u = second; u != join; u = parent[u]) { e = pred_edge[u]; d = forward[u] ? capacity[e] - flow[e] : flow[e]; if (d <= delta) { delta = d; u_out = u; u_in = second; v_in = first; result = true; } } return result; } /// \brief Changes flow and state edge maps. void changeFlows(bool change) { // Augmenting along the cycle if (delta > 0) { Capacity val = state[in_edge] * delta; flow[in_edge] += val; for (Node u = graph.source(in_edge); u != join; u = parent[u]) { flow[pred_edge[u]] += forward[u] ? -val : val; } for (Node u = graph.target(in_edge); u != join; u = parent[u]) { flow[pred_edge[u]] += forward[u] ? val : -val; } } // Updating the state of the entering and leaving edges if (change) { state[in_edge] = TREE; state[pred_edge[u_out]] = (flow[pred_edge[u_out]] == 0) ? LOWER : UPPER; } else { state[in_edge] = -state[in_edge]; } } /// \brief Updates thread and parent node maps. void updateThreadParent() { Node u; v_out = parent[u_out]; // Handling the case when join and v_out coincide bool par_first = false; if (join == v_out) { for (u = join; u != u_in && u != v_in; u = thread[u]) ; if (u == v_in) { par_first = true; while (thread[u] != u_out) u = thread[u]; first = u; } } // Finding the last successor of u_in (u) and the node after it // (right) according to the thread index for (u = u_in; depth[thread[u]] > depth[u_in]; u = thread[u]) ; right = thread[u]; if (thread[v_in] == u_out) { for (last = u; depth[last] > depth[u_out]; last = thread[last]) ; if (last == u_out) last = thread[last]; } else last = thread[v_in]; // Updating stem nodes thread[v_in] = stem = u_in; par_stem = v_in; while (stem != u_out) { thread[u] = new_stem = parent[stem]; // Finding the node just before the stem node (u) according to // the original thread index for (u = new_stem; thread[u] != stem; u = thread[u]) ; thread[u] = right; // Changing the parent node of stem and shifting stem and // par_stem nodes parent[stem] = par_stem; par_stem = stem; stem = new_stem; // Finding the last successor of stem (u) and the node after it // (right) according to the thread index for (u = stem; depth[thread[u]] > depth[stem]; u = thread[u]) ; right = thread[u]; } parent[u_out] = par_stem; thread[u] = last; if (join == v_out && par_first) { if (first != v_in) thread[first] = right; } else { for (u = v_out; thread[u] != u_out; u = thread[u]) ; thread[u] = right; } } /// \brief Updates pred_edge and forward node maps. void updatePredEdge() { Node u = u_out, v; while (u != u_in) { v = parent[u]; pred_edge[u] = pred_edge[v]; forward[u] = !forward[v]; u = v; } pred_edge[u_in] = in_edge; forward[u_in] = (u_in == graph.source(in_edge)); } /// \brief Updates depth and potential node maps. void updateDepthPotential() { depth[u_in] = depth[v_in] + 1; potential[u_in] = forward[u_in] ? potential[v_in] + cost[pred_edge[u_in]] : potential[v_in] - cost[pred_edge[u_in]]; Node u = thread[u_in], v; while (true) { v = parent[u]; if (v == INVALID) break; depth[u] = depth[v] + 1; potential[u] = forward[u] ? potential[v] + cost[pred_edge[u]] : potential[v] - cost[pred_edge[u]]; if (depth[u] <= depth[v_in]) break; u = thread[u]; } } /// \brief Executes the algorithm. bool start() { // Processing pivots #ifdef _DEBUG_ITER_ int iter_num = 0; #endif #if defined(FIRST_ELIGIBLE_PIVOT) || defined(EDGE_BLOCK_PIVOT) EdgeIt next_edge(graph); while (findEnteringEdge(next_edge)) #else while (findEnteringEdge()) #endif { join = findJoinNode(); bool change = findLeavingEdge(); changeFlows(change); if (change) { updateThreadParent(); updatePredEdge(); updateDepthPotential(); } #ifdef _DEBUG_ITER_ ++iter_num; #endif } #ifdef _DEBUG_ITER_ std::cout << "Network Simplex algorithm finished. " << iter_num << " pivot iterations performed." << std::endl; #endif // Checking if the flow amount equals zero on all the // artificial edges for (InEdgeIt e(graph, root); e != INVALID; ++e) if (flow[e] > 0) return false; for (OutEdgeIt e(graph, root); e != INVALID; ++e) if (flow[e] > 0) return false; // Copying flow values to flow_result if (lower) { for (typename Graph::EdgeIt e(graph_ref); e != INVALID; ++e) flow_result[e] = (*lower)[e] + flow[edge_ref[e]]; } else { for (typename Graph::EdgeIt e(graph_ref); e != INVALID; ++e) flow_result[e] = flow[edge_ref[e]]; } // Copying potential values to potential_result for (typename Graph::NodeIt n(graph_ref); n != INVALID; ++n) potential_result[n] = potential[node_ref[n]]; return true; } }; //class NetworkSimplex ///@} } //namespace lemon #endif //LEMON_NETWORK_SIMPLEX_H