def test_hetero_neurons(Simulator, rng, seed): n_neurons = 100 dt = 0.001 T = 0.1 dims_in = 2 taus = nengo.dists.Uniform(0.001, 0.1).sample(n_neurons, rng=rng) synapses = [Lowpass(tau) for tau in taus] encoders = sphere.sample(n_neurons, dims_in, rng=rng) hs = HeteroSynapse(synapses, dt) def embed_encoders(x): # Reshapes the vectors to be the same dimensionality as the # encoders, and then takes the dot product row by row. # See http://stackoverflow.com/questions/26168363/ for a more # efficient solution. return np.sum(encoders * hs.from_vector(x), axis=1) with Network(seed=seed) as model: # Input stimulus stim = nengo.Node(size_in=dims_in) for i in range(dims_in): nengo.Connection(nengo.Node( output=nengo.processes.WhiteSignal(T, high=10, seed=seed)), stim[i], synapse=None) # HeteroSynapse node syn = nengo.Node(size_in=dims_in, output=hs) # For comparing results x = [ nengo.Ensemble(n_neurons, dims_in, seed=0, encoders=encoders) for _ in range(2) ] # expected, actual # Expected for i, synapse in enumerate(synapses): t = np.zeros_like(encoders) t[i, :] = encoders[i, :] nengo.Connection(stim, x[0].neurons, transform=t, synapse=synapse) # Actual nengo.Connection(stim, syn, synapse=None) nengo.Connection(syn, x[1].neurons, function=embed_encoders, synapse=None) # Probes p_exp = nengo.Probe(x[0].neurons, synapse=None) p_act = nengo.Probe(x[1].neurons, synapse=None) # Check correctness with Simulator(model, dt=dt) as sim: sim.run(T) assert np.allclose(sim.data[p_act], sim.data[p_exp])
def delayed_synapse(): a = 0.1 # desired delay b = 0.01 # synapse delay tau = 0.01 # recurrent tau hz = 15 # input frequency t = 1.0 # simulation time dt = 0.00001 # simulation timestep order = 6 # order of pade approximation tau_probe = 0.02 dexp_synapse = DoubleExp(tau, tau / 5) sys_lambert = lambert_delay(a, b, tau, order - 1, order) synapse = (cont2discrete(Lowpass(tau), dt=dt) * DiscreteDelay(int(b / dt))) n_neurons = 2000 neuron_type = PerfectLIF() A, B, C, D = sys_lambert.observable.transform(5*np.eye(order)).ss sys_normal = PadeDelay(a, order) assert len(sys_normal) == order with Network(seed=0) as model: stim = Node(output=WhiteSignal(t, high=hz, y0=0)) x = EnsembleArray(n_neurons / order, len(A), neuron_type=neuron_type) output = Node(size_in=1) Connection(x.output, x.input, transform=A, synapse=synapse) Connection(stim, x.input, transform=B, synapse=synapse) Connection(x.output, output, transform=C, synapse=None) Connection(stim, output, transform=D, synapse=None) lowpass_delay = LinearNetwork( sys_normal, n_neurons_per_ensemble=n_neurons / order, synapse=tau, input_synapse=tau, dt=None, neuron_type=neuron_type, radii=1.0) Connection(stim, lowpass_delay.input, synapse=None) dexp_delay = LinearNetwork( sys_normal, n_neurons_per_ensemble=n_neurons / order, synapse=dexp_synapse, input_synapse=dexp_synapse, dt=None, neuron_type=neuron_type, radii=1.0) Connection(stim, dexp_delay.input, synapse=None) p_stim = Probe(stim, synapse=tau_probe) p_output_delayed = Probe(output, synapse=tau_probe) p_output_lowpass = Probe(lowpass_delay.output, synapse=tau_probe) p_output_dexp = Probe(dexp_delay.output, synapse=tau_probe) with Simulator(model, dt=dt, seed=0) as sim: sim.run(t) return (a, dt, sim.trange(), sim.data[p_stim], sim.data[p_output_delayed], sim.data[p_output_lowpass], sim.data[p_output_dexp])
def test_impulse(): dt = 0.001 tau = 0.005 length = 500 delta = np.zeros(length) # TODO: turn into a little helper? delta[1] = 1. / dt # starts at 1 to compensate for delay removed by nengo sys = Lowpass(tau) response = impulse(sys, dt, length) assert np.allclose(response[0], 0) # should give the same result as using filt assert np.allclose(response, sys.filt(delta, dt)) # should also accept discrete systems dss = cont2discrete(sys, dt=dt) assert not dss.analog assert np.allclose(response, impulse(dss, dt=None, length=length) / dt)
def test_hetero_vector(Simulator, rng, seed): n_neurons = 20 dt = 0.0005 T = 0.1 dims_in = 2 synapses = [Alpha(0.1), Lowpass(0.005)] assert dims_in == len(synapses) encoders = sphere.sample(n_neurons, dims_in, rng=rng) with Network(seed=seed) as model: # Input stimulus stim = nengo.Node(size_in=dims_in) for i in range(dims_in): nengo.Connection(nengo.Node( output=nengo.processes.WhiteSignal(T, high=10, seed=seed)), stim[i], synapse=None) # HeteroSynapse Nodes syn_elemwise = nengo.Node(size_in=dims_in, output=HeteroSynapse(synapses, dt, elementwise=True)) # For comparing results x = [ nengo.Ensemble(n_neurons, dims_in, seed=0, encoders=encoders) for _ in range(2) ] # expected, actual # Expected for j, synapse in enumerate(synapses): nengo.Connection(stim[j], x[0][j], synapse=synapse) # Actual nengo.Connection(stim, syn_elemwise, synapse=None) nengo.Connection(syn_elemwise, x[1], synapse=None) # Probes p_exp = nengo.Probe(x[0], synapse=None) p_act_elemwise = nengo.Probe(x[1], synapse=None) # Check correctness with Simulator(model, dt=dt) as sim: sim.run(T) assert np.allclose(sim.data[p_act_elemwise], sim.data[p_exp])
def test_invalid_discrete(): dt = 0.001 sys = cont2discrete(Lowpass(0.1), dt=dt) with pytest.raises(ValueError): discrete2cont(sys, dt=dt, method='gbt', alpha=1.1) with pytest.raises(ValueError): discrete2cont(sys, dt=0) with pytest.raises(ValueError): discrete2cont(sys, dt=dt, method=None) with pytest.raises(ValueError): discrete2cont(s, dt=dt) # already continuous with pytest.raises(ValueError): cont2discrete(z, dt=dt) # already discrete
def test_invalid_system(): with pytest.raises(ValueError): HeteroSynapse(Lowpass(0.1)) # no dt provided
def test_hetero_multi_vector(Simulator, rng, seed): n_neurons = 20 dt = 0.0005 T = 0.1 dims_in = 2 synapses = [Alpha(0.1), Lowpass(0.005), Alpha(0.02)] dims_out = len(synapses) * dims_in encoders = sphere.sample(n_neurons, dims_out, rng=rng) with Network(seed=seed) as model: # Input stimulus stim = nengo.Node(size_in=dims_in) for i in range(dims_in): nengo.Connection(nengo.Node( output=nengo.processes.WhiteSignal(T, high=10, seed=seed)), stim[i], synapse=None) # HeteroSynapse Nodes syn_dot = nengo.Node(size_in=dims_in, output=HeteroSynapse(synapses, dt)) syn_elemwise = nengo.Node(size_in=dims_out, output=HeteroSynapse(np.repeat( synapses, dims_in), dt, elementwise=True)) # For comparing results x = [ nengo.Ensemble(n_neurons, dims_out, seed=0, encoders=encoders) for _ in range(3) ] # expected, actual 1, actual 2 # Expected for j, synapse in enumerate(synapses): nengo.Connection(stim, x[0][j * dims_in:(j + 1) * dims_in], synapse=synapse) # Actual (method #1 = matrix multiplies) nengo.Connection(stim, syn_dot, synapse=None) nengo.Connection(syn_dot, x[1], synapse=None) # Actual (method #2 = elementwise) for j in range(len(synapses)): nengo.Connection(stim, syn_elemwise[j * dims_in:(j + 1) * dims_in], synapse=None) nengo.Connection(syn_elemwise, x[2], synapse=None) # Probes p_exp = nengo.Probe(x[0], synapse=None) p_act_dot = nengo.Probe(x[1], synapse=None) p_act_elemwise = nengo.Probe(x[2], synapse=None) # Check correctness with Simulator(model, dt=dt) as sim: sim.run(T) assert np.allclose(sim.data[p_act_dot], sim.data[p_exp]) assert np.allclose(sim.data[p_act_elemwise], sim.data[p_exp])
import pytest from nengolib.signal.discrete import cont2discrete, discrete2cont from nengolib.signal import s, z, ss_equal from nengolib.synapses import Lowpass, Alpha, Highpass @pytest.mark.parametrize( "sys", [Lowpass(0.1), Alpha(0.01), Highpass(0.01, order=4)]) def test_discrete(sys): dt = 0.001 alpha = 0.6 for method in ('gbt', 'bilinear', 'tustin', 'euler', 'forward_diff', 'backward_diff', 'zoh'): dsys = cont2discrete(sys, dt=dt, method=method, alpha=alpha) assert not dsys.analog rsys = discrete2cont(dsys, dt=dt, method=method, alpha=alpha) assert rsys.analog assert ss_equal(sys, rsys, atol=1e-07) def test_invalid_discrete(): dt = 0.001 sys = cont2discrete(Lowpass(0.1), dt=dt) with pytest.raises(ValueError): discrete2cont(sys, dt=dt, method='gbt', alpha=1.1) with pytest.raises(ValueError): discrete2cont(sys, dt=0)
def figure_principle3(targets): theta = 0.1 tau = 0.1 * theta lmbda = tau orders = range(6, 28) freqs = np.linspace(0.1 / theta, 16 / theta, 1000) s = 2.j * np.pi * freqs y = np.exp(-theta * s) Hinvs = (tau * s + 1) * np.exp(lmbda * s) cmap_lamb = sns.color_palette("GnBu_d", len(orders))[::-1] cmap_ignore = sns.color_palette("OrRd_d", len(orders))[::-1] data = np.empty((2, len(DISCRETE_DTS), DISCRETE_SEEDS)) for seed in range(DISCRETE_SEEDS): for i, dt in enumerate(DISCRETE_DTS): npfile = np.load(DISCRETE_SIM % (seed, i)) assert np.allclose(npfile['dt'], dt) delay = npfile['delay'] # t = npfile['t'] stim = npfile['stim'] disc = npfile['disc'] cont = npfile['cont'] target = ideal_delay(stim, delay, dt) e_disc = nrmse(disc, target=target) e_cont = nrmse(cont, target=target) data[0, i, seed] = e_disc data[1, i, seed] = e_cont i = np.where(DISCRETE_DTS == 0.001)[0][0] assert np.allclose(DISCRETE_DTS[i], 0.001) e_disc = np.mean(data, axis=2)[0, i] e_cont = np.mean(data, axis=2)[1, i] improvement = (e_cont - e_disc) / e_cont * 100 logging.info("Paper constant: Improvement at 1 ms: %s (%s -> %s)", improvement, e_cont, e_disc) with sns.axes_style('ticks'): with sns.plotting_context('paper', font_scale=2.8): f, (ax1, ax2) = pylab.subplots(1, 2, figsize=(18, 5)) ax1.set_title("Discrete Lowpass Improvement").set_y(1.05) for i, condition, cpal, marker in ((1, 'Principle 3', sns.color_palette("OrRd_d"), 'X'), (0, 'Extension', sns.color_palette("GnBu_d"), 'o')): sns.tsplot(data[i].T, 1000 * DISCRETE_DTS, condition=condition, color=cpal, marker=marker, markersize=15, lw=3, ci=95, alpha=0.7, ax=ax1) ax1.vlines([1.0], np.min(data[0]), 2.0, linestyle='--', color='black', lw=4, alpha=0.7, zorder=0) ax1.set_xlabel("Discrete Time-step [ms]", labelpad=20) ax1.set_ylabel("Absolute Error", labelpad=20) ax1.set_xlim(0, 1000 * DISCRETE_DTS[-1] + 0.1) ax2.set_title("Delayed Lowpass Improvement").set_y(1.05) for i, q in enumerate(orders): sys = PadeDelay(theta, order=q) mapped = ss2sim(sys, Lowpass(tau), dt=None) lambert = lambert_delay(theta, lmbda, tau, q - 1, q) y_lamb = lambert(Hinvs) y_ignore = mapped(Hinvs) ax2.semilogy(freqs * theta, abs(y - y_ignore), lw=2, alpha=0.8, zorder=len(orders) - i, c=cmap_ignore[i]) ax2.semilogy(freqs * theta, abs(y - y_lamb), lw=2, alpha=0.8, zorder=len(orders) - i, c=cmap_lamb[i]) lc_ignore = LineCollection(len(orders) * [[(0, 0)]], lw=10, colors=cmap_ignore) lc_lamb = LineCollection(len(orders) * [[(0, 0)]], lw=10, colors=cmap_lamb) ax2.legend([lc_ignore, lc_lamb], ['Principle 3', 'Extension'], handlelength=2, handler_map={LineCollection: HandlerDashedLines()}) ax2.set_xlabel(r"Frequency $\times \, \theta$ [Hz $\times$ s]", labelpad=20) sns.despine(offset=15) savefig(targets[0])
def figure_lambert(targets): npfile = np.load(LAMBERT_SIM) delay = npfile['delay'] dt = npfile['dt'] t = npfile['t'] stim = npfile['stim'] delayed = npfile['delayed'] lowpass = npfile['lowpass'] dexp = npfile['dexp'] target = ideal_delay(stim, delay, dt) e_delayed = nrmse(delayed, target=target) e_lowpass = nrmse(lowpass, target=target) e_dexp = nrmse(dexp, target=target) improvement = (e_lowpass - e_delayed) / e_lowpass * 100 logging.info("Paper constant: Lambert improvement: %s", improvement) logging.info("Paper constant: Delayed NRMSE: %s", e_delayed) logging.info("Paper constant: Lowpass NRMSE: %s", e_lowpass) logging.info("Paper constant: Double Exp NRMSE: %s", e_dexp) sample_rate = 100 t = t[::sample_rate] stim = stim[::sample_rate] delayed = delayed[::sample_rate] lowpass = lowpass[::sample_rate] dexp = dexp[::sample_rate] target = target[::sample_rate] tau_over_theta = 0.1 lambda_over_tau = 1.0 max_freq_times_theta = 4.0 theta = 0.1 # <-- the graph is still the same, no matter theta! tau = tau_over_theta * theta lmbda = lambda_over_tau * tau max_freq = max_freq_times_theta / theta tau2 = tau / 5 # TODO: parameters copied from delayed_synapse() q = 6 assert np.allclose(tau, 0.01) assert np.allclose(lmbda, 0.01) freqs = np.linspace(0, max_freq, 200) s = 2.j * np.pi * freqs axis = freqs * theta # scale-invariant axis lw = 3 alpha = 0.8 cmap = sns.color_palette(None, 4) F_lamb = lambert_delay(theta, lmbda, tau, q - 1, q) F_low = ss2sim(PadeDelay(theta, order=q), Lowpass(tau), dt=None) F_alpha = ss2sim(PadeDelay(theta, order=q), DoubleExp(tau, tau2), dt=None) y_low = F_low(tau * s + 1) y_lamb = F_lamb((tau * s + 1) * np.exp(lmbda * s)) y_alpha = F_alpha((tau * s + 1) * (tau2 * s + 1)) y = np.exp(-theta * s) # Compute where lmbda*s + lmbda/tau is within the principal branch tx = lmbda * 2 * np.pi * freqs st = (lmbda / tau > -(tx / np.tan(tx))) & (tx < np.pi) | (tx == 0) p = lmbda * s[st] + lmbda / tau assert np.allclose(lambertw(p * np.exp(p)), p) with sns.axes_style('ticks'): with sns.plotting_context('paper', font_scale=2.8): pylab.figure(figsize=(18, 5)) gs = gridspec.GridSpec(1, 2, width_ratios=[1, 1.618]) gs.update(wspace=0.3) ax1 = plt.subplot(gs[1]) ax2 = plt.subplot(gs[0]) ax1.set_title(r"$0.1\,$s Delay of $15\,$Hz White Noise").set_y( 1.05) ax1.plot(t, target, lw=4, c=cmap[0], zorder=4, linestyle='--') ax1.plot(t, lowpass, alpha=alpha, c=cmap[1], zorder=2) ax1.plot(t, dexp, alpha=alpha, c=cmap[3], zorder=2) ax1.plot(t, delayed, alpha=alpha, c=cmap[2], zorder=3) ax1.set_ylim(-0.5, 0.5) ax1.set_xlabel("Time [s]", labelpad=20) ax1.set_ylabel("Output") ax2.set_title("Delay Accuracy").set_y(1.05) ax2.plot(axis, np.zeros_like(freqs), lw=lw, c=cmap[0], zorder=4, linestyle='--', label=r"Ideal") ax2.plot(axis, abs(y - y_low), lw=lw, alpha=alpha, c=cmap[1], zorder=3, label=r"Lowpass") ax2.plot(axis, abs(y - y_alpha), lw=lw, alpha=alpha, c=cmap[3], zorder=3, label=r"Double-exponential") ax2.plot(axis, abs(y - y_lamb), lw=lw, alpha=alpha, c=cmap[2], zorder=3, label=r"Delayed Lowpass") s = 0.8 pts = np.asarray([[1.5, 0], [1.5 - s, -s], [1.5 + s, -s]]) ax2.add_patch(Polygon(pts, closed=True, color='black')) ax2.set_xlabel(r"Frequency $\times \, \theta$ [Hz $\times$ s]", labelpad=20) ax2.set_ylabel(r"Absolute Error", labelpad=20) ax2.legend(loc='upper left', frameon=True).get_frame().set_alpha(0.8) sns.despine(offset=15) savefig(targets[0])