Skip to main content

sc_neurocore_engine/bindings/maps/
aihara_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 — source-faithful Aihara PyO3 binding
8
9use numpy::{IntoPyArray, PyReadonlyArray1};
10use pyo3::exceptions::{PyFloatingPointError, PyValueError};
11use pyo3::prelude::*;
12use pyo3::types::PyDict;
13
14use crate::neurons::{self, AiharaMapError};
15
16fn map_error(error: AiharaMapError) -> PyErr {
17    match error {
18        AiharaMapError::NonFiniteCandidate => PyFloatingPointError::new_err(error.to_string()),
19        _ => PyValueError::new_err(error.to_string()),
20    }
21}
22
23#[pyclass(
24    name = "AiharaMapNeuron",
25    module = "sc_neurocore_engine.sc_neurocore_engine"
26)]
27#[derive(Clone)]
28pub struct PyAiharaMapNeuron {
29    inner: neurons::AiharaMapNeuron,
30}
31
32#[pymethods]
33impl PyAiharaMapNeuron {
34    #[new]
35    fn new() -> Self {
36        Self {
37            inner: neurons::AiharaMapNeuron::default(),
38        }
39    }
40
41    fn step(&mut self, current: f64) -> PyResult<i32> {
42        self.inner.try_step(current).map_err(map_error)
43    }
44
45    fn reset(&mut self) {
46        self.inner.reset();
47    }
48
49    fn get_state(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
50        let state = PyDict::new(py);
51        state.set_item("y", self.inner.y)?;
52        state.set_item("x", self.inner.output())?;
53        Ok(state.into_any().unbind())
54    }
55}
56
57/// Register the checked class and complete batch function.
58pub(super) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
59    module.add_class::<PyAiharaMapNeuron>()?;
60    module.add_function(wrap_pyfunction!(py_aihara_map_simulate, module)?)?;
61    Ok(())
62}
63
64#[pyfunction]
65#[pyo3(signature = (y, k, alpha, bias, epsilon, current))]
66fn py_aihara_map_simulate<'py>(
67    py: Python<'py>,
68    y: f64,
69    k: f64,
70    alpha: f64,
71    bias: f64,
72    epsilon: f64,
73    current: PyReadonlyArray1<'py, f64>,
74) -> PyResult<Py<PyAny>> {
75    let result = neurons::simulate_aihara_map(y, k, alpha, bias, epsilon, current.as_slice()?)
76        .map_err(map_error)?;
77    let mapping = PyDict::new(py);
78    mapping.set_item("y", result.y.into_pyarray(py))?;
79    mapping.set_item("x", result.x.into_pyarray(py))?;
80    mapping.set_item("spikes", result.spikes.into_pyarray(py))?;
81    mapping.set_item("y_final", result.y_final)?;
82    mapping.set_item("x_final", result.x_final)?;
83    mapping.set_item("spike_count", result.spike_count)?;
84    Ok(mapping.into_any().unbind())
85}