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

Source Code for Module topo.transferfn.optimized

  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  # For backwards compatibility when loading pickled files; can be deleted 
 18  DivisiveNormalizeL1_opt=DivisiveNormalizeL1 
 19   
 20   
 21  # JABALERT: Need to remove 0.0000000000001 constant; 
 22  # currently needed to avoid divide-by-zero issues 
 23  # in some cases, but should be replaced. 
24 -class CFPOF_DivisiveNormalizeL1_opt(CFPOutputFn):
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
33 - def __call__(self, iterator, **params):
34 cf_type=iterator.cf_type 35 cfs = iterator.flatcfs 36 num_cfs = len(iterator.flatcfs) 37 38 # CB: for performance, it is better to process the masks in 39 # the C code (rather than combining them before). 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
108 -class CFPOF_DivisiveNormalizeL1(CFPOutputFn):
109 """ 110 Non-optimized version of CFPOF_DivisiveNormalizeL1_opt. 111 112 Same as CFPOF_Plugin(single_cf_fn=DivisiveNormalizeL1()), except 113 that it supports joint normalization using the norm_total 114 property of ConnectionField. 115 """ 116 117 single_cf_fn = param.ClassSelector( 118 TransferFn,default=DivisiveNormalizeL1(norm_value=1.0),constant=True) 119
120 - def __call__(self, iterator, **params):
121 """ 122 Uses the cf.norm_total attribute to allow optimization 123 by computing the sum separately, and to allow joint 124 normalization. After use, cf.norm_total is deleted because 125 the value it would have has been changed. 126 """ 127 # CEBALERT: fix this here and elsewhere 128 if type(self.single_cf_fn) is not IdentityTF: 129 single_cf_fn = self.single_cf_fn 130 norm_value = self.single_cf_fn.norm_value 131 for cf,i in iterator(): 132 current_sum=cf.norm_total 133 if current_sum > 0.0000000000001: 134 factor = norm_value/current_sum 135 cf.weights *= factor 136 del cf.norm_total
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