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(
59 "cortical_mapping_dst".to_string(),
60 Value::Object(serde_json::Map::new()),
61 );
62 props
63}
64
65pub fn create_death_area() -> CorticalArea {
67 let cortical_id = CoreCorticalType::Death.to_cortical_id();
68 let cortical_type = cortical_id
69 .as_cortical_type()
70 .expect("Death cortical ID should map to Core type");
71
72 let mut area = CorticalArea::new(
73 cortical_id,
74 0, "Death".to_string(),
76 CorticalAreaDimensions::new(1, 1, 1).expect("Failed to create dimensions"),
77 GenomeCoordinate3D::new(0, 0, -20),
78 cortical_type,
79 )
80 .expect("Failed to create _death area");
81
82 let mut props = get_default_neural_properties();
83 props.insert("cortical_group".to_string(), Value::from("CORE"));
84 props.insert("2d_coordinate".to_string(), Value::from(vec![-10, -20]));
85 area.properties = props;
86 area
87}
88
89pub fn create_power_area() -> CorticalArea {
91 let cortical_id = CoreCorticalType::Power.to_cortical_id();
92 let cortical_type = cortical_id
93 .as_cortical_type()
94 .expect("Power cortical ID should map to Core type");
95
96 let mut area = CorticalArea::new(
97 cortical_id,
98 1, "Brain_Power".to_string(),
100 CorticalAreaDimensions::new(1, 1, 1).expect("Failed to create dimensions"),
101 GenomeCoordinate3D::new(0, 0, -20),
102 cortical_type,
103 )
104 .expect("Failed to create _power area");
105
106 let mut props = get_default_neural_properties();
107 props.insert("cortical_group".to_string(), Value::from("CORE"));
108 props.insert("2d_coordinate".to_string(), Value::from(vec![-10, -10]));
109 props.insert("firing_threshold".to_string(), Value::from(0.1));
110 props.insert("postsynaptic_current".to_string(), Value::from(500.0));
111 props.insert("neuron_excitability".to_string(), Value::from(100.0));
112 area.properties = props;
113 area
114}
115
116pub fn create_fatigue_area() -> CorticalArea {
118 let cortical_id = CoreCorticalType::Fatigue.to_cortical_id();
119 let cortical_type = cortical_id
120 .as_cortical_type()
121 .expect("Fatigue cortical ID should map to Core type");
122
123 let mut area = CorticalArea::new(
124 cortical_id,
125 2, "Fatigue".to_string(),
127 CorticalAreaDimensions::new(1, 1, 1).expect("Failed to create dimensions"),
128 GenomeCoordinate3D::new(0, 0, -30),
129 cortical_type,
130 )
131 .expect("Failed to create _fatigue area");
132
133 let mut props = get_default_neural_properties();
134 props.insert("cortical_group".to_string(), Value::from("CORE"));
135 props.insert("2d_coordinate".to_string(), Value::from(vec![-10, 0]));
136 area.properties = props;
137 area
138}
139
140pub fn create_minimal_genome(genome_id: String, genome_title: String) -> RuntimeGenome {
142 RuntimeGenome {
143 metadata: GenomeMetadata {
144 genome_id,
145 genome_title,
146 genome_description: "Minimal genome template".to_string(),
147 version: "2.0".to_string(),
148 timestamp: std::time::SystemTime::now()
149 .duration_since(std::time::UNIX_EPOCH)
150 .unwrap()
151 .as_secs_f64(),
152 brain_regions_root: None, },
154 cortical_areas: HashMap::new(),
155 brain_regions: HashMap::new(),
156 morphologies: MorphologyRegistry::new(),
157 physiology: PhysiologyConfig::default(),
158 signatures: GenomeSignatures {
159 genome: String::new(),
160 blueprint: String::new(),
161 physiology: String::new(),
162 morphologies: None,
163 },
164 stats: GenomeStats::default(),
165 }
166}
167
168pub fn create_genome_with_core_areas(genome_id: String, genome_title: String) -> RuntimeGenome {
170 let mut genome = create_minimal_genome(genome_id, genome_title);
171
172 let death_id =
174 crate::genome::parser::string_to_cortical_id("_death").expect("Valid cortical ID");
175 let power_id =
176 crate::genome::parser::string_to_cortical_id("_power").expect("Valid cortical ID");
177 let fatigue_id =
178 crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid cortical ID");
179
180 genome.cortical_areas.insert(death_id, create_death_area());
181 genome.cortical_areas.insert(power_id, create_power_area());
182 genome
183 .cortical_areas
184 .insert(fatigue_id, create_fatigue_area());
185
186 genome
187}
188
189pub fn create_genome_with_core_morphologies(
191 genome_id: String,
192 genome_title: String,
193) -> RuntimeGenome {
194 let mut genome = create_minimal_genome(genome_id, genome_title);
195
196 add_core_morphologies(&mut genome.morphologies);
198
199 genome
200}
201
202pub fn ensure_core_components(genome: &mut RuntimeGenome) -> (usize, usize) {
217 let mut areas_added = 0;
218 let mut morphologies_added = 0;
219
220 let death_id =
222 crate::genome::parser::string_to_cortical_id("_death").expect("Valid cortical ID");
223 let power_id =
224 crate::genome::parser::string_to_cortical_id("_power").expect("Valid cortical ID");
225 let fatigue_id =
226 crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid cortical ID");
227
228 if let std::collections::hash_map::Entry::Vacant(e) = genome.cortical_areas.entry(death_id) {
230 let death_area = create_death_area();
231 e.insert(death_area);
232 areas_added += 1;
233 tracing::info!("Added missing core area: _death (cortical_idx=0)");
234 }
235
236 if let std::collections::hash_map::Entry::Vacant(e) = genome.cortical_areas.entry(power_id) {
237 let power_area = create_power_area();
238 e.insert(power_area);
239 areas_added += 1;
240 tracing::info!("Added missing core area: _power (cortical_idx=1)");
241 }
242
243 if let std::collections::hash_map::Entry::Vacant(e) = genome.cortical_areas.entry(fatigue_id) {
244 let fatigue_area = create_fatigue_area();
245 e.insert(fatigue_area);
246 areas_added += 1;
247 tracing::info!("Added missing core area: _fatigue (cortical_idx=2)");
248 }
249
250 let required_morphologies = vec![
252 "block_to_block",
253 "projector",
254 "memory",
255 "all_to_0-0-0",
256 "0-0-0_to_all",
257 "lateral_+x",
258 "lateral_-x",
259 "lateral_+y",
260 "lateral_-y",
261 "lateral_+z",
262 "lateral_-z",
263 ];
264
265 for morph_name in required_morphologies {
266 if !genome.morphologies.contains(morph_name) {
267 morphologies_added += 1;
268 }
269 }
270
271 if morphologies_added > 0 {
273 add_core_morphologies(&mut genome.morphologies);
274 tracing::info!("Added {} missing core morphologies", morphologies_added);
275 }
276
277 (areas_added, morphologies_added)
278}
279
280pub fn add_core_morphologies(registry: &mut MorphologyRegistry) {
282 use crate::{Morphology, MorphologyParameters, MorphologyType};
283
284 registry.add_morphology(
286 "block_to_block".to_string(),
287 Morphology {
288 morphology_type: MorphologyType::Vectors,
289 parameters: MorphologyParameters::Vectors {
290 vectors: vec![[0, 0, 0]],
291 },
292 class: "core".to_string(),
293 },
294 );
295
296 registry.add_morphology(
298 "projector".to_string(),
299 Morphology {
300 morphology_type: MorphologyType::Functions,
301 parameters: MorphologyParameters::Functions {},
302 class: "core".to_string(),
303 },
304 );
305
306 registry.add_morphology(
308 "memory".to_string(),
309 Morphology {
310 morphology_type: MorphologyType::Functions,
311 parameters: MorphologyParameters::Functions {},
312 class: "core".to_string(),
313 },
314 );
315
316 registry.add_morphology(
318 "all_to_0-0-0".to_string(),
319 Morphology {
320 morphology_type: MorphologyType::Patterns,
321 parameters: MorphologyParameters::Patterns {
322 patterns: vec![[
323 vec![
324 crate::PatternElement::Wildcard,
325 crate::PatternElement::Wildcard,
326 crate::PatternElement::Wildcard,
327 ],
328 vec![
329 crate::PatternElement::Value(0),
330 crate::PatternElement::Value(0),
331 crate::PatternElement::Value(0),
332 ],
333 ]],
334 },
335 class: "core".to_string(),
336 },
337 );
338
339 registry.add_morphology(
341 "0-0-0_to_all".to_string(),
342 Morphology {
343 morphology_type: MorphologyType::Patterns,
344 parameters: MorphologyParameters::Patterns {
345 patterns: vec![[
346 vec![
347 crate::PatternElement::Value(0),
348 crate::PatternElement::Value(0),
349 crate::PatternElement::Value(0),
350 ],
351 vec![
352 crate::PatternElement::Wildcard,
353 crate::PatternElement::Wildcard,
354 crate::PatternElement::Wildcard,
355 ],
356 ]],
357 },
358 class: "core".to_string(),
359 },
360 );
361
362 registry.add_morphology(
364 "lateral_+x".to_string(),
365 Morphology {
366 morphology_type: MorphologyType::Vectors,
367 parameters: MorphologyParameters::Vectors {
368 vectors: vec![[1, 0, 0]],
369 },
370 class: "core".to_string(),
371 },
372 );
373
374 registry.add_morphology(
376 "lateral_-x".to_string(),
377 Morphology {
378 morphology_type: MorphologyType::Vectors,
379 parameters: MorphologyParameters::Vectors {
380 vectors: vec![[-1, 0, 0]],
381 },
382 class: "core".to_string(),
383 },
384 );
385
386 registry.add_morphology(
388 "lateral_+y".to_string(),
389 Morphology {
390 morphology_type: MorphologyType::Vectors,
391 parameters: MorphologyParameters::Vectors {
392 vectors: vec![[0, 1, 0]],
393 },
394 class: "core".to_string(),
395 },
396 );
397
398 registry.add_morphology(
400 "lateral_-y".to_string(),
401 Morphology {
402 morphology_type: MorphologyType::Vectors,
403 parameters: MorphologyParameters::Vectors {
404 vectors: vec![[0, -1, 0]],
405 },
406 class: "core".to_string(),
407 },
408 );
409
410 registry.add_morphology(
412 "lateral_+z".to_string(),
413 Morphology {
414 morphology_type: MorphologyType::Vectors,
415 parameters: MorphologyParameters::Vectors {
416 vectors: vec![[0, 0, 1]],
417 },
418 class: "core".to_string(),
419 },
420 );
421
422 registry.add_morphology(
424 "lateral_-z".to_string(),
425 Morphology {
426 morphology_type: MorphologyType::Vectors,
427 parameters: MorphologyParameters::Vectors {
428 vectors: vec![[0, 0, -1]],
429 },
430 class: "core".to_string(),
431 },
432 );
433}
434
435pub fn load_essential_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
439 use crate::genome::loader::load_genome_from_json;
440 let mut genome = load_genome_from_json(ESSENTIAL_GENOME_JSON)?;
441 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
442 if areas_added > 0 || morphs_added > 0 {
443 tracing::info!(
444 "Essential genome: added {} core areas, {} core morphologies",
445 areas_added,
446 morphs_added
447 );
448 }
449 Ok(genome)
450}
451
452pub fn load_barebones_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
456 use crate::genome::loader::load_genome_from_json;
457 let mut genome = load_genome_from_json(BAREBONES_GENOME_JSON)?;
458 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
459 if areas_added > 0 || morphs_added > 0 {
460 tracing::info!(
461 "Barebones genome: added {} core areas, {} core morphologies",
462 areas_added,
463 morphs_added
464 );
465 }
466 Ok(genome)
467}
468
469pub fn load_test_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
473 use crate::genome::loader::load_genome_from_json;
474 let mut genome = load_genome_from_json(TEST_GENOME_JSON)?;
475 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
476 if areas_added > 0 || morphs_added > 0 {
477 tracing::info!(
478 "Test genome: added {} core areas, {} core morphologies",
479 areas_added,
480 morphs_added
481 );
482 }
483 Ok(genome)
484}
485
486pub fn load_vision_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
490 use crate::genome::loader::load_genome_from_json;
491 let mut genome = load_genome_from_json(VISION_GENOME_JSON)?;
492 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
493 if areas_added > 0 || morphs_added > 0 {
494 tracing::info!(
495 "Vision genome: added {} core areas, {} core morphologies",
496 areas_added,
497 morphs_added
498 );
499 }
500 Ok(genome)
501}
502
503#[cfg(test)]
504mod tests {
505 use super::*;
506
507 #[test]
508 fn test_create_minimal_genome() {
509 let genome = create_minimal_genome("test_genome".to_string(), "Test Genome".to_string());
510
511 assert_eq!(genome.metadata.genome_id, "test_genome");
512 assert_eq!(genome.metadata.version, "2.0");
513 assert_eq!(genome.cortical_areas.len(), 0);
514 assert_eq!(genome.morphologies.count(), 0);
515 }
516
517 #[test]
518 fn test_create_genome_with_core_areas() {
519 let genome =
520 create_genome_with_core_areas("test_genome".to_string(), "Test Genome".to_string());
521
522 assert_eq!(genome.metadata.genome_id, "test_genome");
523 assert_eq!(genome.cortical_areas.len(), 3);
524
525 let death_id = crate::genome::parser::string_to_cortical_id("_death").expect("Valid ID");
526 let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
527 let fatigue_id =
528 crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid ID");
529 assert!(genome.cortical_areas.contains_key(&death_id));
530 assert!(genome.cortical_areas.contains_key(&power_id));
531 assert!(genome.cortical_areas.contains_key(&fatigue_id));
532
533 let power = genome.cortical_areas.get(&power_id).unwrap();
535 assert_eq!(power.cortical_id.as_base_64(), power_id.as_base_64());
536 assert_eq!(power.cortical_idx, 1);
537 assert_eq!(power.dimensions.width, 1);
538 assert_eq!(power.dimensions.height, 1);
539 assert_eq!(power.dimensions.depth, 1);
540 }
541
542 #[test]
543 fn test_create_genome_with_core_morphologies() {
544 let genome = create_genome_with_core_morphologies(
545 "test_genome".to_string(),
546 "Test Genome".to_string(),
547 );
548
549 assert_eq!(genome.metadata.genome_id, "test_genome");
550 assert!(genome.morphologies.count() > 0);
551 assert!(genome.morphologies.contains("block_to_block"));
552 assert!(genome.morphologies.contains("projector"));
553 assert!(genome.morphologies.contains("lateral_+x"));
554 }
555
556 #[test]
557 fn test_add_core_morphologies() {
558 let mut registry = MorphologyRegistry::new();
559 add_core_morphologies(&mut registry);
560
561 assert!(registry.count() >= 11);
563 assert!(registry.contains("block_to_block"));
564 assert!(registry.contains("projector"));
565 assert!(registry.contains("all_to_0-0-0"));
566 assert!(registry.contains("lateral_+x"));
567 assert!(registry.contains("lateral_-z"));
568 }
569
570 #[test]
571 fn test_embedded_genomes_exist() {
572 #[allow(clippy::const_is_empty)]
576 {
577 assert!(!ESSENTIAL_GENOME_JSON.is_empty());
578 assert!(!BAREBONES_GENOME_JSON.is_empty());
579 assert!(!TEST_GENOME_JSON.is_empty());
580 assert!(!VISION_GENOME_JSON.is_empty());
581 }
582 }
583
584 #[test]
585 fn test_load_essential_genome() {
586 let genome = load_essential_genome().expect("Failed to load essential genome");
587 assert!(!genome.cortical_areas.is_empty());
588 let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
590 assert!(genome.cortical_areas.contains_key(&power_id));
591 }
592
593 #[test]
594 fn test_ensure_core_components_adds_missing_areas() {
595 let mut genome = create_minimal_genome("test".to_string(), "Test".to_string());
597
598 assert_eq!(genome.cortical_areas.len(), 0);
599
600 let (areas_added, _) = ensure_core_components(&mut genome);
602
603 assert_eq!(areas_added, 3);
605
606 let death_id = crate::genome::parser::string_to_cortical_id("_death").expect("Valid ID");
607 let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
608 let fatigue_id =
609 crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid ID");
610 assert!(genome.cortical_areas.contains_key(&death_id));
611 assert!(genome.cortical_areas.contains_key(&power_id));
612 assert!(genome.cortical_areas.contains_key(&fatigue_id));
613
614 assert_eq!(
616 genome.cortical_areas.get(&death_id).unwrap().cortical_idx,
617 0
618 );
619 assert_eq!(
620 genome.cortical_areas.get(&power_id).unwrap().cortical_idx,
621 1
622 );
623 assert_eq!(
624 genome.cortical_areas.get(&fatigue_id).unwrap().cortical_idx,
625 2
626 );
627 }
628
629 #[test]
630 fn test_ensure_core_components_adds_missing_morphologies() {
631 let mut genome = create_genome_with_core_areas("test".to_string(), "Test".to_string());
633
634 assert_eq!(genome.morphologies.count(), 0);
635
636 let (_, morphs_added) = ensure_core_components(&mut genome);
638
639 assert!(morphs_added > 0);
641 assert!(genome.morphologies.contains("block_to_block"));
642 assert!(genome.morphologies.contains("projector"));
643 assert!(genome.morphologies.contains("memory"));
644 assert!(genome.morphologies.contains("lateral_+x"));
645 }
646
647 #[test]
648 fn test_ensure_core_components_idempotent() {
649 let mut genome = create_genome_with_core_areas("test".to_string(), "Test".to_string());
651 add_core_morphologies(&mut genome.morphologies);
652
653 let (areas_added, morphs_added) = ensure_core_components(&mut genome);
655
656 assert_eq!(areas_added, 0);
658 assert_eq!(morphs_added, 0);
659 }
660}