Back: Programming
Previous: Compiling functions, timing

Programming in Mathematica

MathLink -- calling Mathematica from C, and vice versa

Calling Mathematica from C; compiling and executing

If a C program makes use of special MathLink functions, and is compiled with mcc instead of cc, it can send expressions to the Mathematica kernel and handle the returned expression. For example, to make use of the extended precision arithmetic of Mathematica to factor large integers, the following C program accepts an arbitrarily long integer, passes it to Mathematica as a character string, gets the factored pieces back (also as character strings) and prints them. Compile this C program (call the file "fac.c") with mcc, and then run with the -linkname option.

		mcc fac.c
		a.out -linkname 'math -mathlink'



Example of C program using MathLink:

#include 
#include 
#include 
#include "mathlink.h"

void error();
static int   read_and_print_expression();
static int   read_and_print_atom();
static int   read_and_print_function();

int main(argc, argv)
        int argc; char* argv[];
{
        char    buf[BUFSIZ];
        MLINK   lp;

        printf( "\n\nInteger to factor:  ");
        scanf( "%s", buf);

        lp = MLOpen( argc, argv);
                if(lp == NULL) return 1;

        /* Send FactorInteger[n]. */
        MLPutFunction( lp, "FactorInteger", 1L);
          MLPutNext( lp, MLTKINT);
          MLPutSize( lp, strlen(buf));
          MLPutData( lp, buf, strlen(buf));
        MLEndPacket( lp);
        /* skip any packets before the first ReturnPacket */
        while(  MLNextPacket( lp) != RETURNPKT ) {
            MLNewPacket( lp);
            if( MLError( lp)) error( lp); }

        read_and_print_expression( lp);
        printf( "\n");
MLPutFunction(lp, "Exit", 0L);
MLClose( lp);
return 0;
}


static int   read_and_print_expression( lp)
MLINK lp;
{
        int tag;

        switch (tag = MLGetNext( lp)) {
        case MLTKSYM:
        case MLTKSTR:
        case MLTKINT:
        case MLTKREAL:
                return read_and_print_atom( lp, tag);
        case MLTKFUNC:
                return (read_and_print_function( lp));
        case MLTKERROR:
        default:
return 0; }
}


static int   read_and_print_atom( lp, tag)
MLINK lp;
int tag;
{
        long  len, gotlen;
        char buf[BUFSIZ];

        if (tag == MLTKSTR) putchar('"');
        while( MLBytesToGet( lp, &len) && len > 0 ) {
                if (len > BUFSIZ-1) len = BUFSIZ-1;
                if( MLGetData( lp, buf, len, &gotlen)){
                        buf[gotlen] = '\0';
                        printf("%s", buf);
                }
        }
        if (tag == MLTKSTR) putchar('"');
        putchar(' ');
return MLError(lp) == MLEOK;
}


static int  read_and_print_function( lp)
MLINK lp;
{
        long  len, i;
        static indent;

        if ( ! MLGetArgCount( lp, &len)) return 0;

        indent += 3;
        printf( "\n%*.*s", indent, indent, "");

        if( read_and_print_expression( lp) == 0) return 0;
        printf( "[");

        for( i = 1; i <= len; ++i) {
                if( read_and_print_expression( lp) == 0) return 0;
                if( i < len) printf( ", ");
        }
        printf( "]");
        indent -= 3;
return 1;
}

void error( lp) MLINK lp;
{
        if (MLError( lp)) {
               fprintf( stderr, "Error detected by MathLink: %s.\n",
                        MLErrorMessage( lp));
        }else{
               fprintf( stderr, "Error detected by this program.\n");
        }
        MLClose( lp);
exit( 1);
}


Calling a C routine from Mathematica; compiling and executing

Your C routine can be called from within a Mathematica session, but it must be given an accompanying template file (named with suffix .tm) to specify the interface. The C program and template are then compiled with mcc.

Then, during a Mathematica session, you install the external program with Install and use the function with the form specified in the template file.

C program (dayofweek.c)

...Includes <mathlink.h>, and calls MLMain(0,0);

 #include <mathlink.h>

 char *dayoweek(d,m,y)
 int d,m,y;
    {    int C,K,Z;
    m -= 2; if (m <= 0) { m += 12; y -= 1; }
    C = y/100;    K = y%100;
    Z = ((26*m - 2)/10 + d + K + K/4 + C/4 - 2*C) % 7 ;
    if (Z == 0) return("Sunday.");
    if (Z == 1) return("Monday.");
    if (Z == 2) return("Tuesday.");
    if (Z == 3) return("Wednesday.");
    if (Z == 4) return("Thursday.");
    if (Z == 5) return("Friday.");
    if (Z == 6) return("Saturday.");
    }

 int main() { return MLMain(0,0); }


Template file (dayofweek.tm)

specifies parameter/result types

  :Begin:
  :Function:       dayoweek
  :Pattern:        DayOfWeek[d_Integer, m_Integer, y_Integer]
  :Arguments:      { d, m, y }
  :ArgumentTypes:  { Integer, Integer, Integer }
  :ReturnType:     String
  :End:


Compile

      mcc  dayofweek.c  dayofweek.tm


Installing and using the function in Mathematica

link = Install["a.out"];
LinkPatterns[link]
DayOfWeek[ 1, 11, 1995 ]

	Wednesday.