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; }
/* * 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; }