0

I'm figuring out the Python/C API for a more complex task. Initially, I wrote a simple example of adding two ndarrays of shape = (2,3) and type = float32.

I am able to pass two numpy arrays into c functions, read their dimensions and data and perform custom addion on data. But when I try to wrap the resulting data using PyArray_SimpleNewFromData, code hangs (returns NULL?)

To replicate the issue, create three files: mymath.c, setup.py, test.py in a folder as follows and run test.py (it runs setup.py to compile and install the module and then runs a simple test).

I'm using python in windows, inside an anaconda environment. I'm new to the Python/C API. So, any help would be much appreciated.

// mymath.c

#include <Python.h>
#include <stdio.h>
#include "numpy/arrayobject.h"
#include "numpy/npy_math.h"
#include <math.h>
#include <omp.h>

/*
  C functions
*/

float* arr_add(float* d1, float* d2, int M, int N){

  float * result = (float *) malloc(sizeof(float)*M*N);

  for (int m=0; m<M; m++)
    for (int n=0; n<N; n++)
      result [m*N+ n] = d1[m*N+ n] + d2[m*N+ n];

  return result;
}

/*
  Unwrap apply and wrap pyObjects
*/

void capsule_cleanup(PyObject *capsule) {
  void *memory = PyCapsule_GetPointer(capsule, NULL);
  free(memory);
}

// add two 2d arrays (float32)
static PyObject *arr_add_fn(PyObject *self, PyObject *args)
{
  PyArrayObject *arr1, *arr2;

  if (!PyArg_ParseTuple(args, "OO", &arr1, &arr2))
    return NULL;
  
  // get data as flat list
  float *d1, *d2;
  d1 = (float *) arr1->data;
  d2 = (float *) arr2->data;

  int M, N;
  M = (int)arr1->dimensions[0];
  N = (int)arr1->dimensions[1];

  printf("Dimensions, %d, %d \n\n", M,N);

  PyObject *result, *capsule;
  npy_intp dim[2];
  dim[0] = M;
  dim[1] = N;

  float * d3 = arr_add(d1, d2, M, N);

  result = PyArray_SimpleNewFromData(2, dim, NPY_FLOAT, (void *)d3);
  if (result == NULL)
    return NULL;

  // -----------This is not executed. code hangs--------------------
  for (int m=0; m<M; m++)
    for (int n=0; n<N; n++)
      printf("%f \n", d3[m*N+n]);

  capsule = PyCapsule_New(d3, NULL, capsule_cleanup);
  PyArray_SetBaseObject((PyArrayObject *) result, capsule);
  return result;
}

/*
  Bundle functions into module
*/

static PyMethodDef MyMethods [] ={
  {"arr_add", arr_add_fn, METH_VARARGS, "Array Add two numbers"},
  {NULL,NULL,0,NULL}
};

/*
  Create module
*/

static struct PyModuleDef mymathmodule = {
  PyModuleDef_HEAD_INIT,
  "mymath", "My doc of mymath", -1, MyMethods
};

PyMODINIT_FUNC PyInit_mymath(void){
  return PyModule_Create(&mymathmodule);
}

# setup.py

from distutils.core import setup, Extension
import numpy

module1 = Extension('mymath',
        sources = ['mymath.c'],
        # define_macros = [('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION')],
        include_dirs=[numpy.get_include()],
        extra_compile_args = ['-fopenmp'],
        extra_link_args = ['-lgomp'])

setup (name = 'mymath',
        version = '1.0',
        description = 'My math',
        ext_modules = [module1])

# test.py

import os

os.system("python .\setup.py install")

import numpy as np
import mymath

a = np.arange(6,dtype=np.float32).reshape(2,3)
b = np.arange(6,dtype=np.float32).reshape(2,3)

c = mymath.arr_add(a,b)
print(c)
3

0

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.