use std::collections::HashMap;
use std::fs;
use std::path::Path;
#[derive(Clone, Debug)]
pub struct Dendrite {
pub block_id: u32,
pub branches: Vec<u32>, pub branch_count: u32,
pub total_length: f32, pub growth_rate: f32, pub pruning_state: u8, }
#[derive(Clone, Debug)]
pub struct NeuronLike {
pub id: u64,
pub blocks: Vec<u32>,
pub dendrite: Dendrite,
pub axon_terminals: Vec<u32>,
pub activation_history: Vec<f32>, pub specialization: String,
}
pub struct StructuralPlasticity {
pub neurons: HashMap<u64, NeuronLike>,
pub dendritic_growth_rate: f32,
pub pruning_threshold: f32,
pub neurogenesis_events: u32,
}
impl Default for StructuralPlasticity {
fn default() -> Self {
Self::new()
}
}
impl StructuralPlasticity {
pub fn new() -> Self {
Self {
neurons: HashMap::new(),
dendritic_growth_rate: 0.05,
pruning_threshold: 0.1,
neurogenesis_events: 0,
}
}
pub fn grow_dendrite(&mut self, neuron_id: u64, new_block: u32) -> bool {
if let Some(neuron) = self.neurons.get_mut(&neuron_id) {
if neuron.dendrite.pruning_state == 0 {
neuron.dendrite.branches.push(new_block);
neuron.dendrite.branch_count += 1;
neuron.dendrite.total_length += self.dendritic_growth_rate;
return true;
}
}
false
}
pub fn mark_for_pruning(&mut self, neuron_id: u64, block_to_remove: u32) {
if let Some(neuron) = self.neurons.get_mut(&neuron_id) {
if let Some(pos) = neuron
.dendrite
.branches
.iter()
.position(|&b| b == block_to_remove)
{
neuron.dendrite.branches.remove(pos);
neuron.dendrite.branch_count = neuron.dendrite.branch_count.saturating_sub(1);
neuron.dendrite.total_length -= 0.05;
}
}
}
pub fn prune_inactive_branches(&mut self, neuron_id: u64) -> u32 {
let mut pruned = 0;
if let Some(neuron) = self.neurons.get_mut(&neuron_id) {
let avg_activation = if neuron.activation_history.is_empty() {
0.0
} else {
neuron.activation_history.iter().sum::<f32>()
/ neuron.activation_history.len() as f32
};
neuron
.dendrite
.branches
.retain(|_| avg_activation > self.pruning_threshold);
let new_count = neuron.dendrite.branches.len() as u32;
pruned = neuron.dendrite.branch_count.saturating_sub(new_count);
neuron.dendrite.branch_count = new_count;
}
pruned
}
pub fn neurogenesis(&mut self, seed_blocks: Vec<u32>, specialization: &str) -> u64 {
let neuron_id = Self::neuron_hash(&seed_blocks);
let dendrite = Dendrite {
block_id: seed_blocks[0],
branches: seed_blocks.clone(),
branch_count: seed_blocks.len() as u32,
total_length: seed_blocks.len() as f32 * 0.1,
growth_rate: 0.05,
pruning_state: 0,
};
let neuron = NeuronLike {
id: neuron_id,
blocks: seed_blocks,
dendrite,
axon_terminals: Vec::new(),
activation_history: Vec::new(),
specialization: specialization.to_string(),
};
self.neurons.insert(neuron_id, neuron);
self.neurogenesis_events += 1;
neuron_id
}
pub fn record_activation(&mut self, neuron_id: u64, strength: f32) {
if let Some(neuron) = self.neurons.get_mut(&neuron_id) {
neuron.activation_history.push(strength);
if neuron.activation_history.len() > 100 {
neuron.activation_history.remove(0); }
}
}
pub fn dendritic_complexity(&self, neuron_id: u64) -> f32 {
if let Some(neuron) = self.neurons.get(&neuron_id) {
(neuron.dendrite.branch_count as f32 * neuron.dendrite.total_length).min(1.0)
} else {
0.0
}
}
pub fn stats(&self) -> (u32, u32, f32, u32) {
let total_neurons = self.neurons.len() as u32;
let total_branches: u32 = self.neurons.values().map(|n| n.dendrite.branch_count).sum();
let avg_dendrite_length = if self.neurons.is_empty() {
0.0
} else {
self.neurons
.values()
.map(|n| n.dendrite.total_length)
.sum::<f32>()
/ self.neurons.len() as f32
};
(
total_neurons,
total_branches,
avg_dendrite_length,
self.neurogenesis_events,
)
}
pub fn specialized_neurons(&self) -> Vec<(u64, &str, u32)> {
let mut specialized: Vec<_> = self
.neurons
.iter()
.map(|(id, n)| (*id, n.specialization.as_str(), n.dendrite.branch_count))
.collect();
specialized.sort_by_key(|b| std::cmp::Reverse(b.2));
specialized
}
pub fn save(&self, dir: &Path) -> Result<(), String> {
let path = dir.join("structural_plasticity.bin");
let mut data = Vec::new();
data.extend_from_slice(b"STPLS");
data.push(1);
let neuron_count = self.neurons.len() as u32;
data.extend_from_slice(&neuron_count.to_le_bytes());
for neuron in self.neurons.values() {
data.extend_from_slice(&neuron.id.to_le_bytes());
let blocks_count = neuron.blocks.len() as u16;
data.extend_from_slice(&blocks_count.to_le_bytes());
for &block in &neuron.blocks {
data.extend_from_slice(&block.to_le_bytes());
}
data.extend_from_slice(&neuron.dendrite.block_id.to_le_bytes());
data.extend_from_slice(&neuron.dendrite.growth_rate.to_le_bytes());
data.push(neuron.dendrite.pruning_state);
let branch_count = neuron.dendrite.branches.len() as u16;
data.extend_from_slice(&branch_count.to_le_bytes());
for &branch in &neuron.dendrite.branches {
data.extend_from_slice(&branch.to_le_bytes());
}
let spec_bytes = neuron.specialization.as_bytes();
data.push(spec_bytes.len() as u8);
data.extend_from_slice(spec_bytes);
}
data.extend_from_slice(&self.neurogenesis_events.to_le_bytes());
let tmp_path = dir.join("structural_plasticity.bin.tmp");
fs::write(&tmp_path, data).map_err(|e| e.to_string())?;
fs::rename(&tmp_path, &path).map_err(|e| e.to_string())
}
pub fn load(dir: &Path) -> Result<Self, String> {
let path = dir.join("structural_plasticity.bin");
if !path.exists() {
return Ok(Self::new());
}
let data = fs::read(&path).map_err(|e| e.to_string())?;
if data.len() < 5 || &data[0..5] != b"STPLS" {
return Ok(Self::new());
}
let mut idx = 6;
let mut neurons = HashMap::new();
if idx + 4 <= data.len() {
let neuron_count =
u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]])
as usize;
idx += 4;
for _ in 0..neuron_count {
if idx + 10 > data.len() {
break;
}
let neuron_id = u64::from_le_bytes([
data[idx],
data[idx + 1],
data[idx + 2],
data[idx + 3],
data[idx + 4],
data[idx + 5],
data[idx + 6],
data[idx + 7],
]);
idx += 8;
let blocks_count = u16::from_le_bytes([data[idx], data[idx + 1]]) as usize;
idx += 2;
let mut blocks = Vec::new();
for _ in 0..blocks_count {
if idx + 4 > data.len() {
break;
}
let block = u32::from_le_bytes([
data[idx],
data[idx + 1],
data[idx + 2],
data[idx + 3],
]);
blocks.push(block);
idx += 4;
}
if idx + 13 > data.len() {
break;
}
let dendrite_block_id =
u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
idx += 4;
let growth_rate =
f32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
idx += 4;
let pruning_state = data[idx];
idx += 1;
let branch_count = u16::from_le_bytes([data[idx], data[idx + 1]]) as usize;
idx += 2;
let mut branches = Vec::new();
for _ in 0..branch_count {
if idx + 4 > data.len() {
break;
}
let branch = u32::from_le_bytes([
data[idx],
data[idx + 1],
data[idx + 2],
data[idx + 3],
]);
branches.push(branch);
idx += 4;
}
if idx >= data.len() {
break;
}
let spec_len = data[idx] as usize;
idx += 1;
if idx + spec_len > data.len() {
break;
}
let specialization =
String::from_utf8_lossy(&data[idx..idx + spec_len]).to_string();
idx += spec_len;
let dendrite = Dendrite {
block_id: dendrite_block_id,
branches,
branch_count: branch_count as u32,
total_length: branch_count as f32 * 0.1,
growth_rate,
pruning_state,
};
neurons.insert(
neuron_id,
NeuronLike {
id: neuron_id,
blocks,
dendrite,
axon_terminals: Vec::new(),
activation_history: Vec::new(),
specialization,
},
);
}
}
let mut neurogenesis_events = 0;
if idx + 4 <= data.len() {
neurogenesis_events =
u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
}
Ok(Self {
neurons,
dendritic_growth_rate: 0.05,
pruning_threshold: 0.1,
neurogenesis_events,
})
}
pub fn load_or_init(dir: &Path) -> Self {
Self::load(dir).unwrap_or_else(|_| Self::new())
}
fn neuron_hash(blocks: &[u32]) -> u64 {
let mut hash: u64 = 0xcbf29ce484222325;
for &block in blocks.iter().take(10) {
hash = hash.wrapping_mul(0x100000001b3) ^ (block as u64);
}
hash
}
}