Package topo :: Package responsefns :: Module optimized
[hide private]
[frames] | no frames]

Source Code for Module topo.responsefns.optimized

  1  """ 
  2  Response functions (see basic.py) and CFProjection response functions 
  3  (see projfns.py) written in C to optimize performance. 
  4   
  5  Requires the weave package; without it unoptimized versions are used. 
  6   
  7  $Id: optimized.py 8030 2008-02-19 15:47:09Z ceball $ 
  8  """ 
  9  __version__='$Revision: 8030 $' 
 10   
 11  from topo.base.functionfamilies import ResponseFn,DotProduct 
 12  from topo.base.cf import CFPResponseFn, CFPRF_Plugin 
 13  from topo.base.parameterclasses import ClassSelectorParameter 
 14   
 15  from topo.misc.inlinec import inline, provide_unoptimized_equivalent 
 16   
 17  from topo.responsefns.projfns import CFPRF_EuclideanDistance 
 18   
19 -class CFPRF_DotProduct_opt(CFPResponseFn):
20 """ 21 Dot-product response function. 22 23 Written in C for a manyfold speedup; see CFPRF_DotProduct for an 24 easier-to-read version in Python. The unoptimized Python version 25 is equivalent to this one, but it also works for 1D arrays. 26 """ 27 28 single_cf_fn = ClassSelectorParameter(ResponseFn,DotProduct(),readonly=True) 29
30 - def __call__(self, iterator, input_activity, activity, strength, **params):
31 32 temp_act = activity 33 rows,cols = activity.shape 34 irows,icols = input_activity.shape 35 X = input_activity.ravel() 36 cfs = iterator.proj._cfs 37 mask = iterator.proj.dest.mask.data 38 39 code = """ 40 double *tact = temp_act; 41 float *wj; 42 PyArrayObject *array; 43 44 for (int r=0; r<rows; ++r) { 45 PyObject *cfsr = PyList_GetItem(cfs,r); 46 for (int l=0; l<cols; ++l) { 47 if((*mask++) == 0.0) 48 *tact = 0; 49 else { 50 PyObject *cf = PyList_GetItem(cfsr,l); 51 PyObject *weights_obj = PyObject_GetAttrString(cf,"weights"); 52 PyObject *slice_obj = PyObject_GetAttrString(cf,"input_sheet_slice"); 53 54 // This code is optimized for contiguous arrays, which are typical, 55 // but we make it work for noncontiguous arrays (e.g. views) by 56 // creating a contiguous copy if necessary. 57 array=0; 58 if(PyArray_ISCONTIGUOUS((PyArrayObject*)weights_obj)) 59 wj = (float *)(((PyArrayObject*)weights_obj)->data); 60 else { 61 array = (PyArrayObject*) PyArray_ContiguousFromObject(weights_obj,PyArray_FLOAT,2,2); 62 wj = (float *) array->data; 63 } 64 int *slice = (int *)(((PyArrayObject*)slice_obj)->data); 65 66 int rr1 = *slice++; 67 int rr2 = *slice++; 68 int cc1 = *slice++; 69 int cc2 = *slice; 70 double tot = 0.0; 71 double *xj = X+icols*rr1+cc1; 72 73 // computes the dot product 74 for (int i=rr1; i<rr2; ++i) { 75 double *xi = xj; 76 float *wi = wj; 77 for (int j=cc1; j<cc2; ++j) { 78 tot += *wi * *xi; 79 ++wi; 80 ++xi; 81 } 82 xj += icols; 83 wj += cc2-cc1; 84 } 85 *tact = tot*strength; 86 87 88 // Anything obtained with PyObject_GetAttrString must be explicitly freed 89 Py_DECREF(weights_obj); 90 Py_DECREF(slice_obj); 91 92 if(array != 0) 93 Py_DECREF(array); 94 } 95 ++tact; 96 } 97 } 98 """ 99 inline(code, ['mask','X', 'strength', 'icols', 'temp_act','cfs','cols','rows'], local_dict=locals())
100
101 -class CFPRF_DotProduct(CFPRF_Plugin):
102 """ 103 Wrapper written to allow transparent non-optimized fallback; 104 equivalent to CFPRF_Plugin(single_cf_fn=DotProduct()). 105 """ 106 # CB: should probably have single_cf_fn here & readonly
107 - def __init__(self,**params):
109 110 provide_unoptimized_equivalent("CFPRF_DotProduct_opt","CFPRF_DotProduct",locals()) 111 112 113
114 -class CFPRF_EuclideanDistance_opt(CFPResponseFn):
115 """ 116 Euclidean-distance response function. 117 118 Written in C for a several-hundred-times speedup; see 119 CFPRF_EuclideanDistance for an easier-to-read (but otherwise 120 equivalent) version in Python. 121 """
122 - def __call__(self, iterator, input_activity, activity, strength, **params):
123 temp_act = activity 124 rows,cols = activity.shape 125 irows,icols = input_activity.shape 126 X = input_activity.ravel() 127 cfs = iterator.proj._cfs 128 129 code = """ 130 #include <math.h> 131 double *tact = temp_act; 132 double max_dist=0.0; 133 134 for (int r=0; r<rows; ++r) { 135 PyObject* cfsr = PyList_GetItem(cfs,r); 136 for (int l=0; l<cols; ++l) { 137 PyObject *cf = PyList_GetItem(cfsr,l); 138 PyObject *weights_obj = PyObject_GetAttrString(cf,"weights"); 139 PyObject *slice_obj = PyObject_GetAttrString(cf,"input_sheet_slice"); 140 141 float *wj = (float *)(((PyArrayObject*)weights_obj)->data); 142 int *slice = (int *)(((PyArrayObject*)slice_obj)->data); 143 144 int rr1 = *slice++; 145 int rr2 = *slice++; 146 int cc1 = *slice++; 147 int cc2 = *slice; 148 149 double *xj = X+icols*rr1+cc1; 150 151 // computes the dot product 152 double tot = 0.0; 153 for (int i=rr1; i<rr2; ++i) { 154 double *xi = xj; 155 float *wi = wj; 156 for (int j=cc1; j<cc2; ++j) { 157 double diff = *wi - *xi; 158 tot += diff*diff; 159 ++wi; 160 ++xi; 161 } 162 xj += icols; 163 wj += cc2-cc1; 164 } 165 166 double euclidean_distance = sqrt(tot); 167 if (euclidean_distance>max_dist) 168 max_dist = euclidean_distance; 169 170 *tact = euclidean_distance; 171 ++tact; 172 173 // Anything obtained with PyObject_GetAttrString must be explicitly freed 174 Py_DECREF(weights_obj); 175 Py_DECREF(slice_obj); 176 } 177 } 178 tact = temp_act; 179 for (int r=0; r<rows; ++r) { 180 for (int l=0; l<cols; ++l) { 181 *tact = strength*(max_dist - *tact); 182 ++tact; 183 } 184 } 185 """ 186 inline(code, ['X', 'strength', 'icols', 'temp_act','cfs','cols','rows'], local_dict=locals())
187 188 provide_unoptimized_equivalent("CFPRF_EuclideanDistance_opt","CFPRF_EuclideanDistance",locals()) 189