NML -- The ultimate Lambda for Scientific Programming
 
 
NML was originally created in late 1999 and has evolved with constant use over the past 7 years. Its source code is freely available and amenable to extension. It is a vectorized math language akin to MatLab and RSI/IDL or PVWave. But unlike those other languages, NML is terse, faster, and more convenient to use.
 
NML derives its power from the adaptation of modern functional programming language concepts. It is written primarily in OCaml with some C and C++ support -- what we call the ``glue routines’’. Its syntax is nearly identical to that of OCaml, which makes it easy to develop hybrid programs written in both OCaml and NML.
 
But unlike OCaml, NML is dynamically typed -- much like Lisp or Scheme. As such, it is an ``unsafe’’ language in that it is possible to construct incorrect programs. OCaml is safe in the sense that its strong compile-time typing prevents the writer from producing incorrectly typed programs. Program logic could still be incorrect, but whatever you write will perform as indicated. With NML this is not true, and you will be able to generate runtime errors -- such as attempting to multiply a string by a matrix -- total nonsense.
 
NML was developed out of years of frustration with the conventional ``Fortran-like” languages. While MatLab and IDL/PVWave are sometimes convenient vectorized math languages, they confuse too many issues from second generation languages with the modern parallel-programming paradigm. As an example, the code in those other languages is typically peppered with array bounds checking code -- tons of IF-THEN code blocks that become severe distractions toward getting the job done.
 
One of the biggest breakthroughs in NML is the use of cyclic array addressing. There are never any bounds violations when accessing arrays. If an index runs off the end of an array, it wraps around to the other end. So arr.[-1] refers to the last element of array arr.
 
Why is this so important? Well for one, it dispels the need for array bounds checking. Secondly, this notion of cyclic array indexing fits naturally with Fourier analysis by way of FFT’s. We live in a toroidal universe with FFT’s and so why not have all of our computational elements conform to that view as well?
 
The other enormous breakthrough with NML -- a breakthrough in the world of scientific programming at least -- is the adoption of functional programming paradigms. Recursion is a natural programming style. Nested functions and anonymous lambda expressions are convenient and easy to use. NML is a language of functional closures.
 
Part and parcel of the functional programming paradigm is the use of immutable variables. Unlike conventional languages, an assignment in NML such as ``let x = 15’’ establishes an immutable binding for the variable named x. This variable will forever hold the value 15 and can never be changed.
 
While immutability of variables seems like an odd attribute at first, it becomes an enormously useful notion once you become accustomed to it. It becomes possible to reason algebraically about the program and what it is expected to accomplish.
 
This weblog is an attempt to explain these radical views of scientific programming, and at the same time, offer an explanation for how to construct such a language. We will cover all the aspects of compiling human readable code into machine executable form. So this blog will be of interest to anyone curious about writing compilers as well as for scientists and engineers desirous of a really good language for numerical programming.
 
What does ``NML’’ stand for? I really never decided what it means. Not ML? Numerical ML? etc.... it just became an easy way to refer to this language.
 
NML began as a distant dream more than 20 years ago. I gave many heroic attempts toward creating such a thing, only to be constantly thwarted by the inevitable complexity of the code. In C or C++ it would represent more than 100,000 lines of code. In C or C++ such a beast would require constant code fixing and bug tracking. It becomes an almost impossible task.
 
But in 1999 I discovered the world of functional programming with SML and OCaml, and my idea took off like greased lightning. In less than 2 months, I had an initial prototype of the language up and running, and solving problems that IDL/PVWave was choking on -- large 190+ variable optimization problems in attempting to derive the Zernike coefficients for imperfect optical trains derived from laboratory observation of point sources.
 
NML represents approximately 35,000 lines of OCaml code plus about 12,000 lines of C and C++ glue routines -- including a very nice publication-quality graphics package for displaying the results of numerical computations.
 
NML has grown organically over these past 7 years, but very little time has been devoted toward debugging the code. Because the core NML is written in OCaml, it generally functions flawlessly once it compiles. The vast majority of debugging effort has been spent on the C and C++ glue routines, and so we try to avoid these low level languages as much as possible. There are some occasions in which one must resort to low level programming, but they are rare, and can generally be dispatched with a minimum of code.
 
We tried to adhere closely to the syntax and lexical conventions of OCaml. But there are some extensions and deviations. And most importantly, there is no compile-time type checking. A good place to begin is a review of the OCaml language, which we leave as an exercise for the reader. You can find out all about OCaml at caml.inria.fr
 
And to pique your interest, here is a teaser of code to display the Sinc function:
 
let x = [0, 0.1, .. 10] in
let y = sin x / x in
  plot(x, y, thick: 2, title: “Sinc(x)”)
 
 
Alternatively, we could have made use of the adaptive-gridding functional plotting routine fplot:
 
fplot([0.001,10], fun x -> sin x / x, title: “Sinc(x)”,
    thick: 2, color: orange)
 
 
 
 
Saturday, February 3, 2007
What is NML?