1use crate::connectome_manager::ConnectomeManager;
22use crate::models::{CorticalArea, CorticalID};
23use crate::types::{BduError, BduResult};
24use feagi_evolutionary::RuntimeGenome;
25use feagi_npu_neural::types::{Precision, QuantizationSpec};
26use parking_lot::RwLock;
27use std::sync::Arc;
28use tracing::{debug, error, info, trace, warn};
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum DevelopmentStage {
33 Initialization,
35 Corticogenesis,
37 Voxelogenesis,
39 Neurogenesis,
41 Synaptogenesis,
43 Completed,
45 Failed,
47}
48
49#[derive(Debug, Clone)]
51pub struct DevelopmentProgress {
52 pub stage: DevelopmentStage,
54 pub progress: u8,
56 pub cortical_areas_created: usize,
58 pub neurons_created: usize,
60 pub synapses_created: usize,
62 pub duration_ms: u64,
64}
65
66impl Default for DevelopmentProgress {
67 fn default() -> Self {
68 Self {
69 stage: DevelopmentStage::Initialization,
70 progress: 0,
71 cortical_areas_created: 0,
72 neurons_created: 0,
73 synapses_created: 0,
74 duration_ms: 0,
75 }
76 }
77}
78
79pub struct Neuroembryogenesis {
87 connectome_manager: Arc<RwLock<ConnectomeManager>>,
89
90 progress: Arc<RwLock<DevelopmentProgress>>,
92
93 start_time: std::time::Instant,
95}
96
97impl Neuroembryogenesis {
98 pub fn new(connectome_manager: Arc<RwLock<ConnectomeManager>>) -> Self {
100 Self {
101 connectome_manager,
102 progress: Arc::new(RwLock::new(DevelopmentProgress::default())),
103 start_time: std::time::Instant::now(),
104 }
105 }
106
107 pub fn get_progress(&self) -> DevelopmentProgress {
109 self.progress.read().clone()
110 }
111
112 pub fn add_cortical_areas(
124 &mut self,
125 areas: Vec<CorticalArea>,
126 genome: &RuntimeGenome,
127 ) -> BduResult<(usize, usize)> {
128 info!(target: "feagi-bdu", "𧬠Incrementally adding {} cortical areas", areas.len());
129
130 let mut total_neurons = 0;
131 let mut total_synapses = 0;
132
133 for area in &areas {
135 let mut manager = self.connectome_manager.write();
136 manager.add_cortical_area(area.clone())?;
137 info!(target: "feagi-bdu", " β Added cortical area structure: {}", area.cortical_id.as_base_64());
138 }
139
140 use feagi_structures::genomic::cortical_area::CoreCorticalType;
143 let death_id = CoreCorticalType::Death.to_cortical_id();
144 let power_id = CoreCorticalType::Power.to_cortical_id();
145 let fatigue_id = CoreCorticalType::Fatigue.to_cortical_id();
146
147 let mut core_areas = Vec::new();
148 let mut other_areas = Vec::new();
149
150 for area in &areas {
152 if area.cortical_id == death_id {
153 core_areas.push((0, area)); } else if area.cortical_id == power_id {
155 core_areas.push((1, area)); } else if area.cortical_id == fatigue_id {
157 core_areas.push((2, area)); } else {
159 other_areas.push(area);
160 }
161 }
162
163 core_areas.sort_by_key(|(idx, _)| *idx);
165
166 if !core_areas.is_empty() {
168 info!(target: "feagi-bdu", " π― Creating core area neurons FIRST ({} areas) for deterministic IDs", core_areas.len());
169 for (core_idx, area) in &core_areas {
170 let neurons_created = {
171 let mut manager = self.connectome_manager.write();
172 manager.create_neurons_for_area(&area.cortical_id)
173 };
174
175 match neurons_created {
176 Ok(count) => {
177 total_neurons += count as usize;
178 info!(target: "feagi-bdu", " β
Created {} neurons for core area {} (deterministic ID: neuron {})",
179 count, area.cortical_id.as_base_64(), core_idx);
180 }
181 Err(e) => {
182 error!(target: "feagi-bdu", " β FATAL: Failed to create neurons for core area {}: {}", area.cortical_id.as_base_64(), e);
183 return Err(e);
184 }
185 }
186 }
187 }
188
189 for area in &other_areas {
191 let neurons_created = {
192 let mut manager = self.connectome_manager.write();
193 manager.create_neurons_for_area(&area.cortical_id)
194 };
195
196 match neurons_created {
197 Ok(count) => {
198 total_neurons += count as usize;
199 trace!(
200 target: "feagi-bdu",
201 "Created {} neurons for area {}",
202 count,
203 area.cortical_id.as_base_64()
204 );
205 }
206 Err(e) => {
207 error!(target: "feagi-bdu", " β FATAL: Failed to create neurons for {}: {}", area.cortical_id.as_base_64(), e);
208 return Err(e);
210 }
211 }
212 }
213
214 for area in &areas {
216 let has_dstmap = area
218 .properties
219 .get("cortical_mapping_dst")
220 .and_then(|v| v.as_object())
221 .map(|m| !m.is_empty())
222 .unwrap_or(false);
223
224 if !has_dstmap {
225 debug!(target: "feagi-bdu", " No mappings for area {}", area.cortical_id.as_base_64());
226 continue;
227 }
228
229 let synapses_created = {
230 let mut manager = self.connectome_manager.write();
231 manager.apply_cortical_mapping(&area.cortical_id)
232 };
233
234 match synapses_created {
235 Ok(count) => {
236 total_synapses += count as usize;
237 trace!(
238 target: "feagi-bdu",
239 "Created {} synapses for area {}",
240 count,
241 area.cortical_id
242 );
243 }
244 Err(e) => {
245 warn!(target: "feagi-bdu", " β οΈ Failed to create synapses for {}: {}", area.cortical_id, e);
246 let estimated = estimate_synapses_for_area(area, genome);
247 total_synapses += estimated;
248 }
249 }
250 }
251
252 info!(target: "feagi-bdu", "β
Incremental add complete: {} areas, {} neurons, {} synapses",
253 areas.len(), total_neurons, total_synapses);
254
255 Ok((total_neurons, total_synapses))
256 }
257
258 pub fn develop_from_genome(&mut self, genome: &RuntimeGenome) -> BduResult<()> {
262 info!(target: "feagi-bdu","𧬠Starting neuroembryogenesis for genome: {}", genome.metadata.genome_id);
263
264 let _quantization_precision = &genome.physiology.quantization_precision;
266 let quant_spec = QuantizationSpec::default();
268
269 info!(target: "feagi-bdu",
270 " Quantization precision: {:?} (range: [{}, {}] for membrane potential)",
271 quant_spec.precision,
272 quant_spec.membrane_potential_min,
273 quant_spec.membrane_potential_max
274 );
275
276 match quant_spec.precision {
280 Precision::FP32 => {
281 info!(target: "feagi-bdu", " β Using FP32 (32-bit floating-point) - highest precision");
282 info!(target: "feagi-bdu", " Memory usage: Baseline (4 bytes/neuron for membrane potential)");
283 }
284 Precision::INT8 => {
285 info!(target: "feagi-bdu", " β Using INT8 (8-bit integer) - memory efficient");
286 info!(target: "feagi-bdu", " Memory reduction: 42% (1 byte/neuron for membrane potential)");
287 info!(target: "feagi-bdu", " Quantization range: [{}, {}]",
288 quant_spec.membrane_potential_min,
289 quant_spec.membrane_potential_max);
290 }
293 Precision::FP16 => {
294 warn!(target: "feagi-bdu", " FP16 quantization requested but not yet implemented.");
295 warn!(target: "feagi-bdu", " FP16 support planned for future GPU optimization.");
296 }
298 }
299
300 info!(target: "feagi-bdu", " β Quantization handled by DynamicNPU (dispatches at runtime)");
303
304 self.update_stage(DevelopmentStage::Initialization, 0);
306
307 self.corticogenesis(genome)?;
309
310 self.voxelogenesis(genome)?;
312
313 self.neurogenesis(genome)?;
315
316 self.synaptogenesis(genome)?;
318
319 self.update_stage(DevelopmentStage::Completed, 100);
321
322 let progress = self.progress.read();
323 info!(target: "feagi-bdu",
324 "β
Neuroembryogenesis completed in {}ms: {} cortical areas, {} neurons, {} synapses",
325 progress.duration_ms,
326 progress.cortical_areas_created,
327 progress.neurons_created,
328 progress.synapses_created
329 );
330
331 Ok(())
332 }
333
334 fn corticogenesis(&mut self, genome: &RuntimeGenome) -> BduResult<()> {
336 self.update_stage(DevelopmentStage::Corticogenesis, 0);
337 info!(target: "feagi-bdu","π§ Stage 1: Corticogenesis - Creating {} cortical areas", genome.cortical_areas.len());
338 info!(target: "feagi-bdu","π Genome brain_regions check: is_empty={}, count={}",
339 genome.brain_regions.is_empty(), genome.brain_regions.len());
340 if !genome.brain_regions.is_empty() {
341 info!(target: "feagi-bdu"," Existing regions: {:?}", genome.brain_regions.keys().collect::<Vec<_>>());
342 }
343
344 let total_areas = genome.cortical_areas.len();
345
346 for (idx, (cortical_id, area)) in genome.cortical_areas.iter().enumerate() {
348 {
350 let mut manager = self.connectome_manager.write();
351 manager.add_cortical_area(area.clone())?;
352 } let progress_pct = ((idx + 1) * 100 / total_areas.max(1)) as u8;
356 self.update_progress(|p| {
357 p.cortical_areas_created = idx + 1;
358 p.progress = progress_pct;
359 });
360
361 trace!(target: "feagi-bdu", "Created cortical area: {} ({})", cortical_id, area.name);
362 }
363
364 info!(target: "feagi-bdu","π BRAIN REGION AUTO-GEN CHECK: genome.brain_regions.is_empty() = {}", genome.brain_regions.is_empty());
367 let (brain_regions_to_add, region_parent_map) = if genome.brain_regions.is_empty() {
368 info!(target: "feagi-bdu"," β
TRIGGERING AUTO-GENERATION: No brain_regions in genome - auto-generating default root region");
369 info!(target: "feagi-bdu"," π Genome has {} cortical areas to process", genome.cortical_areas.len());
370
371 let all_cortical_ids = genome.cortical_areas.keys().cloned().collect::<Vec<_>>();
373 info!(target: "feagi-bdu"," π Collected {} cortical area IDs: {:?}", all_cortical_ids.len(),
374 if all_cortical_ids.len() <= 5 {
375 format!("{:?}", all_cortical_ids.iter().map(|id| id.to_string()).collect::<Vec<_>>())
376 } else {
377 format!("{:?}...", all_cortical_ids[0..5].iter().map(|id| id.to_string()).collect::<Vec<_>>())
378 });
379
380 let mut auto_inputs = Vec::new();
382 let mut auto_outputs = Vec::new();
383
384 let mut ipu_areas = Vec::new(); let mut opu_areas = Vec::new(); let mut core_areas = Vec::new(); let mut custom_memory_areas = Vec::new(); for (area_id, area) in genome.cortical_areas.iter() {
391 let area_id_str = area_id.to_string();
398 let category = if area_id_str.starts_with("___") {
400 "CORE"
401 } else if let Ok(cortical_type) = area.cortical_id.as_cortical_type() {
402 use feagi_structures::genomic::cortical_area::CorticalAreaType;
404 match cortical_type {
405 CorticalAreaType::Core(_) => "CORE",
406 CorticalAreaType::BrainInput(_) => "IPU",
407 CorticalAreaType::BrainOutput(_) => "OPU",
408 CorticalAreaType::Memory(_) => "MEMORY",
409 CorticalAreaType::Custom(_) => "CUSTOM",
410 }
411 } else {
412 let cortical_group = area
414 .properties
415 .get("cortical_group")
416 .and_then(|v| v.as_str())
417 .map(|s| s.to_uppercase());
418
419 match cortical_group.as_deref() {
420 Some("IPU") => "IPU",
421 Some("OPU") => "OPU",
422 Some("CORE") => "CORE",
423 Some("MEMORY") => "MEMORY",
424 Some("CUSTOM") => "CUSTOM",
425 _ => "CUSTOM", }
427 };
428
429 if ipu_areas.len() + opu_areas.len() + core_areas.len() + custom_memory_areas.len()
431 < 5
432 {
433 let source = if area.cortical_id.as_cortical_type().is_ok() {
434 "cortical_id_type"
435 } else if area.properties.contains_key("cortical_group") {
436 "cortical_group"
437 } else {
438 "default_fallback"
439 };
440
441 if area.cortical_id.as_cortical_type().is_ok() {
443 let type_desc = crate::cortical_type_utils::describe_cortical_type(area);
444 let frame_handling =
445 if crate::cortical_type_utils::uses_absolute_frames(area) {
446 "absolute"
447 } else if crate::cortical_type_utils::uses_incremental_frames(area) {
448 "incremental"
449 } else {
450 "n/a"
451 };
452 info!(target: "feagi-bdu"," π {}, frames={}, source={}",
453 type_desc, frame_handling, source);
454 } else {
455 info!(target: "feagi-bdu"," π Area {}: category={}, source={}",
456 area_id_str, category, source);
457 }
458 }
459
460 match category {
462 "IPU" => {
463 ipu_areas.push(*area_id);
464 auto_inputs.push(*area_id);
465 }
466 "OPU" => {
467 opu_areas.push(*area_id);
468 auto_outputs.push(*area_id);
469 }
470 "CORE" => {
471 core_areas.push(*area_id);
472 }
473 "MEMORY" | "CUSTOM" => {
474 custom_memory_areas.push(*area_id);
475 }
476 _ => {}
477 }
478 }
479
480 info!(target: "feagi-bdu"," π Classification complete: IPU={}, OPU={}, CORE={}, CUSTOM/MEMORY={}",
481 ipu_areas.len(), opu_areas.len(), core_areas.len(), custom_memory_areas.len());
482
483 use feagi_structures::genomic::brain_regions::{BrainRegion, RegionID, RegionType};
485 let mut regions_map = std::collections::HashMap::new();
486
487 let mut root_area_ids = Vec::new();
489 root_area_ids.extend(ipu_areas.iter().cloned());
490 root_area_ids.extend(opu_areas.iter().cloned());
491 root_area_ids.extend(core_areas.iter().cloned());
492
493 let (root_inputs, root_outputs) =
495 Self::analyze_region_io(&root_area_ids, &genome.cortical_areas);
496
497 let root_region_id = RegionID::new();
500 let root_region_id_str = root_region_id.to_string();
501
502 let mut root_region = BrainRegion::new(
503 root_region_id,
504 "Root Brain Region".to_string(),
505 RegionType::Undefined,
506 )
507 .expect("Failed to create root region")
508 .with_areas(root_area_ids.iter().cloned());
509
510 if !root_inputs.is_empty() {
512 root_region
513 .add_property("inputs".to_string(), serde_json::json!(root_inputs.clone()));
514 }
515 if !root_outputs.is_empty() {
516 root_region.add_property(
517 "outputs".to_string(),
518 serde_json::json!(root_outputs.clone()),
519 );
520 }
521
522 info!(target: "feagi-bdu"," β
Created root region with {} areas (IPU={}, OPU={}, CORE={}) - analyzed: {} inputs, {} outputs",
523 root_area_ids.len(), ipu_areas.len(), opu_areas.len(), core_areas.len(),
524 root_inputs.len(), root_outputs.len());
525
526 let mut subregion_id = None;
528 if !custom_memory_areas.is_empty() {
529 let mut custom_memory_strs: Vec<String> = custom_memory_areas
531 .iter()
532 .map(|id| id.as_base_64())
533 .collect();
534 custom_memory_strs.sort(); let combined = custom_memory_strs.join("|");
536
537 use std::collections::hash_map::DefaultHasher;
539 use std::hash::{Hash, Hasher};
540 let mut hasher = DefaultHasher::new();
541 combined.hash(&mut hasher);
542 let hash = hasher.finish();
543 let hash_hex = format!("{:08x}", hash as u32);
544 let region_id = format!("region_autogen_{}", hash_hex);
545
546 let (subregion_inputs, subregion_outputs) =
548 Self::analyze_region_io(&custom_memory_areas, &genome.cortical_areas);
549
550 let autogen_position =
552 Self::calculate_autogen_region_position(&root_area_ids, genome);
553
554 let mut subregion = BrainRegion::new(
556 RegionID::new(), "Autogen Region".to_string(),
558 RegionType::Undefined, )
560 .expect("Failed to create subregion")
561 .with_areas(custom_memory_areas.iter().cloned());
562
563 subregion.add_property(
565 "coordinate_3d".to_string(),
566 serde_json::json!(autogen_position),
567 );
568 subregion.add_property("coordinate_2d".to_string(), serde_json::json!([0, 0]));
569
570 if !subregion_inputs.is_empty() {
572 subregion.add_property(
573 "inputs".to_string(),
574 serde_json::json!(subregion_inputs.clone()),
575 );
576 }
577 if !subregion_outputs.is_empty() {
578 subregion.add_property(
579 "outputs".to_string(),
580 serde_json::json!(subregion_outputs.clone()),
581 );
582 }
583
584 let subregion_id_str = subregion.region_id.to_string();
585
586 info!(target: "feagi-bdu"," β
Created subregion '{}' with {} CUSTOM/MEMORY areas ({} inputs, {} outputs)",
587 region_id, custom_memory_areas.len(), subregion_inputs.len(), subregion_outputs.len());
588
589 regions_map.insert(subregion_id_str.clone(), subregion);
590 subregion_id = Some(subregion_id_str);
591 }
592
593 regions_map.insert(root_region_id_str.clone(), root_region);
594
595 let total_inputs = root_inputs.len()
597 + if let Some(ref sid) = subregion_id {
598 regions_map
599 .get(sid)
600 .and_then(|r| r.properties.get("inputs"))
601 .and_then(|v| v.as_array())
602 .map(|a| a.len())
603 .unwrap_or(0)
604 } else {
605 0
606 };
607
608 let total_outputs = root_outputs.len()
609 + if let Some(ref sid) = subregion_id {
610 regions_map
611 .get(sid)
612 .and_then(|r| r.properties.get("outputs"))
613 .and_then(|v| v.as_array())
614 .map(|a| a.len())
615 .unwrap_or(0)
616 } else {
617 0
618 };
619
620 info!(target: "feagi-bdu"," β
Auto-generated {} brain region(s) with {} total cortical areas ({} total inputs, {} total outputs)",
621 regions_map.len(), all_cortical_ids.len(), total_inputs, total_outputs);
622
623 let mut parent_map = std::collections::HashMap::new();
625 if let Some(ref sub_id) = subregion_id {
626 parent_map.insert(sub_id.clone(), root_region_id_str.clone());
627 info!(target: "feagi-bdu"," π Parent relationship: {} -> {}", sub_id, root_region_id_str);
628 }
629
630 (regions_map, parent_map)
631 } else {
632 info!(target: "feagi-bdu"," π Genome already has {} brain regions - using existing structure", genome.brain_regions.len());
633 (
636 genome.brain_regions.clone(),
637 std::collections::HashMap::new(),
638 )
639 };
640
641 {
643 let mut manager = self.connectome_manager.write();
644 let brain_region_count = brain_regions_to_add.len();
645 info!(target: "feagi-bdu"," Adding {} brain regions from genome", brain_region_count);
646
647 let root_entry = brain_regions_to_add
649 .iter()
650 .find(|(_, region)| region.name == "Root Brain Region");
651 if let Some((root_id, root_region)) = root_entry {
652 manager.add_brain_region(root_region.clone(), None)?;
653 debug!(target: "feagi-bdu"," β Added brain region: {} (Root Brain Region) [parent=None]", root_id);
654 }
655
656 for (region_id, region) in brain_regions_to_add.iter() {
658 if region.name == "Root Brain Region" {
659 continue; }
661
662 let parent_id = region_parent_map.get(region_id).cloned();
663 manager.add_brain_region(region.clone(), parent_id.clone())?;
664 debug!(target: "feagi-bdu"," β Added brain region: {} ({}) [parent={:?}]",
665 region_id, region.name, parent_id);
666 }
667
668 info!(target: "feagi-bdu"," Total brain regions in ConnectomeManager: {}", manager.get_brain_region_ids().len());
669 } self.update_stage(DevelopmentStage::Corticogenesis, 100);
672 info!(target: "feagi-bdu"," β
Corticogenesis complete: {} cortical areas created", total_areas);
673
674 Ok(())
675 }
676
677 fn voxelogenesis(&mut self, _genome: &RuntimeGenome) -> BduResult<()> {
679 self.update_stage(DevelopmentStage::Voxelogenesis, 0);
680 info!(target: "feagi-bdu","π Stage 2: Voxelogenesis - Establishing spatial framework");
681
682 self.update_stage(DevelopmentStage::Voxelogenesis, 100);
686 info!(target: "feagi-bdu"," β
Voxelogenesis complete: Spatial framework established");
687
688 Ok(())
689 }
690
691 fn neurogenesis(&mut self, genome: &RuntimeGenome) -> BduResult<()> {
700 self.update_stage(DevelopmentStage::Neurogenesis, 0);
701 info!(target: "feagi-bdu","π¬ Stage 3: Neurogenesis - Generating neurons (SIMD-optimized batches)");
702
703 let expected_neurons = genome.stats.innate_neuron_count;
704 info!(target: "feagi-bdu"," Expected innate neurons from genome: {}", expected_neurons);
705
706 use feagi_structures::genomic::cortical_area::CoreCorticalType;
708 let death_id = CoreCorticalType::Death.to_cortical_id();
709 let power_id = CoreCorticalType::Power.to_cortical_id();
710 let fatigue_id = CoreCorticalType::Fatigue.to_cortical_id();
711
712 let mut core_areas = Vec::new();
713 let mut other_areas = Vec::new();
714
715 for (cortical_id, area) in genome.cortical_areas.iter() {
717 if *cortical_id == death_id {
718 core_areas.push((0, *cortical_id, area)); } else if *cortical_id == power_id {
720 core_areas.push((1, *cortical_id, area)); } else if *cortical_id == fatigue_id {
722 core_areas.push((2, *cortical_id, area)); } else {
724 other_areas.push((*cortical_id, area));
725 }
726 }
727
728 core_areas.sort_by_key(|(idx, _, _)| *idx);
730
731 info!(target: "feagi-bdu"," π― Creating core area neurons FIRST ({} areas) for deterministic IDs", core_areas.len());
732
733 let mut total_neurons_created = 0;
734 let mut processed_count = 0;
735 let total_areas = genome.cortical_areas.len();
736
737 for (core_idx, cortical_id, area) in &core_areas {
739 let per_voxel_count = area
740 .properties
741 .get("neurons_per_voxel")
742 .and_then(|v| v.as_u64())
743 .unwrap_or(1) as i64;
744
745 let cortical_id_str = cortical_id.to_string();
746 info!(target: "feagi-bdu"," π [CORE-AREA {}] {} - dimensions: {:?}, per_voxel: {}",
747 core_idx, cortical_id_str, area.dimensions, per_voxel_count);
748
749 if per_voxel_count == 0 {
750 warn!(target: "feagi-bdu"," β οΈ Skipping core area {} - per_voxel_neuron_cnt is 0", cortical_id_str);
751 continue;
752 }
753
754 let neurons_created = {
756 let manager_arc = self.connectome_manager.clone();
757 let mut manager = manager_arc.write();
758 manager.create_neurons_for_area(cortical_id)
759 };
760
761 match neurons_created {
762 Ok(count) => {
763 total_neurons_created += count as usize;
764 info!(target: "feagi-bdu"," β
Created {} neurons for core area {} (deterministic ID: neuron {})",
765 count, cortical_id_str, core_idx);
766 }
767 Err(e) => {
768 error!(target: "feagi-bdu"," β FATAL: Failed to create neurons for core area {}: {}", cortical_id_str, e);
769 return Err(e);
770 }
771 }
772
773 processed_count += 1;
774 let progress_pct = (processed_count * 100 / total_areas.max(1)) as u8;
775 self.update_progress(|p| {
776 p.neurons_created = total_neurons_created;
777 p.progress = progress_pct;
778 });
779 }
780
781 info!(target: "feagi-bdu"," π¦ Creating neurons for {} other areas", other_areas.len());
783 for (cortical_id, area) in &other_areas {
784 let _per_voxel_count = area
786 .properties
787 .get("neurons_per_voxel")
788 .and_then(|v| v.as_u64())
789 .unwrap_or(1) as i64;
790
791 let per_voxel_count = area
792 .properties
793 .get("neurons_per_voxel")
794 .and_then(|v| v.as_u64())
795 .unwrap_or(1) as i64;
796
797 let cortical_id_str = cortical_id.to_string();
798
799 if per_voxel_count == 0 {
800 warn!(target: "feagi-bdu"," β οΈ Skipping area {} - per_voxel_neuron_cnt is 0 (will have NO neurons!)", cortical_id_str);
801 continue;
802 }
803
804 let neurons_created = {
807 let manager_arc = self.connectome_manager.clone();
808 let mut manager = manager_arc.write();
809 manager.create_neurons_for_area(cortical_id)
810 }; match neurons_created {
813 Ok(count) => {
814 total_neurons_created += count as usize;
815 trace!(
816 target: "feagi-bdu",
817 "Created {} neurons for area {}",
818 count,
819 cortical_id_str
820 );
821 }
822 Err(e) => {
823 warn!(target: "feagi-bdu"," Failed to create neurons for {}: {} (NPU may not be connected)",
825 cortical_id_str, e);
826 let total_voxels = area.dimensions.width as usize
827 * area.dimensions.height as usize
828 * area.dimensions.depth as usize;
829 let expected = total_voxels * per_voxel_count as usize;
830 total_neurons_created += expected;
831 }
832 }
833
834 processed_count += 1;
835 let progress_pct = (processed_count * 100 / total_areas.max(1)) as u8;
837 self.update_progress(|p| {
838 p.neurons_created = total_neurons_created;
839 p.progress = progress_pct;
840 });
841 }
842
843 if expected_neurons > 0 && total_neurons_created != expected_neurons {
845 trace!(target: "feagi-bdu",
846 created_neurons = total_neurons_created,
847 genome_stats_innate = expected_neurons,
848 "Neuron creation complete (genome stats may only count innate neurons)"
849 );
850 }
851
852 self.update_stage(DevelopmentStage::Neurogenesis, 100);
853 info!(target: "feagi-bdu"," β
Neurogenesis complete: {} neurons created", total_neurons_created);
854
855 Ok(())
856 }
857
858 fn synaptogenesis(&mut self, genome: &RuntimeGenome) -> BduResult<()> {
864 self.update_stage(DevelopmentStage::Synaptogenesis, 0);
865 info!(target: "feagi-bdu","π Stage 4: Synaptogenesis - Forming synaptic connections (SIMD-optimized batches)");
866
867 let expected_synapses = genome.stats.innate_synapse_count;
868 info!(target: "feagi-bdu"," Expected innate synapses from genome: {}", expected_synapses);
869
870 let mut total_synapses_created = 0;
871 let total_areas = genome.cortical_areas.len();
872
873 for (idx, (_src_cortical_id, src_area)) in genome.cortical_areas.iter().enumerate() {
876 let has_dstmap = src_area
878 .properties
879 .get("cortical_mapping_dst")
880 .and_then(|v| v.as_object())
881 .map(|m| !m.is_empty())
882 .unwrap_or(false);
883
884 if !has_dstmap {
885 trace!(target: "feagi-bdu", "No dstmap for area {}", &src_area.cortical_id);
886 continue;
887 }
888
889 let src_cortical_id = &src_area.cortical_id;
893 let src_cortical_id_str = src_cortical_id.to_string(); let synapses_created = {
895 let manager_arc = self.connectome_manager.clone();
896 let mut manager = manager_arc.write();
897 manager.apply_cortical_mapping(src_cortical_id)
898 }; match synapses_created {
901 Ok(count) => {
902 total_synapses_created += count as usize;
903 trace!(
904 target: "feagi-bdu",
905 "Created {} synapses for area {}",
906 count,
907 src_cortical_id_str
908 );
909 }
910 Err(e) => {
911 warn!(target: "feagi-bdu"," Failed to create synapses for {}: {} (NPU may not be connected)",
913 src_cortical_id_str, e);
914 let estimated = estimate_synapses_for_area(src_area, genome);
915 total_synapses_created += estimated;
916 }
917 }
918
919 let progress_pct = ((idx + 1) * 100 / total_areas.max(1)) as u8;
921 self.update_progress(|p| {
922 p.synapses_created = total_synapses_created;
923 p.progress = progress_pct;
924 });
925 }
926
927 let npu_arc = {
932 let manager = self.connectome_manager.read();
933 manager.get_npu().cloned()
934 };
935 if let Some(npu_arc) = npu_arc {
936 let mut npu_lock = npu_arc
937 .lock()
938 .map_err(|e| BduError::Internal(format!("Failed to lock NPU: {}", e)))?;
939 npu_lock.rebuild_synapse_index();
940
941 let manager = self.connectome_manager.read();
943 manager.update_cached_synapse_count();
944 }
945
946 #[cfg(feature = "plasticity")]
949 {
950 use feagi_evolutionary::extract_memory_properties;
951 use feagi_npu_plasticity::{MemoryNeuronLifecycleConfig, PlasticityExecutor};
952
953 let manager = self.connectome_manager.read();
954 if let Some(executor) = manager.get_plasticity_executor() {
955 let mut registered_count = 0;
956
957 for area_id in manager.get_cortical_area_ids() {
959 if let Some(area) = manager.get_cortical_area(area_id) {
960 if let Some(mem_props) = extract_memory_properties(&area.properties) {
961 let upstream_areas = manager.get_upstream_cortical_areas(area_id);
962
963 if let Some(npu_arc) = manager.get_npu() {
966 if let Ok(mut npu) = npu_arc.lock() {
967 let existing_configs = npu.get_all_fire_ledger_configs();
968 for &upstream_idx in &upstream_areas {
969 let existing = existing_configs
970 .iter()
971 .find(|(idx, _)| *idx == upstream_idx)
972 .map(|(_, w)| *w)
973 .unwrap_or(0);
974
975 let desired = mem_props.temporal_depth as usize;
976 let resolved = existing.max(desired);
977 if resolved != existing {
978 if let Err(e) = npu.configure_fire_ledger_window(
979 upstream_idx,
980 resolved,
981 ) {
982 warn!(
983 target: "feagi-bdu",
984 "Failed to configure FireLedger window for upstream area idx={} (requested={}): {}",
985 upstream_idx,
986 resolved,
987 e
988 );
989 }
990 }
991 }
992 } else {
993 warn!(target: "feagi-bdu", "Failed to lock NPU for FireLedger configuration");
994 }
995 }
996
997 if let Ok(exec) = executor.lock() {
998 let lifecycle_config = MemoryNeuronLifecycleConfig {
999 initial_lifespan: mem_props.init_lifespan,
1000 lifespan_growth_rate: mem_props.lifespan_growth_rate,
1001 longterm_threshold: mem_props.longterm_threshold,
1002 max_reactivations: 1000,
1003 };
1004
1005 exec.register_memory_area(
1006 area.cortical_idx,
1007 area_id.as_base_64(),
1008 mem_props.temporal_depth,
1009 upstream_areas.clone(),
1010 Some(lifecycle_config),
1011 );
1012
1013 registered_count += 1;
1014 }
1015 }
1016 }
1017 }
1018 let _ = registered_count; }
1020 }
1021
1022 if expected_synapses > 0 {
1024 let diff = (total_synapses_created as i64 - expected_synapses as i64).abs();
1025 let diff_pct = (diff as f64 / expected_synapses.max(1) as f64) * 100.0;
1026
1027 if diff_pct > 10.0 {
1028 warn!(target: "feagi-bdu",
1029 "Synapse count variance: created {} but genome stats expected {} ({:.1}% difference)",
1030 total_synapses_created, expected_synapses, diff_pct
1031 );
1032 } else {
1033 info!(target: "feagi-bdu",
1034 "Synapse count matches genome stats within {:.1}% ({} vs {})",
1035 diff_pct, total_synapses_created, expected_synapses
1036 );
1037 }
1038 }
1039
1040 self.update_stage(DevelopmentStage::Synaptogenesis, 100);
1041 info!(target: "feagi-bdu"," β
Synaptogenesis complete: {} synapses created", total_synapses_created);
1042
1043 Ok(())
1044 }
1045}
1046
1047fn estimate_synapses_for_area(
1051 src_area: &CorticalArea,
1052 genome: &feagi_evolutionary::RuntimeGenome,
1053) -> usize {
1054 let dstmap = match src_area.properties.get("cortical_mapping_dst") {
1055 Some(serde_json::Value::Object(map)) => map,
1056 _ => return 0,
1057 };
1058
1059 let mut total = 0;
1060
1061 for (dst_id, rules) in dstmap {
1062 let dst_cortical_id = match feagi_evolutionary::string_to_cortical_id(dst_id) {
1064 Ok(id) => id,
1065 Err(_) => continue,
1066 };
1067 let dst_area = match genome.cortical_areas.get(&dst_cortical_id) {
1068 Some(area) => area,
1069 None => continue,
1070 };
1071
1072 let rules_array = match rules.as_array() {
1073 Some(arr) => arr,
1074 None => continue,
1075 };
1076
1077 for rule in rules_array {
1078 let morphology_id = rule
1079 .get("morphology_id")
1080 .and_then(|v| v.as_str())
1081 .unwrap_or("unknown");
1082 let scalar = rule
1083 .get("morphology_scalar")
1084 .and_then(|v| v.as_i64())
1085 .unwrap_or(1) as usize;
1086
1087 let src_per_voxel = src_area
1089 .properties
1090 .get("neurons_per_voxel")
1091 .and_then(|v| v.as_u64())
1092 .unwrap_or(1) as usize;
1093 let dst_per_voxel = dst_area
1094 .properties
1095 .get("neurons_per_voxel")
1096 .and_then(|v| v.as_u64())
1097 .unwrap_or(1) as usize;
1098
1099 let src_voxels =
1100 src_area.dimensions.width * src_area.dimensions.height * src_area.dimensions.depth;
1101 let dst_voxels =
1102 dst_area.dimensions.width * dst_area.dimensions.height * dst_area.dimensions.depth;
1103
1104 let src_neurons = src_voxels as usize * src_per_voxel;
1105 let dst_neurons = dst_voxels as usize * dst_per_voxel as usize;
1106
1107 let count = match morphology_id {
1109 "block_to_block" => src_neurons * dst_per_voxel * scalar,
1110 "projector" => src_neurons * dst_neurons * scalar,
1111 _ if morphology_id.contains("lateral") => src_neurons * scalar,
1112 _ => (src_neurons * scalar).min(src_neurons * dst_neurons / 10),
1113 };
1114
1115 total += count;
1116 }
1117 }
1118
1119 total
1120}
1121
1122impl Neuroembryogenesis {
1123 fn calculate_autogen_region_position(
1125 root_area_ids: &[CorticalID],
1126 genome: &feagi_evolutionary::RuntimeGenome,
1127 ) -> [i32; 3] {
1128 if root_area_ids.is_empty() {
1129 return [100, 0, 0];
1130 }
1131
1132 let mut min_x = i32::MAX;
1133 let mut max_x = i32::MIN;
1134 let mut min_y = i32::MAX;
1135 let mut max_y = i32::MIN;
1136 let mut min_z = i32::MAX;
1137 let mut max_z = i32::MIN;
1138
1139 for cortical_id in root_area_ids {
1140 if let Some(area) = genome.cortical_areas.get(cortical_id) {
1141 let pos: (i32, i32, i32) = area.position.into();
1142 let dims = (
1143 area.dimensions.width as i32,
1144 area.dimensions.height as i32,
1145 area.dimensions.depth as i32,
1146 );
1147
1148 min_x = min_x.min(pos.0);
1149 max_x = max_x.max(pos.0 + dims.0);
1150 min_y = min_y.min(pos.1);
1151 max_y = max_y.max(pos.1 + dims.1);
1152 min_z = min_z.min(pos.2);
1153 max_z = max_z.max(pos.2 + dims.2);
1154 }
1155 }
1156
1157 let bbox_width = (max_x - min_x).max(1);
1158 let padding = (bbox_width / 5).max(50);
1159 let autogen_x = max_x + padding;
1160 let autogen_y = (min_y + max_y) / 2;
1161 let autogen_z = (min_z + max_z) / 2;
1162
1163 info!(target: "feagi-bdu",
1164 " π Autogen position: ({}, {}, {}) [padding: {}]",
1165 autogen_x, autogen_y, autogen_z, padding);
1166
1167 [autogen_x, autogen_y, autogen_z]
1168 }
1169
1170 fn analyze_region_io(
1176 region_area_ids: &[feagi_structures::genomic::cortical_area::CorticalID],
1177 all_cortical_areas: &std::collections::HashMap<CorticalID, CorticalArea>,
1178 ) -> (Vec<String>, Vec<String>) {
1179 let area_set: std::collections::HashSet<_> = region_area_ids.iter().cloned().collect();
1180 let mut inputs = Vec::new();
1181 let mut outputs = Vec::new();
1182
1183 let extract_destinations = |area: &CorticalArea| -> Vec<String> {
1185 area.properties
1186 .get("cortical_mapping_dst")
1187 .and_then(|v| v.as_object())
1188 .map(|obj| obj.keys().cloned().collect())
1189 .unwrap_or_default()
1190 };
1191
1192 for area_id in region_area_ids {
1194 if let Some(area) = all_cortical_areas.get(area_id) {
1195 let destinations = extract_destinations(area);
1196 let external_destinations: Vec<_> = destinations
1198 .iter()
1199 .filter_map(|dest| feagi_evolutionary::string_to_cortical_id(dest).ok())
1200 .filter(|dest_id| !area_set.contains(dest_id))
1201 .collect();
1202
1203 if !external_destinations.is_empty() {
1204 outputs.push(area_id.as_base_64());
1205 }
1206 }
1207 }
1208
1209 for (source_area_id, source_area) in all_cortical_areas.iter() {
1211 if area_set.contains(source_area_id) {
1213 continue;
1214 }
1215
1216 let destinations = extract_destinations(source_area);
1217 for dest_str in destinations {
1218 if let Ok(dest_id) = feagi_evolutionary::string_to_cortical_id(&dest_str) {
1219 if area_set.contains(&dest_id) {
1220 let dest_string = dest_id.as_base_64();
1221 if !inputs.contains(&dest_string) {
1222 inputs.push(dest_string);
1223 }
1224 }
1225 }
1226 }
1227 }
1228
1229 (inputs, outputs)
1230 }
1231
1232 fn update_stage(&self, stage: DevelopmentStage, progress: u8) {
1234 let mut p = self.progress.write();
1235 p.stage = stage;
1236 p.progress = progress;
1237 p.duration_ms = self.start_time.elapsed().as_millis() as u64;
1238 }
1239
1240 fn update_progress<F>(&self, f: F)
1242 where
1243 F: FnOnce(&mut DevelopmentProgress),
1244 {
1245 let mut p = self.progress.write();
1246 f(&mut p);
1247 p.duration_ms = self.start_time.elapsed().as_millis() as u64;
1248 }
1249}
1250
1251#[cfg(test)]
1252mod tests {
1253 use super::*;
1254 use feagi_evolutionary::create_genome_with_core_morphologies;
1255 use feagi_structures::genomic::cortical_area::CorticalAreaDimensions;
1256
1257 #[test]
1258 fn test_neuroembryogenesis_creation() {
1259 let manager = ConnectomeManager::instance();
1260 let neuro = Neuroembryogenesis::new(manager);
1261
1262 let progress = neuro.get_progress();
1263 assert_eq!(progress.stage, DevelopmentStage::Initialization);
1264 assert_eq!(progress.progress, 0);
1265 }
1266
1267 #[test]
1268 fn test_development_from_minimal_genome() {
1269 ConnectomeManager::reset_for_testing(); let manager = ConnectomeManager::instance();
1271 let mut neuro = Neuroembryogenesis::new(manager.clone());
1272
1273 let mut genome = create_genome_with_core_morphologies(
1275 "test_genome".to_string(),
1276 "Test Genome".to_string(),
1277 );
1278
1279 let cortical_id = CorticalID::try_from_bytes(b"cst_neur").unwrap(); let cortical_type = cortical_id
1281 .as_cortical_type()
1282 .expect("Failed to get cortical type");
1283 let area = CorticalArea::new(
1284 cortical_id,
1285 0,
1286 "Test Area".to_string(),
1287 CorticalAreaDimensions::new(10, 10, 10).unwrap(),
1288 (0, 0, 0).into(),
1289 cortical_type,
1290 )
1291 .expect("Failed to create cortical area");
1292 genome.cortical_areas.insert(cortical_id, area);
1293
1294 let result = neuro.develop_from_genome(&genome);
1296 assert!(result.is_ok(), "Development failed: {:?}", result);
1297
1298 let progress = neuro.get_progress();
1300 assert_eq!(progress.stage, DevelopmentStage::Completed);
1301 assert_eq!(progress.progress, 100);
1302 assert_eq!(progress.cortical_areas_created, 1);
1303
1304 let mgr = manager.read();
1306 assert!(
1308 mgr.has_cortical_area(&cortical_id),
1309 "Cortical area should have been added to connectome"
1310 );
1311
1312 println!("β
Development completed in {}ms", progress.duration_ms);
1313 }
1314}