Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
This commit is contained in:
636
examples/exo-ai-2025/crates/exo-exotic/src/thermodynamics.rs
Normal file
636
examples/exo-ai-2025/crates/exo-exotic/src/thermodynamics.rs
Normal file
@@ -0,0 +1,636 @@
|
||||
//! # Cognitive Thermodynamics
|
||||
//!
|
||||
//! Deep exploration of Landauer's principle and thermodynamic constraints
|
||||
//! on cognitive processing.
|
||||
//!
|
||||
//! ## Key Concepts
|
||||
//!
|
||||
//! - **Landauer's Principle**: Erasing 1 bit costs kT ln(2) energy
|
||||
//! - **Reversible Computation**: Computation without erasure costs no energy
|
||||
//! - **Cognitive Temperature**: Noise/randomness in cognitive processing
|
||||
//! - **Maxwell's Demon**: Information-to-work conversion
|
||||
//! - **Thought Entropy**: Disorder in cognitive states
|
||||
//!
|
||||
//! ## Theoretical Foundation
|
||||
//!
|
||||
//! Based on:
|
||||
//! - Landauer (1961) - Irreversibility and Heat Generation
|
||||
//! - Bennett - Reversible Computation
|
||||
//! - Szilard Engine - Information thermodynamics
|
||||
//! - Jarzynski Equality - Non-equilibrium thermodynamics
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
/// Cognitive thermodynamics system
|
||||
#[derive(Debug)]
|
||||
pub struct CognitiveThermodynamics {
|
||||
/// Cognitive temperature (noise level)
|
||||
temperature: f64,
|
||||
/// Total entropy of the system
|
||||
entropy: ThoughtEntropy,
|
||||
/// Energy budget tracking
|
||||
energy: EnergyBudget,
|
||||
/// Maxwell's demon instance
|
||||
demon: MaxwellDemon,
|
||||
/// Phase state
|
||||
phase: CognitivePhase,
|
||||
/// History of thermodynamic events
|
||||
history: VecDeque<ThermodynamicEvent>,
|
||||
/// Boltzmann constant (normalized)
|
||||
k_b: f64,
|
||||
}
|
||||
|
||||
/// Entropy tracking for cognitive system
|
||||
#[derive(Debug)]
|
||||
pub struct ThoughtEntropy {
|
||||
/// Current entropy level
|
||||
current: f64,
|
||||
/// Entropy production rate
|
||||
production_rate: f64,
|
||||
/// Entropy capacity
|
||||
capacity: f64,
|
||||
/// Entropy components
|
||||
components: HashMap<String, f64>,
|
||||
}
|
||||
|
||||
/// Energy budget for cognitive operations
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EnergyBudget {
|
||||
/// Available energy
|
||||
available: f64,
|
||||
/// Total energy consumed
|
||||
consumed: f64,
|
||||
/// Energy from erasure
|
||||
erasure_cost: f64,
|
||||
/// Energy recovered from reversible computation
|
||||
recovered: f64,
|
||||
}
|
||||
|
||||
/// Maxwell's Demon for cognitive sorting
|
||||
#[derive(Debug)]
|
||||
pub struct MaxwellDemon {
|
||||
/// Demon's memory (cost of operation)
|
||||
memory: Vec<bool>,
|
||||
/// Memory capacity
|
||||
capacity: usize,
|
||||
/// Work extracted
|
||||
work_extracted: f64,
|
||||
/// Information cost
|
||||
information_cost: f64,
|
||||
/// Operating state
|
||||
active: bool,
|
||||
}
|
||||
|
||||
/// Phase states of cognitive matter
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum CognitivePhase {
|
||||
/// Solid - highly ordered, low entropy
|
||||
Crystalline,
|
||||
/// Liquid - flowing thoughts, moderate entropy
|
||||
Fluid,
|
||||
/// Gas - chaotic, high entropy
|
||||
Gaseous,
|
||||
/// Critical point - phase transition
|
||||
Critical,
|
||||
/// Bose-Einstein condensate analog - unified consciousness
|
||||
Condensate,
|
||||
}
|
||||
|
||||
/// A thermodynamic event
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ThermodynamicEvent {
|
||||
pub event_type: EventType,
|
||||
pub entropy_change: f64,
|
||||
pub energy_change: f64,
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum EventType {
|
||||
Erasure,
|
||||
Computation,
|
||||
Measurement,
|
||||
PhaseTransition,
|
||||
DemonOperation,
|
||||
HeatDissipation,
|
||||
}
|
||||
|
||||
impl CognitiveThermodynamics {
|
||||
/// Create a new cognitive thermodynamics system
|
||||
pub fn new(temperature: f64) -> Self {
|
||||
Self {
|
||||
temperature: temperature.max(0.001), // Avoid division by zero
|
||||
entropy: ThoughtEntropy::new(100.0),
|
||||
energy: EnergyBudget::new(1000.0),
|
||||
demon: MaxwellDemon::new(100),
|
||||
phase: CognitivePhase::Fluid,
|
||||
history: VecDeque::with_capacity(1000),
|
||||
k_b: 1.0, // Normalized Boltzmann constant
|
||||
}
|
||||
}
|
||||
|
||||
/// Measure current cognitive temperature
|
||||
pub fn measure_temperature(&self) -> f64 {
|
||||
self.temperature
|
||||
}
|
||||
|
||||
/// Set cognitive temperature
|
||||
pub fn set_temperature(&mut self, temp: f64) {
|
||||
let old_temp = self.temperature;
|
||||
self.temperature = temp.max(0.001);
|
||||
|
||||
// Check for phase transition
|
||||
self.check_phase_transition(old_temp, self.temperature);
|
||||
}
|
||||
|
||||
fn check_phase_transition(&mut self, old: f64, new: f64) {
|
||||
// Critical temperatures for phase transitions
|
||||
const T_FREEZE: f64 = 100.0;
|
||||
const T_BOIL: f64 = 500.0;
|
||||
const T_CRITICAL: f64 = 1000.0;
|
||||
const T_CONDENSATE: f64 = 10.0;
|
||||
|
||||
let old_phase = self.phase.clone();
|
||||
|
||||
self.phase = if new < T_CONDENSATE {
|
||||
CognitivePhase::Condensate
|
||||
} else if new < T_FREEZE {
|
||||
CognitivePhase::Crystalline
|
||||
} else if new < T_BOIL {
|
||||
CognitivePhase::Fluid
|
||||
} else if new < T_CRITICAL {
|
||||
CognitivePhase::Gaseous
|
||||
} else {
|
||||
CognitivePhase::Critical
|
||||
};
|
||||
|
||||
if old_phase != self.phase {
|
||||
// Record phase transition
|
||||
self.record_event(ThermodynamicEvent {
|
||||
event_type: EventType::PhaseTransition,
|
||||
entropy_change: (new - old).abs() * 0.1,
|
||||
energy_change: -(new - old).abs() * self.k_b,
|
||||
timestamp: self.current_time(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute Landauer cost of erasing n bits
|
||||
pub fn landauer_cost(&self, bits: usize) -> f64 {
|
||||
// E = n * k_B * T * ln(2)
|
||||
bits as f64 * self.k_b * self.temperature * std::f64::consts::LN_2
|
||||
}
|
||||
|
||||
/// Erase information (irreversible)
|
||||
pub fn erase(&mut self, bits: usize) -> ErasureResult {
|
||||
let cost = self.landauer_cost(bits);
|
||||
|
||||
if self.energy.available < cost {
|
||||
return ErasureResult {
|
||||
success: false,
|
||||
bits_erased: 0,
|
||||
energy_cost: 0.0,
|
||||
entropy_increase: 0.0,
|
||||
};
|
||||
}
|
||||
|
||||
// Consume energy
|
||||
self.energy.available -= cost;
|
||||
self.energy.consumed += cost;
|
||||
self.energy.erasure_cost += cost;
|
||||
|
||||
// Increase entropy (heat dissipation)
|
||||
let entropy_increase = bits as f64 * std::f64::consts::LN_2;
|
||||
self.entropy.current += entropy_increase;
|
||||
self.entropy.production_rate = entropy_increase;
|
||||
|
||||
self.record_event(ThermodynamicEvent {
|
||||
event_type: EventType::Erasure,
|
||||
entropy_change: entropy_increase,
|
||||
energy_change: -cost,
|
||||
timestamp: self.current_time(),
|
||||
});
|
||||
|
||||
ErasureResult {
|
||||
success: true,
|
||||
bits_erased: bits,
|
||||
energy_cost: cost,
|
||||
entropy_increase,
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform reversible computation
|
||||
pub fn reversible_compute<T>(
|
||||
&mut self,
|
||||
input: T,
|
||||
forward: impl Fn(T) -> T,
|
||||
_backward: impl Fn(T) -> T,
|
||||
) -> T {
|
||||
// Reversible computation has no erasure cost
|
||||
// Only the logical transformation happens
|
||||
|
||||
self.record_event(ThermodynamicEvent {
|
||||
event_type: EventType::Computation,
|
||||
entropy_change: 0.0, // Reversible = no entropy change
|
||||
energy_change: 0.0,
|
||||
timestamp: self.current_time(),
|
||||
});
|
||||
|
||||
forward(input)
|
||||
}
|
||||
|
||||
/// Perform measurement (gains information, increases entropy elsewhere)
|
||||
pub fn measure(&mut self, precision_bits: usize) -> MeasurementResult {
|
||||
// Measurement is fundamentally irreversible
|
||||
// Gains information but produces entropy
|
||||
|
||||
let information_gained = precision_bits as f64;
|
||||
let entropy_cost = precision_bits as f64 * std::f64::consts::LN_2;
|
||||
let energy_cost = self.landauer_cost(precision_bits);
|
||||
|
||||
self.entropy.current += entropy_cost;
|
||||
self.energy.available -= energy_cost;
|
||||
self.energy.consumed += energy_cost;
|
||||
|
||||
self.record_event(ThermodynamicEvent {
|
||||
event_type: EventType::Measurement,
|
||||
entropy_change: entropy_cost,
|
||||
energy_change: -energy_cost,
|
||||
timestamp: self.current_time(),
|
||||
});
|
||||
|
||||
MeasurementResult {
|
||||
information_gained,
|
||||
entropy_cost,
|
||||
energy_cost,
|
||||
}
|
||||
}
|
||||
|
||||
/// Run Maxwell's demon to extract work
|
||||
pub fn run_demon(&mut self, operations: usize) -> DemonResult {
|
||||
if !self.demon.active {
|
||||
return DemonResult {
|
||||
work_extracted: 0.0,
|
||||
memory_used: 0,
|
||||
erasure_cost: 0.0,
|
||||
net_work: 0.0,
|
||||
};
|
||||
}
|
||||
|
||||
let ops = operations.min(self.demon.capacity - self.demon.memory.len());
|
||||
if ops == 0 {
|
||||
// Demon must erase memory first
|
||||
let erase_cost = self.landauer_cost(self.demon.memory.len());
|
||||
self.demon.memory.clear();
|
||||
self.demon.information_cost += erase_cost;
|
||||
self.energy.available -= erase_cost;
|
||||
|
||||
return DemonResult {
|
||||
work_extracted: 0.0,
|
||||
memory_used: 0,
|
||||
erasure_cost: erase_cost,
|
||||
net_work: -erase_cost,
|
||||
};
|
||||
}
|
||||
|
||||
// Each operation records 1 bit and extracts k_B * T * ln(2) work
|
||||
let work_per_op = self.k_b * self.temperature * std::f64::consts::LN_2;
|
||||
let total_work = ops as f64 * work_per_op;
|
||||
|
||||
for _ in 0..ops {
|
||||
self.demon.memory.push(true);
|
||||
}
|
||||
self.demon.work_extracted += total_work;
|
||||
|
||||
self.record_event(ThermodynamicEvent {
|
||||
event_type: EventType::DemonOperation,
|
||||
entropy_change: -(ops as f64) * std::f64::consts::LN_2, // Local decrease
|
||||
energy_change: total_work,
|
||||
timestamp: self.current_time(),
|
||||
});
|
||||
|
||||
DemonResult {
|
||||
work_extracted: total_work,
|
||||
memory_used: ops,
|
||||
erasure_cost: 0.0,
|
||||
net_work: total_work,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get current phase
|
||||
pub fn phase(&self) -> &CognitivePhase {
|
||||
&self.phase
|
||||
}
|
||||
|
||||
/// Get entropy
|
||||
pub fn entropy(&self) -> &ThoughtEntropy {
|
||||
&self.entropy
|
||||
}
|
||||
|
||||
/// Get energy budget
|
||||
pub fn energy(&self) -> &EnergyBudget {
|
||||
&self.energy
|
||||
}
|
||||
|
||||
/// Add energy to the system
|
||||
pub fn add_energy(&mut self, amount: f64) {
|
||||
self.energy.available += amount;
|
||||
}
|
||||
|
||||
/// Calculate free energy (available for work)
|
||||
pub fn free_energy(&self) -> f64 {
|
||||
// F = E - T*S
|
||||
self.energy.available - self.temperature * self.entropy.current
|
||||
}
|
||||
|
||||
/// Calculate efficiency
|
||||
pub fn efficiency(&self) -> f64 {
|
||||
if self.energy.consumed == 0.0 {
|
||||
return 1.0;
|
||||
}
|
||||
self.energy.recovered / self.energy.consumed
|
||||
}
|
||||
|
||||
/// Get Carnot efficiency limit
|
||||
pub fn carnot_limit(&self, cold_temp: f64) -> f64 {
|
||||
if self.temperature <= cold_temp {
|
||||
return 0.0;
|
||||
}
|
||||
1.0 - cold_temp / self.temperature
|
||||
}
|
||||
|
||||
fn record_event(&mut self, event: ThermodynamicEvent) {
|
||||
self.history.push_back(event);
|
||||
if self.history.len() > 1000 {
|
||||
self.history.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
fn current_time(&self) -> u64 {
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.map(|d| d.as_secs())
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Get thermodynamic statistics
|
||||
pub fn statistics(&self) -> ThermodynamicStatistics {
|
||||
ThermodynamicStatistics {
|
||||
temperature: self.temperature,
|
||||
entropy: self.entropy.current,
|
||||
free_energy: self.free_energy(),
|
||||
energy_available: self.energy.available,
|
||||
efficiency: self.efficiency(),
|
||||
phase: self.phase.clone(),
|
||||
demon_work: self.demon.work_extracted,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ThoughtEntropy {
|
||||
/// Create new entropy tracker
|
||||
pub fn new(capacity: f64) -> Self {
|
||||
Self {
|
||||
current: 0.0,
|
||||
production_rate: 0.0,
|
||||
capacity,
|
||||
components: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get current entropy
|
||||
pub fn current(&self) -> f64 {
|
||||
self.current
|
||||
}
|
||||
|
||||
/// Set entropy for a component
|
||||
pub fn set_component(&mut self, name: &str, entropy: f64) {
|
||||
self.components.insert(name.to_string(), entropy);
|
||||
self.current = self.components.values().sum();
|
||||
}
|
||||
|
||||
/// Get entropy headroom
|
||||
pub fn headroom(&self) -> f64 {
|
||||
(self.capacity - self.current).max(0.0)
|
||||
}
|
||||
|
||||
/// Is at maximum entropy?
|
||||
pub fn is_maximum(&self) -> bool {
|
||||
self.current >= self.capacity * 0.99
|
||||
}
|
||||
}
|
||||
|
||||
impl EnergyBudget {
|
||||
/// Create new energy budget
|
||||
pub fn new(initial: f64) -> Self {
|
||||
Self {
|
||||
available: initial,
|
||||
consumed: 0.0,
|
||||
erasure_cost: 0.0,
|
||||
recovered: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get available energy
|
||||
pub fn available(&self) -> f64 {
|
||||
self.available
|
||||
}
|
||||
|
||||
/// Get total consumed
|
||||
pub fn consumed(&self) -> f64 {
|
||||
self.consumed
|
||||
}
|
||||
}
|
||||
|
||||
impl MaxwellDemon {
|
||||
/// Create new Maxwell's demon
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
Self {
|
||||
memory: Vec::with_capacity(capacity),
|
||||
capacity,
|
||||
work_extracted: 0.0,
|
||||
information_cost: 0.0,
|
||||
active: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Activate demon
|
||||
pub fn activate(&mut self) {
|
||||
self.active = true;
|
||||
}
|
||||
|
||||
/// Deactivate demon
|
||||
pub fn deactivate(&mut self) {
|
||||
self.active = false;
|
||||
}
|
||||
|
||||
/// Get work extracted
|
||||
pub fn work_extracted(&self) -> f64 {
|
||||
self.work_extracted
|
||||
}
|
||||
|
||||
/// Get net work (accounting for erasure)
|
||||
pub fn net_work(&self) -> f64 {
|
||||
self.work_extracted - self.information_cost
|
||||
}
|
||||
|
||||
/// Memory usage fraction
|
||||
pub fn memory_usage(&self) -> f64 {
|
||||
self.memory.len() as f64 / self.capacity as f64
|
||||
}
|
||||
}
|
||||
|
||||
/// Result of erasure operation
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ErasureResult {
|
||||
pub success: bool,
|
||||
pub bits_erased: usize,
|
||||
pub energy_cost: f64,
|
||||
pub entropy_increase: f64,
|
||||
}
|
||||
|
||||
/// Result of measurement
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MeasurementResult {
|
||||
pub information_gained: f64,
|
||||
pub entropy_cost: f64,
|
||||
pub energy_cost: f64,
|
||||
}
|
||||
|
||||
/// Result of demon operation
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DemonResult {
|
||||
pub work_extracted: f64,
|
||||
pub memory_used: usize,
|
||||
pub erasure_cost: f64,
|
||||
pub net_work: f64,
|
||||
}
|
||||
|
||||
/// Thermodynamic statistics
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ThermodynamicStatistics {
|
||||
pub temperature: f64,
|
||||
pub entropy: f64,
|
||||
pub free_energy: f64,
|
||||
pub energy_available: f64,
|
||||
pub efficiency: f64,
|
||||
pub phase: CognitivePhase,
|
||||
pub demon_work: f64,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_thermodynamics_creation() {
|
||||
let thermo = CognitiveThermodynamics::new(300.0);
|
||||
assert_eq!(thermo.measure_temperature(), 300.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_landauer_cost() {
|
||||
let thermo = CognitiveThermodynamics::new(300.0);
|
||||
|
||||
let cost_1bit = thermo.landauer_cost(1);
|
||||
let cost_2bits = thermo.landauer_cost(2);
|
||||
|
||||
// Cost should scale linearly
|
||||
assert!((cost_2bits - 2.0 * cost_1bit).abs() < 0.001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_erasure() {
|
||||
let mut thermo = CognitiveThermodynamics::new(300.0);
|
||||
// Add enough energy for the erasure to succeed
|
||||
thermo.add_energy(10000.0);
|
||||
let initial_energy = thermo.energy().available();
|
||||
|
||||
let result = thermo.erase(10);
|
||||
|
||||
assert!(result.success);
|
||||
assert_eq!(result.bits_erased, 10);
|
||||
assert!(thermo.energy().available() < initial_energy);
|
||||
assert!(thermo.entropy().current() > 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reversible_computation() {
|
||||
let mut thermo = CognitiveThermodynamics::new(300.0);
|
||||
|
||||
let input = 5;
|
||||
let output = thermo.reversible_compute(
|
||||
input,
|
||||
|x| x * 2, // forward
|
||||
|x| x / 2, // backward
|
||||
);
|
||||
|
||||
assert_eq!(output, 10);
|
||||
// Reversible computation shouldn't increase entropy significantly
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_phase_transitions() {
|
||||
let mut thermo = CognitiveThermodynamics::new(300.0);
|
||||
|
||||
// Start in Fluid phase
|
||||
assert_eq!(*thermo.phase(), CognitivePhase::Fluid);
|
||||
|
||||
// Cool down
|
||||
thermo.set_temperature(50.0);
|
||||
assert_eq!(*thermo.phase(), CognitivePhase::Crystalline);
|
||||
|
||||
// Heat up
|
||||
thermo.set_temperature(600.0);
|
||||
assert_eq!(*thermo.phase(), CognitivePhase::Gaseous);
|
||||
|
||||
// Extreme cooling
|
||||
thermo.set_temperature(5.0);
|
||||
assert_eq!(*thermo.phase(), CognitivePhase::Condensate);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_maxwell_demon() {
|
||||
let mut thermo = CognitiveThermodynamics::new(300.0);
|
||||
|
||||
let result = thermo.run_demon(10);
|
||||
|
||||
assert!(result.work_extracted > 0.0);
|
||||
assert_eq!(result.memory_used, 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_free_energy() {
|
||||
let thermo = CognitiveThermodynamics::new(300.0);
|
||||
let free = thermo.free_energy();
|
||||
|
||||
// Free energy should be positive initially
|
||||
assert!(free > 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_entropy_components() {
|
||||
let mut entropy = ThoughtEntropy::new(100.0);
|
||||
|
||||
entropy.set_component("perception", 10.0);
|
||||
entropy.set_component("memory", 15.0);
|
||||
|
||||
assert_eq!(entropy.current(), 25.0);
|
||||
assert!(!entropy.is_maximum());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_demon_memory_limit() {
|
||||
let mut thermo = CognitiveThermodynamics::new(300.0);
|
||||
|
||||
// Fill demon memory
|
||||
for _ in 0..10 {
|
||||
thermo.run_demon(10);
|
||||
}
|
||||
|
||||
// Demon should need to erase memory eventually
|
||||
let usage = thermo.demon.memory_usage();
|
||||
assert!(usage > 0.0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user