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