Skip to main content

sc_neurocore_engine/neurons/
cazelles_map.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 — Cazelles discrete map neuron
8
9//! Cazelles discrete map neuron.
10
11/// Cazelles logistic map neuron — coupled 2D logistic with slow variable.
12#[derive(Clone, Debug)]
13pub struct CazellesMapNeuron {
14    pub x: f64,
15    pub y: f64,
16    pub a: f64,
17    pub epsilon: f64,
18    pub sigma: f64,
19    pub x_threshold: f64,
20}
21
22impl CazellesMapNeuron {
23    pub fn new() -> Self {
24        Self {
25            x: 0.1,
26            y: 0.0,
27            a: 3.8,
28            epsilon: 0.01,
29            sigma: 0.5,
30            x_threshold: 0.9,
31        }
32    }
33    pub fn step(&mut self, current: f64) -> i32 {
34        let f = self.a * self.x * (1.0 - self.x);
35        let x_new = (f - self.y + current).clamp(-2.0, 2.0);
36        let y_new = self.y + self.epsilon * (self.x - self.sigma);
37        self.x = x_new;
38        self.y = y_new;
39        if self.x >= self.x_threshold {
40            1
41        } else {
42            0
43        }
44    }
45    /// Run `n_steps` under a constant input, returning the `x` trace and the
46    /// spike count. Reuses `step` so the trace is bit-identical to the
47    /// per-step path and to the Python reference. The final state is left in
48    /// `self.x` / `self.y`.
49    pub fn simulate(&mut self, n_steps: usize, current: f64) -> (Vec<f64>, i64) {
50        let mut trace = Vec::with_capacity(n_steps);
51        let mut spikes: i64 = 0;
52        for _ in 0..n_steps {
53            let spiked = self.step(current);
54            trace.push(self.x);
55            spikes += spiked as i64;
56        }
57        (trace, spikes)
58    }
59    pub fn reset(&mut self) {
60        self.x = 0.1;
61        self.y = 0.0;
62    }
63}
64impl Default for CazellesMapNeuron {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn cazelles_fires() {
76        let mut n = CazellesMapNeuron::new();
77        let t: i32 = (0..200).map(|_| n.step(0.0)).sum();
78        assert!(t > 0);
79    }
80}