1#[derive(Clone, Debug)]
13pub struct LoihiCUBANeuron {
14 pub v: i32,
15 pub u: i32,
16 pub tau_v: i32,
17 pub tau_u: i32,
18 pub v_threshold: i32,
19 pub v_reset: i32,
20}
21
22impl LoihiCUBANeuron {
23 pub fn new() -> Self {
24 Self {
25 v: 0,
26 u: 0,
27 tau_v: 10,
28 tau_u: 5,
29 v_threshold: 1000,
30 v_reset: 0,
31 }
32 }
33 pub fn step(&mut self, weighted_input: i32) -> i32 {
34 self.u = self.u - self.u / self.tau_u + weighted_input;
35 self.v = self.v - self.v / self.tau_v + self.u;
36 if self.v >= self.v_threshold {
37 self.v = self.v_reset;
38 1
39 } else {
40 0
41 }
42 }
43 pub fn reset(&mut self) {
44 self.v = 0;
45 self.u = 0;
46 }
47}
48impl Default for LoihiCUBANeuron {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54#[derive(Clone, Debug)]
56pub struct Loihi2Neuron {
57 pub s1: i32,
58 pub s2: i32,
59 pub s3: i32,
60 pub tau1: i32,
61 pub tau2: i32,
62 pub tau3: i32,
63 pub w12: i32,
64 pub w13: i32,
65 pub w23: i32,
66 pub s1_threshold: i32,
67 pub s1_reset: i32,
68 pub s3_incr: i32,
69}
70
71impl Loihi2Neuron {
72 pub fn new() -> Self {
73 Self {
74 s1: 0,
75 s2: 0,
76 s3: 0,
77 tau1: 10,
78 tau2: 5,
79 tau3: 50,
80 w12: 1,
81 w13: 0,
82 w23: 0,
83 s1_threshold: 1000,
84 s1_reset: 0,
85 s3_incr: 10,
86 }
87 }
88 pub fn step(&mut self, weighted_input: i32) -> i32 {
89 self.s3 -= self.s3 / self.tau3;
90 self.s2 = self.s2 - self.s2 / self.tau2 + weighted_input + self.w23 * self.s3;
91 self.s1 = self.s1 - self.s1 / self.tau1 + self.w12 * self.s2 + self.w13 * self.s3;
92 if self.s1 >= self.s1_threshold {
93 self.s1 = self.s1_reset;
94 self.s3 += self.s3_incr;
95 1
96 } else {
97 0
98 }
99 }
100 pub fn reset(&mut self) {
101 self.s1 = 0;
102 self.s2 = 0;
103 self.s3 = 0;
104 }
105}
106impl Default for Loihi2Neuron {
107 fn default() -> Self {
108 Self::new()
109 }
110}
111
112#[derive(Clone, Debug)]
114pub struct TrueNorthNeuron {
115 pub v: i32,
116 pub leak: i32,
117 pub threshold: i32,
118 pub v_reset: i32,
119}
120
121impl TrueNorthNeuron {
122 pub fn new(threshold: i32) -> Self {
123 Self {
124 v: 0,
125 leak: 0,
126 threshold,
127 v_reset: 0,
128 }
129 }
130 pub fn step(&mut self, weighted_input: i32) -> i32 {
131 self.v += weighted_input - self.leak;
132 if self.v >= self.threshold {
133 self.v = self.v_reset;
134 1
135 } else {
136 0
137 }
138 }
139 pub fn reset(&mut self) {
140 self.v = 0;
141 }
142}
143impl Default for TrueNorthNeuron {
144 fn default() -> Self {
145 Self::new(100)
146 }
147}
148
149#[derive(Clone, Debug)]
151pub struct BrainScaleSAdExNeuron {
152 pub v: f64,
153 pub w: f64,
154 pub v_rest: f64,
155 pub v_reset: f64,
156 pub v_threshold: f64,
157 pub delta_t: f64,
158 pub v_rh: f64,
159 pub tau: f64,
160 pub tau_w: f64,
161 pub a: f64,
162 pub b: f64,
163 pub hw_speedup: f64,
164 pub dt: f64,
165}
166
167impl BrainScaleSAdExNeuron {
168 pub fn new() -> Self {
169 Self {
170 v: -65.0,
171 w: 0.0,
172 v_rest: -65.0,
173 v_reset: -68.0,
174 v_threshold: -50.0,
175 delta_t: 2.0,
176 v_rh: -55.0,
177 tau: 20.0,
178 tau_w: 100.0,
179 a: 0.5,
180 b: 7.0,
181 hw_speedup: 1000.0,
182 dt: 0.1,
183 }
184 }
185 pub fn step(&mut self, current: f64) -> i32 {
186 let exp_arg = ((self.v - self.v_rh) / self.delta_t).clamp(-20.0, 20.0);
187 let exp_term = self.delta_t * exp_arg.exp();
188 let dv = (-(self.v - self.v_rest) + exp_term - self.w + current) / self.tau * self.dt;
189 let dw = (self.a * (self.v - self.v_rest) - self.w) / self.tau_w * self.dt;
190 self.v += dv;
191 self.w += dw;
192 if self.v >= self.v_threshold {
193 self.v = self.v_reset;
194 self.w += self.b;
195 1
196 } else {
197 0
198 }
199 }
200 pub fn reset(&mut self) {
201 self.v = self.v_rest;
202 self.w = 0.0;
203 }
204}
205impl Default for BrainScaleSAdExNeuron {
206 fn default() -> Self {
207 Self::new()
208 }
209}
210
211#[derive(Clone, Debug)]
213pub struct SpiNNakerLIFNeuron {
214 pub v: f64,
215 pub v_rest: f64,
216 pub v_reset: f64,
217 pub v_threshold: f64,
218 pub tau_m: f64,
219 pub i_offset: f64,
220 pub tau_refrac: f64,
221 pub refrac_count: f64,
222 pub dt: f64,
223}
224
225impl SpiNNakerLIFNeuron {
226 pub fn new() -> Self {
227 Self {
228 v: -70.0,
229 v_rest: -70.0,
230 v_reset: -70.0,
231 v_threshold: -50.0,
232 tau_m: 20.0,
233 i_offset: 0.0,
234 tau_refrac: 2.0,
235 refrac_count: 0.0,
236 dt: 1.0,
237 }
238 }
239 pub fn step(&mut self, current: f64) -> i32 {
240 if self.refrac_count > 0.0 {
241 self.refrac_count -= self.dt;
242 return 0;
243 }
244 self.v += (-(self.v - self.v_rest) + current + self.i_offset) / self.tau_m * self.dt;
245 if self.v >= self.v_threshold {
246 self.v = self.v_reset;
247 self.refrac_count = self.tau_refrac;
248 1
249 } else {
250 0
251 }
252 }
253 pub fn reset(&mut self) {
254 self.v = self.v_rest;
255 self.refrac_count = 0.0;
256 }
257}
258impl Default for SpiNNakerLIFNeuron {
259 fn default() -> Self {
260 Self::new()
261 }
262}
263
264#[derive(Clone, Debug)]
266pub struct SpiNNaker2Neuron {
267 pub v: i32,
268 pub v_rest: i32,
269 pub v_reset: i32,
270 pub v_threshold: i32,
271 pub decay_mult: i32,
272 pub decay_shift: i32,
273 pub refrac_steps: i32,
274 pub refrac_count: i32,
275}
276
277impl SpiNNaker2Neuron {
278 pub fn new() -> Self {
279 Self {
280 v: 0,
281 v_rest: 0,
282 v_reset: 0,
283 v_threshold: 1024,
284 decay_mult: 243,
285 decay_shift: 8,
286 refrac_steps: 2,
287 refrac_count: 0,
288 }
289 }
290 pub fn step(&mut self, current: i32) -> i32 {
291 if self.refrac_count > 0 {
292 self.refrac_count -= 1;
293 return 0;
294 }
295 self.v = ((self.v - self.v_rest).wrapping_mul(self.decay_mult) >> self.decay_shift)
296 + self.v_rest
297 + current;
298 if self.v >= self.v_threshold {
299 self.v = self.v_reset;
300 self.refrac_count = self.refrac_steps;
301 1
302 } else {
303 0
304 }
305 }
306 pub fn reset(&mut self) {
307 self.v = self.v_rest;
308 self.refrac_count = 0;
309 }
310}
311impl Default for SpiNNaker2Neuron {
312 fn default() -> Self {
313 Self::new()
314 }
315}
316
317#[derive(Clone, Debug)]
319pub struct DPINeuron {
320 pub i_mem: f64,
321 pub i_threshold: f64,
322 pub i_reset: f64,
323 pub i_leak: f64,
324 pub tau: f64,
325 pub gain: f64,
326 pub dt: f64,
327}
328
329impl DPINeuron {
330 pub fn new() -> Self {
331 Self {
332 i_mem: 0.0,
333 i_threshold: 1.0,
334 i_reset: 0.0,
335 i_leak: 0.01,
336 tau: 20.0,
337 gain: 1.0,
338 dt: 1.0,
339 }
340 }
341 pub fn step(&mut self, i_syn: f64) -> i32 {
342 self.i_mem += (-self.i_mem + self.gain * i_syn + self.i_leak) / self.tau * self.dt;
343 if self.i_mem >= self.i_threshold {
344 self.i_mem = self.i_reset;
345 1
346 } else {
347 0
348 }
349 }
350 pub fn reset(&mut self) {
351 self.i_mem = 0.0;
352 }
353}
354impl Default for DPINeuron {
355 fn default() -> Self {
356 Self::new()
357 }
358}
359
360#[derive(Clone, Debug)]
362pub struct AkidaNeuron {
363 pub v: i32,
364 pub threshold: i32,
365 pub modulation: f64,
366 pub rank: i32,
367 pub spiked: bool,
368}
369
370impl AkidaNeuron {
371 pub fn new(threshold: i32) -> Self {
372 Self {
373 v: 0,
374 threshold,
375 modulation: 0.75,
376 rank: 0,
377 spiked: false,
378 }
379 }
380 pub fn step(&mut self, weight: f64) -> i32 {
381 if self.spiked {
382 return 0;
383 }
384 self.v += (weight * self.modulation.powi(self.rank)) as i32;
385 self.rank += 1;
386 if self.v >= self.threshold {
387 self.spiked = true;
388 1
389 } else {
390 0
391 }
392 }
393 pub fn reset(&mut self) {
394 self.v = 0;
395 self.rank = 0;
396 self.spiked = false;
397 }
398}
399impl Default for AkidaNeuron {
400 fn default() -> Self {
401 Self::new(100)
402 }
403}
404
405#[derive(Clone, Debug)]
407pub struct NeuroGridNeuron {
408 pub v_s: f64,
409 pub v_d: f64,
410 pub tau_s: f64,
411 pub tau_d: f64,
412 pub g_c: f64,
413 pub delta_t: f64,
414 pub v_rest: f64,
415 pub v_threshold: f64,
416 pub v_peak: f64,
417 pub v_reset: f64,
418 pub dt: f64,
419}
420
421impl NeuroGridNeuron {
422 pub fn new() -> Self {
423 Self {
424 v_s: -65.0,
425 v_d: -65.0,
426 tau_s: 20.0,
427 tau_d: 50.0,
428 g_c: 0.5,
429 delta_t: 2.0,
430 v_rest: -65.0,
431 v_threshold: -50.0,
432 v_peak: 20.0,
433 v_reset: -65.0,
434 dt: 0.1,
435 }
436 }
437 pub fn step(&mut self, current: f64) -> i32 {
438 let dv_d =
439 (-(self.v_d - self.v_rest) + current - self.g_c * (self.v_d - self.v_s)) / self.tau_d;
440 self.v_d += dv_d * self.dt;
441 let exp_arg = ((self.v_s - self.v_threshold) / self.delta_t).min(20.0);
442 let exp_term = self.delta_t * exp_arg.exp();
443 let dv_s =
444 (-(self.v_s - self.v_rest) + exp_term + self.g_c * (self.v_d - self.v_s)) / self.tau_s;
445 self.v_s += dv_s * self.dt;
446 if self.v_s >= self.v_peak {
447 self.v_s = self.v_reset;
448 1
449 } else {
450 0
451 }
452 }
453 pub fn reset(&mut self) {
454 self.v_s = -65.0;
455 self.v_d = -65.0;
456 }
457}
458impl Default for NeuroGridNeuron {
459 fn default() -> Self {
460 Self::new()
461 }
462}
463
464#[cfg(test)]
465mod tests {
466 use super::*;
467
468 #[test]
469 fn loihi_cuba_fires() {
470 let mut n = LoihiCUBANeuron::new();
471 let t: i32 = (0..200).map(|_| n.step(100)).sum();
472 assert!(t > 0);
473 }
474 #[test]
475 fn loihi2_fires() {
476 let mut n = Loihi2Neuron {
477 tau3: 8,
478 ..Loihi2Neuron::new()
479 };
480 let t: i32 = (0..500).map(|_| n.step(200)).sum();
481 assert!(t > 0);
482 }
483 #[test]
484 fn truenorth_fires() {
485 let mut n = TrueNorthNeuron::default();
486 let t: i32 = (0..10).map(|_| n.step(50)).sum();
487 assert!(t > 0);
488 }
489 #[test]
490 fn brainscales_fires() {
491 let mut n = BrainScaleSAdExNeuron::new();
492 let t: i32 = (0..2000).map(|_| n.step(500.0)).sum();
493 assert!(t > 0);
494 }
495 #[test]
496 fn spinnaker_fires() {
497 let mut n = SpiNNakerLIFNeuron::new();
498 let t: i32 = (0..200).map(|_| n.step(30.0)).sum();
499 assert!(t > 0);
500 }
501 #[test]
502 fn spinnaker2_fires() {
503 let mut n = SpiNNaker2Neuron::new();
504 let t: i32 = (0..200).map(|_| n.step(100)).sum();
505 assert!(t > 0);
506 }
507 #[test]
508 fn dpi_fires() {
509 let mut n = DPINeuron::new();
510 let t: i32 = (0..100).map(|_| n.step(1.0)).sum();
511 assert!(t > 0);
512 }
513 #[test]
514 fn akida_fires() {
515 let mut n = AkidaNeuron::default();
516 let t: i32 = (0..10).map(|_| n.step(50.0)).sum();
517 assert!(t > 0);
518 }
519 #[test]
520 fn neurogrid_fires() {
521 let mut n = NeuroGridNeuron::new();
522 let t: i32 = (0..2000).map(|_| n.step(500.0)).sum();
523 assert!(t > 0);
524 }
525
526 #[test]
530 fn loihi_cuba_silent() {
531 let mut n = LoihiCUBANeuron::new();
532 let t: i32 = (0..200).map(|_| n.step(0)).sum();
533 assert_eq!(t, 0);
534 }
535 #[test]
536 fn loihi_cuba_reset() {
537 let mut n = LoihiCUBANeuron::new();
538 for _ in 0..50 {
539 n.step(100);
540 }
541 n.reset();
542 assert_eq!(n.v, 0);
543 assert_eq!(n.u, 0);
544 }
545 #[test]
546 fn loihi_cuba_bounded() {
547 let mut n = LoihiCUBANeuron::new();
548 for _ in 0..1000 {
549 n.step(10000);
550 }
551 }
552
553 #[test]
555 fn loihi2_silent() {
556 let mut n = Loihi2Neuron::new();
557 let t: i32 = (0..200).map(|_| n.step(0)).sum();
558 assert_eq!(t, 0);
559 }
560 #[test]
561 fn loihi2_reset() {
562 let mut n = Loihi2Neuron::new();
563 for _ in 0..50 {
564 n.step(200);
565 }
566 n.reset();
567 assert_eq!(n.s1, 0);
568 }
569 #[test]
570 fn loihi2_bounded() {
571 let mut n = Loihi2Neuron {
572 tau3: 8,
573 ..Loihi2Neuron::new()
574 };
575 for _ in 0..1000 {
576 n.step(10000);
577 }
578 }
579
580 #[test]
582 fn truenorth_silent() {
583 let mut n = TrueNorthNeuron::default();
584 let t: i32 = (0..100).map(|_| n.step(0)).sum();
585 assert_eq!(t, 0);
586 }
587 #[test]
588 fn truenorth_reset() {
589 let mut n = TrueNorthNeuron::default();
590 for _ in 0..10 {
591 n.step(50);
592 }
593 n.reset();
594 assert_eq!(n.v, 0);
595 }
596
597 #[test]
599 fn brainscales_silent() {
600 let mut n = BrainScaleSAdExNeuron::new();
601 let t: i32 = (0..200).map(|_| n.step(0.0)).sum();
602 assert_eq!(t, 0);
603 }
604 #[test]
605 fn brainscales_reset() {
606 let mut n = BrainScaleSAdExNeuron::new();
607 for _ in 0..100 {
608 n.step(500.0);
609 }
610 n.reset();
611 assert!((n.v - n.v_rest).abs() < 1e-10);
612 }
613 #[test]
614 fn brainscales_bounded() {
615 let mut n = BrainScaleSAdExNeuron::new();
616 for _ in 0..2000 {
617 n.step(1e4);
618 }
619 assert!(n.v.is_finite());
620 }
621 #[test]
622 fn brainscales_nan_no_panic() {
623 BrainScaleSAdExNeuron::new().step(f64::NAN);
624 }
625
626 #[test]
628 fn spinnaker_silent() {
629 let mut n = SpiNNakerLIFNeuron::new();
630 let t: i32 = (0..200).map(|_| n.step(0.0)).sum();
631 assert_eq!(t, 0);
632 }
633 #[test]
634 fn spinnaker_reset() {
635 let mut n = SpiNNakerLIFNeuron::new();
636 for _ in 0..50 {
637 n.step(30.0);
638 }
639 n.reset();
640 assert!((n.v - n.v_rest).abs() < 1e-10);
641 }
642 #[test]
643 fn spinnaker_bounded() {
644 let mut n = SpiNNakerLIFNeuron::new();
645 for _ in 0..1000 {
646 n.step(1e4);
647 }
648 assert!(n.v.is_finite());
649 }
650 #[test]
651 fn spinnaker_nan_no_panic() {
652 SpiNNakerLIFNeuron::new().step(f64::NAN);
653 }
654
655 #[test]
657 fn spinnaker2_silent() {
658 let mut n = SpiNNaker2Neuron::new();
659 let t: i32 = (0..200).map(|_| n.step(0)).sum();
660 assert_eq!(t, 0);
661 }
662 #[test]
663 fn spinnaker2_reset() {
664 let mut n = SpiNNaker2Neuron::new();
665 for _ in 0..50 {
666 n.step(100);
667 }
668 n.reset();
669 }
670 #[test]
671 fn spinnaker2_bounded() {
672 let mut n = SpiNNaker2Neuron::new();
673 for _ in 0..1000 {
674 n.step(10000);
675 }
676 }
677
678 #[test]
680 fn dpi_silent() {
681 let mut n = DPINeuron::new();
682 let t: i32 = (0..100).map(|_| n.step(0.0)).sum();
683 assert_eq!(t, 0);
684 }
685 #[test]
686 fn dpi_reset() {
687 let mut n = DPINeuron::new();
688 for _ in 0..50 {
689 n.step(1.0);
690 }
691 n.reset();
692 }
693 #[test]
694 fn dpi_nan_no_panic() {
695 DPINeuron::new().step(f64::NAN);
696 }
697
698 #[test]
700 fn akida_silent() {
701 let mut n = AkidaNeuron::default();
702 let t: i32 = (0..100).map(|_| n.step(0.0)).sum();
703 assert_eq!(t, 0);
704 }
705 #[test]
706 fn akida_reset() {
707 let mut n = AkidaNeuron::default();
708 for _ in 0..10 {
709 n.step(50.0);
710 }
711 n.reset();
712 }
713 #[test]
714 fn akida_nan_no_panic() {
715 AkidaNeuron::default().step(f64::NAN);
716 }
717
718 #[test]
720 fn neurogrid_silent() {
721 let mut n = NeuroGridNeuron::new();
722 let t: i32 = (0..200).map(|_| n.step(0.0)).sum();
723 assert_eq!(t, 0);
724 }
725 #[test]
726 fn neurogrid_reset() {
727 let mut n = NeuroGridNeuron::new();
728 for _ in 0..100 {
729 n.step(500.0);
730 }
731 n.reset();
732 assert!((n.v_s - (-65.0)).abs() < 1e-10);
733 }
734 #[test]
735 fn neurogrid_bounded() {
736 let mut n = NeuroGridNeuron::new();
737 for _ in 0..2000 {
738 n.step(1e4);
739 }
740 assert!(n.v_s.is_finite());
741 }
742 #[test]
743 fn neurogrid_nan_no_panic() {
744 NeuroGridNeuron::new().step(f64::NAN);
745 }
746}