sc_neurocore_engine/neurons/simple_spiking/
lnm.rs1#[derive(Clone, Debug)]
13pub struct LearnableNeuronModel {
14 pub v: f64,
15 pub alpha: f64,
16 pub beta: f64,
17 pub gamma: f64,
18 pub v_threshold: f64,
19 pub f_slope: f64,
20 pub f_shift: f64,
21}
22
23impl LearnableNeuronModel {
24 pub fn new() -> Self {
25 Self {
26 v: 0.0,
27 alpha: 0.9,
28 beta: 0.1,
29 gamma: 0.05,
30 v_threshold: 1.0,
31 f_slope: 5.0,
32 f_shift: 0.5,
33 }
34 }
35 pub fn step(&mut self, current: f64) -> i32 {
36 let f_v = 1.0 / (1.0 + (-(self.f_slope * (self.v - self.f_shift))).exp());
37 self.v = self.alpha * self.v + self.beta * current + self.gamma * f_v;
38 if self.v >= self.v_threshold {
39 self.v = 0.0;
40 1
41 } else {
42 0
43 }
44 }
45 pub fn reset(&mut self) {
46 self.v = 0.0;
47 }
48}
49impl Default for LearnableNeuronModel {
50 fn default() -> Self {
51 Self::new()
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58
59 #[test]
60 fn default_matches_constructor_state() {
61 let default = LearnableNeuronModel::default();
62 let constructed = LearnableNeuronModel::new();
63 assert_eq!(default.v, constructed.v);
64 }
65
66 #[test]
67 fn lnm_fires() {
68 let mut n = LearnableNeuronModel::new();
69 let t: i32 = (0..50).map(|_| n.step(2.0)).sum();
70 assert!(t > 0);
71 }
72
73 #[test]
74 fn lnm_reset_clears_state() {
75 let mut n = LearnableNeuronModel::new();
76 for _ in 0..50 {
77 n.step(2.0);
78 }
79 n.reset();
80 assert!((n.v - 0.0).abs() < 1e-10);
81 }
82
83 #[test]
84 fn lnm_bounded() {
85 let mut n = LearnableNeuronModel::new();
86 for _ in 0..1000 {
87 n.step(100.0);
88 }
89 assert!(n.v.is_finite());
90 }
91
92 #[test]
93 fn lnm_nan_no_panic() {
94 LearnableNeuronModel::new().step(f64::NAN);
95 }
96}