Skip to main content

feagi_evolutionary/
templates.rs

1// Copyright 2025 Neuraville Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4/*!
5Genome templates for FEAGI.
6
7Provides templates for creating genomes from scratch, including:
8- Minimal genome template
9- Cortical area templates (IPU, OPU, CORE)
10- Default neural parameters
11- Embedded default genomes
12
13Copyright 2025 Neuraville Inc.
14Licensed under the Apache License, Version 2.0
15*/
16
17use 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
27/// Embedded essential genome (loaded at compile time)
28pub const ESSENTIAL_GENOME_JSON: &str = include_str!("../genomes/essential_genome.json");
29
30/// Embedded barebones genome (loaded at compile time)
31pub const BAREBONES_GENOME_JSON: &str = include_str!("../genomes/barebones_genome.json");
32
33/// Embedded test genome (loaded at compile time)
34pub const TEST_GENOME_JSON: &str = include_str!("../genomes/test_genome.json");
35
36/// Embedded vision genome (loaded at compile time)
37pub const VISION_GENOME_JSON: &str = include_str!("../genomes/vision_genome.json");
38
39/// Default neural properties for all cortical areas
40pub 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
66/// Create _death cortical area (cortical_idx = 0) from template
67pub 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, // cortical_idx = 0 (reserved)
76        "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
90/// Create _power cortical area (cortical_idx = 1) from template
91pub 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, // cortical_idx = 1 (reserved)
100        "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
117/// Create _fatigue cortical area (cortical_idx = 2) from template
118pub 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, // cortical_idx = 2 (reserved)
127        "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
141/// Create _pain cortical area (cortical_idx = 3) from template
142pub fn create_pain_area() -> CorticalArea {
143    let cortical_id = CoreCorticalType::Pain.to_cortical_id();
144    let cortical_type = cortical_id
145        .as_cortical_type()
146        .expect("Pain cortical ID should map to Core type");
147
148    let mut area = CorticalArea::new(
149        cortical_id,
150        3, // cortical_idx = 3 (reserved)
151        "Pain".to_string(),
152        CorticalAreaDimensions::new(1, 1, 1).expect("Failed to create dimensions"),
153        GenomeCoordinate3D::new(0, 0, -40),
154        cortical_type,
155    )
156    .expect("Failed to create _pain area");
157
158    let mut props = get_default_neural_properties();
159    props.insert("cortical_group".to_string(), Value::from("CORE"));
160    props.insert("2d_coordinate".to_string(), Value::from(vec![-10, 10]));
161    area.properties = props;
162    area
163}
164
165/// Create _pleasure cortical area (cortical_idx = 4) from template
166pub fn create_pleasure_area() -> CorticalArea {
167    let cortical_id = CoreCorticalType::Pleasure.to_cortical_id();
168    let cortical_type = cortical_id
169        .as_cortical_type()
170        .expect("Pleasure cortical ID should map to Core type");
171
172    let mut area = CorticalArea::new(
173        cortical_id,
174        4, // cortical_idx = 4 (reserved)
175        "Pleasure".to_string(),
176        CorticalAreaDimensions::new(1, 1, 1).expect("Failed to create dimensions"),
177        GenomeCoordinate3D::new(0, 0, -50),
178        cortical_type,
179    )
180    .expect("Failed to create _pleasure area");
181
182    let mut props = get_default_neural_properties();
183    props.insert("cortical_group".to_string(), Value::from("CORE"));
184    props.insert("2d_coordinate".to_string(), Value::from(vec![-10, 20]));
185    area.properties = props;
186    area
187}
188
189/// Create _fear cortical area (cortical_idx = 5) from template
190pub fn create_fear_area() -> CorticalArea {
191    let cortical_id = CoreCorticalType::Fear.to_cortical_id();
192    let cortical_type = cortical_id
193        .as_cortical_type()
194        .expect("Fear cortical ID should map to Core type");
195
196    let mut area = CorticalArea::new(
197        cortical_id,
198        5, // cortical_idx = 5 (reserved)
199        "Fear".to_string(),
200        CorticalAreaDimensions::new(1, 1, 1).expect("Failed to create dimensions"),
201        GenomeCoordinate3D::new(0, 0, -60),
202        cortical_type,
203    )
204    .expect("Failed to create _fear area");
205
206    let mut props = get_default_neural_properties();
207    props.insert("cortical_group".to_string(), Value::from("CORE"));
208    props.insert("2d_coordinate".to_string(), Value::from(vec![-10, 30]));
209    area.properties = props;
210    area
211}
212
213/// Create _hope cortical area (cortical_idx = 6) from template
214pub fn create_hope_area() -> CorticalArea {
215    let cortical_id = CoreCorticalType::Hope.to_cortical_id();
216    let cortical_type = cortical_id
217        .as_cortical_type()
218        .expect("Hope cortical ID should map to Core type");
219
220    let mut area = CorticalArea::new(
221        cortical_id,
222        6, // cortical_idx = 6 (reserved)
223        "Hope".to_string(),
224        CorticalAreaDimensions::new(1, 1, 1).expect("Failed to create dimensions"),
225        GenomeCoordinate3D::new(0, 0, -70),
226        cortical_type,
227    )
228    .expect("Failed to create _hope area");
229
230    let mut props = get_default_neural_properties();
231    props.insert("cortical_group".to_string(), Value::from("CORE"));
232    props.insert("2d_coordinate".to_string(), Value::from(vec![-10, 40]));
233    area.properties = props;
234    area
235}
236
237/// Create a minimal empty genome
238pub fn create_minimal_genome(genome_id: String, genome_title: String) -> RuntimeGenome {
239    RuntimeGenome {
240        metadata: GenomeMetadata {
241            genome_id,
242            genome_title,
243            genome_description: "Minimal genome template".to_string(),
244            version: "2.0".to_string(),
245            timestamp: std::time::SystemTime::now()
246                .duration_since(std::time::UNIX_EPOCH)
247                .unwrap()
248                .as_secs_f64(),
249            brain_regions_root: None, // Will be set after neuroembryogenesis
250        },
251        cortical_areas: HashMap::new(),
252        brain_regions: HashMap::new(),
253        morphologies: MorphologyRegistry::new(),
254        physiology: PhysiologyConfig::default(),
255        signatures: GenomeSignatures {
256            genome: String::new(),
257            blueprint: String::new(),
258            physiology: String::new(),
259            morphologies: None,
260        },
261        stats: GenomeStats::default(),
262    }
263}
264
265/// Create a genome with core areas (_death, _power, _fatigue, _pain, _pleasure, _fear, _hope)
266pub fn create_genome_with_core_areas(genome_id: String, genome_title: String) -> RuntimeGenome {
267    let mut genome = create_minimal_genome(genome_id, genome_title);
268
269    // Add core areas (convert 6-char strings to CorticalID)
270    let death_id =
271        crate::genome::parser::string_to_cortical_id("_death").expect("Valid cortical ID");
272    let power_id =
273        crate::genome::parser::string_to_cortical_id("_power").expect("Valid cortical ID");
274    let fatigue_id =
275        crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid cortical ID");
276    let pain_id = crate::genome::parser::string_to_cortical_id("_pain").expect("Valid cortical ID");
277    let pleasure_id =
278        crate::genome::parser::string_to_cortical_id("_pleasure").expect("Valid cortical ID");
279    let fear_id = crate::genome::parser::string_to_cortical_id("_fear").expect("Valid cortical ID");
280    let hope_id = crate::genome::parser::string_to_cortical_id("_hope").expect("Valid cortical ID");
281
282    genome.cortical_areas.insert(death_id, create_death_area());
283    genome.cortical_areas.insert(power_id, create_power_area());
284    genome
285        .cortical_areas
286        .insert(fatigue_id, create_fatigue_area());
287    genome.cortical_areas.insert(pain_id, create_pain_area());
288    genome
289        .cortical_areas
290        .insert(pleasure_id, create_pleasure_area());
291    genome.cortical_areas.insert(fear_id, create_fear_area());
292    genome.cortical_areas.insert(hope_id, create_hope_area());
293
294    genome
295}
296
297/// Create a genome with core morphologies
298pub fn create_genome_with_core_morphologies(
299    genome_id: String,
300    genome_title: String,
301) -> RuntimeGenome {
302    let mut genome = create_minimal_genome(genome_id, genome_title);
303
304    // Add core morphologies
305    add_core_morphologies(&mut genome.morphologies);
306
307    genome
308}
309
310/// CRITICAL: Ensure a genome has all required core components
311///
312/// This function checks if a genome has:
313/// 1. Core cortical areas (_death, _power)
314/// 2. Core morphologies (block_to_block, projector, etc.)
315///
316/// If any are missing, they are automatically added. This ensures every genome
317/// can function properly regardless of its source.
318///
319/// # Arguments
320/// * `genome` - The genome to validate and fix
321///
322/// # Returns
323/// A tuple of (areas_added, morphologies_added) indicating what was added
324pub fn ensure_core_components(genome: &mut RuntimeGenome) -> (usize, usize) {
325    let mut areas_added = 0;
326    let mut morphologies_added = 0;
327
328    // Convert core area IDs
329    let death_id =
330        crate::genome::parser::string_to_cortical_id("_death").expect("Valid cortical ID");
331    let power_id =
332        crate::genome::parser::string_to_cortical_id("_power").expect("Valid cortical ID");
333    let fatigue_id =
334        crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid cortical ID");
335    let pain_id = crate::genome::parser::string_to_cortical_id("_pain").expect("Valid cortical ID");
336    let pleasure_id =
337        crate::genome::parser::string_to_cortical_id("_pleasure").expect("Valid cortical ID");
338    let fear_id = crate::genome::parser::string_to_cortical_id("_fear").expect("Valid cortical ID");
339    let hope_id = crate::genome::parser::string_to_cortical_id("_hope").expect("Valid cortical ID");
340
341    // 1. Ensure core cortical areas exist
342    if let std::collections::hash_map::Entry::Vacant(e) = genome.cortical_areas.entry(death_id) {
343        let death_area = create_death_area();
344        e.insert(death_area);
345        areas_added += 1;
346        tracing::info!("Added missing core area: _death (cortical_idx=0)");
347    }
348
349    if let std::collections::hash_map::Entry::Vacant(e) = genome.cortical_areas.entry(power_id) {
350        let power_area = create_power_area();
351        e.insert(power_area);
352        areas_added += 1;
353        tracing::info!("Added missing core area: _power (cortical_idx=1)");
354    }
355
356    if let std::collections::hash_map::Entry::Vacant(e) = genome.cortical_areas.entry(fatigue_id) {
357        let fatigue_area = create_fatigue_area();
358        e.insert(fatigue_area);
359        areas_added += 1;
360        tracing::info!("Added missing core area: _fatigue (cortical_idx=2)");
361    }
362
363    if let std::collections::hash_map::Entry::Vacant(e) = genome.cortical_areas.entry(pain_id) {
364        let pain_area = create_pain_area();
365        e.insert(pain_area);
366        areas_added += 1;
367        tracing::info!("Added missing core area: _pain (cortical_idx=3)");
368    }
369
370    if let std::collections::hash_map::Entry::Vacant(e) = genome.cortical_areas.entry(pleasure_id) {
371        let pleasure_area = create_pleasure_area();
372        e.insert(pleasure_area);
373        areas_added += 1;
374        tracing::info!("Added missing core area: _pleasure (cortical_idx=4)");
375    }
376
377    if let std::collections::hash_map::Entry::Vacant(e) = genome.cortical_areas.entry(fear_id) {
378        let fear_area = create_fear_area();
379        e.insert(fear_area);
380        areas_added += 1;
381        tracing::info!("Added missing core area: _fear (cortical_idx=5)");
382    }
383
384    if let std::collections::hash_map::Entry::Vacant(e) = genome.cortical_areas.entry(hope_id) {
385        let hope_area = create_hope_area();
386        e.insert(hope_area);
387        areas_added += 1;
388        tracing::info!("Added missing core area: _hope (cortical_idx=6)");
389    }
390
391    // 2. Ensure core morphologies exist
392    let required_morphologies = vec![
393        "block_to_block",
394        "projector",
395        "centered_projector",
396        "transpose_xy",
397        "transpose_yz",
398        "transpose_xz",
399        "sweeper",
400        "last_to_first",
401        "first_to_last",
402        "bitmask_encoder_x",
403        "bitmask_encoder_y",
404        "bitmask_encoder_z",
405        "bitmask_decoder_x",
406        "bitmask_decoder_y",
407        "bitmask_decoder_z",
408        "episodic_memory",
409        "memory_replay",
410        "associative_memory",
411        "rotator_z",
412        "all_to_0-0-0",
413        "0-0-0_to_all",
414        "tile",
415        "lateral_+x",
416        "lateral_-x",
417        "lateral_+y",
418        "lateral_-y",
419        "lateral_+z",
420        "lateral_-z",
421    ];
422
423    for morph_name in required_morphologies {
424        if !genome.morphologies.contains(morph_name) {
425            morphologies_added += 1;
426        }
427    }
428
429    // Add all missing core morphologies in one call
430    if morphologies_added > 0 {
431        add_core_morphologies(&mut genome.morphologies);
432        tracing::info!("Added {} missing core morphologies", morphologies_added);
433    }
434
435    (areas_added, morphologies_added)
436}
437
438/// Add core morphologies to a registry
439pub fn add_core_morphologies(registry: &mut MorphologyRegistry) {
440    use crate::{Morphology, MorphologyParameters, MorphologyType};
441
442    // block_to_block - Connect neurons in same position
443    registry.add_morphology(
444        "block_to_block".to_string(),
445        Morphology {
446            morphology_type: MorphologyType::Vectors,
447            parameters: MorphologyParameters::Vectors {
448                vectors: vec![[0, 0, 0]],
449            },
450            class: "core".to_string(),
451        },
452    );
453
454    // projector - Function-based morphology
455    registry.add_morphology(
456        "projector".to_string(),
457        Morphology {
458            morphology_type: MorphologyType::Functions,
459            parameters: MorphologyParameters::Functions {},
460            class: "core".to_string(),
461        },
462    );
463
464    // centered_projector - Function-based center-aligned 1:1 mapping morphology
465    registry.add_morphology(
466        "centered_projector".to_string(),
467        Morphology {
468            morphology_type: MorphologyType::Functions,
469            parameters: MorphologyParameters::Functions {},
470            class: "core".to_string(),
471        },
472    );
473
474    // transpose_xy - Projector with x/y axis transposition
475    registry.add_morphology(
476        "transpose_xy".to_string(),
477        Morphology {
478            morphology_type: MorphologyType::Functions,
479            parameters: MorphologyParameters::Functions {},
480            class: "core".to_string(),
481        },
482    );
483
484    // transpose_yz - Projector with y/z axis transposition
485    registry.add_morphology(
486        "transpose_yz".to_string(),
487        Morphology {
488            morphology_type: MorphologyType::Functions,
489            parameters: MorphologyParameters::Functions {},
490            class: "core".to_string(),
491        },
492    );
493
494    // transpose_xz - Projector with x/z axis transposition
495    registry.add_morphology(
496        "transpose_xz".to_string(),
497        Morphology {
498            morphology_type: MorphologyType::Functions,
499            parameters: MorphologyParameters::Functions {},
500            class: "core".to_string(),
501        },
502    );
503
504    // sweeper - Function-based sequential sweep mapping morphology
505    registry.add_morphology(
506        "sweeper".to_string(),
507        Morphology {
508            morphology_type: MorphologyType::Functions,
509            parameters: MorphologyParameters::Functions {},
510            class: "core".to_string(),
511        },
512    );
513
514    // last_to_first - connect highest source voxel to destination origin
515    registry.add_morphology(
516        "last_to_first".to_string(),
517        Morphology {
518            morphology_type: MorphologyType::Functions,
519            parameters: MorphologyParameters::Functions {},
520            class: "core".to_string(),
521        },
522    );
523
524    // first_to_last - connect source origin to highest destination voxel
525    registry.add_morphology(
526        "first_to_last".to_string(),
527        Morphology {
528            morphology_type: MorphologyType::Functions,
529            parameters: MorphologyParameters::Functions {},
530            class: "core".to_string(),
531        },
532    );
533
534    // episodic_memory - Function-based morphology
535    registry.add_morphology(
536        "episodic_memory".to_string(),
537        Morphology {
538            morphology_type: MorphologyType::Functions,
539            parameters: MorphologyParameters::Functions {},
540            class: "core".to_string(),
541        },
542    );
543
544    // memory_replay - Function-based morphology
545    registry.add_morphology(
546        "memory_replay".to_string(),
547        Morphology {
548            morphology_type: MorphologyType::Functions,
549            parameters: MorphologyParameters::Functions {},
550            class: "core".to_string(),
551        },
552    );
553
554    // associative_memory (bi-directional STDP) - Function-based morphology
555    registry.add_morphology(
556        "associative_memory".to_string(),
557        Morphology {
558            morphology_type: MorphologyType::Functions,
559            parameters: MorphologyParameters::Functions {},
560            class: "core".to_string(),
561        },
562    );
563
564    // rotator_z - Function-based morphology for z-layered XY rotations [-90,+90]
565    registry.add_morphology(
566        "rotator_z".to_string(),
567        Morphology {
568            morphology_type: MorphologyType::Functions,
569            parameters: MorphologyParameters::Functions {},
570            class: "core".to_string(),
571        },
572    );
573
574    // bitmask_encoder_x - Bitmask encode along X axis
575    registry.add_morphology(
576        "bitmask_encoder_x".to_string(),
577        Morphology {
578            morphology_type: MorphologyType::Functions,
579            parameters: MorphologyParameters::Functions {},
580            class: "core".to_string(),
581        },
582    );
583
584    // bitmask_encoder_y - Bitmask encode along Y axis
585    registry.add_morphology(
586        "bitmask_encoder_y".to_string(),
587        Morphology {
588            morphology_type: MorphologyType::Functions,
589            parameters: MorphologyParameters::Functions {},
590            class: "core".to_string(),
591        },
592    );
593
594    // bitmask_encoder_z - Bitmask encode along Z axis
595    registry.add_morphology(
596        "bitmask_encoder_z".to_string(),
597        Morphology {
598            morphology_type: MorphologyType::Functions,
599            parameters: MorphologyParameters::Functions {},
600            class: "core".to_string(),
601        },
602    );
603
604    // bitmask_decoder_x - Bitmask decode along X axis
605    registry.add_morphology(
606        "bitmask_decoder_x".to_string(),
607        Morphology {
608            morphology_type: MorphologyType::Functions,
609            parameters: MorphologyParameters::Functions {},
610            class: "core".to_string(),
611        },
612    );
613
614    // bitmask_decoder_y - Bitmask decode along Y axis
615    registry.add_morphology(
616        "bitmask_decoder_y".to_string(),
617        Morphology {
618            morphology_type: MorphologyType::Functions,
619            parameters: MorphologyParameters::Functions {},
620            class: "core".to_string(),
621        },
622    );
623
624    // bitmask_decoder_z - Bitmask decode along Z axis
625    registry.add_morphology(
626        "bitmask_decoder_z".to_string(),
627        Morphology {
628            morphology_type: MorphologyType::Functions,
629            parameters: MorphologyParameters::Functions {},
630            class: "core".to_string(),
631        },
632    );
633
634    // all_to_0-0-0 - Connect all neurons to origin
635    registry.add_morphology(
636        "all_to_0-0-0".to_string(),
637        Morphology {
638            morphology_type: MorphologyType::Patterns,
639            parameters: MorphologyParameters::Patterns {
640                patterns: vec![[
641                    vec![
642                        crate::PatternElement::Wildcard,
643                        crate::PatternElement::Wildcard,
644                        crate::PatternElement::Wildcard,
645                    ],
646                    vec![
647                        crate::PatternElement::Value(0),
648                        crate::PatternElement::Value(0),
649                        crate::PatternElement::Value(0),
650                    ],
651                ]],
652            },
653            class: "core".to_string(),
654        },
655    );
656
657    // 0-0-0_to_all - Connect origin to all neurons
658    registry.add_morphology(
659        "0-0-0_to_all".to_string(),
660        Morphology {
661            morphology_type: MorphologyType::Patterns,
662            parameters: MorphologyParameters::Patterns {
663                patterns: vec![[
664                    vec![
665                        crate::PatternElement::Value(0),
666                        crate::PatternElement::Value(0),
667                        crate::PatternElement::Value(0),
668                    ],
669                    vec![
670                        crate::PatternElement::Wildcard,
671                        crate::PatternElement::Wildcard,
672                        crate::PatternElement::Wildcard,
673                    ],
674                ]],
675            },
676            class: "core".to_string(),
677        },
678    );
679
680    // tile - Composite tiling morphology (mapper + subregion parameters)
681    registry.add_morphology(
682        "tile".to_string(),
683        Morphology {
684            morphology_type: MorphologyType::Composite,
685            parameters: MorphologyParameters::Composite {
686                src_seed: [16, 16, 1],
687                src_pattern: vec![[1, 0], [1, 0], [1, 0]],
688                mapper_morphology: "projector".to_string(),
689            },
690            class: "core".to_string(),
691        },
692    );
693
694    // lateral_+x - Connect along +X axis
695    registry.add_morphology(
696        "lateral_+x".to_string(),
697        Morphology {
698            morphology_type: MorphologyType::Vectors,
699            parameters: MorphologyParameters::Vectors {
700                vectors: vec![[1, 0, 0]],
701            },
702            class: "core".to_string(),
703        },
704    );
705
706    // lateral_-x - Connect along -X axis
707    registry.add_morphology(
708        "lateral_-x".to_string(),
709        Morphology {
710            morphology_type: MorphologyType::Vectors,
711            parameters: MorphologyParameters::Vectors {
712                vectors: vec![[-1, 0, 0]],
713            },
714            class: "core".to_string(),
715        },
716    );
717
718    // lateral_+y - Connect along +Y axis
719    registry.add_morphology(
720        "lateral_+y".to_string(),
721        Morphology {
722            morphology_type: MorphologyType::Vectors,
723            parameters: MorphologyParameters::Vectors {
724                vectors: vec![[0, 1, 0]],
725            },
726            class: "core".to_string(),
727        },
728    );
729
730    // lateral_-y - Connect along -Y axis
731    registry.add_morphology(
732        "lateral_-y".to_string(),
733        Morphology {
734            morphology_type: MorphologyType::Vectors,
735            parameters: MorphologyParameters::Vectors {
736                vectors: vec![[0, -1, 0]],
737            },
738            class: "core".to_string(),
739        },
740    );
741
742    // lateral_+z - Connect along +Z axis
743    registry.add_morphology(
744        "lateral_+z".to_string(),
745        Morphology {
746            morphology_type: MorphologyType::Vectors,
747            parameters: MorphologyParameters::Vectors {
748                vectors: vec![[0, 0, 1]],
749            },
750            class: "core".to_string(),
751        },
752    );
753
754    // lateral_-z - Connect along -Z axis
755    registry.add_morphology(
756        "lateral_-z".to_string(),
757        Morphology {
758            morphology_type: MorphologyType::Vectors,
759            parameters: MorphologyParameters::Vectors {
760                vectors: vec![[0, 0, -1]],
761            },
762            class: "core".to_string(),
763        },
764    );
765}
766
767/// Load essential genome from embedded JSON
768///
769/// Automatically ensures core components (_death, _power, core morphologies) are present
770pub fn load_essential_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
771    use crate::genome::loader::load_genome_from_json;
772    let mut genome = load_genome_from_json(ESSENTIAL_GENOME_JSON)?;
773    let (areas_added, morphs_added) = ensure_core_components(&mut genome);
774    if areas_added > 0 || morphs_added > 0 {
775        tracing::info!(
776            "Essential genome: added {} core areas, {} core morphologies",
777            areas_added,
778            morphs_added
779        );
780    }
781    Ok(genome)
782}
783
784/// Load barebones genome from embedded JSON
785///
786/// Automatically ensures core components (_death, _power, core morphologies) are present
787pub fn load_barebones_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
788    use crate::genome::loader::load_genome_from_json;
789    let mut genome = load_genome_from_json(BAREBONES_GENOME_JSON)?;
790    let (areas_added, morphs_added) = ensure_core_components(&mut genome);
791    if areas_added > 0 || morphs_added > 0 {
792        tracing::info!(
793            "Barebones genome: added {} core areas, {} core morphologies",
794            areas_added,
795            morphs_added
796        );
797    }
798    Ok(genome)
799}
800
801/// Load test genome from embedded JSON
802///
803/// Automatically ensures core components (_death, _power, core morphologies) are present
804pub fn load_test_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
805    use crate::genome::loader::load_genome_from_json;
806    let mut genome = load_genome_from_json(TEST_GENOME_JSON)?;
807    let (areas_added, morphs_added) = ensure_core_components(&mut genome);
808    if areas_added > 0 || morphs_added > 0 {
809        tracing::info!(
810            "Test genome: added {} core areas, {} core morphologies",
811            areas_added,
812            morphs_added
813        );
814    }
815    Ok(genome)
816}
817
818/// Load vision genome from embedded JSON
819///
820/// Automatically ensures core components (_death, _power, core morphologies) are present
821pub fn load_vision_genome() -> Result<RuntimeGenome, crate::types::EvoError> {
822    use crate::genome::loader::load_genome_from_json;
823    let mut genome = load_genome_from_json(VISION_GENOME_JSON)?;
824    let (areas_added, morphs_added) = ensure_core_components(&mut genome);
825    if areas_added > 0 || morphs_added > 0 {
826        tracing::info!(
827            "Vision genome: added {} core areas, {} core morphologies",
828            areas_added,
829            morphs_added
830        );
831    }
832    Ok(genome)
833}
834
835#[cfg(test)]
836mod tests {
837    use super::*;
838
839    #[test]
840    fn test_create_minimal_genome() {
841        let genome = create_minimal_genome("test_genome".to_string(), "Test Genome".to_string());
842
843        assert_eq!(genome.metadata.genome_id, "test_genome");
844        assert_eq!(genome.metadata.version, "2.0");
845        assert_eq!(genome.cortical_areas.len(), 0);
846        assert_eq!(genome.morphologies.count(), 0);
847    }
848
849    #[test]
850    fn test_create_genome_with_core_areas() {
851        let genome =
852            create_genome_with_core_areas("test_genome".to_string(), "Test Genome".to_string());
853
854        assert_eq!(genome.metadata.genome_id, "test_genome");
855        assert_eq!(genome.cortical_areas.len(), 7);
856
857        let death_id = crate::genome::parser::string_to_cortical_id("_death").expect("Valid ID");
858        let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
859        let fatigue_id =
860            crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid ID");
861        let pain_id = crate::genome::parser::string_to_cortical_id("_pain").expect("Valid ID");
862        let pleasure_id =
863            crate::genome::parser::string_to_cortical_id("_pleasure").expect("Valid ID");
864        let fear_id = crate::genome::parser::string_to_cortical_id("_fear").expect("Valid ID");
865        let hope_id = crate::genome::parser::string_to_cortical_id("_hope").expect("Valid ID");
866        assert!(genome.cortical_areas.contains_key(&death_id));
867        assert!(genome.cortical_areas.contains_key(&power_id));
868        assert!(genome.cortical_areas.contains_key(&fatigue_id));
869        assert!(genome.cortical_areas.contains_key(&pain_id));
870        assert!(genome.cortical_areas.contains_key(&pleasure_id));
871        assert!(genome.cortical_areas.contains_key(&fear_id));
872        assert!(genome.cortical_areas.contains_key(&hope_id));
873
874        // Verify _power has correct properties
875        let power = genome.cortical_areas.get(&power_id).unwrap();
876        assert_eq!(power.cortical_id.as_base_64(), power_id.as_base_64());
877        assert_eq!(power.cortical_idx, 1);
878        assert_eq!(power.dimensions.width, 1);
879        assert_eq!(power.dimensions.height, 1);
880        assert_eq!(power.dimensions.depth, 1);
881    }
882
883    #[test]
884    fn test_create_genome_with_core_morphologies() {
885        let genome = create_genome_with_core_morphologies(
886            "test_genome".to_string(),
887            "Test Genome".to_string(),
888        );
889
890        assert_eq!(genome.metadata.genome_id, "test_genome");
891        assert!(genome.morphologies.count() > 0);
892        assert!(genome.morphologies.contains("block_to_block"));
893        assert!(genome.morphologies.contains("projector"));
894        assert!(genome.morphologies.contains("centered_projector"));
895        assert!(genome.morphologies.contains("transpose_xy"));
896        assert!(genome.morphologies.contains("transpose_yz"));
897        assert!(genome.morphologies.contains("transpose_xz"));
898        assert!(genome.morphologies.contains("first_to_last"));
899        assert!(genome.morphologies.contains("lateral_+x"));
900    }
901
902    #[test]
903    fn test_add_core_morphologies() {
904        let mut registry = MorphologyRegistry::new();
905        add_core_morphologies(&mut registry);
906
907        // Should have at least 11 core morphologies
908        assert!(registry.count() >= 11);
909        assert!(registry.contains("block_to_block"));
910        assert!(registry.contains("projector"));
911        assert!(registry.contains("centered_projector"));
912        assert!(registry.contains("transpose_xy"));
913        assert!(registry.contains("transpose_yz"));
914        assert!(registry.contains("transpose_xz"));
915        assert!(registry.contains("first_to_last"));
916        assert!(registry.contains("all_to_0-0-0"));
917        assert!(registry.contains("lateral_+x"));
918        assert!(registry.contains("lateral_-z"));
919    }
920
921    #[test]
922    fn test_embedded_genomes_exist() {
923        // Test that embedded genome strings are not empty
924        // These are compile-time constants, so they're always non-empty
925        // The assertions verify the constants are defined correctly
926        #[allow(clippy::const_is_empty)]
927        {
928            assert!(!ESSENTIAL_GENOME_JSON.is_empty());
929            assert!(!BAREBONES_GENOME_JSON.is_empty());
930            assert!(!TEST_GENOME_JSON.is_empty());
931            assert!(!VISION_GENOME_JSON.is_empty());
932        }
933    }
934
935    #[test]
936    fn test_load_essential_genome() {
937        let genome = load_essential_genome().expect("Failed to load essential genome");
938        assert!(!genome.cortical_areas.is_empty());
939        // Essential genome should have _power
940        let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
941        assert!(genome.cortical_areas.contains_key(&power_id));
942    }
943
944    #[test]
945    fn test_ensure_core_components_adds_missing_areas() {
946        // Create a minimal genome without core areas
947        let mut genome = create_minimal_genome("test".to_string(), "Test".to_string());
948
949        assert_eq!(genome.cortical_areas.len(), 0);
950
951        // Ensure core components
952        let (areas_added, _) = ensure_core_components(&mut genome);
953
954        // Should have added _death, _power, _fatigue, _pain, _pleasure, _fear, _hope
955        assert_eq!(areas_added, 7);
956
957        let death_id = crate::genome::parser::string_to_cortical_id("_death").expect("Valid ID");
958        let power_id = crate::genome::parser::string_to_cortical_id("_power").expect("Valid ID");
959        let fatigue_id =
960            crate::genome::parser::string_to_cortical_id("_fatigue").expect("Valid ID");
961        let pain_id = crate::genome::parser::string_to_cortical_id("_pain").expect("Valid ID");
962        let pleasure_id =
963            crate::genome::parser::string_to_cortical_id("_pleasure").expect("Valid ID");
964        let fear_id = crate::genome::parser::string_to_cortical_id("_fear").expect("Valid ID");
965        let hope_id = crate::genome::parser::string_to_cortical_id("_hope").expect("Valid ID");
966        assert!(genome.cortical_areas.contains_key(&death_id));
967        assert!(genome.cortical_areas.contains_key(&power_id));
968        assert!(genome.cortical_areas.contains_key(&fatigue_id));
969        assert!(genome.cortical_areas.contains_key(&pain_id));
970        assert!(genome.cortical_areas.contains_key(&pleasure_id));
971        assert!(genome.cortical_areas.contains_key(&fear_id));
972        assert!(genome.cortical_areas.contains_key(&hope_id));
973
974        // Verify cortical_idx assignments
975        assert_eq!(
976            genome.cortical_areas.get(&death_id).unwrap().cortical_idx,
977            0
978        );
979        assert_eq!(
980            genome.cortical_areas.get(&power_id).unwrap().cortical_idx,
981            1
982        );
983        assert_eq!(
984            genome.cortical_areas.get(&fatigue_id).unwrap().cortical_idx,
985            2
986        );
987        assert_eq!(genome.cortical_areas.get(&pain_id).unwrap().cortical_idx, 3);
988        assert_eq!(
989            genome
990                .cortical_areas
991                .get(&pleasure_id)
992                .unwrap()
993                .cortical_idx,
994            4
995        );
996        assert_eq!(genome.cortical_areas.get(&fear_id).unwrap().cortical_idx, 5);
997        assert_eq!(genome.cortical_areas.get(&hope_id).unwrap().cortical_idx, 6);
998    }
999
1000    #[test]
1001    fn test_ensure_core_components_adds_missing_morphologies() {
1002        // Create a genome with core areas but no morphologies
1003        let mut genome = create_genome_with_core_areas("test".to_string(), "Test".to_string());
1004
1005        assert_eq!(genome.morphologies.count(), 0);
1006
1007        // Ensure core components
1008        let (_, morphs_added) = ensure_core_components(&mut genome);
1009
1010        // Should have added core morphologies
1011        assert!(morphs_added > 0);
1012        assert!(genome.morphologies.contains("block_to_block"));
1013        assert!(genome.morphologies.contains("projector"));
1014        assert!(genome.morphologies.contains("centered_projector"));
1015        assert!(genome.morphologies.contains("transpose_xy"));
1016        assert!(genome.morphologies.contains("transpose_yz"));
1017        assert!(genome.morphologies.contains("transpose_xz"));
1018        assert!(genome.morphologies.contains("first_to_last"));
1019        assert!(genome.morphologies.contains("episodic_memory"));
1020        assert!(genome.morphologies.contains("lateral_+x"));
1021    }
1022
1023    #[test]
1024    fn test_ensure_core_components_idempotent() {
1025        // Create a genome with all core components
1026        let mut genome = create_genome_with_core_areas("test".to_string(), "Test".to_string());
1027        add_core_morphologies(&mut genome.morphologies);
1028
1029        // Run ensure_core_components
1030        let (areas_added, morphs_added) = ensure_core_components(&mut genome);
1031
1032        // Should not add anything (already present)
1033        assert_eq!(areas_added, 0);
1034        assert_eq!(morphs_added, 0);
1035    }
1036}