├── Cython.pdf ├── blog-post └── cython-tutorial.rst ├── cython-tutorial.rst ├── demo ├── blackburn-pendulum │ └── blackburn_pendulum.py ├── class-particle │ ├── Makefile │ ├── particle.pyx │ ├── particle_heap.pyx │ ├── setup.py │ └── test_particle.py ├── cython-julia-set.ipynb ├── fib │ ├── Makefile │ ├── cfib.c │ ├── cfib.h │ ├── cyfib.ipy │ ├── cyfib.ipynb │ ├── fib.c │ ├── fib.py │ ├── fib.pyx │ ├── fib_orig.c │ ├── fib_orig.pyx │ ├── fib_py.c │ ├── hand_fib.c │ ├── hand_fib_setup.py │ ├── main.c │ ├── setup.py │ ├── test.py │ └── wrap_cfib.pyx ├── harmonograph │ ├── harmonograph.py │ └── harmonograph_ui.py ├── wrap-c-time │ ├── setup.py │ └── time_extern.pyx └── wrap-cpp-particle │ ├── particle.cpp │ ├── particle.h │ ├── particle_tmpl.cpp │ ├── particle_tmpl.h │ ├── runjinja.py │ ├── setup.py │ ├── setup_tmpl.py │ ├── test_wrap_particle.py │ ├── wrap_particle.pyx │ ├── wrap_particle_tmpl.pyx.in │ └── wrap_particle_tmpl_jinja.pyx ├── exercises ├── hello-world │ ├── Makefile │ ├── README.rst │ ├── build.bat │ ├── cython-hello-world.ipynb │ ├── cython_hello_world.pyx │ ├── setup.py │ ├── test_hello_world.py │ └── use_pyximport.py ├── julia │ ├── LICENSE.txt │ ├── Makefile │ ├── README.rst │ ├── build.bat │ ├── cython-julia-set.ipynb │ ├── julia.py │ ├── julia_cython.pyx │ ├── julia_cython_solution.pyx │ ├── julia_numpy.py │ ├── julia_pure_python.py │ ├── julia_ui.py │ ├── setup.py │ ├── timing.py │ └── utils.py └── sinc │ ├── Makefile │ ├── README.rst │ ├── setup.py │ ├── sinc_kernel.pyx │ ├── sinc_python.py │ ├── sinc_solution.pyx │ └── test_sinc.py └── test_cython ├── test-cython.ipynb ├── test_cython.pyx └── test_pyximport.py /Cython.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwmsmith/scipy2013-cython-tutorial/ec8bd70194f5822bc9a61798699d6ccb9018ad6f/Cython.pdf -------------------------------------------------------------------------------- /blog-post/cython-tutorial.rst: -------------------------------------------------------------------------------- 1 | SciPy 2013 Cython Tutorial 2 | ------------------------------------------------------------------------------- 3 | 4 | Thanks to everyone who attended the Cython tutorial [tut]_ at this year's 5 | SciPy conference, and thanks to the conference organizers and tutorial chairs 6 | for ensuring everything ran smoothly. The enthusiasm of the students came 7 | through in their questions, and there were several good conversations after 8 | the tutorial throughout the week. 9 | 10 | If you want the tutorial experience from the comfort of your couch, you can 11 | download the tutorial slides, exercises, and demos [content]_, and follow 12 | along with the videos [tut]_. Please read the setup instructions on the 13 | tutorial webpage. The easiest way to satisfy the requirements for the 14 | tutorial is to download and install an existing scientific Python 15 | distribution, such as Enthought's Canopy [canopy]_. You will need Cython 16 | version 0.19 or greater. 17 | 18 | Tutorial Highlights 19 | ------------------------------------------------------------------------------- 20 | 21 | Cython is a language for adding static type information to Python with the 22 | objective of improving Python's performance; it is a compiler (the `cython` 23 | command) for generating Python extension modules; and it helps wrap C and C++ 24 | libraries in a nice and Pythonic way with a minimum of overhead. These three 25 | aspects of Cython are tightly integrated with each other and shouldn't be 26 | thought about in isolation: it is common to have Cython code that is intended 27 | to both speed up a pure-Python algorithm and that also calls out to C or C++ 28 | libraries. 29 | 30 | Compared with some of the newer Python JIT compilers that are on the rise, 31 | Cython is relatively mature -- not SWIG mature, but it certainly has been 32 | around long enough that it has grown features beyond its core functionality: 33 | annotated source files for compile-time performance profiling, runtime 34 | profiling that integrates with Python's profilers, cross-language debugging 35 | capabilities, integration with IPython and the IPython notebook via the 36 | `%%cython` magic and other magic commands, the `pyximport` import hook 37 | support, Python 2 and Python 3 support, parallelization support via OpenMP, 38 | and others. I wanted this tutorial to touch on several of these extra 39 | capabilities that make Cython easier to use. 40 | 41 | The tutorial was in the advanced track because I wanted to dive into newer and 42 | more advanced Cython features, especially typed memoryviews [memviews]_. 43 | Typed memoryviews are Cython's interface to PEP-3118 [3118]_ buffers, the new 44 | buffer protocol for accessing and passing around (possibly strided) blobs of 45 | memory without copying. This is of considerable interest to scientific 46 | computing audiences for whom non-copying array operations are essential. 47 | NumPy arrays support this protocol, and are the primary object used with this 48 | protocol. Cython's syntax for typed memoryviews is nice, and taking a slice 49 | of a typed memoryview yields another typed memoryview and, as you would 50 | expect, does not copy memory. 51 | 52 | I was able to cover typed memoryviews towards the end of the tutorial, but 53 | didn't have quite enough time to demonstrate their full power. Typed 54 | memoryviews are in every way superior to the existing numpy buffer support in 55 | Cython (the `cdef np.ndarray[double, ndim=2]` declarations) -- they are 56 | faster, they are supported in function signatures for every kind of Cython 57 | function definition (`def`, `cdef`, and `cpdef`), they are easier to declare 58 | and use, and they do not have any external dependencies (i.e., you do not have 59 | to `cimport` anything to use them, and you do not have to add extra include 60 | flags when compiling). 61 | 62 | Another advanced topic I touched on in the tutorial was wrapping templated C++ 63 | classes. Cython's syntax for wrapping templated C++ is fairly easy to work 64 | with if you are wrapping just one template instantiation. Once you need to 65 | wrap several template instantiations, I recommend you use a code generation 66 | tool like cheetah or jinja2 to avoid manual code duplication. It is often 67 | helpful to provide a top-level wrapper class for a more Pythonic experience. 68 | Examples of this approach are in the tutorial material zip file. Cython's 69 | fused types can alleviate the need for these workarounds, but can require some 70 | gymnastics of their own to use. The "real" solution to wrapping many 71 | instantiations of C++ templates is a templating system or macro system in 72 | Cython itself, which is hard to get right and is likely beyond the scope of 73 | the project. 74 | 75 | I also wanted to demonstrate how to wrap modern Fortran: user derived types, 76 | assumed shape and assumed size arrays, module procedures, etc. You can 77 | accomplish this using the ISO_C_BINDING module that is part of the Fortran 78 | 2003 standard and supported by nearly every modern Fortran compiler. Alas, 79 | this had to be cut due to time constraints. I want to emphasize that it is 80 | possible to use Cython to provide very nice wrappers for modern Fortran, 81 | keeping Fortran relevant as a viable performance-oriented language that gains 82 | expressivity with Cython-generated Python wrappers. 83 | 84 | Cython Webinar 85 | ------------------------------------------------------------------------------- 86 | 87 | I will be giving a Cython webinar to cover some of the topics that were 88 | skipped during the SciPy tutorial. I will likely cover typed memoryviews in 89 | more depth, and perhaps give more detail on getting Cython to work with modern 90 | Fortran and templated C++. If you have a subscription to Enthought Canopy, 91 | you will receive a notification for the webinar, so stay tuned. Or sign up for an 92 | Enthought account [account] to get a notification. 93 | 94 | 95 | .. [tut] http://conference.scipy.org/scipy2013/tutorial_detail.php?id=105 96 | 97 | .. [content] https://public.enthought.com/~ksmith/scipy2013_cython/scipy-2013-cython-tutorial.zip 98 | 99 | .. [canopy] https://www.enthought.com/products/canopy/ 100 | 101 | .. [memviews] http://docs.cython.org/src/userguide/memoryviews.html 102 | 103 | .. [3118] http://www.python.org/dev/peps/pep-3118/ 104 | 105 | .. [account] https://staging.enthought.com/accounts/register/ 106 | -------------------------------------------------------------------------------- /cython-tutorial.rst: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | Tutorial Title 3 | ------------------------------------------------------------------------------ 4 | 5 | Cython: Speed up Python and NumPy, Pythonize C, C++, and Fortran. 6 | 7 | Author 8 | ------------------------------------------------------------------------------ 9 | Smith, Kurt, Enthought, Inc. 10 | 11 | Bio 12 | ------------------------------------------------------------------------------ 13 | .. A short bio of the presenter or team members, containing a description of 14 | .. past experiences as a trainer/teacher/speaker, and (ideally) links to 15 | .. videos of these experiences if available. 16 | 17 | Dr. Smith has been using Python in scientific computing for nearly ten years, 18 | and has developed tools to simplify the integration of performance-oriented 19 | languages with Python. He has contributed to the Cython project, implementing 20 | the initial version of the typed memoryviews and native cython arrays. He 21 | uses Cython extensively in his consulting work at Enthought. He received his 22 | B.S. in physics and applied mathematics from the University of Dallas, and his 23 | Ph.D. in physics from the University of Wisconsin-Madison. His doctoral 24 | research focused on the application of fluid plasma models to astrophysical 25 | systems, involving the composition of high-performance parallel simulations of 26 | plasma turbulence. 27 | 28 | Dr. Smith has trained hundreds of scientists, engineers, and researchers in 29 | Python, NumPy, Cython, and parallel and high-performance computing as part of 30 | Enthought's five-day scientific Python training course. He has developed 31 | course material for high-performance and parallel computing with Python, and 32 | taught the `"Efficient Parallel Python for High-Performance 33 | Computing"`_ 34 | tutorial at the SciPy 2012 conference. 35 | 36 | Contact Email 37 | ------------------------------------------------------------------------------ 38 | ksmith@enthought.com 39 | 40 | Which Track 41 | ------------------------------------------------------------------------------ 42 | Advanced 43 | 44 | Tutorial Description 45 | ------------------------------------------------------------------------------ 46 | .. A description of the tutorial, suitable for posting on the SciPy website 47 | .. for attendees to view. It should include the target audience, the expected 48 | .. level of knowledge prior to the class, and the goals of the class. 49 | 50 | Cython is a flexible and multi-faceted tool that brings down the barrier 51 | between Python and other languages. With cython, you can add type information 52 | to your Python code to yield dramatic performance improvements. Cython also 53 | allows you to wrap C, C++ and Fortran libraries to work with Python and NumPy. 54 | It is used extensively in research environments and in end-user applications. 55 | 56 | This hands-on tutorial will cover Cython from the ground up, and will include 57 | the newest Cython features, including typed memoryviews. 58 | 59 | Target audience: 60 | 61 | Developers, researchers, scientists, and engineers who use Python and 62 | NumPy and who routinely hit bottlenecks and need improved performance. 63 | 64 | C / C++ / Fortran users who would like their existing code to work with 65 | Python. 66 | 67 | Expected level of knowledge: 68 | 69 | Intermediate and / or regular user of Python and NumPy. Have used 70 | Python's decorators, exceptions, and classes. Knowledge of NumPy arrays, 71 | array views, fancy indexing, and NumPy dtypes. Have programmed in at 72 | least one of C, C++, or Fortran. 73 | 74 | Some familiarity with the Python or NumPy C-API a plus. Familiarity with 75 | memoryviews and buffers a plus. Familiarity with OpenMP a plus. 76 | Array-based inter-language programming between Python and C, C++, or 77 | Fortran a plus. 78 | 79 | Goals: 80 | 81 | Overall goal: Cython familiarity for newcomers, Cython competence for 82 | those with some experience. 83 | 84 | Understand what Cython is, what benefit it brings, when it is appropriate 85 | to use. 86 | 87 | Know how to create and use a setup.py file that will create an extension 88 | module using cython. 89 | 90 | Know how to use Cython from within the IPython notebook. 91 | 92 | Know how and why to add cython type declarations to Python code. 93 | 94 | Know how to create cdef and cpdef functions and cdef classes in Cython. 95 | 96 | Know how to use Cython's typed memoryviews to work with buffer objects and 97 | C / C++ / Fortran arrays. 98 | 99 | Know how to identify cython bottlenecks and speed them up. 100 | 101 | Know how to wrap external C / C++ / Fortran 90 code with Cython. 102 | 103 | Know how to handle inter-language error states with Cython. 104 | 105 | Know how to apply Cython's OpenMP-based parallelism to straightforward 106 | nested loops for further performance. 107 | 108 | 109 | Outline 110 | ------------------------------------------------------------------------------ 111 | .. A more detailed outline of the tutorial content, including the duration of 112 | .. each part, and exercise sessions. Please include a description of how you 113 | .. plan to make the tutorial hands-on. 114 | 115 | Cython overview, basic usage / workflow (30 minutes) 116 | 117 | Simple example (compiling the `sinc` function or similar); .pyx files; 118 | setup.py files; Python extension modules; pure Python mode; crossing the 119 | py2 - py3 divide with cython; Cython within IPython / IPython notebook. 120 | 121 | Exercise: get `add(a,b)` function to compile with Cython using .pyx and 122 | setup.py and from within an IPython notebook. 123 | 124 | Adding type information (30 minutes) 125 | 126 | def, cdef, cpdef functions; cdef variables; cython generated source code; 127 | performance difference between Cython & Python; tradeoffs with using typed 128 | variables. 129 | 130 | Exercise: cythonize `sinc()` function by adding type information, and 131 | vectorize it with numpy's `vectorize` decorator. Compare performance to 132 | pure-python `sinc()` kernel. 133 | 134 | Wrapping external C libraries (30 minutes) 135 | 136 | `cdef extern from` block, declaring external functions and typedefs; 137 | wrapping external functions; declaring external structures; dealing with 138 | "const"; 139 | 140 | Exercise: create `get_date()` function that wraps `time()` and 141 | `localtime()` from "time.h". 142 | 143 | Alternative exercise: wrap simple 1D interpolation routine from GSL. 144 | 145 | cdef classes / extension types (20 minutes) 146 | 147 | Difference between "class Foo" and "cdef class Foo" in Cython; extension 148 | type data / attributes, how different from regular class attributes; 149 | `__cinit__()` and `__dealloc__()`; extension type inheritance limitations. 150 | 151 | Demo of creating a particle `cdef class` in Cython. 152 | 153 | Wrapping C++ classes (30 minutes) 154 | 155 | Simple example -- wrap shape C++ class; `cdef cppclass` declarations; 156 | creating a `cdef class` wrapper around a C++ class; using a thisptr; 157 | memory management. 158 | 159 | Exercise: wrap a simple C++ shape class with a `cdef class` extension 160 | type, using `__cinit__`, `__dealloc__` and an internal thisptr. 161 | 162 | typed memoryviews, fused types (30 minutes) 163 | 164 | Python buffers and memoryviews, NumPy arrays; Cython's typed memoryviews, 165 | syntax and basic example; different declarations -- C / Fortran 166 | contiguous, direct, indirect, strided, generic, etc; interop with NumPy 167 | arrays and C / C++ / Fortran arrays; supported operations, performance; 168 | cython built-in arrays (Fused types will be covered if time permitting.) 169 | 170 | Demo: Implement distance matrix (matrix of "distances" between pairs of 171 | points) calculation using typed memoryviews. 172 | 173 | Capstone exercise: Compute Julia sets (50 minutes) 174 | 175 | `$ cython -a foo.pyx` -- annotations and how to use them; pure python code 176 | for computing Julia set; pure python performance; first step: add type 177 | information to scalars; second step: def -> cdef; third step: type arrays 178 | as memoryviews; fourth step: add cython decorators; fifth step: use 179 | prange. 180 | 181 | Package List 182 | ------------------------------------------------------------------------------ 183 | .. A list of Python packages that attendees will need to have installed prior 184 | .. to the class to follow along. Please mention if any packages are not cross 185 | .. platform. Installation instructions or links to installation documentation 186 | .. should be provided for packages that are not available through 187 | .. easy_install, pip, EPD, Anaconda, etc., or that require third party 188 | .. libraries. 189 | 190 | All necessary packages are available with an academic / full EPD installation, 191 | Anaconda, easy_install, or pip. 192 | 193 | Users must have Cython >= 0.16 for the course. 194 | 195 | The tutorial material (slides, exercises & demos) will be available for 196 | download and on USB drives. 197 | 198 | Documentation 199 | ------------------------------------------------------------------------------ 200 | .. If available, URL links to tutorial notes, slides, exercise files, ipython 201 | .. notebooks, that you already have, even if they are preliminary. 202 | 203 | Basic slide content is based on Enthought's Cython training slides. These 204 | slides will be reworked significantly for this tutorial. In particular, the 205 | NumPy buffer declarations will be taken out and replaced with the typed 206 | memoryview content listed in the outline. Other content (an IPython notebook 207 | with the start of the capstone project) is available as well:: 208 | 209 | http://www.enthought.com/~public_content/ksmith/scipy2013_cython 210 | -------------------------------------------------------------------------------- /demo/blackburn-pendulum/blackburn_pendulum.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from numpy.random import uniform 3 | from scipy.integrate import odeint 4 | 5 | def f(y, t, l0, l1, g): 6 | from math import sin, cos 7 | th0, th1, th0dot, th1dot = y 8 | D = l0 + l1 * cos(th1) 9 | th0ddot = 1. / D * (2 * l1 * sin(th1) * th1dot * th0dot - g * sin(th0)) 10 | th1ddot = -1. / l1 * sin(th1) * (D * th0dot * th0dot + g * cos(th0)) 11 | return [th0dot, th1dot, th0ddot, th1ddot] 12 | 13 | def curve_in_space(th0, th1, l0, l1): 14 | # th0 determines the mass' y position. 15 | # th1 determines the mass' x position. 16 | D = l0 + l1 * np.cos(th1) 17 | ys = D * np.sin(th0) 18 | xs = l0 * np.sin(th1) 19 | return xs, ys 20 | 21 | 22 | # bounds = [(-3.0, 3.0), 23 | # (-3.0, 3.0), 24 | # (-1.0, 1.0), 25 | # (-1.0, 1.0), 26 | # ] 27 | 28 | bounds = [(-1e-2, 1e-2), 29 | (-1e-2, 1e-2), 30 | (-1.0, 1.0), 31 | (-1.0, 1.0), 32 | ] 33 | 34 | def get_random_init_conds(bounds): 35 | return [uniform(*b) for b in bounds] 36 | 37 | def make_plot(soln, l0, l1, fname): 38 | import matplotlib 39 | matplotlib.use('png') 40 | import matplotlib.pyplot as plt 41 | cis = curve_in_space(soln[:,0], soln[:,1], l0, l1) 42 | plt.plot(*cis) 43 | plt.savefig(fname) 44 | plt.close('all') 45 | 46 | def main(N): 47 | t = np.linspace(0, 1000., 5000) 48 | l0 = 1.0 49 | g = 1.0 50 | for _ in range(N): 51 | print "{} / {}".format(_+1, N) 52 | ics = get_random_init_conds(bounds) 53 | l1, = get_random_init_conds([(0.01, 2.0)]) 54 | soln = odeint(f, ics, t, args=(l0, l1, g)) 55 | fname = "blackburn_pendulum_{}_{}_{}_{}_{}.png".format(*(ics + [l1])) 56 | make_plot(soln, l0, l1, fname) 57 | 58 | if __name__ == '__main__': 59 | main(100) 60 | -------------------------------------------------------------------------------- /demo/class-particle/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | python setup.py build_ext --inplace 3 | 4 | clean: 5 | rm -r build particle{,_heap}.{c,so} *.pyc __pycache__ 6 | -------------------------------------------------------------------------------- /demo/class-particle/particle.pyx: -------------------------------------------------------------------------------- 1 | cimport cython 2 | from libc.math cimport sqrt 3 | 4 | DEF _LEN = 3 5 | 6 | @cython.boundscheck(False) 7 | @cython.wraparound(False) 8 | cdef float magnitude(float[::1] vec): 9 | cdef float mag = 0.0 10 | for v in vec: 11 | mag += v*v 12 | return sqrt(mag) 13 | 14 | cdef class Particle: 15 | 16 | cdef: 17 | float psn[_LEN] 18 | float vel[_LEN] 19 | public float mass, charge 20 | 21 | def __init__(self, psn=None, vel=None, mass=0.0, charge=0.0): 22 | zeros = (0.0,)*_LEN 23 | psn = psn or zeros 24 | vel = vel or zeros 25 | for i in range(_LEN): 26 | self.psn[i] = psn[i] 27 | self.vel[i] = vel[i] 28 | self.mass = mass 29 | self.charge = charge 30 | 31 | property position: 32 | 33 | def __get__(self): 34 | return tuple(self.psn[i] for i in range(_LEN)) 35 | 36 | def __set__(self, it): 37 | for i in range(_LEN): 38 | self.psn[i] = it[i] 39 | 40 | property velocity: 41 | 42 | def __get__(self): 43 | return tuple(self.vel[i] for i in range(_LEN)) 44 | 45 | def __set__(self, it): 46 | for i in range(_LEN): 47 | self.vel[i] = it[i] 48 | 49 | property momentum: 50 | 51 | "Particle object's momentum." 52 | 53 | def __get__(self): 54 | return tuple(self.vel[i] * self.mass for i in range(_LEN)) 55 | 56 | property speed: 57 | 58 | def __get__(self): 59 | return magnitude(self.vel) 60 | 61 | property direction: 62 | 63 | def __get__(self): 64 | cdef float spd = self.speed 65 | return tuple(self.vel[i] / spd for i in range(_LEN)) 66 | -------------------------------------------------------------------------------- /demo/class-particle/particle_heap.pyx: -------------------------------------------------------------------------------- 1 | # from cython.view import array as cvarray 2 | cimport cython 3 | from libc.stdlib cimport malloc, free 4 | from libc.math cimport sqrt 5 | 6 | DEF _LEN = 3 7 | 8 | cdef class Particle: 9 | 10 | cdef: 11 | float *psn, *vel 12 | public float mass, charge 13 | 14 | def __cinit__(self): 15 | # allocate the psn and vel arrays on the heap. 16 | self.psn = malloc(_LEN * sizeof(float)) 17 | self.vel = malloc(_LEN * sizeof(float)) 18 | if not self.psn or not self.vel: 19 | raise MemoryError("Cannot allocate memory.") 20 | 21 | def __init__(self, psn=None, vel=None, mass=0.0, charge=0.0): 22 | # called after __cinit__() -- initialize all data. 23 | zeros = (0.0,)*_LEN 24 | psn = psn or zeros 25 | vel = vel or zeros 26 | for i in range(_LEN): 27 | self.psn[i] = psn[i] 28 | self.vel[i] = vel[i] 29 | self.mass = mass 30 | self.charge = charge 31 | 32 | def __dealloc__(self): 33 | # called when cleaning up the object; free malloc'd memory. 34 | if self.psn: 35 | free(self.psn); self.psn == NULL 36 | if self.vel: 37 | free(self.vel); self.vel == NULL 38 | 39 | property position: 40 | 41 | def __get__(self): 42 | return tuple(self.psn[i] for i in range(_LEN)) 43 | 44 | def __set__(self, it): 45 | for i in range(_LEN): 46 | self.psn[i] = it[i] 47 | 48 | property velocity: 49 | 50 | def __get__(self): 51 | return tuple(self.vel[i] for i in range(_LEN)) 52 | 53 | def __set__(self, it): 54 | for i in range(_LEN): 55 | self.vel[i] = it[i] 56 | 57 | property momentum: 58 | 59 | "Particle object's momentum." 60 | 61 | def __get__(self): 62 | return tuple(self.vel[i] * self.mass for i in range(_LEN)) 63 | -------------------------------------------------------------------------------- /demo/class-particle/setup.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Copyright (c) 2012, Enthought, Inc. 3 | # All rights reserved. See LICENSE.txt for details. 4 | # 5 | # Author: Kurt W. Smith 6 | # Date: 26 March 2012 7 | #----------------------------------------------------------------------------- 8 | 9 | from distutils.core import setup 10 | from distutils.extension import Extension 11 | from Cython.Distutils import build_ext 12 | 13 | exts = [Extension("particle", ["particle.pyx"]), 14 | Extension("particle_heap", ["particle_heap.pyx"])] 15 | 16 | setup( 17 | cmdclass = {'build_ext': build_ext}, 18 | ext_modules = exts, 19 | ) 20 | -------------------------------------------------------------------------------- /demo/class-particle/test_particle.py: -------------------------------------------------------------------------------- 1 | from particle import Particle 2 | 3 | p = Particle() 4 | assert(p.mass == 0.0) 5 | assert(p.charge == 0.0) 6 | assert(p.momentum == (0.0,)*3) 7 | assert(p.speed == 0.0) 8 | 9 | p.velocity = [3,4,0] 10 | assert(p.speed == 5) 11 | 12 | p.mass = 2.0 13 | assert(p.momentum == (6,8,0)) 14 | -------------------------------------------------------------------------------- /demo/cython-julia-set.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "cython-julia-set" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "code", 12 | "collapsed": false, 13 | "input": [ 14 | "%load_ext cythonmagic" 15 | ], 16 | "language": "python", 17 | "metadata": {}, 18 | "outputs": [] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "collapsed": false, 23 | "input": [ 24 | "import numpy as np\n", 25 | "from time import time\n", 26 | "\n", 27 | "def kernel(z, c, lim, cutoff=1e6):\n", 28 | " ''' Computes the number, `n`, of iterations necessary such that \n", 29 | " |z_n| > `lim`, where `z_n = z_{n-1}**2 + c`.\n", 30 | " '''\n", 31 | " count = 0\n", 32 | " while abs(z) < lim and count < cutoff:\n", 33 | " z = z * z + c\n", 34 | " count += 1\n", 35 | " return count\n", 36 | "\n", 37 | "\n", 38 | "def compute_julia(c, N, bound=2, lim=1000., kernel=kernel):\n", 39 | " ''' Pure Python calculation of the Julia set for a given `c`. No NumPy\n", 40 | " array operations are used.\n", 41 | " '''\n", 42 | " julia = np.empty((N, N), dtype=np.uint32)\n", 43 | " grid_x = np.linspace(-bound, bound, N)\n", 44 | " grid_y = grid_x * 1j\n", 45 | " c = complex(c)\n", 46 | " t0 = time()\n", 47 | " for i, x in enumerate(grid_x):\n", 48 | " for j, y in enumerate(grid_y):\n", 49 | " julia[i,j] = kernel(x+y, c, lim)\n", 50 | " return julia, time() - t0" 51 | ], 52 | "language": "python", 53 | "metadata": {}, 54 | "outputs": [] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "collapsed": false, 59 | "input": [ 60 | "import pylab as pl\n", 61 | "\n", 62 | "def plot_julia(kwargs, compute_julia):\n", 63 | " ''' Given parameters dict in `kwargs` and a function to compute the Julia\n", 64 | " set (`compute_julia`), plots the resulting Julia set with appropriately\n", 65 | " labeled axes.\n", 66 | " '''\n", 67 | " kwargs = kwargs.copy()\n", 68 | "\n", 69 | " def _plotter(kwargs):\n", 70 | " bound = kwargs['bound']\n", 71 | " julia, time = compute_julia(**kwargs)\n", 72 | " print \"execution time (s):\", time\n", 73 | " julia = np.log(julia)\n", 74 | " pl.imshow(julia, \n", 75 | " interpolation='nearest',\n", 76 | " extent=(-bound, bound)*2)\n", 77 | " pl.colorbar()\n", 78 | " title = r\"Julia set for $C={0.real:5.3f}+{0.imag:5.3f}i$ $[{1}\\times{1}]$\"\n", 79 | " pl.title(title.format(kwargs['c'], kwargs['N']))\n", 80 | " pl.xlabel(\"$Re(z)$\")\n", 81 | " pl.ylabel(\"$Im(z)$\")\n", 82 | "\n", 83 | " pl.figure(figsize=(14, 12))\n", 84 | "\n", 85 | " cvals = [0.285+0.01j, -0.1+0.651j, -0.4+0.6j, -0.8+0.156j]\n", 86 | " subplots = ['221', '222', '223', '224' ]\n", 87 | "\n", 88 | " for c, sp in zip(cvals, subplots):\n", 89 | " kwargs.update(c=c)\n", 90 | " pl.subplot(sp)\n", 91 | " _plotter(kwargs)\n", 92 | "\n", 93 | " pl.show()" 94 | ], 95 | "language": "python", 96 | "metadata": {}, 97 | "outputs": [] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "collapsed": false, 102 | "input": [ 103 | "kwargs = dict(N=100, bound=1.5)\n", 104 | "plot_julia(kwargs, compute_julia)" 105 | ], 106 | "language": "python", 107 | "metadata": {}, 108 | "outputs": [] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "collapsed": false, 113 | "input": [ 114 | "%%cython\n", 115 | "\n", 116 | "from time import time\n", 117 | "\n", 118 | "import numpy as np\n", 119 | "cimport cython\n", 120 | "cimport numpy as cnp\n", 121 | "\n", 122 | "ctypedef double complex cpx_t\n", 123 | "ctypedef double real_t\n", 124 | "\n", 125 | "cdef inline real_t cabs_sq(cpx_t z) nogil:\n", 126 | " ''' Helper inline function, computes the square of the abs. value of the\n", 127 | " complex number `z`.\n", 128 | " '''\n", 129 | " return z.real * z.real + z.imag * z.imag\n", 130 | " \n", 131 | "cpdef unsigned int kernel(cpx_t z, \n", 132 | " cpx_t c,\n", 133 | " real_t lim,\n", 134 | " real_t cutoff=1e6) nogil:\n", 135 | " ''' Cython implementation of the kernel computation.\n", 136 | "\n", 137 | " This is implemented so that no C-API calls are made inside the function\n", 138 | " body. Even still, there is some overhead as compared with a pure C\n", 139 | " implementation.\n", 140 | " '''\n", 141 | " cdef unsigned int count = 0\n", 142 | " cdef real_t lim_sq = lim * lim\n", 143 | " while cabs_sq(z) < lim_sq and count < cutoff:\n", 144 | " z = z * z + c\n", 145 | " count += 1\n", 146 | " return count\n", 147 | "\n", 148 | "@cython.boundscheck(False)\n", 149 | "@cython.wraparound(False)\n", 150 | "def compute_julia_opt(cpx_t c,\n", 151 | " unsigned int N,\n", 152 | " real_t bound=1.5,\n", 153 | " real_t lim=1000.):\n", 154 | " '''\n", 155 | " Cython `compute_julia()` implementation with Numpy array buffer\n", 156 | " declarations and appropriate compiler directives. The body of this\n", 157 | " function is nearly identical to the `compute_julia_no_opt()` function.\n", 158 | "\n", 159 | " '''\n", 160 | "\n", 161 | " cdef cnp.ndarray[cnp.uint32_t, ndim=2, mode='c'] julia \n", 162 | " cdef cnp.ndarray[real_t, ndim=1, mode='c'] grid\n", 163 | " cdef unsigned int i, j\n", 164 | " cdef real_t x, y\n", 165 | "\n", 166 | " julia = np.empty((N, N), dtype=np.uint32)\n", 167 | " grid = np.linspace(-bound, bound, N)\n", 168 | " t0 = time()\n", 169 | " for i in range(N):\n", 170 | " x = grid[i]\n", 171 | " for j in range(N):\n", 172 | " y = grid[j]\n", 173 | " julia[i,j] = kernel(x+y*1j, c, lim)\n", 174 | " return julia, time() - t0" 175 | ], 176 | "language": "python", 177 | "metadata": {}, 178 | "outputs": [] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "collapsed": false, 183 | "input": [ 184 | "kwargs = dict(N=1000, bound=1.5)\n", 185 | "plot_julia(kwargs, compute_julia_opt)" 186 | ], 187 | "language": "python", 188 | "metadata": {}, 189 | "outputs": [] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "collapsed": false, 194 | "input": [], 195 | "language": "python", 196 | "metadata": {}, 197 | "outputs": [] 198 | } 199 | ], 200 | "metadata": {} 201 | } 202 | ] 203 | } -------------------------------------------------------------------------------- /demo/fib/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | python setup.py build_ext --inplace 4 | 5 | clean: 6 | rm -rf build cyfib.{c,so} 7 | -------------------------------------------------------------------------------- /demo/fib/cfib.c: -------------------------------------------------------------------------------- 1 | #include "cfib.h" 2 | 3 | int cfib(int n) 4 | { 5 | int a=1, b=1, i=0, tmp=0; 6 | for(i=0; i /* For offsetof */ 11 | #ifndef offsetof 12 | #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) 13 | #endif 14 | 15 | #if !defined(WIN32) && !defined(MS_WINDOWS) 16 | #ifndef __stdcall 17 | #define __stdcall 18 | #endif 19 | #ifndef __cdecl 20 | #define __cdecl 21 | #endif 22 | #ifndef __fastcall 23 | #define __fastcall 24 | #endif 25 | #endif 26 | 27 | #ifndef DL_IMPORT 28 | #define DL_IMPORT(t) t 29 | #endif 30 | #ifndef DL_EXPORT 31 | #define DL_EXPORT(t) t 32 | #endif 33 | 34 | #ifndef PY_LONG_LONG 35 | #define PY_LONG_LONG LONG_LONG 36 | #endif 37 | 38 | #ifndef Py_HUGE_VAL 39 | #define Py_HUGE_VAL HUGE_VAL 40 | #endif 41 | 42 | #ifdef PYPY_VERSION 43 | #define CYTHON_COMPILING_IN_PYPY 1 44 | #define CYTHON_COMPILING_IN_CPYTHON 0 45 | #else 46 | #define CYTHON_COMPILING_IN_PYPY 0 47 | #define CYTHON_COMPILING_IN_CPYTHON 1 48 | #endif 49 | 50 | #if CYTHON_COMPILING_IN_PYPY 51 | #define __Pyx_PyCFunction_Call PyObject_Call 52 | #else 53 | #define __Pyx_PyCFunction_Call PyCFunction_Call 54 | #endif 55 | 56 | #if PY_VERSION_HEX < 0x02050000 57 | typedef int Py_ssize_t; 58 | #define PY_SSIZE_T_MAX INT_MAX 59 | #define PY_SSIZE_T_MIN INT_MIN 60 | #define PY_FORMAT_SIZE_T "" 61 | #define PyInt_FromSsize_t(z) PyInt_FromLong(z) 62 | #define PyInt_AsSsize_t(o) __Pyx_PyInt_AsInt(o) 63 | #define PyNumber_Index(o) PyNumber_Int(o) 64 | #define PyIndex_Check(o) PyNumber_Check(o) 65 | #define PyErr_WarnEx(category, message, stacklevel) PyErr_Warn(category, message) 66 | #define __PYX_BUILD_PY_SSIZE_T "i" 67 | #else 68 | #define __PYX_BUILD_PY_SSIZE_T "n" 69 | #endif 70 | 71 | #if PY_VERSION_HEX < 0x02060000 72 | #define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt) 73 | #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) 74 | #define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size) 75 | #define PyVarObject_HEAD_INIT(type, size) \ 76 | PyObject_HEAD_INIT(type) size, 77 | #define PyType_Modified(t) 78 | 79 | typedef struct { 80 | void *buf; 81 | PyObject *obj; 82 | Py_ssize_t len; 83 | Py_ssize_t itemsize; 84 | int readonly; 85 | int ndim; 86 | char *format; 87 | Py_ssize_t *shape; 88 | Py_ssize_t *strides; 89 | Py_ssize_t *suboffsets; 90 | void *internal; 91 | } Py_buffer; 92 | 93 | #define PyBUF_SIMPLE 0 94 | #define PyBUF_WRITABLE 0x0001 95 | #define PyBUF_FORMAT 0x0004 96 | #define PyBUF_ND 0x0008 97 | #define PyBUF_STRIDES (0x0010 | PyBUF_ND) 98 | #define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) 99 | #define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) 100 | #define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) 101 | #define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) 102 | #define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_FORMAT | PyBUF_WRITABLE) 103 | #define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_FORMAT | PyBUF_WRITABLE) 104 | 105 | typedef int (*getbufferproc)(PyObject *, Py_buffer *, int); 106 | typedef void (*releasebufferproc)(PyObject *, Py_buffer *); 107 | #endif 108 | 109 | #if PY_MAJOR_VERSION < 3 110 | #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" 111 | #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) \ 112 | PyCode_New(a, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) 113 | #else 114 | #define __Pyx_BUILTIN_MODULE_NAME "builtins" 115 | #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) \ 116 | PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) 117 | #endif 118 | 119 | #if PY_MAJOR_VERSION < 3 && PY_MINOR_VERSION < 6 120 | #define PyUnicode_FromString(s) PyUnicode_Decode(s, strlen(s), "UTF-8", "strict") 121 | #endif 122 | 123 | #if PY_MAJOR_VERSION >= 3 124 | #define Py_TPFLAGS_CHECKTYPES 0 125 | #define Py_TPFLAGS_HAVE_INDEX 0 126 | #endif 127 | 128 | #if (PY_VERSION_HEX < 0x02060000) || (PY_MAJOR_VERSION >= 3) 129 | #define Py_TPFLAGS_HAVE_NEWBUFFER 0 130 | #endif 131 | 132 | 133 | #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_GET_LENGTH) 134 | #define CYTHON_PEP393_ENABLED 1 135 | #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) 136 | #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) 137 | #else 138 | #define CYTHON_PEP393_ENABLED 0 139 | #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) 140 | #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) 141 | #endif 142 | 143 | #if PY_MAJOR_VERSION >= 3 144 | #define PyBaseString_Type PyUnicode_Type 145 | #define PyStringObject PyUnicodeObject 146 | #define PyString_Type PyUnicode_Type 147 | #define PyString_Check PyUnicode_Check 148 | #define PyString_CheckExact PyUnicode_CheckExact 149 | #endif 150 | 151 | #if PY_VERSION_HEX < 0x02060000 152 | #define PyBytesObject PyStringObject 153 | #define PyBytes_Type PyString_Type 154 | #define PyBytes_Check PyString_Check 155 | #define PyBytes_CheckExact PyString_CheckExact 156 | #define PyBytes_FromString PyString_FromString 157 | #define PyBytes_FromStringAndSize PyString_FromStringAndSize 158 | #define PyBytes_FromFormat PyString_FromFormat 159 | #define PyBytes_DecodeEscape PyString_DecodeEscape 160 | #define PyBytes_AsString PyString_AsString 161 | #define PyBytes_AsStringAndSize PyString_AsStringAndSize 162 | #define PyBytes_Size PyString_Size 163 | #define PyBytes_AS_STRING PyString_AS_STRING 164 | #define PyBytes_GET_SIZE PyString_GET_SIZE 165 | #define PyBytes_Repr PyString_Repr 166 | #define PyBytes_Concat PyString_Concat 167 | #define PyBytes_ConcatAndDel PyString_ConcatAndDel 168 | #endif 169 | 170 | #if PY_VERSION_HEX < 0x02060000 171 | #define PySet_Check(obj) PyObject_TypeCheck(obj, &PySet_Type) 172 | #define PyFrozenSet_Check(obj) PyObject_TypeCheck(obj, &PyFrozenSet_Type) 173 | #endif 174 | #ifndef PySet_CheckExact 175 | #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) 176 | #endif 177 | 178 | #define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) 179 | 180 | #if PY_MAJOR_VERSION >= 3 181 | #define PyIntObject PyLongObject 182 | #define PyInt_Type PyLong_Type 183 | #define PyInt_Check(op) PyLong_Check(op) 184 | #define PyInt_CheckExact(op) PyLong_CheckExact(op) 185 | #define PyInt_FromString PyLong_FromString 186 | #define PyInt_FromUnicode PyLong_FromUnicode 187 | #define PyInt_FromLong PyLong_FromLong 188 | #define PyInt_FromSize_t PyLong_FromSize_t 189 | #define PyInt_FromSsize_t PyLong_FromSsize_t 190 | #define PyInt_AsLong PyLong_AsLong 191 | #define PyInt_AS_LONG PyLong_AS_LONG 192 | #define PyInt_AsSsize_t PyLong_AsSsize_t 193 | #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask 194 | #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask 195 | #endif 196 | 197 | #if PY_MAJOR_VERSION >= 3 198 | #define PyBoolObject PyLongObject 199 | #endif 200 | 201 | #if PY_VERSION_HEX < 0x03020000 202 | typedef long Py_hash_t; 203 | #define __Pyx_PyInt_FromHash_t PyInt_FromLong 204 | #define __Pyx_PyInt_AsHash_t PyInt_AsLong 205 | #else 206 | #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t 207 | #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t 208 | #endif 209 | 210 | #if (PY_MAJOR_VERSION < 3) || (PY_VERSION_HEX >= 0x03010300) 211 | #define __Pyx_PySequence_GetSlice(obj, a, b) PySequence_GetSlice(obj, a, b) 212 | #define __Pyx_PySequence_SetSlice(obj, a, b, value) PySequence_SetSlice(obj, a, b, value) 213 | #define __Pyx_PySequence_DelSlice(obj, a, b) PySequence_DelSlice(obj, a, b) 214 | #else 215 | #define __Pyx_PySequence_GetSlice(obj, a, b) (unlikely(!(obj)) ? \ 216 | (PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), (PyObject*)0) : \ 217 | (likely((obj)->ob_type->tp_as_mapping) ? (PySequence_GetSlice(obj, a, b)) : \ 218 | (PyErr_Format(PyExc_TypeError, "'%.200s' object is unsliceable", (obj)->ob_type->tp_name), (PyObject*)0))) 219 | #define __Pyx_PySequence_SetSlice(obj, a, b, value) (unlikely(!(obj)) ? \ 220 | (PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), -1) : \ 221 | (likely((obj)->ob_type->tp_as_mapping) ? (PySequence_SetSlice(obj, a, b, value)) : \ 222 | (PyErr_Format(PyExc_TypeError, "'%.200s' object doesn't support slice assignment", (obj)->ob_type->tp_name), -1))) 223 | #define __Pyx_PySequence_DelSlice(obj, a, b) (unlikely(!(obj)) ? \ 224 | (PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), -1) : \ 225 | (likely((obj)->ob_type->tp_as_mapping) ? (PySequence_DelSlice(obj, a, b)) : \ 226 | (PyErr_Format(PyExc_TypeError, "'%.200s' object doesn't support slice deletion", (obj)->ob_type->tp_name), -1))) 227 | #endif 228 | 229 | #if PY_MAJOR_VERSION >= 3 230 | #define PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : PyInstanceMethod_New(func)) 231 | #endif 232 | 233 | #if PY_VERSION_HEX < 0x02050000 234 | #define __Pyx_GetAttrString(o,n) PyObject_GetAttrString((o),((char *)(n))) 235 | #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),((char *)(n)),(a)) 236 | #define __Pyx_DelAttrString(o,n) PyObject_DelAttrString((o),((char *)(n))) 237 | #else 238 | #define __Pyx_GetAttrString(o,n) PyObject_GetAttrString((o),(n)) 239 | #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),(n),(a)) 240 | #define __Pyx_DelAttrString(o,n) PyObject_DelAttrString((o),(n)) 241 | #endif 242 | 243 | #if PY_VERSION_HEX < 0x02050000 244 | #define __Pyx_NAMESTR(n) ((char *)(n)) 245 | #define __Pyx_DOCSTR(n) ((char *)(n)) 246 | #else 247 | #define __Pyx_NAMESTR(n) (n) 248 | #define __Pyx_DOCSTR(n) (n) 249 | #endif 250 | 251 | #if PY_MAJOR_VERSION >= 3 252 | #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) 253 | #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) 254 | #else 255 | #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) 256 | #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) 257 | #endif 258 | 259 | #ifndef __PYX_EXTERN_C 260 | #ifdef __cplusplus 261 | #define __PYX_EXTERN_C extern "C" 262 | #else 263 | #define __PYX_EXTERN_C extern 264 | #endif 265 | #endif 266 | 267 | #if defined(WIN32) || defined(MS_WINDOWS) 268 | #define _USE_MATH_DEFINES 269 | #endif 270 | #include 271 | #define __PYX_HAVE__fib 272 | #define __PYX_HAVE_API__fib 273 | #ifdef _OPENMP 274 | #include 275 | #endif /* _OPENMP */ 276 | 277 | #ifdef PYREX_WITHOUT_ASSERTIONS 278 | #define CYTHON_WITHOUT_ASSERTIONS 279 | #endif 280 | 281 | 282 | /* inline attribute */ 283 | #ifndef CYTHON_INLINE 284 | #if defined(__GNUC__) 285 | #define CYTHON_INLINE __inline__ 286 | #elif defined(_MSC_VER) 287 | #define CYTHON_INLINE __inline 288 | #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 289 | #define CYTHON_INLINE inline 290 | #else 291 | #define CYTHON_INLINE 292 | #endif 293 | #endif 294 | 295 | /* unused attribute */ 296 | #ifndef CYTHON_UNUSED 297 | # if defined(__GNUC__) 298 | # if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) 299 | # define CYTHON_UNUSED __attribute__ ((__unused__)) 300 | # else 301 | # define CYTHON_UNUSED 302 | # endif 303 | # elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) 304 | # define CYTHON_UNUSED __attribute__ ((__unused__)) 305 | # else 306 | # define CYTHON_UNUSED 307 | # endif 308 | #endif 309 | 310 | typedef struct {PyObject **p; char *s; const long n; const char* encoding; const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; /*proto*/ 311 | 312 | 313 | /* Type Conversion Predeclarations */ 314 | 315 | #define __Pyx_PyBytes_FromUString(s) PyBytes_FromString((char*)s) 316 | #define __Pyx_PyBytes_AsUString(s) ((unsigned char*) PyBytes_AsString(s)) 317 | 318 | #define __Pyx_Owned_Py_None(b) (Py_INCREF(Py_None), Py_None) 319 | #define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False)) 320 | static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); 321 | static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x); 322 | 323 | static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); 324 | static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); 325 | static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject*); 326 | 327 | #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) 328 | #define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) 329 | 330 | #ifdef __GNUC__ 331 | /* Test for GCC > 2.95 */ 332 | #if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)) 333 | #define likely(x) __builtin_expect(!!(x), 1) 334 | #define unlikely(x) __builtin_expect(!!(x), 0) 335 | #else /* __GNUC__ > 2 ... */ 336 | #define likely(x) (x) 337 | #define unlikely(x) (x) 338 | #endif /* __GNUC__ > 2 ... */ 339 | #else /* __GNUC__ */ 340 | #define likely(x) (x) 341 | #define unlikely(x) (x) 342 | #endif /* __GNUC__ */ 343 | 344 | static PyObject *__pyx_m; 345 | static PyObject *__pyx_b; 346 | static PyObject *__pyx_empty_tuple; 347 | static PyObject *__pyx_empty_bytes; 348 | static int __pyx_lineno; 349 | static int __pyx_clineno = 0; 350 | static const char * __pyx_cfilenm= __FILE__; 351 | static const char *__pyx_filename; 352 | 353 | 354 | static const char *__pyx_f[] = { 355 | "fib.pyx", 356 | }; 357 | 358 | /*--- Type declarations ---*/ 359 | #ifndef CYTHON_REFNANNY 360 | #define CYTHON_REFNANNY 0 361 | #endif 362 | #if CYTHON_REFNANNY 363 | typedef struct { 364 | void (*INCREF)(void*, PyObject*, int); 365 | void (*DECREF)(void*, PyObject*, int); 366 | void (*GOTREF)(void*, PyObject*, int); 367 | void (*GIVEREF)(void*, PyObject*, int); 368 | void* (*SetupContext)(const char*, int, const char*); 369 | void (*FinishContext)(void**); 370 | } __Pyx_RefNannyAPIStruct; 371 | static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; 372 | static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); /*proto*/ 373 | #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; 374 | #ifdef WITH_THREAD 375 | #define __Pyx_RefNannySetupContext(name, acquire_gil) \ 376 | if (acquire_gil) { \ 377 | PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure(); \ 378 | __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__); \ 379 | PyGILState_Release(__pyx_gilstate_save); \ 380 | } else { \ 381 | __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__); \ 382 | } 383 | #else 384 | #define __Pyx_RefNannySetupContext(name, acquire_gil) \ 385 | __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) 386 | #endif 387 | #define __Pyx_RefNannyFinishContext() \ 388 | __Pyx_RefNanny->FinishContext(&__pyx_refnanny) 389 | #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) 390 | #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) 391 | #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) 392 | #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__) 393 | #define __Pyx_XINCREF(r) do { if((r) != NULL) {__Pyx_INCREF(r); }} while(0) 394 | #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r); }} while(0) 395 | #define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r); }} while(0) 396 | #define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);}} while(0) 397 | #else 398 | #define __Pyx_RefNannyDeclarations 399 | #define __Pyx_RefNannySetupContext(name, acquire_gil) 400 | #define __Pyx_RefNannyFinishContext() 401 | #define __Pyx_INCREF(r) Py_INCREF(r) 402 | #define __Pyx_DECREF(r) Py_DECREF(r) 403 | #define __Pyx_GOTREF(r) 404 | #define __Pyx_GIVEREF(r) 405 | #define __Pyx_XINCREF(r) Py_XINCREF(r) 406 | #define __Pyx_XDECREF(r) Py_XDECREF(r) 407 | #define __Pyx_XGOTREF(r) 408 | #define __Pyx_XGIVEREF(r) 409 | #endif /* CYTHON_REFNANNY */ 410 | #define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) 411 | #define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) 412 | 413 | static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/ 414 | 415 | static CYTHON_INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject *); 416 | 417 | static CYTHON_INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject *); 418 | 419 | static CYTHON_INLINE unsigned int __Pyx_PyInt_AsUnsignedInt(PyObject *); 420 | 421 | static CYTHON_INLINE char __Pyx_PyInt_AsChar(PyObject *); 422 | 423 | static CYTHON_INLINE short __Pyx_PyInt_AsShort(PyObject *); 424 | 425 | static CYTHON_INLINE int __Pyx_PyInt_AsInt(PyObject *); 426 | 427 | static CYTHON_INLINE signed char __Pyx_PyInt_AsSignedChar(PyObject *); 428 | 429 | static CYTHON_INLINE signed short __Pyx_PyInt_AsSignedShort(PyObject *); 430 | 431 | static CYTHON_INLINE signed int __Pyx_PyInt_AsSignedInt(PyObject *); 432 | 433 | static CYTHON_INLINE int __Pyx_PyInt_AsLongDouble(PyObject *); 434 | 435 | static CYTHON_INLINE unsigned long __Pyx_PyInt_AsUnsignedLong(PyObject *); 436 | 437 | static CYTHON_INLINE unsigned PY_LONG_LONG __Pyx_PyInt_AsUnsignedLongLong(PyObject *); 438 | 439 | static CYTHON_INLINE long __Pyx_PyInt_AsLong(PyObject *); 440 | 441 | static CYTHON_INLINE PY_LONG_LONG __Pyx_PyInt_AsLongLong(PyObject *); 442 | 443 | static CYTHON_INLINE signed long __Pyx_PyInt_AsSignedLong(PyObject *); 444 | 445 | static CYTHON_INLINE signed PY_LONG_LONG __Pyx_PyInt_AsSignedLongLong(PyObject *); 446 | 447 | static int __Pyx_check_binary_version(void); 448 | 449 | typedef struct { 450 | int code_line; 451 | PyCodeObject* code_object; 452 | } __Pyx_CodeObjectCacheEntry; 453 | struct __Pyx_CodeObjectCache { 454 | int count; 455 | int max_count; 456 | __Pyx_CodeObjectCacheEntry* entries; 457 | }; 458 | static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; 459 | static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); 460 | static PyCodeObject *__pyx_find_code_object(int code_line); 461 | static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); 462 | 463 | static void __Pyx_AddTraceback(const char *funcname, int c_line, 464 | int py_line, const char *filename); /*proto*/ 465 | 466 | static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/ 467 | 468 | 469 | /* Module declarations from 'fib' */ 470 | #define __Pyx_MODULE_NAME "fib" 471 | int __pyx_module_is_main_fib = 0; 472 | 473 | /* Implementation of 'fib' */ 474 | static PyObject *__pyx_builtin_range; 475 | static PyObject *__pyx_pf_3fib_fib(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_n); /* proto */ 476 | static char __pyx_k_3[] = "/Users/ksmith/work/training/generated-classes/scipy-2013-cython-tutorial/demo/fib/fib.pyx"; 477 | static char __pyx_k__a[] = "a"; 478 | static char __pyx_k__b[] = "b"; 479 | static char __pyx_k__i[] = "i"; 480 | static char __pyx_k__n[] = "n"; 481 | static char __pyx_k__fib[] = "fib"; 482 | static char __pyx_k__range[] = "range"; 483 | static char __pyx_k____main__[] = "__main__"; 484 | static char __pyx_k____test__[] = "__test__"; 485 | static PyObject *__pyx_kp_s_3; 486 | static PyObject *__pyx_n_s____main__; 487 | static PyObject *__pyx_n_s____test__; 488 | static PyObject *__pyx_n_s__a; 489 | static PyObject *__pyx_n_s__b; 490 | static PyObject *__pyx_n_s__fib; 491 | static PyObject *__pyx_n_s__i; 492 | static PyObject *__pyx_n_s__n; 493 | static PyObject *__pyx_n_s__range; 494 | static PyObject *__pyx_k_tuple_1; 495 | static PyObject *__pyx_k_codeobj_2; 496 | 497 | /* Python wrapper */ 498 | static PyObject *__pyx_pw_3fib_1fib(PyObject *__pyx_self, PyObject *__pyx_arg_n); /*proto*/ 499 | static PyMethodDef __pyx_mdef_3fib_1fib = {__Pyx_NAMESTR("fib"), (PyCFunction)__pyx_pw_3fib_1fib, METH_O, __Pyx_DOCSTR(0)}; 500 | static PyObject *__pyx_pw_3fib_1fib(PyObject *__pyx_self, PyObject *__pyx_arg_n) { 501 | int __pyx_v_n; 502 | PyObject *__pyx_r = 0; 503 | __Pyx_RefNannyDeclarations 504 | __Pyx_RefNannySetupContext("fib (wrapper)", 0); 505 | __pyx_self = __pyx_self; 506 | assert(__pyx_arg_n); { 507 | __pyx_v_n = __Pyx_PyInt_AsInt(__pyx_arg_n); if (unlikely((__pyx_v_n == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L3_error;} 508 | } 509 | goto __pyx_L4_argument_unpacking_done; 510 | __pyx_L3_error:; 511 | __Pyx_AddTraceback("fib.fib", __pyx_clineno, __pyx_lineno, __pyx_filename); 512 | __Pyx_RefNannyFinishContext(); 513 | return NULL; 514 | __pyx_L4_argument_unpacking_done:; 515 | __pyx_r = __pyx_pf_3fib_fib(__pyx_self, ((int)__pyx_v_n)); 516 | __Pyx_RefNannyFinishContext(); 517 | return __pyx_r; 518 | } 519 | 520 | /* "fib.pyx":1 521 | * def fib(int n): # <<<<<<<<<<<<<< 522 | * cdef int a, b, i 523 | * a, b = 1, 1 524 | */ 525 | 526 | static PyObject *__pyx_pf_3fib_fib(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_n) { 527 | int __pyx_v_a; 528 | int __pyx_v_b; 529 | CYTHON_UNUSED int __pyx_v_i; 530 | PyObject *__pyx_r = NULL; 531 | __Pyx_RefNannyDeclarations 532 | int __pyx_t_1; 533 | int __pyx_t_2; 534 | int __pyx_t_3; 535 | int __pyx_t_4; 536 | PyObject *__pyx_t_5 = NULL; 537 | int __pyx_lineno = 0; 538 | const char *__pyx_filename = NULL; 539 | int __pyx_clineno = 0; 540 | __Pyx_RefNannySetupContext("fib", 0); 541 | 542 | /* "fib.pyx":3 543 | * def fib(int n): 544 | * cdef int a, b, i 545 | * a, b = 1, 1 # <<<<<<<<<<<<<< 546 | * for i in range(n): 547 | * a, b = a+b, a 548 | */ 549 | __pyx_t_1 = 1; 550 | __pyx_t_2 = 1; 551 | __pyx_v_a = __pyx_t_1; 552 | __pyx_v_b = __pyx_t_2; 553 | 554 | /* "fib.pyx":4 555 | * cdef int a, b, i 556 | * a, b = 1, 1 557 | * for i in range(n): # <<<<<<<<<<<<<< 558 | * a, b = a+b, a 559 | * return a 560 | */ 561 | __pyx_t_2 = __pyx_v_n; 562 | for (__pyx_t_1 = 0; __pyx_t_1 < __pyx_t_2; __pyx_t_1+=1) { 563 | __pyx_v_i = __pyx_t_1; 564 | 565 | /* "fib.pyx":5 566 | * a, b = 1, 1 567 | * for i in range(n): 568 | * a, b = a+b, a # <<<<<<<<<<<<<< 569 | * return a 570 | */ 571 | __pyx_t_3 = (__pyx_v_a + __pyx_v_b); 572 | __pyx_t_4 = __pyx_v_a; 573 | __pyx_v_a = __pyx_t_3; 574 | __pyx_v_b = __pyx_t_4; 575 | } 576 | 577 | /* "fib.pyx":6 578 | * for i in range(n): 579 | * a, b = a+b, a 580 | * return a # <<<<<<<<<<<<<< 581 | */ 582 | __Pyx_XDECREF(__pyx_r); 583 | __pyx_t_5 = PyInt_FromLong(__pyx_v_a); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 584 | __Pyx_GOTREF(__pyx_t_5); 585 | __pyx_r = __pyx_t_5; 586 | __pyx_t_5 = 0; 587 | goto __pyx_L0; 588 | 589 | __pyx_r = Py_None; __Pyx_INCREF(Py_None); 590 | goto __pyx_L0; 591 | __pyx_L1_error:; 592 | __Pyx_XDECREF(__pyx_t_5); 593 | __Pyx_AddTraceback("fib.fib", __pyx_clineno, __pyx_lineno, __pyx_filename); 594 | __pyx_r = NULL; 595 | __pyx_L0:; 596 | __Pyx_XGIVEREF(__pyx_r); 597 | __Pyx_RefNannyFinishContext(); 598 | return __pyx_r; 599 | } 600 | 601 | static PyMethodDef __pyx_methods[] = { 602 | {0, 0, 0, 0} 603 | }; 604 | 605 | #if PY_MAJOR_VERSION >= 3 606 | static struct PyModuleDef __pyx_moduledef = { 607 | PyModuleDef_HEAD_INIT, 608 | __Pyx_NAMESTR("fib"), 609 | 0, /* m_doc */ 610 | -1, /* m_size */ 611 | __pyx_methods /* m_methods */, 612 | NULL, /* m_reload */ 613 | NULL, /* m_traverse */ 614 | NULL, /* m_clear */ 615 | NULL /* m_free */ 616 | }; 617 | #endif 618 | 619 | static __Pyx_StringTabEntry __pyx_string_tab[] = { 620 | {&__pyx_kp_s_3, __pyx_k_3, sizeof(__pyx_k_3), 0, 0, 1, 0}, 621 | {&__pyx_n_s____main__, __pyx_k____main__, sizeof(__pyx_k____main__), 0, 0, 1, 1}, 622 | {&__pyx_n_s____test__, __pyx_k____test__, sizeof(__pyx_k____test__), 0, 0, 1, 1}, 623 | {&__pyx_n_s__a, __pyx_k__a, sizeof(__pyx_k__a), 0, 0, 1, 1}, 624 | {&__pyx_n_s__b, __pyx_k__b, sizeof(__pyx_k__b), 0, 0, 1, 1}, 625 | {&__pyx_n_s__fib, __pyx_k__fib, sizeof(__pyx_k__fib), 0, 0, 1, 1}, 626 | {&__pyx_n_s__i, __pyx_k__i, sizeof(__pyx_k__i), 0, 0, 1, 1}, 627 | {&__pyx_n_s__n, __pyx_k__n, sizeof(__pyx_k__n), 0, 0, 1, 1}, 628 | {&__pyx_n_s__range, __pyx_k__range, sizeof(__pyx_k__range), 0, 0, 1, 1}, 629 | {0, 0, 0, 0, 0, 0, 0} 630 | }; 631 | static int __Pyx_InitCachedBuiltins(void) { 632 | __pyx_builtin_range = __Pyx_GetName(__pyx_b, __pyx_n_s__range); if (!__pyx_builtin_range) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 633 | return 0; 634 | __pyx_L1_error:; 635 | return -1; 636 | } 637 | 638 | static int __Pyx_InitCachedConstants(void) { 639 | __Pyx_RefNannyDeclarations 640 | __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); 641 | 642 | /* "fib.pyx":1 643 | * def fib(int n): # <<<<<<<<<<<<<< 644 | * cdef int a, b, i 645 | * a, b = 1, 1 646 | */ 647 | __pyx_k_tuple_1 = PyTuple_New(5); if (unlikely(!__pyx_k_tuple_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 648 | __Pyx_GOTREF(__pyx_k_tuple_1); 649 | __Pyx_INCREF(((PyObject *)__pyx_n_s__n)); 650 | PyTuple_SET_ITEM(__pyx_k_tuple_1, 0, ((PyObject *)__pyx_n_s__n)); 651 | __Pyx_GIVEREF(((PyObject *)__pyx_n_s__n)); 652 | __Pyx_INCREF(((PyObject *)__pyx_n_s__n)); 653 | PyTuple_SET_ITEM(__pyx_k_tuple_1, 1, ((PyObject *)__pyx_n_s__n)); 654 | __Pyx_GIVEREF(((PyObject *)__pyx_n_s__n)); 655 | __Pyx_INCREF(((PyObject *)__pyx_n_s__a)); 656 | PyTuple_SET_ITEM(__pyx_k_tuple_1, 2, ((PyObject *)__pyx_n_s__a)); 657 | __Pyx_GIVEREF(((PyObject *)__pyx_n_s__a)); 658 | __Pyx_INCREF(((PyObject *)__pyx_n_s__b)); 659 | PyTuple_SET_ITEM(__pyx_k_tuple_1, 3, ((PyObject *)__pyx_n_s__b)); 660 | __Pyx_GIVEREF(((PyObject *)__pyx_n_s__b)); 661 | __Pyx_INCREF(((PyObject *)__pyx_n_s__i)); 662 | PyTuple_SET_ITEM(__pyx_k_tuple_1, 4, ((PyObject *)__pyx_n_s__i)); 663 | __Pyx_GIVEREF(((PyObject *)__pyx_n_s__i)); 664 | __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_1)); 665 | __pyx_k_codeobj_2 = (PyObject*)__Pyx_PyCode_New(1, 0, 5, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_k_tuple_1, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_3, __pyx_n_s__fib, 1, __pyx_empty_bytes); if (unlikely(!__pyx_k_codeobj_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 666 | __Pyx_RefNannyFinishContext(); 667 | return 0; 668 | __pyx_L1_error:; 669 | __Pyx_RefNannyFinishContext(); 670 | return -1; 671 | } 672 | 673 | static int __Pyx_InitGlobals(void) { 674 | if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; 675 | return 0; 676 | __pyx_L1_error:; 677 | return -1; 678 | } 679 | 680 | #if PY_MAJOR_VERSION < 3 681 | PyMODINIT_FUNC initfib(void); /*proto*/ 682 | PyMODINIT_FUNC initfib(void) 683 | #else 684 | PyMODINIT_FUNC PyInit_fib(void); /*proto*/ 685 | PyMODINIT_FUNC PyInit_fib(void) 686 | #endif 687 | { 688 | PyObject *__pyx_t_1 = NULL; 689 | __Pyx_RefNannyDeclarations 690 | #if CYTHON_REFNANNY 691 | __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); 692 | if (!__Pyx_RefNanny) { 693 | PyErr_Clear(); 694 | __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); 695 | if (!__Pyx_RefNanny) 696 | Py_FatalError("failed to import 'refnanny' module"); 697 | } 698 | #endif 699 | __Pyx_RefNannySetupContext("PyMODINIT_FUNC PyInit_fib(void)", 0); 700 | if ( __Pyx_check_binary_version() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 701 | __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 702 | __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 703 | #ifdef __Pyx_CyFunction_USED 704 | if (__Pyx_CyFunction_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 705 | #endif 706 | #ifdef __Pyx_FusedFunction_USED 707 | if (__pyx_FusedFunction_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 708 | #endif 709 | #ifdef __Pyx_Generator_USED 710 | if (__pyx_Generator_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 711 | #endif 712 | /*--- Library function declarations ---*/ 713 | /*--- Threads initialization code ---*/ 714 | #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS 715 | #ifdef WITH_THREAD /* Python build with threading support? */ 716 | PyEval_InitThreads(); 717 | #endif 718 | #endif 719 | /*--- Module creation code ---*/ 720 | #if PY_MAJOR_VERSION < 3 721 | __pyx_m = Py_InitModule4(__Pyx_NAMESTR("fib"), __pyx_methods, 0, 0, PYTHON_API_VERSION); 722 | #else 723 | __pyx_m = PyModule_Create(&__pyx_moduledef); 724 | #endif 725 | if (!__pyx_m) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; 726 | #if PY_MAJOR_VERSION < 3 727 | Py_INCREF(__pyx_m); 728 | #endif 729 | __pyx_b = PyImport_AddModule(__Pyx_NAMESTR(__Pyx_BUILTIN_MODULE_NAME)); 730 | if (!__pyx_b) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; 731 | if (__Pyx_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; 732 | /*--- Initialize various global constants etc. ---*/ 733 | if (unlikely(__Pyx_InitGlobals() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 734 | if (__pyx_module_is_main_fib) { 735 | if (__Pyx_SetAttrString(__pyx_m, "__name__", __pyx_n_s____main__) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; 736 | } 737 | /*--- Builtin init code ---*/ 738 | if (unlikely(__Pyx_InitCachedBuiltins() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 739 | /*--- Constants init code ---*/ 740 | if (unlikely(__Pyx_InitCachedConstants() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 741 | /*--- Global init code ---*/ 742 | /*--- Variable export code ---*/ 743 | /*--- Function export code ---*/ 744 | /*--- Type init code ---*/ 745 | /*--- Type import code ---*/ 746 | /*--- Variable import code ---*/ 747 | /*--- Function import code ---*/ 748 | /*--- Execution code ---*/ 749 | 750 | /* "fib.pyx":1 751 | * def fib(int n): # <<<<<<<<<<<<<< 752 | * cdef int a, b, i 753 | * a, b = 1, 1 754 | */ 755 | __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_3fib_1fib, NULL, __pyx_n_s__fib); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 756 | __Pyx_GOTREF(__pyx_t_1); 757 | if (PyObject_SetAttr(__pyx_m, __pyx_n_s__fib, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 758 | __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; 759 | __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 760 | __Pyx_GOTREF(((PyObject *)__pyx_t_1)); 761 | if (PyObject_SetAttr(__pyx_m, __pyx_n_s____test__, ((PyObject *)__pyx_t_1)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 762 | __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0; 763 | goto __pyx_L0; 764 | __pyx_L1_error:; 765 | __Pyx_XDECREF(__pyx_t_1); 766 | if (__pyx_m) { 767 | __Pyx_AddTraceback("init fib", __pyx_clineno, __pyx_lineno, __pyx_filename); 768 | Py_DECREF(__pyx_m); __pyx_m = 0; 769 | } else if (!PyErr_Occurred()) { 770 | PyErr_SetString(PyExc_ImportError, "init fib"); 771 | } 772 | __pyx_L0:; 773 | __Pyx_RefNannyFinishContext(); 774 | #if PY_MAJOR_VERSION < 3 775 | return; 776 | #else 777 | return __pyx_m; 778 | #endif 779 | } 780 | 781 | /* Runtime support code */ 782 | #if CYTHON_REFNANNY 783 | static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { 784 | PyObject *m = NULL, *p = NULL; 785 | void *r = NULL; 786 | m = PyImport_ImportModule((char *)modname); 787 | if (!m) goto end; 788 | p = PyObject_GetAttrString(m, (char *)"RefNannyAPI"); 789 | if (!p) goto end; 790 | r = PyLong_AsVoidPtr(p); 791 | end: 792 | Py_XDECREF(p); 793 | Py_XDECREF(m); 794 | return (__Pyx_RefNannyAPIStruct *)r; 795 | } 796 | #endif /* CYTHON_REFNANNY */ 797 | 798 | static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) { 799 | PyObject *result; 800 | result = PyObject_GetAttr(dict, name); 801 | if (!result) { 802 | if (dict != __pyx_b) { 803 | PyErr_Clear(); 804 | result = PyObject_GetAttr(__pyx_b, name); 805 | } 806 | if (!result) { 807 | PyErr_SetObject(PyExc_NameError, name); 808 | } 809 | } 810 | return result; 811 | } 812 | 813 | static CYTHON_INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject* x) { 814 | const unsigned char neg_one = (unsigned char)-1, const_zero = 0; 815 | const int is_unsigned = neg_one > const_zero; 816 | if (sizeof(unsigned char) < sizeof(long)) { 817 | long val = __Pyx_PyInt_AsLong(x); 818 | if (unlikely(val != (long)(unsigned char)val)) { 819 | if (!unlikely(val == -1 && PyErr_Occurred())) { 820 | PyErr_SetString(PyExc_OverflowError, 821 | (is_unsigned && unlikely(val < 0)) ? 822 | "can't convert negative value to unsigned char" : 823 | "value too large to convert to unsigned char"); 824 | } 825 | return (unsigned char)-1; 826 | } 827 | return (unsigned char)val; 828 | } 829 | return (unsigned char)__Pyx_PyInt_AsUnsignedLong(x); 830 | } 831 | 832 | static CYTHON_INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject* x) { 833 | const unsigned short neg_one = (unsigned short)-1, const_zero = 0; 834 | const int is_unsigned = neg_one > const_zero; 835 | if (sizeof(unsigned short) < sizeof(long)) { 836 | long val = __Pyx_PyInt_AsLong(x); 837 | if (unlikely(val != (long)(unsigned short)val)) { 838 | if (!unlikely(val == -1 && PyErr_Occurred())) { 839 | PyErr_SetString(PyExc_OverflowError, 840 | (is_unsigned && unlikely(val < 0)) ? 841 | "can't convert negative value to unsigned short" : 842 | "value too large to convert to unsigned short"); 843 | } 844 | return (unsigned short)-1; 845 | } 846 | return (unsigned short)val; 847 | } 848 | return (unsigned short)__Pyx_PyInt_AsUnsignedLong(x); 849 | } 850 | 851 | static CYTHON_INLINE unsigned int __Pyx_PyInt_AsUnsignedInt(PyObject* x) { 852 | const unsigned int neg_one = (unsigned int)-1, const_zero = 0; 853 | const int is_unsigned = neg_one > const_zero; 854 | if (sizeof(unsigned int) < sizeof(long)) { 855 | long val = __Pyx_PyInt_AsLong(x); 856 | if (unlikely(val != (long)(unsigned int)val)) { 857 | if (!unlikely(val == -1 && PyErr_Occurred())) { 858 | PyErr_SetString(PyExc_OverflowError, 859 | (is_unsigned && unlikely(val < 0)) ? 860 | "can't convert negative value to unsigned int" : 861 | "value too large to convert to unsigned int"); 862 | } 863 | return (unsigned int)-1; 864 | } 865 | return (unsigned int)val; 866 | } 867 | return (unsigned int)__Pyx_PyInt_AsUnsignedLong(x); 868 | } 869 | 870 | static CYTHON_INLINE char __Pyx_PyInt_AsChar(PyObject* x) { 871 | const char neg_one = (char)-1, const_zero = 0; 872 | const int is_unsigned = neg_one > const_zero; 873 | if (sizeof(char) < sizeof(long)) { 874 | long val = __Pyx_PyInt_AsLong(x); 875 | if (unlikely(val != (long)(char)val)) { 876 | if (!unlikely(val == -1 && PyErr_Occurred())) { 877 | PyErr_SetString(PyExc_OverflowError, 878 | (is_unsigned && unlikely(val < 0)) ? 879 | "can't convert negative value to char" : 880 | "value too large to convert to char"); 881 | } 882 | return (char)-1; 883 | } 884 | return (char)val; 885 | } 886 | return (char)__Pyx_PyInt_AsLong(x); 887 | } 888 | 889 | static CYTHON_INLINE short __Pyx_PyInt_AsShort(PyObject* x) { 890 | const short neg_one = (short)-1, const_zero = 0; 891 | const int is_unsigned = neg_one > const_zero; 892 | if (sizeof(short) < sizeof(long)) { 893 | long val = __Pyx_PyInt_AsLong(x); 894 | if (unlikely(val != (long)(short)val)) { 895 | if (!unlikely(val == -1 && PyErr_Occurred())) { 896 | PyErr_SetString(PyExc_OverflowError, 897 | (is_unsigned && unlikely(val < 0)) ? 898 | "can't convert negative value to short" : 899 | "value too large to convert to short"); 900 | } 901 | return (short)-1; 902 | } 903 | return (short)val; 904 | } 905 | return (short)__Pyx_PyInt_AsLong(x); 906 | } 907 | 908 | static CYTHON_INLINE int __Pyx_PyInt_AsInt(PyObject* x) { 909 | const int neg_one = (int)-1, const_zero = 0; 910 | const int is_unsigned = neg_one > const_zero; 911 | if (sizeof(int) < sizeof(long)) { 912 | long val = __Pyx_PyInt_AsLong(x); 913 | if (unlikely(val != (long)(int)val)) { 914 | if (!unlikely(val == -1 && PyErr_Occurred())) { 915 | PyErr_SetString(PyExc_OverflowError, 916 | (is_unsigned && unlikely(val < 0)) ? 917 | "can't convert negative value to int" : 918 | "value too large to convert to int"); 919 | } 920 | return (int)-1; 921 | } 922 | return (int)val; 923 | } 924 | return (int)__Pyx_PyInt_AsLong(x); 925 | } 926 | 927 | static CYTHON_INLINE signed char __Pyx_PyInt_AsSignedChar(PyObject* x) { 928 | const signed char neg_one = (signed char)-1, const_zero = 0; 929 | const int is_unsigned = neg_one > const_zero; 930 | if (sizeof(signed char) < sizeof(long)) { 931 | long val = __Pyx_PyInt_AsLong(x); 932 | if (unlikely(val != (long)(signed char)val)) { 933 | if (!unlikely(val == -1 && PyErr_Occurred())) { 934 | PyErr_SetString(PyExc_OverflowError, 935 | (is_unsigned && unlikely(val < 0)) ? 936 | "can't convert negative value to signed char" : 937 | "value too large to convert to signed char"); 938 | } 939 | return (signed char)-1; 940 | } 941 | return (signed char)val; 942 | } 943 | return (signed char)__Pyx_PyInt_AsSignedLong(x); 944 | } 945 | 946 | static CYTHON_INLINE signed short __Pyx_PyInt_AsSignedShort(PyObject* x) { 947 | const signed short neg_one = (signed short)-1, const_zero = 0; 948 | const int is_unsigned = neg_one > const_zero; 949 | if (sizeof(signed short) < sizeof(long)) { 950 | long val = __Pyx_PyInt_AsLong(x); 951 | if (unlikely(val != (long)(signed short)val)) { 952 | if (!unlikely(val == -1 && PyErr_Occurred())) { 953 | PyErr_SetString(PyExc_OverflowError, 954 | (is_unsigned && unlikely(val < 0)) ? 955 | "can't convert negative value to signed short" : 956 | "value too large to convert to signed short"); 957 | } 958 | return (signed short)-1; 959 | } 960 | return (signed short)val; 961 | } 962 | return (signed short)__Pyx_PyInt_AsSignedLong(x); 963 | } 964 | 965 | static CYTHON_INLINE signed int __Pyx_PyInt_AsSignedInt(PyObject* x) { 966 | const signed int neg_one = (signed int)-1, const_zero = 0; 967 | const int is_unsigned = neg_one > const_zero; 968 | if (sizeof(signed int) < sizeof(long)) { 969 | long val = __Pyx_PyInt_AsLong(x); 970 | if (unlikely(val != (long)(signed int)val)) { 971 | if (!unlikely(val == -1 && PyErr_Occurred())) { 972 | PyErr_SetString(PyExc_OverflowError, 973 | (is_unsigned && unlikely(val < 0)) ? 974 | "can't convert negative value to signed int" : 975 | "value too large to convert to signed int"); 976 | } 977 | return (signed int)-1; 978 | } 979 | return (signed int)val; 980 | } 981 | return (signed int)__Pyx_PyInt_AsSignedLong(x); 982 | } 983 | 984 | static CYTHON_INLINE int __Pyx_PyInt_AsLongDouble(PyObject* x) { 985 | const int neg_one = (int)-1, const_zero = 0; 986 | const int is_unsigned = neg_one > const_zero; 987 | if (sizeof(int) < sizeof(long)) { 988 | long val = __Pyx_PyInt_AsLong(x); 989 | if (unlikely(val != (long)(int)val)) { 990 | if (!unlikely(val == -1 && PyErr_Occurred())) { 991 | PyErr_SetString(PyExc_OverflowError, 992 | (is_unsigned && unlikely(val < 0)) ? 993 | "can't convert negative value to int" : 994 | "value too large to convert to int"); 995 | } 996 | return (int)-1; 997 | } 998 | return (int)val; 999 | } 1000 | return (int)__Pyx_PyInt_AsLong(x); 1001 | } 1002 | 1003 | static CYTHON_INLINE unsigned long __Pyx_PyInt_AsUnsignedLong(PyObject* x) { 1004 | const unsigned long neg_one = (unsigned long)-1, const_zero = 0; 1005 | const int is_unsigned = neg_one > const_zero; 1006 | #if PY_VERSION_HEX < 0x03000000 1007 | if (likely(PyInt_Check(x))) { 1008 | long val = PyInt_AS_LONG(x); 1009 | if (is_unsigned && unlikely(val < 0)) { 1010 | PyErr_SetString(PyExc_OverflowError, 1011 | "can't convert negative value to unsigned long"); 1012 | return (unsigned long)-1; 1013 | } 1014 | return (unsigned long)val; 1015 | } else 1016 | #endif 1017 | if (likely(PyLong_Check(x))) { 1018 | if (is_unsigned) { 1019 | if (unlikely(Py_SIZE(x) < 0)) { 1020 | PyErr_SetString(PyExc_OverflowError, 1021 | "can't convert negative value to unsigned long"); 1022 | return (unsigned long)-1; 1023 | } 1024 | return (unsigned long)PyLong_AsUnsignedLong(x); 1025 | } else { 1026 | return (unsigned long)PyLong_AsLong(x); 1027 | } 1028 | } else { 1029 | unsigned long val; 1030 | PyObject *tmp = __Pyx_PyNumber_Int(x); 1031 | if (!tmp) return (unsigned long)-1; 1032 | val = __Pyx_PyInt_AsUnsignedLong(tmp); 1033 | Py_DECREF(tmp); 1034 | return val; 1035 | } 1036 | } 1037 | 1038 | static CYTHON_INLINE unsigned PY_LONG_LONG __Pyx_PyInt_AsUnsignedLongLong(PyObject* x) { 1039 | const unsigned PY_LONG_LONG neg_one = (unsigned PY_LONG_LONG)-1, const_zero = 0; 1040 | const int is_unsigned = neg_one > const_zero; 1041 | #if PY_VERSION_HEX < 0x03000000 1042 | if (likely(PyInt_Check(x))) { 1043 | long val = PyInt_AS_LONG(x); 1044 | if (is_unsigned && unlikely(val < 0)) { 1045 | PyErr_SetString(PyExc_OverflowError, 1046 | "can't convert negative value to unsigned PY_LONG_LONG"); 1047 | return (unsigned PY_LONG_LONG)-1; 1048 | } 1049 | return (unsigned PY_LONG_LONG)val; 1050 | } else 1051 | #endif 1052 | if (likely(PyLong_Check(x))) { 1053 | if (is_unsigned) { 1054 | if (unlikely(Py_SIZE(x) < 0)) { 1055 | PyErr_SetString(PyExc_OverflowError, 1056 | "can't convert negative value to unsigned PY_LONG_LONG"); 1057 | return (unsigned PY_LONG_LONG)-1; 1058 | } 1059 | return (unsigned PY_LONG_LONG)PyLong_AsUnsignedLongLong(x); 1060 | } else { 1061 | return (unsigned PY_LONG_LONG)PyLong_AsLongLong(x); 1062 | } 1063 | } else { 1064 | unsigned PY_LONG_LONG val; 1065 | PyObject *tmp = __Pyx_PyNumber_Int(x); 1066 | if (!tmp) return (unsigned PY_LONG_LONG)-1; 1067 | val = __Pyx_PyInt_AsUnsignedLongLong(tmp); 1068 | Py_DECREF(tmp); 1069 | return val; 1070 | } 1071 | } 1072 | 1073 | static CYTHON_INLINE long __Pyx_PyInt_AsLong(PyObject* x) { 1074 | const long neg_one = (long)-1, const_zero = 0; 1075 | const int is_unsigned = neg_one > const_zero; 1076 | #if PY_VERSION_HEX < 0x03000000 1077 | if (likely(PyInt_Check(x))) { 1078 | long val = PyInt_AS_LONG(x); 1079 | if (is_unsigned && unlikely(val < 0)) { 1080 | PyErr_SetString(PyExc_OverflowError, 1081 | "can't convert negative value to long"); 1082 | return (long)-1; 1083 | } 1084 | return (long)val; 1085 | } else 1086 | #endif 1087 | if (likely(PyLong_Check(x))) { 1088 | if (is_unsigned) { 1089 | if (unlikely(Py_SIZE(x) < 0)) { 1090 | PyErr_SetString(PyExc_OverflowError, 1091 | "can't convert negative value to long"); 1092 | return (long)-1; 1093 | } 1094 | return (long)PyLong_AsUnsignedLong(x); 1095 | } else { 1096 | return (long)PyLong_AsLong(x); 1097 | } 1098 | } else { 1099 | long val; 1100 | PyObject *tmp = __Pyx_PyNumber_Int(x); 1101 | if (!tmp) return (long)-1; 1102 | val = __Pyx_PyInt_AsLong(tmp); 1103 | Py_DECREF(tmp); 1104 | return val; 1105 | } 1106 | } 1107 | 1108 | static CYTHON_INLINE PY_LONG_LONG __Pyx_PyInt_AsLongLong(PyObject* x) { 1109 | const PY_LONG_LONG neg_one = (PY_LONG_LONG)-1, const_zero = 0; 1110 | const int is_unsigned = neg_one > const_zero; 1111 | #if PY_VERSION_HEX < 0x03000000 1112 | if (likely(PyInt_Check(x))) { 1113 | long val = PyInt_AS_LONG(x); 1114 | if (is_unsigned && unlikely(val < 0)) { 1115 | PyErr_SetString(PyExc_OverflowError, 1116 | "can't convert negative value to PY_LONG_LONG"); 1117 | return (PY_LONG_LONG)-1; 1118 | } 1119 | return (PY_LONG_LONG)val; 1120 | } else 1121 | #endif 1122 | if (likely(PyLong_Check(x))) { 1123 | if (is_unsigned) { 1124 | if (unlikely(Py_SIZE(x) < 0)) { 1125 | PyErr_SetString(PyExc_OverflowError, 1126 | "can't convert negative value to PY_LONG_LONG"); 1127 | return (PY_LONG_LONG)-1; 1128 | } 1129 | return (PY_LONG_LONG)PyLong_AsUnsignedLongLong(x); 1130 | } else { 1131 | return (PY_LONG_LONG)PyLong_AsLongLong(x); 1132 | } 1133 | } else { 1134 | PY_LONG_LONG val; 1135 | PyObject *tmp = __Pyx_PyNumber_Int(x); 1136 | if (!tmp) return (PY_LONG_LONG)-1; 1137 | val = __Pyx_PyInt_AsLongLong(tmp); 1138 | Py_DECREF(tmp); 1139 | return val; 1140 | } 1141 | } 1142 | 1143 | static CYTHON_INLINE signed long __Pyx_PyInt_AsSignedLong(PyObject* x) { 1144 | const signed long neg_one = (signed long)-1, const_zero = 0; 1145 | const int is_unsigned = neg_one > const_zero; 1146 | #if PY_VERSION_HEX < 0x03000000 1147 | if (likely(PyInt_Check(x))) { 1148 | long val = PyInt_AS_LONG(x); 1149 | if (is_unsigned && unlikely(val < 0)) { 1150 | PyErr_SetString(PyExc_OverflowError, 1151 | "can't convert negative value to signed long"); 1152 | return (signed long)-1; 1153 | } 1154 | return (signed long)val; 1155 | } else 1156 | #endif 1157 | if (likely(PyLong_Check(x))) { 1158 | if (is_unsigned) { 1159 | if (unlikely(Py_SIZE(x) < 0)) { 1160 | PyErr_SetString(PyExc_OverflowError, 1161 | "can't convert negative value to signed long"); 1162 | return (signed long)-1; 1163 | } 1164 | return (signed long)PyLong_AsUnsignedLong(x); 1165 | } else { 1166 | return (signed long)PyLong_AsLong(x); 1167 | } 1168 | } else { 1169 | signed long val; 1170 | PyObject *tmp = __Pyx_PyNumber_Int(x); 1171 | if (!tmp) return (signed long)-1; 1172 | val = __Pyx_PyInt_AsSignedLong(tmp); 1173 | Py_DECREF(tmp); 1174 | return val; 1175 | } 1176 | } 1177 | 1178 | static CYTHON_INLINE signed PY_LONG_LONG __Pyx_PyInt_AsSignedLongLong(PyObject* x) { 1179 | const signed PY_LONG_LONG neg_one = (signed PY_LONG_LONG)-1, const_zero = 0; 1180 | const int is_unsigned = neg_one > const_zero; 1181 | #if PY_VERSION_HEX < 0x03000000 1182 | if (likely(PyInt_Check(x))) { 1183 | long val = PyInt_AS_LONG(x); 1184 | if (is_unsigned && unlikely(val < 0)) { 1185 | PyErr_SetString(PyExc_OverflowError, 1186 | "can't convert negative value to signed PY_LONG_LONG"); 1187 | return (signed PY_LONG_LONG)-1; 1188 | } 1189 | return (signed PY_LONG_LONG)val; 1190 | } else 1191 | #endif 1192 | if (likely(PyLong_Check(x))) { 1193 | if (is_unsigned) { 1194 | if (unlikely(Py_SIZE(x) < 0)) { 1195 | PyErr_SetString(PyExc_OverflowError, 1196 | "can't convert negative value to signed PY_LONG_LONG"); 1197 | return (signed PY_LONG_LONG)-1; 1198 | } 1199 | return (signed PY_LONG_LONG)PyLong_AsUnsignedLongLong(x); 1200 | } else { 1201 | return (signed PY_LONG_LONG)PyLong_AsLongLong(x); 1202 | } 1203 | } else { 1204 | signed PY_LONG_LONG val; 1205 | PyObject *tmp = __Pyx_PyNumber_Int(x); 1206 | if (!tmp) return (signed PY_LONG_LONG)-1; 1207 | val = __Pyx_PyInt_AsSignedLongLong(tmp); 1208 | Py_DECREF(tmp); 1209 | return val; 1210 | } 1211 | } 1212 | 1213 | static int __Pyx_check_binary_version(void) { 1214 | char ctversion[4], rtversion[4]; 1215 | PyOS_snprintf(ctversion, 4, "%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION); 1216 | PyOS_snprintf(rtversion, 4, "%s", Py_GetVersion()); 1217 | if (ctversion[0] != rtversion[0] || ctversion[2] != rtversion[2]) { 1218 | char message[200]; 1219 | PyOS_snprintf(message, sizeof(message), 1220 | "compiletime version %s of module '%.100s' " 1221 | "does not match runtime version %s", 1222 | ctversion, __Pyx_MODULE_NAME, rtversion); 1223 | #if PY_VERSION_HEX < 0x02050000 1224 | return PyErr_Warn(NULL, message); 1225 | #else 1226 | return PyErr_WarnEx(NULL, message, 1); 1227 | #endif 1228 | } 1229 | return 0; 1230 | } 1231 | 1232 | static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { 1233 | int start = 0, mid = 0, end = count - 1; 1234 | if (end >= 0 && code_line > entries[end].code_line) { 1235 | return count; 1236 | } 1237 | while (start < end) { 1238 | mid = (start + end) / 2; 1239 | if (code_line < entries[mid].code_line) { 1240 | end = mid; 1241 | } else if (code_line > entries[mid].code_line) { 1242 | start = mid + 1; 1243 | } else { 1244 | return mid; 1245 | } 1246 | } 1247 | if (code_line <= entries[mid].code_line) { 1248 | return mid; 1249 | } else { 1250 | return mid + 1; 1251 | } 1252 | } 1253 | static PyCodeObject *__pyx_find_code_object(int code_line) { 1254 | PyCodeObject* code_object; 1255 | int pos; 1256 | if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { 1257 | return NULL; 1258 | } 1259 | pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); 1260 | if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { 1261 | return NULL; 1262 | } 1263 | code_object = __pyx_code_cache.entries[pos].code_object; 1264 | Py_INCREF(code_object); 1265 | return code_object; 1266 | } 1267 | static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { 1268 | int pos, i; 1269 | __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; 1270 | if (unlikely(!code_line)) { 1271 | return; 1272 | } 1273 | if (unlikely(!entries)) { 1274 | entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); 1275 | if (likely(entries)) { 1276 | __pyx_code_cache.entries = entries; 1277 | __pyx_code_cache.max_count = 64; 1278 | __pyx_code_cache.count = 1; 1279 | entries[0].code_line = code_line; 1280 | entries[0].code_object = code_object; 1281 | Py_INCREF(code_object); 1282 | } 1283 | return; 1284 | } 1285 | pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); 1286 | if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { 1287 | PyCodeObject* tmp = entries[pos].code_object; 1288 | entries[pos].code_object = code_object; 1289 | Py_DECREF(tmp); 1290 | return; 1291 | } 1292 | if (__pyx_code_cache.count == __pyx_code_cache.max_count) { 1293 | int new_max = __pyx_code_cache.max_count + 64; 1294 | entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( 1295 | __pyx_code_cache.entries, new_max*sizeof(__Pyx_CodeObjectCacheEntry)); 1296 | if (unlikely(!entries)) { 1297 | return; 1298 | } 1299 | __pyx_code_cache.entries = entries; 1300 | __pyx_code_cache.max_count = new_max; 1301 | } 1302 | for (i=__pyx_code_cache.count; i>pos; i--) { 1303 | entries[i] = entries[i-1]; 1304 | } 1305 | entries[pos].code_line = code_line; 1306 | entries[pos].code_object = code_object; 1307 | __pyx_code_cache.count++; 1308 | Py_INCREF(code_object); 1309 | } 1310 | 1311 | #include "compile.h" 1312 | #include "frameobject.h" 1313 | #include "traceback.h" 1314 | static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( 1315 | const char *funcname, int c_line, 1316 | int py_line, const char *filename) { 1317 | PyCodeObject *py_code = 0; 1318 | PyObject *py_srcfile = 0; 1319 | PyObject *py_funcname = 0; 1320 | #if PY_MAJOR_VERSION < 3 1321 | py_srcfile = PyString_FromString(filename); 1322 | #else 1323 | py_srcfile = PyUnicode_FromString(filename); 1324 | #endif 1325 | if (!py_srcfile) goto bad; 1326 | if (c_line) { 1327 | #if PY_MAJOR_VERSION < 3 1328 | py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); 1329 | #else 1330 | py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); 1331 | #endif 1332 | } 1333 | else { 1334 | #if PY_MAJOR_VERSION < 3 1335 | py_funcname = PyString_FromString(funcname); 1336 | #else 1337 | py_funcname = PyUnicode_FromString(funcname); 1338 | #endif 1339 | } 1340 | if (!py_funcname) goto bad; 1341 | py_code = __Pyx_PyCode_New( 1342 | 0, /*int argcount,*/ 1343 | 0, /*int kwonlyargcount,*/ 1344 | 0, /*int nlocals,*/ 1345 | 0, /*int stacksize,*/ 1346 | 0, /*int flags,*/ 1347 | __pyx_empty_bytes, /*PyObject *code,*/ 1348 | __pyx_empty_tuple, /*PyObject *consts,*/ 1349 | __pyx_empty_tuple, /*PyObject *names,*/ 1350 | __pyx_empty_tuple, /*PyObject *varnames,*/ 1351 | __pyx_empty_tuple, /*PyObject *freevars,*/ 1352 | __pyx_empty_tuple, /*PyObject *cellvars,*/ 1353 | py_srcfile, /*PyObject *filename,*/ 1354 | py_funcname, /*PyObject *name,*/ 1355 | py_line, /*int firstlineno,*/ 1356 | __pyx_empty_bytes /*PyObject *lnotab*/ 1357 | ); 1358 | Py_DECREF(py_srcfile); 1359 | Py_DECREF(py_funcname); 1360 | return py_code; 1361 | bad: 1362 | Py_XDECREF(py_srcfile); 1363 | Py_XDECREF(py_funcname); 1364 | return NULL; 1365 | } 1366 | static void __Pyx_AddTraceback(const char *funcname, int c_line, 1367 | int py_line, const char *filename) { 1368 | PyCodeObject *py_code = 0; 1369 | PyObject *py_globals = 0; 1370 | PyFrameObject *py_frame = 0; 1371 | py_code = __pyx_find_code_object(c_line ? c_line : py_line); 1372 | if (!py_code) { 1373 | py_code = __Pyx_CreateCodeObjectForTraceback( 1374 | funcname, c_line, py_line, filename); 1375 | if (!py_code) goto bad; 1376 | __pyx_insert_code_object(c_line ? c_line : py_line, py_code); 1377 | } 1378 | py_globals = PyModule_GetDict(__pyx_m); 1379 | if (!py_globals) goto bad; 1380 | py_frame = PyFrame_New( 1381 | PyThreadState_GET(), /*PyThreadState *tstate,*/ 1382 | py_code, /*PyCodeObject *code,*/ 1383 | py_globals, /*PyObject *globals,*/ 1384 | 0 /*PyObject *locals*/ 1385 | ); 1386 | if (!py_frame) goto bad; 1387 | py_frame->f_lineno = py_line; 1388 | PyTraceBack_Here(py_frame); 1389 | bad: 1390 | Py_XDECREF(py_code); 1391 | Py_XDECREF(py_frame); 1392 | } 1393 | 1394 | static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { 1395 | while (t->p) { 1396 | #if PY_MAJOR_VERSION < 3 1397 | if (t->is_unicode) { 1398 | *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); 1399 | } else if (t->intern) { 1400 | *t->p = PyString_InternFromString(t->s); 1401 | } else { 1402 | *t->p = PyString_FromStringAndSize(t->s, t->n - 1); 1403 | } 1404 | #else /* Python 3+ has unicode identifiers */ 1405 | if (t->is_unicode | t->is_str) { 1406 | if (t->intern) { 1407 | *t->p = PyUnicode_InternFromString(t->s); 1408 | } else if (t->encoding) { 1409 | *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL); 1410 | } else { 1411 | *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1); 1412 | } 1413 | } else { 1414 | *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1); 1415 | } 1416 | #endif 1417 | if (!*t->p) 1418 | return -1; 1419 | ++t; 1420 | } 1421 | return 0; 1422 | } 1423 | 1424 | 1425 | /* Type Conversion Functions */ 1426 | 1427 | static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { 1428 | int is_true = x == Py_True; 1429 | if (is_true | (x == Py_False) | (x == Py_None)) return is_true; 1430 | else return PyObject_IsTrue(x); 1431 | } 1432 | 1433 | static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) { 1434 | PyNumberMethods *m; 1435 | const char *name = NULL; 1436 | PyObject *res = NULL; 1437 | #if PY_VERSION_HEX < 0x03000000 1438 | if (PyInt_Check(x) || PyLong_Check(x)) 1439 | #else 1440 | if (PyLong_Check(x)) 1441 | #endif 1442 | return Py_INCREF(x), x; 1443 | m = Py_TYPE(x)->tp_as_number; 1444 | #if PY_VERSION_HEX < 0x03000000 1445 | if (m && m->nb_int) { 1446 | name = "int"; 1447 | res = PyNumber_Int(x); 1448 | } 1449 | else if (m && m->nb_long) { 1450 | name = "long"; 1451 | res = PyNumber_Long(x); 1452 | } 1453 | #else 1454 | if (m && m->nb_int) { 1455 | name = "int"; 1456 | res = PyNumber_Long(x); 1457 | } 1458 | #endif 1459 | if (res) { 1460 | #if PY_VERSION_HEX < 0x03000000 1461 | if (!PyInt_Check(res) && !PyLong_Check(res)) { 1462 | #else 1463 | if (!PyLong_Check(res)) { 1464 | #endif 1465 | PyErr_Format(PyExc_TypeError, 1466 | "__%s__ returned non-%s (type %.200s)", 1467 | name, name, Py_TYPE(res)->tp_name); 1468 | Py_DECREF(res); 1469 | return NULL; 1470 | } 1471 | } 1472 | else if (!PyErr_Occurred()) { 1473 | PyErr_SetString(PyExc_TypeError, 1474 | "an integer is required"); 1475 | } 1476 | return res; 1477 | } 1478 | 1479 | static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { 1480 | Py_ssize_t ival; 1481 | PyObject* x = PyNumber_Index(b); 1482 | if (!x) return -1; 1483 | ival = PyInt_AsSsize_t(x); 1484 | Py_DECREF(x); 1485 | return ival; 1486 | } 1487 | 1488 | static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { 1489 | #if PY_VERSION_HEX < 0x02050000 1490 | if (ival <= LONG_MAX) 1491 | return PyInt_FromLong((long)ival); 1492 | else { 1493 | unsigned char *bytes = (unsigned char *) &ival; 1494 | int one = 1; int little = (int)*(unsigned char*)&one; 1495 | return _PyLong_FromByteArray(bytes, sizeof(size_t), little, 0); 1496 | } 1497 | #else 1498 | return PyInt_FromSize_t(ival); 1499 | #endif 1500 | } 1501 | 1502 | static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject* x) { 1503 | unsigned PY_LONG_LONG val = __Pyx_PyInt_AsUnsignedLongLong(x); 1504 | if (unlikely(val == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())) { 1505 | return (size_t)-1; 1506 | } else if (unlikely(val != (unsigned PY_LONG_LONG)(size_t)val)) { 1507 | PyErr_SetString(PyExc_OverflowError, 1508 | "value too large to convert to size_t"); 1509 | return (size_t)-1; 1510 | } 1511 | return (size_t)val; 1512 | } 1513 | 1514 | 1515 | #endif /* Py_PYTHON_H */ 1516 | -------------------------------------------------------------------------------- /demo/fib/fib.py: -------------------------------------------------------------------------------- 1 | import cython 2 | 3 | @cython.locals(n=cython.int) 4 | def fib(n): 5 | cython.declare(a=cython.int, 6 | b=cython.int, 7 | i=cython.int) 8 | a, b = 1, 1 9 | for i in range(n): 10 | a, b = a+b, a 11 | return a 12 | -------------------------------------------------------------------------------- /demo/fib/fib.pyx: -------------------------------------------------------------------------------- 1 | def fib(int n): 2 | cdef int a, b, i 3 | a, b = 1, 1 4 | for i in range(n): 5 | a, b = a+b, a 6 | return a 7 | -------------------------------------------------------------------------------- /demo/fib/fib_orig.pyx: -------------------------------------------------------------------------------- 1 | def fib(n): 2 | a,b = 1,1 3 | for i in range(n): 4 | a, b = a+b, a 5 | return a 6 | -------------------------------------------------------------------------------- /demo/fib/hand_fib.c: -------------------------------------------------------------------------------- 1 | #include "Python.h" 2 | 3 | static PyObject* hand_fib(PyObject *self, PyObject *args) 4 | { 5 | int n, a, b, i, tmp; 6 | if (!PyArg_ParseTuple(args, "i", &n)) 7 | return NULL; 8 | a = b = 1; 9 | for (i=0; i 3 | 4 | float rms_speeds(std::vector *particles) 5 | { 6 | float sum_speeds_sq = 0; 7 | typedef std::vector::const_iterator ParticleIter; 8 | 9 | for (ParticleIter it=particles->begin(); it != particles->end(); ++it) { 10 | sum_speeds_sq += (*it)->get_speed() * (*it)->get_speed(); 11 | } 12 | return sqrt(sum_speeds_sq / particles->size()); 13 | } 14 | -------------------------------------------------------------------------------- /demo/wrap-cpp-particle/particle.h: -------------------------------------------------------------------------------- 1 | #ifndef _PARTICLE_H_ 2 | #define _PARTICLE_H_ 3 | 4 | #include 5 | #include 6 | 7 | template 8 | inline const T norm2(const T x, const T y, const T z) 9 | { 10 | return sqrt(x * x + y * y + z * z); 11 | } 12 | 13 | class Particle 14 | { 15 | public: 16 | 17 | Particle() : _x(0), _y(0), _z(0), 18 | _vx(0), _vy(0), _vz(0), 19 | _mass(0), _charge(0) {}; 20 | 21 | Particle(float x, float y, float z, 22 | float vx, float vy, float vz, 23 | float mass, float charge) : 24 | _x(x), _y(y), _z(z), 25 | _vx(vx), _vy(vy), _vz(vz), 26 | _mass(mass), _charge(charge) {}; 27 | 28 | const float get_speed() const { 29 | return norm2(_vx, _vy, _vz); 30 | } 31 | 32 | const float& get_x() const { 33 | return _x; 34 | } 35 | 36 | private: 37 | float _x, _y, _z; 38 | float _vx, _vy, _vz; 39 | float _mass; 40 | float _charge; 41 | }; 42 | 43 | float rms_speeds(std::vector *particles); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /demo/wrap-cpp-particle/particle_tmpl.cpp: -------------------------------------------------------------------------------- 1 | #include "particle_tmpl.h" 2 | -------------------------------------------------------------------------------- /demo/wrap-cpp-particle/particle_tmpl.h: -------------------------------------------------------------------------------- 1 | #ifndef _PARTICLE_H_ 2 | #define _PARTICLE_H_ 3 | 4 | #include 5 | #include 6 | 7 | template 8 | inline const T norm2(const T x, const T y, const T z) 9 | { 10 | return sqrt(x * x + y * y + z * z); 11 | } 12 | 13 | template 14 | class Particle 15 | { 16 | public: 17 | 18 | Particle() : _x(0), _y(0), _z(0), 19 | _vx(0), _vy(0), _vz(0), 20 | _mass(0), _charge(0) {}; 21 | 22 | Particle(T x, T y, T z, 23 | T vx, T vy, T vz, 24 | T mass, T charge) : 25 | _x(x), _y(y), _z(z), 26 | _vx(vx), _vy(vy), _vz(vz), 27 | _mass(mass), _charge(charge) {}; 28 | 29 | const T get_speed() const { 30 | return norm2(_vx, _vy, _vz); 31 | } 32 | 33 | const T& get_x() const { 34 | return _x; 35 | } 36 | 37 | private: 38 | T _x, _y, _z; 39 | T _vx, _vy, _vz; 40 | T _mass; 41 | T _charge; 42 | }; 43 | 44 | template 45 | T rms_speeds(std::vector*> *particles) 46 | { 47 | T sum_speeds_sq = 0; 48 | typedef typename std::vector * >::const_iterator ParticleIter; 49 | 50 | for (ParticleIter it=particles->begin(); it != particles->end(); ++it) { 51 | sum_speeds_sq += (*it)->get_speed() * (*it)->get_speed(); 52 | } 53 | return sqrt(sum_speeds_sq / particles->size()); 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /demo/wrap-cpp-particle/runjinja.py: -------------------------------------------------------------------------------- 1 | from jinja2 import Template 2 | 3 | result = Template(open('wrap_particle_tmpl.pyx.in').read()).render(floatings='double float'.split()) 4 | # result = Template(open('wrap_particle_tmpl.pyx.in').read()).render() 5 | print result 6 | open('wrap_particle_tmpl_jinja.pyx', 'w').write(result) 7 | -------------------------------------------------------------------------------- /demo/wrap-cpp-particle/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from distutils.extension import Extension 3 | from Cython.Distutils import build_ext 4 | 5 | # ext = Extension("wrap_particle_tmpl", ["wrap_particle_tmpl.pyx", "particle_tmpl.cpp"], language="c++") 6 | ext = Extension("wrap_particle_tmpl", ["wrap_particle_tmpl_jinja.pyx", "particle_tmpl.cpp"], language="c++") 7 | 8 | setup( 9 | cmdclass = {'build_ext': build_ext}, 10 | ext_modules = [ext], 11 | ) 12 | -------------------------------------------------------------------------------- /demo/wrap-cpp-particle/setup_tmpl.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from distutils.extension import Extension 3 | from Cython.Distutils import build_ext 4 | 5 | ext = Extension("wrap_particle", ["wrap_particle.pyx", "particle.cpp"], language="c++") 6 | 7 | setup( 8 | cmdclass = {'build_ext': build_ext}, 9 | ext_modules = [ext], 10 | ) 11 | -------------------------------------------------------------------------------- /demo/wrap-cpp-particle/test_wrap_particle.py: -------------------------------------------------------------------------------- 1 | import wrap_particle 2 | import numpy as np 3 | 4 | assert np.allclose(wrap_particle.norm2(1, 2, 3), np.sqrt(14.0)) 5 | 6 | args = [0] * 8 7 | 8 | p = wrap_particle.Particle(*args) 9 | p1 = wrap_particle.Particle(*args) 10 | print "p.get_x():", p.get_x() 11 | 12 | class subparticle(wrap_particle.Particle): 13 | def get_x(self): 14 | return super(subparticle, self).get_x() + 10. 15 | 16 | subp = subparticle(*args) 17 | print "subparticle.get_x():", subp.get_x() 18 | 19 | print wrap_particle.rms_speeds([p, p1]) 20 | # print wrap_particle.rms_speeds([p, p1, 'foo']) 21 | -------------------------------------------------------------------------------- /demo/wrap-cpp-particle/wrap_particle.pyx: -------------------------------------------------------------------------------- 1 | from libcpp.vector cimport vector 2 | from cython.operator cimport dereference as deref 3 | 4 | cdef extern from "particle.h": 5 | 6 | const float _norm2 "norm2"(float x, float y, float z) 7 | 8 | cdef cppclass _Particle "Particle": 9 | _Particle() 10 | _Particle(float, float, float, 11 | float, float, float, 12 | float, float) 13 | const float get_speed() 14 | const float get_x() 15 | 16 | float _rms_speeds "rms_speeds"(vector[const _Particle*] *particles) 17 | 18 | def norm2(float x, float y, float z): 19 | cdef float pn = _norm2(x, y, z) 20 | return pn 21 | 22 | cdef class Particle: 23 | cdef _Particle *_thisptr 24 | def __cinit__(self, x, y, z, vx, vy, vz, mass, charge): 25 | self._thisptr = new _Particle(x, y, z, vx, vy, vz, mass, charge) 26 | cpdef float get_x(self): 27 | return self._thisptr.get_x() 28 | def __dealloc__(self): 29 | del self._thisptr 30 | 31 | cpdef float rms_speeds(particles) except *: 32 | 33 | cdef: 34 | vector[const _Particle *] vparticles 35 | _Particle *part 36 | 37 | for particle in particles: 38 | if not isinstance(particle, Particle): 39 | raise TypeError("object %r is not an instance of Particle." % particle) 40 | part = (particle)._thisptr 41 | vparticles.push_back(part) 42 | 43 | return _rms_speeds(&vparticles) 44 | 45 | if __name__ == '__main__': 46 | import numpy as np 47 | assert np.allclose(norm2(1, 2, 3), np.sqrt(14.0)) 48 | -------------------------------------------------------------------------------- /demo/wrap-cpp-particle/wrap_particle_tmpl.pyx.in: -------------------------------------------------------------------------------- 1 | cimport cython 2 | from libcpp.vector cimport vector 3 | from cython.operator cimport dereference as deref 4 | 5 | cdef extern from "particle_tmpl.h": 6 | 7 | cdef cppclass _Particle "Particle"[T]: 8 | _Particle() 9 | _Particle(T, T, T, T, T, T, T, T) 10 | const T get_speed() 11 | const T get_x() 12 | 13 | {% for floating in floatings %} 14 | const {{floating}} _norm2 "norm2"({{floating}} x, {{floating}} y, {{floating}} z) 15 | {{floating}} _rms_speeds "rms_speeds"(vector[const _Particle[{{floating}}]*] *particles) 16 | {% endfor %} 17 | 18 | # depend on type conversion rules to handle this case... 19 | def norm2(double x, double y, double z): 20 | cdef double pn = _norm2(x, y, z) 21 | return pn 22 | 23 | {% for floating in floatings %} 24 | cdef class Particle_{{floating}}: 25 | template_type = "{{floating}}" 26 | cdef _Particle[{{floating}}] *_thisptr 27 | def __cinit__(self, x, y, z, vx, vy, vz, mass, charge): 28 | self._thisptr = new _Particle[{{floating}}](x, y, z, vx, vy, vz, mass, charge) 29 | cpdef {{floating}} get_x(self): 30 | return self._thisptr.get_x() 31 | def __dealloc__(self): 32 | del self._thisptr 33 | 34 | cpdef {{floating}} rms_speeds_{{floating}}(particles) except *: 35 | 36 | cdef: 37 | vector[const _Particle[{{floating}}] *] vparticles 38 | _Particle[{{floating}}] *part 39 | 40 | for particle in particles: 41 | if not isinstance(particle, Particle_{{floating}}): 42 | raise TypeError("object %r is not an instance of Particle." % particle) 43 | part = (particle)._thisptr 44 | vparticles.push_back(part) 45 | 46 | return _rms_speeds(&vparticles) 47 | {% endfor %} 48 | 49 | def Particle(*args, dtype='f'): 50 | type_dict = { 51 | {% for floating in floatings -%} 52 | '{{floating[0]}}': Particle_{{floating}}, 53 | {% endfor -%} 54 | } 55 | return type_dict[dtype](*args) 56 | 57 | def rms_speeds(particles): 58 | type_dict = { 59 | {% for floating in floatings -%} 60 | '{{floating}}': rms_speeds_{{floating}}, 61 | {% endfor -%} 62 | } 63 | tp = particles[0].template_type 64 | return type_dict[tp](particles) 65 | -------------------------------------------------------------------------------- /demo/wrap-cpp-particle/wrap_particle_tmpl_jinja.pyx: -------------------------------------------------------------------------------- 1 | cimport cython 2 | from libcpp.vector cimport vector 3 | from cython.operator cimport dereference as deref 4 | 5 | cdef extern from "particle_tmpl.h": 6 | 7 | cdef cppclass _Particle "Particle"[T]: 8 | _Particle() 9 | _Particle(T, T, T, T, T, T, T, T) 10 | const T get_speed() 11 | const T get_x() 12 | 13 | 14 | const double _norm2 "norm2"(double x, double y, double z) 15 | double _rms_speeds "rms_speeds"(vector[const _Particle[double]*] *particles) 16 | 17 | const float _norm2 "norm2"(float x, float y, float z) 18 | float _rms_speeds "rms_speeds"(vector[const _Particle[float]*] *particles) 19 | 20 | 21 | # depend on type conversion rules to handle this case... 22 | def norm2(double x, double y, double z): 23 | cdef double pn = _norm2(x, y, z) 24 | return pn 25 | 26 | 27 | cdef class Particle_double: 28 | template_type = "double" 29 | cdef _Particle[double] *_thisptr 30 | def __cinit__(self, x, y, z, vx, vy, vz, mass, charge): 31 | self._thisptr = new _Particle[double](x, y, z, vx, vy, vz, mass, charge) 32 | cpdef double get_x(self): 33 | return self._thisptr.get_x() 34 | def __dealloc__(self): 35 | del self._thisptr 36 | 37 | cpdef double rms_speeds_double(particles) except *: 38 | 39 | cdef: 40 | vector[const _Particle[double] *] vparticles 41 | _Particle[double] *part 42 | 43 | for particle in particles: 44 | if not isinstance(particle, Particle_double): 45 | raise TypeError("object %r is not an instance of Particle." % particle) 46 | part = (particle)._thisptr 47 | vparticles.push_back(part) 48 | 49 | return _rms_speeds(&vparticles) 50 | 51 | cdef class Particle_float: 52 | template_type = "float" 53 | cdef _Particle[float] *_thisptr 54 | def __cinit__(self, x, y, z, vx, vy, vz, mass, charge): 55 | self._thisptr = new _Particle[float](x, y, z, vx, vy, vz, mass, charge) 56 | cpdef float get_x(self): 57 | return self._thisptr.get_x() 58 | def __dealloc__(self): 59 | del self._thisptr 60 | 61 | cpdef float rms_speeds_float(particles) except *: 62 | 63 | cdef: 64 | vector[const _Particle[float] *] vparticles 65 | _Particle[float] *part 66 | 67 | for particle in particles: 68 | if not isinstance(particle, Particle_float): 69 | raise TypeError("object %r is not an instance of Particle." % particle) 70 | part = (particle)._thisptr 71 | vparticles.push_back(part) 72 | 73 | return _rms_speeds(&vparticles) 74 | 75 | 76 | def Particle(*args, dtype='f'): 77 | type_dict = { 78 | 'd': Particle_double, 79 | 'f': Particle_float, 80 | } 81 | return type_dict[dtype](*args) 82 | 83 | def rms_speeds(particles): 84 | type_dict = { 85 | 'double': rms_speeds_double, 86 | 'float': rms_speeds_float, 87 | } 88 | tp = particles[0].template_type 89 | return type_dict[tp](particles) -------------------------------------------------------------------------------- /exercises/hello-world/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | python setup.py build_ext --inplace 3 | 4 | test: all 5 | python test_hello_world.py 6 | 7 | clean: 8 | rm -r build cython_hello_world.{c,so} 9 | -------------------------------------------------------------------------------- /exercises/hello-world/README.rst: -------------------------------------------------------------------------------- 1 | Hello World in Cython 2 | ===================== 3 | 4 | This is a simple get-your-feet-wet exercise in Cython. The goal is to show 5 | you different ways to run Cython code -- interactively with IPython, 6 | dynamically compiled with pyximport, and statically generated and compiled 7 | with Python's distutils module. 8 | 9 | 1. Open the ipython notebook file `cython-hello-world.ipynb`:: 10 | 11 | ipython notebook cython-hello-world.ipynb 12 | 13 | Run through and execute the cells there; if successful, you are set up to 14 | interactively use Cython from within IPython. 15 | 16 | 2. You can also type in the contents of the IPython notebook into a 17 | (non-notebook) ipython session (if the notebook is not available to you or 18 | you prefer the IPython qt console). The %%cython magic will work there as 19 | well. 20 | 21 | 3. The script `use_pyximport.py` will automatically compile the 22 | `cython_hello_world.pyx` file for you and import it, allowing you to treat 23 | a `.pyx` file as if it is a regular `.py` file. Run this script and verify 24 | that it works for you:: 25 | 26 | python use_pyximport.py 27 | 8.578156256 28 | 29 | 4. You can use Python's distutils to manually create a Cython extension 30 | module. This method gives you the most control and allows you to 31 | distribute the generated C-extension module without a Cython dependency. 32 | 33 | Mac / Linux: Run the following to compile the extension module:: 34 | 35 | python setup.py build_ext --inplace 36 | 37 | Windows: run the following, making note of the extra command:: 38 | 39 | python setup.py build_ext --inplace --compiler=mingw32 40 | 41 | If successful, you will see a new extension module in your directory. It 42 | will be named `cython_hello_world.so` on Mac or Linux, 43 | `cython_hello_world.pyd` on Windows. 44 | 45 | Run the test script to import and use your new extension module:: 46 | 47 | $ python test_hello_world.py 48 | Pure Python version: 0.293585s 49 | Cython version: 0.115184s 50 | -------------------------------------------------------------------------------- /exercises/hello-world/build.bat: -------------------------------------------------------------------------------- 1 | python setup.py build_ext --inplace --compiler=mingw32 2 | -------------------------------------------------------------------------------- /exercises/hello-world/cython-hello-world.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "cython-hello-world" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "heading", 12 | "level": 1, 13 | "metadata": {}, 14 | "source": [ 15 | "Cython \"Hello World!\"" 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "metadata": {}, 21 | "source": [ 22 | "In this notebook, we will simply verify that the IPython Cython magic commands work properly. If successful, you will be able to use Cython from within IPython and IPython notebooks.\n", 23 | "\n", 24 | "The first step is to load the `cythonmagic` extension:" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "collapsed": false, 30 | "input": [ 31 | "%load_ext cythonmagic" 32 | ], 33 | "language": "python", 34 | "metadata": {}, 35 | "outputs": [] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "If the above cell emits no error then a recent version of Cython is installed and IPython is able to find it.\n", 42 | "\n", 43 | "This next cell will determine whether we can compile Cython code on the fly:" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "collapsed": false, 49 | "input": [ 50 | "%%cython\n", 51 | "def add(int a, int b):\n", 52 | " return 3.1415926 * a + 2.718281828459045 * b" 53 | ], 54 | "language": "python", 55 | "metadata": {}, 56 | "outputs": [] 57 | }, 58 | { 59 | "cell_type": "raw", 60 | "metadata": {}, 61 | "source": [ 62 | "If the above cell emits no error, then you are able to compile and run Cython code inline.\n", 63 | "\n", 64 | "If you make a change to the above cell and re-execute, the %%cython magic function will detect the change, recompile, and import the new compiled code automatically.\n", 65 | "\n", 66 | "Let's define a pure-python version of the same function for comparison:" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "collapsed": false, 72 | "input": [ 73 | "def pyadd(a, b):\n", 74 | " return 3.1415926 * a + 2.718281828459045 * b" 75 | ], 76 | "language": "python", 77 | "metadata": {}, 78 | "outputs": [] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "Lastly, let's compare the performance difference between the two:" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "collapsed": false, 90 | "input": [ 91 | "%timeit add(1, 2)\n", 92 | "%timeit pyadd(1, 2)" 93 | ], 94 | "language": "python", 95 | "metadata": {}, 96 | "outputs": [] 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "metadata": {}, 101 | "source": [ 102 | "I see about a factor of 2 speedup for the Cython version (127 ns vs. 256 ns)." 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "collapsed": false, 108 | "input": [], 109 | "language": "python", 110 | "metadata": {}, 111 | "outputs": [] 112 | } 113 | ], 114 | "metadata": {} 115 | } 116 | ] 117 | } -------------------------------------------------------------------------------- /exercises/hello-world/cython_hello_world.pyx: -------------------------------------------------------------------------------- 1 | def add(int a, int b): 2 | return 3.1415926 * a + 2.718281828 * b 3 | -------------------------------------------------------------------------------- /exercises/hello-world/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from distutils.extension import Extension 3 | from Cython.Distutils import build_ext 4 | 5 | exts = [Extension("cython_hello_world", 6 | ["cython_hello_world.pyx"], 7 | )] 8 | 9 | setup( 10 | cmdclass = {'build_ext': build_ext}, 11 | ext_modules = exts, 12 | ) 13 | 14 | -------------------------------------------------------------------------------- /exercises/hello-world/test_hello_world.py: -------------------------------------------------------------------------------- 1 | from timeit import timeit 2 | 3 | def pyadd(a, b): 4 | return 3.1415926 * a + 2.718281828 * b 5 | 6 | print 'Pure Python version: %fs' % timeit('pyadd(1, 2)', 'from __main__ import pyadd') 7 | print 'Cython version: %fs' % timeit('add(1, 2)', 'from cython_hello_world import add') 8 | -------------------------------------------------------------------------------- /exercises/hello-world/use_pyximport.py: -------------------------------------------------------------------------------- 1 | import pyximport; pyximport.install() 2 | 3 | import cython_hello_world 4 | 5 | print cython_hello_world.add(1,2) 6 | -------------------------------------------------------------------------------- /exercises/julia/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, 2013, Enthought, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /exercises/julia/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | python setup.py build_ext --inplace 4 | 5 | clean: 6 | rm -rf build julia_cython{,_solution}.so julia_cython{,_solution}.c *.pyc 7 | -------------------------------------------------------------------------------- /exercises/julia/README.rst: -------------------------------------------------------------------------------- 1 | Julia Cython 2 | ------------ 3 | 4 | This exercise provides practice at writing a C extension module using Cython. 5 | The object of this is to take an existing Python module `julia_pure_python.py` 6 | and speed it up by re-writing it in Cython. 7 | 8 | 1. The file `julia_pure_python.py` calculates the Julia set in pure Python. 9 | To time it, run the following:: 10 | 11 | python timing.py julia_pure_python.py 12 | 13 | See `python timing.py -h` to see other arguments that the timing script 14 | accepts. 15 | 16 | 2. To bring up an interactive Julia set explorer, run the following:: 17 | 18 | python julia_ui.py julia_pure_python.py 19 | 20 | 3. The pure Python version of the code has been copied into 21 | `julia_cython.pyx`. You will be modifying this file to get better runtime 22 | performance. To get a simple timing, please run the following from the 23 | command line or Windows cmd prompt:: 24 | 25 | python timing.py julia_cython.pyx 26 | 27 | Do you notice any speedup over the pure Python version? To use the 28 | interactive GUI, run:: 29 | 30 | python julia_ui.py julia_cython.pyx 31 | 32 | 3. Add variable typing for the scalar variables in the julia_cython.pyx file. 33 | See how much of a speed-up you get. See the slide material for reference. 34 | 35 | 4. Turn the `kernel` function into a C only function. 36 | 37 | 5. Use typed memoryviews to further improve performance. 38 | 39 | Bonus 40 | ~~~~~ 41 | 42 | If you are using an OpenMP-capable compiler (e.g. gcc; unfortunately clang 43 | does not support OpenMP at this time), use cython's prange to parallelize the 44 | computation. 45 | -------------------------------------------------------------------------------- /exercises/julia/build.bat: -------------------------------------------------------------------------------- 1 | python setup.py build_ext --compiler=mingw32 --inplace 2 | -------------------------------------------------------------------------------- /exercises/julia/cython-julia-set.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "cython-julia-set" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "code", 12 | "collapsed": false, 13 | "input": [ 14 | "%load_ext cythonmagic" 15 | ], 16 | "language": "python", 17 | "metadata": {}, 18 | "outputs": [] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "collapsed": false, 23 | "input": [ 24 | "import numpy as np\n", 25 | "from time import time\n", 26 | "\n", 27 | "def kernel(z, c, lim, cutoff=1e6):\n", 28 | " ''' Computes the number, `n`, of iterations necessary such that \n", 29 | " |z_n| > `lim`, where `z_n = z_{n-1}**2 + c`.\n", 30 | " '''\n", 31 | " count = 0\n", 32 | " while abs(z) < lim and count < cutoff:\n", 33 | " z = z * z + c\n", 34 | " count += 1\n", 35 | " return count\n", 36 | "\n", 37 | "\n", 38 | "def compute_julia(c, N, bound=2, lim=1000., kernel=kernel):\n", 39 | " ''' Pure Python calculation of the Julia set for a given `c`. No NumPy\n", 40 | " array operations are used.\n", 41 | " '''\n", 42 | " julia = np.empty((N, N), dtype=np.uint32)\n", 43 | " grid_x = np.linspace(-bound, bound, N)\n", 44 | " grid_y = grid_x * 1j\n", 45 | " c = complex(c)\n", 46 | " t0 = time()\n", 47 | " for i, x in enumerate(grid_x):\n", 48 | " for j, y in enumerate(grid_y):\n", 49 | " julia[i,j] = kernel(x+y, c, lim)\n", 50 | " return julia, time() - t0" 51 | ], 52 | "language": "python", 53 | "metadata": {}, 54 | "outputs": [] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "collapsed": false, 59 | "input": [ 60 | "import pylab as pl\n", 61 | "\n", 62 | "def plot_julia(kwargs, compute_julia):\n", 63 | " ''' Given parameters dict in `kwargs` and a function to compute the Julia\n", 64 | " set (`compute_julia`), plots the resulting Julia set with appropriately\n", 65 | " labeled axes.\n", 66 | " '''\n", 67 | " kwargs = kwargs.copy()\n", 68 | "\n", 69 | " def _plotter(kwargs):\n", 70 | " bound = kwargs['bound']\n", 71 | " julia, time = compute_julia(**kwargs)\n", 72 | " print \"execution time (s):\", time\n", 73 | " julia = np.log(julia)\n", 74 | " pl.imshow(julia, \n", 75 | " interpolation='nearest',\n", 76 | " extent=(-bound, bound)*2)\n", 77 | " pl.colorbar()\n", 78 | " title = r\"Julia set for $C={0.real:5.3f}+{0.imag:5.3f}i$ $[{1}\\times{1}]$\"\n", 79 | " pl.title(title.format(kwargs['c'], kwargs['N']))\n", 80 | " pl.xlabel(\"$Re(z)$\")\n", 81 | " pl.ylabel(\"$Im(z)$\")\n", 82 | "\n", 83 | " pl.figure(figsize=(14, 12))\n", 84 | "\n", 85 | " cvals = [0.285+0.01j, -0.1+0.651j, -0.4+0.6j, -0.8+0.156j]\n", 86 | " subplots = ['221', '222', '223', '224' ]\n", 87 | "\n", 88 | " for c, sp in zip(cvals, subplots):\n", 89 | " kwargs.update(c=c)\n", 90 | " pl.subplot(sp)\n", 91 | " _plotter(kwargs)\n", 92 | "\n", 93 | " pl.show()" 94 | ], 95 | "language": "python", 96 | "metadata": {}, 97 | "outputs": [] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "collapsed": false, 102 | "input": [ 103 | "kwargs = dict(N=100, bound=1.5)\n", 104 | "plot_julia(kwargs, compute_julia)" 105 | ], 106 | "language": "python", 107 | "metadata": {}, 108 | "outputs": [] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "collapsed": false, 113 | "input": [ 114 | "%%cython\n", 115 | "\n", 116 | "from time import time\n", 117 | "\n", 118 | "import numpy as np\n", 119 | "cimport cython\n", 120 | "cimport numpy as cnp\n", 121 | "\n", 122 | "ctypedef double complex cpx_t\n", 123 | "ctypedef double real_t\n", 124 | "\n", 125 | "cdef inline real_t cabs_sq(cpx_t z) nogil:\n", 126 | " ''' Helper inline function, computes the square of the abs. value of the\n", 127 | " complex number `z`.\n", 128 | " '''\n", 129 | " return z.real * z.real + z.imag * z.imag\n", 130 | " \n", 131 | "cpdef unsigned int kernel(cpx_t z, \n", 132 | " cpx_t c,\n", 133 | " real_t lim,\n", 134 | " real_t cutoff=1e6) nogil:\n", 135 | " ''' Cython implementation of the kernel computation.\n", 136 | "\n", 137 | " This is implemented so that no C-API calls are made inside the function\n", 138 | " body. Even still, there is some overhead as compared with a pure C\n", 139 | " implementation.\n", 140 | " '''\n", 141 | " cdef unsigned int count = 0\n", 142 | " cdef real_t lim_sq = lim * lim\n", 143 | " while cabs_sq(z) < lim_sq and count < cutoff:\n", 144 | " z = z * z + c\n", 145 | " count += 1\n", 146 | " return count\n", 147 | "\n", 148 | "@cython.boundscheck(False)\n", 149 | "@cython.wraparound(False)\n", 150 | "def compute_julia_opt(cpx_t c,\n", 151 | " unsigned int N,\n", 152 | " real_t bound=1.5,\n", 153 | " real_t lim=1000.):\n", 154 | " '''\n", 155 | " Cython `compute_julia()` implementation with Numpy array buffer\n", 156 | " declarations and appropriate compiler directives. The body of this\n", 157 | " function is nearly identical to the `compute_julia_no_opt()` function.\n", 158 | "\n", 159 | " '''\n", 160 | "\n", 161 | " cdef cnp.ndarray[cnp.uint32_t, ndim=2, mode='c'] julia \n", 162 | " cdef cnp.ndarray[real_t, ndim=1, mode='c'] grid\n", 163 | " cdef unsigned int i, j\n", 164 | " cdef real_t x, y\n", 165 | "\n", 166 | " julia = np.empty((N, N), dtype=np.uint32)\n", 167 | " grid = np.linspace(-bound, bound, N)\n", 168 | " t0 = time()\n", 169 | " for i in range(N):\n", 170 | " x = grid[i]\n", 171 | " for j in range(N):\n", 172 | " y = grid[j]\n", 173 | " julia[i,j] = kernel(x+y*1j, c, lim)\n", 174 | " return julia, time() - t0" 175 | ], 176 | "language": "python", 177 | "metadata": {}, 178 | "outputs": [] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "collapsed": false, 183 | "input": [ 184 | "kwargs = dict(N=1000, bound=1.5)\n", 185 | "plot_julia(kwargs, compute_julia_opt)" 186 | ], 187 | "language": "python", 188 | "metadata": {}, 189 | "outputs": [] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "collapsed": false, 194 | "input": [], 195 | "language": "python", 196 | "metadata": {}, 197 | "outputs": [] 198 | } 199 | ], 200 | "metadata": {} 201 | } 202 | ] 203 | } -------------------------------------------------------------------------------- /exercises/julia/julia.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Copyright (c) 2012, Enthought, Inc. 3 | # All rights reserved. See LICENSE.txt for details. 4 | # 5 | # Author: Kurt W. Smith 6 | # Date: 26 March 2012 7 | #----------------------------------------------------------------------------- 8 | 9 | ''' 10 | julia.py 11 | 12 | Compute and plot the Julia set. 13 | 14 | This provides a self-contained---if somewhat contrived---example for comparing 15 | the runtimes between pure Python, Numpy, Cython, and Cython-wrapped C versions 16 | of the julia set calculation. 17 | 18 | It is meant to be run from the command line; run 19 | 20 | $ python julia.py -h 21 | 22 | for details. 23 | 24 | ''' 25 | 26 | # --- Python / Numpy imports ------------------------------------------------- 27 | import numpy as np 28 | import pylab as pl 29 | 30 | # --- Import the various julia set computation modules ----------------------- 31 | import julia_pure_python 32 | import julia_cython_solution as julia_cython 33 | # import julia_cython 34 | import julia_python_numpy_solution as julia_python_numpy 35 | import julia_multiprocessing_solution as julia_multiprocessing 36 | 37 | def printer(label, runtime, speedup): 38 | ''' Given a label, the total runtime in seconds, and a speedup value, 39 | prints things nicely to stdout. 40 | ''' 41 | from sys import stdout 42 | print "{}:".format(label.strip()) 43 | fs = " {:.<15s} {: >6.2g}" 44 | print fs.format("runtime (s)", runtime) 45 | print fs.format("speedup", speedup) 46 | print 47 | stdout.flush() 48 | 49 | # some good c values: 50 | # (-0.1 + 0.651j) 51 | # (-0.4 + 0.6j) 52 | # (0.285 + 0.01j) 53 | 54 | def plot_julia(kwargs, compute_julia): 55 | ''' Given parameters dict in `kwargs` and a function to compute the Julia 56 | set (`compute_julia`), plots the resulting Julia set with appropriately 57 | labeled axes. 58 | ''' 59 | kwargs = kwargs.copy() 60 | 61 | def _plotter(kwargs): 62 | bound = kwargs['bound'] 63 | julia, _ = compute_julia(**kwargs) 64 | julia = np.log(julia) 65 | pl.imshow(julia, 66 | interpolation='nearest', 67 | extent=(-bound, bound)*2) 68 | pl.colorbar() 69 | title = r"Julia set for $C={0.real:5.3f}+{0.imag:5.3f}i$ $[{1}\times{1}]$" 70 | pl.title(title.format(kwargs['c'], kwargs['N'])) 71 | pl.xlabel("$Re(z)$") 72 | pl.ylabel("$Im(z)$") 73 | 74 | pl.figure(figsize=(14, 12)) 75 | 76 | cvals = [0.285+0.01j, -0.1+0.651j, -0.4+0.6j, -0.8+0.156j] 77 | subplots = ['221', '222', '223', '224' ] 78 | 79 | for c, sp in zip(cvals, subplots): 80 | kwargs.update(c=c) 81 | pl.subplot(sp) 82 | _plotter(kwargs) 83 | 84 | pl.show() 85 | 86 | def compare_runtimes(kwargs): 87 | ''' Given a parameter dict `kwargs`, runs different implementations of the 88 | Julia set computation and compares the runtimes of each. 89 | ''' 90 | 91 | ref_julia, python_time = julia_pure_python.compute_julia(**kwargs) 92 | printer("Python only", python_time, 1.0) 93 | 94 | _, numpy_time = julia_python_numpy.compute_julia(**kwargs) 95 | assert np.allclose(ref_julia, _) 96 | printer("Python only + Numpy expressions", numpy_time, 97 | python_time / numpy_time) 98 | 99 | _, cython_kernel_time = julia_pure_python.compute_julia( 100 | kernel=julia_cython.kernel, **kwargs) 101 | assert np.allclose(ref_julia, _) 102 | printer("Python + cythonized kernel", cython_kernel_time, 103 | python_time / cython_kernel_time) 104 | 105 | _, mp_time = julia_multiprocessing.compute_julia_block(kernel=julia_pure_python.kernel, **kwargs) 106 | assert np.allclose(ref_julia, _) 107 | printer("Multiprocessing + Python kernel", mp_time, python_time / mp_time) 108 | 109 | _, mp_time = julia_multiprocessing.compute_julia_block(kernel=julia_cython.kernel, **kwargs) 110 | assert np.allclose(ref_julia, _) 111 | printer("Multiprocessing + cythonized kernel", mp_time, python_time / mp_time) 112 | 113 | _, cython_no_opt_time = julia_cython.compute_julia_no_opt(**kwargs) 114 | assert np.allclose(ref_julia, _) 115 | printer("All Cython, no optimizations", cython_no_opt_time, 116 | python_time / cython_no_opt_time) 117 | 118 | _, cython_opt_time = julia_cython.compute_julia_opt(**kwargs) 119 | assert np.allclose(ref_julia, _) 120 | printer("All Cython, Numpy optimizations", cython_opt_time, 121 | python_time / cython_opt_time) 122 | 123 | _, ext_opt_time = julia_cython.compute_julia_ext(**kwargs) 124 | assert np.allclose(ref_julia, _) 125 | printer("All C version, wrapped with Cython", ext_opt_time, 126 | python_time / ext_opt_time) 127 | 128 | def main(args): 129 | ''' The main entry point; branches on whether `args.action` is "plot" or 130 | "compare". 131 | ''' 132 | bound = 1.5 133 | kwargs = dict(c=(0.285 + 0.01j), 134 | N=args.N, 135 | bound=bound) 136 | 137 | if args.action == 'plot': 138 | plot_julia(kwargs, julia_cython.compute_julia_ext) 139 | elif args.action == 'compare': 140 | compare_runtimes(kwargs) 141 | 142 | description = """ Explore the performance characteristics of Cython and Numpy 143 | when computing the Julia set.""" 144 | 145 | help_arg_n = """ The number of grid points in each dimension; larger for more 146 | resolution. (default 100)) """ 147 | 148 | help_arg_a = """ Either *plot* an approximation of a Julia set with resolution 149 | N (default), or *compare* the runtimes for different implementations.) """ 150 | 151 | if __name__ == '__main__': 152 | from argparse import ArgumentParser 153 | 154 | parser = ArgumentParser(description=description) 155 | 156 | parser.add_argument('-N', type=int, default=200, help=help_arg_n) 157 | parser.add_argument('-a', '--action', type=str, 158 | default='plot', 159 | choices=('plot', 'compare'), 160 | help=help_arg_a) 161 | 162 | args = parser.parse_args() 163 | main(args) 164 | -------------------------------------------------------------------------------- /exercises/julia/julia_cython.pyx: -------------------------------------------------------------------------------- 1 | # --- Python std lib imports ------------------------------------------------- 2 | from time import time 3 | import numpy as np 4 | 5 | cdef float abs_sq(float zr, float zi): 6 | return zr * zr + zi * zi 7 | 8 | cdef int kernel(float zr, float zi, float cr, float ci, float lim, double cutoff): 9 | cdef: 10 | int count = 0 11 | float lim_sq = lim * lim 12 | while abs_sq(zr, zi) < lim_sq and count < cutoff: 13 | zr, zi = zr * zr - zi * zi + cr, 2 * zr * zi + ci 14 | count += 1 15 | return count 16 | 17 | def compute_julia(float cr, float ci, int N, float bound=1.5, float lim=1000., double cutoff=1e6): 18 | cdef: 19 | int i, j 20 | float x, y 21 | unsigned int[:,::1] julia 22 | float[::1] grid 23 | julia = np.empty((N, N), dtype=np.uint32) 24 | grid = np.array(np.linspace(-bound, bound, N), dtype=np.float32) 25 | t0 = time() 26 | for i in range(N): 27 | x = grid[i] 28 | for j in range(N): 29 | y = grid[j] 30 | julia[i,j] = kernel(x, y, cr, ci, lim, cutoff) 31 | return julia, time() - t0 32 | -------------------------------------------------------------------------------- /exercises/julia/julia_cython_solution.pyx: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Copyright (c) 2012, 2013, Enthought, Inc. 3 | # All rights reserved. Distributed under the terms of the 2-clause BSD 4 | # licence. See LICENSE.txt for details. 5 | # 6 | # Author: Kurt W. Smith 7 | # Date: 26 March 2012 8 | #----------------------------------------------------------------------------- 9 | 10 | # --- Python std lib imports ------------------------------------------------- 11 | from time import time 12 | import numpy as np 13 | 14 | # --- Cython cimports -------------------------------------------------------- 15 | cimport cython 16 | from libc.stdint cimport uint32_t, int32_t 17 | from cython.parallel cimport prange 18 | 19 | # --- Ctypedefs -------------------------------------------------------- 20 | ctypedef float real_t 21 | ctypedef uint32_t uint_t 22 | ctypedef int32_t int_t 23 | 24 | #----------------------------------------------------------------------------- 25 | # Cython functions 26 | #----------------------------------------------------------------------------- 27 | cdef real_t abs_sq(real_t zr, real_t zi) nogil: 28 | return zr * zr + zi * zi 29 | 30 | cdef uint_t kernel(real_t zr, real_t zi, 31 | real_t cr, real_t ci, 32 | real_t lim, real_t cutoff) nogil: 33 | cdef: 34 | uint_t count = 0 35 | real_t lim_sq = lim * lim 36 | 37 | while abs_sq(zr, zi) < lim_sq and count < cutoff: 38 | zr, zi = zr * zr - zi * zi + cr, 2 * zr * zi + ci 39 | count += 1 40 | return count 41 | 42 | @cython.boundscheck(False) 43 | @cython.wraparound(False) 44 | def compute_julia(real_t cr, real_t ci, 45 | uint32_t N, real_t bound=1.5, 46 | real_t lim=1000., real_t cutoff=1e6): 47 | cdef: 48 | uint_t[:,::1] julia 49 | real_t[::1] grid 50 | int i, j 51 | real_t x, y 52 | 53 | julia = np.empty((N, N), dtype=np.uint32) 54 | grid = np.asarray(np.linspace(-bound, bound, N), dtype=np.float32) 55 | t0 = time() 56 | for i in range(N): 57 | x = grid[i] 58 | for j in range(N): 59 | y = grid[j] 60 | julia[i,j] = kernel(x, y, cr, ci, lim, cutoff) 61 | return julia, time() - t0 62 | 63 | @cython.boundscheck(False) 64 | @cython.wraparound(False) 65 | def compute_julia_parallel(real_t cr, real_t ci, 66 | uint_t N, real_t bound=1.5, 67 | real_t lim=1000., real_t cutoff=1e6): 68 | cdef: 69 | uint_t[:,::1] julia 70 | real_t[::1] grid 71 | int_t i, j 72 | real_t x 73 | 74 | julia = np.empty((N, N), dtype=np.uint32) 75 | grid = np.asarray(np.linspace(-bound, bound, N), dtype=np.float32) 76 | t0 = time() 77 | for i in prange(N, nogil=True): 78 | x = grid[i] 79 | for j in range(N): 80 | julia[i,j] = kernel(x, grid[j], cr, ci, lim, cutoff) 81 | return julia, time() - t0 82 | -------------------------------------------------------------------------------- /exercises/julia/julia_numpy.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Copyright (c) 2012, Enthought, Inc. 3 | # All rights reserved. See LICENSE.txt for details. 4 | # 5 | # Author: Kurt W. Smith 6 | # Date: 26 March 2012 7 | #----------------------------------------------------------------------------- 8 | 9 | from time import time 10 | import numpy as np 11 | 12 | def compute_julia(cr, ci, N, bound=1.5, lim=4., cutoff=1e6): 13 | ''' Pure Python calculation of the Julia set for a given `c` using NumPy 14 | array operations. 15 | ''' 16 | c = cr + 1j * ci 17 | orig_err = np.seterr() 18 | np.seterr(over='ignore', invalid='ignore') 19 | julia = np.zeros((N, N), dtype=np.uint32) 20 | X, Y = np.ogrid[-bound:bound:N*1j, -bound:bound:N*1j] 21 | iterations = X + Y * 1j 22 | count = 1 23 | t0 = time() 24 | while not np.all(julia) and count < cutoff: 25 | mask = np.logical_not(julia) & (np.abs(iterations) >= lim) 26 | julia[mask] = count 27 | count += 1 28 | iterations = iterations**2 + c 29 | if count == cutoff: 30 | julia[np.logical_not(julia)] = count 31 | np.seterr(**orig_err) 32 | return julia, time() - t0 33 | -------------------------------------------------------------------------------- /exercises/julia/julia_pure_python.py: -------------------------------------------------------------------------------- 1 | # --- Python / Numpy imports ------------------------------------------------- 2 | import numpy as np 3 | from time import time 4 | 5 | def kernel(zr, zi, cr, ci, lim, cutoff): 6 | ''' Computes the number of iterations `n` such that 7 | |z_n| > `lim`, where `z_n = z_{n-1}**2 + c`. 8 | ''' 9 | count = 0 10 | while ((zr*zr + zi*zi) < (lim*lim)) and count < cutoff: 11 | zr, zi = zr * zr - zi * zi + cr, 2 * zr * zi + ci 12 | count += 1 13 | return count 14 | 15 | def compute_julia(cr, ci, N, bound=1.5, lim=1000., cutoff=1e6): 16 | ''' Pure Python calculation of the Julia set for a given `c`. No NumPy 17 | array operations are used. 18 | ''' 19 | julia = np.empty((N, N), dtype=np.uint32) 20 | grid_x = np.linspace(-bound, bound, N) 21 | t0 = time() 22 | for i, x in enumerate(grid_x): 23 | for j, y in enumerate(grid_x): 24 | julia[i,j] = kernel(x, y, cr, ci, lim, cutoff=cutoff) 25 | return julia, time() - t0 26 | -------------------------------------------------------------------------------- /exercises/julia/julia_ui.py: -------------------------------------------------------------------------------- 1 | # --- Imports ---------------------------------------------------------------- 2 | import numpy as np 3 | 4 | from traits.api import (HasTraits, Float, Instance, Array, on_trait_change, 5 | Property, Int, Enum, Callable) 6 | from traitsui.api import View, Item, RangeEditor, Controller, HGroup, Group 7 | from chaco import default_colormaps 8 | from chaco.api import Plot, ArrayPlotData, hot 9 | from enable.api import ComponentEditor 10 | import utils 11 | 12 | # --- Traits classes. -------------------------------------------------------- 13 | 14 | class Julia(HasTraits): 15 | 16 | resolution = Int(100) 17 | cr = Float(-0.1) 18 | ci = Float(0.651) 19 | cutoff = Int(100) 20 | runtime = Float() 21 | julia = Array() 22 | compute_julia = Callable() 23 | 24 | @on_trait_change('cr, ci, resolution, cutoff') 25 | def update_julia(self): 26 | self.julia = self.compute() 27 | 28 | def _julia_default(self): 29 | return self.compute() 30 | 31 | def compute(self): 32 | julia, self.runtime = self.compute_julia(self.cr, self.ci, 33 | self.resolution, 34 | lim=4., cutoff=self.cutoff) 35 | return np.log(julia) 36 | 37 | # --- Set up the colormaps to use -------------------------------------------- 38 | def colormaps(): 39 | cmnames = default_colormaps.color_map_name_dict.keys() 40 | colormaps = sorted(cmnames, key=str.lower) 41 | for boring in 'hot bone gray yarg gist_gray gist_yarg Greys'.split(): 42 | colormaps.remove(boring) 43 | # Make 'hot' the first colormap. 44 | return ['hot'] + colormaps 45 | 46 | class JuliaUI(Controller): 47 | 48 | model = Instance(Julia) 49 | runtime = Property(depends_on=['model.runtime']) 50 | plot = Instance(Plot) 51 | colormap = Enum(colormaps()) 52 | 53 | traits_view = View(Item('controller.plot', editor=ComponentEditor(), show_label=False), 54 | Group( 55 | Item('cr', editor=RangeEditor(low=-2.0, high=2.0, low_label='-2', high_label='2'), show_label=False), 56 | Item('ci', editor=RangeEditor(low=-2.0, high=2.0, low_label='-2', high_label='2'), show_label=False), 57 | label='c_real / c_imaginary', show_border=True, 58 | ), 59 | HGroup( 60 | Item('resolution', editor=RangeEditor(low=50, high=1000, mode='slider')), 61 | Item('cutoff', editor=RangeEditor(low=100, high=300, mode='slider')), 62 | Item('controller.colormap'), 63 | ), 64 | Item('controller.runtime', style='readonly', show_label=False), 65 | width=800, height=900, resizable=True, 66 | title="Julia Set Explorer") 67 | 68 | @on_trait_change('model.runtime') 69 | def _get_runtime(self): 70 | return "Compute time: {:d} ms".format(int(round(self.model.runtime * 1000))) 71 | 72 | @on_trait_change('model.julia') 73 | def update_julia(self): 74 | self.plot.data.set_data('julia', self.model.julia) 75 | 76 | def _plot_default(self): 77 | julia = self.model.julia 78 | apd = ArrayPlotData(julia=julia[:-1,:-1]) 79 | grid = np.linspace(-2, 2, self.model.resolution-1) 80 | X, Y = np.meshgrid(grid, grid) 81 | plot = Plot(apd) 82 | plot.aspect_ratio = 1.0 83 | plot.img_plot("julia", xbounds=X, ybounds=Y, 84 | colormap=hot, interpolation='nearest') 85 | return plot 86 | 87 | def _colormap_changed(self): 88 | cmap = default_colormaps.color_map_name_dict[self.colormap] 89 | if self.plot is not None: 90 | value_range = self.plot.color_mapper.range 91 | self.plot.color_mapper = cmap(value_range) 92 | self.plot.request_redraw() 93 | 94 | 95 | # --- main entry point ------------------------------------------------------- 96 | 97 | def main(args): 98 | suffix = args.module.rsplit('.', 1)[-1] 99 | if suffix in ('so', 'pyd', 'pyx'): 100 | utils.compiler(args.setup) 101 | compute_julia = utils.importer(args.module, args.function) 102 | julia = Julia(compute_julia=compute_julia) 103 | jui = JuliaUI(model=julia) 104 | jui.configure_traits() 105 | 106 | if __name__ == '__main__': 107 | from argparse import ArgumentParser 108 | parser = ArgumentParser() 109 | parser.add_argument('module') 110 | parser.add_argument('-f', '--function', default='compute_julia') 111 | parser.add_argument('--setup', default='setup.py') 112 | main(parser.parse_args()) 113 | -------------------------------------------------------------------------------- /exercises/julia/setup.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Copyright (c) 2012, Enthought, Inc. 3 | # All rights reserved. See LICENSE.txt for details. 4 | # 5 | # Author: Kurt W. Smith 6 | # Date: 26 March 2012 7 | #----------------------------------------------------------------------------- 8 | 9 | from distutils.core import setup 10 | from distutils.extension import Extension 11 | from Cython.Distutils import build_ext 12 | 13 | extra_args = [] 14 | # Comment/Uncomment the following line to disable/enable OpenMP for GCC-ish 15 | # compilers. 16 | # extra_args = ["-fopenmp"] 17 | 18 | exts = [Extension("julia_cython", 19 | ["julia_cython.pyx"], 20 | extra_compile_args=extra_args, 21 | extra_link_args=extra_args), 22 | Extension("julia_cython_solution", 23 | ["julia_cython_solution.pyx"], 24 | extra_compile_args=extra_args, 25 | extra_link_args=extra_args), 26 | ] 27 | 28 | setup( 29 | cmdclass = {'build_ext': build_ext}, 30 | ext_modules = exts, 31 | ) 32 | -------------------------------------------------------------------------------- /exercises/julia/timing.py: -------------------------------------------------------------------------------- 1 | import utils 2 | import pylab as pl 3 | import numpy as np 4 | 5 | def main(args): 6 | suffix = args.module.rsplit('.', 1)[-1] 7 | if suffix in ('so', 'pyd', 'pyx'): 8 | utils.compiler(args.setup) 9 | compute_julia = utils.importer(args.module, args.function) 10 | jla, time = compute_julia(args.cr, args.ci, args.N, 2.0, 4., args.cutoff) 11 | print "Compute time: %fs" % time 12 | pl.imshow(np.log(jla), cmap=pl.cm.hot) 13 | pl.show() 14 | 15 | if __name__ == '__main__': 16 | from argparse import ArgumentParser 17 | parser = ArgumentParser() 18 | parser.add_argument('module', help="""The module to use -- either a pure 19 | python module or a Cython .pyx file. If given a .pyx file, it will 20 | be compiled automatically.""") 21 | parser.add_argument('-f', '--function', default='compute_julia', help="The function from the module to call, default `compute_julia`") 22 | parser.add_argument('--setup', default='setup.py') 23 | parser.add_argument('-cr', default=-0.1, help='The real component of the C parameter.') 24 | parser.add_argument('-ci', default=0.651, help='The imaginary component of the C parameter.') 25 | parser.add_argument('-N', default=200, help='The number of grid points to use.') 26 | parser.add_argument('--cutoff', default=10**3, help='The cutoff value, controls the image detail.') 27 | main(parser.parse_args()) 28 | -------------------------------------------------------------------------------- /exercises/julia/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from subprocess import check_call 3 | import sys, platform 4 | 5 | def compiler(setup_name): 6 | # the Python binary full path. 7 | exe = sys.executable 8 | 9 | # figure out what platform we're on and adjust the commandline flags accordingly. 10 | extras = [] 11 | if platform.system() == 'Windows': 12 | extras = ['--compiler=mingw32'] 13 | 14 | # The distutils command to execute 15 | cmd = [exe, setup_name, 'build_ext', '--inplace'] + extras 16 | print(cmd) 17 | 18 | # runs the command and raises an exception on failure. 19 | check_call(cmd) 20 | 21 | def importer(module_name, function_name): 22 | 23 | # Remove any common ending, both for pure python and extension modules. 24 | for ending in ('.py', '.pyc', '.so', '.pyd'): 25 | module_name = module_name.rsplit(ending)[0] 26 | 27 | mod = __import__(module_name) 28 | 29 | # import the required function, re-raising an ImportError on failure. 30 | try: 31 | return getattr(mod, function_name) 32 | except AttributeError: 33 | raise ImportError("cannot import name %s" % function_name) 34 | -------------------------------------------------------------------------------- /exercises/sinc/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | python setup.py build_ext --inplace 3 | 4 | clean: 5 | rm -r build sinc_kernel.{c,so} sinc_solution.{c,so} *.pyc __pycache__ 6 | -------------------------------------------------------------------------------- /exercises/sinc/README.rst: -------------------------------------------------------------------------------- 1 | Vectorized Sinc with Cython 2 | =========================== 3 | 4 | The goal of this exercise is to add type information to a `def` function to 5 | speed it up with Cython. 6 | 7 | The file `sinc_python.py` defines a simple function `sinc_kernel` that is 8 | designed to be vectorized with numpy's `vectorize` decorator. NumPy's 9 | `vectorize` calls `sinc_kernel` on every element of the input array and 10 | returns a new array of the results. Since `sinc_python.sinc_kernel` is pure 11 | Python, this will be slow. We will be creating a Cython version of the same 12 | kernel function to speed it up. 13 | 14 | 1. Run the `test_sinc.py` script which uses pyximport to compile and import 15 | the Cython source files for this exercise:: 16 | 17 | $ python test_sinc.py 18 | Python time: 0.0476980209351 19 | Cython time: 0.0311279296875 20 | Solution time: 0.0171620845795 21 | 22 | 2. The `sinc_kernel.pyx` file contains an un-optimized version of the sinc 23 | kernel function. Add type information so the `sinc_kernel` function takes 24 | a double and returns a double as a result. Re-run the test script and see 25 | if there is any difference in the "Cython time". 26 | 27 | 3. The `sinc_kernel` function is calling the `sin()` function from Python's 28 | math library, which incurrs Python overhead for every call. Change the 29 | `from math import sin` to `from libc.math cimport sin` to use the `sin()` 30 | function from `math.h` directly. Run the test and see if the "Cython time" 31 | improves. 32 | -------------------------------------------------------------------------------- /exercises/sinc/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from distutils.extension import Extension 3 | from Cython.Distutils import build_ext 4 | 5 | exts = [ 6 | Extension("sinc_kernel", ["sinc_kernel.pyx"]), 7 | Extension("sinc_solution", ["sinc_solution.pyx"]), 8 | ] 9 | 10 | setup( 11 | cmdclass = {'build_ext': build_ext}, 12 | ext_modules = exts, 13 | ) 14 | -------------------------------------------------------------------------------- /exercises/sinc/sinc_kernel.pyx: -------------------------------------------------------------------------------- 1 | from libc.math cimport sin 2 | 3 | cdef double sinc_kernel(double x): 4 | ''' 5 | sinc_kernel(x) -> sin(x) / x 6 | ... 7 | ''' 8 | cdef double out 9 | if -0.01 < x < 0.01: 10 | out = 1.0 11 | else: 12 | out = sin(x) / x 13 | return out 14 | -------------------------------------------------------------------------------- /exercises/sinc/sinc_python.py: -------------------------------------------------------------------------------- 1 | from math import sin 2 | 3 | def sinc_kernel(x): 4 | if -0.01 < x < 0.01: 5 | return 1.0 6 | return sin(x) / x 7 | -------------------------------------------------------------------------------- /exercises/sinc/sinc_solution.pyx: -------------------------------------------------------------------------------- 1 | from libc.math cimport sin 2 | 3 | cpdef double sinc_kernel(double x): 4 | if -0.01 < x < 0.01: 5 | return 1.0 6 | return sin(x) / x 7 | -------------------------------------------------------------------------------- /exercises/sinc/test_sinc.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import timeit 3 | import pyximport 4 | import sys 5 | 6 | setup_args = {} 7 | if sys.platform == 'win32': 8 | setup_args={'options': {'build_ext': {'compiler': 'mingw32'}}} 9 | pyximport.install(setup_args=setup_args) 10 | 11 | import sinc_python 12 | import sinc_kernel 13 | import sinc_solution 14 | 15 | sinc_py = np.vectorize(sinc_python.sinc_kernel) 16 | sinc_cy = np.vectorize(sinc_kernel.sinc_kernel) 17 | sinc_cy_soln = np.vectorize(sinc_solution.sinc_kernel) 18 | 19 | x = np.linspace(-5*np.pi, 5*np.pi, 1000) 20 | 21 | print "Python time:", timeit.timeit('sinc_py(x)', 'from __main__ import sinc_py,x', number=100) 22 | print "Cython time:", timeit.timeit('sinc_cy(x)', 'from __main__ import sinc_cy,x', number=100) 23 | print "Solution time:", timeit.timeit('sinc_cy_soln(x)', 'from __main__ import sinc_cy_soln,x', number=100) 24 | -------------------------------------------------------------------------------- /test_cython/test-cython.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "test-cython" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "code", 12 | "collapsed": false, 13 | "input": [ 14 | "%load_ext cythonmagic" 15 | ], 16 | "language": "python", 17 | "metadata": {}, 18 | "outputs": [] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "collapsed": false, 23 | "input": [ 24 | "%%cython\n", 25 | "def testcython(int n):\n", 26 | " return 3.1415**n" 27 | ], 28 | "language": "python", 29 | "metadata": {}, 30 | "outputs": [] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "collapsed": false, 35 | "input": [ 36 | "print testcython(10)" 37 | ], 38 | "language": "python", 39 | "metadata": {}, 40 | "outputs": [] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "collapsed": false, 45 | "input": [ 46 | "%%cython\n", 47 | "from libc.string cimport strlen\n", 48 | "\n", 49 | "def get_len(char *msg):\n", 50 | " return strlen(msg)" 51 | ], 52 | "language": "python", 53 | "metadata": {}, 54 | "outputs": [] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "collapsed": false, 59 | "input": [ 60 | "get_len(\"asdfasfd\\0asdfasfd\")" 61 | ], 62 | "language": "python", 63 | "metadata": {}, 64 | "outputs": [] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "collapsed": false, 69 | "input": [ 70 | "%%cython\n", 71 | "import numpy as np\n", 72 | "def testmemview(double[:,::1] mv):\n", 73 | " ''' Tests roundtrip: python object -> cython typed memoryview -> python object '''\n", 74 | " print np.sum(mv)" 75 | ], 76 | "language": "python", 77 | "metadata": {}, 78 | "outputs": [] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "collapsed": false, 83 | "input": [ 84 | "from numpy import ones\n", 85 | "testmemview(ones((10, 10)))" 86 | ], 87 | "language": "python", 88 | "metadata": {}, 89 | "outputs": [] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "collapsed": false, 94 | "input": [], 95 | "language": "python", 96 | "metadata": {}, 97 | "outputs": [] 98 | } 99 | ], 100 | "metadata": {} 101 | } 102 | ] 103 | } -------------------------------------------------------------------------------- /test_cython/test_cython.pyx: -------------------------------------------------------------------------------- 1 | def testcython(int n): 2 | return 3.1415**n 3 | 4 | print testcython(10) 5 | 6 | from libc.string cimport strlen 7 | 8 | def get_len(char *msg): 9 | return strlen(msg) 10 | 11 | print get_len("asdfasfd\0asdfasfd") 12 | 13 | import numpy as np 14 | 15 | def testmemview(double[:,::1] mv): 16 | ''' Tests roundtrip: python object -> cython typed memoryview -> python object ''' 17 | print np.sum(mv) 18 | 19 | from numpy import ones 20 | testmemview(ones((10, 10))) 21 | -------------------------------------------------------------------------------- /test_cython/test_pyximport.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pyximport 3 | pyximport.install(setup_args=dict(script_args=['--compiler=mingw32'] if sys.platform == 'win32' else [])) 4 | 5 | import test_cython 6 | --------------------------------------------------------------------------------