sc_neurocore_engine/bindings/
exp_if.rs1use numpy::{IntoPyArray, PyArray1};
12use pyo3::exceptions::PyFloatingPointError;
13use pyo3::prelude::*;
14use pyo3::types::PyDict;
15
16use crate::neuron;
17
18pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
20 module.add_class::<PyExpIFNeuron>()?;
21 module.add_function(wrap_pyfunction!(expif_simulate_complete, module)?)?;
22 Ok(())
23}
24
25type CompleteTracePacket<'py> = (
26 Bound<'py, PyArray1<f64>>,
27 Bound<'py, PyArray1<f64>>,
28 Bound<'py, PyArray1<u8>>,
29 f64,
30 f64,
31);
32
33#[pyfunction]
35#[pyo3(signature = (
36 v, v_rest, v_reset, v_threshold, v_rh, delta_t, tau, dt,
37 refractory_period, refractory_remaining, source_profile, n_steps, current
38))]
39#[allow(clippy::too_many_arguments)]
40fn expif_simulate_complete<'py>(
41 py: Python<'py>,
42 v: f64,
43 v_rest: f64,
44 v_reset: f64,
45 v_threshold: f64,
46 v_rh: f64,
47 delta_t: f64,
48 tau: f64,
49 dt: f64,
50 refractory_period: f64,
51 refractory_remaining: f64,
52 source_profile: bool,
53 n_steps: usize,
54 current: f64,
55) -> PyResult<CompleteTracePacket<'py>> {
56 let mut model = neuron::ExpIfNeuron {
57 v,
58 v_rest,
59 v_reset,
60 v_threshold,
61 v_rh,
62 delta_t,
63 tau,
64 dt,
65 refractory_period,
66 refractory_remaining,
67 source_profile,
68 inv_delta_t: 1.0 / delta_t,
69 dt_div_tau: dt / tau,
70 };
71 let (voltage, refractory, events) =
72 model.simulate_complete(n_steps, current).map_err(|error| {
73 PyFloatingPointError::new_err(format!("ExpIF batch rejected: {error:?}"))
74 })?;
75 Ok((
76 voltage.into_pyarray(py),
77 refractory.into_pyarray(py),
78 events.into_pyarray(py),
79 model.v,
80 model.refractory_remaining,
81 ))
82}
83
84pub(crate) fn register_legacy_alias(module: &Bound<'_, PyModule>) -> PyResult<()> {
86 module.add_class::<PyExpIfNeuron>()?;
87 Ok(())
88}
89
90#[pyclass(
91 name = "ExpIFNeuron",
92 module = "sc_neurocore_engine.sc_neurocore_engine"
93)]
94#[derive(Clone)]
95pub struct PyExpIFNeuron {
96 inner: neuron::ExpIfNeuron,
97}
98
99#[pymethods]
100impl PyExpIFNeuron {
101 #[new]
102 fn new() -> Self {
103 Self {
104 inner: neuron::ExpIfNeuron::new(),
105 }
106 }
107
108 fn step(&mut self, current: f64) -> i32 {
109 self.inner.step(current)
110 }
111
112 fn reset(&mut self) {
113 self.inner.reset();
114 }
115
116 fn get_state(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
117 let d = PyDict::new(py);
118 d.set_item("v", self.inner.v)?;
119 d.set_item("refractory_remaining", self.inner.refractory_remaining)?;
120 Ok(d.into_any().unbind())
121 }
122}
123
124#[pyclass(
125 name = "ExpIfNeuron",
126 module = "sc_neurocore_engine.sc_neurocore_engine"
127)]
128#[derive(Clone)]
129pub struct PyExpIfNeuron {
130 inner: neuron::ExpIfNeuron,
131}
132
133#[pymethods]
134impl PyExpIfNeuron {
135 #[new]
136 fn new() -> Self {
137 Self {
138 inner: neuron::ExpIfNeuron::new(),
139 }
140 }
141 fn step(&mut self, current: f64) -> i32 {
142 self.inner.step(current)
143 }
144 fn reset(&mut self) {
145 self.inner.reset();
146 }
147 fn get_state(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
148 let d = PyDict::new(py);
149 d.set_item("v", self.inner.v)?;
150 d.set_item("refractory_remaining", self.inner.refractory_remaining)?;
151 Ok(d.into_any().unbind())
152 }
153}