Parcourir la source

End of documentation for operators selection process

Jérôme BUISINE il y a 3 ans
Parent
commit
d2fb19586d

BIN
docs/figures/macop_behaviour.kra


BIN
docs/figures/operators_choice.kra


BIN
docs/figures/operators_choice.kra~


BIN
docs/figures/project_knapsack_problem.kra


BIN
docs/figures/project_knapsack_problem_op.kra


BIN
docs/source/_static/documentation/operators_choice.png


+ 92 - 3
docs/source/documentations/policies.rst

@@ -7,11 +7,100 @@ The ``policy`` feature of **Macop** enables to choose the next operator to apply
 ~~~~~~~~~~~~~~~~~~~~~~~
 
 Sometimes the nature of the problem and its instance can strongly influence the search results when using mutation operators or crossovers. 
-Automated operator choice strategies have been developed in the literature, notably based on reinforcement learning.
+Automated operator choice strategies have also been developed in the literature, notably based on reinforcement learning.
+
+The operator choice problem can be seen as the desire to find the best solution generation operator at the next evaluation that will be the most conducive to precisely improving the solution.
+
+.. image:: ../_static/documentation/operators_choice.png
+   :width:  400 px
+   :align: center
 
 .. note::
-    An implementation by reinforcement has been developed as an example in the ``macop.policies.reinforcement`` module. 
+    An implementation using reinforcement learning has been developed as an example in the ``macop.policies.reinforcement`` module. 
     However, it will not be detailed here. You can refer to the API documentation for more details.
 
+
 7.2. Custom policy
-~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~
+
+In our case, we are not going to exploit a complex enough implementation of a ``policy``. Simply, we will use a random choice of operator.
+
+First, let's take a look of the ``policy`` abstract class available in ``macop.policies.base``:
+
+.. code-block:: python
+
+    class Policy():
+
+        def __init__(self, operators):
+            self._operators = operators
+
+        @abstractmethod
+        def select(self):
+            """
+            Select specific operator
+            """
+            pass
+
+        def apply(self, solution):
+            """
+            Apply specific operator to create new solution, compute its fitness and return it
+            """
+            ...
+
+        def setAlgo(self, algo):
+            """
+            Keep into policy reference of the whole algorithm
+            """
+            ...
+
+
+``Policy`` instance will have of ``_operators`` attributs in order to keep track of possible operators when selecting one. 
+Here, in our implementation we only need to specify the ``select`` abstract method. The ``apply`` method will select the next operator and return the new solution.
+
+.. code-block:: python
+
+    """
+    module imports
+    """
+    from macop.policies.base import Policy
+
+    class RandomPolicy(Policy):
+
+        def select(self):
+            """
+            Select specific operator
+            """
+            # choose operator randomly
+            index = random.randint(0, len(self._operators) - 1)
+            return self._operators[index]
+
+
+We can now use this operator choice policy to update our current solution:
+
+
+.. code-block:: python
+
+    """
+    Operators instances
+    """
+    mutator = SimpleMutation()
+    crossover = SimpleCrossover()
+
+    """
+    RandomPolicy instance
+    """
+    policy = RandomPolicy([mutator, crossover])
+
+    """
+    Current solutions instance
+    """
+    solution1 = BinarySolution.random(5)
+    solution2 = BinarySolution.random(5)
+
+    # pass two solutions in parameters in case of selected crossover operator
+    new_solution = policy.apply(solution1, solution2)
+
+.. warning::
+    By default if ``solution2`` parameter is not provided into ``policy.apply`` method for crossover, the best solution known is used from the algorithm linked to the ``policy``.
+
+Updating solutions is therefore now possible with our policy. It is high time to dive into the process of optimizing solutions and digging into our research space.

+ 23 - 6
macop/policies/base.py

@@ -4,6 +4,9 @@ import logging
 from abc import abstractmethod
 
 
+from ..operators.base import KindOperator
+
+
 # define policy to choose `operator` function at current iteration
 class Policy():
     """Abstract class which is used for applying strategy when selecting and applying operator 
@@ -24,12 +27,13 @@ class Policy():
         """
         pass
 
-    def apply(self, solution):
+    def apply(self, solution1, solution2=None):
         """
-        Apply specific operator chosen to create new solution, computes its fitness and returns solution
+        Apply specific operator chosen to create new solution, compute its fitness and return solution
         
         Args:
-            _solution: {Solution} -- the solution to use for generating new solution
+            solution1: {Solution} -- the first solution to use for generating new solution
+            solution2: {Solution} -- the second solution to use for generating new solution (in case of specific crossover, default is best solution from algorithm)
 
         Returns:
             {Solution} -- new generated solution
@@ -38,12 +42,25 @@ class Policy():
         operator = self.select()
 
         logging.info("---- Applying %s on %s" %
-                     (type(operator).__name__, solution))
+                     (type(operator).__name__, solution1))
+
+        # default value of solution2 is current best solution
+        if solution2 is None and self._algo is not None:
+            solution2 = self._algo._bestSolution
+
+        # avoid use of crossover if only one solution is passed
+        if solution2 is None and operator._kind == KindOperator.CROSSOVER:
+
+            while operator._kind == KindOperator.CROSSOVER:            
+                operator = self.select()
 
         # apply operator on solution
-        newSolution = operator.apply(solution)
+        if operator._kind == KindOperator.CROSSOVER:
+            newSolution = operator.apply(solution1, solution2)
+        else:
+            newSolution = operator.apply(solution1)
 
-        logging.info("---- Obtaining %s" % (solution))
+        logging.info("---- Obtaining %s" % (newSolution))
 
         return newSolution