use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::sync::Arc;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AmalgamationPendingSummary {
pub amalgamation_id: String,
pub genome_title: String,
pub circuit_size: [i32; 3],
}
#[derive(Debug, Clone)]
pub struct AmalgamationPending {
pub summary: AmalgamationPendingSummary,
pub genome_json: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AmalgamationHistoryEntry {
pub amalgamation_id: String,
pub genome_title: String,
pub circuit_size: [i32; 3],
pub status: String, pub timestamp_ms: i64,
}
#[derive(Debug, Default, Clone)]
pub struct AmalgamationState {
pub pending: Option<AmalgamationPending>,
pub history: Vec<AmalgamationHistoryEntry>,
}
pub type SharedAmalgamationState = Arc<RwLock<AmalgamationState>>;
pub fn new_shared_state() -> SharedAmalgamationState {
Arc::new(RwLock::new(AmalgamationState::default()))
}
pub fn compute_circuit_size_from_runtime_genome(
genome: &feagi_evolutionary::RuntimeGenome,
) -> [i32; 3] {
let mut any = false;
let mut min_x: i32 = 0;
let mut min_y: i32 = 0;
let mut min_z: i32 = 0;
let mut max_x: i32 = 0;
let mut max_y: i32 = 0;
let mut max_z: i32 = 0;
for area in genome.cortical_areas.values() {
let x0 = area.position.x;
let y0 = area.position.y;
let z0 = area.position.z;
let x1 = x0.saturating_add(area.dimensions.width as i32);
let y1 = y0.saturating_add(area.dimensions.height as i32);
let z1 = z0.saturating_add(area.dimensions.depth as i32);
if !any {
any = true;
min_x = x0;
min_y = y0;
min_z = z0;
max_x = x1;
max_y = y1;
max_z = z1;
} else {
min_x = min_x.min(x0);
min_y = min_y.min(y0);
min_z = min_z.min(z0);
max_x = max_x.max(x1);
max_y = max_y.max(y1);
max_z = max_z.max(z1);
}
}
if !any {
return [0, 0, 0];
}
[
max_x.saturating_sub(min_x),
max_y.saturating_sub(min_y),
max_z.saturating_sub(min_z),
]
}
pub fn pending_summary_to_health_json(summary: &AmalgamationPendingSummary) -> Value {
serde_json::json!({
"amalgamation_id": summary.amalgamation_id,
"genome_title": summary.genome_title,
"circuit_size": summary.circuit_size,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compute_circuit_size_empty_genome_is_zero() {
let genome =
feagi_evolutionary::templates::create_minimal_genome("g".to_string(), "t".to_string());
assert_eq!(compute_circuit_size_from_runtime_genome(&genome), [0, 0, 0]);
}
#[test]
fn compute_circuit_size_single_area_matches_block_boundaries() {
let json = serde_json::json!({
"genome_id": "test",
"genome_title": "Test Genome",
"genome_description": "",
"version": "2.1",
"blueprint": {
"X19fcG93ZXI=": { "cortical_name": "Area",
"block_boundaries": [2, 3, 4],
"relative_coordinate": [1, 1, 1],
"cortical_type": "CUSTOM"
}
},
"brain_regions": {
"root": {
"title": "Root",
"parent_region_id": null,
"coordinate_3d": [0, 0, 0],
"areas": ["X19fcG93ZXI="],
"regions": []
}
},
"physiology": {
"simulation_timestep": 0.025
}
})
.to_string();
let genome = feagi_evolutionary::load_genome_from_json(&json).expect("valid genome json");
assert_eq!(compute_circuit_size_from_runtime_genome(&genome), [2, 3, 4]);
}
}