Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

The use of numpy arrays, or CPython lists for doing element-wise operations (addition, subtraction, multiplication, division) is quite slow if the arrays you are operating on are relatively small (~10 elements). The overhead of array creation further penalizes the numpy solution in particular. Using a subclassed CPython list in Cython you can achieve better speed than either the numpy solution or the CPython list. In the attachment zip file attachment:listmath.zip are included a pure-Python subclassed list implementation of the four fundamental operations, a Cython implementation of the same, and a distutils setup file. The Cython extension can be created by running

python setup.py build_ext --inplace

in the folder that the files are in.

Then the file listmath.py can be run which times an element-wise operation should provide the output something like

Using listm [the pure-Python subclassed list], time is 3.35039 us/call
Using numpy, time is 1.97892 us/call
Using Cython extension type, time is 0.947084 us/call

So the Cython version is 2 times faster than even the numpy solution, and has simple syntax that parallels that of the numpy code.

Essentially the Cython solution overloads the +,*,/,- operators and uses the Cython special methods. So you could create a listm instance from a "normal" list by doing

from _listmath import listm
a=[1,2,3]
am=listm(a)

like is done in the benchmarking code in listmath.py. Finally here is the code for the math-enabled list:

___listmath.pyx__

import cython
cimport cython

cdef class listm(list):
    """
    See http://docs.cython.org/src/userguide/special_methods.html
    """
    def __add__(self,y):
        cdef int i,N

        if isinstance(self,listm):
            N=len(self)
            if isinstance(y,int) or isinstance(y,float):
                return listm([self[i]+y for i in range(N)])
            else:
                return listm([self[i]+y[i] for i in range(N)])
        else:
            ### it is backwards, self is something else, y is a listm
            N=len(y)
            if isinstance(self,int) or isinstance(self,float):
                return listm([y[i]+self for i in range(N)])
            else:
                return listm([self[i]+y[i] for i in range(N)])

    def __mul__(self,y):
        cdef int i,N

        if isinstance(self,listm):
            N=len(self)
            if isinstance(y,int) or isinstance(y,float):
                return listm([self[i]*y for i in range(N)])
            else:
                return listm([self[i]*y[i] for i in range(N)])
        else:
            ### it is backwards, self is something else, y is a listm
            N=len(y)
            if isinstance(self,int) or isinstance(self,float):
                return listm([y[i]*self for i in range(N)])
            else:
                return listm([self[i]*y[i] for i in range(N)])

    def __truediv__(self,y):
        cdef int i,N

        if isinstance(self,listm):
            N=len(self)
            if isinstance(y,int) or isinstance(y,float):
                return listm([self[i]/y for i in range(N)])
            else:
                return listm([self[i]/y[i] for i in range(N)])
        else:
            ### it is backwards, self is something else, y is a listm
            N=len(y)
            if isinstance(self,int) or isinstance(self,float):
                return listm([self/y[i] for i in range(N)])
            else:
                return listm([self[i]/y[i] for i in range(N)])

    def __sub__(self,y):
        cdef int i,N

        if isinstance(self,listm):
            N=len(self)
            if isinstance(y,int) or isinstance(y,float):
                return listm([self[i]-y for i in range(N)])
            else:
                return listm([self[i]-y[i] for i in range(N)])
        else:
            ### it is backwards, self is something else, y is a listm
            N=len(y)
            if isinstance(self,int) or isinstance(self,float):
                return listm([self-y[i] for i in range(N)])
            else:
                return listm([self[i]-y[i] for i in range(N)])
Something went wrong with that request. Please try again.