/* * Sorts items so stride is descending, because C-order * is the default in the face of ambiguity. */ public int CompareTo(object obj) { npy_stride_sort_item a = this; npy_stride_sort_item b = obj as npy_stride_sort_item; npy_intp astride = a.stride; npy_intp bstride = b.stride; /* Sort the absolute value of the strides */ if (astride < 0) { astride = -astride; } if (bstride < 0) { bstride = -bstride; } if (astride == bstride) { /* * Make the qsort stable by next comparing the perm order. * (Note that two perm entries will never be equal) */ npy_intp aperm = a.perm; npy_intp bperm = b.perm; return((aperm < bperm) ? -1 : 1); } if (astride > bstride) { return(-1); } return(1); }
/* * Prepares shape and strides for a simple raw array iteration. * This sorts the strides into FORTRAN order, reverses any negative * strides, then coalesces axes where possible. The results are * filled in the output parameters. * * This is intended for simple, lightweight iteration over arrays * where no buffering of any kind is needed, and the array may * not be stored as a PyArrayObject. * * The arrays shape, out_shape, strides, and out_strides must all * point to different data. * * Returns 0 on success, -1 on failure. */ internal static int PyArray_PrepareOneRawArrayIter(int ndim, npy_intp[] shape, VoidPtr data, npy_intp[] strides, ref int out_ndim, npy_intp[] out_shape, ref VoidPtr out_data, npy_intp[] out_strides) { npy_stride_sort_item [] strideperm = new npy_stride_sort_item[npy_defs.NPY_MAXDIMS]; int i, j; /* Special case 0 and 1 dimensions */ if (ndim == 0) { out_ndim = 1; out_data = data; out_shape[0] = 1; out_strides[0] = 0; return(0); } else if (ndim == 1) { npy_intp stride_entry = strides[0], shape_entry = shape[0]; out_ndim = 1; out_shape[0] = shape[0]; /* Always make a positive stride */ if (stride_entry >= 0) { out_data = data; out_strides[0] = stride_entry; } else { out_data = data + stride_entry * (shape_entry - 1); out_strides[0] = -stride_entry; } return(0); } /* Sort the axes based on the destination strides */ PyArray_CreateSortedStridePerm(ndim, strides, strideperm); for (i = 0; i < ndim; ++i) { npy_intp iperm = strideperm[ndim - i - 1].perm; out_shape[i] = shape[iperm]; out_strides[i] = strides[iperm]; } /* Reverse any negative strides */ for (i = 0; i < ndim; ++i) { npy_intp stride_entry = out_strides[i], shape_entry = out_shape[i]; if (stride_entry < 0) { data += stride_entry * (shape_entry - 1); out_strides[i] = -stride_entry; } /* Detect 0-size arrays here */ if (shape_entry == 0) { out_ndim = 1; out_data = data; out_shape[0] = 0; out_strides[0] = 0; return(0); } } /* Coalesce any dimensions where possible */ i = 0; for (j = 1; j < ndim; ++j) { if (out_shape[i] == 1) { /* Drop axis i */ out_shape[i] = out_shape[j]; out_strides[i] = out_strides[j]; } else if (out_shape[j] == 1) { /* Drop axis j */ } else if (out_strides[i] * out_shape[i] == out_strides[j]) { /* Coalesce axes i and j */ out_shape[i] *= out_shape[j]; } else { /* Can't coalesce, go to next i */ ++i; out_shape[i] = out_shape[j]; out_strides[i] = out_strides[j]; } } ndim = i + 1; #if false /* DEBUG */ { printf("raw iter ndim %d\n", ndim); printf("shape: "); for (i = 0; i < ndim; ++i) { printf("%d ", (int)out_shape[i]); } printf("\n"); printf("strides: "); for (i = 0; i < ndim; ++i) { printf("%d ", (int)out_strides[i]); } printf("\n"); } #endif out_data = data; out_ndim = ndim; return(0); }
/* * The same as PyArray_PrepareOneRawArrayIter, but for three * operands instead of one. Any broadcasting of the three operands * should have already been done before calling this function, * as the ndim and shape is only specified once for all operands. * * Only the strides of the first operand are used to reorder * the dimensions, no attempt to consider all the strides together * is made, as is done in the NpyIter object. * * You can use this together with NPY_RAW_ITER_START and * NPY_RAW_ITER_THREE_NEXT to handle the looping boilerplate of everything * but the innermost loop (which is for idim == 0). * * Returns 0 on success, -1 on failure. */ internal static int PyArray_PrepareThreeRawArrayIter(int ndim, npy_intp[] shape, VoidPtr dataA, npy_intp[] stridesA, VoidPtr dataB, npy_intp[] stridesB, VoidPtr dataC, npy_intp[] stridesC, ref int out_ndim, npy_intp[] out_shape, ref VoidPtr out_dataA, npy_intp[] out_stridesA, ref VoidPtr out_dataB, npy_intp[] out_stridesB, ref VoidPtr out_dataC, npy_intp[] out_stridesC) { npy_stride_sort_item [] strideperm = new npy_stride_sort_item[npy_defs.NPY_MAXDIMS]; int i, j; /* Special case 0 and 1 dimensions */ if (ndim == 0) { out_ndim = 1; out_dataA = dataA; out_dataB = dataB; out_dataC = dataC; out_shape[0] = 1; out_stridesA[0] = 0; out_stridesB[0] = 0; out_stridesC[0] = 0; return(0); } else if (ndim == 1) { npy_intp stride_entryA = stridesA[0]; npy_intp stride_entryB = stridesB[0]; npy_intp stride_entryC = stridesC[0]; npy_intp shape_entry = shape[0]; out_ndim = 1; out_shape[0] = shape[0]; /* Always make a positive stride for the first operand */ if (stride_entryA >= 0) { out_dataA = dataA; out_dataB = dataB; out_dataC = dataC; out_stridesA[0] = stride_entryA; out_stridesB[0] = stride_entryB; out_stridesC[0] = stride_entryC; } else { out_dataA = dataA + stride_entryA * (shape_entry - 1); out_dataB = dataB + stride_entryB * (shape_entry - 1); out_dataC = dataC + stride_entryC * (shape_entry - 1); out_stridesA[0] = -stride_entryA; out_stridesB[0] = -stride_entryB; out_stridesC[0] = -stride_entryC; } return(0); } /* Sort the axes based on the destination strides */ PyArray_CreateSortedStridePerm(ndim, stridesA, strideperm); for (i = 0; i < ndim; ++i) { npy_intp iperm = strideperm[ndim - i - 1].perm; out_shape[i] = shape[iperm]; out_stridesA[i] = stridesA[iperm]; out_stridesB[i] = stridesB[iperm]; out_stridesC[i] = stridesC[iperm]; } /* Reverse any negative strides of operand A */ for (i = 0; i < ndim; ++i) { npy_intp stride_entryA = out_stridesA[i]; npy_intp stride_entryB = out_stridesB[i]; npy_intp stride_entryC = out_stridesC[i]; npy_intp shape_entry = out_shape[i]; if (stride_entryA < 0) { dataA += stride_entryA * (shape_entry - 1); dataB += stride_entryB * (shape_entry - 1); dataC += stride_entryC * (shape_entry - 1); out_stridesA[i] = -stride_entryA; out_stridesB[i] = -stride_entryB; out_stridesC[i] = -stride_entryC; } /* Detect 0-size arrays here */ if (shape_entry == 0) { out_ndim = 1; out_dataA = dataA; out_dataB = dataB; out_dataC = dataC; out_shape[0] = 0; out_stridesA[0] = 0; out_stridesB[0] = 0; out_stridesC[0] = 0; return(0); } } /* Coalesce any dimensions where possible */ i = 0; for (j = 1; j < ndim; ++j) { if (out_shape[i] == 1) { /* Drop axis i */ out_shape[i] = out_shape[j]; out_stridesA[i] = out_stridesA[j]; out_stridesB[i] = out_stridesB[j]; out_stridesC[i] = out_stridesC[j]; } else if (out_shape[j] == 1) { /* Drop axis j */ } else if (out_stridesA[i] * out_shape[i] == out_stridesA[j] && out_stridesB[i] * out_shape[i] == out_stridesB[j] && out_stridesC[i] * out_shape[i] == out_stridesC[j]) { /* Coalesce axes i and j */ out_shape[i] *= out_shape[j]; } else { /* Can't coalesce, go to next i */ ++i; out_shape[i] = out_shape[j]; out_stridesA[i] = out_stridesA[j]; out_stridesB[i] = out_stridesB[j]; out_stridesC[i] = out_stridesC[j]; } } ndim = i + 1; out_dataA = dataA; out_dataB = dataB; out_dataC = dataC; out_ndim = ndim; return(0); }