Numerical Differentiation in IronPython QuickStart Sample

Illustrates how to approximate the derivative of a function in IronPython.

This sample is also available in: C#, Visual Basic, F#.

Overview

This QuickStart sample demonstrates how to perform numerical differentiation using Numerics.NET. It shows how to calculate derivatives of functions using different numerical methods including central, forward, and backward differences.

The sample covers:

  • Using central differences for standard numerical differentiation
  • Handling edge cases with forward and backward differences when central differences aren’t suitable
  • Error estimation in numerical differentiation results
  • Creating derivative functions as delegates that can be passed to other methods
  • Working with functions that have domain restrictions or discontinuities

The code demonstrates practical scenarios where each differentiation method is most appropriate, including functions undefined on part of their domain and functions with discontinuities. It also shows how to obtain error estimates for the calculated derivatives, which is crucial for assessing the accuracy of the numerical results.

The code

import numerics

from math import *
from System import Math

# The numerical differentiation classes reside in the
# Extreme.Mathematics.Calculus namespace.
from Extreme.Mathematics.Calculus import *
# Function delegates reside in the Extreme.Mathematics
# namespace.
from Extreme.Mathematics import *

# Illustrates numerical differentiation using the
# FunctionMath class in the Extreme.Mathematics 
# namespace of Extreme Numerics.NET.

# 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.
fCentral = cos

print "Central differences:"
# The actual calculation is performed by the
# CentralDerivative method.
result = FunctionMath.CentralDerivative(fCentral, 1.0)
print "  Result =", result
print "  Actual =", -sin(1.0)
# This method is overloaded. It has an optional
# out parameter that returns an estimate for the
# error in the result.
import clr
estimatedError = clr.Reference[float]()
result = FunctionMath.CentralDerivative(fCentral, 1.0, estimatedError)
print "Estimated error =", estimatedError.Value

#
# 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:
fForward = lambda x: (x+2) * (x+2) * Math.Sqrt(x+2)
			
# Calculating the derivative using central 
# differences returns NaN (Not a Number):
result = FunctionMath.CentralDerivative(fForward, -2.0, estimatedError)
print "Using central differences may not work:"
print "  Derivative =", result
print "  Estimated error =", estimatedError.Value

# Using the ForwardDerivative method does work:
print "Using forward differences instead:"
result = FunctionMath.ForwardDerivative(fForward, -2.0, estimatedError)
print "  Derivative =", result
print "  Estimated error =", estimatedError
			
# The FBackward function at the end of this file
# is an example of a function that requires
# backward differences for differentiation at
# x = 0.
fBackward = lambda x: 1.0 if x > 0.0 else Math.Sin(x)
print "Using backward differences:"
result = FunctionMath.BackwardDerivative(fBackward, 0.0, estimatedError)
print "  Derivative =", result
print "  Estimated error =", estimatedError

#
# 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.
print "Using delegates:"
			
# For central differences:
dfCentral = FunctionMath.GetNumericalDifferentiator(fCentral)
print "Central: f'(1) =", dfCentral(1)
			
# For forward differences:
dfForward = FunctionMath.GetForwardDifferentiator(fForward)
print "Forward: f'(-2) =", dfForward(-2)

# For backward differences:
dfBackward = FunctionMath.GetBackwardDifferentiator(fBackward)
print "Backward: f'(0) =", dfBackward(0)