2

I have made some Numpy C-extensions before with great help from this site, but as far as I can see the returned parameters are all fixed length.

Is there any way to have a Numpy C-extension return a variable length numpy array instead?

1
  • 2
    what do you refer to as a "variable length numpy array"? As far as I know, numpy arrays cannot be resized once their size is set. Commented Jan 7, 2011 at 14:04

2 Answers 2

3

You may find it easier to make numpy extensions in Cython using the Numpy C-API which simplifies the process as it allows you to mix python and c objects. In that case there is little difficult about making a variable length array, you can simply specify an array with an arbitrary shape.

The Cython numpy tutorial is probably the best source on this topic.

For example, here is a function I recently wrote:

import numpy as np
cimport numpy as np
cimport cython

dtype = np.double
ctypedef double dtype_t

np.import_ufunc()
np.import_array()

def ewma(a, d, axis):
    #Calculates the exponentially weighted moving average of array a along axis using the parameter d.
    cdef void *args[1]

    cdef double weight[1]
    weight[0] = <double>np.exp(-d)


    args[0] = &weight[0]

    return apply_along_axis(&ewma_func, np.array(a, dtype = float), np.double, np.double, False, &(args[0]), <int>axis)

cdef void ewma_func(int n, void* aData,int astride, void* oData, int ostride, void** args):
    #Exponentially weighted moving average calculation function 

    cdef double avg = 0.0
    cdef double weight = (<double*>(args[0]))[0]
    cdef int i = 0

    for i in range(n): 

        avg = (<double*>((<char*>aData) + i * astride))[0]*weight + avg * (1.0 - weight) 


        (<double*>((<char*>oData) + i * ostride))[0] = avg  

ctypedef void (*func_1d)(int, void*, int, void*, int, void **)

cdef apply_along_axis(func_1d function, a, adtype, odtype, reduce,  void** args, int axis):
    #generic function for applying a cython function along a particular dimension

    oshape = list(a.shape)

    if reduce :
        oshape[axis] = 1

    out = np.empty(oshape, odtype)

    cdef np.flatiter ita, ito

    ita = np.PyArray_IterAllButAxis(a,   &axis)
    ito = np.PyArray_IterAllButAxis(out, &axis)

    cdef int axis_length = a.shape[axis]
    cdef int a_axis_stride = a.strides[axis]
    cdef int o_axis_stride = out.strides[axis]

    if reduce: 
        o_axis_stride = 0

    while np.PyArray_ITER_NOTDONE(ita):

        function(axis_length, np.PyArray_ITER_DATA (ita), a_axis_stride, np.PyArray_ITER_DATA (ito), o_axis_stride, args)

        np.PyArray_ITER_NEXT(ita)
        np.PyArray_ITER_NEXT(ito)

    if reduce:  
        oshape.pop(axis)
        out.shape = oshape

    return out  

If this doesn't suit you, there is a function for making a new empty array with arbitrary shape (link).

Sign up to request clarification or add additional context in comments.

Comments

0

I am interpreting your question to mean "I have a function that takes a NumPy array of length n, but it will return another array of length m different from n." If that is the case, you will need to malloc a new C array in the extension, e.g.

new_array = malloc(m * sizeof(int64)); // or whatever your data type is

then create a new NumPy array with that. This example assumes a 1D array:

int npy_intp dims[1];
dims[0] = m;
PyArrayObject *out = (PyArrayObject *)PyArray_SimpleNewFromData(1,          // 1D array
                                                                dims,       // dimensions
                                                                NPY_INT64,  // type
                                                                new_array);
PyArray_ENABLEFLAGS(out, NPY_ARRAY_OWNDATA);

Then return the new array. The important part here is to set the NPY_ARRAY_OWNDATA flag so that the memory you allocated is freed when the Python object is garbage collected.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.