File: functionconvergence.go

package info (click to toggle)
golang-gonum-v1-gonum 0.15.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 18,792 kB
  • sloc: asm: 6,252; fortran: 5,271; sh: 377; ruby: 211; makefile: 98
file content (85 lines) | stat: -rw-r--r-- 2,001 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// 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 optimize

import (
	"math"
)

// Converger returns the convergence of the optimization based on
// locations found during optimization. Converger must not modify the value of
// the provided Location in any of the methods.
type Converger interface {
	Init(dim int)
	Converged(loc *Location) Status
}

var (
	_ Converger = NeverTerminate{}
	_ Converger = (*FunctionConverge)(nil)
)

// NeverTerminate implements Converger, always reporting NotTerminated.
type NeverTerminate struct{}

func (NeverTerminate) Init(dim int) {}

func (NeverTerminate) Converged(loc *Location) Status {
	return NotTerminated
}

// FunctionConverge tests for insufficient improvement in the optimum value
// over the last iterations. A FunctionConvergence status is returned if
// there is no significant decrease for FunctionConverge.Iterations. A
// significant decrease is considered if
//
//	f < f_best
//
// and
//
//	f_best - f > FunctionConverge.Relative * maxabs(f, f_best) + FunctionConverge.Absolute
//
// If the decrease is significant, then the iteration counter is reset and
// f_best is updated.
//
// If FunctionConverge.Iterations == 0, it has no effect.
type FunctionConverge struct {
	Absolute   float64
	Relative   float64
	Iterations int

	first bool
	best  float64
	iter  int
}

func (fc *FunctionConverge) Init(dim int) {
	fc.first = true
	fc.best = 0
	fc.iter = 0
}

func (fc *FunctionConverge) Converged(l *Location) Status {
	f := l.F
	if fc.first {
		fc.best = f
		fc.first = false
		return NotTerminated
	}
	if fc.Iterations == 0 {
		return NotTerminated
	}
	maxAbs := math.Max(math.Abs(f), math.Abs(fc.best))
	if f < fc.best && fc.best-f > fc.Relative*maxAbs+fc.Absolute {
		fc.best = f
		fc.iter = 0
		return NotTerminated
	}
	fc.iter++
	if fc.iter < fc.Iterations {
		return NotTerminated
	}
	return FunctionConvergence
}