Intro to Cython

Why Cython

Outline:

  • Speed up Python code
  • Interact with NumPy arrays
  • Release GIL and get parallel performance
  • Wrap C/C++ code

Part 1: speed up your Python code

We want to integrate the function $f(x) = x^4 - 3x$.


In [1]:
def f(x):
    y = x**4 - 3*x
    return y
    
def integrate_f(a, b, n):
    dx = (b - a) / n
    dx2 = dx / 2
    s = f(a) * dx2
    for i in range(1, n):
        s += f(a + i * dx) * dx
    s += f(b) * dx2
    return s

Now, let's time this:


In [2]:
from scipy.integrate import quad

In [3]:
%timeit quad(f, -100,100)


The slowest run took 4.72 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 15.6 µs per loop

In [4]:
%timeit integrate_f(-100, 100, int(1e5))


10 loops, best of 3: 52.4 ms per loop

Not too bad, but this can add up. Let's see if Cython can do better:


In [5]:
%load_ext cython

In [4]:
%%cython

def f2(x):
    y = x**4 - 3*x
    return y
    
def integrate_f2(a, b, n):
    dx = (b - a) / n
    dx2 = dx / 2
    s = f2(a) * dx2
    for i in range(1, n):
        s += f2(a + i * dx) * dx
    s += f2(b) * dx2
    return s

In [16]:
%timeit integrate_f2(-100, 100, int(1e5))


10 loops, best of 3: 37.6 ms per loop

That's a little bit faster, which is nice since all we did was to call Cython on the exact same code. But can we do better?


In [17]:
%%cython

def f3(double x):
    y = x**4 - 3*x
    return y
    
def integrate_f3(double a, double b, int n):
    dx = (b - a) / n
    dx2 = dx / 2
    s = f3(a) * dx2
    for i in range(1, n):
        s += f3(a + i * dx) * dx
    s += f3(b) * dx2
    return s

In [18]:
%timeit integrate_f3(-100, 100, int(1e5))


10 loops, best of 3: 23.8 ms per loop

The final bit of "easy" Cython optimization is "declaring" the variables inside the function:


In [19]:
%%cython

def f4(double x):
    y = x**4 - 3*x
    return y
    
def integrate_f4(double a, double b, int n):
    cdef:
        double dx = (b - a) / n
        double dx2 = dx / 2
        double s = f4(a) * dx2
        int i = 0
    for i in range(1, n):
        s += f4(a + i * dx) * dx
    s += f4(b) * dx2
    return s

In [21]:
%timeit integrate_f4(-100, 100, int(1e5))


100 loops, best of 3: 14.8 ms per loop

4X speedup with so little effort is pretty nice. What else can we do?

Cython has a nice "-a" flag (for annotation) that can provide clues about why your code is slow.


In [22]:
%%cython -a

def f4(double x):
    y = x**4 - 3*x
    return y
    
def integrate_f4(double a, double b, int n):
    cdef:
        double dx = (b - a) / n
        double dx2 = dx / 2
        double s = f4(a) * dx2
        int i = 0
    for i in range(1, n):
        s += f4(a + i * dx) * dx
    s += f4(b) * dx2
    return s


Out[22]:
Cython: _cython_magic_d12f0b24eb436f44cb71d18b31147b95.pyx

Generated by Cython 0.22.1

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

 01: 
+02: def f4(double x):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_1f4(PyObject *__pyx_self, PyObject *__pyx_arg_x); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_1f4 = {"f4", (PyCFunction)__pyx_pw_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_1f4, METH_O, 0};
static PyObject *__pyx_pw_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_1f4(PyObject *__pyx_self, PyObject *__pyx_arg_x) {
  double __pyx_v_x;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("f4 (wrapper)", 0);
  assert(__pyx_arg_x); {
    __pyx_v_x = __pyx_PyFloat_AsDouble(__pyx_arg_x); if (unlikely((__pyx_v_x == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_d12f0b24eb436f44cb71d18b31147b95.f4", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_f4(__pyx_self, ((double)__pyx_v_x));
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_f4(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_x) {
  double __pyx_v_y;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("f4", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_AddTraceback("_cython_magic_d12f0b24eb436f44cb71d18b31147b95.f4", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple_ = PyTuple_Pack(3, __pyx_n_s_x, __pyx_n_s_x, __pyx_n_s_y); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_tuple_);
  __Pyx_GIVEREF(__pyx_tuple_);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_1f4, NULL, __pyx_n_s_cython_magic_d12f0b24eb436f44cb); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_f4, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__2 = (PyObject*)__Pyx_PyCode_New(1, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple_, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_student_cache_ipython_cyth, __pyx_n_s_f4, 2, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+03:     y = x**4 - 3*x
  __pyx_v_y = (pow(__pyx_v_x, 4.0) - (3.0 * __pyx_v_x));
+04:     return y
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_y); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_r = __pyx_t_1;
  __pyx_t_1 = 0;
  goto __pyx_L0;
 05: 
+06: def integrate_f4(double a, double b, int n):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_3integrate_f4(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_3integrate_f4 = {"integrate_f4", (PyCFunction)__pyx_pw_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_3integrate_f4, METH_VARARGS|METH_KEYWORDS, 0};
static PyObject *__pyx_pw_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_3integrate_f4(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  double __pyx_v_a;
  double __pyx_v_b;
  int __pyx_v_n;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("integrate_f4 (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_a,&__pyx_n_s_b,&__pyx_n_s_n,0};
    PyObject* values[3] = {0,0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_a)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        case  1:
        if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_b)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("integrate_f4", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
        case  2:
        if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_n)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("integrate_f4", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "integrate_f4") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 3) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
      values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
    }
    __pyx_v_a = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_a == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
    __pyx_v_b = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_b == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
    __pyx_v_n = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_n == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("integrate_f4", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_d12f0b24eb436f44cb71d18b31147b95.integrate_f4", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_2integrate_f4(__pyx_self, __pyx_v_a, __pyx_v_b, __pyx_v_n);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_2integrate_f4(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_a, double __pyx_v_b, int __pyx_v_n) {
  double __pyx_v_dx;
  double __pyx_v_dx2;
  double __pyx_v_s;
  int __pyx_v_i;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("integrate_f4", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_XDECREF(__pyx_t_5);
  __Pyx_XDECREF(__pyx_t_6);
  __Pyx_XDECREF(__pyx_t_9);
  __Pyx_AddTraceback("_cython_magic_d12f0b24eb436f44cb71d18b31147b95.integrate_f4", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__3 = PyTuple_Pack(7, __pyx_n_s_a, __pyx_n_s_b, __pyx_n_s_n, __pyx_n_s_dx, __pyx_n_s_dx2, __pyx_n_s_s, __pyx_n_s_i); if (unlikely(!__pyx_tuple__3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_tuple__3);
  __Pyx_GIVEREF(__pyx_tuple__3);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_d12f0b24eb436f44cb71d18b31147b95_3integrate_f4, NULL, __pyx_n_s_cython_magic_d12f0b24eb436f44cb); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_integrate_f4, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 07:     cdef:
+08:         double dx = (b - a) / n
  __pyx_t_1 = (__pyx_v_b - __pyx_v_a);
  if (unlikely(__pyx_v_n == 0)) {
    #ifdef WITH_THREAD
    PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();
    #endif
    PyErr_SetString(PyExc_ZeroDivisionError, "float division");
    #ifdef WITH_THREAD
    PyGILState_Release(__pyx_gilstate_save);
    #endif
    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  }
  __pyx_v_dx = (__pyx_t_1 / __pyx_v_n);
+09:         double dx2 = dx / 2
  __pyx_v_dx2 = (__pyx_v_dx / 2.0);
+10:         double s = f4(a) * dx2
  __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_f4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_4 = PyFloat_FromDouble(__pyx_v_a); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_4);
  __pyx_t_5 = NULL;
  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_3))) {
    __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_3);
    if (likely(__pyx_t_5)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
      __Pyx_INCREF(__pyx_t_5);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_3, function);
    }
  }
  if (!__pyx_t_5) {
    __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_4); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
    __Pyx_GOTREF(__pyx_t_2);
  } else {
    __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_6);
    __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_5); __pyx_t_5 = NULL;
    __Pyx_GIVEREF(__pyx_t_4);
    PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_4);
    __pyx_t_4 = 0;
    __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_6, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_2);
    __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  }
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = PyFloat_FromDouble(__pyx_v_dx2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_6 = PyNumber_Multiply(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_6);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_1 = __pyx_PyFloat_AsDouble(__pyx_t_6); if (unlikely((__pyx_t_1 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __pyx_v_s = __pyx_t_1;
+11:         int i = 0
  __pyx_v_i = 0;
+12:     for i in range(1, n):
  __pyx_t_7 = __pyx_v_n;
  for (__pyx_t_8 = 1; __pyx_t_8 < __pyx_t_7; __pyx_t_8+=1) {
    __pyx_v_i = __pyx_t_8;
+13:         s += f4(a + i * dx) * dx
    __pyx_t_6 = PyFloat_FromDouble(__pyx_v_s); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_6);
    __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_f4); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_4 = PyFloat_FromDouble((__pyx_v_a + (__pyx_v_i * __pyx_v_dx))); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_4);
    __pyx_t_5 = NULL;
    if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_2))) {
      __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_2);
      if (likely(__pyx_t_5)) {
        PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
        __Pyx_INCREF(__pyx_t_5);
        __Pyx_INCREF(function);
        __Pyx_DECREF_SET(__pyx_t_2, function);
      }
    }
    if (!__pyx_t_5) {
      __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
      __Pyx_GOTREF(__pyx_t_3);
    } else {
      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
      __Pyx_GOTREF(__pyx_t_9);
      __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_5); __pyx_t_5 = NULL;
      __Pyx_GIVEREF(__pyx_t_4);
      PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_4);
      __pyx_t_4 = 0;
      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
    }
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __pyx_t_2 = PyFloat_FromDouble(__pyx_v_dx); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_9 = PyNumber_Multiply(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_9);
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __pyx_t_2 = PyNumber_InPlaceAdd(__pyx_t_6, __pyx_t_9); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_2);
    __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
    __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
    __pyx_t_1 = __pyx_PyFloat_AsDouble(__pyx_t_2); if (unlikely((__pyx_t_1 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __pyx_v_s = __pyx_t_1;
  }
+14:     s += f4(b) * dx2
  __pyx_t_2 = PyFloat_FromDouble(__pyx_v_s); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_f4); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_6);
  __pyx_t_3 = PyFloat_FromDouble(__pyx_v_b); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_4 = NULL;
  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_6))) {
    __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_6);
    if (likely(__pyx_t_4)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
      __Pyx_INCREF(__pyx_t_4);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_6, function);
    }
  }
  if (!__pyx_t_4) {
    __pyx_t_9 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_3); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __Pyx_GOTREF(__pyx_t_9);
  } else {
    __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_5);
    __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __pyx_t_4 = NULL;
    __Pyx_GIVEREF(__pyx_t_3);
    PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_t_3);
    __pyx_t_3 = 0;
    __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_5, NULL); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_9);
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  }
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __pyx_t_6 = PyFloat_FromDouble(__pyx_v_dx2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_6);
  __pyx_t_5 = PyNumber_Multiply(__pyx_t_9, __pyx_t_6); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __pyx_t_6 = PyNumber_InPlaceAdd(__pyx_t_2, __pyx_t_5); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_6);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  __pyx_t_1 = __pyx_PyFloat_AsDouble(__pyx_t_6); if (unlikely((__pyx_t_1 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __pyx_v_s = __pyx_t_1;
+15:     return s
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_6 = PyFloat_FromDouble(__pyx_v_s); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_6);
  __pyx_r = __pyx_t_6;
  __pyx_t_6 = 0;
  goto __pyx_L0;

That's a lot of yellow still! How do we reduce this?

Exercise: change the f4 declaration to C


In [53]:
%%cython -a 
#cython: cdivision=True
#import cython

cdef double f5(double x):
    y = x**4 - 3*x
    return y

def integrate_f6(double a, double b, int n):
    cdef:
        double dx = (b - a) / n
        double dx2 = dx / 2
        double s = f5(a) * dx2
        int i = 0
    for i in range(1, n):
        s += f5(a + i * dx) * dx
    s += f5(b) * dx2
    return s


Out[53]:
Cython: _cython_magic_866acf3a78d320cf35b8a8e8296ecbb8.pyx

Generated by Cython 0.22.1

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

 01: #cython: cdivision=True
 02: #import cython
 03: 
+04: cdef double f5(double x):
static double __pyx_f_46_cython_magic_866acf3a78d320cf35b8a8e8296ecbb8_f5(double __pyx_v_x) {
  double __pyx_v_y;
  double __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("f5", 0);
/* … */
  /* function exit code */
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
+05:     y = x**4 - 3*x
  __pyx_v_y = (pow(__pyx_v_x, 4.0) - (3.0 * __pyx_v_x));
+06:     return y
  __pyx_r = __pyx_v_y;
  goto __pyx_L0;
 07: 
+08: def integrate_f6(double a, double b, int n):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_866acf3a78d320cf35b8a8e8296ecbb8_1integrate_f6(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_866acf3a78d320cf35b8a8e8296ecbb8_1integrate_f6 = {"integrate_f6", (PyCFunction)__pyx_pw_46_cython_magic_866acf3a78d320cf35b8a8e8296ecbb8_1integrate_f6, METH_VARARGS|METH_KEYWORDS, 0};
static PyObject *__pyx_pw_46_cython_magic_866acf3a78d320cf35b8a8e8296ecbb8_1integrate_f6(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  double __pyx_v_a;
  double __pyx_v_b;
  int __pyx_v_n;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("integrate_f6 (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_a,&__pyx_n_s_b,&__pyx_n_s_n,0};
    PyObject* values[3] = {0,0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_a)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        case  1:
        if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_b)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("integrate_f6", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
        case  2:
        if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_n)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("integrate_f6", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "integrate_f6") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 3) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
      values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
    }
    __pyx_v_a = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_a == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
    __pyx_v_b = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_b == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
    __pyx_v_n = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_n == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("integrate_f6", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_866acf3a78d320cf35b8a8e8296ecbb8.integrate_f6", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_46_cython_magic_866acf3a78d320cf35b8a8e8296ecbb8_integrate_f6(__pyx_self, __pyx_v_a, __pyx_v_b, __pyx_v_n);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_866acf3a78d320cf35b8a8e8296ecbb8_integrate_f6(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_a, double __pyx_v_b, int __pyx_v_n) {
  double __pyx_v_dx;
  double __pyx_v_dx2;
  double __pyx_v_s;
  int __pyx_v_i;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("integrate_f6", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_AddTraceback("_cython_magic_866acf3a78d320cf35b8a8e8296ecbb8.integrate_f6", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple_ = PyTuple_Pack(7, __pyx_n_s_a, __pyx_n_s_b, __pyx_n_s_n, __pyx_n_s_dx, __pyx_n_s_dx2, __pyx_n_s_s, __pyx_n_s_i); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_tuple_);
  __Pyx_GIVEREF(__pyx_tuple_);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_866acf3a78d320cf35b8a8e8296ecbb8_1integrate_f6, NULL, __pyx_n_s_cython_magic_866acf3a78d320cf35); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_integrate_f6, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 09:     cdef:
+10:         double dx = (b - a) / n
  __pyx_v_dx = ((__pyx_v_b - __pyx_v_a) / __pyx_v_n);
+11:         double dx2 = dx / 2
  __pyx_v_dx2 = (__pyx_v_dx / 2.0);
+12:         double s = f5(a) * dx2
  __pyx_v_s = (__pyx_f_46_cython_magic_866acf3a78d320cf35b8a8e8296ecbb8_f5(__pyx_v_a) * __pyx_v_dx2);
+13:         int i = 0
  __pyx_v_i = 0;
+14:     for i in range(1, n):
  __pyx_t_1 = __pyx_v_n;
  for (__pyx_t_2 = 1; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
    __pyx_v_i = __pyx_t_2;
+15:         s += f5(a + i * dx) * dx
    __pyx_v_s = (__pyx_v_s + (__pyx_f_46_cython_magic_866acf3a78d320cf35b8a8e8296ecbb8_f5((__pyx_v_a + (__pyx_v_i * __pyx_v_dx))) * __pyx_v_dx));
  }
+16:     s += f5(b) * dx2
  __pyx_v_s = (__pyx_v_s + (__pyx_f_46_cython_magic_866acf3a78d320cf35b8a8e8296ecbb8_f5(__pyx_v_b) * __pyx_v_dx2));
+17:     return s
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_3 = PyFloat_FromDouble(__pyx_v_s); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_r = __pyx_t_3;
  __pyx_t_3 = 0;
  goto __pyx_L0;

In [54]:
%timeit integrate_f6(-100, 100, int(1e5))


100 loops, best of 3: 7.18 ms per loop

Part 2: work with NumPy arrays

This is a very small subset of Python. Most scientific application deal not with single values, but with arrays of data.


In [55]:
import numpy as np

def mean3filter(arr):
    arr_out = np.empty_like(arr)
    for i in range(1, arr.shape[0] - 1):
        arr_out[i] = np.sum(arr[i-1 : i+1]) / 3
    arr_out[0] = (arr[0] + arr[1]) / 2
    arr_out[-1] = (arr[-1] + arr[-2]) / 2
    return arr_out

In [56]:
%timeit mean3filter(np.random.rand(1e5))


1 loops, best of 3: 628 ms per loop

In [57]:
%%cython
import cython
import numpy as np

@cython.boundscheck(False)
def mean3filter2(double[::1] arr):
    cdef double[::1] arr_out = np.empty_like(arr)
    cdef int i
    for i in range(1, arr.shape[0]-1):
        arr_out[i] = np.sum(arr[i-1 : i+1]) / 3
    arr_out[0] = (arr[0] + arr[1]) / 2
    arr_out[-1] = (arr[-1] + arr[-2]) / 2
    return np.asarray(arr_out)

In [77]:
%timeit np.convolve(np.random.rand(1e5), np.array([1.,1.,1.]), 'same')


100 loops, best of 3: 3.11 ms per loop

In [58]:
%timeit mean3filter2(np.random.rand(1e5))


1 loops, best of 3: 1.17 s per loop

Rubbish! How do we fix this?

Exercise: use %%cython -a to speed up the code


In [75]:
%%cython -a
import cython
import numpy as np

@cython.boundscheck(False)
def mean3filter2a(double[::1] arr):
    # ::1 means that the array is contiguous
    cdef double[::1] arr_out = np.empty_like(arr)
    cdef int i
    for i in range(1, arr.shape[0]-1):
        #for j in range(3):
        arr_out[i] = arr[i-1] + arr[i] + arr[i+1]
        arr_out[i] *= 0.333333333333333333333333
        #arr_out[i] = np.sum(arr[i-1 : i+1]) / 3
    arr_out[0] = (arr[0] + arr[1]) / 2
    arr_out[-1] = (arr[-1] + arr[-2]) / 2
    return np.asarray(arr_out)


Out[75]:
Cython: _cython_magic_91ce2d70c0de6735a44d76fd658e8707.pyx

Generated by Cython 0.22.1

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

+01: import cython
  __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;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+02: import numpy as np
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 03: 
 04: @cython.boundscheck(False)
+05: def mean3filter2a(double[::1] arr):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_91ce2d70c0de6735a44d76fd658e8707_1mean3filter2a(PyObject *__pyx_self, PyObject *__pyx_arg_arr); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_91ce2d70c0de6735a44d76fd658e8707_1mean3filter2a = {"mean3filter2a", (PyCFunction)__pyx_pw_46_cython_magic_91ce2d70c0de6735a44d76fd658e8707_1mean3filter2a, METH_O, 0};
static PyObject *__pyx_pw_46_cython_magic_91ce2d70c0de6735a44d76fd658e8707_1mean3filter2a(PyObject *__pyx_self, PyObject *__pyx_arg_arr) {
  __Pyx_memviewslice __pyx_v_arr = { 0, 0, { 0 }, { 0 }, { 0 } };
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("mean3filter2a (wrapper)", 0);
  assert(__pyx_arg_arr); {
    __pyx_v_arr = __Pyx_PyObject_to_MemoryviewSlice_dc_double(__pyx_arg_arr); if (unlikely(!__pyx_v_arr.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_91ce2d70c0de6735a44d76fd658e8707.mean3filter2a", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_46_cython_magic_91ce2d70c0de6735a44d76fd658e8707_mean3filter2a(__pyx_self, __pyx_v_arr);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_91ce2d70c0de6735a44d76fd658e8707_mean3filter2a(CYTHON_UNUSED PyObject *__pyx_self, __Pyx_memviewslice __pyx_v_arr) {
  __Pyx_memviewslice __pyx_v_arr_out = { 0, 0, { 0 }, { 0 }, { 0 } };
  int __pyx_v_i;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("mean3filter2a", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_XDECREF(__pyx_t_5);
  __PYX_XDEC_MEMVIEW(&__pyx_t_6, 1);
  __Pyx_AddTraceback("_cython_magic_91ce2d70c0de6735a44d76fd658e8707.mean3filter2a", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __PYX_XDEC_MEMVIEW(&__pyx_v_arr, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_v_arr_out, 1);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__13 = PyTuple_Pack(4, __pyx_n_s_arr, __pyx_n_s_arr, __pyx_n_s_arr_out, __pyx_n_s_i); if (unlikely(!__pyx_tuple__13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_tuple__13);
  __Pyx_GIVEREF(__pyx_tuple__13);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_91ce2d70c0de6735a44d76fd658e8707_1mean3filter2a, NULL, __pyx_n_s_cython_magic_91ce2d70c0de6735a4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_mean3filter2a, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__14 = (PyObject*)__Pyx_PyCode_New(1, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__13, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_student_cache_ipython_cyth, __pyx_n_s_mean3filter2a, 5, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 06:     # ::1 means that the array is contiguous
+07:     cdef double[::1] arr_out = np.empty_like(arr)
  __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_empty_like); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_arr, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_4 = NULL;
  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_3))) {
    __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
    if (likely(__pyx_t_4)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
      __Pyx_INCREF(__pyx_t_4);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_3, function);
    }
  }
  if (!__pyx_t_4) {
    __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __Pyx_GOTREF(__pyx_t_1);
  } else {
    __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_5);
    __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __pyx_t_4 = NULL;
    __Pyx_GIVEREF(__pyx_t_2);
    PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_t_2);
    __pyx_t_2 = 0;
    __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_1);
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  }
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_6 = __Pyx_PyObject_to_MemoryviewSlice_dc_double(__pyx_t_1);
  if (unlikely(!__pyx_t_6.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_arr_out = __pyx_t_6;
  __pyx_t_6.memview = NULL;
  __pyx_t_6.data = NULL;
 08:     cdef int i
+09:     for i in range(1, arr.shape[0]-1):
  __pyx_t_7 = ((__pyx_v_arr.shape[0]) - 1);
  for (__pyx_t_8 = 1; __pyx_t_8 < __pyx_t_7; __pyx_t_8+=1) {
    __pyx_v_i = __pyx_t_8;
 10:         #for j in range(3):
+11:         arr_out[i] = arr[i-1] + arr[i] + arr[i+1]
    __pyx_t_9 = (__pyx_v_i - 1);
    if (__pyx_t_9 < 0) __pyx_t_9 += __pyx_v_arr.shape[0];
    __pyx_t_10 = __pyx_v_i;
    if (__pyx_t_10 < 0) __pyx_t_10 += __pyx_v_arr.shape[0];
    __pyx_t_11 = (__pyx_v_i + 1);
    if (__pyx_t_11 < 0) __pyx_t_11 += __pyx_v_arr.shape[0];
    __pyx_t_12 = __pyx_v_i;
    if (__pyx_t_12 < 0) __pyx_t_12 += __pyx_v_arr_out.shape[0];
    *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr_out.data) + __pyx_t_12)) )) = (((*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_9)) ))) + (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_10)) )))) + (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_11)) ))));
+12:         arr_out[i] *= 0.333333333333333333333333
    __pyx_t_13 = __pyx_v_i;
    if (__pyx_t_13 < 0) __pyx_t_13 += __pyx_v_arr_out.shape[0];
    *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr_out.data) + __pyx_t_13)) )) *= 0.333333333333333333333333;
  }
 13:         #arr_out[i] = np.sum(arr[i-1 : i+1]) / 3
+14:     arr_out[0] = (arr[0] + arr[1]) / 2
  __pyx_t_7 = 0;
  if (__pyx_t_7 < 0) __pyx_t_7 += __pyx_v_arr.shape[0];
  __pyx_t_14 = 1;
  if (__pyx_t_14 < 0) __pyx_t_14 += __pyx_v_arr.shape[0];
  __pyx_t_15 = 0;
  if (__pyx_t_15 < 0) __pyx_t_15 += __pyx_v_arr_out.shape[0];
  *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr_out.data) + __pyx_t_15)) )) = (((*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_7)) ))) + (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_14)) )))) / 2.0);
+15:     arr_out[-1] = (arr[-1] + arr[-2]) / 2
  __pyx_t_16 = -1;
  if (__pyx_t_16 < 0) __pyx_t_16 += __pyx_v_arr.shape[0];
  __pyx_t_17 = -2;
  if (__pyx_t_17 < 0) __pyx_t_17 += __pyx_v_arr.shape[0];
  __pyx_t_18 = -1;
  if (__pyx_t_18 < 0) __pyx_t_18 += __pyx_v_arr_out.shape[0];
  *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr_out.data) + __pyx_t_18)) )) = (((*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_16)) ))) + (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_17)) )))) / 2.0);
+16:     return np.asarray(arr_out)
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_asarray); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = __pyx_memoryview_fromslice(__pyx_v_arr_out, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_2 = NULL;
  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_5))) {
    __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_5);
    if (likely(__pyx_t_2)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
      __Pyx_INCREF(__pyx_t_2);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_5, function);
    }
  }
  if (!__pyx_t_2) {
    __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __Pyx_GOTREF(__pyx_t_1);
  } else {
    __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_4);
    __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __pyx_t_2 = NULL;
    __Pyx_GIVEREF(__pyx_t_3);
    PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_t_3);
    __pyx_t_3 = 0;
    __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_1);
    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  }
  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  __pyx_r = __pyx_t_1;
  __pyx_t_1 = 0;
  goto __pyx_L0;

In [76]:
%timeit mean3filter2a(np.random.rand(1e5))


1000 loops, best of 3: 1.56 ms per loop

Part 3: write parallel code

Warning:: Dragons afoot.


In [82]:
%%cython -a
import cython
from cython.parallel import prange
import numpy as np

@cython.boundscheck(False)
def mean3filter3a(double[::1] arr, double[::1] out):
    cdef int i, j, k = arr.shape[0]-1
    for i in range(1, k-1):
        for j in range(i-1, i+1):
            out[i] += arr[j]
        out[i] /= 3
    out[0] = (arr[0] + arr[1]) / 2
    out[-1] = (arr[-1] + arr[-2]) / 2
    return np.asarray(out)


Out[82]:
Cython: _cython_magic_25a90b065d2abbab3833deaf3d4785cf.pyx

Generated by Cython 0.22.1

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

+01: import cython
  __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;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 02: from cython.parallel import prange
+03: import numpy as np
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 04: 
 05: @cython.boundscheck(False)
+06: def mean3filter3a(double[::1] arr, double[::1] out):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_25a90b065d2abbab3833deaf3d4785cf_1mean3filter3a(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_25a90b065d2abbab3833deaf3d4785cf_1mean3filter3a = {"mean3filter3a", (PyCFunction)__pyx_pw_46_cython_magic_25a90b065d2abbab3833deaf3d4785cf_1mean3filter3a, METH_VARARGS|METH_KEYWORDS, 0};
static PyObject *__pyx_pw_46_cython_magic_25a90b065d2abbab3833deaf3d4785cf_1mean3filter3a(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  __Pyx_memviewslice __pyx_v_arr = { 0, 0, { 0 }, { 0 }, { 0 } };
  __Pyx_memviewslice __pyx_v_out = { 0, 0, { 0 }, { 0 }, { 0 } };
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("mean3filter3a (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_arr,&__pyx_n_s_out,0};
    PyObject* values[2] = {0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_arr)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        case  1:
        if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_out)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("mean3filter3a", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "mean3filter3a") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
    }
    __pyx_v_arr = __Pyx_PyObject_to_MemoryviewSlice_dc_double(values[0]); if (unlikely(!__pyx_v_arr.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
    __pyx_v_out = __Pyx_PyObject_to_MemoryviewSlice_dc_double(values[1]); if (unlikely(!__pyx_v_out.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("mean3filter3a", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_25a90b065d2abbab3833deaf3d4785cf.mean3filter3a", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_46_cython_magic_25a90b065d2abbab3833deaf3d4785cf_mean3filter3a(__pyx_self, __pyx_v_arr, __pyx_v_out);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_25a90b065d2abbab3833deaf3d4785cf_mean3filter3a(CYTHON_UNUSED PyObject *__pyx_self, __Pyx_memviewslice __pyx_v_arr, __Pyx_memviewslice __pyx_v_out) {
  int __pyx_v_i;
  int __pyx_v_j;
  int __pyx_v_k;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("mean3filter3a", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_13);
  __Pyx_XDECREF(__pyx_t_14);
  __Pyx_XDECREF(__pyx_t_15);
  __Pyx_XDECREF(__pyx_t_16);
  __Pyx_XDECREF(__pyx_t_17);
  __Pyx_AddTraceback("_cython_magic_25a90b065d2abbab3833deaf3d4785cf.mean3filter3a", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __PYX_XDEC_MEMVIEW(&__pyx_v_arr, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_v_out, 1);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__13 = PyTuple_Pack(5, __pyx_n_s_arr, __pyx_n_s_out, __pyx_n_s_i, __pyx_n_s_j, __pyx_n_s_k); if (unlikely(!__pyx_tuple__13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_tuple__13);
  __Pyx_GIVEREF(__pyx_tuple__13);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_25a90b065d2abbab3833deaf3d4785cf_1mean3filter3a, NULL, __pyx_n_s_cython_magic_25a90b065d2abbab38); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_mean3filter3a, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__14 = (PyObject*)__Pyx_PyCode_New(2, 0, 5, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__13, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_student_cache_ipython_cyth, __pyx_n_s_mean3filter3a, 6, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+07:     cdef int i, j, k = arr.shape[0]-1
  __pyx_v_k = ((__pyx_v_arr.shape[0]) - 1);
+08:     for i in range(1, k-1):
  __pyx_t_1 = (__pyx_v_k - 1);
  for (__pyx_t_2 = 1; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
    __pyx_v_i = __pyx_t_2;
+09:         for j in range(i-1, i+1):
    __pyx_t_3 = (__pyx_v_i + 1);
    for (__pyx_t_4 = (__pyx_v_i - 1); __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) {
      __pyx_v_j = __pyx_t_4;
+10:             out[i] += arr[j]
      __pyx_t_5 = __pyx_v_j;
      if (__pyx_t_5 < 0) __pyx_t_5 += __pyx_v_arr.shape[0];
      __pyx_t_6 = __pyx_v_i;
      if (__pyx_t_6 < 0) __pyx_t_6 += __pyx_v_out.shape[0];
      *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_out.data) + __pyx_t_6)) )) += (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_5)) )));
    }
+11:         out[i] /= 3
    __pyx_t_4 = __pyx_v_i;
    if (__pyx_t_4 < 0) __pyx_t_4 += __pyx_v_out.shape[0];
    *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_out.data) + __pyx_t_4)) )) /= 3.0;
  }
+12:     out[0] = (arr[0] + arr[1]) / 2
  __pyx_t_7 = 0;
  if (__pyx_t_7 < 0) __pyx_t_7 += __pyx_v_arr.shape[0];
  __pyx_t_8 = 1;
  if (__pyx_t_8 < 0) __pyx_t_8 += __pyx_v_arr.shape[0];
  __pyx_t_9 = 0;
  if (__pyx_t_9 < 0) __pyx_t_9 += __pyx_v_out.shape[0];
  *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_out.data) + __pyx_t_9)) )) = (((*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_7)) ))) + (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_8)) )))) / 2.0);
+13:     out[-1] = (arr[-1] + arr[-2]) / 2
  __pyx_t_10 = -1;
  if (__pyx_t_10 < 0) __pyx_t_10 += __pyx_v_arr.shape[0];
  __pyx_t_11 = -2;
  if (__pyx_t_11 < 0) __pyx_t_11 += __pyx_v_arr.shape[0];
  __pyx_t_12 = -1;
  if (__pyx_t_12 < 0) __pyx_t_12 += __pyx_v_out.shape[0];
  *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_out.data) + __pyx_t_12)) )) = (((*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_10)) ))) + (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_11)) )))) / 2.0);
+14:     return np.asarray(out)
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_14 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_14);
  __pyx_t_15 = __Pyx_PyObject_GetAttrStr(__pyx_t_14, __pyx_n_s_asarray); if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_15);
  __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
  __pyx_t_14 = __pyx_memoryview_fromslice(__pyx_v_out, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_14);
  __pyx_t_16 = NULL;
  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_15))) {
    __pyx_t_16 = PyMethod_GET_SELF(__pyx_t_15);
    if (likely(__pyx_t_16)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_15);
      __Pyx_INCREF(__pyx_t_16);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_15, function);
    }
  }
  if (!__pyx_t_16) {
    __pyx_t_13 = __Pyx_PyObject_CallOneArg(__pyx_t_15, __pyx_t_14); if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
    __Pyx_GOTREF(__pyx_t_13);
  } else {
    __pyx_t_17 = PyTuple_New(1+1); if (unlikely(!__pyx_t_17)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_17);
    __Pyx_GIVEREF(__pyx_t_16); PyTuple_SET_ITEM(__pyx_t_17, 0, __pyx_t_16); __pyx_t_16 = NULL;
    __Pyx_GIVEREF(__pyx_t_14);
    PyTuple_SET_ITEM(__pyx_t_17, 0+1, __pyx_t_14);
    __pyx_t_14 = 0;
    __pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_15, __pyx_t_17, NULL); if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_13);
    __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0;
  }
  __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
  __pyx_r = __pyx_t_13;
  __pyx_t_13 = 0;
  goto __pyx_L0;

In [85]:
%%cython -a
import cython
from cython.parallel import prange
import numpy as np

@cython.boundscheck(False)
def mean3filter3(double[::1] arr, double[::1] out):
    cdef int i, j, k = arr.shape[0]-1
    
    with nogil:
        for i in prange(1, k-1, schedule='static',
                        chunksize=(k-2) // 2, num_threads=4):
            for j in range(i-1, i+1):
                out[i] += arr[j]
            out[i] /= 3
    out[0] = (arr[0] + arr[1]) / 2
    out[-1] = (arr[-1] + arr[-2]) / 2
    return np.asarray(out)


Error compiling Cython file:
------------------------------------------------------------
...
import numpy as np

@cython.boundscheck(False)
def mean3filter3(double[::1] arr, double[::1] out):
    cdef int i, j, k = arr.shape[0]-1
    for i in prange(1, k-1, schedule='static',
                  ^
------------------------------------------------------------

/home/student/.cache/ipython/cython/_cython_magic_01f16d263991d5b51fc55754d032c5d4.pyx:8:19: prange() can only be used without the GIL

In [86]:
%%cython -a
import cython
from cython.parallel import prange
import numpy as np

@cython.boundscheck(False)
def mean3filter3b(double[::1] arr, double[::1] out):
    cdef int i, j, k = arr.shape[0]-1
    for i in range(1, k-1):
        for j in range(i-1, i+1):
            out[i] += arr[j]
    with nogil:
        for i in prange(1, k-1, schedule='static',
                        chunksize=(k-2) // 2, num_threads=4):
            out[i] /= 3
    out[0] = (arr[0] + arr[1]) / 2
    out[-1] = (arr[-1] + arr[-2]) / 2
    return np.asarray(out)


Out[86]:
Cython: _cython_magic_8c69ac4eb3ae7bc63d68edbbdc8f45f1.pyx

Generated by Cython 0.22.1

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

+01: import cython
  __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;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 02: from cython.parallel import prange
+03: import numpy as np
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 04: 
 05: @cython.boundscheck(False)
+06: def mean3filter3b(double[::1] arr, double[::1] out):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_8c69ac4eb3ae7bc63d68edbbdc8f45f1_1mean3filter3b(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_8c69ac4eb3ae7bc63d68edbbdc8f45f1_1mean3filter3b = {"mean3filter3b", (PyCFunction)__pyx_pw_46_cython_magic_8c69ac4eb3ae7bc63d68edbbdc8f45f1_1mean3filter3b, METH_VARARGS|METH_KEYWORDS, 0};
static PyObject *__pyx_pw_46_cython_magic_8c69ac4eb3ae7bc63d68edbbdc8f45f1_1mean3filter3b(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  __Pyx_memviewslice __pyx_v_arr = { 0, 0, { 0 }, { 0 }, { 0 } };
  __Pyx_memviewslice __pyx_v_out = { 0, 0, { 0 }, { 0 }, { 0 } };
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("mean3filter3b (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_arr,&__pyx_n_s_out,0};
    PyObject* values[2] = {0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_arr)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        case  1:
        if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_out)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("mean3filter3b", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "mean3filter3b") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
    }
    __pyx_v_arr = __Pyx_PyObject_to_MemoryviewSlice_dc_double(values[0]); if (unlikely(!__pyx_v_arr.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
    __pyx_v_out = __Pyx_PyObject_to_MemoryviewSlice_dc_double(values[1]); if (unlikely(!__pyx_v_out.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("mean3filter3b", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_8c69ac4eb3ae7bc63d68edbbdc8f45f1.mean3filter3b", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_46_cython_magic_8c69ac4eb3ae7bc63d68edbbdc8f45f1_mean3filter3b(__pyx_self, __pyx_v_arr, __pyx_v_out);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_8c69ac4eb3ae7bc63d68edbbdc8f45f1_mean3filter3b(CYTHON_UNUSED PyObject *__pyx_self, __Pyx_memviewslice __pyx_v_arr, __Pyx_memviewslice __pyx_v_out) {
  int __pyx_v_i;
  int __pyx_v_j;
  int __pyx_v_k;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("mean3filter3b", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_15);
  __Pyx_XDECREF(__pyx_t_16);
  __Pyx_XDECREF(__pyx_t_17);
  __Pyx_XDECREF(__pyx_t_18);
  __Pyx_XDECREF(__pyx_t_19);
  __Pyx_AddTraceback("_cython_magic_8c69ac4eb3ae7bc63d68edbbdc8f45f1.mean3filter3b", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __PYX_XDEC_MEMVIEW(&__pyx_v_arr, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_v_out, 1);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__13 = PyTuple_Pack(5, __pyx_n_s_arr, __pyx_n_s_out, __pyx_n_s_i, __pyx_n_s_j, __pyx_n_s_k); if (unlikely(!__pyx_tuple__13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_tuple__13);
  __Pyx_GIVEREF(__pyx_tuple__13);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_8c69ac4eb3ae7bc63d68edbbdc8f45f1_1mean3filter3b, NULL, __pyx_n_s_cython_magic_8c69ac4eb3ae7bc63d); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_mean3filter3b, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__14 = (PyObject*)__Pyx_PyCode_New(2, 0, 5, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__13, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_student_cache_ipython_cyth, __pyx_n_s_mean3filter3b, 6, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+07:     cdef int i, j, k = arr.shape[0]-1
  __pyx_v_k = ((__pyx_v_arr.shape[0]) - 1);
+08:     for i in range(1, k-1):
  __pyx_t_1 = (__pyx_v_k - 1);
  for (__pyx_t_2 = 1; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
    __pyx_v_i = __pyx_t_2;
+09:         for j in range(i-1, i+1):
    __pyx_t_3 = (__pyx_v_i + 1);
    for (__pyx_t_4 = (__pyx_v_i - 1); __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) {
      __pyx_v_j = __pyx_t_4;
+10:             out[i] += arr[j]
      __pyx_t_5 = __pyx_v_j;
      if (__pyx_t_5 < 0) __pyx_t_5 += __pyx_v_arr.shape[0];
      __pyx_t_6 = __pyx_v_i;
      if (__pyx_t_6 < 0) __pyx_t_6 += __pyx_v_out.shape[0];
      *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_out.data) + __pyx_t_6)) )) += (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_5)) )));
    }
  }
+11:     with nogil:
  {
      #ifdef WITH_THREAD
      PyThreadState *_save;
      Py_UNBLOCK_THREADS
      #endif
      /*try:*/ {
/* … */
      /*finally:*/ {
        /*normal exit:*/{
          #ifdef WITH_THREAD
          Py_BLOCK_THREADS
          #endif
          goto __pyx_L9;
        }
        __pyx_L9:;
      }
  }
+12:         for i in prange(1, k-1, schedule='static',
        __pyx_t_1 = (__pyx_v_k - 1);
        if (1 == 0) abort();
        {
            #if ((defined(__APPLE__) || defined(__OSX__)) && (defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)))))
                #undef likely
                #undef unlikely
                #define likely(x)   (x)
                #define unlikely(x) (x)
            #endif
            __pyx_t_7 = (__pyx_t_1 - 1) / 1;
            if (__pyx_t_7 > 0)
            {
                #ifdef _OPENMP
                #pragma omp parallel
                #endif /* _OPENMP */
                {
                    #ifdef _OPENMP
                    #pragma omp for firstprivate(__pyx_v_i) lastprivate(__pyx_v_i)
/* … */
        __pyx_t_1 = (__pyx_v_k - 1);
        if (1 == 0) abort();
        {
            #if ((defined(__APPLE__) || defined(__OSX__)) && (defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)))))
                #undef likely
                #undef unlikely
                #define likely(x)   (x)
                #define unlikely(x) (x)
            #endif
            __pyx_t_7 = (__pyx_t_1 - 1) / 1;
            if (__pyx_t_7 > 0)
            {
                #ifdef _OPENMP
                #pragma omp parallel
                #endif /* _OPENMP */
                {
                    #ifdef _OPENMP
                    #pragma omp for firstprivate(__pyx_v_i) lastprivate(__pyx_v_i) schedule(static, __pyx_t_8) num_threads(4)
                    #endif /* _OPENMP */
                    for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_7; __pyx_t_3++){
                        {
                            __pyx_v_i = 1 + 1 * __pyx_t_3;
 13:                         chunksize=(k-2) // 2, num_threads=4):
+14:             out[i] /= 3
                            __pyx_t_2 = __pyx_v_i;
                            if (__pyx_t_2 < 0) __pyx_t_2 += __pyx_v_out.shape[0];
                            *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_out.data) + __pyx_t_2)) )) /= 3.0;
                        }
                    }
                }
            }
        }
        #if ((defined(__APPLE__) || defined(__OSX__)) && (defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)))))
            #undef likely
            #undef unlikely
            #define likely(x)   __builtin_expect(!!(x), 1)
            #define unlikely(x) __builtin_expect(!!(x), 0)
        #endif
      }
+15:     out[0] = (arr[0] + arr[1]) / 2
  __pyx_t_9 = 0;
  if (__pyx_t_9 < 0) __pyx_t_9 += __pyx_v_arr.shape[0];
  __pyx_t_10 = 1;
  if (__pyx_t_10 < 0) __pyx_t_10 += __pyx_v_arr.shape[0];
  __pyx_t_11 = 0;
  if (__pyx_t_11 < 0) __pyx_t_11 += __pyx_v_out.shape[0];
  *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_out.data) + __pyx_t_11)) )) = (((*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_9)) ))) + (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_10)) )))) / 2.0);
+16:     out[-1] = (arr[-1] + arr[-2]) / 2
  __pyx_t_12 = -1;
  if (__pyx_t_12 < 0) __pyx_t_12 += __pyx_v_arr.shape[0];
  __pyx_t_13 = -2;
  if (__pyx_t_13 < 0) __pyx_t_13 += __pyx_v_arr.shape[0];
  __pyx_t_14 = -1;
  if (__pyx_t_14 < 0) __pyx_t_14 += __pyx_v_out.shape[0];
  *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_out.data) + __pyx_t_14)) )) = (((*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_12)) ))) + (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_arr.data) + __pyx_t_13)) )))) / 2.0);
+17:     return np.asarray(out)
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_16 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_16);
  __pyx_t_17 = __Pyx_PyObject_GetAttrStr(__pyx_t_16, __pyx_n_s_asarray); if (unlikely(!__pyx_t_17)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_17);
  __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
  __pyx_t_16 = __pyx_memoryview_fromslice(__pyx_v_out, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_16);
  __pyx_t_18 = NULL;
  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_17))) {
    __pyx_t_18 = PyMethod_GET_SELF(__pyx_t_17);
    if (likely(__pyx_t_18)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_17);
      __Pyx_INCREF(__pyx_t_18);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_17, function);
    }
  }
  if (!__pyx_t_18) {
    __pyx_t_15 = __Pyx_PyObject_CallOneArg(__pyx_t_17, __pyx_t_16); if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
    __Pyx_GOTREF(__pyx_t_15);
  } else {
    __pyx_t_19 = PyTuple_New(1+1); if (unlikely(!__pyx_t_19)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_19);
    __Pyx_GIVEREF(__pyx_t_18); PyTuple_SET_ITEM(__pyx_t_19, 0, __pyx_t_18); __pyx_t_18 = NULL;
    __Pyx_GIVEREF(__pyx_t_16);
    PyTuple_SET_ITEM(__pyx_t_19, 0+1, __pyx_t_16);
    __pyx_t_16 = 0;
    __pyx_t_15 = __Pyx_PyObject_Call(__pyx_t_17, __pyx_t_19, NULL); if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_15);
    __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0;
  }
  __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0;
  __pyx_r = __pyx_t_15;
  __pyx_t_15 = 0;
  goto __pyx_L0;

In [91]:
del rin, rout

In [89]:
rin = np.random.rand(1e8)
rout = np.empty_like(rin)

In [90]:
%timeit mean3filter3b(rin, rout)


The slowest run took 14.04 times longer than the fastest. This could mean that an intermediate result is being cached 
1 loops, best of 3: 683 ms per loop

In [84]:
%timeit mean3filter3(rin, rout)


10 loops, best of 3: 45.6 ms per loop

Exercise (if time)

Write a parallel matrix multiplication routine.


In [ ]:

Part 4: interact with C/C++ code


In [92]:
%%cython -a
# distutils: language=c++
import cython
from libcpp.vector cimport vector


@cython.boundscheck(False)
def build_list_with_vector(double[::1] in_arr):
    cdef vector[double] out
    cdef int i
    for i in range(in_arr.shape[0]):
        out.push_back(in_arr[i])
    return out


Out[92]:
Cython: _cython_magic_9e62336531da4dc6d78b22908dd4ed1c.pyx

Generated by Cython 0.22.1

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

+01: # distutils: language=c++
  __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;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 02: import cython
 03: from libcpp.vector cimport vector
 04: 
 05: 
 06: @cython.boundscheck(False)
+07: def build_list_with_vector(double[::1] in_arr):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_9e62336531da4dc6d78b22908dd4ed1c_1build_list_with_vector(PyObject *__pyx_self, PyObject *__pyx_arg_in_arr); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_9e62336531da4dc6d78b22908dd4ed1c_1build_list_with_vector = {"build_list_with_vector", (PyCFunction)__pyx_pw_46_cython_magic_9e62336531da4dc6d78b22908dd4ed1c_1build_list_with_vector, METH_O, 0};
static PyObject *__pyx_pw_46_cython_magic_9e62336531da4dc6d78b22908dd4ed1c_1build_list_with_vector(PyObject *__pyx_self, PyObject *__pyx_arg_in_arr) {
  __Pyx_memviewslice __pyx_v_in_arr = { 0, 0, { 0 }, { 0 }, { 0 } };
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("build_list_with_vector (wrapper)", 0);
  assert(__pyx_arg_in_arr); {
    __pyx_v_in_arr = __Pyx_PyObject_to_MemoryviewSlice_dc_double(__pyx_arg_in_arr); if (unlikely(!__pyx_v_in_arr.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_9e62336531da4dc6d78b22908dd4ed1c.build_list_with_vector", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_46_cython_magic_9e62336531da4dc6d78b22908dd4ed1c_build_list_with_vector(__pyx_self, __pyx_v_in_arr);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_9e62336531da4dc6d78b22908dd4ed1c_build_list_with_vector(CYTHON_UNUSED PyObject *__pyx_self, __Pyx_memviewslice __pyx_v_in_arr) {
  std::vector<double>  __pyx_v_out;
  int __pyx_v_i;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("build_list_with_vector", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_AddTraceback("_cython_magic_9e62336531da4dc6d78b22908dd4ed1c.build_list_with_vector", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __PYX_XDEC_MEMVIEW(&__pyx_v_in_arr, 1);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__13 = PyTuple_Pack(4, __pyx_n_s_in_arr, __pyx_n_s_in_arr, __pyx_n_s_out, __pyx_n_s_i); if (unlikely(!__pyx_tuple__13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_tuple__13);
  __Pyx_GIVEREF(__pyx_tuple__13);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_9e62336531da4dc6d78b22908dd4ed1c_1build_list_with_vector, NULL, __pyx_n_s_cython_magic_9e62336531da4dc6d7); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_build_list_with_vector, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__14 = (PyObject*)__Pyx_PyCode_New(1, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__13, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_student_cache_ipython_cyth, __pyx_n_s_build_list_with_vector, 7, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 08:     cdef vector[double] out
 09:     cdef int i
+10:     for i in range(in_arr.shape[0]):
  __pyx_t_1 = (__pyx_v_in_arr.shape[0]);
  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
    __pyx_v_i = __pyx_t_2;
+11:         out.push_back(in_arr[i])
    __pyx_t_3 = __pyx_v_i;
    if (__pyx_t_3 < 0) __pyx_t_3 += __pyx_v_in_arr.shape[0];
    try {
      __pyx_v_out.push_back((*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_in_arr.data) + __pyx_t_3)) ))));
    } catch(...) {
      __Pyx_CppExn2PyErr();
      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    }
  }
+12:     return out
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_4 = __pyx_convert_vector_to_py_double(__pyx_v_out); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 12; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_4);
  __pyx_r = __pyx_t_4;
  __pyx_t_4 = 0;
  goto __pyx_L0;

In [93]:
build_list_with_vector(np.random.rand(10))


Out[93]:
[0.26085286315839795,
 0.9763933277734224,
 0.9676751436173779,
 0.6887305413123229,
 0.009623500824120224,
 0.2690635362697693,
 0.46649754307129254,
 0.9523794831061152,
 0.3025492210533033,
 0.5987448617009814]

Example: C++ int graph


In [94]:
%%cython -a
#distutils: language=c++
from cython.operator cimport dereference as deref, preincrement as inc

from libcpp.vector cimport vector
from libcpp.map cimport map as cppmap

cdef class Graph:
    cdef cppmap[int, vector[int]] _adj
    
    cpdef int has_node(self, int node):
        return self._adj.find(node) != self._adj.end()
    
    cdef void add_node(self, int new_node):
        cdef vector[int] out
        if not self.has_node(new_node):
            self._adj[new_node] = out
            
    def add_edge(self, int u, int v):
        self.add_node(u)
        self.add_node(v)
        self._adj[u].push_back(v)
        self._adj[v].push_back(u)
        
    def __getitem__(self, int u):
        return self._adj[u]
    
    cdef vector[int] _degrees(self):
        cdef vector[int] deg
        cdef int first = 0
        cdef vector[int] edges
        cdef cppmap[int, vector[int]].iterator it = self._adj.begin()
        while it != self._adj.end():
            deg.push_back(deref(it).second.size())
            it = inc(it)
        return deg
            
    def degrees(self):
        return self._degrees()


Out[94]:
Cython: _cython_magic_207f54e3e5ad780456f48229a083fca4.pyx

Generated by Cython 0.22.1

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

+01: #distutils: language=c++
  __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;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 02: from cython.operator cimport dereference as deref, preincrement as inc
 03: 
 04: from libcpp.vector cimport vector
 05: from libcpp.map cimport map as cppmap
 06: 
+07: cdef class Graph:
struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph {
  PyObject_HEAD
  struct __pyx_vtabstruct_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *__pyx_vtab;
  std::map<int,std::vector<int> >  _adj;
};



struct __pyx_vtabstruct_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph {
  int (*has_node)(struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *, int, int __pyx_skip_dispatch);
  void (*add_node)(struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *, int);
  std::vector<int>  (*_degrees)(struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *);
};
static struct __pyx_vtabstruct_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *__pyx_vtabptr_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph;
 08:     cdef cppmap[int, vector[int]] _adj
 09: 
+10:     cpdef int has_node(self, int node):
static PyObject *__pyx_pw_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_1has_node(PyObject *__pyx_v_self, PyObject *__pyx_arg_node); /*proto*/
static int __pyx_f_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_has_node(struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *__pyx_v_self, int __pyx_v_node, int __pyx_skip_dispatch) {
  int __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("has_node", 0);
  /* Check if called by wrapper */
  if (unlikely(__pyx_skip_dispatch)) ;
  /* Check if overridden in Python */
  else if (unlikely(Py_TYPE(((PyObject *)__pyx_v_self))->tp_dictoffset != 0)) {
    __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_has_node); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_1);
    if (!PyCFunction_Check(__pyx_t_1) || (PyCFunction_GET_FUNCTION(__pyx_t_1) != (PyCFunction)__pyx_pw_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_1has_node)) {
      __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_node); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_INCREF(__pyx_t_1);
      __pyx_t_4 = __pyx_t_1; __pyx_t_5 = NULL;
      if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_4))) {
        __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4);
        if (likely(__pyx_t_5)) {
          PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
          __Pyx_INCREF(__pyx_t_5);
          __Pyx_INCREF(function);
          __Pyx_DECREF_SET(__pyx_t_4, function);
        }
      }
      if (!__pyx_t_5) {
        __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_3); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
        __Pyx_GOTREF(__pyx_t_2);
      } else {
        __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
        __Pyx_GOTREF(__pyx_t_6);
        __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_5); __pyx_t_5 = NULL;
        __Pyx_GIVEREF(__pyx_t_3);
        PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_3);
        __pyx_t_3 = 0;
        __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_6, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
        __Pyx_GOTREF(__pyx_t_2);
        __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
      }
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
      __pyx_t_7 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_7 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
      __pyx_r = __pyx_t_7;
      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
      goto __pyx_L0;
    }
    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  }
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_XDECREF(__pyx_t_5);
  __Pyx_XDECREF(__pyx_t_6);
  __Pyx_WriteUnraisable("_cython_magic_207f54e3e5ad780456f48229a083fca4.Graph.has_node", __pyx_clineno, __pyx_lineno, __pyx_filename, 0, 0);
  __pyx_r = 0;
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_1has_node(PyObject *__pyx_v_self, PyObject *__pyx_arg_node); /*proto*/
static PyObject *__pyx_pw_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_1has_node(PyObject *__pyx_v_self, PyObject *__pyx_arg_node) {
  int __pyx_v_node;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("has_node (wrapper)", 0);
  assert(__pyx_arg_node); {
    __pyx_v_node = __Pyx_PyInt_As_int(__pyx_arg_node); if (unlikely((__pyx_v_node == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_207f54e3e5ad780456f48229a083fca4.Graph.has_node", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_has_node(((struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *)__pyx_v_self), ((int)__pyx_v_node));
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_has_node(struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *__pyx_v_self, int __pyx_v_node) {
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("has_node", 0);
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_f_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_has_node(__pyx_v_self, __pyx_v_node, 1)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_r = __pyx_t_1;
  __pyx_t_1 = 0;
  goto __pyx_L0;

  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_AddTraceback("_cython_magic_207f54e3e5ad780456f48229a083fca4.Graph.has_node", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
+11:         return self._adj.find(node) != self._adj.end()
  __pyx_r = (__pyx_v_self->_adj.find(__pyx_v_node) != __pyx_v_self->_adj.end());
  goto __pyx_L0;
 12: 
+13:     cdef void add_node(self, int new_node):
static void __pyx_f_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_add_node(struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *__pyx_v_self, int __pyx_v_new_node) {
  std::vector<int>  __pyx_v_out;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("add_node", 0);
/* … */
  /* function exit code */
  __Pyx_RefNannyFinishContext();
}
 14:         cdef vector[int] out
+15:         if not self.has_node(new_node):
  __pyx_t_1 = ((!(((struct __pyx_vtabstruct_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *)__pyx_v_self->__pyx_vtab)->has_node(__pyx_v_self, __pyx_v_new_node, 0) != 0)) != 0);
  if (__pyx_t_1) {
+16:             self._adj[new_node] = out
    (__pyx_v_self->_adj[__pyx_v_new_node]) = __pyx_v_out;
    goto __pyx_L3;
  }
  __pyx_L3:;
 17: 
+18:     def add_edge(self, int u, int v):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_3add_edge(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyObject *__pyx_pw_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_3add_edge(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  int __pyx_v_u;
  int __pyx_v_v;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("add_edge (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_u,&__pyx_n_s_v,0};
    PyObject* values[2] = {0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_u)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        case  1:
        if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_v)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("add_edge", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "add_edge") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
    }
    __pyx_v_u = __Pyx_PyInt_As_int(values[0]); if (unlikely((__pyx_v_u == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
    __pyx_v_v = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_v == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("add_edge", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_207f54e3e5ad780456f48229a083fca4.Graph.add_edge", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_2add_edge(((struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *)__pyx_v_self), __pyx_v_u, __pyx_v_v);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_2add_edge(struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *__pyx_v_self, int __pyx_v_u, int __pyx_v_v) {
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("add_edge", 0);
/* … */
  /* function exit code */
  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
  goto __pyx_L0;
  __pyx_L1_error:;
  __Pyx_AddTraceback("_cython_magic_207f54e3e5ad780456f48229a083fca4.Graph.add_edge", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
+19:         self.add_node(u)
  ((struct __pyx_vtabstruct_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *)__pyx_v_self->__pyx_vtab)->add_node(__pyx_v_self, __pyx_v_u);
+20:         self.add_node(v)
  ((struct __pyx_vtabstruct_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *)__pyx_v_self->__pyx_vtab)->add_node(__pyx_v_self, __pyx_v_v);
+21:         self._adj[u].push_back(v)
  try {
    (__pyx_v_self->_adj[__pyx_v_u]).push_back(__pyx_v_v);
  } catch(...) {
    __Pyx_CppExn2PyErr();
    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  }
+22:         self._adj[v].push_back(u)
  try {
    (__pyx_v_self->_adj[__pyx_v_v]).push_back(__pyx_v_u);
  } catch(...) {
    __Pyx_CppExn2PyErr();
    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  }
 23: 
+24:     def __getitem__(self, int u):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_5__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_u); /*proto*/
static PyObject *__pyx_pw_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_5__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_u) {
  int __pyx_v_u;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0);
  assert(__pyx_arg_u); {
    __pyx_v_u = __Pyx_PyInt_As_int(__pyx_arg_u); if (unlikely((__pyx_v_u == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_207f54e3e5ad780456f48229a083fca4.Graph.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_4__getitem__(((struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *)__pyx_v_self), ((int)__pyx_v_u));
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_4__getitem__(struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *__pyx_v_self, int __pyx_v_u) {
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("__getitem__", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_AddTraceback("_cython_magic_207f54e3e5ad780456f48229a083fca4.Graph.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
+25:         return self._adj[u]
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_1 = __pyx_convert_vector_to_py_int((__pyx_v_self->_adj[__pyx_v_u])); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_r = __pyx_t_1;
  __pyx_t_1 = 0;
  goto __pyx_L0;
 26: 
+27:     cdef vector[int] _degrees(self):
static std::vector<int>  __pyx_f_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph__degrees(struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *__pyx_v_self) {
  std::vector<int>  __pyx_v_deg;
  CYTHON_UNUSED int __pyx_v_first;
  std::map<int,std::vector<int> > ::iterator __pyx_v_it;
  std::vector<int>  __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("_degrees", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_WriteUnraisable("_cython_magic_207f54e3e5ad780456f48229a083fca4.Graph._degrees", __pyx_clineno, __pyx_lineno, __pyx_filename, 0, 0);
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 28:         cdef vector[int] deg
+29:         cdef int first = 0
  __pyx_v_first = 0;
 30:         cdef vector[int] edges
+31:         cdef cppmap[int, vector[int]].iterator it = self._adj.begin()
  __pyx_v_it = __pyx_v_self->_adj.begin();
+32:         while it != self._adj.end():
  while (1) {
    __pyx_t_1 = ((__pyx_v_it != __pyx_v_self->_adj.end()) != 0);
    if (!__pyx_t_1) break;
+33:             deg.push_back(deref(it).second.size())
    try {
      __pyx_v_deg.push_back((*__pyx_v_it).second.size());
    } catch(...) {
      __Pyx_CppExn2PyErr();
      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    }
+34:             it = inc(it)
    __pyx_v_it = (++__pyx_v_it);
  }
+35:         return deg
  __pyx_r = __pyx_v_deg;
  goto __pyx_L0;
 36: 
+37:     def degrees(self):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_7degrees(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
static PyObject *__pyx_pw_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_7degrees(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("degrees (wrapper)", 0);
  __pyx_r = __pyx_pf_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_6degrees(((struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *)__pyx_v_self));

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_207f54e3e5ad780456f48229a083fca4_5Graph_6degrees(struct __pyx_obj_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *__pyx_v_self) {
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("degrees", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_AddTraceback("_cython_magic_207f54e3e5ad780456f48229a083fca4.Graph.degrees", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
+38:         return self._degrees()
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_1 = __pyx_convert_vector_to_py_int(((struct __pyx_vtabstruct_46_cython_magic_207f54e3e5ad780456f48229a083fca4_Graph *)__pyx_v_self->__pyx_vtab)->_degrees(__pyx_v_self)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_r = __pyx_t_1;
  __pyx_t_1 = 0;
  goto __pyx_L0;
 39: 

In [95]:
g0 = Graph()

In [96]:
g0.add_edge(1, 5)
g0.add_edge(1, 6)

In [97]:
g0[1]


Out[97]:
[5, 6]

In [98]:
g0.has_node(1)


Out[98]:
1

In [99]:
g0.degrees()


Out[99]:
[2, 1, 1]

In [100]:
import networkx as nx
g = nx.barabasi_albert_graph(100000, 6)
with open('graph.txt', 'w') as fout:
    for u, v in g.edges_iter():
        fout.write('%i,%i\n' % (u, v))

In [101]:
%timeit list(g.degree())


10 loops, best of 3: 51.7 ms per loop

In [102]:
myg = Graph()
def line2edges(line):
    u, v = map(int, line.rstrip().split(','))
    return u, v

edges = map(line2edges, open('graph.txt'))

for u, v in edges:
    myg.add_edge(u, v)

In [103]:
%timeit mydeg = myg.degrees()


100 loops, best of 3: 9.83 ms per loop

Using Cython in production code

Use setup.py to build your Cython files.

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

import numpy as np

setup(
  cmdclass = {'build_ext': build_ext},
  ext_modules = [
    Extension("prange_demo", ["prange_demo.pyx"],
              include_dirs=[np.get_include()],
              extra_compile_args=['-fopenmp'],
              extra_link_args=['-fopenmp', '-lgomp']),
  ]
)

Exercise

Write a Cython module with a setup.py to run the mean-3 filter, then import from the notebook.


In [2]:
import numpy as np
from mean3 import mean3filter
mean3filter(np.random.rand(10))


Out[2]:
array([ 0.6960285 ,  0.56840097,  0.38207445,  0.28536657,  0.37981228,
        0.52849249,  0.60342301,  0.59280659,  0.59454272,  0.67086538])

Complete aside: modernizing Python 2 code


In [ ]: