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.
Files changed (182) hide show
  1. desdeo/__init__.py +8 -8
  2. desdeo/adm/ADMAfsar.py +551 -0
  3. desdeo/adm/ADMChen.py +414 -0
  4. desdeo/adm/BaseADM.py +119 -0
  5. desdeo/adm/__init__.py +11 -0
  6. desdeo/api/README.md +73 -0
  7. desdeo/api/__init__.py +15 -0
  8. desdeo/api/app.py +50 -0
  9. desdeo/api/config.py +90 -0
  10. desdeo/api/config.toml +64 -0
  11. desdeo/api/db.py +27 -0
  12. desdeo/api/db_init.py +85 -0
  13. desdeo/api/db_models.py +164 -0
  14. desdeo/api/malaga_db_init.py +27 -0
  15. desdeo/api/models/__init__.py +266 -0
  16. desdeo/api/models/archive.py +23 -0
  17. desdeo/api/models/emo.py +128 -0
  18. desdeo/api/models/enautilus.py +69 -0
  19. desdeo/api/models/gdm/gdm_aggregate.py +139 -0
  20. desdeo/api/models/gdm/gdm_base.py +69 -0
  21. desdeo/api/models/gdm/gdm_score_bands.py +114 -0
  22. desdeo/api/models/gdm/gnimbus.py +138 -0
  23. desdeo/api/models/generic.py +104 -0
  24. desdeo/api/models/generic_states.py +401 -0
  25. desdeo/api/models/nimbus.py +158 -0
  26. desdeo/api/models/preference.py +128 -0
  27. desdeo/api/models/problem.py +717 -0
  28. desdeo/api/models/reference_point_method.py +18 -0
  29. desdeo/api/models/session.py +49 -0
  30. desdeo/api/models/state.py +463 -0
  31. desdeo/api/models/user.py +52 -0
  32. desdeo/api/models/utopia.py +25 -0
  33. desdeo/api/routers/_EMO.backup +309 -0
  34. desdeo/api/routers/_NAUTILUS.py +245 -0
  35. desdeo/api/routers/_NAUTILUS_navigator.py +233 -0
  36. desdeo/api/routers/_NIMBUS.py +765 -0
  37. desdeo/api/routers/__init__.py +5 -0
  38. desdeo/api/routers/emo.py +497 -0
  39. desdeo/api/routers/enautilus.py +237 -0
  40. desdeo/api/routers/gdm/gdm_aggregate.py +234 -0
  41. desdeo/api/routers/gdm/gdm_base.py +420 -0
  42. desdeo/api/routers/gdm/gdm_score_bands/gdm_score_bands_manager.py +398 -0
  43. desdeo/api/routers/gdm/gdm_score_bands/gdm_score_bands_routers.py +377 -0
  44. desdeo/api/routers/gdm/gnimbus/gnimbus_manager.py +698 -0
  45. desdeo/api/routers/gdm/gnimbus/gnimbus_routers.py +591 -0
  46. desdeo/api/routers/generic.py +233 -0
  47. desdeo/api/routers/nimbus.py +705 -0
  48. desdeo/api/routers/problem.py +307 -0
  49. desdeo/api/routers/reference_point_method.py +93 -0
  50. desdeo/api/routers/session.py +100 -0
  51. desdeo/api/routers/test.py +16 -0
  52. desdeo/api/routers/user_authentication.py +520 -0
  53. desdeo/api/routers/utils.py +187 -0
  54. desdeo/api/routers/utopia.py +230 -0
  55. desdeo/api/schema.py +100 -0
  56. desdeo/api/tests/__init__.py +0 -0
  57. desdeo/api/tests/conftest.py +151 -0
  58. desdeo/api/tests/test_enautilus.py +330 -0
  59. desdeo/api/tests/test_models.py +1179 -0
  60. desdeo/api/tests/test_routes.py +1075 -0
  61. desdeo/api/utils/_database.py +263 -0
  62. desdeo/api/utils/_logger.py +29 -0
  63. desdeo/api/utils/database.py +36 -0
  64. desdeo/api/utils/emo_database.py +40 -0
  65. desdeo/core.py +34 -0
  66. desdeo/emo/__init__.py +159 -0
  67. desdeo/emo/hooks/archivers.py +188 -0
  68. desdeo/emo/methods/EAs.py +541 -0
  69. desdeo/emo/methods/__init__.py +0 -0
  70. desdeo/emo/methods/bases.py +12 -0
  71. desdeo/emo/methods/templates.py +111 -0
  72. desdeo/emo/operators/__init__.py +1 -0
  73. desdeo/emo/operators/crossover.py +1282 -0
  74. desdeo/emo/operators/evaluator.py +114 -0
  75. desdeo/emo/operators/generator.py +459 -0
  76. desdeo/emo/operators/mutation.py +1224 -0
  77. desdeo/emo/operators/scalar_selection.py +202 -0
  78. desdeo/emo/operators/selection.py +1778 -0
  79. desdeo/emo/operators/termination.py +286 -0
  80. desdeo/emo/options/__init__.py +108 -0
  81. desdeo/emo/options/algorithms.py +435 -0
  82. desdeo/emo/options/crossover.py +164 -0
  83. desdeo/emo/options/generator.py +131 -0
  84. desdeo/emo/options/mutation.py +260 -0
  85. desdeo/emo/options/repair.py +61 -0
  86. desdeo/emo/options/scalar_selection.py +66 -0
  87. desdeo/emo/options/selection.py +127 -0
  88. desdeo/emo/options/templates.py +383 -0
  89. desdeo/emo/options/termination.py +143 -0
  90. desdeo/explanations/__init__.py +6 -0
  91. desdeo/explanations/explainer.py +100 -0
  92. desdeo/explanations/utils.py +90 -0
  93. desdeo/gdm/__init__.py +22 -0
  94. desdeo/gdm/gdmtools.py +45 -0
  95. desdeo/gdm/score_bands.py +114 -0
  96. desdeo/gdm/voting_rules.py +50 -0
  97. desdeo/mcdm/__init__.py +41 -0
  98. desdeo/mcdm/enautilus.py +338 -0
  99. desdeo/mcdm/gnimbus.py +484 -0
  100. desdeo/mcdm/nautili.py +345 -0
  101. desdeo/mcdm/nautilus.py +477 -0
  102. desdeo/mcdm/nautilus_navigator.py +656 -0
  103. desdeo/mcdm/nimbus.py +417 -0
  104. desdeo/mcdm/pareto_navigator.py +269 -0
  105. desdeo/mcdm/reference_point_method.py +186 -0
  106. desdeo/problem/__init__.py +83 -0
  107. desdeo/problem/evaluator.py +561 -0
  108. desdeo/problem/external/__init__.py +18 -0
  109. desdeo/problem/external/core.py +356 -0
  110. desdeo/problem/external/pymoo_provider.py +266 -0
  111. desdeo/problem/external/runtime.py +44 -0
  112. desdeo/problem/gurobipy_evaluator.py +562 -0
  113. desdeo/problem/infix_parser.py +341 -0
  114. desdeo/problem/json_parser.py +944 -0
  115. desdeo/problem/pyomo_evaluator.py +487 -0
  116. desdeo/problem/schema.py +1829 -0
  117. desdeo/problem/simulator_evaluator.py +348 -0
  118. desdeo/problem/sympy_evaluator.py +244 -0
  119. desdeo/problem/testproblems/__init__.py +88 -0
  120. desdeo/problem/testproblems/benchmarks_server.py +120 -0
  121. desdeo/problem/testproblems/binh_and_korn_problem.py +88 -0
  122. desdeo/problem/testproblems/cake_problem.py +185 -0
  123. desdeo/problem/testproblems/dmitry_forest_problem_discrete.py +71 -0
  124. desdeo/problem/testproblems/dtlz2_problem.py +102 -0
  125. desdeo/problem/testproblems/forest_problem.py +283 -0
  126. desdeo/problem/testproblems/knapsack_problem.py +163 -0
  127. desdeo/problem/testproblems/mcwb_problem.py +831 -0
  128. desdeo/problem/testproblems/mixed_variable_dimenrions_problem.py +83 -0
  129. desdeo/problem/testproblems/momip_problem.py +172 -0
  130. desdeo/problem/testproblems/multi_valued_constraints.py +119 -0
  131. desdeo/problem/testproblems/nimbus_problem.py +143 -0
  132. desdeo/problem/testproblems/pareto_navigator_problem.py +89 -0
  133. desdeo/problem/testproblems/re_problem.py +492 -0
  134. desdeo/problem/testproblems/river_pollution_problems.py +440 -0
  135. desdeo/problem/testproblems/rocket_injector_design_problem.py +140 -0
  136. desdeo/problem/testproblems/simple_problem.py +351 -0
  137. desdeo/problem/testproblems/simulator_problem.py +92 -0
  138. desdeo/problem/testproblems/single_objective.py +289 -0
  139. desdeo/problem/testproblems/spanish_sustainability_problem.py +945 -0
  140. desdeo/problem/testproblems/zdt_problem.py +274 -0
  141. desdeo/problem/utils.py +245 -0
  142. desdeo/tools/GenerateReferencePoints.py +181 -0
  143. desdeo/tools/__init__.py +120 -0
  144. desdeo/tools/desc_gen.py +22 -0
  145. desdeo/tools/generics.py +165 -0
  146. desdeo/tools/group_scalarization.py +3090 -0
  147. desdeo/tools/gurobipy_solver_interfaces.py +258 -0
  148. desdeo/tools/indicators_binary.py +117 -0
  149. desdeo/tools/indicators_unary.py +362 -0
  150. desdeo/tools/interaction_schema.py +38 -0
  151. desdeo/tools/intersection.py +54 -0
  152. desdeo/tools/iterative_pareto_representer.py +99 -0
  153. desdeo/tools/message.py +265 -0
  154. desdeo/tools/ng_solver_interfaces.py +199 -0
  155. desdeo/tools/non_dominated_sorting.py +134 -0
  156. desdeo/tools/patterns.py +283 -0
  157. desdeo/tools/proximal_solver.py +99 -0
  158. desdeo/tools/pyomo_solver_interfaces.py +477 -0
  159. desdeo/tools/reference_vectors.py +229 -0
  160. desdeo/tools/scalarization.py +2065 -0
  161. desdeo/tools/scipy_solver_interfaces.py +454 -0
  162. desdeo/tools/score_bands.py +627 -0
  163. desdeo/tools/utils.py +388 -0
  164. desdeo/tools/visualizations.py +67 -0
  165. desdeo/utopia_stuff/__init__.py +0 -0
  166. desdeo/utopia_stuff/data/1.json +15 -0
  167. desdeo/utopia_stuff/data/2.json +13 -0
  168. desdeo/utopia_stuff/data/3.json +15 -0
  169. desdeo/utopia_stuff/data/4.json +17 -0
  170. desdeo/utopia_stuff/data/5.json +15 -0
  171. desdeo/utopia_stuff/from_json.py +40 -0
  172. desdeo/utopia_stuff/reinit_user.py +38 -0
  173. desdeo/utopia_stuff/utopia_db_init.py +212 -0
  174. desdeo/utopia_stuff/utopia_problem.py +403 -0
  175. desdeo/utopia_stuff/utopia_problem_old.py +415 -0
  176. desdeo/utopia_stuff/utopia_reference_solutions.py +79 -0
  177. desdeo-2.1.0.dist-info/METADATA +186 -0
  178. desdeo-2.1.0.dist-info/RECORD +180 -0
  179. {desdeo-1.2.dist-info → desdeo-2.1.0.dist-info}/WHEEL +1 -1
  180. desdeo-2.1.0.dist-info/licenses/LICENSE +21 -0
  181. desdeo-1.2.dist-info/METADATA +0 -16
  182. 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
+ )