1use std::collections::HashMap;
5use std::fs;
6use std::path::Path;
7
8#[derive(Clone, Debug)]
9pub struct SynapticConnection {
10 pub from_block: u32,
11 pub to_block: u32,
12 pub weight: f32, pub frequency: u32, pub last_activated_ms: u64,
15 pub plasticity_score: f32, }
17
18#[derive(Clone, Debug)]
19pub struct NeuralPathway {
20 pub id: u64,
21 pub nodes: Vec<u32>, pub strength: f32, pub efficiency: f32, pub usage_count: u32, pub specialized_for: String, }
27
28pub struct Neuroplasticity {
29 pub synapses: HashMap<(u32, u32), SynapticConnection>,
30 pub pathways: HashMap<u64, NeuralPathway>,
31 pub reorganization_threshold: f32,
32 pub plasticity_window_ms: u64,
33}
34
35impl Default for Neuroplasticity {
36 fn default() -> Self {
37 Self::new()
38 }
39}
40
41impl Neuroplasticity {
42 pub fn new() -> Self {
43 Self {
44 synapses: HashMap::new(),
45 pathways: HashMap::new(),
46 reorganization_threshold: 0.5,
47 plasticity_window_ms: 86_400_000, }
49 }
50
51 pub fn strengthen_synapse(&mut self, from: u32, to: u32, success: bool) {
53 let key = (from, to);
54 let now = Self::now_ms();
55
56 self.synapses
57 .entry(key)
58 .and_modify(|s| {
59 s.frequency += 1;
60 let delta = if success { 0.05 } else { -0.02 };
61 s.weight = (s.weight + delta).clamp(0.0, 1.0);
62 s.last_activated_ms = now;
63 })
64 .or_insert_with(|| SynapticConnection {
65 from_block: from,
66 to_block: to,
67 weight: if success { 0.6 } else { 0.3 },
68 frequency: 1,
69 last_activated_ms: now,
70 plasticity_score: 0.8,
71 });
72 }
73
74 pub fn strengthen_pathway(&mut self, nodes: Vec<u32>, domain: &str) -> u64 {
76 let pathway_id = Self::pathway_hash(&nodes);
77
78 self.pathways
79 .entry(pathway_id)
80 .and_modify(|p| {
81 p.usage_count += 1;
82 p.strength = (p.strength + 0.1).min(1.0);
83 p.efficiency = (p.efficiency + 0.05).min(1.0);
84 })
85 .or_insert_with(|| NeuralPathway {
86 id: pathway_id,
87 nodes: nodes.clone(),
88 strength: 0.5,
89 efficiency: 0.4,
90 usage_count: 1,
91 specialized_for: domain.to_string(),
92 });
93
94 pathway_id
95 }
96
97 pub fn prune_weak_synapses(&mut self, strength_threshold: f32) -> usize {
99 let before = self.synapses.len();
100 self.synapses.retain(|_, s| s.weight > strength_threshold);
101 before - self.synapses.len()
102 }
103
104 pub fn reorganize_pathways(&mut self) -> usize {
106 let mut reorganized = 0;
107 let now = Self::now_ms();
108
109 for pathway in self.pathways.values_mut() {
111 if pathway.usage_count >= 10 {
112 pathway.strength = (pathway.strength + 0.02).min(1.0);
113 reorganized += 1;
114 }
115 }
116
117 let unused_before = self.pathways.len();
119 self.pathways.retain(|_, p| {
120 let age = now.saturating_sub(p.id);
121 p.usage_count > 0 || age < self.plasticity_window_ms
122 });
123
124 reorganized + (unused_before - self.pathways.len())
125 }
126
127 pub fn calculate_plasticity(&self) -> f32 {
129 if self.synapses.is_empty() {
130 return 0.0;
131 }
132
133 let weak_synapses = self.synapses.values().filter(|s| s.weight < 0.3).count() as f32;
134 let total = self.synapses.len() as f32;
135
136 (weak_synapses / total).min(1.0)
137 }
138
139 pub fn find_alternative_pathways(&self, source: u32, target: u32) -> Vec<Vec<u32>> {
141 let mut alternatives = Vec::new();
142
143 for (key, synapse) in &self.synapses {
145 if key.0 == source {
146 for (key2, synapse2) in &self.synapses {
147 if key2.0 == key.1 && key2.1 == target {
148 let combined_weight = synapse.weight * synapse2.weight;
149 if combined_weight > 0.2 {
150 alternatives.push(vec![source, key.1, target]);
151 }
152 }
153 }
154 }
155 }
156
157 alternatives
158 }
159
160 pub fn stats(&self) -> (usize, usize, f32, f32, usize) {
162 let synapse_count = self.synapses.len();
163 let pathway_count = self.pathways.len();
164 let avg_weight = if !self.synapses.is_empty() {
165 self.synapses.values().map(|s| s.weight).sum::<f32>() / synapse_count as f32
166 } else {
167 0.0
168 };
169 let plasticity = self.calculate_plasticity();
170 let strong_pathways = self.pathways.values().filter(|p| p.strength > 0.7).count();
171
172 (
173 synapse_count,
174 pathway_count,
175 avg_weight,
176 plasticity,
177 strong_pathways,
178 )
179 }
180
181 pub fn strongest_pathways(&self, k: usize) -> Vec<&NeuralPathway> {
183 let mut sorted: Vec<_> = self.pathways.values().collect();
184 sorted.sort_by(|a, b| b.strength.total_cmp(&a.strength));
185 sorted.into_iter().take(k).collect()
186 }
187
188 pub fn save(&self, dir: &Path) -> Result<(), String> {
189 let path = dir.join("neuroplasticity.bin");
190 let mut data = Vec::new();
191
192 data.extend_from_slice(b"NPLS");
193 data.push(1);
194
195 let synapse_count = self.synapses.len() as u32;
197 data.extend_from_slice(&synapse_count.to_le_bytes());
198 for ((from, to), synapse) in &self.synapses {
199 data.extend_from_slice(&from.to_le_bytes());
200 data.extend_from_slice(&to.to_le_bytes());
201 data.extend_from_slice(&synapse.weight.to_le_bytes());
202 data.extend_from_slice(&synapse.frequency.to_le_bytes());
203 data.extend_from_slice(&synapse.last_activated_ms.to_le_bytes());
204 data.extend_from_slice(&synapse.plasticity_score.to_le_bytes());
205 }
206
207 let pathway_count = self.pathways.len() as u32;
209 data.extend_from_slice(&pathway_count.to_le_bytes());
210 for pathway in self.pathways.values() {
211 data.extend_from_slice(&pathway.id.to_le_bytes());
212 data.extend_from_slice(&pathway.strength.to_le_bytes());
213 data.extend_from_slice(&pathway.efficiency.to_le_bytes());
214 data.extend_from_slice(&pathway.usage_count.to_le_bytes());
215
216 let spec_bytes = pathway.specialized_for.as_bytes();
217 data.push(spec_bytes.len() as u8);
218 data.extend_from_slice(spec_bytes);
219
220 let node_count = pathway.nodes.len() as u16;
221 data.extend_from_slice(&node_count.to_le_bytes());
222 for &node in &pathway.nodes {
223 data.extend_from_slice(&node.to_le_bytes());
224 }
225 }
226
227 let tmp_path = dir.join("neuroplasticity.bin.tmp");
228 fs::write(&tmp_path, data).map_err(|e| e.to_string())?;
229 fs::rename(&tmp_path, &path).map_err(|e| e.to_string())
230 }
231
232 pub fn load(dir: &Path) -> Result<Self, String> {
233 let path = dir.join("neuroplasticity.bin");
234 if !path.exists() {
235 return Ok(Self::new());
236 }
237
238 let data = fs::read(&path).map_err(|e| e.to_string())?;
239 if data.len() < 5 || &data[0..4] != b"NPLS" {
240 return Ok(Self::new());
241 }
242
243 let mut idx = 5;
244 let mut synapses = HashMap::new();
245 let mut pathways = HashMap::new();
246
247 if idx + 4 <= data.len() {
249 let synapse_count =
250 u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]])
251 as usize;
252 idx += 4;
253
254 for _ in 0..synapse_count {
255 if idx + 36 > data.len() {
256 break;
257 }
258
259 let from =
260 u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
261 idx += 4;
262 let to =
263 u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
264 idx += 4;
265 let weight =
266 f32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
267 idx += 4;
268 let frequency =
269 u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
270 idx += 4;
271 let last_activated_ms = u64::from_le_bytes([
272 data[idx],
273 data[idx + 1],
274 data[idx + 2],
275 data[idx + 3],
276 data[idx + 4],
277 data[idx + 5],
278 data[idx + 6],
279 data[idx + 7],
280 ]);
281 idx += 8;
282 let plasticity_score =
283 f32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
284 idx += 4;
285
286 synapses.insert(
287 (from, to),
288 SynapticConnection {
289 from_block: from,
290 to_block: to,
291 weight,
292 frequency,
293 last_activated_ms,
294 plasticity_score,
295 },
296 );
297 }
298 }
299
300 if idx + 4 <= data.len() {
302 let pathway_count =
303 u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]])
304 as usize;
305 idx += 4;
306
307 for _ in 0..pathway_count {
308 if idx + 30 > data.len() {
309 break;
310 }
311
312 let id = u64::from_le_bytes([
313 data[idx],
314 data[idx + 1],
315 data[idx + 2],
316 data[idx + 3],
317 data[idx + 4],
318 data[idx + 5],
319 data[idx + 6],
320 data[idx + 7],
321 ]);
322 idx += 8;
323
324 let strength =
325 f32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
326 idx += 4;
327 let efficiency =
328 f32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
329 idx += 4;
330 let usage_count =
331 u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
332 idx += 4;
333
334 if idx >= data.len() {
335 break;
336 }
337 let spec_len = data[idx] as usize;
338 idx += 1;
339
340 if idx + spec_len > data.len() {
341 break;
342 }
343 let specialized_for =
344 String::from_utf8_lossy(&data[idx..idx + spec_len]).to_string();
345 idx += spec_len;
346
347 if idx + 2 > data.len() {
348 break;
349 }
350 let node_count = u16::from_le_bytes([data[idx], data[idx + 1]]) as usize;
351 idx += 2;
352
353 let mut nodes = Vec::new();
354 for _ in 0..node_count {
355 if idx + 4 > data.len() {
356 break;
357 }
358 let node = u32::from_le_bytes([
359 data[idx],
360 data[idx + 1],
361 data[idx + 2],
362 data[idx + 3],
363 ]);
364 nodes.push(node);
365 idx += 4;
366 }
367
368 pathways.insert(
369 id,
370 NeuralPathway {
371 id,
372 nodes,
373 strength,
374 efficiency,
375 usage_count,
376 specialized_for,
377 },
378 );
379 }
380 }
381
382 Ok(Self {
383 synapses,
384 pathways,
385 reorganization_threshold: 0.5,
386 plasticity_window_ms: 86_400_000,
387 })
388 }
389
390 pub fn load_or_init(dir: &Path) -> Self {
391 Self::load(dir).unwrap_or_else(|_| Self::new())
392 }
393
394 fn pathway_hash(nodes: &[u32]) -> u64 {
395 let mut hash: u64 = 0xcbf29ce484222325;
396 for &node in nodes.iter().take(10) {
397 hash = hash.wrapping_mul(0x100000001b3) ^ (node as u64);
398 }
399 hash
400 }
401
402 fn now_ms() -> u64 {
403 std::time::SystemTime::now()
404 .duration_since(std::time::UNIX_EPOCH)
405 .unwrap_or_default()
406 .as_millis() as u64
407 }
408}