desdeo 1.2__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/__init__.py +8 -8
- 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/README.md +73 -0
- desdeo/api/__init__.py +15 -0
- desdeo/api/app.py +50 -0
- desdeo/api/config.py +90 -0
- desdeo/api/config.toml +64 -0
- desdeo/api/db.py +27 -0
- desdeo/api/db_init.py +85 -0
- desdeo/api/db_models.py +164 -0
- desdeo/api/malaga_db_init.py +27 -0
- desdeo/api/models/__init__.py +266 -0
- desdeo/api/models/archive.py +23 -0
- 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 +128 -0
- desdeo/api/models/problem.py +717 -0
- desdeo/api/models/reference_point_method.py +18 -0
- desdeo/api/models/session.py +49 -0
- desdeo/api/models/state.py +463 -0
- desdeo/api/models/user.py +52 -0
- desdeo/api/models/utopia.py +25 -0
- desdeo/api/routers/_EMO.backup +309 -0
- desdeo/api/routers/_NAUTILUS.py +245 -0
- desdeo/api/routers/_NAUTILUS_navigator.py +233 -0
- desdeo/api/routers/_NIMBUS.py +765 -0
- desdeo/api/routers/__init__.py +5 -0
- 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 +307 -0
- desdeo/api/routers/reference_point_method.py +93 -0
- desdeo/api/routers/session.py +100 -0
- desdeo/api/routers/test.py +16 -0
- desdeo/api/routers/user_authentication.py +520 -0
- desdeo/api/routers/utils.py +187 -0
- desdeo/api/routers/utopia.py +230 -0
- desdeo/api/schema.py +100 -0
- desdeo/api/tests/__init__.py +0 -0
- desdeo/api/tests/conftest.py +151 -0
- desdeo/api/tests/test_enautilus.py +330 -0
- desdeo/api/tests/test_models.py +1179 -0
- desdeo/api/tests/test_routes.py +1075 -0
- desdeo/api/utils/_database.py +263 -0
- desdeo/api/utils/_logger.py +29 -0
- desdeo/api/utils/database.py +36 -0
- desdeo/api/utils/emo_database.py +40 -0
- desdeo/core.py +34 -0
- desdeo/emo/__init__.py +159 -0
- desdeo/emo/hooks/archivers.py +188 -0
- desdeo/emo/methods/EAs.py +541 -0
- desdeo/emo/methods/__init__.py +0 -0
- desdeo/emo/methods/bases.py +12 -0
- desdeo/emo/methods/templates.py +111 -0
- desdeo/emo/operators/__init__.py +1 -0
- desdeo/emo/operators/crossover.py +1282 -0
- desdeo/emo/operators/evaluator.py +114 -0
- desdeo/emo/operators/generator.py +459 -0
- desdeo/emo/operators/mutation.py +1224 -0
- desdeo/emo/operators/scalar_selection.py +202 -0
- desdeo/emo/operators/selection.py +1778 -0
- desdeo/emo/operators/termination.py +286 -0
- 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/explanations/__init__.py +6 -0
- desdeo/explanations/explainer.py +100 -0
- desdeo/explanations/utils.py +90 -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 +41 -0
- desdeo/mcdm/enautilus.py +338 -0
- desdeo/mcdm/gnimbus.py +484 -0
- desdeo/mcdm/nautili.py +345 -0
- desdeo/mcdm/nautilus.py +477 -0
- desdeo/mcdm/nautilus_navigator.py +656 -0
- desdeo/mcdm/nimbus.py +417 -0
- desdeo/mcdm/pareto_navigator.py +269 -0
- desdeo/mcdm/reference_point_method.py +186 -0
- desdeo/problem/__init__.py +83 -0
- desdeo/problem/evaluator.py +561 -0
- 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 +562 -0
- desdeo/problem/infix_parser.py +341 -0
- desdeo/problem/json_parser.py +944 -0
- desdeo/problem/pyomo_evaluator.py +487 -0
- desdeo/problem/schema.py +1829 -0
- desdeo/problem/simulator_evaluator.py +348 -0
- desdeo/problem/sympy_evaluator.py +244 -0
- desdeo/problem/testproblems/__init__.py +88 -0
- desdeo/problem/testproblems/benchmarks_server.py +120 -0
- desdeo/problem/testproblems/binh_and_korn_problem.py +88 -0
- desdeo/problem/testproblems/cake_problem.py +185 -0
- desdeo/problem/testproblems/dmitry_forest_problem_discrete.py +71 -0
- desdeo/problem/testproblems/dtlz2_problem.py +102 -0
- desdeo/problem/testproblems/forest_problem.py +283 -0
- desdeo/problem/testproblems/knapsack_problem.py +163 -0
- desdeo/problem/testproblems/mcwb_problem.py +831 -0
- desdeo/problem/testproblems/mixed_variable_dimenrions_problem.py +83 -0
- desdeo/problem/testproblems/momip_problem.py +172 -0
- desdeo/problem/testproblems/multi_valued_constraints.py +119 -0
- desdeo/problem/testproblems/nimbus_problem.py +143 -0
- desdeo/problem/testproblems/pareto_navigator_problem.py +89 -0
- desdeo/problem/testproblems/re_problem.py +492 -0
- desdeo/problem/testproblems/river_pollution_problems.py +440 -0
- desdeo/problem/testproblems/rocket_injector_design_problem.py +140 -0
- desdeo/problem/testproblems/simple_problem.py +351 -0
- desdeo/problem/testproblems/simulator_problem.py +92 -0
- desdeo/problem/testproblems/single_objective.py +289 -0
- desdeo/problem/testproblems/spanish_sustainability_problem.py +945 -0
- desdeo/problem/testproblems/zdt_problem.py +274 -0
- desdeo/problem/utils.py +245 -0
- desdeo/tools/GenerateReferencePoints.py +181 -0
- desdeo/tools/__init__.py +120 -0
- desdeo/tools/desc_gen.py +22 -0
- desdeo/tools/generics.py +165 -0
- desdeo/tools/group_scalarization.py +3090 -0
- desdeo/tools/gurobipy_solver_interfaces.py +258 -0
- desdeo/tools/indicators_binary.py +117 -0
- desdeo/tools/indicators_unary.py +362 -0
- desdeo/tools/interaction_schema.py +38 -0
- desdeo/tools/intersection.py +54 -0
- desdeo/tools/iterative_pareto_representer.py +99 -0
- desdeo/tools/message.py +265 -0
- desdeo/tools/ng_solver_interfaces.py +199 -0
- desdeo/tools/non_dominated_sorting.py +134 -0
- desdeo/tools/patterns.py +283 -0
- desdeo/tools/proximal_solver.py +99 -0
- desdeo/tools/pyomo_solver_interfaces.py +477 -0
- desdeo/tools/reference_vectors.py +229 -0
- desdeo/tools/scalarization.py +2065 -0
- desdeo/tools/scipy_solver_interfaces.py +454 -0
- desdeo/tools/score_bands.py +627 -0
- desdeo/tools/utils.py +388 -0
- desdeo/tools/visualizations.py +67 -0
- desdeo/utopia_stuff/__init__.py +0 -0
- desdeo/utopia_stuff/data/1.json +15 -0
- desdeo/utopia_stuff/data/2.json +13 -0
- desdeo/utopia_stuff/data/3.json +15 -0
- desdeo/utopia_stuff/data/4.json +17 -0
- desdeo/utopia_stuff/data/5.json +15 -0
- desdeo/utopia_stuff/from_json.py +40 -0
- desdeo/utopia_stuff/reinit_user.py +38 -0
- desdeo/utopia_stuff/utopia_db_init.py +212 -0
- desdeo/utopia_stuff/utopia_problem.py +403 -0
- desdeo/utopia_stuff/utopia_problem_old.py +415 -0
- desdeo/utopia_stuff/utopia_reference_solutions.py +79 -0
- desdeo-2.1.0.dist-info/METADATA +186 -0
- desdeo-2.1.0.dist-info/RECORD +180 -0
- {desdeo-1.2.dist-info → desdeo-2.1.0.dist-info}/WHEEL +1 -1
- desdeo-2.1.0.dist-info/licenses/LICENSE +21 -0
- desdeo-1.2.dist-info/METADATA +0 -16
- desdeo-1.2.dist-info/RECORD +0 -4
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import polars as pl
|
|
5
|
+
|
|
6
|
+
from desdeo.problem.schema import (
|
|
7
|
+
Constraint,
|
|
8
|
+
ConstraintTypeEnum,
|
|
9
|
+
DiscreteRepresentation,
|
|
10
|
+
Objective,
|
|
11
|
+
ObjectiveTypeEnum,
|
|
12
|
+
Problem,
|
|
13
|
+
TensorConstant,
|
|
14
|
+
TensorVariable,
|
|
15
|
+
Variable,
|
|
16
|
+
VariableTypeEnum,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def forest_problem(
|
|
21
|
+
simulation_results: str = "./tests/data/alternatives_290124.csv",
|
|
22
|
+
treatment_key: str = "./tests/data/alternatives_key_290124.csv",
|
|
23
|
+
holding: int = 1,
|
|
24
|
+
comparing: bool = False,
|
|
25
|
+
) -> Problem:
|
|
26
|
+
r"""Defines a test forest problem that has TensorConstants and TensorVariables.
|
|
27
|
+
|
|
28
|
+
The problem has TensorConstants V, W and P as vectors taking values from a data file and
|
|
29
|
+
TensorVariables X_n, where n is the number of units in the data, as vectors matching the constants in shape.
|
|
30
|
+
The variables are binary and each variable vector X_i has one variable with the value 1 while others have value 0.
|
|
31
|
+
The variable with the value 1 for each vector X_i represents the optimal plan for the corresponding unit i.
|
|
32
|
+
The three objective functions f_1, f_2, f_3 represent the net present value, wood volume at the end of
|
|
33
|
+
the planning period, and the profit from harvesting.
|
|
34
|
+
All of the objective functions are to be maximized.
|
|
35
|
+
The problem is defined as follows:
|
|
36
|
+
|
|
37
|
+
\begin{align}
|
|
38
|
+
\max_{\mathbf{x}} & \quad \sum_{j=1}^N\sum_{i \in I_j} v_{ij} x_{ij} & \\
|
|
39
|
+
& \quad \sum_{j=1}^N\sum_{i \in I_j} w_{ij} x_{ij} & \\
|
|
40
|
+
& \quad \sum_{j=1}^N\sum_{i \in I_j} p_{ij} x_{ij} & \\
|
|
41
|
+
\text{s.t.} & \quad \sum\limits_{i \in I_j} x_{ij} = 1, & \forall j = 1 \ldots N \\
|
|
42
|
+
& \quad x_{ij}\in \{0,1\}& \forall j = 1 \ldots N, ~\forall i\in I_j,
|
|
43
|
+
\end{align}
|
|
44
|
+
|
|
45
|
+
where $x_{ij}$ are decision variables representing the choice of implementing management plan $i$ in stand $j$,
|
|
46
|
+
and $I_j$ is the set of available management plans for stand $j$. For each plan $i$ in stand $j$
|
|
47
|
+
the net present value, wood volume at the end of the planning period, and the profit from harvesting
|
|
48
|
+
are represented by $v_{ij}$, $w_{ij}$, and $p_{ij}$ respectively.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
simulation_results (str): Location of the simulation results file.
|
|
52
|
+
treatment_key (str): Location of the file with the treatment information.
|
|
53
|
+
holding (int, optional): The number of the holding to be optimized. Defaults to 1.
|
|
54
|
+
comparing (bool, optional): This is only used for testing the method.
|
|
55
|
+
If comparing == True, the results are nonsense. Defaults to False.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Problem: An instance of the test forest problem.
|
|
59
|
+
"""
|
|
60
|
+
df = pl.read_csv(simulation_results, schema_overrides={"unit": pl.Float64})
|
|
61
|
+
df_key = pl.read_csv(treatment_key, schema_overrides={"unit": pl.Float64})
|
|
62
|
+
|
|
63
|
+
df_joined = df.join(df_key, on=["holding", "unit", "schedule"], how="left")
|
|
64
|
+
|
|
65
|
+
selected_df = df_joined.filter(pl.col("holding") == holding).select(
|
|
66
|
+
[
|
|
67
|
+
"unit",
|
|
68
|
+
"schedule",
|
|
69
|
+
"npv_5_percent",
|
|
70
|
+
"stock_2025",
|
|
71
|
+
"stock_2035",
|
|
72
|
+
"harvest_value_period_2025",
|
|
73
|
+
"harvest_value_period_2030",
|
|
74
|
+
"harvest_value_period_2035",
|
|
75
|
+
"treatment",
|
|
76
|
+
]
|
|
77
|
+
)
|
|
78
|
+
unique_units = selected_df.unique(["unit"], maintain_order=True).get_column("unit")
|
|
79
|
+
n_units = len(unique_units)
|
|
80
|
+
unique_schedules = selected_df.unique(["schedule"], maintain_order=True).get_column("schedule")
|
|
81
|
+
n_schedules = len(unique_schedules)
|
|
82
|
+
|
|
83
|
+
v_array = np.zeros((n_units, n_schedules))
|
|
84
|
+
w_array = np.zeros((n_units, n_schedules))
|
|
85
|
+
p_array = np.zeros((n_units, n_schedules))
|
|
86
|
+
|
|
87
|
+
# This is not the fastest way to do this, but the code is probably more understandable
|
|
88
|
+
for i in range(n_units):
|
|
89
|
+
for j in range(n_schedules):
|
|
90
|
+
unit = unique_units[i]
|
|
91
|
+
schedule = unique_schedules[j]
|
|
92
|
+
print(f"unit {unit} schedule {schedule}")
|
|
93
|
+
if selected_df.filter((pl.col("unit") == unit) & (pl.col("schedule") == schedule)).height == 0:
|
|
94
|
+
continue
|
|
95
|
+
v_array[i][j] = (
|
|
96
|
+
selected_df.filter((pl.col("unit") == unit) & (pl.col("schedule") == schedule))
|
|
97
|
+
.select("npv_5_percent")
|
|
98
|
+
.item()
|
|
99
|
+
)
|
|
100
|
+
w_array[i][j] = (
|
|
101
|
+
selected_df.filter((pl.col("unit") == unit) & (pl.col("schedule") == schedule))
|
|
102
|
+
.select("stock_2035")
|
|
103
|
+
.item()
|
|
104
|
+
)
|
|
105
|
+
if comparing:
|
|
106
|
+
w_array[i][j] -= (
|
|
107
|
+
selected_df.filter((pl.col("unit") == unit) & (pl.col("schedule") == schedule))
|
|
108
|
+
.select("stock_2025")
|
|
109
|
+
.item()
|
|
110
|
+
)
|
|
111
|
+
# The harvest values are not going to be discounted like this
|
|
112
|
+
p_array[i][j] = sum(
|
|
113
|
+
selected_df.filter((pl.col("unit") == unit) & (pl.col("schedule") == schedule))
|
|
114
|
+
.select(["harvest_value_period_2025", "harvest_value_period_2030", "harvest_value_period_2035"])
|
|
115
|
+
.row(0)
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
constants = []
|
|
119
|
+
variables = []
|
|
120
|
+
constraints = []
|
|
121
|
+
f_1_func = []
|
|
122
|
+
f_2_func = []
|
|
123
|
+
f_3_func = []
|
|
124
|
+
# define the constants V, W and P, decision variable X, constraints, and objective function expressions in one loop
|
|
125
|
+
for i in range(n_units):
|
|
126
|
+
# Constants V, W and P
|
|
127
|
+
v = TensorConstant(
|
|
128
|
+
name=f"V_{i + 1}",
|
|
129
|
+
symbol=f"V_{i + 1}",
|
|
130
|
+
shape=[np.shape(v_array)[1]], # NOTE: vectors have to be of form [2] instead of [2,1] or [1,2]
|
|
131
|
+
values=v_array[i].tolist(),
|
|
132
|
+
)
|
|
133
|
+
constants.append(v)
|
|
134
|
+
w = TensorConstant(
|
|
135
|
+
name=f"W_{i + 1}",
|
|
136
|
+
symbol=f"W_{i + 1}",
|
|
137
|
+
shape=[np.shape(w_array)[1]], # NOTE: vectors have to be of form [2] instead of [2,1] or [1,2]
|
|
138
|
+
values=w_array[i].tolist(),
|
|
139
|
+
)
|
|
140
|
+
constants.append(w)
|
|
141
|
+
p = TensorConstant(
|
|
142
|
+
name=f"P_{i + 1}",
|
|
143
|
+
symbol=f"P_{i + 1}",
|
|
144
|
+
shape=[np.shape(p_array)[1]], # NOTE: vectors have to be of form [2] instead of [2,1] or [1,2]
|
|
145
|
+
values=p_array[i].tolist(),
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Decision variable X
|
|
149
|
+
constants.append(p)
|
|
150
|
+
x = TensorVariable(
|
|
151
|
+
name=f"X_{i + 1}",
|
|
152
|
+
symbol=f"X_{i + 1}",
|
|
153
|
+
variable_type=VariableTypeEnum.binary,
|
|
154
|
+
shape=[np.shape(v_array)[1]], # NOTE: vectors have to be of form [2] instead of [2,1] or [1,2]
|
|
155
|
+
lowerbounds=np.shape(v_array)[1] * [0],
|
|
156
|
+
upperbounds=np.shape(v_array)[1] * [1],
|
|
157
|
+
initial_values=np.shape(v_array)[1] * [0],
|
|
158
|
+
)
|
|
159
|
+
variables.append(x)
|
|
160
|
+
|
|
161
|
+
# Constraints
|
|
162
|
+
con = Constraint(
|
|
163
|
+
name=f"x_con_{i + 1}",
|
|
164
|
+
symbol=f"x_con_{i + 1}",
|
|
165
|
+
cons_type=ConstraintTypeEnum.EQ,
|
|
166
|
+
func=f"Sum(X_{i + 1}) - 1",
|
|
167
|
+
is_linear=True,
|
|
168
|
+
is_convex=False, # not checked
|
|
169
|
+
is_twice_differentiable=True,
|
|
170
|
+
)
|
|
171
|
+
constraints.append(con)
|
|
172
|
+
|
|
173
|
+
# Objective function expressions
|
|
174
|
+
exprs = f"V_{i + 1}@X_{i + 1}"
|
|
175
|
+
f_1_func.append(exprs)
|
|
176
|
+
|
|
177
|
+
exprs = f"W_{i + 1}@X_{i + 1}"
|
|
178
|
+
f_2_func.append(exprs)
|
|
179
|
+
|
|
180
|
+
exprs = f"P_{i + 1}@X_{i + 1}"
|
|
181
|
+
f_3_func.append(exprs)
|
|
182
|
+
|
|
183
|
+
# form the objective function sums
|
|
184
|
+
f_1_func = " + ".join(f_1_func)
|
|
185
|
+
f_2_func = " + ".join(f_2_func)
|
|
186
|
+
f_3_func = " + ".join(f_3_func)
|
|
187
|
+
|
|
188
|
+
f_1 = Objective(
|
|
189
|
+
name="Net present value",
|
|
190
|
+
symbol="f_1",
|
|
191
|
+
func=f_1_func,
|
|
192
|
+
maximize=True,
|
|
193
|
+
objective_type=ObjectiveTypeEnum.analytical,
|
|
194
|
+
is_linear=True,
|
|
195
|
+
is_convex=False, # not checked
|
|
196
|
+
is_twice_differentiable=True,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
f_2 = Objective(
|
|
200
|
+
name="Wood stock volume",
|
|
201
|
+
symbol="f_2",
|
|
202
|
+
func=f_2_func,
|
|
203
|
+
maximize=True,
|
|
204
|
+
objective_type=ObjectiveTypeEnum.analytical,
|
|
205
|
+
is_linear=True,
|
|
206
|
+
is_convex=False, # not checked
|
|
207
|
+
is_twice_differentiable=True,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
f_3 = Objective(
|
|
211
|
+
name="Harvest value",
|
|
212
|
+
symbol="f_3",
|
|
213
|
+
func=f_3_func,
|
|
214
|
+
maximize=True,
|
|
215
|
+
objective_type=ObjectiveTypeEnum.analytical,
|
|
216
|
+
is_linear=True,
|
|
217
|
+
is_convex=False, # not checked
|
|
218
|
+
is_twice_differentiable=True,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
return Problem(
|
|
222
|
+
name="Forest problem",
|
|
223
|
+
description="A test forest problem.",
|
|
224
|
+
constants=constants,
|
|
225
|
+
variables=variables,
|
|
226
|
+
objectives=[f_1, f_2, f_3],
|
|
227
|
+
constraints=constraints,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def forest_problem_discrete() -> Problem:
|
|
232
|
+
"""Implements the forest problem using Pareto front representation.
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
Problem: A problem instance representing the forest problem.
|
|
236
|
+
"""
|
|
237
|
+
filename = "datasets/forest_holding_4.csv"
|
|
238
|
+
|
|
239
|
+
path = Path(__file__).parent.parent.parent.parent / filename
|
|
240
|
+
|
|
241
|
+
obj_names = ["stock", "harvest_value", "npv"]
|
|
242
|
+
|
|
243
|
+
var_name = "index"
|
|
244
|
+
|
|
245
|
+
data = pl.read_csv(
|
|
246
|
+
path, has_header=True, columns=["stock", "harvest_value", "npv"], separator=";", decimal_comma=True
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
variables = [
|
|
250
|
+
Variable(
|
|
251
|
+
name=var_name,
|
|
252
|
+
symbol=var_name,
|
|
253
|
+
variable_type=VariableTypeEnum.integer,
|
|
254
|
+
lowerbound=0,
|
|
255
|
+
upperbound=len(data) - 1,
|
|
256
|
+
initial_value=0,
|
|
257
|
+
)
|
|
258
|
+
]
|
|
259
|
+
|
|
260
|
+
objectives = [
|
|
261
|
+
Objective(
|
|
262
|
+
name=obj_name,
|
|
263
|
+
symbol=obj_name,
|
|
264
|
+
objective_type=ObjectiveTypeEnum.data_based,
|
|
265
|
+
ideal=data[obj_name].max(),
|
|
266
|
+
nadir=data[obj_name].min(),
|
|
267
|
+
maximize=True,
|
|
268
|
+
)
|
|
269
|
+
for obj_name in obj_names
|
|
270
|
+
]
|
|
271
|
+
|
|
272
|
+
discrete_def = DiscreteRepresentation(
|
|
273
|
+
variable_values={"index": list(range(len(data)))},
|
|
274
|
+
objective_values=data[[obj.symbol for obj in objectives]].to_dict(),
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
return Problem(
|
|
278
|
+
name="Finnish Forest Problem (Discrete)",
|
|
279
|
+
description="Defines a forest problem with three objectives: stock, harvest value, and net present value.",
|
|
280
|
+
variables=variables,
|
|
281
|
+
objectives=objectives,
|
|
282
|
+
discrete_representation=discrete_def,
|
|
283
|
+
)
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
from desdeo.problem.schema import (
|
|
2
|
+
Constant,
|
|
3
|
+
Constraint,
|
|
4
|
+
ConstraintTypeEnum,
|
|
5
|
+
Objective,
|
|
6
|
+
ObjectiveTypeEnum,
|
|
7
|
+
Problem,
|
|
8
|
+
TensorConstant,
|
|
9
|
+
TensorVariable,
|
|
10
|
+
Variable,
|
|
11
|
+
VariableTypeEnum,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
def simple_knapsack() -> Problem:
|
|
15
|
+
r"""Defines a simple multiobjective knapsack problem.
|
|
16
|
+
|
|
17
|
+
Given a set of 4 items, each with a weight and three values corresponding to
|
|
18
|
+
different objectives, the problem is defined as follows:
|
|
19
|
+
|
|
20
|
+
- Item 1: weight = 2, values = (5, 10, 15)
|
|
21
|
+
- Item 2: weight = 3, values = (4, 7, 9)
|
|
22
|
+
- Item 3: weight = 1, values = (3, 5, 8)
|
|
23
|
+
- Item 4: weight = 4, values = (2, 3, 5)
|
|
24
|
+
|
|
25
|
+
The problem is then to maximize the following functions:
|
|
26
|
+
|
|
27
|
+
\begin{align*}
|
|
28
|
+
f_1(x) &= 5x_1 + 4x_2 + 3x_3 + 2x_4 \\
|
|
29
|
+
f_2(x) &= 10x_1 + 7x_2 + 5x_3 + 3x_4 \\
|
|
30
|
+
f_3(x) &= 15x_1 + 9x_2 + 8x_3 + 5x_4 \\
|
|
31
|
+
\text{s.t.}\quad & 2x_1 + 3x_2 + 1x_3 + 4x_4 \leq 7 \\
|
|
32
|
+
& x_i \in \{0,1\} \quad \text{for} \quad i = 1, 2, 3, 4,
|
|
33
|
+
\end{align*}
|
|
34
|
+
|
|
35
|
+
where the inequality constraint is a weight constraint. The problem is a binary variable problem.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Problem: the simple knapsack problem.
|
|
39
|
+
"""
|
|
40
|
+
variables = [
|
|
41
|
+
Variable(
|
|
42
|
+
name=f"x_{i}",
|
|
43
|
+
symbol=f"x_{i}",
|
|
44
|
+
variable_type=VariableTypeEnum.binary,
|
|
45
|
+
lowerbound=0,
|
|
46
|
+
upperbound=1,
|
|
47
|
+
initial_value=0,
|
|
48
|
+
)
|
|
49
|
+
for i in range(1, 5)
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
exprs = {
|
|
53
|
+
"f1": "5*x_1 + 4*x_2 + 3*x_3 + 2*x_4",
|
|
54
|
+
"f2": "10*x_1 + 7*x_2 + 5*x_3 + 3*x_4",
|
|
55
|
+
"f3": "15*x_1 + 9*x_2 + 8*x_3 + 5*x_4",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
ideals = {"f1": 15, "f2": 25, "f3": 37}
|
|
59
|
+
|
|
60
|
+
objectives = [
|
|
61
|
+
Objective(
|
|
62
|
+
name=f"f_{i}",
|
|
63
|
+
symbol=f"f_{i}",
|
|
64
|
+
func=exprs[f"f{i}"],
|
|
65
|
+
maximize=True,
|
|
66
|
+
ideal=ideals[f"f{i}"],
|
|
67
|
+
nadir=0,
|
|
68
|
+
objective_type=ObjectiveTypeEnum.analytical,
|
|
69
|
+
is_linear=True,
|
|
70
|
+
is_convex=True,
|
|
71
|
+
is_twice_differentiable=True,
|
|
72
|
+
)
|
|
73
|
+
for i in range(1, 4)
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
constraints = [
|
|
77
|
+
Constraint(
|
|
78
|
+
name="Weight constraint",
|
|
79
|
+
symbol="g_w",
|
|
80
|
+
cons_type=ConstraintTypeEnum.LTE,
|
|
81
|
+
func="2*x_1 + 3*x_2 + 1*x_3 + 4*x_4 - 7",
|
|
82
|
+
is_linear=True,
|
|
83
|
+
is_convex=True,
|
|
84
|
+
is_twice_differentiable=True,
|
|
85
|
+
)
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
return Problem(
|
|
89
|
+
name="Simple knapsack",
|
|
90
|
+
description="A simple knapsack problem with three objectives to be maximized.",
|
|
91
|
+
variables=variables,
|
|
92
|
+
objectives=objectives,
|
|
93
|
+
constraints=constraints,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def simple_knapsack_vectors():
|
|
98
|
+
"""Define a simple variant of the knapsack problem that utilizes vectors (TensorVariable and TensorConstant)."""
|
|
99
|
+
n_items = 4
|
|
100
|
+
weight_values = [2, 3, 4, 5]
|
|
101
|
+
profit_values = [3, 5, 6, 8]
|
|
102
|
+
efficiency_values = [4, 2, 7, 3]
|
|
103
|
+
|
|
104
|
+
max_weight = Constant(name="Maximum weights", symbol="w_max", value=5)
|
|
105
|
+
|
|
106
|
+
weights = TensorConstant(name="Weights of the items", symbol="W", shape=[len(weight_values)], values=weight_values)
|
|
107
|
+
profits = TensorConstant(name="Profits", symbol="P", shape=[len(profit_values)], values=profit_values)
|
|
108
|
+
efficiencies = TensorConstant(
|
|
109
|
+
name="Efficiencies", symbol="E", shape=[len(efficiency_values)], values=efficiency_values
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
choices = TensorVariable(
|
|
113
|
+
name="Chosen items",
|
|
114
|
+
symbol="X",
|
|
115
|
+
shape=[n_items],
|
|
116
|
+
variable_type="binary",
|
|
117
|
+
lowerbounds=n_items * [0],
|
|
118
|
+
upperbounds=n_items * [1],
|
|
119
|
+
initial_values=n_items * [1],
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
profit_objective = Objective(
|
|
123
|
+
name="max profit",
|
|
124
|
+
symbol="f_1",
|
|
125
|
+
func="P@X",
|
|
126
|
+
maximize=True,
|
|
127
|
+
ideal=8,
|
|
128
|
+
nadir=0,
|
|
129
|
+
is_linear=True,
|
|
130
|
+
is_convex=False,
|
|
131
|
+
is_twice_differentiable=False,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
efficiency_objective = Objective(
|
|
135
|
+
name="max efficiency",
|
|
136
|
+
symbol="f_2",
|
|
137
|
+
func="E@X",
|
|
138
|
+
maximize=True,
|
|
139
|
+
ideal=7,
|
|
140
|
+
nadir=0,
|
|
141
|
+
is_linear=True,
|
|
142
|
+
is_convex=False,
|
|
143
|
+
is_twice_differentiable=False,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
weight_constraint = Constraint(
|
|
147
|
+
name="Weight constraint",
|
|
148
|
+
symbol="g_1",
|
|
149
|
+
cons_type="<=",
|
|
150
|
+
func="W@X - w_max",
|
|
151
|
+
is_linear=True,
|
|
152
|
+
is_convex=False,
|
|
153
|
+
is_twice_differentiable=False,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
return Problem(
|
|
157
|
+
name="Simple two-objective Knapsack problem",
|
|
158
|
+
description="A simple variant of the classic combinatorial problem.",
|
|
159
|
+
constants=[max_weight, weights, profits, efficiencies],
|
|
160
|
+
variables=[choices],
|
|
161
|
+
objectives=[profit_objective, efficiency_objective],
|
|
162
|
+
constraints=[weight_constraint],
|
|
163
|
+
)
|