1

I am interested in permuting the elements of a d-dimensional tensor using C code (and hence, using loops only) and I would like to write the function with d as an argument. The tensor data is so far contained in a "d-dimensional" pointer (for example, a simple array when d = 1). So far, I have defined this pointer statically with **T for d = 2, although indications were given here for a dynamic approach: Create a d-dimensional pointer. How to write the code with d as argument without using a (dirty) if loop:

if (d == 2) { 
specific code for permuting
} 
else if (d == 3) { 
other specific code
} 

? Note that the permutation order is an input to the function. Thank you,

baptiste
  • 95
  • 6

2 Answers2

0

Edit: It seems I misinterpreted the question. However the below answer is still relevant to the topic, so I am not going to remove it for now.

The answer could be specific to the problem, perhaps the code for permuting d == 2 can be reduced to the same as d == 3. I don't know exactly what the code would look like as I have not studied tensors, but if it is not reducible then the "dirty" method that you have is your best option.

Alternatively, if you have the number of dimensions #defined similar to the pointer representation in the post you link, you could use pre-processor directives to turn on/off extra loops. This should give you a bit more condensed code. it should probably look like:

#define D 4 // Number of dimensions to use
#define MAX_D 10 // maximum # of dimensions
...
#if D >= MAX_D 
for(int i = 0; i < dimensions[MAX_D - 1]; i++) {
#endif
...
#if D >= 2
for(int i = 0; i < dimensions[1]; i++) {
#endif
// Base case ; D == 1
for(int i = 0; i < dimensions[0]; i++) {
    // Permutation stuff here
}
#if D == 2
}
#elif D == 3
}}
#elif D == 4
}}}
....
#endif

While this is a bit ugly, it prevents you from having to create and maintain a bunch of different versions.


The link provided is really the best approach for creating a d-dimensional pointed in C. However, you can simulate a d-dimensional array with a 1-D array and a bit of math.

You can use the following functions to achieve this:

void get(int *d_dimens, int d, size_t *dimensions, size_t *point, int val) {
    size_t index = 0; // Index of the number
    size_t dim = 1; // Location of the current dimension
    for(int i = 0; i < d; i++) {
        index += point[i] * dim;
        dim *= dimensions[i];
    }
    return d_dimens[index];
}

void set(int *d_dimens, int d, size_t *dimensions, size_t *point, int val) {
    size_t index = 0; // Index of the number
    size_t dim = 1; // Location of the current dimension
    for(int i = 0; i < d; i++) {
        index += point[i] * dim;
        dim *= dimensions[i];
    }
    d_dimens[index] = val;
}

int *create(int d, size_t *dimensions) {
    sizt_t num_elems = 1;
    for(int i = 0; i < d; i++)
        num_elems *= dimensions[i];
    int *ptr = malloc(sizeof (int) * num_elems);
    return ptr;
}

Where dimensions is an array of dimensions, d_dimens is the 1-D array we are using to simulate a d-D array, and d is the number of dimensions. For example if you want a 4x5x2 array, you would use dimensions = {4, 5, 2}; d = 3;

Jacob H
  • 864
  • 1
  • 10
  • 25
  • 1
    This does not appear to address the question of how to permutate the tensor. Also you may want to use `size_t` for indexes. – bitmask Dec 10 '17 at 23:04
  • Yeah, I misinterpreted the question the first time around. I think I fixed it, thanks. – Jacob H Dec 10 '17 at 23:18
  • Thank you for the replies. I think writing the C code for permuting with the dimension as input to the function is related to whether I can do it with loops using any language. For example, if the dimension is 2, two loops do the transpose operation. If the dimension is 3, I need three loops embedded in one another. How to parametrize the number of loops as input of the function and still fill the cube? – baptiste Dec 12 '17 at 14:24
0

So far, I have defined this pointer statically with **T for d = 2, although indications were given here for a dynamic approach: …

I recommend not using multidimensional pointers unless sparse storage is needed. Instead, see this nicely illustrated answer to the question How does NumPy's transpose() method permute the axes of an array? As explained there, with this scheme the tensor values don't even need to be copied for the transpose operation.

Armali
  • 18,255
  • 14
  • 57
  • 171