]> SALOME platform Git repositories - modules/yacs.git/blob - src/engine/Bloc.cxx
Salome HOME
Documentation update
[modules/yacs.git] / src / engine / Bloc.cxx
1 // Copyright (C) 2006-2015  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "Bloc.hxx"
21 #include "LinkInfo.hxx"
22 #include "InputPort.hxx"
23 #include "InputDataStreamPort.hxx"
24 #include "OutputPort.hxx"
25 #include "OutputDataStreamPort.hxx"
26 #include "ElementaryNode.hxx"
27 #include "Visitor.hxx"
28
29 #include <iostream>
30 #include <numeric>
31
32 //#define _DEVDEBUG_
33 #include "YacsTrace.hxx"
34
35 using namespace YACS::ENGINE;
36 using namespace std;
37
38 /*! \class YACS::ENGINE::Bloc
39  *  \brief Composed node to group elementary and composed nodes
40  *
41  * \ingroup Nodes
42  */
43
44 Bloc::Bloc(const Bloc& other, ComposedNode *father, bool editionOnly):StaticDefinedComposedNode(other,father),_fwLinks(0),_bwLinks(0)
45 {
46   for(list<Node *>::const_iterator iter=other._setOfNode.begin();iter!=other._setOfNode.end();iter++)
47     _setOfNode.push_back((*iter)->simpleClone(this,editionOnly));
48
49   //CF Linking
50   vector< pair<OutGate *, InGate *> > cfLinksToReproduce=other.getSetOfInternalCFLinks();
51   vector< pair<OutGate *, InGate *> >::iterator iter1=cfLinksToReproduce.begin();
52   for(;iter1!=cfLinksToReproduce.end();iter1++)
53     edAddCFLink(getChildByName(other.getChildName((*iter1).first->getNode())),getChildByName(other.getChildName((*iter1).second->getNode())));
54
55   //Data + DataStream linking
56   vector< pair<OutPort *, InPort *> > linksToReproduce=other.getSetOfInternalLinks();
57   vector< pair<OutPort *, InPort *> >::iterator iter2=linksToReproduce.begin();
58   for(;iter2!=linksToReproduce.end();iter2++)
59     {
60       OutPort* pout = iter2->first;
61       InPort* pin = iter2->second;
62       if(&other == getLowestCommonAncestor(pout->getNode(), pin->getNode()))
63       {
64         edAddLink(getOutPort(other.getPortName(pout)),getInPort(other.getPortName(pin)));
65       }
66     }
67 }
68
69 //! Create a Bloc node with a given name
70 /*!
71  *   \param name : the given name
72  */
73 Bloc::Bloc(const std::string& name):StaticDefinedComposedNode(name),_fwLinks(0),_bwLinks(0)
74 {
75 }
76
77 Bloc::~Bloc()
78 {
79   for(list<Node *>::iterator iter=_setOfNode.begin();iter!=_setOfNode.end();iter++)
80     delete *iter;
81   delete _fwLinks;
82   delete _bwLinks;
83 }
84
85 //! Initialize the bloc
86 /*!
87  * \param start : a boolean flag indicating the kind of initialization
88  * If start is true, it's a complete initialization with reinitialization of port values
89  * If start is false, there is no initialization of port values
90  */
91 void Bloc::init(bool start)
92 {
93   Node::init(start);
94   for(list<Node *>::iterator iter=_setOfNode.begin();iter!=_setOfNode.end();iter++)
95     (*iter)->init(start);
96 }
97
98 //! Indicate if the bloc execution is finished
99 /*!
100  * The execution bloc is finished if all its child nodes
101  * are finished with or without error or if it is disabled (not to execute)
102  */
103 bool Bloc::isFinished()
104 {
105     if(_state==YACS::DONE)return true;
106     if(_state==YACS::ERROR)return true;
107     if(_state==YACS::FAILED)return true;
108     if(_state==YACS::DISABLED)return true;
109     return false;
110 }
111
112 int Bloc::getNumberOfCFLinks() const
113 {
114   int ret=0;
115   for(list<Node *>::const_iterator iter=_setOfNode.begin();iter!=_setOfNode.end();iter++)
116     ret+=(*iter)->getOutGate()->getNbOfInGatesConnected();
117   return ret;
118 }
119
120 Node *Bloc::simpleClone(ComposedNode *father, bool editionOnly) const
121 {
122   return new Bloc(*this,father,editionOnly);
123 }
124
125 //! Collect all nodes that are ready to execute
126 /*!
127  * \param tasks : vector of tasks to collect ready nodes
128  */
129 void Bloc::getReadyTasks(std::vector<Task *>& tasks)
130 {
131   /*
132    * ComposedNode state goes to ACTIVATED when one of its child has been ACTIVATED
133    * To change this uncomment the following line
134    * Then the father node will go to ACTIVATED state before its child node
135    */
136   if(_state==YACS::TOACTIVATE ) setState(YACS::ACTIVATED);
137   if(_state==YACS::TOACTIVATE || _state==YACS::ACTIVATED)
138     for(list<Node *>::iterator iter=_setOfNode.begin();iter!=_setOfNode.end();iter++)
139       (*iter)->getReadyTasks(tasks);
140 }
141
142 //! Update the bloc state
143 /*!
144  * Update the '_state' attribute.
145  * Typically called by 'this->_inGate' when 'this->_inGate' is ready. 
146  * Contrary to Node::exUpdateState no check done on inputs
147  * because internal linked DF inputports are not valid yet.
148  */
149 void Bloc::exUpdateState()
150 {
151   if(_state == YACS::DISABLED)return;
152   if(_state == YACS::DONE)return;
153   if(_inGate.exIsReady())
154     {
155       setState(YACS::ACTIVATED);
156       for(list<Node *>::iterator iter=_setOfNode.begin();iter!=_setOfNode.end();iter++)
157         if((*iter)->exIsControlReady())
158           (*iter)->exUpdateState();
159     }
160 }
161
162 //! Add a child node to the bloc
163 /*!
164  * \param node: the node to add to the bloc
165  * \return a boolean flag indicating if the node has been added
166  *
167  * If node is already a direct child of current bloc, do nothing.
168  * If node is a child of another bloc, throw exception.
169  * If node name already used in bloc, throw exception.
170  * Publish inputPorts in current bloc and ancestors.
171  */
172 bool Bloc::edAddChild(Node *node) throw(YACS::Exception)
173 {
174   if(isNodeAlreadyAggregated(node))
175     {
176       if(node->_father==this)
177         return false;
178       else
179         {
180           string what = "Bloc::edAddChild : node "; what += node->getName();
181           what += " is already grand children of node";
182           throw Exception(what);
183         }
184     }
185
186   if(node->_father)
187     {
188       string what = "Bloc::edAddChild: node is not orphan: "; what += node->getName();
189       throw Exception(what);
190     }
191   
192   checkNoCrossHierachyWith(node);
193
194   if(isNameAlreadyUsed(node->getName()))
195     {
196       string what("Bloc::edAddChild : name "); what+=node->getName(); 
197       what+=" already exists in the scope of "; what+=_name;
198       throw Exception(what);
199     }
200   
201   node->_father=this;
202   _setOfNode.push_back(node);
203   //should we also set _modified flag for node ??
204   ComposedNode *iter=node->_father;
205   //set the _modified flag so that latter on edUpdateState (eventually called by isValid) refresh state
206   //better call it at end
207   modified();
208   return true;
209 }
210
211 /**
212  * Remove 'node' from the set of direct children.
213  * @exception If 'node' is NOT the son of 'this'.
214  */
215
216 void Bloc::edRemoveChild(Node *node) throw(YACS::Exception)
217 {
218   StaticDefinedComposedNode::edRemoveChild(node);
219   list<Node *>::iterator iter=find(_setOfNode.begin(),_setOfNode.end(),node);
220   if(iter!=_setOfNode.end())
221     {
222       _setOfNode.erase(iter);
223       modified();
224     }
225 }
226
227 Node *Bloc::getChildByShortName(const std::string& name) const throw(YACS::Exception)
228 {
229   for (list<Node *>::const_iterator iter = _setOfNode.begin(); iter != _setOfNode.end(); iter++)
230     if ((*iter)->getName() == name)
231       return (*iter);
232   string what("node "); what+= name ; what+=" is not a child of Bloc "; what += getName();
233   throw Exception(what);
234 }
235
236 bool Bloc::areAllSubNodesDone() const
237 {
238   for(list<Node *>::const_iterator iter=_setOfNode.begin();iter!=_setOfNode.end();iter++)
239     {
240       if((*iter)->_state == YACS::DONE)continue;
241       if((*iter)->_state == YACS::DISABLED)continue;
242       return false;
243     }
244   return true;
245 }
246
247 bool Bloc::areAllSubNodesFinished() const
248 {
249   for(list<Node *>::const_iterator iter=_setOfNode.begin();iter!=_setOfNode.end();iter++)
250     {
251       if((*iter)->_state == YACS::DONE)continue;
252       if((*iter)->_state == YACS::FAILED)continue;
253       if((*iter)->_state == YACS::DISABLED)continue;
254       if((*iter)->_state == YACS::ERROR)continue;
255       if((*iter)->_state == YACS::INTERNALERR)continue;
256       return false;
257     }
258   return true;
259 }
260
261 bool Bloc::isNameAlreadyUsed(const std::string& name) const
262 {
263   for(list<Node *>::const_iterator iter=_setOfNode.begin();iter!=_setOfNode.end();iter++)
264     if((*iter)->getName()==name)
265       return true;
266   return false;
267 }
268
269 bool insertNodeChildrenInSet(Node *node, std::set<Node *>& nodeSet)
270 {
271   bool verdict=true;
272   set<Node *> outNodes=node->getOutNodes();
273   for (set<Node *>::iterator iter=outNodes.begin();iter!=outNodes.end(); iter++)
274     {
275       verdict=(nodeSet.insert(*iter)).second;
276       if (verdict) verdict = insertNodeChildrenInSet((*iter),nodeSet);
277     }
278   return verdict;
279 }
280
281 /*!
282  * \note  Checks that in the forest from 'node' there are NO back-edges.
283  *        \b WARNING : When using this method 'node' has to be checked in order to be part of direct children of 'this'. 
284  *
285  */
286 void Bloc::checkNoCyclePassingThrough(Node *node) throw(YACS::Exception)
287 {
288   set<Node *> currentNodesToTest;
289   //don't insert node to test in set. 
290   //If it is present after insertion of connected nodes we have a loop
291   //collect all connected nodes
292   insertNodeChildrenInSet(node,currentNodesToTest);
293   //try to insert node
294   if(!(currentNodesToTest.insert(node)).second)
295     throw Exception("Cycle has been detected",1);
296 }
297
298 std::vector< std::pair<OutGate *, InGate *> > Bloc::getSetOfInternalCFLinks() const
299 {
300   vector< pair<OutGate *, InGate *> > ret;
301   for(list<Node *>::const_iterator iter=_setOfNode.begin();iter!=_setOfNode.end();iter++)
302     {
303       set<InGate *> outCFLinksOfCurNode=(*iter)->_outGate.edSetInGate();
304       for(set<InGate *>::iterator iter2=outCFLinksOfCurNode.begin();iter2!=outCFLinksOfCurNode.end();iter2++)
305         ret.push_back(pair<OutGate *, InGate *>(&(*iter)->_outGate,*iter2));
306     }
307   return ret;
308 }
309
310 /*!
311  *
312  * @note : Runtime called method. Indirectly called by StaticDefinedComposedNode::updateStateFrom which has dispatch to this method
313  *          'when event == FINISH'.
314  *          WARNING Precondition : '_state == Running' and 'node->_father==this'(garanteed by StaticDefinedComposedNode::notifyFrom)
315  *
316  * Calls the node's outgate OutGate::exNotifyDone if all nodes are not finished
317  */
318 YACS::Event Bloc::updateStateOnFinishedEventFrom(Node *node)
319 {
320   DEBTRACE("Bloc::updateStateOnFinishedEventFrom: " << node->getName());
321   //ASSERT(node->_father==this)
322   if(areAllSubNodesFinished())
323     {
324       setState(YACS::DONE);
325       if(!areAllSubNodesDone())
326         {
327           setState(YACS::FAILED);
328           return YACS::ABORT;
329         }
330       return YACS::FINISH;//notify to father node that 'this' has becomed finished.
331     }
332   //more job to do in 'this' bloc
333   //Conversion exceptions can be thrown so catch them to control errors
334   try
335     {
336       //notify the finished node to propagate to its following nodes
337       node->exForwardFinished();
338     }
339   catch(YACS::Exception& ex)
340     {
341       //The node has failed to propagate. It must be put in error
342       DEBTRACE("Bloc::updateStateOnFinishedEventFrom: " << ex.what());
343       // notify the node it has failed
344       node->exForwardFailed();
345       setState(YACS::FAILED);
346       return YACS::ABORT;
347     }
348   return YACS::NOEVENT;//no notification to father needed because from father point of view nothing happened.
349 }
350
351 //! Notify this bloc that a node has failed
352 /*!
353  * \param node : node that has emitted the event
354  * \return the event to notify to bloc's father
355  */
356 YACS::Event Bloc::updateStateOnFailedEventFrom(Node *node, const Executor *execInst)
357 {
358   node->exForwardFailed();
359   if(areAllSubNodesFinished())
360     {
361       setState(YACS::DONE);
362       if(!areAllSubNodesDone()){
363           setState(YACS::FAILED);
364           return YACS::ABORT;
365       }
366       return YACS::FINISH;//notify to father node that 'this' has becomed finished.
367     }
368   return YACS::NOEVENT;
369 }
370
371 void Bloc::writeDot(std::ostream &os) const
372 {
373     os << "  subgraph cluster_" << getId() << "  {\n" ;
374     list<Node *>nodes=getChildren();
375     for(list<Node *>::const_iterator iter=nodes.begin();iter!=nodes.end();iter++)
376     {
377         (*iter)->writeDot(os);
378         string p=(*iter)->getId();
379         //not connected node
380         if((*iter)->_inGate._backLinks.size() == 0) os << getId() << " -> " << p << ";\n";
381         set<Node *>outnodes = (*iter)->getOutNodes();
382         for(set<Node *>::const_iterator itout=outnodes.begin();itout!=outnodes.end();itout++)
383         {
384             os << p << " -> " << (*itout)->getId() << ";\n";
385         }
386     }
387     os << "}\n" ;
388     os << getId() << "[fillcolor=\"" ;
389     YACS::StatesForNode state=getEffectiveState();
390     os << getColorState(state);
391     os << "\" label=\"" << "Bloc:" ;
392     os << getQualifiedName() <<"\"];\n";
393 }
394
395 void Bloc::accept(Visitor* visitor)
396 {
397   visitor->visitBloc(this);
398 }
399
400 /*!
401  * Returns the max level of parallelism is this. The max of parallelism is equal to the sum of the max parallelism level
402  * for all concurrent branches in \a this.
403  */
404 int Bloc::getMaxLevelOfParallelism() const
405 {
406   std::set<Node *> s(_setOfNode.begin(),_setOfNode.end());
407   for(std::set<Node *>::const_iterator it=s.begin();it!=s.end();it++)
408     (*it)->_colour=White;
409   std::vector<int> levs;
410   while(!s.empty())
411     {
412       Node *seed(*(s.begin()));
413       int myCurLev(0);
414       while(seed)
415         {
416           s.erase(seed);
417           std::set<InGate *> ingates(seed->getOutGate()->edSetInGate());
418           int myCurLev2(seed->getMaxLevelOfParallelism());
419           for(std::set<InGate *>::const_iterator it=ingates.begin();it!=ingates.end();it++)
420             {
421               Node *curNode((*it)->getNode());
422               curNode->_colour=Grey;
423               myCurLev2=std::max(curNode->getMaxLevelOfParallelism(),myCurLev2);
424             }
425           myCurLev=std::max(myCurLev,myCurLev2);
426           seed=0;
427           for(std::set<Node *>::const_iterator it=s.begin();it!=s.end();it++)
428             if((*it)->_colour==Grey)
429               {
430                 seed=*it;
431                 break;
432               }
433         }
434       levs.push_back(myCurLev);
435     }
436   return std::accumulate(levs.begin(),levs.end(),0);
437 }
438
439 /*!
440  * Updates mutable structures _fwLinks and _bwLinks with the result of computation (CPU consuming method).
441  * _fwLinks is a map with a Node* as key and a set<Node*> as value. The set gives
442  * all nodes that are forwardly connected to the key node 
443  * _bwLinks is a map for backward dependencies
444  * The method is : for all CF link (n1->n2) 
445  * add n2 and _fwLinks[n2] in forward dependencies of n1 and _bwLinks[n1]
446  * add n1 and _bwLinks[n1] in backward dependencies of n2 and _fwLinks[n2]
447  * For useless links
448  * If a node is already in a forward dependency when adding and the direct link
449  * already exists so it's a useless link (see the code !)
450  */
451 void Bloc::performCFComputations(LinkInfo& info) const
452 {
453   StaticDefinedComposedNode::performCFComputations(info);
454   delete _fwLinks;//Normally useless
455   delete _bwLinks;//Normally useless
456   _fwLinks=new map<Node *,set<Node *> >;
457   _bwLinks=new map<Node *,set<Node *> >;
458
459   //a set to store all CF links : used to find fastly if two nodes are connected
460   std::set< std::pair< Node*, Node* > > links;
461
462   for(list<Node *>::const_iterator iter=_setOfNode.begin();iter!=_setOfNode.end();iter++)
463     {
464       Node* n1=*iter;
465       std::set<InGate *> ingates=n1->getOutGate()->edSetInGate();
466       for(std::set<InGate *>::const_iterator it2=ingates.begin();it2!=ingates.end();it2++)
467         {
468           //CF link : n1 -> (*it2)->getNode()
469           Node* n2=(*it2)->getNode();
470           links.insert(std::pair< Node*, Node* >(n1,n2));
471           std::set<Node *> bwn1=(*_bwLinks)[n1];
472           std::set<Node *> fwn1=(*_fwLinks)[n1];
473           std::set<Node *> fwn2=(*_fwLinks)[n2];
474           std::set<Node *> bwn2=(*_bwLinks)[n2];
475           std::pair<std::set<Node*>::iterator,bool> ret;
476           for(std::set<Node *>::const_iterator iter2=bwn1.begin();iter2!=bwn1.end();iter2++)
477             {
478               for(std::set<Node *>::const_iterator it3=fwn2.begin();it3!=fwn2.end();it3++)
479                 {
480                   ret=(*_fwLinks)[*iter2].insert(*it3);
481                   if(ret.second==false)
482                     {
483                       //dependency already exists (*iter2) -> (*it3) : if a direct link exists it's a useless one
484                       if(links.find(std::pair< Node*, Node* >(*iter2,*it3)) != links.end())
485                         info.pushUselessCFLink(*iter2,*it3);
486                     }
487                 }
488               ret=(*_fwLinks)[*iter2].insert(n2);
489               if(ret.second==false)
490                 {
491                   //dependency already exists (*iter2) -> n2 : if a direct link exists it's a useless one
492                   if(links.find(std::pair< Node*, Node* >(*iter2,n2)) != links.end())
493                     info.pushUselessCFLink(*iter2,n2);
494                 }
495             }
496           for(std::set<Node *>::const_iterator it3=fwn2.begin();it3!=fwn2.end();it3++)
497             {
498               ret=(*_fwLinks)[n1].insert(*it3);
499               if(ret.second==false)
500                 {
501                   //dependency already exists n1 -> *it3 : if a direct link exists it's a useless one
502                   if(links.find(std::pair< Node*, Node* >(n1,*it3)) != links.end())
503                     info.pushUselessCFLink(n1,*it3);
504                 }
505             }
506           ret=(*_fwLinks)[n1].insert(n2);
507           if(ret.second==false)
508             {
509               //dependency already exists n1 -> n2 : it's a useless link
510               info.pushUselessCFLink(n1,n2);
511             }
512
513           for(std::set<Node *>::const_iterator iter2=fwn2.begin();iter2!=fwn2.end();iter2++)
514             {
515               (*_bwLinks)[*iter2].insert(bwn1.begin(),bwn1.end());
516               (*_bwLinks)[*iter2].insert(n1);
517             }
518           (*_bwLinks)[n2].insert(bwn1.begin(),bwn1.end());
519           (*_bwLinks)[n2].insert(n1);
520         }
521     }
522 }
523
524 void Bloc::destructCFComputations(LinkInfo& info) const
525 {
526   StaticDefinedComposedNode::destructCFComputations(info);
527   delete _fwLinks; _fwLinks=0;
528   delete _bwLinks; _bwLinks=0;
529 }
530
531 /*!
532  * \b WARNING \b Needs call of performCFComputations before beeing called.
533  *  Perform updates of containers regarding attributes of link 'start' -> 'end' and check the correct linking.
534  *  The output is in info struct.
535  *
536  * \param start : start port
537  * \param end : end port
538  * \param cross : 
539  * \param fw out parameter being append if start -> end link is a forward link \b without cross type DF/DS.
540  * \param fwCross out parameter being append if start -> end link is a forward link \b with cross type DF/DS.
541  * \param bw out parameter being append if start -> end link is a backward link.
542  * \param info out parameter being informed about eventual errors.
543  */
544 void Bloc::checkControlDependancy(OutPort *start, InPort *end, bool cross,
545                                   std::map < ComposedNode *,  std::list < OutPort * >, SortHierarc >& fw,
546                                   std::vector<OutPort *>& fwCross,
547                                   std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw,
548                                   LinkInfo& info) const
549 {
550   if(!cross)
551     {
552       Node *startN=isInMyDescendance(start->getNode());
553       Node *endN=isInMyDescendance(end->getNode());
554       if(startN==endN)
555         bw[(ComposedNode *)this].push_back(start);
556       else if(areLinked(startN,endN,true))
557         fw[(ComposedNode *)this].push_back(start);
558       else
559         if(areLinked(startN,endN,false))
560           bw[(ComposedNode *)this].push_back(start);
561         else
562           info.pushErrLink(start,end,E_UNPREDICTABLE_FED);
563     }
564   else//DFDS detected
565     if(arePossiblyRunnableAtSameTime(isInMyDescendance(start->getNode()),isInMyDescendance(end->getNode())))
566       fwCross.push_back(start);
567     else
568       info.pushErrLink(start,end,E_DS_LINK_UNESTABLISHABLE);
569 }
570
571 //! Check if two nodes are linked
572 /*!
573  * 'start' and 'end' \b must be direct son of 'this'.
574  * Typically used for data link.
575  * \param start : start node
576  * \param end : end node
577  * \param fw indicates if it is a forward link searched (true : default value) or a backward link serach.
578  * \return if true or false
579  */
580 bool Bloc::areLinked(Node *start, Node *end, bool fw) const
581 {
582   set<Node *>& nexts=fw ? (*_fwLinks)[start] : (*_bwLinks)[start];
583   return nexts.find(end)!=nexts.end();
584 }
585
586 //! Check if two nodes can run in parallel
587 /*!
588  * Typically used for stream link.
589  * 'start' and 'end' \b must be direct son of 'this'.
590  * \param start : start node
591  * \param end : end node
592  * \return true or false
593  */
594 bool Bloc::arePossiblyRunnableAtSameTime(Node *start, Node *end) const
595 {
596   set<Node *>& nexts=(*_fwLinks)[start];
597   set<Node *>& preds=(*_bwLinks)[start];
598   return nexts.find(end)==nexts.end() && preds.find(end)==preds.end();
599 }
600
601 //! Check control flow links
602 /*!
603  * \param starts If different of 0, must aggregate at leat \b 1 element.
604  * \param end : end port
605  * \param alreadyFed in/out parameter. Indicates if 'end' ports is already and surely set or fed by an another port.
606  * \param direction If true : forward direction else backward direction.
607  * \param info : collected information
608  */
609 void Bloc::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
610 {
611   if(alreadyFed==FREE_ST || alreadyFed==FED_ST)
612     {
613       map<Node *,list <OutPort *> > classPerNodes;
614       for(list< OutPort *>::const_iterator iter1=starts.begin();iter1!=starts.end();iter1++)
615         classPerNodes[isInMyDescendance((*iter1)->getNode())].push_back(*iter1);
616       set<Node *> allNodes;
617       for(map<Node *,list <OutPort *> >::iterator iter2=classPerNodes.begin();iter2!=classPerNodes.end();iter2++)
618         allNodes.insert((*iter2).first);
619       vector<Node *> okAndUseless1,useless2;
620       seekOkAndUseless1(okAndUseless1,allNodes);
621       seekUseless2(useless2,allNodes);//after this point allNodes contains collapses
622       verdictForOkAndUseless1(classPerNodes,end,okAndUseless1,alreadyFed,direction,info);
623       verdictForCollapses(classPerNodes,end,allNodes,alreadyFed,direction,info);
624       verdictForOkAndUseless1(classPerNodes,end,useless2,alreadyFed,direction,info);
625     }
626   else if(alreadyFed==FED_DS_ST)
627     for(list< OutPort *>::const_iterator iter1=starts.begin();iter1!=starts.end();iter1++)
628       info.pushErrLink(*iter1,end,E_COLLAPSE_DFDS);
629 }
630
631 void Bloc::initComputation() const
632 {
633   for(list<Node *>::const_iterator iter=_setOfNode.begin();iter!=_setOfNode.end();iter++)
634     {
635       (*iter)->_colour=White;
636       (*iter)->getInGate()->exReset();
637       (*iter)->getOutGate()->exReset();
638     }
639 }
640
641 /*!
642  * Part of final step for CF graph anylizing. This is the part of non collapse nodes. 
643  * \param pool :
644  * \param end :
645  * \param candidates :
646  * \param alreadyFed in/out parameter. Indicates if 'end' ports is already and surely set or fed by an another port.
647  * \param direction
648  * \param info : collected information
649  */
650 void Bloc::verdictForOkAndUseless1(const std::map<Node *,std::list <OutPort *> >& pool, InputPort *end, 
651                                    const std::vector<Node *>& candidates, unsigned char& alreadyFed, 
652                                    bool direction, LinkInfo& info)
653 {
654   for(vector<Node *>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
655     {
656       const list<OutPort *>& mySet=(*pool.find(*iter)).second;
657       if(mySet.size()==1)
658         {
659           if(alreadyFed==FREE_ST)
660             {
661               alreadyFed=FED_ST;//This the final choice. General case !
662               if(!direction)
663                 info.pushInfoLink(*(mySet.begin()),end,I_BACK);
664             }
665           else if(alreadyFed==FED_ST)
666               info.pushInfoLink(*(mySet.begin()),end,direction ? I_USELESS : I_BACK_USELESS);//Second or more turn in case of alreadyFed==FREE_ST before call of this method
667         }
668       else
669         {
670           if(dynamic_cast<ElementaryNode *>(*iter))
671             {
672               WarnReason reason;
673               if(alreadyFed==FREE_ST)
674                 reason=direction ? W_COLLAPSE_EL : W_BACK_COLLAPSE_EL;
675               else if(alreadyFed==FED_ST)
676                 reason=direction ? W_COLLAPSE_EL_AND_USELESS : W_BACK_COLLAPSE_EL_AND_USELESS;
677               for(list<OutPort *>::const_iterator iter2=mySet.begin();iter2!=mySet.end();iter2++)    
678                 info.pushWarnLink(*iter2,end,reason);
679             }
680           else
681             ((ComposedNode *)(*iter))->checkCFLinks(mySet,end,alreadyFed,direction,info);//Thanks to recursive model!
682         }
683     }
684 }
685
686 /*!
687  * Part of final step for CF graph anylizing. This is the part of collapses nodes. 
688  * \param pool :
689  * \param end :
690  * \param candidates :
691  * \param alreadyFed in/out parameter. Indicates if 'end' ports is already and surely set or fed by an another port.
692  * \param direction
693  * \param info : collected information
694  */
695 void Bloc::verdictForCollapses(const std::map<Node *,std::list <OutPort *> >& pool, InputPort *end, 
696                                const std::set<Node *>& candidates, unsigned char& alreadyFed, 
697                                bool direction, LinkInfo& info)
698 {
699   info.startCollapseTransac();
700   for(set<Node *>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
701     {
702       const list<OutPort *>& mySet=(*pool.find(*iter)).second;
703       if(mySet.size()==1)
704         {
705           if(alreadyFed==FREE_ST)
706             info.pushWarnLink(*(mySet.begin()),end,direction ? W_COLLAPSE : W_BACK_COLLAPSE);
707           else if(alreadyFed==FED_ST)
708             info.pushWarnLink(*(mySet.begin()),end,direction ? W_COLLAPSE_AND_USELESS : W_BACK_COLLAPSE_EL_AND_USELESS);
709         }
710       else
711         {
712           if(dynamic_cast<ElementaryNode *>(*iter))
713             {
714               WarnReason reason;
715               if(alreadyFed==FREE_ST)
716                 reason=direction ? W_COLLAPSE_EL : W_BACK_COLLAPSE_EL;
717               else if(alreadyFed==FED_ST)
718                 reason=direction ? W_COLLAPSE_EL_AND_USELESS : W_BACK_COLLAPSE_EL_AND_USELESS;
719               for(list<OutPort *>::const_iterator iter2=mySet.begin();iter2!=mySet.end();iter2++)    
720                 info.pushWarnLink(*iter2,end,reason);
721             }
722           else
723             {
724               ((ComposedNode *)(*iter))->checkCFLinks(mySet,end,alreadyFed,direction,info);//Thanks to recursive model!
725               WarnReason reason;
726               if(alreadyFed==FREE_ST)
727                 reason=direction ? W_COLLAPSE : W_BACK_COLLAPSE;
728               else if(alreadyFed==FED_ST)
729                 reason=direction ? W_COLLAPSE_AND_USELESS : W_BACK_COLLAPSE_AND_USELESS;
730               for(list<OutPort *>::const_iterator iter2=mySet.begin();iter2!=mySet.end();iter2++)    
731                 info.pushWarnLink(*iter2,end,reason);
732             }
733         }
734     }
735   if(!candidates.empty())
736     if(alreadyFed==FREE_ST)
737       alreadyFed=FED_ST;
738   info.endCollapseTransac();
739 }
740
741 /*!
742  * \b WARNING use this method only after having called Bloc::performCFComputations method.
743  * \param okAndUseless1 out param contains at the end, the nodes without any collapse.
744  * \param allNodes in/out param. At the end, all the nodes in 'okAndUseless1' are deleted from 'allNodes'.
745  */
746 void Bloc::seekOkAndUseless1(std::vector<Node *>& okAndUseless1, std::set<Node *>& allNodes) const
747 {
748   set<Node *>::iterator iter=allNodes.begin();
749   while(iter!=allNodes.end())
750     {
751       set<Node *>& whereToFind=(*_bwLinks)[*iter];
752       std::set<Node *>::iterator iter2;
753       for(iter2=allNodes.begin();iter2!=allNodes.end();iter2++)
754         if((*iter)!=(*iter2))
755           if(whereToFind.find(*iter2)==whereToFind.end())
756             break;
757       if(iter2!=allNodes.end())
758         iter++;
759       else
760         {
761           okAndUseless1.push_back((*iter));
762           allNodes.erase(iter);
763           iter=allNodes.begin();
764         }
765     }
766 }
767
768 /*!
769  * \b WARNING use this method only after having called Bloc::performCFComputations method.
770  * For params see Bloc::seekOkAndUseless1.
771  */
772 void Bloc::seekUseless2(std::vector<Node *>& useless2, std::set<Node *>& allNodes) const
773 {
774   set<Node *>::iterator iter=allNodes.begin();
775   while(iter!=allNodes.end())
776     {
777       set<Node *>& whereToFind=(*_fwLinks)[*iter];
778       std::set<Node *>::iterator iter2;
779       for(iter2=allNodes.begin();iter2!=allNodes.end();iter2++)
780         if((*iter)!=(*iter2))
781           if(whereToFind.find(*iter2)==whereToFind.end())
782             break;
783       if(iter2!=allNodes.end())
784         {
785           iter++;
786         }
787       else
788         {
789           useless2.push_back((*iter));
790           allNodes.erase(iter);
791           iter=allNodes.begin();
792         }
793     }
794 }
795
796 /*! 
797  * Internal method : Given a succeful path : updates 'fastFinder'
798  */
799 void Bloc::updateWithNewFind(const std::vector<Node *>& path, std::map<Node *, std::set<Node *> >& fastFinder)
800 {
801   if(path.size()>=3)
802     {
803       vector<Node *>::const_iterator iter=path.begin(); iter++;
804       vector<Node *>::const_iterator iter2=path.end(); iter2-=1;
805       for(;iter!=iter2;iter++)
806         fastFinder[*iter].insert(*(iter+1));
807     }
808 }
809
810 /*! 
811  * Internal method : After all paths have been found, useless CF links are searched
812  */
813 void Bloc::findUselessLinksIn(const std::list< std::vector<Node *> >& res , LinkInfo& info)
814 {
815   unsigned maxSize=0;
816   list< vector<Node *> >::const_iterator whereToPeerAt;
817   for(list< vector<Node *> >::const_iterator iter=res.begin();iter!=res.end();iter++)
818     if((*iter).size()>maxSize)
819       {
820         maxSize=(*iter).size();
821         whereToPeerAt=iter;
822       }
823   //
824   if(maxSize>1)
825     {
826       vector<Node *>::const_iterator iter2=(*whereToPeerAt).begin();
827       map<Node *,bool>::iterator iter4;
828       set<Node *> searcher(iter2+1,(*whereToPeerAt).end());//to boost research
829       for(;iter2!=((*whereToPeerAt).end()-2);iter2++)
830         {
831           map<InGate *,bool>::iterator iter4;
832           map<InGate *,bool>& nexts=(*iter2)->getOutGate()->edMapInGate();
833           for(iter4=nexts.begin();iter4!=nexts.end();iter4++)
834             if((*iter4).first->getNode()!=*(iter2+1))
835               if(searcher.find((*iter4).first->getNode())!=searcher.end())
836                 info.pushUselessCFLink(*iter2,(*iter4).first->getNode());
837           searcher.erase(*iter2);
838         }
839     }
840 }