github.com/gopherd/gonum@v0.0.4/diff/fd/diff.go (about) 1 // Copyright ©2014 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 ) 11 12 // A Point is a stencil location in a finite difference formula. 13 type Point struct { 14 Loc float64 15 Coeff float64 16 } 17 18 // Formula represents a finite difference formula on a regularly spaced grid 19 // that approximates the derivative of order k of a function f at x as 20 // d^k f(x) ≈ (1 / Step^k) * \sum_i Coeff_i * f(x + Step * Loc_i). 21 // Step must be positive, or the finite difference formula will panic. 22 type Formula struct { 23 // Stencil is the set of sampling Points which are used to estimate the 24 // derivative. The locations will be scaled by Step and are relative to x. 25 Stencil []Point 26 Derivative int // The order of the approximated derivative. 27 Step float64 // Default step size for the formula. 28 } 29 30 func (f Formula) isZero() bool { 31 return f.Stencil == nil && f.Derivative == 0 && f.Step == 0 32 } 33 34 // Settings is the settings structure for computing finite differences. 35 type Settings struct { 36 // Formula is the finite difference formula used 37 // for approximating the derivative. 38 // Zero value indicates a default formula. 39 Formula Formula 40 // Step is the distance between points of the stencil. 41 // If equal to 0, formula's default step will be used. 42 Step float64 43 44 OriginKnown bool // Flag that the value at the origin x is known. 45 OriginValue float64 // Value at the origin (only used if OriginKnown is true). 46 47 Concurrent bool // Should the function calls be executed concurrently. 48 } 49 50 // Forward represents a first-order accurate forward approximation 51 // to the first derivative. 52 var Forward = Formula{ 53 Stencil: []Point{{Loc: 0, Coeff: -1}, {Loc: 1, Coeff: 1}}, 54 Derivative: 1, 55 Step: 2e-8, 56 } 57 58 // Forward2nd represents a first-order accurate forward approximation 59 // to the second derivative. 60 var Forward2nd = Formula{ 61 Stencil: []Point{{Loc: 0, Coeff: 1}, {Loc: 1, Coeff: -2}, {Loc: 2, Coeff: 1}}, 62 Derivative: 2, 63 Step: 1e-4, 64 } 65 66 // Backward represents a first-order accurate backward approximation 67 // to the first derivative. 68 var Backward = Formula{ 69 Stencil: []Point{{Loc: -1, Coeff: -1}, {Loc: 0, Coeff: 1}}, 70 Derivative: 1, 71 Step: 2e-8, 72 } 73 74 // Backward2nd represents a first-order accurate forward approximation 75 // to the second derivative. 76 var Backward2nd = Formula{ 77 Stencil: []Point{{Loc: 0, Coeff: 1}, {Loc: -1, Coeff: -2}, {Loc: -2, Coeff: 1}}, 78 Derivative: 2, 79 Step: 1e-4, 80 } 81 82 // Central represents a second-order accurate centered approximation 83 // to the first derivative. 84 var Central = Formula{ 85 Stencil: []Point{{Loc: -1, Coeff: -0.5}, {Loc: 1, Coeff: 0.5}}, 86 Derivative: 1, 87 Step: 6e-6, 88 } 89 90 // Central2nd represents a secord-order accurate centered approximation 91 // to the second derivative. 92 var Central2nd = Formula{ 93 Stencil: []Point{{Loc: -1, Coeff: 1}, {Loc: 0, Coeff: -2}, {Loc: 1, Coeff: 1}}, 94 Derivative: 2, 95 Step: 1e-4, 96 } 97 98 var negativeStep = "fd: negative step" 99 100 // checkFormula checks if the formula is valid, and panics otherwise. 101 func checkFormula(formula Formula) { 102 if formula.Derivative == 0 || formula.Stencil == nil || formula.Step <= 0 { 103 panic("fd: bad formula") 104 } 105 } 106 107 // computeWorkers returns the desired number of workers given the concurrency 108 // level and number of evaluations. 109 func computeWorkers(concurrent bool, evals int) int { 110 if !concurrent { 111 return 1 112 } 113 nWorkers := runtime.GOMAXPROCS(0) 114 if nWorkers > evals { 115 nWorkers = evals 116 } 117 return nWorkers 118 } 119 120 // usesOrigin returns whether the stencil uses the origin, which is true iff 121 // one of the locations in the stencil equals 0. 122 func usesOrigin(stencil []Point) bool { 123 for _, pt := range stencil { 124 if pt.Loc == 0 { 125 return true 126 } 127 } 128 return false 129 } 130 131 // getOrigin returns the value at the origin. It returns originValue if originKnown 132 // is true. It returns the value returned by f if stencil contains a point with 133 // zero location, and NaN otherwise. 134 func getOrigin(originKnown bool, originValue float64, f func() float64, stencil []Point) float64 { 135 if originKnown { 136 return originValue 137 } 138 for _, pt := range stencil { 139 if pt.Loc == 0 { 140 return f() 141 } 142 } 143 return math.NaN() 144 } 145 146 const ( 147 badDerivOrder = "fd: invalid derivative order" 148 )