Dynamical Attractor Determination and Description¶
One of the most important aspects of understanding the behavior of continuous-time recurrent neural networks (CTRNN) is the identification and characterization of their dynamical attractors (or lack of thereof).
An attractor of a dynamical system is a set of numerical values toward which the system tends to converge over time for a given set of initial conditions. Attractors can take various forms, including fixed points, limit cycles, and strange attractors. Where fixed points are single states that the system settles into, limit cycles are periodic orbits that the system repeatedly follows, and strange attractors exhibit complex, non-repeating behavior that is sensitive to initial conditions (yet the overall structure remains invariant).
In general, finding an attractor of a dynamical system is a NP-Hard problem, and there is no single method that can be used to find all attractors in all systems. Even for a specific system with a specific set of initial conditions this is impossible in general as it can never be known if all possible states have been explored (and we cannot run the system indefinitely). However, there are a number of heuristic methods which can be used to find attractors (or at least an attractor like behavior) in certain scenarios and under certain limiting assumptions (like the maximal simulation time and the length of the attractor period).
ctneat.iznn.dynamic_attractors module provides tools for identifying and characterizing dynamical attractors in
Continuous-Time Recurrent Neural Networks (CTRNNs). It includes functions for simulating network dynamics,
resampling data, and clustering attractor states.
The central function in the module is dynamic_attractors_pipeline(), which is the full pipeline for finding
and characterizing attractors in a CTRNN. It proceeds as follows:
It receives the recordings of the network’s voltages and firing states over time, along with parameters controlling the analysis process (like burn-in time, sampling rate, etc.).
It optionally discards an initial “burn-in” period of the simulation to allow the network to stabilize.
It uses an RQA (Recurrence Quantification Analysis) based method to identify potential attractor periods in the network’s dynamics. This is done by analyzing the recurrence plot of the network’s firing states to find diagonal lines that indicate periodic behavior. This method produces a determinizm score that indicates how deterministic (as opposed to chaotic or random) the dynamics are.
If significant determinism is found, the function proceeds to try to find and fingerprint the attractor.
Depending on the parameters passed to the function, it can use either the full dynamics of all neurons in the network, or perform PCA (Principal Component Analysis) to reduce the dimensionality to a single dimension (the first principal component). Or simply superimpose the dynamics of all neurons into a single vector.
Fast Fourier Transform (FFT) is applied to the selected dynamics to identify dominant frequencies in the network’s behavior. And that frequency is used to determine the period of a supposed limit cycle attractor.
If a plausible period is found, the function extracts the segment of the dynamics corresponding to one full cycle of the attractor and runs a fingerprinting analysis on it.
The fingerprinting analysis can be done either based on the voltages of the neurons, or based on their firing states. The fingerprinting process produces a vector that encodes the attractor’s characteristics.
If no significant determinism is found, or if no plausible attractor period is identified, unless the variable burn-in is used, the function returns None for the attractor fingerprint.
If the variable burn-in is used, the function will iteratively increase the burn-in period and repeat the analysis until either an attractor is found or the maximum burn-in time is reached.
Here are the docstrings for the module:
- ctneat.iznn.dynamic_attractors.characterize_attractor_spikes(fired_history: ndarray, t_start: int, t_end: int, return_vec: bool = False) str | List[float][source]¶
Creates a spike pattern string for a detected attractor period.
- Parameters:
fired_history (np.ndarray) – A 2D array (time steps x neurons) of firing states (1.0 or 0.0).
t_start (int) – The starting time index of the attractor cycle.
t_end (int) – The ending time index of the attractor cycle.
return_vec (bool) – If True, returns a vector representation of the fingerprint instead of a string.
- Returns:
- A string representing the spike pattern. Neurons that fire at each time step are listed,
separated by commas, and time steps are separated by hyphens. Non-firing steps are denoted by ‘_’.
list: If return_vec is True, returns a list containing the vector representation of the fingerprint.
- Return type:
- ctneat.iznn.dynamic_attractors.characterize_attractor_voltage(voltage_history_cycle: ndarray, dt: float, num_peaks: int = 3, min_peak_prominence: float = 0.1, return_vec: bool = False) str | List[float][source]¶
Creates a voltage-based fingerprint for an attractor cycle that is invariant to neuron order.
It works by finding the top frequency components for each neuron’s voltage oscillation, creating a string representation for each, and then sorting these strings before joining them.
- Parameters:
voltage_history_cycle (np.ndarray) – A 2D array (time_steps x neurons) containing the voltage data for one full attractor period.
dt (float) – The time step of the uniformly sampled data in milliseconds.
num_peaks (int) – The maximum number of frequency peaks to include for each neuron.
min_peak_prominence (float) – The minimum prominence for a peak in the frequency spectrum to be considered. This helps filter out noise.
return_vec (bool) – If True, returns a vector representation of the fingerprint instead of a string.
- Returns:
- A canonical fingerprint string of the attractor’s voltage dynamics in the form:
”N1(f:10.5,m:2.3|f:21.0,m:1.1)-N2(f:9.8,m:1.5|f:20.5,m:0.9)” where each neuron’s peaks are sorted by frequency, and neurons are sorted alphabetically by their identifier (N1, N2, …). If the number of time steps is zero, returns “no_data”. If a neuron’s voltage is flat (no significant peaks), it is denoted as N<neuron_id>(flat, v:<last_voltage>).
- list: If return_vec is True, returns a list containing the vector representations of the fingerprints.
The length of the list will be num_neurons * (2 * num_peaks + 1), where each neuron contributes num_peaks frequency-magnitude pairs and one last voltage value (only set in the flat case). For the previous example, the vector would be: [10.5, 2.3, 21.0, 1.1, 0.0,
9.8, 1.5, 20.5, 0.9, 0.0]
In case of a flat signal with voltages of v1 and v2, the vector would be: [0.0, 0.0, 0.0, 0.0, v1,
0.0, 0.0, 0.0, 0.0, v2]
- Return type:
- ctneat.iznn.dynamic_attractors.dynamic_attractors_pipeline(voltage_history: ndarray, fired_history: ndarray, times_np: ndarray, dt_uniform_ms: float | str | None = None, using_simulation: bool = True, net: IZNN | None = None, burn_in: int | float | None = 0.25, variable_burn_in: bool = False, burn_in_rate: float = 0.5, min_repetitions: int = 3, min_points: int = 100, time_delay: int = 1, radius: float | None = None, theiler_corrector: int = 2, det_threshold: float = 0.2, metric: str = 'euclidean', fingerprint_using: str = 'voltage', fingerprint_vec: bool = False, superimpose: bool = False, use_lcm: bool = True, flat_signal_threshold: float = 0.001, num_peaks: int = 3, min_peak_prominence: float = 0.1, printouts: bool = True, verbose: bool = False) str | List[float] | None[source]¶
Full pipeline to analyze dynamic attractors in IZNN data. This includes resampling to uniform time steps, performing RQA, and characterizing attractors.
- Parameters:
voltage_history (np.ndarray) – A 2D numpy array where each row corresponds to a time step, and each column corresponds to a specific neuron’s voltage.
fired_history (np.ndarray) – A 2D numpy array where each row corresponds to a time step, and each column corresponds to a specific neuron’s firing state.
times_np (np.ndarray) – A 1D numpy array of time stamps corresponding to the data points.
dt_uniform_ms (Optional[Union[float, str]]) – The desired uniform time step in milliseconds. Valid options are a positive float or ‘min’, ‘max’, ‘avg’ and ‘median’. If not set, will be set to the smallest interval in times_np.
using_simulation (bool) – If true, uses the network provided in the net argument to recalculate the data. If false, uses linear interpolation to resample the data.
net (IZNN) – The IZNN network used to run the simulation.
burn_in (Optional[Union[int, float]]) – Number of initial time steps to discard from the analysis. If float, treated as percentage. If int, treated as absolute number of steps. If None, defaults to 0.
variable_burn_in (bool) – If True, adds an option to variably increase the burn-in period in case the one provided in burn_in is not sufficient to find the attractor.
burn_in_rate (float) – The rate at which to increase the burn-in period if variable_burn_in is True. For example, a rate of 0.5 means increasing that the new burn-in will include 50% of the non-burned-in data. Burn-in will continuously increase until an attractor is found or until not enough data is left.
min_repetitions (int) – Minimum number of repetitions of the attractor cycle to confirm its presence.
min_points (int) – Minimum number of data points required after burn-in to perform the analysis.
time_delay (int) – Time delay for embedding the time series. The time delay defines the number of time steps to skip when creating the embedded vectors.
radius (float) – The radius for the recurrence plot. If None, a default value is 0.2 * std(data). The radius defines the threshold distance in state space for considering two states as recurrent.
theiler_corrector (int) – Theiler window to exclude temporally close points. This prevents finding “fake” recurrences from points that are close in distance simply because they are also close in time. It excludes points within w time steps of each other from being considered recurrent pairs. A small value (e.g., a few steps more than your time_delay) is usually sufficient to remove these trivial correlations. Setting it to 0 disables it.
det_threshold (float) – The threshold of determinism (DET) above which to attempt attractor characterization. If the DET from RQA is above this threshold, the attractor characterization is performed.
metric (str) – The distance metric to use (‘euclidean’, ‘taxicab’, ‘maximum’) or alternatively (‘l2’, ‘l1’ and ‘linf’). Case insensitive. Default is ‘euclidean’.
fingerprint_using (str) – The method to use for generating the fingerprint of the attractor. Options are ‘voltage’ (using the voltage trace) or ‘firing’ (using the firing rate). Default is ‘voltage’.
fingerprint_vec (bool) – If True, returns a vector representation of the fingerprint instead of a string.
superimpose (bool) – Instead of doing a PCA reduction, simply superimpose all neuron voltages into one signal using max. (Default is False)
use_lcm (bool) – Whether to use the least common multiple of individual neuron periods to determine the overall period. If False, uses the dominant frequency from the combined signal. (Default is True)
flat_signal_threshold (float) – Threshold for standard deviation to consider a signal as “flat” (in mV).
num_peaks (int) – The maximum number of frequency peaks to include for each neuron when using voltage fingerprinting.
min_peak_prominence (float) – The minimum prominence for a peak in the frequency spectrum to be considered when using voltage fingerprinting. This helps filter out noise.
printouts (bool) – If True, prints summary information about the analysis.
verbose (bool) – If True, prints detailed information during the analysis. (If set to true, also enables printouts.)
- Returns:
- A string representing the spike pattern of the attractor, or None if no attractor can be found.
Neurons that fire at each time step are listed, separated by commas, and time steps are separated by hyphens. Non-firing steps are denoted by ‘_’. In case of voltage fingerprinting, the string represents the frequency components of each neuron. If fingerprint_vec is True and voltage fingerprinting is used, returns a list containing the vector representation of the fingerprint. If no attractor is found, returns None.
- Return type:
- Raises:
ValueError – If dt_uniform_ms is invalid or if fingerprint_using is not recognized.
- ctneat.iznn.dynamic_attractors.fingerprint_attractors(voltage_history: ndarray, fired_history: ndarray, times: ndarray, superimpose: bool = False, use_lcm: bool = False, fingerprint_using: str = 'voltage', fingerprint_vec: bool = False, burn_in: int | float | None = None, min_repetitions: int = 3, flat_signal_threshold: float = 0.001, num_peaks: int = 3, min_peak_prominence: float = 0.1, printouts: bool = False) str | List[float] | None[source]¶
Analyzes the voltage and firing history to identify and characterize attractor periods. It estimates the dominant period using FFT (Fast Fourier Transform) and then characterizes the spike pattern during the last full period.
- Parameters:
fired_history (np.ndarray) – A 2D array (time steps x neurons) of firing states (1.0 or 0.0).
voltage_history (np.ndarray) – A 2D array (time steps x neurons) of voltage values.
times (np.ndarray) – A 1D array of time stamps corresponding to the data points.
superimpose (bool) – Instead of doing a PCA reduction, simply superimpose all neuron voltages into one signal using max. (Default is False)
use_lcm (bool) – Whether to use the least common multiple of individual neuron periods to determine the overall period. If False, uses the dominant frequency from the combined signal. (Default is False)
fingerprint_using (str) – The method to use for generating the fingerprint of the attractor. Options are ‘voltage’ (using the voltage trace) or ‘firing’ (using the firing rate). Default is ‘voltage’.
fingerprint_vec (bool) – If True, returns a vector representation of the fingerprint instead of a string.
burn_in (Optional[Union[int, float]]) – Number of initial time steps to discard from the analysis. If float, treated as percentage. If int, treated as absolute number of steps. If None, defaults to 0.
min_repetitions (int) – Minimum number of repetitions of the attractor cycle to confirm its presence.
flat_signal_threshold (float) – Threshold for standard deviation to consider a signal as “flat” (in mV).
num_peaks (int) – The maximum number of frequency peaks to include for each neuron when using voltage fingerprinting.
min_peak_prominence (float) – The minimum prominence for a peak in the frequency spectrum to be considered when using voltage fingerprinting. This helps filter out noise.
printouts (bool) – Whether to print summarized analysis information.
- Returns:
- A string representing the spike pattern of the attractor, or None if no attractor is found.
In case of voltage fingerprinting, the string represents the frequency components of each neuron. In case of firing fingerprinting, the string represents the firing pattern of the attractor.
- Return type:
Optional[str]
- Raises:
ValueError – If the input arrays have incompatible shapes or if the time data is not uniformly sampled.
ValueError – If fingerprint_using is not recognized.
- ctneat.iznn.dynamic_attractors.perform_rqa_analysis(data_points: ndarray, burn_in: int | float | None = 0.25, time_delay: int = 1, radius: float | None = None, theiler_corrector: int = 2, metric: str = 'euclidean', printouts: bool = False, verbose: bool = False) RQAResult[source]¶
Perform Recurrence Quantification Analysis (RQA) on the given data points.
- Parameters:
data_points (np.ndarray) – A 2D numpy array where each row corresponds to a time step, and each column corresponds to a specific variable’s state.
burn_in (Optional[Union[int, float]]) – Number of initial time steps to discard from the analysis. If float, treated as percentage. If int, treated as absolute number of steps. If None, no burn-in is applied (same as if 0).
time_delay (int) – Time delay for embedding the time series. The time delay defines the number of time steps to skip when creating the embedded vectors.
radius (float) – The radius for the recurrence plot. If None, a default value is 0.2 * std(data). The radius defines the threshold distance in state space for considering two states as recurrent.
theiler_corrector (int) – Theiler window to exclude temporally close points. This prevents finding “fake” recurrences from points that are close in distance simply because they are also close in time. It excludes points within w time steps of each other from being considered recurrent pairs. A small value (e.g., a few steps more than your time_delay) is usually sufficient to remove these trivial correlations. Setting it to 0 disables it.
metric (str) – The distance metric to use (‘euclidean’, ‘taxicab’, ‘maximum’) or alternatively (‘l2’, ‘l1’ and ‘linf’). Case insensitive. Default is ‘euclidean’.
printouts (bool) – If True, prints summary information about the analysis.
verbose (bool) – If True, prints detailed information during the analysis. (If set to true, also enables printouts.)
- Returns:
None
- Raises:
ValueError – If an unsupported metric is provided.
- ctneat.iznn.dynamic_attractors.resample_data(times_np: ndarray, data_np: ndarray, dt_uniform_ms: float | str | None = None, using_simulation: bool = False, net: IZNN | None = None, events: bool = False, ret: str = 'voltages') Tuple[ndarray, ndarray][source]¶
Resamples non-uniformly sampled data to a uniform time grid using linear interpolation.
- Parameters:
times_np (np.ndarray) – The 1D array of non-uniform time stamps.
data_np (np.ndarray) – The 2D array of data (time steps x neurons).
dt_uniform_ms (float) – The desired uniform time step in milliseconds. Valid options are a positive float or ‘min’, ‘max’, ‘avg’ and ‘median’. If not set, will be set to the smallest interval in times_np.
using_simulation (bool) – If true, uses the network provided in the net argument to recalculate the data. If false, uses linear interpolation to resample the data.
net (IZNN) – The IZNN network used to run the simulation.
events (bool) – If using_simulation is True, specifies whether to do event-driven simulation.
ret (str) –
If using_simulation is True, specifies what to return from the simulation. Valid strings are:
’fired’ - returns the firing states (1.0 if fired, 0.0 otherwise) ‘voltages’ - returns the membrane potentials (in millivolts) ‘recovery’ - returns the recovery variables (in millivolts)
Default is ‘voltages’.
- Returns:
A tuple (uniform_times, uniform_data)
- Raises:
ValueError – If dt_uniform_ms is invalid or if using_simulation is True but no network is provided.