void nplist_to_C_double_array(PyArrayObject *in_array, double *out_list, int N) { NpyIter *in_iter; NpyIter_IterNextFunc *in_iternext; double **in_ptr; int itr; in_iter = NpyIter_New(in_array, NPY_ITER_READONLY, NPY_KEEPORDER, NPY_NO_CASTING, NULL); if (in_iter == NULL) goto fail; in_iternext = NpyIter_GetIterNext(in_iter, NULL); if (in_iternext == NULL){ NpyIter_Deallocate(in_iter); goto fail; } /* interator pointer to actual numpy data */ in_ptr = (double **) NpyIter_GetDataPtrArray(in_iter); itr=0; do { out_list[itr++] = **in_ptr; } while(in_iternext(in_iter)); NpyIter_Deallocate(in_iter); fail: return NULL; }
/** * parseFloatVec3(vec_in, vec_out) * * @param[in] vec_in the python array to extract elements from * @param[out] vec_out float array of the numbers * @return true if successful, false if not * * Convert a python array type to a 3 element float * vector. */ static bool parseFloatVecN(PyArrayObject *vec_in, float *vec_out, int N) { /* verify it is a valid vector */ if (not_doublevector(vec_in)) return false; if (PyArray_DIM(vec_in,0) != N) { PyErr_Format(PyExc_ValueError, "Vector length incorrect. Received %ld and expected %d", PyArray_DIM(vec_in,0), N); return false; } NpyIter *iter; NpyIter_IterNextFunc *iternext; /* create the iterators */ iter = NpyIter_New(vec_in, NPY_ITER_READONLY, NPY_KEEPORDER, NPY_NO_CASTING, NULL); if (iter == NULL) goto fail; iternext = NpyIter_GetIterNext(iter, NULL); if (iternext == NULL) { NpyIter_Deallocate(iter); goto fail; } double ** dataptr = (double **) NpyIter_GetDataPtrArray(iter); /* iterate over the arrays */ int i = 0; do { vec_out[i++] = **dataptr; } while(iternext(iter) && (i < N)); NpyIter_Deallocate(iter); return true; fail: fprintf(stderr, "Parse fail\r\n"); return false; }
void Fn::NumpyInput::reset() { _io = std::make_shared<IO_double>(_dim,_inputType); // setup numpy iterator if (_iter) { NpyIter_Deallocate(_iter); _iter = NULL; } PyArray_Descr* dtype = PyArray_DescrFromType(NPY_DOUBLE); _iter = NpyIter_New( (PyArrayObject*)_arr, NPY_ITER_READONLY| NPY_ITER_EXTERNAL_LOOP| NPY_ITER_REFS_OK, NPY_KEEPORDER, NPY_UNSAFE_CASTING, dtype ); Py_DECREF(dtype); if (_iter == NULL) { throw std::invalid_argument("An unknown error was encountered. Please contact developers."); } _iternext = NpyIter_GetIterNext(_iter, NULL); if (_iternext == NULL) { NpyIter_Deallocate(_iter); throw std::invalid_argument("An unknown error was encountered. Please contact developers."); } /* The location of the data pointer which the iterator may update */ _dataptr = NpyIter_GetDataPtrArray(_iter); /* The location of the stride which the iterator may update */ _strideptr = NpyIter_GetInnerStrideArray(_iter); /* The location of the inner loop size which the iterator may update */ _innersizeptr = NpyIter_GetInnerLoopSizePtr(_iter); _count = *_innersizeptr; _data = *_dataptr; grab(); }
/* * This function executes all the standard NumPy reduction function * boilerplate code, just calling assign_identity and the appropriate * inner loop function where necessary. * * operand : The array to be reduced. * out : NULL, or the array into which to place the result. * wheremask : NOT YET SUPPORTED, but this parameter is placed here * so that support can be added in the future without breaking * API compatibility. Pass in NULL. * operand_dtype : The dtype the inner loop expects for the operand. * result_dtype : The dtype the inner loop expects for the result. * casting : The casting rule to apply to the operands. * axis_flags : Flags indicating the reduction axes of 'operand'. * reorderable : If True, the reduction being done is reorderable, which * means specifying multiple axes of reduction at once is ok, * and the reduction code may calculate the reduction in an * arbitrary order. The calculation may be reordered because * of cache behavior or multithreading requirements. * keepdims : If true, leaves the reduction dimensions in the result * with size one. * subok : If true, the result uses the subclass of operand, otherwise * it is always a base class ndarray. * assign_identity : If NULL, PyArray_InitializeReduceResult is used, otherwise * this function is called to initialize the result to * the reduction's unit. * loop : The loop which does the reduction. * data : Data which is passed to assign_identity and the inner loop. * buffersize : Buffer size for the iterator. For the default, pass in 0. * funcname : The name of the reduction function, for error messages. * errormask : forwarded from _get_bufsize_errmask * * TODO FIXME: if you squint, this is essentially an second independent * implementation of generalized ufuncs with signature (i)->(), plus a few * extra bells and whistles. (Indeed, as far as I can tell, it was originally * split out to support a fancy version of count_nonzero... which is not * actually a reduction function at all, it's just a (i)->() function!) So * probably these two implementation should be merged into one. (In fact it * would be quite nice to support axis= and keepdims etc. for arbitrary * generalized ufuncs!) */ NPY_NO_EXPORT PyArrayObject * PyUFunc_ReduceWrapper(PyArrayObject *operand, PyArrayObject *out, PyArrayObject *wheremask, PyArray_Descr *operand_dtype, PyArray_Descr *result_dtype, NPY_CASTING casting, npy_bool *axis_flags, int reorderable, int keepdims, int subok, PyArray_AssignReduceIdentityFunc *assign_identity, PyArray_ReduceLoopFunc *loop, void *data, npy_intp buffersize, const char *funcname, int errormask) { PyArrayObject *result = NULL, *op_view = NULL; npy_intp skip_first_count = 0; /* Iterator parameters */ NpyIter *iter = NULL; PyArrayObject *op[2]; PyArray_Descr *op_dtypes[2]; npy_uint32 flags, op_flags[2]; /* Validate that the parameters for future expansion are NULL */ if (wheremask != NULL) { PyErr_SetString(PyExc_RuntimeError, "Reduce operations in NumPy do not yet support " "a where mask"); return NULL; } /* * This either conforms 'out' to the ndim of 'operand', or allocates * a new array appropriate for this reduction. * * A new array with WRITEBACKIFCOPY is allocated if operand and out have memory * overlap. */ Py_INCREF(result_dtype); result = PyArray_CreateReduceResult(operand, out, result_dtype, axis_flags, keepdims, subok, funcname); if (result == NULL) { goto fail; } /* * Initialize the result to the reduction unit if possible, * otherwise copy the initial values and get a view to the rest. */ if (assign_identity != NULL) { /* * If this reduction is non-reorderable, make sure there are * only 0 or 1 axes in axis_flags. */ if (!reorderable && check_nonreorderable_axes(PyArray_NDIM(operand), axis_flags, funcname) < 0) { goto fail; } if (assign_identity(result, data) < 0) { goto fail; } op_view = operand; Py_INCREF(op_view); } else { op_view = PyArray_InitializeReduceResult(result, operand, axis_flags, reorderable, &skip_first_count, funcname); if (op_view == NULL) { goto fail; } /* empty op_view signals no reduction; but 0-d arrays cannot be empty */ if ((PyArray_SIZE(op_view) == 0) || (PyArray_NDIM(operand) == 0)) { Py_DECREF(op_view); op_view = NULL; goto finish; } } /* Set up the iterator */ op[0] = result; op[1] = op_view; op_dtypes[0] = result_dtype; op_dtypes[1] = operand_dtype; flags = NPY_ITER_BUFFERED | NPY_ITER_EXTERNAL_LOOP | NPY_ITER_GROWINNER | NPY_ITER_DONT_NEGATE_STRIDES | NPY_ITER_ZEROSIZE_OK | NPY_ITER_REDUCE_OK | NPY_ITER_REFS_OK; op_flags[0] = NPY_ITER_READWRITE | NPY_ITER_ALIGNED | NPY_ITER_NO_SUBTYPE; op_flags[1] = NPY_ITER_READONLY | NPY_ITER_ALIGNED; iter = NpyIter_AdvancedNew(2, op, flags, NPY_KEEPORDER, casting, op_flags, op_dtypes, -1, NULL, NULL, buffersize); if (iter == NULL) { goto fail; } /* Start with the floating-point exception flags cleared */ PyUFunc_clearfperr(); if (NpyIter_GetIterSize(iter) != 0) { NpyIter_IterNextFunc *iternext; char **dataptr; npy_intp *strideptr; npy_intp *countptr; int needs_api; iternext = NpyIter_GetIterNext(iter, NULL); if (iternext == NULL) { goto fail; } dataptr = NpyIter_GetDataPtrArray(iter); strideptr = NpyIter_GetInnerStrideArray(iter); countptr = NpyIter_GetInnerLoopSizePtr(iter); needs_api = NpyIter_IterationNeedsAPI(iter); /* Straightforward reduction */ if (loop == NULL) { PyErr_Format(PyExc_RuntimeError, "reduction operation %s did not supply an " "inner loop function", funcname); goto fail; } if (loop(iter, dataptr, strideptr, countptr, iternext, needs_api, skip_first_count, data) < 0) { goto fail; } } /* Check whether any errors occurred during the loop */ if (PyErr_Occurred() || _check_ufunc_fperr(errormask, NULL, "reduce") < 0) { goto fail; } NpyIter_Deallocate(iter); Py_DECREF(op_view); finish: /* Strip out the extra 'one' dimensions in the result */ if (out == NULL) { if (!keepdims) { PyArray_RemoveAxesInPlace(result, axis_flags); } } else { PyArray_ResolveWritebackIfCopy(result); /* prevent spurious warnings */ Py_DECREF(result); result = out; Py_INCREF(result); } return result; fail: PyArray_ResolveWritebackIfCopy(result); /* prevent spurious warnings */ Py_XDECREF(result); Py_XDECREF(op_view); if (iter != NULL) { NpyIter_Deallocate(iter); } return NULL; }
/* unravel_index implementation - see add_newdocs.py */ NPY_NO_EXPORT PyObject * arr_unravel_index(PyObject *self, PyObject *args, PyObject *kwds) { PyObject *indices0 = NULL, *ret_tuple = NULL; PyArrayObject *ret_arr = NULL; PyArrayObject *indices = NULL; PyArray_Descr *dtype = NULL; PyArray_Dims dimensions={0,0}; NPY_ORDER order = NPY_CORDER; npy_intp unravel_size; NpyIter *iter = NULL; int i, ret_ndim; npy_intp ret_dims[NPY_MAXDIMS], ret_strides[NPY_MAXDIMS]; char *kwlist[] = {"indices", "dims", "order", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&|O&:unravel_index", kwlist, &indices0, PyArray_IntpConverter, &dimensions, PyArray_OrderConverter, &order)) { goto fail; } if (dimensions.len == 0) { PyErr_SetString(PyExc_ValueError, "dims must have at least one value"); goto fail; } unravel_size = PyArray_MultiplyList(dimensions.ptr, dimensions.len); if (!PyArray_Check(indices0)) { indices = (PyArrayObject*)PyArray_FromAny(indices0, NULL, 0, 0, 0, NULL); if (indices == NULL) { goto fail; } } else { indices = (PyArrayObject *)indices0; Py_INCREF(indices); } dtype = PyArray_DescrFromType(NPY_INTP); if (dtype == NULL) { goto fail; } iter = NpyIter_New(indices, NPY_ITER_READONLY| NPY_ITER_ALIGNED| NPY_ITER_BUFFERED| NPY_ITER_ZEROSIZE_OK| NPY_ITER_DONT_NEGATE_STRIDES| NPY_ITER_MULTI_INDEX, NPY_KEEPORDER, NPY_SAME_KIND_CASTING, dtype); if (iter == NULL) { goto fail; } /* * Create the return array with a layout compatible with the indices * and with a dimension added to the end for the multi-index */ ret_ndim = PyArray_NDIM(indices) + 1; if (NpyIter_GetShape(iter, ret_dims) != NPY_SUCCEED) { goto fail; } ret_dims[ret_ndim-1] = dimensions.len; if (NpyIter_CreateCompatibleStrides(iter, dimensions.len*sizeof(npy_intp), ret_strides) != NPY_SUCCEED) { goto fail; } ret_strides[ret_ndim-1] = sizeof(npy_intp); /* Remove the multi-index and inner loop */ if (NpyIter_RemoveMultiIndex(iter) != NPY_SUCCEED) { goto fail; } if (NpyIter_EnableExternalLoop(iter) != NPY_SUCCEED) { goto fail; } ret_arr = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, ret_ndim, ret_dims, ret_strides, NULL, 0, NULL); dtype = NULL; if (ret_arr == NULL) { goto fail; } if (order == NPY_CORDER) { if (NpyIter_GetIterSize(iter) != 0) { NpyIter_IterNextFunc *iternext; char **dataptr; npy_intp *strides; npy_intp *countptr, count; npy_intp *coordsptr = (npy_intp *)PyArray_DATA(ret_arr); iternext = NpyIter_GetIterNext(iter, NULL); if (iternext == NULL) { goto fail; } dataptr = NpyIter_GetDataPtrArray(iter); strides = NpyIter_GetInnerStrideArray(iter); countptr = NpyIter_GetInnerLoopSizePtr(iter); do { count = *countptr; if (unravel_index_loop_corder(dimensions.len, dimensions.ptr, unravel_size, count, *dataptr, *strides, coordsptr) != NPY_SUCCEED) { goto fail; } coordsptr += count*dimensions.len; } while(iternext(iter)); } } else if (order == NPY_FORTRANORDER) { if (NpyIter_GetIterSize(iter) != 0) { NpyIter_IterNextFunc *iternext; char **dataptr; npy_intp *strides; npy_intp *countptr, count; npy_intp *coordsptr = (npy_intp *)PyArray_DATA(ret_arr); iternext = NpyIter_GetIterNext(iter, NULL); if (iternext == NULL) { goto fail; } dataptr = NpyIter_GetDataPtrArray(iter); strides = NpyIter_GetInnerStrideArray(iter); countptr = NpyIter_GetInnerLoopSizePtr(iter); do { count = *countptr; if (unravel_index_loop_forder(dimensions.len, dimensions.ptr, unravel_size, count, *dataptr, *strides, coordsptr) != NPY_SUCCEED) { goto fail; } coordsptr += count*dimensions.len; } while(iternext(iter)); } } else { PyErr_SetString(PyExc_ValueError, "only 'C' or 'F' order is permitted"); goto fail; } /* Now make a tuple of views, one per index */ ret_tuple = PyTuple_New(dimensions.len); if (ret_tuple == NULL) { goto fail; } for (i = 0; i < dimensions.len; ++i) { PyArrayObject *view; view = (PyArrayObject *)PyArray_New(&PyArray_Type, ret_ndim-1, ret_dims, NPY_INTP, ret_strides, PyArray_BYTES(ret_arr) + i*sizeof(npy_intp), 0, NPY_ARRAY_WRITEABLE, NULL); if (view == NULL) { goto fail; } Py_INCREF(ret_arr); if (PyArray_SetBaseObject(view, (PyObject *)ret_arr) < 0) { Py_DECREF(view); goto fail; } PyTuple_SET_ITEM(ret_tuple, i, PyArray_Return(view)); } Py_DECREF(ret_arr); Py_XDECREF(indices); PyDimMem_FREE(dimensions.ptr); NpyIter_Deallocate(iter); return ret_tuple; fail: Py_XDECREF(ret_tuple); Py_XDECREF(ret_arr); Py_XDECREF(dtype); Py_XDECREF(indices); PyDimMem_FREE(dimensions.ptr); NpyIter_Deallocate(iter); return NULL; }
/* ravel_multi_index implementation - see add_newdocs.py */ NPY_NO_EXPORT PyObject * arr_ravel_multi_index(PyObject *self, PyObject *args, PyObject *kwds) { int i, s; PyObject *mode0=NULL, *coords0=NULL; PyArrayObject *ret = NULL; PyArray_Dims dimensions={0,0}; npy_intp ravel_strides[NPY_MAXDIMS]; NPY_ORDER order = NPY_CORDER; NPY_CLIPMODE modes[NPY_MAXDIMS]; PyArrayObject *op[NPY_MAXARGS]; PyArray_Descr *dtype[NPY_MAXARGS]; npy_uint32 op_flags[NPY_MAXARGS]; NpyIter *iter = NULL; char *kwlist[] = {"multi_index", "dims", "mode", "order", NULL}; memset(op, 0, sizeof(op)); dtype[0] = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&|OO&:ravel_multi_index", kwlist, &coords0, PyArray_IntpConverter, &dimensions, &mode0, PyArray_OrderConverter, &order)) { goto fail; } if (dimensions.len+1 > NPY_MAXARGS) { PyErr_SetString(PyExc_ValueError, "too many dimensions passed to ravel_multi_index"); goto fail; } if (!PyArray_ConvertClipmodeSequence(mode0, modes, dimensions.len)) { goto fail; } switch (order) { case NPY_CORDER: s = 1; for (i = dimensions.len-1; i >= 0; --i) { ravel_strides[i] = s; s *= dimensions.ptr[i]; } break; case NPY_FORTRANORDER: s = 1; for (i = 0; i < dimensions.len; ++i) { ravel_strides[i] = s; s *= dimensions.ptr[i]; } break; default: PyErr_SetString(PyExc_ValueError, "only 'C' or 'F' order is permitted"); goto fail; } /* Get the multi_index into op */ if (sequence_to_arrays(coords0, op, dimensions.len, "multi_index") < 0) { goto fail; } for (i = 0; i < dimensions.len; ++i) { op_flags[i] = NPY_ITER_READONLY| NPY_ITER_ALIGNED; } op_flags[dimensions.len] = NPY_ITER_WRITEONLY| NPY_ITER_ALIGNED| NPY_ITER_ALLOCATE; dtype[0] = PyArray_DescrFromType(NPY_INTP); for (i = 1; i <= dimensions.len; ++i) { dtype[i] = dtype[0]; } iter = NpyIter_MultiNew(dimensions.len+1, op, NPY_ITER_BUFFERED| NPY_ITER_EXTERNAL_LOOP| NPY_ITER_ZEROSIZE_OK, NPY_KEEPORDER, NPY_SAME_KIND_CASTING, op_flags, dtype); if (iter == NULL) { goto fail; } if (NpyIter_GetIterSize(iter) != 0) { NpyIter_IterNextFunc *iternext; char **dataptr; npy_intp *strides; npy_intp *countptr; iternext = NpyIter_GetIterNext(iter, NULL); if (iternext == NULL) { goto fail; } dataptr = NpyIter_GetDataPtrArray(iter); strides = NpyIter_GetInnerStrideArray(iter); countptr = NpyIter_GetInnerLoopSizePtr(iter); do { if (ravel_multi_index_loop(dimensions.len, dimensions.ptr, ravel_strides, *countptr, modes, dataptr, strides) != NPY_SUCCEED) { goto fail; } } while(iternext(iter)); } ret = NpyIter_GetOperandArray(iter)[dimensions.len]; Py_INCREF(ret); Py_DECREF(dtype[0]); for (i = 0; i < dimensions.len; ++i) { Py_XDECREF(op[i]); } PyDimMem_FREE(dimensions.ptr); NpyIter_Deallocate(iter); return PyArray_Return(ret); fail: Py_XDECREF(dtype[0]); for (i = 0; i < dimensions.len; ++i) { Py_XDECREF(op[i]); } PyDimMem_FREE(dimensions.ptr); NpyIter_Deallocate(iter); return NULL; }
static PyObject * PyUFunc_Accumulate(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out, int axis, int otype) { PyArrayObject *op[2]; PyArray_Descr *op_dtypes[2] = {NULL, NULL}; int op_axes_arrays[2][NPY_MAXDIMS]; int *op_axes[2] = {op_axes_arrays[0], op_axes_arrays[1]}; npy_uint32 op_flags[2]; int idim, ndim, otype_final; int needs_api, need_outer_iterator; NpyIter *iter = NULL, *iter_inner = NULL; /* The selected inner loop */ PyUFuncGenericFunction innerloop = NULL; void *innerloopdata = NULL; const char *ufunc_name = ufunc->name ? ufunc->name : "(unknown)"; /* These parameters come from extobj= or from a TLS global */ int buffersize = 0, errormask = 0; NPY_BEGIN_THREADS_DEF; NPY_UF_DBG_PRINT1("\nEvaluating ufunc %s.accumulate\n", ufunc_name); #if 0 printf("Doing %s.accumulate on array with dtype : ", ufunc_name); PyObject_Print((PyObject *)PyArray_DESCR(arr), stdout, 0); printf("\n"); #endif if (_get_bufsize_errmask(NULL, "accumulate", &buffersize, &errormask) < 0) { return NULL; } /* Take a reference to out for later returning */ Py_XINCREF(out); otype_final = otype; if (get_binary_op_function(ufunc, &otype_final, &innerloop, &innerloopdata) < 0) { PyArray_Descr *dtype = PyArray_DescrFromType(otype); PyErr_Format(PyExc_ValueError, "could not find a matching type for %s.accumulate, " "requested type has type code '%c'", ufunc_name, dtype ? dtype->type : '-'); Py_XDECREF(dtype); goto fail; } ndim = PyArray_NDIM(arr); /* * Set up the output data type, using the input's exact * data type if the type number didn't change to preserve * metadata */ if (PyArray_DESCR(arr)->type_num == otype_final) { if (PyArray_ISNBO(PyArray_DESCR(arr)->byteorder)) { op_dtypes[0] = PyArray_DESCR(arr); Py_INCREF(op_dtypes[0]); } else { op_dtypes[0] = PyArray_DescrNewByteorder(PyArray_DESCR(arr), NPY_NATIVE); } } else { op_dtypes[0] = PyArray_DescrFromType(otype_final); } if (op_dtypes[0] == NULL) { goto fail; } #if NPY_UF_DBG_TRACING printf("Found %s.accumulate inner loop with dtype : ", ufunc_name); PyObject_Print((PyObject *)op_dtypes[0], stdout, 0); printf("\n"); #endif /* Set up the op_axes for the outer loop */ for (idim = 0; idim < ndim; ++idim) { op_axes_arrays[0][idim] = idim; op_axes_arrays[1][idim] = idim; } /* The per-operand flags for the outer loop */ op_flags[0] = NPY_ITER_READWRITE | NPY_ITER_NO_BROADCAST | NPY_ITER_ALLOCATE | NPY_ITER_NO_SUBTYPE; op_flags[1] = NPY_ITER_READONLY; op[0] = out; op[1] = arr; need_outer_iterator = (ndim > 1); /* We can't buffer, so must do UPDATEIFCOPY */ if (!PyArray_ISALIGNED(arr) || (out && !PyArray_ISALIGNED(out)) || !PyArray_EquivTypes(op_dtypes[0], PyArray_DESCR(arr)) || (out && !PyArray_EquivTypes(op_dtypes[0], PyArray_DESCR(out)))) { need_outer_iterator = 1; } if (need_outer_iterator) { int ndim_iter = 0; npy_uint32 flags = NPY_ITER_ZEROSIZE_OK| NPY_ITER_REFS_OK; PyArray_Descr **op_dtypes_param = NULL; /* * The way accumulate is set up, we can't do buffering, * so make a copy instead when necessary. */ ndim_iter = ndim; flags |= NPY_ITER_MULTI_INDEX; /* Add some more flags */ op_flags[0] |= NPY_ITER_UPDATEIFCOPY|NPY_ITER_ALIGNED; op_flags[1] |= NPY_ITER_COPY|NPY_ITER_ALIGNED; op_dtypes_param = op_dtypes; op_dtypes[1] = op_dtypes[0]; NPY_UF_DBG_PRINT("Allocating outer iterator\n"); iter = NpyIter_AdvancedNew(2, op, flags, NPY_KEEPORDER, NPY_UNSAFE_CASTING, op_flags, op_dtypes_param, ndim_iter, op_axes, NULL, 0); if (iter == NULL) { goto fail; } /* In case COPY or UPDATEIFCOPY occurred */ op[0] = NpyIter_GetOperandArray(iter)[0]; op[1] = NpyIter_GetOperandArray(iter)[1]; if (PyArray_SIZE(op[0]) == 0) { if (out == NULL) { out = op[0]; Py_INCREF(out); } goto finish; } if (NpyIter_RemoveAxis(iter, axis) != NPY_SUCCEED) { goto fail; } if (NpyIter_RemoveMultiIndex(iter) != NPY_SUCCEED) { goto fail; } } /* Get the output */ if (out == NULL) { if (iter) { op[0] = out = NpyIter_GetOperandArray(iter)[0]; Py_INCREF(out); } else { PyArray_Descr *dtype = op_dtypes[0]; Py_INCREF(dtype); op[0] = out = (PyArrayObject *)PyArray_NewFromDescr( &PyArray_Type, dtype, ndim, PyArray_DIMS(op[1]), NULL, NULL, 0, NULL); if (out == NULL) { goto fail; } } } /* * If the reduction axis has size zero, either return the reduction * unit for UFUNC_REDUCE, or return the zero-sized output array * for UFUNC_ACCUMULATE. */ if (PyArray_DIM(op[1], axis) == 0) { goto finish; } else if (PyArray_SIZE(op[0]) == 0) { goto finish; } if (iter && NpyIter_GetIterSize(iter) != 0) { char *dataptr_copy[3]; npy_intp stride_copy[3]; npy_intp count_m1, stride0, stride1; NpyIter_IterNextFunc *iternext; char **dataptr; int itemsize = op_dtypes[0]->elsize; /* Get the variables needed for the loop */ iternext = NpyIter_GetIterNext(iter, NULL); if (iternext == NULL) { goto fail; } dataptr = NpyIter_GetDataPtrArray(iter); /* Execute the loop with just the outer iterator */ count_m1 = PyArray_DIM(op[1], axis)-1; stride0 = 0, stride1 = PyArray_STRIDE(op[1], axis); NPY_UF_DBG_PRINT("UFunc: Reduce loop with just outer iterator\n"); stride0 = PyArray_STRIDE(op[0], axis); stride_copy[0] = stride0; stride_copy[1] = stride1; stride_copy[2] = stride0; needs_api = NpyIter_IterationNeedsAPI(iter); NPY_BEGIN_THREADS_NDITER(iter); do { dataptr_copy[0] = dataptr[0]; dataptr_copy[1] = dataptr[1]; dataptr_copy[2] = dataptr[0]; /* * Copy the first element to start the reduction. * * Output (dataptr[0]) and input (dataptr[1]) may point to * the same memory, e.g. np.add.accumulate(a, out=a). */ if (otype == NPY_OBJECT) { /* * Incref before decref to avoid the possibility of the * reference count being zero temporarily. */ Py_XINCREF(*(PyObject **)dataptr_copy[1]); Py_XDECREF(*(PyObject **)dataptr_copy[0]); *(PyObject **)dataptr_copy[0] = *(PyObject **)dataptr_copy[1]; } else { memmove(dataptr_copy[0], dataptr_copy[1], itemsize); } if (count_m1 > 0) { /* Turn the two items into three for the inner loop */ dataptr_copy[1] += stride1; dataptr_copy[2] += stride0; NPY_UF_DBG_PRINT1("iterator loop count %d\n", (int)count_m1); innerloop(dataptr_copy, &count_m1, stride_copy, innerloopdata); } } while (iternext(iter)); NPY_END_THREADS; } else if (iter == NULL) { char *dataptr_copy[3]; npy_intp stride_copy[3]; int itemsize = op_dtypes[0]->elsize; /* Execute the loop with no iterators */ npy_intp count = PyArray_DIM(op[1], axis); npy_intp stride0 = 0, stride1 = PyArray_STRIDE(op[1], axis); NPY_UF_DBG_PRINT("UFunc: Reduce loop with no iterators\n"); if (PyArray_NDIM(op[0]) != PyArray_NDIM(op[1]) || !PyArray_CompareLists(PyArray_DIMS(op[0]), PyArray_DIMS(op[1]), PyArray_NDIM(op[0]))) { PyErr_SetString(PyExc_ValueError, "provided out is the wrong size " "for the reduction"); goto fail; } stride0 = PyArray_STRIDE(op[0], axis); stride_copy[0] = stride0; stride_copy[1] = stride1; stride_copy[2] = stride0; /* Turn the two items into three for the inner loop */ dataptr_copy[0] = PyArray_BYTES(op[0]); dataptr_copy[1] = PyArray_BYTES(op[1]); dataptr_copy[2] = PyArray_BYTES(op[0]); /* * Copy the first element to start the reduction. * * Output (dataptr[0]) and input (dataptr[1]) may point to the * same memory, e.g. np.add.accumulate(a, out=a). */ if (otype == NPY_OBJECT) { /* * Incref before decref to avoid the possibility of the * reference count being zero temporarily. */ Py_XINCREF(*(PyObject **)dataptr_copy[1]); Py_XDECREF(*(PyObject **)dataptr_copy[0]); *(PyObject **)dataptr_copy[0] = *(PyObject **)dataptr_copy[1]; } else { memmove(dataptr_copy[0], dataptr_copy[1], itemsize); } if (count > 1) { --count; dataptr_copy[1] += stride1; dataptr_copy[2] += stride0; NPY_UF_DBG_PRINT1("iterator loop count %d\n", (int)count); needs_api = PyDataType_REFCHK(op_dtypes[0]); if (!needs_api) { NPY_BEGIN_THREADS_THRESHOLDED(count); } innerloop(dataptr_copy, &count, stride_copy, innerloopdata); NPY_END_THREADS; } } finish: Py_XDECREF(op_dtypes[0]); NpyIter_Deallocate(iter); NpyIter_Deallocate(iter_inner); return (PyObject *)out; fail: Py_XDECREF(out); Py_XDECREF(op_dtypes[0]); NpyIter_Deallocate(iter); NpyIter_Deallocate(iter_inner); return NULL; }
/********************* * python interface * *********************/ static PyObject* eeint(PyObject* self, PyObject* args){ /*** input variables ***/ /* dictionary */ PyObject *in_dict; PyObject *dictList; PyObject *dictList_fast; PyObject *pyStr; PyObject *item; /* numpy array */ PyArrayObject *in_array1, *in_array2; NpyIter *in_iter; NpyIter_IterNextFunc *in_iternext; /* C data type for input */ int Ngo, Nao; int N, itr; /* basis function variables */ double **in_ptr; // address to numpy pointer double *center; // gaussian center double *cef; // contraction coefficients int *ng; // number of gaussians per AO double *exp; // gaussian exponents int *lm_xyz; // angular momentum /* python output variables */ PyObject *py_out; PyObject *py_out2; double *data, *overlap; double element; int i, j, k, l; int s, t, u, v, w; int mat_dim[4]; /* parse numpy array and two integers as argument */ if (!PyArg_ParseTuple(args, "OO!O!", &in_dict, &PyArray_Type, &in_array1, &PyArray_Type, &in_array2 )) return NULL; if(in_array1 == NULL) return NULL; /*********************** * Construct input data * ***********************/ /*** access dict_list data ***/ /* exponents */ pyStr = PyString_FromString("exponents"); dictList = PyDict_GetItem(in_dict, pyStr); dictList_fast = PySequence_Fast( dictList, "expected a sequence"); Ngo = PySequence_Size(dictList); exp = (double*) malloc(Ngo * sizeof(double)); for(i=0;i<Ngo;i++){ item = PySequence_Fast_GET_ITEM(dictList_fast, i); exp[i] = PyFloat_AsDouble(item); } Py_DECREF(dictList_fast); /* coefficients */ pyStr = PyString_FromString("coefficients"); dictList = PyDict_GetItem(in_dict, pyStr); dictList_fast = PySequence_Fast( dictList, "expected a sequence"); cef = (double*) malloc(Ngo * sizeof(double)); for(i=0;i<Ngo;i++){ item = PySequence_Fast_GET_ITEM(dictList_fast, i); cef[i] = PyFloat_AsDouble(item); } Py_DECREF(dictList_fast); /* number of gaussians per shell */ pyStr = PyString_FromString("n_gaussians"); dictList = PyDict_GetItem(in_dict, pyStr); dictList_fast = PySequence_Fast( dictList, "expected a sequence"); Nao = PySequence_Size(dictList); ng = (int*) malloc(Nao * sizeof(int)); for(i=0;i<Nao;i++){ item = PySequence_Fast_GET_ITEM(dictList_fast, i); ng[i] = PyFloat_AsDouble(item); } Py_DECREF(dictList_fast); /*** end of dict_list data ***/ /*** create the iterators, necessary to access numpy array ***/ /* center */ in_iter = NpyIter_New(in_array1, NPY_ITER_READONLY, NPY_KEEPORDER, NPY_NO_CASTING, NULL); if (in_iter == NULL) goto fail; in_iternext = NpyIter_GetIterNext(in_iter, NULL); if (in_iternext == NULL){ NpyIter_Deallocate(in_iter); goto fail; } /* interator pointer to actual numpy data */ in_ptr = (double **) NpyIter_GetDataPtrArray(in_iter); center = (double*) malloc(3 * Nao * sizeof(double)); itr=0; do { center[itr++] = **in_ptr; } while(in_iternext(in_iter)); NpyIter_Deallocate(in_iter); /* lm_xyz */ in_iter = NpyIter_New(in_array2, NPY_ITER_READONLY, NPY_KEEPORDER, NPY_NO_CASTING, NULL); if (in_iter == NULL) goto fail; in_iternext = NpyIter_GetIterNext(in_iter, NULL); if (in_iternext == NULL){ NpyIter_Deallocate(in_iter); goto fail; } /* interator pointer to actual numpy data */ int **in_ptr2 = (int **) NpyIter_GetDataPtrArray(in_iter); lm_xyz = (int*) malloc(3 * Nao * sizeof(int)); itr=0; do { lm_xyz[itr++] = **in_ptr2; } while(in_iternext(in_iter)); NpyIter_Deallocate(in_iter); /*** end of numpy input data ***/ /***** end of input data construction *****/ /******************* * construct output * *******************/ for(i=0;i<4;i++) mat_dim[i] = Nao; py_out = (PyArrayObject*) PyArray_FromDims(4, mat_dim, NPY_DOUBLE); data = pyvector_to_Carrayptrs(py_out); /* renormalization */ renormalize(center, exp, cef, ng, lm_xyz, Nao); /* orthogonalize */ // no effect at the moment, for debug purpose //py_out2 = (PyArrayObject*) // PyArray_FromDims(2, mat_dim, NPY_DOUBLE); //overlap = pyvector_to_Carrayptrs(py_out2); //orthogonalize(overlap, center, exp, cef, ng, lm_xyz, Nao); #pragma omp parallel private(i, j, k, l, s, t, u, v, w)\ shared(data) { #pragma omp for schedule(dynamic) for(i=0;i<Nao;i++){ for(j=i;j<Nao;j++){ for(k=0;k<Nao;k++){ for(l=k;l<Nao;l++){ if(l+k >= i+j){ s = l + k*Nao + j*Nao*Nao + i*Nao*Nao*Nao; element = eeMatrix(center, exp, cef, ng, lm_xyz, Nao, i, j, k, l); data[s] = element; // symmetry for (ij|kl)=(ij|lk)=(ji|kl)=(ji|lk) t = k + l*Nao + j*Nao*Nao + i*Nao*Nao*Nao; //(ij|lk) u = l + k*Nao + i*Nao*Nao + j*Nao*Nao*Nao; //(ji|kl) v = k + l*Nao + i*Nao*Nao + j*Nao*Nao*Nao; //(ji|lk) data[t] = data[s]; data[u] = data[s]; data[v] = data[s]; // symmetry for (ij|kl)=(kl|ij)=(kl|ji)=(lk|ij)=(lk|ji) t = j + i*Nao + l*Nao*Nao + k*Nao*Nao*Nao; //(kl|ij) u = i + j*Nao + l*Nao*Nao + k*Nao*Nao*Nao; //(kl|ji) v = j + i*Nao + k*Nao*Nao + l*Nao*Nao*Nao; //(lk|ij) w = i + j*Nao + k*Nao*Nao + l*Nao*Nao*Nao; //(lk|ji) data[t] = data[s]; data[u] = data[s]; data[v] = data[s]; data[w] = data[s]; } } } } } } // end of omp loop /********************************* * clean up and return the result * *********************************/ free(exp); free(cef); free(ng); free(center); free(lm_xyz); //free(overlap); Py_INCREF(py_out); return Py_BuildValue("O", py_out); /* in case bad things happen */ fail: Py_XDECREF(py_out); return NULL; } // end of eeint function
/********************* * python interface * *********************/ static PyObject* eekernel(PyObject* self, PyObject* args){ /*** input variables ***/ /* dictionary */ PyObject *in_dict; PyObject *dictList; PyObject *dictList_fast; PyObject *pyStr; PyObject *item; /* list */ PyObject *in_list; PyObject *list_fast; /* numpy array */ PyArrayObject *in_array1, *in_array2, *in_array3; NpyIter *in_iter; NpyIter_IterNextFunc *in_iternext; /* C data type for input */ int Ngo, Nao; int N, itr; double *Z; double *R; /* basis function variables */ double **in_ptr; // address to numpy pointer double *center; // gaussian center double *cef; // contraction coefficients int *ng; // number of gaussians per AO double *exp; // gaussian exponents int *lm_xyz; // angular momentum /* python output variables */ PyObject *py_out; PyObject *py_out2; double *data, *overlap; int i, j, k; int mat_dim[3]; /* parse numpy array and two integers as argument */ if (!PyArg_ParseTuple(args, "OO!O!O!O", &in_dict, &PyArray_Type, &in_array1, &PyArray_Type, &in_array2, &PyArray_Type, &in_array3, &in_list )) return NULL; if(in_array1 == NULL) return NULL; /*********************** * Construct input data * ***********************/ /*** access dict_list data ***/ /* exponents */ pyStr = PyString_FromString("exponents"); dictList = PyDict_GetItem(in_dict, pyStr); dictList_fast = PySequence_Fast( dictList, "expected a sequence"); Ngo = PySequence_Size(dictList); exp = (double*) malloc(Ngo * sizeof(double)); for(i=0;i<Ngo;i++){ item = PySequence_Fast_GET_ITEM(dictList_fast, i); exp[i] = PyFloat_AsDouble(item); } Py_DECREF(dictList_fast); /* coefficients */ pyStr = PyString_FromString("coefficients"); dictList = PyDict_GetItem(in_dict, pyStr); dictList_fast = PySequence_Fast( dictList, "expected a sequence"); cef = (double*) malloc(Ngo * sizeof(double)); for(i=0;i<Ngo;i++){ item = PySequence_Fast_GET_ITEM(dictList_fast, i); cef[i] = PyFloat_AsDouble(item); } Py_DECREF(dictList_fast); /* number of gaussians per shell */ pyStr = PyString_FromString("n_gaussians"); dictList = PyDict_GetItem(in_dict, pyStr); dictList_fast = PySequence_Fast( dictList, "expected a sequence"); Nao = PySequence_Size(dictList); ng = (int*) malloc(Nao * sizeof(int)); for(i=0;i<Nao;i++){ item = PySequence_Fast_GET_ITEM(dictList_fast, i); ng[i] = PyFloat_AsDouble(item); } Py_DECREF(dictList_fast); /*** end of dict_list data ***/ /*** access python list data ***/ list_fast = PySequence_Fast(in_list, "expected a sequence"); N = PySequence_Size(in_list); Z = (double*) malloc(N * sizeof(double)); for(i=0;i<N;i++){ item = PySequence_Fast_GET_ITEM(list_fast, i); Z[i] = PyFloat_AsDouble(item); } Py_DECREF(list_fast); /*** end of list input data ***/ /*** create the iterators, necessary to access numpy array ***/ /* center */ in_iter = NpyIter_New(in_array1, NPY_ITER_READONLY, NPY_KEEPORDER, NPY_NO_CASTING, NULL); if (in_iter == NULL) goto fail; in_iternext = NpyIter_GetIterNext(in_iter, NULL); if (in_iternext == NULL){ NpyIter_Deallocate(in_iter); goto fail; } /* interator pointer to actual numpy data */ in_ptr = (double **) NpyIter_GetDataPtrArray(in_iter); center = (double*) malloc(3 * Nao * sizeof(double)); itr=0; do { center[itr++] = **in_ptr; } while(in_iternext(in_iter)); NpyIter_Deallocate(in_iter); /* lm_xyz */ in_iter = NpyIter_New(in_array2, NPY_ITER_READONLY, NPY_KEEPORDER, NPY_NO_CASTING, NULL); if (in_iter == NULL) goto fail; in_iternext = NpyIter_GetIterNext(in_iter, NULL); if (in_iternext == NULL){ NpyIter_Deallocate(in_iter); goto fail; } /* interator pointer to actual numpy data */ int **in_ptr2 = (int **) NpyIter_GetDataPtrArray(in_iter); lm_xyz = (int*) malloc(3 * Nao * sizeof(int)); itr=0; do { lm_xyz[itr++] = **in_ptr2; } while(in_iternext(in_iter)); NpyIter_Deallocate(in_iter); /* R */ in_iter = NpyIter_New(in_array3, NPY_ITER_READONLY, NPY_KEEPORDER, NPY_NO_CASTING, NULL); if (in_iter == NULL) goto fail; in_iternext = NpyIter_GetIterNext(in_iter, NULL); if (in_iternext == NULL){ NpyIter_Deallocate(in_iter); goto fail; } /* interator pointer to actual numpy data */ in_ptr = (double **) NpyIter_GetDataPtrArray(in_iter); R = (double*) malloc(3 * N * sizeof(double)); itr=0; do { R[itr++] = **in_ptr; } while(in_iternext(in_iter)); NpyIter_Deallocate(in_iter); /*** end of numpy input data ***/ /***** end of input data construction *****/ /******************* * construct output * *******************/ mat_dim[0] = Nao; mat_dim[1] = Nao; mat_dim[2] = N; py_out = (PyArrayObject*) PyArray_FromDims(3, mat_dim, NPY_DOUBLE); data = pyvector_to_Carrayptrs(py_out); /* renormalization */ renormalize(center, exp, cef, ng, lm_xyz, Nao); /* orthogonalize */ // no effect at the moment, for debug purpose //py_out2 = (PyArrayObject*) // PyArray_FromDims(2, mat_dim, NPY_DOUBLE); //overlap = pyvector_to_Carrayptrs(py_out2); //orthogonalize(overlap, center, exp, cef, ng, lm_xyz, Nao); #pragma omp parallel private(i, j, k) shared(data) { #pragma omp for schedule(dynamic) for(i=0;i<Nao;i++){ for(j=i;j<Nao;j++){ eeKernel(R, Z, center, exp, cef, &data[Nao*N*i + N*j], ng, lm_xyz, Nao, N, i, j); if(j!=i){ for(k=0;k<N;k++) data[i*N+j*Nao*N + k] = data[j*N+i*Nao*N + k]; } } } } // end of omp loop /********************************* * clean up and return the result * *********************************/ free(exp); free(cef); free(ng); free(center); free(R); free(Z); free(overlap); Py_INCREF(py_out); return Py_BuildValue("O", py_out); /* in case bad things happen */ fail: Py_XDECREF(py_out); return NULL; }
/* python interface */ static PyObject* kernel_matrix(PyObject* self, PyObject* args){ /* input variables */ PyArrayObject *in_array; NpyIter *in_iter; NpyIter_IterNextFunc *in_iternext; PyObject *klargs; PyObject *seq; PyObject *item; double *data; char *kernel = (char*) malloc(20); double *kerargs; int rows, columns, len; /* python output variables */ PyObject *np_matrix; double *matrix; double *xi, *xj; int vec_dim[1]; int mat_dim[2]; int i, j, itr = 0; /* parse numpy array and two integers as argument */ if (!PyArg_ParseTuple(args, "O!iis|O", &PyArray_Type, &in_array, // O!, NpArray &rows, // i &columns, // i &kernel, // s, kernel /* kernel args */ &klargs)) return NULL; /*********************** * Construct input data * ***********************/ data = (double*) malloc(rows * columns * sizeof(double)); /* create the iterators, necessary to access numpy array */ in_iter = NpyIter_New(in_array, NPY_ITER_READONLY, NPY_KEEPORDER, NPY_NO_CASTING, NULL); /* check input status */ if (in_iter == NULL) goto fail; in_iternext = NpyIter_GetIterNext(in_iter, NULL); if (in_iternext == NULL) { NpyIter_Deallocate(in_iter); goto fail; } /* interator pointer to actual numpy data */ double **in_dataptr = (double **) NpyIter_GetDataPtrArray(in_iter); /* iterate over the arrays */ do { data[itr++] = **in_dataptr; } while(in_iternext(in_iter)); /* access python list data */ seq = PySequence_Fast(klargs, "expected a sequence"); len = PySequence_Size(klargs); kerargs = (double*) malloc(len * sizeof(double)); for(i=0;i<len;i++){ item = PySequence_Fast_GET_ITEM(seq, i); kerargs[i] = PyFloat_AsDouble(item); } Py_DECREF(seq); /***** end of input data construction *****/ /************************** * construct output matrix * **************************/ matrix = (double *) malloc(rows * rows * sizeof(double)); mat_dim[0] = rows; mat_dim[1] = rows; vec_dim[0] = columns; #pragma omp parallel private(i,j,xi,xj) shared(matrix) { #pragma omp for for(i=0;i<rows;i++){ for(j=i;j<rows;j++){ xi = (double*) malloc(columns * sizeof(double)); xj = (double*) malloc(columns * sizeof(double)); /* construct callback input numpy arrays*/ getVector(xi, data, i, columns); getVector(xj, data, j, columns); matrix[j+rows*i] = kerEval(kernel,kerargs,xi,xj,columns); if(i!=j) matrix[i+rows*j] = matrix[j+rows*i]; free(xi); free(xj); } } } np_matrix = PyArray_SimpleNewFromData(2, mat_dim, NPY_DOUBLE, matrix); /***** end of output matrix construction *****/ /********************************* * clean up and return the result * *********************************/ Py_INCREF(np_matrix); return np_matrix; NpyIter_Deallocate(in_iter); /* in case bad things happen */ fail: Py_XDECREF(np_matrix); return NULL; free(data); free(matrix); }
/* * Returns a boolean array with True for input dates which are valid * business days, and False for dates which are not. This is the * low-level function which requires already cleaned input data. * * dates: An array of dates with 'datetime64[D]' data type. * out: Either NULL, or an array with 'bool' data type * in which to place the resulting dates. * weekmask: A 7-element boolean mask, 1 for possible business days and 0 * for non-business days. * busdays_in_weekmask: A count of how many 1's there are in weekmask. * holidays_begin/holidays_end: A sorted list of dates matching '[D]' * unit metadata, with any dates falling on a day of the * week without weekmask[i] == 1 already filtered out. */ NPY_NO_EXPORT PyArrayObject * is_business_day(PyArrayObject *dates, PyArrayObject *out, npy_bool *weekmask, int busdays_in_weekmask, npy_datetime *holidays_begin, npy_datetime *holidays_end) { PyArray_DatetimeMetaData temp_meta; PyArray_Descr *dtypes[2] = {NULL, NULL}; NpyIter *iter = NULL; PyArrayObject *op[2] = {NULL, NULL}; npy_uint32 op_flags[2], flags; PyArrayObject *ret = NULL; if (busdays_in_weekmask == 0) { PyErr_SetString(PyExc_ValueError, "the business day weekmask must have at least one " "valid business day"); return NULL; } /* First create the data types for the dates and the bool output */ temp_meta.base = NPY_FR_D; temp_meta.num = 1; dtypes[0] = create_datetime_dtype(NPY_DATETIME, &temp_meta); if (dtypes[0] == NULL) { goto fail; } dtypes[1] = PyArray_DescrFromType(NPY_BOOL); if (dtypes[1] == NULL) { goto fail; } /* Set up the iterator parameters */ flags = NPY_ITER_EXTERNAL_LOOP| NPY_ITER_BUFFERED| NPY_ITER_ZEROSIZE_OK; op[0] = dates; op_flags[0] = NPY_ITER_READONLY | NPY_ITER_ALIGNED; op[1] = out; op_flags[1] = NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE | NPY_ITER_ALIGNED; /* Allocate the iterator */ iter = NpyIter_MultiNew(2, op, flags, NPY_KEEPORDER, NPY_SAFE_CASTING, op_flags, dtypes); if (iter == NULL) { goto fail; } /* Loop over all elements */ if (NpyIter_GetIterSize(iter) > 0) { NpyIter_IterNextFunc *iternext; char **dataptr; npy_intp *strideptr, *innersizeptr; iternext = NpyIter_GetIterNext(iter, NULL); if (iternext == NULL) { goto fail; } dataptr = NpyIter_GetDataPtrArray(iter); strideptr = NpyIter_GetInnerStrideArray(iter); innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); do { char *data_dates = dataptr[0]; char *data_out = dataptr[1]; npy_intp stride_dates = strideptr[0]; npy_intp stride_out = strideptr[1]; npy_intp count = *innersizeptr; npy_datetime date; int day_of_week; while (count--) { /* Check if it's a business day */ date = *(npy_datetime *)data_dates; day_of_week = get_day_of_week(date); *(npy_bool *)data_out = weekmask[day_of_week] && !is_holiday(date, holidays_begin, holidays_end) && date != NPY_DATETIME_NAT; data_dates += stride_dates; data_out += stride_out; } } while (iternext(iter)); } /* Get the return object from the iterator */ ret = NpyIter_GetOperandArray(iter)[1]; Py_INCREF(ret); goto finish; fail: Py_XDECREF(ret); ret = NULL; finish: Py_XDECREF(dtypes[0]); Py_XDECREF(dtypes[1]); if (iter != NULL) { if (NpyIter_Deallocate(iter) != NPY_SUCCEED) { Py_XDECREF(ret); ret = NULL; } } return ret; }
static PyObject * geoutils_point_to_polygon_distance( PyObject *self, PyObject *args, PyObject *keywds) { static char *kwlist[] = {"cxx", "cyy", /* polygon coords */ "pxx", "pyy", /* points coords */ NULL}; /* sentinel */ PyArrayObject *cxx, *cyy, *pxx, *pyy; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O!O!O!O!", kwlist, // polygon coords &PyArray_Type, &cxx, &PyArray_Type, &cyy, // points coords &PyArray_Type, &pxx, &PyArray_Type, &pyy)) return NULL; PyArray_Descr *double_dtype = PyArray_DescrFromType(NPY_DOUBLE); // we use the first iterator for iterating over edges of the polygon PyArrayObject *op_c[5]; npy_uint32 op_flags_c[5]; npy_uint32 flags_c = 0; NpyIter_IterNextFunc *iternext_c; PyArray_Descr *op_dtypes_c[] = {double_dtype, double_dtype, double_dtype, double_dtype, double_dtype}; char **dataptrarray_c; op_c[0] = cxx; op_c[1] = cyy; op_c[2] = NULL; /* length of the edge */ op_c[3] = NULL; /* cos theta (angle between x-axis and the edge, counterclockwise) */ op_c[4] = NULL; /* sin theta */ op_flags_c[0] = op_flags_c[1] = NPY_ITER_READONLY; op_flags_c[2] = op_flags_c[3] = op_flags_c[4] \ = NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE; NpyIter *iter_c = NpyIter_MultiNew( 5, op_c, flags_c, NPY_KEEPORDER, NPY_NO_CASTING, op_flags_c, op_dtypes_c); if (iter_c == NULL) { Py_DECREF(double_dtype); return NULL; } iternext_c = NpyIter_GetIterNext(iter_c, NULL); dataptrarray_c = NpyIter_GetDataPtrArray(iter_c); double bcx, bcy, ecx, ecy, length, cos_theta, sin_theta; // remember the "end point" of the first segment ecx = *(double *) dataptrarray_c[0]; ecy = *(double *) dataptrarray_c[1]; // here we ignore the first iteration, this is intentional: we need // to iterate over edges, not points while (iternext_c(iter_c)) { // bcx and bcy are coordinates of the "base point" of the current edge // vector, ecx and ecy are ones of the "end point" of it bcx = *(double *) dataptrarray_c[0]; bcy = *(double *) dataptrarray_c[1]; // get the free vector coordinates from the bound one double vx = ecx - bcx; double vy = ecy - bcy; // calculate the length of the edge length = sqrt(vx * vx + vy * vy); // calculate cosine and sine of the angle between x-axis // and the free vector, measured counterclockwise cos_theta = vx / length; sin_theta = vy / length; *(double *) dataptrarray_c[2] = length; *(double *) dataptrarray_c[3] = cos_theta; *(double *) dataptrarray_c[4] = sin_theta; // the "base point" of the current vector is in turn the "end point" // of the next one ecx = bcx; ecy = bcy; } // second iterator is over the target points. // we will collect distance in it as well. PyArrayObject *op_p[3] = {pxx, pyy, NULL /* distance */}; npy_uint32 op_flags_p[3]; npy_uint32 flags_p = 0; NpyIter_IterNextFunc *iternext_p; PyArray_Descr *op_dtypes_p[] = {double_dtype, double_dtype, double_dtype}; char **dataptrarray_p; op_flags_p[0] = op_flags_p[1] = NPY_ITER_READONLY; op_flags_p[2] = NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE; NpyIter *iter_p = NpyIter_MultiNew( 3, op_p, flags_p, NPY_KEEPORDER, NPY_NO_CASTING, op_flags_p, op_dtypes_p); Py_DECREF(double_dtype); if (iter_p == NULL) { NpyIter_Deallocate(iter_c); return NULL; } iternext_p = NpyIter_GetIterNext(iter_p, NULL); dataptrarray_p = NpyIter_GetDataPtrArray(iter_p); do { // loop over points // minimum distance found double min_distance = INFINITY; // point coordinates double px = *(double *) dataptrarray_p[0]; double py = *(double *) dataptrarray_p[1]; // number of intersections between the ray, starting from the point // and running along x-axis, with polygon edges. we use that to find // out whether the point is lying inside the polygon or outside: // zero or even number of intersections means that point is outside int intersections = 0; NpyIter_Reset(iter_c, NULL); ecx = *(double *) dataptrarray_c[0]; ecy = *(double *) dataptrarray_c[1]; while (iternext_c(iter_c)) { // loop over edges: again ignore the first iteration bcx = *(double *) dataptrarray_c[0]; bcy = *(double *) dataptrarray_c[1]; length = *(double *) dataptrarray_c[2]; cos_theta = *(double *) dataptrarray_c[3]; sin_theta = *(double *) dataptrarray_c[4]; if ((px == bcx) && (py == bcy)) { // point is equal to edge's beginning point, set number // of intersections to "1", which means "point is inside" // and quit the loop intersections = 1; break; } // here we want to check if the ray from the point rightwards // intersects the current edge. this is only true if one of the // points of the edge has ordinate equal to or greater than the // current point's ordinate and another point has smaller one. // note that we use non-strict equation for only one point: this // way we don't count intersections for edges that lie on the // ray and we don't count intersection twice if ray crosses one // of polygon's vertices. if (((bcy >= py) && (ecy < py)) || ((ecy >= py) && (bcy < py))) { // checking for intersection is simple: we solve two line // equations, where first one represents the edge and second // one the ray. then we find the abscissa of intersection // point and compare it to point's abscissa: if it is greater, // than the edge crosses the ray. double x_int; if (cos_theta == 0) { // edge is purely vertical, intersection point is equal // to abscissa of any point belonging to it x_int = bcx; } else { // edge's line equation is "y(x) = k*x + b". here "k" // is the tangent of edge's inclination angle. double k = sin_theta / cos_theta; // find the "b" coefficient putting beginning point of the edge // to the equation with known "k" double b = bcy - k * bcx; // find the abscissa of the intersection point between lines x_int = (py - b) / k; } if (x_int > px) // ray intersects the edge intersections += 1; else if (x_int == px) { // point is lying on the edge, distance is zero, no need // to continue the loop intersections = 1; break; } } ecx = bcx; ecy = bcy; // now move the point to the coordinate space of the edge (where // "base point" of the edge has coordinates (0, 0) and the edge // itself goes along x axis) using affine transformations // first translate the coordinates double px2 = px - bcx; double py2 = py - bcy; // then rotate them double dist_x = px2 * cos_theta + py2 * sin_theta; double dist_y = - px2 * sin_theta + py2 * cos_theta; // now dist_y is the perpendicular distance between the point // and the line, containing the edge. it is negative in case // when point lies on the right hand side of the edge vector. // dist_x is the 1d coordinate of the projection of the point // on that line. sign is negative if the projection is on the // opposite side from the "end point" of the vector with respect // to its "base point" double dist; if ((0 <= dist_x) && (dist_x <= length)) { // if point projection falls inside the vector itself, // the actual shortest distance to the vector is dist_y dist = fabs(dist_y); } else { // otherwise we need to consider both dist_x and dist_y, // combining them in Pythagorean formula if (dist_x > length) // point lies above the "end point" of the vector // along the line, so closest x-distance to the vector // is the distance to the end point dist_x -= length; dist = sqrt(dist_x * dist_x + dist_y * dist_y); } if (dist < min_distance) // update the "minimum distance so far" variable if needed min_distance = dist; } if (intersections & 0x01) // odd number of intersections between the ray from the point // and all the edges means that the point is inside the polygon *(double *) dataptrarray_p[2] = 0; else *(double *) dataptrarray_p[2] = min_distance; } while (iternext_p(iter_p)); PyArrayObject *result = NpyIter_GetOperandArray(iter_p)[2]; Py_INCREF(result); if (NpyIter_Deallocate(iter_c) != NPY_SUCCEED || NpyIter_Deallocate(iter_p) != NPY_SUCCEED) { Py_DECREF(result); return NULL; } return (PyObject *) result; }