scirs2_spatial/neuromorphic/core/
events.rs1#[derive(Debug, Clone)]
33pub struct SpikeEvent {
34 pub neuron_id: usize,
36 pub timestamp: f64,
38 pub amplitude: f64,
40 pub spatial_coords: Vec<f64>,
42}
43
44impl SpikeEvent {
45 pub fn new(neuron_id: usize, timestamp: f64, amplitude: f64, spatial_coords: Vec<f64>) -> Self {
56 Self {
57 neuron_id,
58 timestamp,
59 amplitude,
60 spatial_coords,
61 }
62 }
63
64 pub fn neuron_id(&self) -> usize {
66 self.neuron_id
67 }
68
69 pub fn timestamp(&self) -> f64 {
71 self.timestamp
72 }
73
74 pub fn amplitude(&self) -> f64 {
76 self.amplitude
77 }
78
79 pub fn spatial_coords(&self) -> &[f64] {
81 &self.spatial_coords
82 }
83
84 pub fn spatial_dims(&self) -> usize {
86 self.spatial_coords.len()
87 }
88
89 pub fn temporal_distance(&self, other: &SpikeEvent) -> f64 {
97 (self.timestamp - other.timestamp).abs()
98 }
99
100 pub fn spatial_distance(&self, other: &SpikeEvent) -> Option<f64> {
108 if self.spatial_coords.len() != other.spatial_coords.len() {
109 return None;
110 }
111
112 let distance = self
113 .spatial_coords
114 .iter()
115 .zip(other.spatial_coords.iter())
116 .map(|(a, b)| (a - b).powi(2))
117 .sum::<f64>()
118 .sqrt();
119
120 Some(distance)
121 }
122
123 pub fn is_before(&self, other: &SpikeEvent) -> bool {
131 self.timestamp < other.timestamp
132 }
133
134 pub fn is_after(&self, other: &SpikeEvent) -> bool {
142 self.timestamp > other.timestamp
143 }
144
145 pub fn same_neuron(&self, other: &SpikeEvent) -> bool {
153 self.neuron_id == other.neuron_id
154 }
155}
156
157impl PartialEq for SpikeEvent {
158 fn eq(&self, other: &Self) -> bool {
159 self.neuron_id == other.neuron_id
160 && (self.timestamp - other.timestamp).abs() < 1e-9
161 && (self.amplitude - other.amplitude).abs() < 1e-9
162 && self.spatial_coords == other.spatial_coords
163 }
164}
165
166impl PartialOrd for SpikeEvent {
167 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
168 self.timestamp.partial_cmp(&other.timestamp)
169 }
170}
171
172#[derive(Debug, Clone)]
174pub struct SpikeSequence {
175 events: Vec<SpikeEvent>,
177}
178
179impl SpikeSequence {
180 pub fn new() -> Self {
182 Self { events: Vec::new() }
183 }
184
185 pub fn from_events(events: Vec<SpikeEvent>) -> Self {
193 Self { events }
194 }
195
196 pub fn add_event(&mut self, event: SpikeEvent) {
201 self.events.push(event);
202 }
203
204 pub fn events(&self) -> &[SpikeEvent] {
206 &self.events
207 }
208
209 pub fn len(&self) -> usize {
211 self.events.len()
212 }
213
214 pub fn is_empty(&self) -> bool {
216 self.events.is_empty()
217 }
218
219 pub fn sort_by_time(&mut self) {
221 self.events.sort_by(|a, b| {
222 a.timestamp
223 .partial_cmp(&b.timestamp)
224 .expect("Operation failed")
225 });
226 }
227
228 pub fn events_in_window(&self, start_time: f64, end_time: f64) -> Vec<&SpikeEvent> {
237 self.events
238 .iter()
239 .filter(|event| event.timestamp >= start_time && event.timestamp <= end_time)
240 .collect()
241 }
242
243 pub fn events_from_neuron(&self, neuron_id: usize) -> Vec<&SpikeEvent> {
251 self.events
252 .iter()
253 .filter(|event| event.neuron_id == neuron_id)
254 .collect()
255 }
256
257 pub fn firing_rate(&self, neuron_id: usize, time_window: f64) -> f64 {
266 let neuron_events = self.events_from_neuron(neuron_id);
267 if neuron_events.is_empty() || time_window <= 0.0 {
268 return 0.0;
269 }
270
271 neuron_events.len() as f64 / time_window
272 }
273
274 pub fn time_span(&self) -> Option<(f64, f64)> {
279 if self.events.is_empty() {
280 return None;
281 }
282
283 let times: Vec<f64> = self.events.iter().map(|event| event.timestamp).collect();
284 let min_time = times.iter().fold(f64::INFINITY, |a, &b| a.min(b));
285 let max_time = times.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
286
287 Some((min_time, max_time))
288 }
289}
290
291impl Default for SpikeSequence {
292 fn default() -> Self {
293 Self::new()
294 }
295}
296
297#[cfg(test)]
298mod tests {
299 use super::*;
300
301 #[test]
302 fn test_spike_event_creation() {
303 let spike = SpikeEvent::new(42, 1000.5, 1.0, vec![0.5, 0.3, 0.8]);
304
305 assert_eq!(spike.neuron_id(), 42);
306 assert_eq!(spike.timestamp(), 1000.5);
307 assert_eq!(spike.amplitude(), 1.0);
308 assert_eq!(spike.spatial_coords(), &[0.5, 0.3, 0.8]);
309 assert_eq!(spike.spatial_dims(), 3);
310 }
311
312 #[test]
313 fn test_temporal_distance() {
314 let spike1 = SpikeEvent::new(1, 100.0, 1.0, vec![0.0]);
315 let spike2 = SpikeEvent::new(2, 105.0, 1.0, vec![1.0]);
316
317 assert_eq!(spike1.temporal_distance(&spike2), 5.0);
318 assert_eq!(spike2.temporal_distance(&spike1), 5.0);
319 }
320
321 #[test]
322 fn test_spatial_distance() {
323 let spike1 = SpikeEvent::new(1, 100.0, 1.0, vec![0.0, 0.0]);
324 let spike2 = SpikeEvent::new(2, 105.0, 1.0, vec![3.0, 4.0]);
325
326 assert_eq!(spike1.spatial_distance(&spike2), Some(5.0));
327
328 let spike3 = SpikeEvent::new(3, 110.0, 1.0, vec![1.0]);
330 assert_eq!(spike1.spatial_distance(&spike3), None);
331 }
332
333 #[test]
334 fn test_spike_ordering() {
335 let spike1 = SpikeEvent::new(1, 100.0, 1.0, vec![0.0]);
336 let spike2 = SpikeEvent::new(2, 105.0, 1.0, vec![1.0]);
337
338 assert!(spike1.is_before(&spike2));
339 assert!(spike2.is_after(&spike1));
340 assert!(!spike1.is_after(&spike2));
341 assert!(!spike2.is_before(&spike1));
342 }
343
344 #[test]
345 fn test_spike_sequence() {
346 let mut sequence = SpikeSequence::new();
347 assert!(sequence.is_empty());
348
349 let spike1 = SpikeEvent::new(1, 100.0, 1.0, vec![0.0]);
350 let spike2 = SpikeEvent::new(2, 105.0, 1.0, vec![1.0]);
351
352 sequence.add_event(spike1);
353 sequence.add_event(spike2);
354
355 assert_eq!(sequence.len(), 2);
356 assert!(!sequence.is_empty());
357
358 let time_span = sequence.time_span().expect("Operation failed");
359 assert_eq!(time_span.0, 100.0);
360 assert_eq!(time_span.1, 105.0);
361 }
362
363 #[test]
364 fn test_events_in_window() {
365 let mut sequence = SpikeSequence::new();
366 sequence.add_event(SpikeEvent::new(1, 95.0, 1.0, vec![0.0]));
367 sequence.add_event(SpikeEvent::new(2, 100.0, 1.0, vec![1.0]));
368 sequence.add_event(SpikeEvent::new(3, 105.0, 1.0, vec![2.0]));
369 sequence.add_event(SpikeEvent::new(4, 110.0, 1.0, vec![3.0]));
370
371 let windowed_events = sequence.events_in_window(100.0, 105.0);
372 assert_eq!(windowed_events.len(), 2);
373 assert_eq!(windowed_events[0].neuron_id, 2);
374 assert_eq!(windowed_events[1].neuron_id, 3);
375 }
376
377 #[test]
378 fn test_firing_rate() {
379 let mut sequence = SpikeSequence::new();
380 sequence.add_event(SpikeEvent::new(1, 100.0, 1.0, vec![0.0]));
381 sequence.add_event(SpikeEvent::new(1, 105.0, 1.0, vec![0.0]));
382 sequence.add_event(SpikeEvent::new(1, 110.0, 1.0, vec![0.0]));
383 sequence.add_event(SpikeEvent::new(2, 107.0, 1.0, vec![1.0]));
384
385 assert_eq!(sequence.firing_rate(1, 10.0), 0.3);
387
388 assert_eq!(sequence.firing_rate(2, 10.0), 0.1);
390
391 assert_eq!(sequence.firing_rate(99, 10.0), 0.0);
393 }
394}