//==================================================================================================
// 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
// R a n d o m _ g e n e r 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 provides facilities to generate random minimum cost tension problems in graphs. */

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

// Guardian //--------------------------------------------------------------------------------------
#ifndef guGraphProblemMinCostTensionRandomGeneration
#define guGraphProblemMinCostTensionRandomGeneration

// Headers //---------------------------------------------------------------------------------------
#include <set> /*INCLUDE*/
#include <bpp/graph_problem/min_cost_tension/structure.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  graphProblemMinCostTensionRandomGeneration
#define private_area graphProblemMinCostTensionRandomGeneration_private

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

namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------

// Macrocommands //---------------------------------------------------------------------------------
/*ALIAS*/
#define tdGraph class prArcData,class prNodeData //

/*ALIAS*/
#define tuGraph prArcData,prNodeData //

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {}

namespace private_area {
 template <tdGraph> class clRandomLinearCost;
 template <tdGraph> class clRandomConvexCost;
 template <tdGraph> class clRandomPiecewiseCost;
 template <tdGraph> class clMintyColorForCycleDetection;
}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area {
 template <tdGraph> void generateConvexGraph1(clGraph<tuGraph> &,tyCardinal,tyCardinal,
                                              tyInteger,tyCardinal,tyInteger);

 template <tdGraph> void generateConvexGraph2(clGraph<tuGraph> &,tyCardinal,tyCardinal,
                                              tyInteger,tyCardinal);

 template <tdGraph> void generateDiscreteGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,tyInteger,
                                               tyCardinal,tyInteger);

 template <tdGraph> void generateLinearGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,tyInteger,
                                             tyCardinal,tyInteger);

 template <tdGraph> void generatePiecewiseGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,tyInteger,
                                                tyCardinal,tyInteger,tyCardinal);

 template <tdGraph> void
 generateConvexSerialParallelGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,tyCardinal,
                                 tyInteger,tyCardinal,tyInteger,
                                 std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) * =nil);

 template <tdGraph> void
 generateDiscreteSerialParallelGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,tyCardinal,
                                     tyInteger,tyCardinal,tyInteger);

 template <tdGraph> void
 generateLinearSerialParallelGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,tyCardinal,
                                 tyInteger,tyCardinal,tyInteger,
                                 std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) * =nil);

 template <tdGraph> void
 generatePiecewiseSerialParallelGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,tyCardinal,
                                 tyInteger,tyCardinal,tyInteger,tyCardinal,
                                 std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) * =nil);
}

namespace private_area {
 template <tdGraph,class prRandomCost> void
 generateGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,tyInteger,tyCardinal,const prRandomCost &,
               tyBoolean=true);

 template <tdGraph,class prRandomCost> void
 generateSerialParallelGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,tyCardinal,tyInteger,
                             tyCardinal,const prRandomCost &,
                             std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) *,
                             tyBoolean=true);

 template <tdGraph>
 void generateDiscreteGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,
                            tyInteger,tyCardinal,tyInteger,tyBoolean,tyCardinal);
}

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

// Constants & Variables //-------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// R a n d o m L i n e a r C o s t  Interface //----------------------------------------------------
namespace private_area {
 template <tdGraph> class clRandomLinearCost {
  //-----------------------------------------------------------------------------------------Private
  private_property clRandomLinearCost(const clRandomLinearCost &);
  private_property clRandomLinearCost & operator = (const clRandomLinearCost &);

  private_property tyInteger atScale;
  //------------------------------------------------------------------------------------------Public
  public_property constructor clRandomLinearCost(tyInteger agScale) : atScale(agScale+1) {}
  public_property destructor clRandomLinearCost(void) {}

  public_property void run(clArc<tuGraph> & agArc) const {
   agArc.data().shrinkingCost()=(atScale==1 ? 1 : randomCardinal(atScale));
   agArc.data().stretchingCost()=(atScale==1 ? 1 : randomCardinal(atScale));
  }
 };
}

// R a n d o m C o n v e x C o s t  Interface //----------------------------------------------------
namespace private_area {
 template <tdGraph> class clRandomConvexCost {
  //-----------------------------------------------------------------------------------------Private
  private_property clRandomConvexCost(const clRandomConvexCost &);
  private_property clRandomConvexCost & operator = (const clRandomConvexCost &);

  private_property tyInteger atScale;
  //------------------------------------------------------------------------------------------Public
  public_property constructor clRandomConvexCost(tyInteger agScale) : atScale(agScale+1) {}
  public_property destructor clRandomConvexCost(void) {}

  public_property void run(clArc<tuGraph> & agArc) const
  { agArc.data().costAcceleration()=(atScale==1 ? 1 : randomCardinal(atScale)); }
 };
}

// R a n d o m P i e c e w i s e C o s t  Interface //----------------------------------------------
namespace private_area {
 template <tdGraph> class clRandomPiecewiseCost {
  //-----------------------------------------------------------------------------------------Private
  private_property clRandomPiecewiseCost(const clRandomPiecewiseCost &);
  private_property clRandomPiecewiseCost & operator = (const clRandomPiecewiseCost &);

  private_property tyInteger  atScale;
  private_property tyCardinal atNbPiece;
  //------------------------------------------------------------------------------------------Public
  public_property constructor clRandomPiecewiseCost(tyInteger agScale,tyCardinal agNbPiece)
  : atScale(agScale/agNbPiece+1),atNbPiece(agNbPiece) {}

  public_property destructor clRandomPiecewiseCost(void) {}

  public_property void run(clArc<tuGraph> &) const;
 };
}

// M i n t y C o l o r F o r C y c l e D e t e c t i o n  Interface //------------------------------
namespace private_area {
 template <tdGraph> class clMintyColorForCycleDetection {
  //-------------------------------------------------------------------------------------------Types
  public_property typedef clArc<tuGraph> cpArc;
  //-----------------------------------------------------------------------------------------Private
  private_property
  constructor clMintyColorForCycleDetection(const clMintyColorForCycleDetection &);

  private_property
  clMintyColorForCycleDetection & operator = (const clMintyColorForCycleDetection &);
  //------------------------------------------------------------------------------------------Public
  read_only_attribute(tyCardinal,atCardinalityMax,cardinality);

  public_property constructor clMintyColorForCycleDetection(tyCardinal);
  public_property destructor clMintyColorForCycleDetection(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 {
 //-----------------------------------------------------------------------------GenerateConvexGraph1
 /*FUNCTION*/
 /* Generates randomly a minimum cost tension problem with given potential scale and flexibility
    and a given cost acceleration scale, in a graph with given numbers of arcs and nodes. The cost
    functions of the arcs are as defined by the <CODE>clConvexArcData1</CODE> class of the
    <CODE>Structure</CODE> module. */
 template <tdGraph> inline
 void generateConvexGraph1(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,tyCardinal agNbArc,
                           tyInteger agPotentialScale,tyCardinal agFlexibility,
                           tyInteger agAccelerationScale) {
  private_area::clRandomConvexCost<tuGraph> lcCost(agAccelerationScale);

  private_area::generateGraph(agGraph,agNbNode,agNbArc,agPotentialScale,agFlexibility,lcCost);
 }
 //----------------------------------------------------------------------------GenerateDiscreteGraph
 /*FUNCTION*/
 /* Generates randomly a minimum cost tension problem with a given potential scale, a given
    cardinality for the feasible tension sets and a given unit cost scale, in a graph with given
    numbers of arcs and nodes. The cost functions of the arcs are as defined by the
    <CODE>clDiscreteArcData</CODE> class of the <CODE>Structure</CODE> module. */
 template <tdGraph> inline
 void generateDiscreteGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,tyCardinal agNbArc,
                            tyInteger agPotentialScale,tyCardinal agTensionCardinality,
                            tyInteger agUnitCostScale) {
  private_area::generateDiscreteGraph(agGraph,agNbNode,agNbArc,agPotentialScale,
                                      agTensionCardinality,agUnitCostScale,false,0);
 }
 //------------------------------------------------------------------------------GenerateLinearGraph
 /*FUNCTION*/
 /* Generates randomly a minimum cost tension problem with given potential scale and flexibility
    and a given unit cost scale, in a graph with given numbers of arcs and nodes. The cost
    functions of the arcs are as defined by the <CODE>clLinearArcData</CODE> class of the
    <CODE>Structure</CODE> module. */
 template <tdGraph> inline
 void generateLinearGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,tyCardinal agNbArc,
                          tyInteger agPotentialScale,tyCardinal agFlexibility,
                          tyInteger agUnitCostScale) {
  private_area::clRandomLinearCost<tuGraph> lcCost(agUnitCostScale);

  private_area::generateGraph(agGraph,agNbNode,agNbArc,agPotentialScale,agFlexibility,lcCost);
 }
 //---------------------------------------------------------------------------GeneratePiecewiseGraph
 /*FUNCTION*/
 /* Generates randomly a minimum cost tension problem with given potential scale and flexibility
    and a given unit cost scale, in a graph with given numbers of arcs and nodes. The cost
    functions of the arcs are piecewise linear as defined by the <CODE>clPiecewiseArcData</CODE>
    class of the <CODE>Structure</CODE> module. */
 template <tdGraph> inline
 void generatePiecewiseGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,tyCardinal agNbArc,
                             tyInteger agPotentialScale,tyCardinal agFlexibility,
                             tyInteger agUnitCostScale,tyCardinal agNbPiece) {
  private_area::clRandomPiecewiseCost<tuGraph> lcCost(agUnitCostScale,agNbPiece);

  private_area::generateGraph(agGraph,agNbNode,agNbArc,agPotentialScale,agFlexibility,lcCost);
 }
 //----------------------------------------------------------------GenerateConvexSerialParallelGraph
 /*FUNCTION*/
 /* Generates randomly a minimum cost tension problem (with a serial-parallel graph that can be
    disrupted) with given potential scale and flexibility and a given cost acceleration scale,
    in a graph with given numbers of arcs (number for the organized serial-parallel graph and
    number for the disruption) and nodes. The cost functions of the arcs are as defined by the
    <CODE>clConvexArcData1</CODE> class of the <CODE>Structure</CODE> module. If not null, the
    last parameter is a pointer to a vector of SP-components representing the generated graph,
    that is filled during the generation process. The last parameter is null by default. */
 template <tdGraph> inline void
 generateConvexSerialParallelGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,
                            tyCardinal agNbOrganizingArc,tyCardinal agNbDisruptingArc,
                            tyInteger agPotentialScale,tyCardinal agFlexibility,
                            tyInteger agAcceleration,
                            std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) * agTreeS) {
  private_area::clRandomConvexCost<tuGraph> lcCost(agAcceleration);

  private_area::generateSerialParallelGraph(agGraph,agNbNode,agNbOrganizingArc,
                                            agNbDisruptingArc,agPotentialScale,agFlexibility,
                                            lcCost,agTreeS);
 }
 //--------------------------------------------------------------GenerateDiscreteSerialParallelGraph
 /*FUNCTION*/
 /* Generates randomly a minimum cost tension problem (with a serial-parallel graph that can be
    disrupted) with a given potential scale, a given cardinality for the feasible tension sets and
    a given unit cost scale, in a graph with given numbers of arcs (number for the organized
    serial-parallel graph and number for the disruption) and nodes. The cost functions of the
    arcs are as defined by the <CODE>clDiscreteArcData</CODE> class of the <CODE>Structure</CODE>
    module. */
 template <tdGraph> inline void
 generateDiscreteSerialParallelGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,
                                     tyCardinal agNbOrganizingArc,tyCardinal agNbDisruptingArc,
                                     tyInteger agPotentialScale,tyCardinal agTensionCardinality,
                                     tyInteger agUnitCostScale) {
  private_area::generateDiscreteGraph(agGraph,agNbNode,agNbOrganizingArc,agPotentialScale,
                                      agTensionCardinality,agUnitCostScale,true,
                                      agNbDisruptingArc);
 }
 //----------------------------------------------------------------GenerateLinearSerialParallelGraph
 /*FUNCTION*/
 /* Generates randomly a minimum cost tension problem (with a serial-parallel graph that can be
    disrupted) with given potential scale and flexibility and a given unit cost scale, in a graph
    with given numbers of arcs (number for the organized serial-parallel graph and number for
    the disruption) and nodes. The cost functions of the arcs are as defined by the
    <CODE>clLinearArcData</CODE> class of the <CODE>Structure</CODE> module. If not null, the
    last parameter is a pointer to a vector of SP-components representing the generated graph,
    that is filled during the generation process. The last parameter is null by default. */
 template <tdGraph> inline void
 generateLinearSerialParallelGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,
                            tyCardinal agNbOrganizingArc,tyCardinal agNbDisruptingArc,
                            tyInteger agPotentialScale,tyCardinal agFlexibility,
                            tyInteger agUnitCostScale,
                            std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) * agTreeS) {
  private_area::clRandomLinearCost<tuGraph> lcCost(agUnitCostScale);

  private_area::generateSerialParallelGraph(agGraph,agNbNode,agNbOrganizingArc,
                                            agNbDisruptingArc,agPotentialScale,agFlexibility,
                                            lcCost,agTreeS);
 }
 //-------------------------------------------------------------GeneratePiecewiseSerialParallelGraph
 /*FUNCTION*/
 /* Generates randomly a minimum cost tension problem (with a serial-parallel graph that can be
    disrupted) with given potential scale and flexibility and a given unit cost scale, in a graph
    with given numbers of arcs (number for the organized serial-parallel graph and number for
    the disruption) and nodes. The cost functions of the arcs are piecewise linear as defined by
    the <CODE>clLinearArcData</CODE> class of the <CODE>Structure</CODE> module. If not null, the
    last parameter is a pointer to a vector of SP-components representing the generated graph,
    that is filled during the generation process. The last parameter is null by default. */
 template <tdGraph> inline void
 generatePiecewiseSerialParallelGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,
                            tyCardinal agNbOrganizingArc,
                            tyCardinal agNbDisruptingArc,tyInteger agPotentialScale,
                            tyCardinal agFlexibility,tyInteger agUnitCostScale,
                            tyCardinal agNbPiece,
                            std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) * agTreeS) {
  private_area::clRandomPiecewiseCost<tuGraph> lcCost(agUnitCostScale,agNbPiece);

  private_area::generateSerialParallelGraph(agGraph,agNbNode,agNbOrganizingArc,
                                            agNbDisruptingArc,agPotentialScale,agFlexibility,
                                            lcCost,agTreeS);
 }
}

namespace private_area {}

// M i n t y C o l o r F o r C y c l e D e t e c t i o n  Inline //---------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------Constructor
 template <tdGraph> inline
 clMintyColorForCycleDetection<tuGraph>::clMintyColorForCycleDetection(tyCardinal agCardinalityMax)
 : atCardinalityMax(agCardinalityMax) {}
 //----------------------------------------------------------------------------------------------Red
 template <tdGraph>
 inline tyBoolean clMintyColorForCycleDetection<tuGraph>::red(const cpArc & agArc) const
 { return (agArc.data().feasibles().size()<atCardinalityMax); }
 //--------------------------------------------------------------------------------------------Black
 template <tdGraph>
 inline tyBoolean clMintyColorForCycleDetection<tuGraph>::black(const cpArc &) const
 { return (false); }
 //---------------------------------------------------------------------------------------------Blue
 template <tdGraph>
 inline tyBoolean clMintyColorForCycleDetection<tuGraph>::blue(const cpArc &) const
 { return (false); }
 //--------------------------------------------------------------------------------------------Green
 template <tdGraph>
 inline tyBoolean clMintyColorForCycleDetection<tuGraph>::green(const cpArc & agArc) const
 { return (agArc.data().feasibles().size()>=atCardinalityMax); }
}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //-----------------------------------------------------------------------------GenerateConvexGraph2
 /*FUNCTION*/
 /* Generates randomly a minimum cost tension problem with given potential scale and flexibility,
    in a graph with given numbers of arcs and nodes. The cost functions of the arcs are as defined
    by the <CODE>clConvexArcData2</CODE> class of the <CODE>Structure</CODE> module. */
 template <tdGraph> void
 generateConvexGraph2(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,tyCardinal agNbArc,
                      tyInteger agPotentialScale,tyCardinal agFlexibility) {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator  cpArcIterator;
  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator cpNodeIterator;

  clArc<tuGraph> *  lcArc;
  cpArcIterator     lcCurrentArc;
  cpNodeIterator    lcCurrentNode;
  cpArcIterator     lcLastArc;
  cpNodeIterator    lcLastNode;
  clNode<tuGraph> * lcNode;
  clNode<tuGraph> * lcTempoNode;

  tyInteger lcTension;
  tyReal    lcOptimum;
  tyInteger lcMaximum;
  tyInteger lcMinimum;

  // Structure Generation //
  generateConnexGraph(agGraph,agNbNode,agNbArc,false);

  // Potential Generation //
  lcCurrentNode=agGraph.nodes().begin();
  lcLastNode=agGraph.nodes().end();

  while (lcCurrentNode!=lcLastNode) {
   lcNode=(*lcCurrentNode).second;
   lcNode->data().potential()=randomCardinal(agPotentialScale+1);
   lcCurrentNode++;
  }

  // Arc Tension Generation //
  lcCurrentArc=agGraph.arcs().begin();
  lcLastArc=agGraph.arcs().end();

  while (lcCurrentArc!=lcLastArc) {
   lcArc=(*lcCurrentArc).second;
   lcTension=tyInteger(lcArc->targetNode()->data().potential()
                       -lcArc->sourceNode()->data().potential());

   if (lcTension<0) {
    lcTempoNode=lcArc->sourceNode();
    lcArc->setSourceNode(lcArc->targetNode());
    lcArc->setTargetNode(lcTempoNode);
    lcTension*=-1;
   }

   lcMinimum=lcTension-randomCardinal(percentage(lcTension,agFlexibility)+1);
   lcMaximum=lcTension+randomCardinal(percentage(lcTension,agFlexibility)+1);
   lcOptimum=tyReal(lcMaximum+lcMinimum)/2.0;

   lcArc->data().optimum()=lcOptimum;
   lcArc->data().tolerance()=lcOptimum-lcMinimum;
   lcArc->data().expected()=0.0;
   lcCurrentArc++;
  }

  // Potential Cleaning //
  lcCurrentNode=agGraph.nodes().begin();
  lcLastNode=agGraph.nodes().end();

  while (lcCurrentNode!=lcLastNode) {
   lcNode=(*lcCurrentNode).second;
   lcNode->data().potential()=0.0;
   lcCurrentNode++;
  }
 }
}

namespace private_area {
 //------------------------------------------------------------------------------------GenerateGraph
 template <tdGraph,class prRandomCost>
 void generateGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,tyCardinal agNbArc,
                    tyInteger agPotentialScale,tyCardinal agFlexibility,
                    const prRandomCost & agRandomCost,tyBoolean agClean) {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator  cpArcIterator;
  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator cpNodeIterator;

  clArc<tuGraph> *  lcArc;
  cpArcIterator     lcCurrentArc;
  cpNodeIterator    lcCurrentNode;
  cpArcIterator     lcLastArc;
  cpNodeIterator    lcLastNode;
  clNode<tuGraph> * lcNode;
  clNode<tuGraph> * lcTempoNode;

  tyInteger lcTension;
  tyInteger lcOptimum;
  tyInteger lcMaximum;
  tyInteger lcMinimum;

  // Structure Generation //
  generateConnexGraph(agGraph,agNbNode,agNbArc,false);

  // Potential Generation //
  lcCurrentNode=agGraph.nodes().begin();
  lcLastNode=agGraph.nodes().end();

  while (lcCurrentNode!=lcLastNode) {
   lcNode=(*lcCurrentNode).second;
   lcNode->data().potential()=randomCardinal(agPotentialScale+1);
   lcCurrentNode++;
  }

  // Arc Tension Generation //
  lcCurrentArc=agGraph.arcs().begin();
  lcLastArc=agGraph.arcs().end();

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

   lcTension=tyInteger(lcArc->targetNode()->data().potential()
                       -lcArc->sourceNode()->data().potential());

   if (lcTension<0) {
    lcTempoNode=lcArc->sourceNode();
    lcArc->setSourceNode(lcArc->targetNode());
    lcArc->setTargetNode(lcTempoNode);
    lcTension*=-1;
   }

   lcMinimum=lcTension-randomCardinal(percentage(lcTension,agFlexibility)+1);
   lcMaximum=lcTension+randomCardinal(percentage(lcTension,agFlexibility)+1);
   lcOptimum=lcMinimum+randomCardinal(lcMaximum-lcMinimum+1);

   lcArc->data().minimum()=lcMinimum;
   lcArc->data().maximum()=lcMaximum;
   lcArc->data().optimum()=lcOptimum;
   lcArc->data().expected()=0.0;
   agRandomCost.run(*lcArc);

   lcCurrentArc++;
  }

  // Potential Cleaning //
  if (agClean) {
   lcCurrentNode=agGraph.nodes().begin();
   lcLastNode=agGraph.nodes().end();

   while (lcCurrentNode!=lcLastNode) {
    lcNode=(*lcCurrentNode).second;
    lcNode->data().potential()=0.0;
    lcCurrentNode++;
   }
  }
 }
 //----------------------------------------------------------------------GenerateSerialParallelGraph
 template <tdGraph,class prRandomCost> void
 generateSerialParallelGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,
                            tyCardinal agNbOrganizingArc,tyCardinal agNbDisruptingArc,
                            tyInteger agPotentialScale,tyCardinal agFlexibility,
                            const prRandomCost & agRandomCost,
                            std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) * agTreeS,
                            tyBoolean agClean) {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator  cpArcIterator;
  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator cpNodeIterator;
  typedef clSerialParallelData<tuGraph>                      cpSerialParallelData;
  typedef clBinaryTree<cpSerialParallelData >                cpTree;

  typedef typename clGraph<tuGraph>::cpArc  cpArc;
  typedef typename clGraph<tuGraph>::cpNode cpNode;

  typedef std_set(cpNode *)  cpNodeS;
  typedef std_set(tyInteger) clPotentialS;

  cpNodeS * lcNextNodeS  = new_object(cpNodeS);
  cpNodeS * lcNextNodeS2 = new_object(cpNodeS);

  cpArc *               lcArc;
  cpArcIterator         lcCurrentArc;
  cpNodeIterator        lcCurrentNode;
  cpArcIterator         lcLastArc;
  cpNodeIterator        lcLastNode;
  cpNode *              lcNode;
  std_vector(tyNodeKey) lcNodeS;
  tyNodeKey             lcNodeKey1;
  tyNodeKey             lcNodeKey2;
  clPotentialS          lcPotentialS;

  tyInteger lcTension;
  tyInteger lcOptimum;
  tyInteger lcPotential;
  tyInteger lcMaximum;
  tyInteger lcMinimum;

  clPotentialS::const_iterator lcCurrentPotential;

  // Structure Generation //
  graphRandomGeneration_private::generateSerialParallelGraph(agGraph,agNbNode,
                                                             agNbOrganizingArc,lcNodeS);

  if (agTreeS!=nil)
   graphProblemSerialParallel::clDecomposeAlgo<tuGraph>::defaultRun(agGraph,*agTreeS);

  // Potentials Generation //
  while (lcPotentialS.size()!=agNbNode) {
   lcPotential=randomCardinal(maxi(tyCardinal(agPotentialScale),agNbNode)+1);
   if (lcPotentialS.count(lcPotential)==0) lcPotentialS.insert(lcPotential);
  }

  lcCurrentPotential=lcPotentialS.begin();

  // Node Potential Cleaning //
  lcCurrentNode=agGraph.nodes().begin();
  lcLastNode=agGraph.nodes().end();

  while (lcCurrentNode!=lcLastNode) {
   lcNode=(*lcCurrentNode).second;
   lcNode->data().potential()=0.0;

   if (lcNode->incomingArcs().size()==0) {
    lcNextNodeS->insert(lcNode);
    lcNode->data().potential()=*lcCurrentPotential;
    lcCurrentPotential++;
   }

   lcCurrentNode++;
  }

  // Potential Affectation //
  {
   typedef typename cpNodeS::const_iterator cpNodeIterator;

   cpNodeIterator lcCurrentNode;
   cpNodeIterator lcLastNode;
   cpNodeS *      lcTempoSet;

   while (lcNextNodeS->size()>0) {
    lcCurrentNode=lcNextNodeS->begin();
    lcLastNode=lcNextNodeS->end();

    while (lcCurrentNode!=lcLastNode) {
     lcCurrentArc=(*lcCurrentNode)->outgoingArcs().begin();
     lcLastArc=(*lcCurrentNode)->outgoingArcs().end();

     while (lcCurrentArc!=lcLastArc) {
      lcNode=(*lcCurrentArc).second->targetNode();
      lcNode->data().potential()++;

      if (lcNode->data().potential()==lcNode->incomingArcs().size()) {
       lcNextNodeS2->insert(lcNode);
       lcNode->data().potential()=*lcCurrentPotential;
       lcCurrentPotential++;
      }

      lcCurrentArc++;
     }

     lcCurrentNode++;
    }

    lcNextNodeS->erase(lcNextNodeS->begin(),lcNextNodeS->end());
    lcTempoSet=lcNextNodeS;
    lcNextNodeS=lcNextNodeS2;
    lcNextNodeS2=lcTempoSet;
   }
  }

  // Arc Tension Generation //
  lcCurrentArc=agGraph.arcs().begin();
  lcLastArc=agGraph.arcs().end();

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

   lcTension=tyInteger(lcArc->targetNode()->data().potential()
                       -lcArc->sourceNode()->data().potential());

   lcMinimum=lcTension-randomCardinal(percentage(lcTension,agFlexibility)+1);
   lcMaximum=lcTension+randomCardinal(percentage(lcTension,agFlexibility)+1);
   lcOptimum=lcMinimum+randomCardinal(lcMaximum-lcMinimum+1);

   lcArc->data().minimum()=lcMinimum;
   lcArc->data().maximum()=lcMaximum;
   lcArc->data().optimum()=lcOptimum;
   lcArc->data().expected()=0.0;
   agRandomCost.run(*lcArc);

   lcCurrentArc++;
  }

  // Disrupting Arcs Generation //
  while (agNbDisruptingArc>0) {
   lcNodeKey1=lcNodeS[randomCardinal(agNbNode)];

   do {
    lcNodeKey2=lcNodeS[randomCardinal(agNbNode)];
   } while (lcNodeKey2==lcNodeKey1);

   if (agGraph.node(lcNodeKey1).data().potential()>agGraph.node(lcNodeKey2).data().potential())
    standard::swap(lcNodeKey1,lcNodeKey2);

   lcArc=new_object(cpArc(agGraph,agGraph.getNewArcKey(),prArcData(),lcNodeKey1,lcNodeKey2));

   lcTension=tyInteger(lcArc->targetNode()->data().potential()
                       -lcArc->sourceNode()->data().potential());

   lcMinimum=lcTension-randomCardinal(percentage(lcTension,agFlexibility)+1);
   lcMaximum=lcTension+randomCardinal(percentage(lcTension,agFlexibility)+1);
   lcOptimum=lcMinimum+randomCardinal(lcMaximum-lcMinimum+1);

   lcArc->data().minimum()=lcMinimum;
   lcArc->data().maximum()=lcMaximum;
   lcArc->data().optimum()=lcOptimum;
   lcArc->data().expected()=0.0;
   agRandomCost.run(*lcArc);

   if (agTreeS!=nil)
    agTreeS->push_back(new_object(cpTree(cpSerialParallelData(lcArc,cpSerialParallelData::none),
                                         nil,nil)));

   agNbDisruptingArc--;
  }

  // Potential Cleaning //
  if (agClean) {
   lcCurrentNode=agGraph.nodes().begin();
   lcLastNode=agGraph.nodes().end();

   while (lcCurrentNode!=lcLastNode) {
    lcNode=(*lcCurrentNode).second;
    lcNode->data().potential()=0.0;
    lcCurrentNode++;
   }
  }

  // End //
  lcPotentialS.erase(lcPotentialS.begin(),lcPotentialS.end());
  delete_object(lcNextNodeS);
  delete_object(lcNextNodeS2);
 }
 //----------------------------------------------------------------------------GenerateDiscreteGraph
 template <tdGraph>
 void generateDiscreteGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,tyCardinal agNbArc,
                            tyInteger agPotentialScale,tyCardinal agTensionCardinality,
                            tyInteger agUnitCostScale,tyBoolean agSerialParallel,
                            tyCardinal agNbDisruptingArc) {
  typedef clArc<tuGraph>                                       cpArc;
  typedef clGraph<tuGraph>                                     cpGraph;
  typedef clNode<tuGraph>                                      cpNode;
  typedef std_map(cpArc *,tyInteger)                           cpCycle;
  typedef typename cpCycle::difference_type                    cpDistance;
  typedef std_vector(cpArc *)                                  cpSet;
  typedef std_vector(cpSet)                                    cpSetS;
  typedef typename cpGraph::cpArcX::const_iterator             cpArcIterator1;
  typedef typename cpNode::cpArcX::const_iterator              cpArcIterator2;
  typedef typename cpCycle::const_iterator                     cpArcIterator3;
  typedef typename cpGraph::cpNodeX::const_iterator            cpNodeIterator;
  typedef private_area::clMintyColorForCycleDetection<tuGraph> cpMintyTest;
  typedef clRandomLinearCost<tuGraph>                          cpRandomCost;

  cpArc *        lcArc1;
  cpArc *        lcArc2;
  cpSet          lcArcS;
  cpCycle        lcCocycle;
  cpArcIterator1 lcCurrentArc1;
  cpArcIterator2 lcCurrentArc2;
  cpArcIterator3 lcCurrentArc3;
  cpNodeIterator lcCurrentNode;
  cpCycle        lcCycle;
  cpGraph        lcGraph;
  cpArcIterator1 lcLastArc1;
  cpArcIterator2 lcLastArc2;
  cpNodeIterator lcLastNode;
  cpNode *       lcNode;
  cpSetS         lcSetS;

  tyCardinal lcArcCounter;
  tyCardinal lcCardinality;
  tyCardinal lcCounter;
  tyInteger  lcDecreaseMax;
  tyInteger  lcIncreaseMax;
  tyCardinal lcSize;
  tyInteger  lcTension;
  tyBoolean  lcValid;

  cpMintyTest  lcMintyTest(agTensionCardinality);
  cpRandomCost lcRandomCost(agUnitCostScale);

  // Structure Generation //
  if (agSerialParallel)
   generateSerialParallelGraph<tuGraph,cpRandomCost>(agGraph,agNbNode,agNbArc,agNbDisruptingArc,
                               agPotentialScale,0,lcRandomCost,nil,false);
  else
   generateGraph(agGraph,agNbNode,agNbArc,agPotentialScale,0,lcRandomCost,false);

  // Arc Tension Generation //
  lcSetS.push_back(cpSet());
  lcCurrentArc1=agGraph.arcs().begin();
  lcLastArc1=agGraph.arcs().end();

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

   lcTension=tyInteger(lcArc1->targetNode()->data().potential()
                       -lcArc1->sourceNode()->data().potential());

   lcArc1->data().addFeasible(lcTension);
   lcArc1->data().expected()=lcTension;
   ++lcCurrentArc1;
  }

  // Feasible Sets Generation //
  lcArcCounter=agGraph.arcs().size();

  while (lcArcCounter>0) {
   lcGraph=agGraph;

   // Blocking Arcs Removing //
   do {
    lcArc1=nil;
    lcCurrentArc1=lcGraph.arcs().begin();
    lcLastArc1=lcGraph.arcs().end();

    while (lcCurrentArc1!=lcLastArc1 and lcArc1==nil) {
     if (findMintyCycle(*((*lcCurrentArc1).second),lcMintyTest,lcCycle,lcCocycle)) {
      lcCurrentArc3=lcCycle.begin();
      std_advance(lcCurrentArc3,cpDistance(randomCardinal(lcCycle.size())));
      lcArc1=(*lcCurrentArc3).first;
     }

     ++lcCurrentArc1;
    }

    if (lcArc1!=nil) {
     lcArcS.push_back(&(agGraph.arc(lcArc1->key())));
     delete_object(lcArc1);
    }
   }
   while (lcArc1!=nil);

   // Cardinality Sets Building //
   lcSetS.erase(lcSetS.begin(),lcSetS.end());
   lcCurrentArc1=lcGraph.arcs().begin();
   lcLastArc1=lcGraph.arcs().end();

   while (lcCurrentArc1!=lcLastArc1) {
    lcArc1=(*lcCurrentArc1).second;
    lcCardinality=lcArc1->data().feasibles().size();
    while (lcSetS.size()<=lcCardinality) lcSetS.push_back(cpSet());
    lcSetS[lcCardinality].push_back(lcArc1);
    ++lcCurrentArc1;
   }

   // Blocking Arcs Reinsertion //
   lcCounter=0;
   while (lcCounter<lcSetS.size()-1 and lcSetS[lcCounter].size()==0) ++lcCounter;

   while (lcArcS.size()>0) {
    lcArc1=lcArcS.back();
    lcArc2=new_object(cpArc(lcGraph,*lcArc1));
    lcArcS.pop_back();
    lcSetS[lcCounter].push_back(lcArc2);
   }

   // Cocycle Building //
   while (lcGraph.nodes().size()>2) {
    while (lcSetS.back().size()==0) lcSetS.pop_back();
    lcCounter=randomCardinal(lcSetS.back().size());
    lcArc1=lcSetS.back()[lcCounter];
    lcSetS.back()[lcCounter]=lcSetS.back().back();
    lcSetS.back().pop_back();

    if (lcArc1->sourceNode()==nil or lcArc1->targetNode()==nil) delete_object(lcArc1);
    else {
     lcCurrentArc2=lcArc1->sourceNode()->outgoingArcs().begin();
     lcLastArc2=lcArc1->sourceNode()->outgoingArcs().end();

     while (lcCurrentArc2!=lcLastArc2) {
      lcArc2=(*lcCurrentArc2).second;
      if (lcArc2->targetNode()==lcArc1->targetNode() and lcArc2!=lcArc1) lcArcS.push_back(lcArc2);
      ++lcCurrentArc2;
     }

     lcCurrentArc2=lcArc1->sourceNode()->incomingArcs().begin();
     lcLastArc2=lcArc1->sourceNode()->incomingArcs().end();

     while (lcCurrentArc2!=lcLastArc2) {
      lcArc2=(*lcCurrentArc2).second;
      if (lcArc2->sourceNode()==lcArc1->targetNode()) lcArcS.push_back(lcArc2);
      ++lcCurrentArc2;
     }

     while (lcArcS.size()>0) {
      lcArcS.back()->setSourceNode(nil);
      lcArcS.back()->setTargetNode(nil);
      lcArcS.pop_back();
     }

     lcGraph.mergeNodes(*(lcArc1->sourceNode()),*(lcArc1->targetNode()));
    }
   }

   // Maximum Decrease and Increase Computation //
   lcValid=false;
   lcIncreaseMax=integerMax();
   lcDecreaseMax=integerMax();
   lcCurrentArc1=lcGraph.arcs().begin();
   lcLastArc1=lcGraph.arcs().end();

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

    if (lcArc1->sourceNode()!=nil and lcArc1->targetNode()!=nil) {
     lcTension=tyInteger(lcArc1->data().expected());
     if (lcTension<lcDecreaseMax) lcDecreaseMax=lcTension;
     lcTension=agPotentialScale-lcTension;
     if (lcTension<lcIncreaseMax) lcIncreaseMax=lcTension;
     if (lcArc1->data().feasibles().size()<agTensionCardinality) lcValid=true;
     lcArcS.push_back(&(agGraph.arc(lcArc1->key())));
    }

    ++lcCurrentArc1;
   }

   // Cocycle Tension Change //
   if (lcValid) {
    lcTension=randomCardinal(lcDecreaseMax+lcIncreaseMax)+1;
    lcCounter=lcArcS.size();

    if (lcTension<=lcDecreaseMax) {
     while (lcCounter>0) {
      --lcCounter;
      lcArc1=lcArcS[lcCounter];
      lcArc1->data().expected()-=lcTension;
      lcSize=lcArc1->data().feasibles().size();
      lcArc1->data().addFeasible(lcArc1->data().expected());
      if (lcArc1->data().feasibles().size()==agTensionCardinality
          and lcSize<agTensionCardinality) --lcArcCounter;
     }
    }
    else {
     lcTension-=lcDecreaseMax;

     while (lcCounter>0) {
      --lcCounter;
      lcArc1=lcArcS[lcCounter];
      lcArc1->data().expected()+=lcTension;
      lcSize=lcArc1->data().feasibles().size();
      lcArc1->data().addFeasible(lcArc1->data().expected());
      if (lcArc1->data().feasibles().size()==agTensionCardinality
          and lcSize<agTensionCardinality) --lcArcCounter;
     }
    }
   }

   lcArcS.erase(lcArcS.begin(),lcArcS.end());
  }

  // Arc Optimum Tension //
  lcCurrentArc1=agGraph.arcs().begin();
  lcLastArc1=agGraph.arcs().end();

  while (lcCurrentArc1!=lcLastArc1) {
   lcArc1=(*lcCurrentArc1).second;
   lcCardinality=lcArc1->data().feasibles().size();
   lcArc1->data().optimum()=lcArc1->data().feasibles()[randomCardinal(lcCardinality)];
   lcArc1->data().expected()=0.0;
   ++lcCurrentArc1;
  }

  // Potential Cleaning //
  lcCurrentNode=agGraph.nodes().begin();
  lcLastNode=agGraph.nodes().end();

  while (lcCurrentNode!=lcLastNode) {
   lcNode=(*lcCurrentNode).second;
   lcNode->data().potential()=0.0;
   lcCurrentNode++;
  }
 }
}

// R a n d o m P i e c e w i s e C o s t  Implementation //-----------------------------------------
namespace private_area {
 template <tdGraph> void clRandomPiecewiseCost<tuGraph>::run(clArc<tuGraph> & agArc) const {
  tyReal    lcLength;
  tyInteger lcScale;

  tyCardinal lcCounter        = atNbPiece;
  tyReal     lcMaximum        = agArc.data().maximum()-agArc.data().optimum();
  tyReal     lcMinimum        = agArc.data().optimum()-agArc.data().minimum();
  tyReal     lcStretchingCost = 0.0;
  tyReal     lcShrinkingCost  = 0.0;

  agArc.data().expected()=agArc.data().optimum();
  if (agArc.data().needUpdate()) agArc.data().update();

  while (lcCounter>0) {
   lcScale=tyInteger(lcMaximum/lcCounter);

   if (lcScale>0) {
    lcLength=(lcCounter==1 ? lcMaximum : randomCardinal(lcScale)+1);
    lcStretchingCost+=randomCardinal(atScale);
    lcMaximum-=lcLength;
    agArc.data().stretchingCosts().push_back(standard::make_pair(lcLength,lcStretchingCost));
   }

   lcScale=tyInteger(lcMinimum/lcCounter);

   if (lcScale>0) {
    lcLength=(lcCounter==1 ? lcMinimum : randomCardinal(lcScale)+1);
    lcShrinkingCost+=randomCardinal(atScale);
    lcMinimum-=lcLength;
    agArc.data().shrinkingCosts().push_back(standard::make_pair(lcLength,lcShrinkingCost));
   }

   --lcCounter;
  }

  std_reverse(agArc.data().shrinkingCosts().begin(),agArc.data().shrinkingCosts().end());
  std_reverse(agArc.data().stretchingCosts().begin(),agArc.data().stretchingCosts().end());
 }
}

// 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
// R a n d o m _ g e n e r 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/random_generation.cpp"

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

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

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemMinCostTensionRandomGeneration
#define private_area graphProblemMinCostTensionRandomGeneration_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Graph_problem/Min_cost_tension/Random_generation");

// Initialization //--------------------------------------------------------------------------------

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

// Constants & Variables //-------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

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

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

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

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