optimize: unify Gradient and Hessian API behaviour

This commit is contained in:
Dan Kortschak
2019-04-18 17:05:02 +09:30
parent ae324d6d48
commit 9a5a03f262
4 changed files with 47 additions and 148 deletions

View File

@@ -36,13 +36,10 @@ func (Beale) Func(x []float64) float64 {
return f1*f1 + f2*f2 + f3*f3 return f1*f1 + f2*f2 + f3*f3
} }
func (Beale) Grad(grad, x []float64) []float64 { func (Beale) Grad(grad, x []float64) {
if len(x) != 2 { if len(x) != 2 {
panic("dimension of the problem must be 2") panic("dimension of the problem must be 2")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -57,16 +54,13 @@ func (Beale) Grad(grad, x []float64) []float64 {
grad[0] = -2 * (f1*t1 + f2*t2 + f3*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]) grad[1] = 2 * x[0] * (f1 + 2*f2*x[1] + 3*f3*x[1]*x[1])
return grad
} }
func (Beale) Hess(dst *mat.SymDense, x []float64) { func (Beale) Hess(dst *mat.SymDense, x []float64) {
if len(x) != 2 { if len(x) != 2 {
panic("dimension of the problem must be 2") panic("dimension of the problem must be 2")
} }
if dst.IsZero() { if len(x) != dst.Symmetric() {
*dst = *(dst.GrowSym(len(x)).(*mat.SymDense))
} else if len(x) != dst.Symmetric() {
panic("incorrect size of the Hessian") panic("incorrect size of the Hessian")
} }
@@ -119,13 +113,10 @@ func (BiggsEXP2) Func(x []float64) (sum float64) {
return sum return sum
} }
func (BiggsEXP2) Grad(grad, x []float64) []float64 { func (BiggsEXP2) Grad(grad, x []float64) {
if len(x) != 2 { if len(x) != 2 {
panic("dimension of the problem must be 2") panic("dimension of the problem must be 2")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -144,7 +135,6 @@ func (BiggsEXP2) Grad(grad, x []float64) []float64 {
grad[0] += 2 * f * dfdx0 grad[0] += 2 * f * dfdx0
grad[1] += 2 * f * dfdx1 grad[1] += 2 * f * dfdx1
} }
return grad
} }
func (BiggsEXP2) Minima() []Minimum { func (BiggsEXP2) Minima() []Minimum {
@@ -181,13 +171,10 @@ func (BiggsEXP3) Func(x []float64) (sum float64) {
return sum return sum
} }
func (BiggsEXP3) Grad(grad, x []float64) []float64 { func (BiggsEXP3) Grad(grad, x []float64) {
if len(x) != 3 { if len(x) != 3 {
panic("dimension of the problem must be 3") panic("dimension of the problem must be 3")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -208,7 +195,6 @@ func (BiggsEXP3) Grad(grad, x []float64) []float64 {
grad[1] += 2 * f * dfdx1 grad[1] += 2 * f * dfdx1
grad[2] += 2 * f * dfdx2 grad[2] += 2 * f * dfdx2
} }
return grad
} }
func (BiggsEXP3) Minima() []Minimum { func (BiggsEXP3) Minima() []Minimum {
@@ -245,13 +231,10 @@ func (BiggsEXP4) Func(x []float64) (sum float64) {
return sum return sum
} }
func (BiggsEXP4) Grad(grad, x []float64) []float64 { func (BiggsEXP4) Grad(grad, x []float64) {
if len(x) != 4 { if len(x) != 4 {
panic("dimension of the problem must be 4") panic("dimension of the problem must be 4")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -274,7 +257,6 @@ func (BiggsEXP4) Grad(grad, x []float64) []float64 {
grad[2] += 2 * f * dfdx2 grad[2] += 2 * f * dfdx2
grad[3] += 2 * f * dfdx3 grad[3] += 2 * f * dfdx3
} }
return grad
} }
func (BiggsEXP4) Minima() []Minimum { func (BiggsEXP4) Minima() []Minimum {
@@ -311,13 +293,10 @@ func (BiggsEXP5) Func(x []float64) (sum float64) {
return sum return sum
} }
func (BiggsEXP5) Grad(grad, x []float64) []float64 { func (BiggsEXP5) Grad(grad, x []float64) {
if len(x) != 5 { if len(x) != 5 {
panic("dimension of the problem must be 5") panic("dimension of the problem must be 5")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -342,7 +321,6 @@ func (BiggsEXP5) Grad(grad, x []float64) []float64 {
grad[3] += 2 * f * dfdx3 grad[3] += 2 * f * dfdx3
grad[4] += 2 * f * dfdx4 grad[4] += 2 * f * dfdx4
} }
return grad
} }
func (BiggsEXP5) Minima() []Minimum { func (BiggsEXP5) Minima() []Minimum {
@@ -382,13 +360,10 @@ func (BiggsEXP6) Func(x []float64) (sum float64) {
return sum return sum
} }
func (BiggsEXP6) Grad(grad, x []float64) []float64 { func (BiggsEXP6) Grad(grad, x []float64) {
if len(x) != 6 { if len(x) != 6 {
panic("dimension of the problem must be 6") panic("dimension of the problem must be 6")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -415,7 +390,6 @@ func (BiggsEXP6) Grad(grad, x []float64) []float64 {
grad[4] += 2 * f * dfdx4 grad[4] += 2 * f * dfdx4
grad[5] += 2 * f * dfdx5 grad[5] += 2 * f * dfdx5
} }
return grad
} }
func (BiggsEXP6) Minima() []Minimum { func (BiggsEXP6) Minima() []Minimum {
@@ -466,13 +440,10 @@ func (Box3D) Func(x []float64) (sum float64) {
return sum return sum
} }
func (Box3D) Grad(grad, x []float64) []float64 { func (Box3D) Grad(grad, x []float64) {
if len(x) != 3 { if len(x) != 3 {
panic("dimension of the problem must be 3") panic("dimension of the problem must be 3")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -488,7 +459,6 @@ func (Box3D) Grad(grad, x []float64) []float64 {
grad[1] += -2 * f * c * math.Exp(c*x[1]) grad[1] += -2 * f * c * math.Exp(c*x[1])
grad[2] += -2 * f * y grad[2] += -2 * f * y
} }
return grad
} }
func (Box3D) Minima() []Minimum { func (Box3D) Minima() []Minimum {
@@ -573,13 +543,10 @@ func (BrownBadlyScaled) Func(x []float64) float64 {
return f1*f1 + f2*f2 + f3*f3 return f1*f1 + f2*f2 + f3*f3
} }
func (BrownBadlyScaled) Grad(grad, x []float64) []float64 { func (BrownBadlyScaled) Grad(grad, x []float64) {
if len(x) != 2 { if len(x) != 2 {
panic("dimension of the problem must be 2") panic("dimension of the problem must be 2")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -589,16 +556,13 @@ func (BrownBadlyScaled) Grad(grad, x []float64) []float64 {
f3 := x[0]*x[1] - 2 f3 := x[0]*x[1] - 2
grad[0] = 2*f1 + 2*f3*x[1] grad[0] = 2*f1 + 2*f3*x[1]
grad[1] = 2*f2 + 2*f3*x[0] grad[1] = 2*f2 + 2*f3*x[0]
return grad
} }
func (BrownBadlyScaled) Hess(dst *mat.SymDense, x []float64) { func (BrownBadlyScaled) Hess(dst *mat.SymDense, x []float64) {
if len(x) != 2 { if len(x) != 2 {
panic("dimension of the problem must be 2") panic("dimension of the problem must be 2")
} }
if dst.IsZero() { if len(x) != dst.Symmetric() {
*dst = *(dst.GrowSym(len(x)).(*mat.SymDense))
} else if len(x) != dst.Symmetric() {
panic("incorrect size of the Hessian") panic("incorrect size of the Hessian")
} }
@@ -648,13 +612,10 @@ func (BrownAndDennis) Func(x []float64) (sum float64) {
return sum return sum
} }
func (BrownAndDennis) Grad(grad, x []float64) []float64 { func (BrownAndDennis) Grad(grad, x []float64) {
if len(x) != 4 { if len(x) != 4 {
panic("dimension of the problem must be 4") panic("dimension of the problem must be 4")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -672,16 +633,13 @@ func (BrownAndDennis) Grad(grad, x []float64) []float64 {
grad[2] += 4 * f * f2 grad[2] += 4 * f * f2
grad[3] += 4 * f * f2 * math.Sin(c) grad[3] += 4 * f * f2 * math.Sin(c)
} }
return grad
} }
func (BrownAndDennis) Hess(dst *mat.SymDense, x []float64) { func (BrownAndDennis) Hess(dst *mat.SymDense, x []float64) {
if len(x) != 4 { if len(x) != 4 {
panic("dimension of the problem must be 4") panic("dimension of the problem must be 4")
} }
if dst.IsZero() { if len(x) != dst.Symmetric() {
*dst = *(dst.GrowSym(len(x)).(*mat.SymDense))
} else if len(x) != dst.Symmetric() {
panic("incorrect size of the Hessian") panic("incorrect size of the Hessian")
} }
@@ -758,13 +716,10 @@ func (ExtendedPowellSingular) Func(x []float64) (sum float64) {
return sum return sum
} }
func (ExtendedPowellSingular) Grad(grad, x []float64) []float64 { func (ExtendedPowellSingular) Grad(grad, x []float64) {
if len(x)%4 != 0 { if len(x)%4 != 0 {
panic("dimension of the problem must be a multiple of 4") panic("dimension of the problem must be a multiple of 4")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -781,7 +736,6 @@ func (ExtendedPowellSingular) Grad(grad, x []float64) []float64 {
grad[i+2] = 10*f2 - 8*f3*t1 grad[i+2] = 10*f2 - 8*f3*t1
grad[i+3] = -10*f2 - 40*f4*t2 grad[i+3] = -10*f2 - 40*f4*t2
} }
return grad
} }
func (ExtendedPowellSingular) Minima() []Minimum { func (ExtendedPowellSingular) Minima() []Minimum {
@@ -826,10 +780,7 @@ func (ExtendedRosenbrock) Func(x []float64) (sum float64) {
return sum return sum
} }
func (ExtendedRosenbrock) Grad(grad, x []float64) []float64 { func (ExtendedRosenbrock) Grad(grad, x []float64) {
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -845,7 +796,6 @@ func (ExtendedRosenbrock) Grad(grad, x []float64) []float64 {
for i := 1; i < dim; i++ { for i := 1; i < dim; i++ {
grad[i] += 200 * (x[i] - x[i-1]*x[i-1]) grad[i] += 200 * (x[i] - x[i-1]*x[i-1])
} }
return grad
} }
func (ExtendedRosenbrock) Minima() []Minimum { func (ExtendedRosenbrock) Minima() []Minimum {
@@ -952,13 +902,10 @@ func (g Gaussian) Func(x []float64) (sum float64) {
return sum return sum
} }
func (g Gaussian) Grad(grad, x []float64) []float64 { func (g Gaussian) Grad(grad, x []float64) {
if len(x) != 3 { if len(x) != 3 {
panic("dimension of the problem must be 3") panic("dimension of the problem must be 3")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -976,7 +923,6 @@ func (g Gaussian) Grad(grad, x []float64) []float64 {
grad[1] -= f * e * d * x[0] grad[1] -= f * e * d * x[0]
grad[2] += 2 * f * e * x[0] * x[1] * b grad[2] += 2 * f * e * x[0] * x[1] * b
} }
return grad
} }
func (Gaussian) Minima() []Minimum { func (Gaussian) Minima() []Minimum {
@@ -1018,13 +964,10 @@ func (GulfResearchAndDevelopment) Func(x []float64) (sum float64) {
return sum return sum
} }
func (GulfResearchAndDevelopment) Grad(grad, x []float64) []float64 { func (GulfResearchAndDevelopment) Grad(grad, x []float64) {
if len(x) != 3 { if len(x) != 3 {
panic("dimension of the problem must be 3") panic("dimension of the problem must be 3")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -1046,7 +989,6 @@ func (GulfResearchAndDevelopment) Grad(grad, x []float64) []float64 {
grad[0] *= 2 / x[0] grad[0] *= 2 / x[0]
grad[1] *= 2 * x[2] grad[1] *= 2 * x[2]
grad[2] *= 2 grad[2] *= 2
return grad
} }
func (GulfResearchAndDevelopment) Minima() []Minimum { func (GulfResearchAndDevelopment) Minima() []Minimum {
@@ -1100,13 +1042,10 @@ func (HelicalValley) Func(x []float64) float64 {
return f1*f1 + f2*f2 + f3*f3 return f1*f1 + f2*f2 + f3*f3
} }
func (HelicalValley) Grad(grad, x []float64) []float64 { func (HelicalValley) Grad(grad, x []float64) {
if len(x) != 3 { if len(x) != 3 {
panic("dimension of the problem must be 3") panic("dimension of the problem must be 3")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -1125,7 +1064,6 @@ func (HelicalValley) Grad(grad, x []float64) []float64 {
grad[0] = 200 * (5*s*q*x[1] + (h-1)*r*x[0]) 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[1] = 200 * (-5*s*q*x[0] + (h-1)*r*x[1])
grad[2] = 2 * (100*s + x[2]) grad[2] = 2 * (100*s + x[2])
return grad
} }
func (HelicalValley) Minima() []Minimum { func (HelicalValley) Minima() []Minimum {
@@ -1183,10 +1121,7 @@ func (PenaltyI) Func(x []float64) (sum float64) {
return sum return sum
} }
func (PenaltyI) Grad(grad, x []float64) []float64 { func (PenaltyI) Grad(grad, x []float64) {
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -1198,7 +1133,6 @@ func (PenaltyI) Grad(grad, x []float64) []float64 {
for i, v := range x { for i, v := range x {
grad[i] = 2 * (2*s*v + 1e-5*(v-1)) grad[i] = 2 * (2*s*v + 1e-5*(v-1))
} }
return grad
} }
func (PenaltyI) Minima() []Minimum { func (PenaltyI) Minima() []Minimum {
@@ -1252,10 +1186,7 @@ func (PenaltyII) Func(x []float64) (sum float64) {
return sum return sum
} }
func (PenaltyII) Grad(grad, x []float64) []float64 { func (PenaltyII) Grad(grad, x []float64) {
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -1279,7 +1210,6 @@ func (PenaltyII) Grad(grad, x []float64) []float64 {
grad[i] += 1e-5 * f * math.Exp(x[i]/10) / 5 grad[i] += 1e-5 * f * math.Exp(x[i]/10) / 5
} }
grad[0] += 2 * (x[0] - 0.2) grad[0] += 2 * (x[0] - 0.2)
return grad
} }
func (PenaltyII) Minima() []Minimum { func (PenaltyII) Minima() []Minimum {
@@ -1325,13 +1255,10 @@ func (PowellBadlyScaled) Func(x []float64) float64 {
return f1*f1 + f2*f2 return f1*f1 + f2*f2
} }
func (PowellBadlyScaled) Grad(grad, x []float64) []float64 { func (PowellBadlyScaled) Grad(grad, x []float64) {
if len(x) != 2 { if len(x) != 2 {
panic("dimension of the problem must be 2") panic("dimension of the problem must be 2")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -1340,16 +1267,13 @@ func (PowellBadlyScaled) Grad(grad, x []float64) []float64 {
f2 := math.Exp(-x[0]) + math.Exp(-x[1]) - 1.0001 f2 := math.Exp(-x[0]) + math.Exp(-x[1]) - 1.0001
grad[0] = 2 * (1e4*f1*x[1] - f2*math.Exp(-x[0])) grad[0] = 2 * (1e4*f1*x[1] - f2*math.Exp(-x[0]))
grad[1] = 2 * (1e4*f1*x[0] - f2*math.Exp(-x[1])) grad[1] = 2 * (1e4*f1*x[0] - f2*math.Exp(-x[1]))
return grad
} }
func (PowellBadlyScaled) Hess(dst *mat.SymDense, x []float64) { func (PowellBadlyScaled) Hess(dst *mat.SymDense, x []float64) {
if len(x) != 2 { if len(x) != 2 {
panic("dimension of the problem must be 2") panic("dimension of the problem must be 2")
} }
if dst.IsZero() { if len(x) != dst.Symmetric() {
*dst = *(dst.GrowSym(len(x)).(*mat.SymDense))
} else if len(x) != dst.Symmetric() {
panic("incorrect size of the Hessian") panic("incorrect size of the Hessian")
} }
@@ -1401,10 +1325,7 @@ func (Trigonometric) Func(x []float64) (sum float64) {
return sum return sum
} }
func (Trigonometric) Grad(grad, x []float64) []float64 { func (Trigonometric) Grad(grad, x []float64) {
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -1424,7 +1345,6 @@ func (Trigonometric) Grad(grad, x []float64) []float64 {
for i, v := range x { for i, v := range x {
grad[i] += 2 * s2 * math.Sin(v) grad[i] += 2 * s2 * math.Sin(v)
} }
return grad
} }
func (Trigonometric) Minima() []Minimum { func (Trigonometric) Minima() []Minimum {
@@ -1477,10 +1397,7 @@ func (VariablyDimensioned) Func(x []float64) (sum float64) {
return sum return sum
} }
func (VariablyDimensioned) Grad(grad, x []float64) []float64 { func (VariablyDimensioned) Grad(grad, x []float64) {
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -1492,7 +1409,6 @@ func (VariablyDimensioned) Grad(grad, x []float64) []float64 {
for i, v := range x { for i, v := range x {
grad[i] = 2 * (v - 1 + s*float64(i+1)*(1+2*s*s)) grad[i] = 2 * (v - 1 + s*float64(i+1)*(1+2*s*s))
} }
return grad
} }
func (VariablyDimensioned) Minima() []Minimum { func (VariablyDimensioned) Minima() []Minimum {
@@ -1565,10 +1481,7 @@ func (Watson) Func(x []float64) (sum float64) {
return sum return sum
} }
func (Watson) Grad(grad, x []float64) []float64 { func (Watson) Grad(grad, x []float64) {
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -1604,14 +1517,11 @@ func (Watson) Grad(grad, x []float64) []float64 {
t := x[1] - x[0]*x[0] - 1 t := x[1] - x[0]*x[0] - 1
grad[0] += x[0] * (2 - 4*t) grad[0] += x[0] * (2 - 4*t)
grad[1] += 2 * t grad[1] += 2 * t
return grad
} }
func (Watson) Hess(dst *mat.SymDense, x []float64) { func (Watson) Hess(dst *mat.SymDense, x []float64) {
dim := len(x) dim := len(x)
if dst.IsZero() { if len(x) != dst.Symmetric() {
*dst = *(dst.GrowSym(len(x)).(*mat.SymDense))
} else if len(x) != dst.Symmetric() {
panic("incorrect size of the Hessian") panic("incorrect size of the Hessian")
} }
@@ -1709,13 +1619,10 @@ func (Wood) Func(x []float64) (sum float64) {
return 100*f1*f1 + f2*f2 + 90*f3*f3 + f4*f4 + 10*f5*f5 + 0.1*f6*f6 return 100*f1*f1 + f2*f2 + 90*f3*f3 + f4*f4 + 10*f5*f5 + 0.1*f6*f6
} }
func (Wood) Grad(grad, x []float64) []float64 { func (Wood) Grad(grad, x []float64) {
if len(x) != 4 { if len(x) != 4 {
panic("dimension of the problem must be 4") panic("dimension of the problem must be 4")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -1730,16 +1637,13 @@ func (Wood) Grad(grad, x []float64) []float64 {
grad[1] = 2 * (100*f1 + 10*f5 + 0.1*f6) grad[1] = 2 * (100*f1 + 10*f5 + 0.1*f6)
grad[2] = -2 * (180*f3*x[2] + f4) grad[2] = -2 * (180*f3*x[2] + f4)
grad[3] = 2 * (90*f3 + 10*f5 - 0.1*f6) grad[3] = 2 * (90*f3 + 10*f5 - 0.1*f6)
return grad
} }
func (Wood) Hess(dst *mat.SymDense, x []float64) { func (Wood) Hess(dst *mat.SymDense, x []float64) {
if len(x) != 4 { if len(x) != 4 {
panic("dimension of the problem must be 4") panic("dimension of the problem must be 4")
} }
if dst.IsZero() { if len(x) != dst.Symmetric() {
*dst = *(dst.GrowSym(len(x)).(*mat.SymDense))
} else if len(x) != dst.Symmetric() {
panic("incorrect size of the Hessian") panic("incorrect size of the Hessian")
} }
@@ -1780,7 +1684,7 @@ func (ConcaveRight) Func(x []float64) float64 {
return -x[0] / (x[0]*x[0] + 2) return -x[0] / (x[0]*x[0] + 2)
} }
func (ConcaveRight) Grad(grad, x []float64) []float64 { func (ConcaveRight) Grad(grad, x []float64) {
if len(x) != 1 { if len(x) != 1 {
panic("dimension of the problem must be 1") panic("dimension of the problem must be 1")
} }
@@ -1789,7 +1693,6 @@ func (ConcaveRight) Grad(grad, x []float64) []float64 {
} }
xSqr := x[0] * x[0] xSqr := x[0] * x[0]
grad[0] = (xSqr - 2) / (xSqr + 2) / (xSqr + 2) grad[0] = (xSqr - 2) / (xSqr + 2) / (xSqr + 2)
return grad
} }
// ConcaveLeft implements an univariate function that is concave to the left of // ConcaveLeft implements an univariate function that is concave to the left of
@@ -1807,18 +1710,14 @@ func (ConcaveLeft) Func(x []float64) float64 {
return math.Pow(x[0]+0.004, 4) * (x[0] - 1.996) return math.Pow(x[0]+0.004, 4) * (x[0] - 1.996)
} }
func (ConcaveLeft) Grad(grad, x []float64) []float64 { func (ConcaveLeft) Grad(grad, x []float64) {
if len(x) != 1 { if len(x) != 1 {
panic("dimension of the problem must be 1") panic("dimension of the problem must be 1")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
grad[0] = math.Pow(x[0]+0.004, 3) * (5*x[0] - 7.98) grad[0] = math.Pow(x[0]+0.004, 3) * (5*x[0] - 7.98)
return grad
} }
// Plassmann implements an univariate oscillatory function where the value of L // Plassmann implements an univariate oscillatory function where the value of L
@@ -1855,13 +1754,10 @@ func (f Plassmann) Func(x []float64) float64 {
return r return r
} }
func (f Plassmann) Grad(grad, x []float64) []float64 { func (f Plassmann) Grad(grad, x []float64) {
if len(x) != 1 { if len(x) != 1 {
panic("dimension of the problem must be 1") panic("dimension of the problem must be 1")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -1877,7 +1773,6 @@ func (f Plassmann) Grad(grad, x []float64) []float64 {
default: // a > 1+b default: // a > 1+b
grad[0]++ grad[0]++
} }
return grad
} }
// YanaiOzawaKaneko is an univariate convex function where the values of Beta1 // YanaiOzawaKaneko is an univariate convex function where the values of Beta1
@@ -1908,13 +1803,10 @@ func (f YanaiOzawaKaneko) Func(x []float64) float64 {
return g1*math.Sqrt((a-1)*(a-1)+b2*b2) + g2*math.Sqrt(a*a+b1*b1) return g1*math.Sqrt((a-1)*(a-1)+b2*b2) + g2*math.Sqrt(a*a+b1*b1)
} }
func (f YanaiOzawaKaneko) Grad(grad, x []float64) []float64 { func (f YanaiOzawaKaneko) Grad(grad, x []float64) {
if len(x) != 1 { if len(x) != 1 {
panic("dimension of the problem must be 1") panic("dimension of the problem must be 1")
} }
if grad == nil {
grad = make([]float64, len(x))
}
if len(x) != len(grad) { if len(x) != len(grad) {
panic("incorrect size of the gradient") panic("incorrect size of the gradient")
} }
@@ -1924,5 +1816,4 @@ func (f YanaiOzawaKaneko) Grad(grad, x []float64) []float64 {
g1 := math.Sqrt(1+b1*b1) - b1 g1 := math.Sqrt(1+b1*b1) - b1
g2 := math.Sqrt(1+b2*b2) - b2 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) grad[0] = g1*(a-1)/math.Sqrt(b2*b2+(a-1)*(a-1)) + g2*a/math.Sqrt(b1*b1+a*a)
return grad
} }

View File

@@ -41,7 +41,7 @@ func TestBacktracking(t *testing.T) {
type funcGrader interface { type funcGrader interface {
Func([]float64) float64 Func([]float64) float64
Grad([]float64, []float64) []float64 Grad([]float64, []float64)
} }
type linesearcherTest struct { type linesearcherTest struct {

View File

@@ -477,12 +477,20 @@ func evaluate(p *Problem, loc *Location, op Operation, x []float64) {
loc.F = p.Func(x) loc.F = p.Func(x)
} }
if op&GradEvaluation != 0 { if op&GradEvaluation != 0 {
loc.Gradient = p.Grad(loc.Gradient, x) // Make sure we have a destination in which to place the gradient.
// TODO(kortschak): Consider making this a check of len(loc.Gradient) != 0
// to allow reuse of the slice.
if loc.Gradient == nil {
loc.Gradient = make([]float64, len(x))
}
p.Grad(loc.Gradient, x)
} }
if op&HessEvaluation != 0 { if op&HessEvaluation != 0 {
// Make sure we have a destination in which to place the Hessian. // Make sure we have a destination in which to place the Hessian.
// TODO(kortschak): Consider making this a check of loc.Hessian.IsZero()
// to allow reuse of the matrix.
if loc.Hessian == nil { if loc.Hessian == nil {
loc.Hessian = &mat.SymDense{} loc.Hessian = mat.NewSymDense(len(x), nil)
} }
p.Hess(loc.Hessian, x) p.Hess(loc.Hessian, x)
} }

View File

@@ -124,13 +124,13 @@ type Problem struct {
Func func(x []float64) float64 Func func(x []float64) float64
// Grad evaluates the gradient at x and returns the result. Grad may use // Grad evaluates the gradient at x and returns the result. Grad may use
// (and return) the provided slice if it is non-nil, or must allocate a new // the provided slice which will be the same length as x. Grad must not
// slice otherwise. Grad must not modify x. // modify x.
Grad func(grad []float64, x []float64) []float64 Grad func(grad, x []float64)
// Hess evaluates the Hessian at x and stores the result in-place in hess. // Hess evaluates the Hessian at x and stores the result in-place in hess.
// Hess must not modify x. Hess must use the provided mat.SymDense, and // Hess must not modify x. Hess may use the provided mat.SymDense which
// must resize it if it is zero-sized. // will have dimensions matching the length of x.
Hess func(hess *mat.SymDense, x []float64) Hess func(hess *mat.SymDense, x []float64)
// Status reports the status of the objective function being optimized and any // Status reports the status of the objective function being optimized and any