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 "episodic_memory",
256 "memory_replay",
257 "associative_memory",
258 "all_to_0-0-0",
259 "0-0-0_to_all",
260 "lateral_+x",
261 "lateral_-x",
262 "lateral_+y",
263 "lateral_-y",
264 "lateral_+z",
265 "lateral_-z",
266 ];
267
268 for morph_name in required_morphologies {
269 if !genome.morphologies.contains(morph_name) {
270 morphologies_added += 1;
271 }
272 }
273
274 if morphologies_added > 0 {
276 add_core_morphologies(&mut genome.morphologies);
277 tracing::info!("Added {} missing core morphologies", morphologies_added);
278 }
279
280 (areas_added, morphologies_added)
281}
282
283pub fn add_core_morphologies(registry: &mut MorphologyRegistry) {
285 use crate::{Morphology, MorphologyParameters, MorphologyType};
286
287 registry.add_morphology(
289 "block_to_block".to_string(),
290 Morphology {
291 morphology_type: MorphologyType::Vectors,
292 parameters: MorphologyParameters::Vectors {
293 vectors: vec![[0, 0, 0]],
294 },
295 class: "core".to_string(),
296 },
297 );
298
299 registry.add_morphology(
301 "projector".to_string(),
302 Morphology {
303 morphology_type: MorphologyType::Functions,
304 parameters: MorphologyParameters::Functions {},
305 class: "core".to_string(),
306 },
307 );
308
309 registry.add_morphology(
311 "episodic_memory".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 "memory_replay".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 "associative_memory".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 "all_to_0-0-0".to_string(),
342 Morphology {
343 morphology_type: MorphologyType::Patterns,
344 parameters: MorphologyParameters::Patterns {
345 patterns: vec![[
346 vec![
347 crate::PatternElement::Wildcard,
348 crate::PatternElement::Wildcard,
349 crate::PatternElement::Wildcard,
350 ],
351 vec![
352 crate::PatternElement::Value(0),
353 crate::PatternElement::Value(0),
354 crate::PatternElement::Value(0),
355 ],
356 ]],
357 },
358 class: "core".to_string(),
359 },
360 );
361
362 registry.add_morphology(
364 "0-0-0_to_all".to_string(),
365 Morphology {
366 morphology_type: MorphologyType::Patterns,
367 parameters: MorphologyParameters::Patterns {
368 patterns: vec![[
369 vec![
370 crate::PatternElement::Value(0),
371 crate::PatternElement::Value(0),
372 crate::PatternElement::Value(0),
373 ],
374 vec![
375 crate::PatternElement::Wildcard,
376 crate::PatternElement::Wildcard,
377 crate::PatternElement::Wildcard,
378 ],
379 ]],
380 },
381 class: "core".to_string(),
382 },
383 );
384
385 registry.add_morphology(
387 "lateral_+x".to_string(),
388 Morphology {
389 morphology_type: MorphologyType::Vectors,
390 parameters: MorphologyParameters::Vectors {
391 vectors: vec![[1, 0, 0]],
392 },
393 class: "core".to_string(),
394 },
395 );
396
397 registry.add_morphology(
399 "lateral_-x".to_string(),
400 Morphology {
401 morphology_type: MorphologyType::Vectors,
402 parameters: MorphologyParameters::Vectors {
403 vectors: vec![[-1, 0, 0]],
404 },
405 class: "core".to_string(),
406 },
407 );
408
409 registry.add_morphology(
411 "lateral_+y".to_string(),
412 Morphology {
413 morphology_type: MorphologyType::Vectors,
414 parameters: MorphologyParameters::Vectors {
415 vectors: vec![[0, 1, 0]],
416 },
417 class: "core".to_string(),
418 },
419 );
420
421 registry.add_morphology(
423 "lateral_-y".to_string(),
424 Morphology {
425 morphology_type: MorphologyType::Vectors,
426 parameters: MorphologyParameters::Vectors {
427 vectors: vec![[0, -1, 0]],
428 },
429 class: "core".to_string(),
430 },
431 );
432
433 registry.add_morphology(
435 "lateral_+z".to_string(),
436 Morphology {
437 morphology_type: MorphologyType::Vectors,
438 parameters: MorphologyParameters::Vectors {
439 vectors: vec![[0, 0, 1]],
440 },
441 class: "core".to_string(),
442 },
443 );
444
445 registry.add_morphology(
447 "lateral_-z".to_string(),
448 Morphology {
449 morphology_type: MorphologyType::Vectors,
450 parameters: MorphologyParameters::Vectors {
451 vectors: vec![[0, 0, -1]],
452 },
453 class: "core".to_string(),
454 },
455 );
456}
457
458pub fn load_essential_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
462 use crate::genome::loader::load_genome_from_json;
463 let mut genome = load_genome_from_json(ESSENTIAL_GENOME_JSON)?;
464 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
465 if areas_added > 0 || morphs_added > 0 {
466 tracing::info!(
467 "Essential genome: added {} core areas, {} core morphologies",
468 areas_added,
469 morphs_added
470 );
471 }
472 Ok(genome)
473}
474
475pub fn load_barebones_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
479 use crate::genome::loader::load_genome_from_json;
480 let mut genome = load_genome_from_json(BAREBONES_GENOME_JSON)?;
481 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
482 if areas_added > 0 || morphs_added > 0 {
483 tracing::info!(
484 "Barebones genome: added {} core areas, {} core morphologies",
485 areas_added,
486 morphs_added
487 );
488 }
489 Ok(genome)
490}
491
492pub fn load_test_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
496 use crate::genome::loader::load_genome_from_json;
497 let mut genome = load_genome_from_json(TEST_GENOME_JSON)?;
498 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
499 if areas_added > 0 || morphs_added > 0 {
500 tracing::info!(
501 "Test genome: added {} core areas, {} core morphologies",
502 areas_added,
503 morphs_added
504 );
505 }
506 Ok(genome)
507}
508
509pub fn load_vision_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
513 use crate::genome::loader::load_genome_from_json;
514 let mut genome = load_genome_from_json(VISION_GENOME_JSON)?;
515 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
516 if areas_added > 0 || morphs_added > 0 {
517 tracing::info!(
518 "Vision genome: added {} core areas, {} core morphologies",
519 areas_added,
520 morphs_added
521 );
522 }
523 Ok(genome)
524}
525
526#[cfg(test)]
527mod tests {
528 use super::*;
529
530 #[test]
531 fn test_create_minimal_genome() {
532 let genome = create_minimal_genome("test_genome".to_string(), "Test Genome".to_string());
533
534 assert_eq!(genome.metadata.genome_id, "test_genome");
535 assert_eq!(genome.metadata.version, "2.0");
536 assert_eq!(genome.cortical_areas.len(), 0);
537 assert_eq!(genome.morphologies.count(), 0);
538 }
539
540 #[test]
541 fn test_create_genome_with_core_areas() {
542 let genome =
543 create_genome_with_core_areas("test_genome".to_string(), "Test Genome".to_string());
544
545 assert_eq!(genome.metadata.genome_id, "test_genome");
546 assert_eq!(genome.cortical_areas.len(), 3);
547
548 let death_id = crate::genome::parser::string_to_cortical_id("_death").expect("Valid ID");
549 let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
550 let fatigue_id =
551 crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid ID");
552 assert!(genome.cortical_areas.contains_key(&death_id));
553 assert!(genome.cortical_areas.contains_key(&power_id));
554 assert!(genome.cortical_areas.contains_key(&fatigue_id));
555
556 let power = genome.cortical_areas.get(&power_id).unwrap();
558 assert_eq!(power.cortical_id.as_base_64(), power_id.as_base_64());
559 assert_eq!(power.cortical_idx, 1);
560 assert_eq!(power.dimensions.width, 1);
561 assert_eq!(power.dimensions.height, 1);
562 assert_eq!(power.dimensions.depth, 1);
563 }
564
565 #[test]
566 fn test_create_genome_with_core_morphologies() {
567 let genome = create_genome_with_core_morphologies(
568 "test_genome".to_string(),
569 "Test Genome".to_string(),
570 );
571
572 assert_eq!(genome.metadata.genome_id, "test_genome");
573 assert!(genome.morphologies.count() > 0);
574 assert!(genome.morphologies.contains("block_to_block"));
575 assert!(genome.morphologies.contains("projector"));
576 assert!(genome.morphologies.contains("lateral_+x"));
577 }
578
579 #[test]
580 fn test_add_core_morphologies() {
581 let mut registry = MorphologyRegistry::new();
582 add_core_morphologies(&mut registry);
583
584 assert!(registry.count() >= 11);
586 assert!(registry.contains("block_to_block"));
587 assert!(registry.contains("projector"));
588 assert!(registry.contains("all_to_0-0-0"));
589 assert!(registry.contains("lateral_+x"));
590 assert!(registry.contains("lateral_-z"));
591 }
592
593 #[test]
594 fn test_embedded_genomes_exist() {
595 #[allow(clippy::const_is_empty)]
599 {
600 assert!(!ESSENTIAL_GENOME_JSON.is_empty());
601 assert!(!BAREBONES_GENOME_JSON.is_empty());
602 assert!(!TEST_GENOME_JSON.is_empty());
603 assert!(!VISION_GENOME_JSON.is_empty());
604 }
605 }
606
607 #[test]
608 fn test_load_essential_genome() {
609 let genome = load_essential_genome().expect("Failed to load essential genome");
610 assert!(!genome.cortical_areas.is_empty());
611 let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
613 assert!(genome.cortical_areas.contains_key(&power_id));
614 }
615
616 #[test]
617 fn test_ensure_core_components_adds_missing_areas() {
618 let mut genome = create_minimal_genome("test".to_string(), "Test".to_string());
620
621 assert_eq!(genome.cortical_areas.len(), 0);
622
623 let (areas_added, _) = ensure_core_components(&mut genome);
625
626 assert_eq!(areas_added, 3);
628
629 let death_id = crate::genome::parser::string_to_cortical_id("_death").expect("Valid ID");
630 let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
631 let fatigue_id =
632 crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid ID");
633 assert!(genome.cortical_areas.contains_key(&death_id));
634 assert!(genome.cortical_areas.contains_key(&power_id));
635 assert!(genome.cortical_areas.contains_key(&fatigue_id));
636
637 assert_eq!(
639 genome.cortical_areas.get(&death_id).unwrap().cortical_idx,
640 0
641 );
642 assert_eq!(
643 genome.cortical_areas.get(&power_id).unwrap().cortical_idx,
644 1
645 );
646 assert_eq!(
647 genome.cortical_areas.get(&fatigue_id).unwrap().cortical_idx,
648 2
649 );
650 }
651
652 #[test]
653 fn test_ensure_core_components_adds_missing_morphologies() {
654 let mut genome = create_genome_with_core_areas("test".to_string(), "Test".to_string());
656
657 assert_eq!(genome.morphologies.count(), 0);
658
659 let (_, morphs_added) = ensure_core_components(&mut genome);
661
662 assert!(morphs_added > 0);
664 assert!(genome.morphologies.contains("block_to_block"));
665 assert!(genome.morphologies.contains("projector"));
666 assert!(genome.morphologies.contains("episodic_memory"));
667 assert!(genome.morphologies.contains("lateral_+x"));
668 }
669
670 #[test]
671 fn test_ensure_core_components_idempotent() {
672 let mut genome = create_genome_with_core_areas("test".to_string(), "Test".to_string());
674 add_core_morphologies(&mut genome.morphologies);
675
676 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
678
679 assert_eq!(areas_added, 0);
681 assert_eq!(morphs_added, 0);
682 }
683}