In a
previous post I explained how to work with passing in and returning atomic data with LibraryLink. But
what if you want to pass in a list of numbers to do some computation on? In that case you will need to use
a data structure in LibraryLink called an MTensor, which is a general n-dimensional list structure meaning
you can use it for lists, matrices and higher dimensional equivalents of those structures.
Here is a simple example for calculating the mean value of a list of values. This means that a list of values
needs to be passed into the C function as an MTensor:
#include "WolframLibrary.h"
DLLEXPORT int MeanValue(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) {
MTensor tensor;
double* data;
double total,result;
mint i,length;
tensor = MArgument_getMTensor(Args[0]);
data = libData->MTensor_getRealData(tensor);
length = libData->MTensor_getFlattenedLength(tensor);
total=0;
for(i=0; i<length; i++) { total += data[i]; }
result = total/length;
MArgument_setReal(Res,result);
return LIBRARY_NO_ERROR;
}
This code introduces a number of new concepts that need to be explained. First, to pass in a list of real numbers we need
the MTensor data structure to hold this general data. In addition we also need a C array of doubles to extract the list of
reals from the tensor. And we also need an integer called length to hold the length of the list.
This is also the first example where we make explicit use of the WolframLibraryData (libData) data structure to extract
specific data from the MTensor. After we extract the required data, we can write the C for loop to compute the total
and finally compute the mean value result by dividing the result by the length of the list.
The Wolfram Language build and function loading code will now need to specify that we are going to pass in a 1-dimensional tensor
(i.e. a list), which is done by putting the type and its tensor dimension in a list like {Real,1}:
Needs["CCompilerDriver`"];
lib = CreateLibrary[{"MeanValue.c"},"MeanValue"];
MeanValue = LibraryFunctionLoad[lib,"MeanValue",{{Real,1}},Real];
Now we can try running this code in the Wolfram Language:
Mathematica 10.0 for Microsoft Windows (64-bit)
Copyright 1988-2013 Wolfram Research, Inc.
In[1]:= Get["MeanValue.m"]
In[2]:= MeanValue[{11,13}]
Out[2]= 12.
In[3]:= MeanValue[Range[100]^2]
Out[3]= 3383.5
Note that this is also the first example where perfomance of the LibraryLink code can be appreciated:
In[4]:= r=RandomReal[{0,100},10^7];
In[5]:= MeanValue[r] // AbsoluteTiming
Out[5]= {0.050047, 50.0127}
So, 0.05 seconds versus 9.48 seconds for a simple/naive Wolfram Language implementation of the same code:
In[6]:= AbsoluteTiming[ total=0; Do[total+=r[[i]], {i,Length[r]}]; total/Length[r] ]
Out[6]= {9.483029, 50.0127}
Still, the built-in Mean[] function is a bit faster than both:
In[7]:= Mean[r] // AbsoluteTiming
Out[7]= {0.016015, 50.0127}
In the next post we will take a look at
how to create a matrix by passing in the number of rows and columns.