Skip to main content

sc_neurocore_engine/bindings/biophysical/
mainen_sejnowski.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 — Mainen-Sejnowski neuron PyO3 binding
8
9use pyo3::exceptions::PyValueError;
10use pyo3::prelude::*;
11use pyo3::types::PyDict;
12
13use crate::neurons;
14
15#[pyclass(
16    name = "MainenSejnowskiNeuron",
17    module = "sc_neurocore_engine.sc_neurocore_engine"
18)]
19#[derive(Clone)]
20pub struct PyMainenSejnowskiNeuron {
21    inner: neurons::MainenSejnowskiNeuron,
22}
23
24#[pymethods]
25impl PyMainenSejnowskiNeuron {
26    #[new]
27    fn new() -> Self {
28        Self {
29            inner: neurons::MainenSejnowskiNeuron::default(),
30        }
31    }
32
33    /// Reconstruct the original engine configuration (Gauss-Seidel
34    /// compartment ordering with the historical rate handling) without
35    /// adding a second catalogue identity.
36    #[staticmethod]
37    fn legacy_sequential() -> Self {
38        Self {
39            inner: neurons::MainenSejnowskiNeuron::new_legacy_sequential(),
40        }
41    }
42
43    /// Advance one step; raises `ValueError` with the state unchanged for
44    /// a non-finite drive, an invalid configuration, or a non-finite
45    /// candidate.
46    fn step(&mut self, current: f64) -> PyResult<i32> {
47        self.inner.try_step(current).map_err(PyValueError::new_err)
48    }
49
50    /// Restore dynamic state to the initial values, preserving parameters.
51    fn reset(&mut self) {
52        self.inner.reset();
53    }
54
55    /// Return the complete dynamic state as a Python dictionary.
56    fn get_state(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
57        let state = PyDict::new(py);
58        state.set_item("vs", self.inner.vs)?;
59        state.set_item("va", self.inner.va)?;
60        state.set_item("m", self.inner.m)?;
61        state.set_item("h", self.inner.h)?;
62        state.set_item("n", self.inner.n)?;
63        Ok(state.into_any().unbind())
64    }
65}
66
67/// Register the Mainen-Sejnowski neuron class.
68pub(super) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
69    module.add_class::<PyMainenSejnowskiNeuron>()?;
70    Ok(())
71}