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