Source code for skneuromsi.neural._paredes2025

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This file is part of the
#   Scikit-NeuroMSI Project (https://github.com/renatoparedes/scikit-neuromsi).
# Copyright (c) 2021-2025, Renato Paredes; Cabral, Juan
# License: BSD 3-Clause
# Full Text:
#     https://github.com/renatoparedes/scikit-neuromsi/blob/main/LICENSE.txt


import copy
from dataclasses import dataclass

from brainpy import odeint

import numpy as np

from ..core import SKNMSIMethodABC
from ..utils.neural_tools import (
    calculate_inter_areal_synapses,
    calculate_lateral_synapses,
    calculate_stimuli_input,
    compute_latency,
    create_unimodal_stimuli_matrix,
    prune_synapses,
)
from ..utils.readout_tools import calculate_spatiotemporal_causes_from_peaks


[docs] @dataclass class Paredes2025Integrator: """A class representing the integrator for the Paredes2025 model.""" tau: tuple s: float theta: float name: str = "Paredes2025Integrator" @property def __name__(self): """Return the name of the Integrator.""" return self.name
[docs] def sigmoid(self, u): """ Computes the sigmoid activation function. Parameters ---------- u : float or np.ndarray The input to the sigmoid function. Returns ------- float or np.ndarray The result of the sigmoid function applied to `u`. """ return 1 / (1 + np.exp(-self.s * (u - self.theta)))
def __call__(self, y_a, y_v, y_m, t, u_a, u_v, u_m): """ Computes the activities of neurons. Parameters ---------- y_a : np.ndarray The current state of the auditory layer neurons. y_v : np.ndarray The current state of the visual layer neurons. y_m : np.ndarray The current state of the multisensory layer neurons. t : float The current time in the simulation. u_a : np.ndarray The total input to the auditory layer neurons. u_v : np.ndarray The total input to the visual layer neurons. u_m : np.ndarray The total input to the multisensory layer neurons. Returns ------- tuple A tuple containing the activities of neurons. """ # Auditory dy_a = (-y_a + self.sigmoid(u_a)) * (1 / self.tau) # Visual dy_v = (-y_v + self.sigmoid(u_v)) * (1 / self.tau) # Multisensory dy_m = (-y_m + self.sigmoid(u_m)) * (1 / self.tau) return dy_a, dy_v, dy_m
[docs] @dataclass class Paredes2025TemporalFilter: """Temporal filter for the Paredes2025 model.""" tau: tuple name: str = "Paredes2025TemporalFilter" @property def __name__(self): """Return the name of the Temporal Filter.""" return self.name def __call__( self, a_outside_input, v_outside_input, m_outside_input, auditoryfilter_input, visualfilter_input, multisensoryfilter_input, t, a_external_input, v_external_input, m_external_input, a_cross_modal_input, v_cross_modal_input, a_feedback_input, v_feedback_input, a_gain, v_gain, m_gain, a_noise, v_noise, include_noise, include_temporal_noise, a_temporal_noise, v_temporal_noise, m_temporal_noise, ): """ Computes the temporal filtering for the neural inputs. Parameters ---------- a_outside_input : np.ndarray The outside input to the auditory layer after filtering. v_outside_input : np.ndarray The outside input to the visual layer after filtering. m_outside_input : np.ndarray The outside input to the multisensory layer after filtering. auditoryfilter_input : np.ndarray The current auditory filter input. visualfilter_input : np.ndarray The current visual filter input. multisensoryfilter_input : np.ndarray The current multisensory filter input. t : float The current time in the simulation. a_external_input : np.ndarray The external input to the auditory layer neurons. v_external_input : np.ndarray The external input to the visual layer neurons. m_external_input : np.ndarray The external input to the multisensory layer neurons. a_cross_modal_input : np.ndarray The cross-modal input to the auditory layer neurons. v_cross_modal_input : np.ndarray The cross-modal input to the visual layer neurons. a_feedback_input : np.ndarray The feedback input to the auditory layer neurons. v_feedback_input : np.ndarray The feedback input to the visual layer neurons. a_gain : float The gain factor for the auditory layer. v_gain : float The gain factor for the visual layer. m_gain : float The gain factor for the multisensory layer. a_noise : np.ndarray The noise added to the auditory layer input. v_noise : np.ndarray The noise added to the visual layer input. include_noise : bool Whether to include noise in the calculations. include_temporal_noise : bool Whether to include temporal noise in the calculations. a_temporal_noise : float The temporal noise scale for the auditory layer. v_temporal_noise : float The temporal noise scale for the visual layer. m_temporal_noise : float The temporal noise scale for the multisensory layer. Returns ------- tuple A tuple containing the updated outside inputs and filtered inputs for the auditory, visual, and multisensory layers. """ if not include_noise: a_noise, v_noise = 0, 0 if include_temporal_noise: a_tau, v_tau, m_tau = ( a_temporal_noise, v_temporal_noise, m_temporal_noise, ) else: a_tau, v_tau, m_tau = self.tau[0], self.tau[1], self.tau[2] # Auditory da_outside_input = auditoryfilter_input dauditory_filter_input = ( (a_gain / a_tau) * ( a_external_input + a_cross_modal_input + a_feedback_input + a_noise ) - ((2 * auditoryfilter_input) / a_tau) - a_outside_input / np.square(a_tau) ) # Visual dv_outside_input = visualfilter_input dvisual_filter_input = ( (v_gain / v_tau) * ( v_external_input + v_cross_modal_input + v_feedback_input + v_noise ) - ((2 * visualfilter_input) / v_tau) - v_outside_input / np.square(v_tau) ) # Multisensory dm_outside_input = multisensoryfilter_input dmultisensory_filter_input = ( (m_gain / m_tau) * (m_external_input) - ((2 * multisensoryfilter_input) / m_tau) - m_outside_input / np.square(m_tau) ) return ( da_outside_input, dv_outside_input, dm_outside_input, dauditory_filter_input, dvisual_filter_input, dmultisensory_filter_input, )
[docs] class Paredes2025(SKNMSIMethodABC): r""" Causal Inference Network Model of Paredes et al. (2025). This model builds upon previous network models for multisensory integration (Cuppini et al., 2014; Cuppini et al., 2017) and consists of three layers: two unisensory layers (auditory and visual) and a multisensory layer. The unisensory layers encode auditory and visual stimuli separately and connect to the multisensory layer via feedforward and feedback synapses. The model computes implicit causal inference at the unisensory layers and explicit causal inference at the multisensory layer, mimicking the responses of neurons in the parietal-temporal association cortices. References ---------- :cite:p:`cuppini2014neurocomputational` :cite:p:`cuppini2017biologically` :cite:p:`paredes2025excitation` Notes ----- The Paredes2025 model maintains the neural connectivity (lateral, crossmodal, feedforward) and inputs as described in the network presented in Cuppini et al. (2017). This new model includes feedback connectivity and temporal filters as detailed below. The feedback synaptic weights are calculated using: .. math:: B^{cm}_{jk} = B^{cm}_{0} \cdot \exp \left( - \frac{\left(D_{jk}\right)^{2}}{2 \left(\sigma^{cm}\right)^{2}} \right) where: - :math:`B^{cm}_{0}`: Highest level of synaptic efficacy. - :math:`D_{jk}`: Distance between neuron at position :math:`j` in the post-synaptic unisensory region and neuron at position :math:`k` in the pre-synaptic multisensory region. - :math:`\sigma^{cm}`: Width of the feedback synapses, which is the same for both auditory-to-multisensory (:math:`am`) and visual-to-multisensory (:math:`vm`) connections. The overall feedback input to the unisensory neurons is given by: .. math:: b^{c}_{j}\left(t\right) = \sum^{N}_{k=1} B^{cm}_{jk} \cdot y^{c}_{k}\left(t - \Delta t_{feed}\right) where :math:`\Delta t_{feed}` represents the latency of feedback inputs between the multisensory and unisensory regions. The feedback synaptic weights are symmetrically defined: .. math:: B_{0}^{am} = B_{0}^{vm} \quad \text{and} \quad \sigma^{am} = \sigma^{vm} The external sources in unisensory regions are filtered using a second-order differential equation: .. math:: \left\{ \begin{matrix} \frac{d}{dt} o^{c}_{j}\left(t\right) = \delta^{c}_{j} \left(t\right) \\ \frac{d}{dt} \delta^{c}_{j} \left(t\right) = \frac{G^{c}}{\tau^{c}} \cdot \left[ e^{c}_{j}\left(t\right) + c^{c}_{j}\left(t\right) + b^{c}_{j}\left(t\right) + n^{c}_{j} \right] - \frac{2 \cdot \delta^{c}_{j} \left(t\right)}{\tau^{c}} - \frac{o^{c}_{j}\left(t\right)}{\left( \tau^{c} \right)^{2}} \end{matrix} \right. where: - :math:`G^{c}`: Gain of the unisensory regions. - :math:`\tau^{c}`: Time constant of the unisensory regions. - :math:`c` : Indicates the unisensory region (auditory or visual). The external sources in multisensory regions are filtered using a second-order differential equation: .. math:: \left\{ \begin{matrix} \frac{d}{dt} o^{m}_{j}\left(t\right) = \delta^{m}_{j} \left(t\right) \\ \frac{d}{dt} \delta^{m}_{j} \left(t\right) = \frac{G^{m}}{\tau^{m}} \cdot \left[ i^{m}_{j}\left(t\right) \right] - \frac{2 \cdot \delta^{m}_{j} \left(t\right)}{\tau^{m}} - \frac{o^{m}_{j}\left(t\right)}{\left( \tau^{m} \right)^{2}} \end{matrix} \right. where: - :math:`G^{m}`: Gain of the multisensory regions. - :math:`\tau^{m}`: Time constant of the multisensory regions. The cross-modal input to the unisensory neurons is calculated as: .. math:: \begin{matrix} c^{a}_{j}\left(t\right) = \sum^{N}_{k=1} W^{av}_{jk} \cdot y^{v}_{k} \left(t - \Delta t_{cross} \right) \\ c^{v}_{j}\left(t\right) = \sum^{N}_{k=1} W^{va}_{jk} \cdot y^{a}_{k} \left(t - \Delta t_{cross}\right) \end{matrix} where :math:`\Delta t_{cross}` represents the latency of cross-modal inputs between the unisensory regions. """ _model_name = "Paredes2025" _model_type = "Neural" _run_input = [ {"target": "auditory_position", "template": "${mode0}_position"}, {"target": "visual_position", "template": "${mode1}_position"}, {"target": "auditory_intensity", "template": "${mode0}_intensity"}, {"target": "visual_intensity", "template": "${mode1}_intensity"}, {"target": "auditory_duration", "template": "${mode0}_duration"}, {"target": "visual_duration", "template": "${mode1}_duration"}, {"target": "auditory_onset", "template": "${mode0}_onset"}, {"target": "visual_onset", "template": "${mode1}_onset"}, ] _run_output = [ {"target": "auditory", "template": "${mode0}"}, {"target": "visual", "template": "${mode1}"}, ] _output_mode = "multi" def __init__( self, *, neurons=90, tau=(15, 25, 5), tau_neurons=1, s=2, theta=16, seed=None, mode0="auditory", mode1="visual", position_range=(0, 90), position_res=1, time_range=(0, 200), time_res=0.01, **integrator_kws, ): """ Initialize the Paredes2025 model. Parameters ---------- neurons : int, optional Number of neurons in the network. Default is 90. tau : tuple of float, optional Time constants for the temporal filters. Default is (15, 25, 5). tau_neurons : float, optional Time constant for the neuron integrator. Default is 1. s : float, optional Parameter related to the integrator model. Default is 2. theta : float, optional Threshold parameter for the integrator model. Default is 16. seed : int or None, optional Seed for the random number generator. Default is None. mode0 : str, optional The name for the first sensory modality. Default is "auditory". mode1 : str, optional The name for the second sensory modality. Default is "visual". position_range : tuple of int, optional Range of positions for stimuli in degrees as (min, max). Default is (0, 90). position_res : int or float, optional Resolution of the position range in degrees. Default is 1. time_range : tuple of float, optional Time range for the simulation in miliseconds. Default is (0, 200). time_res : float, optional Time resolution of the simulation in miliseconds. Default is 0.01. **integrator_kws Additional keyword arguments for the integrator. Raises ------ ValueError If `tau` does not contain exactly 3 elements. """ if len(tau) != 3: raise ValueError() self._neurons = neurons self._position_range = position_range self._position_res = float(position_res) self._time_range = time_range self._time_res = float(time_res) integrator_kws.setdefault("method", "euler") integrator_kws.setdefault("dt", self._time_res) integrator_model = Paredes2025Integrator( tau=tau_neurons, s=s, theta=theta ) self._integrator = odeint(f=integrator_model, **integrator_kws) temporal_filter_model = Paredes2025TemporalFilter(tau=tau) self._temporal_filter = odeint( f=temporal_filter_model, **integrator_kws ) self.set_random(np.random.default_rng(seed=seed)) self._mode0 = mode0 self._mode1 = mode1 # PROPERTY ================================================================ @property def neurons(self): """ Returns the number of neurons in the network. Returns ------- int The number of neurons. """ return self._neurons @property def tau_neurons(self): """ Returns the time constant for the neuron integrator. Returns ------- float The time constant for the neuron integrator. """ return self._integrator.f.tau @property def tau(self): """ Returns the time constants for the temporal filters. Returns ------- tuple of float The time constants for the temporal filters. """ return self._temporal_filter.f.tau @property def s(self): """ Slope of the sigmoid activation function. Returns ------- float The slope parameter of the sigmoid function used in the model. """ return self._integrator.f.s @property def theta(self): """ Central position of the sigmoid activation function. Returns ------- float The central position parameter of the sigmoid function used in the model. """ return self._integrator.f.theta @property def random(self): """ Returns the random number generator. Returns ------- np.random.Generator The random number """ return self._random @property def time_range(self): """ Time range for simulation. Returns ------- tuple of 2 float The start and end times for the simulation in seconds. """ return self._time_range @property def time_res(self): """ Time resolution of the simulation. Returns ------- float The time step size for the simulation in seconds. """ return self._time_res @property def position_range(self): """ Range of positions in degrees. Returns ------- tuple of 2 int The minimum and maximum positions in degrees. """ return self._position_range @property def position_res(self): """ Resolution of position encoding. Returns ------- float The resolution of position encoding in degrees. """ return self._position_res @property def mode0(self): """ Returns the name of the first sensory modality. Returns ------- str The name of the first sensory modality. """ return self._mode0 @property def mode1(self): """ Returns the name of the second sensory modality. Returns ------- str The name of the second sensory modality. """ return self._mode1 # Model run
[docs] def set_random(self, rng): """ Set the random number generator for the model. This method allows for setting a custom random number generator, which can be useful for ensuring reproducibility or for using different random number generation strategies. Parameters ---------- rng : numpy.random.Generator The random number generator to be used. It should be an instance of `numpy.random.Generator`. """ self._random = rng
[docs] def run( self, *, auditory_soa=50, visual_soa=None, auditory_onset=16, visual_onset=16, auditory_duration=7, visual_duration=12, auditory_position=None, visual_position=None, auditory_intensity=2.4, visual_intensity=1.4, auditory_sigma=32, visual_sigma=4, noise=False, noise_level=0.40, temporal_noise=False, temporal_noise_scale=5, lateral_excitation=2, lateral_excitation_sigma=3, lateral_inhibition=1.8, lateral_inhibition_sigma=24, cross_modal_weight=0.075, cross_modal_latency=16, feed_latency=95, feedback_weight=0.10, feedforward_weight=1.4, auditory_gain=None, visual_gain=None, multisensory_gain=None, auditory_stim_n=2, visual_stim_n=1, feedforward_pruning_threshold=0, cross_modal_pruning_threshold=0, causes_kind="count", causes_dim="space", causes_peak_threshold=0.80, causes_peak_distance=None, ): """ Runs the model simulation with specified parameters. Parameters ---------- auditory_soa : float, optional Stimulus-onset asynchrony for auditory stimuli (default is 50). visual_soa : float, optional Stimulus-onset asynchrony for visual stimuli (default is None). auditory_onset : float, optional Onset time for auditory stimuli (default is 16). visual_onset : float, optional Onset time for visual stimuli (default is 16). auditory_duration : float, optional Duration of auditory stimuli (default is 7). visual_duration : float, optional Duration of visual stimuli (default is 12). auditory_position : float, optional Position of auditory stimuli (default is middle of the range). visual_position : float, optional Position of visual stimuli (default is middle of the range). auditory_intensity : float, optional Intensity of auditory stimuli (default is 2.4). visual_intensity : float, optional Intensity of visual stimuli (default is 1.4). auditory_sigma : float, optional Standard deviation for auditory stimuli (default is 32). visual_sigma : float, optional Standard deviation for visual stimuli (default is 4). noise : bool, optional Whether to include noise in the simulation (default is False). noise_level : float, optional Level of noise to add (default is 0.40). temporal_noise : bool, optional Whether to include temporal noise (default is False). temporal_noise_scale : float, optional Scale of temporal noise (default is 5). lateral_excitation : float, optional Lateral excitation weight parameter (default is 2). lateral_excitation_sigma : float, optional Lateral excitation spread parameter (default is 3). lateral_inhibition : float, optional Lateral inhibition weight parameter (default is 1.8). lateral_inhibition_sigma : float, optional Lateral inhibition spread parameter (default is 24). cross_modal_weight : float, optional Weight for cross-modal connections (default is 0.075). cross_modal_latency : float, optional Latency for cross-modal inputs (default is 16). feed_latency : float, optional Latency for feedforward inputs (default is 95). feedback_weight : float, optional Weight for feedback connections (default is 0.10). feedforward_weight : float, optional Weight for feedforward connections (default is 1.4). auditory_gain : float, optional Gain for auditory processing (default is None, which sets to exp(1)). visual_gain : float, optional Gain for visual processing (default is None, which sets to exp(1)). multisensory_gain : float, optional Gain for multisensory processing (default is None, which sets to exp(1)). auditory_stim_n : int, optional Number of auditory stimuli (default is 2). visual_stim_n : int, optional Number of visual stimuli (default is 1). feedforward_pruning_threshold : float, optional Threshold for pruning feedforward synapses (default is 0). cross_modal_pruning_threshold : float, optional Threshold for pruning cross-modal synapses (default is 0). causes_kind : str, optional Method for calculating causes ("count" or other) (default is "count"). causes_dim : str, optional Dimension for calculating causes ("space" or other) (default is "space"). causes_peak_threshold : float, optional Peak threshold for causes calculation (default is 0.80). Returns ------- tuple A tuple containing: - response (dict): A dictionary with keys "auditory", "visual", and "multi", containing the simulation results for each layer. - extra (dict): A dictionary with additional information such as total inputs, causes parameters, and stimulus positions. """ auditory_position = ( int(self._position_range[1] / 2) if auditory_position is None else auditory_position ) visual_position = ( int(self._position_range[1] / 2) if visual_position is None else visual_position ) auditory_gain = np.exp(1) if auditory_gain is None else auditory_gain visual_gain = np.exp(1) if visual_gain is None else visual_gain multisensory_gain = ( np.exp(1) if multisensory_gain is None else multisensory_gain ) hist_times = np.arange( self._time_range[0], self._time_range[1], self._integrator.dt ) sim_cross_modal_latency = int( cross_modal_latency / self._integrator.dt ) sim_feed_latency = int(feed_latency / self._integrator.dt) # Build synapses auditory_latsynapses = calculate_lateral_synapses( neurons=self.neurons, excitation_loc=lateral_excitation, inhibition_loc=lateral_inhibition, excitation_scale=lateral_excitation_sigma, inhibition_scale=lateral_inhibition_sigma, ) visual_latsynapses = calculate_lateral_synapses( neurons=self.neurons, excitation_loc=lateral_excitation, inhibition_loc=lateral_inhibition, excitation_scale=lateral_excitation_sigma, inhibition_scale=lateral_inhibition_sigma, ) multi_latsynapses = calculate_lateral_synapses( neurons=self.neurons, excitation_loc=lateral_excitation, inhibition_loc=lateral_inhibition, excitation_scale=lateral_excitation_sigma, inhibition_scale=lateral_inhibition_sigma, ) auditory_to_visual_synapses = calculate_inter_areal_synapses( neurons=self.neurons, weight=cross_modal_weight, sigma=5 ) visual_to_auditory_synapses = calculate_inter_areal_synapses( neurons=self.neurons, weight=cross_modal_weight, sigma=5 ) auditory_to_multi_synapses = calculate_inter_areal_synapses( neurons=self.neurons, weight=feedforward_weight, sigma=0.5 ) visual_to_multi_synapses = calculate_inter_areal_synapses( neurons=self.neurons, weight=feedforward_weight, sigma=0.5 ) multi_to_auditory_synapses = calculate_inter_areal_synapses( neurons=self.neurons, weight=feedback_weight, sigma=0.5 ) multi_to_visual_synapses = calculate_inter_areal_synapses( neurons=self.neurons, weight=feedback_weight, sigma=0.5 ) # Prune synapses auditory_to_multi_synapses = prune_synapses( auditory_to_multi_synapses, feedforward_pruning_threshold ) visual_to_multi_synapses = prune_synapses( visual_to_multi_synapses, feedforward_pruning_threshold ) auditory_to_visual_synapses = prune_synapses( auditory_to_visual_synapses, cross_modal_pruning_threshold ) visual_to_auditory_synapses = prune_synapses( visual_to_auditory_synapses, cross_modal_pruning_threshold ) # Generate Stimuli point_auditory_stimuli = calculate_stimuli_input( neurons=self.neurons, intensity=auditory_intensity, scale=auditory_sigma, loc=auditory_position, ) point_visual_stimuli = calculate_stimuli_input( neurons=self.neurons, intensity=visual_intensity, scale=visual_sigma, loc=visual_position, ) auditory_stimuli = create_unimodal_stimuli_matrix( neurons=self.neurons, stimuli=point_auditory_stimuli, stimuli_duration=auditory_duration, onset=auditory_onset, simulation_length=self._time_range[1], time_res=self.time_res, dt=self._integrator.dt, stimuli_n=auditory_stim_n, soa=auditory_soa, ) visual_stimuli = create_unimodal_stimuli_matrix( neurons=self.neurons, stimuli=point_visual_stimuli, stimuli_duration=visual_duration, onset=visual_onset, simulation_length=self._time_range[1], time_res=self.time_res, dt=self._integrator.dt, stimuli_n=visual_stim_n, soa=visual_soa, ) # Data holders z_1d = np.zeros(self.neurons) auditory_y, visual_y, multi_y = ( copy.deepcopy(z_1d), copy.deepcopy(z_1d), copy.deepcopy(z_1d), ) ( auditory_outside_input, visual_outside_input, multisensory_outside_input, ) = (copy.deepcopy(z_1d), copy.deepcopy(z_1d), copy.deepcopy(z_1d)) auditoryfilter_input, visualfilter_input, multisensoryfilter_input = ( copy.deepcopy(z_1d), copy.deepcopy(z_1d), copy.deepcopy(z_1d), ) z_2d = np.zeros( (int(self._time_range[1] / self._integrator.dt), self.neurons) ) auditory_res, visual_res, multi_res = ( copy.deepcopy(z_2d), copy.deepcopy(z_2d), copy.deepcopy(z_2d), ) ( auditory_total_inputs, visual_total_inputs, multisensory_total_inputs, ) = (copy.deepcopy(z_2d), copy.deepcopy(z_2d), copy.deepcopy(z_2d)) del z_1d, z_2d # Temporal noise rand_a_tau, rand_v_tau, rand_m_tau = ( self.random.uniform( self.tau[0] - temporal_noise_scale / 2, self.tau[0] + temporal_noise_scale / 2, ), self.random.uniform( self.tau[1] - temporal_noise_scale / 2, self.tau[1] + temporal_noise_scale / 2, ), self.random.uniform( self.tau[2] - temporal_noise_scale / 2, self.tau[2] + temporal_noise_scale / 2, ), ) for i in range(hist_times.size): time = int(hist_times[i] / self._integrator.dt) # Input noise auditory_noise = -(auditory_intensity * noise_level) + ( 2 * auditory_intensity * noise_level ) * self.random.random(self.neurons) visual_noise = -(visual_intensity * noise_level) + ( 2 * visual_intensity * noise_level ) * self.random.random(self.neurons) # Compute cross-modal input computed_cross_latency = compute_latency( time, sim_cross_modal_latency ) auditory_cm_input = np.sum( visual_to_auditory_synapses.T * visual_res[computed_cross_latency, :], axis=1, ) visual_cm_input = np.sum( auditory_to_visual_synapses.T * auditory_res[computed_cross_latency, :], axis=1, ) # Compute feedback input computed_feed_latency = compute_latency(time, sim_feed_latency) auditory_feedback_input = np.sum( multi_to_auditory_synapses.T * multi_res[computed_feed_latency, :], axis=1, ) visual_feedback_input = np.sum( multi_to_visual_synapses.T * multi_res[computed_feed_latency, :], axis=1, ) # Compute feedforward input multi_input = np.sum( auditory_to_multi_synapses.T * auditory_res[computed_feed_latency, :], axis=1, ) + np.sum( visual_to_multi_synapses.T * visual_res[computed_feed_latency, :], axis=1, ) ( auditory_outside_input, visual_outside_input, multisensory_outside_input, auditoryfilter_input, visualfilter_input, multisensoryfilter_input, ) = self._temporal_filter( a_outside_input=auditory_outside_input, v_outside_input=visual_outside_input, m_outside_input=multisensory_outside_input, auditoryfilter_input=auditoryfilter_input, visualfilter_input=visualfilter_input, multisensoryfilter_input=multisensoryfilter_input, t=time, a_external_input=auditory_stimuli[i], v_external_input=visual_stimuli[i], m_external_input=multi_input, a_cross_modal_input=auditory_cm_input, v_cross_modal_input=visual_cm_input, a_feedback_input=auditory_feedback_input, v_feedback_input=visual_feedback_input, a_gain=auditory_gain, v_gain=visual_gain, m_gain=multisensory_gain, a_noise=auditory_noise, v_noise=visual_noise, include_noise=noise, include_temporal_noise=temporal_noise, a_temporal_noise=rand_a_tau, v_temporal_noise=rand_v_tau, m_temporal_noise=rand_m_tau, ) # Compute lateral inpunt la = np.sum(auditory_latsynapses.T * auditory_y, axis=1) lv = np.sum(visual_latsynapses.T * visual_y, axis=1) lm = np.sum(multi_latsynapses.T * multi_y, axis=1) # Compute unisensory total input auditory_u = la + auditory_outside_input visual_u = lv + visual_outside_input # Compute multisensory total input u_m = lm + multisensory_outside_input ( auditory_total_inputs[i, :], visual_total_inputs[i, :], multisensory_total_inputs[i, :], ) = ( auditory_u, visual_u, u_m, ) # Compute neurons activity auditory_y, visual_y, multi_y = self._integrator( y_a=auditory_y, y_v=visual_y, y_m=multi_y, t=time, u_a=auditory_u, u_v=visual_u, u_m=u_m, ) auditory_res[i, :], visual_res[i, :], multi_res[i, :] = ( auditory_y, visual_y, multi_y, ) response = { "auditory": auditory_res, "visual": visual_res, "multi": multi_res, } extra = { "auditory_total_input": auditory_total_inputs, "visual_total_input": visual_total_inputs, "multi_total_input": multisensory_total_inputs, "causes_kind": causes_kind, "causes_dim": causes_dim, "causes_peak_threshold": causes_peak_threshold, "causes_peak_distance": causes_peak_distance, "stim_position": [auditory_position, visual_position], } return response, extra
[docs] def calculate_causes( self, multi, causes_kind, causes_dim, causes_peak_threshold, causes_peak_distance, stim_position, **kwargs, ): """ Calculate the causes based on spatiotemporal peaks. This method computes the causes (i.e., the underlying factors or sources) of multisensory activity based on the peaks in the multisensory data. The calculation considers the specified method and dimension for cause determination. Parameters ---------- multi : np.ndarray Multisensory activity data. causes_kind : str Method for calculating causes ("count" or other). causes_dim : str Dimension for calculating causes ("space" or other). causes_peak_threshold : float Peak threshold for causes calculation. stim_position : list of float List containing the positions of the stimuli. **kwargs : keyword arguments Additional arguments for the causes calculation. Returns ------- causes : np.ndarray Calculated causes based on the specified method and parameters. """ # Calculate the average stimuli position position = int(np.mean([stim_position[0], stim_position[1]])) # Calculates the causes in the desired dimension # using the specified method causes = calculate_spatiotemporal_causes_from_peaks( mode_spatiotemporal_activity_data=multi, causes_kind=causes_kind, causes_dim=causes_dim, peak_threshold=causes_peak_threshold, peak_distance=causes_peak_distance, time_point=-1, spatial_point=position, ) # Return the calculated causes return causes