github.com/gopherd/gonum@v0.0.4/optimize/listsearch.go (about) 1 // Copyright ©2018 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package optimize 6 7 import ( 8 "math" 9 10 "github.com/gopherd/gonum/mat" 11 ) 12 13 var _ Method = (*ListSearch)(nil) 14 15 // ListSearch finds the optimum location from a specified list of possible 16 // optimum locations. 17 type ListSearch struct { 18 // Locs is the list of locations to optimize. Each row of Locs is a location 19 // to optimize. The number of columns of Locs must match the dimensions 20 // passed to InitGlobal, and Locs must have at least one row. 21 Locs mat.Matrix 22 23 eval int 24 rows int 25 bestF float64 26 bestIdx int 27 } 28 29 func (*ListSearch) Uses(has Available) (uses Available, err error) { 30 return has.function() 31 } 32 33 // Init initializes the method for optimization. The input dimension 34 // must match the number of columns of Locs. 35 func (l *ListSearch) Init(dim, tasks int) int { 36 if dim <= 0 { 37 panic(nonpositiveDimension) 38 } 39 if tasks < 0 { 40 panic(negativeTasks) 41 } 42 r, c := l.Locs.Dims() 43 if r == 0 { 44 panic("listsearch: list matrix has no rows") 45 } 46 if c != dim { 47 panic("listsearch: supplied dimension does not match list columns") 48 } 49 l.eval = 0 50 l.rows = r 51 l.bestF = math.Inf(1) 52 l.bestIdx = -1 53 return min(r, tasks) 54 } 55 56 func (l *ListSearch) sendNewLoc(operation chan<- Task, task Task) { 57 task.Op = FuncEvaluation 58 task.ID = l.eval 59 mat.Row(task.X, l.eval, l.Locs) 60 l.eval++ 61 operation <- task 62 } 63 64 func (l *ListSearch) updateMajor(operation chan<- Task, task Task) { 65 // Update the best value seen so far, and send a MajorIteration. 66 if task.F < l.bestF { 67 l.bestF = task.F 68 l.bestIdx = task.ID 69 } else { 70 task.F = l.bestF 71 mat.Row(task.X, l.bestIdx, l.Locs) 72 } 73 task.Op = MajorIteration 74 operation <- task 75 } 76 77 func (l *ListSearch) Status() (Status, error) { 78 if l.eval < l.rows { 79 return NotTerminated, nil 80 } 81 return MethodConverge, nil 82 } 83 84 func (l *ListSearch) Run(operation chan<- Task, result <-chan Task, tasks []Task) { 85 // Send initial tasks to evaluate 86 for _, task := range tasks { 87 l.sendNewLoc(operation, task) 88 } 89 // Read from the channel until PostIteration is sent or until the list of 90 // tasks is exhausted. 91 Loop: 92 for { 93 task := <-result 94 switch task.Op { 95 default: 96 panic("unknown operation") 97 case PostIteration: 98 break Loop 99 case MajorIteration: 100 if l.eval == l.rows { 101 task.Op = MethodDone 102 operation <- task 103 continue 104 } 105 l.sendNewLoc(operation, task) 106 case FuncEvaluation: 107 l.updateMajor(operation, task) 108 } 109 } 110 111 // Post iteration was sent, or the list has been completed. Read in the final 112 // list of tasks. 113 for task := range result { 114 switch task.Op { 115 default: 116 panic("unknown operation") 117 case MajorIteration: 118 case FuncEvaluation: 119 l.updateMajor(operation, task) 120 } 121 } 122 close(operation) 123 }