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