1use std::collections::{HashMap, HashSet};
23use std::sync::{Arc, Mutex};
24use xxhash_rust::xxh64::xxh64;
25
26#[derive(Debug, Clone)]
28pub struct PatternConfig {
29 pub default_temporal_depth: u32,
31
32 pub min_activity_threshold: usize,
34
35 pub max_pattern_cache_size: usize,
37}
38
39impl Default for PatternConfig {
40 fn default() -> Self {
41 Self {
42 default_temporal_depth: 3,
43 min_activity_threshold: 1,
44 max_pattern_cache_size: 10000,
45 }
46 }
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, Hash)]
51pub struct TemporalPattern {
52 pub pattern_hash: u64,
54
55 pub temporal_depth: u32,
57
58 pub upstream_areas: Vec<u32>,
60
61 pub timestep_neuron_counts: Vec<usize>,
63
64 pub total_activity: usize,
66}
67
68#[derive(Debug, Clone, Default)]
70pub struct PatternDetectorStats {
71 pub patterns_detected: usize,
72 pub cache_hits: usize,
73 pub cache_misses: usize,
74 pub empty_patterns: usize,
75 pub set_operations: usize,
76}
77
78pub struct PatternDetector {
80 config: PatternConfig,
81
82 pattern_cache: Arc<Mutex<HashMap<u64, TemporalPattern>>>,
84
85 cache_access_order: Arc<Mutex<Vec<u64>>>,
87
88 area_temporal_depths: Arc<Mutex<HashMap<u32, u32>>>,
90
91 stats: Arc<Mutex<PatternDetectorStats>>,
93}
94
95impl PatternDetector {
96 pub fn new(config: PatternConfig) -> Self {
98 Self {
99 config,
100 pattern_cache: Arc::new(Mutex::new(HashMap::new())),
101 cache_access_order: Arc::new(Mutex::new(Vec::new())),
102 area_temporal_depths: Arc::new(Mutex::new(HashMap::new())),
103 stats: Arc::new(Mutex::new(PatternDetectorStats::default())),
104 }
105 }
106
107 pub fn detect_pattern(
109 &self,
110 memory_area_idx: u32,
111 upstream_areas: &[u32],
112 _current_timestep: u64,
113 timestep_bitmaps: Vec<HashSet<u32>>,
114 temporal_depth: Option<u32>,
115 ) -> Option<TemporalPattern> {
116 if upstream_areas.is_empty() {
117 return None;
118 }
119
120 let area_temporal_depth =
122 temporal_depth.unwrap_or_else(|| self.get_area_temporal_depth(memory_area_idx));
123
124 if timestep_bitmaps.is_empty() {
125 let mut stats = self.stats.lock().unwrap();
126 stats.empty_patterns += 1;
127 return None;
128 }
129
130 let total_activity: usize = timestep_bitmaps.iter().map(|set| set.len()).sum();
132
133 if total_activity < self.config.min_activity_threshold {
134 let mut stats = self.stats.lock().unwrap();
135 stats.empty_patterns += 1;
136 return None;
137 }
138
139 let pattern_hash = self.create_pattern_hash(×tep_bitmaps);
141
142 {
144 let cache = self.pattern_cache.lock().unwrap();
145 if let Some(pattern) = cache.get(&pattern_hash) {
146 self.update_cache_access(pattern_hash);
147 let mut stats = self.stats.lock().unwrap();
148 stats.cache_hits += 1;
149 return Some(pattern.clone());
150 }
151 }
152
153 let timestep_neuron_counts: Vec<usize> =
155 timestep_bitmaps.iter().map(|set| set.len()).collect();
156
157 let mut sorted_upstream = upstream_areas.to_vec();
158 sorted_upstream.sort_unstable();
159
160 let pattern = TemporalPattern {
161 pattern_hash,
162 temporal_depth: area_temporal_depth,
163 upstream_areas: sorted_upstream,
164 timestep_neuron_counts,
165 total_activity,
166 };
167
168 self.add_to_cache(pattern.clone());
170
171 let mut stats = self.stats.lock().unwrap();
172 stats.patterns_detected += 1;
173 stats.cache_misses += 1;
174
175 Some(pattern)
176 }
177
178 fn create_pattern_hash(&self, timestep_bitmaps: &[HashSet<u32>]) -> u64 {
190 let mut buffer = Vec::new();
191
192 for bitmap in timestep_bitmaps {
194 let mut sorted_ids: Vec<u32> = bitmap.iter().copied().collect();
196 sorted_ids.sort_unstable();
197
198 let len = sorted_ids.len() as u32;
200 buffer.extend_from_slice(&len.to_le_bytes());
201
202 for id in sorted_ids {
204 buffer.extend_from_slice(&id.to_le_bytes());
205 }
206 }
207
208 xxh64(&buffer, 0)
210 }
211
212 fn add_to_cache(&self, pattern: TemporalPattern) {
214 let pattern_hash = pattern.pattern_hash;
215
216 let mut cache = self.pattern_cache.lock().unwrap();
217 let mut access_order = self.cache_access_order.lock().unwrap();
218
219 cache.insert(pattern_hash, pattern);
221 access_order.push(pattern_hash);
222
223 if cache.len() > self.config.max_pattern_cache_size {
225 if let Some(oldest_hash) = access_order.first().copied() {
226 access_order.remove(0);
227 cache.remove(&oldest_hash);
228 }
229 }
230 }
231
232 fn update_cache_access(&self, pattern_hash: u64) {
234 let mut access_order = self.cache_access_order.lock().unwrap();
235 if let Some(pos) = access_order.iter().position(|&h| h == pattern_hash) {
236 access_order.remove(pos);
237 }
238 access_order.push(pattern_hash);
239 }
240
241 pub fn configure_area_temporal_depth(&self, memory_area_idx: u32, temporal_depth: u32) {
243 let mut depths = self.area_temporal_depths.lock().unwrap();
244 depths.insert(memory_area_idx, temporal_depth);
245 }
246
247 fn get_area_temporal_depth(&self, memory_area_idx: u32) -> u32 {
249 let depths = self.area_temporal_depths.lock().unwrap();
250 depths
251 .get(&memory_area_idx)
252 .copied()
253 .unwrap_or(self.config.default_temporal_depth)
254 }
255
256 pub fn get_stats(&self) -> PatternDetectorStats {
258 self.stats.lock().unwrap().clone()
259 }
260
261 pub fn clear_cache(&self) {
263 let mut cache = self.pattern_cache.lock().unwrap();
264 let mut access_order = self.cache_access_order.lock().unwrap();
265 cache.clear();
266 access_order.clear();
267 }
268
269 pub fn reset_stats(&self) {
271 let mut stats = self.stats.lock().unwrap();
272 *stats = PatternDetectorStats::default();
273 }
274}
275
276pub struct BatchPatternDetector {
278 pub(crate) base_config: PatternConfig,
279 pub(crate) detectors: Arc<Mutex<HashMap<u32, PatternDetector>>>,
280}
281
282impl BatchPatternDetector {
283 pub fn new(base_config: PatternConfig) -> Self {
285 Self {
286 base_config,
287 detectors: Arc::new(Mutex::new(HashMap::new())),
288 }
289 }
290
291 pub fn get_detector(&self, memory_area_idx: u32, temporal_depth: u32) -> PatternDetector {
293 let mut detectors = self.detectors.lock().unwrap();
294
295 detectors.entry(memory_area_idx).or_insert_with(|| {
296 let detector = PatternDetector::new(self.base_config.clone());
297 detector.configure_area_temporal_depth(memory_area_idx, temporal_depth);
298 detector
299 });
300
301 detectors.get(&memory_area_idx).unwrap().clone()
303 }
304
305 pub fn get_batch_stats(&self) -> HashMap<u32, PatternDetectorStats> {
307 let detectors = self.detectors.lock().unwrap();
308 detectors
309 .iter()
310 .map(|(&area_idx, detector)| (area_idx, detector.get_stats()))
311 .collect()
312 }
313}
314
315impl Clone for PatternDetector {
316 fn clone(&self) -> Self {
317 Self {
318 config: self.config.clone(),
319 pattern_cache: Arc::clone(&self.pattern_cache),
320 cache_access_order: Arc::clone(&self.cache_access_order),
321 area_temporal_depths: Arc::clone(&self.area_temporal_depths),
322 stats: Arc::clone(&self.stats),
323 }
324 }
325}
326
327impl Clone for BatchPatternDetector {
328 fn clone(&self) -> Self {
329 Self {
330 base_config: self.base_config.clone(),
331 detectors: Arc::clone(&self.detectors),
332 }
333 }
334}
335
336#[cfg(test)]
337mod tests {
338 use super::*;
339
340 #[test]
341 fn test_pattern_config_default() {
342 let config = PatternConfig::default();
343 assert_eq!(config.default_temporal_depth, 3);
344 assert_eq!(config.min_activity_threshold, 1);
345 assert_eq!(config.max_pattern_cache_size, 10000);
346 }
347
348 #[test]
349 fn test_pattern_detection() {
350 let config = PatternConfig::default();
351 let detector = PatternDetector::new(config);
352
353 let mut bitmap1 = HashSet::new();
355 bitmap1.insert(1);
356 bitmap1.insert(2);
357
358 let mut bitmap2 = HashSet::new();
359 bitmap2.insert(3);
360 bitmap2.insert(4);
361
362 let bitmaps = vec![bitmap1, bitmap2];
363 let upstream_areas = vec![1, 2];
364
365 let pattern = detector.detect_pattern(
366 100, &upstream_areas,
368 10, bitmaps,
370 None,
371 );
372
373 assert!(pattern.is_some());
374 let pattern = pattern.unwrap();
375 assert_eq!(pattern.temporal_depth, 3);
376 assert_eq!(pattern.total_activity, 4);
377 assert_eq!(pattern.timestep_neuron_counts, vec![2, 2]);
378 assert_eq!(pattern.upstream_areas, vec![1, 2]);
379 }
380
381 #[test]
382 fn test_pattern_detection_empty() {
383 let config = PatternConfig::default();
384 let detector = PatternDetector::new(config);
385
386 let bitmaps = vec![];
387 let upstream_areas = vec![1];
388
389 let pattern = detector.detect_pattern(100, &upstream_areas, 10, bitmaps, None);
390 assert!(pattern.is_none());
391
392 let stats = detector.get_stats();
393 assert_eq!(stats.empty_patterns, 1);
394 }
395
396 #[test]
397 fn test_pattern_detection_no_upstream() {
398 let config = PatternConfig::default();
399 let detector = PatternDetector::new(config);
400
401 let mut bitmap = HashSet::new();
402 bitmap.insert(1);
403
404 let bitmaps = vec![bitmap];
405 let upstream_areas = vec![];
406
407 let pattern = detector.detect_pattern(100, &upstream_areas, 10, bitmaps, None);
408 assert!(pattern.is_none());
409 }
410
411 #[test]
412 fn test_pattern_detection_below_threshold() {
413 let config = PatternConfig {
414 min_activity_threshold: 10,
415 ..Default::default()
416 };
417 let detector = PatternDetector::new(config);
418
419 let mut bitmap = HashSet::new();
420 bitmap.insert(1);
421 bitmap.insert(2);
422
423 let bitmaps = vec![bitmap];
424 let upstream_areas = vec![1];
425
426 let pattern = detector.detect_pattern(100, &upstream_areas, 10, bitmaps, None);
427 assert!(pattern.is_none());
428
429 let stats = detector.get_stats();
430 assert_eq!(stats.empty_patterns, 1);
431 }
432
433 #[test]
434 fn test_pattern_cache() {
435 let config = PatternConfig::default();
436 let detector = PatternDetector::new(config);
437
438 let mut bitmap = HashSet::new();
439 bitmap.insert(1);
440 bitmap.insert(2);
441
442 let bitmaps = vec![bitmap.clone()];
443 let upstream_areas = vec![1];
444
445 let pattern1 = detector.detect_pattern(100, &upstream_areas, 10, bitmaps.clone(), None);
447 assert!(pattern1.is_some());
448
449 let stats = detector.get_stats();
450 assert_eq!(stats.cache_misses, 1);
451 assert_eq!(stats.cache_hits, 0);
452 assert_eq!(stats.patterns_detected, 1);
453
454 let pattern2 = detector.detect_pattern(100, &upstream_areas, 11, bitmaps, None);
456 assert!(pattern2.is_some());
457
458 let stats = detector.get_stats();
459 assert_eq!(stats.cache_hits, 1);
460 assert_eq!(stats.patterns_detected, 1); assert_eq!(
464 pattern1.unwrap().pattern_hash,
465 pattern2.unwrap().pattern_hash
466 );
467 }
468
469 #[test]
470 fn test_cache_eviction() {
471 let config = PatternConfig {
472 max_pattern_cache_size: 2,
473 ..Default::default()
474 };
475 let detector = PatternDetector::new(config);
476
477 for i in 0..3 {
479 let mut bitmap = HashSet::new();
480 bitmap.insert(i);
481 detector.detect_pattern(100, &[1], 10, vec![bitmap], None);
482 }
483
484 let cache = detector.pattern_cache.lock().unwrap();
486 assert!(cache.len() <= 2);
487 }
488
489 #[test]
490 fn test_deterministic_hashing() {
491 let config = PatternConfig::default();
492 let detector = PatternDetector::new(config);
493
494 let mut bitmap = HashSet::new();
495 bitmap.insert(3);
496 bitmap.insert(1);
497 bitmap.insert(2);
498
499 let hash1 = detector.create_pattern_hash(&[bitmap.clone()]);
500 let hash2 = detector.create_pattern_hash(&[bitmap]);
501
502 assert_eq!(hash1, hash2);
503 }
504
505 #[test]
506 fn test_different_patterns_different_hashes() {
507 let config = PatternConfig::default();
508 let detector = PatternDetector::new(config);
509
510 let mut bitmap1 = HashSet::new();
511 bitmap1.insert(1);
512 bitmap1.insert(2);
513
514 let mut bitmap2 = HashSet::new();
515 bitmap2.insert(1);
516 bitmap2.insert(3); let hash1 = detector.create_pattern_hash(&[bitmap1]);
519 let hash2 = detector.create_pattern_hash(&[bitmap2]);
520
521 assert_ne!(hash1, hash2);
522 }
523
524 #[test]
525 fn test_temporal_order_sensitivity() {
526 let config = PatternConfig::default();
527 let detector = PatternDetector::new(config);
528
529 let mut bitmap1 = HashSet::new();
530 bitmap1.insert(1);
531
532 let mut bitmap2 = HashSet::new();
533 bitmap2.insert(2);
534
535 let hash1 = detector.create_pattern_hash(&[bitmap1.clone(), bitmap2.clone()]);
537 let hash2 = detector.create_pattern_hash(&[bitmap2, bitmap1]);
538
539 assert_ne!(hash1, hash2);
540 }
541
542 #[test]
543 fn test_configure_area_temporal_depth() {
544 let config = PatternConfig::default();
545 let default_temp_depth = config.default_temporal_depth;
546 let detector = PatternDetector::new(config);
547
548 detector.configure_area_temporal_depth(100, 5);
549
550 let depth = detector.get_area_temporal_depth(100);
551 assert_eq!(depth, 5);
552
553 let default_depth = detector.get_area_temporal_depth(999);
555 assert_eq!(default_depth, default_temp_depth);
556 }
557
558 #[test]
559 fn test_clear_cache() {
560 let config = PatternConfig::default();
561 let detector = PatternDetector::new(config);
562
563 let mut bitmap = HashSet::new();
564 bitmap.insert(1);
565 detector.detect_pattern(100, &[1], 10, vec![bitmap], None);
566
567 {
569 let cache = detector.pattern_cache.lock().unwrap();
570 assert!(!cache.is_empty());
571 }
572
573 detector.clear_cache();
574
575 let cache = detector.pattern_cache.lock().unwrap();
577 assert!(cache.is_empty());
578 }
579
580 #[test]
581 fn test_reset_stats() {
582 let config = PatternConfig::default();
583 let detector = PatternDetector::new(config);
584
585 let mut bitmap = HashSet::new();
586 bitmap.insert(1);
587 detector.detect_pattern(100, &[1], 10, vec![bitmap], None);
588
589 let stats = detector.get_stats();
590 assert!(stats.patterns_detected > 0);
591
592 detector.reset_stats();
593
594 let stats = detector.get_stats();
595 assert_eq!(stats.patterns_detected, 0);
596 assert_eq!(stats.cache_hits, 0);
597 assert_eq!(stats.cache_misses, 0);
598 }
599
600 #[test]
601 fn test_batch_pattern_detector() {
602 let config = PatternConfig::default();
603 let batch_detector = BatchPatternDetector::new(config);
604
605 let detector = batch_detector.get_detector(100, 5);
606
607 let mut bitmap = HashSet::new();
608 bitmap.insert(1);
609 let pattern = detector.detect_pattern(100, &[1], 10, vec![bitmap], None);
610
611 assert!(pattern.is_some());
612 }
613
614 #[test]
615 fn test_batch_stats() {
616 let config = PatternConfig::default();
617 let batch_detector = BatchPatternDetector::new(config);
618
619 for area_idx in [100, 200, 300] {
621 let detector = batch_detector.get_detector(area_idx, 3);
622 let mut bitmap = HashSet::new();
623 bitmap.insert(area_idx);
624 detector.detect_pattern(area_idx, &[1], 10, vec![bitmap], None);
625 }
626
627 let stats = batch_detector.get_batch_stats();
628 assert_eq!(stats.len(), 3);
629 assert!(stats.contains_key(&100));
630 assert!(stats.contains_key(&200));
631 assert!(stats.contains_key(&300));
632 }
633}