1use std::collections::HashMap;
5use std::fs;
6use std::path::Path;
7
8#[derive(Clone, Debug)]
9pub struct Dendrite {
10 pub block_id: u32,
11 pub branches: Vec<u32>, pub branch_count: u32,
13 pub total_length: f32, pub growth_rate: f32, pub pruning_state: u8, }
17
18#[derive(Clone, Debug)]
19pub struct NeuronLike {
20 pub id: u64,
21 pub blocks: Vec<u32>,
22 pub dendrite: Dendrite,
23 pub axon_terminals: Vec<u32>,
24 pub activation_history: Vec<f32>, pub specialization: String,
26}
27
28pub struct StructuralPlasticity {
29 pub neurons: HashMap<u64, NeuronLike>,
30 pub dendritic_growth_rate: f32,
31 pub pruning_threshold: f32,
32 pub neurogenesis_events: u32,
33}
34
35impl Default for StructuralPlasticity {
36 fn default() -> Self {
37 Self::new()
38 }
39}
40
41impl StructuralPlasticity {
42 pub fn new() -> Self {
43 Self {
44 neurons: HashMap::new(),
45 dendritic_growth_rate: 0.05,
46 pruning_threshold: 0.1,
47 neurogenesis_events: 0,
48 }
49 }
50
51 pub fn grow_dendrite(&mut self, neuron_id: u64, new_block: u32) -> bool {
53 if let Some(neuron) = self.neurons.get_mut(&neuron_id) {
54 if neuron.dendrite.pruning_state == 0 {
56 neuron.dendrite.branches.push(new_block);
57 neuron.dendrite.branch_count += 1;
58 neuron.dendrite.total_length += self.dendritic_growth_rate;
59 return true;
60 }
61 }
62 false
63 }
64
65 pub fn mark_for_pruning(&mut self, neuron_id: u64, block_to_remove: u32) {
67 if let Some(neuron) = self.neurons.get_mut(&neuron_id) {
68 if let Some(pos) = neuron
69 .dendrite
70 .branches
71 .iter()
72 .position(|&b| b == block_to_remove)
73 {
74 neuron.dendrite.branches.remove(pos);
75 neuron.dendrite.branch_count = neuron.dendrite.branch_count.saturating_sub(1);
76 neuron.dendrite.total_length -= 0.05;
77 }
78 }
79 }
80
81 pub fn prune_inactive_branches(&mut self, neuron_id: u64) -> u32 {
83 let mut pruned = 0;
84
85 if let Some(neuron) = self.neurons.get_mut(&neuron_id) {
86 let avg_activation = if neuron.activation_history.is_empty() {
87 0.0
88 } else {
89 neuron.activation_history.iter().sum::<f32>()
90 / neuron.activation_history.len() as f32
91 };
92
93 neuron
94 .dendrite
95 .branches
96 .retain(|_| avg_activation > self.pruning_threshold);
97 let new_count = neuron.dendrite.branches.len() as u32;
98 pruned = neuron.dendrite.branch_count.saturating_sub(new_count);
99 neuron.dendrite.branch_count = new_count;
100 }
101
102 pruned
103 }
104
105 pub fn neurogenesis(&mut self, seed_blocks: Vec<u32>, specialization: &str) -> u64 {
107 let neuron_id = Self::neuron_hash(&seed_blocks);
108
109 let dendrite = Dendrite {
110 block_id: seed_blocks[0],
111 branches: seed_blocks.clone(),
112 branch_count: seed_blocks.len() as u32,
113 total_length: seed_blocks.len() as f32 * 0.1,
114 growth_rate: 0.05,
115 pruning_state: 0,
116 };
117
118 let neuron = NeuronLike {
119 id: neuron_id,
120 blocks: seed_blocks,
121 dendrite,
122 axon_terminals: Vec::new(),
123 activation_history: Vec::new(),
124 specialization: specialization.to_string(),
125 };
126
127 self.neurons.insert(neuron_id, neuron);
128 self.neurogenesis_events += 1;
129 neuron_id
130 }
131
132 pub fn record_activation(&mut self, neuron_id: u64, strength: f32) {
134 if let Some(neuron) = self.neurons.get_mut(&neuron_id) {
135 neuron.activation_history.push(strength);
136 if neuron.activation_history.len() > 100 {
137 neuron.activation_history.remove(0); }
139 }
140 }
141
142 pub fn dendritic_complexity(&self, neuron_id: u64) -> f32 {
144 if let Some(neuron) = self.neurons.get(&neuron_id) {
145 (neuron.dendrite.branch_count as f32 * neuron.dendrite.total_length).min(1.0)
146 } else {
147 0.0
148 }
149 }
150
151 pub fn stats(&self) -> (u32, u32, f32, u32) {
153 let total_neurons = self.neurons.len() as u32;
154 let total_branches: u32 = self.neurons.values().map(|n| n.dendrite.branch_count).sum();
155 let avg_dendrite_length = if self.neurons.is_empty() {
156 0.0
157 } else {
158 self.neurons
159 .values()
160 .map(|n| n.dendrite.total_length)
161 .sum::<f32>()
162 / self.neurons.len() as f32
163 };
164
165 (
166 total_neurons,
167 total_branches,
168 avg_dendrite_length,
169 self.neurogenesis_events,
170 )
171 }
172
173 pub fn specialized_neurons(&self) -> Vec<(u64, &str, u32)> {
175 let mut specialized: Vec<_> = self
176 .neurons
177 .iter()
178 .map(|(id, n)| (*id, n.specialization.as_str(), n.dendrite.branch_count))
179 .collect();
180 specialized.sort_by_key(|b| std::cmp::Reverse(b.2));
181 specialized
182 }
183
184 pub fn save(&self, dir: &Path) -> Result<(), String> {
185 let path = dir.join("structural_plasticity.bin");
186 let mut data = Vec::new();
187
188 data.extend_from_slice(b"STPLS");
189 data.push(1);
190
191 let neuron_count = self.neurons.len() as u32;
193 data.extend_from_slice(&neuron_count.to_le_bytes());
194 for neuron in self.neurons.values() {
195 data.extend_from_slice(&neuron.id.to_le_bytes());
196
197 let blocks_count = neuron.blocks.len() as u16;
198 data.extend_from_slice(&blocks_count.to_le_bytes());
199 for &block in &neuron.blocks {
200 data.extend_from_slice(&block.to_le_bytes());
201 }
202
203 data.extend_from_slice(&neuron.dendrite.block_id.to_le_bytes());
205 data.extend_from_slice(&neuron.dendrite.growth_rate.to_le_bytes());
206 data.push(neuron.dendrite.pruning_state);
207
208 let branch_count = neuron.dendrite.branches.len() as u16;
209 data.extend_from_slice(&branch_count.to_le_bytes());
210 for &branch in &neuron.dendrite.branches {
211 data.extend_from_slice(&branch.to_le_bytes());
212 }
213
214 let spec_bytes = neuron.specialization.as_bytes();
216 data.push(spec_bytes.len() as u8);
217 data.extend_from_slice(spec_bytes);
218 }
219
220 data.extend_from_slice(&self.neurogenesis_events.to_le_bytes());
221
222 let tmp_path = dir.join("structural_plasticity.bin.tmp");
223 fs::write(&tmp_path, data).map_err(|e| e.to_string())?;
224 fs::rename(&tmp_path, &path).map_err(|e| e.to_string())
225 }
226
227 pub fn load(dir: &Path) -> Result<Self, String> {
228 let path = dir.join("structural_plasticity.bin");
229 if !path.exists() {
230 return Ok(Self::new());
231 }
232
233 let data = fs::read(&path).map_err(|e| e.to_string())?;
234 if data.len() < 5 || &data[0..5] != b"STPLS" {
235 return Ok(Self::new());
236 }
237
238 let mut idx = 6;
239 let mut neurons = HashMap::new();
240
241 if idx + 4 <= data.len() {
243 let neuron_count =
244 u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]])
245 as usize;
246 idx += 4;
247
248 for _ in 0..neuron_count {
249 if idx + 10 > data.len() {
250 break;
251 }
252
253 let neuron_id = u64::from_le_bytes([
254 data[idx],
255 data[idx + 1],
256 data[idx + 2],
257 data[idx + 3],
258 data[idx + 4],
259 data[idx + 5],
260 data[idx + 6],
261 data[idx + 7],
262 ]);
263 idx += 8;
264
265 let blocks_count = u16::from_le_bytes([data[idx], data[idx + 1]]) as usize;
266 idx += 2;
267
268 let mut blocks = Vec::new();
269 for _ in 0..blocks_count {
270 if idx + 4 > data.len() {
271 break;
272 }
273 let block = u32::from_le_bytes([
274 data[idx],
275 data[idx + 1],
276 data[idx + 2],
277 data[idx + 3],
278 ]);
279 blocks.push(block);
280 idx += 4;
281 }
282
283 if idx + 13 > data.len() {
284 break;
285 }
286 let dendrite_block_id =
287 u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
288 idx += 4;
289
290 let growth_rate =
291 f32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
292 idx += 4;
293
294 let pruning_state = data[idx];
295 idx += 1;
296
297 let branch_count = u16::from_le_bytes([data[idx], data[idx + 1]]) as usize;
298 idx += 2;
299
300 let mut branches = Vec::new();
301 for _ in 0..branch_count {
302 if idx + 4 > data.len() {
303 break;
304 }
305 let branch = u32::from_le_bytes([
306 data[idx],
307 data[idx + 1],
308 data[idx + 2],
309 data[idx + 3],
310 ]);
311 branches.push(branch);
312 idx += 4;
313 }
314
315 if idx >= data.len() {
316 break;
317 }
318 let spec_len = data[idx] as usize;
319 idx += 1;
320
321 if idx + spec_len > data.len() {
322 break;
323 }
324 let specialization =
325 String::from_utf8_lossy(&data[idx..idx + spec_len]).to_string();
326 idx += spec_len;
327
328 let dendrite = Dendrite {
329 block_id: dendrite_block_id,
330 branches,
331 branch_count: branch_count as u32,
332 total_length: branch_count as f32 * 0.1,
333 growth_rate,
334 pruning_state,
335 };
336
337 neurons.insert(
338 neuron_id,
339 NeuronLike {
340 id: neuron_id,
341 blocks,
342 dendrite,
343 axon_terminals: Vec::new(),
344 activation_history: Vec::new(),
345 specialization,
346 },
347 );
348 }
349 }
350
351 let mut neurogenesis_events = 0;
352 if idx + 4 <= data.len() {
353 neurogenesis_events =
354 u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
355 }
356
357 Ok(Self {
358 neurons,
359 dendritic_growth_rate: 0.05,
360 pruning_threshold: 0.1,
361 neurogenesis_events,
362 })
363 }
364
365 pub fn load_or_init(dir: &Path) -> Self {
366 Self::load(dir).unwrap_or_else(|_| Self::new())
367 }
368
369 fn neuron_hash(blocks: &[u32]) -> u64 {
370 let mut hash: u64 = 0xcbf29ce484222325;
371 for &block in blocks.iter().take(10) {
372 hash = hash.wrapping_mul(0x100000001b3) ^ (block as u64);
373 }
374 hash
375 }
376}