Exemple #1
0
def test_bad_filt():
    sys = PadeDelay(0.1, order=4).X
    with pytest.raises(ValueError):
        sys.filt(np.ones((4, 4)))
    with pytest.raises(ValueError):
        sys.filt(np.ones((4, 1)), filtfilt=True)
    with pytest.raises(ValueError):
        sys.filt(np.ones((4,)), copy=False)
def test_readout(legendre, d, tol):
    theta = 0.1

    if legendre:
        sys = LegendreDelay(theta, d)
        readout = _legendre_readout
    else:
        sys = PadeDelay(theta, d)
        readout = _pade_readout
    # decoding at r=1 (t=-theta) is equivalent to decoding a delay of theta
    C = readout(d, 1)
    assert np.allclose(sys.C, C)
    assert np.allclose(sys.D, 0)

    freqs = np.linspace(0, 5, 100)
    s = 2j * np.pi * freqs

    # check that frequency response has small error at low-frequencies
    # for a variety of different readouts
    for r in np.linspace(0, 1, 100):
        C = readout(d, r)

        sys = LinearSystem((sys.A, sys.B, C, sys.D), analog=True)
        error = np.abs(sys(s) - np.exp(-r*theta*s))
        assert 0 < rms(error) < tol, r
def test_output_filter(Simulator, seed, rng):
    dt = 0.001
    T = 1.0

    sys = PadeDelay(0.1, order=3, p=3)
    assert sys.has_passthrough
    synapse = 0.01

    with Network(seed=seed) as model:
        stim = nengo.Node(
            output=nengo.processes.WhiteSignal(T, high=10, seed=seed))
        subnet = LinearNetwork(sys,
                               1,
                               synapse=synapse,
                               output_synapse=synapse,
                               dt=dt,
                               neuron_type=nengo.neurons.Direct())
        nengo.Connection(stim, subnet.input, synapse=None)

        assert subnet.input_synapse is None

        p_ideal = nengo.Probe(subnet.input, synapse=sys)
        p_output = nengo.Probe(subnet.output, synapse=None)

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

    assert np.allclose(sim.data[p_output][:-1], sim.data[p_ideal][1:])
Exemple #4
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)
Exemple #5
0
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])
Exemple #6
0
def time_cells(order):
    seed = 0
    n_neurons = 300
    theta = 4.784
    tau = 0.1
    radius = 0.3
    realizer = Balanced


    # The following was patched from nengolib commit
    # 7e204e0c305e34a4f63d0a6fbba7197862bbcf22, prior to
    # aee92b8fc45749f07f663fe696745cf0a33bfa17, so that
    # the generated PDF is consistent with the version that the
    # overlay was added to.
    def PadeDelay(c, q):
        j = np.arange(1, q+1, dtype=np.float64)
        u = (q + j - 1) * (q - j + 1) / (c * j)

        A = np.zeros((q, q))
        B = np.zeros((q, 1))
        C = np.zeros((1, q))
        D = np.zeros((1,))

        A[0, :] = B[0, 0] = -u[0]
        A[1:, :-1][np.diag_indices(q-1)] = u[1:]
        C[0, :] = - j / float(q) * (-1) ** (q - j)
        return LinearSystem((A, B, C, D), analog=True)

    F = PadeDelay(theta, order)
    synapse = Alpha(tau)

    pulse_s = 0
    pulse_w = 1.0
    pulse_h = 1.5

    T = 6.0
    dt = 0.001
    pulse = np.zeros(int(T/dt))
    pulse[int(pulse_s/dt):int((pulse_s + pulse_w)/dt)] = pulse_h

    with Network(seed=seed) as model:
        u = Node(output=PresentInput(pulse, dt))

        delay = LinearNetwork(
            F, n_neurons_per_ensemble=n_neurons / len(F), synapse=synapse,
            input_synapse=None, radii=radius, dt=dt, realizer=realizer())
        Connection(u, delay.input, synapse=None)

        p_x = Probe(delay.state.input, synapse=None)
        p_a = Probe(delay.state.add_neuron_output(), synapse=None)

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

    return sim.trange(), sim.data[p_x], sim.data[p_a]
Exemple #7
0
def test_invalid_sample():
    process = WhiteSignal(1.0, high=10)
    sys = PadeDelay(0.1, order=4)

    dist = EvalPoints(sys, process)
    with pytest.raises(ValidationError):
        dist.sample(100, len(sys))  # needs to equal sys.size_out

    dist = Encoders(sys, process)
    with pytest.raises(ValidationError):
        dist.sample(100, len(sys))  # needs to equal sys.size_out
Exemple #8
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)
Exemple #9
0
def test_non_siso_filtering(rng):
    sys = PadeDelay(0.1, order=4)
    length = 1000

    SIMO = sys.X
    assert not SIMO.is_SISO
    assert SIMO.size_in == 1
    assert SIMO.size_out == len(sys)

    x = SIMO.impulse(length)
    for i, (sub1, sub2) in enumerate(zip(sys, SIMO)):
        assert sub1 == sub2
        y1 = sub1.impulse(length)
        y2 = sub2.impulse(length)
        _transclose(shift(y1), shift(y2), x[:, i])

    B = np.asarray([[1, 2, 3], [0, 0, 0], [0, 0, 0], [0, 0, 0]]) * sys.B
    u = rng.randn(length, 3)

    Bu = u.dot([1, 2, 3])
    assert Bu.shape == (length,)
    MISO = LinearSystem((sys.A, B, sys.C, np.zeros((1, 3))), analog=True)
    assert not MISO.is_SISO
    assert MISO.size_in == 3
    assert MISO.size_out == 1

    y = cont2discrete(MISO, dt=0.001).filt(u)
    assert y.shape == (length,)
    assert np.allclose(shift(sys.filt(Bu)), y)

    MIMO = MISO.X
    assert not MIMO.is_SISO
    assert MIMO.size_in == 3
    assert MIMO.size_out == 4

    y = MIMO.filt(u)
    I = np.eye(len(sys))
    for i, sub1 in enumerate(MIMO):
        sub2 = LinearSystem((sys.A, B, I[i:i+1], np.zeros((1, 3))))
        _transclose(sub1.filt(u), sub2.filt(u), y[:, i])
Exemple #10
0
def discrete_example(seed, dt):
    n_neurons = 1000
    theta = 0.1
    freq = 50
    q = 27
    radii = 1.0
    sys = PadeDelay(theta, q)

    T = 5000*(dt+0.001)
    rms = 1.0
    signal = WhiteSignal(T, high=freq, rms=rms, y0=0)

    tau = 0.1
    tau_probe = 0.02
    reg = 0.1

    # Determine radii using direct mode
    with LinearNetwork(
            sys, n_neurons_per_ensemble=1, input_synapse=tau, synapse=tau,
            dt=dt, neuron_type=Direct(),
            realizer=Balanced()) as model:
        Connection(Node(output=signal), model.input, synapse=None)
        p_x = Probe(model.state.input, synapse=None)

    with Simulator(model, dt=dt, seed=seed+1) as sim:
        sim.run(T)

    radii *= np.max(abs(sim.data[p_x]), axis=0)
    logging.info("Radii: %s", radii)

    with Network(seed=seed) as model:
        u = Node(output=signal)

        kwargs = dict(
            n_neurons_per_ensemble=n_neurons / len(sys),
            input_synapse=tau, synapse=tau, radii=radii,
            solver=LstsqL2(reg=reg), realizer=Balanced())
        delay_disc = LinearNetwork(sys, dt=dt, **kwargs)
        delay_cont = LinearNetwork(sys, dt=None, **kwargs)
        Connection(u, delay_disc.input, synapse=None)
        Connection(u, delay_cont.input, synapse=None)

        p_u = Probe(u, synapse=tau_probe)
        p_y_disc = Probe(delay_disc.output, synapse=tau_probe)
        p_y_cont = Probe(delay_cont.output, synapse=tau_probe)

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

    return (theta, dt, sim.trange(), sim.data[p_u],
            sim.data[p_y_disc], sim.data[p_y_cont])
Exemple #11
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)
def test_radii(Simulator, seed, plt):
    sys = canonical(PadeDelay(0.2, order=3))
    dt = 0.001
    T = 0.5

    plt.figure()

    # Precompute the exact bounds for an impulse stimulus
    radii = []
    for sub in sys:
        response = sub.impulse(int(T / dt), dt=dt)
        amplitude = np.max(abs(response))
        assert amplitude >= 1e-4  # otherwise numerical issues
        radii.append(amplitude)

        plt.plot(response / amplitude, linestyle='--')

    with Network(seed=seed) as model:
        # Impulse stimulus
        stim = nengo.Node(output=lambda t: 1 / dt if t <= dt else 0)

        # Set explicit radii for controllable realization
        subnet = LinearNetwork(sys,
                               n_neurons_per_ensemble=1,
                               synapse=0.2,
                               input_synapse=0.2,
                               dt=dt,
                               radii=radii,
                               realizer=Identity(),
                               neuron_type=nengo.neurons.Direct())
        nengo.Connection(stim, subnet.input, synapse=None)
        p = nengo.Probe(subnet.state.output, synapse=None)

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

    plt.plot(sim.data[p], lw=5, alpha=0.5)

    assert np.allclose(np.max(abs(sim.data[p]), axis=0), 1, atol=1e-4)
Exemple #13
0
    Q = observe_gram(balsys)

    diag = np.diag_indices(len(P))
    offdiag = np.ones_like(P, dtype=bool)
    offdiag[diag] = False
    offdiag = np.where(offdiag)

    assert np.allclose(P[diag], S)
    assert np.allclose(P[offdiag], 0)
    assert np.allclose(Q[diag], S)
    assert np.allclose(Q[offdiag], 0)


@pytest.mark.parametrize(
    "sys",
    [PadeDelay(0.1, 4), PadeDelay(0.2, 5, 5),
     Alpha(0.2)])
def test_hankel(sys):
    assert np.allclose(hsvd(sys), balanced_transformation(sys)[2])


def test_l1_norm_known():
    # Check that Lowpass has a norm of exactly 1
    l1, rtol = l1_norm(Lowpass(0.1))
    assert np.allclose(l1, 1)
    assert np.allclose(rtol, 0)

    # Check that passthrough is handled properly
    assert np.allclose(l1_norm(Lowpass(0.1) + 5)[0], 6)
    assert np.allclose(l1_norm(Lowpass(0.1) - 5)[0], 6)
Exemple #14
0
    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)


@pytest.mark.parametrize("sys", [PadeDelay(0.1, order=5), Lowpass(0.1)])
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)
Exemple #15
0
def go(name, tau, factory, recurrent_solver=Default,
       pre_fixture=None, post_fixture=None):

    set_style()
 
    theta = 0.1
    order = 3
    freq = 3
    power = 1.0  # chosen to keep radii within [-1, 1]

    # print("PadeDelay(%s, %s) => %f%% error @ %sHz" % (
    #     theta, order, 100*abs(pade_delay_error(theta*freq, order=order)), freq))
    pd = PadeDelay(theta=theta, order=order)

    # Heuristic for normalizing state so that each dimension is ~[-1, +1]
    rz = Balanced()(pd, radii=1./(np.arange(len(pd))+1))
    sys = rz.realization

    # Compute matrix to transform from state (x) -> sampled window (u)
    t_samples = 100
    C = np.asarray([readout(len(pd), r)
                    for r in np.linspace(0, 1, t_samples)]).dot(rz.T)
    assert C.shape == (t_samples, len(sys))


    n_neurons = 128  # per dimension
    map_hw = ss2sim(sys, synapse=Lowpass(tau), dt=None)  # analog mapping
    assert np.allclose(map_hw.A, tau*sys.A + np.eye(len(sys)))
    assert np.allclose(map_hw.B, tau*sys.B)

    with nengo.Network() as model:
        if pre_fixture is not None:
            pre_fixture(model)

        u = nengo.Node(output=0, label='u')
        p_u = nengo.Probe(u, synapse=None)
        
        # This is needed because a single node can't connect to multiple
        # different ensembles. We need a separate node for each ensemble.
        Bu = [nengo.Node(output=lambda _, u, b_i=map_hw.B[i].squeeze(): b_i*u,
                         size_in=1, label='Bu[%d]' % i)
              for i in range(len(sys))]
        
        X = []
        for i in range(len(sys)):
            ens = nengo.Ensemble(
                n_neurons=n_neurons, dimensions=1, label='X[%d]' % i)

            X.append(ens)
     
        P = []
        for i in range(len(sys)):
            nengo.Connection(u, Bu[i], synapse=None)
            nengo.Connection(Bu[i], X[i], synapse=tau)
            for j in range(len(sys)):
                nengo.Connection(X[j], X[i], synapse=tau,
                                 function=lambda x_j, a_ij=map_hw.A[i, j]: a_ij*x_j,
                                 solver=recurrent_solver)
            P.append(nengo.Probe(X[i], synapse=None))


    def do_trial(name, seed, length=2000, dt=0.001, tau_probe=0.02,
                 sanity=False, **kwargs):
        # Note: depends on the globals, (factory, C, model, u, p_u, P, sys)

        process = nengo.processes.WhiteSignal(
            period=length*dt, rms=power, high=freq, y0=0, seed=seed)

        test_u = process.run_steps(length, dt=dt)
        x_ideal = sys.X.filt(test_u, dt=dt)

        if sanity:
            analyze("ideal-%s" % name, 
                    t=process.ntrange(length, dt=dt),
                    u=test_u,
                    x_hat=x_ideal,
                    x_ideal=x_ideal,
                    C=C,
                    theta=theta,
                    dump_file=False,
                    do_plot=False)
            
        u.output = process

        with factory(network=model, dt=dt) as sim:
            sim.run(length*dt)
            if post_fixture:
                post_fixture(sim)

        assert np.allclose(test_u, np.asarray(sim.data[p_u]))

        # Use discrete principle 3, offline, to get x_hat
        # from the unfiltered spikes representing x.
        # This is analagous to probing the PSC, pre-encoding.
        syn_probe = Lowpass(tau_probe)
        map_out = ss2sim(sys, synapse=syn_probe, dt=dt)
        x_raw = np.asarray([sim.data[p] for p in P]).squeeze()
        f = map_out.A.dot(x_raw) + map_out.B.dot(test_u.T)
        x_hat = syn_probe.filt(f, axis=1, dt=dt).T

        return analyze(
            name=name, t=sim.trange(), u=test_u,
            x_hat=x_hat, x_ideal=x_ideal, C=C,
            theta=theta, **kwargs)


    data = defaultdict(list)
    for trial in range(25):
        for seed in range(1, 11):
            data['Trial'].append(trial)
            data['Test Case (#)'].append(seed)
            data['NRMSE'].append(
                do_trial(name="scratch-%s-DN-%d-%d" % (name, trial, seed),
                         seed=seed, dump_file=False))

    df = DataFrame(data)
    df.to_pickle(datapath("%s-delay-network.pkl" % name))

    return bs.bootstrap(np.asarray(df['NRMSE']),
                        stat_func=bs_stats.mean, alpha=1-0.95)  # 95% CI
Exemple #16
0
def figure_delay_full(targets):
    q = 12
    freq_times_theta = 1.0
    theta = 0.2  # affects resolution of plot alongside dt

    T = 10 * theta
    dt = 0.005
    seed = 5  # chosen to look "interesting"
    u = WhiteSignal(T, high=freq_times_theta / theta, seed=seed, y0=0,
                    rms=0.4).run(T, dt=dt)
    t = np.arange(0, T, dt)

    i = q - 1 - np.arange(q, dtype=np.float64)
    assert np.allclose(delay_readout(q, theta, theta),
                       (-1)**(q - 1 - i) * (i + 1) / q)

    num_thetas = 200
    num_freqs = 200
    props = np.linspace(0, 1.0, num_thetas)
    freqs = np.linspace(0, 10. / theta, num_freqs)
    s = 2.j * np.pi * freqs

    cmap = sns.diverging_palette(h_neg=34,
                                 h_pos=215,
                                 s=99,
                                 l=66,
                                 sep=1,
                                 center="dark",
                                 n=num_thetas)

    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[0])
            ax2 = plt.subplot(gs[1])

            ax1.set_title(r"Temporal Coding Accuracy").set_y(1.05)
            ax2.set_title(r"Decoding at $\theta$ = Frequency$^{-1}$").set_y(
                1.05)

            for i, thetap in enumerate(props * theta):
                A, B, _, D = PadeDelay(theta, order=q).ss
                C = delay_readout(q, thetap, theta)[::-1]
                tf = LinearSystem((A, B, C, D))

                ax1.plot(freqs * theta,
                         abs(np.exp(-s * thetap) - tf(s)),
                         c=cmap[i],
                         alpha=0.7)
                ax2.plot(t / theta, tf.filt(u, dt=dt), c=cmap[i], alpha=0.5)

            s = 0.4
            pts = np.asarray([[freq_times_theta, 0],
                              [(1 - s) * freq_times_theta, -s / 2],
                              [(1 + s) * freq_times_theta, -s / 2]])
            ax1.add_patch(Polygon(pts, closed=True, color='black'))

            ax1.set_xlabel(r"Frequency $\times \, \theta$ [Hz $\times$ s]",
                           labelpad=20)
            ax1.set_ylabel(r"Absolute Error", labelpad=20)

            ax2.set_xlabel(r"Time $\times \, \theta^{-1}$ [s / s]",
                           labelpad=20)
            ax2.set_ylabel(r"Output")

            lc = LineCollection(len(cmap) * [[(0, 0)]], lw=10, colors=cmap)
            ax2.legend([lc], [r"$\theta'$"],
                       handlelength=2,
                       handler_map={type(lc): HandlerDashedLines()},
                       bbox_to_anchor=(1.02, 1),
                       loc=2,
                       borderaxespad=0.)

            sns.despine(offset=15)

            savefig(targets[0])
Exemple #17
0
def delay_example():
    seed = 2

    n_neurons = 1000
    theta = 1.0
    sys = PadeDelay(theta, 6)

    T = 20.0
    dt = 0.001
    freq = 1
    rms = 0.4

    tau = 0.1
    #tau_probe = 0.02

    radii = np.ones(len(sys))  # initial guess
    desired_radius = 0.8  # aiming to get this as largest x
    num_iter = 5  # number of times to simulate and retry new radius

    # could also do this simply by the direct method in discrete_example
    # but this is just to demonstrate that you can do something iterative
    # within the same network
    for _ in range(num_iter):
        with Network(seed=seed) as model:
            signal = WhiteSignal(T, high=freq, rms=rms, y0=0)
            u = Node(output=signal)

            delay = LinearNetwork(
                sys, n_neurons_per_ensemble=n_neurons / len(sys), synapse=tau,
                input_synapse=tau, radii=radii, realizer=Balanced(), dt=None)
            Connection(u, delay.input, synapse=None)

            # Since delay.state.input is the PSC x, when we can transform
            # that with C to get y (note D=0) without applying any filters
            assert np.allclose(delay.D, 0)
            output = Node(size_in=1)
            Connection(delay.state.input, output, transform=delay.C,
                       synapse=None)
            # Alternative: create an output tau*dy + y such that when
            # filtered we get back y! Note: dy = C(Ax + Bu), since D=0.
            #Connection(delay.state.output, output,
            #           transform=tau*delay.C.dot(delay.A), synapse=tau)
            #Connection(u, output,
            #           transform=tau*delay.C.dot(delay.B), synapse=tau)
            #Connection(delay.output, output, synapse=tau)

            p_u = Probe(u, synapse=None)
            p_x = Probe(delay.state.input, synapse=None)
            p_a = Probe(delay.state.add_neuron_output(), synapse=None)
            p_y = Probe(output, synapse=None)

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

        # place the worst case at x=desired_radius and re-run
        worst_x = np.max(np.abs(sim.data[p_x]), axis=0)
        radii *= (worst_x / desired_radius)
        logging.info("Radii: %s\nWorst x: %s", radii, worst_x)

    return (theta, dt, sim.trange(), sim.data[p_u], sim.data[p_x],
            sim.data[p_a], sim.data[p_y])
Exemple #18
0
def figure_pca(targets):
    orders = [3, 6, 9, 12, 15, 27]
    theta = 10.
    dt = 0.01
    T = theta

    length = int(T / dt)
    t = np.linspace(0, T - dt, length)
    t_norm = np.linspace(0, 1, len(t))
    cmap = sns.diverging_palette(h_neg=34,
                                 h_pos=215,
                                 s=99,
                                 l=66,
                                 sep=1,
                                 center="dark",
                                 as_cmap=True)

    class MidpointNormalize(colors.Normalize):
        """Stolen from http://matplotlib.org/users/colormapnorms.html"""
        def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
            self.midpoint = midpoint
            colors.Normalize.__init__(self, vmin, vmax, clip)

        def __call__(self, value, clip=None):
            # I'm ignoring masked values and all kinds of edge cases to make a
            # simple example...
            x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
            return np.ma.masked_array(np.interp(value, x, y))

    with sns.axes_style('white'):
        with sns.plotting_context('paper', font_scale=2.8):
            pylab.figure(figsize=(22, 7))
            gs = gridspec.GridSpec(2, len(orders), height_ratios=[1.3, 1])

            for k, order in enumerate(orders):
                F = PadeDelay(theta, order)
                A = F.A
                dA, dB, _, _ = cont2discrete(F, dt=dt).ss

                dx = np.empty((length, len(F)))
                x = np.empty((length, len(F)))
                x[0, :] = dB.squeeze()  # the x0 from delta input

                for j in range(length - 1):
                    dx[j, :] = A.dot(x[j, :])
                    x[j + 1, :] = dA.dot(x[j, :])
                dx[-1, :] = A.dot(x[-1, :])

                # Compute PCA of trajectory for top half
                pca = PCA(x, standardize=False)
                p = pca.Y[:, :3]

                logging.info("%d Accounted Variance: %s", order,
                             np.sum(pca.fracs[:3]) / np.sum(pca.fracs))

                # Compute curve for bottom half (and color map center)
                dist = np.cumsum(np.linalg.norm(dx, axis=1))
                dist = dist / np.max(dist)
                infl = np.where((np.diff(np.diff(dist)) >= 0)
                                & (t_norm[:-2] >= 0))[0][-1]
                cnorm = MidpointNormalize(midpoint=t_norm[infl])

                ax = plt.subplot(gs[k], projection='3d')
                ax.set_title(r"$q = %d$" % order).set_y(1.1)

                # Draw in reverse order so the start is on top
                ax.scatter(p[::-1, 0],
                           p[::-1, 1],
                           p[::-1, 2],
                           lw=5,
                           c=t_norm[::-1],
                           cmap=cmap,
                           norm=cnorm,
                           alpha=0.5)
                ax.set_xticks([])
                ax.set_yticks([])
                ax.set_zticks([])
                if k == 0:
                    ax.annotate('PCA',
                                xy=(-50, 150),
                                ha='left',
                                va='top',
                                size=22,
                                rotation=90,
                                bbox=None,
                                xycoords='axes points')
                ax.view_init(elev=25, azim=150)

                ax = plt.subplot(gs[len(orders) + k])
                ax.scatter(t, dist, lw=5, c=t_norm, cmap=cmap, norm=cnorm)
                ax.vlines(t[infl], 0, 1, linestyle='--', lw=3, alpha=0.7)
                if k == 0:
                    ax.set_yticks([0, 1])
                    ax.set_ylabel("Length of Curve")
                else:
                    ax.set_yticks([])
                ax.set_xticks([0, theta / 2, theta])
                ax.set_xticklabels(
                    [r"$0$", r"$\frac{\theta}{2}$", r"$\theta$"])
                ax.xaxis.set_tick_params(pad=10)
                ax.set_xlabel("Time [s]", labelpad=20)

                sns.despine(offset=10, ax=ax)

            savefig(targets[0])
Exemple #19
0
                    ([[-20, 1], [-100, 0]], [[0], [100]], [[1, 0]], [[0]]))


def test_is_stable():
    sys = Lowpass(0.1)
    assert sys.is_stable

    assert not (~s).is_stable  # integrator

    assert LinearSystem(1).is_stable

    assert (~(z * (z - 0.5))).is_stable
    assert not (z / (z - 1)).is_stable  # discrete integrator


@pytest.mark.parametrize("sys", [PadeDelay(0.1, 4), PadeDelay(0.2, 5, 5)])
def test_decompose_states(sys):
    assert np.dot(sys.C, list(sys)) + sys.D == sys


def test_non_siso_manipulation():
    sys = Alpha(0.1)
    A, B, C, D = sys.ss

    SIMO = LinearSystem((A, B, np.eye(len(A)), [[0], [0]]))
    assert not SIMO.is_SISO
    assert SIMO.size_in == 1
    assert SIMO.size_out == 2
    assert SIMO.shape == (2, 1)
    assert not SIMO.has_passthrough
    assert ss_equal(_eval(SIMO), SIMO)
Exemple #20
0
    rsys = realize_result.realization
    assert ss_equal(rsys, sys.transform(realize_result.T))

    # Check that it's still the same system, even though different matrices
    assert sys_equal(sys, rsys)
    if radii == 1:
        assert ss_equal(sys, rsys)
    else:
        assert not np.allclose(sys.B, rsys.B)
        assert not np.allclose(sys.C, rsys.C)

    # Check that the state vectors have scaled power
    assert np.allclose(state_norm(sys) / radii, state_norm(rsys))


@pytest.mark.parametrize("sys", [PadeDelay(0.1, 4), PadeDelay(0.05, 5, 5)])
def test_balreal_normalization(sys):
    radii = np.arange(len(sys)) + 1

    balanced = Balanced()
    assert repr(balanced) == "Balanced()"

    realizer_result = balanced(sys, radii)

    T, Tinv, _ = balanced_transformation(sys)

    assert np.allclose(realizer_result.T / radii[None, :], T)
    assert np.allclose(realizer_result.Tinv * radii[:, None], Tinv)
    assert np.allclose(inv(T), Tinv)

    assert sys_equal(sys, realizer_result.realization)
Exemple #21
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 compute_error(phi_times_freq, depth, order, p=None):
    pf = np.asarray(phi_times_freq)
    # switch to a delay of 1 for simplicity
    # this works due to the substitution of variables: theta*s <-> 1*s'
    sys = PadeDelay(1., order, p=p)
    return sys.evaluate(pf / depth)**depth - np.exp(-2j * np.pi * pf)
Exemple #23
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])