Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

ListExample

IanBell edited this page · 4 revisions
Clone this wiki locally

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.