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