Skip to content
This repository was archived by the owner on Nov 23, 2018. It is now read-only.

Commit b822807

Browse files
committed
Merge remote-tracking branch 'remotes/hypoactiv/master'
Closes #102
2 parents 60750bc + c04183d commit b822807

13 files changed

+631
-244
lines changed

backtracking.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type Backtracking struct {
3232
initG float64
3333
}
3434

35-
func (b *Backtracking) Init(loc LinesearchLocation, step float64, _ *FunctionInfo) EvaluationType {
35+
func (b *Backtracking) Init(loc LinesearchLocation, step float64, _ *ProblemInfo) EvaluationType {
3636
if step <= 0 {
3737
panic("backtracking: bad step size")
3838
}

bfgs.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ type BFGS struct {
4141
// NOTE: This method exists so that it's easier to use a bfgs algorithm because
4242
// it implements Method
4343

44-
func (b *BFGS) Init(loc *Location, f *FunctionInfo, xNext []float64) (EvaluationType, IterationType, error) {
44+
func (b *BFGS) Init(loc *Location, p *ProblemInfo, xNext []float64) (EvaluationType, IterationType, error) {
4545
if b.LinesearchMethod == nil {
4646
b.LinesearchMethod = &Bisection{}
4747
}
@@ -51,7 +51,7 @@ func (b *BFGS) Init(loc *Location, f *FunctionInfo, xNext []float64) (Evaluation
5151
b.linesearch.Method = b.LinesearchMethod
5252
b.linesearch.NextDirectioner = b
5353

54-
return b.linesearch.Init(loc, f, xNext)
54+
return b.linesearch.Init(loc, p, xNext)
5555
}
5656

5757
func (b *BFGS) Iterate(loc *Location, xNext []float64) (EvaluationType, IterationType, error) {

bisection.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type Bisection struct {
2626
maxGrad float64
2727
}
2828

29-
func (b *Bisection) Init(loc LinesearchLocation, step float64, _ *FunctionInfo) EvaluationType {
29+
func (b *Bisection) Init(loc LinesearchLocation, step float64, _ *ProblemInfo) EvaluationType {
3030
if loc.Derivative >= 0 {
3131
panic("bisection: init G non-negative")
3232
}

cg.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ type CG struct {
9494
gradPrevNorm float64
9595
}
9696

97-
func (cg *CG) Init(loc *Location, funcInfo *FunctionInfo, xNext []float64) (EvaluationType, IterationType, error) {
97+
func (cg *CG) Init(loc *Location, p *ProblemInfo, xNext []float64) (EvaluationType, IterationType, error) {
9898
if cg.IterationRestartFactor < 0 {
9999
panic("cg: IterationRestartFactor is negative")
100100
}
@@ -125,7 +125,7 @@ func (cg *CG) Init(loc *Location, funcInfo *FunctionInfo, xNext []float64) (Eval
125125
cg.linesearch.Method = cg.LinesearchMethod
126126
cg.linesearch.NextDirectioner = cg
127127

128-
return cg.linesearch.Init(loc, funcInfo, xNext)
128+
return cg.linesearch.Init(loc, p, xNext)
129129
}
130130

131131
func (cg *CG) Iterate(loc *Location, xNext []float64) (EvaluationType, IterationType, error) {

gradientdescent.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ type GradientDescent struct {
1818
linesearch *Linesearch
1919
}
2020

21-
func (g *GradientDescent) Init(loc *Location, f *FunctionInfo, xNext []float64) (EvaluationType, IterationType, error) {
21+
func (g *GradientDescent) Init(loc *Location, p *ProblemInfo, xNext []float64) (EvaluationType, IterationType, error) {
2222
if g.StepSizer == nil {
2323
g.StepSizer = &QuadraticStepSize{}
2424
}
@@ -31,7 +31,7 @@ func (g *GradientDescent) Init(loc *Location, f *FunctionInfo, xNext []float64)
3131
g.linesearch.Method = g.LinesearchMethod
3232
g.linesearch.NextDirectioner = g
3333

34-
return g.linesearch.Init(loc, f, xNext)
34+
return g.linesearch.Init(loc, p, xNext)
3535
}
3636

3737
func (g *GradientDescent) Iterate(loc *Location, xNext []float64) (EvaluationType, IterationType, error) {

interfaces.go

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,14 @@
44

55
package optimize
66

7-
import "github.com/gonum/matrix/mat64"
8-
9-
// Function evaluates the objective function at the given location. F
10-
// must not modify x.
11-
type Function interface {
12-
Func(x []float64) (obj float64)
13-
}
14-
15-
// Gradient evaluates the gradient at x and stores the result in-place in grad.
16-
// Grad must not modify x.
17-
type Gradient interface {
18-
Grad(x, grad []float64)
19-
}
20-
21-
// Hessian evaluates the Hessian at x and stores the result in-place in hess.
22-
// Hess must not modify x.
23-
type Hessian interface {
24-
Hess(x []float64, hess *mat64.SymDense)
25-
}
26-
277
// LinesearchMethod is a type that can perform a line search. Typically, these
288
// methods will not be called by the user directly, as they will be called by
299
// a Linesearch struct.
3010
type LinesearchMethod interface {
3111
// Init initializes the linesearch method. LinesearchLocation contains the
3212
// function information at step == 0, and step contains the first step length
3313
// as specified by the NextDirectioner.
34-
Init(loc LinesearchLocation, step float64, f *FunctionInfo) EvaluationType
14+
Init(loc LinesearchLocation, step float64, p *ProblemInfo) EvaluationType
3515

3616
// Finished takes in the function result at the most recent linesearch location,
3717
// and returns true if the line search has been concluded.
@@ -62,7 +42,7 @@ type NextDirectioner interface {
6242
// A Method can optimize an objective function.
6343
type Method interface {
6444
// Initializes the method and returns the first location to evaluate
65-
Init(loc *Location, f *FunctionInfo, xNext []float64) (EvaluationType, IterationType, error)
45+
Init(loc *Location, p *ProblemInfo, xNext []float64) (EvaluationType, IterationType, error)
6646

6747
// Stores the next location to evaluate in xNext
6848
Iterate(loc *Location, xNext []float64) (EvaluationType, IterationType, error)

lbfgs.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ type LBFGS struct {
3838
rhoHist []float64 // last Store iterations of rho
3939
}
4040

41-
func (l *LBFGS) Init(loc *Location, f *FunctionInfo, xNext []float64) (EvaluationType, IterationType, error) {
41+
func (l *LBFGS) Init(loc *Location, p *ProblemInfo, xNext []float64) (EvaluationType, IterationType, error) {
4242
if l.LinesearchMethod == nil {
4343
l.LinesearchMethod = &Bisection{}
4444
}
@@ -47,7 +47,7 @@ func (l *LBFGS) Init(loc *Location, f *FunctionInfo, xNext []float64) (Evaluatio
4747
}
4848
l.linesearch.Method = l.LinesearchMethod
4949
l.linesearch.NextDirectioner = l
50-
return l.linesearch.Init(loc, f, xNext)
50+
return l.linesearch.Init(loc, p, xNext)
5151
}
5252

5353
func (l *LBFGS) Iterate(loc *Location, xNext []float64) (EvaluationType, IterationType, error) {

linesearch.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ type Linesearch struct {
2121
initX []float64
2222
dir []float64
2323

24-
funcInfo *FunctionInfo
24+
probInfo *ProblemInfo
2525

2626
lastEvalType EvaluationType
2727
iterType IterationType
2828
}
2929

30-
func (ls *Linesearch) Init(loc *Location, f *FunctionInfo, xNext []float64) (EvaluationType, IterationType, error) {
30+
func (ls *Linesearch) Init(loc *Location, p *ProblemInfo, xNext []float64) (EvaluationType, IterationType, error) {
3131
ls.initX = resize(ls.initX, len(loc.X))
3232
copy(ls.initX, loc.X)
3333

@@ -45,9 +45,9 @@ func (ls *Linesearch) Init(loc *Location, f *FunctionInfo, xNext []float64) (Eva
4545
F: loc.F,
4646
Derivative: projGrad,
4747
}
48-
evalType := ls.Method.Init(lsLoc, stepSize, f)
48+
evalType := ls.Method.Init(lsLoc, stepSize, p)
4949
floats.AddScaledTo(xNext, ls.initX, stepSize, ls.dir)
50-
ls.funcInfo = f
50+
ls.probInfo = p
5151
ls.lastEvalType = evalType
5252
ls.iterType = MinorIteration
5353
return evalType, ls.iterType, nil
@@ -120,7 +120,7 @@ func (ls *Linesearch) initNextLinesearch(loc *Location, xNext []float64) (Evalua
120120
F: loc.F,
121121
Derivative: projGrad,
122122
}
123-
evalType := ls.Method.Init(lsLoc, stepsize, ls.funcInfo)
123+
evalType := ls.Method.Init(lsLoc, stepsize, ls.probInfo)
124124
floats.AddScaledTo(xNext, ls.initX, stepsize, ls.dir)
125125
// Compare the starting point for the current iteration with the next
126126
// evaluation point to make sure that rounding errors do not prevent progress.

local.go

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,25 @@ import (
4949
// function evaluations. If you would like to put limits on this, for example
5050
// maximum runtime or maximum function evaluations, please modify the Settings
5151
// input struct.
52-
func Local(f Function, initX []float64, settings *Settings, method Method) (*Result, error) {
52+
func Local(p Problem, initX []float64, settings *Settings, method Method) (*Result, error) {
53+
if p.Func == nil {
54+
panic("optimize: objective function is undefined")
55+
}
5356
if len(initX) == 0 {
5457
panic("optimize: initial X has zero length")
5558
}
5659

5760
startTime := time.Now()
58-
funcInfo := newFunctionInfo(f)
61+
5962
if method == nil {
60-
method = getDefaultMethod(funcInfo)
63+
method = getDefaultMethod(&p)
6164
}
62-
if err := funcInfo.satisfies(method); err != nil {
65+
if err := p.satisfies(method); err != nil {
6366
return nil, err
6467
}
6568

66-
if funcInfo.IsStatuser {
67-
_, err := funcInfo.statuser.Status()
69+
if p.Status != nil {
70+
_, err := p.Status()
6871
if err != nil {
6972
return nil, err
7073
}
@@ -84,7 +87,7 @@ func Local(f Function, initX []float64, settings *Settings, method Method) (*Res
8487
}
8588

8689
stats := &Stats{}
87-
optLoc, evalType, err := getStartingLocation(funcInfo, method, initX, stats, settings)
90+
optLoc, evalType, err := getStartingLocation(&p, method, initX, stats, settings)
8891
if err != nil {
8992
return nil, err
9093
}
@@ -106,7 +109,7 @@ func Local(f Function, initX []float64, settings *Settings, method Method) (*Res
106109
// The starting location is not good enough, we need to perform a
107110
// minimization. The optimal location will be stored in-place in
108111
// optLoc.
109-
status, err = minimize(settings, method, funcInfo, stats, optLoc, startTime)
112+
status, err = minimize(settings, method, &p, stats, optLoc, startTime)
110113
}
111114

112115
if settings.Recorder != nil && err == nil {
@@ -121,30 +124,30 @@ func Local(f Function, initX []float64, settings *Settings, method Method) (*Res
121124
}, err
122125
}
123126

124-
func minimize(settings *Settings, method Method, funcInfo *functionInfo, stats *Stats, optLoc *Location, startTime time.Time) (status Status, err error) {
127+
func minimize(settings *Settings, method Method, p *Problem, stats *Stats, optLoc *Location, startTime time.Time) (status Status, err error) {
125128
loc := &Location{}
126129
copyLocation(loc, optLoc)
127130
xNext := make([]float64, len(loc.X))
128131

129132
methodStatus, methodIsStatuser := method.(Statuser)
130133

131-
evalType, iterType, err := method.Init(loc, &funcInfo.FunctionInfo, xNext)
134+
evalType, iterType, err := method.Init(loc, newProblemInfo(p), xNext)
132135
if err != nil {
133136
return Failure, err
134137
}
135138

136139
for {
137-
if funcInfo.IsStatuser {
140+
if p.Status != nil {
138141
// Check the function status before evaluating.
139-
status, err = funcInfo.statuser.Status()
142+
status, err = p.Status()
140143
if err != nil || status != NotTerminated {
141144
return
142145
}
143146
}
144147

145148
// Perform evalType evaluation of the function at xNext and store the
146149
// result in location.
147-
evaluate(funcInfo, evalType, xNext, loc, stats)
150+
evaluate(p, evalType, xNext, loc, stats)
148151
// Update the stats and optLoc.
149152
update(loc, optLoc, stats, iterType, startTime)
150153
// Get the convergence status before recording the new location.
@@ -198,15 +201,15 @@ func copyLocation(dst, src *Location) {
198201
}
199202
}
200203

201-
func getDefaultMethod(funcInfo *functionInfo) Method {
202-
if funcInfo.IsGradient {
204+
func getDefaultMethod(p *Problem) Method {
205+
if p.Grad != nil {
203206
return &BFGS{}
204207
}
205208
return &NelderMead{}
206209
}
207210

208211
// getStartingLocation allocates and initializes the starting location for the minimization.
209-
func getStartingLocation(funcInfo *functionInfo, method Method, initX []float64, stats *Stats, settings *Settings) (*Location, EvaluationType, error) {
212+
func getStartingLocation(p *Problem, method Method, initX []float64, stats *Stats, settings *Settings) (*Location, EvaluationType, error) {
210213
dim := len(initX)
211214
loc := &Location{
212215
X: make([]float64, dim),
@@ -250,7 +253,7 @@ func getStartingLocation(funcInfo *functionInfo, method Method, initX []float64,
250253
if loc.Hessian != nil {
251254
evalType |= HessEvaluation
252255
}
253-
evaluate(funcInfo, evalType, loc.X, loc, stats)
256+
evaluate(p, evalType, loc.X, loc, stats)
254257
}
255258

256259
if math.IsNaN(loc.F) {
@@ -345,11 +348,11 @@ func invalidate(loc *Location) {
345348
}
346349
}
347350

348-
// evaluate evaluates the function given by f at xNext, stores the answer into
351+
// evaluate evaluates the problem given by p at xNext, stores the answer into
349352
// loc and updates stats. If loc.X is not equal to xNext, then unused fields of
350353
// loc are set to NaN.
351354
// evaluate panics if the function does not support the requested evalType.
352-
func evaluate(f *functionInfo, evalType EvaluationType, xNext []float64, loc *Location, stats *Stats) {
355+
func evaluate(p *Problem, evalType EvaluationType, xNext []float64, loc *Location, stats *Stats) {
353356
if !floats.Equal(loc.X, xNext) {
354357
if evalType == NoEvaluation {
355358
// Optimizers should not request NoEvaluation at a new location.
@@ -362,17 +365,17 @@ func evaluate(f *functionInfo, evalType EvaluationType, xNext []float64, loc *Lo
362365

363366
toEval := evalType
364367
if evalType&FuncEvaluation != 0 {
365-
loc.F = f.function.Func(loc.X)
368+
loc.F = p.Func(loc.X)
366369
stats.FuncEvaluations++
367370
toEval &= ^FuncEvaluation
368371
}
369372
if evalType&GradEvaluation != 0 {
370-
f.gradient.Grad(loc.X, loc.Gradient)
373+
p.Grad(loc.X, loc.Gradient)
371374
stats.GradEvaluations++
372375
toEval &= ^GradEvaluation
373376
}
374377
if evalType&HessEvaluation != 0 {
375-
f.hessian.Hess(loc.X, loc.Hessian)
378+
p.Hess(loc.X, loc.Hessian)
376379
stats.HessEvaluations++
377380
toEval &= ^HessEvaluation
378381
}

neldermead.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ type NelderMead struct {
8181
reflectedValue float64 // Value at the last reflection point
8282
}
8383

84-
func (n *NelderMead) Init(loc *Location, f *FunctionInfo, xNext []float64) (EvaluationType, IterationType, error) {
84+
func (n *NelderMead) Init(loc *Location, p *ProblemInfo, xNext []float64) (EvaluationType, IterationType, error) {
8585
dim := len(loc.X)
8686
if cap(n.vertices) < dim+1 {
8787
n.vertices = make([][]float64, dim+1)

0 commit comments

Comments
 (0)