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