1use crate::neuron_id_manager::{AllocationStats, NeuronIdManager};
20use std::collections::{HashMap, HashSet};
21
22#[derive(Debug, Clone, Copy)]
24pub struct MemoryNeuronLifecycleConfig {
25 pub initial_lifespan: u32,
27
28 pub lifespan_growth_rate: f32,
30
31 pub longterm_threshold: u32,
33
34 pub max_reactivations: u32,
36}
37
38impl Default for MemoryNeuronLifecycleConfig {
39 fn default() -> Self {
40 Self {
41 initial_lifespan: 20,
42 lifespan_growth_rate: 3.0,
43 longterm_threshold: 100,
44 max_reactivations: 1000,
45 }
46 }
47}
48
49#[derive(Debug, Clone, Default)]
51pub struct MemoryNeuronStats {
52 pub total_capacity: usize,
53 pub active_neurons: usize,
54 pub longterm_neurons: usize,
55 pub dead_neurons: usize,
56 pub reusable_indices: usize,
57 pub memory_usage_bytes: usize,
58 pub avg_lifespan: f64,
59 pub avg_activation_count: f64,
60}
61
62pub struct MemoryNeuronArray {
64 capacity: usize,
65
66 neuron_ids: Vec<u32>,
68 cortical_area_ids: Vec<u32>,
69 is_active: Vec<bool>,
70
71 lifespan_current: Vec<u32>,
73 lifespan_initial: Vec<u32>,
74 lifespan_growth_rate: Vec<f32>,
75 is_longterm_memory: Vec<bool>,
76
77 creation_burst: Vec<u64>,
79 last_activation_burst: Vec<u64>,
80 activation_count: Vec<u32>,
81
82 pattern_hash_to_index: HashMap<u64, usize>,
84 index_to_pattern_hash: HashMap<usize, u64>,
85
86 next_available_index: usize,
88 reusable_indices: HashSet<usize>,
89
90 area_neuron_indices: HashMap<u32, HashSet<usize>>,
92
93 id_manager: NeuronIdManager,
95}
96
97impl MemoryNeuronArray {
98 pub fn new(capacity: usize) -> Self {
100 Self {
101 capacity,
102 neuron_ids: vec![0; capacity],
103 cortical_area_ids: vec![0; capacity],
104 is_active: vec![false; capacity],
105 lifespan_current: vec![0; capacity],
106 lifespan_initial: vec![0; capacity],
107 lifespan_growth_rate: vec![0.0; capacity],
108 is_longterm_memory: vec![false; capacity],
109 creation_burst: vec![0; capacity],
110 last_activation_burst: vec![0; capacity],
111 activation_count: vec![0; capacity],
112 pattern_hash_to_index: HashMap::new(),
113 index_to_pattern_hash: HashMap::new(),
114 next_available_index: 0,
115 reusable_indices: HashSet::new(),
116 area_neuron_indices: HashMap::new(),
117 id_manager: NeuronIdManager::new(),
118 }
119 }
120
121 pub fn create_memory_neuron(
123 &mut self,
124 pattern_hash: u64,
125 cortical_area_id: u32,
126 current_burst: u64,
127 config: &MemoryNeuronLifecycleConfig,
128 ) -> Option<usize> {
129 if let Some(&existing_idx) = self.pattern_hash_to_index.get(&pattern_hash) {
131 if self.is_active[existing_idx] {
132 return self.reactivate_memory_neuron_internal(existing_idx, current_burst);
134 }
135 }
136
137 let neuron_idx = self.get_available_index_internal()?;
139
140 let neuron_id = self.id_manager.allocate_memory_neuron_id()?;
142
143 self.neuron_ids[neuron_idx] = neuron_id;
145 self.cortical_area_ids[neuron_idx] = cortical_area_id;
146 self.is_active[neuron_idx] = true;
147
148 self.lifespan_current[neuron_idx] = config.initial_lifespan;
150 self.lifespan_initial[neuron_idx] = config.initial_lifespan;
151 self.lifespan_growth_rate[neuron_idx] = config.lifespan_growth_rate;
152 self.is_longterm_memory[neuron_idx] = false;
153
154 self.creation_burst[neuron_idx] = current_burst;
156 self.last_activation_burst[neuron_idx] = current_burst;
157 self.activation_count[neuron_idx] = 1;
158
159 self.pattern_hash_to_index.insert(pattern_hash, neuron_idx);
161 self.index_to_pattern_hash.insert(neuron_idx, pattern_hash);
162
163 self.area_neuron_indices
165 .entry(cortical_area_id)
166 .or_default()
167 .insert(neuron_idx);
168
169 Some(neuron_idx)
170 }
171
172 pub fn reactivate_memory_neuron(&mut self, neuron_idx: usize, current_burst: u64) -> bool {
174 self.reactivate_memory_neuron_internal(neuron_idx, current_burst)
175 .is_some()
176 }
177
178 fn reactivate_memory_neuron_internal(
180 &mut self,
181 neuron_idx: usize,
182 current_burst: u64,
183 ) -> Option<usize> {
184 if !self.is_valid_index(neuron_idx) || !self.is_active[neuron_idx] {
185 return None;
186 }
187
188 self.last_activation_burst[neuron_idx] = current_burst;
190 self.activation_count[neuron_idx] += 1;
191
192 if !self.is_longterm_memory[neuron_idx] {
194 let current_lifespan = self.lifespan_current[neuron_idx];
195 let growth = self.lifespan_growth_rate[neuron_idx] as u32;
196 self.lifespan_current[neuron_idx] = current_lifespan.saturating_add(growth);
197 }
198
199 Some(neuron_idx)
200 }
201
202 pub fn age_memory_neurons(&mut self, _current_burst: u64) -> Vec<usize> {
204 let n = self.next_available_index;
205 if n == 0 {
206 return Vec::new();
207 }
208
209 let mut died_indices = Vec::new();
210
211 for i in 0..n {
213 if self.is_active[i] && !self.is_longterm_memory[i] && self.lifespan_current[i] > 0 {
214 self.lifespan_current[i] -= 1;
215
216 if self.lifespan_current[i] == 0 {
218 self.is_active[i] = false;
219 died_indices.push(i);
220 }
221 }
222 }
223
224 for &i in &died_indices {
226 self.cleanup_dead_neuron_internal(i);
227 }
228
229 died_indices
230 }
231
232 pub fn check_longterm_conversion(&mut self, longterm_threshold: u32) -> Vec<usize> {
234 let n = self.next_available_index;
235 if n == 0 {
236 return Vec::new();
237 }
238
239 let mut converted_indices = Vec::new();
240
241 for i in 0..n {
242 if self.is_active[i]
243 && !self.is_longterm_memory[i]
244 && self.lifespan_current[i] >= longterm_threshold
245 {
246 self.is_longterm_memory[i] = true;
247 converted_indices.push(i);
248 }
249 }
250
251 converted_indices
252 }
253
254 pub fn check_longterm_conversion_by_area(
258 &mut self,
259 lifecycle_configs: &HashMap<u32, MemoryNeuronLifecycleConfig>,
260 default_threshold: u32,
261 ) -> Vec<usize> {
262 let n = self.next_available_index;
263 if n == 0 {
264 return Vec::new();
265 }
266
267 let area_indices: Vec<(u32, Vec<usize>)> = self
268 .area_neuron_indices
269 .iter()
270 .map(|(&area, indices)| (area, indices.iter().copied().collect()))
271 .collect();
272
273 let mut converted_indices = Vec::new();
274 for (area_id, indices) in area_indices {
275 let threshold = lifecycle_configs
276 .get(&area_id)
277 .map(|config| config.longterm_threshold)
278 .unwrap_or(default_threshold);
279
280 for neuron_idx in indices {
281 if self.is_active[neuron_idx]
282 && !self.is_longterm_memory[neuron_idx]
283 && self.lifespan_current[neuron_idx] >= threshold
284 {
285 self.is_longterm_memory[neuron_idx] = true;
286 converted_indices.push(neuron_idx);
287 }
288 }
289 }
290
291 converted_indices
292 }
293
294 pub fn get_active_neurons_by_area(&self, cortical_area_id: u32) -> Vec<u32> {
296 if let Some(indices) = self.area_neuron_indices.get(&cortical_area_id) {
297 indices
298 .iter()
299 .filter(|&&idx| self.is_valid_index(idx) && self.is_active[idx])
300 .map(|&idx| self.neuron_ids[idx])
301 .collect()
302 } else {
303 Vec::new()
304 }
305 }
306
307 pub fn find_neuron_by_pattern(&self, pattern_hash: &u64) -> Option<usize> {
309 self.pattern_hash_to_index
310 .get(pattern_hash)
311 .copied()
312 .filter(|&idx| self.is_valid_index(idx) && self.is_active[idx])
313 }
314
315 pub fn get_neuron_id(&self, neuron_idx: usize) -> Option<u32> {
317 if self.is_valid_index(neuron_idx) {
318 Some(self.neuron_ids[neuron_idx])
319 } else {
320 None
321 }
322 }
323
324 pub fn get_cortical_area_id(&self, neuron_idx: usize) -> Option<u32> {
326 if self.is_valid_index(neuron_idx) {
327 Some(self.cortical_area_ids[neuron_idx])
328 } else {
329 None
330 }
331 }
332
333 pub fn get_pattern_hash(&self, neuron_idx: usize) -> Option<u64> {
334 self.index_to_pattern_hash.get(&neuron_idx).copied()
335 }
336
337 pub fn get_stats(&self) -> MemoryNeuronStats {
339 let n = self.next_available_index;
340
341 if n == 0 {
342 return MemoryNeuronStats {
343 total_capacity: self.capacity,
344 ..Default::default()
345 };
346 }
347
348 let active_count = self.is_active[..n].iter().filter(|&&x| x).count();
349 let longterm_count = (0..n)
350 .filter(|&i| self.is_active[i] && self.is_longterm_memory[i])
351 .count();
352 let dead_count = n - active_count;
353
354 let (avg_lifespan, avg_activation_count) = if active_count > 0 {
356 let total_lifespan: u32 = (0..n)
357 .filter(|&i| self.is_active[i])
358 .map(|i| self.lifespan_current[i])
359 .sum();
360 let total_activations: u32 = (0..n)
361 .filter(|&i| self.is_active[i])
362 .map(|i| self.activation_count[i])
363 .sum();
364
365 (
366 total_lifespan as f64 / active_count as f64,
367 total_activations as f64 / active_count as f64,
368 )
369 } else {
370 (0.0, 0.0)
371 };
372
373 let memory_usage = self.capacity * (
375 std::mem::size_of::<u32>() * 4 + std::mem::size_of::<f32>() + std::mem::size_of::<u64>() * 2 + std::mem::size_of::<bool>() * 2 ) + self.pattern_hash_to_index.len() * (8 + 8) + self.area_neuron_indices.len() * 64; MemoryNeuronStats {
383 total_capacity: self.capacity,
384 active_neurons: active_count,
385 longterm_neurons: longterm_count,
386 dead_neurons: dead_count,
387 reusable_indices: self.reusable_indices.len(),
388 memory_usage_bytes: memory_usage,
389 avg_lifespan,
390 avg_activation_count,
391 }
392 }
393
394 pub fn get_id_allocation_stats(&self) -> AllocationStats {
396 self.id_manager.get_allocation_stats()
397 }
398
399 fn get_available_index_internal(&mut self) -> Option<usize> {
401 if let Some(&idx) = self.reusable_indices.iter().next() {
403 self.reusable_indices.remove(&idx);
404 return Some(idx);
405 }
406
407 if self.next_available_index < self.capacity {
409 let idx = self.next_available_index;
410 self.next_available_index += 1;
411 Some(idx)
412 } else {
413 None
414 }
415 }
416
417 fn cleanup_dead_neuron_internal(&mut self, neuron_idx: usize) {
419 let neuron_id = self.neuron_ids[neuron_idx];
421 self.id_manager.deallocate_memory_neuron_id(neuron_id);
422
423 if let Some(pattern_hash) = self.index_to_pattern_hash.remove(&neuron_idx) {
425 self.pattern_hash_to_index.remove(&pattern_hash);
426 }
427
428 let area_id = self.cortical_area_ids[neuron_idx];
430 if let Some(indices) = self.area_neuron_indices.get_mut(&area_id) {
431 indices.remove(&neuron_idx);
432 }
433
434 self.reusable_indices.insert(neuron_idx);
436 }
437
438 fn is_valid_index(&self, neuron_idx: usize) -> bool {
440 neuron_idx < self.next_available_index
441 }
442
443 pub fn reset(&mut self) {
445 self.neuron_ids.fill(0);
446 self.cortical_area_ids.fill(0);
447 self.is_active.fill(false);
448 self.lifespan_current.fill(0);
449 self.lifespan_initial.fill(0);
450 self.lifespan_growth_rate.fill(0.0);
451 self.is_longterm_memory.fill(false);
452 self.creation_burst.fill(0);
453 self.last_activation_burst.fill(0);
454 self.activation_count.fill(0);
455
456 self.pattern_hash_to_index.clear();
457 self.index_to_pattern_hash.clear();
458 self.area_neuron_indices.clear();
459
460 self.next_available_index = 0;
461 self.reusable_indices.clear();
462
463 self.id_manager.reset();
464 }
465}
466
467#[cfg(test)]
468mod tests {
469 use super::*;
470
471 #[test]
472 fn test_lifecycle_config_default() {
473 let config = MemoryNeuronLifecycleConfig::default();
474 assert_eq!(config.initial_lifespan, 20);
475 assert_eq!(config.lifespan_growth_rate, 3.0);
476 assert_eq!(config.longterm_threshold, 100);
477 assert_eq!(config.max_reactivations, 1000);
478 }
479
480 #[test]
481 fn test_create_memory_neuron() {
482 let mut array = MemoryNeuronArray::new(1000);
483 let config = MemoryNeuronLifecycleConfig::default();
484
485 let pattern_hash = 0x0101010101010101u64;
486 let neuron_idx = array.create_memory_neuron(pattern_hash, 100, 0, &config);
487
488 assert!(neuron_idx.is_some());
489 let idx = neuron_idx.unwrap();
490 assert!(array.is_active[idx]);
491 assert_eq!(array.cortical_area_ids[idx], 100);
492 assert_eq!(array.lifespan_current[idx], config.initial_lifespan);
493 assert_eq!(array.activation_count[idx], 1);
494 assert_eq!(array.creation_burst[idx], 0);
495 }
496
497 #[test]
498 fn test_create_duplicate_pattern() {
499 let mut array = MemoryNeuronArray::new(1000);
500 let config = MemoryNeuronLifecycleConfig::default();
501
502 let pattern_hash = 0x0101010101010101u64;
503 let idx1 = array
504 .create_memory_neuron(pattern_hash, 100, 0, &config)
505 .unwrap();
506
507 let idx2 = array
509 .create_memory_neuron(pattern_hash, 100, 1, &config)
510 .unwrap();
511
512 assert_eq!(idx1, idx2);
513 assert_eq!(array.activation_count[idx1], 2); }
515
516 #[test]
517 fn test_multiple_neurons() {
518 let mut array = MemoryNeuronArray::new(1000);
519 let config = MemoryNeuronLifecycleConfig::default();
520
521 let mut neurons = Vec::new();
522 for i in 0..10 {
523 let pattern_hash = i as u64;
524 let idx = array
525 .create_memory_neuron(pattern_hash, 100, 0, &config)
526 .unwrap();
527 neurons.push(idx);
528 }
529
530 assert_eq!(neurons.len(), 10);
531 assert_eq!(array.next_available_index, 10);
532
533 let stats = array.get_stats();
534 assert_eq!(stats.active_neurons, 10);
535 }
536
537 #[test]
538 fn test_reactivate_memory_neuron() {
539 let mut array = MemoryNeuronArray::new(1000);
540 let config = MemoryNeuronLifecycleConfig::default();
541
542 let pattern_hash = 0x0101010101010101u64;
543 let idx = array
544 .create_memory_neuron(pattern_hash, 100, 0, &config)
545 .unwrap();
546
547 let initial_count = array.activation_count[idx];
548 let initial_lifespan = array.lifespan_current[idx];
549
550 assert!(array.reactivate_memory_neuron(idx, 1));
551
552 assert_eq!(array.activation_count[idx], initial_count + 1);
553 assert_eq!(array.last_activation_burst[idx], 1);
554
555 let expected_lifespan = initial_lifespan + config.lifespan_growth_rate as u32;
557 assert_eq!(array.lifespan_current[idx], expected_lifespan);
558 }
559
560 #[test]
561 fn test_reactivate_invalid_neuron() {
562 let mut array = MemoryNeuronArray::new(1000);
563
564 assert!(!array.reactivate_memory_neuron(0, 1));
566 assert!(!array.reactivate_memory_neuron(999, 1));
567 }
568
569 #[test]
570 fn test_age_memory_neurons() {
571 let mut array = MemoryNeuronArray::new(1000);
572 let config = MemoryNeuronLifecycleConfig {
573 initial_lifespan: 2,
574 ..Default::default()
575 };
576
577 let pattern_hash = 0x0101010101010101u64;
578 let idx = array
579 .create_memory_neuron(pattern_hash, 100, 0, &config)
580 .unwrap();
581
582 let died = array.age_memory_neurons(1);
584 assert!(died.is_empty());
585 assert_eq!(array.lifespan_current[idx], 1);
586
587 let died = array.age_memory_neurons(2);
589 assert_eq!(died.len(), 1);
590 assert_eq!(died[0], idx);
591 assert!(!array.is_active[idx]);
592
593 let found = array.find_neuron_by_pattern(&pattern_hash);
595 assert!(found.is_none());
596 }
597
598 #[test]
599 fn test_age_multiple_neurons() {
600 let mut array = MemoryNeuronArray::new(1000);
601 let config = MemoryNeuronLifecycleConfig {
602 initial_lifespan: 5,
603 ..Default::default()
604 };
605
606 let mut neurons = Vec::new();
607 for i in 0..10 {
608 let pattern_hash = i as u64;
609 let idx = array
610 .create_memory_neuron(pattern_hash, 100, 0, &config)
611 .unwrap();
612 neurons.push(idx);
613 }
614
615 for burst in 1..=5 {
617 let died = array.age_memory_neurons(burst);
618 if burst < 5 {
619 assert_eq!(died.len(), 0);
620 } else {
621 assert_eq!(died.len(), 10);
622 }
623 }
624
625 let stats = array.get_stats();
626 assert_eq!(stats.active_neurons, 0);
627 assert_eq!(stats.dead_neurons, 10);
628 }
629
630 #[test]
631 fn test_longterm_memory_no_aging() {
632 let mut array = MemoryNeuronArray::new(1000);
633 let config = MemoryNeuronLifecycleConfig {
634 initial_lifespan: 100,
635 ..Default::default()
636 };
637
638 let pattern_hash = 0x0101010101010101u64;
639 let idx = array
640 .create_memory_neuron(pattern_hash, 100, 0, &config)
641 .unwrap();
642
643 let converted = array.check_longterm_conversion(100);
645 assert_eq!(converted.len(), 1);
646 assert!(array.is_longterm_memory[idx]);
647
648 let initial_lifespan = array.lifespan_current[idx];
649
650 for burst in 1..=50 {
652 array.age_memory_neurons(burst);
653 }
654
655 assert!(array.is_active[idx]);
656 assert_eq!(array.lifespan_current[idx], initial_lifespan); }
658
659 #[test]
660 fn test_longterm_conversion() {
661 let mut array = MemoryNeuronArray::new(1000);
662 let config = MemoryNeuronLifecycleConfig {
663 initial_lifespan: 100,
664 ..Default::default()
665 };
666
667 let pattern_hash = 0x0101010101010101u64;
668 let idx = array
669 .create_memory_neuron(pattern_hash, 100, 0, &config)
670 .unwrap();
671
672 let converted = array.check_longterm_conversion(100);
673 assert_eq!(converted.len(), 1);
674 assert_eq!(converted[0], idx);
675 assert!(array.is_longterm_memory[idx]);
676
677 let converted2 = array.check_longterm_conversion(100);
679 assert_eq!(converted2.len(), 0);
680 }
681
682 #[test]
683 fn test_longterm_conversion_threshold() {
684 let mut array = MemoryNeuronArray::new(1000);
685 let config = MemoryNeuronLifecycleConfig {
686 initial_lifespan: 50,
687 ..Default::default()
688 };
689
690 let pattern_hash = 0x0101010101010101u64;
691 let idx = array
692 .create_memory_neuron(pattern_hash, 100, 0, &config)
693 .unwrap();
694
695 let converted = array.check_longterm_conversion(100);
697 assert_eq!(converted.len(), 0);
698 assert!(!array.is_longterm_memory[idx]);
699
700 for burst in 1..=20 {
702 array.reactivate_memory_neuron(idx, burst);
703 }
704
705 let converted = array.check_longterm_conversion(100);
707 assert_eq!(converted.len(), 1);
708 assert!(array.is_longterm_memory[idx]);
709 }
710
711 #[test]
712 fn test_find_neuron_by_pattern() {
713 let mut array = MemoryNeuronArray::new(1000);
714 let config = MemoryNeuronLifecycleConfig::default();
715
716 let pattern_hash = 0x0101010101010101u64;
717 let idx = array
718 .create_memory_neuron(pattern_hash, 100, 0, &config)
719 .unwrap();
720
721 let found = array.find_neuron_by_pattern(&pattern_hash);
722 assert_eq!(found, Some(idx));
723
724 let pattern_hash2 = 0x0202020202020202u64;
726 let found2 = array.find_neuron_by_pattern(&pattern_hash2);
727 assert_eq!(found2, None);
728 }
729
730 #[test]
731 fn test_get_active_neurons_by_area() {
732 let mut array = MemoryNeuronArray::new(1000);
733 let config = MemoryNeuronLifecycleConfig::default();
734
735 for area in [100, 200] {
737 for i in 0..5 {
738 let pattern_hash = ((area as u64) << 32) | (i as u64);
739 array.create_memory_neuron(pattern_hash, area, 0, &config);
740 }
741 }
742
743 let area100_neurons = array.get_active_neurons_by_area(100);
744 let area200_neurons = array.get_active_neurons_by_area(200);
745
746 assert_eq!(area100_neurons.len(), 5);
747 assert_eq!(area200_neurons.len(), 5);
748
749 let area999_neurons = array.get_active_neurons_by_area(999);
751 assert_eq!(area999_neurons.len(), 0);
752 }
753
754 #[test]
755 fn test_get_neuron_id() {
756 let mut array = MemoryNeuronArray::new(1000);
757 let config = MemoryNeuronLifecycleConfig::default();
758
759 let pattern_hash = 0x0101010101010101u64;
760 let idx = array
761 .create_memory_neuron(pattern_hash, 100, 0, &config)
762 .unwrap();
763
764 let neuron_id = array.get_neuron_id(idx);
765 assert!(neuron_id.is_some());
766
767 let invalid_id = array.get_neuron_id(999);
769 assert!(invalid_id.is_none());
770 }
771
772 #[test]
773 fn test_index_reuse() {
774 let mut array = MemoryNeuronArray::new(1000);
775 let config = MemoryNeuronLifecycleConfig {
776 initial_lifespan: 1,
777 ..Default::default()
778 };
779
780 let pattern_hash = 0x0101010101010101u64;
781 let idx1 = array
782 .create_memory_neuron(pattern_hash, 100, 0, &config)
783 .unwrap();
784 assert_eq!(idx1, 0);
785
786 array.age_memory_neurons(1);
788 assert!(!array.is_active[idx1]);
789
790 let pattern_hash2 = 0x0202020202020202u64;
792 let idx2 = array
793 .create_memory_neuron(pattern_hash2, 100, 2, &config)
794 .unwrap();
795 assert_eq!(idx2, 0); assert_eq!(array.next_available_index, 1); }
798
799 #[test]
800 fn test_get_stats() {
801 let mut array = MemoryNeuronArray::new(1000);
802 let config = MemoryNeuronLifecycleConfig::default();
803
804 for i in 0..10 {
806 let pattern_hash = i as u64;
807 array.create_memory_neuron(pattern_hash, 100, 0, &config);
808 }
809
810 let stats = array.get_stats();
811 assert_eq!(stats.total_capacity, 1000);
812 assert_eq!(stats.active_neurons, 10);
813 assert_eq!(stats.longterm_neurons, 0);
814 assert_eq!(stats.dead_neurons, 0);
815 assert!(stats.avg_lifespan > 0.0);
816 assert!(stats.avg_activation_count >= 1.0);
817 assert!(stats.memory_usage_bytes > 0);
818 }
819
820 #[test]
821 fn test_capacity_exhaustion() {
822 let mut array = MemoryNeuronArray::new(5);
823 let config = MemoryNeuronLifecycleConfig::default();
824
825 for i in 0..5 {
827 let pattern_hash = i as u64;
828 let idx = array.create_memory_neuron(pattern_hash, 100, 0, &config);
829 assert!(idx.is_some());
830 }
831
832 let pattern_hash = 0x6363636363636363u64;
834 let idx = array.create_memory_neuron(pattern_hash, 100, 0, &config);
835 assert!(idx.is_none());
836 }
837
838 #[test]
839 fn test_reset() {
840 let mut array = MemoryNeuronArray::new(1000);
841 let config = MemoryNeuronLifecycleConfig::default();
842
843 for i in 0..5 {
845 let pattern_hash = i as u64;
846 array.create_memory_neuron(pattern_hash, 100, 0, &config);
847 }
848
849 assert_eq!(array.next_available_index, 5);
850
851 array.reset();
852
853 assert_eq!(array.next_available_index, 0);
854 let stats = array.get_stats();
855 assert_eq!(stats.active_neurons, 0);
856 }
857
858 #[test]
859 fn test_lifespan_growth_on_reactivation() {
860 let mut array = MemoryNeuronArray::new(1000);
861 let config = MemoryNeuronLifecycleConfig {
862 initial_lifespan: 10,
863 lifespan_growth_rate: 5.0,
864 longterm_threshold: 100,
865 max_reactivations: 1000,
866 };
867
868 let pattern_hash = 0x0101010101010101u64;
869 let idx = array
870 .create_memory_neuron(pattern_hash, 100, 0, &config)
871 .unwrap();
872
873 assert_eq!(array.lifespan_current[idx], 10);
874
875 array.reactivate_memory_neuron(idx, 1);
876 assert_eq!(array.lifespan_current[idx], 15);
877
878 array.reactivate_memory_neuron(idx, 2);
879 assert_eq!(array.lifespan_current[idx], 20);
880 }
881}