-
Notifications
You must be signed in to change notification settings - Fork 78
Description
Currently information about solver state and meta info is split across multiple places:
Model:solver_model,solver_name,status,termination_conditionResult:status,solution,solver_modelSolver: onlysolver_optionsModel.solve(): inlined result-to-model mapping logic (normal, remote, and mock paths each have independent mapping)solver_capabilities.py: global capability lookup- direct conversion entry points live on
Model(delegating tolinopy/io.pyfunctions)
We want to refactor to better encapsulate needed information.
Changes to Solver Class
The following new attributes:
options: dict[str, Any]status: Status | Nonesolution: Solution | Nonesolver_model: Anyio_api: str | Nonecapability: SolverInfo | Noneenv: gurobipy.Env | None(and other solver envs)solver_name: str(current)
and the following functions:
to_solver_model(model, explicit_coordinate_names=False, env=None): thin wrapper around existinglinopy/io.pyconversion functions (model.to_gurobipy(),model.to_highspy(), raisesNotImplementedErrorfor solver wo interfaceupdate_solver_model(model, explicit_coordinate_names=False, env=None): synchronize native solver model after linopy model changes. Not implemented nowresolve(sense) -> Result: solve or re-solveself.solver_model. Stores result on the solver instance (self.status,self.solution,self.solver_model) and returnsResult. Raises ifself.solver_model is None.
(Note currently the Gurobi Env is created inside a contextlib.ExitStack scoped to solve_problem_from_model() — if solver_model persists beyond solve(), the env must also persist)
Assign the Solver instance to the linopy model at model.solver (add "solver" to __slots__), None at initialization
Changes to Result Class
Add solver_name: str to the Result dataclass. Currently Result holds status, solution, and solver_model. Adding solver_name makes Result fully self-describing — no need to pass solver identity out-of-band.
Changes to Model class
-
Add
apply_result(result: Result | None = None) -> tuple[str, str]as proposed in Solver Refactor and Extension #628 but witht the difference whenresultisNone, pull the result fromself.solver(readsself.solver.status,self.solver.solution,self.solver.solver_model). This enables a clean post-resolve()flow where the solver already has the result. Whenresultis provided explicitly, use it directly (for remote solve, mock, or detached workflows). Used for status and termination updates, objective assignment, primal and dual value assignments. -
Model.solver_modelshould point toModel.solver.solver_model. -
Model.solver_nameshould point toModel.solver.solver_name.