//================================================================================================== // G r a p h _ p r o b l e m Interface // M i n _ c o s t _ f l o w // C y c l e _ c a n c e l i n g // By Bruno Bachelet //================================================================================================== // Copyright (c) 1999-2016 // Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net // // This file is part of the B++ Library. This library is free software; you can redistribute it // and/or modify it under the terms of the GNU Library General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your option) any later // version. // // This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See // the GNU Library General Public License for more details (http://www.gnu.org).
/*DESCRIPTION*/ /* This module implements the cycle-canceling algorithm to solve the minimum cost flow problem (with linear costs) in graphs. */
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "graph_problem/min_cost_flow/cycle_canceling.hpp"
// Guardian //-------------------------------------------------------------------------------------- #ifndef guGraphProblemMinCostFlowCycleCanceling #define guGraphProblemMinCostFlowCycleCanceling
// Headers //--------------------------------------------------------------------------------------- #include <bpp/graph_problem/min_cost_flow/algorithm.hpp> /*INCLUDE*/
namespace bpp {
// Importation/Exportation //----------------------------------------------------------------------- #ifdef GRAPH_PROBLEM_MIN_COST_FLOW_DLL #define dll_export DLL_EXPORT #else #define dll_export DLL_IMPORT #endif
// Namespaces //------------------------------------------------------------------------------------ #define public_area graphProblemMinCostFlowCycleCanceling #define private_area graphProblemMinCostFlowCycleCanceling_private
namespace public_area { /*NAMESPACE*/ using namespace graphProblemMinCostFlowAlgorithm; } namespace private_area { using namespace public_area; }
extern_module_name;
// Initialization //-------------------------------------------------------------------------------- #define iniGraphProblemMinCostFlowCycleCanceling has_initializer;
// Macrocommands //--------------------------------------------------------------------------------- /*ALIAS*/ #define tdGraph class prArcData,class prNodeData //
/*ALIAS*/ #define tuGraph prArcData,prNodeData //
// Types & Classes //------------------------------------------------------------------------------- namespace public_area { //------------------------------------------------------------------------------------------Classes template <tdGraph> class clSolveAlgo; }
namespace private_area { template <tdGraph> struct tyDistanceInfo { clArc<tuGraph> * predecessor; tyReal distance; }; }
// Functions Interface //--------------------------------------------------------------------------- namespace public_area { template <tdGraph> tyBoolean findNegativeCycle(clGraph<tuGraph> &,std_map(clArc<tuGraph> *,tyInteger) &); }
namespace private_area { template <tdGraph> void buildNegativeCycle(std_map(clArc<tuGraph> *,tyInteger) &,clNode<tuGraph> *,tyMark);
testing_mode ( function void test(void); ) }
// Errors //---------------------------------------------------------------------------------------- namespace public_area { /*ERROR*/ extern_error erNegativeCycleProblem; /* Problem to build the negative cycle. */ }
// Constants & Variables //------------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// S o l v e A l g o Interface //------------------------------------------------------------------ namespace public_area { /*CLASS clSolveAlgo */ /* Represents an algorithm to solve the minimum cost flow problem in a graph using the cycle-canceling method. */ template <tdGraph> class clSolveAlgo : public clSolver<tuGraph> { //-----------------------------------------------------------------------------------------Private private_property constructor clSolveAlgo(const clSolveAlgo &); private_property clSolveAlgo & operator = (const clSolveAlgo &); //------------------------------------------------------------------------------------------Public public_property constructor clSolveAlgo(void); public_property virtual destructor clSolveAlgo(void);
public_property tyInteger run(clGraph<tuGraph> &) const; }; }
// Functions Inline //------------------------------------------------------------------------------ namespace public_area {} namespace private_area {}
// S o l v e A l g o Inline //--------------------------------------------------------------------- namespace public_area { //--------------------------------------------------------------------------------------Constructor /*METHOD clSolveAlgo */ /* Builds an algorithm to solve the minimum cost flow problem in a graph. */ template <tdGraph> inline clSolveAlgo<tuGraph>::clSolveAlgo(void) {} //---------------------------------------------------------------------------------------Destructor /*METHOD clSolveAlgo */ /* Destructs the algorithm. */ template <tdGraph> inline clSolveAlgo<tuGraph>::~clSolveAlgo(void) {} }
// Functions Implementation //---------------------------------------------------------------------- namespace public_area { //--------------------------------------------------------------------------------FindNegativeCycle /*FUNCTION*/ /* Finds a negative cost cycle. <CODE>false</CODE> is returned if no such cycle exists. */ template <tdGraph> tyBoolean findNegativeCycle(clGraph<tuGraph> & agGraph, std_map(clArc<tuGraph> *,tyInteger) & agCycle) { typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpArcIterator1; typedef typename clNode<tuGraph>::cpArcX::const_iterator cpArcIterator2; typedef typename clGraph<tuGraph>::cpNodeX::const_iterator cpNodeIterator;
typedef std_vector(clNode<tuGraph> *) cpNodeS; typedef private_area::tyDistanceInfo<tuGraph> tyInfo;
clArc<tuGraph> * lcArc; cpArcIterator2 lcCurrentArc2; cpNodeIterator lcCurrentNode2; tyInfo * lcInfo1; tyInfo * lcInfo2; cpArcIterator2 lcLastArc2; cpNodeIterator lcLastNode2; tyReal lcNewDistance; clNode<tuGraph> * lcNode; cpNodeS lcNodeS; clNode<tuGraph> * lcStartNode;
cpArcIterator1 lcCurrentArc1 = agGraph.arcs().begin(); cpNodeIterator lcCurrentNode1 = agGraph.nodes().begin(); cpArcIterator2 lcLastArc1 = agGraph.arcs().end(); cpNodeIterator lcLastNode1 = agGraph.nodes().end(); tyMark lcMark1 = ++(agGraph.mark()); tyMark lcMark2 = ++(agGraph.mark()); tyReal lcMaximumCost = 0.0;
// Nodes Initialization // while (lcCurrentNode1!=lcLastNode1) { lcNode=(*lcCurrentNode1).second; lcNode->work()=new_object(tyInfo); ++lcCurrentNode1; }
// Maximum Cost Search // while (lcCurrentArc1!=lcLastArc1) { lcArc=(*lcCurrentArc1).second; if (lcArc->data().unitCost()>lcMaximumCost) lcMaximumCost=lcArc->data().unitCost(); ++lcCurrentArc1; }
lcMaximumCost*=-1.0;
// Negative Cycle Search // lcCurrentNode1=agGraph.nodes().begin(); lcLastNode1=agGraph.nodes().end();
while (lcCurrentNode1!=lcLastNode1) { lcStartNode=(*lcCurrentNode1).second;
if (lcStartNode->mark()!=lcMark2) { // Nodes Initialization // lcCurrentNode2=agGraph.nodes().begin(); lcLastNode2=agGraph.nodes().end();
while (lcCurrentNode2!=lcLastNode2) { lcNode=(*lcCurrentNode2).second; lcInfo1=static_cast<tyInfo *>(lcNode->work()); lcInfo1->distance=realMax(); lcInfo1->predecessor=nil; ++lcCurrentNode2; }
// Start Node Initialization // lcInfo1=static_cast<tyInfo *>(lcStartNode->work()); lcInfo1->distance=0.0; lcNodeS.push_back(lcStartNode); lcStartNode->mark()=lcMark2;
// Cycle Search // while (lcNodeS.size()!=0) { lcNode=lcNodeS.back(); lcNodeS.pop_back(); lcInfo1=static_cast<tyInfo *>(lcNode->work()); lcNode->mark()=lcMark2;
// Outgoing Arcs // lcCurrentArc2=lcNode->outgoingArcs().begin(); lcLastArc2=lcNode->outgoingArcs().end();
while (lcCurrentArc2!=lcLastArc2) { lcArc=(*lcCurrentArc2).second;
if (lcArc->data().flow()<lcArc->data().maximum()) { lcInfo2=static_cast<tyInfo *>(lcArc->targetNode()->work()); lcNewDistance=lcInfo1->distance+lcArc->data().unitCost();
if (lcInfo2->distance>lcNewDistance) { lcInfo2->distance=lcNewDistance; lcInfo2->predecessor=lcArc;
if (lcArc->targetNode()->mark()!=lcMark1) { lcArc->targetNode()->mark()=lcMark1; lcNodeS.push_back(lcArc->targetNode()); }
if (lcNewDistance<agGraph.nodes().size()*lcMaximumCost) { private_area::buildNegativeCycle(agCycle,lcArc->targetNode(),++(agGraph.mark())); deleteNodeWorkspace(agGraph,tyInfo()); return (true); } } }
++lcCurrentArc2; }
// Incoming Arcs // lcCurrentArc2=lcNode->incomingArcs().begin(); lcLastArc2=lcNode->incomingArcs().end();
while (lcCurrentArc2!=lcLastArc2) { lcArc=(*lcCurrentArc2).second;
if (lcArc->data().flow()>lcArc->data().minimum()) { lcInfo2=static_cast<tyInfo *>(lcArc->sourceNode()->work()); lcNewDistance=lcInfo1->distance-lcArc->data().unitCost();
if (lcInfo2->distance>lcNewDistance) { lcInfo2->distance=lcNewDistance; lcInfo2->predecessor=lcArc;
if (lcArc->sourceNode()->mark()!=lcMark1) { lcArc->sourceNode()->mark()=lcMark1; lcNodeS.push_back(lcArc->sourceNode()); }
if (lcNewDistance<agGraph.nodes().size()*lcMaximumCost) { private_area::buildNegativeCycle(agCycle,lcArc->sourceNode(),++(agGraph.mark())); deleteNodeWorkspace(agGraph,tyInfo()); return (true); } } }
++lcCurrentArc2; } } }
++lcCurrentNode1; }
deleteNodeWorkspace(agGraph,tyInfo()); return (false); } }
namespace private_area { //-------------------------------------------------------------------------------BuildNegativeCycle template <tdGraph> void buildNegativeCycle(std_map(clArc<tuGraph> *,tyInteger) & agCycle, clNode<tuGraph> * agStartNode,tyMark agMark) { method_name("BuildNegativeCycle");
typedef private_area::tyDistanceInfo<tuGraph> tyInfo;
clArc<tuGraph> * lcArc; clNode<tuGraph> * lcNode; clNode<tuGraph> * lcFirstNode;
clNode<tuGraph> * lcPredecessor = agStartNode;
agCycle.erase(agCycle.begin(),agCycle.end());
// Cycle Search // do { lcNode=lcPredecessor; lcNode->mark()=agMark; lcArc=static_cast<tyInfo *>(lcNode->work())->predecessor;
if (lcArc->targetNode()==lcNode) lcPredecessor=lcArc->sourceNode(); else lcPredecessor=lcArc->targetNode(); } while (lcPredecessor!=nil and lcPredecessor->mark()!=agMark);
if (lcPredecessor==nil) send_error(erNegativeCycleProblem); lcFirstNode=lcPredecessor;
// Cycle Building // do { lcNode=lcPredecessor; lcArc=static_cast<tyInfo *>(lcNode->work())->predecessor;
if (lcArc->targetNode()==lcNode) { lcPredecessor=lcArc->sourceNode(); agCycle.insert(std_make_pair(lcArc,+1)); } else { lcPredecessor=lcArc->targetNode(); agCycle.insert(std_make_pair(lcArc,-1)); } } while (lcPredecessor!=lcFirstNode and lcPredecessor!=nil); } }
// S o l v e A l g o Implementation //------------------------------------------------------------- namespace public_area { //----------------------------------------------------------------------------------------------Run /*METHOD clSolveAlgo */ /* Solves the minimum cost flow problem using the cycle-canceling method. */ template <tdGraph> tyInteger clSolveAlgo<tuGraph>::run(clGraph<tuGraph> & agGraph) const { method_name("solveAlgo::run");
typedef clArc<tuGraph> cpArc; typedef std_map(cpArc *,tyInteger) cpCycle; typedef clNode<tuGraph> cpNode;
typedef typename cpCycle::const_iterator cpIterator1; typedef typename clNode<tuGraph>::cpArcX::const_iterator cpIterator2;
cpArc * lcArc; cpIterator1 lcCurrentArc1; cpIterator2 lcCurrentArc2; cpCycle lcCycle; tyReal lcIncrement; cpIterator1 lcLastArc1; cpIterator2 lcLastArc2; tyReal lcLeft; tyCardinal lcNbIteration; cpArc * lcReturnLoop;
cpNode * lcSourceNode = firstNode(agGraph); cpNode * lcTargetNode = lastNode(agGraph);
// Compatible Flow Search // lcNbIteration=findCompatibleFlow(agGraph,false); if (not agGraph.solved()) return (lcNbIteration); agGraph.solved()=false;
// Return Loop Adding // if (lcSourceNode==nil or lcTargetNode==nil) send_error(erInvalidFlowGraph);
lcReturnLoop=new_object(cpArc(agGraph,agGraph.getNewArcKey(),prArcData(), lcTargetNode->key(),lcSourceNode->key()));
lcReturnLoop->data().minimum()=prArcData::negativeInfinity(); lcReturnLoop->data().maximum()=prArcData::positiveInfinity(); lcReturnLoop->data().unitCost()=0.0; lcReturnLoop->data().flow()=0.0;
lcCurrentArc2=lcReturnLoop->sourceNode()->incomingArcs().begin(); lcLastArc2=lcReturnLoop->sourceNode()->incomingArcs().end();
while (lcCurrentArc2!=lcLastArc2) { lcReturnLoop->data().flow()+=(*lcCurrentArc2).second->data().flow(); lcCurrentArc2++; }
// Cycle Canceling // while (findNegativeCycle(agGraph,lcCycle)) { lcNbIteration++; lcIncrement=realMax(); lcCurrentArc1=lcCycle.begin(); lcLastArc1=lcCycle.end();
while (lcCurrentArc1!=lcLastArc1) { lcArc=(*lcCurrentArc1).first;
if ((*lcCurrentArc1).second==+1) lcLeft=lcArc->data().maximum()-lcArc->data().flow(); else lcLeft=lcArc->data().flow()-lcArc->data().minimum();
if (lcLeft<lcIncrement) lcIncrement=lcLeft; lcCurrentArc1++; }
increaseFlow(lcCycle,lcIncrement); }
delete_object(lcReturnLoop); agGraph.solved()=true; return (lcNbIteration); } }
// End //------------------------------------------------------------------------------------------- } #undef dll_export #undef tdGraph #undef tuGraph #undef public_area #undef private_area #endif |
//================================================================================================== // G r a p h _ p r o b l e m Implementation // M i n _ c o s t _f l o w // C y c le _ c a n c e l i n g // By Bruno Bachelet //================================================================================================== // Copyright (c) 1999-2016 // Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net // // This file is part of the B++ Library. This library is free software; you can redistribute it // and/or modify it under the terms of the GNU Library General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your option) any later // version. // // This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See // the GNU Library General Public License for more details (http://www.gnu.org).
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "graph_problem/min_cost_flow/cycle_canceling.cpp"
// DLL Belonging //--------------------------------------------------------------------------------- #define GRAPH_PROBLEM_MIN_COST_FLOW_DLL
// Headers //--------------------------------------------------------------------------------------- #include <bpp/graph_problem/min_cost_flow/cycle_canceling.hpp> /*INTERFACE*/
namespace bpp {
// Namespaces //------------------------------------------------------------------------------------ #define public_area graphProblemMinCostFlowCycleCanceling #define private_area graphProblemMinCostFlowCycleCanceling_private #define dll_export DLL_EXPORT
namespace public_area {} namespace private_area {}
static_module_name("Graph_problem/Min_cost_flow/Cycle_canceling");
// Initialization //-------------------------------------------------------------------------------- #undef iniGraphProblemMinCostFlowCycleCanceling static_constant(private_area::clInitializer,goInitializer);
// Errors //---------------------------------------------------------------------------------------- namespace public_area { static_error erNegativeCycleProblem; }
// Constants & Variables //------------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// Static Members //-------------------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// Functions Implementation //---------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// X X X Implementation //------------------------------------------------------------------------- namespace {}
// I n i t i a l i z e r Implementation //--------------------------------------------------------- namespace private_area { //--------------------------------------------------------------------------------------------Start property void clInitializer::start(void) { if (atCounter++ == 0) { try { #include <bpp/modules.hpp> /*NEED*/ registerStop(this); environment::informInitialization(goModuleName);
erNegativeCycleProblem.create("Min Cost Flow - Problem to build the negative cycle."); }
initializer_catch; } } //---------------------------------------------------------------------------------------------Stop property void clInitializer::stop(void) { environment::informTermination(goModuleName); } }
// End //------------------------------------------------------------------------------------------- } |
|