05.06.07
ASDF system definition files for Fortran 77 codes
One of the Common Lisp packages that I find very useful is f2cl, originally written by Kevin A. Broughan and Diane M. K. Willcock [1], with recent contributions by Richard J. Fateman and Raymond Toy [2]. It can convert a lot of the Fortran 77 codes out there fairly reliably into quite fast Common Lisp code. The lack of a fancy home page or even a separate project (it is currently part of CLOCC) makes it somewhat hard to find, but should not be taken as a sign of abandon. A more prominent project that uses f2cl is the open source CAS system Maxima.
The advantages of using f2cl over a foreign function interface are, among other things, that the generated Common Lisp code has far better error handling, and is much more convenient to use (for a Common Lisp programmer, at least).
I think it would be nice to have ASDF system definitions for the Fortran 77 packages bundled with f2cl. This would complement the mk:defsystem definitions already available. A small difficulty is that the f2cl compiler has a lot of options, and it is desirable to want to set them globally, eventually overriding them on a file by file basis. At least, this is what is done in some of the .system files. I managed to convince ASDF to do this, but I am not sure if the way i did it is the best solution. From the point of view of OOP this can be (and will be) improved, of course. I’m referring more to the need of things like accessing ASDF symbols that are not exported. In any case, having global options that can be overriden on a component basis looks like a feature one would like to have every now and then.
A typical f2cl .system file looks like this (for example):
(mk:define-language :f2cl
:compiler #'f2cl:f2cl-compile
:source-extension "f")
(mk:defsystem minpack
:source-pathname "clocc:src;f2cl;packages;minpack"
:components
((:file "minpack"
:language :lisp)
(:module "minpack"
:source-pathname ""
:source-extension "f"
:package :minpack
:language :f2cl
:compiler-options (:include-comments t
:keep-lisp-file t
:relaxed-array-decls nil
:array-type :array
:array-slicing t
:package :minpack)
;; etc
Note that :file components can also have a :compiler-options, although I don’t know how the overriding behavior really is.
To convince ASDF to behave in a similar way, I subclassed the asdf:module class, adding an f2cl-options slot.
(defclass f2cl-module (module) ((f2cl-options :initform nil :initarg :f2cl-options :accessor f2cl-options)))
To have an f2cl source file type with corresponding compilation, one does
(defclass f77-source-file (cl-source-file) ((f2cl-options :initform nil :initarg :f2cl-options))) (defmethod source-file-type ((c f77-source-file) (s module)) "f") (defmethod perform ((o compile-op) (f f77-source-file)) (apply #'f2cl:f2cl-compile (cons (make-pathname :name (component-name f) :type "f" :defaults (component-pathname f)) (compiler-options f))))
But here is the catch. Compiler options have to be computed from the module *and* the file. I did it like this
(defmethod f2cl-options ((c f77-source-file))
(let* ((c-c-o (slot-value c 'f2cl-options))
(p-c-o (when (typep (parent c) 'f2cl-module)
(f2cl-options (parent c)))))
;; override global options.
(append c-c-o p-c-o)))
where
(defmethod parent ((c f77-source-file)) (slot-value c 'asdf::parent)) ;; Oops
Anyway, it works. Now I am wondering if I overlooked the apropriate feature in ASDF, or another way of doing this. Accessing ‘asdf::parent is good enough for me, but before attempting to contribute .asd files to f2cl, I would prefer to have a more solid solution.
11.05.06
Grid Restrained Nelder-Mead
The Nelder-Mead algorithm is a rather popular algorithm for (low dimensional) nonlinear programming. The original version (from 1965, see [1]) has known and varied failure modes, but never really had to fear for its popularity. It doesn’t need derivatives, which can be quite convenient, and has a reputation to work well even with noisy and rough functions.
Recently, a few provably convergent variants have been devised (see [2], [3], and [4]). The one by A. Bürmen et al [4], the “Grid Restrained Nelder-Mead Algorithm” (GRNMA) is notable because it does not impose a “sufficient descent” condition at each iteration, which makes it closer to the original algorithm.
A reliable, simple-to-use derivative free minimization routine is a handy little tool to have around. It turns out that implementing the GRNMA is also a pleasant programming project.
04.23.06
More on the alias method
It turns out that, as pointed out by Jens Axel Søgaard, the method I wrote about a few days ago is the alias method by Walker, as found in D. Knuth’s TAOCP, but with a modification by R. A. Kronmal and A. V. Peterson. Their contribution, it seems, was the algorithm to rearrange the intervals in O(N) operations.
In any case, there is a very good and complete textbook, nowadays available freely on the net, where all these things are explained, disected, and thoroughly overengineered in every good sense of the word. The book is “Non-Uniform Random Variate Generation”, by Luc Devroye (thanks to Brad Lucier for mailing me this great link).
Below you’ll find some additional notes about the method, prompted by reading part of the book, and a link to an updated version of the CL code. (For simplicity, I will write as if in the context of my first post).
04.20.06
Slime 2.0
A new version of slime has been released. See here, or download it directly as a gzipped tar archive or as a zip file.
04.17.06
The Alias Method
Some days ago, there was some discussion in #lisp about how to program a random variable with nontrivial probability distribution. That is, given values x1,…,xn, and probabilities p1,…,pn, how to write a function that randomly returns one of those values with the corresponding probability each time it is called.
It turns out this problem has a beautiful, simple, and efficient solution called the alias method (R. A. Kronmal and A. V. Peterson. On the alias method for generating random variables from a discrete distribution. The American Statistician, 33:214–218, 1979.), that requires only one call to the random number generator. While I haven’t read any complete explanation of it (only the one in R. A. Kronmal, A. V. Peterson, The alias and alias-rejection-mixture methods for generating random variables from probability distributions. Proc. 1979 Winter Simulation Conference (ed. H.J. Highland et al.) 269–280, 1979, which isn’t complete), I think it is highly unlikely that it is different from the method I describe below.
An Common Lisp implementation can be found here.