123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- package gss
- import (
- "log"
- "math"
- )
- var (
- sqrt5 = math.Sqrt(5)
- invphi = (sqrt5 - 1) / 2 //# 1/phi
- invphi2 = (3 - sqrt5) / 2 //# 1/phi^2
- nan = math.NaN()
- )
- // Gss golden section search (recursive version)
- // https://en.wikipedia.org/wiki/Golden-section_search
- // https://github.com/pa-m/optimize/blob/master/gss.go
- // '''
- // Golden section search, recursive.
- // Given a function f with a single local minimum in
- // the interval [a,b], gss returns a subset interval
- // [c,d] that contains the minimum with d-c <= tol.
- //
- // logger may be nil
- //
- // example:
- // >>> f = lambda x: (x-2)**2
- // >>> a = 1
- // >>> b = 5
- // >>> tol = 1e-5
- // >>> (c,d) = gssrec(f, a, b, tol)
- // >>> print (c,d)
- // (1.9999959837979107, 2.0000050911830893)
- // '''
- func Gss(fWrapped func(float64, bool) float64, a, b, tol float64, logger *log.Logger) (float64, float64) {
- if a > b {
- a, b = b, a
- }
- h := b - a
- if h <= tol {
- return a, b
- }
- n := int(math.Ceil(math.Log(tol/h) / math.Log(invphi)))
- if logger != nil {
- logger.Printf("About to perform %d iterations of golden section search to find the best framerate", n)
- }
- c := a + invphi2*h
- d := a + invphi*h
- yc := fWrapped(c, n == 1)
- yd := fWrapped(d, n == 1)
- for i := 0; i < n-1; i++ {
- if logger != nil {
- logger.Printf("%d\t%9.6g\t%9.6g\n", i, a, b)
- }
- if yc < yd {
- b = d
- d = c
- yd = yc
- h = invphi * h
- c = a + invphi2*h
- yc = fWrapped(c, i == n-2)
- } else {
- a = c
- c = d
- yc = yd
- h = invphi * h
- d = a + invphi*h
- yd = fWrapped(d, i == n-2)
- }
- }
- if yc < yd {
- return a, d
- } else {
- return c, b
- }
- //return gss(f, a, b, tol, nan, nan, nan, nan, nan, logger)
- }
- func gss(f func(float64) float64, a, b, tol, h, c, d, fc, fd float64, logger *log.Logger) (float64, float64) {
- if a > b {
- a, b = b, a
- }
- h = b - a
- it := 0
- for {
- if logger != nil {
- logger.Printf("%d\t%9.6g\t%9.6g\n", it, a, b)
- }
- it++
- if h < tol {
- return a, b
- }
- if a > b {
- a, b = b, a
- }
- if math.IsNaN(c) {
- c = a + invphi2*h
- fc = f(c)
- }
- if math.IsNaN(d) {
- d = a + invphi*h
- fd = f(d)
- }
- if fc < fd {
- b, h, c, fc, d, fd = d, h*invphi, nan, nan, c, fc
- } else {
- a, h, c, fc, d, fd = c, h*invphi, d, fd, nan, nan
- }
- }
- }
|