Thursday, April 21, 2011

Mathematica as a C code generator

Mathematica is able to generate C code ready to be compiled and ultimately capable to produce a stand alone executable file. Nice !. There are restrictions on the extent of what can be be processed in this way but it can be really useful in practice as it is right now.

The generation of the executable can be done within Mathematica or outside Mathematica. The Mathematica 8.0 help for my Linux Fedora 64bits requires a minor adjustment in order to work. For Linux systems:

"Libraries" -> "WolframRTL_Static_Minimal.lib"

must be replaced by

"Libraries" -> "WolframRTL_Static_Minimal"


(Thanks to Abdul Dakkak for helping on this)

How do we compile the generated code outside Mathematica? This issue is detailed next



  •  The Mathematica code that generates the C code for a simple example taken from the help is

code =
  CProgram[
   CInclude["stdio.h"],
   CInclude["compute.h"],
   CFunction["int", 
    "main", {{"int", "argc"}, {"char", 
      CDereference[CArray["arg", {}]]}},
    CBlock[{
      CDeclare["double", CAssign["num1", 20.4]],
      CDeclare["double", "num2"],
      CDeclare["WolframLibraryData", 
       CAssign["libData", 
        CCall["WolframLibraryData_new", {"WolframLibraryVersion"}]]],
      CCall["Initialize_compute", {"libData"}],
      CCall["compute", {"libData", "num1", CAddress["num2"]}],
      CCall["printf", {CString["%5.2f\n"], "num2"}],
      CCall["WolframLibraryData_free", {"libData"}],
      CReturn[0]}]]
   ];
cStr = ToCCodeString[code]

mainSource = Export[FileNameJoin[{outDir, "main.c"}], cStr, "Text"]

c = Compile[{{x}}, x^2];
CCodeGenerate[c, "compute", FileNameJoin[{outDir, "compute.c"}], 
  "CodeTarget" -> "WolframRTL"];
CCodeGenerate[c, "compute", FileNameJoin[{outDir, "compute.h"}], 
  "CodeTarget" -> "WolframRTLHeader"];

where
outDir
must be defined according the user's desires


  • The generated main.c file with a minor manual retouching in the printf function is


#include "compute.h"

#include "WolframRTL.h"


int main(int argc, char *arg[])
{
double num1 = 20.4;

double num2;
WolframLibraryData libData = WolframLibraryData_new(WolframLibraryVersion);
Initialize_compute(libData);

compute(libData, num1, &num2);
printf("%5.2f\n", num2);

WolframLibraryData_free(libData);
return 0;
}



  • The generated file compute.c is

#include "math.h"

#include "WolframRTL.h"

static WolframCompileLibrary_Functions funStructCompile;

static mbool initialize = 1;

#include "compute.h"

DLLEXPORT int Initialize_compute(WolframLibraryData libData)
{

if( initialize)
{
funStructCompile = libData->compileLibraryFunctions;
initialize = 0;
}

return 0;
}

DLLEXPORT void Uninitialize_compute(WolframLibraryData libData)
{
if( !initialize)
{

initialize = 1;
}
}

DLLEXPORT int compute(WolframLibraryData libData, mreal A1, mreal *Res)
{

mreal R0_0;
mreal R0_1;
R0_0 = A1;
R0_1 = R0_0 * R0_0;
*Res = R0_1;

funStructCompile->WolframLibraryData_cleanUp(libData, 1);
return 0;
}


  • The generated file compute .h is

#include "WolframLibrary.h"

EXTERN_C DLLEXPORT int Initialize_compute(WolframLibraryData libData);

EXTERN_C DLLEXPORT void Uninitialize_compute(WolframLibraryData libData);

EXTERN_C DLLEXPORT int compute(WolframLibraryData libData, mreal A1, mreal *Res);



  • Finally, the Makefile that takes care of the compilation is

CXX = /usr/bin/c++

MATHEMATICA_INCLUDE_PATH = /usr/local/Wolfram/Mathematica/8.0/SystemFiles/IncludeFiles/C

MATHEMATICA_LIB_PATH = /usr/local/Wolfram/Mathematica/8.0/SystemFiles/Libraries/Linux-x86-64


a.out: main.c compute.o
 ${CXX} -I${MATHEMATICA_INCLUDE_PATH} -L${MATHEMATICA_LIB_PATH} -lm -lWolframRTL -lmkl_intel_lp64 -lmkl_intel_thread -lmkl_core -liomp5 -pthread compute.o main.c

compute.o: compute.c
 ${CXX} -c -I${MATHEMATICA_INCLUDE_PATH}  -L${MATHEMATICA_LIB_PATH}  compute.c 



Of course, make sure that the libraries are in the right place and eventually you will need to add the path of the Mathematica libraries in  ld.so.conf and apply /sbin/ldconfig





  • A more elaborated example taking a real matrix input and a real matrix output is here
  • A similar example implemented for complex matrices here

Wednesday, April 20, 2011

GDP per energy consumption

Here, the world map for the GDP per unit of energy consumption. The world map has so much variation of this index that I had to make a log plot
In the case of the American continent, the linear scale is better

Sunday, April 17, 2011

Energy consumption per capita

I pulled out some data from Wolfram Alpha to make the following world map of the energy consumption per capita

A close up of America is also interesting

Friday, April 8, 2011

Thursday, April 7, 2011

Energy consumption by country

This is my first widget from Wolfram Alpha



Wow!! so nice and simple to make