//==================================================================================================
// 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
// C o n f o r m i n g _ c o n v e x
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU Library General Public License for more details (http://www.gnu.org).

/*DESCRIPTION*/
/* This module implements the conforming algorithm to solve the minimum cost tension
   problem in graphs. The cost functions of the arcs in the graph must be convex as defined by
   the <CODE>clConvexArcData1</CODE> or <CODE>clConvexArcData2</CODE> class of the
   <CODE>Structure</CODE> module. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "graph_problem/min_cost_tension/conforming_convex.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guGraphProblemMinCostTensionConformingConvex
#define guGraphProblemMinCostTensionConformingConvex

// Headers //---------------------------------------------------------------------------------------
#include <bpp/graph_problem/min_cost_tension/conforming.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  graphProblemMinCostTensionConformingConvex
#define private_area graphProblemMinCostTensionConformingConvex_private

namespace public_area { /*NAMESPACE*/ using namespace graphProblemMinCostTensionConforming; }

namespace private_area {
 using namespace public_area;
 using namespace graphProblemMinCostTensionConforming_private;
}

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 clSolveAlgo;
 template <tdGraph> class clSolveAlgoI;
 template <tdGraph> class clSolveAlgoII;
 template <tdGraph> class clSolveAlgoIII;
}

namespace private_area { template <tdGraph> class clConformity; }

// Functions Interface //---------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// 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
    conforming method. It is an abstract class. */
 template <tdGraph> class clSolveAlgo : public clConvexSolver<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);

  /*AMETHOD clSolveAlgo */
  /* Solves the minimum cost tension problem of a graph with a given precision. Abstract method. */
  public_property virtual tyInteger run(clGraph<tuGraph> & agGraph,tyReal agPrecision) const = 0;

  public_property static tyInteger defaultRun(clGraph<tuGraph> &,tyReal);
 };
}

// S o l v e A l g o I  Interface //----------------------------------------------------------------
namespace public_area {
 /*CLASS clSolveAlgoI */
 /* Represents an algorithm to solve the minimum cost tension problem in a graph using the
    conforming method (version I). */
 template <tdGraph> class clSolveAlgoI : public clSolveAlgo<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clSolveAlgoI(const clSolveAlgoI &);
  private_property clSolveAlgoI & operator = (const clSolveAlgoI &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clSolveAlgoI(void);
  public_property destructor clSolveAlgoI(void);

  public_property tyInteger run(clGraph<tuGraph> &,tyReal) const;
 };
}

// S o l v e A l g o I I  Interface //--------------------------------------------------------------
namespace public_area {
 /*CLASS clSolveAlgoII */
 /* Represents an algorithm to solve the minimum cost tension problem in a graph using the
    conforming method (version II). */
 template <tdGraph> class clSolveAlgoII : public clSolveAlgo<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clSolveAlgoII(const clSolveAlgoII &);
  private_property clSolveAlgoII & operator = (const clSolveAlgoII &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clSolveAlgoII(void);
  public_property destructor clSolveAlgoII(void);

  public_property tyInteger run(clGraph<tuGraph> &,tyReal) const;
 };
}

// S o l v e A l g o I I I  Interface //------------------------------------------------------------
namespace public_area {
 /*CLASS clSolveAlgoIII */
 /* Represents an algorithm to solve the minimum cost tension problem in a graph using the
    conforming method (version III). */
 template <tdGraph> class clSolveAlgoIII : public clSolveAlgo<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clSolveAlgoIII(const clSolveAlgoIII &);
  private_property clSolveAlgoIII & operator = (const clSolveAlgoIII &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clSolveAlgoIII(void);
  public_property destructor clSolveAlgoIII(void);

  public_property tyInteger run(clGraph<tuGraph> &,tyReal) const;
  public_property tyInteger run(clGraph<tuGraph> &,tyReal,tyBoolean) const;
 };
}

// C o n f o r m i t y  Interface //----------------------------------------------------------------
namespace private_area {
 template <tdGraph> class clConformity {
  //-----------------------------------------------------------------------------------------Private
  private_property clConformity(const clConformity &);
  private_property clConformity & operator = (const clConformity &);

  private_property tyReal atPrecision;
  private_property tyReal atGap;
  //------------------------------------------------------------------------------------------Public
  public_property
  constructor clConformity(tyReal agPrecision) : atPrecision(agPrecision),atGap(1.0/agPrecision) {}

  public_property destructor clConformity(void) {}

  public_property tyMintyColor arcColor(const clArc<tuGraph> &) const;
  public_property tyBoolean    conformedArc(const clArc<tuGraph> &) const;
  public_property tyReal       derivative(const clArc<tuGraph> &,tyReal) const;
  public_property void         setPrecision(tyReal);

  public_property void getBoundaries(const clArc<tuGraph> &,tyReal,tyReal,
                                     tyMintyColor &,tyBoolean &,
                                     tyReal &,tyReal &,tyReal &,tyReal &,tyCardinal &) const;

  public_property tyReal maximumDecreaseFlow(const clArc<tuGraph> &) const;
  public_property tyReal maximumIncreaseFlow(const clArc<tuGraph> &) const;
  public_property tyReal maximumDecreaseTension(const clArc<tuGraph> &) const;
  public_property tyReal maximumIncreaseTension(const clArc<tuGraph> &) const;
 };
}

// Functions Inline //------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// S o l v e A l g o  Inline //---------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSolveAlgo */ /* Builds an algorithm to solve the minimum cost tension problem. */
 template <tdGraph> inline clSolveAlgo<tuGraph>::clSolveAlgo(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clSolveAlgo */ /* Destructs the algorithm. */
 template <tdGraph> inline clSolveAlgo<tuGraph>::~clSolveAlgo(void) {}
 //---------------------------------------------------------------------------------------DefaultRun
 /*METHOD clSolveAlgo */
 /* Solves the minimum cost tension problem of a graph using the default version of the algorithm
    (version III). Static method. */
 template <tdGraph> inline
 tyInteger clSolveAlgo<tuGraph>::defaultRun(clGraph<tuGraph> & agGraph,tyReal agPrecision) {
  clSolveAlgoIII<tuGraph> lcSolveAlgo;

  return (lcSolveAlgo.run(agGraph,agPrecision));
 }
}

// S o l v e A l g o I  Inline //-------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSolveAlgoI */ /* Builds an algorithm to solve the minimum cost tension problem. */
 template <tdGraph> inline clSolveAlgoI<tuGraph>::clSolveAlgoI(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clSolveAlgoI */ /* Destructs the algorithm. */
 template <tdGraph> inline clSolveAlgoI<tuGraph>::~clSolveAlgoI(void) {}
}

// S o l v e A l g o I I  Inline //-----------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSolveAlgoII */ /* Builds an algorithm to solve the minimum cost tension problem. */
 template <tdGraph> inline clSolveAlgoII<tuGraph>::clSolveAlgoII(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clSolveAlgoII */ /* Destructs the algorithm. */
 template <tdGraph> inline clSolveAlgoII<tuGraph>::~clSolveAlgoII(void) {}
}

// S o l v e A l g o I I I  Inline //---------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSolveAlgoIII */ /* Builds an algorithm to solve the minimum cost tension problem. */
 template <tdGraph> inline clSolveAlgoIII<tuGraph>::clSolveAlgoIII(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clSolveAlgoIII */ /* Destructs the algorithm. */
 template <tdGraph> inline clSolveAlgoIII<tuGraph>::~clSolveAlgoIII(void) {}
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clSolveAlgoIII */
 /* Solves the minimum cost tension problem of a graph. Process information is not displayed. */
 template <tdGraph>
 inline tyInteger clSolveAlgoIII<tuGraph>::run(clGraph<tuGraph> & agGraph,tyReal agPrecision) const
 { return (run(agGraph,agPrecision,false)); }
}

// C o n f o r m i t y  Inline //-------------------------------------------------------------------
namespace private_area {
 //-----------------------------------------------------------------------------------------ArcColor
 template <tdGraph>
 inline tyMintyColor clConformity<tuGraph>::arcColor(const clArc<tuGraph> & agArc) const {
  tyCardinal   lcCase;
  tyMintyColor lcColor;
  tyBoolean    lcConformed;
  tyReal       lcFlowInc;
  tyReal       lcFlowDec;
  tyReal       lcTensionInc;
  tyReal       lcTensionDec;

  getBoundaries(agArc,agArc.data().tension(),agArc.data().flow(),
                lcColor,lcConformed,lcFlowInc,lcFlowDec,lcTensionInc,lcTensionDec,lcCase);

  return (lcColor);
 }
 //-------------------------------------------------------------------------------------ConformedArc
 template <tdGraph> inline
 tyBoolean clConformity<tuGraph>::conformedArc(const clArc<tuGraph> & agArc) const {
  tyCardinal   lcCase;
  tyMintyColor lcColor;
  tyBoolean    lcConformed;
  tyReal       lcFlowInc;
  tyReal       lcFlowDec;
  tyReal       lcTensionInc;
  tyReal       lcTensionDec;

  getBoundaries(agArc,agArc.data().tension(),agArc.data().flow(),
                lcColor,lcConformed,lcFlowInc,lcFlowDec,lcTensionInc,lcTensionDec,lcCase);

  return (lcConformed);
 }
 //---------------------------------------------------------------------------------------Derivative
 template <tdGraph> inline tyReal clConformity<tuGraph>::derivative(const clArc<tuGraph> & agArc,
                                                                    tyReal agTension) const {
  tyReal lcBottom = standard::floor(agTension*atPrecision)*atGap;

  return ((agArc.data().cost(lcBottom+atGap)-agArc.data().cost(lcBottom))*atPrecision);
 }
 //-------------------------------------------------------------------------------------SetPrecision
 template <tdGraph> inline void clConformity<tuGraph>::setPrecision(tyReal agPrecision) {
  atPrecision=agPrecision;
  atGap=1.0/agPrecision;
 }
 //------------------------------------------------------------------------------------GetBoundaries
 template <tdGraph> inline
 void clConformity<tuGraph>::getBoundaries(const clArc<tuGraph> & agArc,
                                           tyReal agTension,tyReal agFlow,
                                           tyMintyColor & agColor,tyBoolean & agConformed,
                                           tyReal & agFlowInc,tyReal & agFlowDec,
                                           tyReal & agTensionInc,tyReal & agTensionDec,
                                           tyCardinal & agCase) const {
  tyReal lcTensionRound;
  tyReal lcTensionDown;
  tyReal lcTensionUp;
  tyReal lcDerivative;
  tyReal lcDerivativePrevious;

  tyReal lcTension = agTension;
  tyReal lcFlow    = agFlow;
  tyReal lcMaximum = agArc.data().maximum();
  tyReal lcMinimum = agArc.data().minimum();
  tyReal lcBottom  = standard::floor(agTension*atPrecision)*atGap;
  tyReal lcTop     = lcBottom+atGap;

  if (isEqual(lcTension,maxi(lcMinimum,lcBottom))) {
   lcTension=maxi(lcMinimum,lcBottom);
   lcTensionRound=lcTension;
   lcTensionDown=maxi(lcMinimum,lcBottom-atGap);
   lcTensionUp=mini(lcMaximum,lcBottom+atGap);
  }
  else if (isEqual(lcTension,mini(lcMaximum,lcTop))) {
   lcTension=mini(lcMaximum,lcTop);
   lcTensionRound=lcTension;
   lcTensionDown=maxi(lcMinimum,lcTop-atGap);
   lcTensionUp=mini(lcMaximum,lcTop+atGap);
  }
  else {
   lcTensionRound=maxi(lcMinimum,lcBottom);
   lcTensionDown=maxi(lcMinimum,lcBottom-atGap);
   lcTensionUp=mini(lcMaximum,lcBottom+atGap);
  }

  lcBottom=maxi(lcMinimum,lcBottom);
  lcTop=mini(lcMaximum,lcBottom);

  lcDerivative=derivative(agArc,lcTension);
  lcDerivativePrevious=derivative(agArc,lcTensionDown);

  if (isEqual(lcMinimum,lcMaximum)) {
   // Case 10 //
   agCase=10;
   agColor=green;
   agConformed=true;
   agFlowInc=realMax();
   agFlowDec=realMax();
   agTensionInc=0.0;
   agTensionDec=0.0;
  }
  else if (isEqual(lcTension,lcMaximum)) {
   if (isInferior(lcFlow,lcDerivativePrevious)) {
    // Case 14 //
    agCase=14;
    agColor=blue;
    agConformed=false;
    agFlowInc=lcDerivativePrevious-lcFlow;
    agFlowDec=0.0;
    agTensionInc=0.0;
    agTensionDec=lcTension-lcTensionDown;
   }
   else if (isSuperior(lcFlow,lcDerivativePrevious)) {
    // Case 16 //
    agCase=16;
    agColor=green;
    agConformed=true;
    agFlowInc=realMax();
    agFlowDec=lcFlow-lcDerivativePrevious;
    agTensionInc=0.0;
    agTensionDec=0.0;
   }
   else {
    // Case 15 //
    agCase=15;
    agColor=blue;
    agConformed=true;
    agFlowInc=realMax();
    agFlowDec=0.0;
    agTensionInc=0.0;
    agTensionDec=lcTension-lcTensionDown;
   }
  }
  else if (isEqual(lcTension,lcMinimum)) {
   if (isInferior(lcFlow,lcDerivative)) {
    // Case 11 //
    agCase=11;
    agColor=green;
    agConformed=true;
    agFlowInc=lcDerivative-lcFlow;
    agFlowDec=realMax();
    agTensionInc=0.0;
    agTensionDec=0.0;
   }
   else if (isSuperior(lcFlow,lcDerivative)) {
    // Case 13 //
    agCase=13;
    agColor=black;
    agConformed=false;
    agFlowInc=0.0;
    agFlowDec=lcFlow-lcDerivative;
    agTensionInc=lcTensionUp-lcTension;
    agTensionDec=0.0;
   }
   else {
    // Case 12 //
    agCase=12;
    agColor=black;
    agConformed=true;
    agFlowInc=0.0;
    agFlowDec=realMax();
    agTensionInc=lcTensionUp-lcTension;
    agTensionDec=0.0;
   }
  }
  else {
   if (lcTension>lcTensionRound) {
    if (isInferior(lcFlow,lcDerivative)) {
     // Case 1 //
     agCase=1;
     agColor=blue;
     agConformed=false;
     agFlowInc=lcDerivative-lcFlow;
     agFlowDec=0.0;
     agTensionInc=0.0;
     agTensionDec=lcTension-lcTensionRound;
    }
    else if (isSuperior(lcFlow,lcDerivative)) {
     // Case 3 //
     agCase=3;
     agColor=black;
     agConformed=false;
     agFlowInc=0.0;
     agFlowDec=lcFlow-lcDerivative;
     agTensionInc=lcTensionUp-lcTension;
     agTensionDec=0.0;
    }
    else {
     // Case 2 //
     agCase=2;
     agColor=red;
     agConformed=true;
     agFlowInc=0.0;
     agFlowDec=0.0;
     agTensionInc=lcTensionUp-lcTension;
     agTensionDec=lcTension-lcTensionRound;
    }
   }
   else {
    if (isInferior(lcFlow,lcDerivativePrevious)) {
     // Case 4 //
     agCase=4;
     agColor=blue;
     agConformed=false;
     agFlowInc=lcDerivativePrevious-lcFlow;
     agFlowDec=0.0;
     agTensionInc=0.0;
     agTensionDec=lcTension-lcTensionDown;
    }
    else if (isSuperior(lcFlow,lcDerivative)) {
     // Case 8 //
     agCase=8;
     agColor=black;
     agConformed=false;
     agFlowInc=0.0;
     agFlowDec=lcFlow-lcDerivative;
     agTensionInc=lcTensionUp-lcTension;
     agTensionDec=0.0;
    }
    else {
     if (isInferior(lcDerivativePrevious+epsilon(),lcDerivative)) {
      if (isEqual(lcFlow,lcDerivativePrevious)) {
       // Case 5 //
       agCase=5;
       agColor=blue;
       agConformed=true;
       agFlowInc=lcDerivative-lcFlow;
       agFlowDec=0.0;
       agTensionInc=0.0;
       agTensionDec=lcTension-lcTensionDown;
      }
      else if (isInferior(lcFlow,lcDerivative)) {
       // Case 6 //
       agCase=6;
       agColor=green;
       agConformed=true;
       agFlowInc=lcDerivative-lcFlow;
       agFlowDec=lcFlow-lcDerivativePrevious;
       agTensionInc=0.0;
       agTensionDec=0.0;
      }
      else {
       // Case 7 //
       agCase=7;
       agColor=black;
       agConformed=true;
       agFlowInc=0.0;
       agFlowDec=lcDerivative-lcDerivativePrevious;
       agTensionInc=lcTensionUp-lcTension;
       agTensionDec=0.0;
      }
     }
     else {
      // Case 9 //
      agCase=9;
      agColor=red;
      agConformed=true;
      agFlowInc=0.0;
      agFlowDec=0.0;
      agTensionInc=lcTensionUp-lcTension;
      agTensionDec=lcTension-lcTensionDown;
     }
    }
   }
  }
 }
 //------------------------------------------------------------------------------MaximumDecreaseFlow
 template <tdGraph> inline
 tyReal clConformity<tuGraph>::maximumDecreaseFlow(const clArc<tuGraph> & agArc) const {
  tyCardinal   lcCase;
  tyMintyColor lcColor;
  tyBoolean    lcConformed;
  tyReal       lcFlowInc;
  tyReal       lcFlowDec;
  tyReal       lcTensionInc;
  tyReal       lcTensionDec;

  tyReal lcDec  = 0.0;
  tyReal lcFlow = agArc.data().flow();

  getBoundaries(agArc,agArc.data().tension(),lcFlow,
                lcColor,lcConformed,lcFlowInc,lcFlowDec,lcTensionInc,lcTensionDec,lcCase);

  if ((lcColor==black or lcColor==green) and lcFlowDec<1e6) {
   lcDec+=lcFlowDec;
   lcFlow-=lcFlowDec;
  }

  if (lcFlowDec>=1e6) lcDec=1e6;
  return (lcDec);
 }
 //------------------------------------------------------------------------------MaximumIncreaseFlow
 template <tdGraph> inline
 tyReal clConformity<tuGraph>::maximumIncreaseFlow(const clArc<tuGraph> & agArc) const {
  tyCardinal   lcCase;
  tyMintyColor lcColor;
  tyBoolean    lcConformed;
  tyReal       lcFlowInc;
  tyReal       lcFlowDec;
  tyReal       lcTensionInc;
  tyReal       lcTensionDec;

  tyReal lcInc = 0.0;
  tyReal lcFlow = agArc.data().flow();

  getBoundaries(agArc,agArc.data().tension(),lcFlow,
                lcColor,lcConformed,lcFlowInc,lcFlowDec,lcTensionInc,lcTensionDec,lcCase);

  if ((lcColor==blue or lcColor==green) and lcFlowInc<1e6) {
   lcInc+=lcFlowInc;
   lcFlow+=lcFlowInc;
  }

  if (lcFlowInc>=1e6) lcInc=1e6;
  return (lcInc);
 }
}

// S o l v e A l g o I  Implementation //-----------------------------------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clSolveAlgoI */
 /* Solves the minimum cost tension problem of a graph with a given precision. */
 template <tdGraph>
 tyInteger clSolveAlgoI<tuGraph>::run(clGraph<tuGraph> & agGraph,tyReal agPrecision) const {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpIterator;

  cpIterator lcCurrentArc = agGraph.arcs().begin();
  cpIterator lcLastArc    = agGraph.arcs().end();

  tyInteger lcIteration = 0;

  private_area::clConformity<tuGraph> lcConformity(agPrecision);

  graphProblemTensionAlgorithm::clCompatibleTensionAlgo<tuGraph>::defaultRun(agGraph);
  if (agGraph.solved()==false) return (-1);
  agGraph.solved()=false;
  nullFlow(agGraph);

  while (lcCurrentArc!=lcLastArc) {
   lcIteration+=private_area::conformArc((*(*lcCurrentArc).second),lcConformity);
   lcCurrentArc++;
  }

  agGraph.solved()=true;
  return (lcIteration);
 }
}

// S o l v e A l g o I I  Implementation //---------------------------------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clSolveAlgoII */
 /* Solves the minimum cost tension problem of a graph with a given precision. */
 template <tdGraph>
 tyInteger clSolveAlgoII<tuGraph>::run(clGraph<tuGraph> & agGraph,tyReal agPrecision) const {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpIterator;

  tyInteger  lcIteration = 0;
  cpIterator lcLastArc   = agGraph.arcs().end();

  tyBoolean        lcAgain;
  clArc<tuGraph> * lcArc;
  cpIterator       lcCurrentArc;

  private_area::clConformity<tuGraph> lcConformity(agPrecision);

  graphProblemMinCostTensionConforming_private::
  clDirectMintyColor<tuGraph,private_area::clConformity<tuGraph> >
  lcDirectMintyColor(lcConformity);

  graphProblemMinCostTensionConforming_private::
  clInverseMintyColor<tuGraph,private_area::clConformity<tuGraph> >
  lcInverseMintyColor(lcConformity);

  graphProblemTensionAlgorithm::clCompatibleTensionAlgo<tuGraph>::defaultRun(agGraph);
  if (agGraph.solved()==false) return (-1);
  agGraph.solved()=false;
  nullFlow(agGraph);

  do {
   lcAgain=false;
   lcCurrentArc=agGraph.arcs().begin();

   while (lcCurrentArc!=lcLastArc) {
    lcArc=(*lcCurrentArc).second;

    if (not lcConformity.conformedArc(*lcArc)) {
     lcAgain=true;
     lcIteration++;
     private_area::improveArc(*lcArc,lcDirectMintyColor,lcInverseMintyColor,lcConformity);
    }

    lcCurrentArc++;
   }
  }
  while (lcAgain);

  agGraph.solved()=true;
  return (lcIteration);
 }
}

// S o l v e A l g o I I I  Implementation //-------------------------------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clSolveAlgoIII */
 /* Solves the minimum cost tension problem of a graph with a given precision.
    Process information can be displayed. */
 template <tdGraph>
 tyInteger clSolveAlgoIII<tuGraph>::run(clGraph<tuGraph> & agGraph,tyReal agPrecision,
                                        tyBoolean agDisplayed) const {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpIterator;

  cpIterator lcCurrentArc = agGraph.arcs().begin();
  tyInteger  lcIteration  = 0;
  cpIterator lcLastArc    = agGraph.arcs().end();
  tyReal     lcPrecision  = 0.0;

  tyCardinal lcCounter;
  tyReal     lcGap;

  graphProblemTensionAlgorithm::clCompatibleTensionAlgo<tuGraph>::defaultRun(agGraph);
  if (agGraph.solved()==false) return (-1);
  agGraph.solved()=false;
  nullFlow(agGraph);

  while (lcCurrentArc!=lcLastArc) {
   lcGap=(*lcCurrentArc).second->data().maximum()-(*lcCurrentArc).second->data().minimum();
   if (lcGap>lcPrecision) lcPrecision=lcGap;

   lcCurrentArc++;
  }

  lcCounter=tyInteger(standard::floor(std::log(lcPrecision)/std::log(10.0)));
  lcPrecision=1.0;

  while (lcCounter>0) {
   lcCounter--;
   lcPrecision/=10.0;
  }

  /*
  while (isInferiorEqual(lcPrecision,agPrecision)) {
   if (agDisplayed) {
    environment::out("Precision = ",false,true);
    environment::out(lcPrecision);
   }

   lcCurrentArc=agGraph.arcs().begin();

   while (lcCurrentArc!=lcLastArc) {
    lcIteration+=private_area::conformArc((*(*lcCurrentArc).second),
                 private_area::clConformity<tuGraph>(lcPrecision));

    lcCurrentArc++;
   }

   if (agDisplayed) {
    environment::out(" Iterations = ");
    environment::out(lcIteration,true);
   }

   if (isInferior(lcPrecision,agPrecision)) {
    lcPrecision*=10.0;
    if (isSuperior(lcPrecision,agPrecision)) lcPrecision=agPrecision;
   }
   else lcPrecision*=10.0;
  }
  */

  //-------------------
  typedef clArc<tuGraph> *                    cpArc;
  typedef private_area::clConformity<tuGraph> cpConformity;

  typedef graphProblemMinCostTensionConforming_private::clDirectMintyColor<tuGraph,cpConformity>
  cpDirectMintyColor;

  typedef graphProblemMinCostTensionConforming_private::clInverseMintyColor<tuGraph,cpConformity>
  cpInverseMintyColor;

  cpArc * lcArc1S = new_array(cpArc,agGraph.arcs().size());
  cpArc * lcArc2S = new_array(cpArc,agGraph.arcs().size());

  cpConformity lcConformity(agPrecision);

  cpArc      lcArc;
  tyCardinal lcCounter1;
  tyCardinal lcCounter2;

  while (isInferiorEqual(lcPrecision,agPrecision)) {
   if (agDisplayed) {
    environment::out("Precision = ",false,true);
    environment::out(lcPrecision);
   }

   // Non Conformed Arcs List //
   lcCurrentArc=agGraph.arcs().begin();
   lcLastArc=agGraph.arcs().end();

   lcCounter1=0;

   while (lcCurrentArc!=lcLastArc) {
    lcArc1S[lcCounter1]=(*lcCurrentArc).second;
    ++lcCounter1;
    ++lcCurrentArc;
   }

   lcConformity.setPrecision(lcPrecision);

   cpDirectMintyColor  lcDirectMintyColor(lcConformity);
   cpInverseMintyColor lcInverseMintyColor(lcConformity);

   // Conforming //
   while (lcCounter1!=0) {
    standard::swap(lcArc1S,lcArc2S);
    lcCounter2=lcCounter1;
    lcCounter1=0;

    while (lcCounter2>0) {
     lcCounter2--;
     lcArc=lcArc2S[lcCounter2];

     if (not lcConformity.conformedArc(*lcArc)) {
      lcIteration++;
      private_area::improveArc(*lcArc,lcDirectMintyColor,lcInverseMintyColor,lcConformity);
      lcArc1S[lcCounter1]=lcArc;
      lcCounter1++;
     }
    }
   }

   if (agDisplayed) {
    environment::out(" Iterations = ");
    environment::out(lcIteration,true);
   }

   if (isInferior(lcPrecision,agPrecision)) {
    lcPrecision*=10.0;
    if (isSuperior(lcPrecision,agPrecision)) lcPrecision=agPrecision;
   }
   else lcPrecision*=10.0;
  }

  delete_array(lcArc1S);
  delete_array(lcArc2S);
  //-------------------

  agGraph.solved()=true;
  return (lcIteration);
 }
}

// C o n f o r m i t y  Implementation //-----------------------------------------------------------
namespace private_area {
 //---------------------------------------------------------------------------MaximumDecreaseTension
 template <tdGraph>
 tyReal clConformity<tuGraph>::maximumDecreaseTension(const clArc<tuGraph> & agArc) const {
  tyReal       lcBottom;
  tyCardinal   lcCase;
  tyMintyColor lcColor;
  tyBoolean    lcConformed;
  tyReal       lcFlowInc;
  tyReal       lcFlowDec;
  tyReal       lcNext;
  tyReal       lcTensionInc;
  tyReal       lcTensionDec;

  tyReal lcDec     = 0.0;
  tyReal lcTension = agArc.data().tension();

  getBoundaries(agArc,lcTension,agArc.data().flow(),
                lcColor,lcConformed,lcFlowInc,lcFlowDec,lcTensionInc,lcTensionDec,lcCase);

  if (lcColor==blue or lcColor==red) {
   lcTension+=lcTensionDec;
   lcDec=lcTensionDec;
   lcBottom=standard::floor(lcTension*atPrecision)*atGap;
   lcNext=lcBottom;

   while (isInferiorEqual(agArc.data().flow(),derivative(agArc,lcBottom))
          and lcTension>agArc.data().minimum()) {
    lcTension=maxi(lcNext,agArc.data().minimum());
    lcBottom-=atGap;
    lcNext=lcBottom;
   }
  }

  return (maxi(lcDec,agArc.data().tension()-lcTension));
 }
 //---------------------------------------------------------------------------MaximumIncreaseTension
 template <tdGraph>
 tyReal clConformity<tuGraph>::maximumIncreaseTension(const clArc<tuGraph> & agArc) const {
  tyReal       lcBottom;
  tyCardinal   lcCase;
  tyMintyColor lcColor;
  tyBoolean    lcConformed;
  tyReal       lcFlowInc;
  tyReal       lcFlowDec;
  tyReal       lcNext;
  tyReal       lcTensionInc;
  tyReal       lcTensionDec;

  tyReal lcInc     = 0.0;
  tyReal lcTension = agArc.data().tension();

  getBoundaries(agArc,lcTension,agArc.data().flow(),
                lcColor,lcConformed,lcFlowInc,lcFlowDec,lcTensionInc,lcTensionDec,lcCase);

  if (lcColor==black or lcColor==red) {
   lcInc=lcTensionInc;
   lcTension+=lcTensionInc;
   lcBottom=standard::floor(lcTension*atPrecision)*atGap;
   lcNext=lcBottom+atGap;

   while (isSuperiorEqual(agArc.data().flow(),derivative(agArc,lcBottom))
          and lcTension<agArc.data().maximum()) {
    lcTension=mini(lcNext,agArc.data().maximum());
    lcBottom+=atGap;
    lcNext=lcBottom+atGap;
   }
  }

  return (maxi(lcInc,lcTension-agArc.data().tension()));
 }
}

// 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
// C o n f o r m i n g _ c o n v e x
//                                                                                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/conforming_convex.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define GRAPH_PROBLEM_MIN_COST_TENSION_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/graph_problem/min_cost_tension/conforming_convex.hpp> /*INTERFACE*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemMinCostTensionConformingConvex
#define private_area graphProblemMinCostTensionConformingConvex_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Graph_problem/Min_cost_tension/Conforming_convex");

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