Files
gonum/optimize/functions/functions.go
Dan Kortschak f42c07e8cb all: fix typos
2025-01-01 08:26:48 +10:30

1854 lines
43 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright ©2015 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package functions
import (
"math"
"gonum.org/v1/gonum/floats"
"gonum.org/v1/gonum/mat"
)
// Beale implements the Beale's function.
//
// Standard starting points:
//
// Easy: [1, 1]
// Hard: [1, 4]
//
// References:
// - Beale, E.: On an Iterative Method for Finding a Local Minimum of a
// Function of More than One Variable. Technical Report 25, Statistical
// Techniques Research Group, Princeton University (1958)
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type Beale struct{}
func (Beale) Func(x []float64) float64 {
if len(x) != 2 {
panic("dimension of the problem must be 2")
}
f1 := 1.5 - x[0]*(1-x[1])
f2 := 2.25 - x[0]*(1-x[1]*x[1])
f3 := 2.625 - x[0]*(1-x[1]*x[1]*x[1])
return f1*f1 + f2*f2 + f3*f3
}
func (Beale) Grad(grad, x []float64) {
if len(x) != 2 {
panic("dimension of the problem must be 2")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
t1 := 1 - x[1]
t2 := 1 - x[1]*x[1]
t3 := 1 - x[1]*x[1]*x[1]
f1 := 1.5 - x[0]*t1
f2 := 2.25 - x[0]*t2
f3 := 2.625 - x[0]*t3
grad[0] = -2 * (f1*t1 + f2*t2 + f3*t3)
grad[1] = 2 * x[0] * (f1 + 2*f2*x[1] + 3*f3*x[1]*x[1])
}
func (Beale) Hess(dst *mat.SymDense, x []float64) {
if len(x) != 2 {
panic("dimension of the problem must be 2")
}
if len(x) != dst.SymmetricDim() {
panic("incorrect size of the Hessian")
}
t1 := 1 - x[1]
t2 := 1 - x[1]*x[1]
t3 := 1 - x[1]*x[1]*x[1]
f1 := 1.5 - x[1]*t1
f2 := 2.25 - x[1]*t2
f3 := 2.625 - x[1]*t3
h00 := 2 * (t1*t1 + t2*t2 + t3*t3)
h01 := 2 * (f1 + x[1]*(2*f2+3*x[1]*f3) - x[0]*(t1+x[1]*(2*t2+3*x[1]*t3)))
h11 := 2 * x[0] * (x[0] + 2*f2 + x[1]*(6*f3+x[0]*x[1]*(4+9*x[1]*x[1])))
dst.SetSym(0, 0, h00)
dst.SetSym(0, 1, h01)
dst.SetSym(1, 1, h11)
}
func (Beale) Minima() []Minimum {
return []Minimum{
{
X: []float64{3, 0.5},
F: 0,
Global: true,
},
}
}
// BiggsEXP2 implements the Biggs' EXP2 function.
//
// Standard starting point:
//
// [1, 2]
//
// Reference:
//
// Biggs, M.C.: Minimization algorithms making use of non-quadratic properties
// of the objective function. IMA J Appl Math 8 (1971), 315-327; doi:10.1093/imamat/8.3.315
type BiggsEXP2 struct{}
func (BiggsEXP2) Func(x []float64) (sum float64) {
if len(x) != 2 {
panic("dimension of the problem must be 2")
}
for i := 1; i <= 10; i++ {
z := float64(i) / 10
y := math.Exp(-z) - 5*math.Exp(-10*z)
f := math.Exp(-x[0]*z) - 5*math.Exp(-x[1]*z) - y
sum += f * f
}
return sum
}
func (BiggsEXP2) Grad(grad, x []float64) {
if len(x) != 2 {
panic("dimension of the problem must be 2")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
for i := range grad {
grad[i] = 0
}
for i := 1; i <= 10; i++ {
z := float64(i) / 10
y := math.Exp(-z) - 5*math.Exp(-10*z)
f := math.Exp(-x[0]*z) - 5*math.Exp(-x[1]*z) - y
dfdx0 := -z * math.Exp(-x[0]*z)
dfdx1 := 5 * z * math.Exp(-x[1]*z)
grad[0] += 2 * f * dfdx0
grad[1] += 2 * f * dfdx1
}
}
func (BiggsEXP2) Minima() []Minimum {
return []Minimum{
{
X: []float64{1, 10},
F: 0,
Global: true,
},
}
}
// BiggsEXP3 implements the Biggs' EXP3 function.
//
// Standard starting point:
//
// [1, 2, 1]
//
// Reference:
//
// Biggs, M.C.: Minimization algorithms making use of non-quadratic properties
// of the objective function. IMA J Appl Math 8 (1971), 315-327; doi:10.1093/imamat/8.3.315
type BiggsEXP3 struct{}
func (BiggsEXP3) Func(x []float64) (sum float64) {
if len(x) != 3 {
panic("dimension of the problem must be 3")
}
for i := 1; i <= 10; i++ {
z := float64(i) / 10
y := math.Exp(-z) - 5*math.Exp(-10*z)
f := math.Exp(-x[0]*z) - x[2]*math.Exp(-x[1]*z) - y
sum += f * f
}
return sum
}
func (BiggsEXP3) Grad(grad, x []float64) {
if len(x) != 3 {
panic("dimension of the problem must be 3")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
for i := range grad {
grad[i] = 0
}
for i := 1; i <= 10; i++ {
z := float64(i) / 10
y := math.Exp(-z) - 5*math.Exp(-10*z)
f := math.Exp(-x[0]*z) - x[2]*math.Exp(-x[1]*z) - y
dfdx0 := -z * math.Exp(-x[0]*z)
dfdx1 := x[2] * z * math.Exp(-x[1]*z)
dfdx2 := -math.Exp(-x[1] * z)
grad[0] += 2 * f * dfdx0
grad[1] += 2 * f * dfdx1
grad[2] += 2 * f * dfdx2
}
}
func (BiggsEXP3) Minima() []Minimum {
return []Minimum{
{
X: []float64{1, 10, 5},
F: 0,
Global: true,
},
}
}
// BiggsEXP4 implements the Biggs' EXP4 function.
//
// Standard starting point:
//
// [1, 2, 1, 1]
//
// Reference:
//
// Biggs, M.C.: Minimization algorithms making use of non-quadratic properties
// of the objective function. IMA J Appl Math 8 (1971), 315-327; doi:10.1093/imamat/8.3.315
type BiggsEXP4 struct{}
func (BiggsEXP4) Func(x []float64) (sum float64) {
if len(x) != 4 {
panic("dimension of the problem must be 4")
}
for i := 1; i <= 10; i++ {
z := float64(i) / 10
y := math.Exp(-z) - 5*math.Exp(-10*z)
f := x[2]*math.Exp(-x[0]*z) - x[3]*math.Exp(-x[1]*z) - y
sum += f * f
}
return sum
}
func (BiggsEXP4) Grad(grad, x []float64) {
if len(x) != 4 {
panic("dimension of the problem must be 4")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
for i := range grad {
grad[i] = 0
}
for i := 1; i <= 10; i++ {
z := float64(i) / 10
y := math.Exp(-z) - 5*math.Exp(-10*z)
f := x[2]*math.Exp(-x[0]*z) - x[3]*math.Exp(-x[1]*z) - y
dfdx0 := -z * x[2] * math.Exp(-x[0]*z)
dfdx1 := z * x[3] * math.Exp(-x[1]*z)
dfdx2 := math.Exp(-x[0] * z)
dfdx3 := -math.Exp(-x[1] * z)
grad[0] += 2 * f * dfdx0
grad[1] += 2 * f * dfdx1
grad[2] += 2 * f * dfdx2
grad[3] += 2 * f * dfdx3
}
}
func (BiggsEXP4) Minima() []Minimum {
return []Minimum{
{
X: []float64{1, 10, 1, 5},
F: 0,
Global: true,
},
}
}
// BiggsEXP5 implements the Biggs' EXP5 function.
//
// Standard starting point:
//
// [1, 2, 1, 1, 1]
//
// Reference:
//
// Biggs, M.C.: Minimization algorithms making use of non-quadratic properties
// of the objective function. IMA J Appl Math 8 (1971), 315-327; doi:10.1093/imamat/8.3.315
type BiggsEXP5 struct{}
func (BiggsEXP5) Func(x []float64) (sum float64) {
if len(x) != 5 {
panic("dimension of the problem must be 5")
}
for i := 1; i <= 11; i++ {
z := float64(i) / 10
y := math.Exp(-z) - 5*math.Exp(-10*z) + 3*math.Exp(-4*z)
f := x[2]*math.Exp(-x[0]*z) - x[3]*math.Exp(-x[1]*z) + 3*math.Exp(-x[4]*z) - y
sum += f * f
}
return sum
}
func (BiggsEXP5) Grad(grad, x []float64) {
if len(x) != 5 {
panic("dimension of the problem must be 5")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
for i := range grad {
grad[i] = 0
}
for i := 1; i <= 11; i++ {
z := float64(i) / 10
y := math.Exp(-z) - 5*math.Exp(-10*z) + 3*math.Exp(-4*z)
f := x[2]*math.Exp(-x[0]*z) - x[3]*math.Exp(-x[1]*z) + 3*math.Exp(-x[4]*z) - y
dfdx0 := -z * x[2] * math.Exp(-x[0]*z)
dfdx1 := z * x[3] * math.Exp(-x[1]*z)
dfdx2 := math.Exp(-x[0] * z)
dfdx3 := -math.Exp(-x[1] * z)
dfdx4 := -3 * z * math.Exp(-x[4]*z)
grad[0] += 2 * f * dfdx0
grad[1] += 2 * f * dfdx1
grad[2] += 2 * f * dfdx2
grad[3] += 2 * f * dfdx3
grad[4] += 2 * f * dfdx4
}
}
func (BiggsEXP5) Minima() []Minimum {
return []Minimum{
{
X: []float64{1, 10, 1, 5, 4},
F: 0,
Global: true,
},
}
}
// BiggsEXP6 implements the Biggs' EXP6 function.
//
// Standard starting point:
//
// [1, 2, 1, 1, 1, 1]
//
// References:
// - Biggs, M.C.: Minimization algorithms making use of non-quadratic
// properties of the objective function. IMA J Appl Math 8 (1971), 315-327;
// doi:10.1093/imamat/8.3.315
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type BiggsEXP6 struct{}
func (BiggsEXP6) Func(x []float64) (sum float64) {
if len(x) != 6 {
panic("dimension of the problem must be 6")
}
for i := 1; i <= 13; i++ {
z := float64(i) / 10
y := math.Exp(-z) - 5*math.Exp(-10*z) + 3*math.Exp(-4*z)
f := x[2]*math.Exp(-x[0]*z) - x[3]*math.Exp(-x[1]*z) + x[5]*math.Exp(-x[4]*z) - y
sum += f * f
}
return sum
}
func (BiggsEXP6) Grad(grad, x []float64) {
if len(x) != 6 {
panic("dimension of the problem must be 6")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
for i := range grad {
grad[i] = 0
}
for i := 1; i <= 13; i++ {
z := float64(i) / 10
y := math.Exp(-z) - 5*math.Exp(-10*z) + 3*math.Exp(-4*z)
f := x[2]*math.Exp(-x[0]*z) - x[3]*math.Exp(-x[1]*z) + x[5]*math.Exp(-x[4]*z) - y
dfdx0 := -z * x[2] * math.Exp(-x[0]*z)
dfdx1 := z * x[3] * math.Exp(-x[1]*z)
dfdx2 := math.Exp(-x[0] * z)
dfdx3 := -math.Exp(-x[1] * z)
dfdx4 := -z * x[5] * math.Exp(-x[4]*z)
dfdx5 := math.Exp(-x[4] * z)
grad[0] += 2 * f * dfdx0
grad[1] += 2 * f * dfdx1
grad[2] += 2 * f * dfdx2
grad[3] += 2 * f * dfdx3
grad[4] += 2 * f * dfdx4
grad[5] += 2 * f * dfdx5
}
}
func (BiggsEXP6) Minima() []Minimum {
return []Minimum{
{
X: []float64{1, 10, 1, 5, 4, 3},
F: 0,
Global: true,
},
{
X: []float64{1.7114159947956764, 17.68319817846745, 1.1631436609697268,
5.1865615510738605, 1.7114159947949301, 1.1631436609697998},
F: 0.005655649925499929,
Global: false,
},
{
// X: []float64{1.22755594752403, X[1] >> 0, 0.83270306333466, X[3] << 0, X[4] = X[0], X[5] = X[2]},
X: []float64{1.22755594752403, 1000, 0.83270306333466, -1000, 1.22755594752403, 0.83270306333466},
F: 0.306366772624790,
Global: false,
},
}
}
// Box3D implements the Box' three-dimensional function.
//
// Standard starting point:
//
// [0, 10, 20]
//
// References:
// - Box, M.J.: A comparison of several current optimization methods, and the
// use of transformations in constrained problems. Comput J 9 (1966), 67-77
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type Box3D struct{}
func (Box3D) Func(x []float64) (sum float64) {
if len(x) != 3 {
panic("dimension of the problem must be 3")
}
for i := 1; i <= 10; i++ {
c := -float64(i) / 10
y := math.Exp(c) - math.Exp(10*c)
f := math.Exp(c*x[0]) - math.Exp(c*x[1]) - x[2]*y
sum += f * f
}
return sum
}
func (Box3D) Grad(grad, x []float64) {
if len(x) != 3 {
panic("dimension of the problem must be 3")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
grad[0] = 0
grad[1] = 0
grad[2] = 0
for i := 1; i <= 10; i++ {
c := -float64(i) / 10
y := math.Exp(c) - math.Exp(10*c)
f := math.Exp(c*x[0]) - math.Exp(c*x[1]) - x[2]*y
grad[0] += 2 * f * c * math.Exp(c*x[0])
grad[1] += -2 * f * c * math.Exp(c*x[1])
grad[2] += -2 * f * y
}
}
func (Box3D) Minima() []Minimum {
return []Minimum{
{
X: []float64{1, 10, 1},
F: 0,
Global: true,
},
{
X: []float64{10, 1, -1},
F: 0,
Global: true,
},
{
// Any point at the line {a, a, 0}.
X: []float64{1, 1, 0},
F: 0,
Global: true,
},
}
}
// BraninHoo implements the Branin-Hoo function. BraninHoo is a 2-dimensional
// test function with three global minima. It is typically evaluated in the domain
// x_0 ∈ [-5, 10], x_1 ∈ [0, 15].
//
// f(x) = (x_1 - (5.1/(4π^2))*x_0^2 + (5/π)*x_0 - 6)^2 + 10*(1-1/(8π))cos(x_0) + 10
//
// It has a minimum value of 0.397887 at x^* = {(-π, 12.275), (π, 2.275), (9.424778, 2.475)}
//
// Reference:
//
// https://www.sfu.ca/~ssurjano/branin.html (obtained June 2017)
type BraninHoo struct{}
func (BraninHoo) Func(x []float64) float64 {
if len(x) != 2 {
panic("functions: dimension of the problem must be 2")
}
a, b, c, r, s, t := 1.0, 5.1/(4*math.Pi*math.Pi), 5/math.Pi, 6.0, 10.0, 1/(8*math.Pi)
term := x[1] - b*x[0]*x[0] + c*x[0] - r
return a*term*term + s*(1-t)*math.Cos(x[0]) + s
}
func (BraninHoo) Minima() []Minimum {
return []Minimum{
{
X: []float64{-math.Pi, 12.275},
F: 0.397887,
Global: true,
},
{
X: []float64{math.Pi, 2.275},
F: 0.397887,
Global: true,
},
{
X: []float64{9.424778, 2.475},
F: 0.397887,
Global: true,
},
}
}
// BrownBadlyScaled implements the Brown's badly scaled function.
//
// Standard starting point:
//
// [1, 1]
//
// References:
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type BrownBadlyScaled struct{}
func (BrownBadlyScaled) Func(x []float64) float64 {
if len(x) != 2 {
panic("dimension of the problem must be 2")
}
f1 := x[0] - 1e6
f2 := x[1] - 2e-6
f3 := x[0]*x[1] - 2
return f1*f1 + f2*f2 + f3*f3
}
func (BrownBadlyScaled) Grad(grad, x []float64) {
if len(x) != 2 {
panic("dimension of the problem must be 2")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
f1 := x[0] - 1e6
f2 := x[1] - 2e-6
f3 := float64(x[0]*x[1]) - 2 // Prevent fused multiply subtract.
grad[0] = 2*f1 + 2*f3*x[1]
grad[1] = 2*f2 + 2*f3*x[0]
}
func (BrownBadlyScaled) Hess(dst *mat.SymDense, x []float64) {
if len(x) != 2 {
panic("dimension of the problem must be 2")
}
if len(x) != dst.SymmetricDim() {
panic("incorrect size of the Hessian")
}
h00 := 2 + 2*x[1]*x[1]
h01 := 4*x[0]*x[1] - 4
h11 := 2 + 2*x[0]*x[0]
dst.SetSym(0, 0, h00)
dst.SetSym(0, 1, h01)
dst.SetSym(1, 1, h11)
}
func (BrownBadlyScaled) Minima() []Minimum {
return []Minimum{
{
X: []float64{1e6, 2e-6},
F: 0,
Global: true,
},
}
}
// BrownAndDennis implements the Brown and Dennis function.
//
// Standard starting point:
//
// [25, 5, -5, -1]
//
// References:
// - Brown, K.M., Dennis, J.E.: New computational algorithms for minimizing a
// sum of squares of nonlinear functions. Research Report Number 71-6, Yale
// University (1971)
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type BrownAndDennis struct{}
func (BrownAndDennis) Func(x []float64) (sum float64) {
if len(x) != 4 {
panic("dimension of the problem must be 4")
}
for i := 1; i <= 20; i++ {
c := float64(i) / 5
f1 := x[0] + c*x[1] - math.Exp(c)
f2 := x[2] + x[3]*math.Sin(c) - math.Cos(c)
f := f1*f1 + f2*f2
sum += f * f
}
return sum
}
func (BrownAndDennis) Grad(grad, x []float64) {
if len(x) != 4 {
panic("dimension of the problem must be 4")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
for i := range grad {
grad[i] = 0
}
for i := 1; i <= 20; i++ {
c := float64(i) / 5
f1 := x[0] + c*x[1] - math.Exp(c)
f2 := x[2] + x[3]*math.Sin(c) - math.Cos(c)
f := f1*f1 + f2*f2
grad[0] += 4 * f * f1
grad[1] += 4 * f * f1 * c
grad[2] += 4 * f * f2
grad[3] += 4 * f * f2 * math.Sin(c)
}
}
func (BrownAndDennis) Hess(dst *mat.SymDense, x []float64) {
if len(x) != 4 {
panic("dimension of the problem must be 4")
}
if len(x) != dst.SymmetricDim() {
panic("incorrect size of the Hessian")
}
for i := 0; i < 4; i++ {
for j := i; j < 4; j++ {
dst.SetSym(i, j, 0)
}
}
for i := 1; i <= 20; i++ {
d1 := float64(i) / 5
d2 := math.Sin(d1)
t1 := x[0] + d1*x[1] - math.Exp(d1)
t2 := x[2] + d2*x[3] - math.Cos(d1)
t := t1*t1 + t2*t2
s3 := 2 * t1 * t2
r1 := t + 2*t1*t1
r2 := t + 2*t2*t2
dst.SetSym(0, 0, dst.At(0, 0)+r1)
dst.SetSym(0, 1, dst.At(0, 1)+d1*r1)
dst.SetSym(1, 1, dst.At(1, 1)+d1*d1*r1)
dst.SetSym(0, 2, dst.At(0, 2)+s3)
dst.SetSym(1, 2, dst.At(1, 2)+d1*s3)
dst.SetSym(2, 2, dst.At(2, 2)+r2)
dst.SetSym(0, 3, dst.At(0, 3)+d2*s3)
dst.SetSym(1, 3, dst.At(1, 3)+d1*d2*s3)
dst.SetSym(2, 3, dst.At(2, 3)+d2*r2)
dst.SetSym(3, 3, dst.At(3, 3)+d2*d2*r2)
}
for i := 0; i < 4; i++ {
for j := i; j < 4; j++ {
dst.SetSym(i, j, 4*dst.At(i, j))
}
}
}
func (BrownAndDennis) Minima() []Minimum {
return []Minimum{
{
X: []float64{-11.594439904762162, 13.203630051207202, -0.4034394881768612, 0.2367787744557347},
F: 85822.20162635634,
Global: true,
},
}
}
// ExtendedPowellSingular implements the extended Powell's function.
// Its Hessian matrix is singular at the minimizer.
//
// Standard starting point:
//
// [3, -1, 0, 3, 3, -1, 0, 3, ..., 3, -1, 0, 3]
//
// References:
// - Spedicato E.: Computational experience with quasi-Newton algorithms for
// minimization problems of moderately large size. Towards Global
// Optimization 2 (1978), 209-219
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type ExtendedPowellSingular struct{}
func (ExtendedPowellSingular) Func(x []float64) (sum float64) {
if len(x)%4 != 0 {
panic("dimension of the problem must be a multiple of 4")
}
for i := 0; i < len(x); i += 4 {
f1 := x[i] + 10*x[i+1]
f2 := x[i+2] - x[i+3]
t := x[i+1] - 2*x[i+2]
f3 := t * t
t = x[i] - x[i+3]
f4 := t * t
sum += f1*f1 + 5*f2*f2 + f3*f3 + 10*f4*f4
}
return sum
}
func (ExtendedPowellSingular) Grad(grad, x []float64) {
if len(x)%4 != 0 {
panic("dimension of the problem must be a multiple of 4")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
for i := 0; i < len(x); i += 4 {
f1 := x[i] + 10*x[i+1]
f2 := x[i+2] - x[i+3]
t1 := x[i+1] - 2*x[i+2]
f3 := t1 * t1
t2 := x[i] - x[i+3]
f4 := t2 * t2
grad[i] = 2*f1 + 40*f4*t2
grad[i+1] = 20*f1 + 4*f3*t1
grad[i+2] = 10*f2 - 8*f3*t1
grad[i+3] = -10*f2 - 40*f4*t2
}
}
func (ExtendedPowellSingular) Minima() []Minimum {
return []Minimum{
{
X: []float64{0, 0, 0, 0},
F: 0,
Global: true,
},
{
X: []float64{0, 0, 0, 0, 0, 0, 0, 0},
F: 0,
Global: true,
},
{
X: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
F: 0,
Global: true,
},
}
}
// ExtendedRosenbrock implements the extended, multidimensional Rosenbrock
// function.
//
// Standard starting point:
//
// Easy: [-1.2, 1, -1.2, 1, ...]
// Hard: any point far from the minimum
//
// References:
// - Rosenbrock, H.H.: An Automatic Method for Finding the Greatest or Least
// Value of a Function. Computer J 3 (1960), 175-184
// - http://en.wikipedia.org/wiki/Rosenbrock_function
type ExtendedRosenbrock struct{}
func (ExtendedRosenbrock) Func(x []float64) (sum float64) {
for i := 0; i < len(x)-1; i++ {
a := 1 - x[i]
b := x[i+1] - x[i]*x[i]
sum += a*a + 100*b*b
}
return sum
}
func (ExtendedRosenbrock) Grad(grad, x []float64) {
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
dim := len(x)
for i := range grad {
grad[i] = 0
}
// Prevent fused multiply add and fused multiply subtract.
for i := 0; i < dim-1; i++ {
grad[i] -= float64(2 * (1 - x[i]))
grad[i] -= float64(400 * (x[i+1] - float64(x[i]*x[i])) * x[i])
}
for i := 1; i < dim; i++ {
grad[i] += float64(200 * (x[i] - float64(x[i-1]*x[i-1])))
}
}
func (ExtendedRosenbrock) Minima() []Minimum {
return []Minimum{
{
X: []float64{1, 1},
F: 0,
Global: true,
},
{
X: []float64{1, 1, 1},
F: 0,
Global: true,
},
{
X: []float64{1, 1, 1, 1},
F: 0,
Global: true,
},
{
X: []float64{-0.7756592265653526, 0.6130933654850433,
0.38206284633839305, 0.14597201855219452},
F: 3.701428610430017,
Global: false,
},
{
X: []float64{1, 1, 1, 1, 1},
F: 0,
Global: true,
},
{
X: []float64{-0.9620510206947502, 0.9357393959767103,
0.8807136041943204, 0.7778776758544063, 0.6050936785926526},
F: 3.930839434133027,
Global: false,
},
{
X: []float64{-0.9865749795709938, 0.9833982288361819, 0.972106670053092,
0.9474374368264362, 0.8986511848517299, 0.8075739520354182},
F: 3.973940500930295,
Global: false,
},
{
X: []float64{-0.9917225725614055, 0.9935553935033712, 0.992173321594692,
0.9868987626903134, 0.975164756608872, 0.9514319827049906, 0.9052228177139495},
F: 3.9836005364248543,
Global: false,
},
{
X: []float64{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
F: 0,
Global: true,
},
}
}
// Gaussian implements the Gaussian function.
// The function has one global minimum and a number of false local minima
// caused by the finite floating point precision.
//
// Standard starting point:
//
// [0.4, 1, 0]
//
// Reference:
//
// More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained optimization
// software. ACM Trans Math Softw 7 (1981), 17-41
type Gaussian struct{}
func (Gaussian) y(i int) (yi float64) {
switch i {
case 1, 15:
yi = 0.0009
case 2, 14:
yi = 0.0044
case 3, 13:
yi = 0.0175
case 4, 12:
yi = 0.0540
case 5, 11:
yi = 0.1295
case 6, 10:
yi = 0.2420
case 7, 9:
yi = 0.3521
case 8:
yi = 0.3989
}
return yi
}
func (g Gaussian) Func(x []float64) (sum float64) {
if len(x) != 3 {
panic("dimension of the problem must be 3")
}
for i := 1; i <= 15; i++ {
c := 0.5 * float64(8-i)
b := c - x[2]
d := b * b
e := math.Exp(-0.5 * x[1] * d)
f := x[0]*e - g.y(i)
sum += f * f
}
return sum
}
func (g Gaussian) Grad(grad, x []float64) {
if len(x) != 3 {
panic("dimension of the problem must be 3")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
grad[0] = 0
grad[1] = 0
grad[2] = 0
for i := 1; i <= 15; i++ {
c := 0.5 * float64(8-i)
b := c - x[2]
d := b * b
e := math.Exp(-0.5 * x[1] * d)
f := x[0]*e - g.y(i)
grad[0] += 2 * f * e
grad[1] -= f * e * d * x[0]
grad[2] += 2 * f * e * x[0] * x[1] * b
}
}
func (Gaussian) Minima() []Minimum {
return []Minimum{
{
X: []float64{0.398956137837997, 1.0000190844805048, 0},
F: 1.12793276961912e-08,
Global: true,
},
}
}
// GulfResearchAndDevelopment implements the Gulf Research and Development function.
//
// Standard starting point:
//
// [5, 2.5, 0.15]
//
// References:
// - Cox, R.A.: Comparison of the performance of seven optimization algorithms
// on twelve unconstrained minimization problems. Ref. 1335CNO4, Gulf
// Research and Development Company, Pittsburg (1969)
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type GulfResearchAndDevelopment struct{}
func (GulfResearchAndDevelopment) Func(x []float64) (sum float64) {
if len(x) != 3 {
panic("dimension of the problem must be 3")
}
for i := 1; i <= 99; i++ {
arg := float64(i) / 100
r := math.Pow(-50*math.Log(arg), 2.0/3.0) + 25 - x[1]
t1 := math.Pow(math.Abs(r), x[2]) / x[0]
t2 := math.Exp(-t1)
t := t2 - arg
sum += t * t
}
return sum
}
func (GulfResearchAndDevelopment) Grad(grad, x []float64) {
if len(x) != 3 {
panic("dimension of the problem must be 3")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
for i := range grad {
grad[i] = 0
}
for i := 1; i <= 99; i++ {
arg := float64(i) / 100
r := math.Pow(-50*math.Log(arg), 2.0/3.0) + 25 - x[1]
t1 := math.Pow(math.Abs(r), x[2]) / x[0]
t2 := math.Exp(-t1)
t := t2 - arg
s1 := t1 * t2 * t
grad[0] += s1
grad[1] += s1 / r
grad[2] -= s1 * math.Log(math.Abs(r))
}
grad[0] *= 2 / x[0]
grad[1] *= 2 * x[2]
grad[2] *= 2
}
func (GulfResearchAndDevelopment) Minima() []Minimum {
return []Minimum{
{
X: []float64{50, 25, 1.5},
F: 0,
Global: true,
},
{
X: []float64{99.89529935174151, 60.61453902799833, 9.161242695144592},
F: 32.8345,
Global: false,
},
{
X: []float64{201.662589489426, 60.61633150468155, 10.224891158488965},
F: 32.8345,
Global: false,
},
}
}
// HelicalValley implements the helical valley function of Fletcher and Powell.
// Function is not defined at x[0] = 0.
//
// Standard starting point:
//
// [-1, 0, 0]
//
// References:
// - Fletcher, R., Powell, M.J.D.: A rapidly convergent descent method for
// minimization. Comput J 6 (1963), 163-168
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type HelicalValley struct{}
func (HelicalValley) Func(x []float64) float64 {
if len(x) != 3 {
panic("dimension of the problem must be 3")
}
if x[0] == 0 {
panic("function not defined at x[0] = 0")
}
theta := 0.5 * math.Atan(x[1]/x[0]) / math.Pi
if x[0] < 0 {
theta += 0.5
}
f1 := 10 * (x[2] - 10*theta)
f2 := 10 * (math.Hypot(x[0], x[1]) - 1)
f3 := x[2]
return f1*f1 + f2*f2 + f3*f3
}
func (HelicalValley) Grad(grad, x []float64) {
if len(x) != 3 {
panic("dimension of the problem must be 3")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
if x[0] == 0 {
panic("function not defined at x[0] = 0")
}
theta := 0.5 * math.Atan(x[1]/x[0]) / math.Pi
if x[0] < 0 {
theta += 0.5
}
h := math.Hypot(x[0], x[1])
r := 1 / h
q := r * r / math.Pi
s := x[2] - 10*theta
grad[0] = 200 * (5*s*q*x[1] + (h-1)*r*x[0])
grad[1] = 200 * (-5*s*q*x[0] + (h-1)*r*x[1])
grad[2] = 2 * (100*s + x[2])
}
func (HelicalValley) Minima() []Minimum {
return []Minimum{
{
X: []float64{1, 0, 0},
F: 0,
Global: true,
},
}
}
// Linear implements a linear function.
type Linear struct{}
func (Linear) Func(x []float64) float64 {
return floats.Sum(x)
}
func (Linear) Grad(grad, x []float64) []float64 {
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
for i := range grad {
grad[i] = 1
}
return grad
}
// PenaltyI implements the first penalty function by Gill, Murray and Pitfield.
//
// Standard starting point:
//
// [1, ..., n]
//
// References:
// - Gill, P.E., Murray, W., Pitfield, R.A.: The implementation of two revised
// quasi-Newton algorithms for unconstrained optimization. Report NAC 11,
// National Phys Lab (1972), 82-83
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type PenaltyI struct{}
func (PenaltyI) Func(x []float64) (sum float64) {
for _, v := range x {
sum += (v - 1) * (v - 1)
}
sum *= 1e-5
var s float64
for _, v := range x {
s += v * v
}
sum += (s - 0.25) * (s - 0.25)
return sum
}
func (PenaltyI) Grad(grad, x []float64) {
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
s := -0.25
for _, v := range x {
s += v * v
}
for i, v := range x {
grad[i] = 2 * (2*s*v + 1e-5*(v-1))
}
}
func (PenaltyI) Minima() []Minimum {
return []Minimum{
{
X: []float64{0.2500074995875379, 0.2500074995875379, 0.2500074995875379, 0.2500074995875379},
F: 2.2499775008999372e-05,
Global: true,
},
{
X: []float64{0.15812230111311634, 0.15812230111311634, 0.15812230111311634,
0.15812230111311634, 0.15812230111311634, 0.15812230111311634,
0.15812230111311634, 0.15812230111311634, 0.15812230111311634, 0.15812230111311634},
F: 7.087651467090369e-05,
Global: true,
},
}
}
// PenaltyII implements the second penalty function by Gill, Murray and Pitfield.
//
// Standard starting point:
//
// [0.5, ..., 0.5]
//
// References:
// - Gill, P.E., Murray, W., Pitfield, R.A.: The implementation of two revised
// quasi-Newton algorithms for unconstrained optimization. Report NAC 11,
// National Phys Lab (1972), 82-83
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type PenaltyII struct{}
func (PenaltyII) Func(x []float64) (sum float64) {
dim := len(x)
s := -1.0
for i, v := range x {
s += float64(dim-i) * v * v
}
for i := 1; i < dim; i++ {
yi := math.Exp(float64(i+1)/10) + math.Exp(float64(i)/10)
f := math.Exp(x[i]/10) + math.Exp(x[i-1]/10) - yi
sum += f * f
}
for i := 1; i < dim; i++ {
f := math.Exp(x[i]/10) - math.Exp(-1.0/10)
sum += f * f
}
sum *= 1e-5
sum += (x[0] - 0.2) * (x[0] - 0.2)
sum += s * s
return sum
}
func (PenaltyII) Grad(grad, x []float64) {
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
dim := len(x)
s := -1.0
for i, v := range x {
s += float64(dim-i) * v * v
}
for i, v := range x {
grad[i] = 4 * s * float64(dim-i) * v
}
for i := 1; i < dim; i++ {
yi := math.Exp(float64(i+1)/10) + math.Exp(float64(i)/10)
f := math.Exp(x[i]/10) + math.Exp(x[i-1]/10) - yi
grad[i] += 1e-5 * f * math.Exp(x[i]/10) / 5
grad[i-1] += 1e-5 * f * math.Exp(x[i-1]/10) / 5
}
for i := 1; i < dim; i++ {
f := math.Exp(x[i]/10) - math.Exp(-1.0/10)
grad[i] += 1e-5 * f * math.Exp(x[i]/10) / 5
}
grad[0] += 2 * (x[0] - 0.2)
}
func (PenaltyII) Minima() []Minimum {
return []Minimum{
{
X: []float64{0.19999933335, 0.19131670128566283, 0.4801014860897, 0.5188454026659},
F: 9.376293007355449e-06,
Global: true,
},
{
X: []float64{0.19998360520892217, 0.010350644318663525,
0.01960493546891094, 0.03208906550305253, 0.04993267593895693,
0.07651399534454084, 0.11862407118600789, 0.1921448731780023,
0.3473205862372022, 0.36916437893066273},
F: 0.00029366053745674594,
Global: true,
},
}
}
// PowellBadlyScaled implements the Powell's badly scaled function.
// The function is very flat near the minimum. A satisfactory solution is one
// that gives f(x) ≅ 1e-13.
//
// Standard starting point:
//
// [0, 1]
//
// References:
// - Powell, M.J.D.: A Hybrid Method for Nonlinear Equations. Numerical
// Methods for Nonlinear Algebraic Equations, P. Rabinowitz (ed.), Gordon
// and Breach (1970)
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type PowellBadlyScaled struct{}
func (PowellBadlyScaled) Func(x []float64) float64 {
if len(x) != 2 {
panic("dimension of the problem must be 2")
}
f1 := 1e4*x[0]*x[1] - 1
f2 := math.Exp(-x[0]) + math.Exp(-x[1]) - 1.0001
return f1*f1 + f2*f2
}
func (PowellBadlyScaled) Grad(grad, x []float64) {
if len(x) != 2 {
panic("dimension of the problem must be 2")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
f1 := 1e4*x[0]*x[1] - 1
f2 := math.Exp(-x[0]) + math.Exp(-x[1]) - 1.0001
grad[0] = 2 * (1e4*f1*x[1] - f2*math.Exp(-x[0]))
grad[1] = 2 * (1e4*f1*x[0] - f2*math.Exp(-x[1]))
}
func (PowellBadlyScaled) Hess(dst *mat.SymDense, x []float64) {
if len(x) != 2 {
panic("dimension of the problem must be 2")
}
if len(x) != dst.SymmetricDim() {
panic("incorrect size of the Hessian")
}
t1 := 1e4*x[0]*x[1] - 1
s1 := math.Exp(-x[0])
s2 := math.Exp(-x[1])
t2 := s1 + s2 - 1.0001
h00 := 2 * (1e8*x[1]*x[1] + s1*(s1+t2))
h01 := 2 * (1e4*(1+2*t1) + s1*s2)
h11 := 2 * (1e8*x[0]*x[0] + s2*(s2+t2))
dst.SetSym(0, 0, h00)
dst.SetSym(0, 1, h01)
dst.SetSym(1, 1, h11)
}
func (PowellBadlyScaled) Minima() []Minimum {
return []Minimum{
{
X: []float64{1.0981593296997149e-05, 9.106146739867375},
F: 0,
Global: true,
},
}
}
// Trigonometric implements the trigonometric function.
//
// Standard starting point:
//
// [1/dim, ..., 1/dim]
//
// References:
// - Spedicato E.: Computational experience with quasi-Newton algorithms for
// minimization problems of moderately large size. Towards Global
// Optimization 2 (1978), 209-219
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type Trigonometric struct{}
func (Trigonometric) Func(x []float64) (sum float64) {
var s1 float64
for _, v := range x {
s1 += math.Cos(v)
}
for i, v := range x {
f := float64(len(x)+i+1) - float64(i+1)*math.Cos(v) - math.Sin(v) - s1
sum += f * f
}
return sum
}
func (Trigonometric) Grad(grad, x []float64) {
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
var s1 float64
for _, v := range x {
s1 += math.Cos(v)
}
var s2 float64
for i, v := range x {
f := float64(len(x)+i+1) - float64(i+1)*math.Cos(v) - math.Sin(v) - s1
s2 += f
grad[i] = 2 * f * (float64(i+1)*math.Sin(v) - math.Cos(v))
}
for i, v := range x {
grad[i] += 2 * s2 * math.Sin(v)
}
}
func (Trigonometric) Minima() []Minimum {
return []Minimum{
{
X: []float64{0.04296456438227447, 0.043976287478192246,
0.045093397949095684, 0.04633891624617569, 0.047744381782831,
0.04935473251330618, 0.05123734850076505, 0.19520946391410446,
0.1649776652761741, 0.06014857783799575},
F: 0,
Global: true,
},
{
// TODO(vladimir-ch): If we knew the location of this minimum more
// accurately, we could decrease defaultGradTol.
X: []float64{0.05515090434047145, 0.05684061730812344,
0.05876400231100774, 0.060990608903034337, 0.06362621381044778,
0.06684318087364617, 0.2081615177172172, 0.16436309604419047,
0.08500689695564931, 0.09143145386293675},
F: 2.795056121876575e-05,
Global: false,
},
}
}
// VariablyDimensioned implements a variably dimensioned function.
//
// Standard starting point:
//
// [..., (dim-i)/dim, ...], i=1,...,dim
//
// References:
//
// More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained optimization
// software. ACM Trans Math Softw 7 (1981), 17-41
type VariablyDimensioned struct{}
func (VariablyDimensioned) Func(x []float64) (sum float64) {
for _, v := range x {
t := v - 1
sum += t * t
}
var s float64
for i, v := range x {
s += float64(i+1) * (v - 1)
}
s *= s
sum += s
s *= s
sum += s
return sum
}
func (VariablyDimensioned) Grad(grad, x []float64) {
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
var s float64
for i, v := range x {
s += float64(i+1) * (v - 1)
}
for i, v := range x {
grad[i] = 2 * (v - 1 + s*float64(i+1)*(1+2*s*s))
}
}
func (VariablyDimensioned) Minima() []Minimum {
return []Minimum{
{
X: []float64{1, 1},
F: 0,
Global: true,
},
{
X: []float64{1, 1, 1},
F: 0,
Global: true,
},
{
X: []float64{1, 1, 1, 1},
F: 0,
Global: true,
},
{
X: []float64{1, 1, 1, 1, 1},
F: 0,
Global: true,
},
{
X: []float64{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
F: 0,
Global: true,
},
}
}
// Watson implements the Watson's function.
// Dimension of the problem should be 2 <= dim <= 31. For dim == 9, the problem
// of minimizing the function is very ill conditioned.
//
// Standard starting point:
//
// [0, ..., 0]
//
// References:
// - Kowalik, J.S., Osborne, M.R.: Methods for Unconstrained Optimization
// Problems. Elsevier North-Holland, New York, 1968
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type Watson struct{}
func (Watson) Func(x []float64) (sum float64) {
for i := 1; i <= 29; i++ {
d1 := float64(i) / 29
d2 := 1.0
var s1 float64
for j := 1; j < len(x); j++ {
s1 += float64(j) * d2 * x[j]
d2 *= d1
}
d2 = 1.0
var s2 float64
for _, v := range x {
s2 += d2 * v
d2 *= d1
}
t := s1 - s2*s2 - 1
sum += t * t
}
t := x[1] - x[0]*x[0] - 1
sum += x[0]*x[0] + t*t
return sum
}
func (Watson) Grad(grad, x []float64) {
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
for i := range grad {
grad[i] = 0
}
for i := 1; i <= 29; i++ {
d1 := float64(i) / 29
d2 := 1.0
var s1 float64
for j := 1; j < len(x); j++ {
s1 += float64(j) * d2 * x[j]
d2 *= d1
}
d2 = 1.0
var s2 float64
for _, v := range x {
s2 += d2 * v
d2 *= d1
}
t := s1 - s2*s2 - 1
s3 := 2 * d1 * s2
d2 = 2 / d1
for j := range x {
grad[j] += d2 * (float64(j) - s3) * t
d2 *= d1
}
}
t := x[1] - x[0]*x[0] - 1
grad[0] += x[0] * (2 - 4*t)
grad[1] += 2 * t
}
func (Watson) Hess(dst *mat.SymDense, x []float64) {
dim := len(x)
if len(x) != dst.SymmetricDim() {
panic("incorrect size of the Hessian")
}
for j := 0; j < dim; j++ {
for k := j; k < dim; k++ {
dst.SetSym(j, k, 0)
}
}
for i := 1; i <= 29; i++ {
d1 := float64(i) / 29
d2 := 1.0
var s1 float64
for j := 1; j < dim; j++ {
s1 += float64(j) * d2 * x[j]
d2 *= d1
}
d2 = 1.0
var s2 float64
for _, v := range x {
s2 += d2 * v
d2 *= d1
}
t := s1 - s2*s2 - 1
s3 := 2 * d1 * s2
d2 = 2 / d1
th := 2 * d1 * d1 * t
for j := 0; j < dim; j++ {
v := float64(j) - s3
d3 := 1 / d1
for k := 0; k <= j; k++ {
dst.SetSym(k, j, dst.At(k, j)+d2*d3*(v*(float64(k)-s3)-th))
d3 *= d1
}
d2 *= d1
}
}
t1 := x[1] - x[0]*x[0] - 1
dst.SetSym(0, 0, dst.At(0, 0)+8*x[0]*x[0]+2-4*t1)
dst.SetSym(0, 1, dst.At(0, 1)-4*x[0])
dst.SetSym(1, 1, dst.At(1, 1)+2)
}
func (Watson) Minima() []Minimum {
return []Minimum{
{
X: []float64{-0.01572508644590686, 1.012434869244884, -0.23299162372002916,
1.2604300800978554, -1.51372891341701, 0.9929964286340117},
F: 0.0022876700535523838,
Global: true,
},
{
X: []float64{-1.5307036521992127e-05, 0.9997897039319495, 0.01476396369355022,
0.14634232829939883, 1.0008211030046426, -2.617731140519101, 4.104403164479245,
-3.1436122785568514, 1.0526264080103074},
F: 1.399760138096796e-06,
Global: true,
},
// TODO(vladimir-ch): More, Garbow, Hillstrom list just the value, but
// not the location. Our minimizers find a minimum, but the value is
// different.
// {
// // For dim == 12
// F: 4.72238e-10,
// Global: true,
// },
// TODO(vladimir-ch): netlib/uncon report a value of 2.48631d-20 for dim == 20.
}
}
// Wood implements the Wood's function.
//
// Standard starting point:
//
// [-3, -1, -3, -1]
//
// References:
// - Colville, A.R.: A comparative study of nonlinear programming codes.
// Report 320-2949, IBM New York Scientific Center (1968)
// - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
// optimization software. ACM Trans Math Softw 7 (1981), 17-41
type Wood struct{}
func (Wood) Func(x []float64) (sum float64) {
if len(x) != 4 {
panic("dimension of the problem must be 4")
}
f1 := x[1] - x[0]*x[0]
f2 := 1 - x[0]
f3 := x[3] - x[2]*x[2]
f4 := 1 - x[2]
f5 := x[1] + x[3] - 2
f6 := x[1] - x[3]
return 100*f1*f1 + f2*f2 + 90*f3*f3 + f4*f4 + 10*f5*f5 + 0.1*f6*f6
}
func (Wood) Grad(grad, x []float64) {
if len(x) != 4 {
panic("dimension of the problem must be 4")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
f1 := x[1] - x[0]*x[0]
f2 := 1 - x[0]
f3 := x[3] - x[2]*x[2]
f4 := 1 - x[2]
f5 := x[1] + x[3] - 2
f6 := x[1] - x[3]
grad[0] = -2 * (200*f1*x[0] + f2)
grad[1] = 2 * (100*f1 + 10*f5 + 0.1*f6)
grad[2] = -2 * (180*f3*x[2] + f4)
grad[3] = 2 * (90*f3 + 10*f5 - 0.1*f6)
}
func (Wood) Hess(dst *mat.SymDense, x []float64) {
if len(x) != 4 {
panic("dimension of the problem must be 4")
}
if len(x) != dst.SymmetricDim() {
panic("incorrect size of the Hessian")
}
dst.SetSym(0, 0, 400*(3*x[0]*x[0]-x[1])+2)
dst.SetSym(0, 1, -400*x[0])
dst.SetSym(1, 1, 220.2)
dst.SetSym(0, 2, 0)
dst.SetSym(1, 2, 0)
dst.SetSym(2, 2, 360*(3*x[2]*x[2]-x[3])+2)
dst.SetSym(0, 3, 0)
dst.SetSym(1, 3, 19.8)
dst.SetSym(2, 3, -360*x[2])
dst.SetSym(3, 3, 200.2)
}
func (Wood) Minima() []Minimum {
return []Minimum{
{
X: []float64{1, 1, 1, 1},
F: 0,
Global: true,
},
}
}
// ConcaveRight implements an univariate function that is concave to the right
// of the minimizer which is located at x=sqrt(2).
//
// References:
//
// More, J.J., and Thuente, D.J.: Line Search Algorithms with Guaranteed Sufficient Decrease.
// ACM Transactions on Mathematical Software 20(3) (1994), 286307, eq. (5.1)
type ConcaveRight struct{}
func (ConcaveRight) Func(x []float64) float64 {
if len(x) != 1 {
panic("dimension of the problem must be 1")
}
return -x[0] / (x[0]*x[0] + 2)
}
func (ConcaveRight) Grad(grad, x []float64) {
if len(x) != 1 {
panic("dimension of the problem must be 1")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
xSqr := x[0] * x[0]
grad[0] = (xSqr - 2) / (xSqr + 2) / (xSqr + 2)
}
// ConcaveLeft implements an univariate function that is concave to the left of
// the minimizer which is located at x=399/250=1.596.
//
// References:
//
// More, J.J., and Thuente, D.J.: Line Search Algorithms with Guaranteed Sufficient Decrease.
// ACM Transactions on Mathematical Software 20(3) (1994), 286307, eq. (5.2)
type ConcaveLeft struct{}
func (ConcaveLeft) Func(x []float64) float64 {
if len(x) != 1 {
panic("dimension of the problem must be 1")
}
return math.Pow(x[0]+0.004, 4) * (x[0] - 1.996)
}
func (ConcaveLeft) Grad(grad, x []float64) {
if len(x) != 1 {
panic("dimension of the problem must be 1")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
grad[0] = math.Pow(x[0]+0.004, 3) * (5*x[0] - 7.98)
}
// Plassmann implements an univariate oscillatory function where the value of L
// controls the number of oscillations. The value of Beta controls the size of
// the derivative at zero and the size of the interval where the strong Wolfe
// conditions can hold. For small values of Beta this function represents a
// difficult test problem for linesearchers also because the information based
// on the derivative is unreliable due to the oscillations.
//
// References:
//
// More, J.J., and Thuente, D.J.: Line Search Algorithms with Guaranteed Sufficient Decrease.
// ACM Transactions on Mathematical Software 20(3) (1994), 286307, eq. (5.3)
type Plassmann struct {
L float64 // Number of oscillations for |x-1| ≥ Beta.
Beta float64 // Size of the derivative at zero, f'(0) = -Beta.
}
func (f Plassmann) Func(x []float64) float64 {
if len(x) != 1 {
panic("dimension of the problem must be 1")
}
a := x[0]
b := f.Beta
l := f.L
r := 2 * (1 - b) / l / math.Pi * math.Sin(l*math.Pi/2*a)
switch {
case a <= 1-b:
r += 1 - a
case 1-b < a && a <= 1+b:
r += 0.5 * ((a-1)*(a-1)/b + b)
default: // a > 1+b
r += a - 1
}
return r
}
func (f Plassmann) Grad(grad, x []float64) {
if len(x) != 1 {
panic("dimension of the problem must be 1")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
a := x[0]
b := f.Beta
l := f.L
grad[0] = (1 - b) * math.Cos(l*math.Pi/2*a)
switch {
case a <= 1-b:
grad[0]--
case 1-b < a && a <= 1+b:
grad[0] += (a - 1) / b
default: // a > 1+b
grad[0]++
}
}
// YanaiOzawaKaneko is an univariate convex function where the values of Beta1
// and Beta2 control the curvature around the minimum. Far away from the
// minimum the function approximates an absolute value function. Near the
// minimum, the function can either be sharply curved or flat, controlled by
// the parameter values.
//
// References:
// - More, J.J., and Thuente, D.J.: Line Search Algorithms with Guaranteed Sufficient Decrease.
// ACM Transactions on Mathematical Software 20(3) (1994), 286307, eq. (5.4)
// - Yanai, H., Ozawa, M., and Kaneko, S.: Interpolation methods in one dimensional
// optimization. Computing 27 (1981), 155163
type YanaiOzawaKaneko struct {
Beta1 float64
Beta2 float64
}
func (f YanaiOzawaKaneko) Func(x []float64) float64 {
if len(x) != 1 {
panic("dimension of the problem must be 1")
}
a := x[0]
b1 := f.Beta1
b2 := f.Beta2
g1 := math.Sqrt(1+b1*b1) - b1
g2 := math.Sqrt(1+b2*b2) - b2
return g1*math.Sqrt((a-1)*(a-1)+b2*b2) + g2*math.Sqrt(a*a+b1*b1)
}
func (f YanaiOzawaKaneko) Grad(grad, x []float64) {
if len(x) != 1 {
panic("dimension of the problem must be 1")
}
if len(x) != len(grad) {
panic("incorrect size of the gradient")
}
a := x[0]
b1 := f.Beta1
b2 := f.Beta2
g1 := math.Sqrt(1+b1*b1) - b1
g2 := math.Sqrt(1+b2*b2) - b2
grad[0] = g1*(a-1)/math.Sqrt(b2*b2+(a-1)*(a-1)) + g2*a/math.Sqrt(b1*b1+a*a)
}