2 .. _optimizationplugin:
4 Definition of an algorithm for the OptimizerLoop
5 ==========================================================================
6 The definition of the optimization algorithm is done by way of plugin.
7 The plugin can be a C++ plugin implemented in a dynamic library (.so file) or a Python plugin implemented in a Python module (.py).
8 It is possible to implement two kinds of algorithm : synchronous or asynchronous.
11 --------------------------------------------------
12 In synchronous mode, the OptimizerLoop calls the algorithm to know what are the types of the input port (sample sent to the internal node),
13 and of the output port (data returned by the internal node). Then it calls the algorithm to initialize
14 it. At each iteration, it calls the algorithm to produce new sample or to stop the iteration. Finally, it calls the algorithm
15 to finalize the optimization process.
17 A synchronous algorithm is implemented in a class derived from the base class OptimizerAlgSync with several methods that
18 must be implemented and some optional methods (in C++ and in Python):
20 - **getTCForIn**, this method must return the YACS type of the input port of the internal node
21 - **getTCForOut**, this method must return the YACS type of the output port of the internal node
22 - **initialize** (optional), this method is called during the algorithm initialization
23 - **start**, this method is called at the beginning of iterations
24 - **takeDecision**, this method is called at each iteration
25 - **finish** (optional), this method is called to finish the algorithm at the end of the iteration process
27 In Python you need to implement another method:
29 - **setPool**, this method is used to set the data pool that is used to exchange data
33 Here is a small example of a C++ synchronous algorithm:
39 #include "OptimizerAlg.hxx"
41 using namespace YACS::ENGINE;
45 OptimizerAlgBase * createOptimizerAlgSyncExample(Pool * pool);
48 class OptimizerAlgSyncExample : public OptimizerAlgSync
55 OptimizerAlgSyncExample(Pool *pool);
56 virtual ~OptimizerAlgSyncExample();
57 TypeCode *getTCForIn() const;
58 TypeCode *getTCForOut() const;
61 void initialize(const Any *input) throw(YACS::Exception);
65 OptimizerAlgSyncExample::OptimizerAlgSyncExample(Pool *pool)
66 : OptimizerAlgSync(pool), _tcIn(0), _tcOut(0), _idTest(0)
68 _tcIn=new TypeCode(Double);
69 _tcOut=new TypeCode(Int);
72 OptimizerAlgSyncExample::~OptimizerAlgSyncExample()
78 //! Return the typecode of the expected input type
79 TypeCode * OptimizerAlgSyncExample::getTCForIn() const
84 //! Return the typecode of the expected output type
85 TypeCode * OptimizerAlgSyncExample::getTCForOut() const
90 //! Start to fill the pool with samples to evaluate
91 void OptimizerAlgSyncExample::start()
94 Any *val=AtomAny::New(1.2);
95 _pool->pushInSample(4,val);
96 val=AtomAny::New(3.4);
97 _pool->pushInSample(9,val);
100 //! This method is called each time a sample has been evaluated.
102 * It can either add new samples to evaluate in the pool, do nothing (wait
103 * for more samples), or empty the pool to finish the evaluation.
105 void OptimizerAlgSyncExample::takeDecision()
109 Any *val=AtomAny::New(5.6);
110 _pool->pushInSample(16,val);
111 val=AtomAny::New(7.8);
112 _pool->pushInSample(25,val);
113 val=AtomAny::New(9. );
114 _pool->pushInSample(36,val);
115 val=AtomAny::New(12.3);
116 _pool->pushInSample(49,val);
120 Any *val=AtomAny::New(45.6);
121 _pool->pushInSample(64,val);
122 val=AtomAny::New(78.9);
123 _pool->pushInSample(81,val);
127 Any *tmp= _pool->getCurrentInSample();
128 if(fabs(tmp->getDoubleValue()-45.6)<1.e-12)
134 //! Optional method to initialize the algorithm.
136 * For now, the parameter input is always NULL. It might be used in the
137 * future to initialize an algorithm with custom data.
139 void OptimizerAlgSyncExample::initialize(const Any *input)
140 throw (YACS::Exception)
145 * Optional method called when the algorithm has finished, successfully or
146 * not, to perform any necessary clean up.
148 void OptimizerAlgSyncExample::finish()
152 //! Factory method to create the algorithm.
153 OptimizerAlgBase * createOptimizerAlgSyncExample(Pool *pool)
155 return new OptimizerAlgSyncExample(pool);
159 Here, the entry point in the dynamic library is the name of the factory function : createOptimizerAlgSyncExample
160 that returns an instance of the OptimizerAlgSyncExample class that implements the algorithm.
162 Python plugin example
163 ''''''''''''''''''''''
164 Here, the same example of a synchronous algorithm in Python::
168 class myalgosync(SALOMERuntime.OptimizerAlgSync):
170 SALOMERuntime.OptimizerAlgSync.__init__(self, None)
171 r=SALOMERuntime.getSALOMERuntime()
172 self.tin=r.getTypeCode("double")
173 self.tout=r.getTypeCode("int")
175 def setPool(self,pool):
176 """Must be implemented to set the pool"""
179 def getTCForIn(self):
180 """returns typecode of type expected as Input"""
183 def getTCForOut(self):
184 """returns typecode of type expected as Output"""
187 def initialize(self,input):
188 """Optional method called on initialization. Do nothing here"""
191 """Start to fill the pool with samples to evaluate."""
193 self.pool.pushInSample(4,1.2)
194 self.pool.pushInSample(9,3.4)
196 def takeDecision(self):
197 """ This method is called each time a sample has been evaluated. It can
198 either add new samples to evaluate in the pool, do nothing (wait for
199 more samples), or empty the pool to finish the evaluation.
201 currentId=self.pool.getCurrentId()
204 self.pool.pushInSample(16,5.6)
205 self.pool.pushInSample(25,7.8)
206 self.pool.pushInSample(36,9.)
207 self.pool.pushInSample(49,12.3)
209 self.pool.pushInSample(64,45.6)
210 self.pool.pushInSample(81,78.9)
212 val=self.pool.getCurrentInSample()
213 if abs(val.getDoubleValue()-45.6) < 1.e-12:
214 self.pool.destroyAll()
215 self.iter=self.iter+1
218 """Optional method called when the algorithm has finished, successfully
219 or not, to perform any necessary clean up. Do nothing here"""
221 Here, the entry point in the Python module is directly the name of the class that implements the algorithm : myalgosync.
224 Asynchronous algorithm
225 --------------------------------------------------
226 In asynchronous mode, all is the same except that after the initialization phase, the OptimizerLoop calls the algorithm only one time
227 to start it in a separate thread.
229 An asynchronous algorithm is implemented in a class derived from the base class OptimizerAlgASync with several methods that
230 must be implemented and some optional methods (in C++ and in Python):
232 - **getTCForIn**, this method must return the YACS type of the input port of the internal node
233 - **getTCForOut**, this method must return the YACS type of the output port of the internal node
234 - **initialize** (optional), this method is called during the algorithm initialization
235 - **startToTakeDecision**, this method is called to start the iteration process in a separate thread. It is the body of the algorithm.
236 - **finish** (optional), this method is called to finish the algorithm at the end of the iteration process
238 In Python you need to implement another method:
240 - **setPool**, this method is used to set the data pool that is used to exchange data
244 Here is a small example of a C++ asynchronous algorithm:
248 #include "OptimizerAlg.hxx"
250 using namespace YACS::ENGINE;
254 OptimizerAlgBase * createOptimizerAlgASyncExample(Pool * pool);
257 class OptimizerAlgASyncExample : public OptimizerAlgASync
263 OptimizerAlgASyncExample(Pool * pool);
264 virtual ~OptimizerAlgASyncExample();
265 TypeCode * getTCForIn() const;
266 TypeCode * getTCForOut() const;
267 void startToTakeDecision();
270 OptimizerAlgASyncExample::OptimizerAlgASyncExample(Pool * pool)
271 : OptimizerAlgASync(pool), _tcIn(0), _tcOut(0)
273 _tcIn = new TypeCode(Double);
274 _tcOut = new TypeCode(Int);
277 OptimizerAlgASyncExample::~OptimizerAlgASyncExample()
283 //! Return the typecode of the expected input type
284 TypeCode *OptimizerAlgASyncExample::getTCForIn() const
289 //! Return the typecode of the expected output type
290 TypeCode *OptimizerAlgASyncExample::getTCForOut() const
295 //! This method is called only once to launch the algorithm.
297 * It must first fill the pool with samples to evaluate and call
298 * signalMasterAndWait() to block until a sample has been evaluated. When
299 * returning from this method, it MUST check for an eventual termination
300 * request (with the method isTerminationRequested()). If the termination
301 * is requested, the method must perform any necessary cleanup and return
302 * as soon as possible. Otherwise it can either add new samples to evaluate
303 * in the pool, do nothing (wait for more samples), or empty the pool and
304 * return to finish the evaluation.
306 void OptimizerAlgASyncExample::startToTakeDecision()
309 for (int i=0 ; i<5 ; i++) {
310 // push a sample in the input of the slave node
311 _pool->pushInSample(i, AtomAny::New(val));
312 // wait until next sample is ready
313 signalMasterAndWait();
314 // check error notification
315 if (isTerminationRequested()) {
320 // get a sample from the output of the slave node
321 Any * v = _pool->getCurrentOutSample();
322 val += v->getIntValue();
325 // in the end destroy the pool content
329 //! Factory method to create the algorithm.
330 OptimizerAlgBase * createOptimizerAlgASyncExample(Pool * pool)
332 return new OptimizerAlgASyncExample(pool);
336 Here, the entry point in the dynamic library is the name of the factory function : createOptimizerAlgASyncExample
337 that returns an instance of the OptimizerAlgASyncExample class that implements the algorithm.
339 Python plugin example
340 ''''''''''''''''''''''''
341 Here is an example of an asynchronous algorithm implemented in Python::
345 class myalgoasync(SALOMERuntime.OptimizerAlgASync):
347 SALOMERuntime.OptimizerAlgASync.__init__(self, None)
348 r=SALOMERuntime.getSALOMERuntime()
349 self.tin=r.getTypeCode("double")
350 self.tout=r.getTypeCode("int")
352 def setPool(self,pool):
353 """Must be implemented to set the pool"""
356 def getTCForIn(self):
357 """returns typecode of type expected as Input"""
360 def getTCForOut(self):
361 """returns typecode of type expected as Output"""
364 def startToTakeDecision(self):
365 """This method is called only once to launch the algorithm. It must
366 first fill the pool with samples to evaluate and call
367 self.signalMasterAndWait() to block until a sample has been
368 evaluated. When returning from this method, it MUST check for an
369 eventual termination request (with the method
370 self.isTerminationRequested()). If the termination is requested, the
371 method must perform any necessary cleanup and return as soon as
372 possible. Otherwise it can either add new samples to evaluate in the
373 pool, do nothing (wait for more samples), or empty the pool and
374 return to finish the evaluation.
377 for iter in xrange(5):
378 #push a sample in the input of the slave node
379 self.pool.pushInSample(iter,val)
380 #wait until next sample is ready
381 self.signalMasterAndWait()
382 #check error notification
383 if self.isTerminationRequested():
384 self.pool.destroyAll()
387 #get a sample from the output of the slave node
388 currentId=self.pool.getCurrentId()
389 v=self.pool.getCurrentOutSample()
390 val=val+v.getIntValue()
392 #in the end destroy the pool content
393 self.pool.destroyAll()
395 Here, the entry point in the Python module is directly the name of the class that implements the algorithm : myalgoasync.
398 C++ algorithm calling Python code
399 --------------------------------------------------
401 In some cases, it can be necessary to implement the algorithm as a C++ class but
402 nevertheless to call some Python code from this class. This is also possible with the
403 OptimizerLoop and even quite simple. To achieve this, your C++ class should inherit from
404 PyOptimizerAlgSync for a synchronous algorithm or from PyOptimizerAlgASync for an
405 asynchronous algorithm. The guidelines for developing the algorithm are the same as in
406 the C++ case, but you can also call any method from the Python C API. You don't need to
407 take care of the Python global interpreter lock or of thread states because this is
408 already done in the PyOptimizerAlg classes. An example of this kind of algorithm is the
409 class OpenTURNSScriptLauncher that can be found in the module OPENTURNS_SRC.