desdeo 2.0.0__py3-none-any.whl → 2.1.0__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 +5 -1
- 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/infix_parser.py +2 -2
- desdeo/problem/pyomo_evaluator.py +25 -6
- desdeo/problem/schema.py +69 -48
- 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/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 +48 -35
- 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.0.dist-info}/METADATA +46 -28
- desdeo-2.1.0.dist-info/RECORD +180 -0
- {desdeo-2.0.0.dist-info → desdeo-2.1.0.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.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""Variants of the river pollution problem are defined here."""
|
|
2
|
+
|
|
1
3
|
from pathlib import Path
|
|
2
4
|
|
|
3
5
|
import polars as pl
|
|
@@ -12,6 +14,7 @@ from desdeo.problem.schema import (
|
|
|
12
14
|
VariableTypeEnum,
|
|
13
15
|
)
|
|
14
16
|
|
|
17
|
+
|
|
15
18
|
def river_pollution_problem(*, five_objective_variant: bool = True) -> Problem:
|
|
16
19
|
r"""Create a pydantic dataclass representation of the river pollution problem with either five or four variables.
|
|
17
20
|
|
|
@@ -164,34 +167,34 @@ def river_pollution_problem_discrete(*, five_objective_variant: bool = True) ->
|
|
|
164
167
|
Heidelberg, 1997.
|
|
165
168
|
"""
|
|
166
169
|
filename = "datasets/river_poll_4_objs.csv"
|
|
167
|
-
|
|
168
|
-
|
|
170
|
+
true_var_names = {"x_1": "BOD", "x_2": "DO"}
|
|
171
|
+
true_obj_names = {"f1": "DO city", "f2": "DO municipality", "f3": "ROI fishery", "f4": "ROI city"}
|
|
169
172
|
if five_objective_variant:
|
|
170
173
|
filename = "datasets/river_poll_5_objs.csv"
|
|
171
|
-
|
|
174
|
+
true_obj_names["f5"] = "BOD deviation"
|
|
172
175
|
|
|
173
176
|
path = Path(__file__).parent.parent.parent.parent / filename
|
|
174
177
|
data = pl.read_csv(path, has_header=True)
|
|
175
178
|
|
|
176
179
|
variables = [
|
|
177
180
|
Variable(
|
|
178
|
-
name=
|
|
181
|
+
name=true_var_names[varName],
|
|
179
182
|
symbol=varName,
|
|
180
183
|
variable_type=VariableTypeEnum.real,
|
|
181
184
|
lowerbound=0.3,
|
|
182
185
|
upperbound=1.0,
|
|
183
186
|
initial_value=0.65,
|
|
184
187
|
)
|
|
185
|
-
for varName in
|
|
188
|
+
for varName in true_var_names
|
|
186
189
|
]
|
|
187
190
|
maximize = {"f1": True, "f2": True, "f3": True, "f4": True, "f5": False}
|
|
188
|
-
ideal = {objName: (data[objName].max() if maximize[objName] else data[objName].min()) for objName in
|
|
189
|
-
nadir = {objName: (data[objName].min() if maximize[objName] else data[objName].max()) for objName in
|
|
191
|
+
ideal = {objName: (data[objName].max() if maximize[objName] else data[objName].min()) for objName in true_obj_names}
|
|
192
|
+
nadir = {objName: (data[objName].min() if maximize[objName] else data[objName].max()) for objName in true_obj_names}
|
|
190
193
|
units = {"f1": "mg/L", "f2": "mg/L", "f3": "%", "f4": "%", "f5": "mg/L"}
|
|
191
194
|
|
|
192
195
|
objectives = [
|
|
193
196
|
Objective(
|
|
194
|
-
name=
|
|
197
|
+
name=true_obj_names[objName],
|
|
195
198
|
symbol=objName,
|
|
196
199
|
func=None,
|
|
197
200
|
unit=units[objName],
|
|
@@ -200,12 +203,12 @@ def river_pollution_problem_discrete(*, five_objective_variant: bool = True) ->
|
|
|
200
203
|
ideal=ideal[objName],
|
|
201
204
|
nadir=nadir[objName],
|
|
202
205
|
)
|
|
203
|
-
for objName in
|
|
206
|
+
for objName in true_obj_names
|
|
204
207
|
]
|
|
205
208
|
|
|
206
209
|
discrete_def = DiscreteRepresentation(
|
|
207
|
-
variable_values=data[list(
|
|
208
|
-
objective_values=data[list(
|
|
210
|
+
variable_values=data[list(true_var_names.keys())].to_dict(),
|
|
211
|
+
objective_values=data[list(true_obj_names.keys())].to_dict(),
|
|
209
212
|
)
|
|
210
213
|
|
|
211
214
|
return Problem(
|
|
@@ -254,8 +257,10 @@ def river_pollution_scenario() -> Problem:
|
|
|
254
257
|
$$
|
|
255
258
|
\\begin{equation}
|
|
256
259
|
\\begin{array}{rll}
|
|
257
|
-
\\text{maximize} & f_1(\\mathbf{x}) = & \\alpha + \\left(\\log\\left(\\left(\\frac{\\beta}{2}
|
|
258
|
-
|
|
260
|
+
\\text{maximize} & f_1(\\mathbf{x}) = & \\alpha + \\left(\\log\\left(\\left(\\frac{\\beta}{2}
|
|
261
|
+
- 1.14\\right)^2\\right) + \\beta^3\\right) x_1 \\\\
|
|
262
|
+
\\text{maximize} & f_2(\\mathbf{x}) = & \\gamma + \\delta x_1 + \\xi x_2 + \\frac{0.01}{\\eta - x_1^2}
|
|
263
|
+
+ \\frac{0.30}{\\eta - x_2^2} \\\\
|
|
259
264
|
\\text{maximize} & f_3(\\mathbf{x}) = & r - \\frac{0.71}{1.09 - x_1^2} \\\\
|
|
260
265
|
\\text{minimize} & f_4(\\mathbf{x}) = & -0.96 + \\frac{0.96}{1.09 - x_2^2} \\\\
|
|
261
266
|
\\text{subject to} & & 0.3 \\leq x_1, x_2 \\leq 1.0.
|
|
@@ -278,7 +283,7 @@ def river_pollution_scenario() -> Problem:
|
|
|
278
283
|
Analysis: Proceedings of the XIth International Conference on MCDM, 1-6
|
|
279
284
|
August 1994, Coimbra, Portugal. Berlin, Heidelberg: Springer Berlin
|
|
280
285
|
Heidelberg, 1997.
|
|
281
|
-
"""
|
|
286
|
+
""" # noqa: RUF002
|
|
282
287
|
num_scenarios = 6
|
|
283
288
|
scenario_key_stub = "scenario"
|
|
284
289
|
|
|
@@ -351,22 +356,23 @@ def river_pollution_scenario() -> Problem:
|
|
|
351
356
|
scenario_keys = []
|
|
352
357
|
|
|
353
358
|
for i in range(num_scenarios):
|
|
354
|
-
scenario_key = f"{scenario_key_stub}_{i+1}"
|
|
359
|
+
scenario_key = f"{scenario_key_stub}_{i + 1}"
|
|
355
360
|
scenario_keys.append(scenario_key)
|
|
356
361
|
|
|
357
|
-
gamma_expr = f"Ln(alpha[{i+1}]/2 - 1) + alpha[{i+1}]/2 + 1.5"
|
|
362
|
+
gamma_expr = f"Ln(alpha[{i + 1}]/2 - 1) + alpha[{i + 1}]/2 + 1.5"
|
|
358
363
|
|
|
359
|
-
f1_expr = f"alpha[{i+1}] + (Ln((beta[{i+1}]/2 - 1.14)**2) + beta[{i+1}]**3)*x_1"
|
|
364
|
+
f1_expr = f"alpha[{i + 1}] + (Ln((beta[{i + 1}]/2 - 1.14)**2) + beta[{i + 1}]**3)*x_1"
|
|
360
365
|
f2_expr = (
|
|
361
|
-
f"{gamma_expr} + delta[{i+1}]*x_1 + xi[{i+1}]*x_2 + 0.01/(eta[{i+1}] - x_1**2)
|
|
366
|
+
f"{gamma_expr} + delta[{i + 1}]*x_1 + xi[{i + 1}]*x_2 + 0.01/(eta[{i + 1}] - x_1**2) "
|
|
367
|
+
f"+ 0.3/(eta[{i + 1}] - x_2**2)"
|
|
362
368
|
)
|
|
363
|
-
f3_expr = f"r[{i+1}] - 0.71/(1.09 - x_1**2)"
|
|
369
|
+
f3_expr = f"r[{i + 1}] - 0.71/(1.09 - x_1**2)"
|
|
364
370
|
|
|
365
371
|
# f1
|
|
366
372
|
objectives.append(
|
|
367
373
|
Objective(
|
|
368
374
|
name="DO level city",
|
|
369
|
-
symbol=f"f1_{i+1}",
|
|
375
|
+
symbol=f"f1_{i + 1}",
|
|
370
376
|
scenario_keys=[scenario_key],
|
|
371
377
|
func=f1_expr,
|
|
372
378
|
objective_type=ObjectiveTypeEnum.analytical,
|
|
@@ -381,7 +387,7 @@ def river_pollution_scenario() -> Problem:
|
|
|
381
387
|
objectives.append(
|
|
382
388
|
Objective(
|
|
383
389
|
name="DO level fishery",
|
|
384
|
-
symbol=f"f2_{i+1}",
|
|
390
|
+
symbol=f"f2_{i + 1}",
|
|
385
391
|
scenario_keys=[scenario_key],
|
|
386
392
|
func=f2_expr,
|
|
387
393
|
objective_type=ObjectiveTypeEnum.analytical,
|
|
@@ -396,7 +402,7 @@ def river_pollution_scenario() -> Problem:
|
|
|
396
402
|
objectives.append(
|
|
397
403
|
Objective(
|
|
398
404
|
name="Return of investment",
|
|
399
|
-
symbol=f"f3_{i+1}",
|
|
405
|
+
symbol=f"f3_{i + 1}",
|
|
400
406
|
scenario_keys=[scenario_key],
|
|
401
407
|
func=f3_expr,
|
|
402
408
|
objective_type=ObjectiveTypeEnum.analytical,
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"""Here a variety of single-objective optimization problems are defined."""
|
|
2
|
+
|
|
3
|
+
import math
|
|
4
|
+
|
|
5
|
+
from desdeo.problem import (
|
|
6
|
+
Constant,
|
|
7
|
+
Constraint,
|
|
8
|
+
ConstraintTypeEnum,
|
|
9
|
+
ExtraFunction,
|
|
10
|
+
Objective,
|
|
11
|
+
Problem,
|
|
12
|
+
Variable,
|
|
13
|
+
VariableTypeEnum,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def mystery_function() -> Problem:
|
|
18
|
+
r"""Add the constrained mystery function as defined in Sasena 2002.
|
|
19
|
+
|
|
20
|
+
Global solution's value (constrained): -1.174261 at x = [2.5044, 2.5778].
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Problem: the problem model.
|
|
24
|
+
|
|
25
|
+
References:
|
|
26
|
+
Michael Sasena. 2002. Flexibility and Eiciency Enhancements For
|
|
27
|
+
Constrained Global Design Optimization with Kriging Approximations. Ph.D. Dissertation.
|
|
28
|
+
"""
|
|
29
|
+
pi = Constant(name="Pi", symbol="PI", value=math.pi)
|
|
30
|
+
x_1 = Variable(
|
|
31
|
+
name="x_1", symbol="x_1", variable_type=VariableTypeEnum.real, lowerbound=0.0, upperbound=5.0, initial_value=0.1
|
|
32
|
+
)
|
|
33
|
+
x_2 = Variable(
|
|
34
|
+
name="x_2", symbol="x_2", variable_type=VariableTypeEnum.real, lowerbound=0.0, upperbound=5.0, initial_value=0.1
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
f_1_def = "2 + 0.01*(x_2 - x_1**2)**2 + (1 - x_1)**2 + 2*(2 - x_2)**2 + 7*Sin(0.5*x_1)*Sin(0.7*x_1*x_2)"
|
|
38
|
+
f_1 = Objective(
|
|
39
|
+
name="f_1",
|
|
40
|
+
symbol="f_1",
|
|
41
|
+
func=f_1_def,
|
|
42
|
+
maximize=False,
|
|
43
|
+
is_linear=False,
|
|
44
|
+
is_convex=False,
|
|
45
|
+
is_twice_differentiable=True,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
c_1_def = "-Sin(x_1 - x_2 - PI/8.0)"
|
|
49
|
+
c_1 = Constraint(
|
|
50
|
+
name="c_1",
|
|
51
|
+
symbol="c_1",
|
|
52
|
+
cons_type=ConstraintTypeEnum.LTE,
|
|
53
|
+
func=c_1_def,
|
|
54
|
+
is_linear=False,
|
|
55
|
+
is_convex=False,
|
|
56
|
+
is_twice_differentiable=True,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
return Problem(
|
|
60
|
+
name="Mystery function",
|
|
61
|
+
description="The single-objective mystery function.",
|
|
62
|
+
constants=[pi],
|
|
63
|
+
variables=[x_1, x_2],
|
|
64
|
+
objectives=[f_1],
|
|
65
|
+
constraints=[c_1],
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def new_branin_function() -> Problem:
|
|
70
|
+
"""Implements the new Branin function.
|
|
71
|
+
|
|
72
|
+
Global optimal -268.78792 at x = [3.2730, 0.0489].
|
|
73
|
+
"""
|
|
74
|
+
pi = Constant(name="Pi", symbol="PI", value=math.pi)
|
|
75
|
+
x_1 = Variable(
|
|
76
|
+
name="x_1",
|
|
77
|
+
symbol="x_1",
|
|
78
|
+
variable_type=VariableTypeEnum.real,
|
|
79
|
+
lowerbound=-5.0,
|
|
80
|
+
upperbound=10.0,
|
|
81
|
+
initial_value=0.1,
|
|
82
|
+
)
|
|
83
|
+
x_2 = Variable(
|
|
84
|
+
name="x_2",
|
|
85
|
+
symbol="x_2",
|
|
86
|
+
variable_type=VariableTypeEnum.real,
|
|
87
|
+
lowerbound=0.0,
|
|
88
|
+
upperbound=15.0,
|
|
89
|
+
initial_value=0.1,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
f_1_def = "-(x_1 - 10)**2 - (x_2 - 15)**2"
|
|
93
|
+
f_1 = Objective(
|
|
94
|
+
name="f_1",
|
|
95
|
+
symbol="f_1",
|
|
96
|
+
func=f_1_def,
|
|
97
|
+
maximize=False,
|
|
98
|
+
is_linear=False,
|
|
99
|
+
is_convex=False,
|
|
100
|
+
is_twice_differentiable=True,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
c_1_def = "(x_2 - (5.1 / (4*PI**2)) * x_1**2 + (5 / PI)*x_1 - 6)**2 + 10*(1 - 1/(8*PI))*Cos(x_1) + 5"
|
|
104
|
+
c_1 = Constraint(
|
|
105
|
+
name="c_1",
|
|
106
|
+
symbol="c_1",
|
|
107
|
+
cons_type=ConstraintTypeEnum.LTE,
|
|
108
|
+
func=c_1_def,
|
|
109
|
+
is_linear=False,
|
|
110
|
+
is_convex=False,
|
|
111
|
+
is_twice_differentiable=True,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
return Problem(
|
|
115
|
+
name="New Branin function",
|
|
116
|
+
description="The single-objective mystery function.",
|
|
117
|
+
constants=[pi],
|
|
118
|
+
variables=[x_1, x_2],
|
|
119
|
+
objectives=[f_1],
|
|
120
|
+
constraints=[c_1],
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def mishras_bird_constrained() -> Problem:
|
|
125
|
+
"""Implements the constrained variant of Mishra's bird function.
|
|
126
|
+
|
|
127
|
+
Global optima: -106.7645367 at [-3.1302468, -1.5821422]
|
|
128
|
+
"""
|
|
129
|
+
x_1 = Variable(
|
|
130
|
+
name="x_1",
|
|
131
|
+
symbol="x_1",
|
|
132
|
+
variable_type=VariableTypeEnum.real,
|
|
133
|
+
lowerbound=-10.0,
|
|
134
|
+
upperbound=0.0,
|
|
135
|
+
initial_value=-0.1,
|
|
136
|
+
)
|
|
137
|
+
x_2 = Variable(
|
|
138
|
+
name="x_2",
|
|
139
|
+
symbol="x_2",
|
|
140
|
+
variable_type=VariableTypeEnum.real,
|
|
141
|
+
lowerbound=-6.5,
|
|
142
|
+
upperbound=0.0,
|
|
143
|
+
initial_value=-0.1,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
f_1_def = "Sin(x_2)*Exp((1 - Cos(x_1))**2) + Cos(x_1)*Exp((1 - Sin(x_2))**2) + (x_1 - x_2)**2"
|
|
147
|
+
f_1 = Objective(
|
|
148
|
+
name="f_1",
|
|
149
|
+
symbol="f_1",
|
|
150
|
+
func=f_1_def,
|
|
151
|
+
maximize=False,
|
|
152
|
+
is_linear=False,
|
|
153
|
+
is_convex=False,
|
|
154
|
+
is_twice_differentiable=True,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
c_1_def = "(x_1 + 5)**2 + (x_2 + 5)**2 - 25"
|
|
158
|
+
c_1 = Constraint(
|
|
159
|
+
name="c_1",
|
|
160
|
+
symbol="c_1",
|
|
161
|
+
cons_type=ConstraintTypeEnum.LTE,
|
|
162
|
+
func=c_1_def,
|
|
163
|
+
is_linear=False,
|
|
164
|
+
is_convex=False,
|
|
165
|
+
is_twice_differentiable=True,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
return Problem(
|
|
169
|
+
name="Mishra's bird function",
|
|
170
|
+
description="The constrained variant of Mishra's bird function",
|
|
171
|
+
variables=[x_1, x_2],
|
|
172
|
+
objectives=[f_1],
|
|
173
|
+
constraints=[c_1],
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def rosenbrock_disk() -> Problem:
|
|
178
|
+
"""Defines the Rosenbrock test functions constrained to a disk.
|
|
179
|
+
|
|
180
|
+
Global optima is 0 at [1.0, 1.0].
|
|
181
|
+
"""
|
|
182
|
+
x = Variable(
|
|
183
|
+
name="x",
|
|
184
|
+
symbol="x",
|
|
185
|
+
variable_type=VariableTypeEnum.real,
|
|
186
|
+
lowerbound=-1.5,
|
|
187
|
+
upperbound=1.5,
|
|
188
|
+
initial_value=0.1,
|
|
189
|
+
)
|
|
190
|
+
y = Variable(
|
|
191
|
+
name="y",
|
|
192
|
+
symbol="y",
|
|
193
|
+
variable_type=VariableTypeEnum.real,
|
|
194
|
+
lowerbound=-1.5,
|
|
195
|
+
upperbound=1.5,
|
|
196
|
+
initial_value=0.1,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
f_1_def = "(1 - x)**2 + 100*(y - x**2)**2"
|
|
200
|
+
f_1 = Objective(
|
|
201
|
+
name="f_1",
|
|
202
|
+
symbol="f_1",
|
|
203
|
+
func=f_1_def,
|
|
204
|
+
maximize=False,
|
|
205
|
+
is_linear=False,
|
|
206
|
+
is_convex=False,
|
|
207
|
+
is_twice_differentiable=True,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
c_1_def = "x**2 + y**2 - 2.0"
|
|
211
|
+
c_1 = Constraint(
|
|
212
|
+
name="c_1",
|
|
213
|
+
symbol="c_1",
|
|
214
|
+
cons_type=ConstraintTypeEnum.LTE,
|
|
215
|
+
func=c_1_def,
|
|
216
|
+
is_linear=False,
|
|
217
|
+
is_convex=False,
|
|
218
|
+
is_twice_differentiable=True,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
return Problem(
|
|
222
|
+
name="Rosenbrock test function",
|
|
223
|
+
description="The Rosenbrock test function constrained to a disk.",
|
|
224
|
+
variables=[x, y],
|
|
225
|
+
objectives=[f_1],
|
|
226
|
+
constraints=[c_1],
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def townsend_modified() -> Problem:
|
|
231
|
+
"""Implements the modified Townsend function.
|
|
232
|
+
|
|
233
|
+
Global optima is -2.0239884 at [2.0052938, 1.1944509].
|
|
234
|
+
"""
|
|
235
|
+
x = Variable(
|
|
236
|
+
name="x",
|
|
237
|
+
symbol="x",
|
|
238
|
+
variable_type=VariableTypeEnum.real,
|
|
239
|
+
lowerbound=-2.25,
|
|
240
|
+
upperbound=2.25,
|
|
241
|
+
initial_value=0.1,
|
|
242
|
+
)
|
|
243
|
+
y = Variable(
|
|
244
|
+
name="y",
|
|
245
|
+
symbol="y",
|
|
246
|
+
variable_type=VariableTypeEnum.real,
|
|
247
|
+
lowerbound=-2.5,
|
|
248
|
+
upperbound=1.75,
|
|
249
|
+
initial_value=0.1,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
f_1_def = "-1.0 * (Cos((x - 0.1)*y))**2 - x*Sin(3.0*x + y)"
|
|
253
|
+
f_1 = Objective(
|
|
254
|
+
name="f_1",
|
|
255
|
+
symbol="f_1",
|
|
256
|
+
func=f_1_def,
|
|
257
|
+
maximize=False,
|
|
258
|
+
is_linear=False,
|
|
259
|
+
is_convex=False,
|
|
260
|
+
is_twice_differentiable=True,
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
# define the atan2 functions as the double of the arctangent of the half tangent
|
|
264
|
+
# Obs! Risk of dividing by zero!
|
|
265
|
+
t_symbol = "t"
|
|
266
|
+
t_def = "2.0*Arctan(x / (Sqrt(y**2 + x**2) + y))"
|
|
267
|
+
t = ExtraFunction(
|
|
268
|
+
name="Atan2", symbol=t_symbol, func=t_def, is_convex=False, is_linear=False, is_twice_differentiable=True
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
c_1_def = "x**2 + y**2 - (2.0*Cos(t) - 0.5*Cos(2.0*t) - 0.25*Cos(3.0*t) - 0.125*Cos(4.0*t))**2 - (2.0*Sin(t))**2"
|
|
272
|
+
c_1 = Constraint(
|
|
273
|
+
name="c_1",
|
|
274
|
+
symbol="c_1",
|
|
275
|
+
cons_type=ConstraintTypeEnum.LTE,
|
|
276
|
+
func=c_1_def,
|
|
277
|
+
is_linear=False,
|
|
278
|
+
is_convex=False,
|
|
279
|
+
is_twice_differentiable=True,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
return Problem(
|
|
283
|
+
name="Townsend function",
|
|
284
|
+
description="The modified Townsend function.",
|
|
285
|
+
variables=[x, y],
|
|
286
|
+
objectives=[f_1],
|
|
287
|
+
constraints=[c_1],
|
|
288
|
+
extra_funcs=[t],
|
|
289
|
+
)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from math import pi
|
|
2
|
+
|
|
1
3
|
from desdeo.problem.schema import (
|
|
2
4
|
ExtraFunction,
|
|
3
5
|
Objective,
|
|
@@ -5,6 +7,7 @@ from desdeo.problem.schema import (
|
|
|
5
7
|
Variable,
|
|
6
8
|
)
|
|
7
9
|
|
|
10
|
+
|
|
8
11
|
def zdt1(number_of_variables: int) -> Problem:
|
|
9
12
|
r"""Defines the ZDT1 test problem.
|
|
10
13
|
|
|
@@ -214,7 +217,7 @@ def zdt3(
|
|
|
214
217
|
|
|
215
218
|
# function h(f, g)
|
|
216
219
|
h_symbol = "h"
|
|
217
|
-
h_expr = f"1 - Sqrt(({f1_expr}) / ({g_expr})) - (({f1_expr}) / ({g_expr})) * Sin (10 * {
|
|
220
|
+
h_expr = f"1 - Sqrt(({f1_expr}) / ({g_expr})) - (({f1_expr}) / ({g_expr})) * Sin (10 * {pi} * {f1_expr}) "
|
|
218
221
|
|
|
219
222
|
# function f_2
|
|
220
223
|
f2_symbol = "f_2"
|
desdeo/tools/__init__.py
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
__all__ = [
|
|
4
4
|
"BaseSolver",
|
|
5
5
|
"BonminOptions",
|
|
6
|
-
"IpoptOptions",
|
|
7
6
|
"GurobipySolver",
|
|
7
|
+
"IpoptOptions",
|
|
8
8
|
"NevergradGenericOptions",
|
|
9
9
|
"NevergradGenericSolver",
|
|
10
10
|
"PersistentGurobipySolver",
|
|
@@ -13,26 +13,34 @@ __all__ = [
|
|
|
13
13
|
"PyomoCBCSolver",
|
|
14
14
|
"PyomoGurobiSolver",
|
|
15
15
|
"PyomoIpoptSolver",
|
|
16
|
+
"ScalarizationError",
|
|
16
17
|
"ScipyDeSolver",
|
|
17
18
|
"ScipyMinimizeSolver",
|
|
18
19
|
"SolverOptions",
|
|
19
20
|
"SolverResults",
|
|
20
|
-
"ScalarizationError",
|
|
21
21
|
"add_asf_diff",
|
|
22
|
-
"add_asf_generic_nondiff",
|
|
23
22
|
"add_asf_generic_diff",
|
|
23
|
+
"add_asf_generic_nondiff",
|
|
24
24
|
"add_asf_nondiff",
|
|
25
25
|
"add_epsilon_constraints",
|
|
26
|
-
"add_guess_sf_diff",
|
|
27
|
-
"add_guess_sf_nondiff",
|
|
28
26
|
"add_group_asf",
|
|
27
|
+
"add_group_asf_agg",
|
|
28
|
+
"add_group_asf_agg_diff",
|
|
29
29
|
"add_group_asf_diff",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
30
|
+
"add_group_guess",
|
|
31
|
+
"add_group_guess_agg",
|
|
32
|
+
"add_group_guess_agg_diff",
|
|
33
|
+
"add_group_guess_diff",
|
|
34
|
+
"add_group_nimbus",
|
|
35
|
+
"add_group_nimbus_compromise",
|
|
36
|
+
"add_group_nimbus_compromise_diff",
|
|
37
|
+
"add_group_nimbus_diff",
|
|
38
|
+
"add_group_stom",
|
|
39
|
+
"add_group_stom_agg",
|
|
40
|
+
"add_group_stom_agg_diff",
|
|
41
|
+
"add_group_stom_diff",
|
|
42
|
+
"add_guess_sf_diff",
|
|
43
|
+
"add_guess_sf_nondiff",
|
|
36
44
|
"add_nimbus_sf_diff",
|
|
37
45
|
"add_nimbus_sf_nondiff",
|
|
38
46
|
"add_objective_as_scalarization",
|
|
@@ -42,13 +50,31 @@ __all__ = [
|
|
|
42
50
|
"available_nevergrad_optimizers",
|
|
43
51
|
"available_solvers",
|
|
44
52
|
"find_compatible_solvers",
|
|
53
|
+
"flip_maximized_objective_values",
|
|
45
54
|
"get_corrected_ideal_and_nadir",
|
|
46
|
-
"get_corrected_reference_point",
|
|
47
55
|
"guess_best_solver",
|
|
48
56
|
"payoff_table_method",
|
|
49
57
|
]
|
|
50
58
|
|
|
51
59
|
from desdeo.tools.generics import BaseSolver, SolverOptions, SolverResults
|
|
60
|
+
from desdeo.tools.group_scalarization import (
|
|
61
|
+
add_group_asf,
|
|
62
|
+
add_group_asf_agg,
|
|
63
|
+
add_group_asf_agg_diff,
|
|
64
|
+
add_group_asf_diff,
|
|
65
|
+
add_group_guess,
|
|
66
|
+
add_group_guess_agg,
|
|
67
|
+
add_group_guess_agg_diff,
|
|
68
|
+
add_group_guess_diff,
|
|
69
|
+
add_group_nimbus,
|
|
70
|
+
add_group_nimbus_compromise,
|
|
71
|
+
add_group_nimbus_compromise_diff,
|
|
72
|
+
add_group_nimbus_diff,
|
|
73
|
+
add_group_stom,
|
|
74
|
+
add_group_stom_agg,
|
|
75
|
+
add_group_stom_agg_diff,
|
|
76
|
+
add_group_stom_diff,
|
|
77
|
+
)
|
|
52
78
|
from desdeo.tools.gurobipy_solver_interfaces import (
|
|
53
79
|
GurobipySolver,
|
|
54
80
|
PersistentGurobipySolver,
|
|
@@ -74,14 +100,6 @@ from desdeo.tools.scalarization import (
|
|
|
74
100
|
add_asf_generic_nondiff,
|
|
75
101
|
add_asf_nondiff,
|
|
76
102
|
add_epsilon_constraints,
|
|
77
|
-
add_group_asf,
|
|
78
|
-
add_group_asf_diff,
|
|
79
|
-
add_group_guess_sf,
|
|
80
|
-
add_group_guess_sf_diff,
|
|
81
|
-
add_group_nimbus_sf,
|
|
82
|
-
add_group_nimbus_sf_diff,
|
|
83
|
-
add_group_stom_sf,
|
|
84
|
-
add_group_stom_sf_diff,
|
|
85
103
|
add_guess_sf_diff,
|
|
86
104
|
add_guess_sf_nondiff,
|
|
87
105
|
add_nimbus_sf_diff,
|
|
@@ -95,8 +113,8 @@ from desdeo.tools.scipy_solver_interfaces import ScipyDeSolver, ScipyMinimizeSol
|
|
|
95
113
|
from desdeo.tools.utils import (
|
|
96
114
|
available_solvers,
|
|
97
115
|
find_compatible_solvers,
|
|
116
|
+
flip_maximized_objective_values,
|
|
98
117
|
get_corrected_ideal_and_nadir,
|
|
99
|
-
get_corrected_reference_point,
|
|
100
118
|
guess_best_solver,
|
|
101
119
|
payoff_table_method,
|
|
102
120
|
)
|
desdeo/tools/desc_gen.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""An utility function to generate descriptions related to UTOPIA matters"""
|
|
2
|
+
|
|
3
|
+
def generate_descriptions(mapjson: dict, sid: str, stand: str, holding: str, extension: str) -> dict:
|
|
4
|
+
descriptions = {}
|
|
5
|
+
if holding:
|
|
6
|
+
for feat in mapjson["features"]:
|
|
7
|
+
if False: # noqa: SIM108
|
|
8
|
+
ext = f".{feat["properties"][extension]}"
|
|
9
|
+
else:
|
|
10
|
+
ext = ""
|
|
11
|
+
descriptions[feat["properties"][sid]] = (
|
|
12
|
+
f"Ala {feat["properties"][holding].split("-")[-1]} kuvio {feat["properties"][stand]}{ext}: "
|
|
13
|
+
)
|
|
14
|
+
else:
|
|
15
|
+
for feat in mapjson["features"]:
|
|
16
|
+
if False: # noqa: SIM108
|
|
17
|
+
ext = f".{feat["properties"][extension]}"
|
|
18
|
+
else:
|
|
19
|
+
ext = ""
|
|
20
|
+
descriptions[feat["properties"][sid]
|
|
21
|
+
] = f"Kuvio {feat["properties"][stand]}{ext}: "
|
|
22
|
+
return descriptions
|
desdeo/tools/generics.py
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
4
|
from typing import Any, TypeVar
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import polars as pl
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field, field_serializer
|
|
7
8
|
|
|
8
9
|
from desdeo.problem import (
|
|
9
10
|
Constraint,
|
|
@@ -18,6 +19,25 @@ class SolverError(Exception):
|
|
|
18
19
|
"""Raised when an error with a solver is encountered."""
|
|
19
20
|
|
|
20
21
|
|
|
22
|
+
class EMOResult(BaseModel):
|
|
23
|
+
"""Defines a schema for a dataclass to store the results of an EMO method."""
|
|
24
|
+
|
|
25
|
+
model_config = ConfigDict(arbitrary_types_allowed=True, use_attribute_docstrings=True)
|
|
26
|
+
|
|
27
|
+
optimal_variables: pl.DataFrame = Field()
|
|
28
|
+
"""The decision vectors of the final population."""
|
|
29
|
+
optimal_outputs: pl.DataFrame = Field()
|
|
30
|
+
"""The objective vectors, constraint vectors, extra_funcs, and targets of the final population."""
|
|
31
|
+
|
|
32
|
+
@field_serializer("optimal_variables")
|
|
33
|
+
def _serialize_optimal_variables(self, value: pl.DataFrame) -> dict[str, list[int | float]]:
|
|
34
|
+
return value.to_dict(as_series=False)
|
|
35
|
+
|
|
36
|
+
@field_serializer("optimal_outputs")
|
|
37
|
+
def _serialize_optimal_outputs(self, value: pl.DataFrame) -> dict[str, list[int | float]]:
|
|
38
|
+
return value.to_dict(as_series=False)
|
|
39
|
+
|
|
40
|
+
|
|
21
41
|
class SolverResults(BaseModel):
|
|
22
42
|
"""Defines a schema for a dataclass to store the results of a solver."""
|
|
23
43
|
|
|
@@ -25,7 +45,7 @@ class SolverResults(BaseModel):
|
|
|
25
45
|
optimal_objectives: dict[str, float | list[float]] = Field(
|
|
26
46
|
description="The objective function values corresponding to the optimal decision variables found."
|
|
27
47
|
)
|
|
28
|
-
constraint_values: dict[str, float | list[float]] | None = Field(
|
|
48
|
+
constraint_values: dict[str, float | int | list[float] | list] | None | Any = Field(
|
|
29
49
|
description=(
|
|
30
50
|
"The constraint values of the problem. A negative value means the constraint is respected, "
|
|
31
51
|
"a positive one means it has been breached."
|