sc_neurocore_engine/neurons/trivial/
energy_lif.rs1#[derive(Clone, Debug)]
11pub struct EnergyLIFNeuron {
12 pub v: f64,
13 pub epsilon: f64,
14 pub v_rest: f64,
15 pub v_reset: f64,
16 pub v_threshold: f64,
17 pub tau_m: f64,
18 pub tau_e: f64,
19 pub alpha: f64,
20 pub epsilon_0: f64,
21 pub resistance: f64,
22 pub dt: f64,
23}
24
25impl EnergyLIFNeuron {
26 pub fn new() -> Self {
27 Self {
28 v: -70.0,
29 epsilon: 1.0,
30 v_rest: -70.0,
31 v_reset: -70.0,
32 v_threshold: -50.0,
33 tau_m: 10.0,
34 tau_e: 500.0,
35 alpha: 0.1,
36 epsilon_0: 1.0,
37 resistance: 1.0,
38 dt: 1.0,
39 }
40 }
41
42 pub fn step(&mut self, current: f64) -> i32 {
43 let effective_r = self.resistance * self.epsilon;
44 self.v += (-(self.v - self.v_rest) + effective_r * current) / self.tau_m * self.dt;
45 self.epsilon += (self.epsilon_0 - self.epsilon) / self.tau_e * self.dt;
46 if self.v >= self.v_threshold && self.epsilon > 0.1 {
47 self.v = self.v_reset;
48 self.epsilon -= self.alpha;
49 1
50 } else if self.v >= self.v_threshold {
51 self.v = self.v_threshold;
52 0
53 } else {
54 0
55 }
56 }
57
58 pub fn reset(&mut self) {
59 self.v = self.v_rest;
60 self.epsilon = self.epsilon_0;
61 }
62}
63
64impl Default for EnergyLIFNeuron {
65 fn default() -> Self {
66 Self::new()
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn energy_lif_fires() {
76 let mut n = EnergyLIFNeuron::new();
77 let total: i32 = (0..200).map(|_| n.step(30.0)).sum();
78 assert!(total > 0);
79 }
80 #[test]
81 fn energy_lif_silent_without_input() {
82 let mut n = EnergyLIFNeuron::new();
83 let t: i32 = (0..200).map(|_| n.step(0.0)).sum();
84 assert_eq!(t, 0);
85 }
86 #[test]
87 fn energy_lif_reset_clears_state() {
88 let mut n = EnergyLIFNeuron::new();
89 for _ in 0..100 {
90 n.step(30.0);
91 }
92 n.reset();
93 assert!((n.v - n.v_rest).abs() < 1e-10);
94 }
95 #[test]
96 fn energy_lif_bounded() {
97 let mut n = EnergyLIFNeuron::new();
98 for _ in 0..1000 {
99 n.step(1e4);
100 }
101 assert!(n.v.is_finite());
102 }
103 #[test]
104 fn energy_lif_nan_no_panic() {
105 EnergyLIFNeuron::new().step(f64::NAN);
106 }
107 #[test]
108 fn energy_lif_epsilon_depletes() {
109 let mut n = EnergyLIFNeuron::new();
110 let e0 = n.epsilon;
111 for _ in 0..200 {
112 n.step(30.0);
113 }
114 assert!(n.epsilon < e0, "energy should deplete during spiking");
115 }
116}