//==================================================================================================
// G r a p h                                                                              Interface
// 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 graphs. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "graph/random_generation.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guGraphRandomGeneration
#define guGraphRandomGeneration

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

namespace bpp {

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

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphRandomGeneration
#define private_area graphRandomGeneration_private

namespace public_area  { /*NAMESPACE*/ using namespace graphAlgorithm; }
namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniGraphRandomGeneration
has_initializer;

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

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

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 //-----------------------------------------------------------------------------------Variable Types
 /*TYPE*/ /* List of node keys. */
 typedef std_vector(tyNodeKey) clNodeKeyS;
 //-----------------------------------------------------------------------------------Constant Types
 typedef const clNodeKeyS ctNodeKeyS;
}

namespace private_area { typedef std_vector(tyArcKey) clArcKeyS; }

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

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

 template <tdGraph>
 void generateNonConnexGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,tyBoolean);

 template <tdGraph> void generateSerialParallelGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal);
 template <tdGraph> void generateTree(clGraph<tuGraph> &,tyCardinal);
}

namespace private_area {
 template <tdGraph> void addArcs(clGraph<tuGraph> &,tyCardinal,ctNodeKeyS &);
 template <tdGraph> void addArcsWithoutCircuit(clGraph<tuGraph> &,tyCardinal,ctNodeKeyS &);

 template <tdGraph>
 void generateConnexGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,clNodeKeyS &,tyBoolean);

 template <tdGraph>
 void generateNonConnexGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,clNodeKeyS &,tyBoolean);

 template <tdGraph> void
 generateSerialParallelGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,clNodeKeyS &);

 template <tdGraph> void generateTree(clGraph<tuGraph> &,tyCardinal,clNodeKeyS &);

 template <tdGraph> void parallelize(clGraph<tuGraph> &,tyArcKey,clArcKeyS &);
 template <tdGraph> void serialize(clGraph<tuGraph> &,tyArcKey,clArcKeyS &,clNodeKeyS &);
}

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 /*ERROR*/ extern_error erEmptyKeyList; /* The key list is empty. */

 /*ERROR*/ extern_error erNotEnoughArcsForConnexity;
 /* Not enough arcs to obtain a connex graph. */
}

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

// X X X  Interface //------------------------------------------------------------------------------
namespace {}

// Functions Inline //------------------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------GenerateConnexGraph
 /*FUNCTION*/
 /* Generates randomly a connex graph with given numbers of arcs and nodes. */
 template <tdGraph> inline
 void generateConnexGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,tyCardinal agNbArc,
                          tyBoolean agNoCircuit) {
  clNodeKeyS lcNodeKeyS;
  private_area::generateConnexGraph(agGraph,agNbNode,agNbArc,lcNodeKeyS,agNoCircuit);
 }
 //---------------------------------------------------------------------------GenerateNonConnexGraph
 /*FUNCTION*/
 /* Generates randomly a graph (connex or not) with given numbers of arcs and nodes. */
 template <tdGraph> inline
 void generateNonConnexGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,tyCardinal agNbArc,
                             tyBoolean agNoCircuit) {
  clNodeKeyS lcNodeKeyS;
  private_area::generateNonConnexGraph(agGraph,agNbNode,agNbArc,lcNodeKeyS,agNoCircuit);
 }
 //----------------------------------------------------------------------GenerateSerialParallelGraph
 /*FUNCTION*/
 /* Generates randomly a connex serial-parallel graph with given numbers of arcs and nodes. */
 template <tdGraph> inline
 void generateSerialParallelGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,
                                  tyCardinal agNbArc) {
  clNodeKeyS lcNodeKeyS;
  private_area::generateSerialParallelGraph(agGraph,agNbNode,agNbArc,lcNodeKeyS);
 }
 //-------------------------------------------------------------------------------------GenerateTree
 /*FUNCTION*/
 /* Generates randomly a tree with a given number of nodes. */
 template <tdGraph> inline void generateTree(clGraph<tuGraph> & agGraph,tyCardinal agNbNode) {
  clNodeKeyS lcNodeKeyS;
  private_area::generateTree(agGraph,agNbNode,lcNodeKeyS);
 }
}

namespace private_area {}

// X X X  Inline //---------------------------------------------------------------------------------
namespace {}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------GenerateConnexGraphWithArcValue
 /*FUNCTION*/
 /* Generates randomly a connex graph with given numbers of arcs and nodes. A value between 0 and
    a given number is randomly chosen for each arc. */
 template <tdGraph>
 void generateConnexGraphWithArcValue(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,
                                      tyCardinal agNbArc,tyInteger agValueScale,
                                      tyBoolean agNoCircuit) {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpIterator;

  cpIterator lcCurrentArc;
  cpIterator lcLastArc;
  clNodeKeyS lcNodeKeyS;

  private_area::generateConnexGraph(agGraph,agNbNode,agNbArc,lcNodeKeyS,agNoCircuit);
  lcCurrentArc=agGraph.arcs().begin();
  lcLastArc=agGraph.arcs().end();

  while (lcCurrentArc!=lcLastArc) {
   (*lcCurrentArc).second->data().value()=(agValueScale==0 ? 1 : randomCardinal(agValueScale+1));
   lcCurrentArc++;
  }
 }
}

namespace private_area {
 //------------------------------------------------------------------------------------------AddArcs
 template <tdGraph>
 void addArcs(clGraph<tuGraph> & agGraph,tyCardinal agNbArc,ctNodeKeyS & agNodeKeyS) {
  method_name("addArcs");

  typedef clArc<tuGraph> cpArc;

  tyNodeKey lcSourceKey;
  tyNodeKey lcTargetKey;

  if (agNodeKeyS.size()==0) send_error(erEmptyKeyList);

  // Arcs Generation //
  while (agNbArc>0) {
   do {
    lcSourceKey=agNodeKeyS[randomCardinal(agNodeKeyS.size())];
    lcTargetKey=agNodeKeyS[randomCardinal(agNodeKeyS.size())];
   }
   while (lcSourceKey==lcTargetKey);

   new_object(cpArc(agGraph,agGraph.getNewArcKey(),prArcData(),lcSourceKey,lcTargetKey));
   agNbArc--;
  }
 }
 //----------------------------------------------------------------------------AddArcsWithoutCircuit
 template <tdGraph>
 void addArcsWithoutCircuit(clGraph<tuGraph> & agGraph,tyCardinal agNbArc,ctNodeKeyS & agNodeKeyS) {
  method_name("addArcsWithoutCircuit");

  typedef clArc<tuGraph> cpArc;

  clCycle   lcCircuit;
  cpArc *   lcNewArc;
  tyNodeKey lcSourceKey;
  tyNodeKey lcTargetKey;

  if (agNodeKeyS.size()==0) send_error(erEmptyKeyList);

  // Arcs Generation //
  while (agNbArc>0) {
   do {
    lcSourceKey=agNodeKeyS[randomCardinal(agNodeKeyS.size())];
    lcTargetKey=agNodeKeyS[randomCardinal(agNodeKeyS.size())];
   }
   while (lcSourceKey==lcTargetKey);

   lcNewArc=new_object(cpArc(agGraph,agGraph.getNewArcKey(),prArcData(),lcSourceKey,lcTargetKey));

   if (findCircuit(agGraph,lcNewArc->key(),lcCircuit)) delete_object(lcNewArc);
   else agNbArc--;
  }
 }
 //------------------------------------------------------------------------------GenerateConnexGraph
 template <tdGraph>
 void generateConnexGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,tyCardinal agNbArc,
                          clNodeKeyS & agNodeKeyS,tyBoolean agNoCircuit) {
  method_name("generateConnexGraph");

  if (agNbArc<agNbNode-1) send_error(erNotEnoughArcsForConnexity);
  generateTree(agGraph,agNbNode,agNodeKeyS);

  if (agNoCircuit) private_area::addArcsWithoutCircuit(agGraph,agNbArc-agNbNode+1,agNodeKeyS);
  else private_area::addArcs(agGraph,agNbArc-agNbNode+1,agNodeKeyS);
 }
 //---------------------------------------------------------------------------GenerateNonConnexGraph
 template <tdGraph>
 void generateNonConnexGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,tyCardinal agNbArc,
                             clNodeKeyS & agNodeKeyS,tyBoolean agNoCircuit) {
  typedef clNode<tuGraph> cpNode;

  tyCardinal lcCurrentNode = 0;

  tyNodeKey lcKey;

  agNodeKeyS.erase(agNodeKeyS.begin(),agNodeKeyS.end());
  agNodeKeyS.reserve(agNbNode);

  // Nodes Generation //
  while (lcCurrentNode<agNbNode) {
   lcKey=agGraph.getNewNodeKey();
   agNodeKeyS.push_back(lcKey);
   new_object(cpNode(agGraph,lcKey,prNodeData()));
   lcCurrentNode++;
  }

  // Arcs Generation //
  if (agNoCircuit) private_area::addArcsWithoutCircuit(agGraph,agNbArc,agNodeKeyS);
  else private_area::addArcs(agGraph,agNbArc,agNodeKeyS);
 }
 //----------------------------------------------------------------------GenerateSerialParallelGraph
 template <tdGraph>
 void generateSerialParallelGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,
                                  tyCardinal agNbArc,clNodeKeyS & agNodeKeyS) {
  typedef clArc<tuGraph>  cpArc;
  typedef clNode<tuGraph> cpNode;

  tyCardinal lcNbArc  = 0;
  tyCardinal lcNbNode = 0;

  tyArcKey     lcArcKey;
  clArcKeyS    lcArcKeyS;
  tyNodeKey    lcNodeKey1;
  tyNodeKey    lcNodeKey2;

  agNodeKeyS.erase(agNodeKeyS.begin(),agNodeKeyS.end());
  agNodeKeyS.reserve(agNbNode);
  lcArcKeyS.reserve(agNbArc);

  // First Arc and Nodes //
  lcNodeKey1=agGraph.getNewNodeKey();
  agNodeKeyS.push_back(lcNodeKey1);
  new_object(cpNode(agGraph,lcNodeKey1,prNodeData()));
  lcNbNode++;

  lcNodeKey2=agGraph.getNewNodeKey();
  agNodeKeyS.push_back(lcNodeKey2);
  new_object(cpNode(agGraph,lcNodeKey2,prNodeData()));
  lcNbNode++;

  lcArcKey=agGraph.getNewArcKey();
  lcArcKeyS.push_back(lcArcKey);
  new_object(cpArc(agGraph,lcArcKey,prArcData(),lcNodeKey1,lcNodeKey2));
  lcNbArc++;

  // Serial-Parallel Generation //
  while (lcNbArc<agNbArc) {
   lcArcKey=lcArcKeyS[randomCardinal(lcNbArc)];

   if (randomCardinal(2)) {
    if (agNbNode-lcNbNode < agNbArc-lcNbArc) parallelize(agGraph,lcArcKey,lcArcKeyS);
    else {
     serialize(agGraph,lcArcKey,lcArcKeyS,agNodeKeyS);
     lcNbNode++;
    }
   }
   else {
    if (lcNbNode < agNbNode) {
     serialize(agGraph,lcArcKey,lcArcKeyS,agNodeKeyS);
     lcNbNode++;
    }
    else parallelize(agGraph,lcArcKey,lcArcKeyS);
   }

   lcNbArc++;
  }
 }
 //-------------------------------------------------------------------------------------GenerateTree
 template <tdGraph>
 void generateTree(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,clNodeKeyS & agNodeKeyS) {
  typedef clArc<tuGraph>  cpArc;
  typedef clNode<tuGraph> cpNode;

  tyCardinal lcCurrentNode = 0;

  tyNodeKey lcFirstKey;
  tyNodeKey lcSecondKey;

  agNodeKeyS.erase(agNodeKeyS.begin(),agNodeKeyS.end());
  agNodeKeyS.reserve(agNbNode);

  // Nodes & Arcs Generation //
  while (lcCurrentNode<agNbNode) {
   lcFirstKey=agGraph.getNewNodeKey();
   agNodeKeyS.push_back(lcFirstKey);
   new_object(cpNode(agGraph,lcFirstKey,prNodeData()));

   if (lcCurrentNode>0) {
    lcSecondKey=agNodeKeyS[randomCardinal(lcCurrentNode)];

    if (randomCardinal(2))
     new_object(cpArc(agGraph,agGraph.getNewArcKey(),prArcData(),lcFirstKey,lcSecondKey));
    else new_object(cpArc(agGraph,agGraph.getNewArcKey(),prArcData(),lcSecondKey,lcFirstKey));
   }

   lcCurrentNode++;
  }
 }
 //--------------------------------------------------------------------------------------Parallelize
 template <tdGraph>
 void parallelize(clGraph<tuGraph> & agGraph,tyArcKey agKey,clArcKeyS & agKeyS) {
  typedef clArc<tuGraph> cpArc;

  tyArcKey lcKey = agGraph.getNewArcKey();
  cpArc &  lcArc = agGraph.arc(agKey);

  agKeyS.push_back(lcKey);
  new_object(cpArc(agGraph,lcKey,prArcData(),lcArc.sourceNode()->key(),lcArc.targetNode()->key()));
 }
 //----------------------------------------------------------------------------------------Serialize
 template <tdGraph> void serialize(clGraph<tuGraph> & agGraph,tyArcKey agKey,
                                   clArcKeyS & agArcKeyS,clNodeKeyS & agNodeKeyS) {
  typedef clArc<tuGraph>  cpArc;
  typedef clNode<tuGraph> cpNode;

  cpArc &   lcArc      = agGraph.arc(agKey);
  tyArcKey  lcArcKey   = agGraph.getNewArcKey();
  tyNodeKey lcNodeKey1 = agGraph.getNewNodeKey();
  tyNodeKey lcNodeKey2 = lcArc.targetNode()->key();

  cpNode * lcNode;

  agArcKeyS.push_back(lcArcKey);
  agNodeKeyS.push_back(lcNodeKey1);
  lcNode=new_object(cpNode(agGraph,lcNodeKey1,prNodeData()));
  lcArc.setTargetNode(lcNode);
  new_object(cpArc(agGraph,lcArcKey,prArcData(),lcNodeKey1,lcNodeKey2));
 }
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef tdGraph
#undef tuGraph
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// G r a p h                                                                         Implementation
// 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/random_generation.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define GRAPH_DLL

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

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphRandomGeneration
#define private_area graphRandomGeneration_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Graph/Random_generation");

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

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 static_error erEmptyKeyList;
 static_error erNotEnoughArcsForConnexity;
}

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

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

    erEmptyKeyList.create("Graph - The key list is empty.");
    erNotEnoughArcsForConnexity.create("Graph - Not enough arcs to obtain a connex graph.");
   }

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

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