# Runners#

## Runners for Dynamical Systems#

The convenient simulation interfaces for dynamical systems in BrainPy are implemented in brainpy.simulation.runner. Currently, we implement two kinds of runner: DSRunner and ReportRunner. They have their respective advantages.

import brainpy as bp
import brainpy.math as bm

bp.math.set_platform('cpu')


## Initializing a runner#

Generally, we can initialize a runner with the format of:

SomeRunner(target=instance_of_dynamical_system,
inputs=inputs_for_target_variables,
monitors=interested_variables_to_monitor,
dyn_vars=dynamical_changed_variables,
jit=enable_jit_or_not)


In which

• target specifies the model to be simulated. It must an instance of brainpy.DynamicalSystem.

• monitors is used to define target variables in the model. During the simulation, the history values of the monitored variables will be recorded. More information can be found in the Monitors tutorial.

• inputs is used to define the input operations for specific variables. It will be expanded in the Inputs tutorial.

• dyn_vars is used to specify all the dynamically changed variables used in the target model.

• jit determines whether to use JIT compilation during the simulation.

Here we define an E/I balanced network as the simulation model.

class EINet(bp.Network):
def __init__(self, num_exc=3200, num_inh=800, method='exp_auto'):
# neurons
pars = dict(V_rest=-60., V_th=-50., V_reset=-60., tau=20., tau_ref=5.)
E = bp.dyn.LIF(num_exc, **pars, method=method)
I = bp.dyn.LIF(num_inh, **pars, method=method)
E.V[:] = bm.random.randn(num_exc) * 2 - 55.
I.V[:] = bm.random.randn(num_inh) * 2 - 55.

# synapses
E2E = bp.dyn.ExpCOBA(E, E, bp.conn.FixedProb(prob=0.02),
E=0., g_max=0.6, tau=5., method=method)
E2I = bp.dyn.ExpCOBA(E, I, bp.conn.FixedProb(prob=0.02),
E=0., g_max=0.6, tau=5., method=method)
I2E = bp.dyn.ExpCOBA(I, E, bp.conn.FixedProb(prob=0.02),
E=-80., g_max=6.7, tau=10., method=method)
I2I = bp.dyn.ExpCOBA(I, I, bp.conn.FixedProb(prob=0.02),
E=-80., g_max=6.7, tau=10., method=method)

super(EINet, self).__init__(E2E, E2I, I2E, I2I, E=E, I=I)


Then we will wrap it in different runners for dynamic simulation.

## brainpy.DSRunner#

brainpy.DSRunner aims to provide model simulation with an outstanding performance. It takes advantage of the structural loop primitive to lower the model onto the XLA devices.

net = EINet()

runner = bp.DSRunner(net,
monitors=['E.spike'],
inputs=[('E.input', 20.), ('I.input', 20.)],
jit=True)
runner.run(100.)

1.2974658012390137

bp.visualize.raster_plot(runner.mon.ts, runner.mon['E.spike'], show=True)


Note that if the parameter jit is set to True, then all the variables will be JIT compiled and thus the system cannot be debugged by Python debugging tools. For debugging, users can set jit=False.

## brainpy.ReportRunner#

brainpy.ReportRunner aims to provide a Pythonic interface for model debugging. Users can use the standard Python debugging tools when simulating the model with ReportRunner.

The drawback of the brainpy.ReportRunner is that it is relatively slow. It iterates the loop along times during the simulation.

net = EINet()

runner = bp.ReportRunner(net,
monitors=['E.spike'],
inputs=[('E.input', 20.), ('I.input', 20.)],
jit=True)
runner.run(100.)

3.402564764022827


We can see from the output that the time spent for simulation through ReportRunner is longer than that through DSRunner.

bp.visualize.raster_plot(runner.mon.ts, runner.mon['E.spike'], show=True)