fixed dependencies
This commit is contained in:
146
vendor/gonum.org/v1/gonum/optimize/local.go
generated
vendored
Normal file
146
vendor/gonum.org/v1/gonum/optimize/local.go
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
// 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 (
|
||||
"math"
|
||||
|
||||
"gonum.org/v1/gonum/floats"
|
||||
)
|
||||
|
||||
// localOptimizer is a helper type for running an optimization using a LocalMethod.
|
||||
type localOptimizer struct{}
|
||||
|
||||
// run controls the optimization run for a localMethod. The calling method
|
||||
// must close the operation channel at the conclusion of the optimization. This
|
||||
// provides a happens before relationship between the return of status and the
|
||||
// closure of operation, and thus a call to method.Status (if necessary).
|
||||
func (l localOptimizer) run(method localMethod, gradThresh float64, operation chan<- Task, result <-chan Task, tasks []Task) (Status, error) {
|
||||
// Local methods start with a fully-specified initial location.
|
||||
task := tasks[0]
|
||||
task = l.initialLocation(operation, result, task, method)
|
||||
if task.Op == PostIteration {
|
||||
l.finish(operation, result)
|
||||
return NotTerminated, nil
|
||||
}
|
||||
status, err := l.checkStartingLocation(task, gradThresh)
|
||||
if err != nil {
|
||||
l.finishMethodDone(operation, result, task)
|
||||
return status, err
|
||||
}
|
||||
|
||||
// Send a major iteration with the starting location.
|
||||
task.Op = MajorIteration
|
||||
operation <- task
|
||||
task = <-result
|
||||
if task.Op == PostIteration {
|
||||
l.finish(operation, result)
|
||||
return NotTerminated, nil
|
||||
}
|
||||
op, err := method.initLocal(task.Location)
|
||||
if err != nil {
|
||||
l.finishMethodDone(operation, result, task)
|
||||
return Failure, err
|
||||
}
|
||||
task.Op = op
|
||||
operation <- task
|
||||
Loop:
|
||||
for {
|
||||
r := <-result
|
||||
switch r.Op {
|
||||
case PostIteration:
|
||||
break Loop
|
||||
case MajorIteration:
|
||||
// The last operation was a MajorIteration. Check if the gradient
|
||||
// is below the threshold.
|
||||
if status := l.checkGradientConvergence(r.Gradient, gradThresh); status != NotTerminated {
|
||||
l.finishMethodDone(operation, result, task)
|
||||
return GradientThreshold, nil
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
op, err := method.iterateLocal(r.Location)
|
||||
if err != nil {
|
||||
l.finishMethodDone(operation, result, r)
|
||||
return Failure, err
|
||||
}
|
||||
r.Op = op
|
||||
operation <- r
|
||||
}
|
||||
}
|
||||
l.finish(operation, result)
|
||||
return NotTerminated, nil
|
||||
}
|
||||
|
||||
// initialOperation returns the Operation needed to fill the initial location
|
||||
// based on the needs of the method and the values already supplied.
|
||||
func (localOptimizer) initialOperation(task Task, n needser) Operation {
|
||||
var newOp Operation
|
||||
op := task.Op
|
||||
if op&FuncEvaluation == 0 {
|
||||
newOp |= FuncEvaluation
|
||||
}
|
||||
needs := n.needs()
|
||||
if needs.Gradient && op&GradEvaluation == 0 {
|
||||
newOp |= GradEvaluation
|
||||
}
|
||||
if needs.Hessian && op&HessEvaluation == 0 {
|
||||
newOp |= HessEvaluation
|
||||
}
|
||||
return newOp
|
||||
}
|
||||
|
||||
// initialLocation fills the initial location based on the needs of the method.
|
||||
// The task passed to initialLocation should be the first task sent in RunGlobal.
|
||||
func (l localOptimizer) initialLocation(operation chan<- Task, result <-chan Task, task Task, needs needser) Task {
|
||||
task.Op = l.initialOperation(task, needs)
|
||||
operation <- task
|
||||
return <-result
|
||||
}
|
||||
|
||||
func (l localOptimizer) checkStartingLocation(task Task, gradThresh float64) (Status, error) {
|
||||
if math.IsInf(task.F, 1) || math.IsNaN(task.F) {
|
||||
return Failure, ErrFunc(task.F)
|
||||
}
|
||||
for i, v := range task.Gradient {
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return Failure, ErrGrad{Grad: v, Index: i}
|
||||
}
|
||||
}
|
||||
status := l.checkGradientConvergence(task.Gradient, gradThresh)
|
||||
return status, nil
|
||||
}
|
||||
|
||||
func (localOptimizer) checkGradientConvergence(gradient []float64, gradThresh float64) Status {
|
||||
if gradient == nil || math.IsNaN(gradThresh) {
|
||||
return NotTerminated
|
||||
}
|
||||
if gradThresh == 0 {
|
||||
gradThresh = defaultGradientAbsTol
|
||||
}
|
||||
if norm := floats.Norm(gradient, math.Inf(1)); norm < gradThresh {
|
||||
return GradientThreshold
|
||||
}
|
||||
return NotTerminated
|
||||
}
|
||||
|
||||
// finish completes the channel operations to finish an optimization.
|
||||
func (localOptimizer) finish(operation chan<- Task, result <-chan Task) {
|
||||
// Guarantee that result is closed before operation is closed.
|
||||
for range result {
|
||||
}
|
||||
}
|
||||
|
||||
// finishMethodDone sends a MethodDone signal on operation, reads the result,
|
||||
// and completes the channel operations to finish an optimization.
|
||||
func (l localOptimizer) finishMethodDone(operation chan<- Task, result <-chan Task, task Task) {
|
||||
task.Op = MethodDone
|
||||
operation <- task
|
||||
task = <-result
|
||||
if task.Op != PostIteration {
|
||||
panic("optimize: task should have returned post iteration")
|
||||
}
|
||||
l.finish(operation, result)
|
||||
}
|
||||
Reference in New Issue
Block a user