コード例 #1
0
ファイル: reduction.c プロジェクト: ChrisBarker-NOAA/numpy
/*
 * Conforms an output parameter 'out' to have 'ndim' dimensions
 * with dimensions of size one added in the appropriate places
 * indicated by 'axis_flags'.
 *
 * The return value is a view into 'out'.
 */
static PyArrayObject *
conform_reduce_result(int ndim, npy_bool *axis_flags,
                      PyArrayObject *out, int keepdims, const char *funcname,
                      int need_copy)
{
    npy_intp strides[NPY_MAXDIMS], shape[NPY_MAXDIMS];
    npy_intp *strides_out = PyArray_STRIDES(out);
    npy_intp *shape_out = PyArray_DIMS(out);
    int idim, idim_out, ndim_out = PyArray_NDIM(out);
    PyArray_Descr *dtype;
    PyArrayObject_fields *ret;

    /*
     * If the 'keepdims' parameter is true, do a simpler validation and
     * return a new reference to 'out'.
     */
    if (keepdims) {
        if (PyArray_NDIM(out) != ndim) {
            PyErr_Format(PyExc_ValueError,
                    "output parameter for reduction operation %s "
                    "has the wrong number of dimensions (must match "
                    "the operand's when keepdims=True)", funcname);
            return NULL;
        }

        for (idim = 0; idim < ndim; ++idim) {
            if (axis_flags[idim]) {
                if (shape_out[idim] != 1) {
                    PyErr_Format(PyExc_ValueError,
                            "output parameter for reduction operation %s "
                            "has a reduction dimension not equal to one "
                            "(required when keepdims=True)", funcname);
                    return NULL;
                }
            }
        }

        Py_INCREF(out);
        return out;
    }

    /* Construct the strides and shape */
    idim_out = 0;
    for (idim = 0; idim < ndim; ++idim) {
        if (axis_flags[idim]) {
            strides[idim] = 0;
            shape[idim] = 1;
        }
        else {
            if (idim_out >= ndim_out) {
                PyErr_Format(PyExc_ValueError,
                        "output parameter for reduction operation %s "
                        "does not have enough dimensions", funcname);
                return NULL;
            }
            strides[idim] = strides_out[idim_out];
            shape[idim] = shape_out[idim_out];
            ++idim_out;
        }
    }

    if (idim_out != ndim_out) {
        PyErr_Format(PyExc_ValueError,
                "output parameter for reduction operation %s "
                "has too many dimensions", funcname);
        return NULL;
    }

    /* Allocate the view */
    dtype = PyArray_DESCR(out);
    Py_INCREF(dtype);

    ret = (PyArrayObject_fields *)PyArray_NewFromDescr(&PyArray_Type,
                               dtype,
                               ndim, shape,
                               strides,
                               PyArray_DATA(out),
                               PyArray_FLAGS(out),
                               NULL);
    if (ret == NULL) {
        return NULL;
    }

    Py_INCREF(out);
    if (PyArray_SetBaseObject((PyArrayObject *)ret, (PyObject *)out) < 0) {
        Py_DECREF(ret);
        return NULL;
    }

    if (need_copy) {
        PyArrayObject *ret_copy;

        ret_copy = (PyArrayObject *)PyArray_NewLikeArray(
            (PyArrayObject *)ret, NPY_ANYORDER, NULL, 0);
        if (ret_copy == NULL) {
            Py_DECREF(ret);
            return NULL;
        }

        if (PyArray_CopyInto(ret_copy, (PyArrayObject *)ret) != 0) {
            Py_DECREF(ret);
            Py_DECREF(ret_copy);
            return NULL;
        }

        Py_INCREF(ret);
        if (PyArray_SetWritebackIfCopyBase(ret_copy, (PyArrayObject *)ret) < 0) {
            Py_DECREF(ret);
            Py_DECREF(ret_copy);
            return NULL;
        }

        return ret_copy;
    }
    else {
        return (PyArrayObject *)ret;
    }
}
コード例 #2
0
ファイル: reduction.c プロジェクト: ChrisBarker-NOAA/numpy
/*
 * This function initializes a result array for a reduction operation
 * which has no identity. This means it needs to copy the first element
 * it sees along the reduction axes to result, then return a view of
 * the operand which excludes that element.
 *
 * If a reduction has an identity, such as 0 or 1, the result should be
 * initialized by calling PyArray_AssignZero(result, NULL, NULL) or
 * PyArray_AssignOne(result, NULL, NULL), because this function raises an
 * exception when there are no elements to reduce (which appropriate iff the
 * reduction operation has no identity).
 *
 * This means it copies the subarray indexed at zero along each reduction axis
 * into 'result', then returns a view into 'operand' excluding those copied
 * elements.
 *
 * result  : The array into which the result is computed. This must have
 *           the same number of dimensions as 'operand', but for each
 *           axis i where 'axis_flags[i]' is True, it has a single element.
 * operand : The array being reduced.
 * axis_flags : An array of boolean flags, one for each axis of 'operand'.
 *              When a flag is True, it indicates to reduce along that axis.
 * 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.
 * out_skip_first_count : This gets populated with the number of first-visit
 *                        elements that should be skipped during the
 *                        iteration loop.
 * funcname : The name of the reduction operation, for the purpose of
 *            better quality error messages. For example, "numpy.max"
 *            would be a good name for NumPy's max function.
 *
 * Returns a view which contains the remaining elements on which to do
 * the reduction.
 */
NPY_NO_EXPORT PyArrayObject *
PyArray_InitializeReduceResult(
                    PyArrayObject *result, PyArrayObject *operand,
                    npy_bool *axis_flags, int reorderable,
                    npy_intp *out_skip_first_count, const char *funcname)
{
    npy_intp *strides, *shape, shape_orig[NPY_MAXDIMS];
    PyArrayObject *op_view = NULL;
    int idim, ndim, nreduce_axes;

    ndim = PyArray_NDIM(operand);

    /* Default to no skipping first-visit elements in the iteration */
    *out_skip_first_count = 0;

    /*
     * If this reduction is non-reorderable, make sure there are
     * only 0 or 1 axes in axis_flags.
     */
    if (!reorderable && check_nonreorderable_axes(ndim,
                                    axis_flags, funcname) < 0) {
        return NULL;
    }

    /* Take a view into 'operand' which we can modify. */
    op_view = (PyArrayObject *)PyArray_View(operand, NULL, &PyArray_Type);
    if (op_view == NULL) {
        return NULL;
    }

    /*
     * Now copy the subarray of the first element along each reduction axis,
     * then return a view to the rest.
     *
     * Adjust the shape to only look at the first element along
     * any of the reduction axes. We count the number of reduction axes
     * at the same time.
     */
    shape = PyArray_SHAPE(op_view);
    nreduce_axes = 0;
    memcpy(shape_orig, shape, ndim * sizeof(npy_intp));
    for (idim = 0; idim < ndim; ++idim) {
        if (axis_flags[idim]) {
            if (shape[idim] == 0) {
                PyErr_Format(PyExc_ValueError,
                             "zero-size array to reduction operation %s "
                             "which has no identity",
                             funcname);
                Py_DECREF(op_view);
                return NULL;
            }
            shape[idim] = 1;
            ++nreduce_axes;
        }
    }

    /*
     * Copy the elements into the result to start.
     */
    if (PyArray_CopyInto(result, op_view) < 0) {
        Py_DECREF(op_view);
        return NULL;
    }

    /*
     * If there is one reduction axis, adjust the view's
     * shape to only look at the remaining elements
     */
    if (nreduce_axes == 1) {
        strides = PyArray_STRIDES(op_view);
        for (idim = 0; idim < ndim; ++idim) {
            if (axis_flags[idim]) {
                shape[idim] = shape_orig[idim] - 1;
                ((PyArrayObject_fields *)op_view)->data += strides[idim];
            }
        }
    }
    /* If there are zero reduction axes, make the view empty */
    else if (nreduce_axes == 0) {
        for (idim = 0; idim < ndim; ++idim) {
            shape[idim] = 0;
        }
    }
    /*
     * Otherwise iterate over the whole operand, but tell the inner loop
     * to skip the elements we already copied by setting the skip_first_count.
     */
    else {
        *out_skip_first_count = PyArray_SIZE(result);

        Py_DECREF(op_view);
        Py_INCREF(operand);
        op_view = operand;
    }

    return op_view;
}
コード例 #3
0
ファイル: fortranobject.c プロジェクト: 7924102/numpy
extern
PyArrayObject* array_from_pyobj(const int type_num,
                                npy_intp *dims,
                                const int rank,
                                const int intent,
                                PyObject *obj) {
    /* Note about reference counting
       -----------------------------
       If the caller returns the array to Python, it must be done with
       Py_BuildValue("N",arr).
       Otherwise, if obj!=arr then the caller must call Py_DECREF(arr).

       Note on intent(cache,out,..)
       ---------------------
       Don't expect correct data when returning intent(cache) array.

    */
    char mess[200];
    PyArrayObject *arr = NULL;
    PyArray_Descr *descr;
    char typechar;
    int elsize;

    if ((intent & F2PY_INTENT_HIDE)
        || ((intent & F2PY_INTENT_CACHE) && (obj==Py_None))
        || ((intent & F2PY_OPTIONAL) && (obj==Py_None))
        ) {
        /* intent(cache), optional, intent(hide) */
        if (count_nonpos(rank,dims)) {
            int i;
            strcpy(mess, "failed to create intent(cache|hide)|optional array"
                   "-- must have defined dimensions but got (");
            for(i=0;i<rank;++i)
                sprintf(mess+strlen(mess),"%" NPY_INTP_FMT ",",dims[i]);
            strcat(mess, ")");
            PyErr_SetString(PyExc_ValueError,mess);
            return NULL;
        }
        arr = (PyArrayObject *)
            PyArray_New(&PyArray_Type, rank, dims, type_num,
                        NULL,NULL,0,
                        !(intent&F2PY_INTENT_C),
                        NULL);
        if (arr==NULL) return NULL;
        if (!(intent & F2PY_INTENT_CACHE))
            PyArray_FILLWBYTE(arr, 0);
        return arr;
    }

    descr = PyArray_DescrFromType(type_num);
    elsize = descr->elsize;
    typechar = descr->type;
    Py_DECREF(descr);
    if (PyArray_Check(obj)) {
        arr = (PyArrayObject *)obj;

        if (intent & F2PY_INTENT_CACHE) {
            /* intent(cache) */
            if (PyArray_ISONESEGMENT(arr)
                && PyArray_ITEMSIZE(arr)>=elsize) {
                if (check_and_fix_dimensions(arr,rank,dims)) {
                    return NULL; /*XXX: set exception */
                }
                if (intent & F2PY_INTENT_OUT)
                    Py_INCREF(arr);
                return arr;
            }
            strcpy(mess, "failed to initialize intent(cache) array");
            if (!PyArray_ISONESEGMENT(arr))
                strcat(mess, " -- input must be in one segment");
            if (PyArray_ITEMSIZE(arr)<elsize)
                sprintf(mess+strlen(mess),
                        " -- expected at least elsize=%d but got %" NPY_INTP_FMT,
                        elsize,
                        (npy_intp)PyArray_ITEMSIZE(arr)
                        );
            PyErr_SetString(PyExc_ValueError,mess);
            return NULL;
        }

        /* here we have always intent(in) or intent(inout) or intent(inplace) */

        if (check_and_fix_dimensions(arr,rank,dims)) {
            return NULL; /*XXX: set exception */
        }
	/*
	printf("intent alignement=%d\n", F2PY_GET_ALIGNMENT(intent));
	printf("alignement check=%d\n", F2PY_CHECK_ALIGNMENT(arr, intent));
	int i;
	for (i=1;i<=16;i++)
	  printf("i=%d isaligned=%d\n", i, ARRAY_ISALIGNED(arr, i));
	*/
        if ((! (intent & F2PY_INTENT_COPY))
            && PyArray_ITEMSIZE(arr)==elsize
            && ARRAY_ISCOMPATIBLE(arr,type_num)
	    && F2PY_CHECK_ALIGNMENT(arr, intent)
            ) {
            if ((intent & F2PY_INTENT_C)?PyArray_ISCARRAY(arr):PyArray_ISFARRAY(arr)) {
                if ((intent & F2PY_INTENT_OUT)) {
                    Py_INCREF(arr);
                }
                /* Returning input array */
                return arr;
            }
        }

        if (intent & F2PY_INTENT_INOUT) {
            strcpy(mess, "failed to initialize intent(inout) array");
            if ((intent & F2PY_INTENT_C) && !PyArray_ISCARRAY(arr))
                strcat(mess, " -- input not contiguous");
            if (!(intent & F2PY_INTENT_C) && !PyArray_ISFARRAY(arr))
                strcat(mess, " -- input not fortran contiguous");
            if (PyArray_ITEMSIZE(arr)!=elsize)
                sprintf(mess+strlen(mess),
                        " -- expected elsize=%d but got %" NPY_INTP_FMT,
                        elsize,
                        (npy_intp)PyArray_ITEMSIZE(arr)
                        );
            if (!(ARRAY_ISCOMPATIBLE(arr,type_num)))
                sprintf(mess+strlen(mess)," -- input '%c' not compatible to '%c'",
                        PyArray_DESCR(arr)->type,typechar);
	    if (!(F2PY_CHECK_ALIGNMENT(arr, intent)))
	      sprintf(mess+strlen(mess)," -- input not %d-aligned", F2PY_GET_ALIGNMENT(intent));
            PyErr_SetString(PyExc_ValueError,mess);
            return NULL;
        }

        /* here we have always intent(in) or intent(inplace) */

        {
            PyArrayObject *retarr = (PyArrayObject *) \
                PyArray_New(&PyArray_Type, PyArray_NDIM(arr), PyArray_DIMS(arr), type_num,
                            NULL,NULL,0,
                            !(intent&F2PY_INTENT_C),
                            NULL);
            if (retarr==NULL)
                return NULL;
            F2PY_REPORT_ON_ARRAY_COPY_FROMARR;
            if (PyArray_CopyInto(retarr, arr)) {
                Py_DECREF(retarr);
                return NULL;
            }
            if (intent & F2PY_INTENT_INPLACE) {
                if (swap_arrays(arr,retarr))
                    return NULL; /* XXX: set exception */
                Py_XDECREF(retarr);
                if (intent & F2PY_INTENT_OUT)
                    Py_INCREF(arr);
            } else {
                arr = retarr;
            }
        }
        return arr;
    }

    if ((intent & F2PY_INTENT_INOUT) ||
            (intent & F2PY_INTENT_INPLACE) ||
            (intent & F2PY_INTENT_CACHE)) {
        PyErr_SetString(PyExc_TypeError,
                        "failed to initialize intent(inout|inplace|cache) "
                        "array, input not an array");
        return NULL;
    }

    {
        F2PY_REPORT_ON_ARRAY_COPY_FROMANY;
        arr = (PyArrayObject *) \
            PyArray_FromAny(obj,PyArray_DescrFromType(type_num), 0,0,
                            ((intent & F2PY_INTENT_C)?NPY_ARRAY_CARRAY:NPY_ARRAY_FARRAY) \
                            | NPY_ARRAY_FORCECAST, NULL);
        if (arr==NULL)
            return NULL;
        if (check_and_fix_dimensions(arr,rank,dims))
            return NULL; /*XXX: set exception */
        return arr;
    }

}
コード例 #4
0
ファイル: fortranobject.c プロジェクト: 7924102/numpy
extern
int copy_ND_array(const PyArrayObject *arr, PyArrayObject *out)
{
    F2PY_REPORT_ON_ARRAY_COPY_FROMARR;
    return PyArray_CopyInto(out, (PyArrayObject *)arr);
}
コード例 #5
0
ファイル: dtnode.cpp プロジェクト: azybler/arXivLDA
/**
 * Constructor
 */
dtnode :: dtnode(PyArrayObject* arg_edges, PyObject* arg_children,
                 PyObject* arg_maxind, int arg_leafstart)
{       
  // Do some argument checking
  if(!PyList_Check(arg_children) || !PyList_Check(arg_maxind))
    {    
      // ERROR
      PyErr_SetString(PyExc_RuntimeError,
                      "Non-List children/maxind element in dirtree node");
      throw 1;
    }
  if(arg_leafstart < 0) 
    {
      // ERROR
      PyErr_SetString(PyExc_RuntimeError,
                      "Negative leafstart value in dirtree node");
      throw 1;
    }
  if(PyList_Size(arg_children) != PyList_Size(arg_maxind))
    {
      // ERROR
      PyErr_SetString(PyExc_RuntimeError,
                      "Different sizes for children/maxind in dirtree node");
      throw 1;
    }    
  double edgemin = PyFloat_AsDouble(PyArray_Min(arg_edges,NPY_MAXDIMS,NULL));    
  if(edgemin <= 0) 
    {
      // ERROR
      PyErr_SetString(PyExc_RuntimeError,
                      "Negative/zero edge value in dirtree node");
      throw 1;
    }

  // Populate data members
  int nci = PyList_Size(arg_children);
  this->leafstart = arg_leafstart;
  
  // Get edge values and sum
  // (note that this *must* be a copy!)
  npy_intp* edims = new npy_intp[1];
  edims[0] = PyArray_DIM(arg_edges,0);
  this->edges = (PyArrayObject*) PyArray_ZEROS(1,edims,PyArray_DOUBLE,0);
  PyArray_CopyInto(this->edges,arg_edges);
  this->edgesum = PyFloat_AsDouble(PyArray_Sum(this->edges,NPY_MAXDIMS,
                                               PyArray_DOUBLE,NULL));   
  // Also make a copy of *original* edge values 
  // (not augmented by counts)
  this->orig_edges = (PyArrayObject*) PyArray_ZEROS(1,edims,PyArray_DOUBLE,0);
  PyArray_CopyInto(this->orig_edges,arg_edges);
  this->orig_edgesum = PyFloat_AsDouble(PyArray_Sum(this->orig_edges,NPY_MAXDIMS,
                                                    PyArray_DOUBLE,NULL));   
  delete[] edims;

  // Recursively build children
  // 
  int c;
  for(c = 0; c < nci; c++)
    {    
      // Get max leaf index under this child, check it
      maxind.push_back(PyInt_AsLong(PyList_GetItem(arg_maxind,c)));
      if(maxind[c] < 0)
        {
          // ERROR
          PyErr_SetString(PyExc_RuntimeError,
                          "Negative maxind value in dirtree node");
          throw 1;
        }
      // exploiting boolean short-circuit here...
      if(c > 0 && maxind[c] <= maxind[c-1])
        {
          // ERROR
          PyErr_SetString(PyExc_RuntimeError,
                          "Non-increasing maxind value in dirtree node");
          throw 1;
        }
     
      // Recursively build child
      //
      try{
        // Check that node tuple size is correct
        PyObject* pynode = PyList_GetItem(arg_children,c);
        // Is child a dtnode, or a multinode?
        //
        if(4 == PyTuple_Size(pynode))
          {
            // dtnode

            // Unpack tuple contents
            PyArrayObject* cedges = (PyArrayObject*) PyTuple_GetItem(pynode,0);
            PyObject* cchildren = PyTuple_GetItem(pynode,1);
            PyObject* cmaxind = PyTuple_GetItem(pynode,2);
            int cleafstart = PyInt_AsLong(PyTuple_GetItem(pynode,3));
        
            // Build child dtnode
            node* newchild = new dtnode(cedges,cchildren,
                                        cmaxind,cleafstart);
            ichildren.push_back(newchild);
          }
        else if(5 == PyTuple_Size(pynode))
          {
            // multinode

            // Unpack tuple contents        
            PyObject* cchildren = PyTuple_GetItem(pynode,1);
            PyObject* cmaxind = PyTuple_GetItem(pynode,2);
            int cleafstart = PyInt_AsLong(PyTuple_GetItem(pynode,3));
            PyObject* variants = PyTuple_GetItem(pynode,4);

            // Build child multinode
            node* newchild = new multinode(cchildren,cmaxind,
                                           cleafstart,variants);
            ichildren.push_back(newchild);
          }
        else{
          // ERROR
          PyErr_SetString(PyExc_RuntimeError,
                          "Node has wrong number of elements");
          throw 1;
        }
      }
      catch (int err)
        {
          throw 1;
        }
    }
}