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,114 @@
1
+ """Models for GDM Score Bands.
2
+
3
+ Idea is that in the very first iteration, the filtered indices contains the clustering
4
+ information on the entire data. Since on each iteration, the clustering is different,
5
+ we need to include the indices over and over again. Of course with time the amount of
6
+ indices will get smaller and smaller, and eventually be only ~10 solutions.
7
+
8
+ The names of the classes can be renamed to fit the purpose better, currently they are
9
+ more or less just the first thing that came to my mind.
10
+ """
11
+
12
+ from sqlmodel import JSON, Column, Field, SQLModel
13
+
14
+ from desdeo.api.models.gdm.gdm_base import BaseGroupInfoContainer
15
+ from desdeo.gdm.score_bands import SCOREBandsGDMConfig, SCOREBandsGDMResult
16
+ from desdeo.problem.schema import VariableType
17
+ from desdeo.tools.score_bands import SCOREBandsResult
18
+
19
+
20
+ class GDMSCOREBandInformation(BaseGroupInfoContainer):
21
+ """Class for containing info on which band was voted for."""
22
+ method: str = "gdm-score-bands"
23
+ user_votes: dict[str, int] = Field(
24
+ description="Dictionary of votes."
25
+ )
26
+ user_confirms: list[int] = Field(
27
+ description="List of users who want to move on."
28
+ )
29
+ score_bands_config: SCOREBandsGDMConfig = Field(
30
+ description="The configuration that led to this classification."
31
+ )
32
+ score_bands_result: SCOREBandsGDMResult = Field(
33
+ description="The results of the score bands."
34
+ )
35
+
36
+
37
+ class GDMSCOREBandFinalSelection(BaseGroupInfoContainer):
38
+ """Class for containing the final 10 or less solutions, the final solution and the votes that led to it."""
39
+ method: str = "gdm-score-bands-final"
40
+ user_votes: dict[str, int] = Field(
41
+ description="Dictionary of votes."
42
+ )
43
+ user_confirms: list[int] = Field(
44
+ description="List of users who want to move on."
45
+ )
46
+
47
+ """The 10 or less solutions to choose from"""
48
+ solution_variables: dict[str, list[VariableType]] = Field(sa_column=Column(JSON))
49
+ solution_objectives: dict[str, list[float]] = Field(sa_column=Column(JSON))
50
+
51
+ """The selected (or generated??) of those 10 or less."""
52
+ winner_solution_variables: dict[str, VariableType] = Field(sa_column=Column(JSON))
53
+ winner_solution_objectives: dict[str, float] = Field(sa_column=Column(JSON))
54
+
55
+
56
+ class GDMScoreBandsInitializationRequest(SQLModel):
57
+ """Request class for initialization of score bands."""
58
+ group_id: int = Field(
59
+ description="The group to be initialized."
60
+ )
61
+ score_bands_config: SCOREBandsGDMConfig = Field(
62
+ description="The configuration for the initial score banding."
63
+ )
64
+
65
+ class GDMScoreBandsVoteRequest(SQLModel):
66
+ """Request for voting for a band."""
67
+ group_id: int = Field(
68
+ description="ID of the group in question"
69
+ )
70
+ vote: int = Field(
71
+ description="The vote. Vaalisalaisuus."
72
+ )
73
+
74
+ class GDMSCOREBandsRevertRequest(SQLModel):
75
+ """Request for reverting to a previous setup."""
76
+ group_id: int = Field(
77
+ description="Group ID."
78
+ )
79
+ iteration_number: int = Field(
80
+ description="The number of the iteration that we want to revert to."
81
+ )
82
+
83
+ class GDMSCOREBandsResponse(SQLModel):
84
+ """Response class for GDMSCOREBands, whether it is initialization or not."""
85
+ method: str = "gdm-score-bands"
86
+ group_id: int = Field(
87
+ description="The group in question."
88
+ )
89
+ group_iter_id: int = Field(
90
+ description="ID of the latest group iteration."
91
+ )
92
+ latest_iteration: int = Field(
93
+ description="The latest GDM iteration number. Different from Group Iteration id."
94
+ )
95
+ result: SCOREBandsResult = Field(
96
+ description="The results of the score bands procedure."
97
+ )
98
+
99
+ class GDMSCOREBandsDecisionResponse(SQLModel):
100
+ """Response class for gdm score bands that includes the last 10 or less solutions."""
101
+ method: str = "gdm-score-bands-final"
102
+ group_id: int = Field(
103
+ description="The group in question."
104
+ )
105
+ group_iter_id: int = Field(
106
+ description="ID of the latest group iteration."
107
+ )
108
+ result: GDMSCOREBandFinalSelection = Field(
109
+ description="The container for the solutions and the winner solution."
110
+ )
111
+
112
+ class GDMSCOREBandsHistoryResponse(SQLModel):
113
+ """Response class for all history. Allows for going to a previous iteration."""
114
+ history: list[GDMSCOREBandsResponse | GDMSCOREBandsDecisionResponse]
@@ -0,0 +1,138 @@
1
+ """GNIMBUS specific data classes; REMEMBER to add SER/DES into aggregator!"""
2
+
3
+ import json
4
+
5
+ from pydantic import ValidationError
6
+ from sqlmodel import JSON, Column, Field, SQLModel, TypeDecorator
7
+
8
+ from desdeo.api.models.gdm.gdm_base import (
9
+ BaseGroupInfoContainer,
10
+ BooleanDictTypeDecorator,
11
+ ReferencePoint,
12
+ ReferencePointDictType,
13
+ )
14
+ from desdeo.api.models.generic_states import SolutionReference, SolutionReferenceLite
15
+ from desdeo.tools import SolverResults
16
+
17
+
18
+ class SolverResultType(TypeDecorator):
19
+ """Not sure why the solver results wouldn't serialize but this should do the trick."""
20
+
21
+ impl = JSON
22
+
23
+ def process_bind_param(self, value, dialect):
24
+ """Turns solver results into json."""
25
+ if isinstance(value, list):
26
+ solver_list = []
27
+ for item in value:
28
+ if isinstance(item, SolverResults):
29
+ solver_list.append(item.model_dump_json())
30
+ return json.dumps(solver_list)
31
+ return None
32
+
33
+ def process_result_value(self, value, dialect):
34
+ """And back."""
35
+ if value is not None:
36
+ value_list = json.loads(value)
37
+ solver_list: SolverResults = []
38
+ for item in value_list:
39
+ item_dict = json.loads(item)
40
+ try:
41
+ solver_list.append(SolverResults.model_validate(item_dict))
42
+ except ValidationError as e:
43
+ print(f"Validation error when deserializing SolverResults: {e}")
44
+ continue
45
+ return solver_list
46
+ return None
47
+
48
+
49
+ class GNIMBUSSwitchPhaseRequest(SQLModel):
50
+ """A request for a certain phase. Comes from the group owner/analyst."""
51
+
52
+ group_id: int
53
+ new_phase: str
54
+
55
+
56
+ class GNIMBUSSwitchPhaseResponse(SQLModel):
57
+ """A response for the above request."""
58
+
59
+ old_phase: str
60
+ new_phase: str
61
+
62
+
63
+ class OptimizationPreference(BaseGroupInfoContainer):
64
+ """A structure for storing optimization preferences. See GNIMBUS for details."""
65
+
66
+ method: str = "optimization"
67
+ phase: str = Field(default="learning")
68
+ set_preferences: dict[int, ReferencePoint] = Field(sa_column=Column(ReferencePointDictType))
69
+
70
+
71
+ class VotingPreference(BaseGroupInfoContainer):
72
+ """A structure for storing voting preferences."""
73
+
74
+ method: str = "voting"
75
+ set_preferences: dict[int, int] = Field(
76
+ sa_column=Column(JSON)
77
+ ) # A user votes for an index from the results (or something)
78
+
79
+
80
+ class EndProcessPreference(BaseGroupInfoContainer):
81
+ """A structure for storing info on whether everyone is happy to end the gnimbus process."""
82
+
83
+ method: str = "end"
84
+ success: bool | None = Field()
85
+
86
+ # We check if everyone agrees to stop.
87
+ set_preferences: dict[int, bool] = Field(sa_column=Column(BooleanDictTypeDecorator))
88
+
89
+
90
+ class GNIMBUSResultResponse(SQLModel):
91
+ """The response for getting GNIMBUS results. NOTE: OBSOLETE!"""
92
+
93
+ method: str
94
+ phase: str
95
+ preferences: VotingPreference | OptimizationPreference
96
+ common_results: list[SolutionReference]
97
+ user_results: list[SolutionReference]
98
+ personal_result_index: int | None
99
+
100
+
101
+ class FullIteration(SQLModel):
102
+ """A full iteration item containing results from a complete or incomplete iteration.
103
+
104
+ This is a format to send information to the user interface.
105
+ """
106
+
107
+ phase: str = Field(
108
+ description="The phase of the iteration."
109
+ )
110
+ optimization_preferences: OptimizationPreference | None = Field(
111
+ description="The preferences related to the optimization stage of the full iteration."
112
+ )
113
+ voting_preferences: VotingPreference | EndProcessPreference | None = Field(
114
+ description="The preferences related to the voting phase of the iteration. \
115
+ either actual votes or a vote to see whether to just continue."
116
+ )
117
+ starting_result: SolutionReferenceLite | None = Field(
118
+ description="The starting result of the optimization process. Fetched from the previous \
119
+ iteration's final result."
120
+ )
121
+ common_results: list[SolutionReferenceLite] = Field(
122
+ description="The common results (1 to 4) generated by gnimbus."
123
+ )
124
+ user_results: list[SolutionReferenceLite] = Field(
125
+ description="The user specific results generated by gnimbus in phases learning and crp."
126
+ )
127
+ personal_result_index: int | None = Field(
128
+ description="The user result index of requester."
129
+ )
130
+ final_result: SolutionReferenceLite | None = Field(
131
+ description="The final result after voting."
132
+ )
133
+
134
+
135
+ class GNIMBUSAllIterationsResponse(SQLModel):
136
+ """The response model for getting all found solutions among others."""
137
+
138
+ all_full_iterations: list[FullIteration]
@@ -0,0 +1,104 @@
1
+ """Generic models for the DESDEO API."""
2
+
3
+ from pydantic import ConfigDict
4
+ from sqlmodel import JSON, Column, Field, SQLModel
5
+
6
+ from desdeo.tools.score_bands import SCOREBandsConfig, SCOREBandsResult
7
+
8
+ from .generic_states import SolutionReferenceResponse
9
+
10
+
11
+ class SolutionInfo(SQLModel):
12
+ """Used when we wish to reference a solution in some `StateDB` stored in the database."""
13
+
14
+ state_id: int = Field(description="State of the desired solution.")
15
+ solution_index: int = Field(description="Index of the desired solution.")
16
+ name: str | None = Field(description="Name to be given to the solution. Optional.", default=None)
17
+
18
+
19
+ class IntermediateSolutionRequest(SQLModel):
20
+ """Model of the request to solve intermediate solutions between two solutions."""
21
+
22
+ problem_id: int
23
+ session_id: int | None = Field(default=None)
24
+ parent_state_id: int | None = Field(default=None)
25
+ context: str | None = None # Method context (nimbus, rpm, etc.)
26
+ scalarization_options: dict[str, float | str | bool] | None = Field(sa_column=Column(JSON), default=None)
27
+ solver: str | None = Field(default=None)
28
+ solver_options: dict[str, float | str | bool] | None = Field(sa_column=Column(JSON), default=None)
29
+
30
+ num_desired: int | None = Field(default=1)
31
+
32
+ reference_solution_1: SolutionInfo
33
+ reference_solution_2: SolutionInfo
34
+
35
+
36
+ class GenericIntermediateSolutionResponse(SQLModel):
37
+ """The response from computing intermediate values."""
38
+
39
+ state_id: int | None = Field(description="The newly created state id")
40
+ reference_solution_1: SolutionReferenceResponse = Field(
41
+ sa_column=Column(JSON),
42
+ description="The first solution used when computing intermediate solutions.",
43
+ )
44
+ reference_solution_2: SolutionReferenceResponse = Field(
45
+ sa_column=Column(JSON),
46
+ description="The second solution used when computing intermediate solutions.",
47
+ )
48
+ intermediate_solutions: list[SolutionReferenceResponse] = Field(
49
+ sa_column=Column(JSON), description="The intermediate solutions computed."
50
+ )
51
+
52
+
53
+ class ScoreBandsRequest(SQLModel):
54
+ """Model of the request to calculate SCORE bands parameters."""
55
+
56
+ data: list[list[float]] = Field(description="Matrix of objective values")
57
+ objs: list[str] = Field(description="Array of objective names for each column")
58
+
59
+ # Optional parameters with defaults matching the score_bands.py functions
60
+ dist_parameter: float = Field(default=0.05, description="Distance parameter for axis positioning")
61
+ use_absolute_corr: bool = Field(default=False, description="Use absolute correlation values")
62
+ distance_formula: int = Field(default=1, description="Distance formula (1 or 2)")
63
+ flip_axes: bool = Field(default=True, description="Whether to flip axes based on correlation signs")
64
+ clustering_algorithm: str = Field(default="DBSCAN", description="Clustering algorithm (DBSCAN or GMM)")
65
+ clustering_score: str = Field(default="silhoutte", description="Clustering score metric")
66
+
67
+
68
+ class ScoreBandsResponse(SQLModel):
69
+ """Model of the response containing SCORE bands parameters."""
70
+
71
+ groups: list[int] = Field(description="Cluster group assignments for each data point")
72
+ axis_dist: list[float] = Field(description="Normalized axis positions")
73
+ axis_signs: list[int] | None = Field(description="Axis direction signs (1 or -1)")
74
+ obj_order: list[int] = Field(description="Optimal order of objectives")
75
+
76
+
77
+ class GroupScoreRequest(SQLModel):
78
+ """A generic model for requesting SCORE Bands for a state."""
79
+
80
+ model_config = ConfigDict(use_attribute_docstrings=True)
81
+
82
+ problem_id: int
83
+ group_id: int
84
+ """Database ID of the problem to solve."""
85
+ session_id: int | None = Field(default=None)
86
+ parent_state_id: int | None = Field(default=None)
87
+ """State ID of the parent state, if any."""
88
+
89
+ config: SCOREBandsConfig | None = Field(default=None)
90
+ """Configuration for the SCORE bands visualization."""
91
+
92
+ solution_ids: list[int] = Field()
93
+ """List of solution IDs to score."""
94
+
95
+
96
+ class GroupScoreResponse(SQLModel):
97
+ """Model of the response to an EMO score request."""
98
+
99
+ model_config = ConfigDict(use_attribute_docstrings=True)
100
+
101
+ group_iteration_id: int | None = Field(default=None)
102
+ """The state ID of the newly created group iteration."""
103
+
104
+ result: SCOREBandsResult