129 lines
3.5 KiB
Python
129 lines
3.5 KiB
Python
|
import numpy as np
|
||
|
from scipy.optimize import _lbfgsb, minimize
|
||
|
|
||
|
|
||
|
def objfun(x):
|
||
|
"""simplified objective func to test lbfgsb bound violation"""
|
||
|
x0 = [0.8750000000000278,
|
||
|
0.7500000000000153,
|
||
|
0.9499999999999722,
|
||
|
0.8214285714285992,
|
||
|
0.6363636363636085]
|
||
|
x1 = [1.0, 0.0, 1.0, 0.0, 0.0]
|
||
|
x2 = [1.0,
|
||
|
0.0,
|
||
|
0.9889733043149325,
|
||
|
0.0,
|
||
|
0.026353554421041155]
|
||
|
x3 = [1.0,
|
||
|
0.0,
|
||
|
0.9889917442915558,
|
||
|
0.0,
|
||
|
0.020341986743231205]
|
||
|
|
||
|
f0 = 5163.647901211178
|
||
|
f1 = 5149.8181642072905
|
||
|
f2 = 5149.379332309634
|
||
|
f3 = 5149.374490771297
|
||
|
|
||
|
g0 = np.array([-0.5934820547965749,
|
||
|
1.6251549718258351,
|
||
|
-71.99168459202559,
|
||
|
5.346636965797545,
|
||
|
37.10732723092604])
|
||
|
g1 = np.array([-0.43295349282641515,
|
||
|
1.008607936794592,
|
||
|
18.223666726602975,
|
||
|
31.927010036981997,
|
||
|
-19.667512518739386])
|
||
|
g2 = np.array([-0.4699874455100256,
|
||
|
0.9466285353668347,
|
||
|
-0.016874360242016825,
|
||
|
48.44999161133457,
|
||
|
5.819631620590712])
|
||
|
g3 = np.array([-0.46970678696829116,
|
||
|
0.9612719312174818,
|
||
|
0.006129809488833699,
|
||
|
48.43557729419473,
|
||
|
6.005481418498221])
|
||
|
|
||
|
if np.allclose(x, x0):
|
||
|
f = f0
|
||
|
g = g0
|
||
|
elif np.allclose(x, x1):
|
||
|
f = f1
|
||
|
g = g1
|
||
|
elif np.allclose(x, x2):
|
||
|
f = f2
|
||
|
g = g2
|
||
|
elif np.allclose(x, x3):
|
||
|
f = f3
|
||
|
g = g3
|
||
|
else:
|
||
|
raise ValueError(
|
||
|
'Simplified objective function not defined '
|
||
|
'at requested point')
|
||
|
return (np.copy(f), np.copy(g))
|
||
|
|
||
|
|
||
|
def test_setulb_floatround():
|
||
|
"""test if setulb() violates bounds
|
||
|
|
||
|
checks for violation due to floating point rounding error
|
||
|
"""
|
||
|
|
||
|
n = 5
|
||
|
m = 10
|
||
|
factr = 1e7
|
||
|
pgtol = 1e-5
|
||
|
maxls = 20
|
||
|
iprint = -1
|
||
|
nbd = np.full((n,), 2)
|
||
|
low_bnd = np.zeros(n, np.float64)
|
||
|
upper_bnd = np.ones(n, np.float64)
|
||
|
|
||
|
x0 = np.array(
|
||
|
[0.8750000000000278,
|
||
|
0.7500000000000153,
|
||
|
0.9499999999999722,
|
||
|
0.8214285714285992,
|
||
|
0.6363636363636085])
|
||
|
x = np.copy(x0)
|
||
|
|
||
|
f = np.array(0.0, np.float64)
|
||
|
g = np.zeros(n, np.float64)
|
||
|
|
||
|
fortran_int = _lbfgsb.types.intvar.dtype
|
||
|
|
||
|
wa = np.zeros(2*m*n + 5*n + 11*m*m + 8*m, np.float64)
|
||
|
iwa = np.zeros(3*n, fortran_int)
|
||
|
task = np.zeros(1, 'S60')
|
||
|
csave = np.zeros(1, 'S60')
|
||
|
lsave = np.zeros(4, fortran_int)
|
||
|
isave = np.zeros(44, fortran_int)
|
||
|
dsave = np.zeros(29, np.float64)
|
||
|
|
||
|
task[:] = b'START'
|
||
|
|
||
|
for n_iter in range(7): # 7 steps required to reproduce error
|
||
|
f, g = objfun(x)
|
||
|
|
||
|
_lbfgsb.setulb(m, x, low_bnd, upper_bnd, nbd, f, g, factr,
|
||
|
pgtol, wa, iwa, task, iprint, csave, lsave,
|
||
|
isave, dsave, maxls)
|
||
|
|
||
|
assert (x <= upper_bnd).all() and (x >= low_bnd).all(), (
|
||
|
"_lbfgsb.setulb() stepped to a point outside of the bounds")
|
||
|
|
||
|
|
||
|
def test_gh_issue18730():
|
||
|
# issue 18730 reported that l-bfgs-b did not work with objectives
|
||
|
# returning single precision gradient arrays
|
||
|
def fun_single_precision(x):
|
||
|
x = x.astype(np.float32)
|
||
|
return np.sum(x**2), (2*x)
|
||
|
|
||
|
res = minimize(fun_single_precision, x0=np.array([1., 1.]), jac=True,
|
||
|
method="l-bfgs-b")
|
||
|
np.testing.assert_allclose(res.fun, 0., atol=1e-15)
|