1 """
2 Output functions (see basic.py) and projection-level output functions
3 (see projfn.py) written in C to optimize performance.
4
5 Requires the weave package; without it unoptimized versions are used.
6 """
7
8 import param
9
10 from topo.base.cf import CFPOutputFn
11 from topo.base.functionfamily import TransferFn, IdentityTF
12 from topo.misc.inlinec import inline,provide_unoptimized_equivalent,c_header
13
14 from basic import DivisiveNormalizeL1
15
16
17
18 DivisiveNormalizeL1_opt=DivisiveNormalizeL1
19
20
21
22
23
25 """
26 Performs divisive normalization of the weights of all cfs.
27 Intended to be equivalent to, but faster than,
28 CFPOF_DivisiveNormalizeL1.
29 """
30 single_cf_fn = param.ClassSelector(
31 TransferFn,DivisiveNormalizeL1(norm_value=1.0),readonly=True)
32
34 cf_type=iterator.cf_type
35 cfs = iterator.flatcfs
36 num_cfs = len(iterator.flatcfs)
37
38
39
40 active_units_mask = iterator.get_active_units_mask()
41 sheet_mask = iterator.get_sheet_mask()
42
43 code = c_header + """
44 // CEBALERT: should provide a macro for getting offset
45
46 ///// GET WEIGHTS OFFSET
47 PyMemberDescrObject *weights_descr = (PyMemberDescrObject *)PyObject_GetAttrString(cf_type,"weights");
48 Py_ssize_t weights_offset = weights_descr->d_member->offset;
49 Py_DECREF(weights_descr);
50
51 ///// GET SLICE OFFSET
52 PyMemberDescrObject *slice_descr = (PyMemberDescrObject *)PyObject_GetAttrString(cf_type,"input_sheet_slice");
53 Py_ssize_t slice_offset = slice_descr->d_member->offset;
54 Py_DECREF(slice_descr);
55
56 // CB: I doubt norm_total can be a property and a slot, but maybe
57 // it could be, or maybe we could use the actual attribute...
58
59 npfloat *x = active_units_mask;
60 npfloat *m = sheet_mask;
61
62 for (int r=0; r<num_cfs; ++r) {
63 double load = *x++;
64 double msk = *m++;
65 if (load != 0 && msk != 0) {
66 PyObject *cf = PyList_GetItem(cfs,r);
67
68 PyArrayObject *weights_obj = *((PyArrayObject **)((char *)cf + weights_offset));
69 PyArrayObject *slice_obj = *((PyArrayObject **)((char *)cf + slice_offset));
70
71 PyObject *sum_obj = PyObject_GetAttrString(cf,"norm_total");
72
73 float *wi = (float *)(weights_obj->data);
74 int *slice = (int *)(slice_obj->data);
75
76 double total = PyFloat_AsDouble(sum_obj); // sum of the cf's weights
77
78 if( total > 0.0000000000001 ) {
79
80 int rr1 = *slice++;
81 int rr2 = *slice++;
82 int cc1 = *slice++;
83 int cc2 = *slice;
84
85 // normalize the weights
86 double factor = 1.0/total;
87 int rc = (rr2-rr1)*(cc2-cc1);
88 for (int i=0; i<rc; ++i) {
89 *(wi++) *= factor;
90 }
91
92 }
93
94 // Anything obtained with PyObject_GetAttrString must be explicitly freed
95 Py_DECREF(sum_obj);
96
97 // Indicate that norm_total is stale
98 PyObject_SetAttrString(cf,"_has_norm_total",Py_False);
99 }
100
101 }
102 """
103 inline(code, ['sheet_mask','active_units_mask','cfs','cf_type','num_cfs'],
104 local_dict=locals(),
105 headers=['<structmember.h>'])
106
107
137
138
139 provide_unoptimized_equivalent("CFPOF_DivisiveNormalizeL1_opt","CFPOF_DivisiveNormalizeL1",locals())
140
141
142 __all__ = list(set([k for k,v in locals().items() if isinstance(v,type) and
143 (issubclass(v,TransferFn) or issubclass(v,CFPOutputFn))]))
144