desdeo 2.0.0__py3-none-any.whl → 2.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- desdeo/adm/ADMAfsar.py +551 -0
- desdeo/adm/ADMChen.py +414 -0
- desdeo/adm/BaseADM.py +119 -0
- desdeo/adm/__init__.py +11 -0
- desdeo/api/__init__.py +6 -6
- desdeo/api/app.py +38 -28
- desdeo/api/config.py +65 -44
- desdeo/api/config.toml +23 -12
- desdeo/api/db.py +10 -8
- desdeo/api/db_init.py +12 -6
- desdeo/api/models/__init__.py +220 -20
- desdeo/api/models/archive.py +16 -27
- desdeo/api/models/emo.py +128 -0
- desdeo/api/models/enautilus.py +69 -0
- desdeo/api/models/gdm/gdm_aggregate.py +139 -0
- desdeo/api/models/gdm/gdm_base.py +69 -0
- desdeo/api/models/gdm/gdm_score_bands.py +114 -0
- desdeo/api/models/gdm/gnimbus.py +138 -0
- desdeo/api/models/generic.py +104 -0
- desdeo/api/models/generic_states.py +401 -0
- desdeo/api/models/nimbus.py +158 -0
- desdeo/api/models/preference.py +44 -6
- desdeo/api/models/problem.py +274 -64
- desdeo/api/models/session.py +4 -1
- desdeo/api/models/state.py +419 -52
- desdeo/api/models/user.py +7 -6
- desdeo/api/models/utopia.py +25 -0
- desdeo/api/routers/_EMO.backup +309 -0
- desdeo/api/routers/_NIMBUS.py +6 -3
- desdeo/api/routers/emo.py +497 -0
- desdeo/api/routers/enautilus.py +237 -0
- desdeo/api/routers/gdm/gdm_aggregate.py +234 -0
- desdeo/api/routers/gdm/gdm_base.py +420 -0
- desdeo/api/routers/gdm/gdm_score_bands/gdm_score_bands_manager.py +398 -0
- desdeo/api/routers/gdm/gdm_score_bands/gdm_score_bands_routers.py +377 -0
- desdeo/api/routers/gdm/gnimbus/gnimbus_manager.py +698 -0
- desdeo/api/routers/gdm/gnimbus/gnimbus_routers.py +591 -0
- desdeo/api/routers/generic.py +233 -0
- desdeo/api/routers/nimbus.py +705 -0
- desdeo/api/routers/problem.py +201 -4
- desdeo/api/routers/reference_point_method.py +20 -44
- desdeo/api/routers/session.py +50 -26
- desdeo/api/routers/user_authentication.py +180 -26
- desdeo/api/routers/utils.py +187 -0
- desdeo/api/routers/utopia.py +230 -0
- desdeo/api/schema.py +10 -4
- desdeo/api/tests/conftest.py +94 -2
- desdeo/api/tests/test_enautilus.py +330 -0
- desdeo/api/tests/test_models.py +550 -72
- desdeo/api/tests/test_routes.py +902 -43
- desdeo/api/utils/_database.py +263 -0
- desdeo/api/utils/database.py +28 -266
- desdeo/api/utils/emo_database.py +40 -0
- desdeo/core.py +7 -0
- desdeo/emo/__init__.py +154 -24
- desdeo/emo/hooks/archivers.py +18 -2
- desdeo/emo/methods/EAs.py +128 -5
- desdeo/emo/methods/bases.py +9 -56
- desdeo/emo/methods/templates.py +111 -0
- desdeo/emo/operators/crossover.py +544 -42
- desdeo/emo/operators/evaluator.py +10 -14
- desdeo/emo/operators/generator.py +127 -24
- desdeo/emo/operators/mutation.py +212 -41
- desdeo/emo/operators/scalar_selection.py +202 -0
- desdeo/emo/operators/selection.py +956 -214
- desdeo/emo/operators/termination.py +124 -16
- desdeo/emo/options/__init__.py +108 -0
- desdeo/emo/options/algorithms.py +435 -0
- desdeo/emo/options/crossover.py +164 -0
- desdeo/emo/options/generator.py +131 -0
- desdeo/emo/options/mutation.py +260 -0
- desdeo/emo/options/repair.py +61 -0
- desdeo/emo/options/scalar_selection.py +66 -0
- desdeo/emo/options/selection.py +127 -0
- desdeo/emo/options/templates.py +383 -0
- desdeo/emo/options/termination.py +143 -0
- desdeo/gdm/__init__.py +22 -0
- desdeo/gdm/gdmtools.py +45 -0
- desdeo/gdm/score_bands.py +114 -0
- desdeo/gdm/voting_rules.py +50 -0
- desdeo/mcdm/__init__.py +23 -1
- desdeo/mcdm/enautilus.py +338 -0
- desdeo/mcdm/gnimbus.py +484 -0
- desdeo/mcdm/nautilus_navigator.py +7 -6
- desdeo/mcdm/reference_point_method.py +70 -0
- desdeo/problem/__init__.py +16 -11
- desdeo/problem/evaluator.py +4 -5
- desdeo/problem/external/__init__.py +18 -0
- desdeo/problem/external/core.py +356 -0
- desdeo/problem/external/pymoo_provider.py +266 -0
- desdeo/problem/external/runtime.py +44 -0
- desdeo/problem/gurobipy_evaluator.py +37 -12
- desdeo/problem/infix_parser.py +1 -16
- desdeo/problem/json_parser.py +7 -11
- desdeo/problem/pyomo_evaluator.py +25 -6
- desdeo/problem/schema.py +73 -55
- desdeo/problem/simulator_evaluator.py +65 -15
- desdeo/problem/testproblems/__init__.py +26 -11
- desdeo/problem/testproblems/benchmarks_server.py +120 -0
- desdeo/problem/testproblems/cake_problem.py +185 -0
- desdeo/problem/testproblems/dmitry_forest_problem_discrete.py +71 -0
- desdeo/problem/testproblems/forest_problem.py +77 -69
- desdeo/problem/testproblems/multi_valued_constraints.py +119 -0
- desdeo/problem/testproblems/{river_pollution_problem.py → river_pollution_problems.py} +28 -22
- desdeo/problem/testproblems/single_objective.py +289 -0
- desdeo/problem/testproblems/zdt_problem.py +4 -1
- desdeo/problem/utils.py +1 -1
- desdeo/tools/__init__.py +39 -21
- desdeo/tools/desc_gen.py +22 -0
- desdeo/tools/generics.py +22 -2
- desdeo/tools/group_scalarization.py +3090 -0
- desdeo/tools/indicators_binary.py +107 -1
- desdeo/tools/indicators_unary.py +3 -16
- desdeo/tools/message.py +33 -2
- desdeo/tools/non_dominated_sorting.py +4 -3
- desdeo/tools/patterns.py +9 -7
- desdeo/tools/pyomo_solver_interfaces.py +49 -36
- desdeo/tools/reference_vectors.py +118 -351
- desdeo/tools/scalarization.py +340 -1413
- desdeo/tools/score_bands.py +491 -328
- desdeo/tools/utils.py +117 -49
- desdeo/tools/visualizations.py +67 -0
- desdeo/utopia_stuff/utopia_problem.py +1 -1
- desdeo/utopia_stuff/utopia_problem_old.py +1 -1
- {desdeo-2.0.0.dist-info → desdeo-2.1.1.dist-info}/METADATA +47 -30
- desdeo-2.1.1.dist-info/RECORD +180 -0
- {desdeo-2.0.0.dist-info → desdeo-2.1.1.dist-info}/WHEEL +1 -1
- desdeo-2.0.0.dist-info/RECORD +0 -120
- /desdeo/api/utils/{logger.py → _logger.py} +0 -0
- {desdeo-2.0.0.dist-info → desdeo-2.1.1.dist-info/licenses}/LICENSE +0 -0
desdeo/emo/__init__.py
CHANGED
|
@@ -1,29 +1,159 @@
|
|
|
1
1
|
"""Imports available from the desdeo emo."""
|
|
2
2
|
|
|
3
3
|
__all__ = [
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"MaxGenerationsTerminator",
|
|
16
|
-
"Archive",
|
|
17
|
-
"FeasibleArchive",
|
|
18
|
-
"NonDominatedArchive",
|
|
4
|
+
"algorithms",
|
|
5
|
+
"crossover",
|
|
6
|
+
"generator",
|
|
7
|
+
"mutation",
|
|
8
|
+
"other",
|
|
9
|
+
"preference_handling",
|
|
10
|
+
"repair",
|
|
11
|
+
"scalar_selection",
|
|
12
|
+
"selection",
|
|
13
|
+
"templates",
|
|
14
|
+
"termination",
|
|
19
15
|
]
|
|
20
16
|
|
|
21
|
-
from
|
|
22
|
-
|
|
23
|
-
from .
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
17
|
+
from types import SimpleNamespace
|
|
18
|
+
|
|
19
|
+
from .options.algorithms import (
|
|
20
|
+
emo_constructor,
|
|
21
|
+
ibea_mixed_integer_options,
|
|
22
|
+
ibea_options,
|
|
23
|
+
nsga2_options,
|
|
24
|
+
nsga3_mixed_integer_options,
|
|
25
|
+
nsga3_options,
|
|
26
|
+
rvea_mixed_integer_options,
|
|
27
|
+
rvea_options,
|
|
28
|
+
)
|
|
29
|
+
from .options.crossover import (
|
|
30
|
+
BlendAlphaCrossoverOptions,
|
|
31
|
+
BoundedExponentialCrossoverOptions,
|
|
32
|
+
LocalCrossoverOptions,
|
|
33
|
+
SimulatedBinaryCrossoverOptions,
|
|
34
|
+
SingleArithmeticCrossoverOptions,
|
|
35
|
+
SinglePointBinaryCrossoverOptions,
|
|
36
|
+
UniformIntegerCrossoverOptions,
|
|
37
|
+
UniformMixedIntegerCrossoverOptions,
|
|
38
|
+
)
|
|
39
|
+
from .options.generator import (
|
|
40
|
+
LHSGeneratorOptions,
|
|
41
|
+
RandomBinaryGeneratorOptions,
|
|
42
|
+
RandomGeneratorOptions,
|
|
43
|
+
RandomIntegerGeneratorOptions,
|
|
44
|
+
RandomMixedIntegerGeneratorOptions,
|
|
45
|
+
)
|
|
46
|
+
from .options.mutation import (
|
|
47
|
+
BinaryFlipMutationOptions,
|
|
48
|
+
BoundedPolynomialMutationOptions,
|
|
49
|
+
IntegerRandomMutationOptions,
|
|
50
|
+
MixedIntegerRandomMutationOptions,
|
|
51
|
+
MPTMutationOptions,
|
|
52
|
+
NonUniformMutationOptions,
|
|
53
|
+
PowerMutationOptions,
|
|
54
|
+
SelfAdaptiveGaussianMutationOptions,
|
|
55
|
+
)
|
|
56
|
+
from .options.repair import ClipRepairOptions, NoRepairOptions
|
|
57
|
+
from .options.scalar_selection import RouletteWheelSelectionOptions, TournamentSelectionOptions
|
|
58
|
+
from .options.selection import (
|
|
59
|
+
IBEASelectorOptions,
|
|
60
|
+
NSGA2SelectorOptions,
|
|
61
|
+
NSGA3SelectorOptions,
|
|
62
|
+
ReferenceVectorOptions,
|
|
63
|
+
RVEASelectorOptions,
|
|
64
|
+
)
|
|
65
|
+
from .options.templates import (
|
|
66
|
+
DesirableRangesOptions,
|
|
67
|
+
NonPreferredSolutionsOptions,
|
|
68
|
+
PreferredSolutionsOptions,
|
|
69
|
+
ReferencePointOptions,
|
|
70
|
+
Template1Options,
|
|
71
|
+
Template2Options,
|
|
72
|
+
)
|
|
73
|
+
from .options.termination import (
|
|
74
|
+
CompositeTerminatorOptions,
|
|
75
|
+
ExternalCheckTerminatorOptions,
|
|
76
|
+
MaxEvaluationsTerminatorOptions,
|
|
77
|
+
MaxGenerationsTerminatorOptions,
|
|
78
|
+
MaxTimeTerminatorOptions,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Just didn't want to have a thousand imports in the main namespace
|
|
82
|
+
algorithms = SimpleNamespace(
|
|
83
|
+
rvea_options=rvea_options,
|
|
84
|
+
nsga2_options=nsga2_options,
|
|
85
|
+
nsga3_options=nsga3_options,
|
|
86
|
+
ibea_options=ibea_options,
|
|
87
|
+
rvea_mixed_integer_options=rvea_mixed_integer_options,
|
|
88
|
+
nsga3_mixed_integer_options=nsga3_mixed_integer_options,
|
|
89
|
+
ibea_mixed_integer_options=ibea_mixed_integer_options,
|
|
90
|
+
emo_constructor=emo_constructor,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
termination = SimpleNamespace(
|
|
94
|
+
MaxEvaluationsTerminatorOptions=MaxEvaluationsTerminatorOptions,
|
|
95
|
+
MaxGenerationsTerminatorOptions=MaxGenerationsTerminatorOptions,
|
|
96
|
+
MaxTimeTerminatorOptions=MaxTimeTerminatorOptions,
|
|
97
|
+
CompositeTerminatorOptions=CompositeTerminatorOptions,
|
|
98
|
+
ExternalCheckTerminatorOptions=ExternalCheckTerminatorOptions,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
selection = SimpleNamespace(
|
|
102
|
+
IBEASelectorOptions=IBEASelectorOptions,
|
|
103
|
+
NSGA3SelectorOptions=NSGA3SelectorOptions,
|
|
104
|
+
NSGA2SelectorOptions=NSGA2SelectorOptions,
|
|
105
|
+
RVEASelectorOptions=RVEASelectorOptions,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
other = SimpleNamespace(
|
|
109
|
+
ReferenceVectorOptions=ReferenceVectorOptions,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
scalar_selection = SimpleNamespace(
|
|
113
|
+
TournamentSelectionOptions=TournamentSelectionOptions,
|
|
114
|
+
RouletteWheelSelectionOptions=RouletteWheelSelectionOptions,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
mutation = SimpleNamespace(
|
|
118
|
+
BinaryFlipMutationOptions=BinaryFlipMutationOptions,
|
|
119
|
+
BoundedPolynomialMutationOptions=BoundedPolynomialMutationOptions,
|
|
120
|
+
IntegerRandomMutationOptions=IntegerRandomMutationOptions,
|
|
121
|
+
MixedIntegerRandomMutationOptions=MixedIntegerRandomMutationOptions,
|
|
122
|
+
MPTMutationOptions=MPTMutationOptions,
|
|
123
|
+
NonUniformMutationOptions=NonUniformMutationOptions,
|
|
124
|
+
PowerMutationOptions=PowerMutationOptions,
|
|
125
|
+
SelfAdaptiveGaussianMutationOptions=SelfAdaptiveGaussianMutationOptions,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
generator = SimpleNamespace(
|
|
129
|
+
LHSGeneratorOptions=LHSGeneratorOptions,
|
|
130
|
+
RandomBinaryGeneratorOptions=RandomBinaryGeneratorOptions,
|
|
131
|
+
RandomGeneratorOptions=RandomGeneratorOptions,
|
|
132
|
+
RandomIntegerGeneratorOptions=RandomIntegerGeneratorOptions,
|
|
133
|
+
RandomMixedIntegerGeneratorOptions=RandomMixedIntegerGeneratorOptions,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
templates = SimpleNamespace(
|
|
137
|
+
Template1Options=Template1Options,
|
|
138
|
+
Template2Options=Template2Options,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
repair = SimpleNamespace(NoRepairOptions=NoRepairOptions, ClipRepairOptions=ClipRepairOptions)
|
|
142
|
+
|
|
143
|
+
preference_handling = SimpleNamespace(
|
|
144
|
+
ReferencePointOptions=ReferencePointOptions,
|
|
145
|
+
DesirableRangesOptions=DesirableRangesOptions,
|
|
146
|
+
PreferredSolutionsOptions=PreferredSolutionsOptions,
|
|
147
|
+
NonPreferredSolutionsOptions=NonPreferredSolutionsOptions,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
crossover = SimpleNamespace(
|
|
151
|
+
BlendAlphaCrossoverOptions=BlendAlphaCrossoverOptions,
|
|
152
|
+
BoundedExponentialCrossoverOptions=BoundedExponentialCrossoverOptions,
|
|
153
|
+
LocalCrossoverOptions=LocalCrossoverOptions,
|
|
154
|
+
SimulatedBinaryCrossoverOptions=SimulatedBinaryCrossoverOptions,
|
|
155
|
+
SingleArithmeticCrossoverOptions=SingleArithmeticCrossoverOptions,
|
|
156
|
+
SinglePointBinaryCrossoverOptions=SinglePointBinaryCrossoverOptions,
|
|
157
|
+
UniformIntegerCrossoverOptions=UniformIntegerCrossoverOptions,
|
|
158
|
+
UniformMixedIntegerCrossoverOptions=UniformMixedIntegerCrossoverOptions,
|
|
159
|
+
)
|
desdeo/emo/hooks/archivers.py
CHANGED
|
@@ -5,6 +5,7 @@ from collections.abc import Sequence
|
|
|
5
5
|
import polars as pl
|
|
6
6
|
|
|
7
7
|
from desdeo.problem import Problem
|
|
8
|
+
from desdeo.tools.generics import EMOResult
|
|
8
9
|
from desdeo.tools.message import (
|
|
9
10
|
EvaluatorMessageTopics,
|
|
10
11
|
GeneratorMessageTopics,
|
|
@@ -72,6 +73,14 @@ class BaseArchive(Subscriber):
|
|
|
72
73
|
self.selections = pl.concat([self.selections, data], how="vertical")
|
|
73
74
|
return
|
|
74
75
|
|
|
76
|
+
@property
|
|
77
|
+
def results(self) -> EMOResult:
|
|
78
|
+
"""Return the results of the archiver."""
|
|
79
|
+
dec_vars = [x.symbol for x in self.problem.get_flattened_variables()]
|
|
80
|
+
all_cols = self.solutions.columns
|
|
81
|
+
non_decs = [col for col in all_cols if col not in dec_vars]
|
|
82
|
+
return EMOResult(optimal_variables=self.solutions[dec_vars], optimal_outputs=self.solutions[non_decs])
|
|
83
|
+
|
|
75
84
|
|
|
76
85
|
class FeasibleArchive(BaseArchive):
|
|
77
86
|
"""An archiver that stores all feasible solutions evaluated during evolution."""
|
|
@@ -104,7 +113,7 @@ class FeasibleArchive(BaseArchive):
|
|
|
104
113
|
data = message.value
|
|
105
114
|
feasible_mask = (data[self.cons_symb] <= 0).to_numpy().all(axis=1)
|
|
106
115
|
feasible_data = data.filter(feasible_mask)
|
|
107
|
-
feasible_data =
|
|
116
|
+
feasible_data = feasible_data.with_columns(generation=self.generation_number)
|
|
108
117
|
if self.solutions is None:
|
|
109
118
|
self.solutions = feasible_data
|
|
110
119
|
else:
|
|
@@ -135,7 +144,7 @@ class Archive(BaseArchive):
|
|
|
135
144
|
|
|
136
145
|
|
|
137
146
|
class NonDominatedArchive(Archive):
|
|
138
|
-
"""An archiver that stores only the non-dominated solutions evaluated during evolution."""
|
|
147
|
+
"""An archiver that stores only the feasible non-dominated solutions evaluated during evolution."""
|
|
139
148
|
|
|
140
149
|
def __init__(self, *, problem: Problem, publisher: Publisher):
|
|
141
150
|
"""Initialize the archiver.
|
|
@@ -146,6 +155,10 @@ class NonDominatedArchive(Archive):
|
|
|
146
155
|
"""
|
|
147
156
|
super().__init__(problem=problem, publisher=publisher)
|
|
148
157
|
self.targets = [f"{x.symbol}_min" for x in problem.objectives]
|
|
158
|
+
if problem.constraints is None:
|
|
159
|
+
self.cons_symb = []
|
|
160
|
+
else:
|
|
161
|
+
self.cons_symb = [x.symbol for x in problem.constraints]
|
|
149
162
|
|
|
150
163
|
def update(self, message: Message) -> None:
|
|
151
164
|
"""Update the archiver with the new data.
|
|
@@ -163,6 +176,9 @@ class NonDominatedArchive(Archive):
|
|
|
163
176
|
data = data.with_columns(generation=self.generation_number)
|
|
164
177
|
if type(data) is not pl.DataFrame:
|
|
165
178
|
raise ValueError("Data should be a polars DataFrame")
|
|
179
|
+
if self.cons_symb:
|
|
180
|
+
feasible_mask = (data[self.cons_symb] <= 0).to_numpy().all(axis=1)
|
|
181
|
+
data = data.filter(feasible_mask)
|
|
166
182
|
if self.solutions is None:
|
|
167
183
|
non_dom_mask = non_dominated(data[self.targets].to_numpy())
|
|
168
184
|
self.solutions = data.filter(non_dom_mask)
|
desdeo/emo/methods/EAs.py
CHANGED
|
@@ -1,18 +1,33 @@
|
|
|
1
|
-
"""Implements common evolutionary algorithms for multi-objective optimization.
|
|
1
|
+
"""[Deprecated] Implements common evolutionary algorithms for multi-objective optimization.
|
|
2
|
+
|
|
3
|
+
Use desdeo.emo.options.algorithms instead.
|
|
4
|
+
"""
|
|
2
5
|
|
|
3
6
|
from collections.abc import Callable
|
|
4
7
|
from functools import partial
|
|
8
|
+
from warnings import warn
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
5
11
|
|
|
6
|
-
from desdeo.emo.methods.
|
|
12
|
+
from desdeo.emo.methods.templates import EMOResult, template1, template2
|
|
7
13
|
from desdeo.emo.operators.crossover import SimulatedBinaryCrossover, UniformMixedIntegerCrossover
|
|
8
14
|
from desdeo.emo.operators.evaluator import EMOEvaluator
|
|
9
15
|
from desdeo.emo.operators.generator import LHSGenerator, RandomMixedIntegerGenerator
|
|
10
16
|
from desdeo.emo.operators.mutation import BoundedPolynomialMutation, MixedIntegerRandomMutation
|
|
11
|
-
from desdeo.emo.operators.
|
|
17
|
+
from desdeo.emo.operators.scalar_selection import TournamentSelection
|
|
18
|
+
from desdeo.emo.operators.selection import IBEASelector, NSGA3Selector, ReferenceVectorOptions, RVEASelector
|
|
12
19
|
from desdeo.emo.operators.termination import MaxEvaluationsTerminator, MaxGenerationsTerminator
|
|
13
20
|
from desdeo.problem import Problem
|
|
21
|
+
from desdeo.tools.indicators_binary import self_epsilon
|
|
14
22
|
from desdeo.tools.patterns import Publisher
|
|
15
23
|
|
|
24
|
+
warn(
|
|
25
|
+
"desdeo.emo.methods.EAs is deprecated and will be removed in future versions. "
|
|
26
|
+
"Please use desdeo.emo.options.algorithms instead.",
|
|
27
|
+
category=DeprecationWarning,
|
|
28
|
+
stacklevel=1,
|
|
29
|
+
)
|
|
30
|
+
|
|
16
31
|
|
|
17
32
|
def rvea(
|
|
18
33
|
*,
|
|
@@ -159,7 +174,7 @@ def nsga3(
|
|
|
159
174
|
verbosity=forced_verbosity if forced_verbosity is not None else 2,
|
|
160
175
|
)
|
|
161
176
|
|
|
162
|
-
selector =
|
|
177
|
+
selector = NSGA3Selector(
|
|
163
178
|
problem=problem,
|
|
164
179
|
publisher=publisher,
|
|
165
180
|
verbosity=forced_verbosity if forced_verbosity is not None else 2,
|
|
@@ -216,6 +231,114 @@ def nsga3(
|
|
|
216
231
|
)
|
|
217
232
|
|
|
218
233
|
|
|
234
|
+
def ibea(
|
|
235
|
+
*,
|
|
236
|
+
problem: Problem,
|
|
237
|
+
population_size: int = 100,
|
|
238
|
+
n_generations: int = 100,
|
|
239
|
+
max_evaluations: int | None = None,
|
|
240
|
+
kappa: float = 0.05,
|
|
241
|
+
binary_indicator: Callable[[np.ndarray], np.ndarray] = self_epsilon,
|
|
242
|
+
seed: int = 0,
|
|
243
|
+
forced_verbosity: int | None = None,
|
|
244
|
+
) -> tuple[Callable[[], EMOResult], Publisher]:
|
|
245
|
+
"""Implements the Indicator-Based Evolutionary Algorithm (IBEA).
|
|
246
|
+
|
|
247
|
+
References:
|
|
248
|
+
Zitzler, E., Künzli, S. (2004). Indicator-Based Selection in Multiobjective Search. In: Yao, X., et al.
|
|
249
|
+
Parallel Problem Solving from Nature - PPSN VIII. PPSN 2004. Lecture Notes in Computer Science, vol 3242.
|
|
250
|
+
Springer, Berlin, Heidelberg. https://doi.org/10.1007/978-3-540-30217-9_84
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
problem (Problem): The problem to be solved.
|
|
254
|
+
population_size (int, optional): The size of the population. Defaults to 100.
|
|
255
|
+
n_generations (int, optional): The number of generations to run the algorithm. Defaults to 100.
|
|
256
|
+
max_evaluations (int | None, optional): The maximum number of evaluations to run the algorithm. If None, the
|
|
257
|
+
algorithm will run for n_generations. Defaults to None. If both n_generations and max_evaluations are
|
|
258
|
+
provided, the algorithm will run until max_evaluations is reached.
|
|
259
|
+
kappa (float, optional): The kappa value for the IBEA selection. Defaults to 0.05.
|
|
260
|
+
binary_indicator (Callable[[np.ndarray], np.ndarray], optional): A binary indicator function that takes the
|
|
261
|
+
target values and returns a binary indicator for each individual. Defaults to self_epsilon with uses
|
|
262
|
+
binary adaptive epsilon indicator.
|
|
263
|
+
seed (int, optional): The seed for the random number generator. Defaults to 0.
|
|
264
|
+
forced_verbosity (int | None, optional): If not None, the verbosity of the algorithm is forced to this value.
|
|
265
|
+
Defaults to None.
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
tuple[Callable[[], EMOResult], Publisher]: A tuple containing the function to run the algorithm and the
|
|
269
|
+
publisher object. The publisher object can be used to subscribe to the topics of the algorithm components,
|
|
270
|
+
as well as to inject additional functionality such as archiving the results.
|
|
271
|
+
"""
|
|
272
|
+
publisher = Publisher()
|
|
273
|
+
evaluator = EMOEvaluator(
|
|
274
|
+
problem=problem,
|
|
275
|
+
publisher=publisher,
|
|
276
|
+
verbosity=forced_verbosity if forced_verbosity is not None else 2,
|
|
277
|
+
)
|
|
278
|
+
selector = IBEASelector(
|
|
279
|
+
problem=problem,
|
|
280
|
+
verbosity=forced_verbosity if forced_verbosity is not None else 2,
|
|
281
|
+
publisher=publisher,
|
|
282
|
+
population_size=population_size,
|
|
283
|
+
kappa=kappa,
|
|
284
|
+
binary_indicator=binary_indicator,
|
|
285
|
+
)
|
|
286
|
+
generator = LHSGenerator(
|
|
287
|
+
problem=problem,
|
|
288
|
+
evaluator=evaluator,
|
|
289
|
+
publisher=publisher,
|
|
290
|
+
n_points=population_size,
|
|
291
|
+
seed=seed,
|
|
292
|
+
verbosity=forced_verbosity if forced_verbosity is not None else 1,
|
|
293
|
+
)
|
|
294
|
+
crossover = SimulatedBinaryCrossover(
|
|
295
|
+
problem=problem,
|
|
296
|
+
publisher=publisher,
|
|
297
|
+
seed=seed,
|
|
298
|
+
verbosity=forced_verbosity if forced_verbosity is not None else 1,
|
|
299
|
+
)
|
|
300
|
+
mutation = BoundedPolynomialMutation(
|
|
301
|
+
problem=problem,
|
|
302
|
+
publisher=publisher,
|
|
303
|
+
seed=seed,
|
|
304
|
+
verbosity=forced_verbosity if forced_verbosity is not None else 1,
|
|
305
|
+
)
|
|
306
|
+
if max_evaluations is not None:
|
|
307
|
+
terminator = MaxEvaluationsTerminator(max_evaluations, publisher=publisher)
|
|
308
|
+
else:
|
|
309
|
+
terminator = MaxGenerationsTerminator(
|
|
310
|
+
n_generations,
|
|
311
|
+
publisher=publisher,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
scalar_selector = TournamentSelection(publisher=publisher, verbosity=0, winner_size=population_size, seed=seed)
|
|
315
|
+
|
|
316
|
+
components = [
|
|
317
|
+
evaluator,
|
|
318
|
+
generator,
|
|
319
|
+
crossover,
|
|
320
|
+
mutation,
|
|
321
|
+
selector,
|
|
322
|
+
terminator,
|
|
323
|
+
scalar_selector,
|
|
324
|
+
]
|
|
325
|
+
[publisher.auto_subscribe(x) for x in components]
|
|
326
|
+
[publisher.register_topics(x.provided_topics[x.verbosity], x.__class__.__name__) for x in components]
|
|
327
|
+
return (
|
|
328
|
+
partial(
|
|
329
|
+
template2,
|
|
330
|
+
evaluator=evaluator,
|
|
331
|
+
crossover=crossover,
|
|
332
|
+
mutation=mutation,
|
|
333
|
+
generator=generator,
|
|
334
|
+
selection=selector,
|
|
335
|
+
terminator=terminator,
|
|
336
|
+
mate_selection=scalar_selector,
|
|
337
|
+
),
|
|
338
|
+
publisher,
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
|
|
219
342
|
def nsga3_mixed_integer(
|
|
220
343
|
*,
|
|
221
344
|
problem: Problem,
|
|
@@ -261,7 +384,7 @@ def nsga3_mixed_integer(
|
|
|
261
384
|
verbosity=forced_verbosity if forced_verbosity is not None else 2,
|
|
262
385
|
)
|
|
263
386
|
|
|
264
|
-
selector =
|
|
387
|
+
selector = NSGA3Selector(
|
|
265
388
|
problem=problem,
|
|
266
389
|
publisher=publisher,
|
|
267
390
|
verbosity=forced_verbosity if forced_verbosity is not None else 2,
|
desdeo/emo/methods/bases.py
CHANGED
|
@@ -1,59 +1,12 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Deprecated module."""
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
"""
|
|
3
|
+
import warnings
|
|
5
4
|
|
|
6
|
-
import
|
|
7
|
-
import polars as pl
|
|
8
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
5
|
+
from desdeo.emo.methods.templates import EMOResult, template1, template2
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class EMOResult(BaseModel):
|
|
19
|
-
solutions: pl.DataFrame = Field(description="The decision vectors of the final population.")
|
|
20
|
-
"""The decision vectors of the final population."""
|
|
21
|
-
outputs: pl.DataFrame = Field(
|
|
22
|
-
description="The objective vectors, constraint vectors, and targets of the final population."
|
|
23
|
-
)
|
|
24
|
-
"""The objective vectors, constraint vectors, and targets of the final population."""
|
|
25
|
-
|
|
26
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def template1(
|
|
30
|
-
evaluator: EMOEvaluator,
|
|
31
|
-
crossover: BaseCrossover,
|
|
32
|
-
mutation: BaseMutation,
|
|
33
|
-
generator: BaseGenerator,
|
|
34
|
-
selection: BaseSelector,
|
|
35
|
-
terminator: BaseTerminator,
|
|
36
|
-
) -> EMOResult:
|
|
37
|
-
"""Implements a template that many EMO methods, such as RVEA and NSGA-III, follow.
|
|
38
|
-
|
|
39
|
-
Args:
|
|
40
|
-
evaluator (EMOEvaluator): A class that evaluates the solutions and provides the objective vectors, constraint
|
|
41
|
-
vectors, and targets.
|
|
42
|
-
crossover (BaseCrossover): The crossover operator.
|
|
43
|
-
mutation (BaseMutation): The mutation operator.
|
|
44
|
-
generator (BaseGenerator): A class that generates the initial population.
|
|
45
|
-
selection (BaseSelector): The selection operator.
|
|
46
|
-
terminator (BaseTerminator): The termination operator.
|
|
47
|
-
|
|
48
|
-
Returns:
|
|
49
|
-
EMOResult: The final population and their objective vectors, constraint vectors, and targets
|
|
50
|
-
"""
|
|
51
|
-
solutions, outputs = generator.do()
|
|
52
|
-
|
|
53
|
-
while not terminator.check():
|
|
54
|
-
offspring = crossover.do(population=solutions)
|
|
55
|
-
offspring = mutation.do(offspring, solutions)
|
|
56
|
-
offspring_outputs = evaluator.evaluate(offspring)
|
|
57
|
-
solutions, outputs = selection.do(parents=(solutions, outputs), offsprings=(offspring, offspring_outputs))
|
|
58
|
-
|
|
59
|
-
return EMOResult(solutions=solutions, outputs=outputs)
|
|
7
|
+
warnings.warn(
|
|
8
|
+
"The EMO methods in this module are deprecated and will be removed in a future release. "
|
|
9
|
+
"Please use the methods in desdeo.emo.methods.templates instead.",
|
|
10
|
+
DeprecationWarning,
|
|
11
|
+
stacklevel=2,
|
|
12
|
+
)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""This module contains the basic functional implementations for the EMO methods.
|
|
2
|
+
|
|
3
|
+
This can be used as a template for the implementation of the EMO methods.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
|
|
8
|
+
import polars as pl
|
|
9
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
10
|
+
|
|
11
|
+
from desdeo.emo.operators.crossover import BaseCrossover
|
|
12
|
+
from desdeo.emo.operators.evaluator import EMOEvaluator
|
|
13
|
+
from desdeo.emo.operators.generator import BaseGenerator
|
|
14
|
+
from desdeo.emo.operators.mutation import BaseMutation
|
|
15
|
+
from desdeo.emo.operators.scalar_selection import BaseScalarSelector
|
|
16
|
+
from desdeo.emo.operators.selection import BaseSelector
|
|
17
|
+
from desdeo.emo.operators.termination import BaseTerminator
|
|
18
|
+
from desdeo.tools.generics import EMOResult
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def template1(
|
|
22
|
+
evaluator: EMOEvaluator,
|
|
23
|
+
crossover: BaseCrossover,
|
|
24
|
+
mutation: BaseMutation,
|
|
25
|
+
generator: BaseGenerator,
|
|
26
|
+
selection: BaseSelector,
|
|
27
|
+
terminator: BaseTerminator,
|
|
28
|
+
repair: Callable[[pl.DataFrame], pl.DataFrame] = lambda x: x, # Default to identity function if no repair is needed
|
|
29
|
+
) -> EMOResult:
|
|
30
|
+
"""Implements a template that many EMO methods, such as RVEA and NSGA-III, follow.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
evaluator (EMOEvaluator): A class that evaluates the solutions and provides the objective vectors, constraint
|
|
34
|
+
vectors, and targets.
|
|
35
|
+
crossover (BaseCrossover): The crossover operator.
|
|
36
|
+
mutation (BaseMutation): The mutation operator.
|
|
37
|
+
generator (BaseGenerator): A class that generates the initial population.
|
|
38
|
+
selection (BaseSelector): The selection operator.
|
|
39
|
+
terminator (BaseTerminator): The termination operator.
|
|
40
|
+
repair (Callable, optional): A function that repairs the offspring if they go out of bounds. Defaults to an
|
|
41
|
+
identity function, meaning no repair is done. See :py:func:`desdeo.tools.utils.repair` as an example of a
|
|
42
|
+
repair function.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
EMOResult: The final population and their objective vectors, constraint vectors, and targets
|
|
46
|
+
"""
|
|
47
|
+
solutions, outputs = generator.do()
|
|
48
|
+
|
|
49
|
+
while not terminator.check():
|
|
50
|
+
offspring = crossover.do(population=solutions)
|
|
51
|
+
offspring = mutation.do(offspring, solutions)
|
|
52
|
+
# Repair offspring if they go out of bounds
|
|
53
|
+
offspring = repair(offspring)
|
|
54
|
+
offspring_outputs = evaluator.evaluate(offspring)
|
|
55
|
+
solutions, outputs = selection.do(parents=(solutions, outputs), offsprings=(offspring, offspring_outputs))
|
|
56
|
+
|
|
57
|
+
return EMOResult(optimal_variables=solutions, optimal_outputs=outputs)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def template2(
|
|
61
|
+
evaluator: EMOEvaluator,
|
|
62
|
+
crossover: BaseCrossover,
|
|
63
|
+
mutation: BaseMutation,
|
|
64
|
+
generator: BaseGenerator,
|
|
65
|
+
selection: BaseSelector,
|
|
66
|
+
mate_selection: BaseScalarSelector,
|
|
67
|
+
terminator: BaseTerminator,
|
|
68
|
+
repair: Callable[[pl.DataFrame], pl.DataFrame] = lambda x: x, # Default to identity function if no repair is needed
|
|
69
|
+
) -> EMOResult:
|
|
70
|
+
"""Implements a template that many EMO methods, such as IBEA, follow.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
evaluator (EMOEvaluator): A class that evaluates the solutions and provides the objective vectors, constraint
|
|
74
|
+
vectors, and targets.
|
|
75
|
+
crossover (BaseCrossover): The crossover operator.
|
|
76
|
+
mutation (BaseMutation): The mutation operator.
|
|
77
|
+
generator (BaseGenerator): A class that generates the initial population.
|
|
78
|
+
selection (BaseSelector): The selection operator.
|
|
79
|
+
mate_selection (BaseScalarSelector): The mating selection operator, which selects parents for mating.
|
|
80
|
+
This is typically a scalar selector that selects parents based on their fitness.
|
|
81
|
+
terminator (BaseTerminator): The termination operator.
|
|
82
|
+
repair (Callable, optional): A function that repairs the offspring if they go out of bounds. Defaults to an
|
|
83
|
+
identity function, meaning no repair is done. See :py:func:`desdeo.tools.utils.repair` as an example of a
|
|
84
|
+
repair function.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
EMOResult: The final population and their objective vectors, constraint vectors, and targets
|
|
88
|
+
"""
|
|
89
|
+
solutions, outputs = generator.do()
|
|
90
|
+
# This is just a hack to make all selection operators work (they require offsprings to be passed separately rn)
|
|
91
|
+
offspring = pl.DataFrame(
|
|
92
|
+
schema=solutions.schema,
|
|
93
|
+
)
|
|
94
|
+
offspring_outputs = pl.DataFrame(
|
|
95
|
+
schema=outputs.schema,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
while True:
|
|
99
|
+
solutions, outputs = selection.do(parents=(solutions, outputs), offsprings=(offspring, offspring_outputs))
|
|
100
|
+
if terminator.check():
|
|
101
|
+
# Weird way to do looping, but IBEA does environmental selection before the loop check, and...
|
|
102
|
+
# does mating afterwards.
|
|
103
|
+
break
|
|
104
|
+
parents, _ = mate_selection.do((solutions, outputs))
|
|
105
|
+
offspring = crossover.do(population=parents)
|
|
106
|
+
offspring = mutation.do(offspring, solutions)
|
|
107
|
+
# Repair offspring if they go out of bounds
|
|
108
|
+
offspring = repair(offspring)
|
|
109
|
+
offspring_outputs = evaluator.evaluate(offspring)
|
|
110
|
+
|
|
111
|
+
return EMOResult(optimal_variables=solutions, optimal_outputs=outputs)
|