BUG: optimize.linprog TestLinprogIPSparse.test_bug_6139 fails with OpenBLAS due to deprecated interior-point solver
Describe your issue.
Two scipy.optimize.linprog tests still exercise the deprecated method='interior-point' solver and fail a tight assert_allclose (rtol=atol=1e-08) when SciPy is linked against OpenBLAS.
optimize/tests/test_linprog.py::TestLinprogIPSparse::test_bug_6139optimize/tests/test_linprog.py::TestLinprogIPSparsePresolve::test_bug_6139
Reproduced on SciPy 1.14.1, 1.15.x, 1.16.3, and 1.17.0.
The solver still converges to essentially the expected solution [5, 4.95, 5]; the max absolute difference is about 8.86e-08 (relative ~1.79e-08), just outside the test tolerance. The same problem with method='highs', 'highs-ipm', or 'simplex' does not fail.
This looks like numerical sensitivity in the legacy interior-point sparse path (_linprog_ip._sym_solve) plus a too-tight check, not a wrong optimum. The tests remain in the suite even though 'interior-point' was deprecated and scheduled for removal.
Related:
- PR #15512 made HiGHS the default and deprecated
'interior-point'(removal was documented for 1.11.0). - #15707 still tracks removing the deprecated linprog methods.
- #20216 skipped the dense
TestLinprogIPDense.test_bug_6139variant for the same family of failures. - #25488 reports the same two sparse tests failing with
-march=znver5/ Skylake.
Please consider skipping, xfailing, or dropping these remaining LinprogIP* tests, and/or finishing removal of the deprecated solver, consistent with #20216.
Reproducing Code Example
import numpy as np
from scipy.optimize import linprog
from numpy.testing import assert_allclose, assert_equal
def _assert_success(res, desired_fun=None, desired_x=None, rtol=1e-8, atol=1e-8):
if not res.success:
raise AssertionError(f"linprog status {res.status}, message: {res.message}")
assert_equal(res.status, 0)
if desired_fun is not None:
assert_allclose(res.fun, desired_fun,
err_msg="converged to an unexpected objective value",
rtol=rtol, atol=atol)
if desired_x is not None:
assert_allclose(res.x, desired_x,
err_msg="converged to an unexpected solution",
rtol=rtol, atol=atol)
c = np.array([1, 1, 1])
A_eq = np.array([[1., 0., 0.], [-1000., 0., -1000.]])
b_eq = np.array([5.00000000e+00, -1.00000000e+04])
A_ub = -np.array([[0., 1000000., 1010000.]])
b_ub = -np.array([10000000.])
bounds = (None, None)
method = "interior-point"
# method = "highs" # passes
# method = "highs-ipm" # passes
options = {"sparse": True, "cholesky": False, "sym_pos": False}
res = linprog(c, A_ub, b_ub, A_eq, b_eq, bounds, method=method, options=options)
print(f"result fun: {res.fun}")
print(f"result x: {res.x}")
_assert_success(res, desired_fun=14.95, desired_x=np.array([5, 4.95, 5]))Error message
FAILED optimize/tests/test_linprog.py::TestLinprogIPSparse::test_bug_6139 - AssertionError:
Not equal to tolerance rtol=1e-08, atol=1e-08
converged to an unexpected solution
Mismatched elements: 2 / 3 (66.7%)
Max absolute difference among violations: 8.8555848e-08
Max relative difference among violations: 1.78900703e-08
ACTUAL: array([5. , 4.95, 5. ])
DESIRED: array([5. , 4.95, 5. ])
FAILED optimize/tests/test_linprog.py::TestLinprogIPSparsePresolve::test_bug_6139 - AssertionError:
Not equal to tolerance rtol=1e-08, atol=1e-08
converged to an unexpected solution
Mismatched elements: 2 / 3 (66.7%)
Max absolute difference among violations: 8.8555848e-08
Max relative difference among violations: 1.78900703e-08
ACTUAL: array([5. , 4.95, 5. ])
DESIRED: array([5. , 4.95, 5. ])Switching method to 'highs' or 'highs-ipm' succeeds.
SciPy/NumPy/Python version and system information
Reproduced with SciPy 1.14.1, 1.15.x, 1.16.3, 1.17.0 linked against OpenBLAS.
- Python: 3.11, 3.12, 3.13
- OS: Rocky Linux 8, Rocky Linux 9, Ubuntu
- CPU: x86-64 (
znver4/znver5/znver6)
Happy to add scipy.show_config() from a specific build if useful.
Source: scipy/scipy