sc_neurocore_engine/bindings/
iqif.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::<PyIntegerQIFNeuron>()?;
21 module.add_function(wrap_pyfunction!(py_iqif_simulate, module)?)?;
22 Ok(())
23}
24
25#[pyclass(
26 name = "IntegerQIFNeuron",
27 module = "sc_neurocore_engine.sc_neurocore_engine"
28)]
29#[derive(Clone)]
30pub struct PyIntegerQIFNeuron {
31 inner: neurons::IntegerQIFNeuron,
32}
33
34#[pymethods]
35impl PyIntegerQIFNeuron {
36 #[new]
37 #[pyo3(signature = (v=128, v_rest=128, v_threshold=200, v_reset=128, a=1, b=1, v_max=255, v_min=0))]
38 #[allow(clippy::too_many_arguments)]
39 fn new(
40 v: i32,
41 v_rest: i32,
42 v_threshold: i32,
43 v_reset: i32,
44 a: i32,
45 b: i32,
46 v_max: i32,
47 v_min: i32,
48 ) -> PyResult<Self> {
49 Ok(Self {
50 inner: neurons::IntegerQIFNeuron::with_parameters(
51 v,
52 v_rest,
53 v_threshold,
54 v_reset,
55 a,
56 b,
57 v_max,
58 v_min,
59 )
60 .map_err(PyValueError::new_err)?,
61 })
62 }
63 fn step(&mut self, current: i32) -> PyResult<i32> {
64 self.inner.try_step(current).map_err(PyValueError::new_err)
65 }
66 fn reset(&mut self) {
67 self.inner.reset();
68 }
69 fn get_state(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
70 let d = PyDict::new(py);
71 d.set_item("v", self.inner.v)?;
72 d.set_item("v_rest", self.inner.v_rest)?;
73 d.set_item("v_threshold", self.inner.v_threshold)?;
74 d.set_item("v_reset", self.inner.v_reset)?;
75 d.set_item("a", self.inner.a)?;
76 d.set_item("b", self.inner.b)?;
77 d.set_item("v_max", self.inner.v_max)?;
78 d.set_item("v_min", self.inner.v_min)?;
79 Ok(d.into_any().unbind())
80 }
81}
82
83#[pyfunction]
85#[pyo3(signature = (v, v_rest, v_threshold, v_reset, a, b, v_max, v_min, n_steps, current))]
86#[allow(clippy::too_many_arguments, clippy::type_complexity)]
87fn py_iqif_simulate<'py>(
88 py: Python<'py>,
89 v: i32,
90 v_rest: i32,
91 v_threshold: i32,
92 v_reset: i32,
93 a: i32,
94 b: i32,
95 v_max: i32,
96 v_min: i32,
97 n_steps: usize,
98 current: i32,
99) -> PyResult<(Bound<'py, PyArray1<i64>>, i64, i64)> {
100 let mut neuron = crate::neurons::IntegerQIFNeuron::with_parameters(
101 v,
102 v_rest,
103 v_threshold,
104 v_reset,
105 a,
106 b,
107 v_max,
108 v_min,
109 )
110 .map_err(PyValueError::new_err)?;
111 let mut trace = Vec::with_capacity(n_steps);
112 let mut spikes = 0_i64;
113 for _ in 0..n_steps {
114 spikes += i64::from(neuron.try_step(current).map_err(PyValueError::new_err)?);
115 trace.push(neuron.v);
116 }
117 Ok((trace.into_pyarray(py), spikes, neuron.v))
118}