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