// copy construct into state 1, always. // This is a choice, even if X is state 2 (a numpy). // We copy a numpy into a regular C++ array, which can then be used at max speed. mem_block (mem_block const & X): size_(X.size()), py_numpy(nullptr), py_guard(nullptr) { try { p = new ValueType[X.size()];} catch (std::bad_alloc& ba) { TRIQS_RUNTIME_ERROR<< "Memory allocation error in memblock copy construction. Size :"<<X.size() << " bad_alloc error : "<< ba.what();} TRACE_MEM_DEBUG("Allocating from C++ a block of size "<< X.size() << " at address " <<p); TRIQS_MEMORY_USED_INC(X.size()); ref_count=1; weak_ref_count =0; // now we copy the data #ifndef TRIQS_WITH_PYTHON_SUPPORT copy_from(X); #else // if X is in state 1 or 3 if (X.py_numpy==nullptr) { copy_from(X); } else { // X was in state 2 // else make a new copy of the numpy ... import_numpy_array(); if (!is_scalar_or_pod<ValueType>::value) TRIQS_RUNTIME_ERROR << "Internal Error : memcpy on non-scalar"; #ifdef TRIQS_NUMPY_VERSION_LT_17 PyObject * arr3 = X.py_numpy; #else // STRANGE : uncommenting this leads to a segfault on mac ??? // TO BE INVESTIGATED, IT IS NOT NORMAL //if (!PyArray_Check(X.py_numpy)) TRIQS_RUNTIME_ERROR<<"Internal error : is not an array"; PyArrayObject * arr3 = (PyArrayObject *)(X.py_numpy); #endif // if we can make a memcpy, do it. if ( ( PyArray_ISFORTRAN(arr3)) || (PyArray_ISCONTIGUOUS(arr3))) { memcpy (p,PyArray_DATA(arr3),size_ * sizeof(ValueType)); } else { // if the X.py_numpy is not contiguous, first let numpy copy it properly, then memcpy PyObject * na = PyObject_CallMethod(X.py_numpy,(char *)"copy",nullptr); assert(na); #ifdef TRIQS_NUMPY_VERSION_LT_17 PyObject * arr = na; #else if (!PyArray_Check(na)) TRIQS_RUNTIME_ERROR<<"Internal error : is not an array"; PyArrayObject * arr = (PyArrayObject *)(na); #endif assert( ( PyArray_ISFORTRAN(arr)) || (PyArray_ISCONTIGUOUS(arr))); memcpy (p,PyArray_DATA(arr),size_ * sizeof(ValueType)); Py_DECREF(na); } } #endif }
static mxArray *makeMxFromNumeric(const PyArrayObject *pSrc) { npy_intp lRows=0, lCols=0; bool lIsComplex; bool lIsNotAMatrix = false; double *lR = NULL; double *lI = NULL; mxArray *lRetval = NULL; mwSize dims[NPY_MAXDIMS]; mwSize nDims = pSrc->nd; const PyArrayObject *ap=NULL; switch (pSrc->nd) { case 0: // XXX the evil 0D lRows = 1; lCols = 1; lIsNotAMatrix = true; break; case 1: lRows = pSrc->dimensions[0]; lCols = min(1, lRows); // for array([]): to avoid zeros((0,1)) ! lIsNotAMatrix = true; break; default: for (mwSize i = 0;i != nDims; i++) { dims[i]=(mwSize)pSrc->dimensions[i]; } break; } switch (pSrc->descr->type_num) { case PyArray_OBJECT: PyErr_SetString(PyExc_TypeError, "Non-numeric array types not supported"); return NULL; case PyArray_CFLOAT: case PyArray_CDOUBLE: lIsComplex = true; break; default: lIsComplex = false; } // converts to fortran order if not already if(!PyArray_ISFORTRAN(pSrc)){ ap = (PyArrayObject * const)PyArray_FromArray((PyArrayObject*)pSrc,NULL,NPY_ALIGNED|NPY_F_CONTIGUOUS); } else{ ap = pSrc; } if(lIsNotAMatrix) lRetval = mxCreateDoubleMatrix(lRows, lCols, lIsComplex ? mxCOMPLEX : mxREAL); else lRetval = mxCreateNumericArray(nDims,dims,mxDOUBLE_CLASS,lIsComplex ? mxCOMPLEX : mxREAL); if (lRetval == NULL) return NULL; lR = mxGetPr(lRetval); lI = mxGetPi(lRetval); if (lIsNotAMatrix) { void *p = PyArray_DATA(ap); switch (ap->descr->type_num) { case PyArray_CHAR: copyNumericVector2Mx((char *)(p), lRows, lR, pSrc->strides); break; case PyArray_UBYTE: copyNumericVector2Mx((unsigned char *)(p), lRows, lR, pSrc->strides); break; case PyArray_SBYTE: copyNumericVector2Mx((signed char *)(p), lRows, lR, pSrc->strides); break; case PyArray_SHORT: copyNumericVector2Mx((short *)(p), lRows, lR, pSrc->strides); break; case PyArray_INT: copyNumericVector2Mx((int *)(p), lRows, lR, pSrc->strides); break; case PyArray_LONG: copyNumericVector2Mx((long *)(p), lRows, lR, pSrc->strides); break; case PyArray_FLOAT: copyNumericVector2Mx((float *)(p), lRows, lR, pSrc->strides); break; case PyArray_DOUBLE: copyNumericVector2Mx((double *)(p), lRows, lR, pSrc->strides); break; case PyArray_CFLOAT: copyCplxNumericVector2Mx((float *)(p), lRows, lR, lI, pSrc->strides); break; case PyArray_CDOUBLE: copyCplxNumericVector2Mx((double *)(p), lRows, lR, lI, pSrc->strides); break; } } else { void *p = PyArray_DATA(ap); npy_intp size = PyArray_SIZE(pSrc); switch (pSrc->descr->type_num) { case PyArray_CHAR: copyNumeric2Mx((char *)p,size,lR); break; case PyArray_UBYTE: copyNumeric2Mx((unsigned char *)p,size,lR); break; case PyArray_SBYTE: copyNumeric2Mx((signed char *)p,size,lR); break; case PyArray_SHORT: copyNumeric2Mx((short *)p,size,lR); break; case PyArray_INT: copyNumeric2Mx((int *)p,size,lR); break; case PyArray_LONG: copyNumeric2Mx((long *)p,size,lR); break; case PyArray_FLOAT: copyNumeric2Mx((float *)p,size,lR); break; case PyArray_DOUBLE: copyNumeric2Mx((double *)p,size,lR); break; case PyArray_CFLOAT: copyCplxNumeric2Mx((float *)p,size,lR,lI); break; case PyArray_CDOUBLE: copyCplxNumeric2Mx((double *)p,size,lR,lI); break; } } if(ap != pSrc){ Py_DECREF(const_cast<PyArrayObject *>(ap)); } return lRetval; }
numpy_extractor ( PyObject * X, bool allow_copy) { if (X==NULL) TRIQS_RUNTIME_ERROR<<"numpy interface : the python object is NULL !"; if (_import_array()!=0) TRIQS_RUNTIME_ERROR <<"Internal Error in importing numpy"; // make sure IndexMap is cuboid ?s static const char Order = IndexMapType::index_order_type::C_or_F; static_assert( ((Order=='F')||(Order=='C')), "Ordering must be C or Fortran"); if ((!PyArray_Check(X)) && (Order=='D')) TRIQS_RUNTIME_ERROR<<"numpy interface : the python object is not a numpy and you ask me to deduce the ordering in memory !"; const int elementsType (numpy_to_C_type<typename boost::remove_const<ValueType>::type>::arraytype); int rank = IndexMapType::rank; static const char * error_msg = " A deep copy of the object would be necessary while views are supposed to guarantee to present a *view* of the python data.\n"; if (!allow_copy) { // in case of a view, we decide ourselves if we can do it... // a previous uses PyArray_FromAny, but behaviour changes between different version of numpy, so it is not portable... if (!PyArray_Check(X)) throw copy_exception () << error_msg<<" Indeed the object was not even an array !\n"; if ( elementsType != PyArray_TYPE((PyArrayObject*)X)) throw copy_exception () << error_msg<<" The deep copy is caused by a type mismatch of the elements. \n"; PyArrayObject *arr = (PyArrayObject *)X; if ( arr->nd != rank) throw copy_exception () << error_msg<<" Rank mismatch . numpy array is of rank "<< arr->nd << "while you ask for rank "<< rank<<". \n"; if ((Order == 'C') && (PyArray_ISFORTRAN(arr))) throw copy_exception () << error_msg<<" The numpy is in Fortran order while it is expected in C order. \n"; if ((Order == 'F') && (!PyArray_ISFORTRAN(arr))) throw copy_exception () << error_msg<<" The numpy is not in Fortran order as it is expected. \n"; numpy_obj = X; Py_INCREF(X); } else { // From X, we ask the numpy library to make a numpy, and of the correct type. // This handles automatically the cases where : // - we have list, or list of list/tuple // - the numpy type is not the one we want. // - adjust the dimension if needed // If X is an array : // - if Order is same, don't change it // - else impose it (may provoque a copy). // if X is not array : // - Order = FortranOrder or SameOrder - > Fortran order otherwise C bool ForceCast = false;// Unless FORCECAST is present in flags, this call will generate an error if the data type cannot be safely obtained from the object. int flags = (ForceCast ? NPY_FORCECAST : 0) ;// do NOT force a copy | (make_copy ? NPY_ENSURECOPY : 0); if (!(PyArray_Check(X) && (Order=='D'))) flags |= (Order =='F' ? NPY_F_CONTIGUOUS : NPY_C_CONTIGUOUS); //impose mem order //if (!(PyArray_Check(X) && (Order=='D'))) flags |= (Order =='F' ? NPY_FARRAY : NPY_CARRAY); //impose mem order numpy_obj= PyArray_FromAny(X,PyArray_DescrFromType(elementsType), rank,rank, flags , NULL ); // do several checks if (!numpy_obj) {// The convertion of X to a numpy has failed ! if (PyErr_Occurred()) {PyErr_Print();PyErr_Clear();} TRIQS_RUNTIME_ERROR<<"numpy interface : the python object is not convertible to a numpy. "; } assert (PyArray_Check(numpy_obj)); assert((numpy_obj->ob_refcnt==1) || ((numpy_obj ==X))); arr_obj = (PyArrayObject *)numpy_obj; try { if (arr_obj->nd!=rank) TRIQS_RUNTIME_ERROR<<"numpy interface : internal error : dimensions do not match"; if (arr_obj->descr->type_num != elementsType) TRIQS_RUNTIME_ERROR<<"numpy interface : internal error : incorrect type of element :" <<arr_obj->descr->type_num <<" vs "<<elementsType; if (Order == 'F') { if (!PyArray_ISFORTRAN(numpy_obj)) TRIQS_RUNTIME_ERROR<<"numpy interface : internal error : should be Fortran array";} else {if (!PyArray_ISCONTIGUOUS(numpy_obj)) TRIQS_RUNTIME_ERROR<<"numpy interface : internal error : should be contiguous";} } catch(...) { Py_DECREF(numpy_obj); throw;} // make sure that in case of problem, the reference counting of python is still ok... } arr_obj = (PyArrayObject *)numpy_obj; }
static PyObject *product_matrix_vector_(PyObject *self, PyObject *args) { PyArrayObject *matrix, *vector, *result; double alpha = 1.; double beta = 0.; int int_one = 1; int m, n; char trans[2] = "T"; extern void dgemv_(char *trans, int *m, int *n, double *alpha, double *a, int *lda, double *x, int *incx, double *beta, double *Y, int *incy); if (!PyArg_ParseTuple(args, "O!O!O!", &PyArray_Type, &matrix, &PyArray_Type, &vector, &PyArray_Type, &result)) return NULL; if ( (NULL == matrix) || (NULL == vector) || (NULL == result) ) return NULL; if ( (matrix->descr->type_num != NPY_DOUBLE) || (vector->descr->type_num != NPY_DOUBLE) || (result->descr->type_num != NPY_DOUBLE) || !PyArray_CHKFLAGS(matrix,NPY_ALIGNED) || !(PyArray_CHKFLAGS(matrix,NPY_C_CONTIGUOUS) || PyArray_CHKFLAGS(matrix,NPY_F_CONTIGUOUS)) || !PyArray_CHKFLAGS(vector,NPY_C_CONTIGUOUS|NPY_ALIGNED) || !PyArray_CHKFLAGS(result,NPY_C_CONTIGUOUS|NPY_ALIGNED|NPY_WRITEABLE) ) { PyErr_SetString(PyExc_ValueError, "In product_matrix_vector: all arguments must be of type double, contiguous and aligned, and targets should be writeable"); return NULL; } if ( (matrix->nd != 2) || (vector->nd != 1) || (result->nd != 1) ) { PyErr_SetString(PyExc_ValueError, "In product_matrix_vector: not all arguments have the right dimensionality"); return NULL; } /* Figure out correct values for args to blas*/ if (PyArray_ISFORTRAN(matrix)) { m = matrix->dimensions[0]; n = matrix->dimensions[1]; trans[0] = 'N'; } else /*if (PyArray_ISCONTIGUOUS(matrix))*/ { /* Equivalent to matrix being the transposed of a Fortran matrix*/ m = matrix->dimensions[1]; n = matrix->dimensions[0]; } /* Check if dimensions are compatible */ if (matrix->dimensions[1] != vector->dimensions[0]) { PyErr_SetString(PyExc_ValueError, "In product_matrix_vector: input dimensions are not compatible"); return NULL; } if (result->dimensions[0] != matrix->dimensions[0]) { PyErr_SetString(PyExc_ValueError, "In product_matrix_vector: target dimension is not compatible"); return NULL; } dgemv_(trans, &m, &n, &alpha, (double *)matrix->data, &m, (double *)vector->data, &int_one, &beta, (double *)result->data, &int_one); Py_RETURN_NONE; }
static mxArray *makeMxFromNumeric(const PyArrayObject *pSrc, bool &is_reference) { npy_intp lRows=0, lCols=0; bool lIsComplex; bool lIsNotAMatrix = false; double *lR = NULL; double *lI = NULL; mxArray *lRetval = NULL; mwSize dims[NPY_MAXDIMS]; mwSize dimsEmpty [2]; memset(&dimsEmpty, 0, 2 * sizeof(mwSize)); mwSize nDims = pSrc->nd; const PyArrayObject *ap=NULL; mxClassID classID = mxUNKNOWN_CLASS; switch (pSrc->nd) { case 0: // XXX the evil 0D lRows = 1; lCols = 1; lIsNotAMatrix = true; break; case 1: lRows = pSrc->dimensions[0]; lCols = min(1, lRows); // for array([]): to avoid zeros((0,1)) ! lIsNotAMatrix = true; break; default: for (mwSize i = 0;i != nDims; i++) { dims[i]=(mwSize)pSrc->dimensions[i]; } break; } switch (pSrc->descr->type_num) { case PyArray_OBJECT: PyErr_SetString(PyExc_TypeError, "Non-numeric array types not supported"); return NULL; case PyArray_CFLOAT: case PyArray_CDOUBLE: lIsComplex = true; break; default: lIsComplex = false; } // converts to fortran order if not already if(!PyArray_ISFORTRAN(pSrc)){ ap = (PyArrayObject * const)PyArray_FromArray((PyArrayObject*)pSrc,NULL,NPY_ALIGNED|NPY_F_CONTIGUOUS); } else{ ap = pSrc; } if(lIsNotAMatrix) lRetval = mxCreateDoubleMatrix(lRows, lCols, lIsComplex ? mxCOMPLEX : mxREAL); else { switch (ap->descr->type_num) { case PyArray_CFLOAT: case PyArray_CDOUBLE: classID = mxDOUBLE_CLASS; is_reference = false; break; case PyArray_BOOL: classID = mxLOGICAL_CLASS; is_reference = true; break; case PyArray_CHAR: classID = mxCHAR_CLASS; is_reference = true; break; case PyArray_DOUBLE: classID = mxDOUBLE_CLASS; is_reference = true; break; case PyArray_FLOAT: classID = mxSINGLE_CLASS; is_reference = true; break; case PyArray_INT8: classID = mxINT8_CLASS; is_reference = true; break; case PyArray_UINT8: classID = mxUINT8_CLASS; is_reference = true; break; case PyArray_INT16: classID = mxINT16_CLASS; is_reference = true; break; case PyArray_UINT16: classID = mxUINT16_CLASS; is_reference = true; break; case PyArray_INT32: classID = mxINT32_CLASS; is_reference = true; break; case PyArray_UINT32: classID = mxUINT32_CLASS; is_reference = true; break; #ifdef NPY_INT64 case PyArray_INT64: classID = mxINT64_CLASS; is_reference = true; break; case PyArray_UINT64: classID = mxUINT64_CLASS; is_reference = true; break; #endif } if (!is_reference) { lRetval = mxCreateNumericArray(nDims,dims,classID,lIsComplex ? mxCOMPLEX : mxREAL); } else { /* // code for create and mxArray ref on the numpy object lRetval = mxCreateNumericArray(2, dimsEmpty, classID, lIsComplex ? mxCOMPLEX : mxREAL); if (mxSetDimensions(lRetval, dims, nDims) == 1) { // failed to reset the dimensions mxDestroyArray(lRetval); lRetval = NULL; } else { mxSetData(lRetval, PyArray_DATA(ap)); } */ // uses memcopy for faster copying is_reference = false; lRetval = mxCreateNumericArray(nDims, dims, classID, lIsComplex ? mxCOMPLEX : mxREAL); // this is a sanity check, it should not fail int matlab_nbytes = mxGetNumberOfElements(lRetval) * mxGetElementSize(lRetval); if (matlab_nbytes == PyArray_NBYTES(pSrc)) { memcpy(mxGetData(lRetval), PyArray_DATA(ap), PyArray_NBYTES(pSrc)); } else { PyErr_SetString(PyExc_TypeError, "Number of bytes do not match"); } } } if (lRetval == NULL) return NULL; lR = mxGetPr(lRetval); lI = mxGetPi(lRetval); if (lIsNotAMatrix) { void *p = PyArray_DATA(ap); switch (ap->descr->type_num) { case PyArray_CHAR: copyNumericVector2Mx((char *)(p), lRows, lR, pSrc->strides); break; case PyArray_UBYTE: copyNumericVector2Mx((unsigned char *)(p), lRows, lR, pSrc->strides); break; case PyArray_SBYTE: copyNumericVector2Mx((signed char *)(p), lRows, lR, pSrc->strides); break; case PyArray_SHORT: copyNumericVector2Mx((short *)(p), lRows, lR, pSrc->strides); break; case PyArray_INT: copyNumericVector2Mx((int *)(p), lRows, lR, pSrc->strides); break; case PyArray_LONG: copyNumericVector2Mx((long *)(p), lRows, lR, pSrc->strides); break; case PyArray_FLOAT: copyNumericVector2Mx((float *)(p), lRows, lR, pSrc->strides); break; case PyArray_DOUBLE: copyNumericVector2Mx((double *)(p), lRows, lR, pSrc->strides); break; case PyArray_CFLOAT: copyCplxNumericVector2Mx((float *)(p), lRows, lR, lI, pSrc->strides); break; case PyArray_CDOUBLE: copyCplxNumericVector2Mx((double *)(p), lRows, lR, lI, pSrc->strides); break; } } else { void *p = PyArray_DATA(ap); npy_intp size = PyArray_SIZE(pSrc); switch (pSrc->descr->type_num) { case PyArray_CFLOAT: copyCplxNumeric2Mx((float *)p,size,lR,lI); break; case PyArray_CDOUBLE: copyCplxNumeric2Mx((double *)p,size,lR,lI); break; } } if(ap != pSrc){ Py_DECREF(const_cast<PyArrayObject *>(ap)); } return lRetval; }
static PyObject *product_matrix_matrix_(PyObject *self, PyObject *args) { PyArrayObject *matrix1, *matrix2, *result, *A, *B; double alpha = 1.; double beta = 0.; int m, n, k; /* Watch out: m and n have a different meaning from that for dgemv, where it is the dimensionality BEFORE the transpose, whereas dgemm requires the dimensionality AFTER. */ int lda, ldb, ldc; char transa[2] = "T"; char transb[2] = "T"; extern void dgemm_(char* transa, char* transb, int* m, int* n, int* k, double *alpha, double *a, int* lda, double *b, int *ldb, double *beta, double *c, int* ldc); if (!PyArg_ParseTuple(args, "O!O!O!", &PyArray_Type, &matrix1, &PyArray_Type, &matrix2, &PyArray_Type, &result)) return NULL; if ( (NULL == matrix1) || (NULL == matrix2) || (NULL == result) ) return NULL; if ( (matrix1->descr->type_num != NPY_DOUBLE) || (matrix2->descr->type_num != NPY_DOUBLE) || (result->descr->type_num != NPY_DOUBLE) || !PyArray_CHKFLAGS(matrix1,NPY_ALIGNED) || !(PyArray_CHKFLAGS(matrix1,NPY_C_CONTIGUOUS) || PyArray_CHKFLAGS(matrix1,NPY_F_CONTIGUOUS)) || !PyArray_CHKFLAGS(matrix2,NPY_ALIGNED) || !(PyArray_CHKFLAGS(matrix2,NPY_C_CONTIGUOUS) || PyArray_CHKFLAGS(matrix2,NPY_F_CONTIGUOUS)) || !PyArray_CHKFLAGS(result,NPY_ALIGNED|NPY_WRITEABLE) || !(PyArray_CHKFLAGS(result,NPY_C_CONTIGUOUS) || PyArray_CHKFLAGS(result,NPY_F_CONTIGUOUS)) ) { PyErr_SetString(PyExc_ValueError, "In product_matrix_matrix: all arguments must be of type double, contiguous and aligned, and targets should be writeable"); return NULL; } if ( (matrix1->nd != 2) || (matrix2->nd != 2) || (result->nd != 2) ) { PyErr_SetString(PyExc_ValueError, "In product_matrix_matrix: not all arguments have the right dimensionality"); return NULL; } /* Figure out correct values for args to blas*/ if (PyArray_ISFORTRAN(result)) { /* Matrix result has Fortran order */ A = matrix1; B = matrix2; m = matrix1->dimensions[0]; k = matrix1->dimensions[1]; if (PyArray_ISFORTRAN(matrix1)) { transa[0] = 'N'; lda = m; } else /*if (PyArray_ISCONTIGUOUS(matrix1))*/ { /* Equivalent to matrix being the transposed of a Fortran matrix*/ lda = k; } n = matrix2->dimensions[1]; k = matrix2->dimensions[0]; if (PyArray_ISFORTRAN(matrix2)) { transb[0] = 'N'; ldb = k; } else /*if (PyArray_ISCONTIGUOUS(matrix2))*/ { /* Equivalent to matrix being the transposed of a Fortran matrix*/ ldb = n; } } else /*if (PyArray_ISCONTIGUOUS(result))*/ { /* Matrix result has C order! Must be careful how blas is called! Must interchange matrix1 with matrix2, and interchange how the C and Fortran matrices are processed. */ A = matrix2; B = matrix1; m = matrix2->dimensions[1]; k = matrix2->dimensions[0]; if (PyArray_ISFORTRAN(matrix2)) { lda = k; } else /*if (PyArray_ISCONTIGUOUS(matrix2))*/ { /* Equivalent to matrix being the transposed of a Fortran matrix*/ transa[0] = 'N'; lda = m; } n = matrix1->dimensions[0]; k = matrix1->dimensions[1]; if (PyArray_ISFORTRAN(matrix1)) { ldb = n; } else /*if (PyArray_ISCONTIGUOUS(matrix1))*/ { /* Equivalent to matrix being the transposed of a Fortran matrix*/ transb[0] = 'N'; ldb = k; } } ldc = m; if ( matrix1->dimensions[1] != matrix2->dimensions[0] ) { PyErr_SetString(PyExc_ValueError, "In product_matrix_matrix: input matrices dimensions are not compatible"); return NULL; } if ( (matrix1->dimensions[0] != result->dimensions[0]) || (matrix2->dimensions[1] != result->dimensions[1]) ) { PyErr_SetString(PyExc_ValueError, "In product_matrix_matrix: target dimensions are not compatible"); return NULL; } dgemm_(transa, transb, &m, &n, &k, &alpha, (double *)A->data, &lda, (double *)B->data, &ldb, &beta, (double *)result->data, &ldc ); Py_RETURN_NONE; }
/* * optimize float array or complex array to a scalar power * returns 0 on success, -1 if no optimization is possible * the result is in value (can be NULL if an error occurred) */ static int fast_scalar_power(PyArrayObject *a1, PyObject *o2, int inplace, PyObject **value) { double exponent; NPY_SCALARKIND kind; /* NPY_NOSCALAR is not scalar */ if (PyArray_Check(a1) && !PyArray_ISOBJECT(a1) && ((kind=is_scalar_with_conversion(o2, &exponent))>0)) { PyObject *fastop = NULL; if (PyArray_ISFLOAT(a1) || PyArray_ISCOMPLEX(a1)) { if (exponent == 1.0) { fastop = n_ops.positive; } else if (exponent == -1.0) { fastop = n_ops.reciprocal; } else if (exponent == 0.0) { fastop = n_ops._ones_like; } else if (exponent == 0.5) { fastop = n_ops.sqrt; } else if (exponent == 2.0) { fastop = n_ops.square; } else { return -1; } if (inplace || can_elide_temp_unary(a1)) { *value = PyArray_GenericInplaceUnaryFunction(a1, fastop); } else { *value = PyArray_GenericUnaryFunction(a1, fastop); } return 0; } /* Because this is called with all arrays, we need to * change the output if the kind of the scalar is different * than that of the input and inplace is not on --- * (thus, the input should be up-cast) */ else if (exponent == 2.0) { fastop = n_ops.square; if (inplace) { *value = PyArray_GenericInplaceUnaryFunction(a1, fastop); } else { /* We only special-case the FLOAT_SCALAR and integer types */ if (kind == NPY_FLOAT_SCALAR && PyArray_ISINTEGER(a1)) { PyArray_Descr *dtype = PyArray_DescrFromType(NPY_DOUBLE); a1 = (PyArrayObject *)PyArray_CastToType(a1, dtype, PyArray_ISFORTRAN(a1)); if (a1 != NULL) { /* cast always creates a new array */ *value = PyArray_GenericInplaceUnaryFunction(a1, fastop); Py_DECREF(a1); } } else { *value = PyArray_GenericUnaryFunction(a1, fastop); } } return 0; } } /* no fast operation found */ return -1; }
/* optimize float array or complex array to a scalar power */ static PyObject * fast_scalar_power(PyArrayObject *a1, PyObject *o2, int inplace) { double exponent; NPY_SCALARKIND kind; /* NPY_NOSCALAR is not scalar */ if (PyArray_Check(a1) && ((kind=is_scalar_with_conversion(o2, &exponent))>0)) { PyObject *fastop = NULL; if (PyArray_ISFLOAT(a1) || PyArray_ISCOMPLEX(a1)) { if (exponent == 1.0) { /* we have to do this one special, as the "copy" method of array objects isn't set up early enough to be added by PyArray_SetNumericOps. */ if (inplace) { Py_INCREF(a1); return (PyObject *)a1; } else { return PyArray_Copy(a1); } } else if (exponent == -1.0) { fastop = n_ops.reciprocal; } else if (exponent == 0.0) { fastop = n_ops._ones_like; } else if (exponent == 0.5) { fastop = n_ops.sqrt; } else if (exponent == 2.0) { fastop = n_ops.square; } else { return NULL; } if (inplace) { return PyArray_GenericInplaceUnaryFunction(a1, fastop); } else { return PyArray_GenericUnaryFunction(a1, fastop); } } /* Because this is called with all arrays, we need to * change the output if the kind of the scalar is different * than that of the input and inplace is not on --- * (thus, the input should be up-cast) */ else if (exponent == 2.0) { fastop = n_ops.multiply; if (inplace) { return PyArray_GenericInplaceBinaryFunction (a1, (PyObject *)a1, fastop); } else { PyArray_Descr *dtype = NULL; PyObject *res; /* We only special-case the FLOAT_SCALAR and integer types */ if (kind == NPY_FLOAT_SCALAR && PyArray_ISINTEGER(a1)) { dtype = PyArray_DescrFromType(NPY_DOUBLE); a1 = (PyArrayObject *)PyArray_CastToType(a1, dtype, PyArray_ISFORTRAN(a1)); if (a1 == NULL) { return NULL; } } else { Py_INCREF(a1); } res = PyArray_GenericBinaryFunction(a1, (PyObject *)a1, fastop); Py_DECREF(a1); return res; } } } return NULL; }
/*NUMPY_API * Clip */ NPY_NO_EXPORT PyObject * PyArray_Clip(PyArrayObject *self, PyObject *min, PyObject *max, PyArrayObject *out) { PyArray_FastClipFunc *func; int outgood = 0, ingood = 0; PyArrayObject *maxa = NULL; PyArrayObject *mina = NULL; PyArrayObject *newout = NULL, *newin = NULL; PyArray_Descr *indescr = NULL, *newdescr = NULL; char *max_data, *min_data; PyObject *zero; /* Treat None the same as NULL */ if (min == Py_None) { min = NULL; } if (max == Py_None) { max = NULL; } if ((max == NULL) && (min == NULL)) { PyErr_SetString(PyExc_ValueError, "array_clip: must set either max or min"); return NULL; } func = PyArray_DESCR(self)->f->fastclip; if (func == NULL || (min != NULL && !PyArray_CheckAnyScalar(min)) || (max != NULL && !PyArray_CheckAnyScalar(max)) || PyArray_ISBYTESWAPPED(self) || (out && PyArray_ISBYTESWAPPED(out))) { return _slow_array_clip(self, min, max, out); } /* Use the fast scalar clip function */ /* First we need to figure out the correct type */ if (min != NULL) { indescr = PyArray_DescrFromObject(min, NULL); if (indescr == NULL) { goto fail; } } if (max != NULL) { newdescr = PyArray_DescrFromObject(max, indescr); Py_XDECREF(indescr); indescr = NULL; if (newdescr == NULL) { goto fail; } } else { /* Steal the reference */ newdescr = indescr; indescr = NULL; } /* * Use the scalar descriptor only if it is of a bigger * KIND than the input array (and then find the * type that matches both). */ if (PyArray_ScalarKind(newdescr->type_num, NULL) > PyArray_ScalarKind(PyArray_DESCR(self)->type_num, NULL)) { indescr = PyArray_PromoteTypes(newdescr, PyArray_DESCR(self)); if (indescr == NULL) { goto fail; } func = indescr->f->fastclip; if (func == NULL) { Py_DECREF(indescr); return _slow_array_clip(self, min, max, out); } } else { indescr = PyArray_DESCR(self); Py_INCREF(indescr); } Py_DECREF(newdescr); newdescr = NULL; if (!PyDataType_ISNOTSWAPPED(indescr)) { PyArray_Descr *descr2; descr2 = PyArray_DescrNewByteorder(indescr, '='); Py_DECREF(indescr); indescr = NULL; if (descr2 == NULL) { goto fail; } indescr = descr2; } /* Convert max to an array */ if (max != NULL) { Py_INCREF(indescr); maxa = (PyArrayObject *)PyArray_FromAny(max, indescr, 0, 0, NPY_ARRAY_DEFAULT, NULL); if (maxa == NULL) { goto fail; } } /* * If we are unsigned, then make sure min is not < 0 * This is to match the behavior of _slow_array_clip * * We allow min and max to go beyond the limits * for other data-types in which case they * are interpreted as their modular counterparts. */ if (min != NULL) { if (PyArray_ISUNSIGNED(self)) { int cmp; zero = PyInt_FromLong(0); cmp = PyObject_RichCompareBool(min, zero, Py_LT); if (cmp == -1) { Py_DECREF(zero); goto fail; } if (cmp == 1) { min = zero; } else { Py_DECREF(zero); Py_INCREF(min); } } else { Py_INCREF(min); } /* Convert min to an array */ Py_INCREF(indescr); mina = (PyArrayObject *)PyArray_FromAny(min, indescr, 0, 0, NPY_ARRAY_DEFAULT, NULL); Py_DECREF(min); if (mina == NULL) { goto fail; } } /* * Check to see if input is single-segment, aligned, * and in native byteorder */ if (PyArray_ISONESEGMENT(self) && PyArray_CHKFLAGS(self, NPY_ARRAY_ALIGNED) && PyArray_ISNOTSWAPPED(self) && (PyArray_DESCR(self) == indescr)) { ingood = 1; } if (!ingood) { int flags; if (PyArray_ISFORTRAN(self)) { flags = NPY_ARRAY_FARRAY; } else { flags = NPY_ARRAY_CARRAY; } Py_INCREF(indescr); newin = (PyArrayObject *)PyArray_FromArray(self, indescr, flags); if (newin == NULL) { goto fail; } } else { newin = self; Py_INCREF(newin); } /* * At this point, newin is a single-segment, aligned, and correct * byte-order array of the correct type * * if ingood == 0, then it is a copy, otherwise, * it is the original input. */ /* * If we have already made a copy of the data, then use * that as the output array */ if (out == NULL && !ingood) { out = newin; } /* * Now, we know newin is a usable array for fastclip, * we need to make sure the output array is available * and usable */ if (out == NULL) { Py_INCREF(indescr); out = (PyArrayObject*)PyArray_NewFromDescr(Py_TYPE(self), indescr, PyArray_NDIM(self), PyArray_DIMS(self), NULL, NULL, PyArray_ISFORTRAN(self), (PyObject *)self); if (out == NULL) { goto fail; } outgood = 1; } else Py_INCREF(out); /* Input is good at this point */ if (out == newin) { outgood = 1; } /* make sure the shape of the output array is the same */ if (!PyArray_SAMESHAPE(newin, out)) { PyErr_SetString(PyExc_ValueError, "clip: Output array must have the" "same shape as the input."); goto fail; } if (!outgood && PyArray_EQUIVALENTLY_ITERABLE( self, out, PyArray_TRIVIALLY_ITERABLE_OP_READ, PyArray_TRIVIALLY_ITERABLE_OP_NOREAD) && PyArray_CHKFLAGS(out, NPY_ARRAY_ALIGNED) && PyArray_ISNOTSWAPPED(out) && PyArray_EquivTypes(PyArray_DESCR(out), indescr)) { outgood = 1; } /* * Do we still not have a suitable output array? * Create one, now. No matter why the array is not suitable a copy has * to be made. This may be just to avoid memory overlap though. */ if (!outgood) { int oflags; if (PyArray_ISFORTRAN(self)) { oflags = NPY_ARRAY_FARRAY; } else { oflags = NPY_ARRAY_CARRAY; } oflags |= (NPY_ARRAY_WRITEBACKIFCOPY | NPY_ARRAY_FORCECAST | NPY_ARRAY_ENSURECOPY); Py_INCREF(indescr); newout = (PyArrayObject*)PyArray_FromArray(out, indescr, oflags); if (newout == NULL) { goto fail; } } else { newout = out; Py_INCREF(newout); } /* Now we can call the fast-clip function */ min_data = max_data = NULL; if (mina != NULL) { min_data = PyArray_DATA(mina); } if (maxa != NULL) { max_data = PyArray_DATA(maxa); } func(PyArray_DATA(newin), PyArray_SIZE(newin), min_data, max_data, PyArray_DATA(newout)); /* Clean up temporary variables */ Py_XDECREF(indescr); Py_XDECREF(newdescr); Py_XDECREF(mina); Py_XDECREF(maxa); Py_DECREF(newin); /* Copy back into out if out was not already a nice array. */ PyArray_ResolveWritebackIfCopy(newout); Py_DECREF(newout); return (PyObject *)out; fail: Py_XDECREF(indescr); Py_XDECREF(newdescr); Py_XDECREF(maxa); Py_XDECREF(mina); Py_XDECREF(newin); PyArray_DiscardWritebackIfCopy(newout); Py_XDECREF(newout); return NULL; }
/*NUMPY_API * Round */ NPY_NO_EXPORT PyObject * PyArray_Round(PyArrayObject *a, int decimals, PyArrayObject *out) { PyObject *f, *ret = NULL, *tmp, *op1, *op2; int ret_int=0; PyArray_Descr *my_descr; if (out && (PyArray_SIZE(out) != PyArray_SIZE(a))) { PyErr_SetString(PyExc_ValueError, "invalid output shape"); return NULL; } if (PyArray_ISCOMPLEX(a)) { PyObject *part; PyObject *round_part; PyObject *arr; int res; if (out) { arr = (PyObject *)out; Py_INCREF(arr); } else { arr = PyArray_Copy(a); if (arr == NULL) { return NULL; } } /* arr.real = a.real.round(decimals) */ part = PyObject_GetAttrString((PyObject *)a, "real"); if (part == NULL) { Py_DECREF(arr); return NULL; } part = PyArray_EnsureAnyArray(part); round_part = PyArray_Round((PyArrayObject *)part, decimals, NULL); Py_DECREF(part); if (round_part == NULL) { Py_DECREF(arr); return NULL; } res = PyObject_SetAttrString(arr, "real", round_part); Py_DECREF(round_part); if (res < 0) { Py_DECREF(arr); return NULL; } /* arr.imag = a.imag.round(decimals) */ part = PyObject_GetAttrString((PyObject *)a, "imag"); if (part == NULL) { Py_DECREF(arr); return NULL; } part = PyArray_EnsureAnyArray(part); round_part = PyArray_Round((PyArrayObject *)part, decimals, NULL); Py_DECREF(part); if (round_part == NULL) { Py_DECREF(arr); return NULL; } res = PyObject_SetAttrString(arr, "imag", round_part); Py_DECREF(round_part); if (res < 0) { Py_DECREF(arr); return NULL; } return arr; } /* do the most common case first */ if (decimals >= 0) { if (PyArray_ISINTEGER(a)) { if (out) { if (PyArray_AssignArray(out, a, NULL, NPY_DEFAULT_ASSIGN_CASTING) < 0) { return NULL; } Py_INCREF(out); return (PyObject *)out; } else { Py_INCREF(a); return (PyObject *)a; } } if (decimals == 0) { if (out) { return PyObject_CallFunction(n_ops.rint, "OO", a, out); } return PyObject_CallFunction(n_ops.rint, "O", a); } op1 = n_ops.multiply; op2 = n_ops.true_divide; } else { op1 = n_ops.true_divide; op2 = n_ops.multiply; decimals = -decimals; } if (!out) { if (PyArray_ISINTEGER(a)) { ret_int = 1; my_descr = PyArray_DescrFromType(NPY_DOUBLE); } else { Py_INCREF(PyArray_DESCR(a)); my_descr = PyArray_DESCR(a); } out = (PyArrayObject *)PyArray_Empty(PyArray_NDIM(a), PyArray_DIMS(a), my_descr, PyArray_ISFORTRAN(a)); if (out == NULL) { return NULL; } } else { Py_INCREF(out); } f = PyFloat_FromDouble(power_of_ten(decimals)); if (f == NULL) { return NULL; } ret = PyObject_CallFunction(op1, "OOO", a, f, out); if (ret == NULL) { goto finish; } tmp = PyObject_CallFunction(n_ops.rint, "OO", ret, ret); if (tmp == NULL) { Py_DECREF(ret); ret = NULL; goto finish; } Py_DECREF(tmp); tmp = PyObject_CallFunction(op2, "OOO", ret, f, ret); if (tmp == NULL) { Py_DECREF(ret); ret = NULL; goto finish; } Py_DECREF(tmp); finish: Py_DECREF(f); Py_DECREF(out); if (ret_int) { Py_INCREF(PyArray_DESCR(a)); tmp = PyArray_CastToType((PyArrayObject *)ret, PyArray_DESCR(a), PyArray_ISFORTRAN(a)); Py_DECREF(ret); return tmp; } return ret; }
/*NUMPY_API*/ NPY_NO_EXPORT int PyArray_CopyObject(PyArrayObject *dest, PyObject *src_object) { int ret; PyArrayObject *src; PyArray_Descr *dtype = NULL; int ndim = 0; npy_intp dims[NPY_MAXDIMS]; Py_INCREF(src_object); /* * Special code to mimic Numeric behavior for * character arrays. */ if (dest->descr->type == PyArray_CHARLTR && dest->nd > 0 \ && PyString_Check(src_object)) { npy_intp n_new, n_old; char *new_string; PyObject *tmp; n_new = dest->dimensions[dest->nd-1]; n_old = PyString_Size(src_object); if (n_new > n_old) { new_string = (char *)malloc(n_new); memmove(new_string, PyString_AS_STRING(src_object), n_old); memset(new_string + n_old, ' ', n_new - n_old); tmp = PyString_FromStringAndSize(new_string, n_new); free(new_string); Py_DECREF(src_object); src_object = tmp; } } /* * Get either an array object we can copy from, or its parameters * if there isn't a convenient array available. */ if (PyArray_GetArrayParamsFromObject(src_object, PyArray_DESCR(dest), 0, &dtype, &ndim, dims, &src, NULL) < 0) { Py_DECREF(src_object); return -1; } /* If it's not an array, either assign from a sequence or as a scalar */ if (src == NULL) { /* If the input is scalar */ if (ndim == 0) { /* If there's one dest element and src is a Python scalar */ if (PyArray_IsScalar(src_object, Generic)) { src = (PyArrayObject *)PyArray_FromScalar(src_object, dtype); if (src == NULL) { Py_DECREF(src_object); return -1; } } else { if (PyArray_SIZE(dest) == 1) { Py_DECREF(dtype); return PyArray_DESCR(dest)->f->setitem(src_object, PyArray_DATA(dest), dest); } else { src = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, 0, NULL, NULL, NULL, 0, NULL); if (src == NULL) { Py_DECREF(src_object); return -1; } if (PyArray_DESCR(src)->f->setitem(src_object, PyArray_DATA(src), src) < 0) { Py_DECREF(src_object); Py_DECREF(src); return -1; } } } } else { /* * If there are more than enough dims, use AssignFromSequence * because it can handle this style of broadcasting. */ if (ndim >= PyArray_NDIM(dest)) { int res; Py_DECREF(dtype); res = PyArray_AssignFromSequence(dest, src_object); Py_DECREF(src_object); return res; } /* Otherwise convert to an array and do an array-based copy */ src = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, ndim, dims, NULL, NULL, PyArray_ISFORTRAN(dest), NULL); if (src == NULL) { Py_DECREF(src_object); return -1; } if (PyArray_AssignFromSequence(src, src_object) < 0) { Py_DECREF(src); Py_DECREF(src_object); return -1; } } } /* If it's an array, do a move (handling possible overlapping data) */ ret = PyArray_MoveInto(dest, src); Py_DECREF(src); Py_DECREF(src_object); return ret; }