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
desdeo/mcdm/gnimbus.py ADDED
@@ -0,0 +1,484 @@
1
+ """Functions related to the GNIMBUS method.
2
+
3
+ References:
4
+ TBA
5
+ """
6
+
7
+ from typing import Literal
8
+
9
+ import numpy as np
10
+
11
+ from desdeo.gdm.gdmtools import agg_aspbounds, dict_of_rps_to_list_of_rps, scale_delta
12
+ from desdeo.gdm.voting_rules import plurality_rule
13
+ from desdeo.mcdm.nimbus import infer_classifications, solve_sub_problems
14
+ from desdeo.problem import (
15
+ Problem,
16
+ )
17
+ from desdeo.tools import (
18
+ BaseSolver,
19
+ SolverOptions,
20
+ SolverResults,
21
+ GurobipySolver,
22
+ add_group_asf,
23
+ add_group_asf_agg,
24
+ add_group_asf_agg_diff,
25
+ add_group_asf_diff,
26
+ add_group_guess,
27
+ add_group_guess_agg,
28
+ add_group_guess_agg_diff,
29
+ add_group_guess_diff,
30
+ add_group_nimbus,
31
+ add_group_nimbus_compromise,
32
+ add_group_nimbus_compromise_diff,
33
+ add_group_nimbus_diff,
34
+ add_group_stom,
35
+ add_group_stom_agg,
36
+ add_group_stom_agg_diff,
37
+ add_group_stom_diff,
38
+ guess_best_solver,
39
+ )
40
+
41
+
42
+ class GNIMBUSError(Exception):
43
+ """Raised when an error with a NIMBUS method is encountered."""
44
+
45
+
46
+ def voting_procedure(problem: Problem, solutions, votes_idxs: dict[str, int]) -> SolverResults:
47
+ """More general procedure for GNIMBUS for any number of DMs.
48
+ TODO(@jpajasmaa): docs and cleaning up.
49
+ """
50
+ # winner_idx = None
51
+ # call majority
52
+ """ general procedure does not apply majority rule
53
+ winner_idx = majority_rule(votes_idxs)
54
+ if winner_idx is not None:
55
+ print("Majority winner", winner_idx)
56
+ return solutions[winner_idx]
57
+ """
58
+ # call plurality
59
+ winners = plurality_rule(votes_idxs)
60
+ print("winners")
61
+ if len(winners) == 1:
62
+ print("Plurality winner", winners[0])
63
+ return solutions[winners[0]] # need to unlist the winners list
64
+
65
+ print("TIE-breaking, select a solution randomly among top voted ones")
66
+ """
67
+ # if two same solutions with same number of votes, call intermediate
68
+ # TODO:(@jpajasmaa) not perfect check as it is possible to have a problem that we can calculate more solutions
69
+ # AND discrete representation also.
70
+ if problem.discrete_representation is None:
71
+ wsol1, wsol2 = solutions[winners[0]].optimal_variables, solutions[winners[1]].optimal_variables
72
+ else:
73
+ wsol1, wsol2 = solutions[winners[0]].optimal_objectives, solutions[winners[1]].optimal_objectives
74
+ print("Finding intermediate solution between", wsol1, wsol2)
75
+ # return solve_intermediate_solutions_only_objs(problem, wsol1, wsol2, num_desired=3)
76
+ return solve_intermediate_solutions(problem, wsol1, wsol2, num_desired=1)[0]
77
+ """
78
+ # n_of_sols = len(solutions)
79
+ rng = np.random.default_rng()
80
+ random_idx = rng.choice(winners)
81
+ return solutions[random_idx]
82
+
83
+
84
+ def infer_group_classifications(
85
+ problem: Problem,
86
+ current_objectives: dict[str, float],
87
+ reference_points: dict[str, dict[str, float]],
88
+ *,
89
+ silent: bool = True,
90
+ ) -> dict[str, tuple[Literal["improve", "worsen", "conflict"], list[float]]]:
91
+ """Infers group classification from the reference points given by the group.
92
+
93
+ Args:
94
+ problem (Problem): the problem being solved
95
+ current_objectives (dict[str, float]): objective values at the current iteration
96
+ reference_points (dict[str, dict[str, float]]): The reference points given by the group.
97
+ The keys of the outer dict are the decision makers and the keys of the inner dict are objective symbols.
98
+ silent (bool): If false, the classifications will be printed.
99
+
100
+ Raises:
101
+ GNIMBUSError: _description_
102
+
103
+ Returns:
104
+ dict[str, tuple[str, list[float]]]: _description_
105
+ """
106
+ for dm, reference_point in reference_points.items():
107
+ # for rp in reference_point:
108
+ if not all(obj.symbol in reference_point for obj in problem.objectives):
109
+ print(reference_point)
110
+ msg = (
111
+ f"The reference point {reference_point} of {dm} is missing entries "
112
+ "for one or more of the objective functions."
113
+ )
114
+ raise GNIMBUSError(msg)
115
+
116
+ group_classifications = {}
117
+ for obj in problem.objectives:
118
+ # maximization
119
+ if obj.maximize and all(
120
+ (
121
+ reference_points[dm][obj.symbol] >= current_objectives[obj.symbol]
122
+ or np.isclose(reference_points[dm][obj.symbol], current_objectives[obj.symbol])
123
+ )
124
+ for dm in reference_points
125
+ ):
126
+ classify = "improve"
127
+ elif obj.maximize and all(
128
+ reference_points[dm][obj.symbol] < current_objectives[obj.symbol] for dm in reference_points
129
+ ):
130
+ classify = "worsen"
131
+ # minimization
132
+ elif (not obj.maximize) and all(
133
+ (
134
+ reference_points[dm][obj.symbol] <= current_objectives[obj.symbol]
135
+ or np.isclose(reference_points[dm][obj.symbol], current_objectives[obj.symbol])
136
+ )
137
+ for dm in reference_points
138
+ ):
139
+ classify = "improve"
140
+ elif (not obj.maximize) and all(
141
+ reference_points[dm][obj.symbol] > current_objectives[obj.symbol] for dm in reference_points
142
+ ):
143
+ classify = "worsen"
144
+ else:
145
+ classify = "conflict"
146
+ group_classifications[obj.symbol] = (classify, [reference_points[dm][obj.symbol] for dm in reference_points])
147
+
148
+ if not silent:
149
+ for symbol, value in group_classifications.items():
150
+ if value[0] == "improve":
151
+ print(f"The group wants to improve objective {symbol}")
152
+ print(value[1])
153
+ if value[0] == "worsen":
154
+ print(f"The group wants to worsen objective {symbol}")
155
+ print(value[1])
156
+ if value[0] == "conflict":
157
+ print(f"The group has conflicting views about objective {symbol}")
158
+ print(value[1])
159
+
160
+ return group_classifications
161
+
162
+
163
+ def solve_group_sub_problems( # noqa: PLR0913, RET503
164
+ problem: Problem,
165
+ current_objectives: dict[str, float],
166
+ reference_points: dict[str, dict[str, float]],
167
+ phase: str,
168
+ scalarization_options: dict | None = None,
169
+ create_solver: BaseSolver | None = None,
170
+ solver_options: SolverOptions | None = None,
171
+ ) -> list[SolverResults]:
172
+ r"""Solves a number of sub-problems as defined in the GNIMBUS methods.
173
+
174
+ TODO: update docs
175
+
176
+ Solves 4 scalarized problems utilizing different scalarization
177
+ functions. The scalarizations are based on the classification of a
178
+ solutions provided by a decision maker. The classifications
179
+ are represented by a reference point. Returns a number of new solutions
180
+ corresponding to the number of scalarization functions solved.
181
+
182
+ Solves the following scalarized problems corresponding
183
+ the the following scalarization functions:
184
+
185
+ 1. the NIMBUS scalarization function,
186
+ 2. the STOM scalarization function,
187
+ 3. the achievement scalarizing function, and
188
+ 4. the GUESS scalarization function.
189
+
190
+ Raises:
191
+ GNIMBUSError: the given problem has an undefined ideal or nadir point, or both.
192
+ GNIMBUSError: either the reference point of current objective functions value are
193
+ missing entries for one or more of the objective functions defined in the problem.
194
+
195
+ Args:
196
+ problem(Problem): the problem being solved.
197
+ current_objectives(dict[str, float]): an objective dictionary with the objective functions values
198
+ the classifications have been given with respect to.
199
+ reference_points(dict[str, dict[str, float]]): A dictionary containing an objective dictionary with a reference point for each DM.
200
+ The classifications utilized in the sub problems are derived from
201
+ the reference points.
202
+ phase(str): The selected phase of the solution process. Must be one of "learning", "crp", "decision" or "compromise".
203
+ scalarization_options(dict | None, optional): optional kwargs passed to the scalarization function.
204
+ Defaults to None.
205
+ create_solver(CreateSolverType | None, optional): a function that given a problem, will return a solver.
206
+ If not given, an appropriate solver will be automatically determined based on the features of `problem`.
207
+ Defaults to None.
208
+ solver_options(SolverOptions | None, optional): optional options passed
209
+ to the `create_solver` routine. Ignored if `create_solver` is `None`.
210
+ Defaults to None.
211
+
212
+ Returns:
213
+ list[SolverResults]: a list of `SolverResults` objects. Contains as many elements
214
+ as defined in `num_desired`.
215
+ """
216
+ if None in problem.get_ideal_point() or None in problem.get_nadir_point():
217
+ msg = "The given problem must have both an ideal and nadir point defined."
218
+ raise GNIMBUSError(msg)
219
+
220
+ DMs = reference_points.keys()
221
+ for dm in DMs:
222
+ reference_point = reference_points[dm]
223
+ # for rp in reference_point:
224
+ if not all(obj.symbol in reference_point for obj in problem.objectives):
225
+ print(reference_point)
226
+ msg = (
227
+ f"The reference point {reference_point} is missing entries for one or more of the objective functions."
228
+ )
229
+ raise GNIMBUSError(msg)
230
+ # check that at least one objective function is allowed to be improved and one is allowed to worsen
231
+ classifications = infer_classifications(problem, current_objectives, reference_point)
232
+ if not any(classifications[obj.symbol][0] in ["<", "<="] for obj in problem.objectives) or not any(
233
+ classifications[obj.symbol][0] in [">=", "0"] for obj in problem.objectives
234
+ ):
235
+ msg = (
236
+ f"The given classifications {classifications} should allow at least one objective function value "
237
+ "to improve and one to worsen."
238
+ )
239
+ raise GNIMBUSError(msg)
240
+
241
+ if not all(obj.symbol in current_objectives for obj in problem.objectives):
242
+ msg = f"The current point {current_objectives} is missing entries for one or more of the objective functions."
243
+ raise GNIMBUSError(msg)
244
+
245
+ init_solver = create_solver if create_solver is not None else guess_best_solver(problem)
246
+ if init_solver is GurobipySolver and not solver_options:
247
+ solver_options = {"OutputFlag": 0} #TODO: how does one want this to behave?
248
+ _solver_options = solver_options if solver_options is not None else None
249
+ # print("solver is ", init_solver)
250
+
251
+ solutions = []
252
+ classification_list = []
253
+ achievable_prefs = []
254
+
255
+ ind_sols = []
256
+ reference_points_list = dict_of_rps_to_list_of_rps(reference_points)
257
+
258
+ # Solve for individual solutions using nimbus scalarization.
259
+ for dm_rp in reference_points:
260
+ ind_sols.append(solve_sub_problems(
261
+ problem=problem,
262
+ current_objectives=current_objectives,
263
+ reference_point=reference_points[dm_rp],
264
+ num_desired=1,
265
+ scalarization_options=None,
266
+ solver=init_solver,
267
+ solver_options=_solver_options)[0],
268
+ )
269
+
270
+ achievable_prefs = []
271
+ for q in range(len(reference_points)):
272
+ achievable_prefs.append(ind_sols[q].optimal_objectives)
273
+
274
+ agg_aspirations, agg_bounds = agg_aspbounds(achievable_prefs, problem)
275
+ delta = scale_delta(problem, d=1e-6)
276
+
277
+ if phase == "decision":
278
+ for dm_rp in reference_points:
279
+ classification_list.append(infer_classifications(problem, current_objectives, reference_points[dm_rp]))
280
+ gnimbus_scala = add_group_nimbus_diff if problem.is_twice_differentiable else add_group_nimbus
281
+ add_nimbus_sf = gnimbus_scala
282
+
283
+ problem_g_nimbus, gnimbus_target = add_nimbus_sf(
284
+ problem, "nimbus_sf", classification_list, current_objectives, agg_bounds, delta, **(scalarization_options or {})
285
+ )
286
+
287
+ if _solver_options:
288
+ gnimbus_solver = init_solver(problem_g_nimbus, _solver_options) # type:ignore
289
+ else:
290
+ gnimbus_solver = init_solver(problem_g_nimbus) # type:ignore
291
+
292
+ solutions.append(gnimbus_solver.solve(gnimbus_target))
293
+
294
+ infer_group_classifications(problem, current_objectives, reference_points, silent=False)
295
+
296
+ return solutions
297
+
298
+ elif phase == "compromise":
299
+ # Run compromise phase with applying group-asf.
300
+ reference_points_list = dict_of_rps_to_list_of_rps(reference_points)
301
+ # solve ASF
302
+ add_asf = add_group_asf_diff if problem.is_twice_differentiable else add_group_asf
303
+ problem_w_asf, asf_target = add_asf(
304
+ problem, "asf", reference_points_list, agg_bounds, delta, **(scalarization_options or {})
305
+ )
306
+ if _solver_options:
307
+ asf_solver = init_solver(problem_w_asf, _solver_options) # type:ignore
308
+ else:
309
+ asf_solver = init_solver(problem_w_asf) # type:ignore
310
+
311
+ solutions.append(asf_solver.solve(asf_target))
312
+
313
+ return solutions
314
+
315
+ """
316
+ classification_list = infer_group_classifications(problem, current_objectives, reference_points)
317
+ # All cool, the preference's are in a bit of a different format that other branches but works.
318
+
319
+ gnimbus_scala = add_group_nimbus_compromise_diff \
320
+ if problem.is_twice_differentiable else add_group_nimbus_compromise
321
+ add_nimbus_sf = gnimbus_scala
322
+
323
+ problem_g_nimbus, gnimbus_target = add_nimbus_sf(
324
+ problem, "nimbus_sf", classification_list, current_objectives, **(scalarization_options or {})
325
+ )
326
+ # ISSUE: makes the problem not twice differentiable, thus the initial solver doesn't work
327
+ # Also needed a little tweaking inside the scalarization functions.
328
+
329
+ if _solver_options:
330
+ gnimbus_solver = init_solver(problem_g_nimbus, _solver_options) # type:ignore
331
+ else:
332
+ gnimbus_solver = init_solver(problem_g_nimbus) # type:ignore
333
+
334
+ solutions.append(gnimbus_solver.solve(gnimbus_target))
335
+
336
+ infer_group_classifications(problem, current_objectives, reference_points, silent=False)
337
+
338
+ return solutions
339
+ """
340
+
341
+ elif phase == "learning":
342
+ reference_points_list = dict_of_rps_to_list_of_rps(reference_points)
343
+
344
+ # Add individual solutions
345
+ for i in range(len(ind_sols)):
346
+ solutions.append(ind_sols[i])
347
+ """ Group nimbus scalarization with delta and added hard_constraints """
348
+ classification_list = []
349
+ for dm_rp in reference_points:
350
+ classification_list.append(infer_classifications(problem, current_objectives, reference_points[dm_rp]))
351
+ print(classification_list)
352
+ gnimbus_scala = add_group_nimbus_diff if problem.is_twice_differentiable else add_group_nimbus
353
+ add_nimbus_sf = gnimbus_scala
354
+
355
+ problem_w_nimbus, nimbus_target = add_nimbus_sf(
356
+ problem,
357
+ "nimbus_sf",
358
+ classification_list,
359
+ current_objectives,
360
+ agg_bounds,
361
+ delta,
362
+ **(scalarization_options or {}),
363
+ )
364
+
365
+ if _solver_options:
366
+ nimbus_solver = init_solver(problem_w_nimbus, _solver_options) # type:ignore
367
+ else:
368
+ nimbus_solver = init_solver(problem_w_nimbus) # type:ignore
369
+
370
+ solutions.append(nimbus_solver.solve(nimbus_target))
371
+
372
+ """ SOLVING Group Scals with scaled delta, original RPs and hard_constraints """
373
+ # solve STOM
374
+ add_stom_sf = add_group_stom_diff if problem.is_twice_differentiable else add_group_stom
375
+ problem_w_stom, stom_target = add_stom_sf(
376
+ problem, "stom_sf", reference_points_list, agg_bounds, delta, **(scalarization_options or {})
377
+ )
378
+ if _solver_options:
379
+ stom_solver = init_solver(problem_w_stom, _solver_options) # type:ignore
380
+ else:
381
+ stom_solver = init_solver(problem_w_stom) # type:ignore
382
+
383
+ solutions.append(stom_solver.solve(stom_target))
384
+
385
+ # solve ASF
386
+ add_asf = add_group_asf_diff if problem.is_twice_differentiable else add_group_asf
387
+ problem_w_asf, asf_target = add_asf(
388
+ problem, "asf", reference_points_list, agg_bounds, delta, **(scalarization_options or {})
389
+ )
390
+ if _solver_options:
391
+ asf_solver = init_solver(problem_w_asf, _solver_options) # type:ignore
392
+ else:
393
+ asf_solver = init_solver(problem_w_asf) # type:ignore
394
+
395
+ solutions.append(asf_solver.solve(asf_target))
396
+
397
+ # Solve GUESS
398
+ add_guess_sf = add_group_guess_diff if problem.is_twice_differentiable else add_group_guess
399
+ problem_w_guess, guess_target = add_guess_sf(
400
+ problem, "guess_sf", reference_points_list, agg_bounds, delta, **(scalarization_options or {})
401
+ )
402
+ if _solver_options:
403
+ guess_solver = init_solver(problem_w_guess, _solver_options) # type:ignore
404
+ else:
405
+ guess_solver = init_solver(problem_w_guess) # type:ignore
406
+
407
+ solutions.append(guess_solver.solve(guess_target))
408
+
409
+ infer_group_classifications(problem, current_objectives, reference_points, silent=False)
410
+
411
+ return solutions
412
+
413
+ else: # phase is concsensus reaching
414
+ # Add individual solutions
415
+ for i in range(len(ind_sols)):
416
+ solutions.append(ind_sols[i])
417
+
418
+ """ Group nimbus scalarization with delta and added hard_constraints """
419
+ classification_list = []
420
+ for dm_rp in reference_points:
421
+ print("RPS", reference_points[dm_rp])
422
+ classification_list.append(infer_classifications(problem, current_objectives, reference_points[dm_rp]))
423
+ print(classification_list)
424
+ gnimbus_scala = add_group_nimbus_diff if problem.is_twice_differentiable else add_group_nimbus
425
+ add_nimbus_sf = gnimbus_scala
426
+
427
+ problem_w_nimbus, nimbus_target = add_nimbus_sf(
428
+ problem,
429
+ "nimbus_sf",
430
+ classification_list,
431
+ current_objectives,
432
+ agg_bounds,
433
+ delta,
434
+ **(scalarization_options or {}),
435
+ )
436
+
437
+ if _solver_options:
438
+ nimbus_solver = init_solver(problem_w_nimbus, _solver_options) # type:ignore
439
+ else:
440
+ nimbus_solver = init_solver(problem_w_nimbus) # type:ignore
441
+
442
+ solutions.append(nimbus_solver.solve(nimbus_target))
443
+
444
+ """ SOLVING Group Scals with scaled delta, agg. aspirations and hard_constraints """
445
+
446
+ add_stom_sf2 = add_group_stom_agg_diff if problem.is_twice_differentiable else add_group_stom_agg
447
+
448
+ problem_g_stom, stomg_target = add_stom_sf2(
449
+ problem, "stom_sf2", agg_aspirations, agg_bounds, delta, **(scalarization_options or {})
450
+ )
451
+ if _solver_options:
452
+ stomg_solver = init_solver(problem_g_stom, _solver_options) # type:ignore
453
+ else:
454
+ stomg_solver = init_solver(problem_g_stom) # type:ignore
455
+
456
+ solutions.append(stomg_solver.solve(stomg_target))
457
+
458
+ add_asf2 = add_group_asf_agg_diff if problem.is_twice_differentiable else add_group_asf_agg
459
+ problem_g_asf, asfg_target = add_asf2(
460
+ problem, "asf2", agg_aspirations, agg_bounds, delta, **(scalarization_options or {})
461
+ )
462
+ if _solver_options:
463
+ asfg_solver = init_solver(problem_g_asf, _solver_options) # type:ignore
464
+ else:
465
+ asfg_solver = init_solver(problem_g_asf) # type:ignore
466
+
467
+ solutions.append(asfg_solver.solve(asfg_target))
468
+
469
+ add_guess_sf2 = add_group_guess_agg_diff if problem.is_twice_differentiable else add_group_guess_agg
470
+
471
+ problem_g_guess, guess2_target = add_guess_sf2(
472
+ problem, "guess_sf2", agg_aspirations, agg_bounds, delta, **(scalarization_options or {})
473
+ )
474
+
475
+ if _solver_options:
476
+ guess2_solver = init_solver(problem_g_guess, _solver_options) # type:ignore
477
+ else:
478
+ guess2_solver = init_solver(problem_g_guess) # type:ignore
479
+
480
+ solutions.append(guess2_solver.solve(guess2_target))
481
+
482
+ infer_group_classifications(problem, current_objectives, reference_points, silent=False)
483
+
484
+ return solutions