We like to make our libraries easily accessible from other languages and environments other than Fortran and C, for example Excel in VB or Matlab through our toolbox. It allows users to quickly and simply access Library functionality without the hassle of making and compiling a C or Fortran program. Environments like Matlab or Octave are particularly interesting as we can combine their strong codebase and powerful visualisation tools with our libraries (we provide technical reports on how to use the NAG Libraries from Scilab and Octave).
A Few days ago, I discovered Freemat, which is another prototyping tool inspired by Matlab and IDL. As Octave or SciLab, Freemat is an open source program which supports Matlab scripting, Mex interfaces and more. But the particularly interesting feature it has is their import function. It allows users to dynamically load a shared library into Freemat and use it directly, without having to write interface script or C code (as in Matlab, Scilab or Octave). I then decided to try to call our Fortran Library from here, and I will describe here how I did it and the results.
When we try to interface our Library with something else, we start easy. I usually start with a00aaf because it's the simplest we have: no arguments, no return value. It only prints the Library description to stdout. By looking at the import doc of Freemat, I can see that the call is really simple, I just need to make two lists of types, one for the arguments and one for the return value:
Saved it in load_fll3a22dfl.m and I can test it.
--> source load_fll3a22df.m
As expected I don't get any result. But disappointingly I don't see my library information anywhere. That is because a00aaf prints it to stdout, not in the freemat window. By looking my calling shell, I can see it.
[nicolas@stretton:~]$ freemat *** Start of NAG Library implementation details *** Implementation title: Linux/gfortran 32-bit Precision: FORTRAN double precision Product Code: FLL3A22DFL Mark: 22.0 (self-contained) *** End of NAG Library implementation details ***
The S chapter: Bessel functions
a00aaf is nice, but not really useful. My next step when calling the library is always the S chapter and especially s17acf. It takes two arguments and returns a double number. That is the perfect candidate for my next test.
import(lib,'s17acf_','s17acf','double','double &x, int32 &ifail');
The important thing to remember when calling a Fortran library is that all argument are passed by references. That means we have to give pointers from Freemat even if the values are declared as
INTENT(IN), hence the
&before x and ifail.
Doing the same for the other Bessel functions gives a nice graph.
The E02 chapter: Curve fitting functions
For this example, I adapted the curve fitting demo from our Nag Toolbox for Matlab.
The routines I'm using here are e02bef and e02bbf. Why these? Because e02bef takes a character as its first argument, and passing character arrays are always tricky.
e02bef takes 15 arguments when called from Fortran, but a 16th argument is hidden from the user when doing this: the size of the character string. If this last argument isn't specified, it causes a bad segmentation fault. The proper imports are
import(lib,'e02bbf_','e02bb','void',' int32 &ncap7, double &lamda, double &c, double &x, double &s, int32 &ifail');
import(lib,'e02bef_','e02be','void',' string start, int32 &m, double &x, double &y, double &w, double &s, int32 &nest, int32 &n, double &lamda, double &c, double &fp, double &wrk, int32 &lwrk, int32 &iwrk, int32 &ifail, int32 &start_Len');
The rest is pretty straight forward and the demo works after some modifications.
Unfortunately, I couldn't import routines expecting a user callback. It doesn't seem to be support for passing pointers to Freemat user defined functions to the routines in the library, but I might be wrong. Freemat limits the import function to void problems of badly allocated memory for example, and keeping a clean interface while allowing callbacks like we would like to have is not easy to do.
Another limitation in our scenario, is getting the routines output inside of Freemat. They are pretty smart and have something already to do it, by exporting a special function in our library. But in our case where we want to use the library without additional modifications/code, it's not working. If you want to experiment with that, it's described in the import function documentation.
Again, my experience with Freemat is limited and I haven't yet explored all their code yet. If any experienced user of Freemat have solution or suggestions to these points, feel free to post them here.
I have to say that I was really impressed when trying that the first time. When I read the doc I thought "Well, that can't be that easy", but in fact it was. I quickly made a script to generate imports from almost all of our routines (except the ones taking callbacks) and make them work. This approach is really interesting, compared to generating mex files and get them to work, as we avoid the hassle of converting types or copying data.
Here is the file containing the imports for ~1560 routines I generated for FLL3A32DFL. You can use it to try the library from a friendly environment. With slight modifications, you should be able to use this file for every version of the FL22, but if you have trouble doing it, I can certainly help you. I haven't tested them all, but it should work. Be aware that if one the import is wrong, it will crash Freemat. If you test it, it would be nice to have some feedback on errors or usage example. If you manage to do anything with it, share it in the comments! Is anyone interested in having the routines callbacks as well?
Here are some links to things mentioned in this post
- Documentation of the library used for these examples
- Freemat's homepage
- Documentation of the external interface of Freemat