sc_neurocore_engine/analysis/
basic.rs1pub fn spike_times(binary_train: &[i32], dt: f64) -> Vec<f64> {
11 binary_train
12 .iter()
13 .enumerate()
14 .filter(|(_, &s)| s > 0)
15 .map(|(i, _)| i as f64 * dt)
16 .collect()
17}
18
19pub fn isi(binary_train: &[i32], dt: f64) -> Vec<f64> {
21 let times = spike_times(binary_train, dt);
22 if times.len() < 2 {
23 return vec![];
24 }
25 times.windows(2).map(|w| w[1] - w[0]).collect()
26}
27
28pub fn firing_rate(binary_train: &[i32], dt: f64) -> f64 {
30 let duration = binary_train.len() as f64 * dt;
31 if duration <= 0.0 {
32 return 0.0;
33 }
34 let count: i64 = binary_train.iter().map(|&s| s as i64).sum();
35 count as f64 / duration
36}
37
38pub fn spike_count(binary_train: &[i32]) -> i64 {
40 let mut total = 0_i64;
41 let mut chunks = binary_train.chunks_exact(4);
42 for c in chunks.by_ref() {
43 total += (c[0] + c[1] + c[2] + c[3]) as i64;
44 }
45 for &s in chunks.remainder() {
46 total += s as i64;
47 }
48 total
49}
50
51pub fn bin_spike_train(binary_train: &[i32], bin_size: usize) -> Vec<i64> {
53 let n = binary_train.len();
54 let n_bins = n / bin_size;
55 if n_bins == 0 {
56 return vec![binary_train.iter().map(|&s| s as i64).sum()];
57 }
58 let mut res = Vec::with_capacity(n_bins);
59 for i in 0..n_bins {
60 let chunk = &binary_train[i * bin_size..(i + 1) * bin_size];
61 let mut total = 0_i64;
62 let mut c_iter = chunk.chunks_exact(4);
63 for c in c_iter.by_ref() {
64 total += (c[0] + c[1] + c[2] + c[3]) as i64;
65 }
66 for &s in c_iter.remainder() {
67 total += s as i64;
68 }
69 res.push(total);
70 }
71 res
72}
73
74pub fn spike_times_f64(binary_train: &[f64], dt: f64) -> Vec<f64> {
78 binary_train
79 .iter()
80 .enumerate()
81 .filter(|(_, &s)| s > 0.5)
82 .map(|(i, _)| i as f64 * dt)
83 .collect()
84}
85
86pub fn isi_f64(binary_train: &[f64], dt: f64) -> Vec<f64> {
88 let times = spike_times_f64(binary_train, dt);
89 if times.len() < 2 {
90 return vec![];
91 }
92 times.windows(2).map(|w| w[1] - w[0]).collect()
93}
94
95pub fn firing_rate_f64(binary_train: &[f64], dt: f64) -> f64 {
97 let duration = binary_train.len() as f64 * dt;
98 if duration <= 0.0 {
99 return 0.0;
100 }
101 let count: f64 = binary_train.iter().sum();
102 count / duration
103}
104
105pub fn spike_count_f64(binary_train: &[f64]) -> i64 {
107 binary_train.iter().filter(|&&s| s > 0.5).count() as i64
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn test_spike_times_basic() {
116 let train = vec![0, 1, 0, 0, 1, 1, 0];
117 let times = spike_times(&train, 0.001);
118 assert_eq!(times.len(), 3);
119 assert!((times[0] - 0.001).abs() < 1e-12);
120 assert!((times[1] - 0.004).abs() < 1e-12);
121 assert!((times[2] - 0.005).abs() < 1e-12);
122 }
123
124 #[test]
125 fn test_spike_times_empty() {
126 let train = vec![0, 0, 0];
127 assert!(spike_times(&train, 0.001).is_empty());
128 }
129
130 #[test]
131 fn test_isi_basic() {
132 let train = vec![0, 1, 0, 0, 1, 0];
133 let intervals = isi(&train, 0.001);
134 assert_eq!(intervals.len(), 1);
135 assert!((intervals[0] - 0.003).abs() < 1e-12);
136 }
137
138 #[test]
139 fn test_isi_single_spike() {
140 let train = vec![0, 1, 0];
141 assert!(isi(&train, 0.001).is_empty());
142 }
143
144 #[test]
145 fn test_firing_rate() {
146 let train = vec![1, 0, 1, 0, 1, 0, 1, 0, 1, 0];
147 let rate = firing_rate(&train, 0.001);
148 assert!((rate - 500.0).abs() < 0.01);
149 }
150
151 #[test]
152 fn test_firing_rate_zero() {
153 let train = vec![0, 0, 0];
154 assert_eq!(firing_rate(&train, 0.001), 0.0);
155 }
156
157 #[test]
158 fn test_spike_count() {
159 let train = vec![1, 0, 1, 1, 0, 1];
160 assert_eq!(spike_count(&train), 4);
161 }
162
163 #[test]
164 fn test_bin_spike_train() {
165 let train = vec![1, 0, 1, 1, 0, 0, 1, 1, 1, 0];
166 let bins = bin_spike_train(&train, 5);
167 assert_eq!(bins, vec![3, 3]);
168 }
169
170 #[test]
171 fn test_bin_spike_train_remainder() {
172 let train = vec![1, 1, 1, 1, 1, 1, 1];
173 let bins = bin_spike_train(&train, 3);
174 assert_eq!(bins, vec![3, 3]); }
176
177 #[test]
178 fn test_f64_variants() {
179 let train = vec![0.0, 1.0, 0.0, 1.0, 0.0];
180 assert_eq!(spike_count_f64(&train), 2);
181 assert!((firing_rate_f64(&train, 0.001) - 400.0).abs() < 0.01);
182 assert_eq!(spike_times_f64(&train, 0.001).len(), 2);
183 assert_eq!(isi_f64(&train, 0.001).len(), 1);
184 }
185}