1use crate::{
18 GenomeMetadata, GenomeSignatures, GenomeStats, MorphologyRegistry, PhysiologyConfig,
19 RuntimeGenome,
20};
21use feagi_structures::genomic::cortical_area::CoreCorticalType;
22use feagi_structures::genomic::cortical_area::{CorticalArea, CorticalAreaDimensions};
23use feagi_structures::genomic::descriptors::GenomeCoordinate3D;
24use serde_json::Value;
25use std::collections::HashMap;
26
27pub const ESSENTIAL_GENOME_JSON: &str = include_str!("../genomes/essential_genome.json");
29
30pub const BAREBONES_GENOME_JSON: &str = include_str!("../genomes/barebones_genome.json");
32
33pub const TEST_GENOME_JSON: &str = include_str!("../genomes/test_genome.json");
35
36pub const VISION_GENOME_JSON: &str = include_str!("../genomes/vision_genome.json");
38
39pub fn get_default_neural_properties() -> HashMap<String, Value> {
41 let mut props = HashMap::new();
42 props.insert("per_voxel_neuron_cnt".to_string(), Value::from(1));
43 props.insert("synapse_attractivity".to_string(), Value::from(100.0));
44 props.insert("degeneration".to_string(), Value::from(0.0));
45 props.insert("psp_uniform_distribution".to_string(), Value::from(true));
46 props.insert("postsynaptic_current_max".to_string(), Value::from(10000.0));
47 props.insert("postsynaptic_current".to_string(), Value::from(500.0));
48 props.insert("firing_threshold".to_string(), Value::from(0.1));
49 props.insert("refractory_period".to_string(), Value::from(0));
50 props.insert("leak_coefficient".to_string(), Value::from(0.0));
51 props.insert("leak_variability".to_string(), Value::from(0.0));
52 props.insert("consecutive_fire_cnt_max".to_string(), Value::from(0));
53 props.insert("snooze_length".to_string(), Value::from(0));
54 props.insert("mp_charge_accumulation".to_string(), Value::from(false));
55 props.insert("mp_driven_psp".to_string(), Value::from(false));
56 props.insert("neuron_excitability".to_string(), Value::from(1.0));
57 props.insert("visualization".to_string(), Value::from(true));
58 props.insert("memory_twin_of".to_string(), Value::Null);
59 props.insert(
60 "cortical_mapping_dst".to_string(),
61 Value::Object(serde_json::Map::new()),
62 );
63 props
64}
65
66pub fn create_death_area() -> CorticalArea {
68 let cortical_id = CoreCorticalType::Death.to_cortical_id();
69 let cortical_type = cortical_id
70 .as_cortical_type()
71 .expect("Death cortical ID should map to Core type");
72
73 let mut area = CorticalArea::new(
74 cortical_id,
75 0, "Death".to_string(),
77 CorticalAreaDimensions::new(1, 1, 1).expect("Failed to create dimensions"),
78 GenomeCoordinate3D::new(0, 0, -20),
79 cortical_type,
80 )
81 .expect("Failed to create _death area");
82
83 let mut props = get_default_neural_properties();
84 props.insert("cortical_group".to_string(), Value::from("CORE"));
85 props.insert("2d_coordinate".to_string(), Value::from(vec![-10, -20]));
86 area.properties = props;
87 area
88}
89
90pub fn create_power_area() -> CorticalArea {
92 let cortical_id = CoreCorticalType::Power.to_cortical_id();
93 let cortical_type = cortical_id
94 .as_cortical_type()
95 .expect("Power cortical ID should map to Core type");
96
97 let mut area = CorticalArea::new(
98 cortical_id,
99 1, "Brain_Power".to_string(),
101 CorticalAreaDimensions::new(1, 1, 1).expect("Failed to create dimensions"),
102 GenomeCoordinate3D::new(0, 0, -20),
103 cortical_type,
104 )
105 .expect("Failed to create _power area");
106
107 let mut props = get_default_neural_properties();
108 props.insert("cortical_group".to_string(), Value::from("CORE"));
109 props.insert("2d_coordinate".to_string(), Value::from(vec![-10, -10]));
110 props.insert("firing_threshold".to_string(), Value::from(0.1));
111 props.insert("postsynaptic_current".to_string(), Value::from(500.0));
112 props.insert("neuron_excitability".to_string(), Value::from(100.0));
113 area.properties = props;
114 area
115}
116
117pub fn create_fatigue_area() -> CorticalArea {
119 let cortical_id = CoreCorticalType::Fatigue.to_cortical_id();
120 let cortical_type = cortical_id
121 .as_cortical_type()
122 .expect("Fatigue cortical ID should map to Core type");
123
124 let mut area = CorticalArea::new(
125 cortical_id,
126 2, "Fatigue".to_string(),
128 CorticalAreaDimensions::new(1, 1, 1).expect("Failed to create dimensions"),
129 GenomeCoordinate3D::new(0, 0, -30),
130 cortical_type,
131 )
132 .expect("Failed to create _fatigue area");
133
134 let mut props = get_default_neural_properties();
135 props.insert("cortical_group".to_string(), Value::from("CORE"));
136 props.insert("2d_coordinate".to_string(), Value::from(vec![-10, 0]));
137 area.properties = props;
138 area
139}
140
141pub fn create_minimal_genome(genome_id: String, genome_title: String) -> RuntimeGenome {
143 RuntimeGenome {
144 metadata: GenomeMetadata {
145 genome_id,
146 genome_title,
147 genome_description: "Minimal genome template".to_string(),
148 version: "2.0".to_string(),
149 timestamp: std::time::SystemTime::now()
150 .duration_since(std::time::UNIX_EPOCH)
151 .unwrap()
152 .as_secs_f64(),
153 brain_regions_root: None, },
155 cortical_areas: HashMap::new(),
156 brain_regions: HashMap::new(),
157 morphologies: MorphologyRegistry::new(),
158 physiology: PhysiologyConfig::default(),
159 signatures: GenomeSignatures {
160 genome: String::new(),
161 blueprint: String::new(),
162 physiology: String::new(),
163 morphologies: None,
164 },
165 stats: GenomeStats::default(),
166 }
167}
168
169pub fn create_genome_with_core_areas(genome_id: String, genome_title: String) -> RuntimeGenome {
171 let mut genome = create_minimal_genome(genome_id, genome_title);
172
173 let death_id =
175 crate::genome::parser::string_to_cortical_id("_death").expect("Valid cortical ID");
176 let power_id =
177 crate::genome::parser::string_to_cortical_id("_power").expect("Valid cortical ID");
178 let fatigue_id =
179 crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid cortical ID");
180
181 genome.cortical_areas.insert(death_id, create_death_area());
182 genome.cortical_areas.insert(power_id, create_power_area());
183 genome
184 .cortical_areas
185 .insert(fatigue_id, create_fatigue_area());
186
187 genome
188}
189
190pub fn create_genome_with_core_morphologies(
192 genome_id: String,
193 genome_title: String,
194) -> RuntimeGenome {
195 let mut genome = create_minimal_genome(genome_id, genome_title);
196
197 add_core_morphologies(&mut genome.morphologies);
199
200 genome
201}
202
203pub fn ensure_core_components(genome: &mut RuntimeGenome) -> (usize, usize) {
218 let mut areas_added = 0;
219 let mut morphologies_added = 0;
220
221 let death_id =
223 crate::genome::parser::string_to_cortical_id("_death").expect("Valid cortical ID");
224 let power_id =
225 crate::genome::parser::string_to_cortical_id("_power").expect("Valid cortical ID");
226 let fatigue_id =
227 crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid cortical ID");
228
229 if let std::collections::hash_map::Entry::Vacant(e) = genome.cortical_areas.entry(death_id) {
231 let death_area = create_death_area();
232 e.insert(death_area);
233 areas_added += 1;
234 tracing::info!("Added missing core area: _death (cortical_idx=0)");
235 }
236
237 if let std::collections::hash_map::Entry::Vacant(e) = genome.cortical_areas.entry(power_id) {
238 let power_area = create_power_area();
239 e.insert(power_area);
240 areas_added += 1;
241 tracing::info!("Added missing core area: _power (cortical_idx=1)");
242 }
243
244 if let std::collections::hash_map::Entry::Vacant(e) = genome.cortical_areas.entry(fatigue_id) {
245 let fatigue_area = create_fatigue_area();
246 e.insert(fatigue_area);
247 areas_added += 1;
248 tracing::info!("Added missing core area: _fatigue (cortical_idx=2)");
249 }
250
251 let required_morphologies = vec![
253 "block_to_block",
254 "projector",
255 "sweeper",
256 "last_to_first",
257 "bitmask_encoder_x",
258 "bitmask_encoder_y",
259 "bitmask_encoder_z",
260 "bitmask_decoder_x",
261 "bitmask_decoder_y",
262 "bitmask_decoder_z",
263 "episodic_memory",
264 "memory_replay",
265 "associative_memory",
266 "rotator_z",
267 "all_to_0-0-0",
268 "0-0-0_to_all",
269 "tile",
270 "lateral_+x",
271 "lateral_-x",
272 "lateral_+y",
273 "lateral_-y",
274 "lateral_+z",
275 "lateral_-z",
276 ];
277
278 for morph_name in required_morphologies {
279 if !genome.morphologies.contains(morph_name) {
280 morphologies_added += 1;
281 }
282 }
283
284 if morphologies_added > 0 {
286 add_core_morphologies(&mut genome.morphologies);
287 tracing::info!("Added {} missing core morphologies", morphologies_added);
288 }
289
290 (areas_added, morphologies_added)
291}
292
293pub fn add_core_morphologies(registry: &mut MorphologyRegistry) {
295 use crate::{Morphology, MorphologyParameters, MorphologyType};
296
297 registry.add_morphology(
299 "block_to_block".to_string(),
300 Morphology {
301 morphology_type: MorphologyType::Vectors,
302 parameters: MorphologyParameters::Vectors {
303 vectors: vec![[0, 0, 0]],
304 },
305 class: "core".to_string(),
306 },
307 );
308
309 registry.add_morphology(
311 "projector".to_string(),
312 Morphology {
313 morphology_type: MorphologyType::Functions,
314 parameters: MorphologyParameters::Functions {},
315 class: "core".to_string(),
316 },
317 );
318
319 registry.add_morphology(
321 "sweeper".to_string(),
322 Morphology {
323 morphology_type: MorphologyType::Functions,
324 parameters: MorphologyParameters::Functions {},
325 class: "core".to_string(),
326 },
327 );
328
329 registry.add_morphology(
331 "last_to_first".to_string(),
332 Morphology {
333 morphology_type: MorphologyType::Functions,
334 parameters: MorphologyParameters::Functions {},
335 class: "core".to_string(),
336 },
337 );
338
339 registry.add_morphology(
341 "episodic_memory".to_string(),
342 Morphology {
343 morphology_type: MorphologyType::Functions,
344 parameters: MorphologyParameters::Functions {},
345 class: "core".to_string(),
346 },
347 );
348
349 registry.add_morphology(
351 "memory_replay".to_string(),
352 Morphology {
353 morphology_type: MorphologyType::Functions,
354 parameters: MorphologyParameters::Functions {},
355 class: "core".to_string(),
356 },
357 );
358
359 registry.add_morphology(
361 "associative_memory".to_string(),
362 Morphology {
363 morphology_type: MorphologyType::Functions,
364 parameters: MorphologyParameters::Functions {},
365 class: "core".to_string(),
366 },
367 );
368
369 registry.add_morphology(
371 "rotator_z".to_string(),
372 Morphology {
373 morphology_type: MorphologyType::Functions,
374 parameters: MorphologyParameters::Functions {},
375 class: "core".to_string(),
376 },
377 );
378
379 registry.add_morphology(
381 "bitmask_encoder_x".to_string(),
382 Morphology {
383 morphology_type: MorphologyType::Functions,
384 parameters: MorphologyParameters::Functions {},
385 class: "core".to_string(),
386 },
387 );
388
389 registry.add_morphology(
391 "bitmask_encoder_y".to_string(),
392 Morphology {
393 morphology_type: MorphologyType::Functions,
394 parameters: MorphologyParameters::Functions {},
395 class: "core".to_string(),
396 },
397 );
398
399 registry.add_morphology(
401 "bitmask_encoder_z".to_string(),
402 Morphology {
403 morphology_type: MorphologyType::Functions,
404 parameters: MorphologyParameters::Functions {},
405 class: "core".to_string(),
406 },
407 );
408
409 registry.add_morphology(
411 "bitmask_decoder_x".to_string(),
412 Morphology {
413 morphology_type: MorphologyType::Functions,
414 parameters: MorphologyParameters::Functions {},
415 class: "core".to_string(),
416 },
417 );
418
419 registry.add_morphology(
421 "bitmask_decoder_y".to_string(),
422 Morphology {
423 morphology_type: MorphologyType::Functions,
424 parameters: MorphologyParameters::Functions {},
425 class: "core".to_string(),
426 },
427 );
428
429 registry.add_morphology(
431 "bitmask_decoder_z".to_string(),
432 Morphology {
433 morphology_type: MorphologyType::Functions,
434 parameters: MorphologyParameters::Functions {},
435 class: "core".to_string(),
436 },
437 );
438
439 registry.add_morphology(
441 "all_to_0-0-0".to_string(),
442 Morphology {
443 morphology_type: MorphologyType::Patterns,
444 parameters: MorphologyParameters::Patterns {
445 patterns: vec![[
446 vec![
447 crate::PatternElement::Wildcard,
448 crate::PatternElement::Wildcard,
449 crate::PatternElement::Wildcard,
450 ],
451 vec![
452 crate::PatternElement::Value(0),
453 crate::PatternElement::Value(0),
454 crate::PatternElement::Value(0),
455 ],
456 ]],
457 },
458 class: "core".to_string(),
459 },
460 );
461
462 registry.add_morphology(
464 "0-0-0_to_all".to_string(),
465 Morphology {
466 morphology_type: MorphologyType::Patterns,
467 parameters: MorphologyParameters::Patterns {
468 patterns: vec![[
469 vec![
470 crate::PatternElement::Value(0),
471 crate::PatternElement::Value(0),
472 crate::PatternElement::Value(0),
473 ],
474 vec![
475 crate::PatternElement::Wildcard,
476 crate::PatternElement::Wildcard,
477 crate::PatternElement::Wildcard,
478 ],
479 ]],
480 },
481 class: "core".to_string(),
482 },
483 );
484
485 registry.add_morphology(
487 "tile".to_string(),
488 Morphology {
489 morphology_type: MorphologyType::Composite,
490 parameters: MorphologyParameters::Composite {
491 src_seed: [16, 16, 1],
492 src_pattern: vec![[1, 0], [1, 0], [1, 0]],
493 mapper_morphology: "projector".to_string(),
494 },
495 class: "core".to_string(),
496 },
497 );
498
499 registry.add_morphology(
501 "lateral_+x".to_string(),
502 Morphology {
503 morphology_type: MorphologyType::Vectors,
504 parameters: MorphologyParameters::Vectors {
505 vectors: vec![[1, 0, 0]],
506 },
507 class: "core".to_string(),
508 },
509 );
510
511 registry.add_morphology(
513 "lateral_-x".to_string(),
514 Morphology {
515 morphology_type: MorphologyType::Vectors,
516 parameters: MorphologyParameters::Vectors {
517 vectors: vec![[-1, 0, 0]],
518 },
519 class: "core".to_string(),
520 },
521 );
522
523 registry.add_morphology(
525 "lateral_+y".to_string(),
526 Morphology {
527 morphology_type: MorphologyType::Vectors,
528 parameters: MorphologyParameters::Vectors {
529 vectors: vec![[0, 1, 0]],
530 },
531 class: "core".to_string(),
532 },
533 );
534
535 registry.add_morphology(
537 "lateral_-y".to_string(),
538 Morphology {
539 morphology_type: MorphologyType::Vectors,
540 parameters: MorphologyParameters::Vectors {
541 vectors: vec![[0, -1, 0]],
542 },
543 class: "core".to_string(),
544 },
545 );
546
547 registry.add_morphology(
549 "lateral_+z".to_string(),
550 Morphology {
551 morphology_type: MorphologyType::Vectors,
552 parameters: MorphologyParameters::Vectors {
553 vectors: vec![[0, 0, 1]],
554 },
555 class: "core".to_string(),
556 },
557 );
558
559 registry.add_morphology(
561 "lateral_-z".to_string(),
562 Morphology {
563 morphology_type: MorphologyType::Vectors,
564 parameters: MorphologyParameters::Vectors {
565 vectors: vec![[0, 0, -1]],
566 },
567 class: "core".to_string(),
568 },
569 );
570}
571
572pub fn load_essential_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
576 use crate::genome::loader::load_genome_from_json;
577 let mut genome = load_genome_from_json(ESSENTIAL_GENOME_JSON)?;
578 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
579 if areas_added > 0 || morphs_added > 0 {
580 tracing::info!(
581 "Essential genome: added {} core areas, {} core morphologies",
582 areas_added,
583 morphs_added
584 );
585 }
586 Ok(genome)
587}
588
589pub fn load_barebones_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
593 use crate::genome::loader::load_genome_from_json;
594 let mut genome = load_genome_from_json(BAREBONES_GENOME_JSON)?;
595 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
596 if areas_added > 0 || morphs_added > 0 {
597 tracing::info!(
598 "Barebones genome: added {} core areas, {} core morphologies",
599 areas_added,
600 morphs_added
601 );
602 }
603 Ok(genome)
604}
605
606pub fn load_test_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
610 use crate::genome::loader::load_genome_from_json;
611 let mut genome = load_genome_from_json(TEST_GENOME_JSON)?;
612 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
613 if areas_added > 0 || morphs_added > 0 {
614 tracing::info!(
615 "Test genome: added {} core areas, {} core morphologies",
616 areas_added,
617 morphs_added
618 );
619 }
620 Ok(genome)
621}
622
623pub fn load_vision_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
627 use crate::genome::loader::load_genome_from_json;
628 let mut genome = load_genome_from_json(VISION_GENOME_JSON)?;
629 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
630 if areas_added > 0 || morphs_added > 0 {
631 tracing::info!(
632 "Vision genome: added {} core areas, {} core morphologies",
633 areas_added,
634 morphs_added
635 );
636 }
637 Ok(genome)
638}
639
640#[cfg(test)]
641mod tests {
642 use super::*;
643
644 #[test]
645 fn test_create_minimal_genome() {
646 let genome = create_minimal_genome("test_genome".to_string(), "Test Genome".to_string());
647
648 assert_eq!(genome.metadata.genome_id, "test_genome");
649 assert_eq!(genome.metadata.version, "2.0");
650 assert_eq!(genome.cortical_areas.len(), 0);
651 assert_eq!(genome.morphologies.count(), 0);
652 }
653
654 #[test]
655 fn test_create_genome_with_core_areas() {
656 let genome =
657 create_genome_with_core_areas("test_genome".to_string(), "Test Genome".to_string());
658
659 assert_eq!(genome.metadata.genome_id, "test_genome");
660 assert_eq!(genome.cortical_areas.len(), 3);
661
662 let death_id = crate::genome::parser::string_to_cortical_id("_death").expect("Valid ID");
663 let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
664 let fatigue_id =
665 crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid ID");
666 assert!(genome.cortical_areas.contains_key(&death_id));
667 assert!(genome.cortical_areas.contains_key(&power_id));
668 assert!(genome.cortical_areas.contains_key(&fatigue_id));
669
670 let power = genome.cortical_areas.get(&power_id).unwrap();
672 assert_eq!(power.cortical_id.as_base_64(), power_id.as_base_64());
673 assert_eq!(power.cortical_idx, 1);
674 assert_eq!(power.dimensions.width, 1);
675 assert_eq!(power.dimensions.height, 1);
676 assert_eq!(power.dimensions.depth, 1);
677 }
678
679 #[test]
680 fn test_create_genome_with_core_morphologies() {
681 let genome = create_genome_with_core_morphologies(
682 "test_genome".to_string(),
683 "Test Genome".to_string(),
684 );
685
686 assert_eq!(genome.metadata.genome_id, "test_genome");
687 assert!(genome.morphologies.count() > 0);
688 assert!(genome.morphologies.contains("block_to_block"));
689 assert!(genome.morphologies.contains("projector"));
690 assert!(genome.morphologies.contains("lateral_+x"));
691 }
692
693 #[test]
694 fn test_add_core_morphologies() {
695 let mut registry = MorphologyRegistry::new();
696 add_core_morphologies(&mut registry);
697
698 assert!(registry.count() >= 11);
700 assert!(registry.contains("block_to_block"));
701 assert!(registry.contains("projector"));
702 assert!(registry.contains("all_to_0-0-0"));
703 assert!(registry.contains("lateral_+x"));
704 assert!(registry.contains("lateral_-z"));
705 }
706
707 #[test]
708 fn test_embedded_genomes_exist() {
709 #[allow(clippy::const_is_empty)]
713 {
714 assert!(!ESSENTIAL_GENOME_JSON.is_empty());
715 assert!(!BAREBONES_GENOME_JSON.is_empty());
716 assert!(!TEST_GENOME_JSON.is_empty());
717 assert!(!VISION_GENOME_JSON.is_empty());
718 }
719 }
720
721 #[test]
722 fn test_load_essential_genome() {
723 let genome = load_essential_genome().expect("Failed to load essential genome");
724 assert!(!genome.cortical_areas.is_empty());
725 let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
727 assert!(genome.cortical_areas.contains_key(&power_id));
728 }
729
730 #[test]
731 fn test_ensure_core_components_adds_missing_areas() {
732 let mut genome = create_minimal_genome("test".to_string(), "Test".to_string());
734
735 assert_eq!(genome.cortical_areas.len(), 0);
736
737 let (areas_added, _) = ensure_core_components(&mut genome);
739
740 assert_eq!(areas_added, 3);
742
743 let death_id = crate::genome::parser::string_to_cortical_id("_death").expect("Valid ID");
744 let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
745 let fatigue_id =
746 crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid ID");
747 assert!(genome.cortical_areas.contains_key(&death_id));
748 assert!(genome.cortical_areas.contains_key(&power_id));
749 assert!(genome.cortical_areas.contains_key(&fatigue_id));
750
751 assert_eq!(
753 genome.cortical_areas.get(&death_id).unwrap().cortical_idx,
754 0
755 );
756 assert_eq!(
757 genome.cortical_areas.get(&power_id).unwrap().cortical_idx,
758 1
759 );
760 assert_eq!(
761 genome.cortical_areas.get(&fatigue_id).unwrap().cortical_idx,
762 2
763 );
764 }
765
766 #[test]
767 fn test_ensure_core_components_adds_missing_morphologies() {
768 let mut genome = create_genome_with_core_areas("test".to_string(), "Test".to_string());
770
771 assert_eq!(genome.morphologies.count(), 0);
772
773 let (_, morphs_added) = ensure_core_components(&mut genome);
775
776 assert!(morphs_added > 0);
778 assert!(genome.morphologies.contains("block_to_block"));
779 assert!(genome.morphologies.contains("projector"));
780 assert!(genome.morphologies.contains("episodic_memory"));
781 assert!(genome.morphologies.contains("lateral_+x"));
782 }
783
784 #[test]
785 fn test_ensure_core_components_idempotent() {
786 let mut genome = create_genome_with_core_areas("test".to_string(), "Test".to_string());
788 add_core_morphologies(&mut genome.morphologies);
789
790 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
792
793 assert_eq!(areas_added, 0);
795 assert_eq!(morphs_added, 0);
796 }
797}