Calculating the normal CDF in AMPL with shared libraries

UPDATE: AMPL has since added support for the GNU Scientific Library which includes an error function, as discussed here.

AMPL does not have a built in function for the normal cdf (error function) — see the post from Robert Fourer on the Google Groups page for AMPL (a great resource). To use the function in a model, you need to use a shared C library that can do the computation. I got it working (on my Mac) using the following process.

The AMPL site has a page on this topic. It turns out you need to find the folder …/ampl/solvers/ on your system. I couldn’t find it for my version of AMPL (perhaps because I have a version that comes packaged with the Knitro solver). But netlib.org hosts a copy of the folder. They say you can get a copy of the whole thing by emailing them, but this didn’t work quickly for me, so I used wget to download the whole thing, as described here, with the following command:

wget -r -np -nH –cut-dirs=3 -R index.html http://www.netlib.org/ampl/solvers

The goal is to compile the file …/ampl/solvers/funclink/funcadd.c into the library amplfunc.dlll. (This funcadd.c doesn’t include the error function, but that’s the easy part once you get this working…) I tried to compile with the following commands (which require compilers — you can get these on a Mac by downloading Xcode):

cd .../ampl/solvers/funclink
make -f makefile.macosx

This threw me an error that there was no stdio1.h. I tried renaming …/ampl/solvers/stdio1.h0 to …/ampl/solvers/stdio1.h and that seemed to resolve the issue. I was able to successfully run

ampl silly.x >silly.out 2>silly.2

as described in the funclink README. But we still don’t have error function code itself. To get it, downloaded Robert Vanderbei’s code for his version of funcadd.c, which includes a function myerf(). I replaced the file …/ampl/solvers/funclink/funcadd.c from netlib.org with Vanderbei’s version and tried to recompile using the make command above. Turns out I also needed to download Vanderbei’s file myalloc.h, which I placed in …/ampl/solvers/funclink/, and the compiler couldn’t initially find OS X’s built-in malloc.h, so I changed the following line in myalloc.h:

#include <malloc.h>

to

#include </usr/include/sys/malloc.h>

This worked, and regenerated the file amplfunc.dlll, though it threw a bunch of warnings in the process. I copied this file into the directory where I wanted to run the AMPL model from (AMPL automatically looks for such a file in the directory where it is launched). Upon launching AMPL interactively, I typed

function myerf;

to import the function, then

display myerf(1.96);

and I got the output:

myerf(1.96) = 0.975002
About these ads

12 thoughts on “Calculating the normal CDF in AMPL with shared libraries

  1. hello , your blog is really helpful to me , but I cannot get access to the ampl folder somehow , would you send me a copy if you don’t mind ? Thanks very much . My email address is kingzth@126.com .

  2. hello again… I have got the folder from the website , but compiling it in VC6.0 I got lots of errors, don’t know if it’s because of the compiler . Do you have some suggestions?

    • Hi Tianhang,

      I’m not sure what the issue would be, but I can tell you that it took quite a bit of trial-and-error to get the library to compile on my Mac. I also tried to get it working on a PC and never succeeded. What OS are you using?

      Thanks for reading,

      Ben

      • It’s so nice to here from you~ I’m still using winXP. BTW, what do you mean by never succeeded…? That doesn’t sound good to me …

      • I use a Mac for most things, and I got the erf working on there successfully (OS 10.7). But I later tried to compile it on Windows 7 for someone else to use, and I couldn’t get it to work. Seems like it should be possible, but I don’t use Windows much, so I wasn’t able to debug very well.

  3. Well then. The problems I encountered with compiling in winXP are some syntax errors , all “cannot convert from ‘const char *’ to ‘char *’” stuffs , and that’s why I’m confused. I wonder if you got the same in windows7. I’ll try again and let you know if I finally work it out.

  4. hello ben, I’ve corrected some errors in the code and I finally get a funadd.dll. But the software pop out a error saying ” can’t invoke unavailable function myerf” as I input the “display myerf(1.96) ” command. I have put the .dll file in the AMPL folder and don’t know if there’s any procedure I missed , do you have any idea of that ?

    • Hi Tianhang,

      I think the file has to be in the working directory where you’re running AMPL, rather than the AMPL folder. So in terminal, cd to the folder where your funadd.dll file is, and launch AMPL from there. Also, make sure you declare the function in AMPL by including the line “function myerf;” near the beginning of your AMPL script, or typing it interactively before invoking the function. Let me know if this helps at all.

      Ben

      • Hello Ben:
        I followed the suggestions below and succeeded, and then I notice you compile the code to amplfunc.dll directly, I think that is it. This is really nice to have it run properly and having you helping all along, thanks very much Ben~

    • AMPL automatically loads ampltabl.dll and amplfunc.dll. Since your library is named differently (funadd.dll) it is not loaded thus the error. You can either rename your library to amplfunc.dll or use the command “load path/to/funadd.dll;” to load it manually. See http://www.ampl.com/NEW/libload.html for more details.

      • Thanks bro, your suggestion is really straight to the point. It’s working alright, thanks very much~

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s