summaryrefslogtreecommitdiff
path: root/numpy/doc/cython/numpyx.pyx
blob: 84dc333df24d4ab812d516592f24be29c1152ef8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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)