feagi_evolutionary/
plasticity_detector.rs1use serde_json::Value;
7use std::collections::HashMap;
8use tracing::debug;
9
10pub fn genome_has_plasticity(genome_json: &Value) -> bool {
23 let has_memory = has_memory_areas(genome_json);
24 let has_stdp = has_stdp_connections(genome_json);
25
26 debug!(
27 target: "feagi-evolutionary",
28 "Plasticity detection: memory_areas={}, stdp_connections={}",
29 has_memory, has_stdp
30 );
31
32 has_memory || has_stdp
33}
34
35fn has_memory_areas(genome_json: &Value) -> bool {
41 if let Some(blueprint) = genome_json.get("blueprint").and_then(|b| b.as_object()) {
42 for (key, value) in blueprint {
43 if key.ends_with("-cx-memory-b") {
45 if let Some(is_memory) = value.as_bool() {
46 if is_memory {
47 debug!(
48 target: "feagi-evolutionary",
49 "Found memory area via key: {}", key
50 );
51 return true;
52 }
53 }
54 }
55 }
56 }
57 false
58}
59
60fn has_stdp_connections(genome_json: &Value) -> bool {
65 if let Some(blueprint) = genome_json.get("blueprint").and_then(|b| b.as_object()) {
66 for (key, value) in blueprint {
67 if key.ends_with("-cx-dstmap-d") {
69 if let Some(dstmap) = value.as_object() {
70 for (dst_area_id, morphology_list) in dstmap {
71 if let Some(morphologies) = morphology_list.as_array() {
72 for morph in morphologies {
73 if let Some(plasticity_flag) = morph.get("plasticity_flag") {
74 if plasticity_flag.as_bool() == Some(true) {
75 debug!(
76 target: "feagi-evolutionary",
77 "Found STDP connection: key={}, dst={}", key, dst_area_id
78 );
79 return true;
80 }
81 }
82 }
83 }
84 }
85 }
86 }
87 }
88 }
89 false
90}
91
92#[derive(Debug, Clone)]
94pub struct MemoryAreaProperties {
95 pub temporal_depth: u32,
97 pub longterm_threshold: u32,
99 pub lifespan_growth_rate: f32,
101 pub init_lifespan: u32,
103 pub mp_learning_enabled: bool,
105}
106
107impl Default for MemoryAreaProperties {
108 fn default() -> Self {
109 Self {
110 temporal_depth: 1,
113 longterm_threshold: 100,
114 lifespan_growth_rate: 1.0,
115 init_lifespan: 9,
116 mp_learning_enabled: false,
117 }
118 }
119}
120
121pub fn extract_memory_properties(
130 properties: &HashMap<String, Value>,
131) -> Option<MemoryAreaProperties> {
132 let is_memory = properties
133 .get("is_mem_type")
134 .and_then(|v| v.as_bool())
135 .unwrap_or(false);
136
137 if !is_memory {
138 return None;
139 }
140
141 Some(MemoryAreaProperties {
142 temporal_depth: properties
143 .get("temporal_depth")
144 .and_then(|v| v.as_u64())
145 .unwrap_or(1)
146 .max(1) as u32,
147 longterm_threshold: properties
148 .get("longterm_mem_threshold")
149 .and_then(|v| v.as_u64())
150 .unwrap_or(100) as u32,
151 lifespan_growth_rate: properties
152 .get("lifespan_growth_rate")
153 .and_then(|v| v.as_f64())
154 .unwrap_or(1.0) as f32,
155 init_lifespan: properties
156 .get("init_lifespan")
157 .and_then(|v| v.as_u64())
158 .unwrap_or(9) as u32,
159 mp_learning_enabled: properties
160 .get("mp_learning_enabled")
161 .and_then(|v| v.as_bool())
162 .unwrap_or(false),
163 })
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169 use serde_json::json;
170
171 #[test]
172 fn test_no_plasticity() {
173 let genome = json!({
174 "blueprint": {
175 "_____10c-Y2FfX19fX50=-cx-_group-t": "CUSTOM",
176 "_____10c-Y2FfX19fX50=-cx-memory-b": false,
177 "_____10c-Y2FfX19fX50=-cx-dstmap-d": {
178 "b2ltZwkAAAA=": [{
179 "morphology_id": "projector",
180 "plasticity_flag": false
181 }]
182 }
183 }
184 });
185
186 assert!(!genome_has_plasticity(&genome));
187 }
188
189 #[test]
190 fn test_has_memory_areas() {
191 let genome = json!({
192 "blueprint": {
193 "_____10c-Y21fX19fXxg=-cx-_group-t": "CUSTOM",
194 "_____10c-Y21fX19fXxg=-cx-memory-b": true,
195 "_____10c-Y21fX19fXxg=-cx-mem__t-i": 100
196 }
197 });
198
199 assert!(genome_has_plasticity(&genome));
200 assert!(has_memory_areas(&genome));
201 assert!(!has_stdp_connections(&genome));
202 }
203
204 #[test]
205 fn test_has_stdp_connections() {
206 let genome = json!({
207 "blueprint": {
208 "_____10c-Y2FfX19fX50=-cx-_group-t": "CUSTOM",
209 "_____10c-Y2FfX19fX50=-cx-memory-b": false,
210 "_____10c-Y2FfX19fX50=-cx-dstmap-d": {
211 "b2ltZwkAAAA=": [{
212 "morphology_id": "projector",
213 "plasticity_flag": true,
214 "postSynapticCurrent_multiplier": 1
215 }]
216 }
217 }
218 });
219
220 assert!(genome_has_plasticity(&genome));
221 assert!(!has_memory_areas(&genome));
222 assert!(has_stdp_connections(&genome));
223 }
224
225 #[test]
226 fn test_has_both_plasticity_types() {
227 let genome = json!({
228 "blueprint": {
229 "_____10c-Y21fX19fXxg=-cx-memory-b": true,
230 "_____10c-Y2FfX19fX50=-cx-dstmap-d": {
231 "b2ltZwkAAAA=": [{
232 "morphology_id": "projector",
233 "plasticity_flag": true
234 }]
235 }
236 }
237 });
238
239 assert!(genome_has_plasticity(&genome));
240 assert!(has_memory_areas(&genome));
241 assert!(has_stdp_connections(&genome));
242 }
243
244 #[test]
245 fn test_extract_memory_properties() {
246 let mut properties = HashMap::new();
247 properties.insert("is_mem_type".to_string(), json!(true));
248 properties.insert("temporal_depth".to_string(), json!(5));
249 properties.insert("longterm_mem_threshold".to_string(), json!(200));
250 properties.insert("lifespan_growth_rate".to_string(), json!(1.5));
251 properties.insert("init_lifespan".to_string(), json!(15));
252
253 let mem_props = extract_memory_properties(&properties).expect("Should extract properties");
254 assert_eq!(mem_props.temporal_depth, 5);
255 assert_eq!(mem_props.longterm_threshold, 200);
256 assert_eq!(mem_props.lifespan_growth_rate, 1.5);
257 assert_eq!(mem_props.init_lifespan, 15);
258 }
259
260 #[test]
261 fn test_extract_memory_properties_defaults() {
262 let mut properties = HashMap::new();
263 properties.insert("is_mem_type".to_string(), json!(true));
264
265 let mem_props = extract_memory_properties(&properties).expect("Should extract properties");
266 assert_eq!(mem_props.temporal_depth, 1);
267 assert_eq!(mem_props.longterm_threshold, 100);
268 assert_eq!(mem_props.lifespan_growth_rate, 1.0);
269 assert_eq!(mem_props.init_lifespan, 9);
270 }
271
272 #[test]
273 fn test_extract_memory_properties_non_memory() {
274 let mut properties = HashMap::new();
275 properties.insert("is_mem_type".to_string(), json!(false));
276
277 assert!(extract_memory_properties(&properties).is_none());
278 }
279}