Documentation
¶
Overview ¶
Package optimize provides numerical optimisation and root finding in pure Go: unconstrained and bound-constrained minimisation (Nelder–Mead, Powell, CG, BFGS, Newton-CG, L-BFGS-B), scalar minimisation (Brent, golden section, bounded), scalar roots (Brent, Ridder, bisection, Newton, secant, Halley), systems of equations (MINPACK's hybrid Powell method), nonlinear least squares (MINPACK Levenberg–Marquardt and trust-region reflective with bounds and robust losses), curve fitting with parameter covariance, and linear programming.
The API follows scipy.optimize closely enough that each function documents the SciPy call it corresponds to, and the test suite checks the results against SciPy fixtures; the implementation is independent Go.
Index ¶
- Constants
- Variables
- func ApproxFprime(f func([]float64) float64, x []float64, epsilon float64) []float64
- func Bracket(f func(float64) float64, xa, xb float64) (x [3]float64, fx [3]float64, nfev int, err error)
- func CheckGrad(f func([]float64) float64, grad func(x, g []float64), x []float64, ...) float64
- type Bound
- type BracketError
- type BracketOptions
- type BruteOptions
- type BruteResult
- type Constraint
- type ConstraintKind
- type ConstraintSpec
- type CurveFitOptions
- type CurveFitResult
- type FDMethod
- type LPConstraints
- type LPDual
- type LPMethod
- type LPOptions
- type LPResult
- type LSMethod
- type LSOptions
- type LSProblem
- type LSResult
- type LeastsqOptions
- type LeastsqResult
- type LinearConstraint
- type Loss
- type Method
- type Model
- type NewtonOptions
- type NonlinearConstraint
- type Options
- type Problem
- type QPConstraints
- type QPMethod
- type QPOptions
- type QPProblem
- type QPResult
- type QPSolver
- type Range
- type Result
- type RootOptions
- type RootResult
- type RootScalarOptions
- type RootScalarResult
- func Bisect(f func(float64) float64, a, b float64, o *BracketOptions) (*RootScalarResult, error)
- func Brenth(f func(float64) float64, a, b float64, o *BracketOptions) (*RootScalarResult, error)
- func Brentq(f func(float64) float64, a, b float64, o *BracketOptions) (*RootScalarResult, error)
- func Newton(f func(float64) float64, x0 float64, o *NewtonOptions) (*RootScalarResult, error)
- func Ridder(f func(float64) float64, a, b float64, o *BracketOptions) (*RootScalarResult, error)
- func RootScalar(f func(float64) float64, method string, o *RootScalarOptions) (*RootScalarResult, error)
- type ScalarMethod
- type ScalarOptions
- type ScalarResult
- type SystemProblem
Examples ¶
Constants ¶
const ( LPOptimal = 0 // optimisation terminated successfully LPIterLimit = 1 // iteration limit reached LPInfeasible = 2 // problem appears to be infeasible LPUnbounded = 3 // problem appears to be unbounded LPNumericalFail = 4 // numerical difficulties encountered )
LP status codes, as scipy.optimize.linprog reports them in status.
const ( QPOptimal = 0 // KKT conditions hold within tolerance QPIterLimit = 1 QPInfeasible = 2 // with a certificate in PrimalCert QPUnbounded = 3 // with a certificate in DualCert (ADMM only) QPNumericalFail = 4 QPNonConvex = 5 // ADMM residuals above 1e30 (OSQP_NON_CVX) QPInaccurate = 6 // ADMM met the tolerances ×10 only )
QP status codes. 0–4 have Linprog's meaning; 5 and 6 are QP-specific.
const ( FlagConverged = "converged" FlagConvErr = "convergence error" FlagSignErr = "sign error" )
Root-finder flags, as SciPy's RootResults.flag strings.
Variables ¶
var ( // ErrDimension reports slices whose lengths disagree. ErrDimension = errors.New("optimize: dimension mismatch") // ErrMethod reports an unknown or unsupported method. ErrMethod = errors.New("optimize: unknown method") // ErrBounds reports inconsistent bounds or a starting point outside them. ErrBounds = errors.New("optimize: invalid bounds") // ErrBracket reports a scalar root bracket whose ends do not change sign. ErrBracket = errors.New("optimize: f(a) and f(b) must have different signs") // ErrInput reports any other invalid argument. ErrInput = errors.New("optimize: invalid input") )
Errors returned for invalid input. Failure to converge is not an error: it is reported through the Success, Status and Message fields of a result, as SciPy does, so the caller still receives the best point found.
var ErrNotConverged = errors.New("optimize: optimal parameters not found")
ErrNotConverged is returned by CurveFit when the least-squares solver did not converge (SciPy raises RuntimeError("Optimal parameters not found")). The partial result is returned alongside it.
Functions ¶
func ApproxFprime ¶
ApproxFprime returns the forward-difference gradient of f at x with the absolute step epsilon (0 selects SciPy's default sqrt(eps) ≈ 1.49e-8), as scipy.optimize.approx_fprime(xk, f, epsilon) does.
func Bracket ¶
func Bracket(f func(float64) float64, xa, xb float64) (x [3]float64, fx [3]float64, nfev int, err error)
Bracket searches downhill from xa, xb (0 and 1 when both are zero) for three points xa, xb, xc with f(xb) below f(xa) and f(xc); it is scipy.optimize.bracket(func, xa, xb, grow_limit=110, maxiter=1000). It returns the points, their values and the number of evaluations, or a *BracketError.
func CheckGrad ¶
func CheckGrad(f func([]float64) float64, grad func(x, g []float64), x []float64, epsilon float64) float64
CheckGrad returns the Euclidean norm of the difference between grad(x) and a forward-difference gradient of f with absolute step epsilon (0 for the default), like scipy.optimize.check_grad(func, grad, x0, epsilon=...). grad writes the gradient at x into its second argument.
Types ¶
type Bound ¶
type Bound struct {
Lo, Hi float64
}
Bound is a closed interval [Lo, Hi] for one variable. Use math.Inf(-1) and math.Inf(1) for a missing side; the zero value Bound{} pins the variable to zero, so use Unbounded() for a free variable.
type BracketError ¶
BracketError reports that Bracket found no valid bracket. It carries the last three points, as SciPy's BracketError does.
func (*BracketError) Error ¶
func (e *BracketError) Error() string
type BracketOptions ¶
BracketOptions configures the bracketing root finders. Zero values select SciPy's defaults: Xtol 2e-12, Rtol 4·eps (the smallest allowed), MaxIter 100.
type BruteOptions ¶
type BruteOptions struct {
// Ns is the number of grid points per axis when Range.Step is 0 (20).
Ns int
// NoFinish skips the final local minimisation (SciPy's finish=None).
NoFinish bool
// Finish is the local method polishing the best grid point
// (Nelder-Mead, SciPy's fmin). Finish options come from FinishOptions.
Finish Method
FinishOptions *Options
// Workers evaluates the grid with this many goroutines (1). The
// objective must then be safe for concurrent use.
Workers int
}
BruteOptions configures Brute.
type BruteResult ¶
type BruteResult struct {
// X and Fun are the minimiser and its value (after the finish step).
X []float64
Fun float64
// Success is false when the finish step did not converge.
Success bool
// Axes holds the coordinates of each grid axis; Jout the objective on
// the grid, row-major over the axes (shape len(Axes[0]) × …).
Axes [][]float64
Jout []float64
}
BruteResult is Brute's full output (SciPy's full_output=True).
func Brute ¶
func Brute(f func([]float64) float64, ranges []Range, o *BruteOptions) (*BruteResult, error)
Brute minimises f by evaluating it on a grid and polishing the best point with a local method; it is scipy.optimize.brute(func, ranges, Ns=20, full_output=True, finish=fmin, workers=...). The finish step may leave the grid's box, as in SciPy.
type Constraint ¶ added in v0.3.0
type Constraint struct {
// Kind selects c(x) = 0 (Eq) or c(x) >= 0 (Ineq).
Kind ConstraintKind
// M is the number of outputs of Func.
M int
// Func writes the M constraint values at x into c.
Func func(x, c []float64)
// Jac writes the M×n Jacobian at x into jac, row-major. When nil it is
// estimated by forward differences.
Jac func(x, jac []float64)
}
Constraint is a block of M constraint functions of one kind, SciPy's dictionary form {'type': 'eq'|'ineq', 'fun': ..., 'jac': ...}.
type ConstraintKind ¶ added in v0.3.0
type ConstraintKind int
ConstraintKind tells whether a Constraint is an equality or an inequality.
const ( // Eq is the equality constraint c(x) = 0 (SciPy type 'eq'). Eq ConstraintKind = iota // Ineq is the inequality constraint c(x) >= 0 (SciPy type 'ineq'). Ineq )
type ConstraintSpec ¶ added in v0.3.0
type ConstraintSpec interface {
// contains filtered or unexported methods
}
ConstraintSpec is a general constraint accepted by the constrained minimisers (Options.Constraints): a Constraint, a NonlinearConstraint or a LinearConstraint, the three forms scipy.optimize.minimize accepts. The interface is sealed. SLSQP reduces every form to equality blocks c(x) = 0 and inequality blocks c(x) >= 0; trust-constr keeps SciPy's general form lb <= f(x) <= ub.
type CurveFitOptions ¶
type CurveFitOptions struct {
// Sigma is the uncertainty of ydata: a 1-D array of standard
// deviations (the residuals are divided by it) or a 2-D covariance
// matrix (the residuals are whitened by its Cholesky factor). nil means
// unit weights.
Sigma *ndarray.Array
// AbsoluteSigma uses Sigma in an absolute sense: Pcov is not scaled by
// the reduced chi-square.
AbsoluteSigma bool
// Bounds on the parameters; bounds select TRF.
Bounds []Bound
// Method is LM (the default without bounds) or TRF (with bounds).
Method LSMethod
// MaxFev, Ftol, Xtol and Gtol are passed to the solver (SciPy's maxfev
// for LM, max_nfev for TRF; tolerances 1.49012e-8 for LM, 1e-8 for TRF).
MaxFev int
Ftol, Xtol, Gtol float64
// Loss and FScale select a robust loss (TRF only), as SciPy forwards
// loss= and f_scale= to least_squares.
Loss Loss
FScale float64
// Workers evaluates the model over the samples with this many
// goroutines when there are at least 2048 samples (default 1). The
// model must then be safe for concurrent use; the result is identical.
Workers int
}
CurveFitOptions configures CurveFit. Zero values select SciPy's defaults.
type CurveFitResult ¶
type CurveFitResult struct {
// Popt holds the fitted parameters.
Popt []float64
// Pcov is the n×n covariance of Popt, row-major. When it cannot be
// estimated every entry is +Inf and CovOK is false (SciPy warns).
Pcov []float64
CovOK bool
// Fvec holds the (weighted) residuals at Popt and Nfev the solver's
// count of residual evaluations (SciPy's infodict['nfev']: MINPACK's
// count including finite differences for LM, least_squares' count
// excluding them for TRF).
Fvec []float64
Nfev int
// Status and Message are the solver's (SciPy's ier and mesg).
Status int
Message string
}
CurveFitResult is the outcome of CurveFit: SciPy's (popt, pcov) plus its full_output information.
func CurveFit ¶
func CurveFit(f func(x float64, p []float64) float64, xdata, ydata *ndarray.Array, p0 []float64, o *CurveFitOptions) (*CurveFitResult, error)
CurveFit fits a 1-D model f(x; p) to (xdata, ydata) by nonlinear least squares; it is scipy.optimize.curve_fit(f, xdata, ydata, p0, sigma=..., absolute_sigma=..., bounds=..., method=...). See CurveFitModel for models of several independent variables or with analytic derivatives.
Example ¶
popt, pcov = scipy.optimize.curve_fit(lambda x, a, b, c: a*np.exp(-b*x) + c, x, y)
package main
import (
"fmt"
"math"
"github.com/go-ndarray/ndarray"
"github.com/go-numerics/optimize"
)
func main() {
x, _ := ndarray.Linspace(0, 4, 50)
y := x.Map(func(v float64) float64 { return 2.5*math.Exp(-1.3*v) + 0.5 + 0.01*math.Sin(37*v) })
model := func(x float64, p []float64) float64 { return p[0]*math.Exp(-p[1]*x) + p[2] }
r, err := optimize.CurveFit(model, x, y, []float64{1, 1, 1}, nil)
if err != nil {
panic(err)
}
perr := r.Perr()
fmt.Printf("a = %.3f ± %.3f, b = %.3f ± %.3f, c = %.3f ± %.3f\n",
r.Popt[0], perr[0], r.Popt[1], perr[1], r.Popt[2], perr[2])
}
Output: a = 2.500 ± 0.004, b = 1.300 ± 0.005, c = 0.500 ± 0.002
func CurveFitModel ¶
func CurveFitModel(model Model, xdata, ydata *ndarray.Array, p0 []float64, o *CurveFitOptions) (*CurveFitResult, error)
CurveFitModel is CurveFit for a general Model. xdata is 1-D (m samples) or 2-D (k, m); ydata is 1-D with m elements. p0 sets the number of parameters; nil starts from SciPy's default (ones, or a feasible point inside the bounds) when Bounds gives the count.
Without bounds the default method is MINPACK's Levenberg–Marquardt and the covariance is SciPy leastsq's cov_x; with TRF it is the pseudo-inverse of JᵀJ from the SVD of the final Jacobian, discarding singular values below eps·max(m, n)·s₀. Unless AbsoluteSigma is set the covariance is scaled by the reduced chi-square Σr²/(m − n).
func (*CurveFitResult) PcovArray ¶
func (r *CurveFitResult) PcovArray() *ndarray.Array
PcovArray returns Pcov as an n×n ndarray.
func (*CurveFitResult) Perr ¶
func (r *CurveFitResult) Perr() []float64
Perr returns the one-standard-deviation errors √diag(Pcov).
func (*CurveFitResult) PoptArray ¶
func (r *CurveFitResult) PoptArray() *ndarray.Array
PoptArray returns Popt as a 1-D ndarray.
type FDMethod ¶
type FDMethod int
FDMethod selects a finite-difference scheme.
const ( // FD2Point is the forward difference (SciPy '2-point'), one evaluation // per variable, error O(h). FD2Point FDMethod = iota // FD3Point is the central difference (SciPy '3-point'), two evaluations // per variable, error O(h²); it falls back to a one-sided second-order // formula next to a bound. FD3Point )
type LPConstraints ¶
type LPConstraints struct {
// AUb and BUb are the inequality constraints A_ub·x <= b_ub.
AUb, BUb *ndarray.Array
// AEq and BEq are the equality constraints A_eq·x == b_eq.
AEq, BEq *ndarray.Array
// Bounds gives one interval per variable. nil means linprog's default
// (0, +Inf) for every variable — note that this differs from Minimize,
// where nil means unbounded. Use Unbounded() for a free variable.
Bounds []Bound
}
LPConstraints holds the constraints of a linear program
A_ub·x <= b_ub, A_eq·x == b_eq, Bounds[i].Lo <= x[i] <= Bounds[i].Hi,
in the shape of linprog's A_ub, b_ub, A_eq, b_eq and bounds arguments. Any of the matrices may be nil (no such constraints); a non-nil matrix must be 2-D with len(c) columns and its right-hand side 1-D with one entry per row.
type LPDual ¶
type LPDual struct {
// Residual is the slack of each constraint: b_ub − A_ub·x for
// inequalities, b_eq − A_eq·x for equalities, x − lb and ub − x for
// the bounds (±Inf for a missing bound).
Residual []float64
// Marginals is the sensitivity of the optimal objective to the
// constraint's right-hand side (∂fun/∂b), with SciPy's HiGHS sign
// convention: ineqlin and upper marginals are <= 0, lower marginals
// are >= 0, eqlin marginals have any sign. They satisfy
// c = A_ubᵀ·ineqlin + A_eqᵀ·eqlin + lower + upper. nil unless Status
// is 0.
Marginals []float64
}
LPDual pairs the residuals of one family of constraints with their marginals (dual values), like the ineqlin, eqlin, lower and upper fields of SciPy's HiGHS result.
type LPMethod ¶
type LPMethod string
LPMethod names a linear-programming algorithm. The values are the strings SciPy's linprog accepts for the matching legacy methods.
const ( // LPSimplex is a dense bounded-variable revised simplex method with an // LU-factorised basis and product-form updates. It is the default: it // ends on a vertex, its duals are exact for the final basis, and it // certifies infeasibility and unboundedness directly. LPSimplex LPMethod = "revised simplex" // LPInteriorPoint is the homogeneous self-dual primal–dual // interior-point method of Andersen & Andersen with Mehrotra's // predictor–corrector, solving dense normal equations by Cholesky. Its // solution is interior to the optimal face, not a vertex. LPInteriorPoint LPMethod = "interior-point" )
Linear-programming methods implemented by Linprog.
type LPOptions ¶
type LPOptions struct {
// Method selects the algorithm; the default is LPSimplex.
Method LPMethod
// Tol is the primal and dual feasibility tolerance. Default 1e-9 for
// LPSimplex and 1e-8 for LPInteriorPoint (SciPy's interior-point
// default). As in SciPy, the final feasibility check uses 10·√Tol.
Tol float64
// MaxIter bounds the iterations (simplex pivots and bound flips over
// both phases, or interior-point iterations). Default 5000 for
// LPSimplex and 1000 for LPInteriorPoint, as in SciPy.
MaxIter int
// NoPresolve disables the presolve pass (linprog's presolve=False).
NoPresolve bool
}
LPOptions configures Linprog. Zero values select the defaults listed with each field.
type LPResult ¶
type LPResult struct {
// X is the solution. When Status is not 0 it is the last point the
// solver held (it may violate the constraints), or nil when presolve
// stopped before any solve.
X []float64
// Fun is c·X.
Fun float64
// Slack is b_ub − A_ub·X and Con is b_eq − A_eq·X.
Slack, Con []float64
// IneqLin, EqLin, Lower and Upper hold residuals and marginals of the
// inequality rows, equality rows, lower bounds and upper bounds.
IneqLin, EqLin, Lower, Upper LPDual
// Status is SciPy's code: 0 optimal, 1 iteration limit, 2 infeasible,
// 3 unbounded, 4 numerical difficulties.
Status int
// Success reports Status == 0.
Success bool
// Message describes the reason for termination.
Message string
// Nit counts iterations over all phases.
Nit int
}
LPResult is the outcome of Linprog, the counterpart of the OptimizeResult that scipy.optimize.linprog returns.
func Linprog ¶
func Linprog(c []float64, cons LPConstraints, opts *LPOptions) (*LPResult, error)
Linprog minimises c·x subject to cons; it is the counterpart of scipy.optimize.linprog(c, A_ub, b_ub, A_eq, b_eq, bounds, method=...). SciPy's default HiGHS solvers are not available; opts.Method selects a dense revised simplex (default) or a dense interior-point method, after a light version of the presolve SciPy applies to its legacy methods: empty rows and columns and fixed variables are removed, trivial infeasibility and unboundedness are reported with SciPy's messages, and linearly dependent equality rows are dropped (or reported inconsistent). Unlike SciPy, singleton rows are left to the solver. The marginals are those of the original problem, with HiGHS's sign convention.
Invalid input (shapes, NaN or Inf coefficients, NaN bounds, unknown method) is an error wrapping ErrDimension, ErrInput, ErrBounds or ErrMethod. Infeasible, unbounded or unsolved problems are not errors: they are reported through Status, Success and Message.
Example ¶
scipy.optimize.linprog(c, A_ub=A, b_ub=b, bounds=[(None, None), (-3, None)])
package main
import (
"fmt"
"math"
"github.com/go-ndarray/ndarray"
"github.com/go-numerics/optimize"
)
func main() {
A, _ := ndarray.FromData([]float64{-3, 1, 1, 2}, 2, 2)
b, _ := ndarray.FromData([]float64{6, 4}, 2)
r, _ := optimize.Linprog([]float64{-1, 4}, optimize.LPConstraints{AUb: A, BUb: b,
Bounds: []optimize.Bound{optimize.Unbounded(), {Lo: -3, Hi: math.Inf(1)}}}, nil)
fmt.Printf("x = [%.1f %.1f], fun = %.1f, %s\n", r.X[0], r.X[1], r.Fun, r.Message)
}
Output: x = [10.0 -3.0], fun = -22.0, Optimization terminated successfully.
type LSMethod ¶
type LSMethod string
LSMethod names a least-squares algorithm; the values are SciPy's least_squares method strings.
const ( // TRF is the trust-region reflective method (SciPy's default), which // supports bounds and robust loss functions. TRF LSMethod = "trf" // LM is the Levenberg–Marquardt method of MINPACK (lmdif/lmder); it // needs m >= n and supports neither bounds nor robust losses. LM LSMethod = "lm" )
Least-squares methods.
type LSOptions ¶
type LSOptions struct {
// Bounds constrains the variables (TRF only). nil means unbounded.
Bounds []Bound
// Ftol, Xtol and Gtol are the termination tolerances (1e-8 each).
// SciPy lets None disable one; here a negative value disables it.
Ftol, Xtol, Gtol float64
// MaxNfev bounds function evaluations (100·n; for LM it bounds
// MINPACK's count, which leaves out finite-difference evaluations).
MaxNfev int
// XScale is the characteristic scale of each variable. nil means 1
// (TRF) or 'jac' (LM, SciPy's default for that method); XScaleJac
// selects SciPy's x_scale='jac'.
XScale []float64
XScaleJac bool
// Loss is the robust loss (TRF only; LossLinear by default) and FScale
// its soft margin between inliers and outliers (1).
Loss Loss
FScale float64
// DiffStep is the relative finite-difference step (SciPy diff_step);
// 0 selects the default of the scheme.
DiffStep float64
// FDMethod is the finite-difference scheme for TRF (FD2Point). LM uses
// MINPACK's own forward differences.
FDMethod FDMethod
}
LSOptions configures LeastSquares. Zero values select SciPy's defaults.
type LSProblem ¶
type LSProblem struct {
// Func writes the m residuals at x into f. Required.
Func func(x, f []float64)
// Jac writes the m×n Jacobian at x into jac, row-major. Optional:
// finite differences are used when it is nil.
Jac func(x, jac []float64)
// M is the number of residuals. Required.
M int
}
LSProblem is a nonlinear least-squares problem: minimise ½·Σ ρ(f_i(x)²) over x, with m residuals f_i and n variables.
type LSResult ¶
type LSResult struct {
// X is the solution.
X []float64
// Cost is ½·Σρ(f_i²) at X.
Cost float64
// Fun holds the m residuals at X.
Fun []float64
// Jac is the m×n Jacobian at X, row-major (modified by the loss, as in
// SciPy).
Jac []float64
// Grad is the gradient of the cost at X.
Grad []float64
// Optimality is the first-order optimality measure (max-norm of the
// scaled gradient, as SciPy defines it per method).
Optimality float64
// ActiveMask is -1 or +1 for a variable at its lower or upper bound,
// 0 otherwise.
ActiveMask []int
// Nfev and Njev count residual and Jacobian evaluations.
Nfev, Njev int
// Status follows SciPy: -1 improper input, 0 max_nfev reached, 1 gtol,
// 2 ftol, 3 xtol, 4 both ftol and xtol satisfied.
Status int
// Success is Status > 0.
Success bool
// Message describes the termination.
Message string
}
LSResult is the outcome of LeastSquares, mirroring the OptimizeResult of scipy.optimize.least_squares.
func LeastSquares ¶
LeastSquares solves a nonlinear least-squares problem from x0; it is scipy.optimize.least_squares(fun, x0, jac=..., bounds=..., method=..., ftol=..., xtol=..., gtol=..., x_scale=..., loss=..., f_scale=..., diff_step=..., max_nfev=...). method "" selects TRF.
Example ¶
scipy.optimize.least_squares(fun, x0, bounds=([0, 0], [2, 0.5]), loss='soft_l1')
package main
import (
"fmt"
"math"
"github.com/go-numerics/optimize"
)
func main() {
t := []float64{0, 1, 2, 3, 4, 5}
y := []float64{1.0, 0.62, 0.36, 0.23, 0.13, 3.0} // the last point is an outlier
p := optimize.LSProblem{M: len(t), Func: func(x, f []float64) {
for i := range t {
f[i] = x[0]*math.Exp(-x[1]*t[i]) - y[i]
}
}}
r, _ := optimize.LeastSquares(p, []float64{1, 0.1}, optimize.TRF, &optimize.LSOptions{
Bounds: []optimize.Bound{{Lo: 0, Hi: 2}, {Lo: 0, Hi: 0.5}}, Loss: optimize.LossSoftL1, FScale: 0.1})
fmt.Printf("x = [%.3f %.3f] active %v\n", r.X[0], r.X[1], r.ActiveMask)
}
Output: x = [0.990 0.466] active [0 0]
type LeastsqOptions ¶
type LeastsqOptions struct {
// Ftol is the relative error desired in the sum of squares and Xtol the
// relative error desired in the solution (1.49012e-8 each; a negative
// value means exactly 0). Gtol is the orthogonality desired between the
// residuals and the Jacobian columns (0).
Ftol, Xtol, Gtol float64
// Maxfev bounds the calls to Func: 0 selects 100·(n+1) with a Jacobian
// and 200·(n+1) without.
Maxfev int
// Epsfcn sets the forward-difference step sqrt(Epsfcn)·|x_j| when there
// is no Jacobian; 0 selects the machine epsilon.
Epsfcn float64
// Factor sets the initial step bound Factor·|diag·x0| (100).
Factor float64
// Diag holds n positive scale factors for the variables; nil lets
// MINPACK scale by the Jacobian column norms.
Diag []float64
}
LeastsqOptions configures Leastsq. Zero values select the defaults of scipy.optimize.leastsq.
type LeastsqResult ¶
type LeastsqResult struct {
// X is the solution (or the last iterate).
X []float64
// CovX is inv(JᵀJ) at X, n×n row-major, from the final R and
// permutation; nil when R is singular or the run did not converge
// (Ier not in 1..4). Multiply it by the residual variance to obtain the
// covariance of X.
CovX []float64
// Nfev counts calls to Func, including those of the finite-difference
// Jacobian; Njev counts calls to Jac (0 without one).
Nfev, Njev int
// Fvec holds the residuals at X.
Fvec []float64
// Fjac is SciPy's infodict['fjac']: an n×m row-major array whose rows
// are the columns of MINPACK's final QR workspace, so that the upper
// triangle of its transpose's first n rows is R with Jac·P = Q·R.
Fjac []float64
// Ipvt is the permutation P: column j of P is column Ipvt[j]
// (zero-based) of the identity.
Ipvt []int
// Qtf is the first n components of Qᵀ·Fvec.
Qtf []float64
// Ier is MINPACK's info: 1 to 4 mean a solution was found, 5 to 8 that
// it was not.
Ier int
// Mesg is SciPy's message for Ier.
Mesg string
}
LeastsqResult is the full output of Leastsq: SciPy's tuple (x, cov_x, infodict, mesg, ier).
func Leastsq ¶
func Leastsq(p LSProblem, x0 []float64, opts *LeastsqOptions) (*LeastsqResult, error)
Leastsq minimises the sum of squares of p.M residuals with MINPACK's Levenberg–Marquardt method; it is scipy.optimize.leastsq(func, x0, Dfun=p.Jac, full_output=True, ftol, xtol, gtol, maxfev, epsfcn, factor, diag). Without p.Jac it runs lmdif (forward differences), otherwise lmder. Non-convergence is reported through Ier and Mesg.
func (*LeastsqResult) CovXArray ¶
func (r *LeastsqResult) CovXArray() *ndarray.Array
CovXArray returns CovX as an n×n ndarray, or nil when absent.
func (*LeastsqResult) FjacArray ¶
func (r *LeastsqResult) FjacArray() *ndarray.Array
FjacArray returns Fjac as an n×m ndarray.
func (*LeastsqResult) Success ¶
func (r *LeastsqResult) Success() bool
Success reports whether Ier is 1, 2, 3 or 4, as SciPy's leastsq judges it.
func (*LeastsqResult) XArray ¶
func (r *LeastsqResult) XArray() *ndarray.Array
XArray returns X as a 1-D ndarray.
type LinearConstraint ¶ added in v0.3.0
LinearConstraint is Lb <= A·x <= Ub, SciPy's LinearConstraint. A is 2-D with n columns (or 1-D, one row); Lb and Ub follow NonlinearConstraint's rules.
type Method ¶
type Method string
Method names a minimisation algorithm. The values are the strings SciPy's minimize accepts for its method argument.
const ( NelderMead Method = "Nelder-Mead" Powell Method = "Powell" CG Method = "CG" BFGS Method = "BFGS" NewtonCG Method = "Newton-CG" LBFGSB Method = "L-BFGS-B" // SLSQP is sequential least-squares quadratic programming; it is the // method that accepts Options.Constraints. SLSQP Method = "SLSQP" // TrustConstr is the trust-region interior-point method (SciPy // 'trust-constr', MATLAB fmincon 'interior-point'); it also accepts // Options.Constraints. TrustConstr Method = "trust-constr" )
Methods implemented by Minimize.
type Model ¶
type Model struct {
// F returns the model value at sample x for parameters p. Required.
F func(x, p []float64) float64
// Grad writes ∂f/∂p at sample x into grad (len(p) values). Optional:
// finite differences are used when it is nil (SciPy's jac=callable).
Grad func(x, p, grad []float64)
// contains filtered or unexported fields
}
Model is a curve-fitting model y = f(x; p) evaluated at one sample. For 1-D xdata x has one element; for xdata of shape (k, m) — k independent variables, m samples, SciPy's layout — x holds the k values of one sample.
type NewtonOptions ¶
type NewtonOptions struct {
// Fprime is the derivative; nil selects the secant method.
Fprime func(float64) float64
// Fprime2 is the second derivative; with Fprime it selects Halley's
// method.
Fprime2 func(float64) float64
// X1 is the second starting point of the secant method; 0 means
// x0·(1+1e-4) ± 1e-4, as in SciPy. Set X1Set to use an explicit 0.
X1 float64
X1Set bool
// Tol and Rtol are the absolute and relative tolerances on successive
// iterates (numpy.isclose semantics).
Tol, Rtol float64
MaxIter int
}
NewtonOptions configures Newton. Zero values select SciPy's defaults: Tol 1.48e-8, Rtol 0, MaxIter 50.
type NonlinearConstraint ¶ added in v0.3.0
type NonlinearConstraint struct {
// M is the number of outputs of Func.
M int
// Func writes the M constraint values at x into c.
Func func(x, c []float64)
// Jac writes the M×n Jacobian, row-major; nil means finite differences.
Jac func(x, jac []float64)
// Lb and Ub bound Func(x).
Lb, Ub []float64
}
NonlinearConstraint is Lb <= Func(x) <= Ub, SciPy's NonlinearConstraint. Lb and Ub have M entries or one entry broadcast to all; nil means -Inf and +Inf. Components with Lb == Ub are equalities; components unbounded on both sides are ignored, as SciPy does.
type Options ¶
type Options struct {
// Bounds constrains the variables (L-BFGS-B, SLSQP, trust-constr,
// Nelder-Mead and Powell, as in SciPy). nil means unbounded.
Bounds []Bound
// Constraints are general equality and inequality constraints
// (SLSQP and trust-constr): Constraint, NonlinearConstraint or
// LinearConstraint values, SciPy's constraints argument. Other methods
// return an error when it is set, where SciPy only warns.
Constraints []ConstraintSpec
// BarrierTol is trust-constr's barrier-parameter tolerance for the xtol
// test (1e-8).
BarrierTol float64
// InitialTrRadius, InitialConstrPenalty, InitialBarrierParameter and
// InitialBarrierTolerance are trust-constr's initial trust radius (1),
// merit penalty (1), barrier parameter (0.1) and barrier subproblem
// tolerance (0.1).
InitialTrRadius, InitialConstrPenalty float64
InitialBarrierParameter, InitialBarrierTolerance float64
// Tol is minimize's tol argument: it sets the method's main tolerance
// the way SciPy does (Nelder-Mead: Xatol and Fatol; Powell: Xtol and
// Ftol; CG and BFGS: Gtol; Newton-CG: Xtol; L-BFGS-B: Ftol and Gtol;
// SLSQP: Ftol; trust-constr: Gtol, Xtol and BarrierTol) when those
// fields are zero.
Tol float64
// MaxIter bounds the iterations (Nelder-Mead 200·n, Powell 1000·n,
// CG, BFGS and Newton-CG 200·n, L-BFGS-B 15000, SLSQP 100,
// trust-constr 1000). For Nelder-Mead and
// Powell, setting only one of MaxIter and MaxFev leaves the other
// unlimited, as in SciPy.
MaxIter int
// MaxFev bounds function evaluations (Nelder-Mead 200·n, Powell 1000·n,
// L-BFGS-B 15000).
MaxFev int
// Gtol is the gradient tolerance: CG and BFGS stop when the Norm-norm
// of the gradient is below it (1e-5); L-BFGS-B stops when the max-norm
// of the projected gradient is below it (SciPy pgtol, 1e-5);
// trust-constr stops when the max-norm of the Lagrangian gradient and
// the constraint violation are both below it (1e-8).
Gtol float64
// Ftol is the relative reduction tolerance: Powell (1e-4),
// L-BFGS-B ((f_k - f_{k+1})/max(|f_k|,|f_{k+1}|,1) <= Ftol, 2.22e-9);
// for SLSQP it is the accuracy goal of the stopping tests (1e-6).
Ftol float64
// Xtol is the step tolerance: Powell (1e-4), Newton-CG (1e-5),
// trust-constr's trust radius (1e-8).
Xtol float64
// Xatol and Fatol are Nelder-Mead's absolute tolerances (1e-4 each).
Xatol, Fatol float64
// Adaptive makes Nelder-Mead adapt its coefficients to the dimension.
Adaptive bool
// InitialSimplex is Nelder-Mead's initial simplex, n+1 points.
InitialSimplex [][]float64
// Direc is Powell's initial set of directions, n vectors.
Direc [][]float64
// Norm is the order of the gradient norm for CG and BFGS (+Inf).
Norm float64
// Eps is the absolute finite-difference step for gradient-based
// methods when no gradient is given (sqrt(eps) ≈ 1.49e-8 for CG and
// BFGS, 1e-8 for L-BFGS-B). It is ignored when FiniteDiffRelStep is set.
Eps float64
// FiniteDiffRelStep selects a relative finite-difference step instead
// of the absolute Eps (SciPy finite_diff_rel_step with jac='2-point').
FiniteDiffRelStep float64
// FDMethod is the finite-difference scheme (FD2Point).
FDMethod FDMethod
// M is the number of L-BFGS-B correction pairs (10).
M int
// MaxLS bounds L-BFGS-B line-search steps per iteration (20).
MaxLS int
// C1 and C2 are the Wolfe constants for CG (1e-4, 0.4) and BFGS
// (1e-4, 0.9).
C1, C2 float64
// HessInv0 is BFGS's initial inverse Hessian, n*n row-major (identity).
HessInv0 []float64
// XRtol is BFGS's relative step tolerance (0: disabled).
XRtol float64
// Callback is called after each iteration with a copy of the current
// point and the objective value; returning true stops the minimisation,
// which then reports Success false and Status 99 (SciPy's callback
// raising StopIteration).
Callback func(x []float64, f float64) (stop bool)
}
Options configures Minimize. Zero values select the SciPy defaults of the chosen method, listed with each field.
type Problem ¶
type Problem struct {
// Func returns f(x).
Func func(x []float64) float64
// Grad writes ∇f(x) into grad (SciPy's jac=callable).
Grad func(x, grad []float64)
// FuncGrad returns f(x) and writes ∇f(x) into grad in one call
// (SciPy's jac=True). It takes precedence over Func and Grad.
FuncGrad func(x, grad []float64) float64
// Hess writes the n×n Hessian at x into hess, row-major (SciPy's hess).
Hess func(x, hess []float64)
// HessP writes the Hessian at x times p into hp (SciPy's hessp).
HessP func(x, p, hp []float64)
}
Problem describes a scalar objective for Minimize. Func is required unless FuncGrad is set. Derivatives are optional: when neither Grad nor FuncGrad is given, gradient-based methods use finite differences with SciPy's step rules (see Options.Eps, Options.FiniteDiffRelStep, Options.FDMethod).
Every callback receives the point first and writes its outputs into the slices that follow; it must not retain x.
type QPConstraints ¶ added in v0.5.0
type QPConstraints struct {
// AUb·x <= BUb. AUb is m×n (or one row of length n); BUb has one entry
// per row, +Inf for a vacuous row.
AUb, BUb *ndarray.Array
// AEq·x = BEq, with finite right-hand sides.
AEq, BEq *ndarray.Array
// Linear holds blocks Lb <= A·x <= Ub, the type of Minimize's constraints.
Linear []LinearConstraint
// ASparse holds rows l <= ASparse·x <= u (QPADMM only); L and U have one
// entry per row, or one entry broadcast, or nil for -Inf and +Inf.
ASparse *sparse.CSC[float64]
L, U []float64
// Bounds are the variable bounds; nil means free, as in Minimize (not
// Linprog's (0, +Inf)).
Bounds []Bound
}
QPConstraints mirrors quadprog's (A, b, Aeq, beq, lb, ub) and adds the two-sided rows of OSQP. Every part is optional.
type QPMethod ¶ added in v0.5.0
type QPMethod string
QPMethod names a quadratic-programming algorithm.
const ( // QPAuto picks the method: QPActiveSet when P is given dense and positive // definite, no ASparse is given and n + m <= 2000, QPADMM otherwise. QPAuto QPMethod = "" // QPActiveSet is the Goldfarb–Idnani dual active-set method: dense, // P positive definite. QPActiveSet QPMethod = "active-set" // QPADMM is OSQP's ADMM method: dense or sparse, P positive semidefinite. QPADMM QPMethod = "admm" )
type QPOptions ¶ added in v0.5.0
type QPOptions struct {
Method QPMethod
// MaxIter is the iteration limit: 10·(n + m) for the active set, 4000 for
// ADMM when zero.
MaxIter int
// FeasTol is the active set's primal feasibility tolerance (default 1e-9).
FeasTol float64
// ADMM settings: the zero value of each selects OSQP v1.0.0's default
// (EpsAbs and EpsRel 1e-3, EpsPrimInf and EpsDualInf 1e-4, Rho 0.1,
// Sigma 1e-6, Alpha 1.6, ScalingIter 10, AdaptiveRhoInterval 50,
// CheckInterval 25, PolishDelta 1e-6, PolishRefine 3). A negative
// ScalingIter or AdaptiveRhoInterval disables that step.
EpsAbs, EpsRel float64
EpsPrimInf, EpsDualInf float64
Rho, Sigma, Alpha float64
ScalingIter int
AdaptiveRhoInterval int
CheckInterval int
Polish bool
PolishDelta float64
PolishRefine int
NoDualGapCheck bool
// X0 and Y0 (lengths n and the number of canonical rows) warm-start ADMM,
// WorkingSet (canonical row indices) warm-starts the active set; both are
// validated.
X0, Y0 []float64
WorkingSet []int
}
QPOptions tunes Quadprog. The zero value selects every default.
type QPProblem ¶ added in v0.5.0
type QPProblem struct {
// P is n×n and is symmetrised as (P+Pᵀ)/2, as MATLAB's quadprog does.
P *ndarray.Array
// PSparse is n×n and holds the entries with row <= column only.
PSparse *sparse.CSC[float64]
// Q has length n and defines n.
Q []float64
Cons QPConstraints
}
QPProblem is min ½xᵀPx + qᵀx subject to the constraints. Give P either dense (P) or sparse (PSparse, upper triangle only, as OSQP takes it), never both; nil for both means P = 0 (an LP, ADMM only).
type QPResult ¶ added in v0.5.0
type QPResult struct {
X []float64
Fun float64
// Residuals and marginals per family of constraints, one entry per input
// row (a row unbounded on both sides has residual +Inf and marginal 0).
// The marginal of a row a is the coefficient with which it enters
// P·x + q = Σ marginal·a, so that
// P·x + q = AUbᵀ·IneqLin + AEqᵀ·EqLin + Aᵀ·Linear + A_sparseᵀ·Sparse
// + Lower + Upper,
// the sign convention of Linprog (HiGHS). The residual of a two-sided row
// (Linear, Sparse) is the slack of its nearer finite side. Lower and Upper
// are indexed by variable; a variable pinned by lb == ub puts its marginal
// in Lower when it is >= 0 and in Upper otherwise.
IneqLin, EqLin, Linear, Sparse, Lower, Upper LPDual
// Y holds OSQP-form multipliers (P·x + q + Aᵀy = 0, so y = −marginal) of
// the canonical rows (design-qp.md §2.2: AEq rows, AUb rows, the Linear
// blocks, the ASparse rows, then the finite bounds, rows unbounded on both
// sides dropped).
Y []float64
// ActiveSet lists the canonical rows in the final working set.
ActiveSet []int
// PrimalCert and DualCert are the certificates of infeasibility and
// unboundedness (nil until the solvers that produce them exist).
PrimalCert, DualCert []float64
// Optimality is ‖P·x + q − Σ marginal·a‖∞ recomputed from scratch,
// ConstrViolation the largest violation of a canonical row, DualityGap the
// gap between the primal and dual objectives (0 for a direct solve).
Optimality, ConstrViolation, DualityGap float64
Status int
// Success reports Status == QPOptimal.
Success bool
Message string
// Method is the method that ran (QPAuto resolved).
Method QPMethod
Nit int
RhoUpdates int
Polished bool
}
QPResult is the outcome of Quadprog.
type QPSolver ¶ added in v0.5.0
type QPSolver struct {
// contains filtered or unexported fields
}
QPSolver holds a validated problem and the factors of the last solve. It is not safe for concurrent use. The updates and warm starts are in qp_solver.go.
func NewQPSolver ¶ added in v0.5.0
NewQPSolver validates p and builds the canonical rows. It reports every invalid input as an error (ErrDimension, ErrInput, ErrBounds or ErrMethod) before allocating anything proportional to the data it did not receive.
func (*QPSolver) UpdateBounds ¶ added in v0.5.0
UpdateBounds replaces the sides l and u of the canonical rows (design-qp.md §2.2: AEq rows, AUb rows, the Linear blocks, the ASparse rows, then the finite bounds; one entry per canonical row, -Inf and +Inf for a missing side). A row keeps the kind it was created with: a finite side cannot become infinite or the reverse, and an equality (l == u) cannot become an interval or the reverse; otherwise the error is ErrBounds. The active-set factors are kept. ADMM takes any sides and refactors only if a row changes type (OSQP's update_rho_vec).
func (*QPSolver) UpdateMatrixValues ¶ added in v0.5.0
UpdateMatrixValues replaces the values of P and of the dense constraint rows without changing their patterns. p holds the n×n values row-major for a dense P (symmetrised as (P+Pᵀ)/2), or the entries of PSparse in their stored order; a holds the dense canonical rows (AEq, AUb, the Linear blocks) row-major, the bound rows excluded, followed by the entries of ASparse in its CSC storage order (ADMM only). nil keeps the old values. The active-set factors are rebuilt on the next Solve, seeded with the previous active set; a P that is no longer positive definite is rejected and nothing changes. The ADMM solver reruns its scaling and refactors numerically on the stored symbolic factor (a new ordering only if the nonzero pattern of a dense P changed), keeps ρ and the iterates as the warm start, and rejects a P that makes the KKT matrix not quasi-definite, leaving the solver as it was.
func (*QPSolver) WarmStart ¶ added in v0.5.0
WarmStart sets the starting point of the next Solve: x (length n) and y (the canonical rows' multipliers), either may be nil. The active set ignores them (it starts from its working set, design-qp.md §5); they are validated all the same, and kept for the ADMM solver.
type Range ¶
type Range struct {
Lo, Hi, Step float64
}
Range is one axis of a Brute grid. With Step 0 the axis holds Ns points from Lo to Hi inclusive (SciPy's (low, high) tuple, i.e. slice(low, high, Ns*1j)); with Step > 0 it holds Lo, Lo+Step, … below Hi (slice(low, high, step)).
type Result ¶
type Result struct {
// X is the solution.
X []float64
// Fun is the objective value at X.
Fun float64
// Jac is the gradient at X, when the method computes one.
Jac []float64
// HessInv is the final inverse-Hessian approximation as an n*n row-major
// matrix (BFGS only, nil otherwise).
HessInv []float64
// Multipliers are the Lagrange multipliers of the constraints at X.
// SLSQP: equalities first and then inequalities, in the order of the
// standardised constraint blocks (SciPy's result.multipliers).
// trust-constr: one per component of each constraint of
// Options.Constraints, in order, with SciPy's sign (its result.v
// without the bounds).
Multipliers []float64
// Optimality is the max-norm of the Lagrangian gradient and
// ConstrViolation the largest constraint violation at X (trust-constr).
Optimality, ConstrViolation float64
// Nit, Nfev, Njev and Nhev count iterations and evaluations of the
// objective, the gradient and the Hessian. Function evaluations spent on
// finite-difference gradients are counted in Nfev, and each such gradient
// also counts once in Njev, as in SciPy.
Nit, Nfev, Njev, Nhev int
// Status is a method-specific termination code; 0 means success.
Status int
// Success reports whether the method met its convergence criteria.
Success bool
// Message describes the reason for termination.
Message string
}
Result is the outcome of Minimize, the counterpart of SciPy's OptimizeResult for scipy.optimize.minimize.
func Minimize ¶
Minimize minimises p from x0 with the given method; it is scipy.optimize.minimize(fun, x0, method=..., jac=..., hess=..., bounds=..., tol=..., options=...).
Invalid input returns an error; non-convergence returns a Result with Success false.
Example ¶
scipy.optimize.minimize(rosen, x0, jac=rosen_der, method='BFGS')
package main
import (
"fmt"
"math"
"github.com/go-numerics/optimize"
)
func main() {
rosen := func(x []float64) float64 {
return 100*math.Pow(x[1]-x[0]*x[0], 2) + math.Pow(1-x[0], 2)
}
grad := func(x, g []float64) {
g[0] = -400*x[0]*(x[1]-x[0]*x[0]) - 2*(1-x[0])
g[1] = 200 * (x[1] - x[0]*x[0])
}
r, err := optimize.Minimize(optimize.Problem{Func: rosen, Grad: grad}, []float64{-1.2, 1}, optimize.BFGS, nil)
if err != nil {
panic(err)
}
fmt.Printf("x = [%.6f %.6f], nit = %d, %s\n", r.X[0], r.X[1], r.Nit, r.Message)
}
Output: x = [1.000000 1.000000], nit = 32, Optimization terminated successfully.
Example (Bounds) ¶
scipy.optimize.minimize(f, x0, method='L-BFGS-B', bounds=[(-2, 0.5), (None, None)])
package main
import (
"fmt"
"github.com/go-numerics/optimize"
)
func main() {
f := func(x []float64) float64 { return (x[0]-1)*(x[0]-1) + (x[1]+2)*(x[1]+2) }
opts := &optimize.Options{Bounds: []optimize.Bound{{Lo: -2, Hi: 0.5}, optimize.Unbounded()}}
r, _ := optimize.Minimize(optimize.Problem{Func: f}, []float64{0, 0}, optimize.LBFGSB, opts)
fmt.Printf("x = [%.4f %.4f]\n", r.X[0], r.X[1])
}
Output: x = [0.5000 -2.0000]
Example (Slsqp) ¶
Hock–Schittkowski problem 71: scipy.optimize.minimize(f, [1, 5, 5, 1], method='SLSQP', bounds=[(1, 5)]*4,
constraints=[{'type': 'ineq', 'fun': g}, {'type': 'eq', 'fun': h}])
package main
import (
"fmt"
"github.com/go-numerics/optimize"
)
func main() {
f := func(x []float64) float64 { return x[0]*x[3]*(x[0]+x[1]+x[2]) + x[2] }
g := func(x, c []float64) { c[0] = x[0]*x[1]*x[2]*x[3] - 25 }
h := func(x, c []float64) { c[0] = x[0]*x[0] + x[1]*x[1] + x[2]*x[2] + x[3]*x[3] - 40 }
bound := optimize.Bound{Lo: 1, Hi: 5}
r, err := optimize.Minimize(optimize.Problem{Func: f}, []float64{1, 5, 5, 1}, optimize.SLSQP,
&optimize.Options{
Bounds: []optimize.Bound{bound, bound, bound, bound},
Constraints: []optimize.ConstraintSpec{
optimize.Constraint{Kind: optimize.Ineq, M: 1, Func: g},
optimize.Constraint{Kind: optimize.Eq, M: 1, Func: h},
}})
if err != nil {
panic(err)
}
fmt.Printf("f = %.7f, x = [%.4f %.4f %.4f %.4f], nit = %d, %s\n",
r.Fun, r.X[0], r.X[1], r.X[2], r.X[3], r.Nit, r.Message)
}
Output: f = 17.0140172, x = [1.0000 4.7430 3.8212 1.3794], nit = 5, Optimization terminated successfully
Example (TrustConstr) ¶
Hock–Schittkowski problem 71 by the interior-point method: scipy.optimize.minimize(f, [1, 5, 5, 1], method='trust-constr', bounds=..., constraints=...)
package main
import (
"fmt"
"github.com/go-numerics/optimize"
)
func main() {
f := func(x []float64) float64 { return x[0]*x[3]*(x[0]+x[1]+x[2]) + x[2] }
g := func(x, c []float64) { c[0] = x[0]*x[1]*x[2]*x[3] - 25 }
h := func(x, c []float64) { c[0] = x[0]*x[0] + x[1]*x[1] + x[2]*x[2] + x[3]*x[3] - 40 }
bound := optimize.Bound{Lo: 1, Hi: 5}
r, err := optimize.Minimize(optimize.Problem{Func: f}, []float64{1, 5, 5, 1}, optimize.TrustConstr,
&optimize.Options{
Bounds: []optimize.Bound{bound, bound, bound, bound},
Constraints: []optimize.ConstraintSpec{
optimize.Constraint{Kind: optimize.Ineq, M: 1, Func: g},
optimize.Constraint{Kind: optimize.Eq, M: 1, Func: h},
}})
if err != nil {
panic(err)
}
fmt.Printf("f = %.5f, x = [%.3f %.3f %.3f %.3f], success = %v\n",
r.Fun, r.X[0], r.X[1], r.X[2], r.X[3], r.Success)
}
Output: f = 17.01402, x = [1.000 4.743 3.821 1.379], success = true
func (*Result) HessInvArray ¶
HessInvArray returns HessInv as an n×n ndarray, or nil when absent.
type RootOptions ¶
type RootOptions struct {
// Xtol stops the iteration when the relative error between two
// consecutive iterates is at most Xtol (1.49012e-8; a negative value
// means exactly 0).
Xtol float64
// Maxfev bounds the calls to Func: 0 selects 200·(n+1) without a
// Jacobian (forward-difference calls included) and 100·(n+1) with one.
Maxfev int
// Eps sets the forward-difference step sqrt(Eps)·|x_j| when there is no
// Jacobian (SciPy's eps for root, epsfcn for fsolve); 0 selects the
// machine epsilon.
Eps float64
// Factor sets the initial step bound Factor·|Diag·x0| (100).
Factor float64
// Diag holds n positive scale factors for the variables; nil lets
// MINPACK scale by the Jacobian column norms.
Diag []float64
}
RootOptions configures Root and Fsolve. Zero values select SciPy's defaults.
type RootResult ¶
type RootResult struct {
// X is the solution (or the last iterate).
X []float64
// Fun holds F(X).
Fun []float64
// Fjac is SciPy's fjac: the orthogonal factor Q of the QR factorisation
// of the final approximate Jacobian, stored column-wise, so that as an
// n×n row-major array it reads Qᵀ (row i is column i of Q).
Fjac []float64
// R is the upper-triangular factor packed by rows (n(n+1)/2 entries).
R []float64
// Qtf is Qᵀ·Fun.
Qtf []float64
// Nfev counts calls to Func, including those of finite differences;
// Njev counts calls to Jac (0 without one). SciPy's root and fsolve
// report two more calls: those their wrappers make outside MINPACK (a
// shape check and the initial evaluation), which do not happen here.
Nfev, Njev int
// Status is MINPACK's info: 1 converged, 2 Maxfev reached, 3 Xtol too
// small, 4 and 5 no progress.
Status int
// Success is Status == 1.
Success bool
// Message is SciPy's message for Status.
Message string
}
RootResult is the outcome of Root and Fsolve, mirroring the OptimizeResult of scipy.optimize.root(method='hybr').
func Fsolve ¶
func Fsolve(p SystemProblem, x0 []float64, opts *RootOptions) (*RootResult, error)
Fsolve is scipy.optimize.fsolve(func, x0, fprime=p.Jac, full_output=True, xtol, maxfev, epsfcn=opts.Eps, factor, diag): the same computation as Root, returning the same result (SciPy's infodict holds Fun as fvec, Nfev, Njev, Fjac, R and Qtf; ier is Status and mesg Message).
func Root ¶
func Root(p SystemProblem, x0 []float64, opts *RootOptions) (*RootResult, error)
Root solves the square system p.Func(x) = 0 from x0 with Powell's hybrid method of MINPACK; it is scipy.optimize.root(fun, x0, jac=p.Jac, method='hybr', options={'xtol', 'maxfev', 'eps', 'factor', 'diag'}) (the 'band' and 'col_deriv' options are not supported). Without p.Jac it runs hybrd, otherwise hybrj. Non-convergence is reported through Status and Message.
Example ¶
scipy.optimize.root(fun, [0, 0], method='hybr')
package main
import (
"fmt"
"math"
"github.com/go-numerics/optimize"
)
func main() {
fun := func(x, f []float64) {
f[0] = x[0] + 0.5*math.Pow(x[0]-x[1], 3) - 1
f[1] = 0.5*math.Pow(x[1]-x[0], 3) + x[1]
}
r, _ := optimize.Root(optimize.SystemProblem{Func: fun}, []float64{0, 0}, nil)
fmt.Printf("x = [%.6f %.6f] %v\n", r.X[0], r.X[1], r.Success)
}
Output: x = [0.841164 0.158836] true
func (*RootResult) FjacArray ¶
func (r *RootResult) FjacArray() *ndarray.Array
FjacArray returns Fjac as an n×n ndarray.
func (*RootResult) XArray ¶
func (r *RootResult) XArray() *ndarray.Array
XArray returns X as a 1-D ndarray.
type RootScalarOptions ¶
type RootScalarOptions struct {
// Bracket [a, b] for the bracketing methods.
Bracket []float64
// Fprime and Fprime2 are the first and second derivatives.
Fprime, Fprime2 func(float64) float64
// X0 and X1 are starting points for Newton, Halley and the secant
// method; X0Set/X1Set mark them as given (0 is a valid start).
X0, X1 float64
X0Set, X1Set bool
// Xtol, Rtol and MaxIter override the method's defaults.
Xtol, Rtol float64
MaxIter int
}
RootScalarOptions configures RootScalar.
type RootScalarResult ¶
type RootScalarResult struct {
// Root is the estimated root.
Root float64
// Iterations and FunctionCalls count the work done (derivative
// evaluations count as function calls for Newton and Halley).
Iterations, FunctionCalls int
// Converged reports whether the tolerance was met.
Converged bool
// Flag is "converged", "convergence error" or a message describing the
// failure.
Flag string
// Method is the algorithm used.
Method string
}
RootScalarResult describes a scalar root search, like SciPy's RootResults.
func Bisect ¶
func Bisect(f func(float64) float64, a, b float64, o *BracketOptions) (*RootScalarResult, error)
Bisect finds a root of f in [a, b] by bisection; it is scipy.optimize.bisect.
func Brenth ¶
func Brenth(f func(float64) float64, a, b float64, o *BracketOptions) (*RootScalarResult, error)
Brenth is Brentq with hyperbolic instead of inverse quadratic extrapolation (Bus & Dekker 1975); it is scipy.optimize.brenth.
func Brentq ¶
func Brentq(f func(float64) float64, a, b float64, o *BracketOptions) (*RootScalarResult, error)
Brentq finds a root of f in [a, b], where f(a) and f(b) have opposite signs, with Brent's (1973) method using inverse quadratic extrapolation; it is scipy.optimize.brentq(f, a, b, xtol, rtol, maxiter, full_output=True). The returned root x satisfies |x − x₀| <= 4·(Xtol + Rtol·|x₀|) for the exact root x₀.
A bracket without a sign change returns ErrBracket; a NaN function value returns an error together with the result describing where it happened; running out of iterations is reported by Converged false.
Example ¶
scipy.optimize.brentq(lambda x: x**3 - 2*x - 5, 2, 3)
package main
import (
"fmt"
"github.com/go-numerics/optimize"
)
func main() {
r, _ := optimize.Brentq(func(x float64) float64 { return x*x*x - 2*x - 5 }, 2, 3, nil)
fmt.Printf("%.12f after %d iterations\n", r.Root, r.Iterations)
}
Output: 2.094551481542 after 7 iterations
func Newton ¶
func Newton(f func(float64) float64, x0 float64, o *NewtonOptions) (*RootScalarResult, error)
Newton finds a root of f near x0 with the Newton–Raphson method (given Fprime), Halley's method (given Fprime and Fprime2) or the secant method (neither); it is scipy.optimize.newton(func, x0, fprime, tol=1.48e-8, maxiter=50, fprime2, x1, rtol=0, full_output=True, disp=False).
Failure to converge (including a zero derivative) is reported by Converged false and Flag "convergence error", not as an error.
func Ridder ¶
func Ridder(f func(float64) float64, a, b float64, o *BracketOptions) (*RootScalarResult, error)
Ridder finds a root of f in [a, b] with Ridders' (1979) method; it is scipy.optimize.ridder.
func RootScalar ¶
func RootScalar(f func(float64) float64, method string, o *RootScalarOptions) (*RootScalarResult, error)
RootScalar finds a root of a scalar function; it is scipy.optimize.root_scalar(f, method, bracket, fprime, fprime2, x0, x1, xtol, rtol, maxiter). method is one of "brentq", "brenth", "ridder", "bisect", "newton", "halley", "secant", or "" to choose as SciPy does: a bracket selects brentq; otherwise x0 with Fprime selects newton (halley with Fprime2), x0 with x1 the secant method, and x0 alone Newton with a finite-difference derivative.
type ScalarMethod ¶
type ScalarMethod string
ScalarMethod names a scalar minimisation algorithm; the values are the method strings of scipy.optimize.minimize_scalar.
const ( // Brent is Brent's method: parabolic interpolation safeguarded by // golden-section steps, from a bracket. Brent ScalarMethod = "brent" // Bounded is Brent's method restricted to a finite interval (the // algorithm of fminbound). Bounded ScalarMethod = "bounded" // Golden is the golden-section search, from a bracket. Golden ScalarMethod = "golden" )
Scalar minimisation methods.
type ScalarOptions ¶
type ScalarOptions struct {
// Bracket is a bracketing interval for Brent and Golden: two points
// (xa, xb) from which Bracket searches downhill, or three points
// (xa, xb, xc) with xa < xb < xc and f(xb) < f(xa), f(xc). nil starts
// the downhill search from (0, 1).
Bracket []float64
// Bounds is the interval for the Bounded method; setting it selects
// Bounded when the method is "".
Bounds *Bound
// Tol is minimize_scalar's tol: it sets Xtol (Brent, Golden) or Xatol
// (Bounded) when those are zero.
Tol float64
// Xtol is the relative tolerance of Brent (1.48e-8) and Golden
// (√eps ≈ 1.49e-8).
Xtol float64
// Xatol is the absolute tolerance of Bounded (1e-5).
Xatol float64
// MaxIter bounds iterations (Brent 500, Golden 5000) or function
// evaluations (Bounded 500).
MaxIter int
}
ScalarOptions configures MinimizeScalar. Zero values select SciPy's defaults.
type ScalarResult ¶
type ScalarResult struct {
X, Fun float64
Nit, Nfev int
Status int // Bounded only: 0 solution found, 1 maxfun, 2 NaN
Success bool
Message string
}
ScalarResult is the outcome of MinimizeScalar, the OptimizeResult of scipy.optimize.minimize_scalar.
func Fminbound ¶
Fminbound minimises f on [x1, x2] with absolute tolerance xtol (1e-5 when 0) and at most maxfun evaluations (500 when 0); it is scipy.optimize.fminbound(func, x1, x2, xtol, maxfun, full_output=True).
func MinimizeScalar ¶
func MinimizeScalar(f func(float64) float64, method ScalarMethod, o *ScalarOptions) (*ScalarResult, error)
MinimizeScalar minimises a function of one variable; it is scipy.optimize.minimize_scalar(fun, bracket=..., bounds=..., method=..., tol=..., options={'xtol'/'xatol', 'maxiter'}). method "" selects Brent, or Bounded when o.Bounds is set.
A failed bracket search is not an error: as in SciPy, the result then holds the best of the three points and Success is false.
type SystemProblem ¶
type SystemProblem struct {
// Func writes the n values of F at x into f. Required. It must not
// modify x.
Func func(x, f []float64)
// Jac writes the n×n Jacobian of F at x into jac, row-major
// (jac[i*n+j] = ∂F_i/∂x_j). Optional: MINPACK's forward differences are
// used when it is nil.
Jac func(x, jac []float64)
}
SystemProblem is a square system of nonlinear equations F(x) = 0 with n equations in n unknowns.
Source Files
¶
- bfgs.go
- brute.go
- cg.go
- constraints.go
- curvefit.go
- dcsrch.go
- doc.go
- hybrd.go
- lapack.go
- lbfgsb.go
- lbfgsb_sub.go
- leastsquares.go
- linesearch.go
- linprog.go
- linprog_ip.go
- linprog_presolve.go
- linprog_simplex.go
- lmdif.go
- minimize.go
- minpack.go
- neldermead.go
- newtoncg.go
- numdiff.go
- powell.go
- qp_admm.go
- qp_admm_check.go
- qp_admm_polish.go
- qp_admm_scale.go
- qp_gi.go
- qp_kkt.go
- qp_solver.go
- quadprog.go
- root.go
- roots.go
- scalar.go
- slsqp.go
- slsqp_lsq.go
- trf.go
- trustconstr.go
- trustconstr_linalg.go
- types.go
Directories
¶
| Path | Synopsis |
|---|---|
|
tools
|
|
|
globaloracle
module
|
|
|
nofma
module
|
|
|
qpbench
module
|
|
|
qporacle
module
|
|
|
slsqpbench
module
|
|
|
slsqporacle
module
|
