Search code examples
pythonarrayscython

Creating 2D/3D C arrays in cython


Can anyone enlighten me how to pass a 2D array created in cython to a cdef function? I can do that with 1D array, but not with 2D (or higher), let me illustrate the situation:

This is the C code that I would like to reproduce in cython:

#include <stdio.h>

void print_my_1Darray();
void print_my_2Darray();

int main(void){

    int arr1D[] = {1,2,3,4,5,6,7,8,9,10,11,12};
    int arr2D[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; 

    print_my_1Darray(arr1D);   
    printf("\n");
    print_my_2Darray(arr2D);
    printf("\n");
    return 0;
}

void print_my_1Darray( int x[] ){
   
    int i;       
    for(i=0; i < 12; i++){
        printf("c[%d] = %d\n",i, x[i]);
    }
}

void print_my_2Darray( int x[3][4] ){
   
    int i, j;         
    for(i=0; i < 3; i++){
        for(j=0; j < 4; j++){
            printf("c[%d][%d] = %d\n",j, i, x[i][j]);
        } 
    }
}

And then if I try to reproduce this in Cython like this:

cimport cython
import numpy as np
cimport numpy as cnp

def testfunc():
    
    cdef int *arr1D = [1,2,3,4,5,6,7,8,9,10,11,12]
    print_my_1D_array(arr1D)
    
    cdef int *arr2D = [[1,2,3,4], [5,6,7,8], [9,10,11,12]]   # <-- WRONG!
    print_my_2D_array(arr2D)


cdef void print_my_1D_array(int c_arr[12]):
    
    cdef int i
    
    for i in range(4):
    print c_arr[i]  

cdef void print_my_2D_array(int c_arr[3][4]):
    
    cdef int i, j
    
    for i in range(3):
        for j in range(4):
            print c_arr[i][j]

and when I compile this pyx script I get the error:

    cdef int *arr2D = [[1,2,3,4][5,6,7,8][9,10,11,12]]   
    print_my_2D_array(arr2D)
                      ^
    ------------------------------------------------------------
 
    test2.pyx:18:27: Cannot assign type 'int *' to 'int (*)[4]'

It seems that I can create something with the

  "cdef int *arr2D = [[1,2,3,4][5,6,7,8][9,10,11,12]]" 

line and it compiles ok until I try to pass it to a function or simply print it's members...

Can anyone explain what's happening there and how to create pure-c 2D/3D arrays in cython and how to pass them to c-level functions? Also, I am trying to avoid numpy arrays there to avoid python overhead, as my code will require very fast calculations on arrays.


Solution

  • You need to make your input array static:

    cdef int arr2D[3][4]
    arr2D[0][:] = [1,  2,  3,  4]
    arr2D[1][:] = [5,  6,  7,  8]
    arr2D[2][:] = [9, 10, 11, 12]