You are here

How to Use Mathematica from ROOT?

Instructions for ROOT

It is possible to invoke functions from libraries in an interactive Root session. However, because the Mathematica libraries have not been compiled with the compiler option Position Independent Code, it is not possible to call these routines from a shared library. One must build a main program or libraries with explicit references to the list of functions that one intend to call from the interpreter. The instructions below are for Mathematica version 11.2.

Create files defining the C++ functions usable from ROOT

The file MathematicaFunctions.h below must include the list of prototypes for the functions to be called. In this example, the function callMathematicaGamma(x) is declared. Add as many such lines than you have functions.

MathematicaFunctions.h

// MathematicaFunctions.h
#ifndef MathematicaFunctions_H
#define MathematicaFunctions_H

int startMathematica();
void stopMathematica();

double callMathematicaGamma(double x);

#endif // MathematicaFunctions_H

We also define the functions startMathematica() and stopMathematica() which are needed in order to avoid the time-consuming restarting of the Mathematica engine each time the function is evaluated.

MathematicaFunctions.cxx

#include "/afs/cern.ch/project/parc/math112/SystemFiles/Links/MathLink/DeveloperKit/Linux/CompilerAdditions/mathlink.h" 
#include "MathematicaMacros.h"
#include <string>
#include <iostream>

MLINK lp; 
MLEnvironment env; 

int startMathematica() {

  env = MLInitialize(NULL); 
  if (env == NULL) return 1; 
  int argc = 4; 
  char *argv[5] = {static_cast<char*>("-linkname"),
                   static_cast<char*>("/afs/cern.ch/project/parc/math112/Executables/math -mathlink"),
                   static_cast<char*>("-linkmode"),
                   static_cast<char*>("launch"), NULL};
  lp = MLOpen(argc, argv); 
  if (lp == NULL) return 1; 
  std::cout << "Started Mathematica Engine..." << std::endl;
  return 0;

}


void stopMathematica() {
  MLClose(lp); 
  MLDeinitialize(env); 
}


double callMathematicaGamma(double x) {

  double result;

  MLPutFunction(lp, "Gamma", 1);
  MLPutDouble(lp, x);
  MLEndPacket(lp);

  while (MLNextPacket(lp) != RETURNPKT) MLNewPacket(lp); 

  MLGetDouble(lp, &result); 
  return result;

}

Generate the MathematicaMacros.h file

The file MathematicaMacros.h can be downloaded here. It contains the macro definitions needed for Mathematica. If you Then you need to generate for your platform a file, MathematicaMacro.h in the following way:

touch MathematicaMacros.h
/afs/cern.ch/project/parc/math112/SystemFiles/Links/MathLink/DeveloperKit/Linux/CompilerAdditions/mprep \
-prototypes MathematicaMacros.h > MathematicaMacros.h

Then you might add ifdefs protecting against multiple inclusion and commenting out the mathlink.h include because it might confuse rootcint. In principle, you could run the preprocessor on the file referencing the Mathematica library. However, this is not a good practice for several reasons. One is that your file gets heavily modified so you will need to always keep a copy without the macro definitions and preprocess the file after every change. Two, if you have several files referencing the Mathematica library you will end up with multiple definitions of the same macro. So, it is better to preprocess an empty file once for all and include it when needed.

The file MathematicaLinkDef.h below includes the directives for rootcint and it is needed for ROOT 5 but not for ROOT 6. It declares the list of functions callable from the CINT interpreter.

//MathematicaLinkDef.h
#ifdef __CINT__

#pragma link C++ function startMathematica();
#pragma link C++ function callMathematicaGamma(double );
#pragma link C++ function stopMathematica();

#endif

We are now ready to generate the dictionary and interface function for the interpreter (here called Mathematica.cxx). Execute the following shell script command:

rootcint -f Mathematica.cxx -c MathematicaFunctions.h MathematicaLinkDef.h

Make your own main program

As an example of main program, you can copy the standard Root main program and add to it the references to the Mathematica functions as illustrated in the example below,

rootMathematica.cxx

//rootMathematica.cxx

///////////////////////////////////////////////////////////////////////////
//                                                                       //
// RMain                                                                 //
//                                                                       //
// Main program used to create RINT application with Mathematica support //
//                                                                       //
///////////////////////////////////////////////////////////////////////////

#include "TRint.h"
#include "MathematicaFunctions.h"

//_________________________________________________________________________
int main(int argc, char **argv)
{

  if (0) {
    // dummy block to force the Mathematica functions to be linked by C++
    callMathematicaGamma(1.0);
  }

   // Create an interactive ROOT application
   TRint *theApp = new TRint("Rint", &argc, argv);

   // and enter the event loop...
   theApp->Run();

   delete theApp;

   return 0;
}

Compile and link

Modify your Makefile to include the files above and reference the libraries. Below is an example valid on Linux with the g++ compiler. Examples of linking a Root application are given for your platform in ${ROOTSYS}/test/Makefile. This example references the Mathematica software on the CERN afs cell. Please update this reference to your own installation of Mathematica.

g++ -I $ROOTSYS/include \   
-I/afs/cern.ch/project/parc/math112/SystemFiles/Links/MathLink/DeveloperKit/Linux/CompilerAdditions/ \   
rootMathematica.cxx MathematicaFunctions.cxx \  
/afs/cern.ch/project/parc/math112/SystemFiles/Links/MathLink/DeveloperKit/Linux/CompilerAdditions/libML64i4.a\  
-o rootMathematica `root-config --glibs` -lrt

As example here is a Makefile for building rootMathematica

Makefile

ROOTDIR = ${ROOTSYS}/include
CADDSDIR = /afs/cern.ch/project/parc/math112/SystemFiles/Links/MathLink/DeveloperKit/Linux-x86-64/CompilerAdditions
EXTRA_CFLAGS= -I`root-config --cflags --libs` 

INCDIR = ${CADDSDIR}
LIBDIR = ${CADDSDIR}

rootMathematica : rootMathematica.cxx MathematicaFunctions.cxx
    # ${CXX} ${EXTRA_CFLAGS} -I ${ROOTDIR} -I ${INCDIR} rootMathematica.cxx  MathematicaFunctions.cxx ${LIBDIR}/libML64i4.a -lm -lpthr
ead -lrt -ldl -luuid `root-config --glibs` -o $@
    ${CXX} ${EXTRA_CFLAGS} -I ${ROOTDIR} -I ${INCDIR} rootMathematica.cxx  MathematicaFunctions.cxx ${LIBDIR}/libML64i4.a -lm -lpthrea
d -lrt -ldl -luuid `root-config --glibs` -o $@
    # ${CXX} -I ${ROOTDIR} -I ${INCDIR} rootMathematica.cxx  MathematicaFunctions.cxx ${LIBDIR}/libML64i4.a -lm -lpthread -lrt -ldl -l
uuid `root-config --glibs` -o $@

Running rootMathematica

This command invokes the C++ compiler and creates an executable module called rootMathematica. Your path to Mathematica may vary depending on your system. We are now ready to execute this interactive module. The example below shows a few commands typed in an interactive session. The first line (loading of the header MathematicaFunctions.h) is needed only for ROOT 6 to make the functions available in the interpreter since we don't have in this case a dictionary.

   root [0] .L MathematicaFunctions.h
   root [1] startMathematica()       
   Started Mathematica Engine...
   (int)0
   root [2] callMathematicaGamma(5.0)
   (double)2.40000000000000000e+01
   root [3] callMathematicaGamma(5.45)
   (double)4.83037558000228415e+01
   root [4] stopMathematica()        
   root [5] .q

WARNING! If you use Mathematica this way, normally the Mathematica process will be shut down anyway when you quit ROOT. However, if you use Mathematica from a separate wrapper or shared library, make sure that you stop Mathematica at the end of your application as Mathematica licences might be limited (as is the case at CERN) and restarting ROOT might create each time a new process eating up the licences!