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 "transpose_xy",
256 "transpose_yz",
257 "transpose_xz",
258 "sweeper",
259 "last_to_first",
260 "bitmask_encoder_x",
261 "bitmask_encoder_y",
262 "bitmask_encoder_z",
263 "bitmask_decoder_x",
264 "bitmask_decoder_y",
265 "bitmask_decoder_z",
266 "episodic_memory",
267 "memory_replay",
268 "associative_memory",
269 "rotator_z",
270 "all_to_0-0-0",
271 "0-0-0_to_all",
272 "tile",
273 "lateral_+x",
274 "lateral_-x",
275 "lateral_+y",
276 "lateral_-y",
277 "lateral_+z",
278 "lateral_-z",
279 ];
280
281 for morph_name in required_morphologies {
282 if !genome.morphologies.contains(morph_name) {
283 morphologies_added += 1;
284 }
285 }
286
287 if morphologies_added > 0 {
289 add_core_morphologies(&mut genome.morphologies);
290 tracing::info!("Added {} missing core morphologies", morphologies_added);
291 }
292
293 (areas_added, morphologies_added)
294}
295
296pub fn add_core_morphologies(registry: &mut MorphologyRegistry) {
298 use crate::{Morphology, MorphologyParameters, MorphologyType};
299
300 registry.add_morphology(
302 "block_to_block".to_string(),
303 Morphology {
304 morphology_type: MorphologyType::Vectors,
305 parameters: MorphologyParameters::Vectors {
306 vectors: vec![[0, 0, 0]],
307 },
308 class: "core".to_string(),
309 },
310 );
311
312 registry.add_morphology(
314 "projector".to_string(),
315 Morphology {
316 morphology_type: MorphologyType::Functions,
317 parameters: MorphologyParameters::Functions {},
318 class: "core".to_string(),
319 },
320 );
321
322 registry.add_morphology(
324 "transpose_xy".to_string(),
325 Morphology {
326 morphology_type: MorphologyType::Functions,
327 parameters: MorphologyParameters::Functions {},
328 class: "core".to_string(),
329 },
330 );
331
332 registry.add_morphology(
334 "transpose_yz".to_string(),
335 Morphology {
336 morphology_type: MorphologyType::Functions,
337 parameters: MorphologyParameters::Functions {},
338 class: "core".to_string(),
339 },
340 );
341
342 registry.add_morphology(
344 "transpose_xz".to_string(),
345 Morphology {
346 morphology_type: MorphologyType::Functions,
347 parameters: MorphologyParameters::Functions {},
348 class: "core".to_string(),
349 },
350 );
351
352 registry.add_morphology(
354 "sweeper".to_string(),
355 Morphology {
356 morphology_type: MorphologyType::Functions,
357 parameters: MorphologyParameters::Functions {},
358 class: "core".to_string(),
359 },
360 );
361
362 registry.add_morphology(
364 "last_to_first".to_string(),
365 Morphology {
366 morphology_type: MorphologyType::Functions,
367 parameters: MorphologyParameters::Functions {},
368 class: "core".to_string(),
369 },
370 );
371
372 registry.add_morphology(
374 "episodic_memory".to_string(),
375 Morphology {
376 morphology_type: MorphologyType::Functions,
377 parameters: MorphologyParameters::Functions {},
378 class: "core".to_string(),
379 },
380 );
381
382 registry.add_morphology(
384 "memory_replay".to_string(),
385 Morphology {
386 morphology_type: MorphologyType::Functions,
387 parameters: MorphologyParameters::Functions {},
388 class: "core".to_string(),
389 },
390 );
391
392 registry.add_morphology(
394 "associative_memory".to_string(),
395 Morphology {
396 morphology_type: MorphologyType::Functions,
397 parameters: MorphologyParameters::Functions {},
398 class: "core".to_string(),
399 },
400 );
401
402 registry.add_morphology(
404 "rotator_z".to_string(),
405 Morphology {
406 morphology_type: MorphologyType::Functions,
407 parameters: MorphologyParameters::Functions {},
408 class: "core".to_string(),
409 },
410 );
411
412 registry.add_morphology(
414 "bitmask_encoder_x".to_string(),
415 Morphology {
416 morphology_type: MorphologyType::Functions,
417 parameters: MorphologyParameters::Functions {},
418 class: "core".to_string(),
419 },
420 );
421
422 registry.add_morphology(
424 "bitmask_encoder_y".to_string(),
425 Morphology {
426 morphology_type: MorphologyType::Functions,
427 parameters: MorphologyParameters::Functions {},
428 class: "core".to_string(),
429 },
430 );
431
432 registry.add_morphology(
434 "bitmask_encoder_z".to_string(),
435 Morphology {
436 morphology_type: MorphologyType::Functions,
437 parameters: MorphologyParameters::Functions {},
438 class: "core".to_string(),
439 },
440 );
441
442 registry.add_morphology(
444 "bitmask_decoder_x".to_string(),
445 Morphology {
446 morphology_type: MorphologyType::Functions,
447 parameters: MorphologyParameters::Functions {},
448 class: "core".to_string(),
449 },
450 );
451
452 registry.add_morphology(
454 "bitmask_decoder_y".to_string(),
455 Morphology {
456 morphology_type: MorphologyType::Functions,
457 parameters: MorphologyParameters::Functions {},
458 class: "core".to_string(),
459 },
460 );
461
462 registry.add_morphology(
464 "bitmask_decoder_z".to_string(),
465 Morphology {
466 morphology_type: MorphologyType::Functions,
467 parameters: MorphologyParameters::Functions {},
468 class: "core".to_string(),
469 },
470 );
471
472 registry.add_morphology(
474 "all_to_0-0-0".to_string(),
475 Morphology {
476 morphology_type: MorphologyType::Patterns,
477 parameters: MorphologyParameters::Patterns {
478 patterns: vec![[
479 vec![
480 crate::PatternElement::Wildcard,
481 crate::PatternElement::Wildcard,
482 crate::PatternElement::Wildcard,
483 ],
484 vec![
485 crate::PatternElement::Value(0),
486 crate::PatternElement::Value(0),
487 crate::PatternElement::Value(0),
488 ],
489 ]],
490 },
491 class: "core".to_string(),
492 },
493 );
494
495 registry.add_morphology(
497 "0-0-0_to_all".to_string(),
498 Morphology {
499 morphology_type: MorphologyType::Patterns,
500 parameters: MorphologyParameters::Patterns {
501 patterns: vec![[
502 vec![
503 crate::PatternElement::Value(0),
504 crate::PatternElement::Value(0),
505 crate::PatternElement::Value(0),
506 ],
507 vec![
508 crate::PatternElement::Wildcard,
509 crate::PatternElement::Wildcard,
510 crate::PatternElement::Wildcard,
511 ],
512 ]],
513 },
514 class: "core".to_string(),
515 },
516 );
517
518 registry.add_morphology(
520 "tile".to_string(),
521 Morphology {
522 morphology_type: MorphologyType::Composite,
523 parameters: MorphologyParameters::Composite {
524 src_seed: [16, 16, 1],
525 src_pattern: vec![[1, 0], [1, 0], [1, 0]],
526 mapper_morphology: "projector".to_string(),
527 },
528 class: "core".to_string(),
529 },
530 );
531
532 registry.add_morphology(
534 "lateral_+x".to_string(),
535 Morphology {
536 morphology_type: MorphologyType::Vectors,
537 parameters: MorphologyParameters::Vectors {
538 vectors: vec![[1, 0, 0]],
539 },
540 class: "core".to_string(),
541 },
542 );
543
544 registry.add_morphology(
546 "lateral_-x".to_string(),
547 Morphology {
548 morphology_type: MorphologyType::Vectors,
549 parameters: MorphologyParameters::Vectors {
550 vectors: vec![[-1, 0, 0]],
551 },
552 class: "core".to_string(),
553 },
554 );
555
556 registry.add_morphology(
558 "lateral_+y".to_string(),
559 Morphology {
560 morphology_type: MorphologyType::Vectors,
561 parameters: MorphologyParameters::Vectors {
562 vectors: vec![[0, 1, 0]],
563 },
564 class: "core".to_string(),
565 },
566 );
567
568 registry.add_morphology(
570 "lateral_-y".to_string(),
571 Morphology {
572 morphology_type: MorphologyType::Vectors,
573 parameters: MorphologyParameters::Vectors {
574 vectors: vec![[0, -1, 0]],
575 },
576 class: "core".to_string(),
577 },
578 );
579
580 registry.add_morphology(
582 "lateral_+z".to_string(),
583 Morphology {
584 morphology_type: MorphologyType::Vectors,
585 parameters: MorphologyParameters::Vectors {
586 vectors: vec![[0, 0, 1]],
587 },
588 class: "core".to_string(),
589 },
590 );
591
592 registry.add_morphology(
594 "lateral_-z".to_string(),
595 Morphology {
596 morphology_type: MorphologyType::Vectors,
597 parameters: MorphologyParameters::Vectors {
598 vectors: vec![[0, 0, -1]],
599 },
600 class: "core".to_string(),
601 },
602 );
603}
604
605pub fn load_essential_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
609 use crate::genome::loader::load_genome_from_json;
610 let mut genome = load_genome_from_json(ESSENTIAL_GENOME_JSON)?;
611 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
612 if areas_added > 0 || morphs_added > 0 {
613 tracing::info!(
614 "Essential genome: added {} core areas, {} core morphologies",
615 areas_added,
616 morphs_added
617 );
618 }
619 Ok(genome)
620}
621
622pub fn load_barebones_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
626 use crate::genome::loader::load_genome_from_json;
627 let mut genome = load_genome_from_json(BAREBONES_GENOME_JSON)?;
628 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
629 if areas_added > 0 || morphs_added > 0 {
630 tracing::info!(
631 "Barebones genome: added {} core areas, {} core morphologies",
632 areas_added,
633 morphs_added
634 );
635 }
636 Ok(genome)
637}
638
639pub fn load_test_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
643 use crate::genome::loader::load_genome_from_json;
644 let mut genome = load_genome_from_json(TEST_GENOME_JSON)?;
645 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
646 if areas_added > 0 || morphs_added > 0 {
647 tracing::info!(
648 "Test genome: added {} core areas, {} core morphologies",
649 areas_added,
650 morphs_added
651 );
652 }
653 Ok(genome)
654}
655
656pub fn load_vision_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
660 use crate::genome::loader::load_genome_from_json;
661 let mut genome = load_genome_from_json(VISION_GENOME_JSON)?;
662 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
663 if areas_added > 0 || morphs_added > 0 {
664 tracing::info!(
665 "Vision genome: added {} core areas, {} core morphologies",
666 areas_added,
667 morphs_added
668 );
669 }
670 Ok(genome)
671}
672
673#[cfg(test)]
674mod tests {
675 use super::*;
676
677 #[test]
678 fn test_create_minimal_genome() {
679 let genome = create_minimal_genome("test_genome".to_string(), "Test Genome".to_string());
680
681 assert_eq!(genome.metadata.genome_id, "test_genome");
682 assert_eq!(genome.metadata.version, "2.0");
683 assert_eq!(genome.cortical_areas.len(), 0);
684 assert_eq!(genome.morphologies.count(), 0);
685 }
686
687 #[test]
688 fn test_create_genome_with_core_areas() {
689 let genome =
690 create_genome_with_core_areas("test_genome".to_string(), "Test Genome".to_string());
691
692 assert_eq!(genome.metadata.genome_id, "test_genome");
693 assert_eq!(genome.cortical_areas.len(), 3);
694
695 let death_id = crate::genome::parser::string_to_cortical_id("_death").expect("Valid ID");
696 let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
697 let fatigue_id =
698 crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid ID");
699 assert!(genome.cortical_areas.contains_key(&death_id));
700 assert!(genome.cortical_areas.contains_key(&power_id));
701 assert!(genome.cortical_areas.contains_key(&fatigue_id));
702
703 let power = genome.cortical_areas.get(&power_id).unwrap();
705 assert_eq!(power.cortical_id.as_base_64(), power_id.as_base_64());
706 assert_eq!(power.cortical_idx, 1);
707 assert_eq!(power.dimensions.width, 1);
708 assert_eq!(power.dimensions.height, 1);
709 assert_eq!(power.dimensions.depth, 1);
710 }
711
712 #[test]
713 fn test_create_genome_with_core_morphologies() {
714 let genome = create_genome_with_core_morphologies(
715 "test_genome".to_string(),
716 "Test Genome".to_string(),
717 );
718
719 assert_eq!(genome.metadata.genome_id, "test_genome");
720 assert!(genome.morphologies.count() > 0);
721 assert!(genome.morphologies.contains("block_to_block"));
722 assert!(genome.morphologies.contains("projector"));
723 assert!(genome.morphologies.contains("transpose_xy"));
724 assert!(genome.morphologies.contains("transpose_yz"));
725 assert!(genome.morphologies.contains("transpose_xz"));
726 assert!(genome.morphologies.contains("lateral_+x"));
727 }
728
729 #[test]
730 fn test_add_core_morphologies() {
731 let mut registry = MorphologyRegistry::new();
732 add_core_morphologies(&mut registry);
733
734 assert!(registry.count() >= 11);
736 assert!(registry.contains("block_to_block"));
737 assert!(registry.contains("projector"));
738 assert!(registry.contains("transpose_xy"));
739 assert!(registry.contains("transpose_yz"));
740 assert!(registry.contains("transpose_xz"));
741 assert!(registry.contains("all_to_0-0-0"));
742 assert!(registry.contains("lateral_+x"));
743 assert!(registry.contains("lateral_-z"));
744 }
745
746 #[test]
747 fn test_embedded_genomes_exist() {
748 #[allow(clippy::const_is_empty)]
752 {
753 assert!(!ESSENTIAL_GENOME_JSON.is_empty());
754 assert!(!BAREBONES_GENOME_JSON.is_empty());
755 assert!(!TEST_GENOME_JSON.is_empty());
756 assert!(!VISION_GENOME_JSON.is_empty());
757 }
758 }
759
760 #[test]
761 fn test_load_essential_genome() {
762 let genome = load_essential_genome().expect("Failed to load essential genome");
763 assert!(!genome.cortical_areas.is_empty());
764 let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
766 assert!(genome.cortical_areas.contains_key(&power_id));
767 }
768
769 #[test]
770 fn test_ensure_core_components_adds_missing_areas() {
771 let mut genome = create_minimal_genome("test".to_string(), "Test".to_string());
773
774 assert_eq!(genome.cortical_areas.len(), 0);
775
776 let (areas_added, _) = ensure_core_components(&mut genome);
778
779 assert_eq!(areas_added, 3);
781
782 let death_id = crate::genome::parser::string_to_cortical_id("_death").expect("Valid ID");
783 let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
784 let fatigue_id =
785 crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid ID");
786 assert!(genome.cortical_areas.contains_key(&death_id));
787 assert!(genome.cortical_areas.contains_key(&power_id));
788 assert!(genome.cortical_areas.contains_key(&fatigue_id));
789
790 assert_eq!(
792 genome.cortical_areas.get(&death_id).unwrap().cortical_idx,
793 0
794 );
795 assert_eq!(
796 genome.cortical_areas.get(&power_id).unwrap().cortical_idx,
797 1
798 );
799 assert_eq!(
800 genome.cortical_areas.get(&fatigue_id).unwrap().cortical_idx,
801 2
802 );
803 }
804
805 #[test]
806 fn test_ensure_core_components_adds_missing_morphologies() {
807 let mut genome = create_genome_with_core_areas("test".to_string(), "Test".to_string());
809
810 assert_eq!(genome.morphologies.count(), 0);
811
812 let (_, morphs_added) = ensure_core_components(&mut genome);
814
815 assert!(morphs_added > 0);
817 assert!(genome.morphologies.contains("block_to_block"));
818 assert!(genome.morphologies.contains("projector"));
819 assert!(genome.morphologies.contains("transpose_xy"));
820 assert!(genome.morphologies.contains("transpose_yz"));
821 assert!(genome.morphologies.contains("transpose_xz"));
822 assert!(genome.morphologies.contains("episodic_memory"));
823 assert!(genome.morphologies.contains("lateral_+x"));
824 }
825
826 #[test]
827 fn test_ensure_core_components_idempotent() {
828 let mut genome = create_genome_with_core_areas("test".to_string(), "Test".to_string());
830 add_core_morphologies(&mut genome.morphologies);
831
832 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
834
835 assert_eq!(areas_added, 0);
837 assert_eq!(morphs_added, 0);
838 }
839}