desdeo 1.2__py3-none-any.whl → 2.0.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 (122) hide show
  1. desdeo/__init__.py +8 -8
  2. desdeo/api/README.md +73 -0
  3. desdeo/api/__init__.py +15 -0
  4. desdeo/api/app.py +40 -0
  5. desdeo/api/config.py +69 -0
  6. desdeo/api/config.toml +53 -0
  7. desdeo/api/db.py +25 -0
  8. desdeo/api/db_init.py +79 -0
  9. desdeo/api/db_models.py +164 -0
  10. desdeo/api/malaga_db_init.py +27 -0
  11. desdeo/api/models/__init__.py +66 -0
  12. desdeo/api/models/archive.py +34 -0
  13. desdeo/api/models/preference.py +90 -0
  14. desdeo/api/models/problem.py +507 -0
  15. desdeo/api/models/reference_point_method.py +18 -0
  16. desdeo/api/models/session.py +46 -0
  17. desdeo/api/models/state.py +96 -0
  18. desdeo/api/models/user.py +51 -0
  19. desdeo/api/routers/_NAUTILUS.py +245 -0
  20. desdeo/api/routers/_NAUTILUS_navigator.py +233 -0
  21. desdeo/api/routers/_NIMBUS.py +762 -0
  22. desdeo/api/routers/__init__.py +5 -0
  23. desdeo/api/routers/problem.py +110 -0
  24. desdeo/api/routers/reference_point_method.py +117 -0
  25. desdeo/api/routers/session.py +76 -0
  26. desdeo/api/routers/test.py +16 -0
  27. desdeo/api/routers/user_authentication.py +366 -0
  28. desdeo/api/schema.py +94 -0
  29. desdeo/api/tests/__init__.py +0 -0
  30. desdeo/api/tests/conftest.py +59 -0
  31. desdeo/api/tests/test_models.py +701 -0
  32. desdeo/api/tests/test_routes.py +216 -0
  33. desdeo/api/utils/database.py +274 -0
  34. desdeo/api/utils/logger.py +29 -0
  35. desdeo/core.py +27 -0
  36. desdeo/emo/__init__.py +29 -0
  37. desdeo/emo/hooks/archivers.py +172 -0
  38. desdeo/emo/methods/EAs.py +418 -0
  39. desdeo/emo/methods/__init__.py +0 -0
  40. desdeo/emo/methods/bases.py +59 -0
  41. desdeo/emo/operators/__init__.py +1 -0
  42. desdeo/emo/operators/crossover.py +780 -0
  43. desdeo/emo/operators/evaluator.py +118 -0
  44. desdeo/emo/operators/generator.py +356 -0
  45. desdeo/emo/operators/mutation.py +1053 -0
  46. desdeo/emo/operators/selection.py +1036 -0
  47. desdeo/emo/operators/termination.py +178 -0
  48. desdeo/explanations/__init__.py +6 -0
  49. desdeo/explanations/explainer.py +100 -0
  50. desdeo/explanations/utils.py +90 -0
  51. desdeo/mcdm/__init__.py +19 -0
  52. desdeo/mcdm/nautili.py +345 -0
  53. desdeo/mcdm/nautilus.py +477 -0
  54. desdeo/mcdm/nautilus_navigator.py +655 -0
  55. desdeo/mcdm/nimbus.py +417 -0
  56. desdeo/mcdm/pareto_navigator.py +269 -0
  57. desdeo/mcdm/reference_point_method.py +116 -0
  58. desdeo/problem/__init__.py +79 -0
  59. desdeo/problem/evaluator.py +561 -0
  60. desdeo/problem/gurobipy_evaluator.py +562 -0
  61. desdeo/problem/infix_parser.py +341 -0
  62. desdeo/problem/json_parser.py +944 -0
  63. desdeo/problem/pyomo_evaluator.py +468 -0
  64. desdeo/problem/schema.py +1808 -0
  65. desdeo/problem/simulator_evaluator.py +298 -0
  66. desdeo/problem/sympy_evaluator.py +244 -0
  67. desdeo/problem/testproblems/__init__.py +73 -0
  68. desdeo/problem/testproblems/binh_and_korn_problem.py +88 -0
  69. desdeo/problem/testproblems/dtlz2_problem.py +102 -0
  70. desdeo/problem/testproblems/forest_problem.py +275 -0
  71. desdeo/problem/testproblems/knapsack_problem.py +163 -0
  72. desdeo/problem/testproblems/mcwb_problem.py +831 -0
  73. desdeo/problem/testproblems/mixed_variable_dimenrions_problem.py +83 -0
  74. desdeo/problem/testproblems/momip_problem.py +172 -0
  75. desdeo/problem/testproblems/nimbus_problem.py +143 -0
  76. desdeo/problem/testproblems/pareto_navigator_problem.py +89 -0
  77. desdeo/problem/testproblems/re_problem.py +492 -0
  78. desdeo/problem/testproblems/river_pollution_problem.py +434 -0
  79. desdeo/problem/testproblems/rocket_injector_design_problem.py +140 -0
  80. desdeo/problem/testproblems/simple_problem.py +351 -0
  81. desdeo/problem/testproblems/simulator_problem.py +92 -0
  82. desdeo/problem/testproblems/spanish_sustainability_problem.py +945 -0
  83. desdeo/problem/testproblems/zdt_problem.py +271 -0
  84. desdeo/problem/utils.py +245 -0
  85. desdeo/tools/GenerateReferencePoints.py +181 -0
  86. desdeo/tools/__init__.py +102 -0
  87. desdeo/tools/generics.py +145 -0
  88. desdeo/tools/gurobipy_solver_interfaces.py +258 -0
  89. desdeo/tools/indicators_binary.py +11 -0
  90. desdeo/tools/indicators_unary.py +375 -0
  91. desdeo/tools/interaction_schema.py +38 -0
  92. desdeo/tools/intersection.py +54 -0
  93. desdeo/tools/iterative_pareto_representer.py +99 -0
  94. desdeo/tools/message.py +234 -0
  95. desdeo/tools/ng_solver_interfaces.py +199 -0
  96. desdeo/tools/non_dominated_sorting.py +133 -0
  97. desdeo/tools/patterns.py +281 -0
  98. desdeo/tools/proximal_solver.py +99 -0
  99. desdeo/tools/pyomo_solver_interfaces.py +464 -0
  100. desdeo/tools/reference_vectors.py +462 -0
  101. desdeo/tools/scalarization.py +3138 -0
  102. desdeo/tools/scipy_solver_interfaces.py +454 -0
  103. desdeo/tools/score_bands.py +464 -0
  104. desdeo/tools/utils.py +320 -0
  105. desdeo/utopia_stuff/__init__.py +0 -0
  106. desdeo/utopia_stuff/data/1.json +15 -0
  107. desdeo/utopia_stuff/data/2.json +13 -0
  108. desdeo/utopia_stuff/data/3.json +15 -0
  109. desdeo/utopia_stuff/data/4.json +17 -0
  110. desdeo/utopia_stuff/data/5.json +15 -0
  111. desdeo/utopia_stuff/from_json.py +40 -0
  112. desdeo/utopia_stuff/reinit_user.py +38 -0
  113. desdeo/utopia_stuff/utopia_db_init.py +212 -0
  114. desdeo/utopia_stuff/utopia_problem.py +403 -0
  115. desdeo/utopia_stuff/utopia_problem_old.py +415 -0
  116. desdeo/utopia_stuff/utopia_reference_solutions.py +79 -0
  117. desdeo-2.0.0.dist-info/LICENSE +21 -0
  118. desdeo-2.0.0.dist-info/METADATA +168 -0
  119. desdeo-2.0.0.dist-info/RECORD +120 -0
  120. {desdeo-1.2.dist-info → desdeo-2.0.0.dist-info}/WHEEL +1 -1
  121. desdeo-1.2.dist-info/METADATA +0 -16
  122. desdeo-1.2.dist-info/RECORD +0 -4
@@ -0,0 +1,102 @@
1
+ """Imports available form the desdeo-tools package."""
2
+
3
+ __all__ = [
4
+ "BaseSolver",
5
+ "BonminOptions",
6
+ "IpoptOptions",
7
+ "GurobipySolver",
8
+ "NevergradGenericOptions",
9
+ "NevergradGenericSolver",
10
+ "PersistentGurobipySolver",
11
+ "ProximalSolver",
12
+ "PyomoBonminSolver",
13
+ "PyomoCBCSolver",
14
+ "PyomoGurobiSolver",
15
+ "PyomoIpoptSolver",
16
+ "ScipyDeSolver",
17
+ "ScipyMinimizeSolver",
18
+ "SolverOptions",
19
+ "SolverResults",
20
+ "ScalarizationError",
21
+ "add_asf_diff",
22
+ "add_asf_generic_nondiff",
23
+ "add_asf_generic_diff",
24
+ "add_asf_nondiff",
25
+ "add_epsilon_constraints",
26
+ "add_guess_sf_diff",
27
+ "add_guess_sf_nondiff",
28
+ "add_group_asf",
29
+ "add_group_asf_diff",
30
+ "add_group_guess_sf",
31
+ "add_group_guess_sf_diff",
32
+ "add_group_nimbus_sf",
33
+ "add_group_nimbus_sf_diff",
34
+ "add_group_stom_sf",
35
+ "add_group_stom_sf_diff",
36
+ "add_nimbus_sf_diff",
37
+ "add_nimbus_sf_nondiff",
38
+ "add_objective_as_scalarization",
39
+ "add_stom_sf_diff",
40
+ "add_stom_sf_nondiff",
41
+ "add_weighted_sums",
42
+ "available_nevergrad_optimizers",
43
+ "available_solvers",
44
+ "find_compatible_solvers",
45
+ "get_corrected_ideal_and_nadir",
46
+ "get_corrected_reference_point",
47
+ "guess_best_solver",
48
+ "payoff_table_method",
49
+ ]
50
+
51
+ from desdeo.tools.generics import BaseSolver, SolverOptions, SolverResults
52
+ from desdeo.tools.gurobipy_solver_interfaces import (
53
+ GurobipySolver,
54
+ PersistentGurobipySolver,
55
+ )
56
+ from desdeo.tools.ng_solver_interfaces import (
57
+ NevergradGenericOptions,
58
+ NevergradGenericSolver,
59
+ available_nevergrad_optimizers,
60
+ )
61
+ from desdeo.tools.proximal_solver import ProximalSolver
62
+ from desdeo.tools.pyomo_solver_interfaces import (
63
+ BonminOptions,
64
+ IpoptOptions,
65
+ PyomoBonminSolver,
66
+ PyomoCBCSolver,
67
+ PyomoGurobiSolver,
68
+ PyomoIpoptSolver,
69
+ )
70
+ from desdeo.tools.scalarization import (
71
+ ScalarizationError,
72
+ add_asf_diff,
73
+ add_asf_generic_diff,
74
+ add_asf_generic_nondiff,
75
+ add_asf_nondiff,
76
+ add_epsilon_constraints,
77
+ add_group_asf,
78
+ add_group_asf_diff,
79
+ add_group_guess_sf,
80
+ add_group_guess_sf_diff,
81
+ add_group_nimbus_sf,
82
+ add_group_nimbus_sf_diff,
83
+ add_group_stom_sf,
84
+ add_group_stom_sf_diff,
85
+ add_guess_sf_diff,
86
+ add_guess_sf_nondiff,
87
+ add_nimbus_sf_diff,
88
+ add_nimbus_sf_nondiff,
89
+ add_objective_as_scalarization,
90
+ add_stom_sf_diff,
91
+ add_stom_sf_nondiff,
92
+ add_weighted_sums,
93
+ )
94
+ from desdeo.tools.scipy_solver_interfaces import ScipyDeSolver, ScipyMinimizeSolver
95
+ from desdeo.tools.utils import (
96
+ available_solvers,
97
+ find_compatible_solvers,
98
+ get_corrected_ideal_and_nadir,
99
+ get_corrected_reference_point,
100
+ guess_best_solver,
101
+ payoff_table_method,
102
+ )
@@ -0,0 +1,145 @@
1
+ """Defines generic classes, functions, and objects utilized in the tools module."""
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import Any, TypeVar
5
+
6
+ from pydantic import BaseModel, Field
7
+
8
+ from desdeo.problem import (
9
+ Constraint,
10
+ Objective,
11
+ Problem,
12
+ ScalarizationFunction,
13
+ Variable,
14
+ )
15
+
16
+
17
+ class SolverError(Exception):
18
+ """Raised when an error with a solver is encountered."""
19
+
20
+
21
+ class SolverResults(BaseModel):
22
+ """Defines a schema for a dataclass to store the results of a solver."""
23
+
24
+ optimal_variables: dict[str, int | float | list] = Field(description="The optimal decision variables found.")
25
+ optimal_objectives: dict[str, float | list[float]] = Field(
26
+ description="The objective function values corresponding to the optimal decision variables found."
27
+ )
28
+ constraint_values: dict[str, float | list[float]] | None = Field(
29
+ description=(
30
+ "The constraint values of the problem. A negative value means the constraint is respected, "
31
+ "a positive one means it has been breached."
32
+ ),
33
+ default=None,
34
+ )
35
+ extra_func_values: dict[str, float | list[float]] | None = Field(
36
+ description=("The extra function values of the problem."), default=None
37
+ )
38
+ scalarization_values: dict[str, float | list[float]] | None = Field(
39
+ description=("The scalarization function values of the problem."), default=None
40
+ )
41
+ success: bool = Field(description="A boolean flag indicating whether the optimization was successful or not.")
42
+ message: str = Field(description="Description of the cause of termination.")
43
+
44
+
45
+ class BaseSolver(ABC):
46
+ """Defines a schema for a solver base class."""
47
+
48
+ evaluator: object
49
+ problem: Problem
50
+
51
+ def __init__(self, problem: Problem, options: dict[str, any] | None = None):
52
+ """Initializer for the persistent solver.
53
+
54
+ Args:
55
+ problem (Problem): The problem for the solver.
56
+ options (dict[str,any]): Dictionary of parameters to set.
57
+ What these should be depends on the solver used.
58
+ """
59
+ self.problem = problem
60
+
61
+ @abstractmethod
62
+ def solve(self, target: str) -> SolverResults:
63
+ """Solves the current problem with the specified target.
64
+
65
+ Args:
66
+ target (str): a str representing the symbol of the target function.
67
+
68
+ Returns:
69
+ SolverResults: The results of the solver
70
+ """
71
+
72
+
73
+ class PersistentSolver:
74
+ """Defines a schema for a persistent solver class.
75
+
76
+ Can be used when reinitializing the solver every time the problem is changed is not practical.
77
+ """
78
+
79
+ evaluator: object
80
+ problem: Problem
81
+
82
+ def __init__(self, problem: Problem, options: dict[str, any] | None = None):
83
+ """Initializer for the persistent solver.
84
+
85
+ Args:
86
+ problem (Problem): The problem for the solver.
87
+ options (dict[str,any]): Dictionary of parameters to set.
88
+ What these should be depends on the solver used.
89
+ """
90
+ self.problem = problem
91
+
92
+ def add_constraint(self, constraint: Constraint | list[Constraint]):
93
+ """Add a constraint expression to the solver.
94
+
95
+ Args:
96
+ constraint (Constraint): the constraint function expression.
97
+ """
98
+
99
+ def add_objective(self, objective: Objective):
100
+ """Adds an objective function expression to the solver.
101
+
102
+ Args:
103
+ objective (Objective): an objective function expression to be added.
104
+ """
105
+
106
+ def add_scalarization_function(self, scalarization: ScalarizationFunction):
107
+ """Adds a scalrization expression to the solver.
108
+
109
+ Args:
110
+ scalarization (ScalarizationFunction): A scalarization function to be added.
111
+ """
112
+
113
+ def add_variable(self, variable: Variable):
114
+ """Add a variable to the solver.
115
+
116
+ Args:
117
+ variable (Variable): The definition of the variable to be added.
118
+ """
119
+
120
+ def remove_constraint(self, symbol: str):
121
+ """Removes a constraint from the solver.
122
+
123
+ Args:
124
+ symbol (str): a str representing the symbol of the constraint to be removed.
125
+ """
126
+
127
+ def remove_variable(self, symbol: str):
128
+ """Removes a variable from the model.
129
+
130
+ Args:
131
+ symbol (str): a str representing the symbol of the variable to be removed.
132
+ """
133
+
134
+ def solve(self, target: str) -> SolverResults:
135
+ """Solves the current problem with the specified target.
136
+
137
+ Args:
138
+ target (str): a str representing the symbol of the target function.
139
+
140
+ Returns:
141
+ SolverResults: The results of the solver
142
+ """
143
+
144
+
145
+ SolverOptions = TypeVar("SolverOptions", bound=Any)
@@ -0,0 +1,258 @@
1
+ """Defines solver interfaces for gurobipy."""
2
+
3
+ import gurobipy as gp
4
+
5
+ from desdeo.problem import (
6
+ Constraint,
7
+ GurobipyEvaluator,
8
+ Objective,
9
+ Problem,
10
+ ScalarizationFunction,
11
+ TensorVariable,
12
+ Variable,
13
+ )
14
+ from desdeo.tools.generics import BaseSolver, PersistentSolver, SolverResults
15
+
16
+
17
+ def parse_gurobipy_optimizer_results(problem: Problem, evaluator: GurobipyEvaluator) -> SolverResults:
18
+ """Parses results from GurobipyEvaluator's model into DESDEO SolverResults.
19
+
20
+ Args:
21
+ problem (Problem): the problem being solved.
22
+ evaluator (GurobipyEvaluator): the evaluator utilized to solve the problem.
23
+
24
+ Returns:
25
+ SolverResults: DESDEO solver results.
26
+ """
27
+ results = evaluator.get_values()
28
+
29
+ variable_values = {var.symbol: results[var.symbol] for var in problem.variables}
30
+ objective_values = {obj.symbol: results[obj.symbol] for obj in problem.objectives}
31
+ constraint_values = (
32
+ {con.symbol: results[con.symbol] for con in problem.constraints} if problem.constraints is not None else None
33
+ )
34
+ extra_func_values = (
35
+ {extra.symbol: results[extra.symbol] for extra in problem.extra_funcs}
36
+ if problem.extra_funcs is not None
37
+ else None
38
+ )
39
+ scalarization_values = (
40
+ {scal.symbol: results[scal.symbol] for scal in problem.scalarization_funcs}
41
+ if problem.scalarization_funcs is not None
42
+ else None
43
+ )
44
+ success = evaluator.model.status == gp.GRB.OPTIMAL
45
+ if evaluator.model.status == gp.GRB.OPTIMAL:
46
+ status = "Optimal solution found."
47
+ elif evaluator.model.status == gp.GRB.INFEASIBLE:
48
+ status = "Model is infeasible."
49
+ elif evaluator.model.status == gp.GRB.UNBOUNDED:
50
+ status = "Model is unbounded."
51
+ elif evaluator.model.status == gp.GRB.INF_OR_UNBD:
52
+ status = "Model is either infeasible or unbounded."
53
+ else:
54
+ status = f"Optimization ended with status: {evaluator.model.status}"
55
+ msg = f"Gurobipy solver status is: '{status}'"
56
+
57
+ return SolverResults(
58
+ optimal_variables=variable_values,
59
+ optimal_objectives=objective_values,
60
+ constraint_values=constraint_values,
61
+ extra_func_values=extra_func_values,
62
+ scalarization_values=scalarization_values,
63
+ success=success,
64
+ message=msg,
65
+ )
66
+
67
+
68
+ class GurobipySolver(BaseSolver):
69
+ """Creates a gurobipy solver that utilizes gurobi's own Python implementation."""
70
+
71
+ def __init__(self, problem: Problem, options: dict[str, any] | None = None):
72
+ """The solver is initialized by supplying a problem and options.
73
+
74
+ Unlike with Pyomo you do not need to have gurobi installed on your system
75
+ for this to work. Suitable for solving mixed-integer linear and quadratic optimization
76
+ problems.
77
+
78
+ Args:
79
+ problem (Problem): the problem to be solved.
80
+ options (dict[str,any]): Dictionary of Gurobi parameters to set.
81
+ You probably don't need to set any of these and can just use the defaults.
82
+ For available parameters see https://www.gurobi.com/documentation/current/refman/parameters.html
83
+ """
84
+ self.evaluator = GurobipyEvaluator(problem)
85
+ self.problem = problem
86
+
87
+ if options is not None:
88
+ for key, value in options.items():
89
+ self.evaluator.model.setParam(key, value)
90
+
91
+ def solve(self, target: str) -> SolverResults:
92
+ """Solve the problem for the given target.
93
+
94
+ Args:
95
+ target (str): the symbol of the function to be optimized, and which is
96
+ defined in the problem given when initializing the solver.
97
+
98
+ Returns:
99
+ SolverResults: the results of the optimization.
100
+ """
101
+ self.evaluator.set_optimization_target(target)
102
+ self.evaluator.model.optimize()
103
+ return parse_gurobipy_optimizer_results(self.problem, self.evaluator)
104
+
105
+
106
+ class PersistentGurobipySolver(PersistentSolver):
107
+ """A persistent solver class utlizing gurobipy.
108
+
109
+ Use this instead of create_gurobipy_solver when re-initializing the
110
+ solver every time the problem is changed is not practical.
111
+ """
112
+
113
+ evaluator: GurobipyEvaluator
114
+
115
+ def __init__(self, problem: Problem, options: dict[str, any] | None = None):
116
+ """Initializer for the persistent solver.
117
+
118
+ Args:
119
+ problem (Problem): the problem to be transformed in a GurobipyModel.
120
+ options (dict[str,any]): Dictionary of Gurobi parameters to set.
121
+ You probably don't need to set any of these and can just use the defaults.
122
+ For available parameters see https://www.gurobi.com/documentation/current/refman/parameters.html
123
+ """
124
+ self.problem = problem
125
+ self.evaluator = GurobipyEvaluator(problem)
126
+ if options is not None:
127
+ for key, value in options.items():
128
+ self.evaluator.model.setParam(key, value)
129
+
130
+ def add_constraint(self, constraint: Constraint | list[Constraint]) -> gp.Constr | list[gp.Constr]:
131
+ """Add one or more constraint expressions to the solver.
132
+
133
+ If adding a lot of constraints or dealing with a large model, this function
134
+ may end up being very slow compared to adding the constraints to the model
135
+ stored in the evaluator directly.
136
+
137
+ Args:
138
+ constraint (Constraint): the constraint function expression or a list of
139
+ constraint function expressions.
140
+
141
+ Raises:
142
+ GurobipyEvaluatorError: when an unsupported constraint type is encountered.
143
+
144
+ Returns:
145
+ gurobipy.Constr: The gurobipy constraint that was added or a list of gurobipy
146
+ constraints if the constraint argument was a list.
147
+ """
148
+ if isinstance(constraint, list):
149
+ cons_list = list[gp.Constr]
150
+ for cons in constraint:
151
+ cons_list.append(self.evaluator.add_constraint(cons))
152
+ return cons_list
153
+
154
+ return self.evaluator.add_constraint(constraint)
155
+
156
+ def add_objective(self, objective: Objective | list[Objective]):
157
+ """Adds an objective function expression to the solver.
158
+
159
+ Does not yet add any actual gurobipy optimization objectives, only adds them to the dict
160
+ containing the expressions of the objectives. The objective expressions are stored in the
161
+ evaluator and the evaluator must add the appropiate gurobipy objective before solving.
162
+
163
+ Args:
164
+ objective (Objective): an objective function expression or a list of objective function
165
+ expressions to be added.
166
+ """
167
+ if not isinstance(objective, list):
168
+ objective = [objective]
169
+
170
+ for obj in objective:
171
+ self.evaluator.add_objective(obj)
172
+
173
+ def add_scalarization_function(self, scalarization: ScalarizationFunction | list[ScalarizationFunction]):
174
+ """Adds a scalrization expression to the solver.
175
+
176
+ Scalarizations work identically to objectives, except they are stored in a different
177
+ dict in the evaluator. If you want to solve the problem using a scalarization, the
178
+ evaluator needs to set it as an optimization target first.
179
+
180
+ Args:
181
+ scalarization (ScalarizationFunction): A scalarization function or a list of
182
+ scalarization functions to be added.
183
+ """
184
+ if not isinstance(scalarization, list):
185
+ scalarization = [scalarization]
186
+
187
+ for scal in scalarization:
188
+ self.evaluator.add_scalarization_function(scal)
189
+
190
+ def add_variable(
191
+ self, variable: Variable | TensorVariable | list[Variable] | list[TensorVariable]
192
+ ) -> gp.Var | gp.MVar | list[gp.Var] | list[gp.MVar]:
193
+ """Add one or more variables to the solver.
194
+
195
+ If adding a lot of variables or dealing with a large model, this function
196
+ may end up being very slow compared to adding the variables to the model
197
+ stored in the evaluator directly.
198
+
199
+ Args:
200
+ variable (Variable): The definition of the variable or a list of variables to be added.
201
+
202
+ Raises:
203
+ GurobipyEvaluatorError: when a problem in extracting the variables is encountered.
204
+ I.e., the variables are of a non supported type.
205
+
206
+ Returns:
207
+ gp.Var: the variable that was added to the model or a list of variables if
208
+ variable argument was a list.
209
+ """
210
+ if isinstance(variable, list):
211
+ var_list = list[gp.Var | gp.MVar]
212
+ for var in variable:
213
+ var_list.append(self.evaluator.add_variable(var))
214
+ return var_list
215
+
216
+ return self.evaluator.add_variable(variable)
217
+
218
+ def remove_constraint(self, symbol: str | list[str]):
219
+ """Removes a constraint from the solver.
220
+
221
+ If removing a lot of constraints or dealing with a very large model this function
222
+ may be slow because of the model.update() calls. Accessing the model stored in the
223
+ evaluator directly may be faster.
224
+
225
+ Args:
226
+ symbol (str): a str representing the symbol of the constraint to be removed.
227
+ Can also be a list of multiple symbols.
228
+ """
229
+ if not isinstance(symbol, list):
230
+ symbol = [symbol]
231
+ for s in symbol:
232
+ self.evaluator.remove_constraint(s)
233
+
234
+ def remove_variable(self, symbol: str | list[str]):
235
+ """Removes a variable from the model.
236
+
237
+ If removing a lot of variables or dealing with a very large model this function
238
+ may be slow because of the model.update() calls. Accessing the model stored in
239
+ the evaluator directly may be faster.
240
+
241
+ Args:
242
+ symbol (str): a str representing the symbol of the variable to be removed.
243
+ Can also be a list of multiple symbols.
244
+ """
245
+ self.evaluator.remove_variable(symbol)
246
+
247
+ def solve(self, target: str) -> SolverResults:
248
+ """Solves the current problem with the specified target.
249
+
250
+ Args:
251
+ target (str): a str representing the symbol of the target function.
252
+
253
+ Returns:
254
+ SolverResults: The results of the solver
255
+ """
256
+ self.evaluator.set_optimization_target(target)
257
+ self.evaluator.model.optimize()
258
+ return parse_gurobipy_optimizer_results(self.problem, self.evaluator)
@@ -0,0 +1,11 @@
1
+ """This module implements unary indicators that can be used to compare two solution sets.
2
+
3
+ It assumes that the solution set has been normalized just that _some_ ideal point (not necessarily the ideal point
4
+ of the set) is the origin and _some_ nadir point (not necessarily the nadir point of the set) is (1, 1, ..., 1).
5
+ The normalized solution set is assumed to be inside the bounding box [0, 1]^k where k is the number of objectives.
6
+ If these conditions are not met, the results of the indicators will not be meaningful.
7
+
8
+ Additionally, the set may be assumed to only contain mutually non-dominated solutions, depending on the indicator.
9
+
10
+ For now, we rely on pymoo for the implementation of many of the indicators.
11
+ """