Approximate Functions and Interpolation

In many kinds of numerical computations, it is convenient to introduce approximate functions. Approximate functions can be thought of as generalizations of ordinary approximate real numbers. While an approximate real number gives the value to a certain precision of a single numerical quantity, an approximate function gives the value to a certain precision of a quantity which depends on one or more parameters. The Wolfram Language uses approximate functions, for example, to represent numerical solutions to differential equations obtained with (RefLink[NDSolve, paclet:ref/NDSolve]), as discussed in "Numerical Differential Equations".

Approximate functions in the Wolfram Language are represented by (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) objects. These objects work like the pure functions discussed in "Pure Functions". The basic idea is that when given a particular argument, an (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) object finds the approximate function value that corresponds to that argument.

The (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) object contains a representation of the approximate function based on interpolation. Typically it contains values and possibly derivatives at a sequence of points. It effectively assumes that the function varies smoothly between these points. As a result, when you ask for the value of the function with a particular argument, the (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) object can interpolate to find an approximation to the value you want.

Constructing approximate functions.

Here is a table of the values of the sine function:

Table[{x,Sin[x]},{x,0,2,0.25}]

This constructs an approximate function which represents these values:

sin=Interpolation[%]

The approximate function reproduces each of the values in the original table:

sin[0.25]

It also allows you to get approximate values at other points:

sin[0.3]

In this case the interpolation is a fairly good approximation to the true sine function:

Sin[0.3]

You can work with approximate functions much as you would with any other Wolfram Language functions. You can plot approximate functions, or perform numerical operations such as integration or root finding.

If you give a non-numerical argument, the approximate function is left in symbolic form:

sin[x]

Here is a numerical integral of the approximate function:

NIntegrate[sin[x]^2,{x,0,Pi/2}]

Here is the same numerical integral for the true sine function:

NIntegrate[Sin[x]^2,{x,0,Pi/2}]

A plot of the approximate function is essentially indistinguishable from the true sine function:

Plot[sin[x],{x,0,2}]

If you differentiate an approximate function, the Wolfram Language will return another approximate function that represents the derivative.

This finds the derivative of the approximate sine function, and evaluates it at π/6:

sin'[Pi/6]

The result is close to the exact one:

N[Cos[Pi/6]]

(RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) objects contain all the information the Wolfram Language needs about approximate functions. In standard Wolfram Language output format, however, only the part that gives the domain of the (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) object is printed explicitly. The lists of actual parameters used in the (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) object are shown only in iconic form.

In standard output format, the only parts of an (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) object printed explicitly are its domain and output type:

sin

If you ask for a value outside of the domain, the Wolfram Language prints a warning, then uses extrapolation to find a result:

sin[3]

The more information you give about the function you are trying to approximate, the better the approximation the Wolfram Language constructs can be. You can, for example, specify not only values of the function at a sequence of points, but also derivatives.

Constructing approximate functions with specified derivatives.

This interpolates through the values of the sine function and its first derivative:

sind=Interpolation[Table[{{x},Sin[x],Cos[x]},{x,0,2,0.25}]]

This finds a better approximation to the derivative than the previous interpolation:

sind'[Pi/6]

(RefLink[Interpolation, paclet:ref/Interpolation]) works by fitting polynomial curves between the points you specify. You can use the option (RefLink[InterpolationOrder, paclet:ref/InterpolationOrder]) to specify the degree of these polynomial curves. The default setting is (RefLink[InterpolationOrder, paclet:ref/InterpolationOrder])->3, yielding cubic curves.

This makes a table of values of the cosine function:

tab=Table[{x,Cos[x]},{x,0,6}];

This creates an approximate function using linear interpolation between the values in the table:

Interpolation[tab,InterpolationOrder->1]

The approximate function consists of a collection of straight-line segments:

Plot[%[x],{x,0,6}]

With the default setting (RefLink[InterpolationOrder, paclet:ref/InterpolationOrder])->3, cubic curves are used, and the function looks smooth:

Plot[Evaluate[Interpolation[tab]][x],{x,0,6}]

Increasing the setting for (RefLink[InterpolationOrder, paclet:ref/InterpolationOrder]) typically leads to smoother approximate functions. However, if you increase the setting too much, spurious wiggles may develop.

Interpolating multidimensional arrays of data.

This interpolates an array of values from integer grid points:

ListInterpolation[Table[1.5/(x^2+y^3),{x,10},{y,15}]]

Here is the value at a particular position:

%[6.5,7.2]

Here is another array of values:

tab=Table[1.5/(x^2+y^3),{x,5.5,7.2,.2},{y,2.3,8.9,.1}];

To interpolate this array you explicitly have to tell the Wolfram Language the domain it covers:

ListInterpolation[tab,{{5.5,7.2},{2.3,8.9}}]

(RefLink[ListInterpolation, paclet:ref/ListInterpolation]) works for arrays of any dimension, and in each case it produces an (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) object which takes the appropriate number of arguments.

This interpolates a three-dimensional array:

ListInterpolation[Array[#1^2+#2^2-#3^2&,{10,10,10}]]

The resulting (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) object takes three arguments:

%[3.4,7.8,2.6]

The Wolfram Language can handle not only purely numerical approximate functions, but also ones which involve symbolic parameters.

This generates an (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) that depends on the parameters a and b:

sfun=ListInterpolation[{1+a,2,3,4+b,5}];

This shows how the interpolated value at 2.2 depends on the parameters:

sfun[2.2]//Simplify

With the default setting for (RefLink[InterpolationOrder, paclet:ref/InterpolationOrder]) used, the value at this point no longer depends on a:

sfun[3.8]//Simplify

In working with approximate functions, you can quite often end up with complicated combinations of (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) objects. You can always tell the Wolfram Language to produce a single (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) object valid over a particular domain by using (RefLink[FunctionInterpolation, paclet:ref/FunctionInterpolation]).

This generates a new (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) object valid in the domain 0 to 1:

FunctionInterpolation[x+sin[x^2],{x,0,1}]

This generates a nested (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) object:

ListInterpolation[{3,4,5,sin[a],6}][4]

This produces a pure two-dimensional (RefLink[InterpolatingFunction, paclet:ref/InterpolatingFunction]) object:

FunctionInterpolation[x^2+%,{x,1,3},{a,0,1.5}]

Constructing approximate functions by evaluating expressions.