Skip to content

Commit dc20cc4

Browse files
RobbieKiwiRobbie MuirFabianHofmann
authored
Feature/dummy solve (#534)
* add mock solve * formatting * add release notes --------- Co-authored-by: Robbie Muir <robbie.muir@gmail.com> Co-authored-by: Fabian Hofmann <fab.hof@gmx.de>
1 parent c6d9e4b commit dc20cc4

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

doc/release_notes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Release Notes
22
=============
33

44
.. Upcoming Version
5-
5+
* Add ``mock_solve`` option to model.solve for quick testing without actual solving
66
* Bugfix for missing dependency for jupyter notebook example in documentation
77
* Add support for SOS1 and SOS2 (Special Ordered Sets) constraints via ``Model.add_sos_constraints()`` and ``Model.remove_sos_constraints()``
88
* Add simplify method to LinearExpression to combine duplicate terms

linopy/model.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,7 @@ def solve(
11241124
slice_size: int = 2_000_000,
11251125
remote: RemoteHandler | OetcHandler = None, # type: ignore
11261126
progress: bool | None = None,
1127+
mock_solve: bool = False,
11271128
**solver_options: Any,
11281129
) -> tuple[str, str]:
11291130
"""
@@ -1191,6 +1192,8 @@ def solve(
11911192
Whether to show a progress bar of writing the lp file. The default is
11921193
None, which means that the progress bar is shown if the model has more
11931194
than 10000 variables and constraints.
1195+
mock_solve : bool, optional
1196+
Whether to run a mock solve. This will skip the actual solving. Variables will be set to have dummy values
11941197
**solver_options : kwargs
11951198
Options passed to the solver.
11961199
@@ -1200,6 +1203,11 @@ def solve(
12001203
Tuple containing the status and termination condition of the
12011204
optimization process.
12021205
"""
1206+
if mock_solve:
1207+
return self._mock_solve(
1208+
sanitize_zeros=sanitize_zeros, sanitize_infinities=sanitize_infinities
1209+
)
1210+
12031211
# clear cached matrix properties potentially present from previous solve commands
12041212
self.matrices.clean_cached_properties()
12051213

@@ -1375,6 +1383,40 @@ def solve(
13751383

13761384
return result.status.status.value, result.status.termination_condition.value
13771385

1386+
def _mock_solve(
1387+
self,
1388+
sanitize_zeros: bool = True,
1389+
sanitize_infinities: bool = True,
1390+
) -> tuple[str, str]:
1391+
solver_name = "mock"
1392+
1393+
# clear cached matrix properties potentially present from previous solve commands
1394+
self.matrices.clean_cached_properties()
1395+
1396+
logger.info(f" Solve problem using {solver_name.title()} solver")
1397+
# reset result
1398+
self.reset_solution()
1399+
1400+
if sanitize_zeros:
1401+
self.constraints.sanitize_zeros()
1402+
1403+
if sanitize_infinities:
1404+
self.constraints.sanitize_infinities()
1405+
1406+
self.objective._value = 0.0
1407+
self.status = "ok"
1408+
self.termination_condition = TerminationCondition.optimal.value
1409+
self.solver_model = None
1410+
self.solver_name = solver_name
1411+
1412+
for name, var in self.variables.items():
1413+
var.solution = xr.DataArray(0.0, var.coords)
1414+
1415+
for name, con in self.constraints.items():
1416+
con.dual = xr.DataArray(0.0, con.labels.coords)
1417+
1418+
return "ok", "none"
1419+
13781420
def compute_infeasibilities(self) -> list[int]:
13791421
"""
13801422
Compute a set of infeasible constraints.

test/test_optimization.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,19 @@ def test_model_maximization(
464464
assert np.isclose(m.objective.value or 0, 3.3)
465465

466466

467+
def test_mock_solve(model_maximization: Model) -> None:
468+
m = model_maximization
469+
assert m.objective.sense == "max"
470+
assert m.objective.value is None
471+
472+
status, condition = m.solve(solver="some_non_existant_solver", mock_solve=True)
473+
assert status == "ok"
474+
assert m.objective.value == 0
475+
x_solution = m.variables["x"].solution
476+
assert x_solution.coords == m.variables["x"].coords
477+
assert (x_solution == 0).all()
478+
479+
467480
@pytest.mark.parametrize("solver,io_api,explicit_coordinate_names", params)
468481
def test_default_settings_chunked(
469482
model_chunked: Model, solver: str, io_api: str, explicit_coordinate_names: bool

0 commit comments

Comments
 (0)