Skip to content

Commit 9b80b32

Browse files
feat: gently handle unknown status (#409)
* feat: improve log for unknown status, set status to ok if solution could be parsed * add test for ipm in highspy
1 parent cf3df99 commit 9b80b32

File tree

4 files changed

+21
-5
lines changed

4 files changed

+21
-5
lines changed

linopy/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def set_int_index(series: pd.Series) -> pd.Series:
4242
"""
4343
Convert string index to int index.
4444
"""
45-
if not series.empty and not series.index.is_integer():
45+
if not series.empty and not pd.api.types.is_integer_dtype(series.index):
4646
cutoff = count_initial_letters(str(series.index[0]))
4747
series.index = series.index.str[cutoff:].astype(int)
4848
return series

linopy/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,4 +239,4 @@ def info(self) -> None:
239239
else:
240240
logger.info(" Optimization successful: \n%s\n", self)
241241
else:
242-
logger.warning("Optimization failed: \n%s\n", self)
242+
logger.warning("Optimization potentially failed: \n%s\n", self)

linopy/solvers.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,14 @@ def safe_get_solution(self, status: Status, func: Callable) -> Solution:
217217
if status.is_ok:
218218
return func()
219219
elif status.status == SolverStatus.unknown:
220-
with contextlib.suppress(Exception):
220+
try:
221221
logger.warning("Solution status unknown. Trying to parse solution.")
222-
return func()
222+
sol = func()
223+
status.status = SolverStatus.ok
224+
logger.warning("Solution parsed successfully.")
225+
return sol
226+
except Exception as e:
227+
logger.error(f"Failed to parse solution: {e}")
223228
return Solution()
224229

225230
@abstractmethod

test/test_optimization.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ def test_default_settings_small_slices(model, solver, io_api):
410410

411411

412412
@pytest.mark.parametrize("solver,io_api", params)
413-
def test_solver_options(model, solver, io_api):
413+
def test_solver_time_limit_options(model, solver, io_api):
414414
time_limit_option = {
415415
"cbc": {"sec": 1},
416416
"gurobi": {"TimeLimit": 1},
@@ -427,6 +427,17 @@ def test_solver_options(model, solver, io_api):
427427
assert status == "ok"
428428

429429

430+
@pytest.mark.parametrize("solver,io_api", params)
431+
def test_solver_method_options(model, solver, io_api):
432+
method_options = {
433+
"highs": {"solver": "ipm", "run_crossover": "off", "parallel": "on"},
434+
}
435+
if solver in method_options:
436+
status, condition = model.solve(solver, io_api=io_api, **method_options[solver])
437+
assert status == "ok"
438+
assert np.isclose(model.objective.value, 3.3)
439+
440+
430441
@pytest.mark.parametrize("solver,io_api", params)
431442
def test_duplicated_variables(model_with_duplicated_variables, solver, io_api):
432443
status, condition = model_with_duplicated_variables.solve(solver, io_api=io_api)

0 commit comments

Comments
 (0)