github.com/gopherd/gonum@v0.0.4/diff/fd/watson_test.go (about)

     1  // Copyright ©2017 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package fd
     6  
     7  import "github.com/gopherd/gonum/mat"
     8  
     9  // Watson implements the Watson's function.
    10  // Dimension of the problem should be 2 <= dim <= 31. For dim == 9, the problem
    11  // of minimizing the function is very ill conditioned.
    12  //
    13  // This is copied from gonum.org/v1/optimize/functions for testing Hessian-like
    14  // derivative methods.
    15  //
    16  // References:
    17  //  - Kowalik, J.S., Osborne, M.R.: Methods for Unconstrained Optimization
    18  //    Problems. Elsevier North-Holland, New York, 1968
    19  //  - More, J., Garbow, B.S., Hillstrom, K.E.: Testing unconstrained
    20  //    optimization software. ACM Trans Math Softw 7 (1981), 17-41
    21  type Watson struct{}
    22  
    23  func (Watson) Func(x []float64) (sum float64) {
    24  	for i := 1; i <= 29; i++ {
    25  		d1 := float64(i) / 29
    26  
    27  		d2 := 1.0
    28  		var s1 float64
    29  		for j := 1; j < len(x); j++ {
    30  			s1 += float64(j) * d2 * x[j]
    31  			d2 *= d1
    32  		}
    33  
    34  		d2 = 1.0
    35  		var s2 float64
    36  		for _, v := range x {
    37  			s2 += d2 * v
    38  			d2 *= d1
    39  		}
    40  
    41  		t := s1 - s2*s2 - 1
    42  		sum += t * t
    43  	}
    44  	t := x[1] - x[0]*x[0] - 1
    45  	sum += x[0]*x[0] + t*t
    46  	return sum
    47  }
    48  
    49  func (Watson) Grad(grad, x []float64) {
    50  	if len(x) != len(grad) {
    51  		panic("incorrect size of the gradient")
    52  	}
    53  
    54  	for i := range grad {
    55  		grad[i] = 0
    56  	}
    57  	for i := 1; i <= 29; i++ {
    58  		d1 := float64(i) / 29
    59  
    60  		d2 := 1.0
    61  		var s1 float64
    62  		for j := 1; j < len(x); j++ {
    63  			s1 += float64(j) * d2 * x[j]
    64  			d2 *= d1
    65  		}
    66  
    67  		d2 = 1.0
    68  		var s2 float64
    69  		for _, v := range x {
    70  			s2 += d2 * v
    71  			d2 *= d1
    72  		}
    73  
    74  		t := s1 - s2*s2 - 1
    75  		s3 := 2 * d1 * s2
    76  		d2 = 2 / d1
    77  		for j := range x {
    78  			grad[j] += d2 * (float64(j) - s3) * t
    79  			d2 *= d1
    80  		}
    81  	}
    82  	t := x[1] - x[0]*x[0] - 1
    83  	grad[0] += x[0] * (2 - 4*t)
    84  	grad[1] += 2 * t
    85  }
    86  
    87  func (Watson) Hess(hess mat.MutableSymmetric, x []float64) {
    88  	dim := len(x)
    89  	if dim != hess.SymmetricDim() {
    90  		panic("incorrect size of the Hessian")
    91  	}
    92  
    93  	for j := 0; j < dim; j++ {
    94  		for k := j; k < dim; k++ {
    95  			hess.SetSym(j, k, 0)
    96  		}
    97  	}
    98  	for i := 1; i <= 29; i++ {
    99  		d1 := float64(i) / 29
   100  		d2 := 1.0
   101  		var s1 float64
   102  		for j := 1; j < dim; j++ {
   103  			s1 += float64(j) * d2 * x[j]
   104  			d2 *= d1
   105  		}
   106  
   107  		d2 = 1.0
   108  		var s2 float64
   109  		for _, v := range x {
   110  			s2 += d2 * v
   111  			d2 *= d1
   112  		}
   113  
   114  		t := s1 - s2*s2 - 1
   115  		s3 := 2 * d1 * s2
   116  		d2 = 2 / d1
   117  		th := 2 * d1 * d1 * t
   118  		for j := 0; j < dim; j++ {
   119  			v := float64(j) - s3
   120  			d3 := 1 / d1
   121  			for k := 0; k <= j; k++ {
   122  				hess.SetSym(k, j, hess.At(k, j)+d2*d3*(v*(float64(k)-s3)-th))
   123  				d3 *= d1
   124  			}
   125  			d2 *= d1
   126  		}
   127  	}
   128  	t1 := x[1] - x[0]*x[0] - 1
   129  	hess.SetSym(0, 0, hess.At(0, 0)+8*x[0]*x[0]+2-4*t1)
   130  	hess.SetSym(0, 1, hess.At(0, 1)-4*x[0])
   131  	hess.SetSym(1, 1, hess.At(1, 1)+2)
   132  }