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)
Abarajithan
  • 333
  • 4
  • 12
  • 2
    It looks like you are missing a call of [`import_array()`](https://numpy.org/doc/stable/reference/c-api/array.html#importing-the-api). Your question might be a duplicate of [Segmentation fault creating PyArrayObject using PyArray_SimpleNew](https://stackoverflow.com/questions/61259441/segmentation-fault-creating-pyarrayobject-using-pyarray-simplenew) – Warren Weckesser Jul 02 '21 at 11:48
  • 1
    Here is a little bit more explanation: https://stackoverflow.com/a/47027598/5769463 - you need to init numpy API before you can call simpleNewFromData. – ead Jul 02 '21 at 12:19
  • Thanks a lot. that was the issue. should i just delete this question, since its a duplicate? – Abarajithan Jul 02 '21 at 17:30

0 Answers0