pub mod analysis;
pub mod connectivity;
pub mod error;
pub mod mean_field;
pub mod network;
pub mod population;
pub mod projection;
pub mod recording;
pub mod stimulation;
pub use error::{NeuralDynamicsError, Result};
pub use network::{Network, NetworkBuilder, NetworkStats, SynapseType};
pub use population::{NeuralPopulation, PopulationStats};
pub use projection::{Connection, DelayInit, Projection, WeightInit, WeightStats};
pub use connectivity::{ConnectionPattern, NetworkStats as ConnectivityStats};
pub use recording::{PopulationRateRecorder, SpikeRecorder, VoltageRecorder};
pub use mean_field::{WilsonCowanModel, PopulationRateModel};
pub use hodgkin_huxley;
pub use synapse_models;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
#[cfg(test)]
mod integration_tests {
use super::*;
use analysis::*;
use connectivity::*;
use stimulation::*;
use approx::assert_relative_eq;
#[test]
fn test_small_network_simulation() {
let mut network = NetworkBuilder::new(0.1)
.unwrap()
.add_excitatory_population("E", 10)
.unwrap()
.with_spike_recording()
.build();
let stim = CurrentInjection::new(10.0, 0.0, 50.0);
network.add_stimulation(0, Box::new(stim)).unwrap();
network.run(50.0).unwrap();
let stats = network.statistics();
assert!(stats.total_spikes > 0);
}
#[test]
fn test_ei_network() {
let mut network = NetworkBuilder::new(0.1)
.unwrap()
.add_excitatory_population("E", 20)
.unwrap()
.add_inhibitory_population("I", 5)
.unwrap()
.connect(
0, 0,
ConnectionPattern::FixedProbability(0.2),
SynapseType::Excitatory,
0.5, 1.0
)
.unwrap()
.connect(
0, 1,
ConnectionPattern::FixedProbability(0.3),
SynapseType::Excitatory,
0.8, 1.0
)
.unwrap()
.connect(
1, 0,
ConnectionPattern::FixedProbability(0.4),
SynapseType::Inhibitory,
1.2, 0.5
)
.unwrap()
.with_spike_recording()
.build();
let stim = CurrentInjection::new(8.0, 0.0, 100.0);
network.add_stimulation(0, Box::new(stim)).unwrap();
network.run(100.0).unwrap();
let recorder = network.spike_recorder.as_ref().unwrap();
assert!(recorder.total_spikes() > 0);
}
#[test]
fn test_synchrony_emergence() {
let mut network = NetworkBuilder::new(0.1)
.unwrap()
.add_excitatory_population("E", 30)
.unwrap()
.connect(
0, 0,
ConnectionPattern::SmallWorld { k: 6, p: 0.1 },
SynapseType::Excitatory,
1.0, 1.0
)
.unwrap()
.with_spike_recording()
.build();
let stim = CurrentInjection::new(6.0, 0.0, 200.0);
network.add_stimulation(0, Box::new(stim)).unwrap();
network.run(200.0).unwrap();
let recorder = network.spike_recorder.as_ref().unwrap();
assert!(recorder.total_spikes() > 50);
}
#[test]
fn test_avalanche_detection_in_network() {
let mut network = NetworkBuilder::new(0.1)
.unwrap()
.add_excitatory_population("E", 50)
.unwrap()
.connect(
0, 0,
ConnectionPattern::FixedProbability(0.08),
SynapseType::Excitatory,
0.8, 1.0
)
.unwrap()
.with_spike_recording()
.build();
let stim = CurrentInjection::new(3.0, 0.0, 500.0);
network.add_stimulation(0, Box::new(stim)).unwrap();
network.run(500.0).unwrap();
let pop = network.get_population(0).unwrap();
let spike_trains: Vec<Vec<f64>> = (0..pop.size)
.map(|i| pop.get_spike_times(i).unwrap().to_vec())
.collect();
let avalanches = detect_avalanches(&spike_trains, 1.0, 2).unwrap();
assert!(!avalanches.is_empty());
}
#[test]
fn test_wilson_cowan_integration() {
let mut model = WilsonCowanModel::balanced_network().unwrap();
model.set_input(1.0, 0.5);
let trace = model.simulate(100.0, 0.1).unwrap();
let final_e = trace.last().unwrap().1;
let final_i = trace.last().unwrap().2;
assert!(final_e > 0.0 && final_e < 1.0);
assert!(final_i > 0.0 && final_i < 1.0);
}
#[test]
fn test_connectivity_patterns() {
let mut rng = rand::thread_rng();
let patterns = vec![
ConnectionPattern::AllToAll,
ConnectionPattern::OneToOne,
ConnectionPattern::FixedProbability(0.3),
ConnectionPattern::FixedNumber(5),
ConnectionPattern::SmallWorld { k: 4, p: 0.2 },
ConnectionPattern::ScaleFree { m: 3 },
ConnectionPattern::Gaussian { sigma: 0.2 },
];
for pattern in patterns {
let connections = pattern.generate(20, 20, &mut rng);
assert!(connections.is_ok());
}
}
#[test]
fn test_population_rate_calculation() {
let spike_trains = vec![
vec![10.0, 20.0, 30.0, 40.0],
vec![15.0, 25.0, 35.0],
vec![12.0, 22.0, 32.0, 42.0],
];
let rate = population_firing_rate(&spike_trains, (0.0, 50.0));
assert!(rate > 60.0 && rate < 90.0);
}
#[test]
fn test_branching_parameter() {
let spike_trains = vec![
vec![1.0, 2.0, 3.0, 4.0, 5.0],
vec![1.5, 2.5, 3.5, 4.5],
vec![2.0, 3.0, 4.0, 5.0],
];
let sigma = branching_parameter(&spike_trains, 0.5).unwrap();
assert!(sigma > 0.0 && sigma < 3.0);
}
#[test]
fn test_kuramoto_synchrony() {
use std::f64::consts::PI;
let phases = vec![0.0; 10];
let r = kuramoto_order_parameter(&phases);
assert_relative_eq!(r, 1.0, epsilon = 1e-10);
let phases: Vec<f64> = (0..10).map(|i| 2.0 * PI * i as f64 / 10.0).collect();
let r = kuramoto_order_parameter(&phases);
assert!(r < 0.3);
}
}