desdeo 2.1.0__tar.gz → 2.2.0__tar.gz

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 (181) hide show
  1. {desdeo-2.1.0 → desdeo-2.2.0}/PKG-INFO +21 -12
  2. {desdeo-2.1.0 → desdeo-2.2.0}/README.md +20 -11
  3. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/nimbus.py +8 -4
  4. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/emo.py +75 -104
  5. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/generic.py +26 -58
  6. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/nimbus.py +108 -247
  7. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/problem.py +69 -56
  8. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/reference_point_method.py +29 -27
  9. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/session.py +15 -11
  10. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/user_authentication.py +27 -5
  11. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/utils.py +42 -37
  12. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/utopia.py +11 -12
  13. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/tests/test_routes.py +6 -5
  14. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/__init__.py +2 -0
  15. desdeo-2.2.0/desdeo/emo/operators/__init__.py +1 -0
  16. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/operators/generator.py +153 -2
  17. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/options/__init__.py +4 -0
  18. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/options/generator.py +24 -0
  19. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/__init__.py +12 -11
  20. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/evaluator.py +4 -5
  21. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/gurobipy_evaluator.py +37 -12
  22. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/infix_parser.py +1 -16
  23. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/json_parser.py +7 -11
  24. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/schema.py +6 -9
  25. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/utils.py +1 -1
  26. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/pyomo_solver_interfaces.py +1 -1
  27. {desdeo-2.1.0 → desdeo-2.2.0}/pyproject.toml +28 -48
  28. desdeo-2.1.0/desdeo/emo/operators/__init__.py +0 -1
  29. {desdeo-2.1.0 → desdeo-2.2.0}/LICENSE +0 -0
  30. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/__init__.py +0 -0
  31. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/adm/ADMAfsar.py +0 -0
  32. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/adm/ADMChen.py +0 -0
  33. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/adm/BaseADM.py +0 -0
  34. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/adm/__init__.py +0 -0
  35. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/README.md +0 -0
  36. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/__init__.py +0 -0
  37. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/app.py +0 -0
  38. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/config.py +0 -0
  39. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/config.toml +0 -0
  40. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/db.py +0 -0
  41. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/db_init.py +0 -0
  42. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/db_models.py +0 -0
  43. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/malaga_db_init.py +0 -0
  44. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/__init__.py +0 -0
  45. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/archive.py +0 -0
  46. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/emo.py +0 -0
  47. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/enautilus.py +0 -0
  48. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/gdm/gdm_aggregate.py +0 -0
  49. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/gdm/gdm_base.py +0 -0
  50. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/gdm/gdm_score_bands.py +0 -0
  51. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/gdm/gnimbus.py +0 -0
  52. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/generic.py +0 -0
  53. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/generic_states.py +0 -0
  54. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/preference.py +0 -0
  55. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/problem.py +0 -0
  56. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/reference_point_method.py +0 -0
  57. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/session.py +0 -0
  58. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/state.py +0 -0
  59. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/user.py +0 -0
  60. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/models/utopia.py +0 -0
  61. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/_EMO.backup +0 -0
  62. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/_NAUTILUS.py +0 -0
  63. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/_NAUTILUS_navigator.py +0 -0
  64. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/_NIMBUS.py +0 -0
  65. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/__init__.py +0 -0
  66. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/enautilus.py +0 -0
  67. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/gdm/gdm_aggregate.py +0 -0
  68. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/gdm/gdm_base.py +0 -0
  69. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/gdm/gdm_score_bands/gdm_score_bands_manager.py +0 -0
  70. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/gdm/gdm_score_bands/gdm_score_bands_routers.py +0 -0
  71. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/gdm/gnimbus/gnimbus_manager.py +0 -0
  72. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/gdm/gnimbus/gnimbus_routers.py +0 -0
  73. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/routers/test.py +0 -0
  74. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/schema.py +0 -0
  75. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/tests/__init__.py +0 -0
  76. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/tests/conftest.py +0 -0
  77. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/tests/test_enautilus.py +0 -0
  78. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/tests/test_models.py +0 -0
  79. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/utils/_database.py +0 -0
  80. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/utils/_logger.py +0 -0
  81. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/utils/database.py +0 -0
  82. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/api/utils/emo_database.py +0 -0
  83. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/core.py +0 -0
  84. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/hooks/archivers.py +0 -0
  85. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/methods/EAs.py +0 -0
  86. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/methods/__init__.py +0 -0
  87. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/methods/bases.py +0 -0
  88. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/methods/templates.py +0 -0
  89. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/operators/crossover.py +0 -0
  90. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/operators/evaluator.py +0 -0
  91. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/operators/mutation.py +0 -0
  92. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/operators/scalar_selection.py +0 -0
  93. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/operators/selection.py +0 -0
  94. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/operators/termination.py +0 -0
  95. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/options/algorithms.py +0 -0
  96. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/options/crossover.py +0 -0
  97. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/options/mutation.py +0 -0
  98. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/options/repair.py +0 -0
  99. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/options/scalar_selection.py +0 -0
  100. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/options/selection.py +0 -0
  101. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/options/templates.py +0 -0
  102. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/emo/options/termination.py +0 -0
  103. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/explanations/__init__.py +0 -0
  104. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/explanations/explainer.py +0 -0
  105. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/explanations/utils.py +0 -0
  106. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/gdm/__init__.py +0 -0
  107. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/gdm/gdmtools.py +0 -0
  108. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/gdm/score_bands.py +0 -0
  109. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/gdm/voting_rules.py +0 -0
  110. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/mcdm/__init__.py +0 -0
  111. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/mcdm/enautilus.py +0 -0
  112. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/mcdm/gnimbus.py +0 -0
  113. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/mcdm/nautili.py +0 -0
  114. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/mcdm/nautilus.py +0 -0
  115. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/mcdm/nautilus_navigator.py +0 -0
  116. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/mcdm/nimbus.py +0 -0
  117. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/mcdm/pareto_navigator.py +0 -0
  118. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/mcdm/reference_point_method.py +0 -0
  119. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/external/__init__.py +0 -0
  120. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/external/core.py +0 -0
  121. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/external/pymoo_provider.py +0 -0
  122. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/external/runtime.py +0 -0
  123. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/pyomo_evaluator.py +0 -0
  124. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/simulator_evaluator.py +0 -0
  125. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/sympy_evaluator.py +0 -0
  126. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/__init__.py +0 -0
  127. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/benchmarks_server.py +0 -0
  128. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/binh_and_korn_problem.py +0 -0
  129. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/cake_problem.py +0 -0
  130. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/dmitry_forest_problem_discrete.py +0 -0
  131. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/dtlz2_problem.py +0 -0
  132. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/forest_problem.py +0 -0
  133. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/knapsack_problem.py +0 -0
  134. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/mcwb_problem.py +0 -0
  135. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/mixed_variable_dimenrions_problem.py +0 -0
  136. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/momip_problem.py +0 -0
  137. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/multi_valued_constraints.py +0 -0
  138. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/nimbus_problem.py +0 -0
  139. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/pareto_navigator_problem.py +0 -0
  140. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/re_problem.py +0 -0
  141. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/river_pollution_problems.py +0 -0
  142. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/rocket_injector_design_problem.py +0 -0
  143. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/simple_problem.py +0 -0
  144. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/simulator_problem.py +0 -0
  145. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/single_objective.py +0 -0
  146. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/spanish_sustainability_problem.py +0 -0
  147. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/problem/testproblems/zdt_problem.py +0 -0
  148. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/GenerateReferencePoints.py +0 -0
  149. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/__init__.py +0 -0
  150. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/desc_gen.py +0 -0
  151. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/generics.py +0 -0
  152. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/group_scalarization.py +0 -0
  153. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/gurobipy_solver_interfaces.py +0 -0
  154. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/indicators_binary.py +0 -0
  155. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/indicators_unary.py +0 -0
  156. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/interaction_schema.py +0 -0
  157. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/intersection.py +0 -0
  158. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/iterative_pareto_representer.py +0 -0
  159. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/message.py +0 -0
  160. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/ng_solver_interfaces.py +0 -0
  161. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/non_dominated_sorting.py +0 -0
  162. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/patterns.py +0 -0
  163. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/proximal_solver.py +0 -0
  164. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/reference_vectors.py +0 -0
  165. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/scalarization.py +0 -0
  166. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/scipy_solver_interfaces.py +0 -0
  167. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/score_bands.py +0 -0
  168. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/utils.py +0 -0
  169. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/tools/visualizations.py +0 -0
  170. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/utopia_stuff/__init__.py +0 -0
  171. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/utopia_stuff/data/1.json +0 -0
  172. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/utopia_stuff/data/2.json +0 -0
  173. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/utopia_stuff/data/3.json +0 -0
  174. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/utopia_stuff/data/4.json +0 -0
  175. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/utopia_stuff/data/5.json +0 -0
  176. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/utopia_stuff/from_json.py +0 -0
  177. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/utopia_stuff/reinit_user.py +0 -0
  178. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/utopia_stuff/utopia_db_init.py +0 -0
  179. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/utopia_stuff/utopia_problem.py +0 -0
  180. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/utopia_stuff/utopia_problem_old.py +0 -0
  181. {desdeo-2.1.0 → desdeo-2.2.0}/desdeo/utopia_stuff/utopia_reference_solutions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: desdeo
3
- Version: 2.1.0
3
+ Version: 2.2.0
4
4
  Summary: DESDEO is a modular and open source framework for interactive multiobjective optimization.
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -40,10 +40,14 @@ Project-URL: Homepage, https://github.com/industrial-optimization-group/DESDEO
40
40
  Project-URL: Repository, https://github.com/industrial-optimization-group/DESDEO
41
41
  Description-Content-Type: text/markdown
42
42
 
43
- # DESDEO: the open-source software framework for interactive multiobjective optimization
44
-
45
- [![Discord](https://img.shields.io/discord/1382614276409266206?style=flat&label=Join%20our%20Discord&labelColor=%237289da)](https://discord.gg/uGCEgQTJyY) [![Documentation Status](https://img.shields.io/readthedocs/desdeo.svg?version=desdeo2&label=Documentation)](https://desdeo.readthedocs.io/en/latest/) ![Tests](https://img.shields.io/github/actions/workflow/status/industrial-optimization-group/DESDEO/unit_tests.yaml?branch=desdeo2&label=Tests)
43
+ ![Latest release](https://img.shields.io/github/v/release/industrial-optimization-group/DESDEO?label=Latest%20release)
44
+ [![PyPI version](https://img.shields.io/pypi/v/desdeo?label=PyPI)](https://pypi.org/project/desdeo/)
45
+ [![Documentation Status](https://img.shields.io/readthedocs/desdeo.svg?version=desdeo2&label=Documentation)](https://desdeo.readthedocs.io/en/latest/)
46
+ ![Tests](https://img.shields.io/github/actions/workflow/status/industrial-optimization-group/DESDEO/unit_tests.yaml?branch=master&label=Tests)
47
+ [![Discord](https://img.shields.io/discord/1382614276409266206?style=flat&label=Join%20our%20Discord&labelColor=%237289da)](https://discord.gg/uGCEgQTJyY)
46
48
 
49
+
50
+ # DESDEO: the open-source software framework for interactive multiobjective optimization
47
51
  ## Introduction
48
52
 
49
53
  DESDEO is an open-source framework for interactive multiobjective optimization
@@ -74,13 +78,17 @@ decision-support using the framework. __The
74
78
  web-API is currently under heavy development, and is subject to changes.__
75
79
  3. The __web-GUI__ (WIP), which implements a web-based interface for utilizing
76
80
  the interactive methods and tools for modeling and solving multiobjective
77
- optimization problems. __The web-GUI relies heavily on the web-API, and is also being actively developed currently, and therefore subject to sudden changes.__
81
+ optimization problems.
82
+
83
+ > __The web-GUI relies heavily on the web-API, and is also being actively developed currently, and therefore subject to sudden changes.__
78
84
 
79
85
  For developing and experimenting with interactive multiobjective optimization
80
86
  methods on a "grass root" level, the __core-logic__ provides the necessary
81
- tools. For deploying interactive methods, the __web-API__ and the __web_GUI__
87
+ tools. For deploying interactive methods, the __web-API__ and the __web-GUI__
82
88
  play a central role.
83
89
 
90
+ > Users interested in using or developing the web-API and/or web-GUI are highly encouraged to express such intentions on our [Discord server](https://discord.gg/uGCEgQTJyY)!.
91
+
84
92
  DESDEO is an open-source project and everybody is welcome to contribute!
85
93
 
86
94
  ## Core-logic: key features
@@ -112,11 +120,12 @@ issue](https://github.com/industrial-optimization-group/DESDEO/issues/245).
112
120
 
113
121
  ## Web-GUI: key features
114
122
 
115
- DESDEO's web-GUI is currently in a planning stage. Once its active development
116
- starts, an issue will be created for documenting its development, as is
117
- currently the case with the web-API.
123
+ DESDEO's web-GUI is currently under active development. Once it stabilized, its
124
+ key features will be listed here. In the meantime, the interested user can
125
+ follow (and contribute!) the development progress of the web-API in [this
126
+ issue](https://github.com/industrial-optimization-group/DESDEO/issues/251).
118
127
 
119
- ## Installation instructions
128
+ ## Installation instructions (core-logic)
120
129
 
121
130
  DESDEO is available on PyPI to be installed via pip:
122
131
 
@@ -175,12 +184,12 @@ this repository's master branch is considered to be _DESDEO 2.0_.
175
184
 
176
185
  ## Funding
177
186
 
178
- Currently, DESDEO's development is partly funded by two projects granted by the
187
+ Currently, DESDEO's development has been funded by projects granted by the
179
188
  [Research Council of Finland](https://www.aka.fi/en/). The most recent ones
180
189
  include:
181
190
 
182
191
  - DESIDES (project 355346)
183
192
  - UTOPIA (project 352784)
184
193
  - DAEMON (project 322221)
185
-
194
+ - DESDEO (project 287496)
186
195
 
@@ -1,7 +1,11 @@
1
- # DESDEO: the open-source software framework for interactive multiobjective optimization
2
-
3
- [![Discord](https://img.shields.io/discord/1382614276409266206?style=flat&label=Join%20our%20Discord&labelColor=%237289da)](https://discord.gg/uGCEgQTJyY) [![Documentation Status](https://img.shields.io/readthedocs/desdeo.svg?version=desdeo2&label=Documentation)](https://desdeo.readthedocs.io/en/latest/) ![Tests](https://img.shields.io/github/actions/workflow/status/industrial-optimization-group/DESDEO/unit_tests.yaml?branch=desdeo2&label=Tests)
1
+ ![Latest release](https://img.shields.io/github/v/release/industrial-optimization-group/DESDEO?label=Latest%20release)
2
+ [![PyPI version](https://img.shields.io/pypi/v/desdeo?label=PyPI)](https://pypi.org/project/desdeo/)
3
+ [![Documentation Status](https://img.shields.io/readthedocs/desdeo.svg?version=desdeo2&label=Documentation)](https://desdeo.readthedocs.io/en/latest/)
4
+ ![Tests](https://img.shields.io/github/actions/workflow/status/industrial-optimization-group/DESDEO/unit_tests.yaml?branch=master&label=Tests)
5
+ [![Discord](https://img.shields.io/discord/1382614276409266206?style=flat&label=Join%20our%20Discord&labelColor=%237289da)](https://discord.gg/uGCEgQTJyY)
4
6
 
7
+
8
+ # DESDEO: the open-source software framework for interactive multiobjective optimization
5
9
  ## Introduction
6
10
 
7
11
  DESDEO is an open-source framework for interactive multiobjective optimization
@@ -32,13 +36,17 @@ decision-support using the framework. __The
32
36
  web-API is currently under heavy development, and is subject to changes.__
33
37
  3. The __web-GUI__ (WIP), which implements a web-based interface for utilizing
34
38
  the interactive methods and tools for modeling and solving multiobjective
35
- optimization problems. __The web-GUI relies heavily on the web-API, and is also being actively developed currently, and therefore subject to sudden changes.__
39
+ optimization problems.
40
+
41
+ > __The web-GUI relies heavily on the web-API, and is also being actively developed currently, and therefore subject to sudden changes.__
36
42
 
37
43
  For developing and experimenting with interactive multiobjective optimization
38
44
  methods on a "grass root" level, the __core-logic__ provides the necessary
39
- tools. For deploying interactive methods, the __web-API__ and the __web_GUI__
45
+ tools. For deploying interactive methods, the __web-API__ and the __web-GUI__
40
46
  play a central role.
41
47
 
48
+ > Users interested in using or developing the web-API and/or web-GUI are highly encouraged to express such intentions on our [Discord server](https://discord.gg/uGCEgQTJyY)!.
49
+
42
50
  DESDEO is an open-source project and everybody is welcome to contribute!
43
51
 
44
52
  ## Core-logic: key features
@@ -70,11 +78,12 @@ issue](https://github.com/industrial-optimization-group/DESDEO/issues/245).
70
78
 
71
79
  ## Web-GUI: key features
72
80
 
73
- DESDEO's web-GUI is currently in a planning stage. Once its active development
74
- starts, an issue will be created for documenting its development, as is
75
- currently the case with the web-API.
81
+ DESDEO's web-GUI is currently under active development. Once it stabilized, its
82
+ key features will be listed here. In the meantime, the interested user can
83
+ follow (and contribute!) the development progress of the web-API in [this
84
+ issue](https://github.com/industrial-optimization-group/DESDEO/issues/251).
76
85
 
77
- ## Installation instructions
86
+ ## Installation instructions (core-logic)
78
87
 
79
88
  DESDEO is available on PyPI to be installed via pip:
80
89
 
@@ -133,11 +142,11 @@ this repository's master branch is considered to be _DESDEO 2.0_.
133
142
 
134
143
  ## Funding
135
144
 
136
- Currently, DESDEO's development is partly funded by two projects granted by the
145
+ Currently, DESDEO's development has been funded by projects granted by the
137
146
  [Research Council of Finland](https://www.aka.fi/en/). The most recent ones
138
147
  include:
139
148
 
140
149
  - DESIDES (project 355346)
141
150
  - UTOPIA (project 352784)
142
151
  - DAEMON (project 322221)
143
-
152
+ - DESDEO (project 287496)
@@ -36,11 +36,13 @@ class NIMBUSSaveRequest(SQLModel):
36
36
 
37
37
  solution_info: list[SolutionInfo]
38
38
 
39
+
39
40
  class NIMBUSDeleteSaveRequest(SQLModel):
40
41
  """Request model for deletion of a saved solution."""
41
42
 
42
- state_id : int = Field(description="The ID of the save state.")
43
+ state_id: int = Field(description="The ID of the save state.")
43
44
  solution_index: int = Field(description="The ID of the solution within the above state.")
45
+ problem_id: int = Field(description="The ID of the problem.")
44
46
 
45
47
 
46
48
  class NIMBUSFinalizeRequest(SQLModel):
@@ -50,7 +52,7 @@ class NIMBUSFinalizeRequest(SQLModel):
50
52
  session_id: int | None = Field(default=None)
51
53
  parent_state_id: int | None = Field(default=None)
52
54
 
53
- solution_info: SolutionInfo # the final solution
55
+ solution_info: SolutionInfo # the final solution
54
56
 
55
57
 
56
58
  class NIMBUSClassificationResponse(SQLModel):
@@ -98,12 +100,14 @@ class NIMBUSSaveResponse(SQLModel):
98
100
 
99
101
  state_id: int | None = Field(description="The id of the newest state")
100
102
 
103
+
101
104
  class NIMBUSDeleteSaveResponse(SQLModel):
102
105
  """Response of NIMBUS save deletion."""
103
106
 
104
107
  response_type: str = "nimbus.delete_save"
105
108
 
106
- message: str | None
109
+ message: str | None = None
110
+
107
111
 
108
112
  class NIMBUSFinalizeResponse(SQLModel):
109
113
  """The response from NIMBUS finish endpoint."""
@@ -144,7 +148,7 @@ class NIMBUSIntermediateSolutionResponse(SQLModel):
144
148
  reference_solution_1: dict[str, float] = Field(
145
149
  sa_column=Column(JSON), description="The first solution used when computing intermediate points."
146
150
  )
147
- reference_solution_2: dict[str, float]= Field(
151
+ reference_solution_2: dict[str, float] = Field(
148
152
  sa_column=Column(JSON), description="The second solution used when computing intermediate points."
149
153
  )
150
154
  current_solutions: list[SolutionReferenceResponse] = Field(
@@ -15,30 +15,24 @@ import polars as pl
15
15
  from fastapi import APIRouter, Depends, HTTPException, WebSocket, WebSocketDisconnect, status
16
16
  from fastapi.encoders import jsonable_encoder
17
17
  from fastapi.responses import StreamingResponse
18
- from sqlmodel import Session, select
18
+ from sqlmodel import select
19
19
  from websockets.asyncio.client import connect
20
20
 
21
21
  from desdeo.api.db import get_session
22
- from desdeo.api.models import InteractiveSessionDB, StateDB
22
+ from desdeo.api.models import StateDB
23
23
  from desdeo.api.models.emo import (
24
24
  EMOFetchRequest,
25
- EMOFetchResponse,
26
25
  EMOIterateRequest,
27
26
  EMOIterateResponse,
28
- EMOSaveRequest,
29
27
  EMOScoreRequest,
30
28
  EMOScoreResponse,
31
- Solution,
32
29
  )
33
- from desdeo.api.models.problem import ProblemDB
34
- from desdeo.api.models.state import EMOFetchState, EMOIterateState, EMOSaveState, EMOSCOREState
35
- from desdeo.api.models.user import User
36
- from desdeo.api.routers.user_authentication import get_current_user
30
+ from desdeo.api.models.state import EMOIterateState, EMOSCOREState
37
31
  from desdeo.emo.options.templates import EMOOptions, PreferenceOptions, TemplateOptions, emo_constructor
38
32
  from desdeo.problem import Problem
39
- from desdeo.tools.score_bands import SCOREBandsConfig, SCOREBandsResult, score_json
33
+ from desdeo.tools.score_bands import SCOREBandsConfig, score_json
40
34
 
41
- from .utils import fetch_interactive_session, fetch_user_problem
35
+ from .utils import SessionContext, get_session_context
42
36
 
43
37
  router = APIRouter(prefix="/method/emo", tags=["EMO"])
44
38
 
@@ -113,7 +107,6 @@ async def websocket_endpoint(
113
107
  try:
114
108
  while True:
115
109
  data = await websocket.receive_json()
116
- print(data)
117
110
  if "send_to" in data:
118
111
  try:
119
112
  await ws_manager.send_private_message(data, data["send_to"])
@@ -153,71 +146,55 @@ def get_templates() -> list[TemplateOptions]:
153
146
  @router.post("/iterate")
154
147
  def iterate(
155
148
  request: EMOIterateRequest,
156
- user: Annotated[User, Depends(get_current_user)],
157
- session: Annotated[Session, Depends(get_session)],
149
+ context: Annotated[SessionContext, Depends(get_session_context)],
158
150
  ) -> EMOIterateResponse:
159
- """Starts the EMO method.
151
+ """Fetches results from a completed EMO method.
160
152
 
161
- Args:
162
- request (EMOSolveRequest): The request object containing parameters for the EMO method.
163
- user (Annotated[User, Depends]): The current user.
164
- session (Annotated[Session, Depends]): The database session.
153
+ Args: request (EMOIterateRequest): The request object containing parameters for fetching results.
154
+ context (Annotated[SessionContext, Depends]): The session context.
165
155
 
166
- Raises:
167
- HTTPException: If the request is invalid or the EMO method fails.
168
-
169
- Returns:
170
- IterateResponse: A response object containing a list of IDs to be used for websocket communication.
171
- Also contains the StateDB id where the results will be stored.
156
+ Raises: HTTPException: If the request is invalid or the EMO method fails.
157
+ Returns: IterateResponse: A response object containing a list of IDs to be used for websocket communication.
158
+ Also contains the StateDB id where the results will be stored.
172
159
  """
173
- interactive_session: InteractiveSessionDB | None = fetch_interactive_session(user, request, session)
160
+ # Get context objects
161
+ db_session = context.db_session
162
+ interactive_session = context.interactive_session
163
+ parent_state = context.parent_state
174
164
 
175
- problem_db = fetch_user_problem(user, request, session)
165
+ # Ensure problem exists
166
+ if context.problem_db is None:
167
+ raise HTTPException(status_code=404, detail="Problem not found")
168
+
169
+ problem_db = context.problem_db
176
170
  problem = Problem.from_problemdb(problem_db)
177
171
 
178
- templates = request.template_options
172
+ # Templates
173
+ templates = request.template_options or get_templates()
179
174
 
180
- if templates is None:
181
- templates = get_templates()
175
+ web_socket_ids = [
176
+ f"{template.algorithm_name.lower()}_{datetime.now().strftime('%Y%m%d%H%M%S%f')}" for template in templates
177
+ ]
182
178
 
183
- web_socket_ids = []
184
- for template in templates:
185
- # Ensure unique names
186
- web_socket_ids.append(f"{template.algorithm_name.lower()}_{datetime.now().strftime('%Y%m%d%H%M%S%f')}")
187
179
  client_id = f"client_{datetime.now().strftime('%Y%m%d%H%M%S%f')}"
188
- client_id = "client"
189
-
190
- # Save request (incomplete and EAs have not finished running yet)
191
-
192
- # Handle parent state
193
- if request.parent_state_id is None:
194
- parent_state = None
195
- else:
196
- statement = select(StateDB).where(StateDB.id == request.parent_state_id)
197
- parent_state = session.exec(statement).first()
198
-
199
- if parent_state is None:
200
- raise HTTPException(
201
- status_code=status.HTTP_404_NOT_FOUND,
202
- detail=f"Could not find state with id={request.parent_state_id}",
203
- )
204
180
 
181
+ # 4) Create incomplete state
205
182
  emo_iterate_state = EMOIterateState(
206
183
  template_options=jsonable_encoder(templates),
207
184
  preference_options=jsonable_encoder(request.preference_options),
208
185
  )
209
186
 
210
187
  incomplete_db_state = StateDB.create(
211
- database_session=session,
188
+ database_session=db_session,
212
189
  problem_id=problem_db.id,
213
190
  session_id=interactive_session.id if interactive_session else None,
214
191
  parent_id=parent_state.id if parent_state else None,
215
192
  state=emo_iterate_state,
216
193
  )
217
194
 
218
- session.add(incomplete_db_state)
219
- session.commit()
220
- session.refresh(incomplete_db_state)
195
+ db_session.add(incomplete_db_state)
196
+ db_session.commit()
197
+ db_session.refresh(incomplete_db_state)
221
198
 
222
199
  state_id = incomplete_db_state.id
223
200
  if state_id is None:
@@ -225,10 +202,8 @@ def iterate(
225
202
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
226
203
  detail="Failed to create a new state in the database.",
227
204
  )
228
- # Close db session
229
- session.close()
230
205
 
231
- # Spawn a new process to handle EMO method creation
206
+ # Start process
232
207
  Process(
233
208
  target=_spawn_emo_process,
234
209
  args=(
@@ -319,7 +294,7 @@ def _spawn_emo_process(
319
294
  session.close()
320
295
 
321
296
 
322
- def _ea_sync( # noqa: PLR0913
297
+ def _ea_sync(
323
298
  problem: Problem,
324
299
  template: TemplateOptions,
325
300
  preference_options: PreferenceOptions | None,
@@ -352,7 +327,7 @@ def _ea_sync( # noqa: PLR0913
352
327
  )
353
328
 
354
329
 
355
- async def _ea_async( # noqa: PLR0913
330
+ async def _ea_async(
356
331
  problem: Problem,
357
332
  websocket_id: str,
358
333
  client_id: str,
@@ -388,33 +363,29 @@ async def _ea_async( # noqa: PLR0913
388
363
  @router.post("/fetch")
389
364
  async def fetch_results(
390
365
  request: EMOFetchRequest,
391
- user: Annotated[User, Depends(get_current_user)],
392
- session: Annotated[Session, Depends(get_session)],
366
+ context: Annotated[SessionContext, Depends(get_session_context)],
393
367
  ) -> StreamingResponse:
394
368
  """Fetches results from a completed EMO method.
395
369
 
396
370
  Args:
397
371
  request (EMOFetchRequest): The request object containing parameters for fetching results.
398
- user (Annotated[User, Depends]): The current user.
399
- session (Annotated[Session, Depends]): The database session.
372
+ context (Annotated[SessionContext, Depends]): The session context.
400
373
 
401
- Raises:
402
- HTTPException: If the request is invalid or the EMO method has not completed.
374
+ Raises: HTTPException: If the request is invalid or the EMO method has not completed.
403
375
 
404
- Returns:
405
- StreamingResponse: A streaming response containing the results of the EMO method.
376
+ Returns: StreamingResponse: A streaming response containing the results of the EMO method.
406
377
  """
407
- parent_state = request.parent_state_id
408
- statement = select(StateDB).where(StateDB.id == parent_state)
409
- state = session.exec(statement).first()
378
+ # Use context instead of manual fetch
379
+ state = context.parent_state
380
+
410
381
  if state is None:
411
382
  raise HTTPException(status_code=404, detail="Parent state not found.")
412
383
 
413
384
  if not isinstance(state.state, EMOIterateState):
414
- raise TypeError(f"State with id={parent_state} is not of type EMOIterateState.")
385
+ raise TypeError(f"State with id={request.parent_state_id} is not of type EMOIterateState.")
415
386
 
416
387
  if not (state.state.objective_values and state.state.decision_variables):
417
- raise ValueError(f"State does not contain results yet.")
388
+ raise ValueError("State does not contain results yet.")
418
389
 
419
390
  # Convert objs: dict[str, list[float]] to objs: list[dict[str, float]]
420
391
  raw_objs: dict[str, list[float]] = state.state.objective_values
@@ -422,14 +393,15 @@ async def fetch_results(
422
393
  objs: list[dict[str, float]] = [{k: v[i] for k, v in raw_objs.items()} for i in range(n_solutions)]
423
394
 
424
395
  raw_decs: dict[str, list[float]] = state.state.decision_variables
425
-
426
396
  decs: list[dict[str, float]] = [{k: v[i] for k, v in raw_decs.items()} for i in range(n_solutions)]
427
397
 
428
- response: list[Solution] = []
429
-
430
398
  def result_stream():
431
399
  for i in range(n_solutions):
432
- item = {"solution_id": i, "objective_values": objs[i], "decision_variables": decs[i]}
400
+ item = {
401
+ "solution_id": i,
402
+ "objective_values": objs[i],
403
+ "decision_variables": decs[i],
404
+ }
433
405
  yield json.dumps(item) + "\n"
434
406
 
435
407
  return StreamingResponse(result_stream())
@@ -438,16 +410,13 @@ async def fetch_results(
438
410
  @router.post("/fetch_score")
439
411
  async def fetch_score_bands(
440
412
  request: EMOScoreRequest,
441
- user: Annotated[User, Depends(get_current_user)],
442
- session: Annotated[Session, Depends(get_session)],
413
+ context: Annotated[SessionContext, Depends(get_session_context)],
443
414
  ) -> EMOScoreResponse:
444
415
  """Fetches results from a completed EMO method.
445
416
 
446
- Args:
447
- request (EMOFetchRequest): The request object containing parameters for fetching results and of the SCORE bands
448
- visualization.
449
- user (Annotated[User, Depends]): The current user.
450
- session (Annotated[Session, Depends]): The database session.
417
+ Args: request (EMOFetchRequest): The request object containing parameters for fetching
418
+ results and of the SCORE bands visualization.
419
+ context (Annotated[SessionContext, Depends]): The session context.
451
420
 
452
421
  Raises:
453
422
  HTTPException: If the request is invalid or the EMO method has not completed.
@@ -455,24 +424,23 @@ async def fetch_score_bands(
455
424
  Returns:
456
425
  SCOREBandsResult: The results of the SCORE bands visualization.
457
426
  """
458
- if request.config is None:
459
- score_config = SCOREBandsConfig()
460
- else:
461
- score_config = request.config
462
- parent_state = request.parent_state_id
463
- statement = select(StateDB).where(StateDB.id == parent_state)
464
- state = session.exec(statement).first()
465
- if state is None:
427
+ # Use context instead of manual fetch
428
+ parent_state = context.parent_state
429
+ db_session = context.db_session
430
+ problem_db = context.problem_db
431
+
432
+ if parent_state is None:
466
433
  raise HTTPException(status_code=404, detail="Parent state not found.")
467
434
 
468
- if not isinstance(state.state, EMOIterateState):
469
- raise TypeError(f"State with id={parent_state} is not of type EMOIterateState.")
435
+ if not isinstance(parent_state.state, EMOIterateState):
436
+ raise TypeError(f"State with id={request.parent_state_id} is not of type EMOIterateState.")
470
437
 
471
- if not (state.state.objective_values and state.state.decision_variables):
472
- raise ValueError(f"State does not contain results yet.")
438
+ if not (parent_state.state.objective_values and parent_state.state.decision_variables):
439
+ raise ValueError("State does not contain results yet.")
473
440
 
474
- # Convert objs: dict[str, list[float]] to objs: list[dict[str, float]]
475
- raw_objs: dict[str, list[float]] = state.state.objective_values
441
+ score_config = SCOREBandsConfig() if request.config is None else request.config
442
+
443
+ raw_objs: dict[str, list[float]] = parent_state.state.objective_values
476
444
  objs = pl.DataFrame(raw_objs)
477
445
 
478
446
  results = score_json(
@@ -482,16 +450,19 @@ async def fetch_score_bands(
482
450
 
483
451
  score_state = EMOSCOREState(result=results.model_dump())
484
452
 
453
+ # Use the session + problem from context instead of request directly
485
454
  score_db_state = StateDB.create(
486
- database_session=session,
487
- problem_id=request.problem_id,
488
- session_id=request.session_id,
489
- parent_id=parent_state,
455
+ database_session=db_session,
456
+ problem_id=problem_db.id,
457
+ session_id=parent_state.session_id,
458
+ parent_id=parent_state.id,
490
459
  state=score_state,
491
460
  )
492
- session.add(score_db_state)
493
- session.commit()
494
- session.refresh(score_db_state)
461
+
462
+ db_session.add(score_db_state)
463
+ db_session.commit()
464
+ db_session.refresh(score_db_state)
465
+
495
466
  state_id = score_db_state.id
496
467
 
497
468
  return EMOScoreResponse(result=results, state_id=state_id)