Skip to main content

sc_neurocore_engine/neurons/trivial/
klif.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 — KLIF Neuron
8
9/// KLIF — learnable LIF with scaling factor k. Eshraghian et al. 2021.
10#[derive(Clone, Debug)]
11pub struct KLIFNeuron {
12    pub v: f64,
13    pub k: f64,
14    pub alpha: f64,
15    pub v_threshold: f64,
16    pub v_reset: f64,
17}
18
19impl KLIFNeuron {
20    pub fn new(tau: f64, k: f64, dt: f64) -> Self {
21        Self {
22            v: 0.0,
23            k,
24            alpha: (-dt / tau).exp(),
25            v_threshold: 1.0,
26            v_reset: 0.0,
27        }
28    }
29
30    pub fn step(&mut self, current: f64) -> i32 {
31        self.v = self.alpha * self.v + self.k * current;
32        if self.v >= self.v_threshold {
33            self.v = self.v_reset;
34            1
35        } else {
36            0
37        }
38    }
39
40    pub fn reset(&mut self) {
41        self.v = 0.0;
42    }
43}
44
45impl Default for KLIFNeuron {
46    fn default() -> Self {
47        Self::new(10.0, 1.0, 1.0)
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn klif_fires() {
57        let mut n = KLIFNeuron::default();
58        let total: i32 = (0..50).map(|_| n.step(0.5)).sum();
59        assert!(total > 0);
60    }
61    #[test]
62    fn klif_silent_without_input() {
63        let mut n = KLIFNeuron::default();
64        let t: i32 = (0..100).map(|_| n.step(0.0)).sum();
65        assert_eq!(t, 0);
66    }
67    #[test]
68    fn klif_reset_clears_state() {
69        let mut n = KLIFNeuron::default();
70        for _ in 0..20 {
71            n.step(0.5);
72        }
73        n.reset();
74        assert!((n.v - 0.0).abs() < 1e-10);
75    }
76    #[test]
77    fn klif_bounded() {
78        let mut n = KLIFNeuron::default();
79        for _ in 0..1000 {
80            n.step(100.0);
81        }
82        assert!(n.v.is_finite());
83    }
84    #[test]
85    fn klif_nan_no_panic() {
86        KLIFNeuron::default().step(f64::NAN);
87    }
88}