The site is currently in read-only mode for maintenance. Posting of new items will be available again shortly.

## Introduction

Some twenty-seven years ago I had occasion to write some numerical methods in Pascal. Many algorithms used nested functions. This article describes how I successfully migrated many of these functions to C# 4.0 using nested lambda functions.

I was designing a yacht and the problem was to produce not only a fair surface but to calculate displacement, centre of buoyancy and wetted surface area, amongst other data arising from the hull surface definition. At the time there were no CAD programs available that could run on my BBC computer. It boasted an 8 bit 6502 processor, running at 2 MHz and 32 kbytes of RAM. In practice, at that time, hull lines were plotted full scale and smoothing was accomplished with a flexible wooden batten or spline. Measurements were taken from lofted lines or scale drawings and Simpson’s rule was used, with hand calculations, to determine displacement, centre of buoyancy and other data arising from the hull shape.

At that time, there was a Pascal compiler for the BBC computer. I was also able to program a function that specified the hull. Then, by using numerical computations, I could generate the required hull data. Moreover, I was able to iteratively modify the parameters that specified the hull and besides other desirable capabilities, optimize wetted surface area with a required heeling moment. Admittedly the graphics were absolutely rudimentary but by using general conics as fairing curves, a fair hull could be obtained.

The 12 m yacht, Apollonius (note those conics), a cruiser racer, was built. This yacht has successfully completed many blue water ocean races. These days I find more pleasure in cruising about the islands of Bass Strait, a turbulent stretch of water between Tasmania and the Australian mainland.

## Background

Let’s leave this digression. Last week, when clearing out some old cardboard folders, I came across some of my old Pascal code, just readable, produced on a long extinct dot matrix printer. It went something like this:

program boatHull(input, output);
type posint = 1..maxint;
{Much code omitted - for brevity}
function integral(function f(x : real) : real; a, b : real; n : posint) : real;
type
{types} ;
var
{vars};
begin
{chosen algorithm}
end {integral};
function doubleIntegral (function f(x, y : real) : real;
function g(y : real): real; function h(y : real): real; a,
b : real; m, n: posint ) : real;
{end of parameters}
function area(y: real): real; {
first nested function; note g, h, and m are in scope}
function argument(x : real) : real; {
second nested function; note y is in scope}
begin {argument}
argument := f(x,y)
end {argument};
begin {area}
area := integral(argument, g(y), h(y), m)
end {area};
begin {doubleIntegral}
doubleIntegral:= integral(area, a, b, n)
end {doubleIntegral};
begin {demo}
{input, output code goes here}
end. {boatHull}

We can see that the scopes of the functions `integral`

and `doubleIntegral`

make them available to the program boatHull. However, the function `doubleIntegral`

is able to call the function `integral`

. The function area is nested within `doubleIntegral`

and is only available to `doubleIntegral`

. Similarly the function argument is only available to the function area.

Encapsulation is the compelling reason for using nested functions in the Pascal function `doubleIntegral`

. The nested function area has no significance outside `doubleIntegral`

and neither does the function argument have any reason to exist outside the area function.

## Moving to C# 4.0

In my retirement I design and implement online SQL database applications for educational environments. I use C# for code-behind in .aspx pages. Naturally I wondered how, using coding principles similar to the above, a double integral could be achieved using nested functions.

In C#, Pascal functions correspond to methods. However, a direct translation of the code is not possible as C#, although supporting nested classes, does not support nested methods.However, lambda functions, relatively new to C#, may be nested. So, I downloaded Visual C# 2010 Express, a consumer of .NET 4.0, to have a go.

At this stage, if readers are unfamiliar with lambda notation and delegates, then they should consult an appropriate reference, of which there are many.

First, after preliminaries, some delegates:

using System;
using System.Linq;
namespace Computationals
{
delegate double Function(double x);
delegate double Functionxy(double x, double y);
delegate double Integral(Function f, double a, double b, int n);
public class LambdaNumericals
{

Next, some integration methods: Firstly, Simpson’s Method

static Integral SimpInt()
{
Integral integral = (f, a, b, n) =>
{
double sum = 0;
double h = (b - a) / n;
for (int i = 0; i < n; i = i + 2)
sum = sum + (f(a + i * h) + 4 * f(a + (i + 1) * h) + f(a + (i + 2) * h)) * h / 3;
return sum;
};
return integral;
}

Secondly, the Gaussian-Legendre 4 point Algorithm

static Integral GaussInt()
{
Integral integral = (f, a, b, n) =>
{
double[] weight = new double[4];
weight[2] = 0.652145154862546;
weight[1] = weight[2];
weight[3] = 0.347854845137454;
weight[0] = weight[3];
double[] point = new double[4];
point[3] = 0.861136311594053;
point[0] = -point[3];
point[2] = 0.339981043584856;
point[1] = -point[2];
double sum = 0;
double h = (b - a) / n;
double xr, xl, m, c, s;
for (int i = 0; i < n; i++)
{
s = 0;
xl = a + i * h;
xr = xl + h;
m = (xr - xl) / 2;
c = (xr + xl) / 2;
for (int j = 0; j < 4; j++)
s = s + weight[j] * f(m * point[j] + c) * m;
sum = sum + s;
}
return sum;
};
return integral;
}

Now, we can use the above in:

static double dubInt(Functionxy fxy, Function g, Function h, double a, double b,
int m, int n, Integral inInt, Integral outInt)
{
return outInt((double y) => inInt((double x) => fxy(x, y), g(y), h(y), m), a, b, n);
}

inInt and outInt are parameters accepting integration functions, SimpInt() or GaussInt().

The Pascal doubleIntegral function becomes outInt(area, a ,b, n).

The area function in the Pascal code corresponds to the snippet (double y) => inInt(argument, g(y), h(y), m).

Finally the argument function corresponds to (double x) => fxy(x, y).

To test our code we can define the following test functions to be used as parameters:

public static double p(double x, double y)
{
return x * y;
}
public static double f1(double x)
{
return x;
}
public static double f2(double x)
{
return 2 * x;
}
public static double sine(double x)
{
return Math.Sin(x);
}

We can then invoke our integration methods using:

public static void Main()
{
Integral integrate1, integrate2;
integrate1 = SimpInt();
Console.WriteLine(integrate1(sine, 0, Math.PI, 60));
integrate2 = GaussInt();
Console.WriteLine(integrate2(sine, 0, Math.PI, 15));
Console.WriteLine(integrate2(Math.Sin, 0, Math.PI, 15));
Console.WriteLine(dubInt(p, f1, f2, 1, 2, 4, 4, integrate1, integrate2));
}
}

## Point of Interest

Following on, using similar strategies, I have applied lambda methodology to differentiation, double differentiation, curve length, partial derivatives, surface area and curvature. Code with examples is included is in the downloads.

The techniques demonstrated can easily be extended to integration in polar coordinates, triple integrals, and integration in cylindrical and spherical coordinates. Parametric functions, splines and surfaces and differential equations are possible candidates for lambda functions. No doubt this is only the tip of the iceberg.

## Limitations on the Application of Code

In conclusion, I must emphasise that this article concerns the techniques of lambda and nested lambda functions applied to numerical computations. The actual numerical algorithms, in a library context would, of course, contain error specifications. Also, the best values for some constants are machine dependant. I make no suggestions on the suitability of the above for particular applications.

Nevertheless, once a programmer is comfortable with the syntax of lambda functions, they potentially can provide a remarkably succinct and productive entry into non trivial, numerical computations.