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,188 @@
1
+ """A collection of archivers for storing solutions evaluated during evolution."""
2
+
3
+ from collections.abc import Sequence
4
+
5
+ import polars as pl
6
+
7
+ from desdeo.problem import Problem
8
+ from desdeo.tools.generics import EMOResult
9
+ from desdeo.tools.message import (
10
+ EvaluatorMessageTopics,
11
+ GeneratorMessageTopics,
12
+ Message,
13
+ MessageTopics,
14
+ SelectorMessageTopics,
15
+ TerminatorMessageTopics,
16
+ )
17
+ from desdeo.tools.non_dominated_sorting import non_dominated, non_dominated_merge
18
+ from desdeo.tools.patterns import Publisher, Subscriber
19
+
20
+
21
+ class BaseArchive(Subscriber):
22
+ """Base class for archivers."""
23
+
24
+ @property
25
+ def interested_topics(self) -> Sequence[MessageTopics]:
26
+ """Return the message topics that the archiver is interested in."""
27
+ return [
28
+ GeneratorMessageTopics.VERBOSE_OUTPUTS,
29
+ EvaluatorMessageTopics.VERBOSE_OUTPUTS,
30
+ SelectorMessageTopics.SELECTED_VERBOSE_OUTPUTS,
31
+ TerminatorMessageTopics.GENERATION,
32
+ ]
33
+
34
+ @property
35
+ def provided_topics(self) -> dict[int, Sequence[MessageTopics]]:
36
+ """Return the topics provided by the archiver."""
37
+ return {0: []}
38
+
39
+ def __init__(self, *, problem: Problem, publisher: Publisher):
40
+ """Initialize the base archiver.
41
+
42
+ Args:
43
+ problem (Problem): The problem being solved.
44
+ publisher (Publisher): The publisher object.
45
+ """
46
+ super().__init__(publisher, verbosity=0)
47
+ self.solutions: pl.DataFrame = None
48
+ self.selections: pl.DataFrame = None
49
+ self.problem = problem
50
+ self.generation_number = 1
51
+
52
+ def state(self) -> Sequence[Message]:
53
+ """Return the state of the archiver."""
54
+ return []
55
+
56
+ def update(self, message: Message) -> None:
57
+ """Updae the archiver with new data.
58
+
59
+ Takes care of common archiving jobs. Make sure to run this for every archiver.
60
+
61
+ Args:
62
+ message (Message): Message from the publisher.
63
+ """
64
+ if message.topic == TerminatorMessageTopics.GENERATION:
65
+ self.generation_number = message.value
66
+ return
67
+ if message.topic == SelectorMessageTopics.SELECTED_VERBOSE_OUTPUTS:
68
+ data: pl.DataFrame = message.value
69
+ data = data.with_columns(generation=self.generation_number)
70
+ if self.selections is None:
71
+ self.selections = data
72
+ else:
73
+ self.selections = pl.concat([self.selections, data], how="vertical")
74
+ return
75
+
76
+ @property
77
+ def results(self) -> EMOResult:
78
+ """Return the results of the archiver."""
79
+ dec_vars = [x.symbol for x in self.problem.get_flattened_variables()]
80
+ all_cols = self.solutions.columns
81
+ non_decs = [col for col in all_cols if col not in dec_vars]
82
+ return EMOResult(optimal_variables=self.solutions[dec_vars], optimal_outputs=self.solutions[non_decs])
83
+
84
+
85
+ class FeasibleArchive(BaseArchive):
86
+ """An archiver that stores all feasible solutions evaluated during evolution."""
87
+
88
+ def __init__(self, *, problem: Problem, publisher: Publisher):
89
+ """Initialize the archiver.
90
+
91
+ Args:
92
+ problem (Problem): The problem being solved.
93
+ publisher (Publisher): The publisher object.
94
+ """
95
+ super().__init__(problem=problem, publisher=publisher)
96
+
97
+ if problem.constraints is None:
98
+ raise ValueError("The problem has no constraints.")
99
+ self.cons_symb = [x.symbol for x in problem.constraints]
100
+
101
+ def update(self, message: Message) -> None:
102
+ """Update the archiver with the new data.
103
+
104
+ Args:
105
+ message (Message): Message from the publisher.
106
+ """
107
+ if (
108
+ message.topic == TerminatorMessageTopics.GENERATION # NOQA: PLR1714
109
+ or message.topic == SelectorMessageTopics.SELECTED_VERBOSE_OUTPUTS
110
+ ):
111
+ super().update(message)
112
+ return
113
+ data = message.value
114
+ feasible_mask = (data[self.cons_symb] <= 0).to_numpy().all(axis=1)
115
+ feasible_data = data.filter(feasible_mask)
116
+ feasible_data = feasible_data.with_columns(generation=self.generation_number)
117
+ if self.solutions is None:
118
+ self.solutions = feasible_data
119
+ else:
120
+ self.solutions = pl.concat([self.solutions, feasible_data])
121
+
122
+
123
+ class Archive(BaseArchive):
124
+ """An archiver that stores the solutions evaluated during evolution."""
125
+
126
+ def update(self, message: Message) -> None:
127
+ """Update the archiver with the new data.
128
+
129
+ Args:
130
+ message (Message): Message from the publisher.
131
+ """
132
+ if (
133
+ message.topic == TerminatorMessageTopics.GENERATION # NOQA: PLR1714
134
+ or message.topic == SelectorMessageTopics.SELECTED_VERBOSE_OUTPUTS
135
+ ):
136
+ super().update(message)
137
+ return
138
+ data = message.value
139
+ data = data.with_columns(generation=self.generation_number)
140
+ if self.solutions is None:
141
+ self.solutions = data
142
+ else:
143
+ self.solutions = pl.concat([self.solutions, data])
144
+
145
+
146
+ class NonDominatedArchive(Archive):
147
+ """An archiver that stores only the feasible non-dominated solutions evaluated during evolution."""
148
+
149
+ def __init__(self, *, problem: Problem, publisher: Publisher):
150
+ """Initialize the archiver.
151
+
152
+ Args:
153
+ problem (Problem): The problem being solved.
154
+ publisher (Publisher): The publisher object.
155
+ """
156
+ super().__init__(problem=problem, publisher=publisher)
157
+ self.targets = [f"{x.symbol}_min" for x in problem.objectives]
158
+ if problem.constraints is None:
159
+ self.cons_symb = []
160
+ else:
161
+ self.cons_symb = [x.symbol for x in problem.constraints]
162
+
163
+ def update(self, message: Message) -> None:
164
+ """Update the archiver with the new data.
165
+
166
+ Args:
167
+ message (Message): Message from the publisher.
168
+ """
169
+ if (
170
+ message.topic == TerminatorMessageTopics.GENERATION # NOQA: PLR1714
171
+ or message.topic == SelectorMessageTopics.SELECTED_VERBOSE_OUTPUTS
172
+ ):
173
+ super().update(message)
174
+ return
175
+ data = message.value
176
+ data = data.with_columns(generation=self.generation_number)
177
+ if type(data) is not pl.DataFrame:
178
+ raise ValueError("Data should be a polars DataFrame")
179
+ if self.cons_symb:
180
+ feasible_mask = (data[self.cons_symb] <= 0).to_numpy().all(axis=1)
181
+ data = data.filter(feasible_mask)
182
+ if self.solutions is None:
183
+ non_dom_mask = non_dominated(data[self.targets].to_numpy())
184
+ self.solutions = data.filter(non_dom_mask)
185
+ else:
186
+ to_add = data.filter(non_dominated(data[self.targets].to_numpy()))
187
+ mask1, mask2 = non_dominated_merge(self.solutions[self.targets].to_numpy(), to_add[self.targets].to_numpy())
188
+ self.solutions = pl.concat([self.solutions.filter(mask1), to_add.filter(mask2)])