I really like PyD and I'm considering using it write numerical code. Is it possible to write functions in D involving D-arrays and have PyD generate a module which maps automatically between D-arrays and NumPy arrays? This is basically what f2py does with Fortran arrays. I was hoping that something similar might be possible with PyD and D.

In order to map between D arrays and NumPy arrays directly, I would have to find some way to reach into NumPy's innards and grab a slice of the NumPy array's internal buffer. I don't know nearly enough about how NumPy works to do this, and have serious doubts that it's even possible to do it in a useful way.

Therefore, the next best thing is writing a D type that wraps NumPy array objects and overloads appropriate operators so that it acts like an array. As it happens, Pyd already has PydObject, a type which wraps any arbitrary Python object. Your best bet is to have your function parameters that accept these arrays to be of type PydObject. You should then be able to index the PydObject normally.

This would get trickier with multi-dimensional arrays. To index a multi-dimensional NumPy array, you pass a tuple as the index. Therefore, you would have to pass a PydObject holding a tuple to PydObject.opIndex. Building PydObjects like this is one of Pyd's rougher edges. Making a PydObject-tuple from D items the easy way looks like this:

Code:

new PydObject(PyTuple_FromItems(1, 2, 3));

PyTuple_FromItems is an undocumented function inside of Pyd, which looks like this:

Code:

PyObject* PyTuple_FromItems(T ...) (T t);

It wouldn't be hard to shorten the above with a simple wrapper function, and I fully plan on adding such a thing to Pyd in the future. (There are a number of PydObject features that need to be fleshed out, but the bits that are there should work.)

However, the use of PydObject implies a certain overhead. (It is a class, after all, and goes on the heap.) If you want to minimize overhead for your numerics code, then you are effectively on your own, and must deal with the C API directly. This is made available by saying "import python;". After that, you may have your functions accept PyObject*s, and Python objects will be passed in directly as borrowed references. You are responsible for reference counts and exception handling whenever you call the Python/C API directly. Pyd's handle_exception() function is the recommended way to deal with Python/C API exceptions; simply call it whenever an exception may have occurred (it will do nothing if no exception has occurred, and throw the exception as a PythonException if one has).

In short: My personal recommendation is to use PydObject, though I am very interested in whatever shortcomings you may come across with it.