Message Boards Message Boards

GROUPS:

Transposing an integer matrix with LibraryLink

Posted 5 years ago
5083 Views
|
7 Replies
|
2 Total Likes
|

In a previous post I explained how to create and return a matrix with LibraryLink. In this post we are going to expand on this a bit and create a function which accepts an integer matrix and returns the transposed result.

Here is the code (call it IntegerMatrixTranspose.c):

#include "WolframLibrary.h"

DLLEXPORT int IntegerMatrixTranspose(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) {

 /* Variable declarations */

 int err = LIBRARY_NO_ERROR;

 MTensor in;
 mint in_type;
 mint in_rank;
 mint const *in_dims;
 mint *in_data;

 MTensor out;
 mint out_type;
 mint out_rank;
 mint const *out_dims;
 mint *out_data;

 int i;
 mint *tmp_dims;

 mint rows, row, cols, col;

 /* Code section */

 /* Get the input matrix */
 in = MArgument_getMTensor(Args[0]);
 in_type = libData->MTensor_getType(in);
 in_rank = libData->MTensor_getRank(in);
 in_dims = libData->MTensor_getDimensions(in);
 in_data = libData->MTensor_getIntegerData(in);

 /* The type and rank of the output matrix is the same as the input matrix */
 out_type = in_type;
 out_rank = in_rank;

 /* The output dimensions are the reverse of the input dimensions */
 tmp_dims = (mint *) malloc(in_rank * sizeof(mint));
 for(i=0; i<in_rank; i++) { tmp_dims[i] = in_dims[in_rank-i-1]; }
 out_dims = tmp_dims;
 free(tmp_dims);

 /* Create the output matrix */
 err = libData->MTensor_new(out_type, out_rank, out_dims, &out);
 out_data = libData->MTensor_getIntegerData(out);

 /* Set the elements of the output matrix */
 rows = in_dims[0];
 cols = in_dims[1];
 for(row=0; row<rows; row++) {
  for(col=0; col<cols; col++) {
   out_data[row+rows*col] = in_data[col+cols*row];
  }
 }

 MArgument_setMTensor(Res,out);
 return err;

}

Let's take a look at each section of this code to understand what is going on. The top section labelled 'Variable declarations' declares the variables we need for transposing a matrix with LibraryLink. We need two tensors ('in' and 'out'). Each tensor has a type (for example the integer type (known as MType_Integer, but that is not needed in the code)). Each tensor also has a rank, and since we're dealing with matrices in this function the rank is going to be '2'. The tensor dimensions 'in_dims' is an array of 'rank' elements. In this case it will indicate the rows and columns. The tensor dimensions for 'out' are the same as 'in' except the rows and columns are reversed.

Now let's take a look at the 'Code section'. First we get the tensor 'in' from the first argument Args[0]. We then use the libData structure to extract the type, rank, dimensions and elements from this tensor. Next we will create the 'out' tensor. For this we need to set the result type (the same as the input type: integer), the result rank (also the same as the input) and the dimensions.

To get the dimensions we create a temporary array to store the dimensions of the input dimensions, but in reversed order.

Now we can create the output tensor 'out' with MTensor_new. This only leaves the task to assign each element in[row,col] to out[col,row], which is achieved by the double for loop in the code.

Finally we return the result using MArgument_setMTensor.

The Wolfram Language build and function loading code will now need to specify that we are going to pass in an integer matrix and that we are going to return an integer matrix (IntegerMatrixTranspose.m):

Needs["CCompilerDriver`"];
lib = CreateLibrary[{"IntegerMatrixTranspose.c"}, "IntegerMatrixTranspose"];
IntegerMatrixTranspose = LibraryFunctionLoad[lib, "IntegerMatrixTranspose", {{Integer, 2}}, {Integer, 2}];

Now we can run this code in the Wolfram Language, and transpose an integer matrix with the c code we just wrote:

Mathematica 10.2.0 for Microsoft Windows (64-bit)
Copyright 1988-2015 Wolfram Research, Inc.

In[1]:= Get["IntegerMatrixTranspose.m"]

In[2]:= IntegerMatrixTranspose[ {{1,2,3}, {4,5,6}, {7,8,9}, {10,11,12}} ] // Grid

Out[2]= 1   4   7   10

        2   5   8   11

        3   6   9   12

In the next post we will take a look at how to work with complex numbers.

7 Replies

I've used MathLink to send data back and forth across LibraryLink. What are the pros and cons of doing that?

Both are equivalent in their end results. I would expect a little bit more communication overhead when using MathLink (WSTP), but I don't have any data in hand to back this claim up.

I did some benchmarks for this recently:

In short:

  • for an empty function call LibraryLink passing is ~5 times faster than MathLink passing.
  • for cycling a large array it's 25 times faster

Keep in mind that: these numbers are specific to the precise passing method I used and my own computer. Check the full post to see what it is precisely that was benchmarked. There are many variations on how this can be done.

I thought I had to use MathLink to do callbacks to Mathematica through LibraryLink. Is that correct?

I think so, but it's not something I personally have a lot of experience with (yet).

Not necessarily. Check the section titled "Library Callback Functions" in the LibraryLink docs and ConnectLibraryCallbackFunction. This is much more limited than MathLink and only supports compiled functions. I have never used it, but I would expect it to also be much faster than MathLink.

This is a great post for educational purposes, but it should be pointed out that it is (very likely, I haven't tried) going to be significantly slower than the builtin Transpose.

The reason is that naive implementations of simple operations like transposition, array addition, etc. will not be as fast as an explicitly vectorized version. Writing it to take advantage of SIMD operations (like SSE) and considering cache effects should speed it up considerably. The builtin Transpose is certainly written this way.

The point I want to come to is that it would be great if LibraryLink provided access to some of these operations, in particular transposition. Mathematica stores matrices in row-major order (for very good reasons). Most other libraries use column-major order. If we want to transfer data between the two, it becomes necessary to transpose while copying. In a future version I would love to see a transpose-copy function for this purpose.

Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract