Salome HOME
Merge branch 'omu/update_doc_77'
[modules/yacs.git] / src / engine / OptimizerLoop.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 "OptimizerLoop.hxx"
21 #include "OutputPort.hxx"
22 #include "Visitor.hxx"
23
24 #include <iostream>
25
26 //#define _DEVDEBUG_
27 #include "YacsTrace.hxx"
28
29 using namespace YACS::ENGINE;
30 using namespace std;
31
32 const char FakeNodeForOptimizerLoop::NAME[]="thisIsAFakeNode";
33
34 const int OptimizerLoop::NOT_RUNNING_BRANCH_ID=-1973012217;
35 const int OptimizerLoop::NOT_INITIALIZED_BRANCH_ID=-1973;
36
37 const char OptimizerLoop::NAME_OF_ALGO_INIT_PORT[] = "algoInit";
38 const char OptimizerLoop::NAME_OF_OUT_POOL_INPUT[] = "evalResults";
39 const char OptimizerLoop::NAME_OF_ALGO_RESULT_PORT[] = "algoResults";
40
41
42 FakeNodeForOptimizerLoop::FakeNodeForOptimizerLoop(OptimizerLoop *loop, bool normal, std::string message)
43   : ElementaryNode(NAME), _loop(loop), _normal(normal), _message(message)
44 {
45   _state=YACS::TOACTIVATE;
46   _father=_loop->getFather();
47 }
48
49 FakeNodeForOptimizerLoop::FakeNodeForOptimizerLoop(const FakeNodeForOptimizerLoop& other)
50   : ElementaryNode(other), _loop(0), _normal(other._normal), _message(other._message)
51
52 }
53
54 Node *FakeNodeForOptimizerLoop::simpleClone(ComposedNode *father, bool editionOnly) const
55 {
56   return new FakeNodeForOptimizerLoop(*this);
57 }
58
59 void FakeNodeForOptimizerLoop::exForwardFailed()
60 {
61   _loop->exForwardFailed();
62 }
63
64 void FakeNodeForOptimizerLoop::exForwardFinished()
65 {
66   _loop->exForwardFinished();
67 }
68
69 void FakeNodeForOptimizerLoop::execute()
70 {
71   DEBTRACE("FakeNodeForOptimizerLoop::execute: " << _message)
72   if (!_normal) {
73     _loop->_errorDetails = _message;
74     throw Exception(_message);
75   }
76   else
77   {
78     _loop->_algoResultPort.put(_loop->_alg->getAlgoResultProxy());
79   }
80 }
81
82 void FakeNodeForOptimizerLoop::aborted()
83 {
84   _loop->setState(YACS::ERROR);
85 }
86
87 void FakeNodeForOptimizerLoop::finished()
88 {
89   _loop->setState(YACS::DONE);
90 }
91
92 /*! \class YACS::ENGINE::OptimizerLoop
93  *  \brief class to build optimization loops
94  *
95  * \ingroup ComposedNodes
96  */
97
98 OptimizerLoop::OptimizerLoop(const std::string& name, const std::string& algLibWthOutExt,
99                              const std::string& symbolNameToOptimizerAlgBaseInstanceFactory,
100                              bool algInitOnFile,bool initAlgo, Proc * procForTypes):
101         DynParaLoop(name,Runtime::_tc_string),_algInitOnFile(algInitOnFile),_alglib(algLibWthOutExt),
102         _algoInitPort(NAME_OF_ALGO_INIT_PORT, this, Runtime::_tc_string, true),
103         _loader(NULL),_alg(0),_convergenceReachedWithOtherCalc(false),
104         _retPortForOutPool(NAME_OF_OUT_POOL_INPUT,this,Runtime::_tc_string),
105         _nodeForSpecialCases(0), _algoResultPort(NAME_OF_ALGO_RESULT_PORT, this, Runtime::_tc_string)
106 {
107   //We need this because calling a virtual method in a constructor does not call the most derived method but the method of the class
108   //A derived class must take care to manage that 
109   if(initAlgo)
110     setAlgorithm(algLibWthOutExt,symbolNameToOptimizerAlgBaseInstanceFactory, procForTypes);
111 }
112
113 OptimizerLoop::OptimizerLoop(const OptimizerLoop& other, ComposedNode *father, bool editionOnly):
114   DynParaLoop(other,father,editionOnly),_algInitOnFile(other._algInitOnFile),_alglib(other._alglib),
115   _convergenceReachedWithOtherCalc(false),_loader(NULL),_alg(0),_algoInitPort(other._algoInitPort,this),
116   _retPortForOutPool(other._retPortForOutPool,this),_nodeForSpecialCases(0),
117   _algoResultPort(other._algoResultPort, this)
118 {
119   //Don't call setAlgorithm here because it will be called several times if the class is derived. Call it in simpleClone for cloning
120   
121   // Create the links to evalResults port
122   set<OutPort *> fromPortsToReproduce=other._retPortForOutPool.edSetOutPort();
123   for(set<OutPort *>::iterator iter=fromPortsToReproduce.begin();iter!=fromPortsToReproduce.end();iter++)
124     edAddLink(getOutPort(other.getPortName(*iter)),&_retPortForOutPool);
125 }
126
127 OptimizerLoop::~OptimizerLoop()
128 {
129   if(_alg)
130     _alg->decrRef();
131   cleanDynGraph();
132   cleanInterceptors();
133   delete _loader;
134   delete _nodeForSpecialCases;
135 }
136
137 Node *OptimizerLoop::simpleClone(ComposedNode *father, bool editionOnly) const
138 {
139   OptimizerLoop* ol=new OptimizerLoop(*this,father,editionOnly);
140   // TODO: Remove this const_cast (find a better design to get the type codes from the original node)
141   Proc * procForTypes = ol->getProc();
142   if (procForTypes == NULL) {
143     const Proc * origProc = getProc();
144     procForTypes = const_cast<Proc *>(origProc);
145   }
146   ol->setAlgorithm(_alglib, _symbol, false, procForTypes);
147   return ol;
148 }
149
150 void OptimizerLoop::init(bool start)
151 {
152   DynParaLoop::init(start);
153   _algoInitPort.exInit(start);
154   _retPortForOutPool.exInit(start);
155   _algoResultPort.exInit();
156   _convergenceReachedWithOtherCalc=false;
157   cleanDynGraph();
158   cleanInterceptors();
159 }
160
161 void OptimizerLoop::exUpdateState()
162 {
163   if(_state == YACS::DISABLED)
164     return;
165   delete _nodeForSpecialCases;
166   _nodeForSpecialCases = NULL;
167   try
168     {
169       if(_inGate.exIsReady())
170         {
171           setState(YACS::TOACTIVATE);
172           // Force termination in case the previous algorithm did not finish properly (manual stop)
173           _alg->finishProxy();
174           _myPool.destroyAll();
175
176           // Initialize and launch the algorithm
177           _alg->initializeProxy(_algoInitPort.getValue());
178           if (_alg->hasError()) {
179             string error = _alg->getError();
180             _alg->finishProxy();
181             throw Exception(error);
182           }
183
184           //internal graph update
185           int i;
186           int nbOfBr=_nbOfBranches.getIntValue();
187           _alg->setNbOfBranches(nbOfBr);
188
189           _alg->startProxy();
190           if (_alg->hasError()) {
191             string error = _alg->getError();
192             _alg->finishProxy();
193             throw Exception(error);
194           }
195
196           if(nbOfBr==0)
197             {
198               // A number of branches of 0 is acceptable if there are no output ports
199               // leaving OptimizerLoop
200               bool normal = getAllOutPortsLeavingCurrentScope().empty();
201               _nodeForSpecialCases = new FakeNodeForOptimizerLoop(this, normal,
202                   "OptimizerLoop has no branch to run the internal node(s)");
203               return;
204             }
205           _execNodes.resize(nbOfBr);
206           _execIds.resize(nbOfBr);
207           if(_initNode)
208             {
209               _execInitNodes.resize(nbOfBr);
210               _initNodeUpdated.resize(nbOfBr);
211               for(i=0;i<nbOfBr;i++)
212                 _initNodeUpdated[i]=false;
213             }
214           _initializingCounter = 0;
215           if (_finalizeNode)
216             _execFinalizeNodes.resize(nbOfBr);
217           vector<Node *> origNodes;
218           origNodes.push_back(_initNode);
219           origNodes.push_back(_node);
220           origNodes.push_back(_finalizeNode);
221           for(i=0;i<nbOfBr;i++)
222             {
223               _execIds[i]=NOT_INITIALIZED_BRANCH_ID;
224               vector<Node *> clonedNodes = cloneAndPlaceNodesCoherently(origNodes);
225               if(_initNode)
226                 _execInitNodes[i] = clonedNodes[0];
227               _execNodes[i] = clonedNodes[1];
228               if(_finalizeNode)
229                 _execFinalizeNodes[i] = clonedNodes[2];
230               prepareInputsFromOutOfScope(i);
231             }
232           initInterceptors(nbOfBr);
233           int id;
234           unsigned char priority;
235           Any *val=_myPool.getNextSampleWithHighestPriority(id,priority);
236           if(!val)
237             {
238               // It is acceptable to have no sample to launch if there are no output ports
239               // leaving OptimizerLoop
240               std::set<OutPort *> setOutPort = getAllOutPortsLeavingCurrentScope();
241               // Special in the special
242               // We do not check algoResult
243               setOutPort.erase(&_algoResultPort);
244               bool normal = setOutPort.empty();
245               _nodeForSpecialCases = new FakeNodeForOptimizerLoop(this, normal,
246                   string("The algorithm of OptimizerLoop with name ") + _name +
247                   " returns no sample to launch");
248               return;
249             }
250           launchMaxOfSamples(true);
251         }
252     }
253   catch (const exception & e)
254     {
255       _nodeForSpecialCases = new FakeNodeForOptimizerLoop(this, false,
256           string("An error happened in the control algorithm of OptimizerLoop \"") + _name +
257           "\": " + e.what());
258     }
259 }
260
261 int OptimizerLoop::getNumberOfInputPorts() const
262 {
263   return DynParaLoop::getNumberOfInputPorts()+2;
264 }
265
266 InputPort *OptimizerLoop::getInputPort(const std::string& name) const throw(YACS::Exception)
267 {
268   if (name == NAME_OF_ALGO_INIT_PORT)
269     return (InputPort *)&_algoInitPort;
270   else if (name == NAME_OF_OUT_POOL_INPUT)
271     return (InputPort *)&_retPortForOutPool;
272   else
273     return DynParaLoop::getInputPort(name);
274 }
275
276 std::list<InputPort *> OptimizerLoop::getSetOfInputPort() const
277 {
278   list<InputPort *> ret=DynParaLoop::getSetOfInputPort();
279   ret.push_back((InputPort *)&_algoInitPort);
280   ret.push_back((InputPort *)&_retPortForOutPool);
281   return ret;
282 }
283
284 std::list<InputPort *> OptimizerLoop::getLocalInputPorts() const
285 {
286   list<InputPort *> ret=DynParaLoop::getLocalInputPorts();
287   ret.push_back((InputPort *)&_algoInitPort);
288   ret.push_back((InputPort *)&_retPortForOutPool);
289   return ret;
290 }
291
292 void OptimizerLoop::selectRunnableTasks(std::vector<Task *>& tasks)
293 {
294 }
295
296 void OptimizerLoop::getReadyTasks(std::vector<Task *>& tasks)
297 {
298   if(!_node)
299     return;
300   if(_state==YACS::TOACTIVATE || _state==YACS::ACTIVATED)
301     {
302       if(_nodeForSpecialCases)
303         {
304           _nodeForSpecialCases->getReadyTasks(tasks);
305           return ;
306         }
307       vector<Node *>::iterator iter;
308       for (iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++)
309         (*iter)->getReadyTasks(tasks);
310       for (iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++)
311         (*iter)->getReadyTasks(tasks);
312       for (iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++)
313         (*iter)->getReadyTasks(tasks);
314     }
315 }
316
317 YACS::Event OptimizerLoop::updateStateOnFinishedEventFrom(Node *node)
318 {
319   if (getState() == YACS::FAILED)
320     {
321       // This happens when a valid computation on a branch finishes after an error on another branch.
322       // In this case we just ignore the new result because the algorithm has already been terminated.
323       return YACS::NOEVENT;
324     }
325   unsigned int id;
326   switch(getIdentityOfNotifyerNode(node,id))
327     {
328     case INIT_NODE:
329     {
330       _execNodes[id]->exUpdateState();
331       _nbOfEltConsumed++;
332       _initializingCounter--;
333       if (_initializingCounter == 0) _initNode->setState(DONE);
334       break;
335     }
336     case WORK_NODE:
337     {
338       if(_convergenceReachedWithOtherCalc)
339         { //This case happens when alg has reached its convergence whereas other calculations still compute
340           _execIds[id]=NOT_RUNNING_BRANCH_ID;
341           if(!isFullyLazy())
342             return YACS::NOEVENT;
343           else
344             return finalize();
345         }
346       _myPool.putOutSampleAt(_execIds[id],_interceptorsForOutPool[id]->getValue());
347       _myPool.setCurrentId(_execIds[id]);
348       _alg->takeDecisionProxy();
349       if (_alg->hasError()) {
350         _errorDetails = string("An error happened in the control algorithm of optimizer loop: ") +
351                         _alg->getError();
352         _alg->finishProxy();
353         setState(YACS::FAILED);
354         return YACS::ABORT;
355       }
356
357       _myPool.destroyCurrentCase();
358       if(_myPool.empty())
359         {
360           pushValueOutOfScopeForCase(id);
361           _execIds[id]=NOT_RUNNING_BRANCH_ID;
362           if(!isFullyLazy())
363             {// This case happens when the hand is returned to continue, whereas some other are working in parallel for nothing.
364               _convergenceReachedWithOtherCalc=true;
365               return YACS::NOEVENT;
366             }
367           return finalize();
368         }
369       _execIds[id]=NOT_RUNNING_BRANCH_ID;
370       int newId;
371       unsigned char priority;
372       Any *val=_myPool.getNextSampleWithHighestPriority(newId, priority);
373       if(!val)
374         {
375           bool isFinished=true;
376           for(int i=0;i<_execIds.size() && isFinished;i++)
377             isFinished=(_execIds[i]==NOT_RUNNING_BRANCH_ID || _execIds[i]==NOT_INITIALIZED_BRANCH_ID);
378           if(isFinished)
379             {
380               std::cerr <<"OptimizerLoop::updateStateOnFinishedEventFrom: Alg has not inserted more cases whereas last element has been calculated !" << std::endl;
381               setState(YACS::ERROR);
382               exForwardFailed();
383               _alg->finishProxy();
384               return YACS::FINISH;
385             }
386           return YACS::NOEVENT;
387         }
388       launchMaxOfSamples(false);
389       break;
390     }
391     case FINALIZE_NODE:
392     {
393       _unfinishedCounter--;
394       if (_unfinishedCounter == 0)
395         {
396           _finalizeNode->setState(YACS::DONE);
397           setState(YACS::DONE);
398           return YACS::FINISH;
399         }
400       else
401         return YACS::NOEVENT;
402       break;
403     }
404     default:
405       YASSERT(false);
406     }
407   return YACS::NOEVENT;
408 }
409
410 YACS::Event OptimizerLoop::finalize()
411 {
412   //update internal node (definition node) state
413   if (_node)
414     {
415       _node->setState(YACS::DONE);
416       ComposedNode* compNode = dynamic_cast<ComposedNode*>(_node);
417       if (compNode)
418         {
419           std::list<Node *> aChldn = compNode->getAllRecursiveConstituents();
420           std::list<Node *>::iterator iter=aChldn.begin();
421           for(;iter!=aChldn.end();iter++)
422             (*iter)->setState(YACS::DONE);
423         }
424     }
425   _alg->finishProxy();
426   _algoResultPort.put(_alg->getAlgoResultProxy());
427   if (_finalizeNode == NULL)
428     {
429       // No finalize node, we just finish OptimizerLoop at the end of exec nodes execution
430       setState(YACS::DONE);
431       return YACS::FINISH;
432     }
433   else
434     {
435       // Run the finalize nodes, the OptimizerLoop will be done only when they all finish
436       _unfinishedCounter = 0;  // This counter indicates how many branches are not finished
437       for (int i=0 ; i<_nbOfBranches.getIntValue() ; i++)
438         if (_execIds[i] == NOT_RUNNING_BRANCH_ID)
439           {
440             DEBTRACE("Launching finalize node for branch " << i)
441             _execFinalizeNodes[i]->exUpdateState();
442             _unfinishedCounter++;
443           }
444         else
445           // There should not be any running branch at this point
446           YASSERT(_execIds[i] == NOT_INITIALIZED_BRANCH_ID)
447       return YACS::NOEVENT;
448     }
449 }
450
451 //! Method used to notify the node that a child node has failed
452 /*!
453  * Notify the slave thread of the error, update the current state and
454  * return the change state
455  *
456  *  \param node : the child node that has failed
457  *  \return the state change
458  */
459 YACS::Event OptimizerLoop::updateStateOnFailedEventFrom(Node *node, const Executor *execInst)
460 {
461   DEBTRACE("OptimizerLoop::updateStateOnFailedEventFrom " << node->getName());
462   _alg->setError(string("Error during the execution of YACS node ") + node->getName() +
463                  ": " + node->getErrorReport());
464   _alg->finishProxy();
465   _myPool.destroyAll();
466   DEBTRACE("OptimizerLoop::updateStateOnFailedEventFrom: returned from error notification.");
467   return DynParaLoop::updateStateOnFailedEventFrom(node,execInst);
468 }
469
470 void OptimizerLoop::checkNoCyclePassingThrough(Node *node) throw(YACS::Exception)
471 {
472 }
473
474 void OptimizerLoop::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
475 {
476   DynParaLoop::buildDelegateOf(port,initialStart,pointsOfView);
477   if(port==&_retPortForOutPool)
478   {
479     std::string linkName("(");
480     linkName += initialStart->getName()+" to "+port->getName()+")";
481     throw Exception(std::string("Illegal OptimizerLoop link: \
482 The 'evalResults' port must be linked within the scope of the loop.")
483                     + linkName);
484   }
485 }
486
487 void OptimizerLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
488 {
489   DynParaLoop::buildDelegateOf(port,finalTarget,pointsOfView);
490   if(port.first != &_algoResultPort)
491   {
492     std::string linkName("(");
493     linkName += port.first->getName()+" to "+finalTarget->getName()+")";
494     throw Exception(std::string("Illegal OptimizerLoop link: \
495 Only the algorithm result port can be linked to a port outside the scope of the loop.")
496                     + linkName);
497   }
498
499   string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
500   if(typeOfPortInstance!=OutputPort::NAME)
501     throw Exception("OptimizerLoop::buildDelegateOf : not implemented for DS because not specified ");
502 }
503
504 void OptimizerLoop::checkControlDependancy(OutPort *start, InPort *end, bool cross,
505                                            std::map < ComposedNode *,  std::list < OutPort * >, SortHierarc >& fw,
506                                            std::vector<OutPort *>& fwCross,
507                                            std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw,
508                                            LinkInfo& info) const
509 {
510   if(end==&_retPortForOutPool)
511     fw[(ComposedNode *)this].push_back(start);
512   else
513     DynParaLoop::checkControlDependancy(start,end,cross,fw,fwCross,bw,info);
514 }
515
516 void OptimizerLoop::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
517 {
518   if(end==&_retPortForOutPool)
519     solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
520   else
521     DynParaLoop::checkCFLinks(starts,end,alreadyFed,direction,info);
522 }
523
524 void OptimizerLoop::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
525                           InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(YACS::Exception)
526 {
527   DynParaLoop::checkLinkPossibility(start, pointsOfViewStart, end, pointsOfViewEnd);
528   std::string linkName("(");
529   linkName += start->getName()+" to "+end->getName()+")";
530
531   // Yes, it should be possible to link back the result port to any input port of the loop.
532   if(end == &_nbOfBranches || end == &_algoInitPort)
533     if(start != &_algoResultPort)
534       throw Exception(std::string("Illegal OptimizerLoop link.") + linkName);
535     else
536       return;
537
538   if(start == &_algoResultPort)
539     throw Exception(std::string("Illegal OptimizerLoop link: \
540 The 'algoResult' port can't be linked within the scope of the loop.") + linkName);
541   
542   if(end == &_retPortForOutPool && isInMyDescendance(start->getNode())!=_node)
543     throw Exception(std::string("Illegal OptimizerLoop link: \
544 The 'evalResults' port can only be linked to the working node.") + linkName);
545 }
546
547 void OptimizerLoop::cleanInterceptors()
548 {
549   // At this point all garanties taken let's clean all.
550   map<InputPort *,vector<InputPort *> >::iterator iter=_interceptors.begin();
551   for(;iter!=_interceptors.end();iter++)
552     for(vector<InputPort *>::iterator iter2=(*iter).second.begin();iter2!=(*iter).second.end();iter2++)
553       delete (*iter2);
554   _interceptors.clear();
555   for(vector<AnyInputPort *>::iterator iter3=_interceptorsForOutPool.begin();iter3!=_interceptorsForOutPool.end();iter3++)
556     delete (*iter3);
557   _interceptorsForOutPool.clear();
558 }
559
560 void OptimizerLoop::launchMaxOfSamples(bool first)
561 {
562   int id;
563   unsigned char priority;
564   Any *val;
565   unsigned i;
566   for (val = _myPool.getNextSampleWithHighestPriority(id, priority);
567        !isFullyBusy(i) && val;
568        val = _myPool.getNextSampleWithHighestPriority(id, priority))
569     {
570       if(_execIds[i] == NOT_INITIALIZED_BRANCH_ID)
571         first=true; // node is not initialized (first pass)
572       else
573         first=false; // node is initialized (second pass)
574       _execIds[i]=id;
575       _myPool.markIdAsInUse(id);
576       if(_initNode && !_initNodeUpdated[i])
577         {
578           putValueOnBranch(val,i,first);
579           _execInitNodes[i]->exUpdateState();
580           _initNodeUpdated[i]=true;
581           _initializingCounter++;
582         }
583       else
584         {
585           if(!first)
586             _execNodes[i]->init(first);
587           putValueOnBranch(val,i,first);
588           _execNodes[i]->exUpdateState();
589           _nbOfEltConsumed++;
590         }
591     }
592 }
593
594 bool OptimizerLoop::isFullyLazy() const
595 {
596   bool isLazy=true;
597   for(unsigned i=0;i<_execIds.size() && isLazy;i++)
598     isLazy=(_execIds[i]==NOT_RUNNING_BRANCH_ID || _execIds[i]==NOT_INITIALIZED_BRANCH_ID);
599   return isLazy;
600 }
601
602 /*!
603  * Returns if a dynamic branch is available.
604  * \param branchId Out param. Only usable if returned value is equal to \b false.
605  */
606 bool OptimizerLoop::isFullyBusy(unsigned& branchId) const
607 {
608   bool isFinished=true;
609   unsigned i;
610   for(i=0;i<_execIds.size() && isFinished;i++)
611     isFinished=(_execIds[i]!=NOT_RUNNING_BRANCH_ID && _execIds[i]!=NOT_INITIALIZED_BRANCH_ID);
612   if(!isFinished)
613     branchId=i-1;
614   return isFinished;
615 }
616
617 /*!
618  * Perform initialization of interceptors. \b WARNING _execNodes have to be created before.
619  */
620 void OptimizerLoop::initInterceptors(unsigned nbOfBr)
621 {
622   //For all classical outputports leaving 'this'
623   set<OutPort *> portsToIntercept=getAllOutPortsLeavingCurrentScope();
624   portsToIntercept.erase(&_algoResultPort);
625   for(set<OutPort *>::iterator iter=portsToIntercept.begin();iter!=portsToIntercept.end();iter++)
626     {
627       OutputPort *portC=(OutputPort *)(*iter);//Warrantied by OptimizerLoop::buildDelegateOf
628       const set<InputPort *>& links=portC->getSetOfPhyLinks();
629       for(set<InputPort *>::const_iterator iter2=links.begin();iter2!=links.end();iter2++)
630         {
631 #ifdef NOCOVARIANT
632           InputPort *reprCur=dynamic_cast<InputPort *>((*iter2)->getPublicRepresentant());
633 #else
634           InputPort *reprCur=(*iter2)->getPublicRepresentant();
635 #endif
636           if(!isInMyDescendance(reprCur->getNode()))
637             {//here we've got an out of scope link : Let's intercept it
638               if(_interceptors.find(reprCur)==_interceptors.end())
639                 {
640                   _interceptors[reprCur].resize(nbOfBr);
641                   for(unsigned i=0;i<nbOfBr;i++)
642                     {
643                       OutputPort *portExecC=(OutputPort *)_execNodes[i]->getOutputPort(_node->getOutPortName(portC));
644                       InputPort *clone=reprCur->clone(0);
645                       _interceptors[reprCur][i]=clone;
646                       portExecC->edAddInputPort(clone);
647                     }
648                 }
649               else
650                 {
651                   for(unsigned i=0;i<nbOfBr;i++)
652                     {
653                       OutputPort *portExecC=(OutputPort *)_execNodes[i]->getOutputPort(_node->getOutPortName(portC));
654                       portExecC->edAddInputPort(_interceptors[reprCur][i]);
655                     }
656                 }
657             }
658         }
659     }
660   // For out pool
661   _interceptorsForOutPool.resize(nbOfBr);
662   set< OutPort * > links=_retPortForOutPool.edSetOutPort();
663   for(unsigned i=0;i<nbOfBr;i++)
664     _interceptorsForOutPool[i]=(AnyInputPort *)_retPortForOutPool.clone(this);
665   for(set<OutPort *>::iterator iter2=links.begin();iter2!=links.end();iter2++)
666     for(unsigned j=0;j<nbOfBr;j++)
667       {
668         OutPort *portExec;
669         Node *whatType=isInMyDescendance((*iter2)->getNode());
670         if(whatType==_node)
671           {
672             portExec=_execNodes[j]->getOutPort(_node->getOutPortName(*iter2));
673             portExec->addInPort(_interceptorsForOutPool[j]);
674           }
675         else if(whatType==_initNode && whatType!=0)//This case should never happend. Useless !
676           {
677             portExec=_execInitNodes[j]->getOutPort(_node->getOutPortName(*iter2));
678             portExec->addInPort(_interceptorsForOutPool[j]);
679           }
680       }
681 }
682
683 /*!
684  * Typically called when _alg has decided that convergence has been reached. In this case the links leaving the current scope are activated and filled
685  * with value of the branch specified by 'branchId' that is the branch in which the convergence has been reached.
686  */
687 void OptimizerLoop::pushValueOutOfScopeForCase(unsigned branchId)
688 {
689   map<InputPort *, std::vector<InputPort *> >::iterator iter;
690   for(iter=_interceptors.begin();iter!=_interceptors.end();iter++)
691     (*iter).first->put((*iter).second[branchId]->get());
692 }
693
694 void OptimizerLoop::accept(Visitor *visitor)
695 {
696   visitor->visitOptimizerLoop(this);
697 }
698
699 //! Set the algorithm library name and factory name (symbol in library) to create the algorithm and change it if the node is not connected
700 /*!
701  *   throw an exception if the node is connected
702  */
703 void OptimizerLoop::setAlgorithm(const std::string& alglib, const std::string& symbol,
704                                  bool checkLinks, Proc * procForTypes)
705 {
706   if(checkLinks)
707     {
708       if (_splittedPort.edGetNumberOfOutLinks() != 0 ||
709           _retPortForOutPool.edGetNumberOfLinks() != 0 ||
710           _algoInitPort.edGetNumberOfLinks() != 0 ||
711           _algoResultPort.edGetNumberOfOutLinks() != 0)
712         throw Exception("The OptimizerLoop node must be disconnected before setting the algorithm");
713     }
714
715   _symbol = symbol;
716   _alglib = alglib;
717
718   if (_alg) {
719     _alg->decrRef();
720     _alg = NULL;
721   }
722
723   loadAlgorithm();
724
725   if(_alg)
726     {
727       _alg->setProc((procForTypes == NULL) ? getProc() : procForTypes);
728
729       // Delete the values in the input ports if they were initialized
730       _retPortForOutPool.put((Any *)NULL);
731       _algoInitPort.put((Any *)NULL);
732
733       // Change the type of the ports
734       _splittedPort.edSetType(checkTypeCode(_alg->getTCForInProxy(), NAME_OF_SPLITTED_SEQ_OUT));
735       _retPortForOutPool.edSetType(checkTypeCode(_alg->getTCForOutProxy(), NAME_OF_OUT_POOL_INPUT));
736       _algoInitPort.edSetType(checkTypeCode(_alg->getTCForAlgoInitProxy(), NAME_OF_ALGO_INIT_PORT));
737       _algoResultPort.edSetType(checkTypeCode(_alg->getTCForAlgoResultProxy(), NAME_OF_ALGO_RESULT_PORT));
738     }
739
740   modified();
741 }
742
743 TypeCode * OptimizerLoop::checkTypeCode(TypeCode * tc, const char * portName)
744 {
745   if (tc == NULL) {
746     ostringstream errorMsg;
747     errorMsg << "The algorithm specified for OptimizerLoop node \"" << getName() <<
748                 "\" provided an invalid type for port \"" << portName << "\"";
749     throw Exception(errorMsg.str());
750   }
751   return tc;
752 }
753
754 //! Load the algorithm from the dynamic library
755 /*!
756  *
757  */
758 void OptimizerLoop::loadAlgorithm()
759 {
760   YASSERT(_alg == NULL)
761
762   if (_loader != NULL) {
763     delete _loader;
764     _loader = NULL;
765   }
766   _loader = new YACS::BASES::DynLibLoader(_alglib);
767   OptimizerAlgBaseFactory algFactory = NULL;
768
769   if (_alglib != "" && _symbol != "")
770     {
771       try
772         {
773           _errorDetails = "";
774           algFactory = (OptimizerAlgBaseFactory)_loader->getHandleOnSymbolWithName(_symbol);
775         }
776       catch (YACS::Exception& e)
777         {
778           _errorDetails = e.what();
779           modified();
780           throw;
781         }
782     }
783
784   if (algFactory != NULL)
785     _alg = algFactory(&_myPool);
786 }
787
788 //! Return the name of the algorithm library
789 /*!
790  *
791  */
792 std::string OptimizerLoop::getAlgLib() const
793 {
794   return _alglib;
795 }
796
797 //! Check validity for the node.
798 /*!
799  *  Throw an exception if the node is not valid
800  */
801 void OptimizerLoop::checkBasicConsistency() const throw(YACS::Exception)
802 {
803   DEBTRACE("OptimizerLoop::checkBasicConsistency");
804   if (_alglib == "")
805     throw Exception("No library specified for the OptimizerLoop control algorithm");
806   if (_symbol == "")
807     throw Exception("No symbol specified for the OptimizerLoop control algorithm");
808   if(_alg == NULL)
809     throw YACS::Exception("Problem during library loading: "+_errorDetails);
810
811   DynParaLoop::checkBasicConsistency();
812 }
813
814 int OptimizerLoop::getNumberOfOutputPorts() const
815 {
816   return DynParaLoop::getNumberOfOutputPorts() + 1;
817 }
818
819 std::list<OutputPort *> OptimizerLoop::getSetOfOutputPort() const
820 {
821   list<OutputPort *> ret = DynParaLoop::getSetOfOutputPort();
822   ret.push_back((OutputPort *)&_algoResultPort);
823   return ret;
824 }
825
826 std::list<OutputPort *> OptimizerLoop::getLocalOutputPorts() const
827 {
828   list<OutputPort *> ret = DynParaLoop::getLocalOutputPorts();
829   ret.push_front((OutputPort *)&_algoResultPort);
830   return ret;
831 }
832
833 OutPort * OptimizerLoop::getOutPort(const std::string& name) const throw(YACS::Exception)
834 {
835   return (name == NAME_OF_ALGO_RESULT_PORT) ? (OutPort *)&_algoResultPort :
836                                               DynParaLoop::getOutPort(name);
837 }
838
839
840 OutputPort * OptimizerLoop::getOutputPort(const std::string& name) const throw(YACS::Exception)
841 {
842   return (name == NAME_OF_ALGO_RESULT_PORT) ? (OutputPort *)&_algoResultPort :
843                                               DynParaLoop::getOutputPort(name);
844 }