diff options
author | Travis Oliphant <oliphant@enthought.com> | 2007-12-30 09:32:31 +0000 |
---|---|---|
committer | Travis Oliphant <oliphant@enthought.com> | 2007-12-30 09:32:31 +0000 |
commit | fdeac7465818652d5fb31e7e0e27f9debd0f54b8 (patch) | |
tree | 4d3146fdb9fb8f78eb6bf68891550e9b77b3ad44 /numpy/lib/src/_compiled_base.c | |
parent | 083ca64099268bc5967d25a15f9a4d26d750eb69 (diff) | |
parent | 50b26d2464f607566bf66986832636816eaa6d05 (diff) | |
download | numpy-fdeac7465818652d5fb31e7e0e27f9debd0f54b8.tar.gz |
Merge the lib_for_io branch back into the trunk.
Diffstat (limited to 'numpy/lib/src/_compiled_base.c')
-rw-r--r-- | numpy/lib/src/_compiled_base.c | 272 |
1 files changed, 271 insertions, 1 deletions
diff --git a/numpy/lib/src/_compiled_base.c b/numpy/lib/src/_compiled_base.c index 42c0183e8..654e7d95b 100644 --- a/numpy/lib/src/_compiled_base.c +++ b/numpy/lib/src/_compiled_base.c @@ -9,6 +9,9 @@ static PyObject *ErrorObject; goto fail;} \ } +#define PYSETERROR(message) \ +{ PyErr_SetString(ErrorObject, message); goto fail; } + static intp incr_slot_ (double x, double *bins, intp lbins) { @@ -526,6 +529,269 @@ arr_add_docstring(PyObject *dummy, PyObject *args) return Py_None; } + +static char packbits_doc[] = + "out = numpy.packbits(myarray, axis=None)\n\n" + " myarray : an integer type array whose elements should be packed to bits\n\n" + " This routine packs the elements of a binary-valued dataset into a\n" + " NumPy array of type uint8 ('B') whose bits correspond to\n" + " the logical (0 or nonzero) value of the input elements.\n" + " The dimension over-which bit-packing is done is given by axis.\n" + " The shape of the output has the same number of dimensions as the input\n" + " (unless axis is None, in which case the output is 1-d).\n" + "\n" + " Example:\n" + " >>> a = array([[[1,0,1],\n" + " ... [0,1,0]],\n" + " ... [[1,1,0],\n" + " ... [0,0,1]]])\n" + " >>> b = numpy.packbits(a,axis=-1)\n" + " >>> b\n" + " array([[[160],[64]],[[192],[32]]], dtype=uint8)\n\n" + " Note that 160 = 128 + 32\n" + " 192 = 128 + 64\n"; + +static char unpackbits_doc[] = + "out = numpy.unpackbits(myarray, axis=None)\n\n" + " myarray - array of uint8 type where each element represents a bit-field\n" + " that should be unpacked into a boolean output array\n\n" + " The shape of the output array is either 1-d (if axis is None) or\n" + " the same shape as the input array with unpacking done along the\n" + " axis specified."; + +/* PACKBITS + + This function packs binary (0 or 1) 1-bit per pixel arrays + into contiguous bytes. + +*/ + +static void +_packbits( + void *In, + int element_size, /* in bytes */ + npy_intp in_N, + npy_intp in_stride, + void *Out, + npy_intp out_N, + npy_intp out_stride + ) +{ + char build; + int i, index; + npy_intp out_Nm1; + int maxi, remain, nonzero, j; + char *outptr,*inptr; + + outptr = Out; /* pointer to output buffer */ + inptr = In; /* pointer to input buffer */ + + /* Loop through the elements of In */ + /* Determine whether or not it is nonzero. + Yes: set correspdoning bit (and adjust build value) + No: move on + /* Every 8th value, set the value of build and increment the outptr */ + + remain = in_N % 8; /* uneven bits */ + if (remain == 0) remain = 8; + out_Nm1 = out_N - 1; + for (index = 0; index < out_N; index++) { + build = 0; + maxi = (index != out_Nm1 ? 8 : remain); + for (i = 0; i < maxi ; i++) { + build <<= 1; /* shift bits left one bit */ + nonzero = 0; + for (j = 0; j < element_size; j++) /* determine if this number is non-zero */ + nonzero += (*(inptr++) != 0); + inptr += (in_stride - element_size); /* advance to next input */ + build += (nonzero != 0); /* add to this bit if the input value is non-zero */ + } + if (index == out_Nm1) build <<= (8-remain); + /* printf("Here: %d %d %d %d\n",build,slice,index,maxi); + */ + *outptr = build; + outptr += out_stride; + } + return; +} + + +static void +_unpackbits( + void *In, + int el_size, /* unused */ + npy_intp in_N, + npy_intp in_stride, + void *Out, + npy_intp out_N, + npy_intp out_stride + ) +{ + unsigned char mask; + int i,index; + char *inptr, *outptr; + + /* Loop through the elements of out + */ + outptr = Out; + inptr = In; + for (index = 0; index < in_N; index++) { + mask = 128; + for (i = 0; i < 8 ; i++) { + *outptr = ((mask & (unsigned char)(*inptr)) != 0); + outptr += out_stride; + mask >>= 1; + } + inptr += in_stride; + } + return; +} + +static PyObject * +pack_or_unpack_bits(PyObject *input, int axis, int unpack) +{ + PyArrayObject *inp; + PyObject *new=NULL; + PyObject *out=NULL; + npy_intp outdims[MAX_DIMS]; + int i; + void (*thefunc)(void *, int, npy_intp, npy_intp, void *, npy_intp, npy_intp); + PyArrayIterObject *it, *ot; + + inp = (PyArrayObject *)PyArray_FROM_O(input); + + if (inp == NULL) return NULL; + + if (unpack) { + if (PyArray_TYPE(inp) != NPY_UBYTE) + PYSETERROR("Expecting an input array of unsigned byte data type"); + } + else { + if (!PyArray_ISINTEGER(inp)) + PYSETERROR("Expecting an input array of integer data type"); + } + + new = PyArray_CheckAxis(inp, &axis, 0); + Py_DECREF(inp); + if (new == NULL) return NULL; + + /* Handle zero-dim array separately */ + if (PyArray_SIZE(new) == 0) { + return PyArray_Copy((PyArrayObject *)new); + } + + if (PyArray_NDIM(new) == 0) { + if (unpack) { + /* Handle 0-d array by converting it to a 1-d array */ + PyObject *temp; + PyArray_Dims newdim = {NULL, 1}; + npy_intp shape=1; + newdim.ptr = &shape; + temp = PyArray_Newshape((PyArrayObject *)new, &newdim, NPY_CORDER); + if (temp == NULL) goto fail; + Py_DECREF(new); + new = temp; + } + else { + ubyte *optr, *iptr; + out = PyArray_New(new->ob_type, 0, NULL, NPY_UBYTE, + NULL, NULL, 0, 0, NULL); + if (out == NULL) goto fail; + optr = PyArray_DATA(out); + iptr = PyArray_DATA(new); + *optr = 0; + for (i=0; i<PyArray_ITEMSIZE(new); i++) { + if (*iptr != 0) { + *optr = 1; + break; + } + iptr++; + } + goto finish; + } + } + + + /* Setup output shape */ + for (i=0; i<PyArray_NDIM(new); i++) { + outdims[i] = PyArray_DIM(new, i); + } + + if (unpack) { + /* Multiply axis dimension by 8 */ + outdims[axis] <<= 3; + thefunc = _unpackbits; + } + else { + /* Divide axis dimension by 8 */ + /* 8 -> 1, 9 -> 2, 16 -> 2, 17 -> 3 etc.. */ + outdims[axis] = ((outdims[axis] - 1) >> 3) + 1; + thefunc = _packbits; + } + + /* Create output array */ + out = PyArray_New(new->ob_type, PyArray_NDIM(new), outdims, PyArray_UBYTE, + NULL, NULL, 0, PyArray_ISFORTRAN(new), NULL); + if (out == NULL) goto fail; + + /* Setup iterators to iterate over all but given axis */ + it = (PyArrayIterObject *)PyArray_IterAllButAxis((PyObject *)new, &axis); + ot = (PyArrayIterObject *)PyArray_IterAllButAxis((PyObject *)out, &axis); + if (it == NULL || ot == NULL) { + Py_XDECREF(it); + Py_XDECREF(ot); + goto fail; + } + + while(PyArray_ITER_NOTDONE(it)) { + thefunc(PyArray_ITER_DATA(it), PyArray_ITEMSIZE(new), + PyArray_DIM(new, axis), PyArray_STRIDE(new, axis), + PyArray_ITER_DATA(ot), PyArray_DIM(out, axis), + PyArray_STRIDE(out, axis)); + PyArray_ITER_NEXT(it); + PyArray_ITER_NEXT(ot); + } + Py_DECREF(it); + Py_DECREF(ot); + + finish: + Py_DECREF(new); + return out; + + fail: + Py_XDECREF(new); + Py_XDECREF(out); + return NULL; +} + + + +static PyObject * +io_pack(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *obj; + int axis=NPY_MAXDIMS; + static char *kwlist[] = {"in", "axis", NULL}; + + if (!PyArg_ParseTupleAndKeywords( args, kwds, "O|O&" , kwlist, + &obj, PyArray_AxisConverter, &axis)) + return NULL; + return pack_or_unpack_bits(obj, axis, 0); +} + +static PyObject * +io_unpack(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *obj; + int axis=NPY_MAXDIMS; + static char *kwlist[] = {"in", "axis", NULL}; + + if (!PyArg_ParseTupleAndKeywords( args, kwds, "O|O&" , kwlist, + &obj, PyArray_AxisConverter, &axis)) + return NULL; + return pack_or_unpack_bits(obj, axis, 1); +} + static struct PyMethodDef methods[] = { {"_insert", (PyCFunction)arr_insert, METH_VARARGS | METH_KEYWORDS, arr_insert__doc__}, @@ -537,6 +803,10 @@ static struct PyMethodDef methods[] = { NULL}, {"add_docstring", (PyCFunction)arr_add_docstring, METH_VARARGS, NULL}, + {"packbits", (PyCFunction)io_pack, METH_VARARGS | METH_KEYWORDS, + packbits_doc}, + {"unpackbits", (PyCFunction)io_unpack, METH_VARARGS | METH_KEYWORDS, + unpackbits_doc}, {NULL, NULL} /* sentinel */ }; @@ -578,7 +848,7 @@ PyMODINIT_FUNC init_compiled_base(void) { PyDict_SetItemString(d, "__version__", s); Py_DECREF(s); - ErrorObject = PyString_FromString("numpy.lib._compiled_base.error"); + ErrorObject = PyString_FromString("numpy.lib.error"); PyDict_SetItemString(d, "error", ErrorObject); Py_DECREF(ErrorObject); |