def test_preference(self): for i in range(3): for j in range(2): self.assertAlmostEqual(self.fm1.weighted_average()[i,j], 0.5) self.assertAlmostEqual(self.fm2.weighted_average()[i,j], 0.5) # To test the update function self.fm1.update(self.a1,0.7) self.fm2.update(self.a1,0.7) for i in range(3): for j in range(2): self.assertAlmostEqual(self.fm1.weighted_average()[i,j], 0.6) vect_sum = wrap(0,1,arg(exp(0.7*2*pi*1j)+exp(0.5*2*pi*1j))/(2*pi)) self.assertAlmostEqual(self.fm2.weighted_average()[i,j],vect_sum) # To test the keep_peak=True self.fm1.update(self.a1,0.7) self.fm2.update(self.a1,0.7) for i in range(3): for j in range(2): self.assertAlmostEqual(self.fm1.weighted_average()[i,j], 0.6) vect_sum =wrap(0,1,arg(exp(0.7*2*pi*1j)+exp(0.5*2*pi*1j))/(2*pi)) self.assertAlmostEqual(self.fm2.weighted_average()[i,j],vect_sum) self.fm1.update(self.a2,0.7) self.fm2.update(self.a2,0.7) for i in range(3): for j in range(2): self.assertAlmostEqual(self.fm1.weighted_average()[i,j], 0.65) vect_sum =wrap(0,1,arg(3*exp(0.7*2*pi*1j)+exp(0.5*2*pi*1j))/(2*pi)) self.assertAlmostEqual(self.fm2.weighted_average()[i,j],vect_sum) # to even test more.... self.fm1.update(self.a3,0.9) self.fm2.update(self.a3,0.9) for i in range(3): self.assertAlmostEqual(self.fm1.weighted_average()[i,0], 0.65) self.assertAlmostEqual(self.fm1.weighted_average()[i,1], 0.7) vect_sum = wrap(0,1,arg(3*exp(0.7*2*pi*1j)+exp(0.5*2*pi*1j))/(2*pi)) self.assertAlmostEqual(self.fm2.weighted_average()[i,0],vect_sum) vect_sum = wrap(0,1,arg(3*exp(0.7*2*pi*1j)+exp(0.5*2*pi*1j)+exp(0.9*2*pi*1j))/(2*pi)) self.assertAlmostEqual(self.fm2.weighted_average()[i,1],vect_sum)
def vector_sum(self, d): """ Return the vector sum of the distribution as a tuple (magnitude, avgbinnum). Each bin contributes a vector of length equal to its value, at a direction corresponding to the bin number. Specifically, the total bin number range is mapped into a direction range [0,2pi]. For a cyclic distribution, the avgbinnum will be a continuous measure analogous to the max_value_bin() of the distribution. But this quantity has more precision than max_value_bin() because it is computed from the entire distribution instead of just the peak bin. However, it is likely to be useful only for uniform or very dense sampling; with sparse, non-uniform sampling the estimates will be biased significantly by the particular samples chosen. The avgbinnum is not meaningful when the magnitude is 0, because a zero-length vector has no direction. To find out whether such cases occurred, you can compare the value of undefined_vals before and after a series of calls to this function. """ # vectors are represented in polar form as complex numbers h = d._data r = h.values() theta = d._bins_to_radians(array(h.keys())) v_sum = innerproduct(r, exp(theta * 1j)) magnitude = abs(v_sum) direction = arg(v_sum) if v_sum == 0: d.undefined_vals += 1 direction_radians = d._radians_to_bins(direction) # wrap the direction because arctan2 returns principal values wrapped_direction = wrap(d.axis_bounds[0], d.axis_bounds[1], direction_radians) return (magnitude, wrapped_direction)
def vector_sum(self, d ): """ Return the vector sum of the distribution as a tuple (magnitude, avgbinnum). Each bin contributes a vector of length equal to its value, at a direction corresponding to the bin number. Specifically, the total bin number range is mapped into a direction range [0,2pi]. For a cyclic distribution, the avgbinnum will be a continuous measure analogous to the max_value_bin() of the distribution. But this quantity has more precision than max_value_bin() because it is computed from the entire distribution instead of just the peak bin. However, it is likely to be useful only for uniform or very dense sampling; with sparse, non-uniform sampling the estimates will be biased significantly by the particular samples chosen. The avgbinnum is not meaningful when the magnitude is 0, because a zero-length vector has no direction. To find out whether such cases occurred, you can compare the value of undefined_vals before and after a series of calls to this function. """ # vectors are represented in polar form as complex numbers h = d._data r = h.values() theta = d._bins_to_radians(array( h.keys() )) v_sum = innerproduct(r, exp(theta*1j)) magnitude = abs(v_sum) direction = arg(v_sum) if v_sum == 0: d.undefined_vals += 1 direction_radians = d._radians_to_bins(direction) # wrap the direction because arctan2 returns principal values wrapped_direction = wrap(d.axis_bounds[0], d.axis_bounds[1], direction_radians) return (magnitude, wrapped_direction)
def test_preference(self): for i in range(3): for j in range(2): self.assertAlmostEqual(weighted_average(self.fm1)[i, j], 0.5) self.assertAlmostEqual(weighted_average(self.fm2)[i, j], 0.5) # To test the update function self.fm1.update(self.a1, 0.7) self.fm2.update(self.a1, 0.7) for i in range(3): for j in range(2): self.assertAlmostEqual(weighted_average(self.fm1)[i, j], 0.6) vect_sum = wrap( 0, 1, arg(exp(0.7 * 2 * pi * 1j) + exp(0.5 * 2 * pi * 1j)) / (2 * pi)) self.assertAlmostEqual( weighted_average(self.fm2)[i, j], vect_sum) # To test the keep_peak=True self.fm1.update(self.a1, 0.7) self.fm2.update(self.a1, 0.7) for i in range(3): for j in range(2): self.assertAlmostEqual(weighted_average(self.fm1)[i, j], 0.6) vect_sum = wrap( 0, 1, arg(exp(0.7 * 2 * pi * 1j) + exp(0.5 * 2 * pi * 1j)) / (2 * pi)) self.assertAlmostEqual( weighted_average(self.fm2)[i, j], vect_sum) self.fm1.update(self.a2, 0.7) self.fm2.update(self.a2, 0.7) for i in range(3): for j in range(2): self.assertAlmostEqual(weighted_average(self.fm1)[i, j], 0.65) vect_sum = wrap( 0, 1, arg(3 * exp(0.7 * 2 * pi * 1j) + exp(0.5 * 2 * pi * 1j)) / (2 * pi)) self.assertAlmostEqual( weighted_average(self.fm2)[i, j], vect_sum) # to even test more.... self.fm1.update(self.a3, 0.9) self.fm2.update(self.a3, 0.9) for i in range(3): self.assertAlmostEqual(weighted_average(self.fm1)[i, 0], 0.65) self.assertAlmostEqual(weighted_average(self.fm1)[i, 1], 0.7) vect_sum = wrap( 0, 1, arg(3 * exp(0.7 * 2 * pi * 1j) + exp(0.5 * 2 * pi * 1j)) / (2 * pi)) self.assertAlmostEqual(weighted_average(self.fm2)[i, 0], vect_sum) vect_sum = wrap( 0, 1, arg(3 * exp(0.7 * 2 * pi * 1j) + exp(0.5 * 2 * pi * 1j) + exp(0.9 * 2 * pi * 1j)) / (2 * pi)) self.assertAlmostEqual(weighted_average(self.fm2)[i, 1], vect_sum)
def get_input_params(old_compat=False): """ Return iterators over list of float values for C++ LISSOM's cx, cy, and theta for multiple eyes, as well as sign. Expects log file with values held in lines like this:: 'Iteration: 000000 [Eye0 [Obj0 cx:02.1 cy:11.6 theta:074.0]]\n' or this: 'Iteration: 000000 [Eye0 [Obj0 cx:23.4 cy:10.0 theta:059.6]] [Eye1 [Obj0 cx:22.6 cy:10.5 theta:059.6]] [Eye2 [Obj0 cx:21.7 cy:11.1 theta:059.6]] [Eye3 [Obj0 cx:20.8 cy:11.6 theta:059.6]]\n' """ logfile = filename_base + "log" print "Reading input params from %s" % logfile f = open(logfile, "r") # first iter is test in c++ lissom; use to get num eyes n_eyes = len(f.readline().split("Eye")[1::]) input_params = dict([(i, dict(cx=list(), cy=list(), theta=list(), sign=list())) for i in range(n_eyes)]) lines = f.readlines() for line, lineno in zip(lines, range(len(lines))): eyes = line.split("Eye")[1::] for eye, i in zip(eyes, range(n_eyes)): # e.g. eye='1 [Obj0 cx:-0.2 cy:13.8 theta:011.7]] [' cx, cy, theta = [W.split(":")[1].split("]")[0] for W in eye.split(" ")[2:5]] if not old_compat: for X in ["cx", "cy", "theta"]: input_params[i][X].append(round(float(locals()[X]), 1)) else: # old compat: log file with degrees etc input_params[i]["cx"].append(float(cx)) input_params[i]["cy"].append(float(cy)) input_params[i]["theta"].append(float(theta)) del cx del cy del theta if len(eyes) > 1: # CeBALERLT: not general (assuming motion just because more than 1 eye) ##### get sign X1 = complex(input_params[0]["cx"][lineno], input_params[0]["cy"][lineno]) X2 = complex(input_params[len(eyes) - 1]["cx"][lineno], input_params[len(eyes) - 1]["cy"][lineno]) realdir = arg(X2 - X1) # for 0<=realdir<2pi (instead of -pi<=realdir<pi) if realdir < 0: realdir += 2 * pi topo_dir = input_params[0]["theta"][lineno] + pi / 2 # dir that will be given to topographica # if realdir & topo_dir aren't the same, it's because # c lissom used sign=-1 (& the dirs will be pi apart) E = 0.05 # (imprecision from getting dir from 1-dp positions) if abs(realdir - topo_dir) < E: s = 1 elif pi - E <= abs(realdir - topo_dir) < pi + E: s = -1 else: assert False # if using speed=0, just replace this line with s=0 # CEBALERT: should actually handle that case! ##### for i in range(n_eyes): input_params[i]["sign"].append(s) for i in input_params: for val in input_params[i]: input_params[i][val] = iter(input_params[i][val]) return len(lines), input_params
def get_input_params(old_compat=False): """ Return iterators over list of float values for C++ LISSOM's cx, cy, and theta for multiple eyes, as well as sign. Expects log file with values held in lines like this:: 'Iteration: 000000 [Eye0 [Obj0 cx:02.1 cy:11.6 theta:074.0]]\n' or this: 'Iteration: 000000 [Eye0 [Obj0 cx:23.4 cy:10.0 theta:059.6]] [Eye1 [Obj0 cx:22.6 cy:10.5 theta:059.6]] [Eye2 [Obj0 cx:21.7 cy:11.1 theta:059.6]] [Eye3 [Obj0 cx:20.8 cy:11.6 theta:059.6]]\n' """ logfile = filename_base + 'log' print "Reading input params from %s" % logfile f = open(logfile, 'r') # first iter is test in c++ lissom; use to get num eyes n_eyes = len(f.readline().split('Eye')[1::]) input_params = dict([(i, dict(cx=list(), cy=list(), theta=list(), sign=list())) for i in range(n_eyes)]) lines = f.readlines() for line, lineno in zip(lines, range(len(lines))): eyes = line.split('Eye')[1::] for eye, i in zip(eyes, range(n_eyes)): # e.g. eye='1 [Obj0 cx:-0.2 cy:13.8 theta:011.7]] [' cx, cy, theta = [ W.split(":")[1].split("]")[0] for W in eye.split(" ")[2:5] ] if not old_compat: for X in ['cx', 'cy', 'theta']: input_params[i][X].append(round(float(locals()[X]), 1)) else: # old compat: log file with degrees etc input_params[i]['cx'].append(float(cx)) input_params[i]['cy'].append(float(cy)) input_params[i]['theta'].append(float(theta)) del cx del cy del theta if len( eyes ) > 1: # CeBALERLT: not general (assuming motion just because more than 1 eye) ##### get sign X1 = complex(input_params[0]['cx'][lineno], input_params[0]['cy'][lineno]) X2 = complex(input_params[len(eyes) - 1]['cx'][lineno], input_params[len(eyes) - 1]['cy'][lineno]) realdir = arg(X2 - X1) # for 0<=realdir<2pi (instead of -pi<=realdir<pi) if realdir < 0: realdir += 2 * pi topo_dir = input_params[0]['theta'][ lineno] + pi / 2 # dir that will be given to topographica # if realdir & topo_dir aren't the same, it's because # c lissom used sign=-1 (& the dirs will be pi apart) E = 0.05 # (imprecision from getting dir from 1-dp positions) if abs(realdir - topo_dir) < E: s = 1 elif pi - E <= abs(realdir - topo_dir) < pi + E: s = -1 else: assert False # if using speed=0, just replace this line with s=0 # CEBALERT: should actually handle that case! ##### for i in range(n_eyes): input_params[i]['sign'].append(s) for i in input_params: for val in input_params[i]: input_params[i][val] = iter(input_params[i][val]) return len(lines), input_params