test_slsqp.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. """
  2. Unit test for SLSQP optimization.
  3. """
  4. from numpy.testing import (assert_, assert_array_almost_equal,
  5. assert_allclose, assert_equal)
  6. from pytest import raises as assert_raises
  7. import pytest
  8. import numpy as np
  9. from scipy.optimize import fmin_slsqp, minimize, Bounds, NonlinearConstraint
  10. class MyCallBack:
  11. """pass a custom callback function
  12. This makes sure it's being used.
  13. """
  14. def __init__(self):
  15. self.been_called = False
  16. self.ncalls = 0
  17. def __call__(self, x):
  18. self.been_called = True
  19. self.ncalls += 1
  20. class TestSLSQP:
  21. """
  22. Test SLSQP algorithm using Example 14.4 from Numerical Methods for
  23. Engineers by Steven Chapra and Raymond Canale.
  24. This example maximizes the function f(x) = 2*x*y + 2*x - x**2 - 2*y**2,
  25. which has a maximum at x=2, y=1.
  26. """
  27. def setup_method(self):
  28. self.opts = {'disp': False}
  29. def fun(self, d, sign=1.0):
  30. """
  31. Arguments:
  32. d - A list of two elements, where d[0] represents x and d[1] represents y
  33. in the following equation.
  34. sign - A multiplier for f. Since we want to optimize it, and the SciPy
  35. optimizers can only minimize functions, we need to multiply it by
  36. -1 to achieve the desired solution
  37. Returns:
  38. 2*x*y + 2*x - x**2 - 2*y**2
  39. """
  40. x = d[0]
  41. y = d[1]
  42. return sign*(2*x*y + 2*x - x**2 - 2*y**2)
  43. def jac(self, d, sign=1.0):
  44. """
  45. This is the derivative of fun, returning a NumPy array
  46. representing df/dx and df/dy.
  47. """
  48. x = d[0]
  49. y = d[1]
  50. dfdx = sign*(-2*x + 2*y + 2)
  51. dfdy = sign*(2*x - 4*y)
  52. return np.array([dfdx, dfdy], float)
  53. def fun_and_jac(self, d, sign=1.0):
  54. return self.fun(d, sign), self.jac(d, sign)
  55. def f_eqcon(self, x, sign=1.0):
  56. """ Equality constraint """
  57. return np.array([x[0] - x[1]])
  58. def fprime_eqcon(self, x, sign=1.0):
  59. """ Equality constraint, derivative """
  60. return np.array([[1, -1]])
  61. def f_eqcon_scalar(self, x, sign=1.0):
  62. """ Scalar equality constraint """
  63. return self.f_eqcon(x, sign)[0]
  64. def fprime_eqcon_scalar(self, x, sign=1.0):
  65. """ Scalar equality constraint, derivative """
  66. return self.fprime_eqcon(x, sign)[0].tolist()
  67. def f_ieqcon(self, x, sign=1.0):
  68. """ Inequality constraint """
  69. return np.array([x[0] - x[1] - 1.0])
  70. def fprime_ieqcon(self, x, sign=1.0):
  71. """ Inequality constraint, derivative """
  72. return np.array([[1, -1]])
  73. def f_ieqcon2(self, x):
  74. """ Vector inequality constraint """
  75. return np.asarray(x)
  76. def fprime_ieqcon2(self, x):
  77. """ Vector inequality constraint, derivative """
  78. return np.identity(x.shape[0])
  79. # minimize
  80. def test_minimize_unbounded_approximated(self):
  81. # Minimize, method='SLSQP': unbounded, approximated jacobian.
  82. jacs = [None, False, '2-point', '3-point']
  83. for jac in jacs:
  84. res = minimize(self.fun, [-1.0, 1.0], args=(-1.0, ),
  85. jac=jac, method='SLSQP',
  86. options=self.opts)
  87. assert_(res['success'], res['message'])
  88. assert_allclose(res.x, [2, 1])
  89. def test_minimize_unbounded_given(self):
  90. # Minimize, method='SLSQP': unbounded, given Jacobian.
  91. res = minimize(self.fun, [-1.0, 1.0], args=(-1.0, ),
  92. jac=self.jac, method='SLSQP', options=self.opts)
  93. assert_(res['success'], res['message'])
  94. assert_allclose(res.x, [2, 1])
  95. def test_minimize_bounded_approximated(self):
  96. # Minimize, method='SLSQP': bounded, approximated jacobian.
  97. jacs = [None, False, '2-point', '3-point']
  98. for jac in jacs:
  99. with np.errstate(invalid='ignore'):
  100. res = minimize(self.fun, [-1.0, 1.0], args=(-1.0, ),
  101. jac=jac,
  102. bounds=((2.5, None), (None, 0.5)),
  103. method='SLSQP', options=self.opts)
  104. assert_(res['success'], res['message'])
  105. assert_allclose(res.x, [2.5, 0.5])
  106. assert_(2.5 <= res.x[0])
  107. assert_(res.x[1] <= 0.5)
  108. def test_minimize_unbounded_combined(self):
  109. # Minimize, method='SLSQP': unbounded, combined function and Jacobian.
  110. res = minimize(self.fun_and_jac, [-1.0, 1.0], args=(-1.0, ),
  111. jac=True, method='SLSQP', options=self.opts)
  112. assert_(res['success'], res['message'])
  113. assert_allclose(res.x, [2, 1])
  114. def test_minimize_equality_approximated(self):
  115. # Minimize with method='SLSQP': equality constraint, approx. jacobian.
  116. jacs = [None, False, '2-point', '3-point']
  117. for jac in jacs:
  118. res = minimize(self.fun, [-1.0, 1.0], args=(-1.0, ),
  119. jac=jac,
  120. constraints={'type': 'eq',
  121. 'fun': self.f_eqcon,
  122. 'args': (-1.0, )},
  123. method='SLSQP', options=self.opts)
  124. assert_(res['success'], res['message'])
  125. assert_allclose(res.x, [1, 1])
  126. def test_minimize_equality_given(self):
  127. # Minimize with method='SLSQP': equality constraint, given Jacobian.
  128. res = minimize(self.fun, [-1.0, 1.0], jac=self.jac,
  129. method='SLSQP', args=(-1.0,),
  130. constraints={'type': 'eq', 'fun':self.f_eqcon,
  131. 'args': (-1.0, )},
  132. options=self.opts)
  133. assert_(res['success'], res['message'])
  134. assert_allclose(res.x, [1, 1])
  135. def test_minimize_equality_given2(self):
  136. # Minimize with method='SLSQP': equality constraint, given Jacobian
  137. # for fun and const.
  138. res = minimize(self.fun, [-1.0, 1.0], method='SLSQP',
  139. jac=self.jac, args=(-1.0,),
  140. constraints={'type': 'eq',
  141. 'fun': self.f_eqcon,
  142. 'args': (-1.0, ),
  143. 'jac': self.fprime_eqcon},
  144. options=self.opts)
  145. assert_(res['success'], res['message'])
  146. assert_allclose(res.x, [1, 1])
  147. def test_minimize_equality_given_cons_scalar(self):
  148. # Minimize with method='SLSQP': scalar equality constraint, given
  149. # Jacobian for fun and const.
  150. res = minimize(self.fun, [-1.0, 1.0], method='SLSQP',
  151. jac=self.jac, args=(-1.0,),
  152. constraints={'type': 'eq',
  153. 'fun': self.f_eqcon_scalar,
  154. 'args': (-1.0, ),
  155. 'jac': self.fprime_eqcon_scalar},
  156. options=self.opts)
  157. assert_(res['success'], res['message'])
  158. assert_allclose(res.x, [1, 1])
  159. def test_minimize_inequality_given(self):
  160. # Minimize with method='SLSQP': inequality constraint, given Jacobian.
  161. res = minimize(self.fun, [-1.0, 1.0], method='SLSQP',
  162. jac=self.jac, args=(-1.0, ),
  163. constraints={'type': 'ineq',
  164. 'fun': self.f_ieqcon,
  165. 'args': (-1.0, )},
  166. options=self.opts)
  167. assert_(res['success'], res['message'])
  168. assert_allclose(res.x, [2, 1], atol=1e-3)
  169. def test_minimize_inequality_given_vector_constraints(self):
  170. # Minimize with method='SLSQP': vector inequality constraint, given
  171. # Jacobian.
  172. res = minimize(self.fun, [-1.0, 1.0], jac=self.jac,
  173. method='SLSQP', args=(-1.0,),
  174. constraints={'type': 'ineq',
  175. 'fun': self.f_ieqcon2,
  176. 'jac': self.fprime_ieqcon2},
  177. options=self.opts)
  178. assert_(res['success'], res['message'])
  179. assert_allclose(res.x, [2, 1])
  180. def test_minimize_bounded_constraint(self):
  181. # when the constraint makes the solver go up against a parameter
  182. # bound make sure that the numerical differentiation of the
  183. # jacobian doesn't try to exceed that bound using a finite difference.
  184. # gh11403
  185. def c(x):
  186. assert 0 <= x[0] <= 1 and 0 <= x[1] <= 1, x
  187. return x[0] ** 0.5 + x[1]
  188. def f(x):
  189. assert 0 <= x[0] <= 1 and 0 <= x[1] <= 1, x
  190. return -x[0] ** 2 + x[1] ** 2
  191. cns = [NonlinearConstraint(c, 0, 1.5)]
  192. x0 = np.asarray([0.9, 0.5])
  193. bnd = Bounds([0., 0.], [1.0, 1.0])
  194. minimize(f, x0, method='SLSQP', bounds=bnd, constraints=cns)
  195. def test_minimize_bound_equality_given2(self):
  196. # Minimize with method='SLSQP': bounds, eq. const., given jac. for
  197. # fun. and const.
  198. res = minimize(self.fun, [-1.0, 1.0], method='SLSQP',
  199. jac=self.jac, args=(-1.0, ),
  200. bounds=[(-0.8, 1.), (-1, 0.8)],
  201. constraints={'type': 'eq',
  202. 'fun': self.f_eqcon,
  203. 'args': (-1.0, ),
  204. 'jac': self.fprime_eqcon},
  205. options=self.opts)
  206. assert_(res['success'], res['message'])
  207. assert_allclose(res.x, [0.8, 0.8], atol=1e-3)
  208. assert_(-0.8 <= res.x[0] <= 1)
  209. assert_(-1 <= res.x[1] <= 0.8)
  210. # fmin_slsqp
  211. def test_unbounded_approximated(self):
  212. # SLSQP: unbounded, approximated Jacobian.
  213. res = fmin_slsqp(self.fun, [-1.0, 1.0], args=(-1.0, ),
  214. iprint = 0, full_output = 1)
  215. x, fx, its, imode, smode = res
  216. assert_(imode == 0, imode)
  217. assert_array_almost_equal(x, [2, 1])
  218. def test_unbounded_given(self):
  219. # SLSQP: unbounded, given Jacobian.
  220. res = fmin_slsqp(self.fun, [-1.0, 1.0], args=(-1.0, ),
  221. fprime = self.jac, iprint = 0,
  222. full_output = 1)
  223. x, fx, its, imode, smode = res
  224. assert_(imode == 0, imode)
  225. assert_array_almost_equal(x, [2, 1])
  226. def test_equality_approximated(self):
  227. # SLSQP: equality constraint, approximated Jacobian.
  228. res = fmin_slsqp(self.fun,[-1.0,1.0], args=(-1.0,),
  229. eqcons = [self.f_eqcon],
  230. iprint = 0, full_output = 1)
  231. x, fx, its, imode, smode = res
  232. assert_(imode == 0, imode)
  233. assert_array_almost_equal(x, [1, 1])
  234. def test_equality_given(self):
  235. # SLSQP: equality constraint, given Jacobian.
  236. res = fmin_slsqp(self.fun, [-1.0, 1.0],
  237. fprime=self.jac, args=(-1.0,),
  238. eqcons = [self.f_eqcon], iprint = 0,
  239. full_output = 1)
  240. x, fx, its, imode, smode = res
  241. assert_(imode == 0, imode)
  242. assert_array_almost_equal(x, [1, 1])
  243. def test_equality_given2(self):
  244. # SLSQP: equality constraint, given Jacobian for fun and const.
  245. res = fmin_slsqp(self.fun, [-1.0, 1.0],
  246. fprime=self.jac, args=(-1.0,),
  247. f_eqcons = self.f_eqcon,
  248. fprime_eqcons = self.fprime_eqcon,
  249. iprint = 0,
  250. full_output = 1)
  251. x, fx, its, imode, smode = res
  252. assert_(imode == 0, imode)
  253. assert_array_almost_equal(x, [1, 1])
  254. def test_inequality_given(self):
  255. # SLSQP: inequality constraint, given Jacobian.
  256. res = fmin_slsqp(self.fun, [-1.0, 1.0],
  257. fprime=self.jac, args=(-1.0, ),
  258. ieqcons = [self.f_ieqcon],
  259. iprint = 0, full_output = 1)
  260. x, fx, its, imode, smode = res
  261. assert_(imode == 0, imode)
  262. assert_array_almost_equal(x, [2, 1], decimal=3)
  263. def test_bound_equality_given2(self):
  264. # SLSQP: bounds, eq. const., given jac. for fun. and const.
  265. res = fmin_slsqp(self.fun, [-1.0, 1.0],
  266. fprime=self.jac, args=(-1.0, ),
  267. bounds = [(-0.8, 1.), (-1, 0.8)],
  268. f_eqcons = self.f_eqcon,
  269. fprime_eqcons = self.fprime_eqcon,
  270. iprint = 0, full_output = 1)
  271. x, fx, its, imode, smode = res
  272. assert_(imode == 0, imode)
  273. assert_array_almost_equal(x, [0.8, 0.8], decimal=3)
  274. assert_(-0.8 <= x[0] <= 1)
  275. assert_(-1 <= x[1] <= 0.8)
  276. def test_scalar_constraints(self):
  277. # Regression test for gh-2182
  278. x = fmin_slsqp(lambda z: z**2, [3.],
  279. ieqcons=[lambda z: z[0] - 1],
  280. iprint=0)
  281. assert_array_almost_equal(x, [1.])
  282. x = fmin_slsqp(lambda z: z**2, [3.],
  283. f_ieqcons=lambda z: [z[0] - 1],
  284. iprint=0)
  285. assert_array_almost_equal(x, [1.])
  286. def test_integer_bounds(self):
  287. # This should not raise an exception
  288. fmin_slsqp(lambda z: z**2 - 1, [0], bounds=[[0, 1]], iprint=0)
  289. def test_array_bounds(self):
  290. # NumPy used to treat n-dimensional 1-element arrays as scalars
  291. # in some cases. The handling of `bounds` by `fmin_slsqp` still
  292. # supports this behavior.
  293. bounds = [(-np.inf, np.inf), (np.array([2]), np.array([3]))]
  294. x = fmin_slsqp(lambda z: np.sum(z**2 - 1), [2.5, 2.5], bounds=bounds,
  295. iprint=0)
  296. assert_array_almost_equal(x, [0, 2])
  297. def test_obj_must_return_scalar(self):
  298. # Regression test for Github Issue #5433
  299. # If objective function does not return a scalar, raises ValueError
  300. with assert_raises(ValueError):
  301. fmin_slsqp(lambda x: [0, 1], [1, 2, 3])
  302. def test_obj_returns_scalar_in_list(self):
  303. # Test for Github Issue #5433 and PR #6691
  304. # Objective function should be able to return length-1 Python list
  305. # containing the scalar
  306. fmin_slsqp(lambda x: [0], [1, 2, 3], iprint=0)
  307. def test_callback(self):
  308. # Minimize, method='SLSQP': unbounded, approximated jacobian. Check for callback
  309. callback = MyCallBack()
  310. res = minimize(self.fun, [-1.0, 1.0], args=(-1.0, ),
  311. method='SLSQP', callback=callback, options=self.opts)
  312. assert_(res['success'], res['message'])
  313. assert_(callback.been_called)
  314. assert_equal(callback.ncalls, res['nit'])
  315. def test_inconsistent_linearization(self):
  316. # SLSQP must be able to solve this problem, even if the
  317. # linearized problem at the starting point is infeasible.
  318. # Linearized constraints are
  319. #
  320. # 2*x0[0]*x[0] >= 1
  321. #
  322. # At x0 = [0, 1], the second constraint is clearly infeasible.
  323. # This triggers a call with n2==1 in the LSQ subroutine.
  324. x = [0, 1]
  325. f1 = lambda x: x[0] + x[1] - 2
  326. f2 = lambda x: x[0]**2 - 1
  327. sol = minimize(
  328. lambda x: x[0]**2 + x[1]**2,
  329. x,
  330. constraints=({'type':'eq','fun': f1},
  331. {'type':'ineq','fun': f2}),
  332. bounds=((0,None), (0,None)),
  333. method='SLSQP')
  334. x = sol.x
  335. assert_allclose(f1(x), 0, atol=1e-8)
  336. assert_(f2(x) >= -1e-8)
  337. assert_(sol.success, sol)
  338. def test_regression_5743(self):
  339. # SLSQP must not indicate success for this problem,
  340. # which is infeasible.
  341. x = [1, 2]
  342. sol = minimize(
  343. lambda x: x[0]**2 + x[1]**2,
  344. x,
  345. constraints=({'type':'eq','fun': lambda x: x[0]+x[1]-1},
  346. {'type':'ineq','fun': lambda x: x[0]-2}),
  347. bounds=((0,None), (0,None)),
  348. method='SLSQP')
  349. assert_(not sol.success, sol)
  350. def test_gh_6676(self):
  351. def func(x):
  352. return (x[0] - 1)**2 + 2*(x[1] - 1)**2 + 0.5*(x[2] - 1)**2
  353. sol = minimize(func, [0, 0, 0], method='SLSQP')
  354. assert_(sol.jac.shape == (3,))
  355. def test_invalid_bounds(self):
  356. # Raise correct error when lower bound is greater than upper bound.
  357. # See Github issue 6875.
  358. bounds_list = [
  359. ((1, 2), (2, 1)),
  360. ((2, 1), (1, 2)),
  361. ((2, 1), (2, 1)),
  362. ((np.inf, 0), (np.inf, 0)),
  363. ((1, -np.inf), (0, 1)),
  364. ]
  365. for bounds in bounds_list:
  366. with assert_raises(ValueError):
  367. minimize(self.fun, [-1.0, 1.0], bounds=bounds, method='SLSQP')
  368. def test_bounds_clipping(self):
  369. #
  370. # SLSQP returns bogus results for initial guess out of bounds, gh-6859
  371. #
  372. def f(x):
  373. return (x[0] - 1)**2
  374. sol = minimize(f, [10], method='slsqp', bounds=[(None, 0)])
  375. assert_(sol.success)
  376. assert_allclose(sol.x, 0, atol=1e-10)
  377. sol = minimize(f, [-10], method='slsqp', bounds=[(2, None)])
  378. assert_(sol.success)
  379. assert_allclose(sol.x, 2, atol=1e-10)
  380. sol = minimize(f, [-10], method='slsqp', bounds=[(None, 0)])
  381. assert_(sol.success)
  382. assert_allclose(sol.x, 0, atol=1e-10)
  383. sol = minimize(f, [10], method='slsqp', bounds=[(2, None)])
  384. assert_(sol.success)
  385. assert_allclose(sol.x, 2, atol=1e-10)
  386. sol = minimize(f, [-0.5], method='slsqp', bounds=[(-1, 0)])
  387. assert_(sol.success)
  388. assert_allclose(sol.x, 0, atol=1e-10)
  389. sol = minimize(f, [10], method='slsqp', bounds=[(-1, 0)])
  390. assert_(sol.success)
  391. assert_allclose(sol.x, 0, atol=1e-10)
  392. def test_infeasible_initial(self):
  393. # Check SLSQP behavior with infeasible initial point
  394. def f(x):
  395. x, = x
  396. return x*x - 2*x + 1
  397. cons_u = [{'type': 'ineq', 'fun': lambda x: 0 - x}]
  398. cons_l = [{'type': 'ineq', 'fun': lambda x: x - 2}]
  399. cons_ul = [{'type': 'ineq', 'fun': lambda x: 0 - x},
  400. {'type': 'ineq', 'fun': lambda x: x + 1}]
  401. sol = minimize(f, [10], method='slsqp', constraints=cons_u)
  402. assert_(sol.success)
  403. assert_allclose(sol.x, 0, atol=1e-10)
  404. sol = minimize(f, [-10], method='slsqp', constraints=cons_l)
  405. assert_(sol.success)
  406. assert_allclose(sol.x, 2, atol=1e-10)
  407. sol = minimize(f, [-10], method='slsqp', constraints=cons_u)
  408. assert_(sol.success)
  409. assert_allclose(sol.x, 0, atol=1e-10)
  410. sol = minimize(f, [10], method='slsqp', constraints=cons_l)
  411. assert_(sol.success)
  412. assert_allclose(sol.x, 2, atol=1e-10)
  413. sol = minimize(f, [-0.5], method='slsqp', constraints=cons_ul)
  414. assert_(sol.success)
  415. assert_allclose(sol.x, 0, atol=1e-10)
  416. sol = minimize(f, [10], method='slsqp', constraints=cons_ul)
  417. assert_(sol.success)
  418. assert_allclose(sol.x, 0, atol=1e-10)
  419. def test_inconsistent_inequalities(self):
  420. # gh-7618
  421. def cost(x):
  422. return -1 * x[0] + 4 * x[1]
  423. def ineqcons1(x):
  424. return x[1] - x[0] - 1
  425. def ineqcons2(x):
  426. return x[0] - x[1]
  427. # The inequalities are inconsistent, so no solution can exist:
  428. #
  429. # x1 >= x0 + 1
  430. # x0 >= x1
  431. x0 = (1,5)
  432. bounds = ((-5, 5), (-5, 5))
  433. cons = (dict(type='ineq', fun=ineqcons1), dict(type='ineq', fun=ineqcons2))
  434. res = minimize(cost, x0, method='SLSQP', bounds=bounds, constraints=cons)
  435. assert_(not res.success)
  436. def test_new_bounds_type(self):
  437. f = lambda x: x[0]**2 + x[1]**2
  438. bounds = Bounds([1, 0], [np.inf, np.inf])
  439. sol = minimize(f, [0, 0], method='slsqp', bounds=bounds)
  440. assert_(sol.success)
  441. assert_allclose(sol.x, [1, 0])
  442. def test_nested_minimization(self):
  443. class NestedProblem():
  444. def __init__(self):
  445. self.F_outer_count = 0
  446. def F_outer(self, x):
  447. self.F_outer_count += 1
  448. if self.F_outer_count > 1000:
  449. raise Exception("Nested minimization failed to terminate.")
  450. inner_res = minimize(self.F_inner, (3, 4), method="SLSQP")
  451. assert_(inner_res.success)
  452. assert_allclose(inner_res.x, [1, 1])
  453. return x[0]**2 + x[1]**2 + x[2]**2
  454. def F_inner(self, x):
  455. return (x[0] - 1)**2 + (x[1] - 1)**2
  456. def solve(self):
  457. outer_res = minimize(self.F_outer, (5, 5, 5), method="SLSQP")
  458. assert_(outer_res.success)
  459. assert_allclose(outer_res.x, [0, 0, 0])
  460. problem = NestedProblem()
  461. problem.solve()
  462. def test_gh1758(self):
  463. # the test suggested in gh1758
  464. # https://nlopt.readthedocs.io/en/latest/NLopt_Tutorial/
  465. # implement two equality constraints, in R^2.
  466. def fun(x):
  467. return np.sqrt(x[1])
  468. def f_eqcon(x):
  469. """ Equality constraint """
  470. return x[1] - (2 * x[0]) ** 3
  471. def f_eqcon2(x):
  472. """ Equality constraint """
  473. return x[1] - (-x[0] + 1) ** 3
  474. c1 = {'type': 'eq', 'fun': f_eqcon}
  475. c2 = {'type': 'eq', 'fun': f_eqcon2}
  476. res = minimize(fun, [8, 0.25], method='SLSQP',
  477. constraints=[c1, c2], bounds=[(-0.5, 1), (0, 8)])
  478. np.testing.assert_allclose(res.fun, 0.5443310539518)
  479. np.testing.assert_allclose(res.x, [0.33333333, 0.2962963])
  480. assert res.success
  481. def test_gh9640(self):
  482. np.random.seed(10)
  483. cons = ({'type': 'ineq', 'fun': lambda x: -x[0] - x[1] - 3},
  484. {'type': 'ineq', 'fun': lambda x: x[1] + x[2] - 2})
  485. bnds = ((-2, 2), (-2, 2), (-2, 2))
  486. target = lambda x: 1
  487. x0 = [-1.8869783504471584, -0.640096352696244, -0.8174212253407696]
  488. res = minimize(target, x0, method='SLSQP', bounds=bnds, constraints=cons,
  489. options={'disp':False, 'maxiter':10000})
  490. # The problem is infeasible, so it cannot succeed
  491. assert not res.success
  492. def test_parameters_stay_within_bounds(self):
  493. # gh11403. For some problems the SLSQP Fortran code suggests a step
  494. # outside one of the lower/upper bounds. When this happens
  495. # approx_derivative complains because it's being asked to evaluate
  496. # a gradient outside its domain.
  497. np.random.seed(1)
  498. bounds = Bounds(np.array([0.1]), np.array([1.0]))
  499. n_inputs = len(bounds.lb)
  500. x0 = np.array(bounds.lb + (bounds.ub - bounds.lb) *
  501. np.random.random(n_inputs))
  502. def f(x):
  503. assert (x >= bounds.lb).all()
  504. return np.linalg.norm(x)
  505. with pytest.warns(RuntimeWarning, match='x were outside bounds'):
  506. res = minimize(f, x0, method='SLSQP', bounds=bounds)
  507. assert res.success