scijit.optimize.fmin_slsqp¶
- scijit.optimize.fmin_slsqp(func, x0, eqcons=(), f_eqcons=None, ieqcons=(), f_ieqcons=None, bounds=(), fprime=None, fprime_eqcons=None, fprime_ieqcons=None, args=(), iter=100, acc=1e-06, iprint=1, disp=None, full_output=0, epsilon=1.4901161193847656e-08, callback=None)¶
Minimize a function subject to equality, inequality and bound constraints.
SLSQP – sequential least-squares programming – replaces the problem at each iteration with a quadratic model under linearized constraints, and solves that subproblem as a least-squares fit.
Callable from Python and from inside
@njit. Both entries run the same compiled driver. Where a refused argument is reported differs: from Python as aValueErrorwhile the call runs, from@njitas aTypingErrorwhile it compiles, both naming the argument.- Parameters:
- funccallable
A plain
@njitf(x, *args) -> value.- x0array_like
Initial guess. Any rank is flattened, and it is clipped into bounds before the first evaluation.
- eqconstuple of callables, optional
Equality constraints
g(x, *args) -> floatorg(x, *args) -> array, feasible where the result is0. An entry returning an array contributes one constraint per element. Every entry is a plain@njitfunction. Empty (default) is no equality constraint. Inside@njitthe tuple is a compile-time constant: its length and the functions in it decide what is compiled. Given together with f_eqcons the two are APPENDED, these entries first, and these entries are differenced even when f_eqcons carries an analytic Jacobian.- f_eqconscallable or None, optional
ceq(x, *args) -> array, all equality constraints at once, feasible where the result is0. Compile-time constant inside@njit.- ieqconstuple of callables, optional
Inequality constraints, feasible where the result is
>= 0. Otherwise as eqcons, and appended ahead of f_ieqcons the same way.- f_ieqconscallable or None, optional
cineq(x, *args) -> array, all inequality constraints at once, feasible where the result is>= 0.- boundssequence of (min, max) pairs, (n, 2) ndarray, or (), optional
Every spelling
fmin_l_bfgs_b()accepts. Empty (default) andNoneare both unbounded, where fmin_l_bfgs_b takesNonealone and refuses an empty sequence. A length other thanlen(x0)is an IndexError here and a ValueError there. The pairs are read by transposition, so each row must hold exactly two entries.- fprimecallable or None, optional
grad(x, *args) -> array.None(default) computes the gradient by forward differences with absolute step epsilon.- fprime_eqcons, fprime_ieqconscallable or None, optional
(m, n)Jacobian of f_eqcons / f_ieqcons alone, not of the eqcons / ieqcons entries appended before it.None(default) computes it by forward differences. Ignored when the matching vector function is absent.- argstuple or ndarray, optional
Extra values for every callback. A tuple is unpacked into their argument lists,
f(x, *args); the entries may be of any types the callbacks accept.()(default) callsf(x).- iterint, optional
Maximum major iterations. Default 100.
- accfloat, optional
Requested accuracy. Default 1e-6.
- iprintint, optional
1(default) prints the exit summary.0and below are silent.2and above add a per-iteration table, one row per major iteration, ahead of the summary.- dispint or None, optional
Overrides iprint when it is not
None.- full_outputbool, optional
False(default) returns x alone.Truereturns the 5-tuple. Compile-time constant inside@njit: it selects the return type.- epsilonfloat or ndarray, optional
Absolute step for every finite-difference path. Default
sqrt(eps). An array gives one step per coordinate; a size-1 array applies to every coordinate.- callbackcallable, optional
Called once per major iteration, as
callback(xk)orcallback(intermediate_result). Two spellings are served: a plain Python callable, which halts the solve when it raisesStopIteration, and a numba@njitcallback(xk), which halts when it raises any exception. See Notes.
- Returns:
- outndarray, or tuple
x alone, or with full_output the 5-tuple
(x, fx, its, imode, smode): the minimizer, its objective value, the major-iteration count, the exit mode and the message for it.imode == 0is success,8a bad line search and9the iteration limit.
- Raises:
- IndexError
If the length of bounds is neither 0 nor
len(x0).- ValueError
If callback is a
@cfunc, a raw function address or a non-callable; if an entry of eqcons or ieqcons is a plain Python callable; if a row of bounds does not hold two entries; if any lower bound exceeds its upper bound; if epsilon does not broadcast against x0 while a forward difference is taken; or if a gradient or constraint Jacobian comes back with the wrong shape.- TypeError
If an entry of eqcons or ieqcons is not callable, or if a row of bounds is a number rather than a pair.
See also
scipy.optimize.fmin_slsqpThe scipy routine this mirrors.
scijit.optimize.minimizeDispatches here for
method='SLSQP'.scijit.optimize.fmin_cobylaDerivative-free, nonlinear constraints.
scijit.optimize.fmin_l_bfgs_bBounds only, no general constraints.
Notes
eqcons and ieqcons are a TUPLE of
@njitfunctions, where scipy takes a list of Python callables. The tuple is combined into one vector-valued function when the call compiles and handed to the same slot f_eqcons and f_ieqcons fill, so the two spellings run the same code and their Jacobians come from the same forward differences.An ndarray or a list args reaches every callback as ONE argument,
f(x, args), where scipy unpacks those two element by element. The arity of a compiled call is fixed when it compiles, so a sequence whose length is known only at run time cannot be unpacked.Whether f_eqcons, f_ieqcons, fprime, fprime_eqcons and fprime_ieqcons are
Noneis a compile-time constant inside@njit, since numba has noNone-able function argument. full_output is likewise a compile-time literal, because it selects the return type.A Python callback is reached from compiled code through a module-level slot and a
numba.objmodeblock, so it takes the GIL and pays an interpreter round trip once per major iteration. It is also notprange-safe, because the slot is module state that two concurrent solves share. Inside@njitonly the@njitspelling is accepted, since a Python callable cannot cross into compiled code as an argument.The two spellings differ in what halts the solve. The Python one halts on
StopIteration, which is scipy’s contract; anything else it raises reaches the caller. The@njitone halts on ANY exception, because numba matches no exception class:except StopIterationdoes not compile.iprint prints scipy’s exit summary at its scipy default of
1, so a bare call writes to stdout.A bounds LONGER than x0 raises the same
IndexErroras a shorter one. scipy reaches annp.clipbefore its own length test in that direction and surfaces a numpy broadcastValueErrorinstead.A gradient or constraint Jacobian of the wrong shape raises. numba applies no bounds checking, so an unchecked wrong shape would read past the end of the buffer rather than fail.
Safe to call from a
numba.prangeloop with callback atNoneor an@njitfunction: the solver is reverse communication, so its state lives in caller-owned arrays. A Python callback is not, and serializes the loop.https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.fmin_slsqp.html
Examples
Minimize
x0**2 + x1**2subject tox0 + x1 >= 1:>>> import numpy as np >>> from numba import njit >>> from scijit.optimize import fmin_slsqp >>> @njit ... def obj(x): ... return x[0] ** 2 + x[1] ** 2 >>> @njit ... def cineq(x): ... return np.array([x[0] + x[1] - 1.0]) >>> @njit ... def run(): ... return fmin_slsqp(obj, np.array([2.0, 1.0]), f_ieqcons=cineq) >>> run() Optimization terminated successfully (Exit mode 0) Current function value: 0.5 Iterations: 4 Function evaluations: 12 Gradient evaluations: 4 array([0.5, 0.5])
iprint defaults to scipy’s
1, so the exit summary above is what a bare call writes to stdout. With full_output, which must be a literal inside@njit:>>> @njit ... def run_full(): ... return fmin_slsqp(obj, np.array([2.0, 1.0]), f_ieqcons=cineq, ... full_output=True) >>> x, fx, its, imode, smode = run_full() Optimization terminated successfully (Exit mode 0) Current function value: 0.5 Iterations: 4 Function evaluations: 12 Gradient evaluations: 4 >>> fx, its, imode (0.5, 4, 0) >>> smode 'Optimization terminated successfully'