Passing a C++ Complex Array to C

Passing a C++ complex array to C

The C++0x standard went to lengths to guarantee that such conversions will work (§26.4):

Moreover, if a is an expression of type cv std::complex<T>* and the expression a[i] is well-defined for an integer expression i, then:

reinterpret_cast<cv T*>(a)[2*i] shall designate the real part of a[i], and

reinterpret_cast<cv T*>(a)[2*i + 1] shall designate the imaginary part of a[i].

and (§23.3.6):

The elements of a vector are stored contiguously, meaning that if v is a vector<T, Allocator> where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().

The layout of the complex value is not guaranteed by the prevailing C++03 standard (though the vector layout is), but I would be surprised to find an implementation for which it does not hold.

Pass complex numpy array to C++ in Cython

This error message is telling you what's wrong:

mat.pyx:17:27: Cannot assign type 'double complex *' to 'double *'

That is, you have a double complex pointer from numpy (pointer to complex128 numpy dtype) and you're trying to pass that into the C++ function using double pointers. C++ needs to be able to deal with the complex numbers, so if you change your double* -> std::complex this should fix your problem

void mult(double *M, double *N, double *Q)

becomes

#include <complex>
void mult(std::complex<double> *M, std::complex<double> *N, std::complex<double> *Q)

Does numpy matrix multiply not suffice for your use case? Cython might be overkill.

Edit: Ok I finally got something, there's something a bit weird dealing with C++ std::complex and C double _Complex types.

cppmul.pyx:

import numpy as np
cimport numpy as np

cdef extern from "./matmult.h" nogil:
void mult(np.complex128_t* M, np.complex128_t* N, np.complex128_t* Q)

def sim():
cdef:
np.ndarray[np.complex128_t,ndim=2] N = np.zeros(( 2 , 2 ), dtype=np.complex128)
np.ndarray[np.complex128_t,ndim=2] Q = np.zeros(( 2 , 2 ), dtype=np.complex128)
np.ndarray[np.complex128_t,ndim=2] M = np.zeros(( 2 , 2 ), dtype=np.complex128)

N = np.array([[1.1 + 2j,2.2],[3.3,4.4]])
Q = np.array([[3.3,4.4+5j],[5.5,6.6]])

mult(&M[0,0], &N[0,0], &Q[0,0])
print M

matmul.c:

#include "matmult.h"

void mult(complex_t *M, complex_t *N, complex_t *Q)
{
complex_t P[2][2], A[2][2], B[2][2];

for (int i=0; i<2; i++)
{
for (int j=0; j<2; j++)
{
A[i][j] = *( N + ((2*i) + j) );
B[i][j] = *( Q + ((2*i) + j) );
P[i][j] = 0;
}
}

for (int i=0; i<2; i++)
{
for (int j=0; j<2; j++)
{
for (int k=0; k<2; k++)
{
P[i][j] += A[i][k]*B[k][i];
}
}
}

for (int i=0; i<2; i++)
{
for (int j=0; j<2; j++)
{
*( M + ((2*i) + j) ) = P[i][j];
}
}
}

matmult.h:

#include <complex.h>

typedef double _Complex complex_t;
void mult(complex_t *M, complex_t *N, complex_t *Q);

setup.py:

from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension
import numpy as np

sourcefiles = ['cppmul.pyx', 'matmult.c']

extensions = [Extension("cppmul",
sourcefiles,
include_dirs=[np.get_include()],
extra_compile_args=['-O3']
)]

setup(
ext_modules = cythonize(extensions)
)

after running python setup.py build_ext --inplace it imports and runs as expected

import cppmul
cppmul.sim()

result:

[[15.73 +6.6j 15.73 +6.6j]
[43.56+16.5j 43.56+16.5j]]

Passing big complex arrays from Python to C++ - what's my best option?

An easy solution that I used many times is to build your "C++ side" as a dll (=shared object on Linux/OS X), provide a simple, C-like entrypoint (straight integers, pointers & co., no STL stuff) and pass the data through ctypes.

This avoids boost/SIP/Swig/... build nightmares, can be kept zero-copy (with ctypes you can pass a straight pointer to your numpy data) and allow you to do whatever you want (especially on the build-side - no friggin' distutils, no boost, no nothing - build it with whatever can build a C-like dll) on the C++ side. It has also the nice side-effect of having your C++ algorithm callable from other languages (virtually any language has some way to interface with C libraries).


Here's a quick artificial example. The C++ side is just:

extern "C" {
double sum_it(double *array, int size) {
double ret = 0.;
for(int i=0; i<size; ++i) {
ret += array[i];
}
return ret;
}
}

This has to be compiled to a dll (on Windows) or a .so (on Linux), making sure to export the sum_it function (automatic with gcc, requires a .def file with VC++).

On the Python side, we can have a wrapper like

import ctypes
import os
import sys
import numpy as np

path = os.path.dirname(__file__)
cdll = ctypes.CDLL(os.path.join(path, "summer.dll" if sys.platform.startswith("win") else "summer.so"))
_sum_it = cdll.sum_it
_sum_it.restype = ctypes.c_double

def sum_it(l):
if isinstance(l, np.ndarray) and l.dtype == np.float64 and len(l.shape)==1:
# it's already a numpy array with the right features - go zero-copy
a = l.ctypes.data
else:
# it's a list or something else - try to create a copy
arr_t = ctypes.c_double * len(l)
a = arr_t(*l)
return _sum_it(a, len(l))

which makes sure that the data is marshaled correctly; then invoking the function is as trivial as

import summer
import numpy as np
# from a list (with copy)
print summer.sum_it([1, 2, 3, 4.5])
# from a numpy array of the right type - zero-copy
print summer.sum_it(np.array([3., 4., 5.]))

See the ctypes documentation for more information on how to use it. See also the relevant documentation in numpy.


For complex numbers, the situation is slightly more complicated, as there's no builtin for it in ctypes; if we want to use std::complex<double> on the C++ side (which is pretty much guaranteed to work fine with the numpy complex layout, namely a sequence of two doubles), we can write the C++ side as:

extern "C" {
std::complex<double> sum_it_cplx(std::complex<double> *array, int size) {
std::complex<double> ret(0., 0.);
for(int i=0; i<size; ++i) {
ret += array[i];
}
return ret;
}
}

Then, on the Python side, we have to replicate the c_complex layout to retrieve the return value (or to be able to build complex arrays without numpy):

class c_complex(ctypes.Structure):
# Complex number, compatible with std::complex layout
_fields_ = [("real", ctypes.c_double), ("imag", ctypes.c_double)]

def __init__(self, pycomplex):
# Init from Python complex
self.real = pycomplex.real
self.imag = pycomplex.imag

def to_complex(self):
# Convert to Python complex
return self.real + (1.j) * self.imag

Inheriting from ctypes.Structure enables the ctypes marshalling magic, which is performed according to the _fields_ member; the constructor and extra methods are just for ease of use on the Python side.

Then, we have to tell ctypes the return type

_sum_it_cplx = cdll.sum_it_cplx
_sum_it_cplx.restype = c_complex

and finally write our wrapper, in a similar fashion to the previous one:

def sum_it_cplx(l):
if isinstance(l, np.ndarray) and l.dtype == np.complex and len(l.shape)==1:
# the numpy array layout for complexes (sequence of two double) is already
# compatible with std::complex (see https://stackoverflow.com/a/5020268/214671)
a = l.ctypes.data
else:
# otherwise, try to build our c_complex
arr_t = c_complex * len(l)
a = arr_t(*(c_complex(r) for r in l))
ret = _sum_it_cplx(a, len(l))
return ret.to_complex()

Testing it as above

# from a complex list (with copy)
print summer.sum_it_cplx([1. + 0.j, 0 + 1.j, 2 + 2.j])
# from a numpy array of the right type - zero-copy
print summer.sum_it_cplx(np.array([1. + 0.j, 0 + 1.j, 2 + 2.j]))

yields the expected results:

(3+3j)
(3+3j)

How to build a complex array in a C header file?

You can achieve the effect you want by putting this in a header file:

typedef struct fontTypeDef {
uint16_t xOffset;
uint16_t yOffset;
uint16_t width;
uint16_t height;
const uint32_t *bitmapPtr;
} fontTypeDef;

extern const fontTypeDef font[128];

and this in one source file:

const fontTypeDef font[128] =
{

[32] = {0, 0, 8, 1, (const uint32_t []) {0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0x0}},
[33] = {1, 2, 3, 1, (const uint32_t []) {0xABCDEF, 0x0, 0xFF, 0xAB, 0xCC, 0x12321}},

}

Notes:

  • This puts the declarations in a header file, making them visible to all source files that include the header. It puts the definition of the data in a source file, so that the array font will be defined only once in the whole program.
  • Although other comments and answers have cautioned against using “global” variables or file-scope identifiers, it is reasonable to define constant data this way. As long as you want the data to be built into the program permanently, rather than read from a reference file, this is fine.
  • const has been added since we are defining data that is fixed when (or before) the program is built, and it should not be changed by the program.
  • The pointer member is initialized using a compound literal. The syntax (type) { initial values… } creates an initialized object. The code above uses it to create an array of uint32_t. The array is automatically converted to a pointer to its first element, and that pointer initializes the bitmapPtr element.
  • The elements of the font array are initialized using the designated initializer syntax [index] = { initial values… }, where index gives the index of the array element being initialized. If you initialize all array elements in order, you can also simply use a list of { initial values… }, omitting the [index] =.
  • The semicolons after the initial values in your original code have been changed to commas, as this is now a list of initializers inside an array definition rather than a sequence of statements.

How to pass multidimensional Numpy arrays to C function using CFFI?

The types double[3][3] and double *[3] are not equivalent. The former is an 2D array of double 3x3, stored as 9 contiguous double. The latter is an array of 3 double pointers, which is not how 2D static arrays are implemented in C or C++.

Both numpy arrays and C++ static arrays are represented in memory as a contiguous block of elements, it's just the double *[3] type in the middle that's throwing a wrench in the works. What you'd want is to use double[3][3] proper or double[3]* (a pointer to a row of three doubles). Note that if you use the latter you may need to change the function prototype to take double [][3].

Can I pass a C# array to a C pointer via a C++/CLI wrapper?

The correct solution (both Lirik and pst gave pointers in the right direction) would be:

int Class1::FXForwardRateW(array<int>^ premium, double %fwdRate)
{
double tempFwdRate = fwdRate;
pin_ptr<int> premiumPtr = &premium[0];
int status = FXForwardRate(premiumPtr, &tempFwdRate);
fwdRate = tempFwdRate;
return status;
}

Passing a 2-D array in pure C

Just use

void reverse(int vertexes, int v[vertexes][vertexes])

Trying to use int ** will not immediately work with built-in 2D arrays. If you want to insist on int ** interface, then you'll have to create an additional temporary row-index array as described here

Passing two-dimensional array via pointer

or here

conversion of 2D array to pointer-to-pointer

How to pass complex numbers from python numpy to c (trying to use SWIG at the moment)

I'm not sure how this interacts with Numpy, but SWIG certainly includes support for C99's complex types. I was able to verify this with the following example:

%module test
%{
#include <complex.h>
%}

%include <complex.i>

%inline %{
double complex test(double complex X) {
return X;
}
%}

This uses the SWIG complex.i interface.

(Note that here %inline is used to declare, define and wrap all in one place - handy for testing, but for 'real' code I tend to use %include).

I compiled this (on Linux) with:

swig -Wall -python test.i 
gcc -std=c99 -Wall -Wextra test_wrap.c -I/usr/include/python2.7 -shared -o _test.so

Which built fine with only one warning. Once that was done I could then do:

LD_LIBRARY_PATH=.  python                       
Python 2.7.3 (default, Aug 1 2012, 05:16:07)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import test
>>> test.test(complex(0,1))
1j
>>> test.test(complex(0,2))
2j
>>> test.test(complex(1,2))
(1+2j)
>>>

Which seems to be accepting and returning native Python complex types.

I was also able to make the following interface compile:

%{
#define SWIG_FILE_WITH_INIT
#include <complex.h>
%}
%include <complex.i>
%include <numpy.i>
%init %{
import_array();
%}

%numpy_typemaps(complex float, NPY_CFLOAT , int)
%numpy_typemaps(complex double, NPY_CDOUBLE, int)
%numpy_typemaps(complex long double, NPY_CLONGDOUBLE, int)

%module test

%inline %{
double complex test(double complex X) {
return X;
}
%}

With the addition of %include <complex.i> and -std=c99 to the compiler flags. I think you can make distutils set that for you using something like these options.

Passing an array of strings to a C function by reference

You've already got it.

#include <stdio.h>
static void func(char *p[])
{
p[0] = "Hello";
p[1] = "World";
}
int main(int argc, char *argv[])
{
char *strings[2];
func(strings);
printf("%s %s\n", strings[0], strings[1]);
return 0;
}

In C, when you pass an array to a function, the compiler turns the array into a pointer. (The array "decays" into a pointer.) The "func" above is exactly equivalent to:

static void func(char **p)
{
p[0] = "Hello";
p[1] = "World";
}

Since a pointer to the array is passed, when you modify the array, you are modifying the original array and not a copy.

You may want to read up on how pointers and arrays work in C. Unlike most languages, in C, pointers (references) and arrays are treated similarly in many ways. An array sometimes decays into a pointer, but only under very specific circumstances. For example, this does not work:

void func(char **p);
void other_func(void)
{
char arr[5][3];
func(arr); // does not work!
}


Related Topics



Leave a reply



Submit