use crate::delta::Delta;
use crate::error::Result;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NeuromodState {
pub dopamine: f32,
pub serotonin: f32,
pub norepinephrine: f32,
pub acetylcholine: f32,
}
impl Default for NeuromodState {
fn default() -> Self {
Self {
dopamine: 0.5,
serotonin: 0.5,
norepinephrine: 0.5,
acetylcholine: 0.5,
}
}
}
impl NeuromodState {
pub fn baseline() -> Self {
Self::default()
}
pub fn reward(&mut self, amount: f32) {
self.dopamine = (self.dopamine + amount).clamp(0.0, 1.0);
}
pub fn stress(&mut self, amount: f32) {
self.serotonin = (self.serotonin - amount).clamp(0.0, 1.0);
self.norepinephrine = (self.norepinephrine + amount).clamp(0.0, 1.0);
}
pub fn focus(&mut self, amount: f32) {
self.acetylcholine = (self.acetylcholine + amount).clamp(0.0, 1.0);
}
pub fn decay(&mut self, rate: f32) {
let baseline = Self::baseline();
self.dopamine += (baseline.dopamine - self.dopamine) * rate;
self.serotonin += (baseline.serotonin - self.serotonin) * rate;
self.norepinephrine += (baseline.norepinephrine - self.norepinephrine) * rate;
self.acetylcholine += (baseline.acetylcholine - self.acetylcholine) * rate;
}
}
pub trait PlasticityEngine: Send + Sync {
fn process(&mut self, activation: &[f32], neuromod: &NeuromodState) -> Result<Vec<Delta>>;
fn sync_neuromod(&mut self, neuromod: &NeuromodState);
fn state(&self) -> PlasticityEngineState;
fn restore(&mut self, state: &PlasticityEngineState) -> Result<()>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlasticityEngineState {
pub engine_type: String,
pub neuromod: NeuromodState,
pub custom_state: Vec<u8>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NeuromodSyncConfig {
pub enabled: bool,
pub sync_rate: f32,
pub sync_interval_ms: u64,
}
impl Default for NeuromodSyncConfig {
fn default() -> Self {
Self {
enabled: true,
sync_rate: 0.1, sync_interval_ms: 100, }
}
}
impl NeuromodSyncConfig {
pub fn independent() -> Self {
Self {
enabled: false,
sync_rate: 0.0,
sync_interval_ms: 0,
}
}
pub fn full_sync() -> Self {
Self {
enabled: true,
sync_rate: 1.0,
sync_interval_ms: 50,
}
}
pub fn apply_sync(&self, local: &mut NeuromodState, external: &NeuromodState) {
if !self.enabled {
return;
}
let rate = self.sync_rate;
local.dopamine += (external.dopamine - local.dopamine) * rate;
local.serotonin += (external.serotonin - local.serotonin) * rate;
local.norepinephrine += (external.norepinephrine - local.norepinephrine) * rate;
local.acetylcholine += (external.acetylcholine - local.acetylcholine) * rate;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_neuromod_reward() {
let mut state = NeuromodState::baseline();
state.reward(0.3);
assert!(state.dopamine > 0.5);
}
#[test]
fn test_neuromod_stress() {
let mut state = NeuromodState::baseline();
state.stress(0.2);
assert!(state.serotonin < 0.5);
assert!(state.norepinephrine > 0.5);
}
#[test]
fn test_neuromod_decay() {
let mut state = NeuromodState::baseline();
state.dopamine = 1.0;
state.decay(0.1);
assert!(state.dopamine < 1.0);
assert!(state.dopamine > 0.5); }
#[test]
fn test_sync_config() {
let config = NeuromodSyncConfig::default();
let mut local = NeuromodState::baseline();
let mut external = NeuromodState::baseline();
external.dopamine = 1.0;
config.apply_sync(&mut local, &external);
assert!(local.dopamine > 0.5);
assert!(local.dopamine < 1.0);
}
#[test]
fn test_independent_no_sync() {
let config = NeuromodSyncConfig::independent();
let mut local = NeuromodState::baseline();
let mut external = NeuromodState::baseline();
external.dopamine = 1.0;
config.apply_sync(&mut local, &external);
assert_eq!(local.dopamine, 0.5);
}
}