Skip to main content

sc_neurocore_engine/neurons/rate/
parallel_spiking.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 — Parallel spiking neuron model
8
9/// Parallel Spiking Neuron — convolution-based filter. Fang et al. 2023.
10#[derive(Clone, Debug)]
11pub struct ParallelSpikingNeuron {
12    pub kernel: Vec<f64>,
13    pub buffer: Vec<f64>,
14    pub v_threshold: f64,
15    ptr: usize,
16}
17
18impl ParallelSpikingNeuron {
19    pub fn new(kernel_size: usize, v_threshold: f64) -> Self {
20        let k = 1.0 / kernel_size as f64;
21        Self {
22            kernel: vec![k; kernel_size],
23            buffer: vec![0.0; kernel_size],
24            v_threshold,
25            ptr: 0,
26        }
27    }
28    pub fn step(&mut self, current: f64) -> i32 {
29        let ks = self.buffer.len();
30        self.buffer[self.ptr % ks] = current;
31        self.ptr += 1;
32        let n = self.ptr.min(ks);
33        let score: f64 = self.kernel[..n]
34            .iter()
35            .zip(self.buffer[..n].iter())
36            .map(|(&w, &b)| w * b)
37            .sum();
38        if score >= self.v_threshold {
39            self.buffer.fill(0.0);
40            1
41        } else {
42            0
43        }
44    }
45    pub fn reset(&mut self) {
46        self.buffer.fill(0.0);
47        self.ptr = 0;
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn psn_fires() {
57        let mut n = ParallelSpikingNeuron::new(4, 0.5);
58        let t: i32 = (0..20).map(|_| n.step(1.0)).sum();
59        assert!(t > 0);
60    }
61
62    #[test]
63    fn psn_reset() {
64        let mut n = ParallelSpikingNeuron::new(4, 0.5);
65        for _ in 0..20 {
66            n.step(1.0);
67        }
68        n.reset();
69    }
70
71    #[test]
72    fn psn_nan_no_panic() {
73        ParallelSpikingNeuron::new(4, 0.5).step(f64::NAN);
74    }
75}