Numerical Differentiation in F# QuickStart Sample
Illustrates how to approximate the derivative of a function in F#.
View this sample in: C# Visual Basic IronPython
// Illustrates numerical differentiation using the
// FunctionMath class in the Numerics.NET
// namespace of Numerics.NET.
#light
open System
open Numerics.NET
// The license is verified at runtime. We're using a 30 day trial key here.
// For more information, see:
// https://numerics.net/trial-key
let licensed = Numerics.NET.License.Verify("64542-18980-57619-62268")
// Numerical differentiation is a fairly simple
// procedure. Its accuracy is inherently limited
// because of unavoidable round-off error.
//
// All calculations are performed by static methods
// of the FunctionMath class. All methods are extension
// methods, so they can be applied to the delegates
// directly.
//
// Standard numerical differentiation.
//
// Central differences are the standard way of
// approximating the result of a function.
// For this to work, it must be possible to
// evaluate the target function on both sides of
// the point where the numerical result is
// requested.
// The function must be provided as a
// Func<double, double>. For more information about
// this delegate, see the FunctionDelegates
// QuickStart Sample.
let fCentral = Func<_,_> Math.Cos
printfn "Central differences:"
// The actual calculation is performed by the
// CentralDerivative method.
let result = fCentral.CentralDerivative(1.0)
printfn " Result = %A" result
printfn " Actual = %A" (-Math.Sin(1.0))
// This method is overloaded. It has an optional
// out parameter that returns an estimate for the
// error in the result. In F#, we can get both
// value and error in a tuple:
let _, estimatedError = fCentral.CentralDerivative(1.0)
printfn "Estimated error = %A" estimatedError
//
// Forward and backward differences.
//
// Some functions are not defined everywhere.
// If the result is required on a boundary
// of the domain where it is defined, the central
// differences method breaks down. This also happens
// if the function has a discontinuity close to the
// differentiation point.
//
// In these cases, either forward or backward
// differences may be used instead.
//
// Here is an example of a function that may require
// forward differences. It is undefined for
// x < -2:
let fForward = Func<_,_> (fun x -> (pown (x+2.0) 2) * sqrt(x+2.0))
// Calculating the derivative using central
// differences returns NaN (Not a Number):
let result2, estimatedError2 = fForward.CentralDerivative(-2.0)
printfn "Using central differences may not work:"
printfn " Derivative = %A" result2
printfn " Estimated error = %A" estimatedError2
// Using the ForwardDerivative method does work:
printfn "Using forward differences instead:"
let result3, estimatedError3 = fForward.ForwardDerivative(-2.0)
printfn " Derivative = %A" result3
printfn " Estimated error = %A" estimatedError3
// The FBackward function at the end of this file
// is an example of a function that requires
// backward differences for differentiation at
// x = 0.
let fBackward = Func<_,_> (fun x -> if x > 0.0 then 1.0 else sin(x))
printfn "Using backward differences:"
let result4, estimatedError4 = fBackward.BackwardDerivative(0.0)
printfn " Derivative = %A" result4
printfn " Estimated error = %A" estimatedError4
//
// Derivative function
//
// In some cases, it may be useful to have the
// derivative of a function in the form of a
// Func<double, double>, so it can be passed as
// an argument to other methods. This is very
// easy to do.
printfn "Using delegates:"
// For central differences:
let dfCentral = fCentral.GetNumericalDifferentiator().Invoke
printfn "Central: f'(1) = %A" (dfCentral 1.0)
// For forward differences:
let dfForward = fForward.GetForwardDifferentiator().Invoke
printfn "Forward: f'(-2) = %A" (dfForward -2.0)
// For backward differences:
let dfBackward = fBackward.GetBackwardDifferentiator().Invoke
printfn "Backward: f'(0) = %A" (dfBackward 0.0)
printf "Press Enter key to exit..."
Console.ReadLine() |> ignore