How to convert a list of lists of floats in to a C double ** using ctypes in Python

60 views Asked by At

Im trying to convert a Python list of lists of floats into a C double ** ptr

lst = [[1,1,1,1],[2,2,2,2],[3,3,3,3]]
c_dbl_ptr = (ctypes.c_double * len(lst) * len(lst[0])) (*(tuple(tuple(sublist) for sublist in lst)))

Which yields IndexError: invalid index

This method is from How do I convert a Python list of lists of lists into a C array by using ctypes? but it seems im doing something wrong when trying to apply it to a 2d list.

2

There are 2 answers

0
Mark Tolonen On BEST ANSWER

A double** is an pointer to one or more double*, so each row of doubles needs to be in a double array, and each of those separate arrays used as initializers to a double* array:

import ctypes as ct

lst = [[1,1,1,1],[2,2,2,2],[3,3,3,3]]

# Equivalent to C double* array[3].
# Ctypes passes as double** when passed to a C function.
pdbl_array = (ct.POINTER(ct.c_double) * len(lst))(*[(ct.c_double * len(n))(*n) for n in lst])
for pdbl in pdbl_array:
    print(pdbl[:4]) # since it is a pointer, must provide size.

Output:

[1.0, 1.0, 1.0, 1.0]
[2.0, 2.0, 2.0, 2.0]
[3.0, 3.0, 3.0, 3.0]

Maybe easier to read in steps, but not quite equivalent since it assumes all the sub-lists are the same length. The former code supports variable length sub-lists.

PDBL_ARRAY_TYPE = ct.POINTER(ct.c_double) * len(lst)  # (double*)[3] type
DBL_ARRAY_TYPE = ct.c_double * len(lst[0])  # double[4] type

# Python list of double[4] arrays using sublists as initializers
arrays = [DBL_ARRAY_TYPE(*sublst) for sublst in lst]

# ctypes (double*)[3] array using arrays as initializers
pdbl_array = PDBL_ARRAY_TYPE(*arrays)

If instead you really just need a 2D array, the original code had the array sizes reversed. In ctypes, a C double[3][4] is declared with the sizes in reverse, e.g., ctypes.c_double * 4 * 3. 4 * ctypes.c_double * 3 or 3 * (4 * ctypes.c_double) also work. Basically, the row multiplication has to happen first.

import ctypes as ct

lst = [[1,1,1,1],[2,2,2,2],[3,3,3,3]]
dbl_2darray = (ct.c_double * len(lst[0]) * len(lst))(*(tuple(tuple(sublist) for sublist in lst)))
for arr in dbl_2darray:
    print(list(arr))

Output:

[1.0, 1.0, 1.0, 1.0]
[2.0, 2.0, 2.0, 2.0]
[3.0, 3.0, 3.0, 3.0]
2
Lexpj On

There is something wrong with your list comprehension. When applying this, you get a list of ctypes.c_double arrays. This is done by iterating over each array in the list (which I have renamed due to list being a method)

import ctypes
lst = [[1,1,1,1],[2,2,2,2],[3,3,3,3]]
x = [(ctypes.c_double* len(sublst))(*sublst) for sublst in lst]

Hope this helps!