15"""Solve optimization problems, as defined by Model in model.py."""
17from typing
import Callable, Optional
32from pybind11_abseil.status
import StatusNotOk
38 opt_model: model.Model,
43 msg_cb: Optional[message_callback.SolveMessageCallback] =
None,
45 cb: Optional[SolveCallback] =
None,
47 remove_names: bool =
False,
50 """Solves an optimization model.
52 Thread-safety: this function must not be called while modifying the Model
53 (adding variables...). Some solvers may add more restriction regarding
54 threading. Please see SolverType::XXX documentation for details.
57 opt_model: The optimization model.
58 solver_type: The underlying solver to use.
59 params: Configuration of the underlying solver.
60 model_params: Configuration of the solver that is model specific.
61 msg_cb: A callback that gives back the underlying solver's logs by the line.
62 callback_reg: Configures when the callback will be invoked (if provided) and
63 what data will be collected to access in the callback.
64 cb: A callback that will be called periodically as the solver runs.
65 streamable_init_args: Configuration for initializing the underlying solver.
66 remove_names: When true, remove all names for the ModelProto.
67 interrupter: An optional interrupter that the solver can use to interrupt
71 A SolveResult containing the termination reason, solution(s) and stats.
74 RuntimeError: On a solve error.
81 streamable_init_args = (
84 model_proto = opt_model.export_model(remove_names=remove_names)
87 proto_cb =
lambda x: cb(
88 callback.parse_callback_data(x, opt_model)
92 proto_result = solver.solve(
95 streamable_init_args.to_proto(),
97 model_params.to_proto(),
99 callback_reg.to_proto(),
101 interrupter.pybind_interrupter
if interrupter
is not None else None,
103 except StatusNotOk
as e:
105 return result.parse_solve_result(proto_result, opt_model, validate=
False)
109 opt_model: model.Model,
113 msg_cb: Optional[message_callback.SolveMessageCallback] =
None,
115 remove_names: bool =
False,
118 """Computes an infeasible subsystem of the input model.
121 opt_model: The optimization model to check for infeasibility.
122 solver_type: Which solver to use to compute the infeasible subsystem. As of
123 August 2023, the only supported solver is Gurobi.
124 params: Configuration of the underlying solver.
125 msg_cb: A callback that gives back the underlying solver's logs by the line.
126 streamable_init_args: Configuration for initializing the underlying solver.
127 remove_names: When true, remove all names for the ModelProto.
128 interrupter: An optional interrupter that the solver can use to interrupt
132 An `ComputeInfeasibleSubsystemResult` where `feasibility` indicates if the
133 problem was proven infeasible.
136 RuntimeError: on invalid inputs or an internal solver error.
139 streamable_init_args = (
142 model_proto = opt_model.export_model(remove_names=remove_names)
145 proto_result = solver.compute_infeasible_subsystem(
148 streamable_init_args.to_proto(),
151 interrupter.pybind_interrupter
if interrupter
is not None else None,
153 except StatusNotOk
as e:
156 compute_infeasible_subsystem_result.parse_compute_infeasible_subsystem_result(
157 proto_result, opt_model
163 """Solve an optimization multiple times, with modifications between solves.
165 Prefer calling simply solve() above in most cases when incrementalism is not
168 Thread-safety: The __init__(), solve() methods must not be called while
169 modifying the Model (adding variables...). The user is expected to use proper
170 synchronization primitives to serialize changes to the model and the use of
171 this object. Note though that it is safe to call methods from different
172 IncrementalSolver instances on the same Model concurrently. The solve() method
173 must not be called concurrently on different threads for the same
174 IncrementalSolver. Some solvers may add more restriction regarding
175 threading. Please see to SolverType::XXX documentation for details.
177 This class references some resources that are freed when it is garbage
178 collected (which should usually happen when the last reference is lost). In
179 particular, it references some C++ objects. Although it is not mandatory, it
180 is recommended to free those as soon as possible. To do so it is possible to
181 use this class in the `with` statement:
183 with IncrementalSolver(model, SolverType.GLOP) as solver:
186 When it is not possible to use `with`, the close() method can be called.
191 opt_model: model.Model,
194 streamable_init_args: Optional[
197 remove_names: bool =
False,
199 streamable_init_args = (
208 self.
_model.export_model(remove_names=remove_names),
209 streamable_init_args.to_proto(),
211 except StatusNotOk
as e:
220 msg_cb: Optional[message_callback.SolveMessageCallback] =
None,
222 cb: Optional[SolveCallback] =
None,
225 """Solves the current optimization model.
228 params: The non-model specific solve parameters.
229 model_params: The model specific solve parameters.
230 msg_cb: An optional callback for solver messages.
231 callback_reg: The parameters controlling when cb is called.
232 cb: An optional callback for LP/MIP events.
233 interrupter: An optional interrupter that the solver can use to interrupt
237 The result of the solve.
240 RuntimeError: If called after being closed, or on a solve error.
243 raise RuntimeError(
"the solver is closed")
246 if update
is not None:
251 self.
_model.export_model(),
252 parameters_pb2.SolverInitializerProto(),
254 except StatusNotOk
as e:
262 proto_cb =
lambda x: cb(
263 callback.parse_callback_data(x, self.
_model)
268 model_params.to_proto(),
270 callback_reg.to_proto(),
272 interrupter.pybind_interrupter
if interrupter
is not None else None,
274 except StatusNotOk
as e:
276 return result.parse_solve_result(result_proto, self.
_model, validate=
False)
279 """Closes this solver, freeing all its resources.
281 This is optional, the code is correct without calling this function. See the
282 class documentation for details.
284 After a solver has been closed, it can't be used anymore. Prefer using the
285 context manager API when possible instead of calling close() directly:
287 with IncrementalSolver(model, SolverType.GLOP) as solver:
300 """Returns the solver itself."""
305 exc_type: Optional[type[BaseException]],
306 exc_val: Optional[BaseException],
307 exc_tb: Optional[types.TracebackType],
309 """Closes the solver."""
314 """Converts a StatusNotOk to the best matching Python exception.
317 err: The input errors.
320 The corresponding exception.
322 ret = errors.status_proto_to_exception(
323 rpc_pb2.StatusProto(code=err.canonical_code, message=err.message)
326 assert ret
is not None, err