From Predictive Chemistry
Jump to: navigation, search

Class 1, an in-depth look at class structure

  • magic methods, __init__, etc.
  • class inheritance - extending something that does almost what you want
    • ex. inheriting from dict
  • isinstance() function
  • methods and calling convention - the first argument to a class method is always the class (i.e. self)
  • Binary operations __add__, __mul__, etc. - these have type class -> class -> class
  • static (immutable) vs. dynamic (mutable)
    • classes are static
    • instances are dynamic
      • unless you only initialize and don't ever change them
      • if you know it's static and __hash__ is implemented, you can use it as a key

Example - wrapping a numpy array in a static class to build a cache: <source lang="python"> from numpy import *

  1. TODO: make static!

class s_ndarray:

   def __init__(self, x):
       self.x = x
   def __hash__(self):
       return hash(self.x.__repr__())

a = s_ndarray(arange(12))

  1. array -> float

def en(x): print "Running (expensive) energy calculation." return x[0]

  1. { s_ndarray : float } -> s_ndarray -> float

def en_cached(cache, x): if x not in cache: cache[x] = en(x.x) # peel off s_ndarray and run the en function return cache[x]

cache = {} x = s_ndarray(arange(12)) y = s_ndarray(ones(12)) print en_cached(cache, x) print en_cached(cache, y)

print cache

  1. these don't need to call en

print en_cached(cache, y) print en_cached(cache, y) </source>

Class 2, python's ctypes

  • Compiling a c code as a shared object
    • the trouble with integers - always pick a fixed size!
  • loading with ctypes
    • Declaring function types.
    • Performance test

Reference: Python Docs Numpy + Ctypes Cookbook

dwt.c - run one step of a discrete wavelet transformation.

<source lang="C">

  1. include <stdint.h>

/* Calculate the step-function discrete wavelet transformation

* on the data x, placing the result in y.
*   This assumes x and y are already allocated and of size n.
* x = ababab ababab
* y = (a+b)  (b-a)

int32_t dwt(double *x, double *y, int32_t n) { int i; // index into x, moves from 0, ..., n-1 int a = 0; // index into y sum, moves from 0, ..., ceil n/2 int b = (n+1)/2; // index into y difference, moves from (ceil n/2)+1, ..., n-1

for(i=0; i<n-1; i+=2) { y[a] = 0.5*(x[i+1]+x[i]); y[b] = x[i+1]-x[i]; a += 1; b += 1; } // odd case, ceil n/2 = (n+1)/2 and we have an extra sum if(i == n-1) { y[a] = x[i]; }

return 0; } </source>

Compile the C code to a shared library using gcc:

<source lang="bash"> gcc -o -shared dwt.c </source> - load and run the object from python

<source lang="python"> from ctypes import CDLL, c_int32, c_double import numpy as np import numpy.ctypeslib as ct import os

cwd = os.path.dirname(os.path.abspath(__file__)) dw = CDLL(os.path.join(cwd, ""))

  1. Shorthand for setting function prototypes

def decl_fn(a, *args):

       a.argtypes = args[:-1]
       a.restype = args[-1]

def void_fn(a, *args):

       decl_fn(a, *(args+(None,)))

def int_fn(a, *args):

       decl_fn(a, *(args+(c_int32,)))

def dbl_fn(a, *args):

       decl_fn(a, *(args+(c_double,)))
  1. Building up common, useful data types

intarr = np.ctypeslib.ndpointer(dtype=np.int32, flags='C_CONTIGUOUS') dblarr = np.ctypeslib.ndpointer(dtype=np.float64, flags='C_CONTIGUOUS')

decl_fn(dw.dwt, dblarr, dblarr, c_int32)

def run_dwt(x): y = np.zeros(x.shape, dtype=np.float64) print dw.dwt(x.astype(np.float64), y, len(x)) return y

print run_dwt(np.arange(12)) print run_dwt(np.arange(11)) </source> - visualize the DWT by running on image data

<source lang="python"> from PIL import Image from pylab import imshow, show from dwt import run_dwt, np

  1. convert to 1-color (luminance)

img ="Mitosis.png").convert("L") x = np.array(img)

y = np.array(map(run_dwt, x))

imshow(y) show()

  1. img = Image.fromarray(y)


Here's a test image to use:

Error creating thumbnail: File missing

Image from Brooke Borel.