Skip to main content

sc_neurocore_engine/neuron/adex/
simulation.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Commercial license available
3// © Concepts 1996–2026 Miroslav Šotek. All rights reserved.
4// © Code 2020–2026 Miroslav Šotek. All rights reserved.
5// ORCID: 0009-0009-3560-0851
6// Contact: www.anulum.li | protoscience@anulum.li
7// SC-NeuroCore — Atomic AdEx batch simulation
8
9use super::AdExNeuron;
10
11/// Aligned voltage, adaptation, and event traces from one AdEx batch.
12pub type AdExSimulation = (Vec<f64>, Vec<f64>, Vec<u8>);
13
14impl AdExNeuron {
15    /// Return aligned voltage, adaptation, and event traces atomically.
16    ///
17    /// The receiver is committed only after every candidate step succeeds.
18    pub fn simulate_complete(
19        &mut self,
20        n_steps: usize,
21        current: f64,
22    ) -> Result<AdExSimulation, &'static str> {
23        let mut candidate = self.clone();
24        let mut v_trace = Vec::with_capacity(n_steps);
25        let mut w_trace = Vec::with_capacity(n_steps);
26        let mut event_trace = Vec::with_capacity(n_steps);
27        for _ in 0..n_steps {
28            let event = candidate.try_step(current)?;
29            v_trace.push(candidate.v);
30            w_trace.push(candidate.w);
31            event_trace.push(u8::try_from(event).map_err(|_| "invalid AdEx event value")?);
32        }
33        self.v = candidate.v;
34        self.w = candidate.w;
35        Ok((v_trace, w_trace, event_trace))
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::AdExNeuron;
42
43    #[test]
44    fn complete_batch_is_full_parameter_and_failure_atomic() {
45        let mut neuron = AdExNeuron {
46            v: -60.0,
47            w: 3.0,
48            v_rest: -64.0,
49            v_reset: -69.0,
50            v_threshold: -49.0,
51            v_rh: -54.0,
52            delta_t: 2.5,
53            tau: 18.0,
54            tau_w: 120.0,
55            a: 0.7,
56            b: 8.0,
57            c_m: 180.0,
58            dt: 0.2,
59        };
60        let (v_trace, w_trace, events) = neuron
61            .simulate_complete(250, 410.0)
62            .expect("finite configured AdEx trajectory");
63        assert_eq!(
64            (v_trace.len(), w_trace.len(), events.len()),
65            (250, 250, 250)
66        );
67        assert_eq!(
68            events
69                .iter()
70                .map(|event| usize::from(*event))
71                .sum::<usize>(),
72            5
73        );
74        assert_eq!((neuron.v, neuron.w), (v_trace[249], w_trace[249]));
75
76        let mut rejected = AdExNeuron::new();
77        rejected.dt = 1.0e308;
78        let before = (rejected.v, rejected.w);
79        assert!(rejected.simulate_complete(2, 1.0e308).is_err());
80        assert_eq!((rejected.v, rejected.w), before);
81    }
82}