Skip to main content

sc_neurocore_engine/bindings/rate/
compte_wm.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 — Compte pyramidal-cell PyO3 binding
8
9//! Python boundary for the complete Compte cell and channel state.
10
11use pyo3::exceptions::PyValueError;
12use pyo3::prelude::*;
13use pyo3::types::PyDict;
14
15use crate::neurons;
16
17/// PyO3 owner for one configured Compte pyramidal cell.
18#[pyclass(
19    name = "CompteWMNeuron",
20    module = "sc_neurocore_engine.sc_neurocore_engine"
21)]
22#[derive(Clone)]
23pub struct PyCompteWMNeuron {
24    inner: neurons::CompteWMNeuron,
25}
26
27#[pymethods]
28impl PyCompteWMNeuron {
29    /// Construct a configured cell; omitted arguments use source defaults.
30    #[new]
31    #[pyo3(signature = (
32        v=-70.0, s_ampa=0.0, s_nmda=0.0, x_nmda=0.0, s_gaba=0.0,
33        ref_remaining=0.0, g_l=0.025, g_ampa=0.0031, g_nmda=0.000381,
34        g_gaba=0.001336, e_l=-70.0, e_exc=0.0, e_inh=-70.0, c_m=0.5,
35        mg=1.0, tau_ampa=2.0, tau_nmda=100.0, tau_x=2.0, tau_gaba=10.0,
36        alpha_nmda=0.5, v_threshold=-50.0, v_reset=-60.0, tau_ref=2.0,
37        dt=0.02
38    ))]
39    #[allow(clippy::too_many_arguments)]
40    fn new(
41        v: f64,
42        s_ampa: f64,
43        s_nmda: f64,
44        x_nmda: f64,
45        s_gaba: f64,
46        ref_remaining: f64,
47        g_l: f64,
48        g_ampa: f64,
49        g_nmda: f64,
50        g_gaba: f64,
51        e_l: f64,
52        e_exc: f64,
53        e_inh: f64,
54        c_m: f64,
55        mg: f64,
56        tau_ampa: f64,
57        tau_nmda: f64,
58        tau_x: f64,
59        tau_gaba: f64,
60        alpha_nmda: f64,
61        v_threshold: f64,
62        v_reset: f64,
63        tau_ref: f64,
64        dt: f64,
65    ) -> PyResult<Self> {
66        let inner = neurons::CompteWMNeuron {
67            v,
68            s_ampa,
69            s_nmda,
70            x_nmda,
71            s_gaba,
72            ref_remaining,
73            g_l,
74            g_ampa,
75            g_nmda,
76            g_gaba,
77            e_l,
78            e_exc,
79            e_inh,
80            c_m,
81            mg,
82            tau_ampa,
83            tau_nmda,
84            tau_x,
85            tau_gaba,
86            alpha_nmda,
87            v_threshold,
88            v_reset,
89            tau_ref,
90            dt,
91        };
92        if !inner.validate() {
93            return Err(PyValueError::new_err(
94                "invalid Compte state or configuration",
95            ));
96        }
97        Ok(Self { inner })
98    }
99
100    /// Advance one atomic source-level step.
101    #[pyo3(signature = (
102        current, recurrent_event=false, external_event=false, inhibitory_event=false
103    ))]
104    fn step(
105        &mut self,
106        current: f64,
107        recurrent_event: bool,
108        external_event: bool,
109        inhibitory_event: bool,
110    ) -> PyResult<i32> {
111        self.inner
112            .step_events(current, recurrent_event, external_event, inhibitory_event)
113            .map_err(PyValueError::new_err)
114    }
115
116    /// Reset dynamic state while retaining configuration.
117    fn reset(&mut self) {
118        self.inner.reset();
119    }
120
121    /// Return the complete named dynamic state.
122    fn get_state(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
123        let d = PyDict::new(py);
124        let values = self.inner.get_state();
125        for (name, value) in ["v", "s_ampa", "s_nmda", "x_nmda", "s_gaba", "ref_remaining"]
126            .into_iter()
127            .zip(values)
128        {
129            d.set_item(name, value)?;
130        }
131        Ok(d.into_any().unbind())
132    }
133}
134
135pub(super) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
136    module.add_class::<PyCompteWMNeuron>()?;
137    Ok(())
138}