ソースを参照

new documentation version

Jérôme BUISINE 3 年 前
コミット
32441a78f2

+ 0 - 1
.github/workflows/docs.yml

@@ -22,7 +22,6 @@ jobs:
     - name: Commit documentation changes
     - name: Commit documentation changes
       run: |
       run: |
         git clone https://github.com/jbuisine/macop.git --branch gh-pages --single-branch gh-pages
         git clone https://github.com/jbuisine/macop.git --branch gh-pages --single-branch gh-pages
-        ls -l docs/_build
         cp -r docs/* gh-pages/docs
         cp -r docs/* gh-pages/docs
         cd gh-pages
         cd gh-pages
         touch .nojekyll
         touch .nojekyll

+ 1 - 1
.github/workflows/python-app.yml

@@ -15,7 +15,7 @@ jobs:
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
     strategy:
     strategy:
       matrix:
       matrix:
-        python-version: [3.6, 3.7, 3.8]
+        python-version: [3.8, 3.9]
 
 
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2

+ 1 - 1
.github/workflows/python-publish.yml

@@ -18,7 +18,7 @@ jobs:
     - name: Set up Python
     - name: Set up Python
       uses: actions/setup-python@v2
       uses: actions/setup-python@v2
       with:
       with:
-        python-version: '3.x'
+        python-version: '3.8'
     - name: Install dependencies
     - name: Install dependencies
       run: |
       run: |
         python -m pip install --upgrade pip
         python -m pip install --upgrade pip

+ 3 - 0
docs/source/conf.py

@@ -154,6 +154,9 @@ html_static_path = ['_static']
 # 'searchbox.html']``.
 # 'searchbox.html']``.
 #
 #
 # html_sidebars = {}
 # html_sidebars = {}
+# html_sidebars = { '**': ['globaltoc.html', 'relations.html', 'sourcelink.html', 'searchbox.html'] }
+
+html_sidebars = {'**': ['fulltoc.html', 'relations.html', 'sourcelink.html', 'searchbox.html']}
 
 
 # -- Options for HTMLHelp output ---------------------------------------------
 # -- Options for HTMLHelp output ---------------------------------------------
 
 

ファイルの差分が大きいため隠しています
+ 1329 - 0
docs/source/documentations.rst


+ 1 - 1
docs/source/documentations/operators.rst

@@ -193,7 +193,7 @@ We can now use the crossover operator created to generate new solutions. Here is
     # obtaining new solution using crossover
     # obtaining new solution using crossover
     offspring = crossover.apply(solution1, solution2)
     offspring = crossover.apply(solution1, solution2)
 
 
-.. warning::
+.. tip::
     The developed ``SimpleCrossover`` is available into ``macop.operators.discrete.crossovers.SimpleCrossover`` in **Macop**.
     The developed ``SimpleCrossover`` is available into ``macop.operators.discrete.crossovers.SimpleCrossover`` in **Macop**.
     However, the choice of halves of the merged data is made randomly.
     However, the choice of halves of the merged data is made randomly.
 
 

+ 1 - 1
docs/source/documentations/policies.rst

@@ -100,7 +100,7 @@ We can now use this operator choice policy to update our current solution:
     # pass two solutions in parameters in case of selected crossover operator
     # pass two solutions in parameters in case of selected crossover operator
     new_solution = policy.apply(solution1, solution2)
     new_solution = policy.apply(solution1, solution2)
 
 
-.. warning::
+.. caution::
     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``.
     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.
 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.

+ 1 - 1
docs/source/documentations/validator.rst

@@ -62,7 +62,7 @@ We can now generate solutions randomly by passing our validation function as a p
     solution = BinarySolution.random(5, validator)
     solution = BinarySolution.random(5, validator)
 
 
 
 
-.. warning::
+.. caution::
     If the search space for valid solutions is very small compared to the overall search space, this can involve a considerable time for validating the solution and therefore obtaining a solution.
     If the search space for valid solutions is very small compared to the overall search space, this can involve a considerable time for validating the solution and therefore obtaining a solution.
 
 
 The validation of a solution is therefore now possible. In the next part we will focus on the evaluation of a solution.
 The validation of a solution is therefore now possible. In the next part we will focus on the evaluation of a solution.

+ 2 - 2
docs/source/examples.rst

@@ -9,8 +9,8 @@ Implemented problem examples
 .. toctree::
 .. toctree::
    :maxdepth: 1
    :maxdepth: 1
 
 
-   examples/qap/index
-   examples/ubqp/index
+   examples/qap/global
+   examples/ubqp/global
 
 
 
 
 Available code examples
 Available code examples

+ 303 - 0
docs/source/examples/qap/global.rst

@@ -0,0 +1,303 @@
+===============================
+Quadratric Assignment Problem
+===============================
+
+This example will deal with the use of the **Macop** package in relation to a quadratic assignment problem (QAP). We will use a known example of this problem to associate a set of facilities (:math:`F`) to a set of locations (:math:`L`).
+
+.. image:: ../../_static/examples/qap/factories_qap.png
+   :width: 50 %
+   :align: center
+   :alt: Example of QAP facilities to locations problem
+
+
+.. note:: 
+   The full code for what will be proposed in this example is available: qapExample.py_.
+
+.. _qapExample.py: https://github.com/jbuisine/macop/blob/master/examples/qapExample.py
+
+
+QAP problem definition
+======================
+
+The quadratic assignment problem (QAP) was introduced by Koopmans and Beckman in 1957 in the context of locating "indivisible economic activities". The objective of the problem is to assign a set of facilities to a set of locations in such a way as to minimize the total assignment cost. The assignment cost for a pair of facilities is a function of the flow between the facilities and the distance between the locations of the facilities.
+
+Location assignment example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Consider a **facility location problem** with **four** facilities (and **four** locations). One possible assignment is shown in the figure below: facility 4 is assigned to location 1, facility 1 
+is assigned to location 2, facility 3 is assigned to location 3, and facility 2 is assigned to location 3. This assignment can be written as the permutation :math:`p=\{4,1,3,2\}`, 
+which means that facility 4 is assigned to location 1, facility 1 is assigned to location 2, facility 3 is assigned to location 3, and facility 2 is assigned to location 3. 
+In the figure, the line between a pair of facilities indicates that there is required flow between the facilities, and the thickness of the line increases with the value of the flow. 
+
+.. image:: ../../_static/examples/qap/factories_qap.png
+   :width: 50 %
+   :align: center
+   :alt: Example of QAP facilities to locations problem
+
+
+To calculate the assignment cost of the permutation, the required flows between facilities and the distances between locations are needed.
+
+
+.. tabularcolumns:: |p{1cm}|p{1cm}|p{1cm}|p{1cm}|
+
+.. csv-table:: flow of the current facilities
+   :header: facility `i`, facility `j`, flow( `i`\, `j` )
+   :widths: 2, 2, 3
+
+   1, 4, 4
+   3, 4, 10  
+   3, 1, 8
+   2, 1, 6  
+
+
+.. csv-table:: distances of between locations
+   :header: location `i`, location `j`, distances( `i`\, `j` )
+   :widths: 2, 2, 3
+
+   1, 2, 42
+   1, 3, 30  
+   2, 3, 41
+   3, 4, 23  
+
+
+Then, the assignment cost of the permutation can be computed as:
+
+:math:`f(1,4)⋅d(1,2)+f(3,4)⋅d(1,3)+f(1,3)⋅d(2,3)+f(3,2)⋅d(3,4)` 
+with result :math:`4⋅42+10⋅30+8⋅41+6⋅23=934`.
+
+Note that this permutation is not the optimal solution.
+
+Mathematical definition
+~~~~~~~~~~~~~~~~~~~~~~~
+
+**Sets**
+
+- :math:`N=\{1,2,⋯,n\}`
+- :math:`S_n=\phi:N→N` is the set of all permutations
+
+**Parameters**
+
+- :math:`F=(f_{ij})` is an :math:`n×n` matrix where :math:`f_{ij}` is the required flow between facilities :math:`i` and :math:`j`
+- :math:`D=(d_{ij})` is an :math:`n×n` matrix where :math:`d_{ij}` is the distance between locations :math:`i` and :math:`j`.
+
+**Optimization Problem**
+
+- :math:`min_{ϕ∈S_n}\sum_{i=1}^{n}{\sum_{j=1}^{n}{f_{ij}⋅d_{\phi(i)\phi(j)}}}`
+
+The assignment of facilities to locations is represented by a permutation :math:`\phi`, where :math:`\phi(i)` is the location to which facility :math:`i` is assigned. Each individual product :math:`f_{ij}⋅d_{\phi(i)\phi(j)}` is the cost of assigning facility :math:`i` to location :math:`\phi(i)` and facility :math:`j` to location :math:`\phi(j)`.
+
+QAP Problem instance generation
+===============================
+
+To define our quadratic assignment problem instance, we will use the available mQAP_ multi-objective quadratic problem generator. 
+
+Genration of the instance
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We will limit ourselves here to a single objective for the purposes of this example. The file **makeQAPuni.cc**, will be used to generate the instance.
+
+.. code:: bash
+
+    g++ makeQAPuni.cc -o mQAPGenerator
+    ./mQAPGenerator -n 100 -k 1 -f 30 -d 80 -s 42 > qap_instance.txt
+
+with the following parameters:
+
+- **-n** positive integer: number of facilities/locations;
+- **-k** positive integer: number of objectives;
+- **-f** positive integer: maximum flow between facilities;
+- **-d** positive integer: maximum distance between locations;
+- **-s** positive long: random seed.
+
+The generated qap_instance.txt_ file contains the two matrices :math:`F` and :math:`D` and define our instance problem.
+
+.. _mQAP: https://www.cs.bham.ac.uk/~jdk/mQAP/
+
+.. _qap_instance.txt: https://github.com/jbuisine/macop/blob/master/examples/instances/qap/qap_instance.txt
+
+
+Load data instance
+~~~~~~~~~~~~~~~~~~
+
+
+We are now going to load this instance via a Python code which will be useful to us later on:
+
+.. code:: Python
+
+    qap_instance_file = 'qap_instance.txt'
+
+    n = 100 # the instance size
+
+    with open(qap_instance_file, 'r') as f:
+        file_data = f.readlines()
+        print(f'Instance information {file_data[0]}')
+
+        D_lines = file_data[1:n + 1]
+        D_data = ''.join(D_lines).replace('\n', '')
+
+        F_lines = file_data[n:2 * n + 1]
+        F_data = ''.join(F_lines).replace('\n', '')
+
+    D_matrix = np.fromstring(D_data, dtype=float, sep=' ').reshape(n, n)
+    print(f'D matrix shape: {D_matrix.shape}')
+    F_matrix = np.fromstring(F_data, dtype=float, sep=' ').reshape(n, n)
+    print(f'F matrix shape: {F_matrix.shape}')
+
+.. note::
+    As we know the size of our instance and the structure of the document, it is quite quick to look for the lines related to the :math:`F` and :math:`D` matrices.
+
+Macop QAP implementation
+========================
+
+Let's see how it is possible with the use of the **Macop** package to implement and deal with this QAP instance problem.
+
+Solution structure definition
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Firstly, we are going to use a type of solution that will allow us to define the structure of our solutions.
+
+The available ``macop.solutions.discrete.CombinatoryIntegerSolution`` type of solution within the Macop package represents exactly what one would wish for. 
+I.e. a solution that stores a sequence of integers relative to the size of the problem, the order of which is not sorted.
+
+Let's see an example of its use:
+
+.. code:: python
+
+    from macop.solutions.discrete import CombinatoryIntegerSolution
+    
+    solution = CombinatoryIntegerSolution.random(10)
+    print(solution)
+
+
+The resulting solution obtained:
+
+.. code:: bash
+
+    Combinatory integer solution [2 9 8 1 7 6 0 4 3 5]
+
+
+QAP Evaluator
+~~~~~~~~~~~~~
+
+Now that we have the structure of our solutions, and the means to generate them, we will seek to evaluate them.
+
+To do this, we need to create a new evaluator specific to our problem and the relative evaluation function:
+
+- :math:`min_{ϕ∈S_n}\sum_{i=1}^{n}{\sum_{j=1}^{n}{f_{ij}⋅d_{\phi(i)\phi(j)}}}`
+
+So we are going to create a class that will inherit from the abstract class ``macop.evalutarors.base.Evaluator``:
+
+
+.. code:: python
+
+    from macop.evaluators.base import Evaluator
+
+    class QAPEvaluator(Evaluator):
+    """QAP evaluator class which enables to compute QAP solution using specific `_data`
+
+    - stores into its `_data` dictionary attritute required measures when computing a QAP solution
+    - `_data['F']` matrix of size n x n with flows data between facilities (stored as numpy array)
+    - `_data['D']` matrix of size n x n with distances data between locations (stored as numpy array)
+    - `compute` method enables to compute and associate a score to a given QAP solution
+    """
+
+    def compute(self, solution):
+        """Apply the computation of fitness from solution
+
+        Args:
+            solution: {Solution} -- QAP solution instance
+    
+        Returns:
+            {float} -- fitness score of solution
+        """
+        fitness = 0
+        for index_i, val_i in enumerate(solution.getData()):
+            for index_j, val_j in enumerate(solution.getData()):
+                fitness += self._data['F'][index_i, index_j] * self._data['D'][val_i, val_j]
+
+        return fitness
+
+The cost function for the quadratic problem is now well defined.
+
+.. tip::
+    The class proposed here, is available in the Macop package ``macop.evaluators.discrete.mono.QAPEvaluator``.
+
+Running algorithm
+~~~~~~~~~~~~~~~~~
+
+Now that the necessary tools are available, we will be able to deal with our problem and look for solutions in the search space of our QAP instance.
+
+Here we will use local search algorithms already implemented in **Macop**.
+
+If you are uncomfortable with some of the elements in the code that will follow, you can refer to the more complete **Macop** documentation_ that focuses more on the concepts and tools of the package.
+
+.. code:: python
+
+    # main imports
+    import numpy as np
+
+    # module imports
+    from macop.solutions.discrete import CombinatoryIntegerSolution
+    from macop.evaluators.discrete.mono import QAPEvaluator
+
+    from macop.operators.discrete.mutators import SimpleMutation
+
+    from macop.policies.classicals import RandomPolicy
+
+    from macop.algorithms.mono import IteratedLocalSearch as ILS
+    from macop.algorithms.mono import HillClimberFirstImprovment
+
+    # usefull instance data
+    n = 100
+    qap_instance_file = 'qap_instance.txt'
+
+    # default validator (check the consistency of our data, i.e. only unique element)
+    def validator(solution):
+        if len(list(solution.getData())) > len(set(list(solution.getData()))):
+            print("not valid")
+            return False
+        return True
+
+    # define init random solution
+    def init():
+        return CombinatoryIntegerSolution.random(n, validator)
+
+    # load qap instance
+    with open(qap_instance_file, 'r') as f:
+        file_data = f.readlines()
+        print(f'Instance information {file_data[0]}')
+
+        D_lines = file_data[1:n + 1]
+        D_data = ''.join(D_lines).replace('\n', '')
+
+        F_lines = file_data[n:2 * n + 1]
+        F_data = ''.join(F_lines).replace('\n', '')
+
+    D_matrix = np.fromstring(D_data, dtype=float, sep=' ').reshape(n, n)
+    print(f'D matrix shape: {D_matrix.shape}')
+    F_matrix = np.fromstring(F_data, dtype=float, sep=' ').reshape(n, n)
+    print(f'F matrix shape: {F_matrix.shape}')
+
+    # only one operator here
+    operators = [SimpleMutation()]
+
+    # random policy even if list of solution has only one element
+    policy = RandomPolicy(operators)
+
+    # use of loaded data from QAP instance
+    evaluator = QAPEvaluator(data={'F': F_matrix, 'D': D_matrix})
+
+    # passing global evaluation param from ILS
+    hcfi = HillClimberFirstImprovment(init, evaluator, operators, policy, validator, maximise=False, verbose=True)
+    algo = ILS(init, evaluator, operators, policy, validator, localSearch=hcfi, maximise=False, verbose=True)
+
+    # run the algorithm
+    bestSol = algo.run(10000, ls_evaluations=100)
+
+    print('Solution for QAP instance score is {}'.format(evaluator.compute(bestSol)))
+
+
+QAP problem solving is now possible with **Macop**. As a reminder, the complete code is available in the qapExample.py_ file.
+
+.. _qapExample.py: https://github.com/jbuisine/macop/blob/master/examples/qapExample.py
+.. _documentation: https://jbuisine.github.io/macop/_build/html/documentations

+ 1 - 1
docs/source/examples/qap/implementation.rst

@@ -71,7 +71,7 @@ So we are going to create a class that will inherit from the abstract class ``ma
 
 
 The cost function for the quadratic problem is now well defined.
 The cost function for the quadratic problem is now well defined.
 
 
-.. warning::
+.. tip::
     The class proposed here, is available in the Macop package ``macop.evaluators.discrete.mono.QAPEvaluator``.
     The class proposed here, is available in the Macop package ``macop.evaluators.discrete.mono.QAPEvaluator``.
 
 
 Running algorithm
 Running algorithm

ファイルの差分が大きいため隠しています
+ 225 - 0
docs/source/examples/ubqp/global.rst


+ 1 - 1
docs/source/examples/ubqp/implementation.rst

@@ -68,7 +68,7 @@ So we are going to create a class that will inherit from the abstract class ``ma
 
 
 The cost function for the Unconstrained binary quadratic problem is now well defined.
 The cost function for the Unconstrained binary quadratic problem is now well defined.
 
 
-.. warning::
+.. tip::
     The class proposed here, is available in the Macop package ``macop.evaluators.discrete.mono.UBQPEvaluator``.
     The class proposed here, is available in the Macop package ``macop.evaluators.discrete.mono.UBQPEvaluator``.
 
 
 Running algorithm
 Running algorithm

+ 2 - 2
docs/source/index.rst

@@ -19,7 +19,7 @@ Contents
 
 
    description
    description
 
 
-   documentations/index
+   documentations
 
 
    api
    api
 
 
@@ -42,7 +42,7 @@ Flexible discrete optimisation package allowing a quick implementation of your p
 
 
 
 
 Indices and tables
 Indices and tables
-------------------
+~~~~~~~~~~~~~~~~~~
 
 
 * :ref:`genindex`
 * :ref:`genindex`
 * :ref:`modindex`
 * :ref:`modindex`

+ 33 - 6
macop/algorithms/mono.py

@@ -30,29 +30,38 @@ class HillClimberFirstImprovment(Algorithm):
     Example:
     Example:
 
 
     >>> import random
     >>> import random
+    >>>
     >>> # operators import
     >>> # operators import
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.mutators import SimpleMutation
     >>> from macop.operators.discrete.mutators import SimpleMutation
+    >>>
     >>> # policy import
     >>> # policy import
     >>> from macop.policies.classicals import RandomPolicy
     >>> from macop.policies.classicals import RandomPolicy
-    >>> # solution and algorithm
+    >>>
+    >>> # solution and algorithm imports
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.algorithms.mono import HillClimberFirstImprovment
     >>> from macop.algorithms.mono import HillClimberFirstImprovment
+    >>>
     >>> # evaluator import
     >>> # evaluator import
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
+    >>>
     >>> # evaluator initialization (worths objects passed into data)
     >>> # evaluator initialization (worths objects passed into data)
     >>> problem_size = 20
     >>> problem_size = 20
     >>> worths = [ random.randint(0, 20) for i in range(problem_size) ]
     >>> worths = [ random.randint(0, 20) for i in range(problem_size) ]
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
+    >>>
     >>> # validator specification (based on weights of each objects)
     >>> # validator specification (based on weights of each objects)
     >>> weights = [ random.randint(5, 30) for i in range(problem_size) ]
     >>> weights = [ random.randint(5, 30) for i in range(problem_size) ]
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
-    >>> # initialiser function with lambda function
+    >>>
+    >>> # initialiser function for binary solution using specific solution size
     >>> initialiser = lambda x=20: BinarySolution.random(x, validator)
     >>> initialiser = lambda x=20: BinarySolution.random(x, validator)
+    >>>
     >>> # operators list with crossover and mutation
     >>> # operators list with crossover and mutation
     >>> operators = [SimpleCrossover(), SimpleMutation()]
     >>> operators = [SimpleCrossover(), SimpleMutation()]
     >>> policy = RandomPolicy(operators)
     >>> policy = RandomPolicy(operators)
     >>> algo = HillClimberFirstImprovment(initialiser, evaluator, operators, policy, validator, maximise=True, verbose=False)
     >>> algo = HillClimberFirstImprovment(initialiser, evaluator, operators, policy, validator, maximise=True, verbose=False)
+    >>>
     >>> # run the algorithm
     >>> # run the algorithm
     >>> solution = algo.run(100)
     >>> solution = algo.run(100)
     >>> solution._score
     >>> solution._score
@@ -134,29 +143,38 @@ class HillClimberBestImprovment(Algorithm):
     Example:
     Example:
 
 
     >>> import random
     >>> import random
+    >>>
     >>> # operators import
     >>> # operators import
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.mutators import SimpleMutation
     >>> from macop.operators.discrete.mutators import SimpleMutation
+    >>>
     >>> # policy import
     >>> # policy import
     >>> from macop.policies.classicals import RandomPolicy
     >>> from macop.policies.classicals import RandomPolicy
-    >>> # solution and algorithm
+    >>>
+    >>> # solution and algorithm imports
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.algorithms.mono import HillClimberBestImprovment
     >>> from macop.algorithms.mono import HillClimberBestImprovment
+    >>>
     >>> # evaluator import
     >>> # evaluator import
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
+    >>>
     >>> # evaluator initialization (worths objects passed into data)
     >>> # evaluator initialization (worths objects passed into data)
     >>> problem_size = 20
     >>> problem_size = 20
     >>> worths = [ random.randint(0, 20) for i in range(problem_size) ]
     >>> worths = [ random.randint(0, 20) for i in range(problem_size) ]
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
+    >>>
     >>> # validator specification (based on weights of each objects)
     >>> # validator specification (based on weights of each objects)
     >>> weights = [ random.randint(5, 30) for i in range(problem_size) ]
     >>> weights = [ random.randint(5, 30) for i in range(problem_size) ]
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
-    >>> # initialiser function with lambda function
+    >>>
+    >>> # initialiser function for binary solution using specific solution size
     >>> initialiser = lambda x=20: BinarySolution.random(x, validator)
     >>> initialiser = lambda x=20: BinarySolution.random(x, validator)
+    >>>
     >>> # operators list with crossover and mutation
     >>> # operators list with crossover and mutation
     >>> operators = [SimpleCrossover(), SimpleMutation()]
     >>> operators = [SimpleCrossover(), SimpleMutation()]
     >>> policy = RandomPolicy(operators)
     >>> policy = RandomPolicy(operators)
     >>> algo = HillClimberBestImprovment(initialiser, evaluator, operators, policy, validator, maximise=True, verbose=False)
     >>> algo = HillClimberBestImprovment(initialiser, evaluator, operators, policy, validator, maximise=True, verbose=False)
+    >>>
     >>> # run the algorithm
     >>> # run the algorithm
     >>> solution = algo.run(100)
     >>> solution = algo.run(100)
     >>> solution._score
     >>> solution._score
@@ -239,32 +257,41 @@ class IteratedLocalSearch(Algorithm):
     Example:
     Example:
 
 
     >>> import random
     >>> import random
+    >>>
     >>> # operators import
     >>> # operators import
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.mutators import SimpleMutation
     >>> from macop.operators.discrete.mutators import SimpleMutation
+    >>>
     >>> # policy import
     >>> # policy import
     >>> from macop.policies.classicals import RandomPolicy
     >>> from macop.policies.classicals import RandomPolicy
-    >>> # solution and algorithm
+    >>>
+    >>> # import for solution and algorithm
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.algorithms.mono import IteratedLocalSearch
     >>> from macop.algorithms.mono import IteratedLocalSearch
     >>> from macop.algorithms.mono import HillClimberFirstImprovment
     >>> from macop.algorithms.mono import HillClimberFirstImprovment
+    >>>
     >>> # evaluator import
     >>> # evaluator import
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
+    >>>
     >>> # evaluator initialization (worths objects passed into data)
     >>> # evaluator initialization (worths objects passed into data)
     >>> problem_size = 20
     >>> problem_size = 20
     >>> worths = [ random.randint(0, 20) for i in range(problem_size) ]
     >>> worths = [ random.randint(0, 20) for i in range(problem_size) ]
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
+    >>>
     >>> # validator specification (based on weights of each objects)
     >>> # validator specification (based on weights of each objects)
     >>> weights = [ random.randint(5, 30) for i in range(problem_size) ]
     >>> weights = [ random.randint(5, 30) for i in range(problem_size) ]
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
+    >>>
     >>> # initialiser function with lambda function
     >>> # initialiser function with lambda function
     >>> initialiser = lambda x=20: BinarySolution.random(x, validator)
     >>> initialiser = lambda x=20: BinarySolution.random(x, validator)
+    >>>
     >>> # operators list with crossover and mutation
     >>> # operators list with crossover and mutation
     >>> operators = [SimpleCrossover(), SimpleMutation()]
     >>> operators = [SimpleCrossover(), SimpleMutation()]
     >>> policy = RandomPolicy(operators)
     >>> policy = RandomPolicy(operators)
     >>> local_search = HillClimberFirstImprovment(initialiser, evaluator, operators, policy, validator, maximise=True, verbose=False)
     >>> local_search = HillClimberFirstImprovment(initialiser, evaluator, operators, policy, validator, maximise=True, verbose=False)
     >>> algo = IteratedLocalSearch(initialiser, evaluator, operators, policy, validator, localSearch=local_search, maximise=True, verbose=False)
     >>> algo = IteratedLocalSearch(initialiser, evaluator, operators, policy, validator, localSearch=local_search, maximise=True, verbose=False)
-    >>> # run the algorithm
+    >>>
+    >>> # run the algorithm using specific number of evaluations for local search
     >>> solution = algo.run(100, ls_evaluations=10)
     >>> solution = algo.run(100, ls_evaluations=10)
     >>> solution._score
     >>> solution._score
     137
     137

+ 26 - 4
macop/algorithms/multi.py

@@ -34,34 +34,45 @@ class MOEAD(Algorithm):
         parent: {Algorithm} -- parent algorithm reference in case of inner Algorithm instance (optional)
         parent: {Algorithm} -- parent algorithm reference in case of inner Algorithm instance (optional)
 
 
     >>> import random
     >>> import random
+    >>>
     >>> # operators import
     >>> # operators import
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.mutators import SimpleMutation
     >>> from macop.operators.discrete.mutators import SimpleMutation
+    >>>
     >>> # policy import
     >>> # policy import
     >>> from macop.policies.classicals import RandomPolicy
     >>> from macop.policies.classicals import RandomPolicy
-    >>> # solution and algorithm
+    >>>
+    >>> # solution and algorithm imports
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.algorithms.multi import MOEAD
     >>> from macop.algorithms.multi import MOEAD
+    >>>
     >>> # evaluator import
     >>> # evaluator import
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
+    >>>
     >>> # evaluator initialization (worths objects passed into data)
     >>> # evaluator initialization (worths objects passed into data)
     >>> problem_size = 20
     >>> problem_size = 20
     >>> worths1 = [ random.randint(0, 20) for i in range(problem_size) ]
     >>> worths1 = [ random.randint(0, 20) for i in range(problem_size) ]
     >>> evaluator1 = KnapsackEvaluator(data={'worths': worths1})
     >>> evaluator1 = KnapsackEvaluator(data={'worths': worths1})
     >>> worths2 = [ random.randint(10, 15) for i in range(problem_size) ]
     >>> worths2 = [ random.randint(10, 15) for i in range(problem_size) ]
     >>> evaluator2 = KnapsackEvaluator(data={'worths': worths2})
     >>> evaluator2 = KnapsackEvaluator(data={'worths': worths2})
+    >>>
     >>> # validator specification (based on weights of each objects)
     >>> # validator specification (based on weights of each objects)
     >>> weights = [ random.randint(5, 30) for i in range(problem_size) ]
     >>> weights = [ random.randint(5, 30) for i in range(problem_size) ]
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
-    >>> # initialiser function with lambda function
+    >>>
+    >>> # initialiser function for binary solution using specific solution size
     >>> initialiser = lambda x=20: BinarySolution.random(x, validator)
     >>> initialiser = lambda x=20: BinarySolution.random(x, validator)
+    >>>
     >>> # operators list with crossover and mutation
     >>> # operators list with crossover and mutation
     >>> operators = [SimpleCrossover(), SimpleMutation()]
     >>> operators = [SimpleCrossover(), SimpleMutation()]
     >>> policy = RandomPolicy(operators)
     >>> policy = RandomPolicy(operators)
+    >>>
     >>> # MOEAD use multi-objective, hence list of evaluators with mu=100 and T=10
     >>> # MOEAD use multi-objective, hence list of evaluators with mu=100 and T=10
     >>> algo = MOEAD(20, 5, initialiser, [evaluator1, evaluator2], operators, policy, validator, maximise=True, verbose=False)
     >>> algo = MOEAD(20, 5, initialiser, [evaluator1, evaluator2], operators, policy, validator, maximise=True, verbose=False)
+    >>>
     >>> # run the algorithm and get the pareto front obtained
     >>> # run the algorithm and get the pareto front obtained
     >>> pf_solutions = algo.run(100)
     >>> pf_solutions = algo.run(100)
+    >>>
     >>> # check size of expected pareto
     >>> # check size of expected pareto
     >>> len(pf_solutions)
     >>> len(pf_solutions)
     33
     33
@@ -431,36 +442,47 @@ class MOSubProblem(Algorithm):
     Example:
     Example:
 
 
     >>> import random
     >>> import random
+    >>>
     >>> # operators import
     >>> # operators import
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.mutators import SimpleMutation
     >>> from macop.operators.discrete.mutators import SimpleMutation
+    >>>
     >>> # policy import
     >>> # policy import
     >>> from macop.policies.classicals import RandomPolicy
     >>> from macop.policies.classicals import RandomPolicy
-    >>> # solution and algorithm
+    >>>
+    >>> # solution and algorithm imports
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.algorithms.multi import MOEAD, MOSubProblem
     >>> from macop.algorithms.multi import MOEAD, MOSubProblem
+    >>>
     >>> # evaluator import
     >>> # evaluator import
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
+    >>>
     >>> # evaluator initialization (worths objects passed into data)
     >>> # evaluator initialization (worths objects passed into data)
     >>> problem_size = 20
     >>> problem_size = 20
     >>> worths1 = [ random.randint(0, 20) for i in range(problem_size) ]
     >>> worths1 = [ random.randint(0, 20) for i in range(problem_size) ]
     >>> evaluator1 = KnapsackEvaluator(data={'worths': worths1})
     >>> evaluator1 = KnapsackEvaluator(data={'worths': worths1})
     >>> worths2 = [ random.randint(10, 15) for i in range(problem_size) ]
     >>> worths2 = [ random.randint(10, 15) for i in range(problem_size) ]
     >>> evaluator2 = KnapsackEvaluator(data={'worths': worths2})
     >>> evaluator2 = KnapsackEvaluator(data={'worths': worths2})
+    >>>
     >>> # validator specification (based on weights of each objects)
     >>> # validator specification (based on weights of each objects)
     >>> weights = [ random.randint(5, 30) for i in range(problem_size) ]
     >>> weights = [ random.randint(5, 30) for i in range(problem_size) ]
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
-    >>> # initialiser function with lambda function
+    >>>
+    >>> # initialiser function for binary solution using specific solution size
     >>> initialiser = lambda x=20: BinarySolution.random(x, validator)
     >>> initialiser = lambda x=20: BinarySolution.random(x, validator)
+    >>>
     >>> # operators list with crossover and mutation
     >>> # operators list with crossover and mutation
     >>> operators = [SimpleCrossover(), SimpleMutation()]
     >>> operators = [SimpleCrossover(), SimpleMutation()]
     >>> policy = RandomPolicy(operators)
     >>> policy = RandomPolicy(operators)
     >>> algo = MOEAD(20, 5, initialiser, [evaluator1, evaluator2], operators, policy, validator, maximise=True, verbose=False)
     >>> algo = MOEAD(20, 5, initialiser, [evaluator1, evaluator2], operators, policy, validator, maximise=True, verbose=False)
+    >>>
     >>> # weights of the sub problem
     >>> # weights of the sub problem
     >>> sub_problem_weights = [0.4, 0.6]
     >>> sub_problem_weights = [0.4, 0.6]
     >>> sub_evaluator = WeightedSum(data={'evaluators': [evaluator1, evaluator2], 'weights': sub_problem_weights})
     >>> sub_evaluator = WeightedSum(data={'evaluators': [evaluator1, evaluator2], 'weights': sub_problem_weights})
+    >>>
     >>> # first parameter is the index of the MOSubProblem
     >>> # first parameter is the index of the MOSubProblem
     >>> subProblem = MOSubProblem(0, sub_problem_weights, initialiser, sub_evaluator, operators, policy, validator, maximise=True, parent=algo, verbose=False)
     >>> subProblem = MOSubProblem(0, sub_problem_weights, initialiser, sub_evaluator, operators, policy, validator, maximise=True, parent=algo, verbose=False)
+    >>>
     >>> # run the algorithm
     >>> # run the algorithm
     >>> solution = subProblem.run(100)
     >>> solution = subProblem.run(100)
     >>> solution._score
     >>> solution._score

+ 19 - 0
macop/evaluators/discrete/mono.py

@@ -14,16 +14,20 @@ class KnapsackEvaluator(Evaluator):
     Example:
     Example:
 
 
     >>> import random
     >>> import random
+    >>>
     >>> # binary solution import
     >>> # binary solution import
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.solutions.discrete import BinarySolution
+    >>>
     >>> # evaluator import
     >>> # evaluator import
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
     >>> solution_data = [1, 0, 0, 1, 1, 0, 1, 0]
     >>> solution_data = [1, 0, 0, 1, 1, 0, 1, 0]
     >>> size = len(solution_data)
     >>> size = len(solution_data)
     >>> solution = BinarySolution(solution_data, size)
     >>> solution = BinarySolution(solution_data, size)
+    >>>
     >>> # evaluator initialization (worths objects passed into data)
     >>> # evaluator initialization (worths objects passed into data)
     >>> worths = [ random.randint(5, 20) for i in range(size) ]
     >>> worths = [ random.randint(5, 20) for i in range(size) ]
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
+    >>>
     >>> # compute solution score
     >>> # compute solution score
     >>> evaluator.compute(solution)
     >>> evaluator.compute(solution)
     40
     40
@@ -58,13 +62,17 @@ class QAPEvaluator(Evaluator):
 
 
     >>> import random
     >>> import random
     >>> import numpy as np
     >>> import numpy as np
+    >>>
     >>> # combinatory solution import
     >>> # combinatory solution import
     >>> from macop.solutions.discrete import CombinatoryIntegerSolution
     >>> from macop.solutions.discrete import CombinatoryIntegerSolution
+    >>>
     >>> # evaluator import
     >>> # evaluator import
     >>> from macop.evaluators.discrete.mono import QAPEvaluator
     >>> from macop.evaluators.discrete.mono import QAPEvaluator
+    >>>
     >>> # define problem data using QAP example instance
     >>> # define problem data using QAP example instance
     >>> qap_instance_file = 'examples/instances/qap/qap_instance.txt'
     >>> qap_instance_file = 'examples/instances/qap/qap_instance.txt'
     >>> n = 100 # problem size
     >>> n = 100 # problem size
+    >>>
     >>> # loading data
     >>> # loading data
     >>> f = open(qap_instance_file, 'r')
     >>> f = open(qap_instance_file, 'r')
     >>> file_data = f.readlines()
     >>> file_data = f.readlines()
@@ -75,10 +83,13 @@ class QAPEvaluator(Evaluator):
     >>> D_matrix = np.fromstring(D_data, dtype=float, sep=' ').reshape(n, n)
     >>> D_matrix = np.fromstring(D_data, dtype=float, sep=' ').reshape(n, n)
     >>> F_matrix = np.fromstring(F_data, dtype=float, sep=' ').reshape(n, n)
     >>> F_matrix = np.fromstring(F_data, dtype=float, sep=' ').reshape(n, n)
     >>> f.close()    
     >>> f.close()    
+    >>>
     >>> # create evaluator instance using loading data
     >>> # create evaluator instance using loading data
     >>> evaluator = QAPEvaluator(data={'F': F_matrix, 'D': D_matrix})
     >>> evaluator = QAPEvaluator(data={'F': F_matrix, 'D': D_matrix})
+    >>>
     >>> # create new random combinatory solution using n, the instance QAP size
     >>> # create new random combinatory solution using n, the instance QAP size
     >>> solution = CombinatoryIntegerSolution.random(n)
     >>> solution = CombinatoryIntegerSolution.random(n)
+    >>>
     >>> # compute solution score
     >>> # compute solution score
     >>> evaluator.compute(solution)
     >>> evaluator.compute(solution)
     6397983.0
     6397983.0
@@ -113,25 +124,33 @@ class UBQPEvaluator(Evaluator):
 
 
     >>> import random
     >>> import random
     >>> import numpy as np
     >>> import numpy as np
+    >>>
     >>> # binary solution import
     >>> # binary solution import
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.solutions.discrete import BinarySolution
+    >>>
     >>> # evaluator import
     >>> # evaluator import
     >>> from macop.evaluators.discrete.mono import UBQPEvaluator
     >>> from macop.evaluators.discrete.mono import UBQPEvaluator
+    >>>
     >>> # define problem data using UBQP example instance
     >>> # define problem data using UBQP example instance
     >>> ubqp_instance_file = 'examples/instances/ubqp/ubqp_instance.txt'
     >>> ubqp_instance_file = 'examples/instances/ubqp/ubqp_instance.txt'
     >>> n = 100 # problem size
     >>> n = 100 # problem size
+    >>>
     >>> # loading data
     >>> # loading data
     >>> f = open(ubqp_instance_file, 'r')
     >>> f = open(ubqp_instance_file, 'r')
     >>> file_data = f.readlines()
     >>> file_data = f.readlines()
+    >>>
     >>> # get all string floating point values of matrix
     >>> # get all string floating point values of matrix
     >>> Q_data = ''.join([ line.replace('\\n', '') for line in file_data[8:] ])
     >>> Q_data = ''.join([ line.replace('\\n', '') for line in file_data[8:] ])
     >>> # load the concatenate obtained string
     >>> # load the concatenate obtained string
     >>> Q_matrix = np.fromstring(Q_data, dtype=float, sep=' ').reshape(n, n)
     >>> Q_matrix = np.fromstring(Q_data, dtype=float, sep=' ').reshape(n, n)
     >>> f.close()    
     >>> f.close()    
+    >>>
     >>> # create evaluator instance using loading data
     >>> # create evaluator instance using loading data
     >>> evaluator = UBQPEvaluator(data={'Q': Q_matrix})
     >>> evaluator = UBQPEvaluator(data={'Q': Q_matrix})
+    >>>
     >>> # create new random combinatory solution using n, the instance QAP size
     >>> # create new random combinatory solution using n, the instance QAP size
     >>> solution = BinarySolution.random(n)
     >>> solution = BinarySolution.random(n)
+    >>>
     >>> # compute solution score
     >>> # compute solution score
     >>> evaluator.compute(solution)
     >>> evaluator.compute(solution)
     477.0
     477.0

+ 6 - 0
macop/evaluators/discrete/multi.py

@@ -13,21 +13,27 @@ class WeightedSum(Evaluator):
     - `compute` method enables to compute and associate a tuples of scores to a given solution
     - `compute` method enables to compute and associate a tuples of scores to a given solution
     
     
     >>> import random
     >>> import random
+    >>>
     >>> # binary solution import
     >>> # binary solution import
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.solutions.discrete import BinarySolution
+    >>>
     >>> # evaluators imports
     >>> # evaluators imports
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
     >>> from macop.evaluators.discrete.multi import WeightedSum
     >>> from macop.evaluators.discrete.multi import WeightedSum
     >>> solution_data = [1, 0, 0, 1, 1, 0, 1, 0]
     >>> solution_data = [1, 0, 0, 1, 1, 0, 1, 0]
     >>> size = len(solution_data)
     >>> size = len(solution_data)
     >>> solution = BinarySolution(solution_data, size)
     >>> solution = BinarySolution(solution_data, size)
+    >>>
     >>> # evaluator 1 initialization (worths objects passed into data)
     >>> # evaluator 1 initialization (worths objects passed into data)
     >>> worths1 = [ random.randint(5, 20) for i in range(size) ]
     >>> worths1 = [ random.randint(5, 20) for i in range(size) ]
     >>> evaluator1 = KnapsackEvaluator(data={'worths': worths1})
     >>> evaluator1 = KnapsackEvaluator(data={'worths': worths1})
+    >>>
     >>> # evaluator 2 initialization (worths objects passed into data)
     >>> # evaluator 2 initialization (worths objects passed into data)
     >>> worths2 = [ random.randint(10, 15) for i in range(size) ]
     >>> worths2 = [ random.randint(10, 15) for i in range(size) ]
     >>> evaluator2 = KnapsackEvaluator(data={'worths': worths2})
     >>> evaluator2 = KnapsackEvaluator(data={'worths': worths2})
     >>> weighted_evaluator = WeightedSum(data={'evaluators': [evaluator1, evaluator2], 'weights': [0.3, 0.7]})
     >>> weighted_evaluator = WeightedSum(data={'evaluators': [evaluator1, evaluator2], 'weights': [0.3, 0.7]})
+    >>>
+    >>> # compute score and check with expected one
     >>> weighted_score = weighted_evaluator.compute(solution)
     >>> weighted_score = weighted_evaluator.compute(solution)
     >>> expected_score = evaluator1.compute(solution) * 0.3 + evaluator2.compute(solution) * 0.7
     >>> expected_score = evaluator1.compute(solution) * 0.3 + evaluator2.compute(solution) * 0.7
     >>> weighted_score == expected_score
     >>> weighted_score == expected_score

+ 20 - 4
macop/operators/discrete/crossovers.py

@@ -19,22 +19,29 @@ class SimpleCrossover(Crossover):
     >>> # operators import
     >>> # operators import
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.mutators import SimpleMutation
     >>> from macop.operators.discrete.mutators import SimpleMutation
+    >>>
     >>> # policy import
     >>> # policy import
     >>> from macop.policies.reinforcement import UCBPolicy
     >>> from macop.policies.reinforcement import UCBPolicy
-    >>> # solution and algorithm
+    >>>
+    >>> # solution and algorithm imports
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.algorithms.mono import IteratedLocalSearch
     >>> from macop.algorithms.mono import IteratedLocalSearch
     >>> from macop.algorithms.mono import HillClimberFirstImprovment
     >>> from macop.algorithms.mono import HillClimberFirstImprovment
+    >>>
     >>> # evaluator import
     >>> # evaluator import
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
+    >>>
     >>> # evaluator initialization (worths objects passed into data)
     >>> # evaluator initialization (worths objects passed into data)
     >>> worths = [ random.randint(0, 20) for i in range(10) ]
     >>> worths = [ random.randint(0, 20) for i in range(10) ]
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
+    >>>
     >>> # validator specification (based on weights of each objects)
     >>> # validator specification (based on weights of each objects)
     >>> weights = [ random.randint(20, 30) for i in range(10) ]
     >>> weights = [ random.randint(20, 30) for i in range(10) ]
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
-    >>> # initialiser function with lambda function
+    >>>
+    >>> # initialiser function for binary solution using specific solution size
     >>> initialiser = lambda x=10: BinarySolution.random(x, validator)
     >>> initialiser = lambda x=10: BinarySolution.random(x, validator)
+    >>>
     >>> # operators list with crossover and mutation
     >>> # operators list with crossover and mutation
     >>> simple_crossover = SimpleCrossover()
     >>> simple_crossover = SimpleCrossover()
     >>> simple_mutation = SimpleMutation()
     >>> simple_mutation = SimpleMutation()
@@ -42,6 +49,7 @@ class SimpleCrossover(Crossover):
     >>> policy = UCBPolicy(operators)
     >>> policy = UCBPolicy(operators)
     >>> local_search = HillClimberFirstImprovment(initialiser, evaluator, operators, policy, validator, maximise=True, verbose=False)
     >>> local_search = HillClimberFirstImprovment(initialiser, evaluator, operators, policy, validator, maximise=True, verbose=False)
     >>> algo = IteratedLocalSearch(initialiser, evaluator, operators, policy, validator, localSearch=local_search, maximise=True, verbose=False)
     >>> algo = IteratedLocalSearch(initialiser, evaluator, operators, policy, validator, localSearch=local_search, maximise=True, verbose=False)
+    >>>
     >>> # using best solution, simple crossover is applied
     >>> # using best solution, simple crossover is applied
     >>> best_solution = algo.run(100)
     >>> best_solution = algo.run(100)
     >>> list(best_solution.getData())
     >>> list(best_solution.getData())
@@ -92,22 +100,29 @@ class RandomSplitCrossover(Crossover):
     >>> # operators import
     >>> # operators import
     >>> from macop.operators.discrete.crossovers import RandomSplitCrossover
     >>> from macop.operators.discrete.crossovers import RandomSplitCrossover
     >>> from macop.operators.discrete.mutators import SimpleMutation
     >>> from macop.operators.discrete.mutators import SimpleMutation
+    >>>
     >>> # policy import
     >>> # policy import
     >>> from macop.policies.reinforcement import UCBPolicy
     >>> from macop.policies.reinforcement import UCBPolicy
-    >>> # solution and algorithm
+    >>>
+    >>> # solution and algorithm imports
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.algorithms.mono import IteratedLocalSearch
     >>> from macop.algorithms.mono import IteratedLocalSearch
     >>> from macop.algorithms.mono import HillClimberFirstImprovment
     >>> from macop.algorithms.mono import HillClimberFirstImprovment
+    >>>
     >>> # evaluator import
     >>> # evaluator import
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
+    >>>
     >>> # evaluator initialization (worths objects passed into data)
     >>> # evaluator initialization (worths objects passed into data)
     >>> worths = [ random.randint(0, 20) for i in range(10) ]
     >>> worths = [ random.randint(0, 20) for i in range(10) ]
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
+    >>>
     >>> # validator specification (based on weights of each objects)
     >>> # validator specification (based on weights of each objects)
     >>> weights = [ random.randint(20, 30) for i in range(10) ]
     >>> weights = [ random.randint(20, 30) for i in range(10) ]
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
-    >>> # initialiser function with lambda function
+    >>>
+    >>> # initialiser function for binary solution using specific solution size
     >>> initialiser = lambda x=10: BinarySolution.random(x, validator)
     >>> initialiser = lambda x=10: BinarySolution.random(x, validator)
+    >>>
     >>> # operators list with crossover and mutation
     >>> # operators list with crossover and mutation
     >>> random_split_crossover = RandomSplitCrossover()
     >>> random_split_crossover = RandomSplitCrossover()
     >>> simple_mutation = SimpleMutation()
     >>> simple_mutation = SimpleMutation()
@@ -115,6 +130,7 @@ class RandomSplitCrossover(Crossover):
     >>> policy = UCBPolicy(operators)
     >>> policy = UCBPolicy(operators)
     >>> local_search = HillClimberFirstImprovment(initialiser, evaluator, operators, policy, validator, maximise=True, verbose=False)
     >>> local_search = HillClimberFirstImprovment(initialiser, evaluator, operators, policy, validator, maximise=True, verbose=False)
     >>> algo = IteratedLocalSearch(initialiser, evaluator, operators, policy, validator, localSearch=local_search, maximise=True, verbose=False)
     >>> algo = IteratedLocalSearch(initialiser, evaluator, operators, policy, validator, localSearch=local_search, maximise=True, verbose=False)
+    >>>
     >>> # using best solution, simple crossover is applied
     >>> # using best solution, simple crossover is applied
     >>> best_solution = algo.run(100)
     >>> best_solution = algo.run(100)
     >>> list(best_solution.getData())
     >>> list(best_solution.getData())

+ 2 - 0
macop/policies/classicals.py

@@ -20,6 +20,8 @@ class RandomPolicy(Policy):
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.mutators import SimpleMutation
     >>> from macop.operators.discrete.mutators import SimpleMutation
     >>> from macop.policies.classicals import RandomPolicy
     >>> from macop.policies.classicals import RandomPolicy
+    >>>
+    >>> # create policy instance and select next operator to apply using policy
     >>> policy = RandomPolicy([SimpleCrossover(), SimpleMutation()])
     >>> policy = RandomPolicy([SimpleCrossover(), SimpleMutation()])
     >>> operator = policy.select()
     >>> operator = policy.select()
     >>> type(operator).__name__
     >>> type(operator).__name__

+ 14 - 2
macop/policies/reinforcement.py

@@ -23,32 +23,44 @@ class UCBPolicy(Policy):
 
 
     Attributes:
     Attributes:
         operators: {[Operator]} -- list of selected operators for the algorithm
         operators: {[Operator]} -- list of selected operators for the algorithm
-        C: {float} -- The second half of the UCB equation adds exploration, with the degree of exploration being controlled by the hyper-parameter `C`.
+        C: {float} -- The second half of the UCB equation adds exploration, with the degree of exploration being controlled by the hyper-parameter ``C``.
         exp_rate: {float} -- exploration rate (probability to choose randomly next operator)
         exp_rate: {float} -- exploration rate (probability to choose randomly next operator)
         rewards: {[float]} -- list of summed rewards obtained for each operator
         rewards: {[float]} -- list of summed rewards obtained for each operator
         occurrences: {[int]} -- number of use (selected) of each operator
         occurrences: {[int]} -- number of use (selected) of each operator
 
 
+    The value of attribute ``C`` will allow us to specify whether we wish to exploit or explore further in relation to our earned rewards. 
+    A low value of ``C`` (e.g. 2) will allow more exploitation, while a high value of ``C`` (e.g. 1000) will allow exploration.
+
+    The ``exp_rate`` variable avoids using an operator too much and allows to explore from time to time (especially if the variable ``C`` has a small value). Typical value for ``exp_rate`` can be 0.9.
+
     Example:
     Example:
 
 
     >>> # operators import
     >>> # operators import
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.crossovers import SimpleCrossover
     >>> from macop.operators.discrete.mutators import SimpleMutation
     >>> from macop.operators.discrete.mutators import SimpleMutation
+    >>>
     >>> # policy import
     >>> # policy import
     >>> from macop.policies.reinforcement import UCBPolicy
     >>> from macop.policies.reinforcement import UCBPolicy
+    >>>
     >>> # solution and algorithm
     >>> # solution and algorithm
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.solutions.discrete import BinarySolution
     >>> from macop.algorithms.mono import IteratedLocalSearch
     >>> from macop.algorithms.mono import IteratedLocalSearch
     >>> from macop.algorithms.mono import HillClimberFirstImprovment
     >>> from macop.algorithms.mono import HillClimberFirstImprovment
+    >>>
     >>> # evaluator import
     >>> # evaluator import
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
     >>> from macop.evaluators.discrete.mono import KnapsackEvaluator
     >>> # evaluator initialization (worths objects passed into data)
     >>> # evaluator initialization (worths objects passed into data)
+    >>>
     >>> worths = [ random.randint(0, 20) for i in range(20) ]
     >>> worths = [ random.randint(0, 20) for i in range(20) ]
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
     >>> evaluator = KnapsackEvaluator(data={'worths': worths})
+    >>>
     >>> # validator specification (based on weights of each objects)
     >>> # validator specification (based on weights of each objects)
     >>> weights = [ random.randint(5, 30) for i in range(20) ]
     >>> weights = [ random.randint(5, 30) for i in range(20) ]
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
     >>> validator = lambda solution: True if sum([weights[i] for i, value in enumerate(solution.getData()) if value == 1]) < 200 else False
+    >>>
     >>> # initialiser function with lambda function
     >>> # initialiser function with lambda function
     >>> initialiser = lambda x=20: BinarySolution.random(x, validator)
     >>> initialiser = lambda x=20: BinarySolution.random(x, validator)
+    >>>
     >>> # operators list with crossover and mutation
     >>> # operators list with crossover and mutation
     >>> operators = [SimpleCrossover(), SimpleMutation()]
     >>> operators = [SimpleCrossover(), SimpleMutation()]
     >>> policy = UCBPolicy(operators)
     >>> policy = UCBPolicy(operators)
@@ -62,7 +74,7 @@ class UCBPolicy(Policy):
     >>> policy.occurences # one more due to first evaluation
     >>> policy.occurences # one more due to first evaluation
     [51, 53]
     [51, 53]
     """
     """
-    def __init__(self, operators, C=100., exp_rate=0.5):
+    def __init__(self, operators, C=100., exp_rate=0.9):
         """UCB Policy initialiser
         """UCB Policy initialiser
 
 
         Args:
         Args:

+ 8 - 0
macop/solutions/discrete.py

@@ -30,9 +30,11 @@ class BinarySolution(Solution):
         Example:
         Example:
 
 
         >>> from macop.solutions.discrete import BinarySolution
         >>> from macop.solutions.discrete import BinarySolution
+        >>>
         >>> # build of a solution using specific data and size
         >>> # build of a solution using specific data and size
         >>> data = [0, 1, 0, 1, 1]
         >>> data = [0, 1, 0, 1, 1]
         >>> solution = BinarySolution(data, len(data))
         >>> solution = BinarySolution(data, len(data))
+        >>>
         >>> # check data content
         >>> # check data content
         >>> sum(solution.getData()) == 3
         >>> sum(solution.getData()) == 3
         True
         True
@@ -58,6 +60,8 @@ class BinarySolution(Solution):
         Example:
         Example:
 
 
         >>> from macop.solutions.discrete import BinarySolution
         >>> from macop.solutions.discrete import BinarySolution
+        >>>
+        >>> # generate random solution using specific validator
         >>> validator = lambda solution: True if sum(solution.getData()) > 5 else False
         >>> validator = lambda solution: True if sum(solution.getData()) > 5 else False
         >>> solution = BinarySolution.random(10, validator)
         >>> solution = BinarySolution.random(10, validator)
         >>> sum(solution.getData()) > 5
         >>> sum(solution.getData()) > 5
@@ -128,6 +132,8 @@ class CombinatoryIntegerSolution(Solution):
         Example:
         Example:
 
 
         >>> from macop.solutions.discrete import CombinatoryIntegerSolution
         >>> from macop.solutions.discrete import CombinatoryIntegerSolution
+        >>>
+        >>> # generate random solution using specific validator
         >>> validator = lambda solution: True if sum(solution.getData()) > 5 else False
         >>> validator = lambda solution: True if sum(solution.getData()) > 5 else False
         >>> solution = CombinatoryIntegerSolution.random(5, validator)
         >>> solution = CombinatoryIntegerSolution.random(5, validator)
         >>> sum(solution.getData()) > 5
         >>> sum(solution.getData()) > 5
@@ -201,6 +207,8 @@ class IntegerSolution(Solution):
         >>> from macop.solutions.discrete import IntegerSolution
         >>> from macop.solutions.discrete import IntegerSolution
         >>> import numpy as np
         >>> import numpy as np
         >>> np.random.seed(42)
         >>> np.random.seed(42)
+        >>>
+        >>> # generate random solution using specific validator
         >>> validator = lambda solution: True if sum(solution.getData()) > 5 else False
         >>> validator = lambda solution: True if sum(solution.getData()) > 5 else False
         >>> solution = IntegerSolution.random(5, validator)
         >>> solution = IntegerSolution.random(5, validator)
         >>> sum(solution.getData()) > 10
         >>> sum(solution.getData()) > 10

ファイルの差分が大きいため隠しています
+ 8 - 3
paper.md