_slsqp_py.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. """
  2. This module implements the Sequential Least Squares Programming optimization
  3. algorithm (SLSQP), originally developed by Dieter Kraft.
  4. See http://www.netlib.org/toms/733
  5. Functions
  6. ---------
  7. .. autosummary::
  8. :toctree: generated/
  9. approx_jacobian
  10. fmin_slsqp
  11. """
  12. __all__ = ['approx_jacobian', 'fmin_slsqp']
  13. import numpy as np
  14. from scipy.optimize._slsqp import slsqp
  15. from numpy import (zeros, array, linalg, append, asfarray, concatenate, finfo,
  16. sqrt, vstack, isfinite, atleast_1d)
  17. from ._optimize import (OptimizeResult, _check_unknown_options,
  18. _prepare_scalar_function, _clip_x_for_func,
  19. _check_clip_x)
  20. from ._numdiff import approx_derivative
  21. from ._constraints import old_bound_to_new, _arr_to_scalar
  22. __docformat__ = "restructuredtext en"
  23. _epsilon = sqrt(finfo(float).eps)
  24. def approx_jacobian(x, func, epsilon, *args):
  25. """
  26. Approximate the Jacobian matrix of a callable function.
  27. Parameters
  28. ----------
  29. x : array_like
  30. The state vector at which to compute the Jacobian matrix.
  31. func : callable f(x,*args)
  32. The vector-valued function.
  33. epsilon : float
  34. The perturbation used to determine the partial derivatives.
  35. args : sequence
  36. Additional arguments passed to func.
  37. Returns
  38. -------
  39. An array of dimensions ``(lenf, lenx)`` where ``lenf`` is the length
  40. of the outputs of `func`, and ``lenx`` is the number of elements in
  41. `x`.
  42. Notes
  43. -----
  44. The approximation is done using forward differences.
  45. """
  46. # approx_derivative returns (m, n) == (lenf, lenx)
  47. jac = approx_derivative(func, x, method='2-point', abs_step=epsilon,
  48. args=args)
  49. # if func returns a scalar jac.shape will be (lenx,). Make sure
  50. # it's at least a 2D array.
  51. return np.atleast_2d(jac)
  52. def fmin_slsqp(func, x0, eqcons=(), f_eqcons=None, ieqcons=(), f_ieqcons=None,
  53. bounds=(), fprime=None, fprime_eqcons=None,
  54. fprime_ieqcons=None, args=(), iter=100, acc=1.0E-6,
  55. iprint=1, disp=None, full_output=0, epsilon=_epsilon,
  56. callback=None):
  57. """
  58. Minimize a function using Sequential Least Squares Programming
  59. Python interface function for the SLSQP Optimization subroutine
  60. originally implemented by Dieter Kraft.
  61. Parameters
  62. ----------
  63. func : callable f(x,*args)
  64. Objective function. Must return a scalar.
  65. x0 : 1-D ndarray of float
  66. Initial guess for the independent variable(s).
  67. eqcons : list, optional
  68. A list of functions of length n such that
  69. eqcons[j](x,*args) == 0.0 in a successfully optimized
  70. problem.
  71. f_eqcons : callable f(x,*args), optional
  72. Returns a 1-D array in which each element must equal 0.0 in a
  73. successfully optimized problem. If f_eqcons is specified,
  74. eqcons is ignored.
  75. ieqcons : list, optional
  76. A list of functions of length n such that
  77. ieqcons[j](x,*args) >= 0.0 in a successfully optimized
  78. problem.
  79. f_ieqcons : callable f(x,*args), optional
  80. Returns a 1-D ndarray in which each element must be greater or
  81. equal to 0.0 in a successfully optimized problem. If
  82. f_ieqcons is specified, ieqcons is ignored.
  83. bounds : list, optional
  84. A list of tuples specifying the lower and upper bound
  85. for each independent variable [(xl0, xu0),(xl1, xu1),...]
  86. Infinite values will be interpreted as large floating values.
  87. fprime : callable `f(x,*args)`, optional
  88. A function that evaluates the partial derivatives of func.
  89. fprime_eqcons : callable `f(x,*args)`, optional
  90. A function of the form `f(x, *args)` that returns the m by n
  91. array of equality constraint normals. If not provided,
  92. the normals will be approximated. The array returned by
  93. fprime_eqcons should be sized as ( len(eqcons), len(x0) ).
  94. fprime_ieqcons : callable `f(x,*args)`, optional
  95. A function of the form `f(x, *args)` that returns the m by n
  96. array of inequality constraint normals. If not provided,
  97. the normals will be approximated. The array returned by
  98. fprime_ieqcons should be sized as ( len(ieqcons), len(x0) ).
  99. args : sequence, optional
  100. Additional arguments passed to func and fprime.
  101. iter : int, optional
  102. The maximum number of iterations.
  103. acc : float, optional
  104. Requested accuracy.
  105. iprint : int, optional
  106. The verbosity of fmin_slsqp :
  107. * iprint <= 0 : Silent operation
  108. * iprint == 1 : Print summary upon completion (default)
  109. * iprint >= 2 : Print status of each iterate and summary
  110. disp : int, optional
  111. Overrides the iprint interface (preferred).
  112. full_output : bool, optional
  113. If False, return only the minimizer of func (default).
  114. Otherwise, output final objective function and summary
  115. information.
  116. epsilon : float, optional
  117. The step size for finite-difference derivative estimates.
  118. callback : callable, optional
  119. Called after each iteration, as ``callback(x)``, where ``x`` is the
  120. current parameter vector.
  121. Returns
  122. -------
  123. out : ndarray of float
  124. The final minimizer of func.
  125. fx : ndarray of float, if full_output is true
  126. The final value of the objective function.
  127. its : int, if full_output is true
  128. The number of iterations.
  129. imode : int, if full_output is true
  130. The exit mode from the optimizer (see below).
  131. smode : string, if full_output is true
  132. Message describing the exit mode from the optimizer.
  133. See also
  134. --------
  135. minimize: Interface to minimization algorithms for multivariate
  136. functions. See the 'SLSQP' `method` in particular.
  137. Notes
  138. -----
  139. Exit modes are defined as follows ::
  140. -1 : Gradient evaluation required (g & a)
  141. 0 : Optimization terminated successfully
  142. 1 : Function evaluation required (f & c)
  143. 2 : More equality constraints than independent variables
  144. 3 : More than 3*n iterations in LSQ subproblem
  145. 4 : Inequality constraints incompatible
  146. 5 : Singular matrix E in LSQ subproblem
  147. 6 : Singular matrix C in LSQ subproblem
  148. 7 : Rank-deficient equality constraint subproblem HFTI
  149. 8 : Positive directional derivative for linesearch
  150. 9 : Iteration limit reached
  151. Examples
  152. --------
  153. Examples are given :ref:`in the tutorial <tutorial-sqlsp>`.
  154. """
  155. if disp is not None:
  156. iprint = disp
  157. opts = {'maxiter': iter,
  158. 'ftol': acc,
  159. 'iprint': iprint,
  160. 'disp': iprint != 0,
  161. 'eps': epsilon,
  162. 'callback': callback}
  163. # Build the constraints as a tuple of dictionaries
  164. cons = ()
  165. # 1. constraints of the 1st kind (eqcons, ieqcons); no Jacobian; take
  166. # the same extra arguments as the objective function.
  167. cons += tuple({'type': 'eq', 'fun': c, 'args': args} for c in eqcons)
  168. cons += tuple({'type': 'ineq', 'fun': c, 'args': args} for c in ieqcons)
  169. # 2. constraints of the 2nd kind (f_eqcons, f_ieqcons) and their Jacobian
  170. # (fprime_eqcons, fprime_ieqcons); also take the same extra arguments
  171. # as the objective function.
  172. if f_eqcons:
  173. cons += ({'type': 'eq', 'fun': f_eqcons, 'jac': fprime_eqcons,
  174. 'args': args}, )
  175. if f_ieqcons:
  176. cons += ({'type': 'ineq', 'fun': f_ieqcons, 'jac': fprime_ieqcons,
  177. 'args': args}, )
  178. res = _minimize_slsqp(func, x0, args, jac=fprime, bounds=bounds,
  179. constraints=cons, **opts)
  180. if full_output:
  181. return res['x'], res['fun'], res['nit'], res['status'], res['message']
  182. else:
  183. return res['x']
  184. def _minimize_slsqp(func, x0, args=(), jac=None, bounds=None,
  185. constraints=(),
  186. maxiter=100, ftol=1.0E-6, iprint=1, disp=False,
  187. eps=_epsilon, callback=None, finite_diff_rel_step=None,
  188. **unknown_options):
  189. """
  190. Minimize a scalar function of one or more variables using Sequential
  191. Least Squares Programming (SLSQP).
  192. Options
  193. -------
  194. ftol : float
  195. Precision goal for the value of f in the stopping criterion.
  196. eps : float
  197. Step size used for numerical approximation of the Jacobian.
  198. disp : bool
  199. Set to True to print convergence messages. If False,
  200. `verbosity` is ignored and set to 0.
  201. maxiter : int
  202. Maximum number of iterations.
  203. finite_diff_rel_step : None or array_like, optional
  204. If `jac in ['2-point', '3-point', 'cs']` the relative step size to
  205. use for numerical approximation of `jac`. The absolute step
  206. size is computed as ``h = rel_step * sign(x) * max(1, abs(x))``,
  207. possibly adjusted to fit into the bounds. For ``method='3-point'``
  208. the sign of `h` is ignored. If None (default) then step is selected
  209. automatically.
  210. """
  211. _check_unknown_options(unknown_options)
  212. iter = maxiter - 1
  213. acc = ftol
  214. epsilon = eps
  215. if not disp:
  216. iprint = 0
  217. # Transform x0 into an array.
  218. x = asfarray(x0).flatten()
  219. # SLSQP is sent 'old-style' bounds, 'new-style' bounds are required by
  220. # ScalarFunction
  221. if bounds is None or len(bounds) == 0:
  222. new_bounds = (-np.inf, np.inf)
  223. else:
  224. new_bounds = old_bound_to_new(bounds)
  225. # clip the initial guess to bounds, otherwise ScalarFunction doesn't work
  226. x = np.clip(x, new_bounds[0], new_bounds[1])
  227. # Constraints are triaged per type into a dictionary of tuples
  228. if isinstance(constraints, dict):
  229. constraints = (constraints, )
  230. cons = {'eq': (), 'ineq': ()}
  231. for ic, con in enumerate(constraints):
  232. # check type
  233. try:
  234. ctype = con['type'].lower()
  235. except KeyError as e:
  236. raise KeyError('Constraint %d has no type defined.' % ic) from e
  237. except TypeError as e:
  238. raise TypeError('Constraints must be defined using a '
  239. 'dictionary.') from e
  240. except AttributeError as e:
  241. raise TypeError("Constraint's type must be a string.") from e
  242. else:
  243. if ctype not in ['eq', 'ineq']:
  244. raise ValueError("Unknown constraint type '%s'." % con['type'])
  245. # check function
  246. if 'fun' not in con:
  247. raise ValueError('Constraint %d has no function defined.' % ic)
  248. # check Jacobian
  249. cjac = con.get('jac')
  250. if cjac is None:
  251. # approximate Jacobian function. The factory function is needed
  252. # to keep a reference to `fun`, see gh-4240.
  253. def cjac_factory(fun):
  254. def cjac(x, *args):
  255. x = _check_clip_x(x, new_bounds)
  256. if jac in ['2-point', '3-point', 'cs']:
  257. return approx_derivative(fun, x, method=jac, args=args,
  258. rel_step=finite_diff_rel_step,
  259. bounds=new_bounds)
  260. else:
  261. return approx_derivative(fun, x, method='2-point',
  262. abs_step=epsilon, args=args,
  263. bounds=new_bounds)
  264. return cjac
  265. cjac = cjac_factory(con['fun'])
  266. # update constraints' dictionary
  267. cons[ctype] += ({'fun': con['fun'],
  268. 'jac': cjac,
  269. 'args': con.get('args', ())}, )
  270. exit_modes = {-1: "Gradient evaluation required (g & a)",
  271. 0: "Optimization terminated successfully",
  272. 1: "Function evaluation required (f & c)",
  273. 2: "More equality constraints than independent variables",
  274. 3: "More than 3*n iterations in LSQ subproblem",
  275. 4: "Inequality constraints incompatible",
  276. 5: "Singular matrix E in LSQ subproblem",
  277. 6: "Singular matrix C in LSQ subproblem",
  278. 7: "Rank-deficient equality constraint subproblem HFTI",
  279. 8: "Positive directional derivative for linesearch",
  280. 9: "Iteration limit reached"}
  281. # Set the parameters that SLSQP will need
  282. # meq, mieq: number of equality and inequality constraints
  283. meq = sum(map(len, [atleast_1d(c['fun'](x, *c['args']))
  284. for c in cons['eq']]))
  285. mieq = sum(map(len, [atleast_1d(c['fun'](x, *c['args']))
  286. for c in cons['ineq']]))
  287. # m = The total number of constraints
  288. m = meq + mieq
  289. # la = The number of constraints, or 1 if there are no constraints
  290. la = array([1, m]).max()
  291. # n = The number of independent variables
  292. n = len(x)
  293. # Define the workspaces for SLSQP
  294. n1 = n + 1
  295. mineq = m - meq + n1 + n1
  296. len_w = (3*n1+m)*(n1+1)+(n1-meq+1)*(mineq+2) + 2*mineq+(n1+mineq)*(n1-meq) \
  297. + 2*meq + n1 + ((n+1)*n)//2 + 2*m + 3*n + 3*n1 + 1
  298. len_jw = mineq
  299. w = zeros(len_w)
  300. jw = zeros(len_jw)
  301. # Decompose bounds into xl and xu
  302. if bounds is None or len(bounds) == 0:
  303. xl = np.empty(n, dtype=float)
  304. xu = np.empty(n, dtype=float)
  305. xl.fill(np.nan)
  306. xu.fill(np.nan)
  307. else:
  308. bnds = array([(_arr_to_scalar(l), _arr_to_scalar(u))
  309. for (l, u) in bounds], float)
  310. if bnds.shape[0] != n:
  311. raise IndexError('SLSQP Error: the length of bounds is not '
  312. 'compatible with that of x0.')
  313. with np.errstate(invalid='ignore'):
  314. bnderr = bnds[:, 0] > bnds[:, 1]
  315. if bnderr.any():
  316. raise ValueError('SLSQP Error: lb > ub in bounds %s.' %
  317. ', '.join(str(b) for b in bnderr))
  318. xl, xu = bnds[:, 0], bnds[:, 1]
  319. # Mark infinite bounds with nans; the Fortran code understands this
  320. infbnd = ~isfinite(bnds)
  321. xl[infbnd[:, 0]] = np.nan
  322. xu[infbnd[:, 1]] = np.nan
  323. # ScalarFunction provides function and gradient evaluation
  324. sf = _prepare_scalar_function(func, x, jac=jac, args=args, epsilon=eps,
  325. finite_diff_rel_step=finite_diff_rel_step,
  326. bounds=new_bounds)
  327. # gh11403 SLSQP sometimes exceeds bounds by 1 or 2 ULP, make sure this
  328. # doesn't get sent to the func/grad evaluator.
  329. wrapped_fun = _clip_x_for_func(sf.fun, new_bounds)
  330. wrapped_grad = _clip_x_for_func(sf.grad, new_bounds)
  331. # Initialize the iteration counter and the mode value
  332. mode = array(0, int)
  333. acc = array(acc, float)
  334. majiter = array(iter, int)
  335. majiter_prev = 0
  336. # Initialize internal SLSQP state variables
  337. alpha = array(0, float)
  338. f0 = array(0, float)
  339. gs = array(0, float)
  340. h1 = array(0, float)
  341. h2 = array(0, float)
  342. h3 = array(0, float)
  343. h4 = array(0, float)
  344. t = array(0, float)
  345. t0 = array(0, float)
  346. tol = array(0, float)
  347. iexact = array(0, int)
  348. incons = array(0, int)
  349. ireset = array(0, int)
  350. itermx = array(0, int)
  351. line = array(0, int)
  352. n1 = array(0, int)
  353. n2 = array(0, int)
  354. n3 = array(0, int)
  355. # Print the header if iprint >= 2
  356. if iprint >= 2:
  357. print("%5s %5s %16s %16s" % ("NIT", "FC", "OBJFUN", "GNORM"))
  358. # mode is zero on entry, so call objective, constraints and gradients
  359. # there should be no func evaluations here because it's cached from
  360. # ScalarFunction
  361. fx = wrapped_fun(x)
  362. g = append(wrapped_grad(x), 0.0)
  363. c = _eval_constraint(x, cons)
  364. a = _eval_con_normals(x, cons, la, n, m, meq, mieq)
  365. while 1:
  366. # Call SLSQP
  367. slsqp(m, meq, x, xl, xu, fx, c, g, a, acc, majiter, mode, w, jw,
  368. alpha, f0, gs, h1, h2, h3, h4, t, t0, tol,
  369. iexact, incons, ireset, itermx, line,
  370. n1, n2, n3)
  371. if mode == 1: # objective and constraint evaluation required
  372. fx = wrapped_fun(x)
  373. c = _eval_constraint(x, cons)
  374. if mode == -1: # gradient evaluation required
  375. g = append(wrapped_grad(x), 0.0)
  376. a = _eval_con_normals(x, cons, la, n, m, meq, mieq)
  377. if majiter > majiter_prev:
  378. # call callback if major iteration has incremented
  379. if callback is not None:
  380. callback(np.copy(x))
  381. # Print the status of the current iterate if iprint > 2
  382. if iprint >= 2:
  383. print("%5i %5i % 16.6E % 16.6E" % (majiter, sf.nfev,
  384. fx, linalg.norm(g)))
  385. # If exit mode is not -1 or 1, slsqp has completed
  386. if abs(mode) != 1:
  387. break
  388. majiter_prev = int(majiter)
  389. # Optimization loop complete. Print status if requested
  390. if iprint >= 1:
  391. print(exit_modes[int(mode)] + " (Exit mode " + str(mode) + ')')
  392. print(" Current function value:", fx)
  393. print(" Iterations:", majiter)
  394. print(" Function evaluations:", sf.nfev)
  395. print(" Gradient evaluations:", sf.ngev)
  396. return OptimizeResult(x=x, fun=fx, jac=g[:-1], nit=int(majiter),
  397. nfev=sf.nfev, njev=sf.ngev, status=int(mode),
  398. message=exit_modes[int(mode)], success=(mode == 0))
  399. def _eval_constraint(x, cons):
  400. # Compute constraints
  401. if cons['eq']:
  402. c_eq = concatenate([atleast_1d(con['fun'](x, *con['args']))
  403. for con in cons['eq']])
  404. else:
  405. c_eq = zeros(0)
  406. if cons['ineq']:
  407. c_ieq = concatenate([atleast_1d(con['fun'](x, *con['args']))
  408. for con in cons['ineq']])
  409. else:
  410. c_ieq = zeros(0)
  411. # Now combine c_eq and c_ieq into a single matrix
  412. c = concatenate((c_eq, c_ieq))
  413. return c
  414. def _eval_con_normals(x, cons, la, n, m, meq, mieq):
  415. # Compute the normals of the constraints
  416. if cons['eq']:
  417. a_eq = vstack([con['jac'](x, *con['args'])
  418. for con in cons['eq']])
  419. else: # no equality constraint
  420. a_eq = zeros((meq, n))
  421. if cons['ineq']:
  422. a_ieq = vstack([con['jac'](x, *con['args'])
  423. for con in cons['ineq']])
  424. else: # no inequality constraint
  425. a_ieq = zeros((mieq, n))
  426. # Now combine a_eq and a_ieq into a single a matrix
  427. if m == 0: # no constraints
  428. a = zeros((la, n))
  429. else:
  430. a = vstack((a_eq, a_ieq))
  431. a = concatenate((a, zeros([la, 1])), 1)
  432. return a