Example #1
0
NPY_NO_EXPORT int
needs_right_binop_forward(PyObject *self, PyObject *other,
                          char *right_name, int inplace_op)
{
    if (other == NULL ||
        self == NULL ||
        Py_TYPE(self) == Py_TYPE(other) ||
        PyArray_CheckExact(other) ||
        PyArray_CheckAnyScalar(other)) {
        /*
         * Quick cases
         */
        return 0;
    }
    if (!inplace_op && PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self)) ||
        !PyArray_Check(self)) {
        /*
         * Bail out if Python would already have called the right-hand
         * operation.
         */
        return 0;
    }
    if (has_ufunc_attr(other) &&
        PyObject_HasAttrString(other, right_name)) {
        return 1;
    }
    else {
        return 0;
    }
}
Example #2
0
/*
 * check if in "alhs @op@ orhs" that alhs is a temporary (refcnt == 1) so we
 * can do in-place operations instead of creating a new temporary
 * "cannot" is set to true if it cannot be done even with swapped arguments
 */
static int
can_elide_temp(PyArrayObject * alhs, PyObject * orhs, int * cannot)
{
    /*
     * to be a candidate the array needs to have reference count 1, be an exact
     * array of a basic type, own its data and size larger than threshold
     */
    if (Py_REFCNT(alhs) != 1 || !PyArray_CheckExact(alhs) ||
            !PyArray_ISNUMBER(alhs) ||
            !PyArray_CHKFLAGS(alhs, NPY_ARRAY_OWNDATA) ||
            !PyArray_ISWRITEABLE(alhs) ||
            PyArray_CHKFLAGS(alhs, NPY_ARRAY_UPDATEIFCOPY) ||
            PyArray_CHKFLAGS(alhs, NPY_ARRAY_WRITEBACKIFCOPY) ||
            PyArray_NBYTES(alhs) < NPY_MIN_ELIDE_BYTES) {
        return 0;
    }
    if (PyArray_CheckExact(orhs) ||
        PyArray_CheckAnyScalar(orhs)) {
        PyArrayObject * arhs;

        /* create array from right hand side */
        Py_INCREF(orhs);
        arhs = (PyArrayObject *)PyArray_EnsureArray(orhs);
        if (arhs == NULL) {
            return 0;
        }

        /*
         * if rhs is not a scalar dimensions must match
         * TODO: one could allow broadcasting on equal types
         */
        if (!(PyArray_NDIM(arhs) == 0 ||
              (PyArray_NDIM(arhs) == PyArray_NDIM(alhs) &&
               PyArray_CompareLists(PyArray_DIMS(alhs), PyArray_DIMS(arhs),
                                    PyArray_NDIM(arhs))))) {
                Py_DECREF(arhs);
                return 0;
        }

        /* must be safe to cast (checks values for scalar in rhs) */
        if (PyArray_CanCastArrayTo(arhs, PyArray_DESCR(alhs),
                                   NPY_SAFE_CASTING)) {
            Py_DECREF(arhs);
            return check_callers(cannot);
        }
        Py_DECREF(arhs);
    }

    return 0;
}
Example #3
0
/*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;
}