athos@610: // -*- c++ -*- athos@610: #ifndef HUGO_MINCOSTFLOWS_H athos@610: #define HUGO_MINCOSTFLOWS_H athos@610: alpar@758: ///\ingroup flowalgs athos@610: ///\file athos@610: ///\brief An algorithm for finding a flow of value \c k (for small values of \c k) having minimal total cost athos@610: athos@611: athos@610: #include <hugo/dijkstra.h> athos@610: #include <hugo/graph_wrapper.h> athos@610: #include <hugo/maps.h> athos@610: #include <vector> athos@610: athos@610: namespace hugo { athos@610: alpar@758: /// \addtogroup flowalgs athos@610: /// @{ athos@610: athos@610: ///\brief Implementation of an algorithm for finding a flow of value \c k athos@610: ///(for small values of \c k) having minimal total cost between 2 nodes athos@610: /// athos@610: /// athos@610: /// The class \ref hugo::MinCostFlows "MinCostFlows" implements athos@610: /// an algorithm for finding a flow of value \c k athos@610: ///(for small values of \c k) having minimal total cost athos@610: /// from a given source node to a given target node in an athos@610: /// edge-weighted directed graph having nonnegative integer capacities. athos@610: /// The range of the length (weight) function is nonnegative reals but athos@610: /// the range of capacity function is the set of nonnegative integers. athos@610: /// It is not a polinomial time algorithm for counting the minimum cost athos@610: /// maximal flow, since it counts the minimum cost flow for every value 0..M athos@610: /// where \c M is the value of the maximal flow. athos@610: /// athos@610: ///\author Attila Bernath athos@610: template <typename Graph, typename LengthMap, typename CapacityMap> athos@610: class MinCostFlows { athos@610: athos@610: typedef typename LengthMap::ValueType Length; athos@610: athos@610: //Warning: this should be integer type athos@610: typedef typename CapacityMap::ValueType Capacity; athos@610: athos@610: typedef typename Graph::Node Node; athos@610: typedef typename Graph::NodeIt NodeIt; athos@610: typedef typename Graph::Edge Edge; athos@610: typedef typename Graph::OutEdgeIt OutEdgeIt; athos@610: typedef typename Graph::template EdgeMap<int> EdgeIntMap; athos@610: athos@610: // typedef ConstMap<Edge,int> ConstMap; athos@610: athos@610: typedef ResGraphWrapper<const Graph,int,CapacityMap,EdgeIntMap> ResGraphType; athos@610: typedef typename ResGraphType::Edge ResGraphEdge; athos@610: athos@610: class ModLengthMap { athos@610: //typedef typename ResGraphType::template NodeMap<Length> NodeMap; athos@610: typedef typename Graph::template NodeMap<Length> NodeMap; athos@610: const ResGraphType& G; athos@610: // const EdgeIntMap& rev; athos@610: const LengthMap &ol; athos@610: const NodeMap &pot; athos@610: public : athos@610: typedef typename LengthMap::KeyType KeyType; athos@610: typedef typename LengthMap::ValueType ValueType; athos@610: athos@610: ValueType operator[](typename ResGraphType::Edge e) const { athos@610: if (G.forward(e)) athos@610: return ol[e]-(pot[G.head(e)]-pot[G.tail(e)]); athos@610: else athos@610: return -ol[e]-(pot[G.head(e)]-pot[G.tail(e)]); athos@610: } athos@610: athos@610: ModLengthMap(const ResGraphType& _G, athos@610: const LengthMap &o, const NodeMap &p) : athos@610: G(_G), /*rev(_rev),*/ ol(o), pot(p){}; athos@610: };//ModLengthMap athos@610: athos@610: athos@610: protected: athos@610: athos@610: //Input athos@610: const Graph& G; athos@610: const LengthMap& length; athos@610: const CapacityMap& capacity; athos@610: athos@610: athos@610: //auxiliary variables athos@610: athos@610: //To store the flow athos@610: EdgeIntMap flow; alpar@785: //To store the potential (dual variables) athos@661: typedef typename Graph::template NodeMap<Length> PotentialMap; athos@661: PotentialMap potential; athos@610: athos@610: athos@610: Length total_length; athos@610: athos@610: athos@610: public : athos@610: athos@610: athos@610: MinCostFlows(Graph& _G, LengthMap& _length, CapacityMap& _cap) : G(_G), athos@610: length(_length), capacity(_cap), flow(_G), potential(_G){ } athos@610: athos@610: athos@610: ///Runs the algorithm. athos@610: athos@610: ///Runs the algorithm. athos@610: ///Returns k if there are at least k edge-disjoint paths from s to t. athos@610: ///Otherwise it returns the number of found edge-disjoint paths from s to t. athos@610: ///\todo May be it does make sense to be able to start with a nonzero athos@610: /// feasible primal-dual solution pair as well. athos@610: int run(Node s, Node t, int k) { athos@610: athos@610: //Resetting variables from previous runs athos@610: total_length = 0; athos@610: marci@788: for (typename Graph::EdgeIt e(G); e!=INVALID; ++e) flow.set(e, 0); athos@634: athos@634: //Initialize the potential to zero marci@788: for (typename Graph::NodeIt n(G); n!=INVALID; ++n) potential.set(n, 0); athos@610: athos@610: athos@610: //We need a residual graph athos@610: ResGraphType res_graph(G, capacity, flow); athos@610: athos@610: athos@610: ModLengthMap mod_length(res_graph, length, potential); athos@610: athos@610: Dijkstra<ResGraphType, ModLengthMap> dijkstra(res_graph, mod_length); athos@610: athos@610: int i; athos@610: for (i=0; i<k; ++i){ athos@610: dijkstra.run(s); athos@610: if (!dijkstra.reached(t)){ athos@610: //There are no k paths from s to t athos@610: break; athos@610: }; athos@610: athos@634: //We have to change the potential marci@788: for(typename ResGraphType::NodeIt n(res_graph); n!=INVALID; ++n) athos@633: potential[n] += dijkstra.distMap()[n]; athos@634: athos@610: athos@610: //Augmenting on the sortest path athos@610: Node n=t; athos@610: ResGraphEdge e; athos@610: while (n!=s){ athos@610: e = dijkstra.pred(n); athos@610: n = dijkstra.predNode(n); athos@610: res_graph.augment(e,1); athos@610: //Let's update the total length athos@610: if (res_graph.forward(e)) athos@610: total_length += length[e]; athos@610: else athos@610: total_length -= length[e]; athos@610: } athos@610: athos@610: athos@610: } athos@610: athos@610: athos@610: return i; athos@610: } athos@610: athos@610: athos@610: athos@610: athos@610: ///This function gives back the total length of the found paths. athos@610: ///Assumes that \c run() has been run and nothing changed since then. athos@610: Length totalLength(){ athos@610: return total_length; athos@610: } athos@610: athos@610: ///Returns a const reference to the EdgeMap \c flow. \pre \ref run() must athos@610: ///be called before using this function. athos@610: const EdgeIntMap &getFlow() const { return flow;} athos@610: athos@610: ///Returns a const reference to the NodeMap \c potential (the dual solution). athos@610: /// \pre \ref run() must be called before using this function. athos@661: const PotentialMap &getPotential() const { return potential;} athos@610: athos@610: ///This function checks, whether the given solution is optimal athos@610: ///Running after a \c run() should return with true athos@610: ///In this "state of the art" this only check optimality, doesn't bother with feasibility athos@610: /// athos@610: ///\todo Is this OK here? athos@610: bool checkComplementarySlackness(){ athos@610: Length mod_pot; athos@610: Length fl_e; marci@788: for(typename Graph::EdgeIt e(G); e!=INVALID; ++e) { athos@610: //C^{\Pi}_{i,j} athos@610: mod_pot = length[e]-potential[G.head(e)]+potential[G.tail(e)]; athos@610: fl_e = flow[e]; athos@610: // std::cout << fl_e << std::endl; athos@610: if (0<fl_e && fl_e<capacity[e]){ athos@610: if (mod_pot != 0) athos@610: return false; athos@610: } athos@610: else{ athos@610: if (mod_pot > 0 && fl_e != 0) athos@610: return false; athos@610: if (mod_pot < 0 && fl_e != capacity[e]) athos@610: return false; athos@610: } athos@610: } athos@610: return true; athos@610: } athos@610: athos@610: athos@610: }; //class MinCostFlows athos@610: athos@610: ///@} athos@610: athos@610: } //namespace hugo athos@610: athos@633: #endif //HUGO_MINCOSTFLOWS_H