I am trying to wrap a c function into python using swig.
The function, defined in my_method.h and implemented in my_method.c, is:
double my_method(const double a[], const double b[], const long int len_a, const long int len_b){
...
}
my swig interface file (my_method.i) is:
/* file : my_method.i */
/* name of the python module*/
%module my_method
%{
#include "my_method.h"
%}
%include "my_method.h"
I use dist-utils to generate the wrapped function
#!/usr/bin/env python
"""
setup.py file for SWIG wrapping
"""
from distutils.core import setup, Extension
my_method_module = Extension('_my_method',
sources=['my_method.c', 'my_method_wrap.c'],
)
setup (name = 'my_method',
version = '0.1',
author = "author",
description = """my method""",
ext_modules = [my_method_module],
py_modules = ["my_method"],
)
and then
swig -python my_method.i
python setup.py build_ext --inplace
however when I run my main script in python:
a = np.ones(4)
b = np.ones(4)
res = my_method(a, b, len(a), len(b))
I get the following error:
return _my_method.my_method(a, b, len_a, len_b)
TypeError: in method 'my_method', argument 1 of type 'double const []'
any suggestion?
SWIG has no idea that double a[]
represents one or many doubles or that len_a
indicates the length. NumPy has a SWIG interface file that defines the typemaps needed to associate a pointer and size with a numpy array or Python list called numpy.i
(docs) (download).
Here's a standalone example. You'll either need to reorder the parameters so pointer/size are together or add an adapter function. I've demonstrated the latter in case reordering is not possible:
%module test
%{
#define SWIG_FILE_WITH_INIT
// sample implementation of OP function.
// Just sum all the values in both arrays.
double my_method(const double a[], const double b[], const long int len_a, const long int len_b) {
double sum = 0.0;
for(long int aa = 0; aa < len_a; ++aa)
sum += a[aa];
for(long int bb = 0; bb < len_b; ++bb)
sum += b[bb];
return sum;
}
// adapter function in case re-ordering parameters is not possible
double my_method2(const double a[], int len_a, const double b[], int len_b) {
return my_method(a, b, len_a, len_b);
}
%}
%include "numpy.i"
%init %{
import_array();
%}
// apply the typemaps for numpy arrays to the two pairs of parameters representing the arrays
%apply (double* IN_ARRAY1, int DIM1) {(double* a, int len_a)};
%apply (double* IN_ARRAY1, int DIM1) {(double* b, int len_b)};
// process the adapter function and rename
%rename(my_method) my_method2;
double my_method2(double* a, int len_a, double* b, int len_b);
I built using MSVC on Windows. Note that include paths are needed to Python and its NumPy package headers:
swig -python test.i
cl /LD /W3 /Ic:\python310\include /Ic:\Python310\Lib\site-packages\numpy\core\include /Fe_test.pyd test_wrap.c -link /libpath:c:\python310\libs
Demo:
>>> import test
>>> test.my_method([1, 2, 3], [4, 5, 6])
21.0
>>> import numpy as np
>>> a = np.ones(4)
>>> b = np.ones(4)
>>> test.my_method(a, b)
8.0