sc_neurocore_engine/bindings/trivial/
mat.rs1use numpy::{IntoPyArray, PyReadonlyArray1};
10use pyo3::exceptions::PyValueError;
11use pyo3::prelude::*;
12use pyo3::types::PyDict;
13
14use crate::neurons;
15
16#[pyclass(name = "MATNeuron", module = "sc_neurocore_engine.sc_neurocore_engine")]
18#[derive(Clone)]
19pub struct PyMATNeuron {
20 inner: neurons::MATNeuron,
21}
22
23#[pymethods]
24impl PyMATNeuron {
25 #[new]
27 #[pyo3(signature = (
28 v=0.0, theta1=0.0, theta2=0.0, refractory_remaining=0.0,
29 omega=19.0, tau_m=5.0, tau_1=10.0, tau_2=200.0,
30 alpha_1=37.0, alpha_2=2.0, resistance=50.0,
31 refractory_period=2.0, dt=0.001
32 ))]
33 #[allow(clippy::too_many_arguments)]
34 fn new(
35 v: f64,
36 theta1: f64,
37 theta2: f64,
38 refractory_remaining: f64,
39 omega: f64,
40 tau_m: f64,
41 tau_1: f64,
42 tau_2: f64,
43 alpha_1: f64,
44 alpha_2: f64,
45 resistance: f64,
46 refractory_period: f64,
47 dt: f64,
48 ) -> PyResult<Self> {
49 let inner = neurons::MATNeuron {
50 v,
51 theta1,
52 theta2,
53 refractory_remaining,
54 omega,
55 tau_m,
56 tau_1,
57 tau_2,
58 alpha_1,
59 alpha_2,
60 resistance,
61 refractory_period,
62 dt,
63 };
64 if !inner.validate() {
65 return Err(PyValueError::new_err("invalid MAT state or configuration"));
66 }
67 Ok(Self { inner })
68 }
69
70 fn step(&mut self, current: f64) -> PyResult<i32> {
72 self.inner.try_step(current).map_err(PyValueError::new_err)
73 }
74
75 fn reset(&mut self) {
77 self.inner.reset();
78 }
79
80 fn get_state(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
82 let state = PyDict::new(py);
83 state.set_item("v", self.inner.v)?;
84 state.set_item("theta1", self.inner.theta1)?;
85 state.set_item("theta2", self.inner.theta2)?;
86 state.set_item("refractory_remaining", self.inner.refractory_remaining)?;
87 Ok(state.into_any().unbind())
88 }
89}
90
91#[pyfunction]
93#[allow(clippy::too_many_arguments)]
94#[pyo3(signature = (
95 v, theta1, theta2, refractory_remaining, omega, tau_m, tau_1, tau_2,
96 alpha_1, alpha_2, resistance, refractory_period, dt, currents
97))]
98fn py_mat_simulate<'py>(
99 py: Python<'py>,
100 v: f64,
101 theta1: f64,
102 theta2: f64,
103 refractory_remaining: f64,
104 omega: f64,
105 tau_m: f64,
106 tau_1: f64,
107 tau_2: f64,
108 alpha_1: f64,
109 alpha_2: f64,
110 resistance: f64,
111 refractory_period: f64,
112 dt: f64,
113 currents: PyReadonlyArray1<'py, f64>,
114) -> PyResult<Py<PyAny>> {
115 let mut neuron = neurons::MATNeuron {
116 v,
117 theta1,
118 theta2,
119 refractory_remaining,
120 omega,
121 tau_m,
122 tau_1,
123 tau_2,
124 alpha_1,
125 alpha_2,
126 resistance,
127 refractory_period,
128 dt,
129 };
130 if !neuron.validate() {
131 return Err(PyValueError::new_err("invalid MAT state or configuration"));
132 }
133 let inputs = currents.as_slice()?;
134 let mut voltages = Vec::with_capacity(inputs.len());
135 let mut theta1_trace = Vec::with_capacity(inputs.len());
136 let mut theta2_trace = Vec::with_capacity(inputs.len());
137 let mut refractory_trace = Vec::with_capacity(inputs.len());
138 let mut events = Vec::with_capacity(inputs.len());
139 for ¤t in inputs {
140 events.push(neuron.try_step(current).map_err(PyValueError::new_err)?);
141 voltages.push(neuron.v);
142 theta1_trace.push(neuron.theta1);
143 theta2_trace.push(neuron.theta2);
144 refractory_trace.push(neuron.refractory_remaining);
145 }
146 let result = PyDict::new(py);
147 result.set_item("voltages", voltages.into_pyarray(py))?;
148 result.set_item("theta1", theta1_trace.into_pyarray(py))?;
149 result.set_item("theta2", theta2_trace.into_pyarray(py))?;
150 result.set_item("refractory", refractory_trace.into_pyarray(py))?;
151 result.set_item("events", events.into_pyarray(py))?;
152 result.set_item("v_final", neuron.v)?;
153 result.set_item("theta1_final", neuron.theta1)?;
154 result.set_item("theta2_final", neuron.theta2)?;
155 result.set_item("refractory_final", neuron.refractory_remaining)?;
156 Ok(result.into_any().unbind())
157}
158
159pub(super) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
161 module.add_class::<PyMATNeuron>()?;
162 module.add_function(wrap_pyfunction!(py_mat_simulate, module)?)?;
163 Ok(())
164}