// 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/stat/distmv" ) var _ Method = (*GuessAndCheck)(nil) // GuessAndCheck is a global optimizer that evaluates the function at random // locations. Not a good optimizer, but useful for comparison and debugging. type GuessAndCheck struct { Rander distmv.Rander bestF float64 bestX []float64 } func (*GuessAndCheck) Uses(has Available) (uses Available, err error) { return has.function() } func (g *GuessAndCheck) 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 tasks } func (g *GuessAndCheck) sendNewLoc(operation chan<- Task, task Task) { g.Rander.Rand(task.X) task.Op = FuncEvaluation operation <- task } func (g *GuessAndCheck) updateMajor(operation chan<- Task, task 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) } else { task.F = g.bestF copy(task.X, g.bestX) } task.Op = MajorIteration operation <- task } func (g *GuessAndCheck) Run(operation chan<- Task, result <-chan Task, tasks []Task) { // Send initial tasks to evaluate for _, task := range tasks { g.sendNewLoc(operation, task) } // Read from the channel until PostIteration is sent. Loop: for { task := <-result switch task.Op { default: panic("unknown operation") case PostIteration: break Loop case MajorIteration: g.sendNewLoc(operation, task) case FuncEvaluation: g.updateMajor(operation, task) } } // PostIteration was sent. Update the best new values. for task := range result { switch task.Op { default: panic("unknown operation") case MajorIteration: case FuncEvaluation: g.updateMajor(operation, task) } } close(operation) }