Example #1
0
static int
arrayflags_ownmaskna_set(PyArrayFlagsObject *self, PyObject *obj)
{
    if (self->arr == NULL) {
        PyErr_SetString(PyExc_ValueError, "Cannot set flags on array scalars.");
        return -1;
    }

    if (PyObject_IsTrue(obj)) {
        return PyArray_AllocateMaskNA((PyArrayObject *)self->arr, 1, 0, 1);
    }
    else {
        if (self->flags & NPY_ARRAY_OWNMASKNA) {
            PyErr_SetString(PyExc_ValueError,
                        "Cannot remove a NumPy array's NA mask");
            return -1;
        }
        else {
            return 0;
        }
    }
}
Example #2
0
/*NUMPY_API
 * Clip
 *
 * TODO: For adding NA support, a Clip UFunc should be created, then
 *       this should call that ufunc. 'min' and 'max' can default to
 *       the -inf/+inf or the smallest/largest representable values
 *       of the dtype respectively.
 */
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, *newdescr;
    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;
    /* Trigger the slow array clip for NA support as well */
    if (func == NULL ||
            PyArray_HASMASKNA(self) ||
            (min != NULL &&
                (!PyArray_CheckAnyScalar(min) ||
                 (PyArray_Check(min) &&
                  PyArray_HASMASKNA((PyArrayObject *)min)))) ||
            (max != NULL &&
                (!PyArray_CheckAnyScalar(max) ||
                 (PyArray_Check(max) &&
                  PyArray_HASMASKNA((PyArrayObject *)max))))) {
        return _slow_array_clip(self, min, max, out);
    }
    /* Use the fast scalar clip function */

    /* First we need to figure out the correct type */
    indescr = NULL;
    if (min != NULL) {
        indescr = PyArray_DescrFromObject(min, NULL);
        if (indescr == NULL) {
            return NULL;
        }
    }
    if (max != NULL) {
        newdescr = PyArray_DescrFromObject(max, indescr);
        Py_XDECREF(indescr);
        if (newdescr == NULL) {
            return NULL;
        }
    }
    else {
        /* Steal the reference */
        newdescr = indescr;
    }


    /*
     * 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));
        func = indescr->f->fastclip;
        if (func == NULL) {
            return _slow_array_clip(self, min, max, out);
        }
    }
    else {
        indescr = PyArray_DESCR(self);
        Py_INCREF(indescr);
    }
    Py_DECREF(newdescr);

    if (!PyDataType_ISNOTSWAPPED(indescr)) {
        PyArray_Descr *descr2;
        descr2 = PyArray_DescrNewByteorder(indescr, '=');
        Py_DECREF(indescr);
        if (descr2 == NULL) {
            goto fail;
        }
        indescr = descr2;
    }

    /* Convert max to an array */
    if (max != NULL) {
        maxa = (PyArrayObject *)PyArray_FromAny(max, indescr, 0, 0,
                                 NPY_ARRAY_DEFAULT, NULL);
        if (maxa == NULL) {
            return NULL;
        }
    }
    else {
        /* Side-effect of PyArray_FromAny */
        Py_DECREF(indescr);
    }

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

        if ((maxa != NULL && PyArray_HASMASKNA(maxa)) ||
                                (mina != NULL && PyArray_HASMASKNA(mina))) {
            if (PyArray_AllocateMaskNA(out, 1, 0, 1) < 0) {
                goto fail;
            }
        }
        outgood = 1;
    }
    else Py_INCREF(out);
    /* Input is good at this point */
    if (out == newin) {
        outgood = 1;
    }
    if (!outgood && PyArray_ISONESEGMENT(out) &&
                        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
     */
    if (!outgood) {
        int oflags;
        if (PyArray_ISFORTRAN(out))
            oflags = NPY_ARRAY_FARRAY;
        else
            oflags = NPY_ARRAY_CARRAY;
        oflags |= NPY_ARRAY_UPDATEIFCOPY | NPY_ARRAY_FORCECAST;
        Py_INCREF(indescr);
        newout = (PyArrayObject*)PyArray_FromArray(out, indescr, oflags);
        if (newout == NULL) {
            goto fail;
        }
    }
    else {
        newout = out;
        Py_INCREF(newout);
    }

    /* make sure the shape of the output array is the same */
    if (!PyArray_SAMESHAPE(newin, newout)) {
        PyErr_SetString(PyExc_ValueError, "clip: Output array must have the"
                        "same shape as the input.");
        goto fail;
    }
    if (PyArray_DATA(newout) != PyArray_DATA(newin)) {
        if (PyArray_AssignArray(newout, newin,
                    NULL, NPY_DEFAULT_ASSIGN_CASTING,
                    0, NULL) < 0) {
            goto fail;
        }
    }

    /* 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(mina);
    Py_XDECREF(maxa);
    Py_DECREF(newin);
    /* Copy back into out if out was not already a nice array. */
    Py_DECREF(newout);
    return (PyObject *)out;

 fail:
    Py_XDECREF(maxa);
    Py_XDECREF(mina);
    Py_XDECREF(newin);
    PyArray_XDECREF_ERR(newout);
    return NULL;
}