NAG F# Examples
Contents
F# — Background
F# is a functional programming language derived from OCAML, which in turn has a shared ancestry with the Standard ML programming that I used over 20 years ago while working on theorem proving systems at Manchester University…
F# uses a syntax derived from OCAML but has many additional features in particular making it interface better with .NET constructs (as it compiles to the same CLR virtual machine as other .NET languages). Thus it should be easy to call the NAG Library for .NET from F#, and so it is, however the resulting interface doesn't always lead to idiomatic functional programming calling conventions. In this post I hope to show some reasons for this, and also show how with a few lines of F#, one can produce alternative interfaces to the NAG library that may allow more natural functional use, and be tuned to the particular requirements of your application.
F# is a very expressive language that is designed to support many different programming styles, although with a strongly functional foundation. As such there are several styles in which one may define a function (method). One of the distinguishing features of the ML family of languages is that they are strongly typed but that (when restricted to the core functional features) types never need to be explicitly declared, the expressions are statically analyzed at compile time and the type inferred.
F# may be used in two ways; as a compiler (compiling to CIL code as is done for C# or VB.NET) but also as an interactive interpreter that offers a read eval print loop interface familiar to lisp programmers and users of systems such as MATLAB or Maple.
Before looking at some specific examples from the NAG library, I want to look at a simpler example of a function for adding two numbers.
Sum Example
The first example uses a style that looks perhaps most familiar. Note however that unlike many imperative programming languages, F# functions only ever take a single argument.
(a,b) here does not represent a pair of values but a single value, being a pair of integers (represented by the type
int * int.
// sum_tuple declaration > let sum_tuple (a,b) = a + b;; val sum_tuple : int * int -> int
A more idiomatically functional style is the curried form, where instead of taking a sequence of values as input, the function takes one integer, returning a function which is in turn applied to the second integer, returning the sum.
// sum_curried declaration > let sum_curried a b = a + b;; val sum_curried : int -> int -> int
As well as variables holding values (int in this case) ML based languages allow variables that hold references (pointers) to values (the type
int ref here). the assignment operator
:= updates the referenced value (while the reference binding itself doesn't change). Passing such a reference type is one way to simulate the “output parameters” of functions or subroutines in imperative languages. The
unit type shown as the return type is similar to void function in C, or a subroutine in Fortran.
// sum_ref declaration > let sum_ref (a,b,r) = r := a + b;; val sum_ref : int * int * int ref -> unit
In addition to the reference types derived from ML, F# provides a syntax to the .NET mechanisms of passing value types by reference. The example below uses the type annotation
r:byref<int> to force this mechanism to be used, and uses the assignment operator
<- rather than
:= to update the value. Passing a value type by reference rather than passing a parameter of reference type isn't something one would often do in native F# code, however methods derived from .NET libraries written in other languages often derive these types in F#.
// sum_byref declaration > let sum_byref (a,b,r:byref<int>) = r <- a + b;; val sum_byref : int * int * byref<int> -> unit
These four definitions may used as follows to calculate 3 = 1 + 2:
// Simple sum examples > let r1 = sum_tuple (1,2);; val r1 : int = 3 > let r2 = sum_curried 1 2;; val r2 : int = 3 > let rr3 = ref 0;; val rr3 : int ref = {contents = 0;} > sum_ref (1,2,rr3);; val it : unit = () > let r3 = !rr3;; val r3 : int = 3 > let mutable r4 = 0;; val mutable r4 : int = 0 > sum_byref(1,2,&r4);; val it : unit = () > r4;; val it : int = 3
The first two forms are clearly a bit more convenient, however the second two forms, which require the declaration of a variable to hold the result, are not hard and should be familiar to anyone used to a more imperative programming style. This essentially is a function of the main design aims of F#, that it should stress the functional approach, but give full access to any .NET methods even if they are designed for an imperative or Object Oriented rather than functional, declarative interface. The extra verbosity of the use of references is over exaggerated in these examples as I am using the interactive F# system and using the
;; terminator to cause the system to echo the value and type of each expression. This is a useful aid to see what's happening, but in practice one would often use the compiler which does not echo types at each stage, or not use the
;; terminator on every line if using the interactive system.
The benefits of the tuple or curried version when used in a functional programming language like F# are more apparent when functions are composed. If one wanted to calculate (1+1) + (2+2) (ignoring the fact that (1+1) + (2+2) is already valid F# ) then as sum_tuple and sum_curried are side effect free functions returning results they may be composed in a very natural way:
// composing sum examples (functional) > let c1=sum_tuple (sum_tuple(1,1),sum_tuple(2,2));; val c1 : int = 6 > let c2=sum_curried (sum_curried 1 1) (sum_curried 2 2);; val c2 : int = 6
The signatures of sum_ref and sum_byref on the other hand lead to a more imperative calling style, where temporary variables need to be declared to hold (references to) the intermediate results.
// composing sum examples (imperative) > let r3a = ref 0;; val r3a : int ref = {contents = 0;} > let r3b = ref 0;; val r3b : int ref = {contents = 0;} > let r3c = ref 0;; val r3c : int ref = {contents = 0;} > sum_ref (1,1,r3a);; val it : unit = () > sum_ref (2,2,r3b);; val it : unit = () > sum_ref (!r3a,!r3b,r3c);; val it : unit = () > let c3 = !r3c;; val c3 : int = 6 > let mutable r4a = 0;; val mutable r4a : int = 0 > let mutable r4b = 0;; val mutable r4b : int = 0 > let mutable c4 = 0;; val mutable c4 : int = 0 > sum_byref (1,1,&r4a);; val it : unit = () > sum_byref (2,2,&r4b);; val it : unit = () > sum_byref (r4a,r4b,&c4);; val it : unit = () > c4;; val it : int = 6
If you had obtained a library providing
sum_ref but you wanted to code in a more natural (in F#) functional style it is easy to “wrap”
sum_ref to give for example the same interface as
nag_curried.
// mysum declaration and use > let mysum a b = let r = ref 0 sum_ref(a,b,r) !r ;; val mysum : int -> int -> int > let c5=mysum(mysum 1 1) (mysum 2 2);; val c5 : int = 6
Having looked at the toy “sum” example, we'll move on to look at some real examples from the NAG Library for .NET.
NAG Library for .NET
Firstly some details to reference the NAG Library. The
#r syntax is only used for the interactive interpreter. For the F# compiler, command-line arguments or the usual Visual Studio reference settings are used instead. Also “open” the System and NagLibrary namespaces to avoid having to use fully qualified names on each method call.
// NAG Library reference for fsi > #if INTERACTIVE #I @"c:\Program Files\NAG\NAG Library for .NET" #r "NagLibrary32.dll" #endif open System open NagLibrary --> Added 'c:\Program Files\NAG\NAG Library for .NET' to library include path --> Referenced 'c:\Program Files\NAG\NAG Library for .NET\NagLibrary32.dll'
A00: Licence Check Example
First call the simplest function in the library, that just returns true if a valid NAG licence is detected.
// a00ac example > printfn "Have a NAG licence: %b" (A00.a00ac()) Have a NAG licence: true val it : unit = ()
While this is a very simple example, it shows many of the advantages of the functional style and the top level interactive loop. Similar to MATLAB, the F# interface allows access to the NAG library functionality with the absolute minimum of additional syntax or programming steps. No main program, no explicit variable declarations, no explicit compilation steps etc.
D01: Quadrature Example
Next we take a slightly more complicated example from the Quadrature chapter. The method integrates the supplied function between the specified bounds, returning extra information about the number of iterations and accuracy. While it is straightforward to call this method, the values returned by byref parameters, and the need to explicitly cast the function to be integrated to the delegate type mean that the style resembles sum_byref above rather than the more idiomatically functional sum_curried.
Just as an example, two styles of setting up the parameters by reference are used. The classic ML style of defining values of reference type, which are dereferenced using
!, and an alternative syntax (for
npts) using an explicitly mutable variable which acts more like variables in imperative languages, in which the dereferencing is automatic.
// d01ah example: direct call > let if1 = ref 0 let mutable npts=0 let relerr= ref 0.0 let f x = Math.Sin(x:double) let nlimit=1000 let ff= D01.D01AH_F(f) let result1 = D01.d01ah( 0.0,Math.PI,0.01,&npts,relerr,ff,nlimit, if1);; val mutable npts : int = 7 val relerr : float ref = {contents = 0.0006944567037;} val f : float -> float val nlimit : int = 1000 val ff : D01.D01AH_F val result1 : float = 2.0 > !if1;; val it : int = 0 > npts;; val it : int = 7 > !relerr; val it : float = 0.0006944567037
F# has some facilities to automatically present output parameters in a more functional style. If parameters passed by reference appear at the end of the .NET signature of a method, F# provides an alternative signature where the reference parameters may be omitted from the method call, and the returned results are provided as a list of values. F# will also implicitly apply a delegate constructor if the method is passed a compatible anonymous function (lambda expression), even though it will not automatically cast a variable bound to a function to the appropriate delegate type.
In this case, we may omit the final
ifail parameter, whose value (0) is returned as the second item in the returned sequence rather than being captured by a reference parameter (
ifl in the above example). However the position of the input parameter
nlimit prevents this automatic system being used to avoid using explicit references for
npts. Also rather than passing the variable
ff, of type
D01.D01AH_FC an anonymous function is used.
// d01ah example: returning a tuple > let (result2,if2) = D01.d01ah( 0.0,Math.PI,0.01,&npts, relerr,(fun x -> f x),nlimit);; val result2 : float = 2.0 val if2 : int = 0 > npts;; val it : int = 7 > !relerr;; val it : float = 0.0006944567037
As with the mysum example above, if this method is to be called often, a more naturally functional interface may be prefered.
The exact choice of interface depends a lot on personal requirements, but also personal aesthetic judgments. In the example below I've used a curried form for the input parameters, and a record type to capture the output fields, but for other uses one may use a tuple form for input and capture the results as a tuple (or by the use of out parameters).
// declaration of myd01ah: curried, returning a record > type d01ahresults = {result: float ; npts: int ; relerr: float; ifail: int} > let myd01ah f interval epsr nlimit = let ff=D01.D01AH_F(f) let (a,b) = interval let npts = ref 0 let relerr = ref 0.0 let ifl = ref 0 let result = D01.d01ah(a,b,epsr,npts,relerr,ff,nlimit,ifl) {result= result; npts= !npts;relerr= !relerr;ifail= !ifl} ;; val myd01ah : (float -> float) -> float * float -> float -> int -> d01ahresults
Having set up this method we may directly integrate Math.Sin over the specified interval without the need to define any subsidiary reference or delegate objects. So the entire d01ah example program collapses into one line.
// using myd01ah > myd01ah Math.Sin (0.0,Math.PI) 0.01 1000 ;; val it : d01ahresults = {result = 2.0; npts = 7; relerr = 0.0006944567037; ifail = 0;}
E04: Optimization Example
Finally, a more complicated example from the optimization chapter. The callback function that must be supplied has reference parameters, and again there are several reference parameters for the top level method.
The style used here is similar to that used for the D01 example, a curried form for input parameters, and a record type to capture the results. In addition pairs of float parameters in the original interface have been combined into a single input parameter and a single result field, denoting intervals.
// declaration of mye04ab: curried, returning a record > type e04abresults = { minimum: float ; x: float; bounds: (float*float); iter: int; ifail: int } > let mye04ab f interv e1 e2 mc = let a,b = interv let ra = ref a let rb = ref b let fx = ref 0.0 let x = ref 0.0 let mcr = ref mc let ifr = ref 0 E04.e04ab((fun x res -> res <- f x), ref e1, ref e2, ra, rb, mcr ,x, fx ,ifr) {minimum = !fx; x = !x;bounds = (!ra,!rb); iter= !mcr; ifail = !ifr} ;; val mye04ab : (float -> float) -> float * float -> float -> float -> int -> e04abresults
Again, once this method is defined, the minimization method can be called directly without having to set up any reference variables or delegates.
// using mye04ab > mye04ab (fun x -> (Math.Sin x) / x) (3.0,5.0) 0.0 0.0 30 ;; val it : e04abresults = {minimum = -0.2172336282; x = 4.493409455; bounds = (4.493409397, 4.493409513); iter = 10; ifail = 0;}
Printed Output
The methods in the NAG Library for .NET typically return results via reference parameters (or return values of functions) however text can be directed to an output stream in the following situations:
- Certain input errors are detected in the .NET interface and an exception of type
NagExceptionis raised. For console applications, this will cause an error message to be displayed on the console. Other applications can catch this exception and handle it using standard .NET techniques.
- The majority of errors and warnings raised by the library, will not throw a .NET exception. Instead the method will return with a non zero
ifailvalue. A message will have been sent to the standard output stream in that case. By default the message will appear on the console in console applications. Other applications may use the
System.Console.Redirectmethod to redirect these messages to a different text stream.
- Certain methods in the library have facilities to display monitoring information. In some cases this monitoring is controlled by a user supplied monitoring function. The C# example programs provided with the library use monitoring callback methods that use
Console.WriteLinehowever the user supplied method may direct the monitoring information to any suitable destination, for example a TextBox in a windows form application. In other cases, monitoring is controlled by integer or boolean flags to enable the monitoring, in this case, in the current release,
Console.WriteLineis always used, however the final destination stream may be controlled as described above for warnings.
The next two examples use a windows form application (derived from a copy of the sample form in the F# sample distribution from Microsoft).
Monitoring Function (e04cb example)
e04cb is an example of a method that takes a user supplied method to monitor the progress of the iteration. We define a small F# wrapper as before (although this time returning a tuple of values rather than a record of a named record type).
// declaration of mye04cb let mye04cb n x tolf tolx func monit maxcal = let ffunc = new E04.E04CB_FUNCT( fun n xc (res:byref<float>) -> res <- func xc) let fmonit = new E04.E04CB_MONIT(monit) let ifl = ref 0 let rf = ref 0.0 E04.e04cb(n,x,rf,tolx,tolf,ffunc,fmonit,maxcal,ifl) (x,!rf)
We then define the function to be minimised, and the initial bounds on the variable.
// object function for e04cb example let mutable e04cbf = fun (xc: float[]) -> Math.Exp(xc.[0]) * (4.00e0 * xc.[0] * (xc.[0] + xc.[1]) + 2.00e0 * xc.[1] * (xc.[1] + 1.00e0) + 1.00e0);
// e04cb example bounds let mutable e04cbx = [|-1.0;1.0|]
In this example we will use a simplified monitoring function that only prints the number of iterations. As we are using a windows form application we don't want to write to the console. the form has a TextBox declared (
textB) and we want the monitoring function to update the text property of that box:
// e04cb monit function let e04cbmonitor fmin fmax sim n ncall se vr = textB.Text <- ( textB.Text + (sprintf " There have been %d function calls\n" ncall))
When the "Run Example 1" menu option is chosen, the
runexmpl1 method is executed:
// run the e04cb example let runexmpl1 () = textB.Text <- "monitor\n" textB2.Text <- sprintf "The final function value is ...\n" let (interv,vl) = mye04cb 2 e04cbx (Math.Sqrt(X02.x02aj())) (Math.Sqrt(Math.Sqrt(X02.x02aj()))) e04cbf e04cbmonitor 100 textB2.Text <- ( textB2.Text + (sprintf " %f \n" vl))
As can be seen, this just initializes the text in the two text boxes, calls
mye04cb and then finally retrieves the reference to the minimum value and updates the results text box. the monitoring text box will have been updated during the progress of the iteration by
e04cbmonitor
If the form is executed by the F# interpreter (fsi command line or the F# interactive window in Visual Studio) then we can make use of the above mutable definitions to change the function to be minimized without restarting the form application. Entering (for example):
// Update e04cb object function e04cbf <- fun (xc: float[]) -> 1.0;;
At the interactive prompt will cause the variable
e04cbf to be updated (to represent the constant function
1) re-selecting the “Run e04cb example” menu option will cause e04cb to be re-executed using this object function (finding the minimum value of 1). Future versions of F# may expose the interpreter as an eval function (as in lisp and some other functional languages) which would avoid the need to maintain an open interpreter window, however use of the interpreter in this way is still quite a powerful way of interacting with the system,
Internal Monitoring (e04xa example)
Some methods in the library do not take a user supplied monitoring function, but instead handle the monitoring internally, often controlled by an integer parameter (or optional parameter) that controls verbosity of the output. In the current Beta 2 interface such monitoring is always handled by the standard
System.Console.WriteLine method. Future releases of the NAG Library for .NET will hopefully provide a more convenient interface, however this monitoring is still usable, even if we are not building a console application. One technique is to redirect the Console method output to an internal stream, and then convert the stream to a string, for example to update a text box. We take
e04xa as a simple example of such a function.
// declaration of mye04xa let mye04xa mlevel n epsrf x mode objfun hforw = let objf = ref 0.0 let objgrd :float array = Array.zeroCreate n let hcntrl :float array = Array.zeroCreate n let h :float [,] = Array2D.zeroCreate n n let info : int array = Array.zeroCreate n let mref = ref mode let objfref = ref 0.0 let warnref = ref 0 let ifailref = ref 0 let objfund = E04.E04XA_OBJFUN( fun (a:byref<int>) b c (d:byref<float>) e f -> d <- objfun a b c d e f ) E04.e04xa (mlevel,n,epsrf,x,mref,objfund,hforw,objfref,objgrd, hcntrl,h,warnref,info,ifailref) (!objfref,objgrd,hcntrl,h,!warnref)
// e04xa object function let e04xaobjfun int n (x: float array) objf objgrd nstate = let a = x.[0] + 10.0*x.[1] let b = x.[2] - x.[3] let c = x.[1] - 2.0*x.[2] let d = x.[0] - x.[3] a*a + 5.0*b*b + c*c*c*c + 10.0*d*d*d*d
This time when the “Run e04xa” menu option is chosen, the following method is executed
// run the e04xa example let runexmpl2 () = textB.Text <- "monitor\n" textB2.Text <- sprintf "The final function value is ...\n" let oldOut = Console.Out let strWriter = new IO.StringWriter() Console.SetOut(strWriter); let (objf,z1,z2,z3,z4)= mye04xa (*mlevel*) 10 (*n*) 4 (*epsrf*) 0.0 (*x*) [|3.0;-1.0;0.0;1.0|] (*mode*) 0 (*objfun*) e04xaobjfun (*hforw*) [|-1.0;-1.0;-1.0;-1.0|] Console.SetOut(oldOut) textB.Text <- strWriter.ToString() textB2.Text <- ( textB2.Text + (sprintf " %f \n" objf))
Here the monitoring information is captured in
strWriter, and then (after the execution of
e04xa has finished) The string value of this buffer is used to update the text box. As noted above, we hope to provide a more direct interface to this monitoring information in later releases.
F# Files
nagfsharp1.fsx: F# file including all the Console Application code shown above.
nagfsharp2.fsx: F# file including the full code for a windows form application, with a drop down menu giving the option to run two example programs with monitoring enabled. This is essentially the “Hello World” Form Example from the F# sample distribution from Microsoft, extended with the code to run NAG examples, as shown in the previous section.
nagfsharp3.fsx: An additional example, from Sorin Seban, giving the e04cb example program as F# code.
Conclusions
This article has give examples showing how to call the NAG Library for .NET from the interactive top level loop of F#, and in particular how writing small functions around the supplied methods can result in greatly simplified calling conventions.
It has been asked whether it would be possible for the supplied .NET methods to be more F#-like. It would be possible for example to place all
out or
ref parameters at the end of the method parameter list, however this wouldn't always lead to the most natural interface in C# or VB.NET, and F# users would perhaps still want to make similar wrappers to avoid the need to explicitly declare delegates, or to use named record types for output, or curried forms for input as in the examples above.
Learn more about the NAG Library for .NET