Skip to content

Commit ad4188b

Browse files
FabianHofmannclaude
andcommitted
refactor: improve Xpress IIS implementation based on code review
- Extract IIS constraint extraction logic into separate helper method for better readability - Optimize memory usage by using constraint-to-index mapping instead of repeated list.index() calls - Add more detailed type annotations and documentation in _extract_iis_constraints method - Improve docstring clarity for compute_infeasibilities method - Add explanatory comments for constraint mapping edge cases Addresses feedback from automated code review focusing on: - Code organization and maintainability - Performance optimization for large models - Better type safety and documentation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 751760d commit ad4188b

File tree

1 file changed

+54
-33
lines changed

1 file changed

+54
-33
lines changed

linopy/model.py

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,7 +1284,8 @@ def compute_infeasibilities(self) -> list[int]:
12841284
Compute a set of infeasible constraints.
12851285
12861286
This function requires that the model was solved with `gurobi` or `xpress`
1287-
and the termination condition was infeasible.
1287+
and the termination condition was infeasible. The solver must have detected
1288+
the infeasibility during the solve process.
12881289
12891290
Returns
12901291
-------
@@ -1354,46 +1355,66 @@ def _compute_infeasibilities_xpress(self, solver_model: Any) -> list[int]:
13541355

13551356
labels = set()
13561357

1357-
# Get all constraints from the model for index mapping
1358-
all_constraints = list(solver_model.getConstraint())
1358+
# Create constraint mapping for efficient lookups
1359+
constraint_to_index = {
1360+
constraint: idx
1361+
for idx, constraint in enumerate(solver_model.getConstraint())
1362+
}
13591363

13601364
# Retrieve each IIS
13611365
for iis_num in range(1, num_iis + 1):
1362-
# Prepare lists to receive IIS data
1363-
miisrow: list[Any] = [] # Constraint objects in the IIS
1364-
miiscol: list[Any] = [] # Variable objects in the IIS
1365-
constrainttype: list[str] = [] # Constraint types
1366-
colbndtype: list[str] = [] # Column bound types
1367-
duals: list[float] = [] # Dual values
1368-
rdcs: list[float] = [] # Reduced costs
1369-
isolationrows: list[str] = [] # Row isolation info
1370-
isolationcols: list[str] = [] # Column isolation info
1371-
1372-
# Get IIS data
1373-
solver_model.getiisdata(
1374-
iis_num,
1375-
miisrow,
1376-
miiscol,
1377-
constrainttype,
1378-
colbndtype,
1379-
duals,
1380-
rdcs,
1381-
isolationrows,
1382-
isolationcols,
1383-
)
1366+
iis_constraints = self._extract_iis_constraints(solver_model, iis_num)
13841367

13851368
# Convert constraint objects to indices
1386-
# miisrow contains xpress.constraint objects
1387-
for constraint_obj in miisrow:
1388-
try:
1389-
idx = all_constraints.index(constraint_obj)
1390-
labels.add(idx)
1391-
except ValueError:
1392-
# If constraint not found, skip it
1393-
pass
1369+
for constraint_obj in iis_constraints:
1370+
if constraint_obj in constraint_to_index:
1371+
labels.add(constraint_to_index[constraint_obj])
1372+
# Note: Silently skip constraints not found in mapping
1373+
# This can happen if the model structure changed after solving
13941374

13951375
return sorted(list(labels))
13961376

1377+
def _extract_iis_constraints(self, solver_model: Any, iis_num: int) -> list[Any]:
1378+
"""
1379+
Extract constraint objects from a specific IIS.
1380+
1381+
Parameters
1382+
----------
1383+
solver_model : xpress.problem
1384+
The Xpress solver model
1385+
iis_num : int
1386+
IIS number (1-indexed)
1387+
1388+
Returns
1389+
-------
1390+
list[Any]
1391+
List of xpress.constraint objects in the IIS
1392+
"""
1393+
# Prepare lists to receive IIS data
1394+
miisrow: list[Any] = [] # xpress.constraint objects in the IIS
1395+
miiscol: list[Any] = [] # xpress.variable objects in the IIS
1396+
constrainttype: list[str] = [] # Constraint types ('L', 'G', 'E')
1397+
colbndtype: list[str] = [] # Column bound types
1398+
duals: list[float] = [] # Dual values
1399+
rdcs: list[float] = [] # Reduced costs
1400+
isolationrows: list[str] = [] # Row isolation info
1401+
isolationcols: list[str] = [] # Column isolation info
1402+
1403+
# Get IIS data from Xpress
1404+
solver_model.getiisdata(
1405+
iis_num,
1406+
miisrow,
1407+
miiscol,
1408+
constrainttype,
1409+
colbndtype,
1410+
duals,
1411+
rdcs,
1412+
isolationrows,
1413+
isolationcols,
1414+
)
1415+
1416+
return miisrow
1417+
13971418
def print_infeasibilities(self, display_max_terms: int | None = None) -> None:
13981419
"""
13991420
Print a list of infeasible constraints.

0 commit comments

Comments
 (0)