# How to get a MTensor variable by a vector object

librarylink have a dirty signature such as:

EXTERN_C DLLEXPORT int fun(WolframLibraryData libData,mint Argc, MArgument* Args, MArgument Res)


But when we are in version 13.1, we don't have to define this form to call c++ functions as my this answer, such as the sort_add2_fc or ragged_mean in it. But the function must return the specified format, such as MTensor,mint or mreal.

Obviously we can't return a vector object. So, if we get a vector in c++, how do I convert it into an MTensor object for return? For example, the following $$\color{red}{\text{semi-finished}}$$ function:

#include<vector>
#include "WolframCompileLibrary.h"

using namespace std;

EXTERN_C DLLEXPORT MTensor whichVec(mint index) {
vector<vector<mint>> vecVec = { {7,11,2},{9,6,3,5} };
vector<mint> result = vecVec[index];
MTensor res;// How to initialize res with the result

//current try:
st_WolframLibraryData libData;
mint dims[] = { result.size()};
libData.MTensor_new(MType_Integer, 1, dims, &res);
auto p = libData.MTensor_getIntegerData(res);
copy(result.begin(), result.end(), p);

return res;
}


But I don't know what is currently wrong in my code. If this function compiles successfully, then the following functions fc should work properly in MMA:

dec=LibraryFunctionDeclaration[fun->"whichVec","dir/*.dll",{"MachineInteger"}->
"PackedArray"::["MachineInteger", 1]];
fc=FunctionCompile[dec,Function[{Typed[lis,"MachineInteger"]}, fun[lis]]]

• I meant to say this already on your last question, but please keep in mind that using std::vector might not be the best idea if you care about performance. Since std::vector always handles its own data, you have to resort to a lot of copying of data into and out of the vector (as you can see from your code), which is potentially quite slow. You might want to consider using some other, non-owning wrapper, such as std::ranges::subrange. Aug 6 at 12:52
• @LukasLang Yes, you are right. I know some data structures that are faster than std::vector, like std::array, but if I can initialize a MTensor with std::vector, then I can do it with std::array. That's why I'm asking this question
– yode
Aug 6 at 13:11
• Well, std::array is not really a faster alternative to std::vector. It is still owning, the data are just contained within the object rather than on the heap. So unless you're doing some questionable casting, I'm not sure you'll gain anything from using std::array over std::vector Aug 6 at 13:41

Here's one way that works, although I am not sure it is the intended way:

Needs["CCompilerDriver"]
lib = CCompilerDriverCreateLibrary["
#include<vector>
#include \"WolframCompileLibrary.h\"

using namespace std;

WolframLibraryData libData;

EXTERN_C DLLEXPORT int WolframLibrary_initialize( WolframLibraryData \
libData_) {
libData = libData_;
return 0;
}

EXTERN_C DLLEXPORT MTensor whichVec(mint index) {
vector<vector<mint>> vecVec = { {7,11,2},{9,6,3,5} };
vector<mint> result = vecVec[index];
MTensor res;
mint dims[] = {result.size()};
libData->MTensor_new(MType_Integer, 1, dims, &res);
auto p = libData->MTensor_getIntegerData(res);
copy(result.begin(), result.end(), p);

return res;
}", "whichVecFile", Language -> "C++"];

dec = LibraryFunctionDeclaration[fun -> "whichVec",
lib, {"MachineInteger"} -> "PackedArray"::["MachineInteger", 1]];
fc = FunctionCompile[dec,
Function[{Typed[lis, "MachineInteger"]}, fun[lis]]]
(* CompiledCodeFunction[...] *)

fc[0]
(* {7, 11, 2} *)


The key difference to your attempt is how the WolframLibraryData struct is obtained: You are trying to simply construct one, but this won't work - it needs to be initialized and given to you by the kernel. The best way I found to obtain a pointer to the correct instance is to use WolframLibrary_initialize to store the pointer passed into that function. For some reason, the "loading" done by LibraryFunctionDeclaration/FunctionCompile does not call that initialization routine, so we manually have to call LibraryLoad before. As you can see from the code above, this then works as expected.

• Very interesting thought, you got a WolframLibraryData by LibraryLoad, which I didn't expect at all. If indeed no user can build this structure by code indeed, then I will accept your answer. Thanks a lot man. This problem has been bothering me for many days :)
– yode
Aug 6 at 15:00
– yode
Aug 7 at 7:07

I introduce a library WolframRTL_Kernel.lib then solve this problem:

Needs["CCompilerDriver"]
lib=CCompilerDriverCreateLibrary["
#include<vector>
#include \"WolframRTL.h\"

using namespace std;

EXTERN_C DLLEXPORT MTensor whichVec(mint index) {
WolframLibraryData libData = WolframLibraryData_new(WolframLibraryVersion);

vector<vector<mint>> vecVec = { {7,11,2},{9,6,3,5} };
vector<mint> result = vecVec[index];
MTensor res;
mint dims[] = { result.size() };
libData->MTensor_new(MType_Integer, 1, dims, &res);
copy(result.begin(), result.end(), (mint*)res->data);

WolframLibraryData_free(libData);

return res;
}","whichVecFile","Language"->"C++","Libraries"->"WolframRTL_Kernel.lib"];

dec=LibraryFunctionDeclaration[fun->"whichVec",lib,{"MachineInteger"}->"PackedArray"::["MachineInteger",1]];
fc=FunctionCompile[dec,Function[{Typed[lis,"MachineInteger"]},fun[lis]]]


We can use it now:

fc[1]


{9, 6, 3, 5}

Of course, we can use this code in c++ code:

#pragma comment(lib,"C:/Program Files/Wolfram Research/Mathematica/13.1/SystemFiles/Libraries/Windows-x86-64/WolframRTL_Kernel.lib")


As the example here, maybe we need "Libraries" -> "WolframRTL_Static_Minimal", then we get a more large .dll file.