1use feagi_structures::genomic::cortical_area::CorticalArea;
15use feagi_structures::genomic::cortical_area::CorticalID;
16use feagi_structures::genomic::BrainRegion;
17use serde::{Deserialize, Serialize};
18use std::collections::HashMap;
19
20#[derive(Debug, Clone)]
22pub struct RuntimeGenome {
23 pub metadata: GenomeMetadata,
25
26 pub cortical_areas: HashMap<CorticalID, CorticalArea>,
28
29 pub brain_regions: HashMap<String, BrainRegion>,
31
32 pub morphologies: MorphologyRegistry,
34
35 pub physiology: PhysiologyConfig,
37
38 pub signatures: GenomeSignatures,
40
41 pub stats: GenomeStats,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct GenomeMetadata {
48 pub genome_id: String,
49 pub genome_title: String,
50 pub genome_description: String,
51 pub version: String,
52 pub timestamp: f64, #[serde(skip_serializing_if = "Option::is_none")]
57 pub brain_regions_root: Option<String>,
58}
59
60#[derive(Debug, Clone, Default)]
62pub struct MorphologyRegistry {
63 morphologies: HashMap<String, Morphology>,
65}
66
67impl MorphologyRegistry {
68 pub fn new() -> Self {
70 Self::default()
71 }
72
73 pub fn add_morphology(&mut self, id: String, morphology: Morphology) {
75 self.morphologies.insert(id, morphology);
76 }
77
78 pub fn get(&self, id: &str) -> Option<&Morphology> {
80 self.morphologies.get(id)
81 }
82
83 pub fn contains(&self, id: &str) -> bool {
85 self.morphologies.contains_key(id)
86 }
87
88 pub fn morphology_ids(&self) -> Vec<String> {
90 self.morphologies.keys().cloned().collect()
91 }
92
93 pub fn remove_morphology(&mut self, id: &str) -> bool {
97 self.morphologies.remove(id).is_some()
98 }
99
100 pub fn count(&self) -> usize {
102 self.morphologies.len()
103 }
104
105 pub fn iter(&self) -> impl Iterator<Item = (&String, &Morphology)> {
107 self.morphologies.iter()
108 }
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct Morphology {
114 pub morphology_type: MorphologyType,
116
117 pub parameters: MorphologyParameters,
119
120 pub class: String,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
126#[serde(rename_all = "lowercase")]
127pub enum MorphologyType {
128 Vectors,
130
131 Patterns,
133
134 Functions,
136
137 Composite,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
143#[serde(untagged)]
144pub enum MorphologyParameters {
145 Vectors { vectors: Vec<[i32; 3]> },
147
148 Patterns {
150 patterns: Vec<[Vec<PatternElement>; 2]>,
151 },
152
153 Functions {},
155
156 Composite {
158 src_seed: [u32; 3],
159 src_pattern: Vec<[i32; 2]>,
160 mapper_morphology: String,
161 },
162}
163
164#[derive(Debug, Clone, PartialEq, Eq)]
166pub enum PatternElement {
167 Value(i32),
169 Wildcard, Skip, Exclude, DirectionPositive, DirectionNegative, DirectionPositiveInclusive, DirectionNegativeInclusive, Offset(i32), Range(i32, i32), AbsoluteRange(i32, i32), }
190
191impl Serialize for PatternElement {
193 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
194 where
195 S: serde::Serializer,
196 {
197 match self {
198 PatternElement::Value(v) => serializer.serialize_i32(*v),
199 PatternElement::Wildcard => serializer.serialize_str("*"),
200 PatternElement::Skip => serializer.serialize_str("?"),
201 PatternElement::Exclude => serializer.serialize_str("!"),
202 PatternElement::DirectionPositive => serializer.serialize_str("?+"),
203 PatternElement::DirectionNegative => serializer.serialize_str("?-"),
204 PatternElement::DirectionPositiveInclusive => serializer.serialize_str("?+="),
205 PatternElement::DirectionNegativeInclusive => serializer.serialize_str("?-="),
206 PatternElement::Offset(off) => {
207 if *off >= 0 {
208 serializer.serialize_str(&format!("?+{}", off))
209 } else {
210 serializer.serialize_str(&format!("?{}", off))
211 }
212 }
213 PatternElement::Range(lo, hi) => {
214 let lo_str = if *lo >= 0 {
215 format!("?+{}", lo)
216 } else {
217 format!("?{}", lo)
218 };
219 let hi_str = if *hi >= 0 {
220 format!("?+{}", hi)
221 } else {
222 format!("?{}", hi)
223 };
224 serializer.serialize_str(&format!("{}:{}", lo_str, hi_str))
225 }
226 PatternElement::AbsoluteRange(lo, hi) => {
227 serializer.serialize_str(&format!("{}..{}", lo, hi))
228 }
229 }
230 }
231}
232
233impl<'de> Deserialize<'de> for PatternElement {
235 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
236 where
237 D: serde::Deserializer<'de>,
238 {
239 let value = serde_json::Value::deserialize(deserializer)?;
240 match value {
241 serde_json::Value::Number(n) => {
242 if let Some(i) = n.as_i64() {
243 Ok(PatternElement::Value(i as i32))
244 } else {
245 Err(serde::de::Error::custom(
246 "Pattern element must be an integer",
247 ))
248 }
249 }
250 serde_json::Value::String(s) => Self::parse_string(&s)
251 .ok_or_else(|| serde::de::Error::custom(format!("Unknown pattern element: {}", s))),
252 _ => Err(serde::de::Error::custom(
253 "Pattern element must be number or string",
254 )),
255 }
256 }
257}
258
259impl PatternElement {
260 pub fn parse_string(s: &str) -> Option<Self> {
262 match s {
263 "*" => Some(PatternElement::Wildcard),
264 "?" => Some(PatternElement::Skip),
265 "!" => Some(PatternElement::Exclude),
266 "?+" => Some(PatternElement::DirectionPositive),
267 "?-" => Some(PatternElement::DirectionNegative),
268 "?+=" => Some(PatternElement::DirectionPositiveInclusive),
269 "?-=" => Some(PatternElement::DirectionNegativeInclusive),
270 _ => {
271 if let Some(range) = Self::try_parse_range(s) {
272 return Some(range);
273 }
274 if let Some(abs_range) = Self::try_parse_absolute_range(s) {
275 return Some(abs_range);
276 }
277 if let Some(offset) = Self::try_parse_offset(s) {
278 return Some(offset);
279 }
280 None
281 }
282 }
283 }
284
285 fn try_parse_range(s: &str) -> Option<Self> {
286 let parts: Vec<&str> = s.split(':').collect();
287 if parts.len() != 2 {
288 return None;
289 }
290 let lo = Self::extract_relative_offset(parts[0])?;
291 let hi = Self::extract_relative_offset(parts[1])?;
292 Some(PatternElement::Range(lo, hi))
293 }
294
295 fn try_parse_absolute_range(s: &str) -> Option<Self> {
296 let idx = s.find("..")?;
297 if s[idx + 2..].contains("..") {
298 return None;
299 }
300 let lo = s[..idx].parse::<i32>().ok()?;
301 let hi = s[idx + 2..].parse::<i32>().ok()?;
302 Some(PatternElement::AbsoluteRange(lo, hi))
303 }
304
305 fn try_parse_offset(s: &str) -> Option<Self> {
306 let offset = Self::extract_relative_offset(s)?;
307 Some(PatternElement::Offset(offset))
308 }
309
310 fn extract_relative_offset(s: &str) -> Option<i32> {
311 if !s.starts_with('?') {
312 return None;
313 }
314 let rest = &s[1..];
315 if rest.is_empty() || rest == "+" || rest == "-" || rest == "+=" || rest == "-=" {
316 return None;
317 }
318 rest.parse::<i32>().ok()
319 }
320}
321
322#[derive(Debug, Clone, Serialize, Deserialize)]
324pub struct PhysiologyConfig {
325 pub simulation_timestep: f64,
327
328 pub max_age: u64,
330
331 pub evolution_burst_count: u64,
333
334 pub ipu_idle_threshold: u64,
336
337 pub plasticity_queue_depth: usize,
339
340 pub lifespan_mgmt_interval: u64,
342
343 #[serde(default = "default_quantization_precision")]
346 pub quantization_precision: String,
347}
348
349pub fn default_quantization_precision() -> String {
350 "int8".to_string() }
352
353impl Default for PhysiologyConfig {
354 fn default() -> Self {
355 Self {
356 simulation_timestep: 0.025,
357 max_age: 10_000_000,
358 evolution_burst_count: 50,
359 ipu_idle_threshold: 1000,
360 plasticity_queue_depth: 3,
361 lifespan_mgmt_interval: 10,
362 quantization_precision: default_quantization_precision(),
363 }
364 }
365}
366
367#[derive(Debug, Clone, Serialize, Deserialize)]
369pub struct GenomeSignatures {
370 pub genome: String,
372
373 pub blueprint: String,
375
376 pub physiology: String,
378
379 #[serde(skip_serializing_if = "Option::is_none")]
381 pub morphologies: Option<String>,
382}
383
384#[derive(Debug, Clone, Serialize, Deserialize, Default)]
386pub struct GenomeStats {
387 pub innate_cortical_area_count: usize,
389
390 pub innate_neuron_count: usize,
392
393 pub innate_synapse_count: usize,
395}
396
397#[cfg(test)]
398mod tests {
399 use super::*;
400
401 #[test]
402 fn test_morphology_registry_creation() {
403 let registry = MorphologyRegistry::new();
404 assert_eq!(registry.count(), 0);
405 }
406
407 #[test]
408 fn test_morphology_registry_add_and_get() {
409 let mut registry = MorphologyRegistry::new();
410
411 let morphology = Morphology {
412 morphology_type: MorphologyType::Vectors,
413 parameters: MorphologyParameters::Vectors {
414 vectors: vec![[1, 0, 0], [0, 1, 0]],
415 },
416 class: "test".to_string(),
417 };
418
419 registry.add_morphology("test_morph".to_string(), morphology);
420
421 assert_eq!(registry.count(), 1);
422 assert!(registry.contains("test_morph"));
423 assert!(registry.get("test_morph").is_some());
424 }
425
426 #[test]
427 fn test_physiology_config_default() {
428 let config = PhysiologyConfig::default();
429 assert_eq!(config.simulation_timestep, 0.025);
430 assert_eq!(config.max_age, 10_000_000);
431 }
432}