//================================================================================================== // G r a p h _ p r o b l e m Interface // M i n _ c o s t _ t e n s i o n // D u a l _ c o s t _ s c a 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 an algorithm to solve the minimum cost tension problem in graphs with integer values. It solves a Lagrangian relaxation of the minimum cost tension problem, which is a minimum cost flow problem. The resolution is performed with the cost-scaling algorithm. The cost functions of the arcs are linear as defined by the <CODE>clLinearArcData</CODE> class of the <CODE>Structure</CODE> module. */
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "graph_problem/min_cost_tension/dual_cost_scaling.hpp"
// Guardian //-------------------------------------------------------------------------------------- #ifndef guGraphProblemMinCostTensionDualCostScaling #define guGraphProblemMinCostTensionDualCostScaling
// Headers //--------------------------------------------------------------------------------------- #include <bpp/graph_problem/min_cost_flow.hpp> /*INCLUDE*/ #include <bpp/graph_problem/min_cost_tension/algorithm.hpp> /*INCLUDE*/ #include <bpp/graph_problem/shortest_path.hpp> /*INCLUDE*/ #include <bpp/graph_problem/tension.hpp> /*INCLUDE*/
namespace bpp {
// Importation/Exportation //----------------------------------------------------------------------- #ifdef GRAPH_PROBLEM_MIN_COST_TENSION_DLL #define dll_export DLL_EXPORT #else #define dll_export DLL_IMPORT #endif
// Namespaces //------------------------------------------------------------------------------------ #define public_area graphProblemMinCostTensionDualCostScaling #define private_area graphProblemMinCostTensionDualCostScaling_private
namespace public_area { /*NAMESPACE*/ using namespace graphProblemMinCostTensionAlgorithm; }
namespace private_area { using namespace public_area; using namespace graphProblemShortestPath; }
extern_module_name;
// Initialization //-------------------------------------------------------------------------------- #define iniGraphProblemMinCostTensionDualCostScaling has_initializer;
// Macrocommands //--------------------------------------------------------------------------------- /*ALIAS*/ #define tdGraph class prArcData,class prNodeData //
/*ALIAS*/ #define tuGraph prArcData,prNodeData //
// Types & Classes //------------------------------------------------------------------------------- namespace public_area { template <tdGraph> class clSolveAlgo; }
namespace private_area { //------------------------------------------------------------------------------------------Classes template <tdGraph> class clPiecewiseConformity;
class clRelaxedArcData; //-----------------------------------------------------------------------------------Variable Types typedef graphProblemMinCostTensionStructure::clNodeData clRelaxedNodeData; typedef clArc<clRelaxedArcData,clRelaxedNodeData> clRelaxedArc; typedef clGraph<clRelaxedArcData,clRelaxedNodeData> clRelaxedGraph; typedef clNode<clRelaxedArcData,clRelaxedNodeData> clRelaxedNode;
typedef clPiecewiseConformity<clRelaxedArcData,clRelaxedNodeData> clRelaxedConformity; }
// Functions Interface //--------------------------------------------------------------------------- namespace public_area {}
namespace private_area { function void buildResidualGraph(clLengthGraph &,clRelaxedGraph &,std_vector(clLengthArc *) &);
template <tdGraph> tyBoolean relaxMinCostTension(clRelaxedGraph &,clGraph<tuGraph> &,tyNodeKey &,tyNodeKey &);
testing_mode ( function void test(void); ) }
// Errors //---------------------------------------------------------------------------------------- namespace public_area {}
// 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 tension problem in a graph using the cost-scaling method on a dual minimum cost flow problem. */ template <tdGraph> class clSolveAlgo : public clLinearSolver<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 virtual tyInteger run(clGraph<tuGraph> &) const; }; }
// P i e c e w i s e C o n f o r m i t y Interface //---------------------------------------------- namespace private_area { template <tdGraph> class clPiecewiseConformity { //-------------------------------------------------------------------------------------------Types public_property typedef clArc<tuGraph> cpArc; //-----------------------------------------------------------------------------------------Private private_property constructor clPiecewiseConformity(const clPiecewiseConformity &); private_property clPiecewiseConformity & operator = (const clPiecewiseConformity &); //------------------------------------------------------------------------------------------Public public_property constructor clPiecewiseConformity(void) {} public_property destructor clPiecewiseConformity(void) {}
public_property tyReal leftBoundary(const cpArc &) const; public_property tyReal rightBoundary(const cpArc &) const; public_property tyReal leftDerivative(const cpArc &) const; public_property tyReal rightDerivative(const cpArc &) const; public_property tyReal maximumDerivative(const cpArc &) const; public_property void nullCost(cpArc &) const; }; }
// R e l a x e d A r c D a t a Interface //-------------------------------------------------------- namespace private_area { class clRelaxedArcData { //-----------------------------------------------------------------------------------------Friends friend class private_area::clInitializer; //-----------------------------------------------------------------------------------------Private private_property static tyReal atNegativeInfinity; private_property static tyReal atPositiveInfinity; //------------------------------------------------------------------------------------------Public read_write_attribute(tyReal,atMinimumTension,minimumTension); read_write_attribute(tyReal,atMaximumTension,maximumTension); read_write_attribute(tyReal,atOptimumTension,optimumTension);
read_write_attribute(tyReal,atShrinkingCost,shrinkingCost); read_write_attribute(tyReal,atStretchingCost,stretchingCost);
read_write_attribute(tyReal,atMinimum,minimum); read_write_attribute(tyReal,atMaximum,maximum); read_write_attribute(tyReal,atFlow,flow);
public_property static tyReal negativeInfinity(void) { return (atNegativeInfinity); } public_property static tyReal positiveInfinity(void) { return (atPositiveInfinity); }
public_property constructor clRelaxedArcData(void); public_property constructor clRelaxedArcData(const clRelaxedArcData &); public_property constructor clRelaxedArcData(clInStream &,tyBoolean) {} public_property destructor clRelaxedArcData(void) {}
public_property void out(clOutStream &,tyBoolean) 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 tension problem in a graph. */ template <tdGraph> inline clSolveAlgo<tuGraph>::clSolveAlgo(void) {} //---------------------------------------------------------------------------------------Destructor /*METHOD clSolveAlgo */ /* Destructs the algorithm. */ template <tdGraph> inline clSolveAlgo<tuGraph>::~clSolveAlgo(void) {} }
// P i e c e w i s e C o n f o r m i t y Inline //------------------------------------------------- namespace private_area { //-------------------------------------------------------------------------------------LeftBoundary template <tdGraph> inline tyReal clPiecewiseConformity<tuGraph>::leftBoundary(const cpArc & agArc) const { tyReal lcTension = agArc.targetNode()->data().potential()-agArc.sourceNode()->data().potential();
if (lcTension>agArc.data().maximumTension()) return (agArc.data().maximum()); if (lcTension>agArc.data().optimumTension()) return (agArc.data().stretchingCost()); if (lcTension>agArc.data().minimumTension()) return (-agArc.data().shrinkingCost()); return (agArc.data().minimum()); } //------------------------------------------------------------------------------------RightBoundary template <tdGraph> inline tyReal clPiecewiseConformity<tuGraph>::rightBoundary(const cpArc & agArc) const { tyReal lcTension = agArc.targetNode()->data().potential()-agArc.sourceNode()->data().potential();
if (lcTension>=agArc.data().maximumTension()) return (agArc.data().maximum()); if (lcTension>=agArc.data().optimumTension()) return (agArc.data().stretchingCost()); if (lcTension>=agArc.data().minimumTension()) return (-agArc.data().shrinkingCost()); return (agArc.data().minimum()); } //-----------------------------------------------------------------------------------LeftDerivative template <tdGraph> inline tyReal clPiecewiseConformity<tuGraph>::leftDerivative(const cpArc & agArc) const { tyReal lcFlow = agArc.data().flow();
if (lcFlow <= -agArc.data().shrinkingCost()) return (agArc.data().minimumTension()); if (lcFlow<=agArc.data().stretchingCost()) return (agArc.data().optimumTension()); return (agArc.data().maximumTension()); } //----------------------------------------------------------------------------------RightDerivative template <tdGraph> inline tyReal clPiecewiseConformity<tuGraph>::rightDerivative(const cpArc & agArc) const { tyReal lcFlow = agArc.data().flow();
if (lcFlow < -agArc.data().shrinkingCost()) return (agArc.data().minimumTension()); if (lcFlow<agArc.data().stretchingCost()) return (agArc.data().optimumTension()); return (agArc.data().maximumTension()); } //--------------------------------------------------------------------------------MaximumDerivative template <tdGraph> inline tyReal clPiecewiseConformity<tuGraph>::maximumDerivative(const cpArc & agArc) const { return (agArc.data().maximumTension()); } //-----------------------------------------------------------------------------------------NullCost template <tdGraph> inline void clPiecewiseConformity<tuGraph>::nullCost(cpArc & agArc) const { agArc.data().shrinkingCost()=0.0; agArc.data().stretchingCost()=0.0; agArc.data().minimumTension()=0.0; agArc.data().optimumTension()=0.0; agArc.data().maximumTension()=0.0; } }
// R e l a x e d A r c D a t a Inline //----------------------------------------------------------- namespace private_area { //--------------------------------------------------------------------------------------Constructor inline clRelaxedArcData::clRelaxedArcData(void) : atMinimumTension(0.0),atMaximumTension(0.0),atOptimumTension(0.0),atShrinkingCost(0.0), atStretchingCost(0.0),atMinimum(0.0),atMaximum(0.0),atFlow(0.0) {} //--------------------------------------------------------------------------------------Constructor inline clRelaxedArcData::clRelaxedArcData(const clRelaxedArcData & agData) : atMinimumTension(agData.atMinimumTension),atMaximumTension(agData.atMaximumTension), atOptimumTension(agData.atOptimumTension),atShrinkingCost(agData.atShrinkingCost), atStretchingCost(agData.atStretchingCost),atMinimum(agData.atMinimum), atMaximum(agData.atMaximum),atFlow(agData.atFlow) {} //----------------------------------------------------------------------------------------------Out inline void clRelaxedArcData::out(clOutStream & agStream,tyBoolean) const { if (atMinimumTension==realMin()) agStream << "-oo , "; else agStream << atMinimumTension << " , ";
if (atMaximumTension==realMax()) agStream << "+oo , "; else agStream << atMaximumTension << " , ";
agStream << atOptimumTension << " ; " << atShrinkingCost << " , " << atStretchingCost << " ; "; agStream << atMinimum << " , " << atMaximum << " ; " << atFlow; } }
// Functions Implementation //---------------------------------------------------------------------- namespace private_area { //------------------------------------------------------------------------------RelaxMinCostTension template <tdGraph> tyBoolean relaxMinCostTension(clRelaxedGraph & agRelaxedGraph,clGraph<tuGraph> & agGraph, tyNodeKey & agSourceKey,tyNodeKey & agTargetKey) { typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpArcIterator; typedef typename clGraph<tuGraph>::cpNodeX::const_iterator cpNodeIterator1; typedef clRelaxedGraph::cpNodeX::const_iterator clNodeIterator2;
cpArcIterator lcCurrentArc = agGraph.arcs().begin(); cpNodeIterator1 lcCurrentNode1 = agGraph.nodes().begin(); cpArcIterator lcLastArc = agGraph.arcs().end(); cpNodeIterator1 lcLastNode1 = agGraph.nodes().end();
clArc<tuGraph> * lcArc1; clRelaxedArc * lcArc2; clNodeIterator2 lcCurrentNode2; tyReal lcFlowBoundary; clNodeIterator2 lcLastNode2; clRelaxedNode * lcNode; clRelaxedNode * lcSourceNode; clRelaxedNode * lcTargetNode;
// Flow Boundary Search // graphProblemTensionAlgorithm::clCompatibleTensionAlgo<tuGraph>::defaultRun(agGraph); if (not agGraph.solved()) return (false); agGraph.solved()=false; lcFlowBoundary=graphProblemMinCostTensionAlgorithm::totalCost(agGraph)+1.0;
// Nodes Duplication // while (lcCurrentNode1!=lcLastNode1) { new_object(clRelaxedNode(agRelaxedGraph,(*lcCurrentNode1).first,clRelaxedNodeData())); ++lcCurrentNode1; }
// Arcs Duplication // while (lcCurrentArc!=lcLastArc) { lcArc1=(*lcCurrentArc).second;
lcArc2=new_object(clRelaxedArc(agRelaxedGraph,lcArc1->key(),clRelaxedArcData(), lcArc1->sourceNode()->key(),lcArc1->targetNode()->key()));
lcArc2->data().minimumTension()=lcArc1->data().minimum(); lcArc2->data().maximumTension()=lcArc1->data().maximum(); lcArc2->data().optimumTension()=lcArc1->data().optimum(); lcArc2->data().stretchingCost()=lcArc1->data().stretchingCost(); lcArc2->data().shrinkingCost()=lcArc1->data().shrinkingCost(); lcArc2->data().minimum()=-lcFlowBoundary; lcArc2->data().maximum()=lcFlowBoundary; ++lcCurrentArc; }
// Source & Target Nodes Adding // agSourceKey=agRelaxedGraph.getNewNodeKey(); lcSourceNode=new_object(clRelaxedNode(agRelaxedGraph,agSourceKey,clRelaxedNodeData())); agTargetKey=agRelaxedGraph.getNewNodeKey(); lcTargetNode=new_object(clRelaxedNode(agRelaxedGraph,agTargetKey,clRelaxedNodeData()));
lcCurrentNode2=agRelaxedGraph.nodes().begin(); lcLastNode2=agRelaxedGraph.nodes().end();
while (lcCurrentNode2!=lcLastNode2) { lcNode=(*lcCurrentNode2).second;
if (lcNode!=lcSourceNode and lcNode->incomingArcs().size()==0) new_object(clRelaxedArc(agRelaxedGraph,agRelaxedGraph.getNewArcKey(),clRelaxedArcData(), agSourceKey,lcNode->key()));
if (lcNode!=lcTargetNode and lcNode->outgoingArcs().size()==0) new_object(clRelaxedArc(agRelaxedGraph,agRelaxedGraph.getNewArcKey(),clRelaxedArcData(), lcNode->key(),agTargetKey));
++lcCurrentNode2; }
return (true); } }
// S o l v e A l g o Implementation //------------------------------------------------------------- namespace public_area { //----------------------------------------------------------------------------------------------Run /*METHOD clSolveAlgo */ /* Solves the minimum cost tension problem in a graph. */ template <tdGraph> tyInteger clSolveAlgo<tuGraph>::run(clGraph<tuGraph> & agGraph) const { typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpArcIterator1; typedef std_vector(private_area::clLengthArc *) clArcS; typedef clArcS::const_iterator clArcIterator2;
typedef graphProblemShortestPath::clFordAlgo<dataStructure::clLengthData,dataStructure::clNoData> clShortestPathAlgo;
typedef clShortestPathAlgo::cpWorkspace clWorkspace;
clArc<tuGraph> * lcArc1; private_area::clLengthArc * lcArc2; clArcS lcAssociation; private_area::clRelaxedConformity lcConformity; cpArcIterator1 lcCurrentArc1; clArcIterator2 lcCurrentArc2; tyInteger lcIteration; cpArcIterator1 lcLastArc1; clArcS lcPath; private_area::clRelaxedGraph lcRelaxedGraph; private_area::clLengthGraph lcResidualGraph; tyNodeKey lcSourceKey; tyNodeKey lcTargetKey;
// Relaxed Problem Resolution // agGraph.solved()=false;
if (not private_area::relaxMinCostTension(lcRelaxedGraph,agGraph,lcSourceKey,lcTargetKey)) return (-1);
lcIteration=graphProblemMinCostFlowCostScaling::findMinimumCostFlow(lcRelaxedGraph,lcConformity);
if (lcRelaxedGraph.solved()) { // Integer Tension Building // delete_object(&(lcRelaxedGraph.node(lcSourceKey))); delete_object(&(lcRelaxedGraph.node(lcTargetKey))); private_area::buildResidualGraph(lcResidualGraph,lcRelaxedGraph,lcAssociation);
clShortestPathAlgo(true).run(lcResidualGraph,(*(lcResidualGraph.nodes().begin())).first, (*(lcResidualGraph.nodes().begin())).first,lcPath);
// Tension Computation // lcCurrentArc1=agGraph.arcs().begin(); lcLastArc1=agGraph.arcs().end(); lcCurrentArc2=lcAssociation.begin();
while (lcCurrentArc1!=lcLastArc1) { lcArc1=(*lcCurrentArc1).second; lcArc2=*lcCurrentArc2;
lcArc1->data().tension()=static_cast<clWorkspace *>(lcArc2->targetNode()->work())->potential() -static_cast<clWorkspace *>(lcArc2->sourceNode()->work())->potential();
++lcCurrentArc1; ++lcCurrentArc2; }
deleteNodeWorkspace(lcResidualGraph,clWorkspace()); }
agGraph.solved()=lcRelaxedGraph.solved(); return (lcIteration); } }
// 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 _ t e n s i o n // D u a l _ c o s t _ s c a 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_tension/dual_cost_scaling.cpp"
// DLL Belonging //--------------------------------------------------------------------------------- #define GRAPH_PROBLEM_MIN_COST_TENSION_DLL
// Headers //--------------------------------------------------------------------------------------- #include <bpp/graph_problem/min_cost_tension/dual_cost_scaling.hpp> /*INTERFACE*/
namespace bpp {
// Namespaces //------------------------------------------------------------------------------------ #define public_area graphProblemMinCostTensionDualCostScaling #define private_area graphProblemMinCostTensionDualCostScaling_private #define dll_export DLL_EXPORT
namespace public_area {} namespace private_area {}
static_module_name("Graph_problem/Min_cost_tension/Dual_cost_scaling");
// Initialization //-------------------------------------------------------------------------------- #undef iniGraphProblemMinCostTensionDualCostScaling static_constant(private_area::clInitializer,goInitializer);
// Errors //---------------------------------------------------------------------------------------- namespace public_area {}
// Constants & Variables //------------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// Static Members //-------------------------------------------------------------------------------- namespace public_area {}
namespace private_area { property tyReal clRelaxedArcData::atNegativeInfinity; property tyReal clRelaxedArcData::atPositiveInfinity; }
// Functions Implementation //---------------------------------------------------------------------- namespace public_area {}
namespace private_area { //-------------------------------------------------------------------------------BuildResidualGraph function void buildResidualGraph(clLengthGraph & agResidualGraph,clRelaxedGraph & agGraph, std_vector(clLengthArc *) & agArcS) { typedef clRelaxedGraph::cpArcX::const_iterator clArcIterator; typedef clRelaxedGraph::cpNodeX::const_iterator clNodeIterator;
clRelaxedArc * lcArc1; clLengthArc * lcArc2;
private_area::clRelaxedConformity lcConformity;
clArcIterator lcCurrentArc = agGraph.arcs().begin(); clNodeIterator lcCurrentNode = agGraph.nodes().begin(); clArcIterator lcLastArc = agGraph.arcs().end(); clNodeIterator lcLastNode = agGraph.nodes().end();
// Nodes Duplication // while (lcCurrentNode!=lcLastNode) { new_object(clLengthNode(agResidualGraph,(*lcCurrentNode).first,dataStructure::clNoData())); ++lcCurrentNode; }
// Arcs Duplication // agArcS.reserve(agGraph.arcs().size()); lcCurrentArc=agGraph.arcs().begin();
while (lcCurrentArc!=lcLastArc) { lcArc1=(*lcCurrentArc).second;
lcArc2=new_object(clLengthArc(agResidualGraph,agResidualGraph.getNewArcKey(), dataStructure::clLengthData(),lcArc1->sourceNode()->key(), lcArc1->targetNode()->key()));
lcArc2->data().length()=lcConformity.rightDerivative(*lcArc1); agArcS.push_back(lcArc2);
lcArc2=new_object(clLengthArc(agResidualGraph,agResidualGraph.getNewArcKey(), dataStructure::clLengthData(),lcArc1->targetNode()->key(), lcArc1->sourceNode()->key()));
lcArc2->data().length()=-(lcConformity.leftDerivative(*lcArc1)); ++lcCurrentArc; } } }
// 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);
clRelaxedArcData::atNegativeInfinity = realMin(); clRelaxedArcData::atPositiveInfinity = realMax(); }
initializer_catch; } } //---------------------------------------------------------------------------------------------Stop property void clInitializer::stop(void) { environment::informTermination(goModuleName); } }
// End //------------------------------------------------------------------------------------------- } |
|