1
$\begingroup$

I've been working on a project for quite a long time, and now when I finally want to use it in praxis I don't know how.

I have created a shared library (libcwv.so) with a header (cwv.so) with nvidia's nvcc. To use the library, one does not need any compiler from CUDA. Hence, I want to use the usual LibraryFunctionLoad in Mathematica for it. Before I post the code, this is the function I want to use in Mathematica:

int timeEvolution(vector<double> times, vector<double> startVector, double deltaE, vector<int> columnIndices, vector<double> nonZeroValues, vector<int> rowPointers, int timeChop, int dimChop, double* RefinalVector, double* ImfinalVector)

Since I haven't even managed to include the c++ vector library, I have also built a wrapper:

int timeEvolution(double* times, double* startVector, double deltaE, int* columnIndices, double* nonZeroValues, int* rowPointers, int timeChop, int dimChop, double* RefinalVector, double* ImfinalVector)

The wrapper contains pointers instead of vectors, and I have already been able to include it:

#include "WolframLibrary.h"

  DLLEXPORT mint WolframLibrary_getVersion(){
    return WolframLibraryVersion;
  }

  DLLEXPORT int WolframLibrary_initialize( WolframLibraryData libData) {
    return 0;
  }

  DLLEXPORT void WolframLibrary_uninitialize(WolframLibraryData libData) {
    return;
  }
  #include "cwv.h"  
  DLLEXPORT double testFunc(WolframLibraryData libData,
            double Argc, MArgument *Args, MArgument Res) {
    MArgument_setReal(Res, MArgument_getReal(Args[0])+1);
    return LIBRARY_NO _ERROR;
  }

The code above successfully compiles via CreateLibrary. Hence, I have managed to at very least include this function. But now is when the trouble begins.

The function timeEvolution modifies the entries of the last two arguments. Those will be the results. It returns 0 if it succeeds, and it returns 1 if it fails. Now I want to create a Mathematica function whose arguments shall be lists as well as real and integer numbers. In the end, I want it to return the two last arguments of timeEvolution as lists. Those entries (RefinalVector and Imfinalvector) can contain anything. They will be overwritten. But they should have a definite size. I will solve the problem with the size on my own. For now let it just be a global constant called "S".

I have made several attempts so far to somehow use my function, but none has lead to any result, yet. Also I don't find any useful results on the internet. (Maybe I'm just too clueless; I'm not exactly an expert with Mathematica)

My questions are therfore: 1. How do I include vectors (#include<vector>) in C++ code for CreateLibrary in Mathematica? (It just tells me that it cannot be found) 2. How do I pass over a set of arguments consisting of lists, reals and integers to a C++ function and call every single one of them individually? 3. Could you give me an example (or at least an idea) of how to use my function in Mathematica?

I know that I'm asking for almost everything and cannot offer anything in return. But I have really tried to find sources explaining how to do this, and I've failed. So please, if anyone knows what to do, be so kind and help me solve this :)

(I have to apologize in advance, because I probably won't be able to read your answers before Monday. Afterwards I will definitely appreciate every help!)

$\endgroup$
  • $\begingroup$ First, double Argc should be mint Argc. That's a very important difference. Your questions: 1. Don't type the code in a Mathematica string. That method only supports C code. Put it in a separate file if you need C++. 2. I don't understand this question. $\endgroup$ – Szabolcs Oct 14 '16 at 17:38
  • $\begingroup$ Thanks for the Answer! Concerning the first: I didn't actually realise this. Thank you! The questions 2 and 3 could basically be reduced to: How do I implement a function that has several lists as input and a list as output? $\endgroup$ – Fred Oct 18 '16 at 19:23
  • $\begingroup$ There's nothing special needed to do that ... It's part of the basics. You should go through the basic examples in the LibraryLink documentation, and ask a more specific question: where are you stuck? Answering this would mean just repeating the introductory documentation ... $\endgroup$ – Szabolcs Oct 18 '16 at 20:05
  • $\begingroup$ Look at how to read arguments, that includes reading multiple arguments. Look at how to return a value. Then just use the tensor type (MTensor) to do this. Take a look at the examples that work with tensors. $\endgroup$ – Szabolcs Oct 18 '16 at 20:06
  • $\begingroup$ Thanks again! I haven't answered earlier, because I was busy trying several things. My main misunderstanding was the way the arguments of such DLLEXPORT functions were defined. Now I got it right. It's embarassing for me to ask you again, but: Now there is one remaining problem. My code is a .so file compiled from C++ code, and like you said, I cannot use C++, but only C. Is there a convenient trick? I have tried it with 'extern "C"' and removed everything belonging to C++, but I'm not familiar with C, and calling any function created in C++ (with extern "C") crashes my Mathematica kernel. $\endgroup$ – Fred Oct 25 '16 at 15:45
1
$\begingroup$

In case anyone has the same (badly formulated) question, here is how you do it. The C code in Mathematica contains the function

DLLEXPORT int (WolframLibraryData libData,
            mint Argc, MArgument *Args, MArgument Res) {
int err;    
double* times = (double*) libData->MTensor_getRealData(MArgument_getMTensor(Args[0]));
double* startVector = (double*) libData->MTensor_getRealData(MArgument_getMTensor(Args[1]));
double deltaE = MArgument_getReal(Args[2]);
int* columnIndices = (int*) libData->MTensor_getIntegerData(MArgument_getMTensor(Args[3]));
double* nonZeroValues = (double*) libData->MTensor_getRealData(MArgument_getMTensor(Args[4]));
int* rowPointers = (int*) libData->MTensor_getIntegerData(MArgument_getMTensor(Args[5]));
int timeChop = MArgument_getReal(Args[6]);
int dimChop = MArgument_getReal(Args[7]);
double* RefinalVector = (double*)malloc(10*sizeof(double));
double* ImfinalVector = (double*)malloc(10*sizeof(double));

err = cwv(times, startVector, deltaE, columnIndices, 
           nonZeroValues, rowPointers, timeChop, dimChop,
           RefinalVector,ImfinalVector);

MArgument_setTensor(Res, RefinalVector);   // Here I still don't know how
                                           // to pass the result. But the
                                           // code answers my question.
free(RefinalVector);
free(ImfinalVector);
return LIBRARY_NO _ERROR;
}

Every argument is stored in *Args. One then picks the argument one needs. In Mathematica you create the function by

CWV = LibraryFunctionLoad[cwvlib, "cwvInMathematica", {{Real, 1}, {Real, 1}, {Real}, {Integer, 1}, {Real,
 1}, {Integer, 1}, {Integer}, {Integer}}, {Real, 1}]

My problem was that I couldn't find this way to work with several arguments and to implement them as tensors. Maybe this provides help to someone. I know that there are still mistakes in it, but I consider it better than nothing.

(For any admin reading this: Feel free to edit! :) )

|improve this answer|||||
$\endgroup$
  • $\begingroup$ To return a tensor, you need to return an MTensor, not a double *. Create it using MTensor_new, get its data pointer, and copy your data into it. $\endgroup$ – Szabolcs Oct 31 '16 at 14:16
  • $\begingroup$ Take a look at the "MTensor Return" section of the LibraryLink tutorial, Automatic Return subheading. It has an example. $\endgroup$ – Szabolcs Oct 31 '16 at 14:18
  • $\begingroup$ And once again thank you very much! :) Actually, I haven't yet even reached this problem. For some reason, my library won't work at all. But as soon as I'm there, I will probably be very happy about that information! (btw. Is there a way to upvote comments? I would really like to after all the help you already provided) $\endgroup$ – Fred Oct 31 '16 at 14:21
  • $\begingroup$ Hmmm... As embarassing as it may sound, I'm stuck again. For some reason Mathematica seems to accept the headers, but not the related .so files. I know that the answer probably lies somewhere in the manual, but I can't find it there. Is it worth opening a new question here? (I've already tried several things, therefore for example I know that it successfully includes the headers themselves) $\endgroup$ – Fred Oct 31 '16 at 15:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.