forked from pa-m/optimize
-
Notifications
You must be signed in to change notification settings - Fork 0
/
powellmethod.go
141 lines (124 loc) · 3.26 KB
/
powellmethod.go
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright ©2016 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"
"gonum.org/v1/gonum/optimize"
)
// Powell is a global optimizer that evaluates the function at random
// locations. Not a good optimizer, but useful for comparison and debugging.
type Powell struct {
PM *PowellMinimizer
settings optimize.Settings
status optimize.Status
err error
bestF float64
bestX []float64
}
// Uses for Powell to implement gonum optimize.Needser
func (g *Powell) Uses(has optimize.Available) (optimize.Available, error) {
return optimize.Available{}, nil
}
// Init for Powell to implement gonum optimize.Method
func (g *Powell) Init(dim, tasks int) int {
if dim <= 0 {
panic(nonpositiveDimension)
}
if tasks < 0 {
panic(negativeTasks)
}
g.bestF = math.Inf(1)
g.bestX = resize(g.bestX, dim)
return 1
}
func (g *Powell) updateMajor(operation chan<- optimize.Task, task optimize.Task) {
// Update the best value seen so far, and send a MajorIteration.
if task.F < g.bestF {
g.bestF = task.F
copy(g.bestX, task.X)
}
task.Op = optimize.MajorIteration
operation <- task
}
// Run for Powell to implement gonum optimize.Method
func (g *Powell) Run(operation chan<- optimize.Task, result <-chan optimize.Task, tasks []optimize.Task) {
var stop bool
fnMaxIter := func(int) bool { return stop }
fnMaxFev := func(int) bool { return stop }
if g.PM == nil {
g.PM = NewPowellMinimizer()
}
pm := g.PM
result1 := make(chan optimize.Task)
// Send initial tasks to evaluate
dup := func(x []float64) []float64 {
r := make([]float64, len(x))
copy(r, x)
return r
}
InitX := tasks[0].Location.X
go func(id int) {
_, warnflag := minimizePowell(func(x []float64) (y float64) {
y = math.NaN()
defer func() {
if r := recover(); r == "send on closed channel" {
return
}
}()
operation <- optimize.Task{ID: id, Op: optimize.FuncEvaluation, Location: &optimize.Location{X: dup(x)}}
task := <-result1
if task.Location != nil {
y = task.Location.F
}
return
}, InitX, nil, pm.Xtol, pm.Ftol, fnMaxIter, fnMaxFev, pm.Logger)
switch warnflag {
case 1:
g.status = optimize.FunctionEvaluationLimit
case 2:
g.status = optimize.IterationLimit
default:
g.status = optimize.MethodConverge
}
defer func() {
if r := recover(); r == "send on closed channel" {
return
}
}()
operation <- optimize.Task{ID: id, Op: optimize.MethodDone}
}(0)
// Read from the channel until PostIteration is sent.
Loop:
for {
task := <-result
switch task.Op {
default:
panic("unknown operation")
case optimize.NoOperation, optimize.PostIteration:
close(result1)
break Loop
case optimize.MajorIteration:
case optimize.FuncEvaluation:
result1 <- task
g.updateMajor(operation, task)
}
}
// PostIteration was sent. Update the best new values.
for task := range result {
switch task.Op {
default:
panic("unknown operation")
case optimize.MajorIteration:
case optimize.FuncEvaluation:
g.updateMajor(operation, task)
case optimize.NoOperation:
}
}
stop = true
close(operation)
}
// Status ...
func (g *Powell) Status() (optimize.Status, error) {
return g.status, g.err
}