feagi_api/
amalgamation.rs1use parking_lot::RwLock;
23use serde::{Deserialize, Serialize};
24use serde_json::Value;
25use std::sync::Arc;
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct AmalgamationPendingSummary {
30 pub amalgamation_id: String,
31 pub genome_title: String,
32 pub circuit_size: [i32; 3],
34}
35
36#[derive(Debug, Clone)]
38pub struct AmalgamationPending {
39 pub summary: AmalgamationPendingSummary,
40 pub genome_json: String,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct AmalgamationHistoryEntry {
47 pub amalgamation_id: String,
48 pub genome_title: String,
49 pub circuit_size: [i32; 3],
50 pub status: String, pub timestamp_ms: i64,
52}
53
54#[derive(Debug, Default, Clone)]
55pub struct AmalgamationState {
56 pub pending: Option<AmalgamationPending>,
57 pub history: Vec<AmalgamationHistoryEntry>,
58}
59
60pub type SharedAmalgamationState = Arc<RwLock<AmalgamationState>>;
61
62pub fn new_shared_state() -> SharedAmalgamationState {
64 Arc::new(RwLock::new(AmalgamationState::default()))
65}
66
67pub fn compute_circuit_size_from_runtime_genome(
76 genome: &feagi_evolutionary::RuntimeGenome,
77) -> [i32; 3] {
78 let mut any = false;
79 let mut min_x: i32 = 0;
80 let mut min_y: i32 = 0;
81 let mut min_z: i32 = 0;
82 let mut max_x: i32 = 0;
83 let mut max_y: i32 = 0;
84 let mut max_z: i32 = 0;
85
86 for area in genome.cortical_areas.values() {
87 let x0 = area.position.x;
88 let y0 = area.position.y;
89 let z0 = area.position.z;
90
91 let x1 = x0.saturating_add(area.dimensions.width as i32);
92 let y1 = y0.saturating_add(area.dimensions.height as i32);
93 let z1 = z0.saturating_add(area.dimensions.depth as i32);
94
95 if !any {
96 any = true;
97 min_x = x0;
98 min_y = y0;
99 min_z = z0;
100 max_x = x1;
101 max_y = y1;
102 max_z = z1;
103 } else {
104 min_x = min_x.min(x0);
105 min_y = min_y.min(y0);
106 min_z = min_z.min(z0);
107 max_x = max_x.max(x1);
108 max_y = max_y.max(y1);
109 max_z = max_z.max(z1);
110 }
111 }
112
113 if !any {
114 return [0, 0, 0];
115 }
116
117 [
118 max_x.saturating_sub(min_x),
119 max_y.saturating_sub(min_y),
120 max_z.saturating_sub(min_z),
121 ]
122}
123
124pub fn pending_summary_to_health_json(summary: &AmalgamationPendingSummary) -> Value {
126 serde_json::json!({
127 "amalgamation_id": summary.amalgamation_id,
128 "genome_title": summary.genome_title,
129 "circuit_size": summary.circuit_size,
130 })
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136
137 #[test]
138 fn compute_circuit_size_empty_genome_is_zero() {
139 let genome =
140 feagi_evolutionary::templates::create_minimal_genome("g".to_string(), "t".to_string());
141 assert_eq!(compute_circuit_size_from_runtime_genome(&genome), [0, 0, 0]);
142 }
143
144 #[test]
145 fn compute_circuit_size_single_area_matches_block_boundaries() {
146 let json = serde_json::json!({
148 "genome_id": "test",
149 "genome_title": "Test Genome",
150 "genome_description": "",
151 "version": "2.1",
152 "blueprint": {
153 "X19fcG93ZXI=": { "cortical_name": "Area",
155 "block_boundaries": [2, 3, 4],
156 "relative_coordinate": [1, 1, 1],
157 "cortical_type": "CUSTOM"
158 }
159 },
160 "brain_regions": {
161 "root": {
162 "title": "Root",
163 "parent_region_id": null,
164 "coordinate_3d": [0, 0, 0],
165 "areas": ["X19fcG93ZXI="],
166 "regions": []
167 }
168 },
169 "physiology": {
170 "simulation_timestep": 0.025
171 }
172 })
173 .to_string();
174
175 let genome = feagi_evolutionary::load_genome_from_json(&json).expect("valid genome json");
176 assert_eq!(compute_circuit_size_from_runtime_genome(&genome), [2, 3, 4]);
177 }
178}