sc_neurocore_engine/bindings/
terman_wang.rs1use numpy::{IntoPyArray, PyArray1};
12use pyo3::exceptions::PyFloatingPointError;
13use pyo3::prelude::*;
14use pyo3::types::PyDict;
15
16use crate::neurons::TermanWangOscillator;
17
18type PyTermanWangBatch<'py> = (Bound<'py, PyArray1<f64>>, i64, f64, f64);
19
20py_neuron_default!("TermanWangOscillator", PyTermanWangOscillator, TermanWangOscillator, state v, state w);
21
22pub(super) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
24 module.add_class::<PyTermanWangOscillator>()?;
25 module.add_function(wrap_pyfunction!(py_terman_wang_simulate, module)?)?;
26 Ok(())
27}
28
29#[pyfunction]
41#[pyo3(signature = (v0, w0, alpha, beta, epsilon, rho, dt, v_peak, n_steps, current))]
42#[allow(clippy::too_many_arguments)]
43fn py_terman_wang_simulate<'py>(
44 py: Python<'py>,
45 v0: f64,
46 w0: f64,
47 alpha: f64,
48 beta: f64,
49 epsilon: f64,
50 rho: f64,
51 dt: f64,
52 v_peak: f64,
53 n_steps: usize,
54 current: f64,
55) -> PyResult<PyTermanWangBatch<'py>> {
56 let mut neuron = TermanWangOscillator {
57 v: v0,
58 w: w0,
59 alpha,
60 beta,
61 epsilon,
62 rho,
63 dt,
64 v_peak,
65 };
66 let Some((trace, spikes)) = neuron.try_simulate(n_steps, current) else {
67 return Err(PyFloatingPointError::new_err(
68 "Terman-Wang Rust batch rejected an invalid candidate",
69 ));
70 };
71 Ok((trace.into_pyarray(py), spikes, neuron.v, neuron.w))
72}