//================================================================================================== // G r a p h _ p r o b l e m Interface // M i n _ c o s t _ f l o w // A l g o r i t h m // 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 provides basic algorithms for the minimum cost flow problem in graphs. */
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "graph_problem/min_cost_flow/algorithm.hpp"
// Guardian //-------------------------------------------------------------------------------------- #ifndef guGraphProblemMinCostFlowAlgorithm #define guGraphProblemMinCostFlowAlgorithm
// Headers //--------------------------------------------------------------------------------------- #include <bpp/graph_problem/min_cost_flow/structure.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 graphProblemMinCostFlowAlgorithm #define private_area graphProblemMinCostFlowAlgorithm_private
namespace public_area { /*NAMESPACE*/ using namespace graphProblemMinCostFlowStructure; } namespace private_area { using namespace public_area; }
extern_module_name;
// Initialization //--------------------------------------------------------------------------------
// Macrocommands //--------------------------------------------------------------------------------- /*ALIAS*/ #define tdGraph class prArcData,class prNodeData //
/*ALIAS*/ #define tuGraph prArcData,prNodeData //
// Types & Classes //------------------------------------------------------------------------------- namespace public_area { //------------------------------------------------------------------------------------------Classes template <tdGraph> class clSolver; }
namespace private_area { template <tdGraph> class clMintyColorForCompatibility1; template <tdGraph> class clMintyColorForCompatibility2; }
// Functions Interface //--------------------------------------------------------------------------- namespace public_area { template <tdGraph> tyBoolean checkCompatibility(const clGraph<tuGraph> &); template <tdGraph> tyBoolean checkFlow(const clGraph<tuGraph> &); template <tdGraph> tyInteger findCompatibleFlow(clGraph<tuGraph> &,tyBoolean); template <tdGraph> void increaseFlow(std_map(clArc<tuGraph> *,tyInteger) &,tyReal); template <tdGraph> tyReal totalCost(const clGraph<tuGraph> &); }
namespace private_area { testing_mode ( function void test(void); ) }
// Errors //---------------------------------------------------------------------------------------- namespace public_area {}
// Constants & Variables //------------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// S o l v e r Interface //------------------------------------------------------------------------ namespace public_area { /*CLASS clSolver */ /* Represents a solver for the minimum cost flow problem with linear costs in a graph. It is an abstract class. */ template <tdGraph> class clSolver { //-----------------------------------------------------------------------------------------Private private_property constructor clSolver(const clSolver &); private_property clSolver & operator = (const clSolver &); //------------------------------------------------------------------------------------------Public public_property constructor clSolver(void); public_property virtual destructor clSolver(void);
/*AMETHOD clSolver */ /* Solves the minimum cost flow problem in a graph. Abstract method. */ public_property virtual tyInteger run(clGraph<tuGraph> & agGraph) const = 0; }; }
// M i n t y C o l o r F o r C o m p a t i b i l i t y 1 Interface //------------------------------ namespace private_area { template <tdGraph> class clMintyColorForCompatibility1 { //-------------------------------------------------------------------------------------------Types public_property typedef clArc<tuGraph> cpArc; //-----------------------------------------------------------------------------------------Private private_property constructor clMintyColorForCompatibility1(const clMintyColorForCompatibility1 &);
private_property clMintyColorForCompatibility1 & operator = (const clMintyColorForCompatibility1 &); //------------------------------------------------------------------------------------------Public public_property constructor clMintyColorForCompatibility1(void) {} public_property destructor clMintyColorForCompatibility1(void) {}
public_property tyBoolean red(const cpArc &) const; public_property tyBoolean black(const cpArc &) const; public_property tyBoolean blue(const cpArc &) const; public_property tyBoolean green(const cpArc &) const;
public_property tcString color(const cpArc &) const; }; }
// M i n t y C o l o r F o r C o m p a t i b i l i t y 2 Interface //------------------------------ namespace private_area { template <tdGraph> class clMintyColorForCompatibility2 { //-------------------------------------------------------------------------------------------Types public_property typedef clArc<tuGraph> cpArc; //-----------------------------------------------------------------------------------------Private private_property constructor clMintyColorForCompatibility2(const clMintyColorForCompatibility2 &);
private_property clMintyColorForCompatibility2 & operator = (const clMintyColorForCompatibility2 &); //------------------------------------------------------------------------------------------Public public_property constructor clMintyColorForCompatibility2(void) {} public_property destructor clMintyColorForCompatibility2(void) {}
public_property tyBoolean red(const cpArc &) const; public_property tyBoolean black(const cpArc &) const; public_property tyBoolean blue(const cpArc &) const; public_property tyBoolean green(const cpArc &) const;
public_property tcString color(const cpArc &) const; }; }
// Functions Inline //------------------------------------------------------------------------------ namespace public_area {} namespace private_area {}
// S o l v e r Inline //--------------------------------------------------------------------------- namespace public_area { //--------------------------------------------------------------------------------------Constructor /*METHOD clSolver */ /* Builds a solver for the minimum cost flow problem in a graph. */ template <tdGraph> inline clSolver<tuGraph>::clSolver(void) {} //---------------------------------------------------------------------------------------Destructor /*METHOD clSolver */ /* Destructs the solver. */ template <tdGraph> inline clSolver<tuGraph>::~clSolver(void) {} }
// M i n t y C o l o r F o r C o m p a t i b i l i t y 1 Inline //--------------------------------- namespace private_area { //----------------------------------------------------------------------------------------------Red template <tdGraph> inline tyBoolean clMintyColorForCompatibility1<tuGraph>::red(const cpArc & agArc) const { return (agArc.data().flow()==agArc.data().minimum() and agArc.data().flow()==agArc.data().maximum()); } //--------------------------------------------------------------------------------------------Black template <tdGraph> inline tyBoolean clMintyColorForCompatibility1<tuGraph>::black(const cpArc & agArc) const { return (agArc.data().flow()<agArc.data().maximum()); } //---------------------------------------------------------------------------------------------Blue template <tdGraph> inline tyBoolean clMintyColorForCompatibility1<tuGraph>::blue(const cpArc & agArc) const { return (agArc.data().flow()>agArc.data().minimum()); } //--------------------------------------------------------------------------------------------Green template <tdGraph> inline tyBoolean clMintyColorForCompatibility1<tuGraph>::green(const cpArc & agArc) const { return (agArc.data().flow()>agArc.data().minimum() and agArc.data().flow()<agArc.data().maximum()); } }
// M i n t y C o l o r F o r C o m p a t i b i l i t y 2 Inline //--------------------------------- namespace private_area { //----------------------------------------------------------------------------------------------Red template <tdGraph> inline tyBoolean clMintyColorForCompatibility2<tuGraph>::red(const cpArc & agArc) const { return (agArc.data().flow()==agArc.data().minimum() and agArc.data().flow()==agArc.data().maximum()); } //--------------------------------------------------------------------------------------------Black template <tdGraph> inline tyBoolean clMintyColorForCompatibility2<tuGraph>::black(const cpArc & agArc) const { return (agArc.data().flow()>agArc.data().minimum()); } //---------------------------------------------------------------------------------------------Blue template <tdGraph> inline tyBoolean clMintyColorForCompatibility2<tuGraph>::blue(const cpArc & agArc) const { return (agArc.data().flow()<agArc.data().maximum()); } //--------------------------------------------------------------------------------------------Green template <tdGraph> inline tyBoolean clMintyColorForCompatibility2<tuGraph>::green(const cpArc & agArc) const { return (agArc.data().flow()>agArc.data().minimum() and agArc.data().flow()<agArc.data().maximum()); } }
// Function Implementation //----------------------------------------------------------------------- namespace public_area { //-------------------------------------------------------------------------------CheckCompatibility /*FUNCTION*/ /* Verifies that the flow in a graph is compatible with the capacity boundaries (<CODE>true</CODE> = compatible). */ template <tdGraph> tyBoolean checkCompatibility(const clGraph<tuGraph> & agGraph) { typedef typename clGraph<tuGraph>::cpArcX::const_iterator clArcIterator;
tyBoolean lcCompatible = true; clArcIterator lcCurrentArc = agGraph.arcs().begin(); clArcIterator lcLastArc = agGraph.arcs().end();
clArc<tuGraph> * lcArc;
while (lcCurrentArc!=lcLastArc and lcCompatible) { lcArc=(*lcCurrentArc).second;
if (lcArc->data().flow()<lcArc->data().minimum() or lcArc->data().flow()>lcArc->data().maximum()) lcCompatible=false;
lcCurrentArc++; }
return (lcCompatible); } //----------------------------------------------------------------------------------------CheckFlow /*FUNCTION*/ /* Verifies that the supposed flow in a graph is really a flow (<CODE>true</CODE> = valid). */ template <tdGraph> tyBoolean checkFlow(const clGraph<tuGraph> & agGraph) { method_name("checkFlow");
typedef typename clGraph<tuGraph>::cpNodeX::const_iterator clNodeIterator; typedef typename clNode<tuGraph>::cpArcX::const_iterator clArcIterator;
tyReal lcFlow;
clNodeIterator lcCurrentNode = agGraph.nodes().begin(); clNodeIterator lcLastNode = agGraph.nodes().end(); clNode<tuGraph> * lcSourceNode = firstNode(agGraph); clNode<tuGraph> * lcTargetNode = lastNode(agGraph);
if (lcSourceNode==nil or lcTargetNode==nil) send_error(erInvalidFlowGraph);
clArcIterator lcCurrentArc = lcSourceNode->outgoingArcs().begin(); clArcIterator lcLastArc = lcSourceNode->outgoingArcs().end(); tyReal lcMainFlow = 0.0; tyBoolean lcValid = true;
while (lcCurrentArc!=lcLastArc) { lcMainFlow+=(*lcCurrentArc).second->data().flow(); lcCurrentArc++; }
while (lcCurrentNode!=lcLastNode and lcValid) { if ((*lcCurrentNode).second!=lcSourceNode) { lcFlow=0.0; lcCurrentArc=(*lcCurrentNode).second->incomingArcs().begin(); lcLastArc=(*lcCurrentNode).second->incomingArcs().end();
while (lcCurrentArc!=lcLastArc) { lcFlow+=(*lcCurrentArc).second->data().flow(); lcCurrentArc++; }
if ((*lcCurrentNode).second==lcTargetNode) lcFlow-=lcMainFlow; else { lcCurrentArc=(*lcCurrentNode).second->outgoingArcs().begin(); lcLastArc=(*lcCurrentNode).second->outgoingArcs().end();
while (lcCurrentArc!=lcLastArc) { lcFlow-=(*lcCurrentArc).second->data().flow(); lcCurrentArc++; } }
if (lcFlow!=0.0) lcValid=false; }
lcCurrentNode++; }
return (lcValid); } //-------------------------------------------------------------------------------FindCompatibleFlow /*FUNCTION*/ /* Finds a compatible flow in a graph. The second argument is set to <CODE>true</CODE> if the algorithm has to consider the current flow of the graph, which is supposed to help it. */ template <tdGraph> tyInteger findCompatibleFlow(clGraph<tuGraph> & agGraph,tyBoolean agKeepFlow) { method_name("findCompatibleFlow");
typedef clArc<tuGraph> cpArc; typedef std_map(cpArc *,tyInteger) cpCocycle; typedef std_map(cpArc *,tyInteger) cpCycle; typedef clNode<tuGraph> cpNode;
typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpIterator1; typedef typename cpCocycle::const_iterator cpIterator2; typedef typename clNode<tuGraph>::cpArcX::const_iterator cpIterator3;
cpArc * lcArc; cpArc * lcArc2; cpCocycle lcCocycle; cpIterator1 lcCurrentArc1; cpIterator2 lcCurrentArc2; cpIterator3 lcCurrentArc3; cpCycle lcCycle; tyReal lcIncrement; cpIterator1 lcLastArc1; cpIterator2 lcLastArc2; cpIterator3 lcLastArc3; cpArc * lcReturnLoop;
private_area::clMintyColorForCompatibility1<tuGraph> lcMintyColor1; private_area::clMintyColorForCompatibility2<tuGraph> lcMintyColor2;
tyCardinal lcNbIteration = 0; cpNode * lcSourceNode = firstNode(agGraph); cpNode * lcTargetNode = lastNode(agGraph);
agGraph.solved()=false;
// Flow Initialization // if (not agKeepFlow) { lcCurrentArc1=agGraph.arcs().begin(); lcLastArc1=agGraph.arcs().end();
while (lcCurrentArc1!=lcLastArc1) { (*lcCurrentArc1).second->data().flow()=0.0; lcCurrentArc1++; } }
// 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().flow()=0.0;
if (agKeepFlow) { lcCurrentArc3=lcReturnLoop->sourceNode()->incomingArcs().begin(); lcLastArc3=lcReturnLoop->sourceNode()->incomingArcs().end();
while (lcCurrentArc3!=lcLastArc3) { lcReturnLoop->data().flow()+=(*lcCurrentArc3).second->data().flow(); lcCurrentArc3++; } }
// Flow Improving // lcCurrentArc1=agGraph.arcs().begin(); lcLastArc1=agGraph.arcs().end();
while (lcCurrentArc1!=lcLastArc1) { lcArc=(*lcCurrentArc1).second;
// Flow Increase // if (lcArc->data().flow()<lcArc->data().minimum()) { while (lcArc->data().flow()<lcArc->data().minimum() and findMintyCycle(*lcArc,lcMintyColor1,lcCycle,lcCocycle)) { lcNbIteration++; lcCurrentArc2=lcCycle.begin(); lcLastArc2=lcCycle.end(); lcIncrement=realMax();
while (lcCurrentArc2!=lcLastArc2) { lcArc2=(*lcCurrentArc2).first;
if ((*lcCurrentArc2).second==+1) lcIncrement=mini(lcArc2->data().maximum()-lcArc2->data().flow(),lcIncrement); else lcIncrement=mini(lcArc2->data().flow()-lcArc2->data().minimum(),lcIncrement);
lcCurrentArc2++; }
increaseFlow(lcCycle,lcIncrement); }
if (lcArc->data().flow()<lcArc->data().minimum()) { delete_object(lcReturnLoop); return (-1); } }
// Flow Decrease // else if (lcArc->data().flow()>lcArc->data().maximum()) { while (lcArc->data().flow()>lcArc->data().maximum() and findMintyCycle(*lcArc,lcMintyColor2,lcCycle,lcCocycle)) { lcNbIteration++; lcCurrentArc2=lcCycle.begin(); lcLastArc2=lcCycle.end(); lcIncrement=realMax();
while (lcCurrentArc2!=lcLastArc2) { lcArc2=(*lcCurrentArc2).first;
if ((*lcCurrentArc2).second==+1) lcIncrement=mini(lcArc2->data().flow()-lcArc2->data().minimum(),lcIncrement); else lcIncrement=mini(lcArc2->data().maximum()-lcArc2->data().flow(),lcIncrement);
lcCurrentArc2++; }
increaseFlow(lcCycle,-lcIncrement); }
if (lcArc->data().flow()>lcArc->data().maximum()) { delete_object(lcReturnLoop); return (-1); } }
lcCurrentArc1++; }
agGraph.solved()=true; delete_object(lcReturnLoop); return (lcNbIteration); } //-------------------------------------------------------------------------------------IncreaseFlow /*FUNCTION*/ /* Increases the flow in a cycle of a given value. */ template <tdGraph> void increaseFlow(std_map(clArc<tuGraph> *,tyInteger) & agCycle,tyReal agValue) { typedef typename std_map(clArc<tuGraph> *,tyInteger)::const_iterator cpIterator;
cpIterator lcCurrentArc = agCycle.begin(); cpIterator lcLastArc = agCycle.end();
while (lcCurrentArc!=lcLastArc) { if ((*lcCurrentArc).second==+1) (*lcCurrentArc).first->data().flow()+=agValue; else (*lcCurrentArc).first->data().flow()-=agValue;
lcCurrentArc++; } } //----------------------------------------------------------------------------------------TotalCost /*FUNCTION*/ /* Computes the total cost of a flow in a graph. */ template <tdGraph> tyReal totalCost(const clGraph<tuGraph> & agGraph) { typedef typename clGraph<tuGraph>::cpArcX::const_iterator clArcIterator;
tyReal lcCost = 0.0; clArcIterator lcCurrentArc = agGraph.arcs().begin(); clArcIterator lcLastArc = agGraph.arcs().end();
while (lcCurrentArc!=lcLastArc) { lcCost+=(*lcCurrentArc).second->data().cost(); lcCurrentArc++; }
return (lcCost); } }
// M i n t y C o l o r F o r C o m p a t i b i l i t y 1 Implementation //------------------------- namespace private_area { //--------------------------------------------------------------------------------------------Color template <tdGraph> tcString clMintyColorForCompatibility1<tuGraph>::color(const cpArc & agArc) const { if (red(agArc)) return ("red"); if (black(agArc)) return ("black"); if (blue(agArc)) return ("blue"); return ("green"); } }
// M i n t y C o l o r F o r C o m p a t i b i l i t y 2 Implementation //------------------------- namespace private_area { //--------------------------------------------------------------------------------------------Color template <tdGraph> tcString clMintyColorForCompatibility2<tuGraph>::color(const cpArc & agArc) const { if (red(agArc)) return ("red"); if (black(agArc)) return ("black"); if (blue(agArc)) return ("blue"); return ("green"); } }
// End //------------------------------------------------------------------------------------------- } #undef dll_export #undef public_area #undef private_area #undef tdGraph #undef tuGraph #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 // A l g o r i t h m // 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/algorithm.cpp"
// DLL Belonging //--------------------------------------------------------------------------------- #define GRAPH_PROBLEM_MIN_COST_FLOW_DLL
// Headers //--------------------------------------------------------------------------------------- #include <bpp/graph_problem/min_cost_flow/algorithm.hpp> /*INTERFACE*/
namespace bpp {
// Namespaces //------------------------------------------------------------------------------------ #define public_area graphProblemMinCostFlowAlgorithm #define private_area graphProblemMinCostFlowAlgorithm_private #define dll_export DLL_EXPORT
namespace public_area {} namespace private_area {}
static_module_name("Graph_problem/Min_cost_flow/Algorithm");
// Initialization //--------------------------------------------------------------------------------
// Errors //---------------------------------------------------------------------------------------- namespace public_area {}
// 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 {}
// End //------------------------------------------------------------------------------------------- } |
|