desdeo 1.1.3__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.
- desdeo/__init__.py +8 -8
- desdeo/api/README.md +73 -0
- desdeo/api/__init__.py +15 -0
- desdeo/api/app.py +40 -0
- desdeo/api/config.py +69 -0
- desdeo/api/config.toml +53 -0
- desdeo/api/db.py +25 -0
- desdeo/api/db_init.py +79 -0
- desdeo/api/db_models.py +164 -0
- desdeo/api/malaga_db_init.py +27 -0
- desdeo/api/models/__init__.py +66 -0
- desdeo/api/models/archive.py +34 -0
- desdeo/api/models/preference.py +90 -0
- desdeo/api/models/problem.py +507 -0
- desdeo/api/models/reference_point_method.py +18 -0
- desdeo/api/models/session.py +46 -0
- desdeo/api/models/state.py +96 -0
- desdeo/api/models/user.py +51 -0
- desdeo/api/routers/_NAUTILUS.py +245 -0
- desdeo/api/routers/_NAUTILUS_navigator.py +233 -0
- desdeo/api/routers/_NIMBUS.py +762 -0
- desdeo/api/routers/__init__.py +5 -0
- desdeo/api/routers/problem.py +110 -0
- desdeo/api/routers/reference_point_method.py +117 -0
- desdeo/api/routers/session.py +76 -0
- desdeo/api/routers/test.py +16 -0
- desdeo/api/routers/user_authentication.py +366 -0
- desdeo/api/schema.py +94 -0
- desdeo/api/tests/__init__.py +0 -0
- desdeo/api/tests/conftest.py +59 -0
- desdeo/api/tests/test_models.py +701 -0
- desdeo/api/tests/test_routes.py +216 -0
- desdeo/api/utils/database.py +274 -0
- desdeo/api/utils/logger.py +29 -0
- desdeo/core.py +27 -0
- desdeo/emo/__init__.py +29 -0
- desdeo/emo/hooks/archivers.py +172 -0
- desdeo/emo/methods/EAs.py +418 -0
- desdeo/emo/methods/__init__.py +0 -0
- desdeo/emo/methods/bases.py +59 -0
- desdeo/emo/operators/__init__.py +1 -0
- desdeo/emo/operators/crossover.py +780 -0
- desdeo/emo/operators/evaluator.py +118 -0
- desdeo/emo/operators/generator.py +356 -0
- desdeo/emo/operators/mutation.py +1053 -0
- desdeo/emo/operators/selection.py +1036 -0
- desdeo/emo/operators/termination.py +178 -0
- desdeo/explanations/__init__.py +6 -0
- desdeo/explanations/explainer.py +100 -0
- desdeo/explanations/utils.py +90 -0
- desdeo/mcdm/__init__.py +19 -0
- desdeo/mcdm/nautili.py +345 -0
- desdeo/mcdm/nautilus.py +477 -0
- desdeo/mcdm/nautilus_navigator.py +655 -0
- desdeo/mcdm/nimbus.py +417 -0
- desdeo/mcdm/pareto_navigator.py +269 -0
- desdeo/mcdm/reference_point_method.py +116 -0
- desdeo/problem/__init__.py +79 -0
- desdeo/problem/evaluator.py +561 -0
- desdeo/problem/gurobipy_evaluator.py +562 -0
- desdeo/problem/infix_parser.py +341 -0
- desdeo/problem/json_parser.py +944 -0
- desdeo/problem/pyomo_evaluator.py +468 -0
- desdeo/problem/schema.py +1808 -0
- desdeo/problem/simulator_evaluator.py +298 -0
- desdeo/problem/sympy_evaluator.py +244 -0
- desdeo/problem/testproblems/__init__.py +73 -0
- desdeo/problem/testproblems/binh_and_korn_problem.py +88 -0
- desdeo/problem/testproblems/dtlz2_problem.py +102 -0
- desdeo/problem/testproblems/forest_problem.py +275 -0
- desdeo/problem/testproblems/knapsack_problem.py +163 -0
- desdeo/problem/testproblems/mcwb_problem.py +831 -0
- desdeo/problem/testproblems/mixed_variable_dimenrions_problem.py +83 -0
- desdeo/problem/testproblems/momip_problem.py +172 -0
- desdeo/problem/testproblems/nimbus_problem.py +143 -0
- desdeo/problem/testproblems/pareto_navigator_problem.py +89 -0
- desdeo/problem/testproblems/re_problem.py +492 -0
- desdeo/problem/testproblems/river_pollution_problem.py +434 -0
- desdeo/problem/testproblems/rocket_injector_design_problem.py +140 -0
- desdeo/problem/testproblems/simple_problem.py +351 -0
- desdeo/problem/testproblems/simulator_problem.py +92 -0
- desdeo/problem/testproblems/spanish_sustainability_problem.py +945 -0
- desdeo/problem/testproblems/zdt_problem.py +271 -0
- desdeo/problem/utils.py +245 -0
- desdeo/tools/GenerateReferencePoints.py +181 -0
- desdeo/tools/__init__.py +102 -0
- desdeo/tools/generics.py +145 -0
- desdeo/tools/gurobipy_solver_interfaces.py +258 -0
- desdeo/tools/indicators_binary.py +11 -0
- desdeo/tools/indicators_unary.py +375 -0
- desdeo/tools/interaction_schema.py +38 -0
- desdeo/tools/intersection.py +54 -0
- desdeo/tools/iterative_pareto_representer.py +99 -0
- desdeo/tools/message.py +234 -0
- desdeo/tools/ng_solver_interfaces.py +199 -0
- desdeo/tools/non_dominated_sorting.py +133 -0
- desdeo/tools/patterns.py +281 -0
- desdeo/tools/proximal_solver.py +99 -0
- desdeo/tools/pyomo_solver_interfaces.py +464 -0
- desdeo/tools/reference_vectors.py +462 -0
- desdeo/tools/scalarization.py +3138 -0
- desdeo/tools/scipy_solver_interfaces.py +454 -0
- desdeo/tools/score_bands.py +464 -0
- desdeo/tools/utils.py +320 -0
- desdeo/utopia_stuff/__init__.py +0 -0
- desdeo/utopia_stuff/data/1.json +15 -0
- desdeo/utopia_stuff/data/2.json +13 -0
- desdeo/utopia_stuff/data/3.json +15 -0
- desdeo/utopia_stuff/data/4.json +17 -0
- desdeo/utopia_stuff/data/5.json +15 -0
- desdeo/utopia_stuff/from_json.py +40 -0
- desdeo/utopia_stuff/reinit_user.py +38 -0
- desdeo/utopia_stuff/utopia_db_init.py +212 -0
- desdeo/utopia_stuff/utopia_problem.py +403 -0
- desdeo/utopia_stuff/utopia_problem_old.py +415 -0
- desdeo/utopia_stuff/utopia_reference_solutions.py +79 -0
- desdeo-2.0.0.dist-info/LICENSE +21 -0
- desdeo-2.0.0.dist-info/METADATA +168 -0
- desdeo-2.0.0.dist-info/RECORD +120 -0
- {desdeo-1.1.3.dist-info → desdeo-2.0.0.dist-info}/WHEEL +1 -1
- desdeo-1.1.3.dist-info/METADATA +0 -18
- desdeo-1.1.3.dist-info/RECORD +0 -4
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
"""Defines solver interfaces for pyomo."""
|
|
2
|
+
|
|
3
|
+
import itertools
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pyomo.environ as pyomo
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
8
|
+
from pyomo.opt import SolverResults as _pyomo_SolverResults
|
|
9
|
+
from pyomo.opt import SolverStatus as _pyomo_SolverStatus
|
|
10
|
+
from pyomo.opt import TerminationCondition as _pyomo_TerminationCondition
|
|
11
|
+
|
|
12
|
+
from desdeo.problem import Problem, PyomoEvaluator, TensorVariable
|
|
13
|
+
from desdeo.tools.generics import BaseSolver, SolverError, SolverResults
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BonminOptions(BaseModel):
|
|
17
|
+
"""Defines a pydantic model to store and pass options to the Bonmin solver.
|
|
18
|
+
|
|
19
|
+
Because Bonmin utilizes many sub-solver, the options specific to Bonmin
|
|
20
|
+
must be prefixed in their name with 'bonmin.{option_name}',
|
|
21
|
+
e.g., `bonmin.integer_tolerance`. For a list of options, see
|
|
22
|
+
https://www.coin-or.org/Bonmin/options_list.html
|
|
23
|
+
|
|
24
|
+
Note:
|
|
25
|
+
Not all options are available through this model.
|
|
26
|
+
Please add options as they are needed and make a pull request.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
tol: float = Field(description="Sets the convergence tolerance of ipopt. Defaults to 1e-8.", default=1e-8)
|
|
30
|
+
"""Sets the convergence tolerance of ipopt. Defaults to 1e-8."""
|
|
31
|
+
|
|
32
|
+
bonmin_integer_tolerance: float = Field(
|
|
33
|
+
description="Numbers within this value of an integer are considered integers. Defaults to 1e-6.", default=1e-6
|
|
34
|
+
)
|
|
35
|
+
"""Numbers within this value of an integer are considered integers. Defaults to 1e-6."""
|
|
36
|
+
|
|
37
|
+
bonmin_algorithm: str = Field(
|
|
38
|
+
description=(
|
|
39
|
+
"Presets some of the options in Bonmin based on the algorithm choice. Defaults to 'B-BB'. "
|
|
40
|
+
"A good first option to try is 'B-Hyb'."
|
|
41
|
+
),
|
|
42
|
+
default="B-BB",
|
|
43
|
+
)
|
|
44
|
+
"""Presets some of the options in Bonmin based on the algorithm choice. Defaults to 'B-BB'.
|
|
45
|
+
A good first option to try is 'B-Hyb'.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def asdict(self) -> dict[str, float]:
|
|
49
|
+
"""Converts the Pydantic model into a dict so that Bonmin specific options are in the correct format.
|
|
50
|
+
|
|
51
|
+
This means that the attributes starting with `bonmin_optionname` will be
|
|
52
|
+
converted to keys in the format `bonmin.optionname` in the returned dict.
|
|
53
|
+
"""
|
|
54
|
+
output = {}
|
|
55
|
+
for field_name, _ in BonminOptions.model_fields.items():
|
|
56
|
+
if (rest := field_name.split(sep="_"))[0] == "bonmin":
|
|
57
|
+
# Convert to Bonmin specific format
|
|
58
|
+
output[f"bonmin.{'_'.join(rest[1:])}"] = getattr(self, field_name)
|
|
59
|
+
else:
|
|
60
|
+
# Keep the field as is
|
|
61
|
+
output[field_name] = getattr(self, field_name)
|
|
62
|
+
|
|
63
|
+
return output
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class IpoptOptions(BaseModel):
|
|
67
|
+
"""Defines a pydantic dataclass to pass options to the Ipopt solver.
|
|
68
|
+
|
|
69
|
+
For more information and documentation on the options,
|
|
70
|
+
see https://coin-or.github.io/Ipopt/
|
|
71
|
+
|
|
72
|
+
Note:
|
|
73
|
+
Not all options are available through this model.
|
|
74
|
+
Please add options as they are needed and make a pull request.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
tol: float = Field(description="The desired relative convergence tolerance. Defaults to 1e-8.", default=1e-8)
|
|
78
|
+
"""The desired relative convergence tolerance. Defaults to 1e-8."""
|
|
79
|
+
|
|
80
|
+
max_iter: int = Field(description="Maximum number of iterations. Must be >1. Defaults to 3000.", default=3000)
|
|
81
|
+
"""Maximum number of iterations. Must be >1. Defaults to 3000."""
|
|
82
|
+
|
|
83
|
+
print_level: str = Field(
|
|
84
|
+
description="The verbosity level of the solver's output. Ranges between 0 and 12. Defaults to 5.", default=5
|
|
85
|
+
)
|
|
86
|
+
"""The verbosity level of the solver's output. Ranges between 0 and 12."""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class CbcOptions(BaseModel):
|
|
90
|
+
"""Defines a pydantic dataclass to pass options to the CBC solver.
|
|
91
|
+
|
|
92
|
+
For more information and documentation on the options,
|
|
93
|
+
see https://github.com/coin-or/Cbc
|
|
94
|
+
|
|
95
|
+
Note:
|
|
96
|
+
Not all options are available through this model.
|
|
97
|
+
Please add options as they are needed and make a pull request.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
model_config = ConfigDict(frozen=True, populate_by_name=True)
|
|
101
|
+
|
|
102
|
+
sec: int = Field(
|
|
103
|
+
description="The maximum amount of time (in seconds) the solver should run. Defaults to None.", default=None
|
|
104
|
+
)
|
|
105
|
+
"""The maximum amount of time (in seconds) the solver should run. Defaults to None."""
|
|
106
|
+
|
|
107
|
+
threads: int = Field(
|
|
108
|
+
description="Number of threads (cores) to use for solving the problem. Defaults to 1.", default=1
|
|
109
|
+
)
|
|
110
|
+
"""Number of threads (cores) to use for solving the problem. Defaults to 1."""
|
|
111
|
+
|
|
112
|
+
log_level: int = Field(
|
|
113
|
+
alias="logLevel",
|
|
114
|
+
description=(
|
|
115
|
+
"Controls the level of logging output. Values range from 0 (no output) to 5 (very detailed output)."
|
|
116
|
+
" Defaults to 1."
|
|
117
|
+
),
|
|
118
|
+
default=1,
|
|
119
|
+
)
|
|
120
|
+
"""Controls the level of logging output. Values range from 0 (no output) to 5 (very detailed output).
|
|
121
|
+
Defaults to 1.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
max_solutions: int = Field(
|
|
125
|
+
alias="maxSolutions",
|
|
126
|
+
description="Limits the number of feasible solutions found by the solver. Defaults to None.",
|
|
127
|
+
default=None,
|
|
128
|
+
)
|
|
129
|
+
"""Limits the number of feasible solutions found by the solver. Defaults to None."""
|
|
130
|
+
|
|
131
|
+
max_nodes: int = Field(
|
|
132
|
+
alias="maxNodes",
|
|
133
|
+
description="Sets the maximum number of branch-and-bound nodes to explore. Defaults to None.",
|
|
134
|
+
default=None,
|
|
135
|
+
)
|
|
136
|
+
"""Sets the maximum number of branch-and-bound nodes to explore. Defaults to None."""
|
|
137
|
+
|
|
138
|
+
ratio_gap: float = Field(
|
|
139
|
+
alias="ratioGap",
|
|
140
|
+
description=(
|
|
141
|
+
"Sets the relative MIP gap (as a fraction of the optimal solution value) at which the solver will"
|
|
142
|
+
" terminate. Defaults to None."
|
|
143
|
+
),
|
|
144
|
+
default=None,
|
|
145
|
+
)
|
|
146
|
+
"""Sets the relative MIP gap (as a fraction of the optimal solution value) at which the solver will terminate.
|
|
147
|
+
Defaults to None.
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
absolute_gap: float = Field(
|
|
151
|
+
alias="absoluteGap",
|
|
152
|
+
description=(
|
|
153
|
+
"Sets the absolute MIP gap (an absolute value) at which the solver will terminate. Defaults to None."
|
|
154
|
+
),
|
|
155
|
+
default=None,
|
|
156
|
+
)
|
|
157
|
+
"""Sets the absolute MIP gap (an absolute value) at which the solver will terminate. Defaults to None."""
|
|
158
|
+
|
|
159
|
+
solve: str = Field(
|
|
160
|
+
description=(
|
|
161
|
+
"Determines the strategy to use for solving the problem (e.g., 'branchAndCut', 'tree', 'trunk')."
|
|
162
|
+
" Defaults to 'branchAndCut'."
|
|
163
|
+
),
|
|
164
|
+
default="branchAndCut",
|
|
165
|
+
)
|
|
166
|
+
"""Determines the strategy to use for solving the problem (e.g., 'branchAndCut', 'tree', 'trunk').
|
|
167
|
+
Defaults to 'branchAndCut'.
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
presolve: int = Field(
|
|
171
|
+
description="Controls the presolve level (0: no presolve, 1: default, 2: aggressive). Defaults to 1.", default=1
|
|
172
|
+
)
|
|
173
|
+
"""Controls the presolve level (0: no presolve, 1: default, 2: aggressive). Defaults to 1."""
|
|
174
|
+
|
|
175
|
+
feasibility_tolerance: float = Field(
|
|
176
|
+
alias="feasibilityTolerance",
|
|
177
|
+
description="Sets the feasibility tolerance for constraints. Defaults to 1e-6.",
|
|
178
|
+
default=1e-6,
|
|
179
|
+
)
|
|
180
|
+
"""Sets the feasibility tolerance for constraints. Defaults to 1e-6."""
|
|
181
|
+
|
|
182
|
+
integer_tolerance: float = Field(
|
|
183
|
+
alias="integerTolerance",
|
|
184
|
+
description="Sets the tolerance for integrality of integer variables. Defaults to 1e-5.",
|
|
185
|
+
default=1e-5,
|
|
186
|
+
)
|
|
187
|
+
"""Sets the tolerance for integrality of integer variables. Defaults to 1e-5."""
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
_default_cbc_options = CbcOptions(
|
|
191
|
+
sec=600,
|
|
192
|
+
threads=4,
|
|
193
|
+
logLevel=2,
|
|
194
|
+
maxSolutions=10,
|
|
195
|
+
maxNodes=1000,
|
|
196
|
+
ratioGap=0.01,
|
|
197
|
+
absoluteGap=1.0,
|
|
198
|
+
solve="branchAndCut",
|
|
199
|
+
presolve=2,
|
|
200
|
+
feasibilityTolerance=1e-6,
|
|
201
|
+
integerTolerance=1e-5,
|
|
202
|
+
)
|
|
203
|
+
"""Defines CBC options with default values."""
|
|
204
|
+
|
|
205
|
+
_default_bonmin_options = BonminOptions()
|
|
206
|
+
"""Defines Bonmin options with default values."""
|
|
207
|
+
|
|
208
|
+
_default_ipopt_options = IpoptOptions()
|
|
209
|
+
"""Defines Ipopt optins with default values."""
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def parse_pyomo_optimizer_results(
|
|
213
|
+
opt_res: _pyomo_SolverResults, problem: Problem, evaluator: PyomoEvaluator
|
|
214
|
+
) -> SolverResults:
|
|
215
|
+
"""Parses pyomo SolverResults into DESDEO SolverResults.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
opt_res (SolverResults): the pyomo solver results.
|
|
219
|
+
problem (Problem): the problem being solved.
|
|
220
|
+
evaluator (PyomoEvaluator): the evaluator utilized to get the pyomo solver results.
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
SolverResults: DESDEO solver results.
|
|
224
|
+
"""
|
|
225
|
+
results = evaluator.get_values()
|
|
226
|
+
|
|
227
|
+
variable_values = {}
|
|
228
|
+
for var in problem.variables:
|
|
229
|
+
if isinstance(var, TensorVariable):
|
|
230
|
+
# handle tensor variables
|
|
231
|
+
# 1-indexing in Pyomo...
|
|
232
|
+
values_list = np.zeros(var.shape)
|
|
233
|
+
for indices in itertools.product(*(range(1, dim + 1) for dim in var.shape)):
|
|
234
|
+
values_list[*[idx - 1 for idx in indices]] = results[var.symbol][
|
|
235
|
+
indices if len(indices) > 1 else indices[0]
|
|
236
|
+
]
|
|
237
|
+
variable_values[var.symbol] = values_list.tolist()
|
|
238
|
+
else:
|
|
239
|
+
# variable_values = {var.symbol: results[var.symbol] for var in problem.variables}
|
|
240
|
+
variable_values[var.symbol] = results[var.symbol]
|
|
241
|
+
|
|
242
|
+
objective_values = {obj.symbol: results[obj.symbol] for obj in problem.objectives}
|
|
243
|
+
constraint_values = (
|
|
244
|
+
{con.symbol: results[con.symbol] for con in problem.constraints} if problem.constraints else None
|
|
245
|
+
)
|
|
246
|
+
extra_func_values = (
|
|
247
|
+
{extra.symbol: results[extra.symbol] for extra in problem.extra_funcs}
|
|
248
|
+
if problem.extra_funcs is not None
|
|
249
|
+
else None
|
|
250
|
+
)
|
|
251
|
+
scalarization_values = (
|
|
252
|
+
{scal.symbol: results[scal.symbol] for scal in problem.scalarization_funcs}
|
|
253
|
+
if problem.scalarization_funcs is not None
|
|
254
|
+
else None
|
|
255
|
+
)
|
|
256
|
+
success = (
|
|
257
|
+
opt_res.solver.status == _pyomo_SolverStatus.ok
|
|
258
|
+
and opt_res.solver.termination_condition == _pyomo_TerminationCondition.optimal
|
|
259
|
+
)
|
|
260
|
+
msg = (
|
|
261
|
+
f"Pyomo solver status is: '{opt_res.solver.status}', with termination condition: "
|
|
262
|
+
f"'{opt_res.solver.termination_condition}'."
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
return SolverResults(
|
|
266
|
+
optimal_variables=variable_values,
|
|
267
|
+
optimal_objectives=objective_values,
|
|
268
|
+
constraint_values=constraint_values,
|
|
269
|
+
extra_func_values=extra_func_values,
|
|
270
|
+
scalarization_values=scalarization_values,
|
|
271
|
+
success=success,
|
|
272
|
+
message=msg,
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
class PyomoBonminSolver(BaseSolver):
|
|
277
|
+
"""Creates pyomo solvers that utilize bonmin."""
|
|
278
|
+
|
|
279
|
+
def __init__(self, problem: Problem, options: BonminOptions | None = _default_bonmin_options):
|
|
280
|
+
"""The solver is initialized with a problem and solver options.
|
|
281
|
+
|
|
282
|
+
Suitable for mixed-integer problems. The objective function being minimized
|
|
283
|
+
(target) and the constraint functions must be twice continuously
|
|
284
|
+
differentiable. When the objective functions and constraints are convex, the
|
|
285
|
+
solution is exact. When the objective or any of the constraints, or both,
|
|
286
|
+
are non-convex, then the solution is based on heuristics.
|
|
287
|
+
|
|
288
|
+
For more info about bonmin, see: https://www.coin-or.org/Bonmin/
|
|
289
|
+
|
|
290
|
+
Note:
|
|
291
|
+
Bonmin must be installed on the system running DESDEO, and its executable
|
|
292
|
+
must be defined in the PATH.
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
problem (Problem): the problem to be solved.
|
|
296
|
+
options (BonminOptions, optional): options to be passed to the Bonmin solver.
|
|
297
|
+
If `None` is passed, defaults to `_default_bonmin_options` defined in
|
|
298
|
+
this source file. Defaults to `None`.
|
|
299
|
+
"""
|
|
300
|
+
if not problem.is_twice_differentiable:
|
|
301
|
+
raise SolverError("Problem must be twice differentiable.")
|
|
302
|
+
self.problem = problem
|
|
303
|
+
self.evaluator = PyomoEvaluator(problem)
|
|
304
|
+
|
|
305
|
+
if options is None:
|
|
306
|
+
self.options = _default_bonmin_options
|
|
307
|
+
else:
|
|
308
|
+
self.options = options
|
|
309
|
+
|
|
310
|
+
def solve(self, target: str) -> SolverResults:
|
|
311
|
+
"""Solve the problem for a given target.
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
target (str): the symbol of the objective function to be optimized.
|
|
315
|
+
|
|
316
|
+
Returns:
|
|
317
|
+
SolverResults: the results of the optimization.
|
|
318
|
+
"""
|
|
319
|
+
self.evaluator.set_optimization_target(target)
|
|
320
|
+
|
|
321
|
+
opt = pyomo.SolverFactory("bonmin", tee=True)
|
|
322
|
+
|
|
323
|
+
# set solver options
|
|
324
|
+
for key, value in self.options.asdict().items():
|
|
325
|
+
opt.options[key] = value
|
|
326
|
+
opt_res = opt.solve(self.evaluator.model)
|
|
327
|
+
|
|
328
|
+
return parse_pyomo_optimizer_results(opt_res, self.problem, self.evaluator)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
class PyomoIpoptSolver(BaseSolver):
|
|
332
|
+
"""Create a pyomo solver that utilizes Ipopt."""
|
|
333
|
+
|
|
334
|
+
def __init__(self, problem: Problem, options: IpoptOptions | None = _default_ipopt_options):
|
|
335
|
+
"""The solver is initialized with a problem and solver options.
|
|
336
|
+
|
|
337
|
+
Suitable for non-linear, twice differentiable constrained problems.
|
|
338
|
+
The problem may be convex or non-convex.
|
|
339
|
+
|
|
340
|
+
For more information, see https://coin-or.github.io/Ipopt/
|
|
341
|
+
|
|
342
|
+
Note:
|
|
343
|
+
Ipopt must be installed on the system running DESDEO, and its executable
|
|
344
|
+
must be defined in the PATH.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
problem (Problem): the problem being solved.
|
|
348
|
+
options (IpoptOptions, optional): options to be passed to the Ipopt solver.
|
|
349
|
+
If `None` is passed, defaults to `_default_ipopt_options` defined in
|
|
350
|
+
this source file. Defaults to `None`.
|
|
351
|
+
"""
|
|
352
|
+
if not problem.is_twice_differentiable:
|
|
353
|
+
raise SolverError("Problem must be twice differentiable.")
|
|
354
|
+
self.problem = problem
|
|
355
|
+
self.evaluator = PyomoEvaluator(problem)
|
|
356
|
+
|
|
357
|
+
if options is None:
|
|
358
|
+
self.options = _default_ipopt_options
|
|
359
|
+
else:
|
|
360
|
+
self.options = options
|
|
361
|
+
|
|
362
|
+
def solve(self, target: str) -> SolverResults:
|
|
363
|
+
"""Solve the problem for a given target.
|
|
364
|
+
|
|
365
|
+
Args:
|
|
366
|
+
target (str): the symbol of the objective function to be optimized.
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
SolverResults: results of the Optimization.
|
|
370
|
+
"""
|
|
371
|
+
self.evaluator.set_optimization_target(target)
|
|
372
|
+
|
|
373
|
+
opt = pyomo.SolverFactory("ipopt", tee=True, options=self.options.model_dump())
|
|
374
|
+
opt_res = opt.solve(self.evaluator.model)
|
|
375
|
+
return parse_pyomo_optimizer_results(opt_res, self.problem, self.evaluator)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
class PyomoGurobiSolver(BaseSolver):
|
|
379
|
+
"""Creates a pyomo solver that utilized Gurobi."""
|
|
380
|
+
|
|
381
|
+
def __init__(self, problem: Problem, options: dict[str, any] | None = None):
|
|
382
|
+
"""Creates a pyomo solver that utilizes gurobi.
|
|
383
|
+
|
|
384
|
+
You need to have gurobi installed on your system for this to work.
|
|
385
|
+
|
|
386
|
+
Suitable for solving mixed-integer linear and quadratic optimization
|
|
387
|
+
problems.
|
|
388
|
+
|
|
389
|
+
Args:
|
|
390
|
+
problem (Problem): the problem to be solved.
|
|
391
|
+
options (GurobiOptions): Dictionary of Gurobi parameters to set.
|
|
392
|
+
This is passed to pyomo as is, so it works the same as options
|
|
393
|
+
would for calling pyomo SolverFactory directly.
|
|
394
|
+
See https://www.gurobi.com/documentation/current/refman/parameters.html
|
|
395
|
+
for information on the available options
|
|
396
|
+
"""
|
|
397
|
+
self.problem = problem
|
|
398
|
+
self.evaluator = PyomoEvaluator(problem)
|
|
399
|
+
|
|
400
|
+
if options is None:
|
|
401
|
+
self.options = {}
|
|
402
|
+
else:
|
|
403
|
+
self.options = options
|
|
404
|
+
|
|
405
|
+
def solve(self, target: str) -> SolverResults:
|
|
406
|
+
"""Solve the problem for a given target.
|
|
407
|
+
|
|
408
|
+
Args:
|
|
409
|
+
target (str): the symbol of the objective function to be optimized.
|
|
410
|
+
|
|
411
|
+
Returns:
|
|
412
|
+
SolverResults: the results of the optimization.
|
|
413
|
+
"""
|
|
414
|
+
self.evaluator.set_optimization_target(target)
|
|
415
|
+
|
|
416
|
+
with pyomo.SolverFactory("gurobi", solver_io="python") as opt:
|
|
417
|
+
opt_res = opt.solve(self.evaluator.model)
|
|
418
|
+
return parse_pyomo_optimizer_results(opt_res, self.problem, self.evaluator)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
class PyomoCBCSolver(BaseSolver):
|
|
422
|
+
"""Create a pyomo solver that utilizes CBC."""
|
|
423
|
+
|
|
424
|
+
def __init__(self, problem: Problem, options: CbcOptions | None = _default_cbc_options):
|
|
425
|
+
"""The solver is initialized with a problem and solver options.
|
|
426
|
+
|
|
427
|
+
Suitable for combinatorial and large-scale mixed-integer linear problems.
|
|
428
|
+
|
|
429
|
+
For more information, see https://coin-or.github.io/Ipopt/
|
|
430
|
+
|
|
431
|
+
Note:
|
|
432
|
+
CBC must be installed on the system running DESDEO, and its executable
|
|
433
|
+
must be defined in the PATH.
|
|
434
|
+
|
|
435
|
+
Args:
|
|
436
|
+
problem (Problem): the problem being solved.
|
|
437
|
+
options (CbcOptions, optional): options to be passed to the CBC solver.
|
|
438
|
+
If `None` is passed, defaults to `_default_cbc_options` defined in
|
|
439
|
+
this source file. Defaults to `None`.
|
|
440
|
+
"""
|
|
441
|
+
if not problem.is_linear:
|
|
442
|
+
raise SolverError("Nonlinear problems not supported.")
|
|
443
|
+
self.problem = problem
|
|
444
|
+
self.evaluator = PyomoEvaluator(problem)
|
|
445
|
+
|
|
446
|
+
if options is None:
|
|
447
|
+
self.options = _default_cbc_options
|
|
448
|
+
else:
|
|
449
|
+
self.options = options
|
|
450
|
+
|
|
451
|
+
def solve(self, target: str) -> SolverResults:
|
|
452
|
+
"""Solve the problem for a given target.
|
|
453
|
+
|
|
454
|
+
Args:
|
|
455
|
+
target (str): the symbol of the objective function to be optimized.
|
|
456
|
+
|
|
457
|
+
Returns:
|
|
458
|
+
SolverResults: results of the Optimization.
|
|
459
|
+
"""
|
|
460
|
+
self.evaluator.set_optimization_target(target)
|
|
461
|
+
|
|
462
|
+
opt = pyomo.SolverFactory("cbc", tee=True, options=self.options.model_dump())
|
|
463
|
+
opt_res = opt.solve(self.evaluator.model)
|
|
464
|
+
return parse_pyomo_optimizer_results(opt_res, self.problem, self.evaluator)
|