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

/*DESCRIPTION*/
/* This module implements an algorithm we call "aggregation" to solve the minimum cost tension
   problem in serial-parallel graphs or almost serial-parallel graphs. The cost functions of the
   arcs in the graph must be linear as defined by the <CODE>clLinearArcData</CODE> class of the
   <CODE>Structure</CODE> module. */

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

// Guardian //--------------------------------------------------------------------------------------
#ifndef guGraphProblemMinCostTensionAggregation
#define guGraphProblemMinCostTensionAggregation

// Headers //---------------------------------------------------------------------------------------
#include <bpp/graph_problem/min_cost_tension/conforming_piecewise.hpp> /*INCLUDE*/
#include <bpp/graph_problem/serial_parallel.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  graphProblemMinCostTensionAggregation
#define private_area graphProblemMinCostTensionAggregation_private

namespace public_area {
 /*NAMESPACE*/ using namespace graphProblemMinCostTensionAlgorithm;
 /*NAMESPACE*/ using namespace graphProblemSerialParallel;
}

namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniGraphProblemMinCostTensionAggregation
has_initializer;

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

namespace private_area {
 template <tdGraph> struct clTreeInfo;
 template <tdGraph> class  clVariation;
}

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

namespace private_area {
 testing_mode ( function void test(void); )

 template <tdGraph> void clean(std_vector(clVariation<tuGraph>) &);

 template <tdGraph>
 tyInteger findMinCostTension(clBinaryTree<clSerialParallelData<tuGraph> > &,
                              std_deque(clVariation<tuGraph>) &,
                              std_deque(clVariation<tuGraph>) &,tyReal &,tyReal * =nil,
                              tyReal * =nil);

 template <tdGraph,class prIterator>
 tyInteger improveBalance(prIterator &,const prIterator,prIterator &,const prIterator,
                          std_deque(clVariation<tuGraph>) &,std_deque(clVariation<tuGraph>) &,
                          tyReal &,tyReal &,tyReal &,tyReal &,tyBoolean);

 template <tdGraph>
 tyBoolean mergeParallelArcs(clBinaryTree<clSerialParallelData<tuGraph> > &,
                             std_deque(clVariation<tuGraph>) &,
                             std_deque(clVariation<tuGraph>) &,
                             std_deque(clVariation<tuGraph>) &,
                             std_deque(clVariation<tuGraph>) &,
                             std_deque(clVariation<tuGraph>) &,
                             std_deque(clVariation<tuGraph>) &,
                             tyReal &,tyReal &,tyBoolean);

 template <tdGraph>
 void mergeParallelVariations(std_deque(clVariation<tuGraph>) &,
                              std_deque(clVariation<tuGraph>) &,
                              std_deque(clVariation<tuGraph>) &);

 template <tdGraph,class prIterator1,class prIterator2>
 void mergeSerialVariations(std_deque(clVariation<tuGraph>) &,prIterator1,const prIterator1,
                            prIterator2,const prIterator2);

 template <tdGraph>
 clPiecewiseArc * createPiecewiseArc(clPiecewiseGraph &,clTreeInfo<tuGraph> &,
                                     clNode<tuGraph> &,clNode<tuGraph> &,tyReal,tyBoolean);

 template <tdGraph>
 void disintegrateArc(clBinaryTree<clSerialParallelData<tuGraph> > &,clPiecewiseGraph &,
                      clNode<tuGraph> **, clNode<tuGraph> **,
                      std_map(clNode<tuGraph> *,clBinaryTree<clSerialParallelData<tuGraph> > *) &,
                      tyBoolean);

 template <tdGraph> void findFlow(clBinaryTree<clSerialParallelData<tuGraph> > &,tyReal &);

 template <tdGraph> void increaseFlow(std_deque(clVariation<tuGraph>) &,tyReal &,tyReal);

 template <class prConformity,class prDirectMintyColor,class prInverseMintyColor>
 tyInteger makeConform(clPiecewiseArc **,tyCardinal &,prConformity &,
                       prDirectMintyColor &,prInverseMintyColor &);

 template <tdGraph> tyReal maximumFlow(clArc<tuGraph> &);

 template <tdGraph> void mergeParallelFlows(std_deque(clVariation<tuGraph>) &,
                                            std_deque(clVariation<tuGraph>) &,
                                            std_deque(clVariation<tuGraph>) &,
                                            tyReal,tyReal);

 template <tdGraph> void mergeSerialFlows(std_deque(clVariation<tuGraph>) &,
                                          std_deque(clVariation<tuGraph>) &,
                                          std_deque(clVariation<tuGraph>) &);

 template <tdGraph> tyReal minimumFlow(clArc<tuGraph> &);
 template <tdGraph> void   updateCosts(clTreeInfo<tuGraph> &);
 template <tdGraph> void   updateTension(clTreeInfo<tuGraph> &);
}

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 /*ERROR*/ extern_error erEmptyArcList; /* The arc list is empty. */
 /*ERROR*/ extern_error erNotEnoughAvailableFlow; /* Can not increase or decrease more a flow. */

 /*ERROR*/ extern_error erNotEnoughAvailableTension;
 /* Can not increase or decrease more a tension. */
}

// Constants & Variables //-------------------------------------------------------------------------
extern_dynamic_constant(private,clString,goDataLocation,?);

// 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
    reconstruction approach that combines the aggregation and the conforming methods. */
 template <tdGraph> class clSolveAlgo : public clLinearSolver<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clSolveAlgo(const clSolveAlgo &);
  private_property clSolveAlgo & operator = (const clSolveAlgo &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clSolveAlgo(void);
  public_property virtual destructor clSolveAlgo(void);

  /*AMETHOD clSolveAlgo */
  /* Solves the minimum cost tension problem of a graph by decomposing the graph into
     serial-parallel components. Abstract method. */
  public_property virtual tyInteger run(clGraph<tuGraph> & agGraph) const = 0;

  /*AMETHOD clSolveAlgo */
  /* Solves the minimum cost tension problem of a graph by decomposing the graph into
     serial-parallel components, using the method given as argument, or directly if serial-parallel
     components are given (default is not). The number of components obtained can be displayed
     (default is not). Abstract method. */
  public_property virtual
  tyInteger run(clGraph<tuGraph> & agGraph,
                const clDecomposeAlgo<tuGraph> & agDecomposeAlgo,
                std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) * agComponentS=nil,
                tyBoolean agDisplayed=false) const = 0;

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

// 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
    reconstruction approach (version I) that combines the aggregation and the conforming
    methods. */
 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 virtual destructor clSolveAlgoI(void);

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

  public_property tyInteger run(clGraph<tuGraph> &,const clDecomposeAlgo<tuGraph> &,
                                std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) * =nil,
                                tyBoolean=false) 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
    reconstruction approach (version II, post-decomposition) that combines the aggregation and the
    conforming methods. */
 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 virtual destructor clSolveAlgoII(void);

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

  public_property tyInteger run(clGraph<tuGraph> &,const clDecomposeAlgo<tuGraph> &,
                                std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) * =nil,
                                tyBoolean=false) const;
 };
}

// S o l v e S e r i a l P a r a l l e l A l g o  Interface //--------------------------------------
namespace public_area {
 /*CLASS clSolveSerialParallelAlgo */
 /* Represents an algorithm to solve the minimum cost tension problem in a serial-parallel graph
    using the recursive aggregation method. */
 template <tdGraph> class clSolveSerialParallelAlgo : public clLinearSolver<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clSolveSerialParallelAlgo(const clSolveSerialParallelAlgo &);
  private_property clSolveSerialParallelAlgo & operator = (const clSolveSerialParallelAlgo &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clSolveSerialParallelAlgo(void);
  public_property virtual destructor clSolveSerialParallelAlgo(void);

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

// V a r i a t i o n  Interface //------------------------------------------------------------------
namespace private_area {
 template <tdGraph> class clVariation {
  //-------------------------------------------------------------------------------------------Types
  public_property typedef std_vector(clArc<tuGraph> *) cpArcS;
  private_property typedef cpArcS *                    cpArcSP;
  //------------------------------------------------------------------------------------------Public
  read_write_attribute(tyReal,atCost,cost);
  read_write_attribute(tyReal,atAvailable,available);
  read_write_attribute(cpArcSP,atArcS,arcs);
  read_write_attribute(tyBoolean,atInfinity,infinity);

  public_property constructor clVariation(void);
  public_property constructor clVariation(tyReal,tyReal,cpArcS *,tyBoolean=false);
  public_property constructor clVariation(const clVariation<tuGraph> &);
  public_property destructor clVariation(void) {}

  public_property clVariation<tuGraph> & operator = (const clVariation<tuGraph> &);

  public_property void addArcs(const clVariation<tuGraph> &);
  public_property void copyArcs(const clVariation<tuGraph> &);
  public_property void decreaseTension(tyReal,tyBoolean);
  public_property void increaseTension(tyReal,tyBoolean);
 };
}

// Types //-----------------------------------------------------------------------------------------
namespace private_area {
 template <tdGraph> struct clTreeInfo {
  tyBoolean                                     aggregated;
  clPiecewiseArc *                              arc;
  std_deque(private_area::clVariation<tuGraph>) shrinkCosts;
  std_deque(private_area::clVariation<tuGraph>) stretchCosts;
  tyReal                                        tension;
 };
}

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

namespace private_area {
 //--------------------------------------------------------------------------------------MaximumFlow
 template <tdGraph> inline tyReal maximumFlow(clArc<tuGraph> & agArc) {
  if (agArc.data().tension()<agArc.data().minimum()
      or agArc.data().tension()>=agArc.data().maximum()) return (realMax());

  if (agArc.data().tension()>=agArc.data().optimum()) return (agArc.data().stretchingCost());
  return (-agArc.data().shrinkingCost());
 }
 //--------------------------------------------------------------------------------------MinimumFlow
 template <tdGraph> inline tyReal minimumFlow(clArc<tuGraph> & agArc) {
  if (agArc.data().tension()<=agArc.data().minimum()
      or agArc.data().tension()>agArc.data().maximum()) return (realMin());

  if (agArc.data().tension()<=agArc.data().optimum()) return (-agArc.data().shrinkingCost());
  return (agArc.data().stretchingCost());
 }
}

// 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 II). Static method. */
 template <tdGraph> inline tyInteger clSolveAlgo<tuGraph>::defaultRun(clGraph<tuGraph> & agGraph)
 { return (clSolveAlgoII<tuGraph>().run(agGraph)); }
}

// 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) {}
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clSolveAlgoI */
 /* Solves the minimum cost tension problem of a graph by decomposing the graph into
    serial-parallel components (using method I). */
 template <tdGraph> inline tyInteger clSolveAlgoI<tuGraph>::run(clGraph<tuGraph> & agGraph) const {
  clDecomposeAlgoI<tuGraph> lcDecomposeAlgo;

  return (run(agGraph,lcDecomposeAlgo,nil,false));
 }
}

// 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) {}
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clSolveAlgoII */
 /* Solves the minimum cost tension problem of a graph by decomposing the graph into
    serial-parallel components (using method I). */
 template <tdGraph>
 inline tyInteger clSolveAlgoII<tuGraph>::run(clGraph<tuGraph> & agGraph) const {
  clDecomposeAlgoI<tuGraph> lcDecomposeAlgo;

  return (run(agGraph,lcDecomposeAlgo,nil,false));
 }
}

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

// V a r i a t i o n  Inline //---------------------------------------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------Constructor
 template <tdGraph> inline clVariation<tuGraph>::clVariation(void)
 : atCost(0.0),atAvailable(0.0),atArcS(nil),atInfinity(false) {}
 //--------------------------------------------------------------------------------------Constructor
 template <tdGraph> inline clVariation<tuGraph>::clVariation(const clVariation<tuGraph> & agData)
 : atCost(agData.atCost),atAvailable(agData.atAvailable),atArcS(agData.atArcS),
   atInfinity(agData.atInfinity) {}
 //--------------------------------------------------------------------------------------Constructor
 template <tdGraph>
 inline clVariation<tuGraph>::clVariation(tyReal agCost,tyReal agAvailable,cpArcS * agArcS,
                                          tyBoolean agInfinity)
 : atCost(agCost),atAvailable(agAvailable),atArcS(agArcS),atInfinity(agInfinity) {}
 //---------------------------------------------------------------------------------------Operator =
 template <tdGraph> inline
 clVariation<tuGraph> & clVariation<tuGraph>::operator = (const clVariation<tuGraph> & agData) {
  atCost=agData.atCost;
  atAvailable=agData.atAvailable;
  atArcS=agData.atArcS;
  atInfinity=agData.atInfinity;
  return (*this);
 }
}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {}

namespace private_area {
 //--------------------------------------------------------------------------------------------Clean
 template <tdGraph> void clean(std_deque(clVariation<tuGraph>) & agVariationS) {
  typedef typename std_deque(clVariation<tuGraph>)::const_iterator cpIterator;

  cpIterator lcCurrentVariation = agVariationS.begin();
  cpIterator lcLastVariation    = agVariationS.end();

  while (lcCurrentVariation!=lcLastVariation) {
   delete_object((*lcCurrentVariation).arcs());
   lcCurrentVariation++;
  }

  agVariationS.clear();
 }
 //-------------------------------------------------------------------------------FindMinCostTension
 template <tdGraph>
 tyInteger findMinCostTension(clBinaryTree<clSerialParallelData<tuGraph> > & agTree,
                              std_deque(clVariation<tuGraph>) & agShrinkS,
                              std_deque(clVariation<tuGraph>) & agStretchS,tyReal & agOptimum,
                              tyReal * agTension,tyReal * agFlow) {
  typedef clArc<tuGraph>                     cpArc;
  typedef std_vector(clArc<tuGraph> *)       cpArcS;
  typedef clSerialParallelData<tuGraph>      cpSerialParallelData;
  typedef clBinaryTree<cpSerialParallelData> cpTree;
  typedef std_vector(cpTree *)               cpTreeS;
  typedef std_vector(tyCardinal)             clCardinalS;
  typedef std_vector(tyReal)                 clRealS;
  typedef std_deque(clVariation<tuGraph>)    cpVariationS;
  typedef std_vector(cpVariationS *)         cpVariationD;

  cpArc *        lcArc;
  clRealS        lcFlowS;
  clRealS        lcOptimumS;
  cpVariationS * lcShrink1S;
  cpVariationS * lcShrink2S;
  cpVariationD   lcShrinkD;
  clCardinalS    lcStateS;
  cpVariationS * lcStretch1S;
  cpVariationS * lcStretch2S;
  cpVariationD   lcStretchD;
  clRealS        lcTensionS;
  cpTree *       lcTree;
  cpTreeS        lcTreeS;

  tyReal         lcFlow2;
  tyReal         lcOptimum1;
  tyReal         lcOptimum2;
  tyReal         lcTension2;

  tyReal         lcFlow      = 0.0;
  tyReal         lcFlow1     = 0.0;
  tyInteger      lcIteration = 0;
  tyReal         lcOptimum   = 0.0;
  cpVariationS * lcShrinkS   = nil;
  cpVariationS * lcStretchS  = nil;
  tyReal         lcTension   = 0.0;
  tyReal         lcTension1  = 0.0;

  // Empty Tree //
  if (agTree.empty()) {
   agOptimum=0.0;
   if (agTension!=nil) *agTension=0.0;
   if (agFlow!=nil) *agFlow=0.0;
   return (0);
  }

  // Main Loop //
  lcTreeS.push_back(&agTree);
  lcStateS.push_back(0);
  lcShrinkD.push_back(nil);
  lcStretchD.push_back(nil);
  lcOptimumS.push_back(0.0);
  if (agTension!=nil) lcTensionS.push_back(0.0);
  if (agFlow!=nil) lcFlowS.push_back(0.0);

  while (lcTreeS.size()>0 and lcIteration!=-1) {
   lcTree=lcTreeS.back();

   switch(++(lcStateS.back())) {
    case 1:
     // Single Arc //
     if (lcTree->data().operation()==cpSerialParallelData::none) {
      lcArc=lcTree->data().arc();
      lcOptimum=lcArc->data().optimum();

      if (agTension==nil) lcArc->data().tension()=lcArc->data().optimum();
      else lcTension=lcArc->data().tension();

      if (agFlow!=nil) lcFlow=lcArc->data().flow();

      if (lcTree==&agTree) {
       lcShrinkS=&agShrinkS;
       lcStretchS=&agStretchS;
      }
      else {
       lcShrinkS=new_object(cpVariationS());
       lcStretchS=new_object(cpVariationS());
      }

      if (lcArc->data().optimum()!=lcArc->data().minimum()) {
       lcShrinkS->push_back(clVariation<tuGraph>());
       lcShrinkS->back().arcs()=new_object(cpArcS());
       lcShrinkS->back().arcs()->push_back(lcArc);
       lcShrinkS->back().cost()=lcArc->data().shrinkingCost();
       lcShrinkS->back().available()=lcArc->data().optimum()-lcArc->data().minimum();
      }

      if (lcArc->data().optimum()!=lcArc->data().maximum()) {
       lcStretchS->push_back(clVariation<tuGraph>());
       lcStretchS->back().arcs()=new_object(cpArcS());
       lcStretchS->back().arcs()->push_back(lcArc);
       lcStretchS->back().cost()=lcArc->data().stretchingCost();
       lcStretchS->back().available()=lcArc->data().maximum()-lcArc->data().optimum();
      }

      lcTreeS.pop_back();
      lcStateS.pop_back();
      lcShrinkD.pop_back();
      lcStretchD.pop_back();
      lcOptimumS.pop_back();
      if (agTension!=nil) lcTensionS.pop_back();
      if (agFlow!=nil) lcFlowS.pop_back();
     }

     // Left Member Of An SP-Operation //
     else {
      lcTreeS.push_back(&(lcTree->left()));
      lcStateS.push_back(0);
      lcShrinkD.push_back(nil);
      lcStretchD.push_back(nil);
      lcOptimumS.push_back(0.0);
      if (agTension!=nil) lcTensionS.push_back(0.0);
      if (agFlow!=nil) lcFlowS.push_back(0.0);
     }

     break;

    case 2: // Right Member Of An SP-Operation //
     lcShrinkD.back()=lcShrinkS;
     lcStretchD.back()=lcStretchS;
     lcOptimumS.back()=lcOptimum;
     if (agTension!=nil) lcTensionS.back()=lcTension;
     if (agFlow!=nil) lcFlowS.back()=lcFlow;

     lcTreeS.push_back(&(lcTree->right()));
     lcStateS.push_back(0);
     lcShrinkD.push_back(nil);
     lcStretchD.push_back(nil);
     lcOptimumS.push_back(0.0);
     if (agTension!=nil) lcTensionS.push_back(0.0);
     if (agFlow!=nil) lcFlowS.push_back(0.0);
     break;

    default:
     // Preparation To SP-Fusion //
     lcShrink1S=lcShrinkD.back();
     lcStretch1S=lcStretchD.back();
     lcOptimum1=lcOptimumS.back();
     if (agTension!=nil) lcTension1=lcTensionS.back();
     if (agFlow!=nil) lcFlow1=lcFlowS.back();
     lcShrink2S=lcShrinkS;
     lcStretch2S=lcStretchS;
     lcOptimum2=lcOptimum;
     lcTension2=lcTension;
     lcFlow2=lcFlow;

     if (lcTree==&agTree) {
      lcShrinkS=&agShrinkS;
      lcStretchS=&agStretchS;
     }
     else {
      lcShrinkS=new_object(cpVariationS());
      lcStretchS=new_object(cpVariationS());
     }

     // Serial Fusion //
     if (lcTree->data().operation()==cpSerialParallelData::serial) {
      lcOptimum=lcOptimum1+lcOptimum2;
      lcTension=lcTension1+lcTension2;
      lcFlow=lcFlow1;

      mergeSerialVariations(*lcShrinkS,lcShrink1S->begin(),lcShrink1S->end(),
                            lcShrink2S->begin(),lcShrink2S->end());

      mergeSerialVariations(*lcStretchS,lcStretch1S->begin(),lcStretch1S->end(),
                            lcStretch2S->begin(),lcStretch2S->end());

      lcIteration+=2;
     }

     // Parallel Fusion //
     else {
      if (mergeParallelArcs(*lcShrinkS,*lcStretchS,*lcShrink1S,*lcStretch1S,*lcShrink2S,
                            *lcStretch2S,lcOptimum1,lcOptimum2,(agTension==nil))) {
       lcIteration+=6;
       lcOptimum=lcOptimum1;
       lcTension=lcTension1;
       lcFlow=lcFlow1+lcFlow2;
      }
      else lcIteration=-1;
     }

     // Cleaning And Stack Update //
     delete_object(lcShrink1S);
     delete_object(lcShrink2S);
     delete_object(lcStretch1S);
     delete_object(lcStretch2S);
     lcTreeS.pop_back();
     lcStateS.pop_back();
     lcShrinkD.pop_back();
     lcStretchD.pop_back();
     lcOptimumS.pop_back();
     if (agTension!=nil) lcTensionS.pop_back();
     if (agFlow!=nil) lcFlowS.pop_back();
   }
  }

  // Termination //
  if (lcIteration==-1) {
   delete_object(lcShrinkS);
   delete_object(lcStretchS);
  }
  else {
   agOptimum=lcOptimum;
   if (agTension!=nil) *agTension=lcTension;
   if (agFlow!=nil) *agFlow=lcFlow;
  }

  return (lcIteration);
 }
 //-----------------------------------------------------------------------------------ImproveBalance
 template <tdGraph,class prIterator> inline
 tyInteger improveBalance(prIterator & agCurrentShrink,const prIterator agLastShrink,
                          prIterator & agCurrentStretch,const prIterator agLastStretch,
                          std_deque(clVariation<tuGraph>) & agNewShrinkS,
                          std_deque(clVariation<tuGraph>) & agNewStretchS,
                          tyReal & agLastDecrease,tyReal & agLastIncrease,
                          tyReal & agOptimum1,tyReal & agOptimum2,tyBoolean agTensionAdjusted) {
  tyReal lcAvailable1;
  tyReal lcAvailable2;
  tyReal lcCost1;
  tyReal lcCost2;
  tyReal lcMax;

  if (agCurrentStretch==agLastStretch) {
   lcCost1=realMax();
   lcAvailable1=realMax();
  }
  else {
   lcCost1=(*agCurrentStretch).cost();
   lcAvailable1=(*agCurrentStretch).available();
  }

  if (agCurrentShrink==agLastShrink) {
   lcCost2=realMax();
   lcAvailable2=realMax();
  }
  else {
   lcCost2=(*agCurrentShrink).cost();
   lcAvailable2=(*agCurrentShrink).available();
  }

  if (lcCost1==realMax() and lcCost2==realMax()) return (-1);

  if (lcCost1<lcCost2) {
   lcMax=mini(lcAvailable1,agOptimum2-agOptimum1);
   agOptimum1+=lcMax;
   if (agLastIncrease==0.0) agLastIncrease=(*agCurrentStretch).available();
   (*agCurrentStretch).increaseTension(lcMax,agTensionAdjusted);

   if ((*agCurrentStretch).available()==0.0) {
    (*agCurrentStretch).available()=agLastIncrease;
    (*agCurrentStretch).cost()*=-1.0;
    agNewShrinkS.push_back(*agCurrentStretch);
    agCurrentStretch++;
    agLastIncrease=0.0;
   }
  }
  else {
   lcMax=mini(lcAvailable2,agOptimum2-agOptimum1);
   agOptimum2-=lcMax;
   if (agLastDecrease==0.0) agLastDecrease=(*agCurrentShrink).available();
   (*agCurrentShrink).decreaseTension(lcMax,agTensionAdjusted);

   if ((*agCurrentShrink).available()==0.0) {
    (*agCurrentShrink).available()=agLastDecrease;
    (*agCurrentShrink).cost()*=-1.0;
    agNewStretchS.push_back(*agCurrentShrink);
    agCurrentShrink++;
    agLastDecrease=0.0;
   }
  }

  return (0);
 }
 //--------------------------------------------------------------------------------MergeParallelArcs
 template <tdGraph>
 tyBoolean mergeParallelArcs(std_deque(clVariation<tuGraph>) & agShrinkS,
                             std_deque(clVariation<tuGraph>) & agStretchS,
                             std_deque(clVariation<tuGraph>) & agShrink1S,
                             std_deque(clVariation<tuGraph>) & agStretch1S,
                             std_deque(clVariation<tuGraph>) & agShrink2S,
                             std_deque(clVariation<tuGraph>) & agStretch2S,
                             tyReal & agOptimum1,tyReal & agOptimum2,tyBoolean agTensionAdjusted) {
  typedef clVariation<tuGraph>            cpVariation;
  typedef std_deque(cpVariation)          cpVariationS;
  typedef typename cpVariationS::iterator cpIterator;

  cpVariationS lcNewShrink1S;
  cpVariationS lcNewShrink2S;
  cpVariationS lcNewStretch1S;
  cpVariationS lcNewStretch2S;
  cpVariationS lcShrink1S;
  cpVariationS lcShrink2S;
  cpVariationS lcStretch1S;
  cpVariationS lcStretch2S;
  cpVariationS lcTempoShrink1S;
  cpVariationS lcTempoShrink2S;
  cpVariationS lcTempoStretch1S;
  cpVariationS lcTempoStretch2S;
  cpVariation  lcVariation;

  tyReal lcLastDecrease1 = 0.0;
  tyReal lcLastDecrease2 = 0.0;
  tyReal lcLastIncrease1 = 0.0;
  tyReal lcLastIncrease2 = 0.0;

  cpIterator lcCurrentShrink1  = agShrink1S.begin();
  cpIterator lcCurrentShrink2  = agShrink2S.begin();
  cpIterator lcCurrentStretch1 = agStretch1S.begin();
  cpIterator lcCurrentStretch2 = agStretch2S.begin();

  while (agOptimum1!=agOptimum2) {
   if (agOptimum1<agOptimum2) {
    if (improveBalance(lcCurrentShrink2,agShrink2S.end(),lcCurrentStretch1,agStretch1S.end(),
                       lcNewShrink1S,lcNewStretch2S,lcLastDecrease2,lcLastIncrease1,agOptimum1,
                       agOptimum2,agTensionAdjusted)==-1) {
     clean(agShrink1S);
     clean(agShrink2S);
     clean(agStretch1S);
     clean(agStretch2S);
     return (false);
    }
   }
   else {
    if (improveBalance(lcCurrentShrink1,agShrink1S.end(),lcCurrentStretch2,agStretch2S.end(),
                       lcNewShrink2S,lcNewStretch1S,lcLastDecrease1,lcLastIncrease2,agOptimum2,
                       agOptimum1,agTensionAdjusted)==-1) {
     clean(agShrink1S);
     clean(agShrink2S);
     clean(agStretch1S);
     clean(agStretch2S);
     return (false);
    }
   }
  }

  if (lcLastIncrease1!=0.0) {
   lcVariation=*lcCurrentStretch1;
   lcVariation.copyArcs(*lcCurrentStretch1);
   lcVariation.available()=lcLastIncrease1-(*lcCurrentStretch1).available();
   lcVariation.cost()*=-1.0;
   lcNewShrink1S.push_back(lcVariation);
  }

  if (lcLastIncrease2!=0.0) {
   lcVariation=*lcCurrentStretch2;
   lcVariation.copyArcs(*lcCurrentStretch2);
   lcVariation.available()=lcLastIncrease2-(*lcCurrentStretch2).available();
   lcVariation.cost()*=-1.0;
   lcNewShrink2S.push_back(lcVariation);
  }

  if (lcLastDecrease1!=0.0) {
   lcVariation=*lcCurrentShrink1;
   lcVariation.copyArcs(*lcCurrentShrink1);
   lcVariation.available()=lcLastDecrease1-(*lcCurrentShrink1).available();
   lcVariation.cost()*=-1.0;
   lcNewStretch1S.push_back(lcVariation);
  }

  if (lcLastDecrease2!=0.0) {
   lcVariation=*lcCurrentShrink2;
   lcVariation.copyArcs(*lcCurrentShrink2);
   lcVariation.available()=lcLastDecrease2-(*lcCurrentShrink2).available();
   lcVariation.cost()*=-1.0;
   lcNewStretch2S.push_back(lcVariation);
  }

  mergeSerialVariations(lcTempoShrink1S,lcNewShrink1S.rbegin(),lcNewShrink1S.rend(),
                        lcCurrentShrink1,agShrink1S.end());

  mergeSerialVariations(lcTempoShrink2S,lcNewShrink2S.rbegin(),lcNewShrink2S.rend(),
                        lcCurrentShrink2,agShrink2S.end());

  mergeSerialVariations(lcTempoStretch1S,lcNewStretch1S.rbegin(),lcNewStretch1S.rend(),
                        lcCurrentStretch1,agStretch1S.end());

  mergeSerialVariations(lcTempoStretch2S,lcNewStretch2S.rbegin(),lcNewStretch2S.rend(),
                        lcCurrentStretch2,agStretch2S.end());

  mergeParallelVariations(agShrinkS,lcTempoShrink1S,lcTempoShrink2S);
  mergeParallelVariations(agStretchS,lcTempoStretch1S,lcTempoStretch2S);

  return (true);
 }
 //--------------------------------------------------------------------------MergeParallelVariations
 template <tdGraph>
 void mergeParallelVariations(std_deque(clVariation<tuGraph>) & agFusion,
                              std_deque(clVariation<tuGraph>) & agList1,
                              std_deque(clVariation<tuGraph>) & agList2) {
  typedef typename std_deque(clVariation<tuGraph>)::iterator cpIterator;

  clVariation<tuGraph> lcVariation;

  cpIterator lcCurrentVariation1 = agList1.begin();
  cpIterator lcCurrentVariation2 = agList2.begin();
  cpIterator lcLastVariation1    = agList1.end();
  cpIterator lcLastVariation2    = agList2.end();

  while (lcCurrentVariation1!=lcLastVariation1 and lcCurrentVariation2!=lcLastVariation2) {
   if ((*lcCurrentVariation1).available()<(*lcCurrentVariation2).available()) {
    lcVariation=*lcCurrentVariation1;
    lcVariation.addArcs(*lcCurrentVariation2);
    lcVariation.cost()+=(*lcCurrentVariation2).cost();
    (*lcCurrentVariation2).available()-=lcVariation.available();
    lcCurrentVariation1++;
   }
   else {
    lcVariation=*lcCurrentVariation2;
    lcVariation.addArcs(*lcCurrentVariation1);
    lcVariation.cost()+=(*lcCurrentVariation1).cost();
    (*lcCurrentVariation1).available()-=lcVariation.available();

    if ((*lcCurrentVariation1).available()==0.0) {
     delete_object((*lcCurrentVariation1).arcs());
     lcCurrentVariation1++;
    }

    lcCurrentVariation2++;
   }

   agFusion.push_back(lcVariation);
  }

  while (lcCurrentVariation1!=lcLastVariation1) {
   delete_object((*lcCurrentVariation1).arcs());
   lcCurrentVariation1++;
  }

  while (lcCurrentVariation2!=lcLastVariation2) {
   delete_object((*lcCurrentVariation2).arcs());
   lcCurrentVariation2++;
  }
 }
 //----------------------------------------------------------------------------MergeSerialVariations
 template <tdGraph,class prIterator1,class prIterator2>
 void mergeSerialVariations(std_deque(clVariation<tuGraph>) & agFusion,
                            prIterator1 agCurrentVariation1,const prIterator1 agLastVariation1,
                            prIterator2 agCurrentVariation2,const prIterator2 agLastVariation2) {
  while (agCurrentVariation1!=agLastVariation1 and agCurrentVariation2!=agLastVariation2) {
   if ((*agCurrentVariation1).cost()<(*agCurrentVariation2).cost()) {
    agFusion.push_back(*agCurrentVariation1);
    agCurrentVariation1++;
   }
   else {
    agFusion.push_back(*agCurrentVariation2);
    agCurrentVariation2++;
   }
  }

  while (agCurrentVariation1!=agLastVariation1) {
   agFusion.push_back(*agCurrentVariation1);
   agCurrentVariation1++;
  }

  while (agCurrentVariation2!=agLastVariation2) {
   agFusion.push_back(*agCurrentVariation2);
   agCurrentVariation2++;
  }
 }
 //-------------------------------------------------------------------------------CreatePiecewiseArc
 template <tdGraph>
 clPiecewiseArc * createPiecewiseArc(clPiecewiseGraph & agGraph,clTreeInfo<tuGraph> & agTreeInfo,
                                     clNode<tuGraph> & agSource,clNode<tuGraph> & agTarget,
                                     tyReal agOptimum,tyBoolean agTensionAdjusted) {
  typedef std_map(clPiecewiseArc *,tyInteger) clCycle;
  typedef clCycle::const_iterator             clArcIterator;

  clArcIterator lcCurrentArc;
  clCycle       lcCycle;
  clArcIterator lcLastArc;

  clPiecewiseArc * lcArc = new_object(clPiecewiseArc(agGraph,agGraph.getNewArcKey(),
                                      clPiecewiseArcData(),agSource.key(),agTarget.key()));

  tyCardinal lcCounter = agTreeInfo.shrinkCosts.size();
  tyReal     lcTension = agOptimum;

  // Shrinking Cost //
  lcArc->data().optimum()=agOptimum;
  lcArc->data().expected()=agOptimum;
  lcArc->data().update();

  while (lcCounter>0) {
   --lcCounter;
   lcTension-=agTreeInfo.shrinkCosts[lcCounter].available();

   lcArc->data().shrinkingCosts().push_back(
                 standard::make_pair(agTreeInfo.shrinkCosts[lcCounter].available(),
                 agTreeInfo.shrinkCosts[lcCounter].cost()));
  }

  // Stretching Cost //
  lcArc->data().minimum()=lcTension;
  lcTension=agOptimum;
  lcCounter=agTreeInfo.stretchCosts.size();

  while (lcCounter>0) {
   --lcCounter;
   lcTension+=agTreeInfo.stretchCosts[lcCounter].available();

   lcArc->data().stretchingCosts().push_back(
                 standard::make_pair(agTreeInfo.stretchCosts[lcCounter].available(),
                 agTreeInfo.stretchCosts[lcCounter].cost()));
  }

  lcArc->data().maximum()=lcTension;
  lcArc->data().flow()=0.0;

  // Tension Adjusting //
  if (agTensionAdjusted and findCycle(*lcArc,lcCycle)) {
   lcCurrentArc=lcCycle.begin();
   lcLastArc=lcCycle.end();
   lcTension=0.0;

   while (lcCurrentArc!=lcLastArc) {
    if ((*lcCurrentArc).second==+1) {
     if ((*lcCurrentArc).first!=lcArc) lcTension-=(*lcCurrentArc).first->data().tension();
    }
    else lcTension+=(*lcCurrentArc).first->data().tension();

    ++lcCurrentArc;
   }

   lcArc->data().tension()=lcTension;
   lcArc->data().update();
  }

  return (lcArc);
 }
 //----------------------------------------------------------------------------------DisintegrateArc
 template <tdGraph>
 void disintegrateArc(clBinaryTree<clSerialParallelData<tuGraph> > & agTree,
                      clPiecewiseGraph & agGraph,
                      clNode<tuGraph> ** agSource,clNode<tuGraph> ** agTarget,
                      std_map(clNode<tuGraph> *,
                              clBinaryTree<clSerialParallelData<tuGraph> > *) & agTreeX,
                      tyBoolean agBackToOriginalGraph) {
  clPiecewiseArc *  lcArc;
  clNode<tuGraph> * lcMiddle;

  if (agTree.data().operation()==clSerialParallelData<tuGraph>::none) {
   lcArc=&(agGraph.arc(agTree.data().arc()->key()));

   if (agBackToOriginalGraph) {
    lcArc->setSourceNode(&(agGraph.node(agTree.data().arc()->sourceNode()->key())));
    lcArc->setTargetNode(&(agGraph.node(agTree.data().arc()->targetNode()->key())));
   }

   lcArc->data().tension()=agTree.data().arc()->data().tension();
   lcArc->data().flow()=agTree.data().arc()->data().flow();
  }
  else {
   disintegrateArc(agTree.left(),agGraph,agSource,&lcMiddle,agTreeX,agBackToOriginalGraph);
   agTreeX.erase(lcMiddle);
   disintegrateArc(agTree.right(),agGraph,&lcMiddle,agTarget,agTreeX,agBackToOriginalGraph);
  }
 }
 //-----------------------------------------------------------------------------------------FindFlow
 template <tdGraph> void findFlow(clBinaryTree<clSerialParallelData<tuGraph> > & agTree,
                                  tyReal & agMainFlow) {
  typedef std_vector(clArc<tuGraph> *)       cpArcS;
  typedef clSerialParallelData<tuGraph>      cpSerialParallelData;
  typedef clBinaryTree<cpSerialParallelData> cpTree;
  typedef std_vector(cpTree *)               cpTreeS;
  typedef std_vector(tyCardinal)             clCardinalS;
  typedef std_vector(tyReal)                 clRealS;
  typedef std_deque(clVariation<tuGraph>)    cpVariationS;
  typedef std_vector(cpVariationS *)         cpVariationD;

  tyReal         lcFlow1;
  tyReal         lcFlow2;
  clRealS        lcFlowS;
  clCardinalS    lcStateS;
  cpTree *       lcTree;
  cpTreeS        lcTreeS;
  cpVariationS * lcVariation1S;
  cpVariationS * lcVariation2S;
  cpVariationD   lcVariationD;

  tyReal         lcFlow       = 0.0;
  cpVariationS * lcVariationS = nil;

  if (not agTree.empty()) {
   lcTreeS.push_back(&agTree);
   lcStateS.push_back(0);
   lcFlowS.push_back(0.0);
   lcVariationD.push_back(nil);

   while (lcTreeS.size()>0) {
    lcTree=lcTreeS.back();

    switch(++(lcStateS.back())) {
     case 1:
      // Single Arc //
      if (lcTree->data().operation()==cpSerialParallelData::none) {
       lcFlow=minimumFlow(*(lcTree->data().arc()));
       lcFlow2=maximumFlow(*(lcTree->data().arc()));
       lcTree->data().arc()->data().flow()=lcFlow;
       lcVariationS=new_object(cpVariationS());

       if (lcFlow==realMin()) {
        lcVariationS->push_back(clVariation<tuGraph>());
        lcVariationS->back().arcs()=new_object(cpArcS());
        lcVariationS->back().arcs()->push_back(lcTree->data().arc());
        lcVariationS->back().infinity()=true;

        if (lcFlow2==realMax()) lcVariationS->back().available()=0.0;
        else {
         lcVariationS->back().available()=lcFlow2;
         lcFlow2=0.0;
        }

        lcTree->data().arc()->data().flow()=lcVariationS->back().available();
       }
       else lcFlow2-=lcFlow;

       if (lcFlow2>0.0) {
        lcVariationS->push_back(clVariation<tuGraph>());
        lcVariationS->back().arcs()=new_object(cpArcS());
        lcVariationS->back().arcs()->push_back(lcTree->data().arc());
        lcVariationS->back().available()=lcFlow2;
       }

       lcTreeS.pop_back();
       lcStateS.pop_back();
       lcFlowS.pop_back();
       lcVariationD.pop_back();
      }

      // Left Member Of An SP-Operation //
      else {
       lcTreeS.push_back(&(lcTree->left()));
       lcStateS.push_back(0);
       lcFlowS.push_back(0.0);
       lcVariationD.push_back(nil);
      }

      break;

     case 2: // Right Member Of An SP-Operation //
      lcVariationD.back()=lcVariationS;
      lcFlowS.back()=lcFlow;
      lcTreeS.push_back(&(lcTree->right()));
      lcStateS.push_back(0);
      lcFlowS.push_back(0.0);
      lcVariationD.push_back(nil);
      break;

     default:
      // Preparation To SP-Fusion //
      lcFlow1=lcFlowS.back();
      lcFlow2=lcFlow;
      lcVariation1S=lcVariationD.back();
      lcVariation2S=lcVariationS;
      lcVariationS=new_object(cpVariationS());

      // Serial Fusion //
      if (lcTree->data().operation()==cpSerialParallelData::serial) {
       if (lcFlow1<lcFlow2) increaseFlow(*lcVariation1S,lcFlow1,lcFlow2);
       else if (lcFlow1>lcFlow2) increaseFlow(*lcVariation2S,lcFlow2,lcFlow1);

       mergeSerialFlows(*lcVariationS,*lcVariation1S,*lcVariation2S);
       lcFlow=lcFlow1;
      }

      // Parallel Fusion //
      else {
       mergeParallelFlows(*lcVariationS,*lcVariation1S,*lcVariation2S,lcFlow1,lcFlow2);
       lcFlow=(lcFlow1==realMin() or lcFlow2==realMin() ? realMin() : lcFlow1+lcFlow2);
      }

      // Cleaning And Stack Update //
      delete_object(lcVariation1S);
      delete_object(lcVariation2S);
      lcTreeS.pop_back();
      lcStateS.pop_back();
      lcFlowS.pop_back();
      lcVariationD.pop_back();
    }
   }

   // Adjusting To Main Flow //
   increaseFlow(*lcVariationS,lcFlow,agMainFlow);
   clean(*lcVariationS);
   delete_object(lcVariationS);
  }
 }
 //-------------------------------------------------------------------------------------IncreaseFlow
 template <tdGraph> void increaseFlow(std_deque(clVariation<tuGraph>) & agVariationS,
                                      tyReal & agOldFlow,tyReal agNewFlow) {
  method_name("increaseFlow");

  tyCardinal lcCounter;
  tyReal     lcIncrement;
  tyReal     lcMaximum;

  if (agNewFlow!=realMin() and agOldFlow<agNewFlow) {
   if (agOldFlow==realMin()) {
    if (agVariationS.size()==0 or not agVariationS.front().infinity())
     send_error(erNotEnoughAvailableFlow);

    lcMaximum=agVariationS.front().available();
    lcIncrement=mini(lcMaximum,agNewFlow);
    lcIncrement=lcMaximum-lcIncrement;
    lcCounter=agVariationS.front().arcs()->size();

    while (lcCounter>0) {
     --lcCounter;
     (*(agVariationS.front().arcs()))[lcCounter]->data().flow()-=lcIncrement;
    }

    agVariationS.front().available()=lcIncrement;
    agVariationS.front().infinity()=false;
    agOldFlow=lcMaximum-lcIncrement;

    if (agVariationS.front().available()==0.0) {
     delete_object(agVariationS.front().arcs());
     agVariationS.pop_front();
    }
   }

   while (agOldFlow<agNewFlow) {
    if (agVariationS.size()==0) send_error(erNotEnoughAvailableFlow);
    lcIncrement=mini(agNewFlow-agOldFlow,agVariationS.front().available());
    lcCounter=agVariationS.front().arcs()->size();

    while (lcCounter>0) {
     --lcCounter;
     (*(agVariationS.front().arcs()))[lcCounter]->data().flow()+=lcIncrement;
    }

    agVariationS.front().available()-=lcIncrement;

    if (agVariationS.front().available()==0.0) {
     delete_object(agVariationS.front().arcs());
     agVariationS.pop_front();
    }

    agOldFlow+=lcIncrement;
   }
  }
 }
 //--------------------------------------------------------------------------------------MakeConform
 template <class prConformity,class prDirectMintyColor,class prInverseMintyColor>
 tyInteger makeConform(clPiecewiseArc ** agArcS,tyCardinal & agCounter,prConformity & agConformity,
                       prDirectMintyColor & agDirectMintyColor,
                       prInverseMintyColor & agInverseMintyColor) {
  clPiecewiseArc * lcArc;

  clPiecewiseArc ** lcArcS      = new_array(clPiecewiseArc *,agCounter);
  clPiecewiseArc ** lcArc2S     = lcArcS;
  tyCardinal        lcCounter   = 0;
  tyInteger         lcIteration = 0;

  try {
   while (agCounter>0) {
    standard::swap(agArcS,lcArcS);
    standard::swap(lcCounter,agCounter);

    while (lcCounter>0) {
     --lcCounter;
     lcArc=lcArcS[lcCounter];

     if (not agConformity.conformedArc(*lcArc)) {
      ++lcIteration;

      graphProblemMinCostTensionConforming_private::
      improveArc(*lcArc,agDirectMintyColor,agInverseMintyColor,agConformity);

      agArcS[agCounter]=lcArc;
      ++agCounter;
     }
    }
   }
  }

  catch (ctError &) {
   delete_array(lcArc2S);
   return (-1);
  }

  delete_array(lcArc2S);
  return (lcIteration);
 }
 //-------------------------------------------------------------------------------MergeParallelFlows
 template <tdGraph> void mergeParallelFlows(std_deque(clVariation<tuGraph>) & agFusion,
                                            std_deque(clVariation<tuGraph>) & agVariation1S,
                                            std_deque(clVariation<tuGraph>) & agVariation2S,
                                            tyReal agFlow1,tyReal agFlow2) {
  typedef typename std_deque(clVariation<tuGraph>)::const_iterator cpIterator;

  cpIterator lcCurrentVariation1 = agVariation1S.begin();
  cpIterator lcCurrentVariation2 = agVariation2S.begin();
  cpIterator lcLastVariation1    = agVariation1S.end();
  cpIterator lcLastVariation2    = agVariation2S.end();

  tyBoolean lcInfinity1 = false;
  tyBoolean lcInfinity2 = false;

  if (lcCurrentVariation1!=lcLastVariation1) lcInfinity1=(*lcCurrentVariation1).infinity();
  if (lcCurrentVariation2!=lcLastVariation2) lcInfinity2=(*lcCurrentVariation2).infinity();

  if (lcInfinity1) {
   agFusion.push_back(*lcCurrentVariation1);
   ++lcCurrentVariation1;

   if (lcInfinity2) {
    agFusion.back().available()+=(*lcCurrentVariation2).available();
    delete_object((*lcCurrentVariation2).arcs());
    ++lcCurrentVariation2;
   }
   else agFusion.back().available()+=agFlow2;
  }
  else if (lcInfinity2) {
   agFusion.push_back(*lcCurrentVariation2);
   ++lcCurrentVariation2;
   agFusion.back().available()+=agFlow1;
  }

  while (lcCurrentVariation1!=lcLastVariation1) {
   agFusion.push_back(*lcCurrentVariation1);
   ++lcCurrentVariation1;
  }

  while (lcCurrentVariation2!=lcLastVariation2) {
   agFusion.push_back(*lcCurrentVariation2);
   ++lcCurrentVariation2;
  }
 }
 //---------------------------------------------------------------------------------MergeSerialFlows
 template <tdGraph> void mergeSerialFlows(std_deque(clVariation<tuGraph>) & agFusion,
                                          std_deque(clVariation<tuGraph>) & agVariation1S,
                                          std_deque(clVariation<tuGraph>) & agVariation2S) {
  method_name("mergeSerialFlows");

  typedef typename std_deque(clVariation<tuGraph>)::iterator cpIterator;

  tyCardinal           lcCounter;
  tyReal               lcIncrement;
  clVariation<tuGraph> lcVariation;

  cpIterator lcCurrentVariation1 = agVariation1S.begin();
  cpIterator lcCurrentVariation2 = agVariation2S.begin();
  cpIterator lcLastVariation1    = agVariation1S.end();
  cpIterator lcLastVariation2    = agVariation2S.end();

  tyBoolean lcInfinity1 = false;
  tyBoolean lcInfinity2 = false;

  if (lcCurrentVariation1!=lcLastVariation1) lcInfinity1=(*lcCurrentVariation1).infinity();
  if (lcCurrentVariation2!=lcLastVariation2) lcInfinity2=(*lcCurrentVariation2).infinity();

  if ((lcInfinity1 and not lcInfinity2) or (not lcInfinity1 and lcInfinity2))
   send_error(erNotEnoughAvailableFlow);

  if (lcInfinity1) {
   lcIncrement=(*lcCurrentVariation1).available()-(*lcCurrentVariation2).available();

   if (lcIncrement<0.0) {
    agFusion.push_back(*lcCurrentVariation1);
    agFusion.back().addArcs(*lcCurrentVariation2);
    lcCounter=(*lcCurrentVariation2).arcs()->size();

    while (lcCounter>0) {
     --lcCounter;
     (*((*lcCurrentVariation2).arcs()))[lcCounter]->data().flow()+=lcIncrement;
    }

    (*lcCurrentVariation2).available()=-lcIncrement;
    (*lcCurrentVariation2).infinity()=false;
    ++lcCurrentVariation1;
   }
   else {
    agFusion.push_back(*lcCurrentVariation2);
    agFusion.back().addArcs(*lcCurrentVariation1);

    if (lcIncrement==0.0) {
     delete_object((*lcCurrentVariation1).arcs());
     ++lcCurrentVariation1;
    }
    else {
     lcCounter=(*lcCurrentVariation1).arcs()->size();

     while (lcCounter>0) {
      --lcCounter;
      (*((*lcCurrentVariation1).arcs()))[lcCounter]->data().flow()-=lcIncrement;
     }

     (*lcCurrentVariation1).available()=lcIncrement;
     (*lcCurrentVariation1).infinity()=false;
    }

    ++lcCurrentVariation2;
   }
  }

  while (lcCurrentVariation1!=lcLastVariation1 and lcCurrentVariation2!=lcLastVariation2) {
   if ((*lcCurrentVariation1).available()<0.0) send_error(erNotEnoughAvailableFlow);
   if ((*lcCurrentVariation2).available()<0.0) send_error(erNotEnoughAvailableFlow);

   if ((*lcCurrentVariation1).available()<(*lcCurrentVariation2).available()) {
    agFusion.push_back(*lcCurrentVariation1);
    agFusion.back().addArcs(*lcCurrentVariation2);
    (*lcCurrentVariation2).available()-=(*lcCurrentVariation1).available();
    ++lcCurrentVariation1;
   }
   else {
    agFusion.push_back(*lcCurrentVariation2);
    agFusion.back().addArcs(*lcCurrentVariation1);
    (*lcCurrentVariation1).available()-=(*lcCurrentVariation2).available();
    ++lcCurrentVariation2;

    if ((*lcCurrentVariation1).available()==0.0) {
     delete_object((*lcCurrentVariation1).arcs());
     ++lcCurrentVariation1;
    }
   }
  }

  while (lcCurrentVariation1!=lcLastVariation1) {
   delete_object((*lcCurrentVariation1).arcs());
   ++lcCurrentVariation1;
  }

  while (lcCurrentVariation2!=lcLastVariation2) {
   delete_object((*lcCurrentVariation2).arcs());
   ++lcCurrentVariation2;
  }
 }
 //--------------------------------------------------------------------------------------UpdateCosts
 template <tdGraph> void updateCosts(clTreeInfo<tuGraph> & agTreeInfo) {
  tyReal lcIncrement;

  tyReal lcNewTension = agTreeInfo.arc->data().tension();
  tyReal lcOldTension = agTreeInfo.arc->data().optimum();

  // Increase Tension //
  if (lcOldTension<lcNewTension) {
   while (lcOldTension<lcNewTension) {
    lcIncrement=mini(lcNewTension-lcOldTension,agTreeInfo.stretchCosts.front().available());
    lcOldTension+=lcIncrement;
    agTreeInfo.shrinkCosts.push_front(agTreeInfo.stretchCosts.front());
    agTreeInfo.shrinkCosts.front().cost()*=-1;

    if (lcIncrement<agTreeInfo.stretchCosts.front().available()) {
     agTreeInfo.shrinkCosts.front().available()=lcIncrement;
     agTreeInfo.shrinkCosts.front().copyArcs(agTreeInfo.stretchCosts.front());
     agTreeInfo.stretchCosts.front().available()-=lcIncrement;
    }
    else agTreeInfo.stretchCosts.pop_front();
   }
  }

  // Decrease Tension //
  else {
   while (lcOldTension>lcNewTension) {
    lcIncrement=mini(lcOldTension-lcNewTension,agTreeInfo.shrinkCosts.front().available());
    lcOldTension-=lcIncrement;
    agTreeInfo.stretchCosts.push_front(agTreeInfo.shrinkCosts.front());
    agTreeInfo.stretchCosts.front().cost()*=-1;

    if (lcIncrement<agTreeInfo.shrinkCosts.front().available()) {
     agTreeInfo.stretchCosts.front().available()=lcIncrement;
     agTreeInfo.stretchCosts.front().copyArcs(agTreeInfo.shrinkCosts.front());
     agTreeInfo.shrinkCosts.front().available()-=lcIncrement;
    }
    else agTreeInfo.shrinkCosts.pop_front();
   }
  }
 }
 //------------------------------------------------------------------------------------UpdateTension
 template <tdGraph> void updateTension(clTreeInfo<tuGraph> & agTreeInfo) {
  method_name("updateTension");

  std_vector(clArc<tuGraph> *) * lcArcS;
  tyCardinal                     lcCounter2;
  tyReal                         lcIncrement;
  tyCardinal                     lcSize;

  tyCardinal lcCounter1   = 0;
  tyReal     lcNewTension = agTreeInfo.arc->data().tension();
  tyReal     lcOldTension = agTreeInfo.tension;

  // Increase Tension //
  if (lcOldTension<lcNewTension) {
   while (lcOldTension<lcNewTension) {
    if (lcCounter1==agTreeInfo.stretchCosts.size()) send_error(erNotEnoughAvailableTension);
    lcIncrement=mini(lcNewTension-lcOldTension,agTreeInfo.stretchCosts[lcCounter1].available());
    lcArcS=agTreeInfo.stretchCosts[lcCounter1].arcs();
    lcSize=(lcArcS==nil ? 0 : lcArcS->size());
    lcCounter2=0;

    while (lcCounter2<lcSize) {
     (*lcArcS)[lcCounter2]->data().tension()+=lcIncrement;
     ++lcCounter2;
    }

    ++lcCounter1;
    lcOldTension+=lcIncrement;
   }
  }

  // Decrease Tension //
  else {
   while (lcOldTension>lcNewTension) {
    if (lcCounter1==agTreeInfo.shrinkCosts.size()) send_error(erNotEnoughAvailableTension);
    lcIncrement=mini(lcOldTension-lcNewTension,agTreeInfo.shrinkCosts[lcCounter1].available());
    lcArcS=agTreeInfo.shrinkCosts[lcCounter1].arcs();
    lcSize=(lcArcS==nil ? 0 : lcArcS->size());
    lcCounter2=0;

    while (lcCounter2<lcSize) {
     (*lcArcS)[lcCounter2]->data().tension()-=lcIncrement;
     ++lcCounter2;
    }

    ++lcCounter1;
    lcOldTension-=lcIncrement;
   }
  }
 }
}

// 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 by decomposing the graph into
    serial-parallel components, using the method given as argument, or directly if serial-parallel
    components are given (default is not). The number of components obtained can be displayed
    (default is not). */
 template <tdGraph> tyInteger clSolveAlgoI<tuGraph>::run(clGraph<tuGraph> & agGraph,
                         const clDecomposeAlgo<tuGraph> & agDecomposeAlgo,
                         std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) * agComponentS,
                         tyBoolean agDisplayed) const {
  typedef clNode<tuGraph>                                 cpNode;
  typedef graphProblemMinCostTensionStructure::clNodeData clNodeData;
  typedef clBinaryTree<clSerialParallelData<tuGraph> >    cpTree;
  typedef private_area::clTreeInfo<tuGraph>               cpTreeInfo;

  typedef typename clGraph<tuGraph>::cpArcX::const_iterator       cpArcIterator;
  typedef typename std_map(cpTree *,cpTreeInfo *)::const_iterator cpInfoIterator;
  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator      cpNodeIterator;

  clPiecewiseArc *               lcArc;
  tyInteger                      lcClock;
  tyReal                         lcCost;
  tyCardinal                     lcCounter1;
  tyCardinal                     lcCounter3;
  cpInfoIterator                 lcCurrentInfo;
  cpNode *                       lcDummyNode;
  clPiecewiseGraph               lcGraph;
  cpInfoIterator                 lcLastInfo;
  tyReal                         lcLength;
  std_vector(cpNode *)           lcNodeS;
  tyReal                         lcOptimum;
  tyInteger                      lcReturn;
  cpNode *                       lcSourceNode;
  cpNode *                       lcTargetNode;
  cpTree *                       lcTree1;
  cpTree *                       lcTree2;
  cpTreeInfo *                   lcTreeInfo;
  std_map(cpTree *,cpTreeInfo *) lcTreeInfoX;
  std_vector(cpTree *)           lcTreeS;
  std_map(cpNode *,cpTree *)     lcTreeX;

  typedef graphProblemMinCostTensionConformingPiecewise_private::
          clConformity<clPiecewiseArcData,clNodeData> clConformity;

  typedef graphProblemMinCostTensionConforming_private::
          clDirectMintyColor<clPiecewiseArcData,clNodeData,clConformity > clDirectMintyColor;

  typedef graphProblemMinCostTensionConforming_private::
          clInverseMintyColor<clPiecewiseArcData,clNodeData,clConformity > clInverseMintyColor;

  clConformity        lcConformity;
  clDirectMintyColor  lcDirectMintyColor(lcConformity);
  clInverseMintyColor lcInverseMintyColor(lcConformity);

  tyInteger         lcAggregationTime    = 0;
  clPiecewiseArc ** lcArcS               = new_array(clPiecewiseArc *,agGraph.arcs().size());
  tyInteger         lcConformingTime     = 0;
  tyCardinal        lcCounter2           = 0;
  cpArcIterator     lcCurrentArc         = agGraph.arcs().begin();
  cpNodeIterator    lcCurrentNode        = agGraph.nodes().begin();
  tyInteger         lcDisintegrationTime = 0;
  tyInteger         lcIteration          = 0;
  cpArcIterator     lcLastArc            = agGraph.arcs().end();
  cpNodeIterator    lcLastNode           = agGraph.nodes().end();

  // Serial-Parallel Decomposition //
  lcClock=environment::currentClock();

  if (agComponentS==nil) agDecomposeAlgo.run(agGraph,lcTreeS);
  else {
   lcCounter1=agComponentS->size();

   while (lcCounter1>0) {
    --lcCounter1;
    lcTreeS.push_back((*agComponentS)[lcCounter1]);
   }
  }

  lcClock=environment::currentClock()-lcClock;

  if (agDisplayed) {
   environment::out("Components = ",false,true);
   environment::out(tyCardinal(lcTreeS.size()),true);
   environment::out("Decomposition Time = ",false,true);
   environment::out(lcClock,true);
  }

  // Nodes Copy //
  while (lcCurrentNode!=lcLastNode) {
   new_object(clPiecewiseNode(lcGraph,(*lcCurrentNode).first,clNodeData()));
   ++lcCurrentNode;
  }

  // Arcs Copy (With Nil Extremities) //
  while (lcCurrentArc!=lcLastArc) {
   lcArc=new_object(clPiecewiseArc(lcGraph,(*lcCurrentArc).first,clPiecewiseArcData(),
                                   nilNode(),nilNode()));

   lcArc->data().optimum()=(*lcCurrentArc).second->data().optimum();
   lcArc->data().tension()=(*lcCurrentArc).second->data().optimum();
   lcArc->data().update();
   lcArc->data().minimum()=(*lcCurrentArc).second->data().minimum();
   lcArc->data().maximum()=(*lcCurrentArc).second->data().maximum();
   lcLength=lcArc->data().optimum()-lcArc->data().minimum();
   lcCost=(*lcCurrentArc).second->data().shrinkingCost();
   lcArc->data().shrinkingCosts().push_back(standard::make_pair(lcLength,lcCost));
   lcLength=lcArc->data().maximum()-lcArc->data().optimum();
   lcCost=(*lcCurrentArc).second->data().stretchingCost();
   lcArc->data().stretchingCosts().push_back(standard::make_pair(lcLength,lcCost));
   lcArc->data().flow()=0.0;
   ++lcCurrentArc;
  }

  // Components Gathering //
  lcCounter1=lcTreeS.size();

  while (lcCounter1>0) {
   --lcCounter1;
   lcTree1=lcTreeS[lcCounter1];
   lcNodeS.erase(lcNodeS.begin(),lcNodeS.end());
   findNodes(*lcTree1,lcNodeS,&lcSourceNode,&lcTargetNode);
   lcCounter3=lcNodeS.size();

   while (lcCounter3>0) {
    --lcCounter3;
    lcTreeX.insert(std_make_pair(lcNodeS[lcCounter3],lcTree1));
   }

   // Arc Disintegration //
   if (lcTreeX.count(lcSourceNode)>0) {
    lcTree2=lcTreeX[lcSourceNode];
    lcTreeInfo=lcTreeInfoX[lcTree2];

    if (lcTreeInfo->aggregated) {
     if (lcCounter2>0) {
      lcClock=environment::currentClock();

      lcReturn=private_area::makeConform(lcArcS,lcCounter2,lcConformity,
                                         lcDirectMintyColor,lcInverseMintyColor);

      if (lcReturn==-1) {
       lcGraph.solved()=false;
       lcIteration=-1;
       goto lbEnd;
      }

      lcIteration+=lcReturn;
      lcConformingTime+=environment::currentClock()-lcClock;
     }

     lcTreeInfo->aggregated=false;
     lcClock=environment::currentClock();
     private_area::updateTension(*lcTreeInfo);
     private_area::findFlow(*lcTree2,lcTreeInfo->arc->data().flow());
     private_area::disintegrateArc(*lcTree2,lcGraph,&lcDummyNode,&lcDummyNode,lcTreeX,true);
     delete_object(lcTreeInfo->arc);
     lcDisintegrationTime+=environment::currentClock()-lcClock;
    }
   }

   if (lcTreeX.count(lcTargetNode)>0) {
    lcTree2=lcTreeX[lcTargetNode];
    lcTreeInfo=lcTreeInfoX[lcTree2];

    if (lcTreeInfo->aggregated) {
     if (lcCounter2>0) {
      lcClock=environment::currentClock();

      lcReturn=private_area::makeConform(lcArcS,lcCounter2,lcConformity,
                                         lcDirectMintyColor,lcInverseMintyColor);

      if (lcReturn==-1) {
       lcGraph.solved()=false;
       lcIteration=-1;
       goto lbEnd;
      }

      lcIteration+=lcReturn;
      lcConformingTime+=environment::currentClock()-lcClock;
     }

     lcClock=environment::currentClock();
     lcTreeInfo->aggregated=false;
     private_area::updateTension(*lcTreeInfo);
     private_area::findFlow(*lcTree2,lcTreeInfo->arc->data().flow());
     private_area::disintegrateArc(*lcTree2,lcGraph,&lcDummyNode,&lcDummyNode,lcTreeX,true);
     delete_object(lcTreeInfo->arc);
     lcDisintegrationTime+=environment::currentClock()-lcClock;
    }
   }

   // Aggregated Arc Creation //
   lcClock=environment::currentClock();
   lcTreeInfo=new_object(cpTreeInfo());
   lcTreeInfoX.insert(std_make_pair(lcTree1,lcTreeInfo));
   lcTreeInfo->aggregated=true;

   if (private_area::findMinCostTension(*lcTree1,lcTreeInfo->shrinkCosts,
                                        lcTreeInfo->stretchCosts,lcOptimum)==-1) {
    lcTreeInfoX.erase(lcTree1);
    delete_object(lcTreeInfo);
    lcGraph.solved()=false;
    lcIteration=-1;
    goto lbEnd;
   }

   lcTreeInfo->arc=private_area::createPiecewiseArc(lcGraph,*lcTreeInfo,*lcSourceNode,
                                                    *lcTargetNode,lcOptimum,true);

   lcTreeInfo->tension=lcOptimum;
   lcAggregationTime+=environment::currentClock()-lcClock;

   // Non-Conform Arcs Listing //
   lcArcS[lcCounter2]=lcTreeInfo->arc;
   ++lcCounter2;
  }

  if (lcCounter2>0) {
   lcClock=environment::currentClock();

   lcReturn=private_area::makeConform(lcArcS,lcCounter2,lcConformity,
                                      lcDirectMintyColor,lcInverseMintyColor);

   if (lcReturn==-1) {
    lcGraph.solved()=false;
    lcIteration=-1;
    goto lbEnd;
   }

   lcIteration+=lcReturn;
   lcConformingTime+=environment::currentClock()-lcClock;
  }

  lcGraph.solved()=true;
  lbEnd:

  // Remaining Aggregated Arcs Disintegration //
  lcCurrentInfo=lcTreeInfoX.begin();
  lcLastInfo=lcTreeInfoX.end();

  while (lcCurrentInfo!=lcLastInfo) {
   lcTreeInfo=(*lcCurrentInfo).second;

   if (lcTreeInfo->aggregated) {
    if (lcGraph.solved()) {
     lcTree2=(*lcCurrentInfo).first;
     lcClock=environment::currentClock();
     private_area::updateTension(*lcTreeInfo);
     private_area::disintegrateArc(*lcTree2,lcGraph,&lcDummyNode,&lcDummyNode,lcTreeX,true);
     lcDisintegrationTime+=environment::currentClock()-lcClock;
    }

    delete_object(lcTreeInfo->arc);
   }

   private_area::clean(lcTreeInfo->shrinkCosts);
   private_area::clean(lcTreeInfo->stretchCosts);
   delete_object(lcTreeInfo);
   ++lcCurrentInfo;
  }

  // Tension Update In Original Graph //
  if (lcGraph.solved()) {
   lcCurrentArc=agGraph.arcs().begin();

   while (lcCurrentArc!=lcLastArc) {
    (*lcCurrentArc).second->data().tension()=lcGraph.arc((*lcCurrentArc).first).data().tension();
    ++lcCurrentArc;
   }

   if (agDisplayed) {
    environment::out("Aggregation Time = ",false,true);
    environment::out(lcAggregationTime,true);
    environment::out("Conforming Time = ",false,true);
    environment::out(lcConformingTime,true);
    environment::out("Disintegration Time = ",false,true);
    environment::out(lcDisintegrationTime,true);
   }
  }

  // Memory Deallocation //
  delete_array(lcArcS);

  if (agComponentS==nil) {
   lcCounter1=lcTreeS.size();

   while (lcCounter1>0) {
    --lcCounter1;
    delete_object(lcTreeS[lcCounter1]);
   }
  }

  agGraph.solved()=lcGraph.solved();
  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 by decomposing the graph into
    serial-parallel components, using the method given as argument, or directly if serial-parallel
    components are given (default is not). The number of components obtained can be displayed
    (default is not). */
 template <tdGraph> tyInteger clSolveAlgoII<tuGraph>::run(clGraph<tuGraph> & agGraph,
                         const clDecomposeAlgo<tuGraph> & agDecomposeAlgo,
                         std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) * agComponentS,
                         tyBoolean agDisplayed) const {
  typedef clNode<tuGraph>                                 cpNode;
  typedef graphProblemMinCostTensionStructure::clNodeData clNodeData;
  typedef clBinaryTree<clSerialParallelData<tuGraph> >    cpTree;
  typedef private_area::clTreeInfo<tuGraph>               cpTreeInfo;
  typedef std_map(cpTree *,cpTreeInfo *)                  cpTreeInfoX;
  typedef std_deque(cpTree *)                             cpTreeS;
  typedef std_deque(cpTreeS *)                            cpTreeD;

  typedef typename std_map(cpTree *,cpTreeInfo *)::const_iterator cpInfoIterator;
  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator      cpNodeIterator;

  tyInteger  lcClock;
  tyCardinal lcCounter1;
  tyCardinal lcCounter2;
  tyReal     lcFlow;
  tyReal     lcOptimum;
  tyInteger  lcReturn;
  tyReal     lcTension;

  cpTreeS              lcBreakerS;
  cpTreeD              lcBrokenD;
  cpTreeS *            lcBrokenS;
  cpTreeS              lcComponentS;
  cpInfoIterator       lcCurrentInfo;
  clPiecewiseGraph     lcGraph;
  cpInfoIterator       lcLastInfo;
  cpTreeD              lcPieceD;
  cpTreeS *            lcPieceS;
  cpNode *             lcSourceNode;
  cpNode *             lcTargetNode;
  cpTree *             lcTree1;
  cpTree *             lcTree2;
  cpTreeInfo *         lcTreeInfo;
  cpTreeInfoX          lcTreeInfoX;
  std_vector(cpTree *) lcTreeS;

  typedef graphProblemMinCostTensionConformingPiecewise_private::
          clConformity<clPiecewiseArcData,clNodeData> clConformity;

  typedef graphProblemMinCostTensionConforming_private::
          clDirectMintyColor<clPiecewiseArcData,clNodeData,clConformity > clDirectMintyColor;

  typedef graphProblemMinCostTensionConforming_private::
          clInverseMintyColor<clPiecewiseArcData,clNodeData,clConformity > clInverseMintyColor;

  clConformity        lcConformity;
  clDirectMintyColor  lcDirectMintyColor(lcConformity);
  clInverseMintyColor lcInverseMintyColor(lcConformity);

  tyInteger         lcAggregationTime    = 0;
  clPiecewiseArc ** lcArcS               = new_array(clPiecewiseArc *,agGraph.arcs().size());
  tyInteger         lcConformingTime     = 0;
  cpNodeIterator    lcCurrentNode        = agGraph.nodes().begin();
  tyCardinal        lcCurrentPiece       = 0;
  tyInteger         lcDisintegrationTime = 0;
  tyInteger         lcIteration          = 0;
  cpNodeIterator    lcLastNode           = agGraph.nodes().end();
  tyCardinal        lcNbArc              = 0;

  // Serial-Parallel Decomposition //
  lcClock=environment::currentClock();

  if (agComponentS==nil) agDecomposeAlgo.run(agGraph,lcTreeS);
  else {
   lcCounter1=agComponentS->size();

   while (lcCounter1>0) {
    --lcCounter1;
    lcTreeS.push_back((*agComponentS)[lcCounter1]);
   }
  }

  postDecompose(lcTreeS,lcBreakerS,lcPieceD,lcBrokenD);
  lcClock=environment::currentClock()-lcClock;

  if (agDisplayed) {
   environment::out("Components = ",false,true);
   environment::out(tyCardinal(lcTreeS.size()),true);
   environment::out("Decomposition Time = ",false,true);
   environment::out(lcClock,true);
  }

  // Nodes Copy //
  while (lcCurrentNode!=lcLastNode) {
   new_object(clPiecewiseNode(lcGraph,(*lcCurrentNode).first,clNodeData()));
   ++lcCurrentNode;
  }

  // Components Gathering //
  lcCounter1=lcTreeS.size();

  while (lcCounter1>0) {
   --lcCounter1;
   lcTree1=lcTreeS[lcCounter1];

   if (lcBreakerS.size()>0 and lcBreakerS.front()==lcTree1) {
    // Conforming //
    if (lcNbArc>0) {
     lcClock=environment::currentClock();

     lcReturn=private_area::makeConform(lcArcS,lcNbArc,lcConformity,
                                        lcDirectMintyColor,lcInverseMintyColor);

     if (lcReturn==-1) {
      lcGraph.solved()=false;
      lcIteration=-1;
      goto lbEnd;
     }

     lcIteration+=lcReturn;
     lcConformingTime+=environment::currentClock()-lcClock;
    }

    // Arcs Disintegration //
    lcBreakerS.pop_front();
    lcClock=environment::currentClock();
    lcBrokenS=lcBrokenD.front();
    lcBrokenD.pop_front();

    while (lcBrokenS->size()>0) {
     lcTree2=lcBrokenS->front();
     lcBrokenS->pop_front();
     lcTreeInfo=lcTreeInfoX[lcTree2];
     private_area::updateTension(*lcTreeInfo);
     private_area::findFlow(*lcTree2,lcTreeInfo->arc->data().flow());
     delete_object(lcTreeInfo->arc);
     lcTreeInfo->aggregated=false;
    }

    delete_object(lcBrokenS);
    lcDisintegrationTime+=environment::currentClock()-lcClock;

    // Replacement Arcs Creation //
    lcClock=environment::currentClock();
    lcPieceS=lcPieceD[lcCurrentPiece++];
    lcCounter2=lcPieceS->size();

    while (lcCounter2>0) {
     --lcCounter2;
     lcTree2=(*lcPieceS)[lcCounter2];
     lcTreeInfo=new_object(cpTreeInfo());
     lcTreeInfoX.insert(std_make_pair(lcTree2,lcTreeInfo));
     lcTreeInfo->aggregated=true;
     lcSourceNode=getTreeSourceNode(*lcTree2);
     lcTargetNode=getTreeTargetNode(*lcTree2);

     if (private_area::findMinCostTension(*lcTree2,lcTreeInfo->shrinkCosts,
                                          lcTreeInfo->stretchCosts,lcOptimum,
                                          &lcTension,&lcFlow)==-1) {
      lcTreeInfoX.erase(lcTree2);
      delete_object(lcTreeInfo);
      lcGraph.solved()=false;
      lcIteration=-1;
      goto lbEnd;
     }

     lcTreeInfo->arc=private_area::createPiecewiseArc(lcGraph,*lcTreeInfo,*lcSourceNode,
                                                      *lcTargetNode,lcOptimum,false);

     lcTreeInfo->tension=lcTension;
     lcTreeInfo->arc->data().expected()=lcTension;
     lcTreeInfo->arc->data().flow()=lcFlow;
     lcTreeInfo->arc->data().update();
     private_area::updateCosts(*lcTreeInfo);
    }

    lcAggregationTime+=environment::currentClock()-lcClock;
   }

   // Aggregated Arc Creation //
   lcClock=environment::currentClock();
   lcTreeInfo=new_object(cpTreeInfo());
   lcTreeInfoX.insert(std_make_pair(lcTree1,lcTreeInfo));
   lcTreeInfo->aggregated=true;
   lcSourceNode=getTreeSourceNode(*lcTree1);
   lcTargetNode=getTreeTargetNode(*lcTree1);

   if (private_area::findMinCostTension(*lcTree1,lcTreeInfo->shrinkCosts,
                                        lcTreeInfo->stretchCosts,lcOptimum)==-1) {
    lcTreeInfoX.erase(lcTree1);
    delete_object(lcTreeInfo);
    lcGraph.solved()=false;
    lcIteration=-1;
    goto lbEnd;
   }

   lcTreeInfo->arc=private_area::createPiecewiseArc(lcGraph,*lcTreeInfo,*lcSourceNode,
                                                    *lcTargetNode,lcOptimum,true);

   lcTreeInfo->tension=lcOptimum;
   lcAggregationTime+=environment::currentClock()-lcClock;

   // Non-Conform Arcs Listing //
   lcArcS[lcNbArc]=lcTreeInfo->arc;
   ++lcNbArc;
  }

  // Conforming //
  if (lcNbArc>0) {
   lcClock=environment::currentClock();

   lcReturn=private_area::makeConform(lcArcS,lcNbArc,lcConformity,
                                      lcDirectMintyColor,lcInverseMintyColor);

   if (lcReturn==-1) {
    lcGraph.solved()=false;
    lcIteration=-1;
    goto lbEnd;
   }

   lcIteration+=lcReturn;
   lcConformingTime+=environment::currentClock()-lcClock;
  }

  lcGraph.solved()=true;
  lbEnd:

  // Remaining Aggregated Arcs Disintegration //
  lcCurrentInfo=lcTreeInfoX.begin();
  lcLastInfo=lcTreeInfoX.end();

  while (lcCurrentInfo!=lcLastInfo) {
   lcTreeInfo=(*lcCurrentInfo).second;

   if (lcTreeInfo->aggregated) {
    if (lcGraph.solved()) {
     lcTree2=(*lcCurrentInfo).first;
     lcClock=environment::currentClock();
     private_area::updateTension(*lcTreeInfo);
     lcDisintegrationTime+=environment::currentClock()-lcClock;
    }

    delete_object(lcTreeInfo->arc);
   }

   private_area::clean(lcTreeInfo->shrinkCosts);
   private_area::clean(lcTreeInfo->stretchCosts);
   delete_object(lcTreeInfo);
   ++lcCurrentInfo;
  }

  if (lcGraph.solved()) {
   if (agDisplayed) {
    environment::out("Aggregation Time = ",false,true);
    environment::out(lcAggregationTime,true);
    environment::out("Conforming Time = ",false,true);
    environment::out(lcConformingTime,true);
    environment::out("Disintegration Time = ",false,true);
    environment::out(lcDisintegrationTime,true);
   }
  }

  // Memory Deallocation //
  delete_array(lcArcS);

  if (agComponentS==nil) {
   lcCounter1=lcTreeS.size();

   while (lcCounter1>0) {
    --lcCounter1;
    delete_object(lcTreeS[lcCounter1]);
   }
  }

  lcCounter1=lcPieceD.size();

  while (lcCounter1>0) {
   --lcCounter1;
   lcPieceS=lcPieceD[lcCounter1];
   lcCounter2=lcPieceS->size();

   while (lcCounter2>0) {
    --lcCounter2;
    delete_object((*lcPieceS)[lcCounter2]);
   }

   delete_object(lcPieceS);
  }

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

// S o l v e S e r i a l P a r a l l e l A l g o  Implementation //---------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clSolveSerialParallelAlgo */ /* Solves the minimum cost tension problem of a graph. */
 template <tdGraph>
 tyInteger clSolveSerialParallelAlgo<tuGraph>::run(clGraph<tuGraph> & agGraph) const {
  method_name("solveSerialParallelAlgo::run");

  typedef std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) cpTreeS;
  typedef std_deque(private_area::clVariation<tuGraph>)              cpVariationS;

  tyInteger    lcIteration;
  tyReal       lcOptimum;
  cpVariationS lcShrinkS;
  cpVariationS lcStretchS;
  cpTreeS      lcTreeS;

  agGraph.solved()=false;
  graphProblemSerialParallel::clDecomposeAlgo<tuGraph>::defaultRun(agGraph,lcTreeS);
  if (lcTreeS.size()!=1) send_error(erNotSerialParallel);

  lcIteration=private_area::findMinCostTension(*(lcTreeS[0]),lcShrinkS,lcStretchS,lcOptimum);
  delete_object(lcTreeS[0]);
  private_area::clean(lcShrinkS);
  private_area::clean(lcStretchS);
  if (lcIteration!=-1) agGraph.solved()=true;
  return (lcIteration);
 }
}

// V a r i a t i o n  Implementation //-------------------------------------------------------------
namespace private_area {
 //------------------------------------------------------------------------------------------AddArcs
 template <tdGraph> void clVariation<tuGraph>::addArcs(const clVariation<tuGraph> & agVariation) {
  typedef typename cpArcS::const_iterator cpIterator;

  cpIterator lcCurrentArc = agVariation.atArcS->begin();
  cpIterator lcLastArc    = agVariation.atArcS->end();

  if (atArcS==nil) atArcS=new_object(cpArcS());

  while (lcCurrentArc!=lcLastArc) {
   atArcS->push_back(*lcCurrentArc);
   lcCurrentArc++;
  }
 }
 //-----------------------------------------------------------------------------------------CopyArcs
 template <tdGraph> void clVariation<tuGraph>::copyArcs(const clVariation<tuGraph> & agVariation) {
  typedef typename cpArcS::const_iterator cpIterator;

  cpIterator lcCurrentArc = agVariation.atArcS->begin();
  cpIterator lcLastArc    = agVariation.atArcS->end();

  atArcS=new_object(cpArcS());

  while (lcCurrentArc!=lcLastArc) {
   atArcS->push_back(*lcCurrentArc);
   lcCurrentArc++;
  }
 }
 //----------------------------------------------------------------------------------DecreaseTension
 template <tdGraph>
 void clVariation<tuGraph>::decreaseTension(tyReal agDecrease,tyBoolean agTensionAdjusted) {
  method_name("variation::decreaseTension");

  typedef typename cpArcS::const_iterator cpIterator;

  cpIterator lcCurrentArc;
  cpIterator lcLastArc;

  if (atArcS==nil) send_error(erEmptyArcList);

  atAvailable-=agDecrease;
  if (atAvailable<0.0) send_error(erNotEnoughAvailableTension);

  if (agTensionAdjusted) {
   lcCurrentArc=atArcS->begin();
   lcLastArc=atArcS->end();

   while (lcCurrentArc!=lcLastArc) {
    (*lcCurrentArc)->data().tension()-=agDecrease;
    lcCurrentArc++;
   }
  }
 }
 //----------------------------------------------------------------------------------IncreaseTension
 template <tdGraph>
 void clVariation<tuGraph>::increaseTension(tyReal agIncrease,tyBoolean agTensionAdjusted) {
  method_name("variation::increaseTension");

  typedef typename std_vector(clArc<tuGraph> *)::const_iterator cpIterator;

  cpIterator lcCurrentArc;
  cpIterator lcLastArc;

  if (atArcS==nil) send_error(erEmptyArcList);

  atAvailable-=agIncrease;
  if (atAvailable<0.0) send_error(erNotEnoughAvailableTension);

  if (agTensionAdjusted) {
   lcCurrentArc=atArcS->begin();
   lcLastArc=atArcS->end();

   while (lcCurrentArc!=lcLastArc) {
    (*lcCurrentArc)->data().tension()+=agIncrease;
    lcCurrentArc++;
   }
  }
 }
}

// 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
// A g g r e g a t i o n
//                                                                                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/aggregation.cpp"

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

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

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemMinCostTensionAggregation
#define private_area graphProblemMinCostTensionAggregation_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Graph_problem/Min_cost_tension/Aggregation");

// Initialization //--------------------------------------------------------------------------------
#undef iniGraphProblemMinCostTensionAggregation
static_constant(private_area::clInitializer,goInitializer);

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 static_error erEmptyArcList;
 static_error erNotEnoughAvailableTension;
 static_error erNotEnoughAvailableFlow;
}

// Constants & Variables //-------------------------------------------------------------------------
dynamic_constant(clString,goDataLocation);

// Static Members //--------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

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

// X X X  Implementation //-------------------------------------------------------------------------
namespace {}

// I n i t i a l i z e r  Implementation //---------------------------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------------Start
 property void clInitializer::start(void) {
  if (atCounter++ == 0) {
   try {
    #include <bpp/modules.hpp> /*NEED*/
    registerStop(this);
    environment::informInitialization(goModuleName);

    erEmptyArcList.create("Min Cost Tension - The arc list is empty.");
    erNotEnoughAvailableFlow.create("Min Cost Tension - Can't increase / decrease more a flow.");
    erNotEnoughAvailableTension.create("Min Cost Tension - Can't increase / decrease more a tension.");

    goDataLocation = new_object(clString(environment::dataLocation()+fileNameSeparator()
                     +"graph_problem"+fileNameSeparator()+"min_cost_tension"
                     +fileNameSeparator()+"serial_parallel"));
   }

   initializer_catch;
  }
 }
 //---------------------------------------------------------------------------------------------Stop
 property void clInitializer::stop(void) {
  try {
   environment::informTermination(goModuleName);

   delete_object(goDataLocation);
  }

  initializer_catch;
 }
}

// End //-------------------------------------------------------------------------------------------
}