Salome HOME
[EDF27816] : Fix bug presence of proxy into a list
[modules/yacs.git] / doc / optimizer.rst
index 9fda369578756e93fe7fd1afef53e991997b080c..9dd3dcf2f46c11d543271969668a6917942e89c6 100644 (file)
@@ -7,6 +7,9 @@ The definition of the optimization algorithm is done by way of plugin.
 The plugin can be a C++ plugin implemented in a dynamic library (.so file) or a Python plugin implemented in a Python module (.py).
 It is possible to implement two kinds of algorithm : synchronous or asynchronous.
 
+The algorithm uses a pool of samples to be evaluated.
+When all the samples of the pool are evaluated, the algorithm stops.
+
 Synchronous algorithm
 --------------------------------------------------
 In synchronous mode, the OptimizerLoop calls the algorithm to know what are the types of the input port (sample sent to the internal node), 
@@ -19,10 +22,13 @@ must be implemented and some optional methods (in C++ and in Python):
 
 - **getTCForIn**, this method must return the YACS type of the input port of the internal node
 - **getTCForOut**, this method must return the YACS type of the output port of the internal node
+- **getTCForAlgoInit** (optional), this method returns the type of the "algoInit" port, string if undefined
+- **getTCForAlgoResult** (optional), this method returns the type of the "algoResult" port, string if undefined
 - **initialize** (optional), this method is called during the algorithm initialization
 - **start**, this method is called at the beginning of iterations
 - **takeDecision**, this method is called at each iteration
 - **finish** (optional), this method is called to finish the algorithm at the end of the iteration process
+- **getAlgoResult** (optional), this method returns the value of the "algoResult" port, "NULL" if undefined
 
 In Python you need to implement another method:
 
@@ -32,191 +38,17 @@ C++ plugin example
 ''''''''''''''''''''
 Here is a small example of a C++ synchronous algorithm:
 
-.. code-block:: cpp
-
-  #include <cmath>
-  
-  #include "OptimizerAlg.hxx"
-  
-  using namespace YACS::ENGINE;
-  
-  extern "C"
-  {
-    OptimizerAlgBase * createOptimizerAlgSyncExample(Pool * pool);
-  }
-  
-  class OptimizerAlgSyncExample : public OptimizerAlgSync
-    {
-    private:
-      int _idTest;
-      TypeCode *_tcIn;
-      TypeCode *_tcOut;
-    public:
-      OptimizerAlgSyncExample(Pool *pool);
-      virtual ~OptimizerAlgSyncExample();
-      TypeCode *getTCForIn() const;
-      TypeCode *getTCForOut() const;
-      void start();
-      void takeDecision();
-      void initialize(const Any *input) throw(YACS::Exception);
-      void finish();
-    };
-  
-  OptimizerAlgSyncExample::OptimizerAlgSyncExample(Pool *pool)
-    : OptimizerAlgSync(pool), _tcIn(0), _tcOut(0), _idTest(0)
-  {
-    _tcIn=new TypeCode(Double);
-    _tcOut=new TypeCode(Int);
-  }
-  
-  OptimizerAlgSyncExample::~OptimizerAlgSyncExample()
-  {
-    _tcIn->decrRef();
-    _tcOut->decrRef();
-  }
-  
-  //! Return the typecode of the expected input type
-  TypeCode * OptimizerAlgSyncExample::getTCForIn() const
-  {
-    return _tcIn;
-  }
-  
-  //! Return the typecode of the expected output type
-  TypeCode * OptimizerAlgSyncExample::getTCForOut() const
-  {
-    return _tcOut;
-  }
-  
-  //! Start to fill the pool with samples to evaluate
-  void OptimizerAlgSyncExample::start()
-  {
-    _idTest=0;
-    Any *val=AtomAny::New(1.2);
-    _pool->pushInSample(4,val);
-    val=AtomAny::New(3.4);
-    _pool->pushInSample(9,val);
-  }
-  
-  //! This method is called each time a sample has been evaluated.
-  /*!
-   *  It can either add new samples to evaluate in the pool, do nothing (wait
-   *  for more samples), or empty the pool to finish the evaluation.
-   */
-  void OptimizerAlgSyncExample::takeDecision()
-  {
-    if(_idTest==1)
-      {
-        Any *val=AtomAny::New(5.6);
-        _pool->pushInSample(16,val);
-        val=AtomAny::New(7.8);
-        _pool->pushInSample(25,val);
-        val=AtomAny::New(9. );
-        _pool->pushInSample(36,val);
-        val=AtomAny::New(12.3);
-        _pool->pushInSample(49,val);
-      }
-    else if(_idTest==4)
-      {
-        Any *val=AtomAny::New(45.6);
-        _pool->pushInSample(64,val);
-        val=AtomAny::New(78.9);
-        _pool->pushInSample(81,val);
-      }
-    else
-      {
-        Any *tmp= _pool->getCurrentInSample();
-        if(fabs(tmp->getDoubleValue()-45.6)<1.e-12)
-          _pool->destroyAll();
-      }
-    _idTest++;
-  }
-  
-  //! Optional method to initialize the algorithm.
-  /*!
-   *  For now, the parameter input is always NULL. It might be used in the
-   *  future to initialize an algorithm with custom data.
-   */
-  void OptimizerAlgSyncExample::initialize(const Any *input)
-    throw (YACS::Exception)
-  {
-  }
-  
-  /*!
-   *  Optional method called when the algorithm has finished, successfully or
-   *  not, to perform any necessary clean up.
-   */
-  void OptimizerAlgSyncExample::finish()
-  {
-  }
-  
-  //! Factory method to create the algorithm.
-  OptimizerAlgBase * createOptimizerAlgSyncExample(Pool *pool)
-  {
-    return new OptimizerAlgSyncExample(pool);
-  }
-
+.. literalinclude:: ../src/yacsloader/Test/OptimizerAlgSyncExample.cxx
+    :language: cpp
 
 Here, the entry point in the dynamic library is the name of the factory function : createOptimizerAlgSyncExample
 that returns an instance of the OptimizerAlgSyncExample class that implements the algorithm.
 
 Python plugin example
 ''''''''''''''''''''''
-Here, the same example of a synchronous algorithm in Python::
-
-  import SALOMERuntime
-  
-  class myalgosync(SALOMERuntime.OptimizerAlgSync):
-    def __init__(self):
-      SALOMERuntime.OptimizerAlgSync.__init__(self, None)
-      r=SALOMERuntime.getSALOMERuntime()
-      self.tin=r.getTypeCode("double")
-      self.tout=r.getTypeCode("int")
-  
-    def setPool(self,pool):
-      """Must be implemented to set the pool"""
-      self.pool=pool
-  
-    def getTCForIn(self):
-      """returns typecode of type expected as Input"""
-      return self.tin
-  
-    def getTCForOut(self):
-      """returns typecode of type expected as Output"""
-      return self.tout
-  
-    def initialize(self,input):
-      """Optional method called on initialization. Do nothing here"""
-  
-    def start(self):
-      """Start to fill the pool with samples to evaluate."""
-      self.iter=0
-      self.pool.pushInSample(4,1.2)
-      self.pool.pushInSample(9,3.4)
-  
-    def takeDecision(self):
-      """ This method is called each time a sample has been evaluated. It can
-          either add new samples to evaluate in the pool, do nothing (wait for
-          more samples), or empty the pool to finish the evaluation.
-      """
-      currentId=self.pool.getCurrentId()
-  
-      if self.iter==1:
-        self.pool.pushInSample(16,5.6)
-        self.pool.pushInSample(25,7.8)
-        self.pool.pushInSample(36,9.)
-        self.pool.pushInSample(49,12.3)
-      elif self.iter==4:
-        self.pool.pushInSample(64,45.6)
-        self.pool.pushInSample(81,78.9)
-      else:
-        val=self.pool.getCurrentInSample()
-        if abs(val.getDoubleValue()-45.6) < 1.e-12:
-          self.pool.destroyAll()
-      self.iter=self.iter+1
-  
-    def finish(self):
-      """Optional method called when the algorithm has finished, successfully
-         or not, to perform any necessary clean up. Do nothing here"""
+Here, the same example of a synchronous algorithm in Python:
+
+.. literalinclude:: ../src/yacsloader/Test/algosyncexample.py
 
 Here, the entry point in the Python module is directly the name of the class that implements the algorithm : myalgosync.
 
@@ -231,9 +63,12 @@ must be implemented and some optional methods (in C++ and in Python):
 
 - **getTCForIn**, this method must return the YACS type of the input port of the internal node
 - **getTCForOut**, this method must return the YACS type of the output port of the internal node
+- **getTCForAlgoInit** (optional), this method returns the type of the "algoInit" port, string if undefined
+- **getTCForAlgoResult** (optional), this method returns the type of the "algoResult" port, string if undefined
 - **initialize** (optional), this method is called during the algorithm initialization
 - **startToTakeDecision**, this method is called to start the iteration process in a separate thread. It is the body of the algorithm.
 - **finish** (optional), this method is called to finish the algorithm at the end of the iteration process
+- **getAlgoResult** (optional), this method returns the value of the "algoResult" port, "NULL" if undefined
 
 In Python you need to implement another method:
 
@@ -243,94 +78,8 @@ C++ plugin example
 ''''''''''''''''''''
 Here is a small example of a C++ asynchronous algorithm:
 
-.. code-block:: cpp
-
-  #include "OptimizerAlg.hxx"
-  
-  using namespace YACS::ENGINE;
-  
-  extern "C"
-  {
-    OptimizerAlgBase * createOptimizerAlgASyncExample(Pool * pool);
-  }
-  
-  class OptimizerAlgASyncExample : public OptimizerAlgASync
-    {
-    private:
-      TypeCode * _tcIn;
-      TypeCode * _tcOut;
-    public:
-      OptimizerAlgASyncExample(Pool * pool);
-      virtual ~OptimizerAlgASyncExample();
-      TypeCode * getTCForIn() const;
-      TypeCode * getTCForOut() const;
-      void startToTakeDecision();
-    };
-  
-  OptimizerAlgASyncExample::OptimizerAlgASyncExample(Pool * pool)
-    : OptimizerAlgASync(pool), _tcIn(0), _tcOut(0)
-  {
-    _tcIn = new TypeCode(Double);
-    _tcOut = new TypeCode(Int);
-  }
-  
-  OptimizerAlgASyncExample::~OptimizerAlgASyncExample()
-  {
-    _tcIn->decrRef();
-    _tcOut->decrRef();
-  }
-  
-  //! Return the typecode of the expected input type
-  TypeCode *OptimizerAlgASyncExample::getTCForIn() const
-  {
-    return _tcIn;
-  }
-  
-  //! Return the typecode of the expected output type
-  TypeCode *OptimizerAlgASyncExample::getTCForOut() const
-  {
-    return _tcOut;
-  }
-  
-  //! This method is called only once to launch the algorithm.
-  /*!
-   *  It must first fill the pool with samples to evaluate and call
-   *  signalMasterAndWait() to block until a sample has been evaluated. When
-   *  returning from this method, it MUST check for an eventual termination
-   *  request (with the method isTerminationRequested()). If the termination
-   *  is requested, the method must perform any necessary cleanup and return
-   *  as soon as possible. Otherwise it can either add new samples to evaluate
-   *  in the pool, do nothing (wait for more samples), or empty the pool and
-   *  return to finish the evaluation.
-   */
-  void OptimizerAlgASyncExample::startToTakeDecision()
-  {
-    double val = 1.2;
-    for (int i=0 ; i<5 ; i++) {
-      // push a sample in the input of the slave node
-      _pool->pushInSample(i, AtomAny::New(val));
-      // wait until next sample is ready
-      signalMasterAndWait();
-      // check error notification
-      if (isTerminationRequested()) {
-        _pool->destroyAll();
-        return;
-      }
-  
-      // get a sample from the output of the slave node
-      Any * v = _pool->getCurrentOutSample();
-      val += v->getIntValue();
-    }
-  
-    // in the end destroy the pool content
-    _pool->destroyAll();
-  }
-  
-  //! Factory method to create the algorithm.
-  OptimizerAlgBase * createOptimizerAlgASyncExample(Pool * pool)
-  {
-    return new OptimizerAlgASyncExample(pool);
-  }
+.. literalinclude:: ../src/yacsloader/Test/OptimizerAlgASyncExample.cxx
+    :language: cpp
 
 
 Here, the entry point in the dynamic library is the name of the factory function : createOptimizerAlgASyncExample
@@ -338,62 +87,59 @@ that returns an instance of the OptimizerAlgASyncExample class that implements t
 
 Python plugin example
 ''''''''''''''''''''''''
-Here is an example of an asynchronous algorithm implemented in Python::
-
-  import SALOMERuntime
-  
-  class myalgoasync(SALOMERuntime.OptimizerAlgASync):
-    def __init__(self):
-      SALOMERuntime.OptimizerAlgASync.__init__(self, None)
-      r=SALOMERuntime.getSALOMERuntime()
-      self.tin=r.getTypeCode("double")
-      self.tout=r.getTypeCode("int")
-  
-    def setPool(self,pool):
-      """Must be implemented to set the pool"""
-      self.pool=pool
-  
-    def getTCForIn(self):
-      """returns typecode of type expected as Input"""
-      return self.tin
-  
-    def getTCForOut(self):
-      """returns typecode of type expected as Output"""
-      return self.tout
-  
-    def startToTakeDecision(self):
-      """This method is called only once to launch the algorithm. It must
-         first fill the pool with samples to evaluate and call
-         self.signalMasterAndWait() to block until a sample has been
-         evaluated. When returning from this method, it MUST check for an
-         eventual termination request (with the method
-         self.isTerminationRequested()). If the termination is requested, the
-         method must perform any necessary cleanup and return as soon as
-         possible. Otherwise it can either add new samples to evaluate in the
-         pool, do nothing (wait for more samples), or empty the pool and
-         return to finish the evaluation.
-      """
-      val=1.2
-      for iter in xrange(5):
-        #push a sample in the input of the slave node
-        self.pool.pushInSample(iter,val)
-        #wait until next sample is ready
-        self.signalMasterAndWait()
-        #check error notification
-        if self.isTerminationRequested():
-          self.pool.destroyAll()
-          return
-  
-        #get a sample from the output of the slave node
-        currentId=self.pool.getCurrentId()
-        v=self.pool.getCurrentOutSample()
-        val=val+v.getIntValue()
-  
-      #in the end destroy the pool content
-      self.pool.destroyAll()
+Here is an example of an asynchronous algorithm implemented in Python:
+
+.. literalinclude:: ../src/yacsloader/Test/algoasyncexample.py
 
 Here, the entry point in the Python module is directly the name of the class that implements the algorithm : myalgoasync.
 
+Managing the pool of samples
+---------------------------------
+
+Samples can be added to the pool at the initialization of the algorithm or
+every time a sample is evaluated (while "taking decision").
+The algorithm stops to take decisions when every sample is evaluated.
+
+A sample has:
+
+- an identifier - *Id*
+- a priority - it is used to choose the order of evaluation
+- a value - *In*
+- an evaluated or computed value - *Out*
+
+The current sample is the sample used by the latest terminated evaluation.
+
+These are the methods needed to manage the pool of samples:
+
+.. code-block:: cpp
+
+  class Pool
+  {
+      //...
+    public:
+      //For algorithm use
+      int getCurrentId() const ;
+      Any *getCurrentInSample() const ;
+      Any *getCurrentOutSample() const ;
+      Any *getOutSample(int id);
+      void pushInSample(int id, Any *inSample, unsigned char priority = 0);
+      void destroyAll();
+      //...
+  }
+
+In C++, the samples are of type ``YACS::ENGINE::Any``, in order to support any
+type supported by YACS. For conversion to standard types, use:
+
+- ``getIntValue``
+- ``getBoolValue``
+- ``getDoubleValue``
+- ``getStringValue``
+
+It is possible to create a pointer to a new object with:
+
+- ``YACS::ENGINE::AtomAny::New``
+
+For further information, see `include/salome/Any.hxx <file:../../../../../include/salome/Any.hxx>`_.
 
 C++ algorithm calling Python code
 --------------------------------------------------