summaryrefslogtreecommitdiff
path: root/docs/examples/userguide/numpy_tutorial
diff options
context:
space:
mode:
authorgabrieldemarmiesse <gabriel.demarmiesse@teraki.com>2018-05-26 14:41:16 +0200
committergabrieldemarmiesse <gabriel.demarmiesse@teraki.com>2018-05-27 14:14:29 +0200
commitf35173fba8614b83d26ce11c9a34af5fc3b3bc71 (patch)
tree7de1a76a7bcd7eed5aed8ccfc00c8bf39d2e6c4d /docs/examples/userguide/numpy_tutorial
parent45df48301b0ab5dd35e9d68581b57f15b69dd74f (diff)
downloadcython-f35173fba8614b83d26ce11c9a34af5fc3b3bc71.tar.gz
Now all the files in the example directory are tested.
Diffstat (limited to 'docs/examples/userguide/numpy_tutorial')
-rw-r--r--docs/examples/userguide/numpy_tutorial/convolve_fused_types.pyx49
-rw-r--r--docs/examples/userguide/numpy_tutorial/convolve_infer_types.pyx39
-rw-r--r--docs/examples/userguide/numpy_tutorial/convolve_memview.pyx39
-rw-r--r--docs/examples/userguide/numpy_tutorial/convolve_py.py42
-rw-r--r--docs/examples/userguide/numpy_tutorial/convolve_typed.pyx53
5 files changed, 222 insertions, 0 deletions
diff --git a/docs/examples/userguide/numpy_tutorial/convolve_fused_types.pyx b/docs/examples/userguide/numpy_tutorial/convolve_fused_types.pyx
new file mode 100644
index 000000000..0b79e3e35
--- /dev/null
+++ b/docs/examples/userguide/numpy_tutorial/convolve_fused_types.pyx
@@ -0,0 +1,49 @@
+# cython: infer_types=True
+import numpy as np
+cimport cython
+
+ctypedef fused my_type:
+ int
+ double
+ long
+
+@cython.boundscheck(False)
+@cython.wraparound(False)
+cpdef naive_convolve(my_type [:,:] f, my_type [:,:] g):
+ if g.shape[0] % 2 != 1 or g.shape[1] % 2 != 1:
+ raise ValueError("Only odd dimensions on filter supported")
+
+ vmax = f.shape[0]
+ wmax = f.shape[1]
+ smax = g.shape[0]
+ tmax = g.shape[1]
+ smid = smax // 2
+ tmid = tmax // 2
+ xmax = vmax + 2*smid
+ ymax = wmax + 2*tmid
+
+ if my_type is int:
+ dtype = np.intc
+ elif my_type is double:
+ dtype = np.double
+ else:
+ dtype = np.long
+
+ h_np = np.zeros([xmax, ymax], dtype=dtype)
+ cdef my_type [:,:] h = h_np
+
+ cdef my_type value
+ for x in range(xmax):
+ for y in range(ymax):
+ s_from = max(smid - x, -smid)
+ s_to = min((xmax - x) - smid, smid + 1)
+ t_from = max(tmid - y, -tmid)
+ t_to = min((ymax - y) - tmid, tmid + 1)
+ value = 0
+ for s in range(s_from, s_to):
+ for t in range(t_from, t_to):
+ v = x - smid + s
+ w = y - tmid + t
+ value += g[smid - s, tmid - t] * f[v, w]
+ h[x, y] = value
+ return h_np \ No newline at end of file
diff --git a/docs/examples/userguide/numpy_tutorial/convolve_infer_types.pyx b/docs/examples/userguide/numpy_tutorial/convolve_infer_types.pyx
new file mode 100644
index 000000000..71bb6c747
--- /dev/null
+++ b/docs/examples/userguide/numpy_tutorial/convolve_infer_types.pyx
@@ -0,0 +1,39 @@
+# cython: infer_types=True
+import numpy as np
+cimport cython
+
+DTYPE = np.intc
+
+@cython.boundscheck(False)
+@cython.wraparound(False)
+def naive_convolve(int [:,::1] f, int [:,::1] g):
+ if g.shape[0] % 2 != 1 or g.shape[1] % 2 != 1:
+ raise ValueError("Only odd dimensions on filter supported")
+
+ vmax = f.shape[0]
+ wmax = f.shape[1]
+ smax = g.shape[0]
+ tmax = g.shape[1]
+ smid = smax // 2
+ tmid = tmax // 2
+ xmax = vmax + 2*smid
+ ymax = wmax + 2*tmid
+
+ h_np = np.zeros([xmax, ymax], dtype=DTYPE)
+ cdef int [:,::1] h = h_np
+
+ cdef int value
+ for x in range(xmax):
+ for y in range(ymax):
+ s_from = max(smid - x, -smid)
+ s_to = min((xmax - x) - smid, smid + 1)
+ t_from = max(tmid - y, -tmid)
+ t_to = min((ymax - y) - tmid, tmid + 1)
+ value = 0
+ for s in range(s_from, s_to):
+ for t in range(t_from, t_to):
+ v = x - smid + s
+ w = y - tmid + t
+ value += g[smid - s, tmid - t] * f[v, w]
+ h[x, y] = value
+ return h_np \ No newline at end of file
diff --git a/docs/examples/userguide/numpy_tutorial/convolve_memview.pyx b/docs/examples/userguide/numpy_tutorial/convolve_memview.pyx
new file mode 100644
index 000000000..b23ebc8ba
--- /dev/null
+++ b/docs/examples/userguide/numpy_tutorial/convolve_memview.pyx
@@ -0,0 +1,39 @@
+import numpy as np
+
+DTYPE = np.intc
+
+# It is possible to declare types in the function declaration.
+def naive_convolve(int [:,:] f, int [:,:] g):
+ if g.shape[0] % 2 != 1 or g.shape[1] % 2 != 1:
+ raise ValueError("Only odd dimensions on filter supported")
+
+ # We don't need to check for the type of NumPy array here because
+ # a check is already performed when calling the function.
+ cdef Py_ssize_t x, y, s, t, v, w, s_from, s_to, t_from, t_to
+ cdef Py_ssize_t vmax = f.shape[0]
+ cdef Py_ssize_t wmax = f.shape[1]
+ cdef Py_ssize_t smax = g.shape[0]
+ cdef Py_ssize_t tmax = g.shape[1]
+ cdef Py_ssize_t smid = smax // 2
+ cdef Py_ssize_t tmid = tmax // 2
+ cdef Py_ssize_t xmax = vmax + 2*smid
+ cdef Py_ssize_t ymax = wmax + 2*tmid
+
+ h_np = np.zeros([xmax, ymax], dtype=DTYPE)
+ cdef int [:,:] h = h_np
+
+ cdef int value
+ for x in range(xmax):
+ for y in range(ymax):
+ s_from = max(smid - x, -smid)
+ s_to = min((xmax - x) - smid, smid + 1)
+ t_from = max(tmid - y, -tmid)
+ t_to = min((ymax - y) - tmid, tmid + 1)
+ value = 0
+ for s in range(s_from, s_to):
+ for t in range(t_from, t_to):
+ v = x - smid + s
+ w = y - tmid + t
+ value += g[smid - s, tmid - t] * f[v, w]
+ h[x, y] = value
+ return h_np \ No newline at end of file
diff --git a/docs/examples/userguide/numpy_tutorial/convolve_py.py b/docs/examples/userguide/numpy_tutorial/convolve_py.py
new file mode 100644
index 000000000..14c8e85a4
--- /dev/null
+++ b/docs/examples/userguide/numpy_tutorial/convolve_py.py
@@ -0,0 +1,42 @@
+from __future__ import division
+import numpy as np
+def naive_convolve(f, g):
+ # f is an image and is indexed by (v, w)
+ # g is a filter kernel and is indexed by (s, t),
+ # it needs odd dimensions
+ # h is the output image and is indexed by (x, y),
+ # it is not cropped
+ if g.shape[0] % 2 != 1 or g.shape[1] % 2 != 1:
+ raise ValueError("Only odd dimensions on filter supported")
+ # smid and tmid are number of pixels between the center pixel
+ # and the edge, ie for a 5x5 filter they will be 2.
+ #
+ # The output size is calculated by adding smid, tmid to each
+ # side of the dimensions of the input image.
+ vmax = f.shape[0]
+ wmax = f.shape[1]
+ smax = g.shape[0]
+ tmax = g.shape[1]
+ smid = smax // 2
+ tmid = tmax // 2
+ xmax = vmax + 2*smid
+ ymax = wmax + 2*tmid
+ # Allocate result image.
+ h = np.zeros([xmax, ymax], dtype=f.dtype)
+ # Do convolution
+ for x in range(xmax):
+ for y in range(ymax):
+ # Calculate pixel value for h at (x,y). Sum one component
+ # for each pixel (s, t) of the filter g.
+ s_from = max(smid - x, -smid)
+ s_to = min((xmax - x) - smid, smid + 1)
+ t_from = max(tmid - y, -tmid)
+ t_to = min((ymax - y) - tmid, tmid + 1)
+ value = 0
+ for s in range(s_from, s_to):
+ for t in range(t_from, t_to):
+ v = x - smid + s
+ w = y - tmid + t
+ value += g[smid - s, tmid - t] * f[v, w]
+ h[x, y] = value
+ return h
diff --git a/docs/examples/userguide/numpy_tutorial/convolve_typed.pyx b/docs/examples/userguide/numpy_tutorial/convolve_typed.pyx
new file mode 100644
index 000000000..4a819d583
--- /dev/null
+++ b/docs/examples/userguide/numpy_tutorial/convolve_typed.pyx
@@ -0,0 +1,53 @@
+import numpy as np
+
+# We now need to fix a datatype for our arrays. I've used the variable
+# DTYPE for this, which is assigned to the usual NumPy runtime
+# type info object.
+DTYPE = np.intc
+
+def naive_convolve(f, g):
+ if g.shape[0] % 2 != 1 or g.shape[1] % 2 != 1:
+ raise ValueError("Only odd dimensions on filter supported")
+ assert f.dtype == DTYPE and g.dtype == DTYPE
+ # The "cdef" keyword is also used within functions to type variables. It
+ # can only be used at the top indentation level (there are non-trivial
+ # problems with allowing them in other places, though we'd love to see
+ # good and thought out proposals for it).
+
+ # Py_ssize_t is the proper C type for Python array indices.
+ cdef Py_ssize_t x, y, s, t, v, w, s_from, s_to, t_from, t_to
+
+ cdef Py_ssize_t vmax = f.shape[0]
+ cdef Py_ssize_t wmax = f.shape[1]
+ cdef Py_ssize_t smax = g.shape[0]
+ cdef Py_ssize_t tmax = g.shape[1]
+ cdef Py_ssize_t smid = smax // 2
+ cdef Py_ssize_t tmid = tmax // 2
+ cdef Py_ssize_t xmax = vmax + 2*smid
+ cdef Py_ssize_t ymax = wmax + 2*tmid
+ h = np.zeros([xmax, ymax], dtype=DTYPE)
+ # It is very important to type ALL your variables. You do not get any
+ # warnings if not, only much slower code (they are implicitly typed as
+ # Python objects).
+ # For the value variable, we want to use the same data type as is
+ # stored in the array, so we use int because it correspond to np.intc.
+ # NB! An important side-effect of this is that if "value" overflows its
+ # datatype size, it will simply wrap around like in C, rather than raise
+ # an error like in Python.
+ cdef int value
+ for x in range(xmax):
+ for y in range(ymax):
+ # Cython has built-in C functions for min and max.
+ # This makes the following lines very fast.
+ s_from = max(smid - x, -smid)
+ s_to = min((xmax - x) - smid, smid + 1)
+ t_from = max(tmid - y, -tmid)
+ t_to = min((ymax - y) - tmid, tmid + 1)
+ value = 0
+ for s in range(s_from, s_to):
+ for t in range(t_from, t_to):
+ v = x - smid + s
+ w = y - tmid + t
+ value += g[smid - s, tmid - t] * f[v, w]
+ h[x, y] = value
+ return h \ No newline at end of file