Skip to content

Commit 89af0e7

Browse files
committed
fix: compute a single IIS in Xpress infeasibility path (#658)
1 parent 0bd3358 commit 89af0e7

2 files changed

Lines changed: 12 additions & 18 deletions

File tree

doc/release_notes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Version 0.6.7
55
-------------
66

77
* Fix Xpress IIS label mapping for masked constraints and add a regression test for matching infeasible coordinates.
8+
* Fix ``Model.compute_infeasibilities`` returning a flattened, deduplicated union of all IIS when Xpress found more than one. The Xpress path now computes a single IIS (via ``firstIIS``), matching the Gurobi path.
89
* Use ``xarray.Dataset.copy`` instead of constructor for compatibility with the latest xarray version.
910
* Blacklist highspy 1.14.0 which produces wrong results due to broken presolve and crashes on Windows (`HiGHS#2964 <https://github.com/ERGO-Code/HiGHS/issues/2964>`_).
1011

linopy/model.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,19 +1601,17 @@ def _compute_infeasibilities_xpress(self, solver_model: Any) -> list[int]:
16011601
be skipped (e.g., labels [0, 2, 4] with gaps instead of sequential
16021602
[0, 1, 2]).
16031603
"""
1604-
# Compute all IIS
1604+
# Compute a single IIS (matches Gurobi behavior; multiple IIS would
1605+
# otherwise get flattened into an ambiguous union). Mode 2 prioritises
1606+
# a fast IIS search over minimality.
16051607
try: # Try new API first
1606-
solver_model.IISAll()
1608+
solver_model.firstIIS(2)
16071609
except AttributeError: # Fallback to old API
1608-
solver_model.iisall()
1610+
solver_model.iisfirst(2)
16091611

1610-
# Get the number of IIS found
1611-
num_iis = solver_model.attributes.numiis
1612-
if num_iis == 0:
1612+
if solver_model.attributes.numiis == 0:
16131613
return []
16141614

1615-
labels = set()
1616-
16171615
clabels = self.matrices.clabels
16181616
constraint_position_map = {}
16191617
for position, constraint_obj in enumerate(solver_model.getConstraint()):
@@ -1622,17 +1620,12 @@ def _compute_infeasibilities_xpress(self, solver_model: Any) -> list[int]:
16221620
if constraint_label >= 0:
16231621
constraint_position_map[constraint_obj] = constraint_label
16241622

1625-
# Retrieve each IIS
1626-
for iis_num in range(1, num_iis + 1):
1627-
iis_constraints = self._extract_iis_constraints(solver_model, iis_num)
1628-
1629-
for constraint_obj in iis_constraints:
1630-
if constraint_obj in constraint_position_map:
1631-
labels.add(constraint_position_map[constraint_obj])
1632-
# Note: Silently skip constraints not found in mapping
1633-
# This can happen if the model structure changed after solving
1623+
labels = set()
1624+
for constraint_obj in self._extract_iis_constraints(solver_model, 1):
1625+
if constraint_obj in constraint_position_map:
1626+
labels.add(constraint_position_map[constraint_obj])
16341627

1635-
return sorted(list(labels))
1628+
return sorted(labels)
16361629

16371630
def _extract_iis_constraints(self, solver_model: Any, iis_num: int) -> list[Any]:
16381631
"""

0 commit comments

Comments
 (0)