#[derive(Debug, Clone, PartialEq)]
pub enum DriveSignal {
Curiosity(f64),
CoherenceSeeking(f64),
ContradictionResolution(f64),
}
impl DriveSignal {
pub fn magnitude(&self) -> f64 {
match self {
Self::Curiosity(m) | Self::CoherenceSeeking(m) | Self::ContradictionResolution(m) => *m,
}
}
pub fn name(&self) -> &'static str {
match self {
Self::Curiosity(_) => "Curiosity",
Self::CoherenceSeeking(_) => "CoherenceSeeking",
Self::ContradictionResolution(_) => "ContradictionResolution",
}
}
}
#[derive(Debug, Clone, Default)]
pub struct DriveState {
pub signals: Vec<DriveSignal>,
}
impl DriveState {
pub fn dominant_drive(&self) -> Option<&DriveSignal> {
self.signals.iter().max_by(|a, b| {
a.magnitude()
.partial_cmp(&b.magnitude())
.unwrap_or(std::cmp::Ordering::Equal)
})
}
pub fn total_urgency(&self) -> f64 {
self.signals.iter().map(|s| s.magnitude()).sum()
}
pub fn is_idle(&self, threshold: f64) -> bool {
self.signals.iter().all(|s| s.magnitude() < threshold)
}
}
#[derive(Debug, Clone)]
pub struct InternalDrive {
pub residual_scale: f64,
pub incoherence_scale: f64,
pub contradiction_scale: usize,
unexplained_residual: f64,
incoherence_count: f64,
contradiction_count: usize,
}
impl InternalDrive {
pub fn new(residual_scale: f64, incoherence_scale: f64, contradiction_scale: usize) -> Self {
Self {
residual_scale: residual_scale.max(1e-9),
incoherence_scale: incoherence_scale.max(1e-9),
contradiction_scale: contradiction_scale.max(1),
unexplained_residual: 0.0,
incoherence_count: 0.0,
contradiction_count: 0,
}
}
pub fn record_residual(&mut self, magnitude: f64) {
self.unexplained_residual += magnitude.abs();
}
pub fn record_incoherence(&mut self, magnitude: f64) {
self.incoherence_count += magnitude.abs();
}
pub fn record_contradiction(&mut self) {
self.contradiction_count += 1;
}
pub fn tick(&mut self) -> DriveState {
let curiosity = (self.unexplained_residual / self.residual_scale).clamp(0.0, 1.0);
let coherence = (self.incoherence_count / self.incoherence_scale).clamp(0.0, 1.0);
let contradiction =
(self.contradiction_count as f64 / self.contradiction_scale as f64).clamp(0.0, 1.0);
self.unexplained_residual = 0.0;
self.incoherence_count = 0.0;
self.contradiction_count = 0;
let mut signals = Vec::with_capacity(3);
if curiosity >= 0.01 {
signals.push(DriveSignal::Curiosity(curiosity));
}
if coherence >= 0.01 {
signals.push(DriveSignal::CoherenceSeeking(coherence));
}
if contradiction >= 0.01 {
signals.push(DriveSignal::ContradictionResolution(contradiction));
}
DriveState { signals }
}
pub fn peek_dominant(&self) -> Option<DriveSignal> {
let curiosity = (self.unexplained_residual / self.residual_scale).clamp(0.0, 1.0);
let coherence = (self.incoherence_count / self.incoherence_scale).clamp(0.0, 1.0);
let contradiction =
(self.contradiction_count as f64 / self.contradiction_scale as f64).clamp(0.0, 1.0);
let candidates = [
DriveSignal::Curiosity(curiosity),
DriveSignal::CoherenceSeeking(coherence),
DriveSignal::ContradictionResolution(contradiction),
];
candidates
.into_iter()
.filter(|s| s.magnitude() >= 0.01)
.max_by(|a, b| {
a.magnitude()
.partial_cmp(&b.magnitude())
.unwrap_or(std::cmp::Ordering::Equal)
})
}
}
impl Default for InternalDrive {
fn default() -> Self {
Self::new(1.0, 10.0, 5)
}
}