[Numpy-discussion] How can CDOUBLE_to_CDOUBLE work correctly?

Pearu Peterson pearu at cens.ioc.ee
Sun Mar 3 04:41:15 CST 2002


I am trying to copy a 2-d complex array to another 2-d complex array in an
extension module. Both arrays may be noncontiguous. But using
the same routine (namely Travis's copy_ND_array, you can find it at the
end of this messsage) as for real arrays seems not work.
After some playing around and reading docs about strides and stuff,
I found that the reason might be in how Numeric (20.3) defines
the CDOUBLE_to_CDOUBLE function:

static void CDOUBLE_to_CDOUBLE(double *ip, int ipstep, 
                               double *op, int opstep, int n)
{int i; for(i=0;i<2*n;i++,ip+=ipstep,op+=opstep) {*op = (double)*ip;}}

It seems not to take into account that real and imaginary part are
always contiguous in memory, even if an array itself is not. Actually, I
don't understand how this code can work (unless some magic is done in
places where this code is used). I would have expected that the code
for CDOUBLE_to_CDOUBLE to be analoguous to relative functions but for the
real data. For example, DOUBLE_to_DOUBLE is defined as

static void DOUBLE_to_DOUBLE(double *ip, int ipstep, 
                             double *op, int opstep, int n)
{int i; for(i=0;i<n;i++,ip+=ipstep,op+=opstep) {*op = (double)*ip;}}

So, I would have expected CDOUBLE_to_CDOUBLE to be

static void CDOUBLE_to_CDOUBLE(double *ip, int ipstep,
                             double *op, int opstep, int n)
{  int i; 
   for(i=0;i<n;i++,ip+=ipstep,op+=opstep) {
     *op = (double)*ip;           /* copy real part */
     *(op+1) = (double)*(ip+1);   /* copy imaginary part that always
                                     follows the real part in memory */

Could someone explain how Numeric can work with the current

Because I don't understand which one is broken, the Numeric's
CDOUBLE_to_CDOUBLE (and relative) functions, or my code.
The latter may be the case, but to fix it, I need some clarification on
the issue. Can you help me?


/************************* copy_ND_array *******************************/

#define INCREMENT(ret_ind, nd, max_ind) \
{ \
  int k; \
  k = (nd) - 1; \
  if (k<0) (ret_ind)[0] = (max_ind)[0]; else \
  if (++(ret_ind)[k] >= (max_ind)[k]) { \
    while (k >= 0 && ((ret_ind)[k] >= (max_ind)[k]-1)) \
      (ret_ind)[k--] = 0; \
    if (k >= 0) (ret_ind)[k]++; \
    else (ret_ind)[0] = (max_ind)[0]; \
  }  \

#define CALCINDEX(indx, nd_index, strides, ndim) \
{ \
  int i; \
  indx = 0; \
  for (i=0; i < (ndim); i++)  \
    indx += nd_index[i]*strides[i]; \

int copy_ND_array(const PyArrayObject *in, PyArrayObject *out)

  /* This routine copies an N-D array in to an N-D array out where both
     can be discontiguous.  An appropriate (raw) cast is made on the data.

  /* It works by using an N-1 length vector to hold the N-1 first indices 
     into the array.  This counter is looped through copying (and casting) 
     the entire last dimension at a time.

  int *nd_index, indx1;
  int indx2, last_dim;
  int instep, outstep;

  if (0 == in->nd) {
    in->descr->cast[out->descr->type_num]((void *)in->data,1,
    return 0;
  if (1 == in->nd) {
    in->descr->cast[out->descr->type_num]((void *)in->data,1,
    return 0;
  nd_index = (int *)calloc(in->nd-1,sizeof(int));
  last_dim = in->nd - 1;
  instep = in->strides[last_dim] / in->descr->elsize;
  outstep = out->strides[last_dim] / out->descr->elsize;
  if (NULL == nd_index ) {
     fprintf(stderr,"Could not allocate memory for index array.\n");
     return -1;

  while(nd_index[0] != in->dimensions[0]) {
    /* Copy (with an appropriate cast) the last dimension of the array */
  return 0;
/* EOF copy_ND_array */

More information about the Numpy-discussion mailing list