sc_neurocore_engine/bindings/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-map PyO3 binding
8
9//! Python binding for the Cazelles-Courbage-Rabinovich bursting map.
10
11use numpy::{IntoPyArray, PyArray1};
12use pyo3::prelude::*;
13use pyo3::types::PyDict;
14
15use crate::neurons::CazellesMapNeuron;
16
17py_neuron_default!("CazellesMapNeuron", PyCazellesMapNeuron, CazellesMapNeuron, state x, state y);
18
19/// Register the Cazelles-map class and simulator with the extension module.
20pub(super) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
21 module.add_class::<PyCazellesMapNeuron>()?;
22 module.add_function(wrap_pyfunction!(py_cazelles_map_simulate, module)?)?;
23 Ok(())
24}
25
26/// N-step Cazelles-Courbage-Rabinovich (2001) bursting-map simulation.
27///
28/// Parity contract with `sc_neurocore.neurons.models.cazelles_map.CazellesMapNeuron.simulate`:
29/// for the same parameters and constant input the returned `x` trace, spike
30/// count, and final `(x, y)` state are bit-identical to the Python reference
31/// (the map is exact floating-point arithmetic, no transcendental functions).
32#[pyfunction]
33#[pyo3(signature = (x0, y0, a, epsilon, sigma, x_threshold, n_steps, current))]
34#[allow(clippy::too_many_arguments)]
35fn py_cazelles_map_simulate<'py>(
36 py: Python<'py>,
37 x0: f64,
38 y0: f64,
39 a: f64,
40 epsilon: f64,
41 sigma: f64,
42 x_threshold: f64,
43 n_steps: usize,
44 current: f64,
45) -> (Bound<'py, PyArray1<f64>>, i64, f64, f64) {
46 let mut neuron = CazellesMapNeuron {
47 x: x0,
48 y: y0,
49 a,
50 epsilon,
51 sigma,
52 x_threshold,
53 };
54 let (trace, spikes) = neuron.simulate(n_steps, current);
55 // Return the trace as a NumPy array directly; marshalling a multi-million
56 // element Vec<f64> into a Python list would dominate the wall-clock.
57 (trace.into_pyarray(py), spikes, neuron.x, neuron.y)
58}