//==================================================================================================
// G r a p h _ p r o b l e m                                                              Interface
// S e r i a l _ p a r a l l e l
//                                                                                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 for serial-parallel graphs. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "graph_problem/serial_parallel.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guGraphProblemSerialParallel
#define guGraphProblemSerialParallel

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

namespace bpp {

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

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemSerialParallel
#define private_area graphProblemSerialParallel_private

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

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniGraphProblemSerialParallel
has_initializer;

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

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

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 template <tdGraph> class clDecomposeAlgo;
 template <tdGraph> class clDecomposeAlgoI;
 template <tdGraph> class clDecomposeAlgoII;
 template <tdGraph> class clDecomposeAlgoIII;
 //------------------------------------------------------------------------------------------Classes
 template <tdGraph> class clSerialParallelData;
}

namespace private_area {}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area {
 template <tdGraph> void associateTreeWithGraph(clBinaryTree<clSerialParallelData<tuGraph> > &,
                                                clGraph<tuGraph> &);

 template <tdGraph> void findArcs(clBinaryTree<clSerialParallelData<tuGraph> > &,
                                  std_vector(clArc<tuGraph> *) &);

 template <tdGraph> void findNodes(clBinaryTree<clSerialParallelData<tuGraph> > &,
                                   std_vector(clNode<tuGraph> *) &,clNode<tuGraph> ** =nil,
                                   clNode<tuGraph> ** =nil);

 template <tdGraph>
 clNode<tuGraph> * getTreeSourceNode(clBinaryTree<clSerialParallelData<tuGraph> > &);

 template <tdGraph>
 clNode<tuGraph> * getTreeTargetNode(clBinaryTree<clSerialParallelData<tuGraph> > &);

 template <tdGraph,class prTreeS>
 void postDecompose(std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) &,
                    prTreeS &,std_deque(prTreeS *) &,std_deque(prTreeS *) &);

 template <tdGraph,class prTreeS>
 tyBoolean splitTree(clBinaryTree<clSerialParallelData<tuGraph> > &,clNode<tuGraph> &,
                     prTreeS &);
}

namespace private_area {
 template <tdGraph>
 void addNodes(std_map(clNode<tuGraph> *,clBinaryTree<clSerialParallelData<tuGraph> > *) &,
               std_vector(clNode<tuGraph> *) &,clBinaryTree<clSerialParallelData<tuGraph> > &);

 template <tdGraph> clArc<tuGraph> * breakCircuit(const std_vector(clNode<tuGraph> *) &,tyMark);

 template <tdGraph>
 void parallelFusion(std_map(tyArcKey,clBinaryTree<clSerialParallelData<tuGraph> > *) &,
                     clArc<tuGraph> & agArc1,clArc<tuGraph> &);

 template <tdGraph> void removeNode(std_vector(clNode<tuGraph> *) &,clNode<tuGraph> *);

 template <tdGraph>
 void removeNodes(std_map(clNode<tuGraph> *,clBinaryTree<clSerialParallelData<tuGraph> > *) &,
                  std_vector(clNode<tuGraph> *) &);

 template <tdGraph>
 void serialFusion(std_map(tyArcKey,clBinaryTree<clSerialParallelData<tuGraph> > *) &,
                   clNode<tuGraph> &);

 template <tdGraph> inline tyReal sourceNodeQuality(const clNode<tuGraph> &);
 template <tdGraph> inline tyReal targetNodeQuality(const clNode<tuGraph> &);

 testing_mode ( function void test(void); )
}

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 /*ERROR*/ extern_error erArcGraphAssociationProblem;
 /* Can not associate the arc with the graph. */

 /*ERROR*/ extern_error erNotSerialParallel; /* The graph is not serial-parallel. */
 /*ERROR*/ extern_error erSplitNotFound; /* Split of the tree not found. */
}

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

extern_static_constant(private,tcString,goParallelFlag,?);
extern_static_constant(private,tcString,goSerialFlag,?);

// D e c o m p o s e A l g o  Interface //----------------------------------------------------------
namespace public_area {
 /*CLASS clDecomposeAlgo */
 /* Represents an algorithm to decompose a graph into serial-parallel components. The components
    are trees that represent the serial-parallel structure of the graph. A node in these trees is
    either a serial operation, a parallel operation or an arc. If the graph is serial-parallel,
    there is only one generated tree. It is an abstract class. */
 template <tdGraph> class clDecomposeAlgo {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clDecomposeAlgo(const clDecomposeAlgo &);
  private_property clDecomposeAlgo & operator = (const clDecomposeAlgo &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clDecomposeAlgo(void);
  public_property virtual destructor clDecomposeAlgo(void);

  /*AMETHOD clDecomposeAlgo */ /* Executes the algorithm. Abstract method. */
  public_property
  virtual void run(const clGraph<tuGraph> & agGraph,
                   std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) & agTreeS) const = 0;

  public_property static
  void defaultRun(const clGraph<tuGraph> &,
                  std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) &);
 };
}

// D e c o m p o s e A l g o I  Interface //--------------------------------------------------------
namespace public_area {
 /*CLASS clDecomposeAlgoI */
 /* Represents the method I to decompose a graph into serial-parallel components. */
 template <tdGraph> class clDecomposeAlgoI : public clDecomposeAlgo<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clDecomposeAlgoI(const clDecomposeAlgoI &);
  private_property clDecomposeAlgoI & operator = (const clDecomposeAlgoI &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clDecomposeAlgoI(void);
  public_property virtual destructor clDecomposeAlgoI(void);

  public_property void run(const clGraph<tuGraph> &,
                           std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) &) const;
 };
}

// D e c o m p o s e A l g o I I  Interface //------------------------------------------------------
namespace public_area {
 /*CLASS clDecomposeAlgoII */
 /* Represents the method II to decompose a graph into serial-parallel components. */
 template <tdGraph> class clDecomposeAlgoII : public clDecomposeAlgo<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clDecomposeAlgoII(const clDecomposeAlgoII &);
  private_property clDecomposeAlgoII & operator = (const clDecomposeAlgoII &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clDecomposeAlgoII(void);
  public_property virtual destructor clDecomposeAlgoII(void);

  public_property void run(const clGraph<tuGraph> &,
                           std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) &) const;
 };
}

// D e c o m p o s e A l g o I I I  Interface //----------------------------------------------------
namespace public_area {
 /*CLASS clDecomposeAlgoIII */
 /* Represents the method III to decompose a graph into serial-parallel components. */
 template <tdGraph> class clDecomposeAlgoIII : public clDecomposeAlgo<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clDecomposeAlgoIII(const clDecomposeAlgoIII &);
  private_property clDecomposeAlgoIII & operator = (const clDecomposeAlgoIII &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clDecomposeAlgoIII(void);
  public_property virtual destructor clDecomposeAlgoIII(void);

  public_property void run(const clGraph<tuGraph> &,
                           std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) &) const;
 };
}

// S e r i a l P a r a l l e l D a t a  Interface //------------------------------------------------
namespace public_area {
 /*CLASS clSerialParallelData */
 /* Represents the data carried by a binary tree representing a serial-parallel component of
    a graph. */
 template <tdGraph> class clSerialParallelData {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clSerialParallelData */ /* Type of an arc. */
  public_property typedef clArc<tuGraph> * cpArc;

  /*TYPE clSerialParallelData */ /* Enumeration of the construction operations. */
  public_property enumeration { none , serial , parallel } tyOperation;
  //-----------------------------------------------------------------------------------------Private
  private_property tyArcKey atArcKey;
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clSerialParallelData */ /* Pointer to an arc, if there is no operation. */
  read_write_attribute(cpArc,atArc,arc);

  /*ATTRIBUTE clSerialParallelData */ /* Construction operation. */
  read_write_attribute(tyOperation,atOperation,operation);

  public_property constructor clSerialParallelData(void);
  public_property constructor clSerialParallelData(cpArc,tyOperation);
  public_property constructor clSerialParallelData(const clSerialParallelData<tuGraph> &);
  public_property constructor clSerialParallelData(clInStream &);
  public_property destructor  clSerialParallelData(void);

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

  public_property void associateArcWithGraph(clGraph<tuGraph> &);
  public_property void out(clOutStream &) const;
 };
}

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

// D e c o m p o s e A l g o  Inline //-------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clDecomposeAlgo */
 /* Builds an algorithm to decompose a graph into serial-parallel components. */
 template <tdGraph> inline clDecomposeAlgo<tuGraph>::clDecomposeAlgo(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clDecomposeAlgo */ /* Destructs the algorithm. */
 template <tdGraph> inline clDecomposeAlgo<tuGraph>::~clDecomposeAlgo(void) {}
}

// D e c o m p o s e A l g o I  Inline //-----------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clDecomposeAlgoI */
 /* Builds an algorithm to decompose a graph into serial-parallel components using the method I. */
 template <tdGraph> inline clDecomposeAlgoI<tuGraph>::clDecomposeAlgoI(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clDecomposeAlgoI */ /* Destructs the algorithm. */
 template <tdGraph> inline clDecomposeAlgoI<tuGraph>::~clDecomposeAlgoI(void) {}
}

// D e c o m p o s e A l g o I I  Inline //---------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clDecomposeAlgoII */
 /* Builds an algorithm to decompose a graph into serial-parallel components using the
    method II. */
 template <tdGraph> inline clDecomposeAlgoII<tuGraph>::clDecomposeAlgoII(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clDecomposeAlgoII */ /* Destructs the algorithm. */
 template <tdGraph> inline clDecomposeAlgoII<tuGraph>::~clDecomposeAlgoII(void) {}
}

// D e c o m p o s e A l g o I I I  Inline //-------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clDecomposeAlgoIII */
 /* Builds an algorithm to decompose a graph into serial-parallel components using the
    method III. */
 template <tdGraph> inline clDecomposeAlgoIII<tuGraph>::clDecomposeAlgoIII(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clDecomposeAlgoIII */ /* Destructs the algorithm. */
 template <tdGraph> inline clDecomposeAlgoIII<tuGraph>::~clDecomposeAlgoIII(void) {}
}

// S e r i a l P a r a l l e l D a t a  Inline //---------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSerialParallelData */ /* Builds a data with the default value. */
 template <tdGraph> inline clSerialParallelData<tuGraph>::clSerialParallelData(void)
 : atArcKey(nilArc()),atArc(nil),atOperation(none) {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSerialParallelData */ /* Builds a data from values. */
 template <tdGraph>
 inline clSerialParallelData<tuGraph>::clSerialParallelData(cpArc agArc,tyOperation agOperation)
 : atArcKey(nilArc()),atArc(agArc),atOperation(agOperation) {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSerialParallelData */ /* Builds and copies a data. */
 template <tdGraph> inline
 clSerialParallelData<tuGraph>::clSerialParallelData(const clSerialParallelData<tuGraph> & agData)
 : atArcKey(nilArc()),atArc(agData.atArc),atOperation(agData.atOperation) {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSerialParallelData */
 /* Builds a data from a stream, but the data is not complete, because it has a pointer to an arc
    that can not be determined here. Use the <CODE>associateArcWithGraph</CODE> method to get the
    right pointer later (a private attribute memorizes the key of the arc). */
 template <tdGraph>
 inline clSerialParallelData<tuGraph>::clSerialParallelData(clInStream & agStream)
 : atArcKey(nilArc()),atArc(nil),atOperation(none) {
  clString lcString;

  agStream >> lcString;

  if (lcString==private_area::goSerialFlag) atOperation=serial;
  else if (lcString==private_area::goParallelFlag) atOperation=parallel;
  else { atArcKey=cardinal(lcString.data()); }

  if (agStream.fail()) send_inline_error(erStreamReading,"serialParallelData::constructor");
 }
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clSerialParallelData */ /* Destructs the data. */
 template <tdGraph> inline clSerialParallelData<tuGraph>::~clSerialParallelData(void) {}
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clSerialParallelData */ /* Copies a data. */
 template <tdGraph> inline clSerialParallelData<tuGraph> &
 clSerialParallelData<tuGraph>::operator = (const clSerialParallelData<tuGraph> & agData) {
  atArcKey=agData.atArcKey;
  atArc=agData.atArc;
  atOperation=agData.atOperation;
  return (*this);
 }
 //----------------------------------------------------------------------------AssociateArcWithGraph
 /*METHOD clSerialParallelData */
 /* Associates the arc of the data with a graph, using the arc key memorized from the
    construction phase. For more details, see the constructor from stream. */
 template <tdGraph> inline
 void clSerialParallelData<tuGraph>::associateArcWithGraph(clGraph<tuGraph> & agGraph) {
  if (atArc!=nil or atArcKey==nilArc())
   send_inline_error(erArcGraphAssociationProblem,"serialParallelData::associateArcWithGraph");

  atArc=&(agGraph.arc(atArcKey));
  atArcKey=nilArc();
 }
 //----------------------------------------------------------------------------------------------Out
 /*METHOD clSerialParallelData */ /* Writes the data into a stream. */
 template <tdGraph>
 inline void clSerialParallelData<tuGraph>::out(clOutStream & agStream) const {
  if (atOperation==serial) agStream << private_area::goSerialFlag;
  else if (atOperation==parallel) agStream << private_area::goParallelFlag;
  else if (atArc!=nil) agStream << atArc->key();
  else if (atArcKey!=nilArc()) agStream << atArcKey;
  else agStream << graphStructure_private::goNoArcFlag;

  if (agStream.fail()) send_inline_error(erStreamWriting,"serialParallelData::out");
 }
}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------AssociateTreeWithGraph
 /*FUNCTION*/ /* Associates a tree just read from a stream with a graph. */
 template <tdGraph>
 void associateTreeWithGraph(clBinaryTree<clSerialParallelData<tuGraph> > & agTree,
                             clGraph<tuGraph> & agGraph) {
  if (not agTree.empty()) {
   if (agTree.data().operation()==clSerialParallelData<tuGraph>::none)
    ((clSerialParallelData<tuGraph> &)(agTree.data())).associateArcWithGraph(agGraph);
   else {
    associateTreeWithGraph(agTree.left(),agGraph);
    associateTreeWithGraph(agTree.right(),agGraph);
   }
  }
 }
 //-----------------------------------------------------------------------------------------FindArcs
 /*FUNCTION*/
 /* Lists all the arcs contained in a serial-parallel component. It stores them in a vector. */
 template <tdGraph> void findArcs(clBinaryTree<clSerialParallelData<tuGraph> > & agTree,
                                  std_vector(clArc<tuGraph> *) & agArcS) {
  typedef clSerialParallelData<tuGraph>      cpSerialParallelData;
  typedef clBinaryTree<cpSerialParallelData> cpTree;
  typedef std_vector(cpTree *)               cpTreeS;
  typedef std_vector(tyCardinal)             clCardinalS;

  clCardinalS lcStateS;
  cpTree *    lcTree;
  cpTreeS     lcTreeS;

  agArcS.erase(agArcS.begin(),agArcS.end());

  if (not agTree.empty()) {
   lcTreeS.push_back(&agTree);
   lcStateS.push_back(0);

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

    switch (++(lcStateS.back())) {
     case 1:
      if (lcTree->data().operation()==cpSerialParallelData::none) {
       agArcS.push_back(lcTree->data().arc());
       lcTreeS.pop_back();
       lcStateS.pop_back();
      }
      else {
       lcTreeS.push_back(&(lcTree->left()));
       lcStateS.push_back(0);
      }

      break;

     case 2:
      lcTreeS.push_back(&(lcTree->right()));
      lcStateS.push_back(0);
      break;

     default:
      lcTreeS.pop_back();
      lcStateS.pop_back();
    }
   }
  }
 }
 //----------------------------------------------------------------------------------------FindNodes
 /*FUNCTION*/
 /* Lists all the nodes contained in a serial-parallel component. It stores them in a vector,
    expect for the source and target nodes of the component that are collected separately in the
    two last arguments of the function. */
 template <tdGraph> void findNodes(clBinaryTree<clSerialParallelData<tuGraph> > & agTree,
                                   std_vector(clNode<tuGraph> *) & agNodeS,
                                   clNode<tuGraph> ** agSourceNode,
                                   clNode<tuGraph> ** agTargetNode) {
  typedef clArc<tuGraph>                     cpArc;
  typedef clSerialParallelData<tuGraph>      cpSerialParallelData;
  typedef clNode<tuGraph>                    cpNode;
  typedef std_vector(cpNode *)               cpNodeS;
  typedef clBinaryTree<cpSerialParallelData> cpTree;
  typedef std_vector(cpTree *)               cpTreeS;
  typedef std_vector(tyCardinal)             clCardinalS;

  cpArc *     lcArc;
  cpNode *    lcMiddleNode;
  cpNodeS     lcMiddleS;
  cpNodeS     lcSourceS;
  clCardinalS lcStateS;
  cpTree *    lcTree;
  cpTreeS     lcTreeS;

  cpNode * lcSourceNode = nil;
  cpNode * lcTargetNode = nil;

  if (not agTree.empty()) {
   lcTreeS.push_back(&agTree);
   lcSourceS.push_back(nil);
   lcMiddleS.push_back(nil);
   lcStateS.push_back(0);

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

    switch (++(lcStateS.back())) {
     case 1:
      if (lcTree->data().operation()==cpSerialParallelData::none) {
       lcArc=lcTree->data().arc();
       lcTreeS.pop_back();
       lcSourceS.pop_back();
       lcMiddleS.pop_back();
       lcStateS.pop_back();
       lcSourceNode=lcArc->sourceNode();
       lcTargetNode=lcArc->targetNode();
      }
      else {
       lcTreeS.push_back(&(lcTree->left()));
       lcSourceS.push_back(nil);
       lcMiddleS.push_back(nil);
       lcStateS.push_back(0);
      }

      break;

     case 2:
      lcSourceS.back()=lcSourceNode;
      lcMiddleS.back()=lcTargetNode;
      lcTreeS.push_back(&(lcTree->right()));
      lcSourceS.push_back(nil);
      lcMiddleS.push_back(nil);
      lcStateS.push_back(0);
      break;

     default:
      lcSourceNode=lcSourceS.back();
      lcMiddleNode=lcMiddleS.back();
      lcTreeS.pop_back();
      lcSourceS.pop_back();
      lcMiddleS.pop_back();
      lcStateS.pop_back();

      if (lcTree->data().operation()==cpSerialParallelData::serial)
       agNodeS.push_back(lcMiddleNode);
    }
   }
  }

  if (agSourceNode!=nil) *agSourceNode=lcSourceNode;
  if (agTargetNode!=nil) *agTargetNode=lcTargetNode;
 }
 //--------------------------------------------------------------------------------GetTreeSourceNode
 /*FUNCTION*/
 /* Returns the source node of the serial-parallel component represented by a binary tree.
    If <CODE>nil</CODE> is returned, it means the tree is empty or invalid. */
 template <tdGraph>
 clNode<tuGraph> * getTreeSourceNode(clBinaryTree<clSerialParallelData<tuGraph> > & agTree) {
  typedef clNode<tuGraph>                              cpNode;
  typedef clSerialParallelData<tuGraph>                cpSerialParallelData;
  typedef clBinaryTree<clSerialParallelData<tuGraph> > cpTree;

  cpNode * lcNode = nil;
  cpTree * lcTree = &agTree;

  while (not lcTree->empty() and lcNode==nil) {
   if (lcTree->data().operation()==cpSerialParallelData::none and lcTree->data().arc()!=nil)
    lcNode=lcTree->data().arc()->sourceNode();
   else lcTree=&(lcTree->left());
  }

  return (lcNode);
 }
 //--------------------------------------------------------------------------------GetTreeTargetNode
 /*FUNCTION*/
 /* Returns the target node of the serial-parallel component represented by a binary tree.
    If <CODE>nil</CODE> is returned, it means the tree is empty or invalid. */
 template <tdGraph>
 clNode<tuGraph> * getTreeTargetNode(clBinaryTree<clSerialParallelData<tuGraph> > & agTree) {
  typedef clNode<tuGraph>                              cpNode;
  typedef clSerialParallelData<tuGraph>                cpSerialParallelData;
  typedef clBinaryTree<clSerialParallelData<tuGraph> > cpTree;

  cpNode * lcNode = nil;
  cpTree * lcTree = &agTree;

  while (not lcTree->empty() and lcNode==nil) {
   if (lcTree->data().operation()==cpSerialParallelData::none and lcTree->data().arc()!=nil)
    lcNode=lcTree->data().arc()->targetNode();
   else lcTree=&(lcTree->right());
  }

  return (lcNode);
 }
 //------------------------------------------------------------------------------------PostDecompose
 /*FUNCTION*/
 /* After a graph has been decomposed into several series-parallel components, this function
    performs a post-process for future algorithms that will need to rebuild the original graph back
    from the series-parallel components. Supposing the series-parallel components are aggregated to
    form single arcs, nodes they hide may need to be revealed by splitting these very same arcs.
    This function proposes a splitting scenario so the original graph can be reconstructed by
    adding one by one the aggregated arcs, and keeping at each step the arcs as aggregated as
    possible. */
 template <tdGraph,class prTreeS>
 void postDecompose(std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) & agTreeS,
                    prTreeS & agBreakerS,std_deque(prTreeS *) & agPieceD,
                    std_deque(prTreeS *) & agBrokenD) {
  method_name("postDecompose");

  typedef clNode<tuGraph>                              cpNode;
  typedef std_vector(cpNode *)                         cpNodeS;
  typedef clBinaryTree<clSerialParallelData<tuGraph> > cpTree;
  typedef std_map(cpNode *,cpTree *)                   cpTreeX;
  typedef std_map(cpTree *,cpNodeS *)                  cpNodeX;
  typedef typename cpNodeX::const_iterator             cpNodeIterator;

  prTreeS *      lcBrokenS;
  cpNodeIterator lcCurrentNode;
  cpNodeIterator lcLastNode;
  cpNodeS *      lcNodeS;
  cpNodeX        lcNodeX;
  prTreeS *      lcPieceS;
  cpNode *       lcSourceNode;
  cpNode *       lcTargetNode;
  cpTree *       lcTree1;
  cpTree *       lcTree2;
  cpTree *       lcTree3;
  cpTreeX        lcTreeX;

  tyCardinal lcCounter2;
  tyBoolean  lcFound1;
  tyBoolean  lcFound2;
  tyBoolean  lcFound3;

  tyCardinal lcCounter1 = agTreeS.size();

  while (lcCounter1>0) {
   // Initialization //
   --lcCounter1;
   lcTree1=agTreeS[lcCounter1];
   lcPieceS=new_object(prTreeS());
   lcBrokenS=new_object(prTreeS());
   lcSourceNode=getTreeSourceNode(*lcTree1);
   lcTargetNode=getTreeTargetNode(*lcTree1);

   // Source Node Breaking Tree Search //
   lcFound1=(lcTreeX.count(lcSourceNode)>0);

   if (lcFound1) {
    lcTree2=lcTreeX[lcSourceNode];
    lcNodeS=lcNodeX[lcTree2];
    private_area::removeNodes(lcTreeX,*lcNodeS);
    delete_object(lcNodeS);
    lcNodeX.erase(lcTree2);
    lcTree3=new_object(cpTree(*lcTree2));
    if (not splitTree(*lcTree3,*lcSourceNode,*lcPieceS)) send_error(erSplitNotFound);
    lcBrokenS->push_back(lcTree2);
    delete_object(lcTree3);
   }

   // Node-To-Tree Relationship Map Update //
   lcCounter2=0;

   while (lcCounter2<lcPieceS->size()) {
    lcNodeS=new_object(cpNodeS());
    lcTree2=(*lcPieceS)[lcCounter2];
    findNodes(*lcTree2,*lcNodeS);
    lcNodeX.insert(std_make_pair(lcTree2,lcNodeS));
    private_area::addNodes(lcTreeX,*lcNodeS,*lcTree2);
    ++lcCounter2;
   }

   // Target Node Breaking Tree Search //
   lcFound2=(lcTreeX.count(lcTargetNode)>0);

   if (lcFound2) {
    lcTree2=lcTreeX[lcTargetNode];
    lcNodeS=lcNodeX[lcTree2];
    private_area::removeNodes(lcTreeX,*lcNodeS);
    lcNodeX.erase(lcTree2);
    delete_object(lcNodeS);
    lcFound3=false;
    lcCounter2=0;

    while (lcCounter2<lcPieceS->size() and not lcFound3) {
     if ((*lcPieceS)[lcCounter2]==lcTree2) lcFound3=true;
     else ++lcCounter2;
    }

    if (lcFound3) {
     (*lcPieceS)[lcCounter2]=lcPieceS->back();
     lcPieceS->pop_back();
     lcCounter2=lcPieceS->size();
     if (not splitTree(*lcTree2,*lcTargetNode,*lcPieceS)) send_error(erSplitNotFound);
     delete_object(lcTree2);
    }
    else {
     lcTree3=new_object(cpTree(*lcTree2));
     if (not splitTree(*lcTree3,*lcTargetNode,*lcPieceS)) send_error(erSplitNotFound);
     lcBrokenS->push_back(lcTree2);
     delete_object(lcTree3);
    }
   }

   // Node-To-Tree Relationship Map Update //
   while (lcCounter2<lcPieceS->size()) {
    lcNodeS=new_object(cpNodeS());
    lcTree2=(*lcPieceS)[lcCounter2];
    findNodes(*lcTree2,*lcNodeS);
    lcNodeX.insert(std_make_pair(lcTree2,lcNodeS));
    private_area::addNodes(lcTreeX,*lcNodeS,*lcTree2);
    ++lcCounter2;
   }

   lcNodeS=new_object(cpNodeS());
   findNodes(*lcTree1,*lcNodeS);
   lcNodeX.insert(std_make_pair(lcTree1,lcNodeS));
   private_area::addNodes(lcTreeX,*lcNodeS,*lcTree1);

   // Result Storage //
   if (lcFound1 or lcFound2) {
    agBreakerS.push_back(lcTree1);
    agPieceD.push_back(lcPieceS);
    agBrokenD.push_back(lcBrokenS);
   }
   else {
    delete_object(lcPieceS);
    delete_object(lcBrokenS);
   }
  }

  // Memory Deallocation //
  lcCurrentNode=lcNodeX.begin();
  lcLastNode=lcNodeX.end();

  while (lcCurrentNode!=lcLastNode) {
   if ((*lcCurrentNode).second!=nil) delete_object((*lcCurrentNode).second);
   ++lcCurrentNode;
  }
 }
 //----------------------------------------------------------------------------------------SplitTree
 /*FUNCTION*/
 /* Splits a serial-parallel component into several serial-parallel subcomponents so a given
    node it contains is not inside a component any more. It returns <CODE>true</CODE> if the
    splitting has indeed been performed. */
 template <tdGraph,class prTreeS>
 tyBoolean splitTree(clBinaryTree<clSerialParallelData<tuGraph> > & agTree,
                     clNode<tuGraph> & agNode,prTreeS & agComponentS) {
  typedef clArc<tuGraph>                     cpArc;
  typedef std_vector(tyCardinal)             clCardinalS;
  typedef clSerialParallelData<tuGraph>      cpSerialParallelData;
  typedef clBinaryTree<cpSerialParallelData> cpTree;
  typedef std_vector(cpTree *)               cpTreeS;

  cpArc *     lcArc;
  tyCardinal  lcChild;
  clCardinalS lcChildS;
  cpTree *    lcLeftTree;
  cpTree *    lcParent;
  cpTreeS     lcParentS;
  cpTree *    lcRightTree;
  cpTreeS     lcSerialS;
  clCardinalS lcStateS;
  cpTree *    lcSubtree;
  cpTreeS     lcSuperS;
  cpTree *    lcTree;
  cpTreeS     lcTreeS;

  tyBoolean lcFound  = false;
  tyBoolean lcLeft   = false;
  tyBoolean lcRight  = false;
  tyBoolean lcSerial = false;

  // Splitting Pivot Search //
  lcTreeS.push_back(&agTree);
  lcSuperS.push_back(nil);
  lcStateS.push_back(0);

  while (lcTreeS.size()>0 and not lcFound) {
   lcTree=lcTreeS.back();
   lcParent=lcSuperS.back();

   switch (++(lcStateS.back())) {
    case 1:// First Visit Of The Node //
     if (lcTree->data().operation()==cpSerialParallelData::none) {
      lcArc=lcTree->data().arc();
      lcLeft=(lcArc->sourceNode()==&agNode);
      lcRight=(lcArc->targetNode()==&agNode);
      lcFound=(lcLeft or lcRight);
      lcTreeS.pop_back();
      lcSuperS.pop_back();
      lcStateS.pop_back();
     }
     else {
      if (lcTree->data().operation()==cpSerialParallelData::serial) {
       lcSerialS.push_back(lcTree);
       lcParentS.push_back(lcParent);
       lcChildS.push_back(1);
      }

      lcTreeS.push_back(&(lcTree->left()));
      lcSuperS.push_back(lcTree);
      lcStateS.push_back(0);
     }

     break;

    case 2: // Left Member Of The Node Visited //
     if (lcTree->data().operation()==cpSerialParallelData::serial) lcChildS.back()=2;
     lcTreeS.push_back(&(lcTree->right()));
     lcSuperS.push_back(lcTree);
     lcStateS.push_back(0);
     break;

    default: // Right Member Of The Node Visited //
     if (lcTree->data().operation()==cpSerialParallelData::serial) {
      lcSerialS.pop_back();
      lcParentS.pop_back();
      lcChildS.pop_back();
     }

     lcTreeS.pop_back();
     lcSuperS.pop_back();
     lcStateS.pop_back();
   }
  }

  if (not lcFound) return (false);
  lcFound=false;

  while (lcSerialS.size()>0 and not lcFound) {
   lcFound=((lcLeft and lcChildS.back()==2) or (lcRight and lcChildS.back()==1));

   if (not lcFound) {
    lcSerialS.pop_back();
    lcParentS.pop_back();
    lcChildS.pop_back();
   }
  }

  if (not lcFound) return (false);

  // First Splitting //
  lcFound=false;

  while (lcSerialS.size()>0 and not lcFound) {
   lcTree=lcSerialS.back();
   lcParent=lcParentS.back();
   lcSerialS.pop_back();
   lcParentS.pop_back();
   lcChildS.pop_back();
   lcLeftTree=&(lcTree->extractLeft());
   lcRightTree=&(lcTree->extractRight());

   if (lcParent!=nil) {
    // Parallel Splitting I //
    if (lcParent->data().operation()==cpSerialParallelData::parallel) {
     if (lcTree==&lcParent->left()) {
      lcParent->setLeft(nil);
      lcSubtree=&(lcParent->extractRight());
     }
     else {
      lcParent->setRight(nil);
      lcSubtree=&(lcParent->extractLeft());
     }

     lcParent->setData(lcSubtree->data());
     lcParent->setLeft(&(lcSubtree->extractLeft()));
     lcParent->setRight(&(lcSubtree->extractRight()));
     delete_object(lcSubtree);
     agComponentS.push_back(lcLeftTree);
     agComponentS.push_back(lcRightTree);
     lcFound=true;
    }
    else {
     // Right Rotation I //
     if (lcTree==&lcParent->left()) {
      lcTree=&(lcParent->extractLeft());
      lcTree->setLeft(lcRightTree);
      lcTree->setRight(&(lcParent->extractRight()));
      lcParent->setLeft(lcLeftTree);
      lcParent->setRight(lcTree);
     }

     // Left Rotation I //
     else {
      lcTree=&(lcParent->extractRight());
      lcTree->setLeft(&(lcParent->extractLeft()));
      lcTree->setRight(lcLeftTree);
      lcParent->setLeft(lcTree);
      lcParent->setRight(lcRightTree);
     }
    }
   }

   // Parallel Splitting I //
   else {
    agComponentS.push_back(lcLeftTree);
    agComponentS.push_back(lcRightTree);
    lcTree->clear();
   }
  }

  // Second Splitting //
  while (lcSerialS.size()>0) {
   lcTree=lcSerialS.back();
   lcParent=lcParentS.back();
   lcChild=lcChildS.back();
   lcSerialS.pop_back();
   lcParentS.pop_back();
   lcChildS.pop_back();
   lcLeftTree=&(lcTree->extractLeft());
   lcRightTree=&(lcTree->extractRight());

   if (lcParent!=nil) {
    // Parallel Splitting II //
    if (lcParent->data().operation()==cpSerialParallelData::parallel) {
     if (lcTree==&lcParent->left()) {
      lcParent->setLeft(nil);
      lcSubtree=&(lcParent->extractRight());
     }
     else {
      lcParent->setRight(nil);
      lcSubtree=&(lcParent->extractLeft());
     }

     lcParent->setData(lcSubtree->data());
     lcParent->setLeft(&(lcSubtree->extractLeft()));
     lcParent->setRight(&(lcSubtree->extractRight()));
     delete_object(lcSubtree);
     lcSerial=false;

     if (not lcLeftTree->empty()) agComponentS.push_back(lcLeftTree);
     else delete_object(lcLeftTree);

     if (not lcRightTree->empty()) agComponentS.push_back(lcRightTree);
     else delete_object(lcRightTree);
    }
    else {
     if (not lcSerial) {
      lcSerial=true;

      // Left Splitting //
      if (lcChild==1) {
       agComponentS.push_back(lcLeftTree);
       lcLeftTree=new_object(cpTree());
      }

      // Right Splitting //
      else {
       agComponentS.push_back(lcRightTree);
       lcRightTree=new_object(cpTree());
      }
     }

     // Right Rotation II //
     if (lcTree==&lcParent->left()) {
      if (not lcRightTree->empty()) {
       lcTree=&(lcParent->extractLeft());
       lcTree->setLeft(lcRightTree);
       lcTree->setRight(&(lcParent->extractRight()));
       lcParent->setRight(lcTree);
      }
      else delete_object(lcRightTree);

      lcParent->setLeft(lcLeftTree);
     }

     // Left Rotation II //
     else {
      if (not lcLeftTree->empty()) {
       lcTree=&(lcParent->extractRight());
       lcTree->setLeft(&(lcParent->extractLeft()));
       lcTree->setRight(lcLeftTree);
       lcParent->setLeft(lcTree);
      }
      else delete_object(lcLeftTree);

      lcParent->setRight(lcRightTree);
     }
    }
   }

   // Parallel Splitting II //
   else {
    if (not lcLeftTree->empty()) agComponentS.push_back(lcLeftTree);
    else delete_object(lcLeftTree);

    if (not lcRightTree->empty()) agComponentS.push_back(lcRightTree);
    else delete_object(lcRightTree);

    lcTree->clear();
   }
  }

  if (not agTree.empty()) {
   lcTree=new_object(cpTree());
   lcTree->setData(agTree.data());
   lcTree->setLeft(&(agTree.extractLeft()));
   lcTree->setRight(&(agTree.extractRight()));
   agTree.clear();
   agComponentS.push_back(lcTree);
  }

  return (true);
 }
}

namespace private_area {
 //-----------------------------------------------------------------------------------------AddNodes
 template <tdGraph>
 void addNodes(std_map(clNode<tuGraph> *,clBinaryTree<clSerialParallelData<tuGraph> > *) & agTreeX,
               std_vector(clNode<tuGraph> *) & agNodeS,
               clBinaryTree<clSerialParallelData<tuGraph> > & agTree) {
  tyCardinal lcCounter = agNodeS.size();

  while (lcCounter>0) {
   --lcCounter;
   agTreeX.insert(std_make_pair(agNodeS[lcCounter],&agTree));
  }
 }
 //-------------------------------------------------------------------------------------BreakCircuit
 template <tdGraph>
 clArc<tuGraph> * breakCircuit(const std_vector(clNode<tuGraph> *) & agNodeS,tyMark agMark) {
  typedef clArc<tuGraph>                          cpArc;
  typedef clNode<tuGraph>                         cpNode;
  typedef typename cpNode::cpArcX::const_iterator cpArcIterator;
  typedef std_map(cpArc *,tyInteger)              cpCycle;

  cpArc *       lcArc;
  cpArcIterator lcCurrentArc;
  cpCycle       lcCycle;
  cpArcIterator lcLastArc;
  tyInteger     lcMark;

  tyCardinal lcCounter    = 0;
  tyBoolean  lcDeleted    = false;
  cpArc *    lcDeletedArc = nil;

  // Circuit Detection //
  while (not lcDeleted and lcCounter<agNodeS.size()) {
   lcCurrentArc=agNodeS[lcCounter]->incomingArcs().begin();
   lcLastArc=agNodeS[lcCounter]->incomingArcs().end();

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

    // Loop //
    if (lcArc->sourceNode()==lcArc->targetNode()) {
     lcDeletedArc=lcArc;
     lcDeleted=true;
    }

    // Circuit Detection //
    else {
     lcMark=*static_cast<tyInteger *>(lcArc->sourceNode()->work());

     if (lcMark>=0 and findCircuit(*lcArc,lcCycle)) {
      lcDeletedArc=lcArc;
      lcDeleted=true;
     }
     else ++lcCurrentArc;
    }
   }

   ++lcCounter;
  }

  // Nodes Marking Back //
  lcCounter=0;

  while (lcCounter<agNodeS.size()) {
   agNodeS[lcCounter]->mark()=agMark;
   ++lcCounter;
  }

  return (lcDeletedArc);
 }
 //-----------------------------------------------------------------------------------ParallelFusion
 template <tdGraph>
 void parallelFusion(std_map(tyArcKey,clBinaryTree<clSerialParallelData<tuGraph> > *) & agTreeX,
                     clArc<tuGraph> & agArc1,clArc<tuGraph> & agArc2) {
  typedef clSerialParallelData<tuGraph>                cpTreeData;
  typedef clBinaryTree<cpTreeData>                     cpTree;
  typedef std_map(tyArcKey,clBinaryTree<cpTreeData> *) cpTreeX;
  typedef typename cpTreeX::value_type                 cpTreePair;

  cpTree * lcTree = new_object(cpTree(cpTreeData(nil,cpTreeData::parallel)));

  lcTree->setLeft(agTreeX[agArc2.key()]);
  lcTree->setRight(agTreeX[agArc1.key()]);
  agTreeX.erase(agArc1.key());
  agTreeX.erase(agArc2.key());
  agTreeX.insert(cpTreePair(agArc2.key(),lcTree));
  delete_object(&agArc1);
 }
 //---------------------------------------------------------------------------------------RemoveNode
 template <tdGraph> void removeNode(std_vector(clNode<tuGraph> *) & agNodeS,
                                    clNode<tuGraph> * agNode) {
  tyCardinal lcCounter = 0;

  while (lcCounter<agNodeS.size()) {
   if (agNodeS[lcCounter]==agNode) agNodeS[lcCounter]=nil;
   ++lcCounter;
  }
 }
 //--------------------------------------------------------------------------------------RemoveNodes
 template <tdGraph> void
 removeNodes(std_map(clNode<tuGraph> *,clBinaryTree<clSerialParallelData<tuGraph> > *) & agTreeX,
             std_vector(clNode<tuGraph> *) & agNodeS) {
  tyCardinal lcCounter = agNodeS.size();

  while (lcCounter>0) {
   --lcCounter;
   agTreeX.erase(agNodeS[lcCounter]);
  }
 }
 //-------------------------------------------------------------------------------------SerialFusion
 template <tdGraph>
 void serialFusion(std_map(tyArcKey,clBinaryTree<clSerialParallelData<tuGraph> > *) & agTreeX,
                   clNode<tuGraph> & agNode) {
  typedef clSerialParallelData<tuGraph>                cpTreeData;
  typedef clBinaryTree<cpTreeData>                     cpTree;
  typedef std_map(tyArcKey,clBinaryTree<cpTreeData> *) cpTreeX;
  typedef typename cpTreeX::value_type                 cpTreePair;

  clArc<tuGraph> * lcArc1 = (*(agNode.incomingArcs().begin())).second;
  clArc<tuGraph> * lcArc2 = (*(agNode.outgoingArcs().begin())).second;
  cpTree *         lcTree = new_object(cpTree(cpTreeData(nil,cpTreeData::serial)));

  lcArc1->setTargetNode(lcArc2->targetNode());
  lcTree->setLeft(agTreeX[lcArc1->key()]);
  lcTree->setRight(agTreeX[lcArc2->key()]);
  agTreeX.erase(lcArc1->key());
  agTreeX.erase(lcArc2->key());
  agTreeX.insert(cpTreePair(lcArc1->key(),lcTree));
  delete_object(static_cast<tyInteger *>(agNode.work()));
  delete_object(&agNode);
 }
 //--------------------------------------------------------------------------------SourceNodeQuality
 template <tdGraph> inline tyReal sourceNodeQuality(const clNode<tuGraph> & agNode) {
  tyCardinal lcInSize  = agNode.incomingArcs().size();
  tyCardinal lcOutSize = agNode.outgoingArcs().size();

  if (lcOutSize==0) return (realMin());
  if (lcOutSize==1) return (-100.0);
  if (lcInSize==0) return (0.0);
  return (1.0/(lcOutSize-1) + 1.0/lcInSize);
 }
 //--------------------------------------------------------------------------------TargetNodeQuality
 template <tdGraph> inline tyReal targetNodeQuality(const clNode<tuGraph> & agNode) {
  tyCardinal lcInSize  = agNode.incomingArcs().size();
  tyCardinal lcOutSize = agNode.outgoingArcs().size();

  if (lcInSize==0) return (realMin());
  if (lcInSize==1) return (-100.0);
  if (lcOutSize==0) return (0.0);
  return (1.0/(lcInSize-1) + 1.0/lcOutSize);
 }
}

// D e c o m p o s e A l g o  Implementation //-----------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------DefaultRun
 /*METHOD clDecomposeAlgo */
 /* Decomposes a graph into serial-parallel components using the default version of the algorithm
    (method I). Static method. */
 template <tdGraph>
 inline void clDecomposeAlgo<tuGraph>::defaultRun(const clGraph<tuGraph> & agGraph,
             std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) & agTreeS)
 { clDecomposeAlgoI<tuGraph>().run(agGraph,agTreeS); }
}

// D e c o m p o s e A l g o I  Implementation //---------------------------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clDecomposeAlgoI */ /* Decomposes a graph into serial-parallel components. */
 template <tdGraph> void clDecomposeAlgoI<tuGraph>::run(const clGraph<tuGraph> & agGraph,
                    std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) & agTreeS) const {
  typedef clArc<tuGraph>   cpArc;
  typedef clGraph<tuGraph> cpGraph;
  typedef clNode<tuGraph>  cpNode;

  typedef std_vector(cpArc *)           cpArcS;
  typedef std_vector(cpNode *)          cpNodeS;
  typedef std_multimap(cpArc *,cpArc *) cpParallelX;
  typedef clSerialParallelData<tuGraph> cpTreeData;
  typedef clBinaryTree<cpTreeData>      cpTree;
  typedef std_map(tyArcKey,cpTree *)    cpTreeX;

  typedef typename cpGraph::cpArcX::const_iterator  cpArcIterator;
  typedef typename cpGraph::cpNodeX::const_iterator cpNodeIterator;
  typedef typename cpParallelX::const_iterator      cpParallelIterator;
  typedef typename cpParallelX::value_type          cpParallelPair;
  typedef typename cpTreeX::value_type              cpTreePair;

  tyBoolean          lcAgain;
  cpArc *            lcArc1;
  cpArc *            lcArc2;
  cpArcS             lcArcS;
  cpArcIterator      lcCurrentArc;
  cpArcIterator      lcCurrentNeighbor;
  cpNodeIterator     lcCurrentNode;
  cpParallelIterator lcCurrentParallel;
  cpArcS             lcDeleteS;
  cpArcIterator      lcLastArc;
  cpArcIterator      lcLastNeighbor;
  cpNodeIterator     lcLastNode;
  cpParallelIterator lcLastParallel;
  cpNode *           lcNode;
  cpNodeS            lcNodeS;
  cpParallelX        lcParallelX;
  cpNodeS            lcSerialS;
  cpTree *           lcTree;
  cpTreeX            lcTreeX;

  tyCardinal lcDepth;
  tyReal     lcMaxQuality;
  tyCardinal lcMinDepth;
  tyReal     lcQuality;

  cpGraph lcGraph(agGraph);

  agTreeS.erase(agTreeS.begin(),agTreeS.end());

  // Component List Initialization //
  lcCurrentArc=agGraph.arcs().begin();
  lcLastArc=agGraph.arcs().end();

  while (lcCurrentArc!=lcLastArc) {
   lcArc1=(*lcCurrentArc).second;
   lcTree=new_object(cpTree(cpTreeData(lcArc1,cpTreeData::none)));
   lcTreeX.insert(cpTreePair(lcArc1->key(),lcTree));
   ++lcCurrentArc;
  }

  // Node List Initialization //
  lcCurrentNode=lcGraph.nodes().begin();
  lcLastNode=lcGraph.nodes().end();

  while (lcCurrentNode!=lcLastNode) {
   lcNodeS.push_back((*lcCurrentNode).second);
   ++lcCurrentNode;
  }

  // Arc List Initialization //
  ++(lcGraph.mark());
  lcCurrentArc=lcGraph.arcs().begin();
  lcLastArc=lcGraph.arcs().end();

  while (lcCurrentArc!=lcLastArc) {
   lcArc1=(*lcCurrentArc).second;
   lcArc1->mark()=lcGraph.mark();
   lcArcS.push_back(lcArc1);
   ++lcCurrentArc;
  }

  // Tree Construction //
  do {
   lcAgain=false;
   if (lcArcS.size()==0) ++(lcGraph.mark());

   // Serial Composition Search //
   while (lcNodeS.size()>0) {
    lcNode=lcNodeS.back();
    lcNodeS.pop_back();

    if (lcNode->incomingArcs().size()==1 and lcNode->outgoingArcs().size()==1) {
     lcArc1=(*lcNode->incomingArcs().begin()).second;
     lcArc2=(*lcNode->outgoingArcs().begin()).second;
     if (lcArc1->sourceNode()!=lcArc2->targetNode()) lcSerialS.push_back(lcNode);
    }
   }

   // Serial Fusion //
   lcAgain=(lcSerialS.size()>0);

   while (lcSerialS.size()>0) {
    lcNode=lcSerialS.back();
    lcSerialS.pop_back();
    lcArc1=(*lcNode->incomingArcs().begin()).second;
    lcArc2=(*lcNode->outgoingArcs().begin()).second;
    lcArc1->setTargetNode(lcArc2->targetNode());
    lcTree=new_object(cpTree(cpTreeData(nil,cpTreeData::serial)));
    lcTree->setLeft(lcTreeX[lcArc1->key()]);
    lcTree->setRight(lcTreeX[lcArc2->key()]);
    lcTreeX.erase(lcArc1->key());
    lcTreeX.erase(lcArc2->key());
    lcTreeX.insert(cpTreePair(lcArc1->key(),lcTree));
    lcArc2->setSourceNode(nil);
    lcArc2->setTargetNode(nil);
    lcDeleteS.push_back(lcArc2);
    delete_object(lcNode);

    lcNode=lcArc1->sourceNode();
    lcCurrentNeighbor=lcNode->outgoingArcs().begin();
    lcLastNeighbor=lcNode->outgoingArcs().end();

    while (lcCurrentNeighbor!=lcLastNeighbor) {
     lcArc1=(*lcCurrentNeighbor).second;

     if (lcArc1->mark()!=lcGraph.mark()) {
      lcArc1->mark()=lcGraph.mark();
      lcArcS.push_back(lcArc1);
     }

     ++lcCurrentNeighbor;
    }
   }

   while(lcDeleteS.size()>0) {
    lcArc1=lcDeleteS.back();
    lcDeleteS.pop_back();
    if (lcArc1->mark()==lcGraph.mark()) lcArc1->mark()=lcGraph.mark()-1;
    else delete_object(lcArc1);
   }

   // Parallel Composition Search //
   ++(lcGraph.mark());

   while (lcArcS.size()>0) {
    lcArc1=lcArcS.back();
    lcArcS.pop_back();

    if (lcArc1->mark()<lcGraph.mark()) {
     if (lcArc1->mark()==lcGraph.mark()-2) delete_object(lcArc1);
     else {
      lcCurrentNeighbor=lcArc1->sourceNode()->outgoingArcs().begin();
      lcLastNeighbor=lcArc1->sourceNode()->outgoingArcs().end();

      while (lcCurrentNeighbor!=lcLastNeighbor) {
       lcArc2=(*lcCurrentNeighbor).second;

       if (lcArc2->targetNode()==lcArc1->targetNode() and lcArc1!=lcArc2) {
        lcArc2->mark()=lcGraph.mark();
        lcParallelX.insert(cpParallelPair(lcArc1,lcArc2));
       }

       ++lcCurrentNeighbor;
      }
     }
    }
   }

   // Parallel Fusion //
   lcCurrentParallel=lcParallelX.begin();
   lcLastParallel=lcParallelX.end();
   lcAgain=(lcAgain or lcCurrentParallel!=lcLastParallel);

   while (lcCurrentParallel!=lcLastParallel) {
    lcArc1=(*lcCurrentParallel).first;
    lcArc2=(*lcCurrentParallel).second;
    lcTree=new_object(cpTree(cpTreeData(nil,cpTreeData::parallel)));
    lcTree->setLeft(lcTreeX[lcArc1->key()]);
    lcTree->setRight(lcTreeX[lcArc2->key()]);
    lcTreeX.erase(lcArc1->key());
    lcTreeX.erase(lcArc2->key());
    lcTreeX.insert(cpTreePair(lcArc1->key(),lcTree));
    delete_object(lcArc2);
    ++lcCurrentParallel;

    if (lcArc1->sourceNode()->mark()!=lcGraph.mark()) {
     lcArc1->sourceNode()->mark()=lcGraph.mark();
     lcNodeS.push_back(lcArc1->sourceNode());
    }

    if (lcArc1->targetNode()->mark()!=lcGraph.mark()) {
     lcArc1->targetNode()->mark()=lcGraph.mark();
     lcNodeS.push_back(lcArc1->targetNode());
    }
   }

   lcParallelX.erase(lcParallelX.begin(),lcParallelX.end());

   // Arc Deletion To Make Serial-Parallel Composition //
   if (not lcAgain) {
    lcCurrentArc=lcGraph.arcs().begin();
    lcLastArc=lcGraph.arcs().end();
    lcMinDepth=cardinalMax();
    lcMaxQuality=realMin();
    lcArc2=nil;

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

     lcQuality=private_area::sourceNodeQuality(*(lcArc1->sourceNode()))
               +private_area::targetNodeQuality(*(lcArc1->targetNode()));

     lcDepth=lcTreeX[lcArc1->key()]->size();

     if (lcMaxQuality<lcQuality-epsilon() or (lcMaxQuality>=lcQuality-epsilon()
         and lcMaxQuality<=lcQuality+epsilon() and lcMinDepth>lcDepth)) {
      lcMinDepth=lcDepth;
      lcMaxQuality=lcQuality;
      lcArc2=lcArc1;
     }

     ++lcCurrentArc;
    }

    if (lcArc2!=nil) {
     agTreeS.push_back(lcTreeX[lcArc2->key()]);
     lcNodeS.push_back(lcArc2->sourceNode());
     lcNodeS.push_back(lcArc2->targetNode());
     delete_object(lcArc2);
    }
   }
  }
  while (lcGraph.arcs().size()>0);
 }
}

// D e c o m p o s e A l g o I I  Implementation //-------------------------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clDecomposeAlgoII */ /* Decomposes a graph into serial-parallel components. */
 template <tdGraph> void clDecomposeAlgoII<tuGraph>::run(const clGraph<tuGraph> & agGraph,
                    std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) & agTreeS) const {
  typedef clArc<tuGraph>   cpArc;
  typedef clGraph<tuGraph> cpGraph;
  typedef clNode<tuGraph>  cpNode;

  typedef std_vector(cpNode *)          cpNodeS;
  typedef clSerialParallelData<tuGraph> cpTreeData;
  typedef clBinaryTree<cpTreeData>      cpTree;
  typedef std_map(tyArcKey,cpTree *)    cpTreeX;

  typedef typename cpGraph::cpArcX::const_iterator  cpArcIterator1;
  typedef typename cpNode::cpArcX::const_iterator   cpArcIterator2;
  typedef typename cpGraph::cpNodeX::const_iterator cpNodeIterator;
  typedef typename cpTreeX::value_type              cpTreePair;

  typedef std_pair(tyInteger,tyNodeKey)         cpNodeSignature;
  typedef std_multimap(cpNodeSignature,cpArc *) cpArcX;
  typedef typename cpArcX::value_type           cpArcPair;

  cpArc *         lcArc1;
  cpArc *         lcArc2;
  cpArcX          lcArcX;
  tyBoolean       lcBlocked;
  cpArcIterator2  lcCurrentArc2;
  cpArcIterator2  lcLastArc2;
  tyInteger       lcMark1;
  cpNode *        lcNode1;
  cpNode *        lcNode2;
  cpNodeSignature lcSignature1;
  cpNodeSignature lcSignature2;
  cpTree *        lcTree;
  cpTreeX         lcTreeX;

  cpGraph lcGraph(agGraph);

  tyCardinal     lcCounter     = 0;
  cpArcIterator1 lcCurrentArc1 = agGraph.arcs().begin();
  cpNodeIterator lcCurrentNode = lcGraph.nodes().begin();
  cpArcIterator1 lcLastArc1    = agGraph.arcs().end();
  cpNodeIterator lcLastNode    = lcGraph.nodes().end();
  tyMark         lcMark2       = ++(lcGraph.mark());
  cpNodeS *      lcNode1S      = new_object(cpNodeS());
  cpNodeS *      lcNode2S      = new_object(cpNodeS());

  agTreeS.erase(agTreeS.begin(),agTreeS.end());

  // Component List Initialization //
  while (lcCurrentArc1!=lcLastArc1) {
   lcArc1=(*lcCurrentArc1).second;
   lcTree=new_object(cpTree(cpTreeData(lcArc1,cpTreeData::none)));
   lcTreeX.insert(cpTreePair(lcArc1->key(),lcTree));
   ++lcCurrentArc1;
  }

  // Workspace Initialization //
  while (lcCurrentNode!=lcLastNode) {
   (*lcCurrentNode).second->work()=new_object(tyInteger);
   *static_cast<tyInteger *>((*lcCurrentNode).second->work())=0;
   ++lcCurrentNode;
  }

  // Trees Construction //
  findFirstNodes(lcGraph,*lcNode1S);

  while (lcCounter<lcNode1S->size()) {
   (*lcNode1S)[lcCounter]->mark()=lcMark2;
   ++lcCounter;
  }

  while (lcNode1S->size()>0) {
   lcBlocked=true;

   while (lcNode1S->size()>0) {
    lcNode1=lcNode1S->back();
    lcNode1S->pop_back();
    lcMark1=*static_cast<tyInteger *>(lcNode1->work());

    if (lcMark1!=tyInteger(lcNode1->incomingArcs().size())) lcNode2S->push_back(lcNode1);
    else {
     lcBlocked=false;

     // Incoming Arcs Sorting //
     lcCurrentArc2=lcNode1->incomingArcs().begin();
     lcLastArc2=lcNode1->incomingArcs().end();
     lcArcX.erase(lcArcX.begin(),lcArcX.end());

     while (lcCurrentArc2!=lcLastArc2) {
      lcArc1=(*lcCurrentArc2).second;
      lcNode2=lcArc1->sourceNode();
      lcMark1=*static_cast<tyInteger *>(lcNode2->work());
      lcArcX.insert(cpArcPair(cpNodeSignature(lcMark1,lcNode2->key()),lcArc1));
      ++lcCurrentArc2;
     }

     // Parallel Fusions //
     while (lcArcX.size()>1) {
      lcSignature1=(*(lcArcX.begin())).first;
      lcSignature2=(*(++(lcArcX.begin()))).first;
      lcArc1=(*(lcArcX.begin())).second;
      lcArc2=(*(++(lcArcX.begin()))).second;

      if (lcSignature1.first==lcSignature2.first and lcSignature1.second==lcSignature2.second) {
       lcNode2=lcArc1->sourceNode();
       private_area::parallelFusion(lcTreeX,*lcArc1,*lcArc2);
       lcArcX.erase(lcArcX.begin());

       if (lcNode2->incomingArcs().size()==1 and lcNode2->outgoingArcs().size()==1) {
        lcArcX.erase(lcArcX.begin());
        lcArc1=(*(lcNode2->incomingArcs().begin())).second;
        private_area::serialFusion(lcTreeX,*lcNode2);
        lcMark1=*static_cast<tyInteger *>(lcArc1->sourceNode()->work());
        lcArcX.insert(cpArcPair(cpNodeSignature(lcMark1,lcArc1->sourceNode()->key()),lcArc1));
       }
      }
      else {
       lcNode2=lcArc1->sourceNode();
       lcArcX.erase(lcArcX.begin());
       agTreeS.push_back(lcTreeX[lcArc1->key()]);
       delete_object(lcArc1);

       if (lcNode2->incomingArcs().size()==1 and lcNode2->outgoingArcs().size()==1)
        private_area::serialFusion(lcTreeX,*lcNode2);
      }
     }

     // Node Level //
     if (lcArcX.size()==1) {
      lcNode2=(*(lcArcX.begin())).second->sourceNode();
      *static_cast<tyInteger *>(lcNode1->work())=*static_cast<tyInteger *>(lcNode2->work())-1;
     }
     else if (lcArcX.size()==0) *static_cast<tyInteger *>(lcNode1->work())=-1;

     // Next Nodes //
     lcCurrentArc2=lcNode1->outgoingArcs().begin();
     lcLastArc2=lcNode1->outgoingArcs().end();

     while (lcCurrentArc2!=lcLastArc2) {
      lcArc1=(*lcCurrentArc2).second;
      lcNode2=lcArc1->targetNode();
      (*static_cast<tyInteger *>(lcNode2->work()))++;

      if (lcNode2->mark()!=lcMark2) {
       lcNode2->mark()=lcMark2;
       lcNode2S->push_back(lcNode2);
      }

      ++lcCurrentArc2;
     }

     // Serial Fusion //
     if (lcNode1->incomingArcs().size()==1 and lcNode1->outgoingArcs().size()==1)
      private_area::serialFusion(lcTreeX,*lcNode1);
    }
   }

   standard::swap(lcNode1S,lcNode2S);

   // Circuit Breaking //
   if (lcBlocked) {
    lcArc1=private_area::breakCircuit(*lcNode1S,lcMark2);
    agTreeS.push_back(lcTreeX[lcArc1->key()]);
    delete_object(lcArc1);
   }
  }

  lcCurrentArc1=lcGraph.arcs().begin();
  lcLastArc1=lcGraph.arcs().end();

  while (lcCurrentArc1!=lcLastArc1) {
   agTreeS.push_back(lcTreeX[(*lcCurrentArc1).second->key()]);
   ++lcCurrentArc1;
  }

  // Cleaning //
  delete_object(lcNode1S);
  delete_object(lcNode2S);
  deleteNodeWorkspace(lcGraph,tyInteger(0));
 }
}

// D e c o m p o s e A l g o I I I  Implementation //-----------------------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clDecomposeAlgoIII */ /* Decomposes a graph into serial-parallel components. */
 template <tdGraph> void clDecomposeAlgoIII<tuGraph>::run(const clGraph<tuGraph> & agGraph,
                    std_vector(clBinaryTree<clSerialParallelData<tuGraph> > *) & agTreeS) const {
  typedef clArc<tuGraph>   cpArc;
  typedef clGraph<tuGraph> cpGraph;
  typedef clNode<tuGraph>  cpNode;

  typedef std_vector(cpNode *)          cpNodeS;
  typedef clSerialParallelData<tuGraph> cpTreeData;
  typedef clBinaryTree<cpTreeData>      cpTree;
  typedef std_map(tyArcKey,cpTree *)    cpTreeX;

  typedef typename cpGraph::cpArcX::const_iterator  cpArcIterator1;
  typedef typename cpNode::cpArcX::const_iterator   cpArcIterator2;
  typedef typename cpGraph::cpNodeX::const_iterator cpNodeIterator;
  typedef typename cpTreeX::value_type              cpTreePair;

  typedef std_pair(tyInteger,tyNodeKey)         cpNodeSignature;
  typedef std_multimap(cpNodeSignature,cpArc *) cpArcX;
  typedef typename cpArcX::value_type           cpArcPair;
  typedef typename cpArcX::const_iterator       cpSignatureIterator;

  tyBoolean           lcAllNeedDeletion;
  cpArc *             lcArc1;
  cpArc *             lcArc2;
  cpArcX              lcArcX;
  tyBoolean           lcBlocked;
  cpArcIterator2      lcCurrentArc2;
  cpSignatureIterator lcCurrentSignature;
  cpArcIterator2      lcLastArc2;
  cpSignatureIterator lcLastSignature;
  tyInteger           lcMark1;
  cpNode *            lcNode1;
  cpNode *            lcNode2;
  cpNode *            lcNode3;
  tyBoolean           lcNodeNeedDeletion;
  cpNodeSignature     lcSignature1;
  cpNodeSignature     lcSignature2;
  tyBoolean           lcSignatureMatch;
  cpTree *            lcTree;
  cpTreeX             lcTreeX;

  cpGraph lcGraph(agGraph);

  tyBoolean      lcCanDelete   = false;
  tyCardinal     lcCounter     = 0;
  cpArcIterator1 lcCurrentArc1 = agGraph.arcs().begin();
  cpNodeIterator lcCurrentNode = lcGraph.nodes().begin();
  cpArcIterator1 lcLastArc1    = agGraph.arcs().end();
  cpNodeIterator lcLastNode    = lcGraph.nodes().end();
  tyMark         lcMark2       = ++(lcGraph.mark());
  cpNodeS *      lcNode1S      = new_object(cpNodeS());
  cpNodeS *      lcNode2S      = new_object(cpNodeS());

  agTreeS.erase(agTreeS.begin(),agTreeS.end());

  // Component List Initialization //
  while (lcCurrentArc1!=lcLastArc1) {
   lcArc1=(*lcCurrentArc1).second;
   lcTree=new_object(cpTree(cpTreeData(lcArc1,cpTreeData::none)));
   lcTreeX.insert(cpTreePair(lcArc1->key(),lcTree));
   ++lcCurrentArc1;
  }

  // Workspace Initialization //
  while (lcCurrentNode!=lcLastNode) {
   (*lcCurrentNode).second->work()=new_object(tyInteger);
   *static_cast<tyInteger *>((*lcCurrentNode).second->work())=0;
   ++lcCurrentNode;
  }

  // Trees Construction //
  findFirstNodes(lcGraph,*lcNode1S);

  while (lcCounter<lcNode1S->size()) {
   (*lcNode1S)[lcCounter]->mark()=lcMark2;
   ++lcCounter;
  }

  while (lcNode1S->size()>0) {
   lcAllNeedDeletion=false;
   lcBlocked=true;

   while (lcNode1S->size()>0) {
    lcNode1=lcNode1S->back();
    lcNode1S->pop_back();

    if (lcNode1!=nil) {
     lcMark1=*static_cast<tyInteger *>(lcNode1->work());

     if (lcMark1<tyInteger(lcNode1->incomingArcs().size())) lcNode2S->push_back(lcNode1);
     else {
      lcNodeNeedDeletion=false;
      lcBlocked=false;

      // Incoming Arcs Sorting //
      lcCurrentArc2=lcNode1->incomingArcs().begin();
      lcLastArc2=lcNode1->incomingArcs().end();
      lcArcX.erase(lcArcX.begin(),lcArcX.end());

      while (lcCurrentArc2!=lcLastArc2) {
       lcArc1=(*lcCurrentArc2).second;
       lcNode2=lcArc1->sourceNode();
       lcMark1=*static_cast<tyInteger *>(lcNode2->work());
       lcArcX.insert(cpArcPair(cpNodeSignature(lcMark1,lcNode2->key()),lcArc1));
       ++lcCurrentArc2;
      }

      // Parallel Fusions //
      while (lcArcX.size()>1) {
       lcSignature1=(*(lcArcX.begin())).first;
       lcSignature2=(*(++(lcArcX.begin()))).first;
       lcArc1=(*(lcArcX.begin())).second;
       lcArc2=(*(++(lcArcX.begin()))).second;

       if (lcSignature1.first==lcSignature2.first and lcSignature1.second==lcSignature2.second) {
        lcAllNeedDeletion=false;
        lcNode2=lcArc1->sourceNode();
        private_area::parallelFusion(lcTreeX,*lcArc1,*lcArc2);
        lcArcX.erase(lcArcX.begin());

        // Serial Fusion //
        if (lcNode2->incomingArcs().size()==1 and lcNode2->outgoingArcs().size()==1) {
         lcArcX.erase(lcArcX.begin());
         lcArc1=(*(lcNode2->incomingArcs().begin())).second;
         private_area::removeNode(*lcNode2S,lcNode2);
         private_area::removeNode(*lcNode1S,lcNode2);
         private_area::serialFusion(lcTreeX,*lcNode2);
         lcMark1=*static_cast<tyInteger *>(lcArc1->sourceNode()->work());
         lcArcX.insert(cpArcPair(cpNodeSignature(lcMark1,lcArc1->sourceNode()->key()),lcArc1));
        }
       }
       else {
        lcArcX.erase(lcArcX.begin());

        // Arc Deletion //
        if (lcCanDelete) {
         lcCanDelete=false;
         lcNode2=lcArc1->sourceNode();

         if (lcNode2->outgoingArcs().size()!=2) {
          agTreeS.push_back(lcTreeX[lcArc1->key()]);
          delete_object(lcArc1);
         }
         else {
          // Signature Matching Check //
          if (lcNode2->incomingArcs().size()==0) lcSignatureMatch=false;
          else {
           lcSignatureMatch=false;
           lcNode3=(*(lcNode2->incomingArcs().begin())).second->sourceNode();
           lcCurrentSignature=lcArcX.begin();
           lcLastSignature=lcArcX.end();

           while (lcCurrentSignature!=lcLastSignature and not lcSignatureMatch) {
            lcSignature1=(*lcCurrentSignature).first;
            lcSignatureMatch=(lcSignature1.second==lcNode3->key());
            ++lcCurrentSignature;
           }
          }

          // Current Arc Deletion //
          if (not lcSignatureMatch) {
           agTreeS.push_back(lcTreeX[lcArc1->key()]);
           delete_object(lcArc1);

           if (lcNode2->incomingArcs().size()==1 and lcNode2->outgoingArcs().size()==1) {
            private_area::removeNode(*lcNode2S,lcNode2);
            private_area::removeNode(*lcNode1S,lcNode2);
            private_area::serialFusion(lcTreeX,*lcNode2);
           }
          }

          // Neighbor Arc Deletion //
          else {
           lcArc2=(*(lcNode2->outgoingArcs().begin())).second;
           if (lcArc2==lcArc1) lcArc2=(*(++(lcNode2->outgoingArcs().begin()))).second;
           agTreeS.push_back(lcTreeX[lcArc2->key()]);
           delete_object(lcArc2);

           if (lcNode2->incomingArcs().size()==1 and lcNode2->outgoingArcs().size()==1) {
            private_area::removeNode(*lcNode2S,lcNode2);
            private_area::removeNode(*lcNode1S,lcNode2);
            lcArc1=(*(lcNode2->incomingArcs().begin())).second;
            private_area::serialFusion(lcTreeX,*lcNode2);
           }

           lcMark1=*static_cast<tyInteger *>(lcArc1->sourceNode()->work());
           lcArcX.insert(cpArcPair(cpNodeSignature(lcMark1,lcArc1->sourceNode()->key()),lcArc1));
          }
         }
        }
        else {
         lcAllNeedDeletion=true;
         lcNodeNeedDeletion=true;
        }
       }
      }

      if (lcNodeNeedDeletion) lcNode2S->push_back(lcNode1);
      else {
       // Node Level //
       if (lcArcX.size()==1) {
        lcNode2=(*(lcArcX.begin())).second->sourceNode();
        *static_cast<tyInteger *>(lcNode1->work())=*static_cast<tyInteger *>(lcNode2->work())-1;
       }
       else if (lcArcX.size()==0) *static_cast<tyInteger *>(lcNode1->work())=-1;

       // Next Nodes //
       lcCurrentArc2=lcNode1->outgoingArcs().begin();
       lcLastArc2=lcNode1->outgoingArcs().end();

       while (lcCurrentArc2!=lcLastArc2) {
        lcArc1=(*lcCurrentArc2).second;
        lcNode2=lcArc1->targetNode();
        (*static_cast<tyInteger *>(lcNode2->work()))++;

        if (lcNode2->mark()!=lcMark2) {
         lcNode2->mark()=lcMark2;
         lcNode2S->push_back(lcNode2);
        }

        ++lcCurrentArc2;
       }

       // Serial Fusion //
       if (lcNode1->incomingArcs().size()==1 and lcNode1->outgoingArcs().size()==1) {
        private_area::removeNode(*lcNode2S,lcNode1);
        private_area::removeNode(*lcNode1S,lcNode1);
        private_area::serialFusion(lcTreeX,*lcNode1);
       }
      }
     }
    }
   }

   standard::swap(lcNode1S,lcNode2S);

   if (lcAllNeedDeletion) lcCanDelete=true;

   // Circuit Breaking //
   if (lcBlocked) {
    lcArc1=private_area::breakCircuit(*lcNode1S,lcMark2);
    agTreeS.push_back(lcTreeX[lcArc1->key()]);
    delete_object(lcArc1);
   }
  }

  lcCurrentArc1=lcGraph.arcs().begin();
  lcLastArc1=lcGraph.arcs().end();

  while (lcCurrentArc1!=lcLastArc1) {
   agTreeS.push_back(lcTreeX[(*lcCurrentArc1).second->key()]);
   ++lcCurrentArc1;
  }

  // Cleaning //
  delete_object(lcNode1S);
  delete_object(lcNode2S);
  deleteNodeWorkspace(lcGraph,tyInteger(0));
 }
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef public_area
#undef private_area
#undef tdGraph
#undef tuGraph
#endif
 
//==================================================================================================
// G r a p h _ p r o b l e m                                                         Implementation
// S e r i a l _ p a r a l l e l
//                                                                                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/serial_parallel.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define GRAPH_PROBLEM_DLL

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

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemSerialParallel
#define private_area graphProblemSerialParallel_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Graph_problem/Serial_parallel");

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

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 static_error erArcGraphAssociationProblem;
 static_error erNotSerialParallel;
 static_error erSplitNotFound;
}

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

static_constant(tcString,goParallelFlag);
static_constant(tcString,goSerialFlag);

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

    erArcGraphAssociationProblem.create("Serial Parallel - Can't associate the arc with the graph.");
    erNotSerialParallel.create("Serial Parallel - The graph isn't serial-parallel.");
    erSplitNotFound.create("Serial Parallel - Split of the tree not found.");

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

    goParallelFlag = "//";
    goSerialFlag   = "+";
   }

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

   delete_object(goDataLocation);
  }

  initializer_catch;
 }
}

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