def test_linearfilter(Simulator, plt, seed, allclose): dt = 1e-3 synapse = LinearFilter(butter_num, butter_den, analog=False) t, x, yhat = run_synapse(Simulator, seed, synapse, dt=dt) y = synapse.filt(x, dt=dt, y0=0) assert signals_allclose(t, y, yhat, delay=dt, plt=plt, allclose=allclose)
def build_gdhl(model, gdhl, rule): """Builds a `.GDHL` object into a model. Calls synapse build functions to filter the pre and post activities, and adds a `.SimGDHL` operator to the model to calculate the delta. Parameters ---------- model : Model The model to build into. gdhl : GDHL Learning rule type to build. rule : LearningRule The learning rule object corresponding to the neuron type. Notes ----- Does not modify ``model.params[]`` and can therefore be called more than once with the same `.GDHL` instance. """ conn = rule.connection pre_activities = model.sig[conn.pre_obj]["out"] if conn.pre_slice is not None: pre_activities = pre_activities[conn.pre_slice] post_activities = model.sig[get_post_ens(conn).neurons]["out"] if conn.post_slice is not None: post_activities = post_activities[conn.post_slice] pre_filtered = build_or_passthrough(model, gdhl.pre_synapse, pre_activities) post_filtered = build_or_passthrough(model, gdhl.post_synapse, post_activities) weights = model.sig[conn]["weights"] d_pre_filtered = build_or_passthrough( model, LinearFilter([1, 0], [1], method="backward_diff").combine(gdhl.pre_synapse), pre_activities) d_post_filtered = build_or_passthrough( model, LinearFilter([1, 0], [1], method="backward_diff").combine(gdhl.post_synapse), post_activities) model.add_op( SimGDHL( pre_filtered, post_filtered, d_pre_filtered, d_post_filtered, weights, model.sig[rule]["delta"], learning_rate=gdhl.learning_rate, sigma=gdhl.sigma, eta=gdhl.eta, jit=gdhl.jit, )) # expose these for probes model.sig[rule]["pre_filtered"] = pre_filtered model.sig[rule]["post_filtered"] = post_filtered
def test_step_errors(): output = np.zeros(3) with pytest.raises(ValueError): LinearFilter.NoDen([1], [1], output) with pytest.raises(ValueError): LinearFilter.Simple([1, 2], [1], output) with pytest.raises(ValueError): LinearFilter.Simple([1], [1, 2], output)
def test_direct(Simulator, plt, seed, allclose): dt = 1e-3 a = 0.7 synapse = LinearFilter([a], [1], analog=False) t, x, yhat = run_synapse(Simulator, seed, synapse, dt=dt) y = synapse.filt(x, dt=dt, y0=0) assert signals_allclose(t, y, yhat, delay=dt, allclose=allclose) assert signals_allclose(t, a * x, y, plt=plt, allclose=allclose)
def test_linearfilter_combine(rng, allclose): nt = 3000 tau0, tau1 = 0.01, 0.02 u = rng.normal(size=(nt, 10)) x = LinearFilter([1], [tau0 * tau1, tau0 + tau1, 1]).filt(u, y0=0) y = Lowpass(tau0).combine(Lowpass(tau1)).filt(u, y0=0) assert allclose(x, y) with pytest.raises(ValidationError, match="other LinearFilters"): Lowpass(0.1).combine(Triangle(0.01)) with pytest.raises(ValidationError, match="analog and digital"): Lowpass(0.1).combine(LinearFilter([1], [1], analog=False))
def test_linearfilter(Simulator, plt, seed): dt = 1e-3 # The following num, den are for a 4th order analog Butterworth filter, # generated with `scipy.signal.butter(4, 0.2, analog=False)` num = np.array( [0.00482434, 0.01929737, 0.02894606, 0.01929737, 0.00482434]) den = np.array([1., -2.36951301, 2.31398841, -1.05466541, 0.18737949]) synapse = LinearFilter(num, den, analog=False) t, x, yhat = run_synapse(Simulator, seed, synapse, dt=dt) y = synapse.filt(x, dt=dt, y0=0) assert allclose(t, y, yhat, delay=dt, plt=plt)
def test_linear_analog(Simulator, seed): dt = 1e-3 # The following num, den are for a 4th order analog Butterworth filter, # generated with `scipy.signal.butter(4, 200, analog=True)` num = np.array([1.60000000e+09]) den = np.array([1.00000000e+00, 5.22625186e+02, 1.36568542e+05, 2.09050074e+07, 1.60000000e+09]) synapse = LinearFilter(num, den, analog=True) t, x, yhat = run_synapse(Simulator, seed, synapse, dt=dt) y = synapse.filt(x, dt=dt, y0=0) assert allclose(t, y, yhat, delay=dt, atol=5e-4)
def test_linear_analog(Simulator, seed): dt = 1e-3 # The following num, den are for a 4th order analog Butterworth filter, # generated with `scipy.signal.butter(4, 200, analog=True)` num = np.array([1.60000000e09]) den = np.array( [1.00000000e00, 5.22625186e02, 1.36568542e05, 2.09050074e07, 1.60000000e09] ) synapse = LinearFilter(num, den, analog=True) t, x, yhat = run_synapse(Simulator, seed, synapse, dt=dt) y = synapse.filt(x, dt=dt, y0=0) assert signals_allclose(t, y, yhat, delay=dt, atol=5e-4)
def test_linearfilter(Simulator, plt, seed): dt = 1e-3 # The following num, den are for a 4th order analog Butterworth filter, # generated with `scipy.signal.butter(4, 1. / 0.03, analog=True)` num = np.array([1234567.90123457]) den = np.array([ 1.0, 87.104197658425107, 3793.5706248589954, 96782.441842694592, 1234567.9012345686 ]) t, x, yhat = run_synapse(Simulator, seed, LinearFilter(num, den), dt=dt) y = filt(x, LinearFilter(num, den), dt=dt) assert allclose(t, y, yhat, delay=dt, plt=plt)
def test_linearfilter_combine(rng): nt = 3000 tau0, tau1 = 0.01, 0.02 u = rng.normal(size=(nt, 10)) x = LinearFilter([1], [tau0 * tau1, tau0 + tau1, 1]).filt(u, y0=0) y = Lowpass(tau0).combine(Lowpass(tau1)).filt(u, y0=0) assert np.allclose(x, y)
def test_lti_lowpass(rng, plt): dt = 1e-3 tend = 3. t = dt * np.arange(tend / dt) nt = len(t) tau = 1e-2 lti = LinearFilter([1], [tau, 1]) u = rng.normal(size=(nt, 10)) x = Lowpass(tau).filt(u, dt=dt) y = lti.filt(u, dt=dt) plt.plot(t, x[:, 0], label="Lowpass") plt.plot(t, y[:, 0], label="LTI") plt.legend(loc="best") assert np.allclose(x, y)
def test_linearfilter_onex(Simulator): with nengo.Network() as net: inp = nengo.Node(lambda t: np.sin(t * 10)) tau = 0.1 # check that linearfilter and lowpass are equivalent # (two versions of each to check that merging works as expected) p_lowpass0 = nengo.Probe(inp, synapse=tau) p_lowpass1 = nengo.Probe(inp, synapse=tau * 2) p_linear0 = nengo.Probe(inp, synapse=LinearFilter([1], [tau, 1])) p_linear1 = nengo.Probe(inp, synapse=LinearFilter([1], [tau * 2, 1])) with Simulator(net) as sim: sim.run(0.1) assert np.allclose(sim.data[p_lowpass0], sim.data[p_linear0]) assert np.allclose(sim.data[p_lowpass1], sim.data[p_linear1])
def test_alpha(Simulator, seed): dt = 1e-3 tau = 0.03 num, den = [1], [tau**2, 2 * tau, 1] t, x, yhat = run_synapse(Simulator, seed, Alpha(tau), dt=dt) y = LinearFilter(num, den).filt(x, dt=dt, y0=0) assert allclose(t, y, yhat, delay=dt, atol=5e-5)
def test_step_errors(): # error for A.shape[0] != B.shape[0] A = np.ones((2, 2)) B = np.ones((1, 1)) C = np.ones((1, 2)) D = np.ones((1, 1)) X = np.ones((2, 10)) with pytest.raises(ValidationError, match="Matrices do not meet"): LinearFilter.General(A, B, C, D, X)
def test_linearfilter_y0(allclose): # --- y0 sets initial state correctly for high-order filter synapse = LinearFilter(butter_num, butter_den, analog=False) v = 9.81 x = v * np.ones(10) assert allclose(synapse.filt(x, y0=v), v) assert not allclose(synapse.filt(x, y0=0), v, record_rmse=False) # --- y0 does not work for high-order synapse when DC gain is zero synapse = LinearFilter([1, 0], [1, 1]) with pytest.raises(ValidationError, match="Cannot solve for state"): synapse.filt(np.ones(10), y0=1)
def test_argreprs(): def check_init_args(cls, args): assert getfullargspec(cls.__init__).args[1:] == args def check_repr(obj): assert eval(repr(obj)) == obj check_init_args(LinearFilter, ["num", "den", "analog", "method"]) check_repr(LinearFilter([1, 2], [3, 4])) check_repr(LinearFilter([1, 2], [3, 4], analog=False)) check_init_args(Lowpass, ["tau"]) check_repr(Lowpass(0.3)) check_init_args(Alpha, ["tau"]) check_repr(Alpha(0.3)) check_init_args(Triangle, ["t"]) check_repr(Triangle(0.3))
def test_argreprs(): def check_init_args(cls, args): assert getfullargspec(cls.__init__).args[1:] == args def check_repr(obj): assert eval(repr(obj)) == obj check_init_args(LinearFilter, ['num', 'den', 'analog']) check_repr(LinearFilter([1, 2], [3, 4])) check_repr(LinearFilter([1, 2], [3, 4], analog=False)) check_init_args(Lowpass, ['tau']) check_repr(Lowpass(0.3)) check_init_args(Alpha, ['tau']) check_repr(Alpha(0.3)) check_init_args(Triangle, ['t']) check_repr(Triangle(0.3))
def test_frozen(): """Test attributes inherited from FrozenObject""" a = LinearFilter([1], [0.04, 1]) b = LinearFilter([1], [0.04, 1]) c = LinearFilter([1], [0.04, 1.1]) assert hash(a) == hash(a) assert hash(b) == hash(b) assert hash(c) == hash(c) assert a == b assert hash(a) == hash(b) assert a != c assert hash(a) != hash(c) # not guaranteed, but highly likely assert b != c assert hash(b) != hash(c) # not guaranteed, but highly likely with pytest.raises((ValueError, RuntimeError)): a.den[0] = 9
def test_zero_matrices(Simulator, zero, seed): dt = 1e-3 A = np.diag(np.ones(2) * dt) B = np.zeros((2, 1)) B[0] = 1 C = np.ones((1, 2)) D = np.ones((1, )) if zero == "C": C[...] = 0 elif zero == "D": D[...] = 0 num, den = ss2tf(A, B, C, D) num = num.flatten() synapse = LinearFilter(num, den, analog=False) t, x, yhat = run_synapse(Simulator, seed, synapse, dt=dt) y = synapse.filt(x, dt=dt, y0=0) assert allclose(t, y, yhat, delay=dt * 2 if zero == "D" else dt, atol=5e-5)
def test_zero_matrices(Simulator, zero, seed): dt = 1e-3 A = np.diag(np.ones(2) * dt) B = np.zeros((2, 1)) B[0] = 1 C = np.ones((1, 2)) D = np.ones((1,)) if zero == "C": C[...] = 0 elif zero == "D": D[...] = 0 num, den = ss2tf(A, B, C, D) num = num.flatten() synapse = LinearFilter(num, den, analog=False) t, x, yhat = run_synapse(Simulator, seed, synapse, dt=dt) y = synapse.filt(x, dt=dt, y0=0) assert allclose(t, y, yhat, delay=dt * 2 if zero == "D" else dt, atol=5e-5)
def test_linearfilter_evaluate(plt): tau = 0.02 ord1 = LinearFilter([1], [tau, 1]) ord2 = LinearFilter([1], [tau**2, 2 * tau, 1]) f = np.logspace(-1, 3, 100) y1 = ord1.evaluate(f) y2 = ord2.evaluate(f) plt.subplot(211) plt.semilogx(f, 20 * np.log10(np.abs(y1))) plt.semilogx(f, 20 * np.log10(np.abs(y2))) plt.subplot(212) plt.semilogx(f, np.angle(y1)) plt.semilogx(f, np.angle(y2)) jw_tau = 2.0j * np.pi * f * tau y1_ref = 1 / (jw_tau + 1) y2_ref = 1 / (jw_tau**2 + 2 * jw_tau + 1) assert np.allclose(y1, y1_ref) assert np.allclose(y2, y2_ref)
def test_mergeable(): # anything is mergeable with an empty list assert mergeable(None, []) # ops with different numbers of sets/incs/reads/updates are not mergeable assert not mergeable(dummies.Op(sets=[dummies.Signal()]), [dummies.Op()]) assert not mergeable(dummies.Op(incs=[dummies.Signal()]), [dummies.Op()]) assert not mergeable(dummies.Op(reads=[dummies.Signal()]), [dummies.Op()]) assert not mergeable(dummies.Op(updates=[dummies.Signal()]), [dummies.Op()]) assert mergeable(dummies.Op(sets=[dummies.Signal()]), [dummies.Op(sets=[dummies.Signal()])]) # check matching dtypes assert not mergeable(dummies.Op(sets=[dummies.Signal(dtype=np.float32)]), [dummies.Op(sets=[dummies.Signal(dtype=np.float64)])]) # shape mismatch assert not mergeable(dummies.Op(sets=[dummies.Signal(shape=(1, 2))]), [dummies.Op(sets=[dummies.Signal(shape=(1, 3))])]) # display shape mismatch assert not mergeable( dummies.Op(sets=[dummies.Signal(base_shape=(2, 2), shape=(4, 1))]), [dummies.Op(sets=[dummies.Signal(base_shape=(2, 2), shape=(1, 4))])]) # first dimension mismatch assert mergeable(dummies.Op(sets=[dummies.Signal(shape=(3, 2))]), [dummies.Op(sets=[dummies.Signal(shape=(4, 2))])]) # Copy (inc must match) assert mergeable(Copy(dummies.Signal(), dummies.Signal(), inc=True), [Copy(dummies.Signal(), dummies.Signal(), inc=True)]) assert not mergeable(Copy(dummies.Signal(), dummies.Signal(), inc=True), [Copy(dummies.Signal(), dummies.Signal(), inc=False)]) # elementwise (first dimension must match) assert mergeable( ElementwiseInc(dummies.Signal(), dummies.Signal(), dummies.Signal()), [ElementwiseInc(dummies.Signal(), dummies.Signal(), dummies.Signal())]) assert mergeable( ElementwiseInc(dummies.Signal(shape=(1,)), dummies.Signal(), dummies.Signal()), [ElementwiseInc(dummies.Signal(shape=()), dummies.Signal(), dummies.Signal())]) assert not mergeable( ElementwiseInc(dummies.Signal(shape=(3,)), dummies.Signal(), dummies.Signal()), [ElementwiseInc(dummies.Signal(shape=(2,)), dummies.Signal(), dummies.Signal())]) # simpyfunc (t input must match) time = dummies.Signal() assert mergeable(SimPyFunc(None, None, time, None), [SimPyFunc(None, None, time, None)]) assert mergeable(SimPyFunc(None, None, None, dummies.Signal()), [SimPyFunc(None, None, None, dummies.Signal())]) assert not mergeable(SimPyFunc(None, None, dummies.Signal(), None), [SimPyFunc(None, None, None, dummies.Signal())]) # simneurons # check matching TF_NEURON_IMPL assert mergeable(SimNeurons(LIF(), dummies.Signal(), dummies.Signal()), [SimNeurons(LIF(), dummies.Signal(), dummies.Signal())]) assert not mergeable(SimNeurons(LIF(), dummies.Signal(), dummies.Signal()), [SimNeurons(LIFRate(), dummies.Signal(), dummies.Signal())]) # check custom with non-custom implementation assert not mergeable(SimNeurons(LIF(), dummies.Signal(), dummies.Signal()), [SimNeurons(Izhikevich(), dummies.Signal(), dummies.Signal())]) # check non-custom matching assert not mergeable( SimNeurons(Izhikevich(), dummies.Signal(), dummies.Signal()), [SimNeurons(AdaptiveLIF(), dummies.Signal(), dummies.Signal())]) assert not mergeable( SimNeurons(Izhikevich(), dummies.Signal(), dummies.Signal(), states=[dummies.Signal(dtype=np.float32)]), [SimNeurons(Izhikevich(), dummies.Signal(), dummies.Signal(), states=[dummies.Signal(dtype=np.int32)])]) assert mergeable( SimNeurons(Izhikevich(), dummies.Signal(), dummies.Signal(), states=[dummies.Signal(shape=(3,))]), [SimNeurons(Izhikevich(), dummies.Signal(), dummies.Signal(), states=[dummies.Signal(shape=(2,))])]) assert not mergeable( SimNeurons(Izhikevich(), dummies.Signal(), dummies.Signal(), states=[dummies.Signal(shape=(2, 1))]), [SimNeurons(Izhikevich(), dummies.Signal(), dummies.Signal(), states=[dummies.Signal(shape=(2, 2))])]) # simprocess # mode must match assert not mergeable( SimProcess(Lowpass(0), None, dummies.Signal(), dummies.Signal(), mode="inc"), [SimProcess(Lowpass(0), None, dummies.Signal(), dummies.Signal(), mode="set")]) # check that lowpass match assert mergeable(SimProcess(Lowpass(0), None, None, dummies.Signal()), [SimProcess(Lowpass(0), None, None, dummies.Signal())]) # check that lowpass and linear don't match assert not mergeable(SimProcess(Lowpass(0), None, None, dummies.Signal()), [SimProcess(Alpha(0), None, None, dummies.Signal())]) # check that two linear do match assert mergeable( SimProcess(Alpha(0.1), dummies.Signal(), None, dummies.Signal()), [SimProcess(LinearFilter([1], [1, 1, 1]), dummies.Signal(), None, dummies.Signal())]) # check custom and non-custom don't match assert not mergeable(SimProcess(Triangle(0), None, None, dummies.Signal()), [SimProcess(Alpha(0), None, None, dummies.Signal())]) # check non-custom matching assert mergeable(SimProcess(Triangle(0), None, None, dummies.Signal()), [SimProcess(Triangle(0), None, None, dummies.Signal())]) # simtensornode a = SimTensorNode(None, dummies.Signal(), None, dummies.Signal()) assert not mergeable(a, [a]) # learning rules a = SimBCM(dummies.Signal((4,)), dummies.Signal(), dummies.Signal(), dummies.Signal(), dummies.Signal()) b = SimBCM(dummies.Signal((5,)), dummies.Signal(), dummies.Signal(), dummies.Signal(), dummies.Signal()) assert not mergeable(a, [b])
def __init__(self, dist=Gaussian(mean=0, std=1), **kwargs): super().__init__(synapse=LinearFilter([1], [1, 0], method="euler"), dist=dist, **kwargs)
def __init__(self, dist=Gaussian(mean=0, std=1), **kwargs): super(BrownNoise, self).__init__(synapse=LinearFilter([1], [1, 0]), synapse_kwargs=dict(method='euler'), dist=dist, **kwargs)
p_lowpass0 = nengo.Probe(inp, synapse=tau) p_lowpass1 = nengo.Probe(inp, synapse=tau * 2) p_linear0 = nengo.Probe(inp, synapse=LinearFilter([1], [tau, 1])) p_linear1 = nengo.Probe(inp, synapse=LinearFilter([1], [tau * 2, 1])) with Simulator(net) as sim: sim.run(0.1) assert np.allclose(sim.data[p_lowpass0], sim.data[p_linear0]) assert np.allclose(sim.data[p_lowpass1], sim.data[p_linear1]) @pytest.mark.parametrize( "synapse", ( LinearFilter([0.1], [1], analog=False), # NoX LinearFilter([1], [0.1, 1]), # OneX Alpha(0.1), # NoD LinearFilter( [0.0004166, 0.0016664, 0.0024996, 0.0016664, 0.0004166], [1.0, -3.18063855, 3.86119435, -2.11215536, 0.43826514], ), # General ), ) def test_linearfilter_minibatched(Simulator, synapse): n_steps = 10 mini_size = 4 signal_d = 3 with nengo.Network() as net: inp = nengo.Node(np.zeros(signal_d))