Skip to main content

sc_neurocore_engine/bindings/
fitzhugh_nagumo.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 — FitzHugh-Nagumo PyO3 binding
8
9//! Python binding for the FitzHugh-Nagumo two-state excitable-system model.
10
11use numpy::{IntoPyArray, PyArray1};
12use pyo3::prelude::*;
13use pyo3::types::PyDict;
14
15use crate::neurons::FitzHughNagumoNeuron;
16
17py_neuron_default!("FitzHughNagumoNeuron", PyFitzHughNagumoNeuron, FitzHughNagumoNeuron, state v, state w);
18
19/// Register the FitzHugh-Nagumo class and batch simulator.
20pub(super) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
21    module.add_class::<PyFitzHughNagumoNeuron>()?;
22    module.add_function(wrap_pyfunction!(py_fitzhugh_nagumo_simulate, module)?)?;
23    Ok(())
24}
25
26/// Parity contract with
27/// `sc_neurocore.neurons.models.fitzhugh_nagumo.FitzHughNagumoNeuron.simulate`:
28/// for the same parameters and constant input the returned `v` trace, upward-
29/// crossing spike count, and final `(v, w)` state are bit-identical to the
30/// Python RK4 reference (the right-hand side is exact arithmetic — a cube
31/// `v.powi(3)` = `v*v*v`, additions and multiplications, no transcendental
32/// functions — and a two-dimensional flow cannot be chaotic).
33#[pyfunction]
34#[pyo3(signature = (v0, w0, a, b, epsilon, dt, v_threshold, n_steps, current))]
35#[allow(clippy::too_many_arguments)]
36fn py_fitzhugh_nagumo_simulate<'py>(
37    py: Python<'py>,
38    v0: f64,
39    w0: f64,
40    a: f64,
41    b: f64,
42    epsilon: f64,
43    dt: f64,
44    v_threshold: f64,
45    n_steps: usize,
46    current: f64,
47) -> (Bound<'py, PyArray1<f64>>, i64, f64, f64) {
48    let mut neuron = FitzHughNagumoNeuron {
49        v: v0,
50        w: w0,
51        a,
52        b,
53        epsilon,
54        dt,
55        v_threshold,
56    };
57    let (trace, spikes) = neuron.simulate(n_steps, current);
58    (trace.into_pyarray(py), spikes, neuron.v, neuron.w)
59}