Skip to main content

sc_neurocore_engine/bindings/
medvedev_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 — Medvedev map PyO3 binding
8
9//! Python binding for the Medvedev slow-calcium first-return map.
10
11use numpy::{IntoPyArray, PyArray1};
12use pyo3::exceptions::PyFloatingPointError;
13use pyo3::prelude::*;
14use pyo3::types::PyDict;
15
16use crate::neurons::MedvedevMapNeuron;
17
18py_neuron_default!("MedvedevMapNeuron", PyMedvedevMapNeuron, MedvedevMapNeuron, state u);
19
20/// Register the Medvedev map class and simulator with the extension module.
21pub(super) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
22    module.add_class::<PyMedvedevMapNeuron>()?;
23    module.add_function(wrap_pyfunction!(py_medvedev_map_simulate, module)?)?;
24    Ok(())
25}
26
27/// N-step Medvedev (2005) slow-calcium first-return simulation.
28///
29/// The recurrence matches the disclosed Section-4 calibration in
30/// `sc_neurocore.neurons.models.medvedev_map.MedvedevMapNeuron`. The returned
31/// trace records `u` after each map iteration and the event count identifies
32/// pre-step states in the active fast-return region `u <= u_HC`. Non-finite or
33/// topologically invalid inputs fail before a corrupt candidate is committed.
34#[pyfunction]
35#[pyo3(signature = (u0, beta_0, beta_hc, beta_sn, delta, decay_t0, alpha_t0, f_0, f_1, homoclinic_exponent, d, input_gain, n_steps, current))]
36#[allow(clippy::too_many_arguments)]
37fn py_medvedev_map_simulate<'py>(
38    py: Python<'py>,
39    u0: f64,
40    beta_0: f64,
41    beta_hc: f64,
42    beta_sn: f64,
43    delta: f64,
44    decay_t0: f64,
45    alpha_t0: f64,
46    f_0: f64,
47    f_1: f64,
48    homoclinic_exponent: f64,
49    d: f64,
50    input_gain: f64,
51    n_steps: usize,
52    current: f64,
53) -> PyResult<(Bound<'py, PyArray1<f64>>, i64, f64)> {
54    let mut neuron = MedvedevMapNeuron {
55        u: u0,
56        beta_0,
57        beta_hc,
58        beta_sn,
59        delta,
60        decay_t0,
61        alpha_t0,
62        f_0,
63        f_1,
64        homoclinic_exponent,
65        d,
66        input_gain,
67    };
68    let (trace, events) = neuron
69        .simulate(n_steps, current)
70        .map_err(PyFloatingPointError::new_err)?;
71    Ok((trace.into_pyarray(py), events, neuron.u))
72}