gonum.org/v1/gonum@v0.14.0/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  	"gonum.org/v1/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  }