Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue 19 : A note on reproducibility #29

Merged
merged 4 commits into from
May 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions docs/tuto.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,18 @@ Because the framework uses the `random` and `numpy` modules, you can be sure
to have the same results by running the same script several times if you
add the following instructions before initializing problems or algorithms:


.. code-block:: python

import random
import numpy
from moead_framework.tool.result import set_seed

seed = 0
random.seed(seed)
np.random.seed(seed)
set_seed(seed)

.. warning::
This approach is not safe in threaded environments.
By re-using a seed value, the same sequence should be reproducible from run to run as long as
multiple threads are not running (https://docs.python.org/3/library/random.html#notes-on-reproducibility)

You can find more information at the following links:

Expand Down
7 changes: 2 additions & 5 deletions moead_framework/test/test_combinatorial_algorithm.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import unittest
import random
import os
import numpy as np
from moead_framework.aggregation.tchebycheff import Tchebycheff
from moead_framework.algorithm.combinatorial import Moead, MoeadDeltaNr, MoeadSPSRandom, MoeadDRA
from moead_framework.problem.combinatorial import Rmnk
from moead_framework.tool.result import compute_hypervolume
from moead_framework.tool.result import compute_hypervolume, set_seed


class AlgorithmsTest(unittest.TestCase):
"""Test implemented algorithms."""

def setUp(self):
"""Init"""
random.seed(1)
np.random.seed(1)
set_seed(1)
self.number_of_evaluations = 100

project_path = os.path.dirname(os.path.abspath(__file__))
Expand Down
6 changes: 2 additions & 4 deletions moead_framework/test/test_genetic_operator.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import unittest
import random
import numpy as np

from moead_framework.core.genetic_operator.combinatorial import Crossover, BinaryMutation
from moead_framework.core.genetic_operator.numerical import DifferentialEvolutionCrossover, PolynomialMutation, \
MoeadDeOperators
from moead_framework.problem.numerical import Zdt1
from moead_framework.tool.result import set_seed


class GeneticOperatorsTest(unittest.TestCase):
"""Test genetic operators."""

def setUp(self):
"""Init"""
random.seed(1)
np.random.seed(1)
set_seed(1)

def test_combinatorial_binary_mutation(self):
"""Test combinatorial binary mutation"""
Expand Down
7 changes: 2 additions & 5 deletions moead_framework/test/test_numerical_algorithm.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import unittest
import random
import os
import numpy as np
from moead_framework.aggregation import Tchebycheff
from moead_framework.algorithm.numerical import Moead
from moead_framework.problem.numerical import Zdt1
from moead_framework.tool.result import compute_hypervolume
from moead_framework.tool.result import compute_hypervolume, set_seed


class AlgorithmsNumericalTest(unittest.TestCase):
"""Test implemented algorithms."""

def setUp(self):
"""Init"""
random.seed(1)
np.random.seed(1)
set_seed(1)
self.number_of_evaluations = 100

project_path = os.path.dirname(os.path.abspath(__file__))
Expand Down
6 changes: 2 additions & 4 deletions moead_framework/test/test_parent_selector.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
import os

import unittest
import random
import numpy as np

from moead_framework.aggregation import Tchebycheff
from moead_framework.algorithm.combinatorial import Moead
from moead_framework.core.parent_selector import TwoRandomParentSelector, OneRandomAndCurrentParentSelector, \
TwoRandomAndCurrentParentSelector
from moead_framework.problem.combinatorial import Rmnk
from moead_framework.tool.result import set_seed


class ParentSelectorTest(unittest.TestCase):
"""Test genetic operators."""

def setUp(self):
"""Init"""
random.seed(1)
np.random.seed(1)
set_seed(1)

self.number_of_evaluations = 100

Expand Down
6 changes: 2 additions & 4 deletions moead_framework/test/test_solution.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
from copy import copy

import numpy as np
import random
import os
import unittest

from moead_framework.problem.combinatorial import Rmnk
from moead_framework.tool.result import set_seed


class RmnkTest(unittest.TestCase):
"""Test the 'rmnk' problem."""

def setUp(self):
"""Init"""
random.seed(1)
np.random.seed(1)
set_seed(1)
project_path = os.path.dirname(os.path.abspath(__file__))
self.problem = Rmnk(project_path + '/data/instances/rmnk_0_2_100_1_0.dat')
self.solution = self.problem.generate_random_solution()
Expand Down
7 changes: 2 additions & 5 deletions moead_framework/test/test_tool.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import unittest
import random
import os
import numpy as np
from moead_framework.problem.combinatorial import Rmnk
from moead_framework.tool.mop import get_non_dominated, population_size_without_duplicate, compute_crowding_distance
from moead_framework.tool.result import save_population, save_population_full, compute_hypervolume
from moead_framework.tool.result import save_population, save_population_full, compute_hypervolume, set_seed


class ToolsTest(unittest.TestCase):
"""Test implemented algorithms."""

def setUp(self):
"""Init"""
random.seed(1)
np.random.seed(1)
set_seed(1)
project_path = os.path.dirname(os.path.abspath(__file__))
self.rmnk = Rmnk(instance_file=project_path + '/data/instances/rmnk_0_2_100_1_0.dat')
self.rmnk3D = Rmnk(instance_file=project_path + '/data/instances/rmnk_0_3_100_1_0.dat')
Expand Down
15 changes: 15 additions & 0 deletions moead_framework/tool/result.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import random
import numpy as np


Expand Down Expand Up @@ -43,6 +44,20 @@ def save_population_full(file_name, population):
file.close()


def set_seed(seed):
"""
Set the seed for numpy and random packages.
Warning, this approach is not safe in threaded environments.
By re-using a seed value, the same sequence should be reproducible from run to run as long as
multiple threads are not running (https://docs.python.org/3/library/random.html#notes-on-reproducibility)

:param seed: integer
:return:
"""
random.seed(seed)
np.random.seed(seed)


def compute_hypervolume(solutions, ref_point):
hypervolume_class = HyperVolume(reference_point=ref_point)

Expand Down