sc_neurocore_engine/neurons/trivial/
sigma_delta.rs1const STATE_LIMIT: f64 = 1.0e12;
11
12#[derive(Clone, Debug)]
14pub struct SigmaDeltaNeuron {
15 pub sigma: f64,
17 pub reconstruction: f64,
19 pub delta: f64,
21 pub tau_reconstruction: f64,
23 pub dt: f64,
25}
26
27impl SigmaDeltaNeuron {
28 pub fn new() -> Self {
30 Self {
31 sigma: 0.0,
32 reconstruction: 0.0,
33 delta: 1.0,
34 tau_reconstruction: 10.0,
35 dt: 0.1,
36 }
37 }
38
39 pub fn validate(&self) -> bool {
41 [
42 self.sigma,
43 self.reconstruction,
44 self.delta,
45 self.tau_reconstruction,
46 self.dt,
47 ]
48 .iter()
49 .all(|value| value.is_finite())
50 && self.sigma.abs() <= STATE_LIMIT
51 && self.reconstruction.abs() <= STATE_LIMIT
52 && self.delta > 0.0
53 && self.tau_reconstruction > 0.0
54 && self.dt > 0.0
55 }
56
57 pub fn try_step(&mut self, current: f64) -> Result<i32, &'static str> {
59 if !current.is_finite() || !self.validate() {
60 return Err("invalid SigmaDelta state, configuration, or current");
61 }
62 let sigma = self.sigma + self.dt * current;
63 let mut reconstruction = self.reconstruction * (-self.dt / self.tau_reconstruction).exp();
64 let spike = sigma - reconstruction >= 0.5 * self.delta;
65 if spike {
66 reconstruction += self.delta;
67 }
68 if !sigma.is_finite()
69 || !reconstruction.is_finite()
70 || sigma.abs() > STATE_LIMIT
71 || reconstruction.abs() > STATE_LIMIT
72 {
73 return Err("SigmaDelta candidate outside safety envelope");
74 }
75 self.sigma = sigma;
76 self.reconstruction = reconstruction;
77 Ok(i32::from(spike))
78 }
79
80 pub fn step(&mut self, current: f64) -> i32 {
82 self.try_step(current).unwrap_or(0)
83 }
84
85 pub fn reset(&mut self) {
87 self.sigma = 0.0;
88 self.reconstruction = 0.0;
89 }
90}
91
92impl Default for SigmaDeltaNeuron {
93 fn default() -> Self {
94 Self::new()
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 #[test]
102 fn source_step_and_atomic_failure() {
103 let mut neuron = SigmaDeltaNeuron {
104 sigma: 0.49,
105 ..SigmaDeltaNeuron::new()
106 };
107 assert_eq!(neuron.try_step(0.2), Ok(1));
108 assert_eq!(neuron.sigma, 0.51);
109 let before = (neuron.sigma, neuron.reconstruction);
110 assert!(neuron.try_step(f64::NAN).is_err());
111 assert_eq!((neuron.sigma, neuron.reconstruction), before);
112 }
113}