Example #1
0
def test_unsupported_synapse():
    with pytest.raises(ValueError):
        ss2sim(sys=Lowpass(0.1), synapse=Alpha(0.1))

    with pytest.raises(ValueError):
        ss2sim(sys=Lowpass(0.1), synapse=LinearFilter([1, 2], [2, 1]), dt=0.01)

    with pytest.raises(ValueError):
        ss2sim(sys=Lowpass(0.1), synapse=LinearFilter(1, 1))

    with pytest.raises(ValueError):
        ss2sim(sys=Lowpass(0.1), synapse=LinearFilter([1, 0.01], [1]))

    with pytest.raises(ValueError):
        ss2sim(sys=Lowpass(0.1), synapse=LinearFilter([1], [2, 1, 1]))
Example #2
0
def test_doubleexp_discrete():
    sys = PadeDelay(0.1, order=5)

    tau1 = 0.05
    tau2 = 0.02
    dt = 0.002
    syn = DoubleExp(tau1, tau2)

    FH = ss2sim(sys, syn, dt=dt)

    a1 = np.exp(-dt / tau1)
    a2 = np.exp(-dt / tau2)
    t1 = 1 / (1 - a1)
    t2 = 1 / (1 - a2)
    c = [a1 * a2 * t1 * t2, - (a1 + a2) * t1 * t2, t1 * t2]
    sys = cont2discrete(sys, dt=dt)

    A = sys.A
    FHA = c[2] * np.dot(A, A) + c[1] * A + c[0] * np.eye(len(A))
    B = sys.B
    FHB = (c[2] * A + (c[1] + c[2]) * np.eye(len(A))).dot(B)
    assert np.allclose(FH.A, FHA)
    assert np.allclose(FH.B, FHB)
    assert np.allclose(FH.C, sys.C)
    assert np.allclose(FH.D, sys.D)
Example #3
0
def test_principle3_discrete():
    sys = PadeDelay(0.1, order=5)

    tau = 0.01
    dt = 0.002
    syn = Lowpass(tau)

    FH = ss2sim(sys, syn, dt=dt)

    a = np.exp(-dt / tau)
    sys = cont2discrete(sys, dt=dt)
    assert np.allclose(FH.A, (sys.A - a * np.eye(len(sys))) / (1 - a))
    assert np.allclose(FH.B, sys.B / (1 - a))
    assert np.allclose(FH.C, sys.C)
    assert np.allclose(FH.D, sys.D)

    # We can also do the discretization ourselves and then pass in dt=None
    assert ss_equal(
        ss2sim(sys, cont2discrete(syn, dt=dt), dt=None), FH)
Example #4
0
def test_principle3_continuous():
    sys = PadeDelay(0.1, order=5)

    tau = 0.01
    syn = Lowpass(tau)

    FH = ss2sim(sys, syn, dt=None)

    assert np.allclose(FH.A, tau * sys.A + np.eye(len(sys)))
    assert np.allclose(FH.B, tau * sys.B)
    assert np.allclose(FH.C, sys.C)
    assert np.allclose(FH.D, sys.D)
Example #5
0
def test_unsupported_mapping():
    lpf = Lowpass(0.1)

    with pytest.raises(ValueError):
        ss2sim(sys=lpf, synapse=Highpass(0.1), dt=None)

    with pytest.raises(ValueError):
        ss2sim(sys=~z, synapse=lpf, dt=None)

    with pytest.raises(ValueError):
        ss2sim(sys=lpf, synapse=~z, dt=None)

    with pytest.raises(ValueError):
        ss2sim(sys=~z, synapse=~z, dt=1.)
Example #6
0
def test_mapping(Simulator, plt, seed):
    sys = Alpha(0.1)
    syn = Lowpass(0.01)
    gsyn = 2*syn  # scaled lowpass
    isyn = 2/s  # scaled integrator
    dt = 0.001

    ss = ss2sim(sys, syn, None)  # normal lowpass, continuous
    dss = ss2sim(sys, syn, dt)  # normal lowpass, discrete
    gss = ss2sim(sys, gsyn, None)  # scaled lowpass, continuous
    gdss = ss2sim(sys, gsyn, dt)  # scaled lowpass, discrete
    iss = ss2sim(sys, isyn, None)  # scaled integrator, continuous
    idss = ss2sim(sys, isyn, dt)  # scaled integrator, discrete
    assert ss.analog and gss.analog and iss.analog
    assert not (dss.analog or gdss.analog or idss.analog)

    with Network(seed=seed) as model:
        stim = nengo.Node(output=lambda t: np.sin(20*np.pi*t))

        probes = []
        for mapped, synapse in ((ss, syn), (dss, syn), (gss, gsyn),
                                (gdss, gsyn), (iss, isyn), (idss, isyn)):
            A, B, C, D = mapped.ss
            x = nengo.Node(size_in=2)
            y = nengo.Node(size_in=1)

            nengo.Connection(stim, x, transform=B, synapse=synapse)
            nengo.Connection(x, x, transform=A, synapse=synapse)
            nengo.Connection(x, y, transform=C, synapse=None)
            nengo.Connection(stim, y, transform=D, synapse=None)

            probes.append(nengo.Probe(y))

        p_stim = nengo.Probe(stim)

    pss, pdss, pgss, pgdss, piss, pidss = probes

    with Simulator(model, dt=dt) as sim:
        sim.run(1.0)

    expected = shift(sys.filt(sim.data[p_stim], dt))

    plt.plot(sim.trange(), sim.data[pss], label="Continuous", alpha=0.5)
    plt.plot(sim.trange(), sim.data[pdss], label="Discrete", alpha=0.5)
    plt.plot(sim.trange(), sim.data[pgss], label="Gain Cont.", alpha=0.5)
    plt.plot(sim.trange(), sim.data[pgdss], label="Gain Disc.", alpha=0.5)
    plt.plot(sim.trange(), sim.data[piss], label="Integ Cont.", alpha=0.5)
    plt.plot(sim.trange(), sim.data[pidss], label="Integ Disc.", alpha=0.5)
    plt.plot(sim.trange(), expected, label="Expected", linestyle='--')
    plt.legend()

    assert np.allclose(sim.data[pss], expected, atol=0.01)
    assert np.allclose(sim.data[pdss], expected)
    assert np.allclose(sim.data[pgss], expected, atol=0.01)
    assert np.allclose(sim.data[pgdss], expected)
    assert np.allclose(sim.data[piss], expected, atol=0.01)
    assert np.allclose(sim.data[pidss], expected)
Example #7
0
def test_doubleexp_continuous(sys):
    tau1 = 0.05
    tau2 = 0.02
    syn = DoubleExp(tau1, tau2)

    FH = ss2sim(sys, syn, dt=None)

    A = sys.A
    FHA = tau1 * tau2 * np.dot(A, A) + (tau1 + tau2) * A + np.eye(len(A))
    B = sys.B
    FHB = (tau1 * tau2 * A + (tau1 + tau2) * np.eye(len(A))).dot(B)
    assert np.allclose(FH.A, FHA)
    assert np.allclose(FH.B, FHB)
    assert np.allclose(FH.C, sys.C)
    assert np.allclose(FH.D, sys.D)
Example #8
0
def test_mapping(Simulator, plt, seed):
    sys = Alpha(0.1)
    syn = Lowpass(0.01)
    gsyn = 2 * syn  # scaled lowpass
    isyn = 2 / s  # scaled integrator
    dt = 0.001

    ss = ss2sim(sys, syn)  # normal lowpass, continuous
    dss = ss2sim(sys, syn, dt)  # normal lowpass, discrete
    gss = ss2sim(sys, gsyn)  # scaled lowpass, continuous
    gdss = ss2sim(sys, gsyn, dt)  # scaled lowpass, discrete
    iss = ss2sim(sys, isyn)  # scaled integrator, continuous
    idss = ss2sim(sys, isyn, dt)  # scaled integrator, discrete
    assert ss.analog and gss.analog and iss.analog
    assert not (dss.analog or gdss.analog or idss.analog)

    with Network(seed=seed) as model:
        stim = nengo.Node(output=lambda t: np.sin(20 * np.pi * t))

        probes = []
        for mapped, synapse in ((ss, syn), (dss, syn), (gss, gsyn), (gdss, gsyn), (iss, isyn), (idss, isyn)):
            A, B, C, D = mapped.ss
            x = nengo.Node(size_in=2)
            y = nengo.Node(size_in=1)

            nengo.Connection(stim, x, transform=B, synapse=synapse)
            nengo.Connection(x, x, transform=A, synapse=synapse)
            nengo.Connection(x, y, transform=C, synapse=None)
            nengo.Connection(stim, y, transform=D, synapse=None)

            probes.append(nengo.Probe(y))

        p_stim = nengo.Probe(stim)

    pss, pdss, pgss, pgdss, piss, pidss = probes

    sim = Simulator(model, dt=dt)
    sim.run(1.0)

    expected = apply_filter(sys, dt, sim.data[p_stim], axis=0)

    plt.plot(sim.trange(), sim.data[pss], label="Continuous", alpha=0.5)
    plt.plot(sim.trange(), sim.data[pdss], label="Discrete", alpha=0.5)
    plt.plot(sim.trange(), sim.data[pgss], label="Gain Cont.", alpha=0.5)
    plt.plot(sim.trange(), sim.data[pgdss], label="Gain Disc.", alpha=0.5)
    plt.plot(sim.trange(), sim.data[piss], label="Integ Cont.", alpha=0.5)
    plt.plot(sim.trange(), sim.data[pidss], label="Integ Disc.", alpha=0.5)
    plt.plot(sim.trange(), expected, label="Expected", linestyle="--")
    plt.legend()

    assert np.allclose(sim.data[pss], expected, atol=0.01)
    assert np.allclose(sim.data[pdss], expected)
    assert np.allclose(sim.data[pgss], expected, atol=0.01)
    assert np.allclose(sim.data[pgdss], expected)
    assert np.allclose(sim.data[piss], expected, atol=0.01)
    assert np.allclose(sim.data[pidss], expected)
Example #9
0
    def __init__(self, sys, n_neurons, synapse, dt, radii=1.0,
                 input_synapse=None, output_synapse=None,
                 normalizer=default_normalizer(), solver=Default,
                 label=None, seed=None, add_to_container=None, **ens_kwargs):
        super(LinearNetwork, self).__init__(label, seed, add_to_container)

        # Parameter checking
        self.sys = LinearSystem(sys)
        self.n_neurons = n_neurons
        self.synapse = synapse
        self.dt = dt
        self.radii = radii
        self.input_synapse = input_synapse
        self.output_synapse = output_synapse
        self.normalizer = normalizer

        if len(self.sys) == 0:
            raise ValueError("system (%s) is zero order" % self.sys)

        # TODO: duplicates checks in ss2sim
        synapse = LinearSystem(self.synapse)
        if len(synapse) != 1 or not synapse.proper or not synapse.analog:
            raise ValueError("synapse (%s) must be first-order, proper, and "
                             "analog" % synapse)

        if not self.sys.analog:
            # this restriction exists to simplify the life of the normalizer
            # by assuming we only need to normalize continuous systems.
            # ss2sim will eventually discretize the system with the given dt
            # as long as it's not None
            raise ValueError("system (%s) must be analog" % self.sys)

        if self.sys.has_passthrough and self.output_synapse is None:
            # the user shouldn't filter the output node themselves. an
            # output synapse should be given so we can do it before the
            # passthrough.
            warnings.warn("output_synapse should be given if the system has "
                          "a passthrough, otherwise filtering the output will "
                          "also filter the passthrough")

        if not self.sys.is_stable:
            # This means certain normalizers won't work, because the worst-case
            # output is now unbounded.
            warnings.warn("system (%s) is not exponentially stable" % self.sys)

        # Obtain a normalized state-space representation
        self.normalized, self.info = self.normalizer(self.sys, self.radii)
        self.A, self.B, self.C, self.D = ss2sim(
            self.normalized, self.synapse, self.dt).ss
        self.size_in = self.B.shape[1]
        self.size_state = len(self.A)
        self.size_out = len(self.C)

        with self:
            # Create internal Nengo objects
            self.input = nengo.Node(size_in=self.size_in, label="input")
            self.output = nengo.Node(size_in=self.size_out, label="output")
            self.x = nengo.networks.EnsembleArray(
                self.n_neurons, self.size_state, ens_dimensions=1,
                **ens_kwargs)

            if solver is not Default:
                # https://github.com/nengo/nengo/issues/1044
                solver._hack = random()

                # https://github.com/nengo/nengo/issues/1040
                self.x.add_output('output', function=None, solver=solver)

            # Connect everything up using (A, B, C, D)
            self.conn_A = nengo.Connection(
                self.x.output, self.x.input, transform=self.A,
                synapse=self.synapse)
            self.conn_B = nengo.Connection(
                self.input, self.x.input, transform=self.B,
                synapse=self.input_synapse)
            self.conn_C = nengo.Connection(
                self.x.output, self.output, transform=self.C,
                synapse=self.output_synapse)
            self.conn_D = nengo.Connection(
                self.input, self.output, transform=self.D,
                synapse=None)
Example #10
0
def test_unsupported_system():
    with pytest.raises(ValueError):
        ss2sim(sys=z, synapse=Lowpass(0.1))
Example #11
0
    def __init__(self, sys, n_neurons_per_ensemble, synapse, dt, radii=1.0,
                 input_synapse=None, output_synapse=None,
                 realizer=Hankel(), solver=Default,
                 label=None, seed=None, add_to_container=None, **ens_kwargs):
        super(LinearNetwork, self).__init__(label, seed, add_to_container)

        # Parameter checking
        self.sys = LinearSystem(sys)
        self.n_neurons_per_ensemble = n_neurons_per_ensemble
        self.synapse = synapse
        self.dt = dt
        self.radii = radii
        self.input_synapse = input_synapse
        self.output_synapse = output_synapse
        self.realizer = realizer

        if solver is not Default:
            # https://github.com/nengo/nengo/issues/1044
            solver._hack = random()

        if len(self.sys) == 0:
            raise ValueError("system (%s) is zero order" % self.sys)

        if self.sys.has_passthrough and self.output_synapse is None:
            # the user shouldn't filter the output node themselves. an
            # output synapse should be given so we can do it before the
            # passthrough.
            warnings.warn("output_synapse should be given if the system has "
                          "a passthrough, otherwise filtering the output will "
                          "also filter the passthrough")

        if not self.sys.is_stable:
            # This means certain normalizers won't work, because the worst-case
            # output is now unbounded.
            warnings.warn("system (%s) is not exponentially stable" % self.sys)

        # Obtain state-space transformation and realization
        self._realizer_result = self.realizer(self.sys, self.radii)

        # Map the system onto the synapse
        self._mapped = ss2sim(self.realization, self.synapse, self.dt)

        with self:
            # Create internal Nengo objects
            self._input = nengo.Node(size_in=self.size_in, label="input")
            self._output = nengo.Node(size_in=self.size_out, label="output")

            x_input, x_output = self._make_core(solver, **ens_kwargs)

            # Connect everything up using (A, B, C, D)
            nengo.Connection(
                x_output, x_input, transform=self.A,
                synapse=self.synapse)
            nengo.Connection(
                self.input, x_input, transform=self.B,
                synapse=self.input_synapse)
            nengo.Connection(
                x_output, self.output, transform=self.C,
                synapse=self.output_synapse)

            if not np.allclose(self.D, 0):
                logging.info("Passthrough (%s) on LinearNetwork with sys=%s",
                             self.D, self.sys)
                nengo.Connection(
                    self.input, self.output, transform=self.D,
                    synapse=None)