| // Copyright ©2014 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 "gonum.org/v1/gonum/floats" |
| |
| var ( |
| _ Method = (*GradientDescent)(nil) |
| _ localMethod = (*GradientDescent)(nil) |
| _ NextDirectioner = (*GradientDescent)(nil) |
| ) |
| |
| // GradientDescent implements the steepest descent optimization method that |
| // performs successive steps along the direction of the negative gradient. |
| type GradientDescent struct { |
| // Linesearcher selects suitable steps along the descent direction. |
| // If Linesearcher is nil, a reasonable default will be chosen. |
| Linesearcher Linesearcher |
| // StepSizer determines the initial step size along each direction. |
| // If StepSizer is nil, a reasonable default will be chosen. |
| StepSizer StepSizer |
| // GradStopThreshold sets the threshold for stopping if the gradient norm |
| // gets too small. If GradStopThreshold is 0 it is defaulted to 1e-12, and |
| // if it is NaN the setting is not used. |
| GradStopThreshold float64 |
| |
| ls *LinesearchMethod |
| |
| status Status |
| err error |
| } |
| |
| func (g *GradientDescent) Status() (Status, error) { |
| return g.status, g.err |
| } |
| |
| func (*GradientDescent) Uses(has Available) (uses Available, err error) { |
| return has.gradient() |
| } |
| |
| func (g *GradientDescent) Init(dim, tasks int) int { |
| g.status = NotTerminated |
| g.err = nil |
| return 1 |
| } |
| |
| func (g *GradientDescent) Run(operation chan<- Task, result <-chan Task, tasks []Task) { |
| g.status, g.err = localOptimizer{}.run(g, g.GradStopThreshold, operation, result, tasks) |
| close(operation) |
| } |
| |
| func (g *GradientDescent) initLocal(loc *Location) (Operation, error) { |
| if g.Linesearcher == nil { |
| g.Linesearcher = &Backtracking{} |
| } |
| if g.StepSizer == nil { |
| g.StepSizer = &QuadraticStepSize{} |
| } |
| |
| if g.ls == nil { |
| g.ls = &LinesearchMethod{} |
| } |
| g.ls.Linesearcher = g.Linesearcher |
| g.ls.NextDirectioner = g |
| |
| return g.ls.Init(loc) |
| } |
| |
| func (g *GradientDescent) iterateLocal(loc *Location) (Operation, error) { |
| return g.ls.Iterate(loc) |
| } |
| |
| func (g *GradientDescent) InitDirection(loc *Location, dir []float64) (stepSize float64) { |
| copy(dir, loc.Gradient) |
| floats.Scale(-1, dir) |
| return g.StepSizer.Init(loc, dir) |
| } |
| |
| func (g *GradientDescent) NextDirection(loc *Location, dir []float64) (stepSize float64) { |
| copy(dir, loc.Gradient) |
| floats.Scale(-1, dir) |
| return g.StepSizer.StepSize(loc, dir) |
| } |
| |
| func (*GradientDescent) needs() struct { |
| Gradient bool |
| Hessian bool |
| } { |
| return struct { |
| Gradient bool |
| Hessian bool |
| }{true, false} |
| } |