sc_neurocore_engine/bindings/
escape_rate.rs1use numpy::{IntoPyArray, PyArray1};
12use pyo3::exceptions::PyValueError;
13use pyo3::prelude::*;
14use pyo3::types::PyDict;
15
16use crate::neurons;
17
18pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
20 module.add_class::<PyEscapeRateNeuron>()?;
21 module.add_function(wrap_pyfunction!(py_escape_rate_simulate, module)?)?;
22 Ok(())
23}
24
25#[pyclass(
27 name = "EscapeRateNeuron",
28 module = "sc_neurocore_engine.sc_neurocore_engine"
29)]
30#[derive(Clone)]
31pub struct PyEscapeRateNeuron {
32 inner: neurons::EscapeRateNeuron,
33}
34
35#[pymethods]
36impl PyEscapeRateNeuron {
37 #[new]
38 #[pyo3(signature = (seed=0xACE1))]
39 fn new(seed: u16) -> Self {
40 Self {
41 inner: neurons::EscapeRateNeuron::new(u64::from(seed)),
42 }
43 }
44 fn step(&mut self, current: f64) -> i32 {
45 self.inner.step(current)
46 }
47 fn reset(&mut self) {
48 self.inner.reset();
49 }
50 fn get_state(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
51 let d = PyDict::new(py);
52 d.set_item("v", self.inner.v)?;
53 d.set_item("rng_state", self.inner.rng_state)?;
54 d.set_item("initial_seed", self.inner.initial_seed)?;
55 Ok(d.into_any().unbind())
56 }
57}
58
59#[pyfunction]
61#[pyo3(signature = (
62 v0, v_rest, v_reset, v_threshold, tau_m, rho_0, delta_u, resistance,
63 dt, rng_state, n_steps, current
64))]
65#[allow(clippy::too_many_arguments, clippy::type_complexity)]
66fn py_escape_rate_simulate<'py>(
67 py: Python<'py>,
68 v0: f64,
69 v_rest: f64,
70 v_reset: f64,
71 v_threshold: f64,
72 tau_m: f64,
73 rho_0: f64,
74 delta_u: f64,
75 resistance: f64,
76 dt: f64,
77 rng_state: u16,
78 n_steps: usize,
79 current: f64,
80) -> PyResult<(
81 Bound<'py, PyArray1<f64>>,
82 Bound<'py, PyArray1<u8>>,
83 f64,
84 u16,
85)> {
86 let mut neuron = crate::neurons::EscapeRateNeuron {
87 v: v0,
88 v_rest,
89 v_reset,
90 v_threshold,
91 tau_m,
92 rho_0,
93 delta_u,
94 resistance,
95 dt,
96 rng_state,
97 initial_seed: rng_state,
98 };
99 if !neuron.valid() || !current.is_finite() {
100 return Err(PyValueError::new_err(
101 "invalid EscapeRate simulation state or input",
102 ));
103 }
104 let mut trace = Vec::with_capacity(n_steps);
105 let mut events = Vec::with_capacity(n_steps);
106 for _ in 0..n_steps {
107 let spike = neuron.try_step(current).map_err(PyValueError::new_err)?;
108 trace.push(neuron.v);
109 events.push(spike as u8);
110 }
111 Ok((
112 trace.into_pyarray(py),
113 events.into_pyarray(py),
114 neuron.v,
115 neuron.rng_state,
116 ))
117}