sc_neurocore_engine/neurons/trivial/
parametric_lif.rs1#[derive(Clone, Debug)]
11pub struct ParametricLIFNeuron {
12 pub v: f64,
13 pub a: f64,
14 pub threshold: f64,
15}
16
17impl ParametricLIFNeuron {
18 pub fn new(a: f64, threshold: f64) -> Self {
19 Self {
20 v: 0.0,
21 a,
22 threshold,
23 }
24 }
25
26 pub fn step(&mut self, current: f64) -> i32 {
27 let alpha = 1.0 / (1.0 + (-self.a).exp());
28 let spike = if self.v >= self.threshold { 1 } else { 0 };
29 self.v = alpha * self.v * (1.0 - spike as f64) + current;
30 spike
31 }
32
33 pub fn reset(&mut self) {
34 self.v = 0.0;
35 }
36}
37
38impl Default for ParametricLIFNeuron {
39 fn default() -> Self {
40 Self::new(0.0, 1.0)
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 #[test]
49 fn plif_fires() {
50 let mut n = ParametricLIFNeuron::default();
51 let total: i32 = (0..20).map(|_| n.step(1.5)).sum();
52 assert!(total > 0);
53 }
54 #[test]
55 fn plif_silent_without_input() {
56 let mut n = ParametricLIFNeuron::default();
57 let t: i32 = (0..100).map(|_| n.step(0.0)).sum();
58 assert_eq!(t, 0);
59 }
60 #[test]
61 fn plif_reset_clears_state() {
62 let mut n = ParametricLIFNeuron::default();
63 for _ in 0..20 {
64 n.step(1.5);
65 }
66 n.reset();
67 assert!((n.v - 0.0).abs() < 1e-10);
68 }
69 #[test]
70 fn plif_bounded() {
71 let mut n = ParametricLIFNeuron::default();
72 for _ in 0..1000 {
73 n.step(100.0);
74 }
75 assert!(n.v.is_finite());
76 }
77 #[test]
78 fn plif_nan_no_panic() {
79 ParametricLIFNeuron::default().step(f64::NAN);
80 }
81}