Package topo :: Package outputfns :: Module basic
[hide private]
[frames] | no frames]

Source Code for Module topo.outputfns.basic

  1  """ 
  2  Simple functions operating on a matrix, potentially modifying it. 
  3   
  4  These are useful for neuron output functions, normalization of 
  5  matrices, etc. 
  6   
  7  All of these function objects (callable objects) should work for 
  8  Numpy array arguments of arbitrary shape.  Some may also work for 
  9  scalars. 
 10   
 11  $Id: basic.py 8029 2008-02-19 15:16:24Z ceball $ 
 12  """ 
 13  __version__='$Revision: 8029 $' 
 14   
 15   
 16  import numpy, numpy.random 
 17  import numpy.oldnumeric as Numeric 
 18  import copy 
 19  import topo 
 20   
 21  from numpy import exp,zeros,ones 
 22  from numpy.oldnumeric import dot, exp 
 23  from math import ceil 
 24   
 25   
 26  from topo.base.sheet import activity_type 
 27  from topo.base.arrayutils import clip_lower 
 28  from topo.base.arrayutils import L2norm, norm, array_argmax 
 29  from topo.base.functionfamilies import OutputFn 
 30  from topo.base.parameterclasses import Parameter,Number,ListParameter,\ 
 31       BooleanParameter, StringParameter, ClassSelectorParameter 
 32  from topo.base.parameterizedobject import ParameterizedObject 
 33  from topo.base.patterngenerator import PatternGenerator,Constant 
 34  from topo.base.boundingregion import BoundingBox 
 35  from topo.patterns.basic import Gaussian 
 36   
 37  # Imported here so that all OutputFns will be in the same package 
 38  from topo.base.functionfamilies import IdentityOF,PipelineOF 
 39   
 40  Pipeline = PipelineOF 
 41   
 42  # CEBHACKALERT: these need to respect the mask - which will be passed in. 
 43   
 44   
45 -class PiecewiseLinear(OutputFn):
46 """ 47 Piecewise-linear OutputFn with lower and upper thresholds. 48 49 Values below the lower_threshold are set to zero, those above 50 the upper threshold are set to 1.0, and those in between are 51 scaled linearly. 52 """ 53 lower_bound = Number(default=0.0,softbounds=(0.0,1.0)) 54 upper_bound = Number(default=1.0,softbounds=(0.0,1.0)) 55
56 - def __call__(self,x):
57 fact = 1.0/(self.upper_bound-self.lower_bound) 58 x -= self.lower_bound 59 x *= fact 60 x.clip(0.0,1.0,out=x)
61 62 63
64 -class Sigmoid(OutputFn):
65 """ 66 Sigmoidal (logistic) output function: 1/(1+exp-(r*x+k)). 67 68 As defined in Jochen Triesch, ICANN 2005, LNCS 3696 pp. 65-70. 69 The parameters control the growth rate (r) and the x position (k) 70 of the exponential. 71 72 This function is a special case of the GeneralizedLogistic 73 function, with parameters r=r, l=0, u=1, m=-k/2r, and b=1. See 74 Richards, F.J. (1959), A flexible growth function for empirical 75 use. J. Experimental Botany 10: 290--300, 1959. 76 http://en.wikipedia.org/wiki/Generalised_logistic_curve 77 """ 78 79 r = Number(default=1,doc="Parameter controlling the growth rate") 80 k = Number(default=0,doc="Parameter controlling the x-postion") 81
82 - def __call__(self,x):
83 x_orig = copy.copy(x) 84 x *= 0.0 85 x += 1.0 / (1.0 + exp(-(self.r*x_orig+self.k)))
86 87 88
89 -class NakaRushton(OutputFn):
90 #JABALERT: Please write the equation into words in the docstring, as in Sigmoid. 91 """ 92 Naka-Rushton curve. 93 94 From Naka, K. and Rushton, W. (1996), S-potentials from luminosity 95 units in the retina of fish (Cyprinidae). J. Physiology 185:587-599. 96 97 The Naka-Rushton curve has been shown to be a good approximation 98 of constrast gain control in cortical neurons. The input of the 99 curve is usually contrast, but under the assumption that the 100 firing rate of a model neuron is directly proportional to the 101 contrast, it can be used as an OutputFn for a Sheet. 102 103 The parameter c50 corresponds to the contrast at which the half of 104 the maximal output is reached. For a Sheet OutputFn this translates 105 to the input for which a neuron will respond with activity 0.5. 106 """ 107 108 c50 = Number(default=0.1, doc=""" 109 The input of the neuron at which it responds at half of its maximal firing rate (1.0).""") 110 111 e = Number(default=1.0,doc="""The exponent of the input x.""") 112 113 #JABALERT: (pow(x_orig,self.e) should presumably be done only once, using a temporary
114 - def __call__(self,x):
115 #print 'A:', x 116 #print 'B:', pow(x,self.e) / (pow(x,self.e) + pow(self.c50,self.e)) 117 x_orig = copy.copy(x) 118 x *= 0 119 x += pow(x_orig,self.e) / (pow(x_orig,self.e) + pow(self.c50,self.e))
120 121 122
123 -class GeneralizedLogistic(OutputFn):
124 """ 125 The generalized logistic curve (Richards' curve): y = l + (u /(1 + b * exp(-r*(x-2*m))^(1/b))). 126 127 The logistic curve is a flexible function for specifying a 128 nonlinear growth curve using five parameters: 129 130 * l: the lower asymptote 131 * u: the upper asymptote minus l 132 * m: the time of maximum growth 133 * r: the growth rate 134 * b: affects near which asymptote maximum growth occurs 135 136 From Richards, F.J. (1959), A flexible growth function for empirical 137 use. J. Experimental Botany 10: 290--300. 138 http://en.wikipedia.org/wiki/Generalised_logistic_curve 139 """ 140 141 # JABALERT: Reword these to say what they are, not what they 142 # control, if they are anything that can be expressed naturally. 143 # E.g. is l a parameter controlling the lower asymptote, or is it 144 # simply the lower asymptote? If it's the lower asymptote, say 145 # doc="Lower asymptote.". Only if the parameter's relationship to 146 # what it controls is very indirect should it be worded as below. 147 l = Number(default=1,doc="Parameter controlling the lower asymptote.") 148 u = Number(default=1,doc="Parameter controlling the upper asymptote (upper asymptote minus lower asymptote.") 149 m = Number(default=1,doc="Parameter controlling the time of maximum growth.") 150 r = Number(default=1,doc="Parameter controlling the growth rate.") 151 b = Number(default=1,doc="Parameter which affects near which asymptote maximum growth occurs.") 152
153 - def __call__(self,x):
154 x_orig = copy.copy(x) 155 x *= 0.0 156 x += self.l + ( self.u /(1 + self.b*exp(-self.r *(x_orig - 2*self.m))**(1 / self.b)) )
157 158 159
160 -class DivisiveNormalizeL1(OutputFn):
161 """ 162 OutputFn that divides an array by its L1 norm. 163 164 This operation ensures that the sum of the absolute values of the 165 array is equal to the specified norm_value, rescaling each value 166 to make this true. The array is unchanged if the sum of absolute 167 values is zero. For arrays of non-negative values where at least 168 one is non-zero, this operation is equivalent to a divisive sum 169 normalization. 170 """ 171 norm_value = Number(default=1.0) 172
173 - def __call__(self,x):
174 """L1-normalize the input array, if it has a nonzero sum.""" 175 current_sum = 1.0*Numeric.sum(abs(x.ravel())) 176 if current_sum != 0: 177 factor = (self.norm_value/current_sum) 178 x *= factor
179 180 181
182 -class DivisiveNormalizeL2(OutputFn):
183 """ 184 OutputFn to divide an array by its Euclidean length (aka its L2 norm). 185 186 For a given array interpreted as a flattened vector, keeps the 187 Euclidean length of the vector at a specified norm_value. 188 """ 189 norm_value = Number(default=1.0) 190
191 - def __call__(self,x):
192 tot = 1.0*L2norm(x.ravel()) 193 if tot != 0: 194 factor = (self.norm_value/tot) 195 x *= factor
196 197 198
199 -class DivisiveNormalizeLinf(OutputFn):
200 """ 201 OutputFn to divide an array by its L-infinity norm 202 (i.e. the maximum absolute value of its elements). 203 204 For a given array interpreted as a flattened vector, scales the 205 elements divisively so that the maximum absolute value is the 206 specified norm_value. 207 208 The L-infinity norm is also known as the divisive infinity norm 209 and Chebyshev norm. 210 """ 211 norm_value = Number(default=1.0) 212
213 - def __call__(self,x):
214 tot = 1.0*max(abs(x.ravel())) 215 if tot != 0: 216 factor = (self.norm_value/tot) 217 x *= factor
218 219 220
221 -class DivisiveNormalizeLp(OutputFn):
222 """ 223 OutputFn to divide an array by its Lp-Norm, where p is specified. 224 225 For a parameter p and a given array interpreted as a flattened 226 vector, keeps the Lp-norm of the vector at a specified norm_value. 227 Faster versions are provided separately for the typical L1-norm 228 and L2-norm cases. Defaults to be the same as an L2-norm, i.e., 229 DivisiveNormalizeL2. 230 """ 231 p = Number(default=2) 232 norm_value = Number(default=1.0) 233
234 - def __call__(self,x):
235 tot = 1.0*norm(x.ravel(),self.p) 236 if tot != 0: 237 factor = (self.norm_value/tot) 238 x *=factor
239 240 241
242 -class HalfRectifyAndSquare(OutputFn):
243 """ 244 Output function that applies a half-wave rectification (clips at zero) 245 and then squares the values. 246 """ 247 lower_bound = Number(default=0.0,softbounds=(0.0,1.0)) 248
249 - def __call__(self,x):
250 clip_lower(x,self.lower_bound) 251 x *= x
252 253 254
255 -class HalfRectify(OutputFn):
256 """ 257 Output function that applies a half-wave rectification (clips at zero) 258 259 """ 260 lower_bound = Number(default=0.0,softbounds=(0.0,1.0)) 261
262 - def __call__(self,x):
264 265 266
267 -class Square(OutputFn):
268 """Output function that applies a squaring nonlinearity.""" 269
270 - def __call__(self,x):
271 x *= x
272 273 274
275 -class BinaryThreshold(OutputFn):
276 """ 277 Forces all values below a threshold to zero, and above it to 1.0. 278 """ 279 threshold = Number(default=0.25, doc="Decision point for determining binary value.") 280
281 - def __call__(self,x):
282 above_threshold = x>=self.threshold 283 x *= 0.0 284 x += above_threshold
285 286 287 288 ### JABALERT: Is this the right location for this class? It brings in 289 ### dependencies on PatternGenerator, which is not something that many 290 ### OutputFns will need.
291 -class PatternCombine(OutputFn):
292 """ 293 Combine the supplied pattern with one generated using a 294 PatternGenerator. 295 296 Useful for operations like adding noise or masking out lesioned 297 items or around the edges of non-rectangular shapes. 298 """ 299 generator = ClassSelectorParameter(PatternGenerator, 300 default=Constant(), doc=""" 301 Pattern to combine with the supplied matrix.""") 302 303 operator = Parameter(numpy.multiply,precedence=0.98,doc=""" 304 Binary Numeric function used to combine the two patterns. 305 306 Any binary Numeric array "ufunc" returning the same type of 307 array as the operands and supporting the reduce operator is 308 allowed here. See topo.patterns.basic.Composite.operator for 309 more details. 310 """) 311
312 - def __call__(self,x):
313 ###JABHACKALERT: Need to set it up to be independent of 314 #density; right now only things like random numbers work 315 #reasonably 316 rows,cols = x.shape 317 bb = BoundingBox(points=((0,0), (rows,cols))) 318 new_pattern = self.operator(x, self.