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
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
102 """
103 Wrapper written to allow transparent non-optimized fallback;
104 equivalent to CFPRF_Plugin(single_cf_fn=DotProduct()).
105 """
106
109
110 provide_unoptimized_equivalent("CFPRF_DotProduct_opt","CFPRF_DotProduct",locals())
111
112
113
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