//==================================================================================================
// 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 //-------------------------------------------------------------------------------------------
}