github.com/gopherd/gonum@v0.0.4/diff/fd/derivative.go (about)

     1  // Copyright ©2017 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 fd
     6  
     7  import (
     8  	"math"
     9  	"runtime"
    10  	"sync"
    11  )
    12  
    13  // Derivative estimates the derivative of the function f at the given location.
    14  // The finite difference formula, the step size, and other options are
    15  // specified by settings. If settings is nil, the first derivative will be
    16  // estimated using the Forward formula and a default step size.
    17  func Derivative(f func(float64) float64, x float64, settings *Settings) float64 {
    18  	// Default settings.
    19  	formula := Forward
    20  	step := formula.Step
    21  	var originValue float64
    22  	var originKnown, concurrent bool
    23  
    24  	// Use user settings if provided.
    25  	if settings != nil {
    26  		if !settings.Formula.isZero() {
    27  			formula = settings.Formula
    28  			step = formula.Step
    29  			checkFormula(formula)
    30  		}
    31  		if settings.Step != 0 {
    32  			step = settings.Step
    33  		}
    34  		originKnown = settings.OriginKnown
    35  		originValue = settings.OriginValue
    36  		concurrent = settings.Concurrent
    37  	}
    38  
    39  	var deriv float64
    40  	if !concurrent || runtime.GOMAXPROCS(0) == 1 {
    41  		for _, pt := range formula.Stencil {
    42  			if originKnown && pt.Loc == 0 {
    43  				deriv += pt.Coeff * originValue
    44  				continue
    45  			}
    46  			deriv += pt.Coeff * f(x+step*pt.Loc)
    47  		}
    48  		return deriv / math.Pow(step, float64(formula.Derivative))
    49  	}
    50  
    51  	wg := &sync.WaitGroup{}
    52  	mux := &sync.Mutex{}
    53  	for _, pt := range formula.Stencil {
    54  		if originKnown && pt.Loc == 0 {
    55  			mux.Lock()
    56  			deriv += pt.Coeff * originValue
    57  			mux.Unlock()
    58  			continue
    59  		}
    60  		wg.Add(1)
    61  		go func(pt Point) {
    62  			defer wg.Done()
    63  			fofx := f(x + step*pt.Loc)
    64  			mux.Lock()
    65  			defer mux.Unlock()
    66  			deriv += pt.Coeff * fofx
    67  		}(pt)
    68  	}
    69  	wg.Wait()
    70  	return deriv / math.Pow(step, float64(formula.Derivative))
    71  }