diff options
Diffstat (limited to 'numpy/doc/cython')
-rw-r--r-- | numpy/doc/cython/MANIFEST | 2 | ||||
-rw-r--r-- | numpy/doc/cython/Makefile | 37 | ||||
-rw-r--r-- | numpy/doc/cython/Python.pxi | 62 | ||||
-rw-r--r-- | numpy/doc/cython/README.txt | 20 | ||||
-rw-r--r-- | numpy/doc/cython/numpy.pxi | 133 | ||||
-rw-r--r-- | numpy/doc/cython/numpyx.pyx | 118 | ||||
-rwxr-xr-x | numpy/doc/cython/run_test.py | 3 | ||||
-rwxr-xr-x | numpy/doc/cython/setup.py | 49 |
8 files changed, 424 insertions, 0 deletions
diff --git a/numpy/doc/cython/MANIFEST b/numpy/doc/cython/MANIFEST new file mode 100644 index 000000000..feb3ec22a --- /dev/null +++ b/numpy/doc/cython/MANIFEST @@ -0,0 +1,2 @@ +numpyx.pyx +setup.py diff --git a/numpy/doc/cython/Makefile b/numpy/doc/cython/Makefile new file mode 100644 index 000000000..80be2c066 --- /dev/null +++ b/numpy/doc/cython/Makefile @@ -0,0 +1,37 @@ +# Simple makefile to quickly access handy build commands for Cython extension +# code generation. Note that the actual code to produce the extension lives in +# the setup.py file, this Makefile is just meant as a command +# convenience/reminder while doing development. + +help: + @echo "Numpy/Cython tasks. Available tasks:" + @echo "ext -> build the Cython extension module." + @echo "html -> create annotated HTML from the .pyx sources" + @echo "test -> run a simple test demo." + @echo "all -> Call ext, html and finally test." + +all: ext html test + +ext: numpyx.so + +test: ext + python run_test.py + +html: numpyx.pyx.html + +numpyx.so: numpyx.pyx numpyx.c + python setup.py build_ext --inplace + +numpyx.pyx.html: numpyx.pyx + cython -a numpyx.pyx + @echo "Annotated HTML of the C code generated in numpy.pyx.html" + +# Phony targets for cleanup and similar uses + +.PHONY: clean +clean: + rm -rf *~ *.so *.c *.o *.html build + +# Suffix rules +%.c : %.pyx + cython $< diff --git a/numpy/doc/cython/Python.pxi b/numpy/doc/cython/Python.pxi new file mode 100644 index 000000000..46d2fd1a7 --- /dev/null +++ b/numpy/doc/cython/Python.pxi @@ -0,0 +1,62 @@ +# :Author: Robert Kern +# :Copyright: 2004, Enthought, Inc. +# :License: BSD Style + + +cdef extern from "Python.h": + # Not part of the Python API, but we might as well define it here. + # Note that the exact type doesn't actually matter for Pyrex. + ctypedef int size_t + + # Some type declarations we need + ctypedef int Py_intptr_t + + + # String API + char* PyString_AsString(object string) + char* PyString_AS_STRING(object string) + object PyString_FromString(char* c_string) + object PyString_FromStringAndSize(char* c_string, int length) + object PyString_InternFromString(char *v) + + # Float API + object PyFloat_FromDouble(double v) + double PyFloat_AsDouble(object ob) + long PyInt_AsLong(object ob) + + + # Memory API + void* PyMem_Malloc(size_t n) + void* PyMem_Realloc(void* buf, size_t n) + void PyMem_Free(void* buf) + + void Py_DECREF(object obj) + void Py_XDECREF(object obj) + void Py_INCREF(object obj) + void Py_XINCREF(object obj) + + # CObject API + ctypedef void (*destructor1)(void* cobj) + ctypedef void (*destructor2)(void* cobj, void* desc) + int PyCObject_Check(object p) + object PyCObject_FromVoidPtr(void* cobj, destructor1 destr) + object PyCObject_FromVoidPtrAndDesc(void* cobj, void* desc, + destructor2 destr) + void* PyCObject_AsVoidPtr(object self) + void* PyCObject_GetDesc(object self) + int PyCObject_SetVoidPtr(object self, void* cobj) + + # TypeCheck API + int PyFloat_Check(object obj) + int PyInt_Check(object obj) + + # Error API + int PyErr_Occurred() + void PyErr_Clear() + int PyErr_CheckSignals() + +cdef extern from "string.h": + void *memcpy(void *s1, void *s2, int n) + +cdef extern from "math.h": + double fabs(double x) diff --git a/numpy/doc/cython/README.txt b/numpy/doc/cython/README.txt new file mode 100644 index 000000000..ff0abb0fe --- /dev/null +++ b/numpy/doc/cython/README.txt @@ -0,0 +1,20 @@ +================== + NumPy and Cython +================== + +This directory contains a small example of how to use NumPy and Cython +together. While much work is planned for the Summer of 2008 as part of the +Google Summer of Code project to improve integration between the two, even +today Cython can be used effectively to write optimized code that accesses +NumPy arrays. + +The example provided is just a stub showing how to build an extension and +access the array objects; improvements to this to show more sophisticated tasks +are welcome. + +To run it locally, simply type:: + + make help + +which shows you the currently available targets (these are just handy +shorthands for common commands).
\ No newline at end of file diff --git a/numpy/doc/cython/numpy.pxi b/numpy/doc/cython/numpy.pxi new file mode 100644 index 000000000..11cb8fac9 --- /dev/null +++ b/numpy/doc/cython/numpy.pxi @@ -0,0 +1,133 @@ +# :Author: Travis Oliphant + +cdef extern from "numpy/arrayobject.h": + + cdef enum NPY_TYPES: + NPY_BOOL + NPY_BYTE + NPY_UBYTE + NPY_SHORT + NPY_USHORT + NPY_INT + NPY_UINT + NPY_LONG + NPY_ULONG + NPY_LONGLONG + NPY_ULONGLONG + NPY_FLOAT + NPY_DOUBLE + NPY_LONGDOUBLE + NPY_CFLOAT + NPY_CDOUBLE + NPY_CLONGDOUBLE + NPY_OBJECT + NPY_STRING + NPY_UNICODE + NPY_VOID + NPY_NTYPES + NPY_NOTYPE + + cdef enum requirements: + NPY_CONTIGUOUS + NPY_FORTRAN + NPY_OWNDATA + NPY_FORCECAST + NPY_ENSURECOPY + NPY_ENSUREARRAY + NPY_ELEMENTSTRIDES + NPY_ALIGNED + NPY_NOTSWAPPED + NPY_WRITEABLE + NPY_UPDATEIFCOPY + NPY_ARR_HAS_DESCR + + NPY_BEHAVED + NPY_BEHAVED_NS + NPY_CARRAY + NPY_CARRAY_RO + NPY_FARRAY + NPY_FARRAY_RO + NPY_DEFAULT + + NPY_IN_ARRAY + NPY_OUT_ARRAY + NPY_INOUT_ARRAY + NPY_IN_FARRAY + NPY_OUT_FARRAY + NPY_INOUT_FARRAY + + NPY_UPDATE_ALL + + cdef enum defines: + NPY_MAXDIMS + + ctypedef struct npy_cdouble: + double real + double imag + + ctypedef struct npy_cfloat: + double real + double imag + + ctypedef int npy_intp + + ctypedef extern class numpy.dtype [object PyArray_Descr]: + cdef int type_num, elsize, alignment + cdef char type, kind, byteorder, hasobject + cdef object fields, typeobj + + ctypedef extern class numpy.ndarray [object PyArrayObject]: + cdef char *data + cdef int nd + cdef npy_intp *dimensions + cdef npy_intp *strides + cdef object base + cdef dtype descr + cdef int flags + + ctypedef extern class numpy.flatiter [object PyArrayIterObject]: + cdef int nd_m1 + cdef npy_intp index, size + cdef ndarray ao + cdef char *dataptr + + ctypedef extern class numpy.broadcast [object PyArrayMultiIterObject]: + cdef int numiter + cdef npy_intp size, index + cdef int nd + cdef npy_intp *dimensions + cdef void **iters + + object PyArray_ZEROS(int ndims, npy_intp* dims, NPY_TYPES type_num, int fortran) + object PyArray_EMPTY(int ndims, npy_intp* dims, NPY_TYPES type_num, int fortran) + dtype PyArray_DescrFromTypeNum(NPY_TYPES type_num) + object PyArray_SimpleNew(int ndims, npy_intp* dims, NPY_TYPES type_num) + int PyArray_Check(object obj) + object PyArray_ContiguousFromAny(object obj, NPY_TYPES type, + int mindim, int maxdim) + object PyArray_ContiguousFromObject(object obj, NPY_TYPES type, + int mindim, int maxdim) + npy_intp PyArray_SIZE(ndarray arr) + npy_intp PyArray_NBYTES(ndarray arr) + void *PyArray_DATA(ndarray arr) + object PyArray_FromAny(object obj, dtype newtype, int mindim, int maxdim, + int requirements, object context) + object PyArray_FROMANY(object obj, NPY_TYPES type_num, int min, + int max, int requirements) + object PyArray_NewFromDescr(object subtype, dtype newtype, int nd, + npy_intp* dims, npy_intp* strides, void* data, + int flags, object parent) + + object PyArray_FROM_OTF(object obj, NPY_TYPES type, int flags) + object PyArray_EnsureArray(object) + + object PyArray_MultiIterNew(int n, ...) + + char *PyArray_MultiIter_DATA(broadcast multi, int i) + void PyArray_MultiIter_NEXTi(broadcast multi, int i) + void PyArray_MultiIter_NEXT(broadcast multi) + + object PyArray_IterNew(object arr) + void PyArray_ITER_NEXT(flatiter it) + + void import_array() diff --git a/numpy/doc/cython/numpyx.pyx b/numpy/doc/cython/numpyx.pyx new file mode 100644 index 000000000..84dc333df --- /dev/null +++ b/numpy/doc/cython/numpyx.pyx @@ -0,0 +1,118 @@ +# -*- Mode: Python -*- Not really, but close enough +"""Cython access to Numpy arrays - simple example. +""" + +# Includes from the python headers +include "Python.pxi" +# Include the Numpy C API for use via Cython extension code +include "numpy.pxi" + +################################################ +# Initialize numpy - this MUST be done before any other code is executed. +import_array() + +# Import the Numpy module for access to its usual Python API +import numpy as np + + +# A 'def' function is visible in the Python-imported module +def print_array_info(ndarray arr): + """Simple information printer about an array. + + Code meant to illustrate Cython/NumPy integration only.""" + + cdef int i + + print '-='*10 + # Note: the double cast here (void * first, then Py_intptr_t) is needed in + # Cython but not in Pyrex, since the casting behavior of cython is slightly + # different (and generally safer) than that of Pyrex. In this case, we + # just want the memory address of the actual Array object, so we cast it to + # void before doing the Py_intptr_t cast: + print 'Printing array info for ndarray at 0x%0lx'% \ + (<Py_intptr_t><void *>arr,) + print 'number of dimensions:',arr.nd + print 'address of strides: 0x%0lx'%(<Py_intptr_t>arr.strides,) + print 'strides:' + for i from 0<=i<arr.nd: + # print each stride + print ' stride %d:'%i,<Py_intptr_t>arr.strides[i] + print 'memory dump:' + print_elements( arr.data, arr.strides, arr.dimensions, + arr.nd, sizeof(double), arr.dtype ) + print '-='*10 + print + +# A 'cdef' function is NOT visible to the python side, but it is accessible to +# the rest of this Cython module +cdef print_elements(char *data, + Py_intptr_t* strides, + Py_intptr_t* dimensions, + int nd, + int elsize, + object dtype): + cdef Py_intptr_t i,j + cdef void* elptr + + if dtype not in [np.dtype(np.object_), + np.dtype(np.float64)]: + print ' print_elements() not (yet) implemented for dtype %s'%dtype.name + return + + if nd ==0: + if dtype==np.dtype(np.object_): + elptr = (<void**>data)[0] #[0] dereferences pointer in Pyrex + print ' ',<object>elptr + elif dtype==np.dtype(np.float64): + print ' ',(<double*>data)[0] + elif nd == 1: + for i from 0<=i<dimensions[0]: + if dtype==np.dtype(np.object_): + elptr = (<void**>data)[0] + print ' ',<object>elptr + elif dtype==np.dtype(np.float64): + print ' ',(<double*>data)[0] + data = data + strides[0] + else: + for i from 0<=i<dimensions[0]: + print_elements(data, strides+1, dimensions+1, nd-1, elsize, dtype) + data = data + strides[0] + +def test_methods(ndarray arr): + """Test a few attribute accesses for an array. + + This illustrates how the pyrex-visible object is in practice a strange + hybrid of the C PyArrayObject struct and the python object. Some + properties (like .nd) are visible here but not in python, while others + like flags behave very differently: in python flags appears as a separate, + object while here we see the raw int holding the bit pattern. + + This makes sense when we think of how pyrex resolves arr.foo: if foo is + listed as a field in the ndarray struct description, it will be directly + accessed as a C variable without going through Python at all. This is why + for arr.flags, we see the actual int which holds all the flags as bit + fields. However, for any other attribute not listed in the struct, it + simply forwards the attribute lookup to python at runtime, just like python + would (which means that AttributeError can be raised for non-existent + attributes, for example).""" + + print 'arr.any() :',arr.any() + print 'arr.nd :',arr.nd + print 'arr.flags :',arr.flags + +def test(): + """this function is pure Python""" + arr1 = np.array(-1e-30,dtype=np.float64) + arr2 = np.array([1.0,2.0,3.0],dtype=np.float64) + + arr3 = np.arange(9,dtype=np.float64) + arr3.shape = 3,3 + + four = 4 + arr4 = np.array(['one','two',3,four],dtype=np.object_) + + arr5 = np.array([1,2,3]) # int types not (yet) supported by print_elements + + for arr in [arr1,arr2,arr3,arr4,arr5]: + print_array_info(arr) + diff --git a/numpy/doc/cython/run_test.py b/numpy/doc/cython/run_test.py new file mode 100755 index 000000000..96388011e --- /dev/null +++ b/numpy/doc/cython/run_test.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python +from numpyx import test +test() diff --git a/numpy/doc/cython/setup.py b/numpy/doc/cython/setup.py new file mode 100755 index 000000000..270e11c56 --- /dev/null +++ b/numpy/doc/cython/setup.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +"""Install file for example on how to use Cython with Numpy. + +Note: Cython is the successor project to Pyrex. For more information, see +http://cython.org. +""" + +from distutils.core import setup +from distutils.extension import Extension + +import numpy + +# We detect whether Cython is available, so that below, we can eventually ship +# pre-generated C for users to compile the extension without having Cython +# installed on their systems. +try: + from Cython.Distutils import build_ext + has_cython = True +except ImportError: + has_cython = False + +# Define a cython-based extension module, using the generated sources if cython +# is not available. +if has_cython: + pyx_sources = ['numpyx.pyx'] + cmdclass = {'build_ext': build_ext} +else: + # In production work, you can ship the auto-generated C source yourself to + # your users. In this case, we do NOT ship the .c file as part of numpy, + # so you'll need to actually have cython installed at least the first + # time. Since this is really just an example to show you how to use + # *Cython*, it makes more sense NOT to ship the C sources so you can edit + # the pyx at will with less chances for source update conflicts when you + # update numpy. + pyx_sources = ['numpyx.c'] + cmdclass = {} + + +# Declare the extension object +pyx_ext = Extension('numpyx', + pyx_sources, + include_dirs = [numpy.get_include()]) + +# Call the routine which does the real work +setup(name = 'numpyx', + description = 'Small example on using Cython to write a Numpy extension', + ext_modules = [pyx_ext], + cmdclass = cmdclass, + ) |