1 // Copyright (C) 2006-2008 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #include "OptimizerLoop.hxx"
20 #include "OutputPort.hxx"
24 using namespace YACS::ENGINE;
27 const char FakeNodeForOptimizerLoop::NAME[]="thisIsAFakeNode";
29 const int OptimizerLoop::NOT_RUNNING_BRANCH_ID=-1973012217;
31 const char OptimizerLoop::NAME_OF_FILENAME_INPUT[]="FileNameInitAlg";
33 const char OptimizerLoop::NAME_OF_OUT_POOL_INPUT[]="retPortForOutPool";
35 OptimizerAlgStandardized::OptimizerAlgStandardized(Pool *pool, OptimizerAlgBase *alg)
36 : OptimizerAlgSync(pool),_algBehind(alg),_threadInCaseOfNotEvent(0)
39 _algBehind->incrRef();
42 OptimizerAlgStandardized::~OptimizerAlgStandardized()
45 _algBehind->decrRef();
48 TypeCode *OptimizerAlgStandardized::getTCForIn() const
50 return _algBehind->getTCForIn();
53 TypeCode *OptimizerAlgStandardized::getTCForOut() const
55 return _algBehind->getTCForOut();
58 void OptimizerAlgStandardized::setAlgPointer(OptimizerAlgBaseFactory algFactory)
61 _algBehind->decrRef();
62 _algBehind=algFactory(_pool);
65 void OptimizerAlgStandardized::parseFileToInit(const std::string& fileName)
67 _algBehind->parseFileToInit(fileName);
70 void OptimizerAlgStandardized::initialize(const Any *input) throw (Exception)
72 _algBehind->initialize(input);
75 void OptimizerAlgStandardized::takeDecision()
77 switch(_algBehind->getType())
81 ((OptimizerAlgSync *) _algBehind)->takeDecision();
84 case NOT_EVENT_ORIENTED:
86 _condition.notifyOneSync();
90 throw Exception("Unrecognized type of algorithm. Only 2 types are available : EVENT_ORIENTED or NOT_EVENT_ORIENTED.");
94 void OptimizerAlgStandardized::finish()
99 void OptimizerAlgStandardized::start()
101 switch(_algBehind->getType())
105 ((OptimizerAlgSync *) _algBehind)->start();
108 case NOT_EVENT_ORIENTED:
110 void **stackForNewTh= new void* [2];
111 stackForNewTh[0]=(void *) ((OptimizerAlgASync *)(_algBehind));//In case of virtual inheritance
112 stackForNewTh[1]=(void *) &_condition;
113 _threadInCaseOfNotEvent=new ::YACS::BASES::Thread(threadFctForAsync,stackForNewTh);
114 _condition.waitForAWait();
118 throw Exception("Unrecognized type of algorithm. Only 2 types are available : EVENT_ORIENTED or NOT_EVENT_ORIENTED.");
122 void *OptimizerAlgStandardized::threadFctForAsync(void* ownStack)
124 void **ownStackCst=(void **)ownStack;
125 OptimizerAlgASync *alg=(OptimizerAlgASync *)ownStackCst[0];
126 ::YACS::BASES::DrivenCondition *cond=(::YACS::BASES::DrivenCondition *)ownStackCst[1];
127 delete [] ownStackCst;
128 alg->startToTakeDecision(cond);
131 FakeNodeForOptimizerLoop::FakeNodeForOptimizerLoop(OptimizerLoop *loop, bool normal, unsigned reason):ElementaryNode(NAME),_loop(loop),
135 _state=YACS::TOACTIVATE;
136 _father=_loop->getFather();
139 FakeNodeForOptimizerLoop::FakeNodeForOptimizerLoop(const FakeNodeForOptimizerLoop& other):ElementaryNode(other),_loop(0),
144 Node *FakeNodeForOptimizerLoop::simpleClone(ComposedNode *father, bool editionOnly) const
146 return new FakeNodeForOptimizerLoop(*this);
149 void FakeNodeForOptimizerLoop::exForwardFailed()
151 _loop->exForwardFailed();
152 FakeNodeForOptimizerLoop *normallyThis=_loop->_nodeForSpecialCases;
153 _loop->_nodeForSpecialCases=0;
157 void FakeNodeForOptimizerLoop::exForwardFinished()
159 _loop->exForwardFinished();
160 FakeNodeForOptimizerLoop *normallyThis=_loop->_nodeForSpecialCases;
161 _loop->_nodeForSpecialCases=0;
165 void FakeNodeForOptimizerLoop::execute()
170 if(_reason==ALG_WITHOUT_START_CASES)
171 what="Alg initialization of optimizerNode with name "; what+=_loop->getName(); what+=" returns no new case(s) to launch";
172 throw Exception(what);
176 void FakeNodeForOptimizerLoop::aborted()
178 _loop->_state=YACS::ERROR;
181 void FakeNodeForOptimizerLoop::finished()
186 OptimizerLoop::OptimizerLoop(const std::string& name, const std::string& algLibWthOutExt,
187 const std::string& symbolNameToOptimizerAlgBaseInstanceFactory,
188 bool algInitOnFile) throw(Exception)
189 try : DynParaLoop(name,Runtime::_tc_string),_loader(algLibWthOutExt),_algInitOnFile(algInitOnFile),
190 _portForInitFile(NAME_OF_FILENAME_INPUT,this,Runtime::_tc_string),
191 _alg(new OptimizerAlgStandardized(&_myPool,0)),_convergenceReachedWithOtherCalc(false),
192 _retPortForOutPool(NAME_OF_OUT_POOL_INPUT,this,Runtime::_tc_string),
193 _nodeForSpecialCases(0),_symbol(symbolNameToOptimizerAlgBaseInstanceFactory)
195 OptimizerAlgBaseFactory algFactory=(OptimizerAlgBaseFactory)_loader.getHandleOnSymbolWithName(_symbol);
197 throw Exception("Problem during library loading.");
198 _alg->setAlgPointer(algFactory);
199 _splittedPort.edSetType(_alg->getTCForIn());
200 _retPortForOutPool.edSetType(_alg->getTCForOut());
206 OptimizerLoop::OptimizerLoop(const OptimizerLoop& other, ComposedNode *father, bool editionOnly):
207 DynParaLoop(other,father,editionOnly),_algInitOnFile(other._algInitOnFile),_loader(other._loader.getLibNameWithoutExt()),_convergenceReachedWithOtherCalc(false),
208 _alg(new OptimizerAlgStandardized(&_myPool,0)),_portForInitFile(other._portForInitFile,this),_retPortForOutPool(other._retPortForOutPool,this),_nodeForSpecialCases(0),_symbol(other._symbol)
210 OptimizerAlgBaseFactory algFactory=(OptimizerAlgBaseFactory)_loader.getHandleOnSymbolWithName(_symbol);
211 _alg->setAlgPointer(algFactory);
212 _splittedPort.edSetType(_alg->getTCForIn());
213 _retPortForOutPool.edSetType(_alg->getTCForOut());
216 OptimizerLoop::~OptimizerLoop()
223 Node *OptimizerLoop::simpleClone(ComposedNode *father, bool editionOnly) const
225 return new OptimizerLoop(*this,father,editionOnly);
228 void OptimizerLoop::init(bool start)
230 DynParaLoop::init(start);
231 _portForInitFile.exInit(start);
232 _convergenceReachedWithOtherCalc=false;
237 void OptimizerLoop::exUpdateState()
239 if(_state == YACS::DISABLED)
241 if(_inGate.exIsReady())
243 _state=YACS::TOACTIVATE;
244 //internal graph update
246 int nbOfBr=_nbOfBranches.getIntValue();
249 delete _nodeForSpecialCases;
250 _nodeForSpecialCases=new FakeNodeForOptimizerLoop(this,getAllOutPortsLeavingCurrentScope().empty(),FakeNodeForOptimizerLoop::NO_BRANCHES);
254 if(_portForInitFile.isEmpty())
256 delete _nodeForSpecialCases;
257 _nodeForSpecialCases=new FakeNodeForOptimizerLoop(this,getAllOutPortsLeavingCurrentScope().empty(),FakeNodeForOptimizerLoop::NO_ALG_INITIALIZATION);
260 _execNodes.resize(nbOfBr);
261 _execIds.resize(nbOfBr);
264 _execInitNodes.resize(nbOfBr);
265 _initNodeUpdated.resize(nbOfBr);
266 for(i=0;i<nbOfBr;i++)
267 _initNodeUpdated[i]=false;
269 for(i=0;i<nbOfBr;i++)
271 _execIds[i]=NOT_RUNNING_BRANCH_ID;
272 _execNodes[i]=_node->clone(this,false);
274 _execInitNodes[i]=_initNode->clone(this,false);
275 prepareInputsFromOutOfScope(i);
277 initInterceptors(nbOfBr);
278 _alg->parseFileToInit(_portForInitFile.getValue()->getStringValue());
281 unsigned char priority;
282 Any *val=_myPool.getNextSampleWithHighestPriority(id,priority);
285 delete _nodeForSpecialCases;
286 _nodeForSpecialCases=new FakeNodeForOptimizerLoop(this,getAllOutPortsLeavingCurrentScope().empty(),FakeNodeForOptimizerLoop::ALG_WITHOUT_START_CASES);
289 launchMaxOfSamples(true);
293 int OptimizerLoop::getNumberOfInputPorts() const
295 return DynParaLoop::getNumberOfInputPorts()+2;
298 InputPort *OptimizerLoop::getInputPort(const std::string& name) const throw(Exception)
300 if(name==NAME_OF_FILENAME_INPUT)
301 return (InputPort *)&_portForInitFile;
302 else if(name==NAME_OF_OUT_POOL_INPUT)
303 return (InputPort *)&_retPortForOutPool;
305 return DynParaLoop::getInputPort(name);
308 std::list<InputPort *> OptimizerLoop::getSetOfInputPort() const
310 list<InputPort *> ret=DynParaLoop::getSetOfInputPort();
311 ret.push_back((InputPort *)&_portForInitFile);
312 ret.push_back((InputPort *)&_retPortForOutPool);
316 std::list<InputPort *> OptimizerLoop::getLocalInputPorts() const
318 list<InputPort *> ret=DynParaLoop::getLocalInputPorts();
319 ret.push_back((InputPort *)&_portForInitFile);
320 ret.push_back((InputPort *)&_retPortForOutPool);
324 void OptimizerLoop::selectRunnableTasks(std::vector<Task *>& tasks)
328 void OptimizerLoop::getReadyTasks(std::vector<Task *>& tasks)
332 if(_state==YACS::TOACTIVATE || _state==YACS::ACTIVATED)
334 if(_nodeForSpecialCases)
336 _nodeForSpecialCases->getReadyTasks(tasks);
339 for(vector<Node *>::iterator iter=_execNodes.begin();iter!=_execNodes.end();iter++)
340 (*iter)->getReadyTasks(tasks);
341 for(vector<Node *>::iterator iter2=_execInitNodes.begin();iter2!=_execInitNodes.end();iter2++)
342 (*iter2)->getReadyTasks(tasks);
348 YACS::Event OptimizerLoop::updateStateOnFinishedEventFrom(Node *node)
351 switch(getIdentityOfNotifyerNode(node,id))
354 _execNodes[id]->exUpdateState();
358 if(_state==YACS::DONE)//This case happend when alg has reached its convergence whereas other calculations still compute.
361 _condForCompletenessB4Relaunch.wait();
362 return YACS::NOEVENT;
364 _myPool.putOutSampleAt(_execIds[id],_interceptorsForOutPool[id]->getValue());
365 _myPool.setCurrentId(_execIds[id]);
366 _alg->takeDecision();
367 _myPool.destroyCurrentCase();
370 pushValueOutOfScopeForCase(id);
371 _execIds[id]=NOT_RUNNING_BRANCH_ID;
372 if(!isFullyLazy())// This case happens when the hand is returned to continue, whereas some other are working in parallel for nothing.
373 _convergenceReachedWithOtherCalc=true;
377 _execIds[id]=NOT_RUNNING_BRANCH_ID;
379 unsigned char priority;
380 Any *val=_myPool.getNextSampleWithHighestPriority(newId, priority);
383 bool isFinished=true;
384 for(int i=0;i<_execIds.size() and isFinished;i++)
385 isFinished=(_execIds[i]==NOT_RUNNING_BRANCH_ID);
388 std::cerr <<"OptimizerLoop::updateStateOnFinishedEventFrom: Alg has not inserted more cases whereas last element has been calculated !" << std::endl;
390 _state=YACS::INTERNALERR;
393 return YACS::NOEVENT;
395 launchMaxOfSamples(false);
397 return YACS::NOEVENT;
400 void OptimizerLoop::checkNoCyclePassingThrough(Node *node) throw(Exception)
404 void OptimizerLoop::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
406 DynParaLoop::buildDelegateOf(port,initialStart,pointsOfView);
407 if(port==&_retPortForOutPool)
408 throw Exception("OptimizerLoop::buildDelegateOf : uncorrect OptimizerLoop link : out pool port must be linked within the scope of OptimizerLoop node it belongs to.");
411 void OptimizerLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
413 DynParaLoop::buildDelegateOf(port,finalTarget,pointsOfView);
414 string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
415 if(typeOfPortInstance!=OutputPort::NAME)
416 throw Exception("OptimizerLoop::buildDelegateOf : not implemented for DS because not specified ");
419 void OptimizerLoop::checkControlDependancy(OutPort *start, InPort *end, bool cross,
420 std::map < ComposedNode *, std::list < OutPort * >, SortHierarc >& fw,
421 std::vector<OutPort *>& fwCross,
422 std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw,
423 LinkInfo& info) const
425 if(end==&_retPortForOutPool)
426 fw[(ComposedNode *)this].push_back(start);
428 DynParaLoop::checkControlDependancy(start,end,cross,fw,fwCross,bw,info);
431 void OptimizerLoop::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
433 if(end==&_retPortForOutPool)
434 solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
436 DynParaLoop::checkCFLinks(starts,end,alreadyFed,direction,info);
439 void OptimizerLoop::cleanInterceptors()
441 //the destruction of interceptors whereas some running nodes can push value on them can lead to SIG SEGV.
442 if(!_execNodes.empty())
444 if(_convergenceReachedWithOtherCalc)
446 cout << "Waiting completion of last other useless cases." << endl;
447 _condForCompletenessB4Relaunch.waitForAWait();
450 // At this point all garanties taken let's clean all.
451 map<InputPort *,vector<InputPort *> >::iterator iter=_interceptors.begin();
452 for(;iter!=_interceptors.end();iter++)
453 for(vector<InputPort *>::iterator iter2=(*iter).second.begin();iter2!=(*iter).second.end();iter2++)
455 _interceptors.clear();
456 for(vector<AnyInputPort *>::iterator iter3=_interceptorsForOutPool.begin();iter3!=_interceptorsForOutPool.end();iter3++)
458 _interceptorsForOutPool.clear();
461 void OptimizerLoop::launchMaxOfSamples(bool first)
464 unsigned char priority;
467 for(val=_myPool.getNextSampleWithHighestPriority(id,priority);!isFullyBusy(i) && val;val=_myPool.getNextSampleWithHighestPriority(id,priority))
470 _myPool.markIdAsInUse(id);
473 if(!_initNodeUpdated[i])
475 putValueOnBranch(val,i,first);
476 _execInitNodes[i]->exUpdateState();
477 _initNodeUpdated[i]=true;
481 putValueOnBranch(val,i,first);
482 _execNodes[i]->exUpdateState();
489 _execNodes[i]->init(first);
490 putValueOnBranch(val,i,first);
491 _execNodes[i]->exUpdateState();
497 bool OptimizerLoop::isFullyLazy() const
500 for(unsigned i=0;i<_execIds.size() and isLazy;i++)
501 isLazy=(_execIds[i]==NOT_RUNNING_BRANCH_ID);
506 * Returns if a dynamic branch is available.
507 * \param branchId Out param. Only usable if returned value is equal to \b false.
509 bool OptimizerLoop::isFullyBusy(unsigned& branchId) const
511 bool isFinished=true;
513 for(i=0;i<_execIds.size() and isFinished;i++)
514 isFinished=(_execIds[i]!=NOT_RUNNING_BRANCH_ID);
521 * Perform initialization of interceptors. \b WARNING _execNodes have to be created before.
523 void OptimizerLoop::initInterceptors(unsigned nbOfBr)
525 //For all classical outputports leaving 'this'
526 set<OutPort *> portsToIntercept=getAllOutPortsLeavingCurrentScope();
527 for(set<OutPort *>::iterator iter=portsToIntercept.begin();iter!=portsToIntercept.end();iter++)
529 OutputPort *portC=(OutputPort *)(*iter);//Warrantied by OptimizerLoop::buildDelegateOf
530 const set<InputPort *>& links=portC->getSetOfPhyLinks();
531 for(set<InputPort *>::const_iterator iter2=links.begin();iter2!=links.end();iter2++)
534 InputPort *reprCur=dynamic_cast<InputPort *>((*iter2)->getPublicRepresentant());
536 InputPort *reprCur=(*iter2)->getPublicRepresentant();
538 if(!isInMyDescendance(reprCur->getNode()))
539 {//here we've got an out of scope link : Let's intercept it
540 if(_interceptors.find(reprCur)==_interceptors.end())
542 _interceptors[reprCur].resize(nbOfBr);
543 for(unsigned i=0;i<nbOfBr;i++)
545 OutputPort *portExecC=(OutputPort *)_execNodes[i]->getOutputPort(_node->getOutPortName(portC));
546 InputPort *clone=reprCur->clone(0);
547 _interceptors[reprCur][i]=clone;
548 portExecC->edAddInputPort(clone);
553 for(unsigned i=0;i<nbOfBr;i++)
555 OutputPort *portExecC=(OutputPort *)_execNodes[i]->getOutputPort(_node->getOutPortName(portC));
556 portExecC->edAddInputPort(_interceptors[reprCur][i]);
563 _interceptorsForOutPool.resize(nbOfBr);
564 set< OutPort * > links=_retPortForOutPool.edSetOutPort();
565 for(unsigned i=0;i<nbOfBr;i++)
566 _interceptorsForOutPool[i]=(AnyInputPort *)_retPortForOutPool.clone(this);
567 for(set<OutPort *>::iterator iter2=links.begin();iter2!=links.end();iter2++)
568 for(unsigned j=0;j<nbOfBr;j++)
571 Node *whatType=isInMyDescendance((*iter2)->getNode());
574 portExec=_execNodes[j]->getOutPort(_node->getOutPortName(*iter2));
575 portExec->addInPort(_interceptorsForOutPool[j]);
577 else if(whatType==_initNode && whatType!=0)//This case should never happend. Useless !
579 portExec=_execInitNodes[j]->getOutPort(_node->getOutPortName(*iter2));
580 portExec->addInPort(_interceptorsForOutPool[j]);
586 * Typically called when _alg has decided that convergence has been reached. In this case the links leaving the current scope are activated and filled
587 * with value of the branch specified by 'branchId' that is the branch in which the convergence has been reached.
589 void OptimizerLoop::pushValueOutOfScopeForCase(unsigned branchId)
591 map<InputPort *, std::vector<InputPort *> >::iterator iter;
592 for(iter=_interceptors.begin();iter!=_interceptors.end();iter++)
593 (*iter).first->put((*iter).second[branchId]->get());