#[derive(Clone, Debug)]
pub struct LoihiCUBANeuron {
pub v: i32,
pub u: i32,
pub tau_v: i32,
pub tau_u: i32,
pub v_threshold: i32,
pub v_reset: i32,
}
impl LoihiCUBANeuron {
pub fn new() -> Self {
Self {
v: 0,
u: 0,
tau_v: 10,
tau_u: 5,
v_threshold: 1000,
v_reset: 0,
}
}
pub fn step(&mut self, weighted_input: i32) -> i32 {
self.u = self.u - self.u / self.tau_u + weighted_input;
self.v = self.v - self.v / self.tau_v + self.u;
if self.v >= self.v_threshold {
self.v = self.v_reset;
1
} else {
0
}
}
pub fn reset(&mut self) {
self.v = 0;
self.u = 0;
}
}
impl Default for LoihiCUBANeuron {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct Loihi2Neuron {
pub s1: i32,
pub s2: i32,
pub s3: i32,
pub tau1: i32,
pub tau2: i32,
pub tau3: i32,
pub w12: i32,
pub w13: i32,
pub w23: i32,
pub s1_threshold: i32,
pub s1_reset: i32,
pub s3_incr: i32,
}
impl Loihi2Neuron {
pub fn new() -> Self {
Self {
s1: 0,
s2: 0,
s3: 0,
tau1: 10,
tau2: 5,
tau3: 50,
w12: 1,
w13: 0,
w23: 0,
s1_threshold: 1000,
s1_reset: 0,
s3_incr: 10,
}
}
pub fn step(&mut self, weighted_input: i32) -> i32 {
self.s2 = self.s2 - (self.s2 >> self.tau2.max(1)) + self.w12 * self.s1;
self.s3 = self.s3 - (self.s3 >> self.tau3.max(1)) + self.w13 * self.s1 + self.w23 * self.s2;
self.s1 = self.s1 - (self.s1 >> self.tau1.max(1)) + self.s2 + weighted_input;
if self.s1 >= self.s1_threshold {
self.s1 = self.s1_reset;
self.s3 += self.s3_incr;
1
} else {
0
}
}
pub fn reset(&mut self) {
self.s1 = 0;
self.s2 = 0;
self.s3 = 0;
}
}
impl Default for Loihi2Neuron {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct TrueNorthNeuron {
pub v: i32,
pub leak: i32,
pub threshold: i32,
pub v_reset: i32,
}
impl TrueNorthNeuron {
pub fn new(threshold: i32) -> Self {
Self {
v: 0,
leak: 0,
threshold,
v_reset: 0,
}
}
pub fn step(&mut self, weighted_input: i32) -> i32 {
self.v += weighted_input - self.leak;
if self.v >= self.threshold {
self.v = self.v_reset;
1
} else {
0
}
}
pub fn reset(&mut self) {
self.v = 0;
}
}
impl Default for TrueNorthNeuron {
fn default() -> Self {
Self::new(100)
}
}
#[derive(Clone, Debug)]
pub struct BrainScaleSAdExNeuron {
pub v: f64,
pub w: f64,
pub v_rest: f64,
pub v_reset: f64,
pub v_threshold: f64,
pub delta_t: f64,
pub v_rh: f64,
pub tau: f64,
pub tau_w: f64,
pub a: f64,
pub b: f64,
pub hw_speedup: f64,
pub dt: f64,
}
impl BrainScaleSAdExNeuron {
pub fn new() -> Self {
Self {
v: -65.0,
w: 0.0,
v_rest: -65.0,
v_reset: -68.0,
v_threshold: -50.0,
delta_t: 2.0,
v_rh: -55.0,
tau: 20.0,
tau_w: 100.0,
a: 0.5,
b: 7.0,
hw_speedup: 1000.0,
dt: 0.1,
}
}
pub fn step(&mut self, current: f64) -> i32 {
let exp_arg = ((self.v - self.v_rh) / self.delta_t).clamp(-20.0, 20.0);
let exp_term = self.delta_t * exp_arg.exp();
let dv = (-(self.v - self.v_rest) + exp_term - self.w + current) / self.tau * self.dt;
let dw = (self.a * (self.v - self.v_rest) - self.w) / self.tau_w * self.dt;
self.v += dv;
self.w += dw;
if self.v >= self.v_threshold {
self.v = self.v_reset;
self.w += self.b;
1
} else {
0
}
}
pub fn reset(&mut self) {
self.v = self.v_rest;
self.w = 0.0;
}
}
impl Default for BrainScaleSAdExNeuron {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct SpiNNakerLIFNeuron {
pub v: f64,
pub v_rest: f64,
pub v_reset: f64,
pub v_threshold: f64,
pub tau_m: f64,
pub i_offset: f64,
pub tau_refrac: f64,
pub refrac_count: f64,
pub dt: f64,
}
impl SpiNNakerLIFNeuron {
pub fn new() -> Self {
Self {
v: -70.0,
v_rest: -70.0,
v_reset: -70.0,
v_threshold: -50.0,
tau_m: 20.0,
i_offset: 0.0,
tau_refrac: 2.0,
refrac_count: 0.0,
dt: 1.0,
}
}
pub fn step(&mut self, current: f64) -> i32 {
if self.refrac_count > 0.0 {
self.refrac_count -= self.dt;
return 0;
}
self.v += (-(self.v - self.v_rest) + current + self.i_offset) / self.tau_m * self.dt;
if self.v >= self.v_threshold {
self.v = self.v_reset;
self.refrac_count = self.tau_refrac;
1
} else {
0
}
}
pub fn reset(&mut self) {
self.v = self.v_rest;
self.refrac_count = 0.0;
}
}
impl Default for SpiNNakerLIFNeuron {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct SpiNNaker2Neuron {
pub v: i32,
pub v_rest: i32,
pub v_reset: i32,
pub v_threshold: i32,
pub decay_mult: i32,
pub decay_shift: i32,
pub refrac_steps: i32,
pub refrac_count: i32,
}
impl SpiNNaker2Neuron {
pub fn new() -> Self {
Self {
v: 0,
v_rest: 0,
v_reset: 0,
v_threshold: 1024,
decay_mult: 243,
decay_shift: 8,
refrac_steps: 2,
refrac_count: 0,
}
}
pub fn step(&mut self, current: i32) -> i32 {
if self.refrac_count > 0 {
self.refrac_count -= 1;
return 0;
}
self.v = ((self.v - self.v_rest).wrapping_mul(self.decay_mult) >> self.decay_shift)
+ self.v_rest
+ current;
if self.v >= self.v_threshold {
self.v = self.v_reset;
self.refrac_count = self.refrac_steps;
1
} else {
0
}
}
pub fn reset(&mut self) {
self.v = self.v_rest;
self.refrac_count = 0;
}
}
impl Default for SpiNNaker2Neuron {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct DPINeuron {
pub i_mem: f64,
pub i_threshold: f64,
pub i_reset: f64,
pub i_leak: f64,
pub tau: f64,
pub gain: f64,
pub dt: f64,
}
impl DPINeuron {
pub fn new() -> Self {
Self {
i_mem: 0.0,
i_threshold: 1.0,
i_reset: 0.0,
i_leak: 0.01,
tau: 20.0,
gain: 1.0,
dt: 1.0,
}
}
pub fn step(&mut self, i_syn: f64) -> i32 {
self.i_mem += (-self.i_mem + self.gain * i_syn + self.i_leak) / self.tau * self.dt;
if self.i_mem >= self.i_threshold {
self.i_mem = self.i_reset;
1
} else {
0
}
}
pub fn reset(&mut self) {
self.i_mem = 0.0;
}
}
impl Default for DPINeuron {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct AkidaNeuron {
pub v: i32,
pub threshold: i32,
pub modulation: f64,
pub rank: i32,
pub spiked: bool,
}
impl AkidaNeuron {
pub fn new(threshold: i32) -> Self {
Self {
v: 0,
threshold,
modulation: 0.75,
rank: 0,
spiked: false,
}
}
pub fn step(&mut self, weight: i32) -> i32 {
if self.spiked {
return 0;
}
self.v += (weight as f64 * self.modulation.powi(self.rank)) as i32;
self.rank += 1;
if self.v >= self.threshold {
self.spiked = true;
1
} else {
0
}
}
pub fn reset(&mut self) {
self.v = 0;
self.rank = 0;
self.spiked = false;
}
}
impl Default for AkidaNeuron {
fn default() -> Self {
Self::new(100)
}
}
#[derive(Clone, Debug)]
pub struct NeuroGridNeuron {
pub v_s: f64,
pub v_d: f64,
pub tau_s: f64,
pub tau_d: f64,
pub g_c: f64,
pub delta_t: f64,
pub v_rest: f64,
pub v_threshold: f64,
pub v_peak: f64,
pub v_reset: f64,
pub dt: f64,
}
impl NeuroGridNeuron {
pub fn new() -> Self {
Self {
v_s: -65.0,
v_d: -65.0,
tau_s: 20.0,
tau_d: 50.0,
g_c: 0.5,
delta_t: 2.0,
v_rest: -65.0,
v_threshold: -50.0,
v_peak: 20.0,
v_reset: -65.0,
dt: 0.1,
}
}
pub fn step(&mut self, current: f64) -> i32 {
let dv_d =
(-(self.v_d - self.v_rest) + current - self.g_c * (self.v_d - self.v_s)) / self.tau_d;
self.v_d += dv_d * self.dt;
let exp_arg = ((self.v_s - self.v_threshold) / self.delta_t).min(20.0);
let exp_term = self.delta_t * exp_arg.exp();
let dv_s =
(-(self.v_s - self.v_rest) + exp_term + self.g_c * (self.v_d - self.v_s)) / self.tau_s;
self.v_s += dv_s * self.dt;
if self.v_s >= self.v_peak {
self.v_s = self.v_reset;
1
} else {
0
}
}
pub fn reset(&mut self) {
self.v_s = -65.0;
self.v_d = -65.0;
}
}
impl Default for NeuroGridNeuron {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn loihi_cuba_fires() {
let mut n = LoihiCUBANeuron::new();
let t: i32 = (0..200).map(|_| n.step(100)).sum();
assert!(t > 0);
}
#[test]
fn loihi2_fires() {
let mut n = Loihi2Neuron {
tau3: 8,
..Loihi2Neuron::new()
};
let t: i32 = (0..500).map(|_| n.step(200)).sum();
assert!(t > 0);
}
#[test]
fn truenorth_fires() {
let mut n = TrueNorthNeuron::default();
let t: i32 = (0..10).map(|_| n.step(50)).sum();
assert!(t > 0);
}
#[test]
fn brainscales_fires() {
let mut n = BrainScaleSAdExNeuron::new();
let t: i32 = (0..2000).map(|_| n.step(500.0)).sum();
assert!(t > 0);
}
#[test]
fn spinnaker_fires() {
let mut n = SpiNNakerLIFNeuron::new();
let t: i32 = (0..200).map(|_| n.step(30.0)).sum();
assert!(t > 0);
}
#[test]
fn spinnaker2_fires() {
let mut n = SpiNNaker2Neuron::new();
let t: i32 = (0..200).map(|_| n.step(100)).sum();
assert!(t > 0);
}
#[test]
fn dpi_fires() {
let mut n = DPINeuron::new();
let t: i32 = (0..100).map(|_| n.step(1.0)).sum();
assert!(t > 0);
}
#[test]
fn akida_fires() {
let mut n = AkidaNeuron::default();
let t: i32 = (0..10).map(|_| n.step(50)).sum();
assert!(t > 0);
}
#[test]
fn neurogrid_fires() {
let mut n = NeuroGridNeuron::new();
let t: i32 = (0..2000).map(|_| n.step(500.0)).sum();
assert!(t > 0);
}
}