{ "metadata": { "name": "Cython Magics" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Cython Magic Functions" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Loading the extension" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "IPtyhon has a `cythonmagic` extension that contains a number of magic functions for working with Cython code. This extension can be loaded using the `%load_ext` magic as follows:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%load_ext cythonmagic" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "The %cython_inline magic" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `%%cython_inline` magic uses `Cython.inline` to compile a Cython expression. This allows you to enter and run a function body with Cython code. Use a bare `return` statement to return values. " ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = 10\n", "b = 20" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "%%cython_inline\n", "return a+b" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 3, "text": [ "30" ] } ], "prompt_number": 3 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "The %cython_pyximport magic" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `%%cython_pyximport` magic allows you to enter arbitrary Cython code into a cell. That Cython code is written as a `.pyx` file in the current working directory and then imported using `pyximport`. You have the specify the name of the module that the Code will appear in. All symbols from the module are imported automatically by the magic function." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%cython_pyximport foo\n", "def f(x):\n", " return 4.0*x" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "f(10)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 5, "text": [ "40.0" ] } ], "prompt_number": 5 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "The %cython magic" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Probably the most important magic is the `%cython` magic. This is similar to the `%%cython_pyximport` magic, but doesn't require you to specify a module name. Instead, the `%%cython` magic uses manages everything using temporary files in the `~/.cython/magic` directory. All of the symbols in the Cython module are imported automatically by the magic.\n", "\n", "Here is a simple example of a Black-Scholes options pricing algorithm written in Cython. Please note that this example might not compile on non-POSIX systems (e.g., Windows) because of a missing `erf` symbol." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%cython\n", "cimport cython\n", "from libc.math cimport exp, sqrt, pow, log, erf\n", "\n", "@cython.cdivision(True)\n", "cdef double std_norm_cdf(double x) nogil:\n", " return 0.5*(1+erf(x/sqrt(2.0)))\n", "\n", "@cython.cdivision(True)\n", "def black_scholes(double s, double k, double t, double v,\n", " double rf, double div, double cp):\n", " \"\"\"Price an option using the Black-Scholes model.\n", " \n", " s : initial stock price\n", " k : strike price\n", " t : expiration time\n", " v : volatility\n", " rf : risk-free rate\n", " div : dividend\n", " cp : +1/-1 for call/put\n", " \"\"\"\n", " cdef double d1, d2, optprice\n", " with nogil:\n", " d1 = (log(s/k)+(rf-div+0.5*pow(v,2))*t)/(v*sqrt(t))\n", " d2 = d1 - v*sqrt(t)\n", " optprice = cp*s*exp(-div*t)*std_norm_cdf(cp*d1) - \\\n", " cp*k*exp(-rf*t)*std_norm_cdf(cp*d2)\n", " return optprice" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "black_scholes(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 7, "text": [ "10.327861752731728" ] } ], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ "%timeit black_scholes(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "1000000 loops, best of 3: 821 ns per loop\n" ] } ], "prompt_number": 8 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "External libraries" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cython allows you to specify additional libraries to be linked with your extension, you can do so with the `-l` flag (also spelled `--lib`). Note that this flag can be passed more than once to specify multiple libraries, such as `-lm -llib2 --lib lib3`. Here's a simple example of how to access the system math library:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%cython -lm\n", "from libc.math cimport sin\n", "print 'sin(1)=', sin(1)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "sin(1)= 0.841470984808\n" ] } ], "prompt_number": 9 }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can similarly use the `-I/--include` flag to add include directories to the search path, and `-c/--compile-args` to add extra flags that are passed to Cython via the `extra_compile_args` of the distutils `Extension` class. Please see [the Cython docs on C library usage](http://docs.cython.org/src/tutorial/clibraries.html) for more details on the use of these flags." ] } ], "metadata": {} } ] }