diff options
author | Stefan van der Walt <stefan@sun.ac.za> | 2008-08-23 23:17:23 +0000 |
---|---|---|
committer | Stefan van der Walt <stefan@sun.ac.za> | 2008-08-23 23:17:23 +0000 |
commit | 5c86844c34674e3d580ac2cd12ef171e18130b13 (patch) | |
tree | 2fdf1150706c07c7e193eb7483ce58a5074e5774 /doc/cython | |
parent | 376d483d31c4c5427510cf3a8c69fc795aef63aa (diff) | |
download | numpy-5c86844c34674e3d580ac2cd12ef171e18130b13.tar.gz |
Move documentation outside of source tree. Remove `doc` import from __init__.
Diffstat (limited to 'doc/cython')
-rw-r--r-- | doc/cython/MANIFEST | 2 | ||||
-rw-r--r-- | doc/cython/Makefile | 37 | ||||
-rw-r--r-- | doc/cython/README.txt | 20 | ||||
-rw-r--r-- | doc/cython/c_numpy.pxd | 136 | ||||
-rw-r--r-- | doc/cython/c_python.pxd | 62 | ||||
-rw-r--r-- | doc/cython/numpyx.pyx | 127 | ||||
-rwxr-xr-x | doc/cython/run_test.py | 3 | ||||
-rwxr-xr-x | doc/cython/setup.py | 49 |
8 files changed, 436 insertions, 0 deletions
diff --git a/doc/cython/MANIFEST b/doc/cython/MANIFEST new file mode 100644 index 000000000..feb3ec22a --- /dev/null +++ b/doc/cython/MANIFEST @@ -0,0 +1,2 @@ +numpyx.pyx +setup.py diff --git a/doc/cython/Makefile b/doc/cython/Makefile new file mode 100644 index 000000000..7c9c72981 --- /dev/null +++ b/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 numpyx.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/doc/cython/README.txt b/doc/cython/README.txt new file mode 100644 index 000000000..ff0abb0fe --- /dev/null +++ b/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/doc/cython/c_numpy.pxd b/doc/cython/c_numpy.pxd new file mode 100644 index 000000000..4a0bd1c01 --- /dev/null +++ b/doc/cython/c_numpy.pxd @@ -0,0 +1,136 @@ +# :Author: Travis Oliphant + +# API declaration section. This basically exposes the NumPy C API to +# Pyrex/Cython programs. + +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/doc/cython/c_python.pxd b/doc/cython/c_python.pxd new file mode 100644 index 000000000..46d2fd1a7 --- /dev/null +++ b/doc/cython/c_python.pxd @@ -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/doc/cython/numpyx.pyx b/doc/cython/numpyx.pyx new file mode 100644 index 000000000..cbc786ef0 --- /dev/null +++ b/doc/cython/numpyx.pyx @@ -0,0 +1,127 @@ +# -*- Mode: Python -*- Not really, but close enough +"""Cython access to Numpy arrays - simple example. +""" + +############################################################################# +# Load C APIs declared in .pxd files via cimport +# +# A 'cimport' is similar to a Python 'import' statement, but it provides access +# to the C part of a library instead of its Python-visible API. See the +# Pyrex/Cython documentation for details. + +cimport c_python as py + +cimport c_numpy as cnp + +# NOTE: numpy MUST be initialized before any other code is executed. +cnp.import_array() + +############################################################################# +# Load Python modules via normal import statements + +import numpy as np + +############################################################################# +# Regular code section begins + +# A 'def' function is visible in the Python-imported module +def print_array_info(cnp.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.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.Py_intptr_t cast: + print 'Printing array info for ndarray at 0x%0lx'% \ + (<py.Py_intptr_t><void *>arr,) + print 'number of dimensions:',arr.nd + print 'address of strides: 0x%0lx'%(<py.Py_intptr_t>arr.strides,) + print 'strides:' + for i from 0<=i<arr.nd: + # print each stride + print ' stride %d:'%i,<py.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.Py_intptr_t* strides, + py.Py_intptr_t* dimensions, + int nd, + int elsize, + object dtype): + cdef py.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(cnp.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/doc/cython/run_test.py b/doc/cython/run_test.py new file mode 100755 index 000000000..96388011e --- /dev/null +++ b/doc/cython/run_test.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python +from numpyx import test +test() diff --git a/doc/cython/setup.py b/doc/cython/setup.py new file mode 100755 index 000000000..270e11c56 --- /dev/null +++ b/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, + ) |