API Reference

This page collects the API that is not tied to a specific model: building and simulating a network, units and helper macros, saving and loading, spatial networks, perturbation experiments and spike-train analysis. The docstrings of the models themselves (neurons, synapses, connections, plasticity rules, stimuli) are in the model catalogue, next to the equations and parameter tables; recording and plotting have their own pages.

TopicPage
Integrate-and-fire neurons (IF, ExtendedIF, AdEx)Integrate-and-fire models
Izhikevich, Hodgkin-Huxley, Morris-LecarOther neuron models
Rate and mean-field modelsRate models
Poisson and other spike sourcesSources
Tripod, BallAndStick, dendritesMulticompartment models
Synapse and receptor modelsSynapses and receptors
Connection types and connectivity rulesConnections
STDP, iSTDP, vSTDP, short-term plasticityPlasticity rules
Normalization, scaling, turnoverMetaplasticity
Stimulus modelsStimuli
Models shipped with SNNUtilsSNNUtils models
monitor!, record, getvariable, ...Recordings
threads, flush-to-zeroRunning simulations
SNNPlots functionsVisualization

All symbols below are exported by SNNModels; with using SpikingNeuralNetworks they are available as SNN.<name> (most of them also unqualified).

Index

Model composition and simulation

A network model is a NamedTuple (pop, syn, stim, name, time) built with compose. sim! integrates it without plasticity; train! runs the same loop and in addition calls update_traces! and plasticity! of every population and connection.

SNNModels.AbstractComponent — Type
AbstractComponent

Root of all network components: populations (AbstractPopulation), connections (AbstractConnection), stimuli (AbstractStimulus), groups of stimuli (AbstractGroup) and synapse models (AbstractSynapseParameter, AbstractSynapseVariable).

source
SNNModels.AbstractConnection — Type
AbstractConnection <: AbstractComponent

Abstract type of connections between populations (synapses, metaplasticity operators). A concrete connection has at least the fields param (an AbstractConnectionParameter), id, name and records (checked by validate_synapse_model), and implements

  • forward!(c, param, dt::Float32, T::Time): propagate presynaptic activity to the postsynaptic target variable; called every step by sim! and train!, after all populations are integrated.
  • optionally update_traces!(c, param, dt, T) and plasticity!(c, param, dt, T), called only by train!.
source
SNNModels.AbstractGroup — Type
AbstractGroup <: AbstractComponent

Abstract type for containers of components that act as one unit (e.g. StimulusGroup).

source
SNNModels.AbstractParameter — Type
AbstractParameter

Root of all parameter types (population, connection and stimulus parameters).

Every model object stores its parameter struct in the field param; the simulation loop dispatches integrate!, forward! and stimulate! on typeof(obj.param). Direct subtypes are AbstractPopulationParameter, AbstractConnectionParameter and AbstractStimulusParameter.

source
SNNModels.AbstractPopulation — Type
AbstractPopulation <: AbstractComponent

Abstract type of neuron populations. A concrete population has at least the fields N, param (an AbstractPopulationParameter), id, name and records (checked by validate_population_model), and implements

  • integrate!(p, param, dt::Float32): advance the state by one step dt (called by sim! and train!).
  • optionally update_traces!(p, param, dt, T) and plasticity!(p, param, dt, T), called only by train! (the defaults do nothing).
source
SNNModels.AbstractStimulus — Type
AbstractStimulus <: AbstractComponent

Abstract type of external inputs. A concrete stimulus has at least the fields param (an AbstractStimulusParameter), id, name and records, and implements

  • stimulate!(s, param, T::Time, dt::Float32): called once per time step, before the populations are integrated, to write the input into the target population variable.
source
SNNModels.AbstractStimulusGroup — Type
AbstractStimulusGroup <: AbstractGroup

Abstract type of groups of stimuli. When a model is simulated, the elements of a group are expanded and each element is stimulated as an individual AbstractStimulus (see sim!/train!).

source
SNNModels.EmptyParam — Type
EmptyParam

A struct representing an empty parameter.

Fields

  • type::Symbol: The type of the parameter, default is :empty.
source
SNNModels.NetworkModel — Type
NetworkModel

Alias of NamedTuple. A network model, as returned by compose, is a NamedTuple with fields pop, syn, stim (each a NamedTuple of components), time::Time and name::String.

source
SNNModels.Spiketimes — Type
Spiketimes

Type alias for Vector{Vector{Float32}}: one vector of spike times (ms) per neuron.

Example

using SpikingNeuralNetworks
st = SNN.Spiketimes([[1.0f0, 5.0f0], Float32[]])   # neuron 1 fires at 1 and 5 ms, neuron 2 never
source
SNNModels.Time — Type
Time(; t = [0.0f0], tt = Int32[0], dt = 0.125f0)
Time{FT}(; t = [zero(FT)], tt = Int32[0], dt = FT(0.125))

Mutable simulation clock shared by all components of a model. Time() is a Time{Float32}; a model whose populations are Float64 (see float_type) gets a Time{Float64} from compose.

The values are stored in one-element vectors so that the clock can be shared and updated in place by update_time!. Use get_time, get_step, get_dt and reset_time! to read or reset it.

Fields

  • t::Vector{FT} = [0.0f0]: current time (ms), t[1].
  • tt::Vector{Int32} = Int32[0]: number of integration steps performed, tt[1].
  • dt::FT = 0.125f0: time step (ms) of the last update.

Example

using SpikingNeuralNetworks
T = SNN.Time()
SNN.get_time(T)   # 0.0f0
source
SNNModels.Time — Method
Time(time::Number; dt = 0.125f0)
Time{FT}(time::Number; dt = 0.125)

Create a clock set at time (ms), with time step dt and step counter tt = round(time / dt) (Float32 unless FT is given).

Example

using SpikingNeuralNetworks
T = SNN.Time(100.0)   # t = 100 ms, tt = 800
source
SNNModels.float_type — Method
float_type(x)

Floating-point element type (Float32 or Float64) of a model object or type. The precision is chosen on the populations (e.g. Identity(N = 10, VFT = Vector{Float64})); connections and stimuli take the type of the variable they write into, and plasticity state, delay buffers and the clock follow. For a type: its first type parameter that is a float or a vector of floats, else Float32. For a network built with compose: the promotion over its populations.

source
SNNModels.isa_model — Method
isa_model(model)

Validate that a model has the required structure for a network model.

Arguments

  • model: The model to validate

Returns

  • true if valid

Throws

  • AssertionError if required fields (pop, syn, stim, time, name) are missing
  • AssertionError if any component fails validation

Details

  • Checks for presence of all required fields
  • Validates each population, synapse, and stimulus
  • Ensures time field is a Time struct
source
SNNModels.validate_population_model — Method
validate_population_model(model)

Validate a population model structure.

Arguments

  • model: The population model to validate

Throws

  • AssertionError if model doesn't inherit from AbstractPopulation
  • AssertionError if param doesn't inherit from AbstractPopulationParameter
  • AssertionError if required fields (N, param, id, name, records) are missing
source
SNNModels.validate_stimulus_model — Method
validate_stimulus_model(model)

Validate a stimulus model structure.

Arguments

  • model: The stimulus model to validate

Throws

  • AssertionError if model doesn't inherit from AbstractStimulus
  • AssertionError if param doesn't inherit from AbstractStimulusParameter
  • AssertionError if required fields (param, id, name, records) are missing
source
SNNModels.validate_synapse_model — Method
validate_synapse_model(model)

Validate a synapse/connection model structure.

Arguments

  • model: The synapse model to validate

Throws

  • AssertionError if model doesn't inherit from AbstractConnection
  • AssertionError if param doesn't inherit from AbstractConnectionParameter
  • AssertionError if required fields (param, id, name, records) are missing
source
SNNModels.change_plasticity — Method
change_plasticity(model, syn_name::Symbol; LTP = nothing, STP = nothing)

A new model in which the synapse syn_name is replaced by with_plasticity(model.syn[syn_name]; LTP, STP) (see with_plasticity): a rule left to nothing is kept, NoLTP() / NoSTP() switch that part off. Everything else in the result is the same object as in model, which is not modified. The rule types are type parameters of the synapse, so there is no in-place model-level variant.

The new synapse shares W, the connectivity, the delay queue, the records and any kept rule state with the old one: simulate only the new model (or deepcopy(model) first). A SynapseNormalization or AggregateScaling in the model keeps acting on the old synapse.

Throws

ArgumentError if syn_name is not a synapse of the model; the message lists the available names.

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 100); E.I .= 300.0
EE = SNN.SpikingSynapse(E, E, :ge; conn = (p = 0.2, μ = 0.5))
model = SNN.compose(; E, EE, silent = true)
model_p = SNN.change_plasticity(model, :EE; LTP = SNN.STDPGerstner())
SNN.train!(; model = model_p, duration = 100ms)
model_f = SNN.change_plasticity(model_p, :EE; LTP = SNN.NoLTP(), STP = SNN.NoSTP())   # weights frozen
source
SNNModels.compose — Method
compose(args...; name = randstring(10), silent = false, time = nothing, kwargs...)

Assemble populations, connections and stimuli (or whole models) into one network model.

Returns the NamedTuple (pop = ..., syn = ..., stim = ..., name = name, time = time), where pop, syn and stim are NamedTuples of components. This is the object accepted by sim!, train!, monitor!, save_model, etc.

Arguments

  • args...: models or containers (NamedTuple/Dict) to merge. Their components keep their own keys. String and Time positional arguments are ignored.
  • kwargs...: components or containers given by key. A component passed as E = pop is stored under :E. A container passed as exc = (E = ..., EE = ...) is flattened with the key as prefix (:exc_E, :exc_EE). Inside containers, the keys :pop, :syn, :stim are descended into without prefixing and the key :name is skipped.
  • name: model name (default: random 10-character string).
  • silent = false: if false, print the model summary with print_model.
  • time = nothing: the clock of the new model; by default a new Time{FT}() with FT the promotion of the float_types of the populations. The clocks of merged models are not reused: pass time = model.time to keep one.

Components are classified by type (AbstractPopulation, AbstractConnection, AbstractStimulus or AbstractStimulusGroup); a duplicated key is an AssertionError (to replace a synapse of an existing model use change_plasticity). pop and syn are sorted by key, stim by the stimuli name.

Example

using SpikingNeuralNetworks
@load_units
E = SNN.IF(N = 10, name = "E")
I = SNN.IF(N = 5, name = "I")
EI = SNN.SpikingSynapse(E, I, :ge, conn = (μ = 1.0, p = 0.2))
model = SNN.compose(; E, I, EI, name = "toy", silent = true)
model2 = SNN.compose(model, extra = (A = SNN.IF(N = 3, name = "A"),), silent = true)
keys(model2.pop)   # (:E, :I, :extra_A)
sim!(model, 100ms)
source
SNNModels.exp256 — Method
exp256(x::AbstractFloat)

Fast approximation of exp(x) as $(1 + x/256)^{256}$, computed with eight squarings. Inputs below -10 are replaced by -256, so that the result is exactly 0.

Returns

  • approximation of exp(x) in the type of x (Float32 or Float64).
source
SNNModels.exp32 — Method
exp32(x::R) where {R<:Real}

Fast approximation of exp(x) as $(1 + x/32)^{32}$, computed with five squarings. Inputs below -10 are clamped to -10.

Returns

  • Float32 approximation of exp(x); accurate only for small |x|.
source
SNNModels.exp64 — Method
exp64(x::AbstractFloat)

Fast approximation of exp(x) as $(1 + x/64)^{64}$, computed with six squarings. Inputs below -10 are replaced by -64, so that the result is exactly 0.

Returns

  • approximation of exp(x) in the type of x (Float32 for an integer argument); accurate only for small |x|.

Example

using SpikingNeuralNetworks
SNNModels.exp64(-1.0f0)   # 0.3650, exp(-1) = 0.3679
source
SNNModels.extract_items — Method
extract_items(root::Symbol, container; pop::Dict{Symbol,Any}, syn::Dict{Symbol,Any}, stim::Dict{Symbol,Any}, time::Time)

Recursively collect the components found in container into pop, syn and stim (helper of compose). Keys of nested containers are prefixed with root (root_key) unless root is empty or one of :pop, :syn, :stim; :name entries and Time values are skipped.

Arguments

  • root::Symbol: The root symbol for the items being extracted.
  • container: The container from which to extract items.
  • pop::Dict{Symbol,Any}: The dictionary to store population items.
  • syn::Dict{Symbol, Any}: The dictionary to store synapse items.
  • stim::Dict{Symbol,Any}: The dictionary to store stimulus items.

Returns

  • true: Always returns true.

Details

  • If the type of the item in the container is AbstractPopulation, it is added to the pop dictionary.
  • If the type of the item in the container is AbstractConnection, it is added to the syn dictionary.
  • If the type of the item in the container is AbstractStimulus, it is added to the stim dictionary.
  • If the type of the item in the container is none of the above, the function is recursively called to extract items from the nested container.
source
SNNModels.f2l — Function
f2l(s, l=10)

Format string to fixed length by padding or truncating.

Arguments

  • s: Input value to convert to string
  • l: Target length (default: 10)

Returns

  • String of exactly length l, padded with spaces or truncated
source
SNNModels.name — Function
name(pre, post, k=nothing)

Generate a Symbol name for connections between populations.

Arguments

  • pre: Pre-synaptic population name
  • post: Post-synaptic population name
  • k: Optional suffix for the name

Returns

  • Symbol in format :pre_to_post or :pre_to_post_k if k is provided
source
SNNModels.print_model — Function
print_model(model, get_keys = false)

Log (with @info) a summary of a model built by compose: name, current time (s), and one line per population (name, type, N, parameter type), per synapse (name, pre/post populations, long-term plasticity type, metaplasticity, short-term plasticity type; AbstractMetaPlasticity connections are skipped in the list) and per stimulus (name, target, type). The connectivity is taken from graph(model). get_keys is accepted but does not change the output.

Arguments

  • model: The model containing populations, synapses, and stimuli to be printed.

Exception

Raises an assertion error if any component in the populations is not a subtype of AbstractPopulation, if any component in the synapses is not a subtype of AbstractConnection, or if any component in the stimuli is not a subtype of AbstractStimulus.

source
SNNModels.rand_value — Method
rand_value(N, p1, p2)

Generate N random values (Float64) uniformly distributed between p1 and p2.

Arguments

  • N: Number of random values to generate
  • p1: First boundary value
  • p2: Second boundary value

Returns

  • Vector of N random values between min(p1,p2) and max(p1,p2)
source
SNNModels.remove_element — Method
remove_element(model, key)

Remove an element (population, synapse, or stimulus) from a model by its key.

Arguments

  • model: The network model
  • key: Symbol key of the element to remove

Returns

  • New model with the element removed

Throws

  • Nothing: if key is not found, an @info message is logged and the model is returned unchanged.

The new model is built with compose(; model..., silent = true), so it keeps the name and time of model. remove_element(model, keys::Vector) removes several elements.

source
SNNModels.sorted_ntuple — Method
sorted_ntuple(d::AbstractDict; by = identity)

NamedTuple with the entries of d ordered by sort(keys; by); String keys become Symbols. Replaces DrWatson.dict2ntuple(sort(d; by)): OrderedCollections 2 removed sort(::Dict).

source
SNNModels.str_name — Function
str_name(pre, post, k=nothing)

Generate a String name for connections between populations.

Arguments

  • pre: Pre-synaptic population name (String or Symbol)
  • post: Post-synaptic population name
  • k: Optional suffix for the name

Returns

  • String in format "pretopost" or "pretopost_k" if k is provided
source
SNNModels.str_name — Function
str_name(pre::String, k=nothing)

Generate a String name with optional suffix.

Arguments

  • pre::String: Base name
  • k: Optional suffix

Returns

  • String in format "pre" or "pre_k" if k is provided
source
SNNModels.sim! — Method
sim!(P::Vector{<:AbstractPopulation}, C::Vector{<:AbstractConnection} = [EmptySynapse()],
     S::Vector{<:AbstractStimulus} = [EmptyStimulus()];
     dt = 0.125f0, duration = 10.0f0, pbar = false, time = Time(), perturbation! = nothing)
sim!(; model, duration = 10ms, dt = 0.125ms, pbar = false, perturbation! = nothing)
sim!(model::NamedTuple, duration = 1s; kwargs...)
sim!(args...; model, kwargs...)

Simulate a network without plasticity for duration (ms) with time step dt (ms).

Each step runs:

  1. update_time! (the clock advances by dt first);
  2. for every stimulus: stimulate!(s, s.param, T, dt), record!;
  3. for every population: integrate!(p, p.param, dt), record!;
  4. for every connection: forward!(c, c.param, dt, T), record!.

The spike list of a population (spike_index) is built once per step and shared by its connections and recorder. A step that throws is a fatal error: discard the run.

No plasticity is applied: sim! never calls update_traces! or plasticity!, so weights and short-term plasticity variables stay constant even if a synapse carries an LTPParam or STPParam. Use train! for plastic networks.

Arguments

  • model: a NamedTuple built with compose; its populations, connections and stimuli (stimulus groups are unpacked) are simulated and model.time is advanced.
  • args...: extra components (or vectors of them) added to those of model.
  • dt = 0.125 ms: time step (converted to the float type of time; each component gets it in its own precision).
  • duration = 10 ms (vector and keyword forms) or 1s (positional model form): the loop runs over 0:dt:(duration - dt).
  • time = Time(): clock of the vector form.
  • perturbation!: optional function called before every step as perturbation!(; P, C, S, t, dt, start_time).
  • pbar = false: show a progress bar with the running firing rates of the populations that record :fire.
  • neurons_per_thread = nothing: chunk size of the threaded updates for this run (nothing keeps the current setting; 0 or Inf turns threading off). See neurons_per_thread.
  • flush_subnormals = true: run with subnormal results flushed to zero (on all threads, restored afterwards), which avoids slow subnormal arithmetic in decaying variables; false keeps IEEE gradual underflow. See SNNModels.with_flush_subnormals.

Recording buffers are sized before the loop (see monitor!). If the model time is 0, a first sample of every record is taken before the first step. Simulations can be continued by calling sim! again: time and recordings continue from where they stopped.

Returns

The Time object (vector form) or the model time in ms after the run (model forms).

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 100)
stim = SNN.Stimulus(SNN.PoissonFixed(rate = 2kHz), E, :ge)
model = SNN.compose(; E, stim)
SNN.monitor!(E, :fire)
SNN.sim!(; model, duration = 1s)
SNN.sim!(model, 500ms)          # continue for 500 ms
SNN.get_time(model.time)        # 1500.0
source
SNNModels.train! — Method
train!(P::Vector{<:AbstractPopulation}, C::Vector{<:AbstractConnection} = [EmptySynapse()],
       S::Vector{<:AbstractStimulus} = [EmptyStimulus()];
       dt = 0.125ms, duration = 10ms, time = Time(), perturbation! = nothing, pbar = false)
train!(; model, duration = 10ms, dt = 0.125ms, pbar = false, perturbation! = nothing)
train!(model::NamedTuple, duration = 1s; kwargs...)
train!(args...; model, kwargs...)

Simulate a network with plasticity for duration (ms) with time step dt (ms).

train! is the only entry point that applies plasticity. Each step runs:

  1. update_time! (the clock advances by dt first);
  2. for every stimulus: stimulate!, record!;
  3. for every population: update_traces!, integrate!, plasticity!, record!;
  4. for every connection: update_traces!, forward!, plasticity!, record!.

The spike list of a population (spike_index) is built once per step and shared by its connections and recorder. A step that throws is a fatal error: discard the run.

sim! runs the same sequence without update_traces! and plasticity!, so weights and STP variables only change under train! (long-term STDP/iSTDP/vSTDP rules, short-term plasticity, metaplasticity components).

Arguments

  • model: a NamedTuple built with compose; its populations, connections and stimuli (stimulus groups are unpacked) are simulated and model.time is advanced.
  • args...: extra components (or vectors of them) added to those of model.
  • dt = 0.125ms: time step (converted to the float type of time; each component gets it in its own precision).
  • duration = 10ms (vector and keyword forms) or 1s (positional model form): simulated time; the loop runs over 0:dt:(duration - dt), i.e. round(duration / dt) steps.
  • time = Time(): clock of the vector form.
  • perturbation!: optional function called before every step as perturbation!(; P, C, S, t, dt, start_time).
  • pbar = false: show a progress bar with the running firing rates of the populations that record :fire.
  • neurons_per_thread = nothing: chunk size of the threaded updates for this run (nothing keeps the current setting; 0 or Inf turns threading off). See neurons_per_thread.
  • flush_subnormals = true: run with subnormal results flushed to zero (on all threads, restored afterwards), which avoids slow subnormal arithmetic in decaying variables; false keeps IEEE gradual underflow. See SNNModels.with_flush_subnormals.

Recording buffers are sized before the loop from duration (see monitor!). If the model time is 0, a first sample of every record is taken before the first step.

Returns

The Time object (vector form) or the model time in ms after the run (model forms).

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 100)
stim = SNN.Stimulus(SNN.PoissonFixed(rate = 2kHz), E, :ge)
EE = SNN.SpikingSynapse(E, E, :ge; conn = (p = 0.1, μ = 0.5), LTPParam = SNN.STDPGerstner())
model = SNN.compose(; E, EE, stim)
SNN.train!(; model, duration = 100ms)
SNN.get_time(model.time)   # 100.0
source
SNNModels.graph — Method
graph(model)

Build a MetaGraphs.MetaDiGraph describing the connectivity of a model created by compose.

Vertices

One per population and one per stimulus, with properties :name (component name), :id (component id) and :key (key in model.pop or model.stim).

Edges

One edge per ordered pair of vertices; several connections between the same pair are stored as vectors in the same edge. Edge properties (vectors with one entry per connection): :type (syn.targets[:type], :fire_to_g for stimuli), :name (connection name), :pop ("pre -> post.sym"), :key, :id, :meta (key of the metaplasticity operator acting on the connection, or :none), :target (targets[:sym]) and :count; :multi is the number of connections on the edge.

  • Connections are added from syn.targets[:fire] (presynaptic id) to syn.targets[:post].
  • Stimuli are drawn as an edge from the stimulus vertex to stim.targets[:post].
  • AbstractMetaPlasticity connections (normalization, scaling, turnover) add no edge; their key is written in the :meta property of the edges of the synapses listed in targets[:synapses].

Errors

Throws ArgumentError for a connection whose targets has no :type entry, and an error if a target population id is not in the model.

Example

using SpikingNeuralNetworks
@load_units
E = SNN.IF(N = 10, name = "E")
EE = SNN.SpikingSynapse(E, E, :ge, conn = (μ = 1.0, p = 0.2))
g = SNN.graph(SNN.compose(; E, EE, silent = true))   # 1 vertex, 1 self-loop edge
source
SNNModels.modelcopy — Method
modelcopy(x)

Deep copy of a model (or of any object), adapted from Base.deepcopy, that does not copy recorded data.

The object graph is copied recursively as with deepcopy (shared references stay shared in the copy). The difference is in Dicts that hold a :data key, i.e. the records dictionaries filled by monitor!:

  • the variables listed in records[:data] are replaced by empty buffers (:fire by an empty spike-record dictionary with :time, :neurons, :times_buf, :neurons_buf; every other variable by an empty Vector{Float32}), so monitors stay configured but hold no data;
  • :start_time and :end_time are replaced by empty dictionaries;
  • :perturbation is replaced by an empty dictionary.

All other fields (state variables, weights, parameters, the Time clock) are copied. Used by perturbation_test to branch a model.

Specialised behaviour for a type T can be added by defining SNNModels.modelcopy_internal(x::T, dict::IdDict).

Example

using SpikingNeuralNetworks
@load_units
E = SNN.IF(N = 10, name = "E")
model = SNN.compose(; E, silent = true)
SNN.monitor!(E, [:v])
sim!(model, 10ms)
model2 = SNN.modelcopy(model)
isempty(model2.pop.E.records[:v])   # true: the copy has no recorded data
source

Units and macros

SNNModels.@load_units — Macro
@load_units

Define the SNNModels unit constants as local variables in the calling scope.

SNNModels represents physical quantities as plain Float32 numbers in a fixed unit system; the constants convert a number to that system (e.g. 10ms == 10f0, 1s == 1000f0, 10Hz == 0.01f0). The base units are

QuantityBase unitValue 1 equals
lengthcm1 cm (metre = 100, um = 1e-4)
timems1 ms (s = second = 1000)
frequencykHz1 kHz (Hz = 1e-3)
voltagemV1 mV
currentpA1 pA
capacitancepF1 pF
conductancenS1 nS
resistanceGΩ1 GΩ (MΩ = 1e-3)
concentrationuM1 μM (M = 1e6, mM = 1e3)

Constants defined by the macro: metre, meter, cm, mm, um, nm, cm2, m2, um2, nm2, second, s, ms, Hz, kHz, voltage, mV, ampere, mA, uA, μA, nA, pA, farad, uF, μF, nF, pF, ufarad, siemens, mS, msiemens, nS, nsiemens, Ω, MΩ, GΩ, M, mM, uM, nM. (mF exists in the module but is not defined by the macro.)

The default integration step of sim!/train! is 0.125ms.

Example

using SpikingNeuralNetworks
@load_units
duration = 2s      # 2000.0f0
rate = 10Hz        # 0.01f0 (per ms)
source
SNNModels.pretty_nt_print — Function
pretty_nt_print(value, indent = 0)

Print a (nested) NamedTuple as an indented tree field := value, one field per line. Non-NamedTuple values are printed with println.

source
SNNModels.snn_kw_finalize — Method
snn_kw_finalize(T, fields::NamedTuple) -> NamedTuple

Hook called by the keyword constructor of @snn_kw with the struct type T (with its type parameters, e.g. HH{Vector{Float64},Vector{Bool}}) and the field values (in field order, before conversion) before the struct is built. The default returns fields. Specialise it to derive or validate interdependent fields (e.g. the membrane pair, see resolve_membrane, and the precision checks of the populations); keep the same keys in the same order.

source
SNNModels.snn_kw_get_concrete_types — Method
snn_kw_get_concrete_types(x)

Infer concrete types for type parameters from field definitions.

Arguments

  • x: Vector of parsed field information

Returns

  • Dictionary mapping type parameters to inferred concrete types
source
SNNModels.snn_kw_str_field — Method
snn_kw_str_field(x)

Parse struct field expressions for the @snn_kw macro.

Arguments

  • x::Symbol: Simple field name
  • x::Expr: Field expression with type annotation or default value

Returns

  • Tuple containing parsed field information
source
SNNModels.snn_kw_str_kws — Method
snn_kw_str_kws(x::Tuple)

Convert parsed field tuple to keyword argument expression.

Arguments

  • x::Tuple: Parsed field information (name, type, default)

Returns

  • Expression for keyword argument in constructor
source
SNNModels.snn_kw_str_kws_types — Method
snn_kw_str_kws_types(x::Tuple)

Convert parsed parameter tuple to typed keyword argument expression.

Arguments

  • x::Tuple: Parsed parameter information

Returns

  • Expression for typed keyword argument
source
SNNModels.snn_kw_str_param — Method
snn_kw_str_param(x)

Parse struct type parameter expressions for the @snn_kw macro.

Arguments

  • x::Symbol: Simple type parameter
  • x::Expr: Type parameter expression with constraints or defaults

Returns

  • Tuple containing parsed parameter information
source
SNNModels.snn_kw_str_sentinel_check — Method
snn_kw_str_sentinel_check(x)

Generate code to check if type parameter was assigned or use default.

Arguments

  • x: Parsed parameter information

Returns

  • Expression checking for sentinel value
source
SNNModels.snn_kw_str_sentinel_check_concrete — Method
snn_kw_str_sentinel_check_concrete(x; dict)

Generate code to infer concrete type from field types if not explicitly provided.

Arguments

  • x: Parsed parameter information
  • dict: Dictionary mapping type parameters to inferred concrete types

Returns

  • Expression checking for sentinel and inferring concrete type
source
SNNModels.snn_kw_str_sentinels — Method
snn_kw_str_sentinels(x)

Add sentinel default values to type parameters for tracking assignment.

Arguments

  • x: Parsed parameter tuple

Returns

  • Tuple with sentinel default value added
source
SNNModels.update_with_merge — Function
update_with_merge(base_config::NamedTuple, path::Vector{Symbol}, value, full_path = nothing)
update_with_merge(base_config, path::Vector{Symbol}, value, full_path = nothing)

Return a copy of base_config with the nested field at path set to value (the function behind @update and @update!).

A missing final key is added with a warning; a missing intermediate key is created as an empty NamedTuple with a warning. If an element on the path is a struct with fields, it is converted to a NamedTuple, updated, and rebuilt with its keyword constructor T(; fields...). Any other type throws a TypeError.

Arguments

  • base_config::NamedTuple: The configuration to update
  • path::Vector{Symbol}: Field path to update (e.g., [:a, :b, :c] for a.b.c)
  • value: New value to assign
  • full_path: Full path for error messages (internal use)

Returns

  • Updated NamedTuple with the field modified
source
SNNModels.@snn_kw — Macro
@snn_kw struct Name{T1 = Default1, T2 <: Bound, ...} <: Super
    field::T1 = default
    ...
end

Variant of Base.@kwdef that also accepts default values for the type parameters.

The macro defines the struct (with the defaults stripped) and one keyword constructor Name(; field1 = default1, ..., T1 = Default1, T2 = ...). Field defaults may refer to earlier fields and to the type parameters (which are the first keyword arguments, and may refer to earlier type parameters). Type parameters are keyword arguments of the constructor:

  • a type parameter with a default (FT = Float32) takes that default unless passed explicitly;
  • a type parameter without a default is inferred as typeof(field) of the first field with a default value that is annotated with that parameter (internally tracked by the sentinel SNNModels.KwStrSentinel); every such parameter must be used by at least one field.

All population, synapse, stimulus and parameter types of SNNModels are defined with this macro.

The macro can be used in any module: nothing besides @snn_kw needs to be imported.

Example

using SpikingNeuralNetworks
using SNNModels: @snn_kw
@snn_kw struct MyStruct{FT = Float32}
    x::FT = 1.0
    y::FT = 2.0
end
MyStruct()              # MyStruct{Float32}(1.0f0, 2.0f0)
MyStruct(FT = Float64)  # MyStruct{Float64}(1.0, 2.0)
MyStruct(x = 3.0)       # MyStruct{Float32}(3.0f0, 2.0f0)
source
SNNModels.@symdict — Macro
@symdict(x...)

Create a Dict{Symbol,Any} from variable names.

Arguments

  • x...: Variable names to include in the dictionary

Returns

  • Dictionary mapping variable names (as symbols) to their values

Example

using SpikingNeuralNetworks
a = 1
b = 2
d = SNNModels.@symdict(a, b)  # Dict{Symbol,Any}(:a => 1, :b => 2)
source
SNNModels.@update! — Macro
@update! base begin
    path.to.field = value
    ...
end

In-place counterpart of @update: computes the updated configuration and rebinds the variable base to it (base = update_with_merge(...)). The single-assignment form @update! base a.b = v also works (up to SNNModels 1.8.4 it did not escape base and failed with an UndefVarError).

Example

using SpikingNeuralNetworks
config = (a = 1, b = (c = 2, d = 3))
@update! config begin
    b.c = 7
end
config.b.c  # 7
source
SNNModels.@update — Macro
@update base begin
    path.to.field = value
    ...
end

Return a copy of the nested configuration base (a NamedTuple, possibly containing structs) with the listed fields replaced. base itself is not modified. Each assignment is applied with update_with_merge; missing intermediate keys are created (with a warning), structs on the path are rebuilt through their keyword constructor.

The single-assignment form @update base a.b = v is equivalent to a block with one line. (Up to SNNModels 1.8.4 it threw UndefVarError: current_config at macro expansion.)

Example

using SpikingNeuralNetworks
config = (a = 1, b = (c = 2, d = 3))
new_config = @update config begin
    b.c = 5
    b.d = 6
end
# new_config == (a = 1, b = (c = 5, d = 6)); config is unchanged
source

Saving and loading

SNNModels.SNNfile — Function
SNNfile(type, count::Int, suffix = "")

File name used by SNNsave/SNNload: "$(type)-$(count)-$(suffix).jld2" for count > 0, "$(type)-$(suffix).jld2" for count == 0 (e.g. "model-.jld2", "data-2-trial.jld2").

source
SNNModels.SNNfolder — Method
SNNfolder(path, name, info)

Folder in which SNNsave stores a model: joinpath(path, savename(name, info, connector = "-")) (DrWatson savename, so the folder name encodes the info parameters).

Arguments

  • path: Base directory path
  • name: Model name
  • info: NamedTuple with model metadata

Returns

  • String path to the model folder
source
SNNModels.SNNload — Method
SNNload(; path, name = "", info = nothing, count = 0, suffix = "", type = :model)
SNNload(path, name = "", info = nothing)

Load a file written by SNNsave.

If path is a file, it is loaded directly. Otherwise the file joinpath(SNNfolder(path, name, info), SNNfile(type, count, suffix)) is loaded.

Arguments

  • path::String: file, or base directory used in SNNsave.
  • name::String, info: model name and metadata NamedTuple (required if path is not a file).
  • count::Int = 0: file counter.
  • suffix = "": file suffix.
  • type::Symbol = :model: :model (records cleared) or :data (with records).

Returns

  • The stored dictionary as a NamedTuple ((model = ..., config = ..., extra keys...)), or nothing (with an @error message) if the file does not exist.

Throws

  • ArgumentError if path is not a file and name or info is missing.

Example

using SpikingNeuralNetworks
@load_units
E = SNN.IF(N = 10, name = "E")
model = SNN.compose(; E, silent = true)
dir = mktempdir()
SNN.save_model(; model, path = dir, name = "toy", info = (seed = 1,))
loaded = SNN.load_model(dir, "toy", (seed = 1,))
loaded.model.pop.E.N   # 10
source
SNNModels.SNNpath — Method
SNNpath(path, name, info, type, count)

Full path joinpath(SNNfolder(path, name, info), SNNfile(type, count)) of a stored file (empty suffix).

Arguments

  • path: Base directory path
  • name: Model name
  • info: NamedTuple with model metadata
  • type: Type of file (:model, :data, etc.)
  • count: File counter

Returns

  • Complete file path string
source
SNNModels.SNNsave — Method
SNNsave(model; path, name, info, suffix = "", config = nothing, type = :all, count = 0, kwargs...)

Save a model to SNNfolder(path, name, info) with JLD2 (through DrWatson.save).

Arguments

  • model: the model to save.
  • path, name, info: base directory, model name and metadata NamedTuple; the folder name is savename(name, info, connector = "-").
  • suffix = "", count = 0: file suffix and counter, see SNNfile.
  • config = nothing: configuration stored with the model and written in config.jl.
  • type = :all: :all writes the :data file (model with records) and the :model file (a deepcopy with clear_records! applied); :model writes only the :model file. Any other value logs an error and saves nothing.
  • kwargs...: additional entries stored in the same file.

When count < 2, the folder also receives a human-readable config.jl written by write_config, with a timestamp and the git commit hash ("unknown" outside a git repository).

Returns

  • The path of the :model file.
source
SNNModels.check_loaded_model — Method
check_loaded_model(x; what = "file")

Throw an ArgumentError if x (a loaded model, params or NamedTuple/Dict of them) contains a JLD2.ReconstructedMutable or JLD2.ReconstructedStatic placeholder, searching recursively through tuples, dictionaries, arrays of non-bits elements and struct fields. JLD2 builds such placeholders when the file holds a type whose layout no longer exists, e.g. a model saved with SNNModels <= 1.9.1; such a model loads without error and then fails later with an unrelated message. No migration is attempted. Returns x.

source
SNNModels.data2model — Method
data2model(; path, name=randstring(10), info=nothing, count = 0, suffix = "", kwargs...)

Create the :model file (records cleared) from an existing :data file, using the layout of SNNsave: SNNfolder(path, name, info)/SNNfile(:data, count, suffix) and .../SNNfile(:model, count, suffix). (Up to SNNModels 1.8.4 it checked joinpath(path, savename(name, info, "data.jld2")), which SNNsave never writes.)

Arguments

  • path: Directory path
  • name: Model name (default: random string)
  • info: Model metadata

Returns

  • true if model file exists or was created, false if data file doesn't exist
source
SNNModels.get_git_commit_hash — Method
get_git_commit_hash()

Get current git commit hash of the repository containing the working directory.

Returns

  • String containing the full commit hash, or "unknown" when the working directory is not inside a git repository or git is not available (e.g. cluster jobs run from a copied directory). write_config records this string, so a missing repository no longer aborts the run.

Note

  • Uses git from PATH; honours GIT_DIR/GIT_WORK_TREE if set.
source
SNNModels.load_data — Method
load_data(path, name, info; kwargs...)

Load the :data file (model with its records) stored by SNNsave; same as SNNload(; path, name, info, kwargs..., type = :data).

Arguments

  • path::String: Directory path
  • name::String: Model name
  • info::NamedTuple: Model metadata
  • kwargs...: Additional arguments passed to SNNload

Returns

  • Loaded data as NamedTuple
source
SNNModels.load_model — Method
load_model(path, name, info; kwargs...)

Load the :model file (records cleared) stored by SNNsave; same as SNNload(; path, name, info, kwargs..., type = :model). Returns nothing if the file is missing.

Arguments

  • path::String: Directory path
  • name::String: Model name
  • info::NamedTuple: Model metadata
  • kwargs...: Additional arguments passed to SNNload

Returns

  • Loaded model as NamedTuple
source
SNNModels.load_or_run — Method
load_or_run(f; path, name, info, exp_config...)

Return load_model(path, name, info) if that file exists; otherwise call f(info), save the result with save_model and return it.

The model is saved in the folder that load_model(path, name, info) reads, so a second call loads it. (Up to SNNModels 1.8.4 name was replaced by savename(name, info) before saving, so the model was written to another folder and never found.)

Arguments

  • f::Function: Function to run if model doesn't exist (receives info as argument)
  • path: Directory path
  • name: Model name
  • info: Model metadata
  • exp_config...: Configuration passed to save_model if running

Returns

  • Loaded or newly generated model
source
SNNModels.read_folder — Function
read_folder(path, files=nothing; my_filter = <SNNfile names of `type`>, type=:model, name=nothing)

List the files of the directory path for which my_filter(file, type) is true (logging each match) and append their full paths to files.

Arguments

  • path: Directory path to read from
  • files: Optional vector to append results to (default: creates new vector)
  • my_filter: Filter function (file, type) -> Bool; the default matches the files written by SNNsave (SNNfile names "$(type)-....jld2", e.g. model-.jld2, data-2-trial.jld2) and the older "...$(type).jld2" names. (Up to SNNModels 1.8.4 the default matched only names ending in "$(type).jld2", so it missed the files of SNNsave.)
  • type: File type to match (default: :model)
  • name: accepted and ignored.

Returns

  • Vector of file paths matching the filter
source
SNNModels.read_folder! — Method
read_folder!(df, path; type=:model, name=nothing)

Same as read_folder(path, df; type, name): append the matching file paths to df.

Arguments

  • df: Vector to append results to
  • path: Directory path to read from
  • type: File type to match (default: :model)
  • name: Optional name filter

Returns

  • The modified df vector
source
SNNModels.save_config — Method
save_config(; path, name=randstring(10), config, info=nothing)

Save config as joinpath(path, savename(name, info, "config.jld2", connector = "-")) (JLD2, key "config"), creating path if needed.

Arguments

  • path: Directory path
  • name: Config name (default: random string)
  • config: Configuration data to save
  • info: Optional metadata

Returns

  • Nothing
source
SNNModels.save_model — Method
save_model(; model, path, name, info, config = nothing, kwargs...)

Save both the :data and the :model file, i.e. SNNsave(model; path, name, info, config, type = :all, kwargs...). See SNNsave for the file layout and load_model/load_data.

Arguments

  • model: The model to save
  • path: Directory path
  • name: Model name
  • info: Model metadata
  • config: Optional configuration
  • kwargs...: Additional data to save

Returns

  • Path to the saved files
source
SNNModels.write_config — Method
write_config(path, info; config, name="", kwargs...)

Write info (and config if not nothing) as Julia source to a text file, preceded by the generation timestamp and the git commit hash (get_git_commit_hash, "unknown" outside a git repository).

Arguments

  • path::String: file path; if name is given, the file is joinpath(path, savename(name, info, "config", connector = "-")) instead.
  • info: NamedTuple written as info = (...).
  • config: NamedTuple written as config = (...), or nothing.
  • kwargs...: accepted and ignored.

Returns

  • The path of the written file.

Details

  • Entries named study or models are skipped. (Up to SNNModels 1.8.4 only models was skipped, because of operator precedence.)
source
SNNModels.write_value — Function
write_value(file, key, value, indent="", equal_sign="=")

Write key = value, to file as Julia source (helper of write_config).

Arguments

  • file: IO stream to write to
  • key: Key name (empty string for array elements)
  • value: Value to write (supports Number, String, Symbol, Tuple, Array, Dict, NamedTuple, etc.)
  • indent: Indentation string (default: "")
  • equal_sign: Assignment operator (default: "=")

Details

  • Recursively handles nested structures; other structs are written as TypeName(field = ..., ...).
  • Formats different types appropriately (quoted strings, symbols with :, ranges as a:s:b).
  • In a Dict, non-numeric values are written as quoted strings.
source

Spatial networks

SNNModels.compute_connections — Method
compute_connections(pre::Symbol, post::Symbol, points; conn::NamedTuple, spatial::NamedTuple, dist::Sampleable)

Draw a distance-dependent connectivity from the population pre to post on a 2D torus.

points is the output of place_populations; points.pre and points.post are used. Connection weights are drawn from the distribution dist. Periodic distances are computed with periodic_distance. spatial.grid_size must have length 2. Two rules are available, selected by spatial.type:

  • :critical_distance (fields dc, ϵ, grid_size, p_long): with $A = L_x L_y$, $p_l =$ spatial.p_long[pre], $\gamma_s = A / (\pi d_c^2)$, $\gamma_l = A / (A - \pi d_c^2)$, a pair closer than $d_c$ is connected with probability $p_{short} = (1 - p_l)\,\gamma_s\,\epsilon\,p$ and a farther pair with $p_{long} = p_l\,\gamma_l\,\epsilon\,p$, where $p$ = conn.p. Autapses are excluded when pre == post. The returned P is all zeros.
  • :gaussian (fields σs, grid_size, ϵ): $(\sigma_x, \sigma_y)$ = spatial.σs[pre]; the pair $(i, j)$ is connected with probability $P_{ij} = \gamma\,\epsilon\,p\,g_{ij}$, with $g_{ij}$ = gaussian_weight(pre_j, post_i) and $\gamma$ the inverse of the mean of the Gaussian profile over a 200x200 grid, so that the mean probability is $\epsilon p$. Pairs with i == j are excluded when pre == post (up to SNNModels 1.8.4 also when pre != post).

Any other spatial.type returns nothing.

Returns

  • L::BitMatrix (N_post x N_pre): connection mask.
  • W::Matrix{Float32}: weights (rand(dist) where L is true, 0 elsewhere).
  • P::Matrix{Float32}: connection probabilities (:gaussian only).

Example

using SpikingNeuralNetworks, Distributions
points = SNN.place_populations((E = 100,), [1.0f0, 1.0f0])
spatial = (type = :gaussian, σs = (E = (0.1f0, 0.1f0),), grid_size = [1.0f0, 1.0f0], ϵ = 1.0f0)
L, W, P = SNN.compute_connections(:E, :E, points; conn = (p = 0.1,), spatial, dist = Normal(1, 0.1))
source
SNNModels.gaussian_weight — Function
gaussian_weight(pre::Vector{Float32}, post::Vector{Float32} = [0, 0]; σx, σy, grid_size::Vector{Float32})

Gaussian profile $\exp(-(d_x/\sigma_x)^2 - (d_y/\sigma_y)^2)$ of the periodic distances $d_x, d_y$ between two 2D points (computed with exp64; note there is no factor 1/2 in the exponent).

Arguments

  • pre::Vector{Float32}: The coordinates of the pre-synaptic neuron.
  • post::Vector{Float32}: The coordinates of the post-synaptic neuron.
  • σx::Float32: The standard deviation of the Gaussian in the x-direction.
  • σy::Float32: The standard deviation of the Gaussian in the y-direction.
  • grid_size::Vector{Float32}: The size of the grid.

Returns

  • weight::Float32: The Gaussian weight between the pre- and post-synaptic neurons.
source
SNNModels.linear_network — Method
linear_network(N; σ_w = 0.38, w_max = 2.0, kwargs...)

Weight matrix of a ring network: N neurons at angles $\theta_i = 2\pi i / N$ with

\[W_{ij} = w_0 + (w_{max} - w_0)\,\exp\!\left(-\frac{d(\theta_i, \theta_j)^2}{2\sigma_w^2}\right), \qquad d = \min(|\theta_i - \theta_j|,\ 2\pi - |\theta_i - \theta_j|),\]

where the baseline $w_0 = w_{max}\,\sigma_w\,(\mathrm{erf}(\pi/(\sqrt{2}\sigma_w)) - \sqrt{2\pi}) / (\sigma_w\,\mathrm{erf}(\pi/(\sqrt{2}\sigma_w)) - \sqrt{2\pi})$ is computed by the function. The diagonal is set to zero. kwargs are ignored.

Reference not given in the code.

Returns

  • W::Matrix{Float64} (N x N).
source
SNNModels.neurons_outside_area — Method
neurons_outside_area(points, center, distance, grid_size)

Find the indices of neurons outside a specified area around a center point.

Arguments

  • points::Vector{Vector{Float32}}: The coordinates of the neurons.
  • center::Vector{Float32}: The coordinates of the center point.
  • distance: The minimum distance from the center point.
  • grid_size: The size of the grid (scalar or vector, see periodic_distance).

Returns

  • Vector{Int}: indices of the neurons with periodic_distance > distance.
source
SNNModels.neurons_within_circle — Method
neurons_within_circle(points, center, distance, grid_size)

Boolean mask of the neurons whose periodic_distance from center is <= distance.

Arguments

  • points::Vector{Vector{Float32}}: The coordinates of the neurons.
  • center::Vector{Float32}: The coordinates of the center point.
  • distance: The maximum distance from the center point.
  • grid_size: The size of the grid (scalar or vector, see periodic_distance).

Returns

  • Vector{Bool} with one entry per point (use findall to get indices).
source
SNNModels.periodic_distance — Method
periodic_distance(x1::Float32, x2::Float32, grid_size::Float32)
periodic_distance(point1::Vector{Float32}, point2::Vector{Float32}, grid_size::Real)
periodic_distance(point1::Vector{Float32}, point2::Vector{Float32}, grid_size::Vector)

Distance on a torus (periodic boundary conditions).

  • Scalars: $d = \min(|x_1 - x_2|,\ L - |x_1 - x_2|)$.
  • Points with a scalar grid_size $L$ (same size in every dimension): Euclidean periodic distance $\sqrt{\sum_n d_n^2}$.
  • Points with a vector grid_size $(L_1, L_2, \dots)$: Euclidean periodic distance $\sqrt{\sum_n d_n^2}$ with $d_n$ computed with $L_n$. (Up to SNNModels 1.8.4 this method computed $\sqrt{(\sum_n d_n)^2} = \sum_n d_n$, the L1 distance.)

Example

using SpikingNeuralNetworks
SNN.periodic_distance([0.05f0, 0.0f0], [0.95f0, 0.0f0], 1.0f0)   # 0.1
source
SNNModels.place_populations — Method
place_populations(Npop, grid_size)

Place the neurons of each population uniformly at random in a box of size grid_size.

Arguments

  • Npop: NamedTuple (or Dict) of population sizes; only entries of type Int64 are used, the others are skipped.
  • grid_size: vector with the box size in each dimension (any number of dimensions).

Returns

  • NamedTuple with, for each population, a Vector of N points, each point a Vector{Float32} with coordinates in [0, grid_size[d]).

Example

using SpikingNeuralNetworks
points = SNN.place_populations((E = 80, I = 20), [1.0f0, 1.0f0])
length(points.E)   # 80
source
SNNModels.spatial_activity — Method
spatial_activity(points, activity; T, L = nothing, N = nothing, grid_size = (x = [0, 0.1], y = [0, 0.1]))

Average activity over the cells of a regular 2D grid and over time windows.

Arguments

  • points: tuple (xs, ys) of the neuron coordinates.
  • activity::Matrix: N_neurons x N_timepoints.
  • T: time windows. A number T gives the windows (1+(t-1)T):(tT) for t = 1:(N_timepoints ÷ T); a vector gives the windows explicitly (each element a range of column indices). (Up to SNNModels 1.8.4 the last column of each window was excluded.)
  • L or N (exactly one must be given): cell side (number, or (x = Lx, y = Ly)), or number of cells per dimension (number, or (x = Nx, y = Ny)).
  • grid_size = (x = [x0, x1], y = [y0, y1]): extent of the grid.

Returns

  • spatial_avg::Array{Any,3}: nx x ny x n_windows, mean activity of the neurons in each cell and window (0 for empty cells).
  • x_range, y_range: ranges spanning grid_size.x and grid_size.y with max(nx, 2) and max(ny, 2) points.

Example

using SpikingNeuralNetworks
xs = [0.05, 0.15, 0.25, 0.35]
ys = [0.05, 0.15, 0.25, 0.35]
activity = rand(4, 100)          # 4 neurons, 100 time points
avg, xr, yr = SNN.spatial_activity((xs, ys), activity; T = 10, L = 0.1,
                                   grid_size = (x = [0, 0.4], y = [0, 0.4]))
size(avg)   # (4, 4, 10)
source

Perturbation analysis

SNNModels.PerturbationSpikeStore — Type
PerturbationSpikeStore(N)

Spike windows (variable :fire) of one condition of an object with N neurons. Fields:

  • version::Int: layout version (1).
  • N::Int: neurons.
  • times::Vector{Float32}, neuron::Vector{Int32}: all spikes of all windows, parallel arrays. Inside a window the spikes are sorted by neuron, then by time (the order of spiketimes(pert_obj) flattened neuron by neuron).
  • offsets::Vector{Int}: length(store) + 1 entries, offsets[1] = 1; window j is the spikes offsets[j] : offsets[j+1]-1 of times/neuron (an empty store has offsets == [1]).
  • tstart, tend, ids, next_id: as in PerturbationStore.
source
SNNModels.PerturbationStore — Type
PerturbationStore(N)

Dense perturbation windows of one (variable, condition) of an object with N rows (neurons or synapses). Built by perturbation_test(...; add_records = condition); fields:

  • version::Int: layout version (1); readers and writers throw an ArgumentError ("upgrade SNNModels") for any other number.
  • N::Int: rows.
  • data::Vector{Float32}: the windows concatenated along time, column-major. Viewed as an N x (sum of window lengths) matrix, window j is the column block offsets[j] : offsets[j+1]-1, i.e. data[(offsets[j]-1)*N+1 : (offsets[j+1]-1)*N]. Nothing divides by N, so objects with 0 rows work.
  • offsets::Vector{Int}: length(store) + 1 entries, offsets[1] = 1; window j is the columns offsets[j] : offsets[j+1]-1 (zero columns allowed; an empty store has offsets == [1]).
  • tstart::Vector{Float32}, tend::Vector{Float32}: absolute simulation interval (ms) of each window.
  • ids::Vector{Int}: window number n (the argument n of clear_perturbation_records!); increasing.
  • next_id::Int: the number the next window gets (then incremented). Window numbers are never reused, not even after every window was deleted; the store is mutable for this counter. compact_perturbation_records! sets it to maximum(legacy keys) + 1.

Windows may differ in length. Appending is amortised O(window size); deleting a window is O(store size) (its columns are removed from data and the later offsets shift down). The fields are plain arrays of bits types and integers: JLD2 stores them as they are.

source
SNNModels.clear_perturbation_monitor! — Method
clear_perturbation_monitor!(obj, variable)
clear_perturbation_monitor!(obj, variable, condition)
clear_perturbation_monitor!(obj, variable, condition; n)

Remove perturbation records for a specific variable (required), optionally filtered by condition and n.

This is the targeted complement to clear_perturbation_records!:

CallEffect
clear_perturbation_monitor!(obj, :v_s)remove all conditions for :v_s
clear_perturbation_monitor!(obj, :v_s, "silence")remove all n under "silence" for :v_s
clear_perturbation_monitor!(obj, :v_s, "silence"; n=2)remove only the window with id 2 (ids are never reused)
source
SNNModels.clear_perturbation_records! — Method
clear_perturbation_records!(obj)
clear_perturbation_records!(obj, condition)
clear_perturbation_records!(obj, condition; variable, n)

Delete stored perturbation data from obj.

  • No condition: removes all perturbation data (all variables, all conditions); n is ignored.
  • With condition: removes all entries for that condition across all variables.
  • With variable kwarg: restricts deletion to that variable only.
  • With both condition and n kwarg: removes only the window numbered n for that condition (and variable if specified): its columns (dense) or spikes (:fire) are removed from the store and the later windows keep their numbers. Window numbers are the ids of the store (1, 2, ... in order of recording); they are never reused, also after the last window was deleted (the empty store stays and keeps counting). Deleting a window of a condition still in the pre-1.9.2 layout throws an ArgumentError (convert with compact_perturbation_records! first); deleting whole conditions, variables or everything works on any layout.

Accepts a single AbstractComponent, a NamedTuple of components (e.g. model.pop), or a full model NamedTuple.

source
SNNModels.compact_perturbation_records! — Method
compact_perturbation_records!(model_or_obj) -> Dict{Symbol,NamedTuple{(:windows,:bytes)}}

The one-time migration of files written before SNNModels 1.9.2 / 2.0.2. Convert, in place, perturbation records written in the legacy layout (one Dict("interval", "data") per window, records[:perturbation][variable][condition][n]) into PerturbationStore / PerturbationSpikeStore. The legacy keys n (which may have gaps) become the window ids, next_id becomes maximum(n) + 1; the insertion order is the order of increasing n. Until a file is converted, every reader, flush and single-window deletion on its legacy records throws an ArgumentError naming the object, variable and condition (legacy and compact records never coexist in a working model); clearing a whole condition, variable or all records still works on legacy records. Save the model again after converting.

Accepts a single component, a NamedTuple of components, a model (pop, syn, stim) or the NamedTuple returned by load_data (its model). The conversion goes one object and one variable at a time: the new stores of a variable are built, checked, replace the dictionaries, and GC.gc() runs before the next variable, so two full copies of a variable are never held.

Safety: before the dictionaries of a (variable, condition) are dropped, the new store is compared with them bit by bit (interval, data, spike times, numbers n); on any difference an error is thrown and the legacy data of that condition stays as it was. A condition that cannot be stored (windows that are not Float32 matrices with the same number of rows, or spike windows with different neuron counts) throws an ArgumentError naming the object, variable, condition and n, without touching it. Conditions already compact are skipped, so running it twice is a no-op.

Returns, per variable, the number of windows converted and the legacy size in bytes (Base.summarysize), summed over the objects; empty when nothing needed conversion.

Run this once on each file written by an older version: it shrinks the file (save again afterwards) and cuts load time and memory. Files with compact records need SNNModels >= 1.9.2 / >= 2.0.2 in every process that reads them.

source
SNNModels.perturbation_record — Method
perturbation_record(obj, variable, condition, interval) -> (data, interval)

Reconstruct a variable trace over interval by splicing stored perturbation windows into the baseline recording.

The baseline is retrieved from obj's normal records, aligned to interval via interpolation. Each stored entry for condition is then overlaid at its recorded [tstart, tend] window (in insertion order n, not sorted by time: overlapping windows overwrite earlier ones). The result is a continuous trace where perturbed segments replace the baseline.

Arguments

  • obj: any AbstractPopulation, AbstractStimulus, or AbstractConnection with a :perturbation record populated by perturbation_test.
  • variable: Symbol of a monitored field (e.g. :v_s, :fire, :ge).
  • condition: the add_records name string used in perturbation_test.
  • interval: AbstractRange in ms, e.g. 0:1ms:2s.

Returns

  • Continuous variables: (Matrix{Float32} of shape (N_neurons, T), interval). T = length(clipped interval) where the interval is clipped to the recorded baseline range.
  • :fire: (Spiketimes, interval) — baseline spikes in each perturbation window removed and replaced by the recorded perturbed spike times.

Returns unmodified baseline when no perturbation data exists for the condition.

Interval alignment detail

interpolated_record(obj, variable) produces a ScaledInterpolation over the full baseline [start_time, end_time]. Evaluating it on eval_r (the requested interval clipped to the recorded range) yields an exactly time-aligned (N, T) Float32 matrix regardless of the original sampling rate. Each perturbation entry's [tstart, tend] is then mapped to column indices in this grid via searchsortedfirst/searchsortedlast on eval_r.

source
SNNModels.perturbation_test — Method
perturbation_test(model, simtime; trigger! = (m -> nothing), perturbation! = nothing,
                  from_state = nothing, add_records = nothing, train = true, kwargs...)

Run a perturbed copy of model for simtime ms and return it, or archive its recordings in model.

The copy is created with modelcopy (deep copy with empty record buffers), trigger! is applied to it once, then the copy is simulated with train! or sim!. The original model is modified only when add_records is given (its records[:perturbation] entries are filled).

Arguments

  • model: source model.
  • simtime: duration in ms, e.g. 500ms.

Keyword arguments

  • trigger! (no-op): (pert_model) -> nothing, applied once to the copy before the run, e.g.
    m -> SNN.set_active!(m.stim.noise, false)   # silence a stimulus
    m -> (m.pop.pv.I .= 200pA)                  # inject current
    m -> SNN.set_LTP!(m.syn.exc_exc, false)     # freeze plasticity
  • perturbation! (nothing): forwarded to train!/sim!, which call perturbation!(; P, C, S, t, dt, start_time) at every time step.
  • from_state (nothing): pre-built model to use instead of modelcopy(model). The caller is responsible for empty records and correct starting state.
  • add_records (nothing): if nothing, returns the perturbed model. If a String/Symbol, appends the recording window of every monitored variable of the perturbed model to model.<component>.records[:perturbation][variable][condition] (see "Storage schema") and returns nothing.
  • train (true): if true runs train! (plasticity active); if false runs sim!.
  • Remaining kwargs forwarded to train!/sim!.

Storage schema (when add_records is set)

From SNNModels 1.9.2 / 2.0.2 the windows of one (variable, condition) are stored in one ragged store (append, delete by id):

obj.records[:perturbation][variable::Symbol][condition::String]
    = PerturbationStore         # dense variables: N x (sum of window lengths) Float32
    | PerturbationSpikeStore    # :fire: flat spike times + neuron indices

See PerturbationStore and PerturbationSpikeStore for the layout, and perturbation_windows to read the windows one by one. Records written by earlier versions (one Dict("interval" => ..., "data" => ...) per window, under records[:perturbation][variable][condition][n]) are NOT read, appended to or edited window by window: the old and the new layout never coexist in a working model, and every flush or reader that meets a legacy store throws an ArgumentError naming object, variable and condition. Any other value (e.g. a NamedTuple) in place of a store is refused the same way, with its type. Convert such files once with compact_perturbation_records! and save them again. The old layout stored 17,160 small dictionaries per variable for 1,320 presentations x 13 conditions; the new one stores a handful of arrays. Only 2-D (N x T) dense windows can be stored; a flush of an N-dimensional window throws an ArgumentError. Files with compact records need SNNModels >= 1.9.2 / >= 2.0.2 in every process that reads them.

Retrieve with perturbation_record(obj, variable, condition, interval).

Example

using SpikingNeuralNetworks
@load_units
E = SNN.IF(N = 20, name = "E")
noise = SNN.CurrentStimulus(E, :I, param = SNN.CurrentNoise(E; I_base = 300pA))
model = SNN.compose(; E, noise, silent = true)
SNN.monitor!(E, [:v, :fire]; sr = 1kHz)
sim!(model, 100ms)                               # baseline
SNN.perturbation_test(model, 50ms; trigger! = m -> (m.pop.E.I .+= 100pA),
                      add_records = "kick", train = false)
v, r = SNN.perturbation_record(E, :v, "kick", 0:1ms:150ms)
source
SNNModels.perturbation_windows — Method
perturbation_windows(obj, variable, condition)

The perturbation windows stored in obj.records[:perturbation][variable][condition], in insertion order (the order of the window numbers n; not sorted by tstart), as a vector of (tstart, tend, data) named tuples. tstart and tend are Float32 absolute simulation times in ms. Returns an empty vector when nothing is stored. Throws an ArgumentError if the records are still in the pre-1.9.2 layout (one Dict per window): convert them once with compact_perturbation_records!.

data is

  • dense variables: the N x T window (a reshape(view(...)) of the store, no copy; T can differ between windows, and the samples span [tstart, tend] evenly);
  • :fire: (neuron, times), two equally long views (Int32 neuron indices, Float32 spike times in ms): the spikes of the window sorted by neuron, then by time. times[neuron .== i] are the spike times of neuron i.

The views alias the store and are read-only; a later flush or clear_* invalidates them (their contents may change or be stale), so copy what you keep.

for (tstart, tend, v) in perturbation_windows(E, :v, "kick")
    @show tstart, tend, size(v)
end
source

Spike-train analysis

SNNModels.FanoFactor — Method
FanoFactor(spiketime::Vector{Float32}; interval::AbstractRange)
FanoFactor(spiketimes::Spiketimes; interval::AbstractRange)
FanoFactor(pop::AbstractPopulation; interval)

Fano factor var(counts) / mean(counts) of the spike counts in the bins of interval (see bin_spiketimes; the bin width is step(interval)), 0 if undefined. The Spiketimes and population methods return one value per neuron.

interval is a required keyword (an AbstractRange). (Up to SNNModels 1.8.4 it defaulted to nothing, and the population method built a tuple, both rejected by bin_spiketimes.)

References

Softky, W. R., & Koch, C. (1993). The highly irregular firing of cortical cells is inconsistent with temporal integration of random EPSPs. Journal of Neuroscience, 13(1), 334–350. https://doi.org/10.1523/JNEUROSCI.13-01-00334.1993

Example

using SpikingNeuralNetworks
@load_units
st = SNN.Spiketimes([Float32.(sort(rand(50) .* 1000))])
SNN.FanoFactor(st; interval = 0:100ms:1s)
source
SNNModels.ISI_CV — Method
ISI_CV(spiketime::Vector{Float32}; interval = nothing)
ISI_CV(spiketimes::Spiketimes; interval = nothing)

Coefficient of variation of the inter-spike intervals, $CV = \sigma_{ISI} / \mu_{ISI}$ (0 if undefined). The Spiketimes method returns one value per neuron; interval is ignored.

Example

using SpikingNeuralNetworks
SNN.ISI_CV(Float32[0, 10, 20, 30])   # 0.0 (regular train)
source
SNNModels.ISI_CV2 — Method
ISI_CV2(spiketime::Vector{Float32}; interval = nothing)
ISI_CV2(spiketimes::Spiketimes; interval = nothing)
ISI_CV2(pop::AbstractPopulation; interval = nothing)

Local coefficient of variation of the inter-spike intervals,

\[CV_2 = \left\langle \frac{2\,|I_{i+1} - I_i|}{I_{i+1} + I_i} \right\rangle_i ,\]

averaged over consecutive ISI pairs of one train (0 if undefined, e.g. fewer than three spikes). The Spiketimes method returns one value per neuron; the population method first restricts the spikes to interval, the other methods ignore interval.

References

Holt, G. R., Softky, W. R., Koch, C., & Douglas, R. J. (1996). Comparison of discharge variability in vitro and in vivo in cat visual cortex neurons. Journal of Neurophysiology, 75(5), 1806–1814. https://doi.org/10.1152/jn.1996.75.5.1806

source
SNNModels.alpha_function — Method
alpha_function(t::Float32, τ::Float32)

Alpha function $\alpha(t) = (t/\tau)\,e^{1 - t/\tau}$ for $t \ge 0$ and $0$ otherwise (peak value 1 at $t = \tau$). Used by alpha_kernel.

source
SNNModels.alpha_kernel — Method
alpha_kernel(; τ = 25ms, interval, kwargs...)

Causal alpha-function kernel sampled with the step of interval on 0:step(interval):10τ, and normalised so that sum(kernel) * step(interval) == 1 (unit area, in 1/ms). Default kernel of firing_rate.

source
SNNModels.average_firing_rate — Method
average_firing_rate(spiketimes::Spiketimes; interval = [])
average_firing_rate(populations; interval)

Spiketimes method: per-neuron time average of the convolved rate returned by firing_rate(spiketimes; interval, interpolate = false) (Hz).

The populations method (a population, a vector or a NamedTuple of populations) returns the histogram of all spike times over the bin edges interval and the left bin edges interval[1:end-1]. (Up to SNNModels 1.8.4 it failed with an UndefVarError: a local variable shadowed the function spiketimes.)

source
SNNModels.bin_spiketimes — Method
bin_spiketimes(spike_times::Vector{Float32}; interval::AbstractRange, do_sparse = true)
bin_spiketimes(spiketimes::Spiketimes; interval, do_sparse = true)
bin_spiketimes(p::Union{AbstractPopulation,AbstractStimulus}; kwargs...)
bin_spiketimes(P, interval::AbstractRange; kwargs...)
bin_spiketimes(populations::NamedTuple; interval = nothing, do_sparse = true)

Count spikes in the bins of interval (bin width step(interval), one bin per element of interval; bin k covers [first(interval) + (k-1)Δ, first(interval) + kΔ)). Spikes at or before first(interval) are ignored.

Returns

  • One train: (counts, interval) with counts a SparseVector (do_sparse = true) or a dense Vector{Float64} of length length(interval).
  • Spiketimes or a population: (counts::Matrix{Float64}, interval) of size (N_neurons, length(interval)).
  • NamedTuple of populations: (counts_per_population, interval, names), via spiketimes_split.

Example

using SpikingNeuralNetworks
@load_units
st = SNN.Spiketimes([[1.5f0, 2.2f0, 7.0f0], Float32[3.0]])
counts, r = SNN.bin_spiketimes(st; interval = 0:1ms:10ms)   # 2 x 11 matrix
source
SNNModels.compute_covariance_density — Method
compute_covariance_density(spike_times1::Vector{Float32}, spike_times2::Vector{Float32};
                           bin_width = 1ms, max_lag = 200ms)

Return (lags, C) with the covariance density $C(\tau) = \mathrm{xcorr}(\tau) - \lambda_x \lambda_y\,\Delta\,n_{bins}$ (cross-correlogram minus its value for independent trains with rates $\lambda_x, \lambda_y$; $\Delta$ = bin_width).

Both trains are binned on the same interval as in compute_cross_correlogram. (Up to SNNModels 1.8.4 the function always threw, see compute_cross_correlogram.)

source
SNNModels.compute_cross_correlogram — Function
compute_cross_correlogram(spike_times1::Vector{Float32}, spike_times2 = Float32[];
                          bin_width = 1ms, max_lag = 100.0, shift_predictor = false)

Return (lags, corr): the cross-correlogram (DSP.xcorr) of the spike trains of two neurons binned with bin_width on the common interval 0:bin_width:(t_last + max_lag), or the autocorrelogram if spike_times2 is empty (with the zero-lag bin set to 0), for lags up to max_lag ms. corr[k] counts the pairs with t2 - t1 in the lag bin lags[k]. With shift_predictor = true the second train is shifted by 1000 ms.

(Up to SNNModels 1.8.4 the function always threw: bin_spiketimes was called without the required interval and the autocorrelation branch referred to an undefined auto_corr.)

source
SNNModels.find_interval_indices — Method
find_interval_indices(intervals::AbstractVector, interval::Vector)

Index range x1:x2 of the vector of times intervals, with x1 (x2) the first index with value >= interval[1] (>= interval[2]).

source
SNNModels.firing_rate — Method
firing_rate(spiketimes::Spiketimes; interval, kwargs...) -> (rates, interval)

firing_rate(p::Union{AbstractPopulation,AbstractStimulus}; kwargs...)
firing_rate(P, interval::AbstractRange; kwargs...)
firing_rate(populations; mean_pop = false, kwargs...) -> (rates_per_pop, interval, names)

Estimate per-neuron instantaneous firing rates (Hz) from a Spiketimes object by convolving each binned spike train (bin = step(interval)) with a kernel of unit area, then multiplying by 1s. Returns (rates, interval).

interval should be an AbstractRange in milliseconds (e.g. 0:1ms:500ms). It sets the time grid for binning and convolution. If it is omitted, it is built as tt0:sampling:ttf with the keyword arguments sampling = 20ms, tt0 = 0 and ttf = last spike time.

A population (or stimulus) is converted with spiketimes first. The method for a collection of populations (e.g. model.pop) applies spiketimes_split and returns one rate object per population with a :fire record (mean_pop = true averages each over its neurons).

Keyword arguments

  • interval: time grid in ms, e.g. 0f0:1f0:1000f0.
  • kernel: kernel function called as kernel(; interval, kwargs...) returning a Vector of weights. Default: alpha_kernel (causal alpha function, controlled by the τ kwarg, default τ=25ms).
  • neurons: neuron subset. :ALL (default) processes every neuron; pass an Int or Vector{Int} to select a subset. Indexing is into spiketimes.
  • interpolate (true): when true, wraps the (N, T) rate matrix in a ScaledInterpolation so rates can be evaluated at arbitrary (neuron, time) pairs via rates(n, t). When false, returns a plain Matrix{Float64} of shape (N_neurons, length(interval)).
  • pop_average (false): if true, averages over neurons (dim 1) and returns a plain Vector of length length(interval) regardless of interpolate.
  • time_average (false): if true, skips convolution entirely and returns the mean firing rate per neuron (in Hz) over interval as a Vector{Float32} (spikes with first(interval) < t <= last(interval); the neurons selection is not applied). Setting both time_average and pop_average collapses to a single scalar.

Return types summary

interpolatepop_averagetime_averagereturn type of rates
truefalsefalseScaledInterpolation — call as rates(n, t)
falsefalsefalseMatrix{Float64} shape (N, T)
anytruefalseVector of length T
anyfalsetrueVector{Float32} of length N (Hz)
anytruetruescalar Float32 (Hz)

Example

using SpikingNeuralNetworks
@load_units
E = SNN.Poisson(N = 10, param = SNN.PoissonParameter(20Hz))
SNN.monitor!(E, [:fire])
sim!(SNN.compose(; E, silent = true), 2s)
st = SNN.spiketimes(E)
fr, r = SNN.firing_rate(st; interval = 0:1ms:2s, τ = 50ms)
fr(3, 500f0)                                   # neuron 3 at t = 500 ms
fr_avg, r = SNN.firing_rate(st; interval = 0:1ms:2s, pop_average = true)
mean_rates, _ = SNN.firing_rate(E; interval = 0:1ms:2s, time_average = true)
source
SNNModels.gaussian_smooth — Method
gaussian_smooth(xs, x, σ; skewed = :none) -> Vector

Apply a normalized Gaussian kernel to signal x sampled on grid xs. Kernel half-width is 3σ (truncated); boundary bins are renormalized by accumulated kernel weight so edge values are not biased toward zero.

Arguments

  • xs: sample-position grid (used only for its step size xs[2]-xs[1])
  • x: signal to smooth, length n
  • sigma: Gaussian standard deviation in the same units as xs
  • skewed: :none (symmetric), :left (causal — uses only past samples), :right (anti-causal — uses only future samples)

Returns

  • smoothed signal, same length as x
source
SNNModels.infer_spikes — Method
infer_spikes(n_spikes::Vector{<:Integer}, interval::AbstractRange; dt = 0.125f0)

Place exactly n_spikes[i] spikes, at distinct random sub-steps of size dt, inside the i-th bin of interval ((interval[i], interval[i] + step(interval)]). Returns a one-element Vector{Vector{Float32}}.

source
SNNModels.infer_spiketimes — Method
infer_spiketimes(rate::Matrix{<:Integer}, interval::AbstractRange; dt = 0.125f0, seed = nothing)

Apply infer_spikes to each row of the spike-count matrix rate (rows = neurons, columns = bins of interval) and return one spike train per row. seed seeds the global RNG.

source
SNNModels.interval_standard_spikes! — Method
interval_standard_spikes!(spiketimes, interval::Vector; margin = [0, 0])
interval_standard_spikes!(spiketimes::Vector{Spiketimes}, intervals::Vector{Vector}; margin = [0, 0])

In-place version of interval_standard_spikes: subtract interval[1] + margin[1] from every spike time; for a Vector{Spiketimes}, element i is shifted by intervals[i].

source
SNNModels.interval_standard_spikes — Method
interval_standard_spikes(spiketimes::Spiketimes, interval::Vector; margin = [0, 0])

Express spike times relative to the interval start: subtract interval[1] + margin[1] from every spike. Works on a copy; see interval_standard_spikes! for the in-place version.

source
SNNModels.isi — Method
isi(spiketimes::Spiketimes) -> Vector{Vector{Float32}}
isi(spiketimes::Vector{Float32}) -> Vector{Float32}
isi(pop::AbstractPopulation; interval = nothing)

Inter-spike intervals (ms), i.e. diff of each (sorted) spike train.

source
SNNModels.merge_spiketimes — Method
merge_spiketimes(spikes::Vector{Spiketimes}; start::Float32 = 0.0f0) -> Spiketimes
merge_spiketimes(spikes::Spiketimes) -> Vector{Float32}

Merge the spike trains of several simulations of the same network, neuron by neuron.

With start > 0, the spikes of the k-th element are shifted by start * (k - 1) in place (the input is modified) before merging, so that consecutive simulations are placed one after the other. The result is sorted per neuron. The neurons are split over Threads.nthreads() tasks; the function is not meant to be called from several threads at once.

The Spiketimes method returns all spikes of all neurons in one sorted vector.

source
SNNModels.relative_time! — Method
relative_time!(spiketimes::Spiketimes, start_time)

Subtract start_time from every spike time (the vectors are replaced in place) and return spiketimes.

source
SNNModels.resample_spikes — Method
resample_spikes(X, Y)

If there are more than 200 000 points, return a random subsample (without replacement) of 200 000 pairs (X[i], Y[i]) and warn; otherwise return (X, Y). Used for raster plots.

source
SNNModels.sample_inputs — Method
sample_inputs(N, rate::Matrix{<:Integer}, interval; dt = 0.125f0, rate_factor = 1.0f0, seed = nothing)
sample_inputs(N, rate::Matrix{<:Real}, interval; dt = 0.125f0, rate_factor = 1.0f0, seed = nothing)
sample_inputs(N, spikes::BitMatrix, interval; rate_factor, dt = 0.125f0, seed = nothing)

Build input spike trains from a matrix sampled on interval (columns = time bins):

  • integer matrix: spike counts per bin, converted with infer_spikes (one train per row; N and rate_factor are ignored);
  • real matrix: rates in Hz, converted with sample_spikes(N, row, interval) (N trains per row, concatenated);
  • BitMatrix: spike indicators; each row gives the train interval[findall(row)].

seed seeds the global RNG. Returns a Vector{Vector{Float32}}.

source
SNNModels.sample_spikes — Method
sample_spikes(N, rate::Vector, interval::AbstractRange; rate_factor = 1.0f0, dt = 0.125f0) -> Vector{Vector{Float32}}

Draw spike trains for N independent neurons from a time-varying rate (Bernoulli approximation of an inhomogeneous Poisson process).

rate[i] is the rate in Hz (a plain number, multiplied by Hz internally) during the i-th step of interval; each step of interval is divided in step(interval) / dt sub-steps, and in every sub-step each neuron spikes with probability rate[i] * Hz * dt * rate_factor. Spike times start at first(interval) + dt. length(rate) == length(interval) is required.

Example

using SpikingNeuralNetworks
@load_units
st = SNN.sample_spikes(5, fill(10.0, 100), 0:10ms:990ms)   # 5 neurons at 10 Hz for 1 s
source
SNNModels.spikecount — Method
spikecount(pop::AbstractPopulation, Trange::AbstractVector, neurons::Vector{Int})

Total number of spikes emitted by the neurons neurons of pop in the interval Trange (open bounds, see spiketimes).

source
SNNModels.spikes_in_interval — Function
spikes_in_interval(spiketimes::Spiketimes, interval, margin = [0, 0]; collapse = false) -> Spiketimes

Copy of the spikes with interval[1] + margin[1] < t <= interval[end] + margin[2] (spike trains must be sorted). collapse is accepted and ignored.

source
SNNModels.spikes_in_intervals — Method
spikes_in_intervals(spiketimes::Spiketimes, intervals::Vector{Vector{R}}; margin = [0, 0], floor = true)

Apply spikes_in_interval to each interval (in parallel with tmap) and return a Vector{Spiketimes}. With floor = true the spikes of each interval are expressed relative to the interval start (interval_standard_spikes!).

source
SNNModels.spiketimes — Method
spiketimes(Ps; kwargs...) -> Spiketimes

Concatenate spike times from all populations in Ps into a single Spiketimes vector. Neurons from the first population occupy indices 1:Ps[1].N, the second population Ps[1].N+1 : Ps[1].N+Ps[2].N, and so on.

Ps can be a NamedTuple (as returned by model.pop) or a Vector of AbstractPopulation/AbstractStimulus. All kwargs are forwarded to the single-population spiketimes dispatch (e.g. interval).

See also: spiketimes_split to keep each population's trains separate.

source
SNNModels.spiketimes — Method
spiketimes(p; interval=nothing) -> Spiketimes

Return spike times for every neuron in p as a Spiketimes (Vector{Vector{Float32}}), one inner vector per neuron.

Dispatches on the fire recording format stored in p.records[:fire]:

  • COO / dense (meta[:mode][:fire] == :dense): reads the pre-allocated times_buf / neurons_buf flat arrays written by the sim loop. If interval is given, binary-search on the sorted buffer restricts the scan to O(log(Nspikes) + Nspikesininterval) instead of a full linear pass.
  • Legacy (push!-based :time / :neurons dict): used when the population was recorded without the dense infrastructure (no monitor! call before the sim).

Arguments

  • p: an AbstractPopulation or AbstractStimulus with a :fire record.

Keyword arguments

  • interval: optional (t0, t1) tuple or any AbstractRange. Spikes satisfy t > t0 and t < t1 (both bounds strict). Pass nothing (default) to return all recorded spikes.

Notes

  • Neurons are indexed 1:p.N in the output vector; empty inner vectors mean the neuron never fired or fired outside the requested interval.
  • The returned Spiketimes is always freshly allocated (safe to mutate).
  • In the legacy format fewer than two recorded spike events return empty trains.

Example

using SpikingNeuralNetworks
@load_units
E = SNN.Poisson(N = 10, param = SNN.PoissonParameter(20Hz))
SNN.monitor!(E, [:fire])
model = SNN.compose(; E, silent = true)
sim!(model, 1s)
st = SNN.spiketimes(E)                          # all spikes
st2 = SNN.spiketimes(E; interval = (200ms, 500ms))
source
SNNModels.spiketimes_split — Method
spiketimes_split(Ps; kwargs...) -> (Vector{Spiketimes}, Vector{String})

Return, for each element of Ps that has a :fire record, its spiketimes(p; kwargs...), together with the vector of the population names. Elements without a :fire record are skipped.

source
SNNModels.st_order — Method
st_order(spiketimes::Vector)
st_order(spiketimes::Spiketimes, pop::Vector{Int}, intervals)
st_order(spiketimes::Spiketimes, populations::Vector{Vector{Int}}, intervals, unique_pop = false)

Indices that sort the elements of spiketimes (sort(eachindex(spiketimes), by = x -> spiketimes[x]); for a Spiketimes, trains are compared lexicographically, i.e. by first spike).

The methods with pop/populations sort the neurons of pop (each vector of populations) by the time of their first spike inside intervals (a vector of [start, end] pairs; neurons without such a spike come last) and return the sorted neuron indices. (Up to SNNModels 1.8.4 they called the undefined spike_statistics and threw an UndefVarError.)

source
SNNModels.STTC — Function
STTC(spiketrains::Vector{Vector{Float32}}, Δt, interval = nothing) -> Matrix{Float32}
STTC(pop::AbstractPopulation; ΔT, interval)
STTC(pop::AbstractPopulation, ΔT::Real, interval::AbstractVector)

Symmetric matrix of the pairwise STTC values of a set of spike trains (diagonal = 1, pairs with a train without spikes in the interval = 0), computed with threads over rows.

Arguments

  • spiketrains: A vector of vectors containing the spike times of each neuron.
  • Δt: The coincidence window (ms).
  • interval: recording interval; if nothing, it spans from the first spike minus Δt to the last spike plus Δt.

The population methods use spiketimes(pop).

source
SNNModels.STTC — Method
STTC(spiketrainA::Vector{Float32}, spiketrainB::Vector{Float32}, Δt::Float32, interval::AbstractVector)

Spike Time Tiling Coefficient between two spike trains,

\[\mathrm{STTC} = \frac{1}{2}\left(\frac{P_A - T_B}{1 - P_A T_B} + \frac{P_B - T_A}{1 - P_B T_A}\right),\]

computed on the spikes inside [t0, t1] = [interval[1], interval[end]]. $P_A$ is the fraction of spikes of A with a spike of B within $\pm\Delta t$; $T_A$ is the length of the union of the windows $[s - \Delta t, s + \Delta t]$ around the spikes of A, clipped to [t0, t1], divided by t1 - t0. A term with $P T = 1$ (0/0) is 1, as in Elephant; the result is 0 if either train has no spike in the interval. The inputs are not modified.

The coefficient saturates when $\Delta t$ times the firing rate is about 1 or more ($T \to 1$): choose $\Delta t$ much shorter than the inter-spike interval.

References

Cutts, C. S., & Eglen, S. J. (2014). Detecting pairwise correlations in spike trains: an objective comparison of methods and application to the study of retinal waves. Journal of Neuroscience, 34(43), 14288–14303.

Example

using SpikingNeuralNetworks
a = Float32[10, 50, 90]
b = Float32[11, 52, 300]
SNN.STTC(a, b, 5.0f0, 0:1:400)
source
SNNModels.asynchronous_state — Function
asynchronous_state(model, interval = nothing, pop = :Exc) -> (cv, ff, si)

Summary statistics of the asynchronous-irregular state of the population model.pop.<pop>.

  • cv: mean over neurons of the ISI coefficient of variation std(ISI) / (mean(ISI) + 1e-6) (NaN set to 0), with the spikes restricted to interval.
  • ff: var / mean of all the spike counts of the binned activity matrix (all neurons and bins pooled).
  • si: mean of the N x N covariance matrix of the binned spike counts of the neurons (cov(bins, dims = 2)), used as a synchrony index.

interval (default 0s:0.5s:get_time(model)) is an AbstractRange; its step is the bin width.

Example

using SpikingNeuralNetworks
@load_units
Exc = SNN.Poisson(N = 20, param = SNN.PoissonParameter(10Hz))
SNN.monitor!(Exc, [:fire])
model = SNN.compose(; Exc, silent = true)
sim!(model, 2s)
cv, ff, si = SNN.asynchronous_state(model, 0s:100ms:2s, :Exc)
source
SNNModels.gaussian_kernel — Method
gaussian_kernel(σ::Real, ll::Int)

Gaussian kernel exp(-t^2 / (2σ^2)), normalised to unit sum, sampled at ll equally spaced points t between -(ll ÷ 2) and ll ÷ 2 (unit spacing when ll is odd).

Arguments

  • σ: Standard deviation of the Gaussian kernel.
  • length: Length of the kernel.

Returns

  • kernel: A vector representing the Gaussian kernel.
source
SNNModels.gaussian_kernel_estimate — Method
gaussian_kernel_estimate(support_vector::Vector, σ::Real; boundary = :continuous)

Smooth support_vector with gaussian_kernel(σ, length(support_vector)) by convolution.

Arguments

  • support_vector: The input vector.
  • σ: Standard deviation of the Gaussian kernel, in samples.
  • boundary: :continuous extends the vector periodically (wrap-around) before convolving; :closed pads it with zeros. Any other value throws an error.

Returns

  • The smoothed vector, cut from the full convolution of the extended vector: same length as the input for odd lengths, one element shorter for even lengths.
source
SNNModels.get_maxima — Method
get_maxima(data)

Indices x of the strict interior local maxima of data (data[x] > data[x-1] and data[x] > data[x+1]).

source
SNNModels.is_attractor_state — Method
is_attractor_state(pop::AbstractPopulation, interval::AbstractVector; ratio = 0.3, σ = 10.0f0, false_value = missing)

Test whether the time-averaged firing-rate profile over the neurons of pop (ordered by index, e.g. a ring network) is a single bump.

The per-neuron mean rate over interval (from firing_rate(pop; interval)) is smoothed with gaussian_kernel_estimate(rates, σ; boundary = :continuous) (periodic). The profile is unimodal if is_unimodal(kde, ratio) holds for the profile or for the profile shifted by half its length.

Returns

  • (width, kde): if unimodal, width is the number of neurons above half of the peak divided by σ;
  • (false_value, kde) otherwise.
source
SNNModels.is_unimodal — Method
is_unimodal(kernel, ratio)

true if at most one local maximum of kernel (see get_maxima) exceeds ratio times the largest local maximum, i.e. maxima below ratio of the main peak are treated as spurious. Throws if kernel has no interior local maximum.

source
SNNModels.tile_interval — Method
tile_interval(spiketrainA::Vector{Float32}, Δt::Float32, interval::StepRangeLen{Float32})

Fraction $T_A$ of interval covered by the windows $±Δt$ around the spikes of spiketrainA (the tiling term of STTC). Sorts spiketrainA in place.

source
SNNModels.average_conn_strength — Method
average_conn_strength(M::AbstractMatrix, pops::Vector{Vector{Int}}, sparsity = 0.2)

Matrix of mean connection strengths between groups of neurons: entry (i, j) is mean(M[pops[i], pops[j]]) / sparsity (post group i, pre group j), i.e. the mean weight of the existing synapses if M has connection density sparsity.

source
SNNModels.filter_items — Method
filter_items(P; condition::Function = no_noise)

Keep the items of P (a NamedTuple of components) that have a name field and for which condition(item) is true. The default condition drops items whose name contains "noise".

Returns

A NamedTuple of the selected items, sorted by their name.

source
SNNModels.population_indices — Method
population_indices(P)

Global neuron indices of each population when the populations of P (a NamedTuple, e.g. model.pop) are concatenated in the order of keys(P), as in spiketimes(model.pop).

Returns

A NamedTuple (sorted by key) mapping each key to the Vector{Int} of its indices.

Example

using SpikingNeuralNetworks
pops = (E = SNN.IF(N = 4), I = SNN.IF(N = 2))
SNN.population_indices(pops)   # (E = [1, 2, 3, 4], I = [5, 6])
source
SNNModels.subpopulations — Function
subpopulations(stim, subset = nothing)

Neurons targeted by each stimulus of stim (a NamedTuple of stimuli, e.g. model.stim).

Arguments

  • stim: NamedTuple of stimuli; neurons(s) gives the target neurons of each.
  • subset: optional collection of stimulus names (strings); other stimuli are skipped.

Returns

  • A NamedTuple, sorted by name, mapping each stimulus name to the unique ids of the neurons it targets.
source
SNNModels.target_neurons — Function
target_neurons(stim, targets)

For each key in targets (strings or symbols), the unique neuron ids targeted by stim[key] (see neurons). Throws if a key is not in stim. Returns a Vector{Vector{Int}}.

source

Module

SNNModels.SNNModels — Module
SNNModels

Core library of the JuliaSNN ecosystem: neuron population models, synapse and receptor models, connections with long- and short-term plasticity, metaplasticity, stimuli, recording, analysis and input/output utilities.

A network is a NamedTuple assembled with compose (fields pop, syn, stim, name, time) and simulated with sim! (no plasticity) or train! (plasticity active). Quantities are plain Float32 in the unit system loaded by @load_units (ms, mV, pA, pF, nS, cm). Users normally load it through SpikingNeuralNetworks, which re-exports it as SNN.SNNModels.

source

Umbrella package

SpikingNeuralNetworks re-exports SNNModels, SNNPlots and SNNUtils.

SpikingNeuralNetworks.SpikingNeuralNetworks — Module
SpikingNeuralNetworks

Umbrella package of the JuliaSNN ecosystem. It loads and re-exports SNNModels (models, simulation, recording, analysis), SNNPlots (plotting) and SNNUtils (stimulation protocols, analysis and classifiers), defines the alias SNN = SpikingNeuralNetworks, applies the SNNPlots Makie theme (@makie_default) and loads the unit constants (@load_units) at load time.

All exported SNNModels names are reachable as SNN.<name> (e.g. SNN.IF, SNN.sim!).

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 100)
model = SNN.compose(; E, silent = true)
SNN.sim!(model, 100ms)
source