Skip to main content

sc_neurocore_engine/bindings/channels/
sk_neuron.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 — SK-channel neuron PyO3 binding
8
9use pyo3::exceptions::PyValueError;
10use pyo3::prelude::*;
11use pyo3::types::PyDict;
12
13use crate::neurons;
14
15#[pyclass(name = "SKNeuron", module = "sc_neurocore_engine.sc_neurocore_engine")]
16#[derive(Clone)]
17pub struct PySKNeuron {
18    inner: neurons::SKNeuron,
19}
20
21#[pymethods]
22impl PySKNeuron {
23    #[new]
24    fn new() -> Self {
25        Self {
26            inner: neurons::SKNeuron::default(),
27        }
28    }
29
30    /// Advance one step; raises `ValueError` with the state unchanged for
31    /// a non-finite drive, an invalid configuration, or a non-finite
32    /// candidate.
33    fn step(&mut self, current: f64) -> PyResult<i32> {
34        self.inner.try_step(current).map_err(PyValueError::new_err)
35    }
36
37    /// Restore dynamic state to the initial values, preserving parameters.
38    fn reset(&mut self) {
39        self.inner.reset();
40    }
41
42    /// Return the complete dynamic state as a Python dictionary.
43    fn get_state(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
44        let state = PyDict::new(py);
45        state.set_item("v", self.inner.v)?;
46        state.set_item("h", self.inner.h)?;
47        state.set_item("n", self.inner.n)?;
48        state.set_item("ca", self.inner.ca)?;
49        Ok(state.into_any().unbind())
50    }
51}
52
53/// Register the SK-channel neuron class.
54pub(super) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
55    module.add_class::<PySKNeuron>()?;
56    Ok(())
57}