[Numpy-discussion] help with typemapping a C function to use numpy arrays

Rich E reakinator at gmail.com
Tue Jan 6 17:51:11 EST 2009


This helped immensely.  I feel like I am getting close to being able
to accomplish what I would like with SWIG: producing a python module
that can be very 'python-like', while co-existing with the c library
that is very 'c-like'.

There is one question still remaining though, is it possible to make
the wrapped function have the same name still?  Using either
my_spectrumMag or spectrumMag means I have to create a number of
inconsistencies between the python module and the c library.  It is
ideal to ignore (%ignore?) the c sms_spectrumMag and instead use the
wrapped one, with the same name.  But my attempts at doing this so far
have not compiled because of name conflictions.

Thanks for the help, I think you are doing great things with this
numpy interface/typemaps system.

regards,
Rich


On Tue, Jan 6, 2009 at 3:47 PM, Egor Zindy <ezindy at gmail.com> wrote:
> Hello again,
>
> I really don't know what came over me when I changed your function
> prototype, that wasn't a very thoughtful thing to do!
>
>> Maybe I should look into using an 'insertion block' of code in the
>> interface file, instead of trying to typemap the array?
>
> Insertion blocks... is that %inline code? In which case, yes! Have a look, I
> attached a new version that uses some %inline directives in the
> dftmagnitude.i file.
>
> Basically, you can inline a new function with an easier prototype to wrap.
> The function allocates memory and calls your sms_spectrumMag() function.
>
> my inline function: void my_spectrumMag( int sizeInMag, float *pInRect, int
> *sizeOutMag, float **pOutMag)
>
> there's also a %rename directive: %rename (spectrumMag) my_spectrumMag;
>
> I had a go at defining some exceptions too (no memory and odd number of
> indexes), but I'm not sure errno is the easiest way to go about it...
>
> Hope this helps!
>
> ... and the python test output:
>
> ~>python test_dftmagnitude.py
> array: [1, 1, 2, 2]
> result: [ 1.41421354  2.82842708]
>
> array: [1, 1, 2, 2, 3, 3, 4, 4]
> result: [ 1.41421354  2.82842708  4.2426405   5.65685415]
>
> array: [1, 1, 2]
> result:
> Traceback (most recent call last):
>   File "test_dftmagnitude.py", line 15, in <module>
>     print "result:",dftmagnitude.spectrumMag(a)
> IndexError: Odd number of elements in input array: 3
>
> ~>
>
> Regards,
> Egor
>
>
> On Tue, Jan 6, 2009 at 1:06 AM, Rich E <reakinator at gmail.com> wrote:
>>
>> Egor,
>>
>> Thanks for the help.  I think I want to leave the C code as-is
>> however, as it is perfectly fine there no knowing 'sizeOutMag' because
>> it can deduce both array sizes from one variable.  There are many
>> other similar cases in my code (many where the size of the array is
>> known by a member of a structure passed to the function).
>>
>> Maybe I should look into using an 'insertion block' of code in the
>> interface file, instead of trying to typemap the array?  I am thinking
>> I may just be able to copy the generated code (from SWIG) into my
>> interface file to do this, but I have not tried it yet.
>>
>> I will experiment a little and post again.  Thanks and happy holidays!
>>
>> regards,
>> Rich
>>
>> On Mon, Jan 5, 2009 at 10:42 AM, Egor Zindy <ezindy at gmail.com> wrote:
>> > Hello Rich,
>> >
>> > sorry it took so long to answer back, holidays and all :-)
>> >
>> > That's exactly the kind of SWIG / numpy.i problems I've been working on
>> > over
>> > the past few months: How to generate an array you don't know the size of
>> > a-priori, and then handle the memory deallocation seamlessly. In your
>> > case,
>> > you know that the output array will be half the size of the input array,
>> > but
>> > this falls under the more general case of "not knowing the output size
>> > a-priori".
>> >
>> > Have a look at the files attached. I've rewritten your function header
>> > as:
>> > void sms_spectrumMag( int sizeInMag, float *pInRect, int *sizeOutMag,
>> > float
>> > **pOutMag);
>> >
>> > Easy to see what the input and output arrays are now. Then my numpy.i
>> > handles the memory deallocation of the **pOutMag array.
>> >
>> > I've actually moved my numpy.i explanations to the scipy/numpy cookbook
>> > last
>> > week :-)
>> > http://www.scipy.org/Cookbook/SWIG_Memory_Deallocation
>> >
>> > Hope it all makes sense. If you have any questions, don't hesitate!
>> >
>> >>python test_dftmagnitude.py
>> > [1, 1, 2, 2]
>> > [ 1.41421354  2.82842708]
>> > [1, 1, 2, 2, 3, 3, 4, 4]
>> > [ 1.41421354  2.82842708  4.2426405   5.65685415]
>> > [1, 1, 2, 2, 3, 3, 4, 4, 5, 5]
>> > [ 1.41421354  2.82842708  4.2426405   5.65685415  7.07106781]
>> >
>> > Regards,
>> > Egor
>> >
>> > On Wed, Dec 24, 2008 at 1:52 AM, Rich E <reakinator at gmail.com> wrote:
>> >>
>> >> Hi list,
>> >>
>> >> My question has to do with the Numpy/SWIG typemapping system.
>> >>
>> >> I recently got the typemaps in numpy.i to work on most of my C
>> >> functions that are wrapped using SWIG, if they have arguments of the
>> >> form (int sizeArray, float *pArray).
>> >>
>> >> Now I am trying to figure out how to wrap function that aren't of the
>> >> form, such as the following function:
>> >>
>> >> /*! \brief compute magnitude spectrum of a DFT
>> >>  *
>> >>  * \param sizeMag              size of output Magnitude (half of input
>> >> real FFT)
>> >>  * \param pFReal               pointer to input FFT real array
>> >> (real/imag floats)
>> >>  * \param pFMAg        pointer to float array of magnitude spectrum
>> >>  */
>> >> void sms_spectrumMag( int sizeMag, float *pInRect, float *pOutMag)
>> >> {
>> >>       int i, it2;
>> >>       float fReal, fImag;
>> >>
>> >>       for (i=0; i<sizeMag; i++)
>> >>       {
>> >>               it2 = i << 1;
>> >>               fReal = pInRect[it2];
>> >>               fImag = pInRect[it2+1];
>> >>               pOutMag[i] = sqrtf(fReal * fReal + fImag * fImag);
>> >>       }
>> >> }
>> >>
>> >> There are two arrays, one is half the size of the other.  But, SWIG
>> >> doesn't know this, according to the type map it will think *pInRect is
>> >> of size sizeMag and will not know anything about *pOutMag.
>> >>
>> >> Ideally in python, I would like to call the function as
>> >> sms_spectrumMag(nArray1, nArray2), where nArray1 is twice the size of
>> >> nArray2, and nArray2 is of size sizeMag.
>> >>
>> >> I think in order to do this (although if someone has a better
>> >> suggestion, I am open to it), I will have to modify the typemap in
>> >> order to tell SWIG how to call the C function properly.  I do not want
>> >> to have to edit the wrapped C file every time it is regenerated from
>> >> the interface file.
>> >>
>> >>
>> >> Here is a start I made with the existing typemap code in numpy.i (not
>> >> working):
>> >>
>> >> /* Typemap suite for (DIM_TYPE DIM1, DATA_TYPE* INPLACE_ARRAY1)
>> >>  */
>> >> %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY,
>> >>          fragment="NumPy_Macros")
>> >>  (DIM_TYPE DIM1, DATA_TYPE* INPLACE_ARRAY1)
>> >> {
>> >>  $1 = is_array($input) && PyArray_EquivTypenums(array_type($input),
>> >>                                                DATA_TYPECODE);
>> >> }
>> >> %typemap(in,
>> >>        fragment="NumPy_Fragments")
>> >>  (DIM_TYPE DIM1, DATA_TYPE* INPLACE_ARRAY1)
>> >>  (PyArrayObject* array=NULL, int i=0)
>> >> {
>> >>  array = obj_to_array_no_conversion($input, DATA_TYPECODE);
>> >>  if (!array || !require_dimensions(array,1) ||
>> >> !require_contiguous(array)
>> >>     || !require_native(array)) SWIG_fail;
>> >>  $1 = 1;
>> >>  for (i=0; i < array_numdims(array); ++i) $1 *= array_size(array,i);
>> >>  $2 = (DATA_TYPE*) array_data(array);
>> >> }
>> >>
>> >> and try to alter it to allow for a conversion of type:
>> >> (DIM_TYPE DIM1, DATA_TYPE* ARRAY1, DATA_TYPE* ARRAY2)
>> >> where ARRAY1 is size DIM1 * 2 and  ARRAY2 is size DIM1.  Then I can
>> >> %apply this to my function that I mentioned in the last post.
>> >>
>> >> So here are my first two questions:
>> >>
>> >> 1) where is DIM1 used to declare the array size?  I don't see where it
>> >> is used at all, and I need to somewhere multiply it by 2 to declare
>> >> the size of ARRAY1
>> >>
>> >> 2) I am not understanding where $input comes from, so I do not
>> >> understand how to distinguish between ARRAY1 and ARRAY2.  In the
>> >> attempt I have already tried, I think I just use the pointer to ARRAY1
>> >> twice.
>> >>
>> >> If anyone has suggestions on how to solve this problem, thanks!
>> >>
>> >> regards,
>> >> Rich
>> >> _______________________________________________
>> >> Numpy-discussion mailing list
>> >> Numpy-discussion at scipy.org
>> >> http://projects.scipy.org/mailman/listinfo/numpy-discussion
>> >
>> >
>
>
> _______________________________________________
> Numpy-discussion mailing list
> Numpy-discussion at scipy.org
> http://projects.scipy.org/mailman/listinfo/numpy-discussion
>
>



More information about the NumPy-Discussion mailing list