scipy: A numerical bug in scipy.optimize.linprog
Hi. I appreciate for contributors to scipy and extended communities. I learned the history of scipy on wikipedia and confirmed why this library is one of the highest quality OSS. But unfortunately, I found apparently a bug in scipy.optimize.linprog. As I run the following test.py, the LP solver incorrectly reports that LP is infeasible.
Reproducing code example:
#test.py
import codecs
from scipy.optimize import linprog
import numpy as np
c=[0,0,0,0,0,0,0,0,0]
ref = np.array([0.917113,0.270876,-0.395955,-0.196867,0.404834,1])
matA = np.array([
[0.656013,-0.365063,-0.983576,1.11294,0.579682,1],
[0.799693,0.50039,-1.32221,0.327986,0.694136,1],
[1.54842,-0.321544,-1.81128,0.949596,0.634807,1],
[1.12977,-0.271752,-1.74754,1.24775,0.641763,1],
[1.05679,0.506714,-0.583986,-0.627243,0.647723,1],
[1,0,0,0,0,1],
[0,1,0,0,0,1],
[0,0,0,1,0,1],
[0,0,0,0,1,1]
])
matA_in=matA.T.tolist()
vecb_in=ref.tolist()
xrange = [
[0,1],[0,1],[0,1],[0,1],[0,1],[0,1],[0,1],[0,1],[0,1]
]
res = linprog(c, A_eq=matA_in, b_eq=vecb_in,bounds=xrange, method='interior-point')
logfile=codecs.open('pyout.log','w','utf-8')
print(res, file=logfile)
if res.status == 2:
print("0UNSAT",file=codecs.open('check_result.log','w','utf-8'))
else:
print("1SAT",file=codecs.open('check_result.log','w','utf-8'))
# But the answer is SAT and
ans_x=np.array([0.04934082, 0, 0, 0.00702774, 0.57388938, 0.2703235, 0, 0.09941856, 0])
# and an evidence of correctness is that
residual = np.dot(matA_in, ans_x)-ref
print("residual = ",file=logfile)
print(residual,file=logfile)
# we get residual = [-9.9293934e-07 -5.2687482e-07, -6.6600600e-08, -3.0158354e-07, -5.2039340e-07, 0.0000000e+00]
#test.py end
Error message:
scipy.optimize.linprog reports the following UNSAT decision.
con: array([-1.69741633, -0.25037501, 1.94817659, -1.35441056, -1.22095061,
-2.57498303])
scipy.optimize.linprog reports the following UNSAT decision. fun: 0.0
message: 'The algorithm terminated successfully and determined that the problem is infeasible.'
nit: 5
slack: array([], dtype=float64)
status: 2
success: False
x: array([0.70514251, 0.10725385, 0.53002431, 0.11401373, 0.59845995,
0.4842205 , 0.62316526, 0.0673947 , 0.34530822])
Scipy/Numpy/Python version information:
Here is a version info. Perhaps little bit old?
>> import sys, scipy, numpy; print(scipy.__version__, numpy.__version__, sys.version_info)
1.2.1 1.17.4 sys.version_info(major=3, minor=7, micro=7, releaselevel='final', serial=0)
Can you reproduce this? I don’t have much time to look into the implementation of this library, but I can generate “MANY” similar class of incorrect reports having the same property orz.
A special property of ref and matA is that all row vectors satisfies the following constraint; [1,1,1,1,1,-1].ref=0 [1,1,1,1,1,-1].matA[i]=0, for any i, 0<=i<9
Here ref and matA[i] are on the same hyper-plane which share the same normal vector [1,1,1,1,1,-1]. So my initial guess is that the bug might result from inadequately solving a matrix equation. If a constraint matrix matA is rank-deficient. A matrix inversion could break a solution to Given_matrix*vecX=Given_vecB. In Eigen3 which I use, there are three QR decompositions with such rank-deficiency in mind. eigen.tuxfamily.org/dox/classEigen_1_1FullPivHouseholderQR.html eigen.tuxfamily.org/dox/classEigen_1_1ColPivHouseholderQR.html eigen.tuxfamily.org/dox/classEigen_1_1HouseholderQR.html
IPOPT also fails to figure out a SATsifiable assignment and instead converge incorrectly in a similar setting. But it happens less frequently than scipy.optimize.linprog showed. Another guess is that it counld result from a difficulty of solving an LP using the current floating point arithmetic IEEE754-FP that causes a rounding-error. A similar technical issue might be in scipy.optimize.linprog/interior-point. But not for sure.
Best regards, Masataka Nishi
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 26 (14 by maintainers)
Thanks. Sorry the existing
linprog
didn’t work out for you. I know you switched to C++, but in case you prefer Python, HiGHS will be available through thelinprog
interface in the next release of SciPy.I switched to HiGHS-1.0 (C++ API) and it does not fail in the cases that I reported above. Now the matA grows up >5 rows*800 columns. Excellent! (though nobody know if I could report a bug next month…) I appreciate for @mdhaber, @pv @jajhall and @mckib2 for these fast, sincere and interactive debugging.
You would also be able to use HiGHS through it without changing your code. We added HiGHS simplex and IPM as
linprog
methods but those aren’t in a release yet.