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

/*DESCRIPTION*/
/* This module provides algorithms to solve tension problems in graphs. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "graph_problem/tension/algorithm.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guGraphProblemTensionAlgorithm
#define guGraphProblemTensionAlgorithm

// Headers //---------------------------------------------------------------------------------------
#include <bpp/graph.hpp> /*INCLUDE*/
#include <bpp/graph_problem/shortest_path.hpp> /*INCLUDE*/

namespace bpp {

// Importation/Exportation //-----------------------------------------------------------------------
#ifdef GRAPH_PROBLEM_TENSION_DLL
 #define dll_export DLL_EXPORT
#else
 #define dll_export DLL_IMPORT
#endif

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemTensionAlgorithm
#define private_area graphProblemTensionAlgorithm_private

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

namespace private_area {
 using namespace public_area;
 using namespace graphProblemShortestPath;
}

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniGraphProblemTensionAlgorithm
has_initializer;

// Macrocommands //---------------------------------------------------------------------------------
#define tdGraph class prArcData,class prNodeData
#define tuGraph prArcData,prNodeData

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------------------Classes
 template <tdGraph> class clCompatibleTensionAlgo;
 template <tdGraph> class clCompatibleTensionAlgoI;
 template <tdGraph> class clCompatibleTensionAlgoII;
 template <tdGraph> class clCompatibleTensionAlgoIII;
 template <tdGraph> class clCompatibleTensionAlgoIV;
}

namespace private_area {
 template <tdGraph> class clConditionForCompatibility;
 template <tdGraph> class clConditionForMaximum;
 template <tdGraph> class clMintyColorForCompatibility;
 template <tdGraph> class clMintyColorForIncrease;

 structure {
  tyCardinal cycle;
  tyInteger  direction;
 }
 tyArcInfo;
}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area {
 template <tdGraph> tyBoolean checkCompatibility(const clGraph<tuGraph> &);
 template <tdGraph> tyBoolean computePotential(clGraph<tuGraph> &);
 template <tdGraph> void      increaseTension(clGraph<tuGraph> &,ctCocycle &,tyReal);
 template <tdGraph> void      increaseTension(const std_map(clArc<tuGraph> *,tyInteger) &,tyReal);
 template <tdGraph> tyInteger makeTensionCompatible(clArc<tuGraph> &,tyReal,tyReal);
 template <tdGraph> tyInteger maximizeTension(clArc<tuGraph> &);
}

namespace private_area {
 template <tdGraph>
 void buildResidualGraph(clLengthGraph &,clGraph<tuGraph> &,std_vector(clLengthArc *) &);

 template <tdGraph,class prCondition>
 tyInteger increaseTension(clArc<tuGraph> &,const prCondition &);

 testing_mode ( function void test(void); )
}

// Errors //----------------------------------------------------------------------------------------
namespace public_area {}

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

// C o m p a t i b l e T e n s i o n A l g o  Interface //------------------------------------------
namespace public_area {
 /*CLASS clCompatibleTensionAlgo */
 /* Represents an algorithm to find a compatible tension in a graph. It is an abstract class. */
 template <tdGraph> class clCompatibleTensionAlgo {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clCompatibleTensionAlgo(const clCompatibleTensionAlgo &);
  private_property clCompatibleTensionAlgo & operator = (const clCompatibleTensionAlgo &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clCompatibleTensionAlgo(void);
  public_property virtual destructor clCompatibleTensionAlgo(void);

  /*AMETHOD clCompatibleTensionAlgo */
  /* Finds a compatible tension in a graph. Abstract method. */
  public_property virtual tyInteger run(clGraph<tuGraph> & agGraph) const = 0;

  /*AMETHOD clCompatibleTensionAlgo */
  /* Finds a compatible tension in a graph. The second argument is set to <CODE>true</CODE>
     if the algorithm has to consider the current tension of the graph, which is supposed to
     help it. Abstract method. */
  public_property virtual tyInteger run(clGraph<tuGraph> & agGraph,
                                        tyBoolean agKeepTension) const = 0;

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

// C o m p a t i b l e T e n s i o n A l g o I  Interface //----------------------------------------
namespace public_area {
 /*CLASS clCompatibleTensionAlgoI */
 /* Represents an algorithm to find a compatible tension in a graph
    (method I: increasing cocycle). */
 template <tdGraph>
 class clCompatibleTensionAlgoI : public clCompatibleTensionAlgo<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clCompatibleTensionAlgoI(const clCompatibleTensionAlgoI &);
  private_property clCompatibleTensionAlgoI & operator = (const clCompatibleTensionAlgoI &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clCompatibleTensionAlgoI(void);
  public_property destructor clCompatibleTensionAlgoI(void);

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

// C o m p a t i b l e T e n s i o n A l g o I I  Interface //--------------------------------------
namespace public_area {
 /*CLASS clCompatibleTensionAlgoII */
 /* Represents an algorithm to find a compatible tension in a graph
    (method II: increasing cocycle). */
 template <tdGraph> class clCompatibleTensionAlgoII : public clCompatibleTensionAlgo<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clCompatibleTensionAlgoII(const clCompatibleTensionAlgoII &);
  private_property clCompatibleTensionAlgoII & operator = (const clCompatibleTensionAlgoII &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clCompatibleTensionAlgoII(void);
  public_property destructor clCompatibleTensionAlgoII(void);

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

// C o m p a t i b l e T e n s i o n A l g o I I I Interface //-------------------------------------
namespace public_area {
 /*CLASS clCompatibleTensionAlgoIII */
 /* Represents an algorithm to find a compatible tension in a graph
    (method III: use of a shortest path algorithm). */
 template <tdGraph> class clCompatibleTensionAlgoIII : public clCompatibleTensionAlgo<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clCompatibleTensionAlgoIII(const clCompatibleTensionAlgoIII &);
  private_property clCompatibleTensionAlgoIII & operator = (const clCompatibleTensionAlgoIII &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clCompatibleTensionAlgoIII(void);
  public_property destructor clCompatibleTensionAlgoIII(void);

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

// C o m p a t i b l e T e n s i o n A l g o I V Interface //---------------------------------------
namespace public_area {
 /*CLASS clCompatibleTensionAlgoIV */
 /* Represents an algorithm to find a compatible tension in a graph
    (method IV: use of a shortest path algorithm). */
 template <tdGraph> class clCompatibleTensionAlgoIV : public clCompatibleTensionAlgo<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clCompatibleTensionAlgoIV(const clCompatibleTensionAlgoIV &);
  private_property clCompatibleTensionAlgoIV & operator = (const clCompatibleTensionAlgoIV &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clCompatibleTensionAlgoIV(void);
  public_property destructor clCompatibleTensionAlgoIV(void);

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

// C o n d i t i o n F o r M a x i m u m  Interface //----------------------------------------------
namespace private_area {
 template <tdGraph> class clConditionForMaximum {
  //-----------------------------------------------------------------------------------------Private
  private_property const clArc<tuGraph> & atArc;

  private_property constructor clConditionForMaximum(const clConditionForMaximum &);
  private_property clConditionForMaximum & operator = (const clConditionForMaximum &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clConditionForMaximum(const clArc<tuGraph> &);
  public_property destructor clConditionForMaximum(void) {}

  public_property tyBoolean evaluate(void) const;
 };
}

// C o n d i t i o n F o r C o m p a t i b i l i t y  Interface //----------------------------------
namespace private_area {
 template <tdGraph> class clConditionForCompatibility {
  //-----------------------------------------------------------------------------------------Private
  private_property const clArc<tuGraph> & atArc;
  private_property tyReal                 atMinimum;
  private_property tyReal                 atMaximum;

  private_property constructor clConditionForCompatibility(const clConditionForCompatibility &);
  private_property clConditionForCompatibility & operator = (const clConditionForCompatibility &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clConditionForCompatibility(const clArc<tuGraph> &,tyReal,tyReal);
  public_property destructor clConditionForCompatibility(void) {}

  public_property tyBoolean evaluate(void) const;
 };
}

// M i n t y C o l o r F o r C o m p a t i b i l i t y  Interface //--------------------------------
namespace private_area {
 template <tdGraph> class clMintyColorForCompatibility {
  //-------------------------------------------------------------------------------------------Types
  public_property typedef clArc<tuGraph> cpArc;
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clMintyColorForCompatibility(const clMintyColorForCompatibility &);

  private_property
  clMintyColorForCompatibility & operator = (const clMintyColorForCompatibility &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clMintyColorForCompatibility(void) {}
  public_property destructor clMintyColorForCompatibility(void) {}

  public_property tyBoolean red(const cpArc &) const;
  public_property tyBoolean black(const cpArc &) const;
  public_property tyBoolean blue(const cpArc &) const;
  public_property tyBoolean green(const cpArc &) const;

  public_property tcString color(const cpArc &) const;
 };
}

// M i n t y C o l o r F o r I n c r e a s e  Interface //------------------------------------------
namespace private_area {
 template <tdGraph> class clMintyColorForIncrease {
  //-------------------------------------------------------------------------------------------Types
  public_property typedef clArc<tuGraph> cpArc;
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clMintyColorForIncrease(const clMintyColorForIncrease &);
  private_property clMintyColorForIncrease & operator = (const clMintyColorForIncrease &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clMintyColorForIncrease(void) {}
  public_property destructor clMintyColorForIncrease(void) {}

  public_property tyBoolean red(const cpArc &) const;
  public_property tyBoolean black(const cpArc &) const;
  public_property tyBoolean blue(const cpArc &) const;
  public_property tyBoolean green(const cpArc &) const;

  public_property tcString color(const cpArc &) const;
 };
}

// Functions Inline //------------------------------------------------------------------------------
namespace public_area {
 //----------------------------------------------------------------------------MakeTensionCompatible
 /*FUNCTION*/ /* Makes the tension of an arc compatible. */
 template <tdGraph> inline
 tyInteger makeTensionCompatible(clArc<tuGraph> & agArc,tyReal agMinimum,tyReal agMaximum) {
  return (private_area::increaseTension
  (agArc,private_area::clConditionForCompatibility<tuGraph>(agArc,agMinimum,agMaximum)));
 }
 //----------------------------------------------------------------------------------MaximizeTension
 /*FUNCTION*/ /* Maximizes the tension of an arc. */
 template <tdGraph> inline tyInteger maximizeTension(clArc<tuGraph> & agArc) {
  return (private_area::increaseTension(agArc,
                                        private_area::clConditionForMaximum<tuGraph>(agArc)));
 }
}

namespace private_area {}

// C o m p a t i b l e T e n s i o n A l g o  Inline //---------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clCompatibleTensionAlgo */
 /* Builds an algorithm to find a compatible tension in a graph. */
 template <tdGraph> inline clCompatibleTensionAlgo<tuGraph>::clCompatibleTensionAlgo(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clCompatibleTensionAlgo */ /* Destructs the algorithm. */
 template <tdGraph> inline clCompatibleTensionAlgo<tuGraph>::~clCompatibleTensionAlgo(void) {}
}

// C o m p a t i b l e T e n s i o n A l g o I  Inline //-------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clCompatibleTensionAlgoI */
 /* Builds an algorithm to find a compatible tension in a graph. */
 template <tdGraph> inline clCompatibleTensionAlgoI<tuGraph>::clCompatibleTensionAlgoI(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clCompatibleTensionAlgoI */ /* Destructs the algorithm. */
 template <tdGraph> inline clCompatibleTensionAlgoI<tuGraph>::~clCompatibleTensionAlgoI(void) {}
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clCompatibleTensionAlgoI */ /* Finds a compatible tension in a graph. */
 template <tdGraph>
 inline tyInteger clCompatibleTensionAlgoI<tuGraph>::run(clGraph<tuGraph> & agGraph) const
 { return (run(agGraph,false)); }
}

// C o m p a t i b l e T e n s i o n A l g o I I  Inline //-----------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clCompatibleTensionAlgoII */
 /* Builds an algorithm to find a compatible tension in a graph. */
 template <tdGraph> inline clCompatibleTensionAlgoII<tuGraph>::clCompatibleTensionAlgoII(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clCompatibleTensionAlgoII */ /* Destructs the algorithm. */
 template <tdGraph> inline clCompatibleTensionAlgoII<tuGraph>::~clCompatibleTensionAlgoII(void) {}
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clCompatibleTensionAlgoII */ /* Finds a compatible tension in a graph. */
 template <tdGraph>
 inline tyInteger clCompatibleTensionAlgoII<tuGraph>::run(clGraph<tuGraph> & agGraph) const
 { return (run(agGraph,false)); }
}

// C o m p a t i b l e T e n s i o n A l g o I I I  Inline //---------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clCompatibleTensionAlgoIII */
 /* Builds an algorithm to find a compatible tension in a graph. */
 template <tdGraph> inline clCompatibleTensionAlgoIII<tuGraph>::clCompatibleTensionAlgoIII(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clCompatibleTensionAlgoIII */ /* Destructs the algorithm. */
 template <tdGraph>
 inline clCompatibleTensionAlgoIII<tuGraph>::~clCompatibleTensionAlgoIII(void) {}
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clCompatibleTensionAlgoIII */
 /* Finds a compatible tension in a graph. The second argument is not used. */
 template <tdGraph> inline
 tyInteger clCompatibleTensionAlgoIII<tuGraph>::run(clGraph<tuGraph> & agGraph,tyBoolean) const
 { return (run(agGraph)); }
}

// C o m p a t i b l e T e n s i o n A l g o I V  Inline //-----------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clCompatibleTensionAlgoIV */
 /* Builds an algorithm to find a compatible tension in a graph. */
 template <tdGraph> inline clCompatibleTensionAlgoIV<tuGraph>::clCompatibleTensionAlgoIV(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clCompatibleTensionAlgoIV */ /* Destructs the algorithm. */
 template <tdGraph>
 inline clCompatibleTensionAlgoIV<tuGraph>::~clCompatibleTensionAlgoIV(void) {}
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clCompatibleTensionAlgoIV */
 /* Finds a compatible tension in a graph. The second argument is not used. */
 template <tdGraph> inline
 tyInteger clCompatibleTensionAlgoIV<tuGraph>::run(clGraph<tuGraph> & agGraph,tyBoolean) const
 { return (run(agGraph)); }
}

// C o n d i t i o n F o r C o m p a t i b i l i t y  Inline //-------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------Constructor
 template <tdGraph> inline clConditionForCompatibility<tuGraph>::
 clConditionForCompatibility(const clArc<tuGraph> & agArc,tyReal agMinimum,tyReal agMaximum)
 : atArc(agArc),atMinimum(agMinimum),atMaximum(agMaximum) {}
 //-----------------------------------------------------------------------------------------Evaluate
 template <tdGraph>
 inline tyBoolean clConditionForCompatibility<tuGraph>::evaluate(void) const
 { return (atArc.data().tension()>=atMinimum and atArc.data().tension()<=atMaximum); }
}

// C o n d i t i o n F o r M a x i m u m  Inline //-------------------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------Constructor
 template <tdGraph> inline
 clConditionForMaximum<tuGraph>::clConditionForMaximum(const clArc<tuGraph> & agArc)
 : atArc(agArc) {}
 //-----------------------------------------------------------------------------------------Evaluate
 template <tdGraph>
 inline tyBoolean clConditionForMaximum<tuGraph>::evaluate(void) const
 { return (atArc.data().tension()==atArc.data().maximum()); }
}

// M i n t y C o l o r F o r C o m p a t i b i l i t y  Inline //-----------------------------------
namespace private_area {
 //----------------------------------------------------------------------------------------------Red
 template <tdGraph>
 inline tyBoolean clMintyColorForCompatibility<tuGraph>::red(const cpArc & agArc) const {
  return (agArc.data().tension()>agArc.data().minimum()
          and agArc.data().tension()<agArc.data().maximum());
 }
 //--------------------------------------------------------------------------------------------Black
 template <tdGraph>
 inline tyBoolean clMintyColorForCompatibility<tuGraph>::black(const cpArc & agArc) const {
  return (agArc.data().tension()<=agArc.data().minimum()
          and agArc.data().tension()<agArc.data().maximum());
 }
 //---------------------------------------------------------------------------------------------Blue
 template <tdGraph>
 inline tyBoolean clMintyColorForCompatibility<tuGraph>::blue(const cpArc & agArc) const {
  return (agArc.data().tension()>=agArc.data().maximum()
          and agArc.data().tension()>agArc.data().minimum());
 }
 //--------------------------------------------------------------------------------------------Green
 template <tdGraph>
 inline tyBoolean clMintyColorForCompatibility<tuGraph>::green(const cpArc & agArc) const {
  return (agArc.data().tension()==agArc.data().minimum()
          and agArc.data().tension()==agArc.data().maximum());
 }
}

// M i n t y C o l o r F o r I n c r e a s e  Inline //---------------------------------------------
namespace private_area {
 //----------------------------------------------------------------------------------------------Red
 template <tdGraph>
 inline tyBoolean clMintyColorForIncrease<tuGraph>::red(const cpArc & agArc) const {
  return (agArc.data().minimum()<agArc.data().tension()
          and agArc.data().tension()<agArc.data().maximum());
 }
 //--------------------------------------------------------------------------------------------Black
 template <tdGraph>
 inline tyBoolean clMintyColorForIncrease<tuGraph>::black(const cpArc & agArc) const {
  return (agArc.data().minimum()==agArc.data().tension()
          and agArc.data().tension()<agArc.data().maximum());
 }
 //---------------------------------------------------------------------------------------------Blue
 template <tdGraph>
 inline tyBoolean clMintyColorForIncrease<tuGraph>::blue(const cpArc & agArc) const {
  return (agArc.data().minimum()<agArc.data().tension()
          and agArc.data().tension()==agArc.data().maximum());
 }
 //--------------------------------------------------------------------------------------------Green
 template <tdGraph>
 inline tyBoolean clMintyColorForIncrease<tuGraph>::green(const cpArc & agArc) const {
  return (agArc.data().minimum()==agArc.data().tension()
          and agArc.data().tension()==agArc.data().maximum());
 }
}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //-------------------------------------------------------------------------------CheckCompatibility
 /*FUNCTION*/
 /* Verifies that the tension in a graph is compatible (<CODE>true</CODE> = compatible). */
 template <tdGraph> tyBoolean checkCompatibility(const clGraph<tuGraph> & agGraph) {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpIterator;

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

  clArc<tuGraph> * lcArc;

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

   if (lcArc->data().tension()<lcArc->data().minimum()
       or lcArc->data().tension()>lcArc->data().maximum()) return (false);

   lcCurrentArc++;
  }

  return (true);
 }
 //---------------------------------------------------------------------------------ComputePotential
 /*FUNCTION*/
 /* Computes the potential of each node according to the tension of the arcs. Returns
    <CODE>false</CODE> if the tension is not feasible. */
 template <tdGraph> tyBoolean computePotential(clGraph<tuGraph> & agGraph) {
  typedef typename clNode<tuGraph>::cpArcX::const_iterator   cpArcIterator;
  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator cpNodeIterator;
  typedef std_vector(clNode<tuGraph> *)                      clNodeS;

  tyMark lcMark = ++(agGraph.mark());

  clArc<tuGraph> *  lcArc;
  cpArcIterator     lcCurrentArc;
  cpNodeIterator    lcCurrentNode;
  cpArcIterator     lcLastArc;
  cpNodeIterator    lcLastNode;
  clNode<tuGraph> * lcNode;
  clNodeS           lcNodeS;
  clNode<tuGraph> * lcSourceNode;
  clNode<tuGraph> * lcTargetNode;
  tyReal            lcTension;

  lcCurrentNode=agGraph.nodes().begin();
  lcLastNode=agGraph.nodes().end();

  while (lcCurrentNode!=lcLastNode) {
   lcNode=(*lcCurrentNode).second;

   if (lcNode->mark()!=lcMark) {
    lcNode->data().potential()=0.0;
    lcNode->mark()=lcMark;
    lcNodeS.push_back(lcNode);
   }

   while (not lcNodeS.empty()) {
    lcNode=lcNodeS.back();
    lcNodeS.pop_back();
    lcCurrentArc=lcNode->outgoingArcs().begin();
    lcLastArc=lcNode->outgoingArcs().end();

    while (lcCurrentArc!=lcLastArc) {
     lcArc=(*lcCurrentArc).second;
     lcTargetNode=lcArc->targetNode();

     if (lcTargetNode->mark()==lcMark) {
      lcTension=lcTargetNode->data().potential()-lcNode->data().potential();
      if (lcTension!=lcArc->data().tension()) return (false);
     }
     else {
      lcTargetNode->data().potential()=lcNode->data().potential()+lcArc->data().tension();
      lcTargetNode->mark()=lcMark;
      lcNodeS.push_back(lcTargetNode);
     }

     lcCurrentArc++;
    }

    lcCurrentArc=lcNode->incomingArcs().begin();
    lcLastArc=lcNode->incomingArcs().end();

    while (lcCurrentArc!=lcLastArc) {
     lcArc=(*lcCurrentArc).second;
     lcSourceNode=lcArc->sourceNode();

     if (lcSourceNode->mark()==lcMark) {
      lcTension=lcNode->data().potential()-lcSourceNode->data().potential();
      if (lcTension!=lcArc->data().tension()) return (false);
     }
     else {
      lcSourceNode->data().potential()=lcNode->data().potential()-lcArc->data().tension();
      lcSourceNode->mark()=lcMark;
      lcNodeS.push_back(lcSourceNode);
     }

     lcCurrentArc++;
    }
   }

   lcCurrentNode++;
  }

  return (true);
 }
 //----------------------------------------------------------------------------------IncreaseTension
 /*FUNCTION*/ /* Increases the tension in a cocycle of a given value. */
 template <tdGraph>
 void increaseTension(clGraph<tuGraph> & agGraph,ctCocycle & agCocycle,tyReal agValue) {
  clCocycle::const_iterator lcCurrentArc = agCocycle.begin();
  clCocycle::const_iterator lcLastArc    = agCocycle.end();

  while (lcCurrentArc!=lcLastArc) {
   if ((*lcCurrentArc).second==+1) agGraph.arc((*lcCurrentArc).first).data().tension()+=agValue;
   else agGraph.arc((*lcCurrentArc).first).data().tension()-=agValue;

   lcCurrentArc++;
  }
 }
 //----------------------------------------------------------------------------------IncreaseTension
 /*FUNCTION*/ /* Increases the tension in a cocycle of a given value. */
 template <tdGraph>
 void increaseTension(const std_map(clArc<tuGraph> *,tyInteger) & agCocycle,tyReal agValue) {
  typedef typename std_map(clArc<tuGraph> *,tyInteger)::const_iterator cpIterator;

  cpIterator lcCurrentArc = agCocycle.begin();
  cpIterator lcLastArc    = agCocycle.end();

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

   lcCurrentArc++;
  }
 }
}

namespace private_area {
 //-------------------------------------------------------------------------------BuildResidualGraph
 template <tdGraph>
 void buildResidualGraph(clLengthGraph & agResidualGraph,clGraph<tuGraph> & agGraph,
                         std_vector(clLengthArc *) & agArcS) {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator  cpArcIterator;
  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator cpNodeIterator;

  clArc<tuGraph> * lcArc1;
  clLengthArc *    lcArc2;

  cpArcIterator  lcCurrentArc  = agGraph.arcs().begin();
  cpNodeIterator lcCurrentNode = agGraph.nodes().begin();
  cpArcIterator  lcLastArc     = agGraph.arcs().end();
  cpNodeIterator lcLastNode    = agGraph.nodes().end();

  // Nodes Duplication //
  while (lcCurrentNode!=lcLastNode) {
   new_object(clLengthNode(agResidualGraph,(*lcCurrentNode).first,dataStructure::clNoData()));
   ++lcCurrentNode;
  }

  // Arcs Duplication //
  agArcS.reserve(agGraph.arcs().size());
  lcCurrentArc=agGraph.arcs().begin();

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

   lcArc2=new_object(clLengthArc(agResidualGraph,agResidualGraph.getNewArcKey(),
                     dataStructure::clLengthData(),lcArc1->sourceNode()->key(),
                     lcArc1->targetNode()->key()));

   lcArc2->data().length()=lcArc1->data().maximum();
   agArcS.push_back(lcArc2);

   lcArc2=new_object(clLengthArc(agResidualGraph,agResidualGraph.getNewArcKey(),
                     dataStructure::clLengthData(),lcArc1->targetNode()->key(),
                     lcArc1->sourceNode()->key()));

   lcArc2->data().length()=-(lcArc1->data().minimum());
   ++lcCurrentArc;
  }
 }
 //----------------------------------------------------------------------------------IncreaseTension
 template <tdGraph,class prCondition>
 tyInteger increaseTension(clArc<tuGraph> & agArc,const prCondition & agCondition) {
  typedef std_map(clArc<tuGraph> *,tyInteger) cpCocycle;
  typedef std_map(clArc<tuGraph> *,tyInteger) cpCycle;
  typedef typename cpCycle::iterator          cpIterator;

  clMintyColorForIncrease<tuGraph> lcMintyColor;

  tyInteger lcNbIteration = 0;

  clArc<tuGraph> * lcArc;
  cpCocycle        lcCocycle;
  cpIterator       lcCurrentArc;
  cpCycle          lcCycle;
  cpIterator       lcLastArc;
  tyReal           lcIncrement;

  while (not agCondition.evaluate() and
         not findMintyCycle(agArc,lcMintyColor,lcCycle,lcCocycle)) {
   lcNbIteration++;
   lcCurrentArc=lcCocycle.begin();
   lcLastArc=lcCocycle.end();
   lcIncrement=realMax();

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

    if ((*lcCurrentArc).second==+1)
     lcIncrement=mini(lcArc->data().maximum()-lcArc->data().tension(),lcIncrement);
    else lcIncrement=mini(lcArc->data().tension()-lcArc->data().minimum(),lcIncrement);

    lcCurrentArc++;
   }

   public_area::increaseTension(lcCocycle,lcIncrement);
  }

  return (lcNbIteration);
 }
}

// C o m p a t i b l e T e n s i o n A l g o  Implementation //-------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------DefaultRun
 /*METHOD clCompatibleTensionAlgo */
 /* Finds a compatible tension in a graph using the default version of the algorithm (method III).
    Static method. */
 template <tdGraph>
 inline tyInteger clCompatibleTensionAlgo<tuGraph>::defaultRun(clGraph<tuGraph> & agGraph)
 { return (clCompatibleTensionAlgoIII<tuGraph>().run(agGraph)); }
 //---------------------------------------------------------------------------------------DefaultRun
 /*METHOD clCompatibleTensionAlgo */
 /* Finds a compatible tension in a graph using the default version of the algorithm (method III).
    The second argument is set to <CODE>true</CODE> if the algorithm has to consider the current
    tension of the graph, which is supposed to help it. Static method. */
 template <tdGraph>
 inline tyInteger clCompatibleTensionAlgo<tuGraph>::defaultRun(clGraph<tuGraph> & agGraph,
                                                               tyBoolean agKeepTension)
 { return (clCompatibleTensionAlgoIII<tuGraph>().run(agGraph,agKeepTension)); }
}

// C o m p a t i b l e T e n s i o n A l g o I  Implementation //-----------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clCompatibleTensionAlgoI */
 /* Finds a compatible tension in a graph. The second argument is set to <CODE>true</CODE>
    if the algorithm has to consider the current tension of the graph, which is supposed to
    help it. */
 template <tdGraph>
 tyInteger clCompatibleTensionAlgoI<tuGraph>::run(clGraph<tuGraph> & agGraph,
                                                  tyBoolean agKeepTension) const {
  typedef std_map(clArc<tuGraph> *,tyInteger)               cpCocycle;
  typedef std_map(clArc<tuGraph> *,tyInteger)               cpCycle;
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpIterator1;
  typedef typename cpCocycle::const_iterator                cpIterator2;

  cpIterator1 lcCurrentArc  = agGraph.arcs().begin();
  cpIterator1 lcLastArc     = agGraph.arcs().end();
  tyCardinal  lcNbIteration = 0;

  clArc<tuGraph> * lcArc;
  clArc<tuGraph> * lcArc2;
  cpCocycle        lcCocycle;
  cpIterator2      lcCurrentArc2;
  cpCycle          lcCycle;
  tyReal           lcIncrement;
  cpIterator2      lcLastArc2;

  private_area::clMintyColorForCompatibility<tuGraph> lcMintyColor;

  agGraph.solved()=false;

  if (not agKeepTension) {
   while (lcCurrentArc!=lcLastArc) {
    (*lcCurrentArc).second->data().tension()=0;
    lcCurrentArc++;
   }

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

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

   if (lcArc->data().tension()<lcArc->data().minimum()) {
    while (lcArc->data().tension()<lcArc->data().minimum()
           and (not findMintyCycle(*lcArc,lcMintyColor,lcCycle,lcCocycle))) {
     lcNbIteration++;
     lcCurrentArc2=lcCocycle.begin();
     lcLastArc2=lcCocycle.end();
     lcIncrement=realMax();

     while (lcCurrentArc2!=lcLastArc2) {
      lcArc2=(*lcCurrentArc2).first;

      if ((*lcCurrentArc2).second==+1)
       lcIncrement=mini(lcArc2->data().maximum()-lcArc2->data().tension(),lcIncrement);
      else lcIncrement=mini(lcArc2->data().tension()-lcArc2->data().minimum(),lcIncrement);

      lcCurrentArc2++;
     }

     increaseTension(lcCocycle,lcIncrement);
    }

    if (lcArc->data().tension()<lcArc->data().minimum()) return (-1);
   }

   lcCurrentArc++;
  }

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

// C o m p a t i b l e T e n s i o n A l g o I I  Implementation //---------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clCompatibleTensionAlgoII */
 /* Finds a compatible tension in a graph. The second argument is set to <CODE>true</CODE>
    if the algorithm has to consider the current tension of the graph, which is supposed to
    help it. */
 template <tdGraph>
 tyInteger clCompatibleTensionAlgoII<tuGraph>::run(clGraph<tuGraph> & agGraph,
                                                   tyBoolean agKeepTension) const {
  typedef std_map(clArc<tuGraph> *,tyInteger)               cpCocycle;
  typedef std_map(clArc<tuGraph> *,tyInteger)               cpCycle;
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpIterator1;
  typedef typename cpCocycle::const_iterator                cpIterator2;

  cpIterator1 lcCurrentArc  = agGraph.arcs().begin();
  cpIterator1 lcLastArc     = agGraph.arcs().end();
  tyCardinal  lcNbIteration = 0;

  tyBoolean        lcAgain;
  clArc<tuGraph> * lcArc;
  clArc<tuGraph> * lcArc2;
  cpCocycle        lcCocycle;
  cpIterator2      lcCurrentArc2;
  cpCycle          lcCycle;
  tyReal           lcIncrement;
  cpIterator2      lcLastArc2;

  private_area::clMintyColorForCompatibility<tuGraph> lcMintyColor;

  agGraph.solved()=false;

  if (not agKeepTension) {
   while (lcCurrentArc!=lcLastArc) {
    (*lcCurrentArc).second->data().tension()=0;
    lcCurrentArc++;
   }
  }

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

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

    if (lcArc->data().tension()<lcArc->data().minimum()) {
     lcAgain=true;

     if (not findMintyCycle(*lcArc,lcMintyColor,lcCycle,lcCocycle)) {
      lcNbIteration++;
      lcCurrentArc2=lcCocycle.begin();
      lcLastArc2=lcCocycle.end();
      lcIncrement=realMax();

      while (lcCurrentArc2!=lcLastArc2) {
       lcArc2=(*lcCurrentArc2).first;

       if ((*lcCurrentArc2).second==+1)
        lcIncrement=mini(lcArc2->data().maximum()-lcArc2->data().tension(),lcIncrement);
       else lcIncrement=mini(lcArc2->data().tension()-lcArc2->data().minimum(),lcIncrement);

       lcCurrentArc2++;
      }

      increaseTension(lcCocycle,lcIncrement);
     }
     else return (0);
    }

    lcCurrentArc++;
   }
  }
  while (lcAgain);

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

// C o m p a t i b l e T e n s i o n A l g o I I I  Implementation //-------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clCompatibleTensionAlgoIII */ /* Finds a compatible tension in a graph. */
 template <tdGraph>
 tyInteger clCompatibleTensionAlgoIII<tuGraph>::run(clGraph<tuGraph> & agGraph) const {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpArcIterator1;
  typedef std_vector(private_area::clLengthArc *)           clArcS;
  typedef clArcS::const_iterator                            clArcIterator2;

  typedef graphProblemShortestPath::clFordAlgo<dataStructure::clLengthData,dataStructure::clNoData>
  clShortestPathAlgo;

  typedef clShortestPathAlgo::cpWorkspace clWorkspace;

  clArc<tuGraph> *            lcArc1;
  private_area::clLengthArc * lcArc2;
  clArcS                      lcAssociation;
  clArcIterator2              lcCurrentArc2;
  clArcS                      lcPath;
  private_area::clLengthGraph lcResidualGraph;

  cpArcIterator1 lcCurrentArc1 = agGraph.arcs().begin();
  cpArcIterator1 lcLastArc1    = agGraph.arcs().end();

  // Compatible Tension Search //
  agGraph.solved()=false;
  private_area::buildResidualGraph(lcResidualGraph,agGraph,lcAssociation);

  try { clShortestPathAlgo(true).run(lcResidualGraph,(*(lcResidualGraph.nodes().begin())).first,
                                     (*(lcResidualGraph.nodes().begin())).first,lcPath); }

  // Inconsistent Constraints //
  catch (ctError &) {
   deleteNodeWorkspace(lcResidualGraph,clWorkspace());
   clearError();
   return (-1);
  }

  // Tension Computation //
  lcCurrentArc2=lcAssociation.begin();

  while (lcCurrentArc1!=lcLastArc1) {
   lcArc1=(*lcCurrentArc1).second;
   lcArc2=*lcCurrentArc2;

   if (lcArc2->sourceNode()!=nil and lcArc2->targetNode()!=nil)
    lcArc1->data().tension()=static_cast<clWorkspace *>(lcArc2->targetNode()->work())->potential()
                             -static_cast<clWorkspace *>(lcArc2->sourceNode()->work())->potential();
   else lcArc1->data().tension()=0.0;

   ++lcCurrentArc1;
   ++lcCurrentArc2;
  }

  deleteNodeWorkspace(lcResidualGraph,clWorkspace());
  agGraph.solved()=true;
  return (0);
 }
}

// C o m p a t i b l e T e n s i o n A l g o I V  Implementation //---------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clCompatibleTensionAlgoIV */ /* Finds a compatible tension in a graph. */
 template <tdGraph>
 tyInteger clCompatibleTensionAlgoIV<tuGraph>::run(clGraph<tuGraph> & agGraph) const {
  typedef std_vector(private_area::clLengthArc *)            clArcS;
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator  cpArcIterator1;
  typedef clArcS::const_iterator                             clArcIterator2;
  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator clNodeIterator;

  typedef graphProblemShortestPath::clFordAlgo<dataStructure::clLengthData,dataStructure::clNoData>
  clShortestPathAlgo;

  clArc<tuGraph> *            lcArc1;
  private_area::clLengthArc * lcArc2;
  private_area::clLengthArc * lcArc3;
  private_area::clLengthArc * lcArc4;
  private_area::clLengthArc * lcArc5;
  clArcS                      lcArcS;
  clArcIterator2              lcCurrentArc2;
  clArcIterator2              lcCurrentArc3;
  private_area::clLengthGraph lcGraph;
  clArcIterator2              lcLastArc2;
  clArcIterator2              lcLastArc3;
  clArcS                      lcPath;
  clShortestPathAlgo          lcShortestPathAlgo(false);
  tyReal                      lcTension;

  cpArcIterator1 lcCurrentArc1 = agGraph.arcs().begin();
  clNodeIterator lcCurrentNode = agGraph.nodes().begin();
  cpArcIterator1 lcLastArc1    = agGraph.arcs().end();
  clNodeIterator lcLastNode    = agGraph.nodes().end();

  agGraph.solved()=false;

  // Shortest Path Problem Conversion //
  while (lcCurrentNode!=lcLastNode) {
   new_object(private_area::clLengthNode(lcGraph,(*lcCurrentNode).first,clNoData()));
   ++lcCurrentNode;
  }

  while (lcCurrentArc1!=lcLastArc1) {
   lcArc1=(*lcCurrentArc1).second;

   lcArc2=new_object(private_area::clLengthArc(lcGraph,lcArc1->key(),
                     clLengthData(lcArc1->data().maximum()),lcArc1->sourceNode()->key(),
                     lcArc1->targetNode()->key()));

   lcArcS.push_back(lcArc2);
   ++lcCurrentArc1;
  }

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

  while (lcCurrentArc1!=lcLastArc1) {
   lcArc1=(*lcCurrentArc1).second;

   lcArc2=new_object(private_area::clLengthArc(lcGraph,lcGraph.getNewArcKey(),
                     clLengthData(-(lcArc1->data().minimum())),lcArc1->targetNode()->key(),
                     lcArc1->sourceNode()->key()));

   lcArc3=&(lcGraph.arc(lcArc1->key()));
   lcArc3->work()=lcArc2;
   lcArc2->work()=lcArc3;
   ++lcCurrentArc1;
  }

  // Compatible Tension Search //
  lcCurrentArc2=lcArcS.begin();
  lcLastArc2=lcArcS.end();

  while (lcCurrentArc2!=lcLastArc2) {
   lcArc2=*lcCurrentArc2;
   lcArc3=(private_area::clLengthArc *)(lcArc2->work());

   if (lcArc2->data().length()!=-(lcArc3->data().length())) {
    try { lcShortestPathAlgo.run(lcGraph,lcArc2->sourceNode()->key(),
          lcArc2->targetNode()->key(),lcPath); }

    catch (ctError &) { clearError(); return (-1); }
    lcTension=0.0;
    lcCurrentArc3=lcPath.begin();
    lcLastArc3=lcPath.end();

    while (lcCurrentArc3!=lcLastArc3) {
     lcArc4=*lcCurrentArc3;
     lcArc5=(private_area::clLengthArc *)(lcArc4->work());
     lcArc5->data().length()=-lcArc4->data().length();
     lcTension+=lcArc4->data().length();
     ++lcCurrentArc3;
    }

    lcArc2->data().length()=lcTension;
    lcArc3->data().length()=-lcTension;
   }

   ++lcCurrentArc2;
  }

  // Compatible Tension Building //
  lcCurrentArc1=agGraph.arcs().begin();
  lcCurrentArc2=lcArcS.begin();

  while (lcCurrentArc1!=lcLastArc1) {
   (*lcCurrentArc1).second->data().tension()=(*lcCurrentArc2)->data().length();
   ++lcCurrentArc1;
   ++lcCurrentArc2;
  }

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

// M i n t y C o l o r F o r C o m p a t i b i l i t y  Implementation //---------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------------Color
 template <tdGraph>
 tcString clMintyColorForCompatibility<tuGraph>::color(const cpArc & agArc) const {
  if (red(agArc)) return ("red");
  if (black(agArc)) return ("black");
  if (blue(agArc)) return ("blue");
  return ("green");
 }
}

// M i n t y C o l o r F o r I n c r e a s e  Implementation //-------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------------Color
 template <tdGraph> tcString clMintyColorForIncrease<tuGraph>::color(const cpArc & agArc) const {
  if (red(agArc)) return ("red");
  if (black(agArc)) return ("black");
  if (blue(agArc)) return ("blue");
  return ("green");
 }
}

// 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
// T e n s i o n
// A l g o r i t h m
//                                                                                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/tension/algorithm.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define GRAPH_PROBLEM_TENSION_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/graph_problem/tension/algorithm.hpp> /*INTERFACE*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemTensionAlgorithm
#define private_area graphProblemTensionAlgorithm_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Graph_problem/Tension/Algorithm");

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

// Errors //----------------------------------------------------------------------------------------
namespace public_area {}

// 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);

    goDataLocation = new_object(clString(environment::dataLocation()+fileNameSeparator()
                     +"graph_problem"+fileNameSeparator()+"tension"
                     +fileNameSeparator()+"algorithm"));
   }

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

   delete_object(goDataLocation);
  }

  initializer_catch;
 }
}

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