//================================================================================================== // 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 // B r a n c h _ b o u n d // 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 branch-and-bound algorithms to solve the minimum cost tension problem with binary costs, as defined by the <CODE>clBinaryArcData</CODE> class of the <CODE>Structure</CODE> module. */
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "graph_problem/min_cost_tension/branch_bound.hpp"
// Guardian //-------------------------------------------------------------------------------------- #ifndef guGraphProblemMinCostTensionBranchBound #define guGraphProblemMinCostTensionBranchBound
// Headers //--------------------------------------------------------------------------------------- #include <bpp/graph_problem/min_cost_tension/aggregation_binary.hpp> /*INCLUDE*/ #include <bpp/graph_problem/min_cost_tension/heuristic_binary.hpp> /*INCLUDE*/ #include <bpp/graph_problem/min_cost_tension/linear_system.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 graphProblemMinCostTensionBranchBound #define private_area graphProblemMinCostTensionBranchBound_private
namespace public_area { /*NAMESPACE*/ using namespace graphProblemMinCostTensionAggregationBinary; /*NAMESPACE*/ using namespace graphProblemMinCostTensionHeuristicBinary; /*NAMESPACE*/ using namespace graphProblemMinCostTensionLinearSystem; }
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 clLinearCut; template <tdGraph> class clLinearSystemRelaxation; template <tdGraph> class clCuttingAlgo; }
namespace private_area { template <tdGraph> class clMintyColorForCutting;
class clConstraintInfo; }
// Functions Interface //--------------------------------------------------------------------------- namespace public_area {} namespace private_area { testing_mode ( function void test(void); ) }
// Errors //---------------------------------------------------------------------------------------- namespace public_area {}
// Constants & Variables //------------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// L i n e a r C u t Interface //------------------------------------------------------------------ namespace public_area { /*CLASS clLinearCut */ /* Represents a cut in a linear system modeling the minimum binary cost tension problem. The cut is based on the resolution of the problem in a cycle. */ template <tdGraph> class clLinearCut { //-------------------------------------------------------------------------------------------Types /*TYPE clLinearCut */ /* Type of an arc for the problem. */ public_property typedef clArc<tuGraph> cpArc;
/*TYPE clLinearCut */ /* Type of the solver of the minimum binary cost tension problem. */ public_property typedef clBinarySolveAlgo<tuGraph> cpBinarySolver;
/*TYPE clLinearCut */ /* Type of a graph modeling the problem. */ public_property typedef clGraph<tuGraph> cpGraph;
/*TYPE clLinearCut */ /* Type of a list of variables of a linear system modeling the problem. */ public_property typedef std_vector(clTensionVariable *) clVariableS;
/*TYPE clLinearCut */ /* Type of an association of variables of a linear system with arcs of a graph. */ public_property typedef std_map(cpArc *,clTensionVariable *) cpVariableX;
private_property typedef clTensionConstraint * clTensionConstraintP; //-----------------------------------------------------------------------------------------Private private_property constructor clLinearCut(const clLinearCut &); private_property clLinearCut & operator = (const clLinearCut &);
private_property void computeBoundaryWithAggregation(ctCycle &,cpGraph &); private_property void computeBoundaryWithMIP(ctCycle &,cpGraph &,const cpBinarySolver &); //------------------------------------------------------------------------------------------Public /*ATTRIBUTE clLinearCut */ /* List of the variables of the linear system involved in the cut. */ read_write_attribute(clVariableS,atVariableS,variables);
/*ATTRIBUTE clLinearCut */ /* Boundary of the cut. */ read_write_attribute(tyReal,atBoundary,boundary);
/*ATTRIBUTE clLinearCut */ /* Counter for the number of times the cut has not been used. */ read_write_attribute(tyCardinal,atCounter,counter);
/*ATTRIBUTE clLinearCut */ /* Pointer to the constraint modeling the cut in the linear system. */ read_only_attribute(clTensionConstraintP,atConstraint,constraint);
public_property constructor clLinearCut(void);
public_property constructor clLinearCut(ctCycle &,cpGraph &,cpVariableX &, const cpBinarySolver &,tyBoolean);
public_property destructor clLinearCut(void);
public_property void insertConstraint(void); public_property void removeConstraint(void); public_property tyReal value(void) const; }; }
// L i n e a r S y s t e m R e l a x a t i o n Interface //---------------------------------------- namespace public_area { /*CLASS clLinearSystemRelaxation */ /* Represents a relaxation of a linear system modeling the minimum binary cost tension problem. Cuts can be added into the linear system. */ template <tdGraph> class clLinearSystemRelaxation { //-------------------------------------------------------------------------------------------Types /*TYPE clLinearSystemRelaxation */ /* Type of the solver of the minimum binary cost tension problem. */ public_property typedef clBinarySolveAlgo<tuGraph> cpBinarySolver;
/*TYPE clLinearSystemRelaxation */ /* Type of a graph modeling the problem. */ public_property typedef clGraph<tuGraph> cpGraph;
/*TYPE clLinearSystemRelaxation */ /* Type of a linear cut for the problem. */ public_property typedef clLinearCut<tuGraph> cpLinearCut;
/*TYPE clLinearSystemRelaxation */ /* Type of a list of linear cuts for the problem. */ public_property typedef std_vector(cpLinearCut *) cpLinearCutS; //-----------------------------------------------------------------------------------------Private private_property typedef clArc<tuGraph> cpArc; private_property typedef std_vector(cpArc *) cpArcS; private_property typedef std_vector(clTensionVariable *) clVariableS; private_property typedef std_map(cpArc *,clTensionVariable *) cpVariableX;
private_property cpGraph & atGraph; private_property const cpBinarySolver & atBinarySolver; private_property clTensionSystemSolver & atLinearSolver; private_property cpArcS atArcS; private_property clVariableS atVariableS; private_property cpVariableX atVariableX; private_property tyBoolean atUseMIP; private_property tyBoolean atDisplayed;
private_property constructor clLinearSystemRelaxation(const clLinearSystemRelaxation &); private_property clLinearSystemRelaxation & operator = (const clLinearSystemRelaxation &); //------------------------------------------------------------------------------------------Public /*ATTRIBUTE clLinearSystemRelaxation */ /* Relaxed linear system. */ read_write_attribute(clTensionSystem,atSystem,system);
/*ATTRIBUTE clLinearSystemRelaxation */ /* Lower bound of the original system (i.e. optimal value of the objective of the relaxed system). */ read_only_attribute(tyReal,atLowerBound,lowerBound);
/*ATTRIBUTE clLinearSystemRelaxation */ /* Number of iterations */ read_only_attribute(tyInteger,atNbIteration,nbIteration);
/*ATTRIBUTE clLinearSystemRelaxation */ /* List of cuts that are not used yet. */ read_only_attribute(cpLinearCutS,atUnusedCutS,unusedCuts);
/*ATTRIBUTE clLinearSystemRelaxation */ /* List of the cuts that are actually used. */ read_only_attribute(cpLinearCutS,atUsedCutS,usedCuts);
public_property constructor clLinearSystemRelaxation(cpGraph &,const cpBinarySolver &,tyBoolean, tyBoolean=false);
public_property destructor clLinearSystemRelaxation(void);
public_property cpGraph & graph(void); public_property const cpGraph & graph(void) const;
public_property tyCardinal addCycleCuts(tyArcKey,tyReal); public_property tyCardinal addSerialParallelCuts(void); public_property tyCardinal addUnusedCuts(void); public_property tyCardinal improveLowerBound(tyBoolean); public_property void solve(void); }; }
// C u t t i n g A l g o Interface //-------------------------------------------------------------- namespace public_area { /*CLASS clCuttingAlgo */ /* Represents an algorithm to solve the minimum binary cost tension problem in a graph by adding progressively extra constraints in the relaxed linear model before solving exactly the whole problem. */ template <tdGraph> class clCuttingAlgo : public clBinarySolver<tuGraph> { //-------------------------------------------------------------------------------------------Types /*TYPE clCuttingAlgo */ /* Type of the solver of the minimum binary cost tension problem. */ public_property typedef graphProblemMinCostTensionLinearSystem::clBinarySolveAlgo<tuGraph> cpBinarySolver; //-----------------------------------------------------------------------------------------Private private_property typedef clArc<tuGraph> cpArc; private_property typedef std_vector(clTensionVariable *) clConstraint; private_property typedef private_area::clConstraintInfo clConstraintInfo; private_property typedef std_vector(clConstraintInfo) clConstraintS; private_property typedef clGraph<tuGraph> cpGraph; private_property typedef clNode<tuGraph> cpNode; private_property typedef std_map(cpArc *,clTensionVariable *) cpVariableX;
private_property constructor clCuttingAlgo(const clCuttingAlgo &); private_property clCuttingAlgo & operator = (const clCuttingAlgo &);
private_property clTensionConstraint * addConstraint(clTensionSystem &, const clConstraint &,tyReal) const;
private_property tyCardinal addCuts(clTensionSystem &,cpArc &,cpVariableX &,clConstraintS &, clConstraintS &,tyReal,tyBoolean, const cpBinarySolver &) const;
private_property clConstraint * buildConstraint(ctCycle &,cpGraph &,cpVariableX &) const; private_property tyReal lowerBoundWithAggregation(cpGraph &,ctCycle &) const;
private_property tyReal lowerBoundWithMIP(cpGraph &,ctCycle &,const cpBinarySolver &) const; private_property tyInteger solveRelaxation(clTensionSystem &,tyReal &,tyBoolean) const; private_property tyReal value(const clConstraint &) const; //------------------------------------------------------------------------------------------Public public_property constructor clCuttingAlgo(void); public_property destructor clCuttingAlgo(void);
public_property tyInteger run(clGraph<tuGraph> &) const;
public_property tyInteger run(clGraph<tuGraph> &,const cpBinarySolver &,tyReal &, tyBoolean=false,tyBoolean=false) const; }; }
// M i n t y C o l o r F o r C u t t i n g Interface //-------------------------------------------- namespace private_area { template <tdGraph> class clMintyColorForCutting { //-------------------------------------------------------------------------------------------Types public_property typedef clArc<tuGraph> cpArc; //-----------------------------------------------------------------------------------------Private private_property tyReal atPrecision;
private_property constructor clMintyColorForCutting(const clMintyColorForCutting &); private_property clMintyColorForCutting & operator = (const clMintyColorForCutting &); //------------------------------------------------------------------------------------------Public public_property constructor clMintyColorForCutting(tyReal); public_property destructor clMintyColorForCutting(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; }; }
// C o n s t r a i n t I n f o Interface //-------------------------------------------------------- namespace private_area { class clConstraintInfo { //-----------------------------------------------------------------------------------------Private private_property typedef std_vector(clTensionVariable *) clConstraint; //------------------------------------------------------------------------------------------Public read_write_attribute(clConstraint *,atConstraint,constraint); read_write_attribute(tyReal,atBound,bound); read_write_attribute(tyCardinal,atCounter,counter);
public_property constructor clConstraintInfo(clConstraint * =nil,tyReal=0.0,tyCardinal=0); public_property constructor clConstraintInfo(const clConstraintInfo &); public_property destructor clConstraintInfo(void) {}
public_property clConstraintInfo & operator = (const clConstraintInfo &); }; }
// Functions Inline //------------------------------------------------------------------------------ namespace public_area {} namespace private_area {}
// L i n e a r C u t Inline //--------------------------------------------------------------------- namespace public_area { //--------------------------------------------------------------------------------------Constructor /*METHOD clLinearCut */ /* Builds a linear cut. */ template <tdGraph> inline clLinearCut<tuGraph>::clLinearCut(void) : atVariableS(),atBoundary(0.0),atCounter(0),atConstraint(nil) {} //---------------------------------------------------------------------------------------Destructor /*METHOD clLinearCut */ /* Destructs the cut. */ template <tdGraph> inline clLinearCut<tuGraph>::~clLinearCut(void) {} //---------------------------------------------------------------------------------RemoveConstraint /*METHOD clLinearCut */ /* Removes the constraint modeling the cut from the linear system. */ template <tdGraph> inline void clLinearCut<tuGraph>::removeConstraint(void) { if (atConstraint!=nil) delete_object(atConstraint); atConstraint=nil; } }
// L i n e a r S y s t e m R e l a x a t i o n Inline //------------------------------------------- namespace public_area { //--------------------------------------------------------------------------------------------Graph /*METHOD clLinearSystemRelaxation */ /* Returns the graph associated with the linear system. Read-write version. */ template <tdGraph> inline clGraph<tuGraph> & clLinearSystemRelaxation<tuGraph>::graph(void) { return (atGraph); } //--------------------------------------------------------------------------------------------Graph /*METHOD clLinearSystemRelaxation */ /* Returns the graph associated with the linear system. Read-only version. */ template <tdGraph> inline const clGraph<tuGraph> & clLinearSystemRelaxation<tuGraph>::graph(void) const { return (atGraph); } //--------------------------------------------------------------------------------------------Solve /*METHOD clLinearSystemRelaxation */ /* Solves the linear system. */ template <tdGraph> inline void clLinearSystemRelaxation<tuGraph>::solve(void) { tyInteger lcIteration = atLinearSolver.run(atSystem);
if (not atSystem.solved()) { atNbIteration=-1; return; }
atNbIteration+=lcIteration; atLowerBound=atSystem.objective().value(); } }
// C u t t i n g A l g o Inline //----------------------------------------------------------------- namespace public_area { //--------------------------------------------------------------------------------------Constructor /*METHOD clCuttingAlgo */ /* Builds an algorithm to solve the minimum cost tension problem. */ template <tdGraph> inline clCuttingAlgo<tuGraph>::clCuttingAlgo(void) {} //---------------------------------------------------------------------------------------Destructor /*METHOD clCuttingAlgo */ /* Destructs the algorithm. */ template <tdGraph> inline clCuttingAlgo<tuGraph>::~clCuttingAlgo(void) {} //----------------------------------------------------------------------------------------------Run /*METHOD clCuttingAlgo */ /* Solves the minimum cost tension problem in a graph, with default parameters to tune the algorithm. */ template <tdGraph> inline tyInteger clCuttingAlgo<tuGraph>::run(clGraph<tuGraph> & agGraph) const { tyReal lcLowerBound; graphProblemMinCostTensionLinearSystem::clBinarySolveAlgoI<tuGraph> lcSolveAlgo;
return (run(agGraph,lcSolveAlgo,lcLowerBound)); } }
// M i n t y C o l o r F o r C u t t i n g Inline //----------------------------------------------- namespace private_area { //--------------------------------------------------------------------------------------Constructor template <tdGraph> inline clMintyColorForCutting<tuGraph>::clMintyColorForCutting(tyReal agPrecision) : atPrecision(agPrecision) {} //----------------------------------------------------------------------------------------------Red template <tdGraph> inline tyBoolean clMintyColorForCutting<tuGraph>::red(const cpArc & agArc) const { tyReal lcCoefficient;
tyReal lcMaximum = agArc.data().maximum(); tyReal lcMinimum = agArc.data().minimum(); tyReal lcOptimum = agArc.data().optimum(); tyReal lcTension = agArc.data().tension();
if (lcTension>=lcOptimum) lcCoefficient=(lcTension-lcOptimum)/(lcMaximum-lcOptimum); else lcCoefficient=(lcOptimum-lcTension)/(lcOptimum-lcMinimum);
return (lcCoefficient<=atPrecision); } //--------------------------------------------------------------------------------------------Black template <tdGraph> inline tyBoolean clMintyColorForCutting<tuGraph>::black(const cpArc &) const { return (false); } //---------------------------------------------------------------------------------------------Blue template <tdGraph> inline tyBoolean clMintyColorForCutting<tuGraph>::blue(const cpArc &) const { return (false); } //--------------------------------------------------------------------------------------------Green template <tdGraph> inline tyBoolean clMintyColorForCutting<tuGraph>::green(const cpArc & agArc) const { return (not red(agArc)); } }
// C o n s t r a i n t I n f o Inline //----------------------------------------------------------- namespace private_area { //--------------------------------------------------------------------------------------Constructor inline clConstraintInfo::clConstraintInfo(clConstraint * agConstraint,tyReal agBound, tyCardinal agCounter) : atConstraint(agConstraint),atBound(agBound),atCounter(agCounter) {} //--------------------------------------------------------------------------------------Constructor inline clConstraintInfo::clConstraintInfo(const clConstraintInfo & agInfo) : atConstraint(agInfo.atConstraint),atBound(agInfo.atBound),atCounter(agInfo.atCounter) {} //---------------------------------------------------------------------------------------Operator = inline clConstraintInfo & clConstraintInfo::operator = (const clConstraintInfo & agInfo) { atConstraint=agInfo.atConstraint; atBound=agInfo.atBound; atCounter=agInfo.atCounter;
return (*this); } }
// L i n e a r C u t Implementation //------------------------------------------------------------- namespace public_area { //-------------------------------------------------------------------ComputeBoundaryWithAggregation template <tdGraph> void clLinearCut<tuGraph>::computeBoundaryWithAggregation(ctCycle & agCycle,cpGraph & agGraph) { typedef clAggregationAlgoII<tuGraph> cpAggregationAlgo; typedef ctCycle::const_iterator clArcIterator;
cpArc * lcArc; std_vector(cpArc *) lcArcS; tyCardinal lcCounter;
clArcIterator lcCurrentArc = agCycle.begin(); clArcIterator lcLastArc = agCycle.end();
atBoundary=0.0;
// Maximum Cost Computation // while (lcCurrentArc!=lcLastArc) { lcArc=&(agGraph.arc(lcCurrentArc->first)); atBoundary+=lcArc->data().weight(); ++lcCurrentArc; }
// Subproblem Resolution // cpAggregationAlgo().run(agGraph,agCycle,lcArcS);
// Cost Computation // lcCounter=lcArcS.size();
while (lcCounter>0) { --lcCounter; atBoundary-=lcArcS[lcCounter]->data().weight(); } } //---------------------------------------------------------------------------ComputeBoundaryWithMIP template <tdGraph> void clLinearCut<tuGraph>::computeBoundaryWithMIP(ctCycle & agCycle,cpGraph & agGraph, const cpBinarySolver & agBinarySolver) { typedef ctCycle::const_iterator clArcIterator; typedef clNode<tuGraph> cpNode; typedef graphProblemMinCostTensionStructure::clNodeData clNodeData;
cpArc * lcArc; cpGraph lcGraph; cpNode * lcNode; cpNode * lcSourceNode; cpNode * lcTargetNode;
clArcIterator lcCurrentArc = agCycle.begin(); clArcIterator lcLastArc = agCycle.end(); tyMark lcMark = ++(agGraph.mark());
// Subproblem Construction // while (lcCurrentArc!=lcLastArc) { lcArc=&(agGraph.arc(lcCurrentArc->first)); lcNode=lcArc->sourceNode();
if (lcNode->mark()<lcMark) { lcSourceNode=new_object(cpNode(lcGraph,lcNode->key(),clNodeData())); lcNode->mark()=agGraph.mark(); } else lcSourceNode=&(lcGraph.node(lcNode->key()));
lcNode=lcArc->targetNode();
if (lcNode->mark()<lcMark) { lcTargetNode=new_object(cpNode(lcGraph,lcNode->key(),clNodeData())); lcNode->mark()=agGraph.mark(); } else lcTargetNode=&(lcGraph.node(lcNode->key()));
lcArc=new_object(cpArc(lcGraph,lcArc->key(),lcArc->data())); lcArc->setSourceNode(lcSourceNode); lcArc->setTargetNode(lcTargetNode); ++lcCurrentArc; }
// Subproblem Resolution // agBinarySolver.run(lcGraph);
// Cost Computation // atBoundary=graphProblemMinCostTensionAlgorithm::totalCost(lcGraph); } //--------------------------------------------------------------------------------------Constructor /*METHOD clLinearCut */ /* Builds a linear cut based on a given cycle. The graph modeling the problem, the arc-variable association and the solver of the problem must be provided. The last argument allows to select either the solver previously provided, or the aggregation method. */ template <tdGraph> clLinearCut<tuGraph>::clLinearCut(ctCycle & agCycle,cpGraph & agGraph, cpVariableX & agVariableX, const cpBinarySolver & agBinarySolver, tyBoolean agUseMIP) : atVariableS(),atBoundary(0.0),atCounter(0),atConstraint(nil) { typedef ctCycle::const_iterator clArcIterator;
cpArc * lcArc;
clArcIterator lcCurrentArc = agCycle.begin(); clArcIterator lcLastArc = agCycle.end();
while (lcCurrentArc!=lcLastArc) { lcArc=&(agGraph.arc(lcCurrentArc->first)); atVariableS.push_back(agVariableX[lcArc]); ++lcCurrentArc; }
if (agUseMIP) computeBoundaryWithMIP(agCycle,agGraph,agBinarySolver); else computeBoundaryWithAggregation(agCycle,agGraph); } //---------------------------------------------------------------------------------InsertConstraint /*METHOD clLinearCut */ /* Inserts a constraint modeling the cut into the linear system. */ template <tdGraph> void clLinearCut<tuGraph>::insertConstraint(void) { typedef clVariableS::const_iterator clVariableIterator;
clTensionVariable * lcVariable;
clVariableIterator lcCurrentVariable = atVariableS.begin(); clVariableIterator lcLastVariable = atVariableS.end();
if (atConstraint!=nil) { delete_object(atConstraint); atConstraint=nil; }
if (lcCurrentVariable!=lcLastVariable) { lcVariable=(*lcCurrentVariable);
clTensionSystem & lcSystem = const_cast<clTensionSystem &>(lcVariable->linearSystem()); ctTensionObjective & lcObjective = lcSystem.objective();
atConstraint=new_object(clTensionConstraint(lcSystem,linearSystem::superiority));
while (lcCurrentVariable!=lcLastVariable) { lcVariable=(*lcCurrentVariable); atConstraint->setCoefficient(lcVariable->key(),lcObjective[lcVariable->key()]); ++lcCurrentVariable; }
atConstraint->boundary()=atBoundary; } } //--------------------------------------------------------------------------------------------Value /*METHOD clLinearCut */ /* Returns the value of the cut (i.e. the cost of the variables involved in the cut). */ template <tdGraph> tyReal clLinearCut<tuGraph>::value(void) const { clTensionVariable * lcVariable;
clVariableS::const_iterator lcCurrentVariable = atVariableS.begin(); clVariableS::const_iterator lcLastVariable = atVariableS.end(); tyReal lcValue = 0.0;
if (lcCurrentVariable!=lcLastVariable) { ctTensionObjective & lcObjective = (*lcCurrentVariable)->linearSystem().objective();
while (lcCurrentVariable!=lcLastVariable) { lcVariable=*lcCurrentVariable; lcValue+=lcVariable->value()*lcObjective[lcVariable->key()]; ++lcCurrentVariable; } }
return (lcValue); } }
// L i n e a r S y s t e m R e l a x a t i o n Implementation //----------------------------------- namespace public_area { //--------------------------------------------------------------------------------------Constructor /*METHOD clLinearSystemRelaxation */ /* Builds the linear relaxation of the minimum binary cost tension problem in a given graph. A solver must be provided to solve exactly the problem. The third argument allows to select either the solver provided previously, or the aggregation method, to build linear cuts. */ template <tdGraph> clLinearSystemRelaxation<tuGraph>:: clLinearSystemRelaxation(cpGraph & agGraph,const cpBinarySolver & agBinarySolver, tyBoolean agUseMIP,tyBoolean agDisplayed) : atGraph(agGraph),atBinarySolver(agBinarySolver), atLinearSolver(clTensionSystemSolver::defaultSolver()),atArcS(),atVariableS(),atVariableX(), atUseMIP(agUseMIP),atDisplayed(agDisplayed),atSystem(),atLowerBound(),atNbIteration(0), atUnusedCutS(),atUsedCutS() { typedef clTensionSystem::cpVariableX::const_iterator cpVariableIterator;
cpArc * lcArc; cpVariableIterator lcCurrentVariable; cpVariableIterator lcLastVariable; clTensionVariable * lcVariable;
// Relaxed System Construction // atBinarySolver.buildLinearRelaxation(atSystem,atGraph); atGraph.solved()=false;
// Arc-Variable Relationship // lcCurrentVariable=atSystem.variables().begin(); lcLastVariable=atSystem.variables().end();
while (lcCurrentVariable!=lcLastVariable) { lcVariable=lcCurrentVariable->second;
if (lcVariable->content().significance()==binary) { lcArc=&(agGraph.arc(lcVariable->content().arc())); atVariableS.push_back(lcVariable); atArcS.push_back(lcArc); atVariableX.insert(std_make_pair(lcArc,lcVariable)); }
++lcCurrentVariable; } } //---------------------------------------------------------------------------------------Destructor /*METHOD clLinearSystemRelaxation */ /* Destructs the relaxation. */ template <tdGraph> clLinearSystemRelaxation<tuGraph>::~clLinearSystemRelaxation(void) { typedef typename cpLinearCutS::const_iterator cpCutIterator;
cpCutIterator lcCurrentCut = atUnusedCutS.begin(); cpCutIterator lcLastCut = atUnusedCutS.end();
while (lcCurrentCut!=lcLastCut) { delete_object(*lcCurrentCut); ++lcCurrentCut; }
lcCurrentCut=atUsedCutS.begin(); lcLastCut=atUsedCutS.end();
while (lcCurrentCut!=lcLastCut) { delete_object(*lcCurrentCut); ++lcCurrentCut; } } //-------------------------------------------------------------------------------------AddCycleCuts /*METHOD clLinearSystemRelaxation */ /* Adds cuts based on cycles into the linear system. The cuts that are not active yet are stored for further use. */ template <tdGraph> tyCardinal clLinearSystemRelaxation<tuGraph>::addCycleCuts(tyArcKey agArcKey,tyReal agPrecision) { typedef std_vector(clNode<tuGraph> *) cpNodeS;
cpArc * lcArc; cpArcS lcArcS; clCocycle lcCocycle; tyCardinal lcCounter; clCycle::const_iterator lcCurrentArc; cpLinearCut * lcCut; clCycle lcCycle; cpNodeS lcSourceS; cpNodeS lcTargetS; tyReal lcValue;
private_area::clMintyColorForCutting<tuGraph> lcMintyColor(agPrecision);
tyBoolean lcCycleFound = true; tyCardinal lcNbAttempt = maxi(tyCardinal(atGraph.arcs().size()/10*(1-agPrecision)),10u); tyCardinal lcNbCut = 0;
while (lcCycleFound and lcNbAttempt>0) { // Cycle Search // lcCycleFound=findMintyCycle(atGraph,agArcKey,lcMintyColor,lcCycle,lcCocycle); --lcNbAttempt;
if (lcCycleFound) { // Cut Building // lcCut=new_object(cpLinearCut(lcCycle,atGraph,atVariableX,atBinarySolver,atUseMIP)); lcValue=lcCut->value();
// Constraint Insertion // if (isSuperior(lcCut->boundary(),lcValue)) { lcCut->insertConstraint(); atUsedCutS.push_back(lcCut); ++lcNbCut; } else if (lcCut->boundary()>=lcValue-1) atUnusedCutS.push_back(lcCut); else delete_object(lcCut);
// Arc Selection For Removal // do { lcCurrentArc=lcCycle.begin(); std_advance(lcCurrentArc,randomCardinal(lcCycle.size())); } while (lcCurrentArc->first==agArcKey);
// Arc Removal // lcArc=&(atGraph.arc((*lcCurrentArc).first)); lcArcS.push_back(lcArc); lcSourceS.push_back(lcArc->sourceNode()); lcTargetS.push_back(lcArc->targetNode()); lcArc->setSourceNode(nil); lcArc->setTargetNode(nil); } }
// Arcs Restitution // lcCounter=lcArcS.size();
while (lcCounter>0) { lcArc=lcArcS[--lcCounter]; lcArc->setSourceNode(lcSourceS[lcCounter]); lcArc->setTargetNode(lcTargetS[lcCounter]); }
return (lcNbCut); } //----------------------------------------------------------------------------AddSerialParallelCuts /*METHOD clLinearSystemRelaxation */ /* Adds cuts based on serial-parallel subgraphs into the linear system. */ template <tdGraph> tyCardinal clLinearSystemRelaxation<tuGraph>::addSerialParallelCuts(void) { typedef typename cpArcS::const_iterator cpArcIterator; typedef clCaseFunction<tuGraph> cpFunction; typedef typename cpFunction::cpCaseS cpCaseS; typedef clSerialParallelData<tuGraph> cpSerialParallelData; typedef clBinaryTree<cpSerialParallelData> cpTree; typedef std_vector(cpTree *) cpTreeS; typedef typename cpVariableX::const_iterator cpVariableIterator;
cpArcS lcArcS; cpCaseS * lcCaseS; tyCardinal lcCounter; tyReal lcCost; cpArcIterator lcCurrentArc; cpLinearCut * lcCut; tyCardinal lcDummy; cpFunction * lcFunction; tyInteger lcIteration; cpArcIterator lcLastArc; cpTreeS lcTreeS; cpVariableIterator lcVariable;
tyCardinal lcLoop = 0; tyCardinal lcNbCut = 0;
while (lcLoop<2) { lcCounter=0;
// Serial-Parallel Decomposition // if (lcLoop==0) graphProblemSerialParallel::clDecomposeAlgoI<tuGraph>().run(atGraph,lcTreeS); else graphProblemSerialParallel::clDecomposeAlgoII<tuGraph>().run(atGraph,lcTreeS);
// Cuts Adding // while (lcCounter<lcTreeS.size()) { // Subproblem Resolution // lcFunction=new_object(cpFunction()); lcIteration=findMinCostTension(*(lcTreeS[lcCounter]),*lcFunction,true,lcDummy);
if (lcIteration==-1) { atNbIteration=-1; return (0); }
findArcs(*(lcTreeS[lcCounter]),lcArcS);
// Maximum Cost Computation // lcCost=0.0; lcCurrentArc=lcArcS.begin(); lcLastArc=lcArcS.end();
while (lcCurrentArc!=lcLastArc) { lcCost+=(*lcCurrentArc)->data().weight(); ++lcCurrentArc; }
// Optimum Cost Computation lcCaseS=lcFunction->bestCases();
if (lcCaseS!=nil) { lcCurrentArc=(*(lcCaseS->begin()))->arcs().begin(); lcLastArc=(*(lcCaseS->begin()))->arcs().end();
while (lcCurrentArc!=lcLastArc) { lcCost-=(*lcCurrentArc)->data().weight(); ++lcCurrentArc; } }
// Constraint Insertion // lcCut=new_object(cpLinearCut()); lcCut->boundary()=lcCost; lcCurrentArc=lcArcS.begin(); lcLastArc=lcArcS.end();
while (lcCurrentArc!=lcLastArc and lcCut!=nil) { lcVariable=atVariableX.find(*lcCurrentArc);
if (lcVariable==atVariableX.end()) { delete_object(lcCut); lcCut=nil; } else lcCut->variables().push_back(lcVariable->second);
++lcCurrentArc; }
delete_object(lcFunction); delete_object(lcTreeS[lcCounter]);
if (lcCut!=nil) { lcCut->insertConstraint(); atUsedCutS.push_back(lcCut); ++lcNbCut; }
++lcCounter; }
++lcLoop; }
return (lcNbCut); } //------------------------------------------------------------------------------------AddUnusedCuts /*METHOD clLinearSystemRelaxation */ /* Adds the unused cuts that are active into the linear system. */ template <tdGraph> tyCardinal clLinearSystemRelaxation<tuGraph>::addUnusedCuts(void) { tyReal lcBoundary; cpLinearCut * lcCut; tyReal lcValue;
tyCardinal lcCounter = 0; tyCardinal lcNbCut = 0; tyCardinal lcUnusedDuration = maxi(tyCardinal(atGraph.arcs().size()/10),10u);
while (lcCounter<atUnusedCutS.size()) { lcCut=atUnusedCutS[lcCounter]; lcBoundary=lcCut->boundary(); lcValue=lcCut->value(); ++(lcCut->counter());
if (isSuperior(lcBoundary,lcValue)) { lcCut->insertConstraint(); atUsedCutS.push_back(lcCut); atUnusedCutS[lcCounter]=atUnusedCutS.back(); atUnusedCutS.pop_back(); ++lcNbCut; } else if (lcBoundary<lcValue-1 or lcCut->counter()>=lcUnusedDuration) { delete_object(lcCut); atUnusedCutS[lcCounter]=atUnusedCutS.back(); atUnusedCutS.pop_back(); } else ++lcCounter; }
return (lcNbCut); } //--------------------------------------------------------------------------------ImproveLowerBound /*METHOD clLinearSystemRelaxation */ /* Improves the lower bound of the original linear system, by adding cuts into the relaxed linear system. */ template <tdGraph> tyCardinal clLinearSystemRelaxation<tuGraph>::improveLowerBound(tyBoolean agSerialParallel) { typedef std_multimap(tyReal,tyCardinal) clVariableNoX; typedef clVariableNoX::const_iterator clVariableNoIterator;
cpArc * lcArc; tyCardinal lcCounter; tyBoolean lcFound; tyCardinal lcNbCut; clTensionVariable * lcVariable; tyCardinal lcVariableNo; clVariableNoX lcVariableNoX;
clVariableNoIterator lcCurrentVariableNo; clVariableNoIterator lcLastVariableNo;
tyReal lcIncrement = 0.0; tyReal lcOldBound = -1.0; tyReal lcPrecision = 0.4; tyCardinal lcTotalCut = 0;
// Initial Relaxation Resolution // solve(); if (atNbIteration==-1) return (0);
if (atDisplayed) { environment::out("Lower Bound = ",false,true); environment::out(atLowerBound,true); }
// Serial-Parallel Cuts Adding // if (agSerialParallel) { if (atDisplayed) { environment::nextLine(); environment::out("Serial-Parallel Cuts Adding",true,true); }
lcNbCut=addSerialParallelCuts(); lcTotalCut+=lcNbCut;
if (atDisplayed) { environment::out("SP-Cuts = ",false,true); environment::out(lcNbCut,true); }
solve();
if (atDisplayed) { environment::out("Lower Bound = ",false,true); environment::out(atLowerBound,true); } }
if (atDisplayed) environment::nextLine();
// Cuts Adding // do { // Unused Cuts Checking // lcNbCut=addUnusedCuts(); lcTotalCut+=lcNbCut; lcFound=(lcNbCut>0);
if (lcFound and atDisplayed) { environment::out("Cycle Cuts (Pool) = ",false,true); environment::out(lcNbCut,true); }
if (not lcFound) { // Variables Sorting // lcCounter=atVariableS.size(); lcVariableNoX.erase(lcVariableNoX.begin(),lcVariableNoX.end());
while (lcCounter>0) { lcVariable=atVariableS[--lcCounter]; lcVariableNoX.insert(std_make_pair(-std::fabs(lcVariable->value()-0.5),lcCounter)); }
// New Cuts Search // lcCurrentVariableNo=lcVariableNoX.begin(); lcLastVariableNo=lcVariableNoX.end();
while (not lcFound and lcCurrentVariableNo!=lcLastVariableNo) { lcVariableNo=lcCurrentVariableNo->second; lcArc=atArcS[lcVariableNo]; lcNbCut=addCycleCuts(lcArc->key(),lcPrecision); lcTotalCut+=lcNbCut; lcFound=(lcNbCut>0);
if (lcFound and atDisplayed) { environment::out("Cycle Cuts (New) = ",false,true); environment::out(lcNbCut,true); }
++lcCurrentVariableNo; } }
// Relaxed System Resolution // if (lcFound) solve();
if (atDisplayed) { environment::out("Pool = ",false,true); environment::out(atUnusedCutS.size(),true); environment::out("Cuts = ",false,true); environment::out(atUsedCutS.size(),true); environment::out("Precision = ",false,true); environment::out(lcPrecision,true); environment::nextLine(); }
lcIncrement=0.1*lcIncrement+(atLowerBound-lcOldBound); lcOldBound=atLowerBound;
if ((not lcFound or lcIncrement<=1e-6) and lcPrecision>0.0) { lcIncrement=1; lcPrecision=tyCardinal(lcPrecision*10-1)*0.1; lcFound=true; } } while (lcFound and lcIncrement>1e-6);
return (lcTotalCut); } }
// C u t t i n g A l g o Implementation //--------------------------------------------------------- namespace public_area { //----------------------------------------------------------------------------------------------Run /*METHOD clCuttingAlgo */ /* Solves the minimum cost tension problem in a graph. A binary solver that solves exactly the problem using a linear modeling must be provided. The best lower bound found during the process can be collected. To solve subproblems, the aggregation technique or mixed integer programming (MIP) can be used (default is aggregation). Information during the process can be displayed (default is not). */ template <tdGraph> tyInteger clCuttingAlgo<tuGraph>::run(clGraph<tuGraph> & agGraph, const cpBinarySolver & agBinarySolver,tyReal & agLowerBound, tyBoolean agUseMIP,tyBoolean agDisplayed) const { typedef clTensionSystem::cpVariableX::const_iterator clVariableIterator;
cpArc * lcArc; tyInteger lcClock; clTensionConstraint* lcConstraint; clVariableIterator lcCurrentVariable; tyInteger lcIteration; clVariableIterator lcLastVariable; clTensionVariable * lcVariable;
clLinearSystemRelaxation<tuGraph> lcRelaxation(agGraph,agBinarySolver,agUseMIP,agDisplayed);
// Relaxation Improvement // lcRelaxation.improveLowerBound(true); agLowerBound=lcRelaxation.lowerBound();
// MIP System Building // lcCurrentVariable=lcRelaxation.system().variables().begin(); lcLastVariable=lcRelaxation.system().variables().end();
while (lcCurrentVariable!=lcLastVariable) { lcVariable=lcCurrentVariable->second;
if (lcVariable->content().significance()==binary) lcVariable->kind()=linearSystem::integralVariable;
++lcCurrentVariable; }
// MIP Resolution // lcClock=environment::currentClock(); lcIteration=clTensionSystemSolver::defaultSolver().run(lcRelaxation.system()); if (not lcRelaxation.system().solved()) return (-1);
// Solution Fixing // lcCurrentVariable=lcRelaxation.system().variables().begin(); lcLastVariable=lcRelaxation.system().variables().end();
while (lcCurrentVariable!=lcLastVariable) { lcVariable=lcCurrentVariable->second;
if (lcVariable->content().significance()==binary) { lcConstraint=new_object(clTensionConstraint(lcRelaxation.system(),linearSystem::equality)); lcConstraint->setCoefficient(lcVariable->key(),1.0);
if (lcVariable->value()<0.5) lcConstraint->boundary()=0.0; else lcConstraint->boundary()=1.0; }
++lcCurrentVariable; }
// MIP Resolution Again (Avoids Precision Problems) // lcIteration+=clTensionSystemSolver::defaultSolver().run(lcRelaxation.system()); if (not lcRelaxation.system().solved()) return (-1); agGraph.solved()=true;
// Solution Extraction // lcCurrentVariable=lcRelaxation.system().variables().begin(); lcLastVariable=lcRelaxation.system().variables().end();
while (lcCurrentVariable!=lcLastVariable) { lcVariable=lcCurrentVariable->second;
if (lcVariable->content().significance()==tension) { lcArc=&(agGraph.arc(lcVariable->content().arc())); lcArc->data().tension()=lcVariable->value(); }
++lcCurrentVariable; }
lcClock=environment::currentClock()-lcClock;
if (agDisplayed) { environment::out("MIP Time = ",false,true); environment::out(lcClock,true); }
return (lcRelaxation.nbIteration()+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 // B r a n c h _ b o u n d // 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/branch_bound.cpp"
// DLL Belonging //--------------------------------------------------------------------------------- #define GRAPH_PROBLEM_MIN_COST_TENSION_DLL
// Headers //--------------------------------------------------------------------------------------- #include <bpp/graph_problem/min_cost_tension/branch_bound.hpp> /*INTERFACE*/
namespace bpp {
// Namespaces //------------------------------------------------------------------------------------ #define public_area graphProblemMinCostTensionBranchBound #define private_area graphProblemMinCostTensionBranchBound_private #define dll_export DLL_EXPORT
namespace public_area {} namespace private_area {}
static_module_name("Graph_problem/Min_cost_tension/Branch_bound");
// 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 //------------------------------------------------------------------------------------------- } |
|