Simulator#
- class brainpy.state.network.Simulator(*args, **kwargs)#
Explicit NEST-flavored network builder and runner.
- Parameters:
dt (
brainunit.Quantity) – Simulation timestep; set intobrainstate.environat construction.
Examples
>>> import brainunit as u >>> from brainpy.state import iaf_psc_alpha, poisson_generator, spike_recorder >>> from brainpy.state import Simulator, all_to_all >>> sim = Simulator(dt=0.1 * u.ms) >>> pop = sim.create(iaf_psc_alpha, 10) >>> noise = sim.create(poisson_generator, rate=8000. * u.Hz) >>> rec = sim.create(spike_recorder) >>> sim.connect(noise, pop, weight=20. * u.pA, delay=1.5 * u.ms, rule=all_to_all) >>> sim.connect(pop, rec) >>> res = sim.simulate(100. * u.ms) >>> rate = res.rate(rec)
- connect(pre, post, *, rule=<brainpy.state._AllToAll object>, weight=None, delay=None, comm='dense', receptor_type=None, synapse=None, vt=None, allow_autapses=True, allow_multapses=True, seed=None)[source]#
Connect
pretopost(or register a recorder tap).comm='sparse'routes the connectivity through a sparse CSR event matmul (memory-light for large fan-out);'dense'(default) uses a dense weight matrix. Both yield identical results for the same rule/seed.receptor_type='uniform'routes each edge to a uniformly-drawn receptor port of a multi-receptor post population (iaf_psc_exp_multisynapse).synapse=<spec>builds a plasticEventPlasticProjfrom a rebuilt_nestsynapse spec (static_synapse, thetsodyks*family,quantal_stp_synapse);weight/delayhere override the spec’s defaults.synapse=None(default) keeps the staticEventProjectionpath unchanged.connect(dopa_pool, vt)(reverse direction,postavolume_transmitterview) registers each presynaptic segment as a dopaminergic source on the transmitter and builds no projection.vt=<volume_transmitter view>binds a transmitter to a synapse spec that reads a broadcast signal (signal_reads, e.g.stdp_dopamine_synapse); such a spec raises if novtis supplied.Analog recorders (
voltmeter/multimeter) are connected in NEST’s reversed direction —connect(recorder, pop)— because the recorder observes the population. This registers a per-step State tap; no projection is built.- Returns:
The projection handle(s) built by this call (a single handle when one projection is built, a list for multi-segment fan-out). A plastic handle (
synapse=spec) can be passed torecord_weight(). Recorder-tap connects (and current injectors) returnNone.- Return type:
EventProjectionorEventPlasticProjorlistorNone
- cont(duration, *, dt=None)[source]#
Continue the rollout for
durationWITHOUT re-initialising state.Unlike
simulate(), state persists across calls (biological time accumulates), so a host loop can interleave Python work between chunks — read this window’s recordings, rewrite ahost_driveschedule, or overwrite static weights viaget_connections(...).set('weight', ...)— while the compiled per-chunkfor_loopis reused (no recompile as long as only State contents change). Lazily initialises on the first call (or afterreset_rollout()). Each call returns aSimulationResultfor that window, whosetimesare absolute (offset by the accumulated rollout clock).
- create(model_cls, size=1, *, params=None, positions=None, **kw)[source]#
Instantiate a population/device and return a
NodeView.Generators are deferred (realised per target at
connect()) so each target receives an independent train, mirroring NEST fan-out.positions=<spatial layer>attaches node coordinates to a neuron population (NESTCreate(model, positions=spatial.grid/free(...))). Agrid()/ concretefree()layer derives the population size from its coordinates (thesizeargument is ignored); a deferredfreelayer (sampled from a distribution) drawssizepositions. The coordinates are stored underid(population)so aspatial_pairwise_bernoulli()rule can be bound to them atconnect().
- get_connections(source=None, target=None, synapse=None)[source]#
Enumerate realized synapses across projections (NEST
GetConnections).Returns a
SynapseCollectionover the edges matching the filters, letting you read and write weights / delays without holding each projection handle. The collection is a lazy view: weights and delays are re-read from the live projections on eachget(), so a query made beforesimulate()still reflects post-simulation evolved plastic weights.- Parameters:
source (
NodeView, optional) – Keep only edges whose presynaptic neuron lies in this view (matched by population identity and population-local index).Nonekeeps all.target (
NodeView, optional) – Keep only edges whose postsynaptic neuron lies in this view.Nonekeeps all.synapse (
str, optional) – Keep only projections with this synapse-model name ('static_synapse'for the static event path, else the plastic spec’s class name such as'stdp_synapse').Nonekeeps all.
- Returns:
A filtered, lazy view over the matching edges (empty if none match).
- Return type:
See also
connectBuild the projections this enumerates.
Examples
>>> import brainunit as u >>> from brainpy import state as bp >>> sim = bp.Simulator(dt=0.1 * u.ms) >>> exc = sim.create(bp.iaf_psc_exp, 4) >>> _ = sim.connect(exc, exc, rule=bp.all_to_all, weight=20. * u.pA, ... allow_autapses=False, comm='sparse') >>> conns = sim.get_connections(source=exc, target=exc) >>> len(conns) 12 >>> bool(u.math.allclose(conns.get('weight'), 20. * u.pA)) True
- get_position(view)[source]#
Node coordinates of a spatial population/view (NEST
GetPosition).- Parameters:
view (
NodeView) – A single-segment view over a population created withcreate(positions=...).- Returns:
(n, ndim)coordinates (length units) in the view’s node order.- Return type:
Quantity- Raises:
ValueError – If the population was not created with
positions=.
Examples
>>> from brainpy import state as bp >>> import brainunit as u >>> sim = bp.Simulator(dt=0.1 * u.ms) >>> pop = sim.create(bp.iaf_psc_alpha, positions=bp.spatial.grid([4, 3], extent=[2.0, 1.5])) >>> [round(float(v), 2) for v in u.get_magnitude(sim.get_position(pop).to(u.um))[0]] [-0.75, 0.5]
- record_weight(proj)[source]#
Register a per-step weight tap on a plastic projection.
projis the handle returned byconnect(..., synapse=spec). Aftersimulate(), read the stacked(n_steps, n_edges)weight trajectory (CSR sorted-by-pre edge order) viaSimulationResult.weight_trace(). Mirrors the analog-recorder tap, but reads the projection’sweightState rather than a population’s recordable.- Returns:
The same
proj, for chaining.- Return type:
- Raises:
TypeError – If
projis not a plastic projection (onlyconnect(..., synapse=)builds one; the static path has no plasticweightState to record).
- reset_rollout(*, dt=None)[source]#
Initialise all state and start a fresh persistent rollout at
t = 0.Calls
brainstate.nn.init_all_states(self)and zeroes the accumulated rollout clock (_base_t/_base_i).simulate()calls this for you; call it explicitly before acont()loop to (re)start cleanly.
- simulate(duration, *, dt=None)[source]#
Run for
durationfrom a freshly initialised state.Spike recorders are stacked as
(n_steps, n_recorded)arrays; analog recorders (voltmeter/multimeter) tap their target population’s State each step (after the update) into(n_steps, n_recorded)traces keyed by recordable. The run’s time axis is exposed asres.times.This re-initialises ALL state (
init_all_states) and runs one window fromt = 0. To continue a rollout across windows without re-initialising — interleaving host-side work between chunks (read recordings, rewritehost_driveschedules, overwrite static weights) — usecont().
- tripartite_connect(pre, post, third, *, conn_spec, third_factor_conn_spec, syn_specs=None, seed=None, comm='dense', allow_autapses=True, allow_multapses=True)[source]#
Wire a tripartite
pre -> post+ astrocyte network (NESTTripartiteConnect).Samples the primary
pre -> postedges once viaconn_specand shares that single realization across three projections (NEST’s tripartite semantics):primary
pre -> post(the direct synapse,syn_specs['primary']).For each realized primary edge
(pre_i -> post_j), thethird_factor_conn_spec(third_factor_bernoulli_with_pool()) runs a Bernoulli(p) trial; if it succeeds the edge is paired with one astrocyte drawn frompost_j’s pool, creating third_inpre_i -> astro(syn_specs['third_in'], delta IP3) and third_outastro -> post_j(syn_specs['third_out'], asic_connection).
Reuses the existing static
EventProjectionpath for primary + third_in and the mergedsic_connection(as_current) path for third_out; no new deposit primitive. Each arm is registered forget_connections().- Parameters:
pre (
NodeView) – Single-population views for the presynaptic, postsynaptic, and astrocyte populations.premay be a prefix slice (e.g. the Brunel excitatory populationneurons[:N_ex]).post (
NodeView) – Single-population views for the presynaptic, postsynaptic, and astrocyte populations.premay be a prefix slice (e.g. the Brunel excitatory populationneurons[:N_ex]).third (
NodeView) – Single-population views for the presynaptic, postsynaptic, and astrocyte populations.premay be a prefix slice (e.g. the Brunel excitatory populationneurons[:N_ex]).conn_spec (
ConnRule) – The primary one-directional rule, e.g.pairwise_bernoulli()orfixed_indegree().third_factor_conn_spec (
_ThirdFactorBernoulliWithPool) – The astrocyte-pool rule fromthird_factor_bernoulli_with_pool().syn_specs (
dict, optional) –{'primary': {...}, 'third_in': {...}, 'third_out': {...}}; each value is a dict ofconnect()keyword arguments (weight,delay,receptor_type,synapse).third_outtypically carries{'synapse': sic_connection(...)}. Missing entries default to{}(a plain unit-weight static delta).seed (
int, optional) – Base PRNG seed for the whole tripartite sample (primary + pairing + pool). The same seed reproduces the same realized edges.comm (
{'dense', 'sparse'}, default'dense') – Communication mode for the primary / third_in arms; third_out (thesic_connection) always rides'dense'(a graded current).allow_autapses (
bool, defaultTrue) – Passed to the primaryconn_spec.sample.allow_multapses (
bool, defaultTrue) – Passed to the primaryconn_spec.sample.
- Returns:
(primary_proj, third_in_proj, third_out_proj).third_in_projandthird_out_projareNonewhen no primary edge was paired (e.g.p=0).- Return type:
Examples
>>> import brainunit as u >>> from brainpy import state as bp >>> sim = bp.Simulator(dt=0.1 * u.ms) >>> pre = sim.create(bp.aeif_cond_alpha_astro, 10, params={'I_e': 1000.0 * u.pA}) >>> post = sim.create(bp.aeif_cond_alpha_astro, 10, params={'I_e': 1000.0 * u.pA}) >>> astro = sim.create(bp.astrocyte_lr_1994, 5, params={'delta_IP3': 0.2}) >>> prim, tin, tout = sim.tripartite_connect( ... pre, post, astro, ... conn_spec=bp.pairwise_bernoulli(1.0), ... third_factor_conn_spec=bp.third_factor_bernoulli_with_pool( ... p=1.0, pool_size=1, pool_type='block'), ... syn_specs={'primary': {'weight': 1.0 * u.nS, 'receptor_type': 1}, ... 'third_in': {'weight': 1.0}, ... 'third_out': {'synapse': bp.sic_connection(weight=1.0)}}, ... seed=0) >>> tout._channel_label 'I_SIC'