use std::ops::{Mul, Not};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
#[repr(i8)]
pub enum Trit {
False = -1,
#[default]
Unknown = 0,
True = 1,
}
impl Trit {
#[inline]
pub fn consensus(self, other: Trit) -> Trit {
let val = (self as i8) * (other as i8);
match val {
-1 => Trit::False,
0 => Trit::Unknown,
1 => Trit::True,
_ => Trit::Unknown,
}
}
#[inline]
pub const fn weight(self) -> i8 {
self as i8
}
#[inline]
pub const fn invert(self) -> Trit {
match self {
Trit::True => Trit::False,
Trit::False => Trit::True,
Trit::Unknown => Trit::Unknown,
}
}
#[inline]
pub const fn from_i8_saturating(val: i8) -> Trit {
if val > 0 {
Trit::True
} else if val < 0 {
Trit::False
} else {
Trit::Unknown
}
}
}
impl Mul for Trit {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self::Output {
self.consensus(rhs)
}
}
impl Not for Trit {
type Output = Self;
#[inline]
fn not(self) -> Self::Output {
self.invert()
}
}
pub mod dimension {
pub const CURIOSITY: usize = 0;
pub const PRESERVATION: usize = 1;
pub const EFFICIENCY: usize = 2;
pub const EMPATHY: usize = 3;
pub const RIGIDITY: usize = 4;
pub const VOLATILITY: usize = 5;
pub const AGGRESSION: usize = 6;
pub const LATENCY: usize = 7;
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct Octet {
pub values: [Trit; 8],
}
impl Octet {
#[inline]
pub const fn new(values: [Trit; 8]) -> Self {
Self { values }
}
#[inline]
pub const fn neutral() -> Self {
Self {
values: [Trit::Unknown; 8],
}
}
pub fn resonance(&self, other: &Octet) -> f64 {
let mut dot_product: i32 = 0;
let mut active_dimensions: i32 = 0;
for i in 0..8 {
let a = self.values[i];
let b = other.values[i];
if a != Trit::Unknown && b != Trit::Unknown {
dot_product += (a * b).weight() as i32;
active_dimensions += 1;
}
}
if active_dimensions == 0 {
0.0
} else {
dot_product as f64 / active_dimensions as f64
}
}
#[inline]
pub fn dissonance(&self, other: &Octet) -> f64 {
let res = self.resonance(other);
if res < 0.0 {
res.abs()
} else {
0.0
}
}
#[inline]
pub const fn get(&self, dim: usize) -> Trit {
self.values[dim]
}
#[inline]
pub fn set(&mut self, dim: usize, value: Trit) {
self.values[dim] = value;
}
pub fn pack(&self) -> u16 {
let mut packed: u16 = 0;
for (i, trit) in self.values.iter().enumerate() {
let bits: u16 = match trit {
Trit::Unknown => 0b00,
Trit::True => 0b01,
Trit::False => 0b11,
};
packed |= bits << (i * 2);
}
packed
}
pub fn unpack(packed: u16) -> Self {
let mut values = [Trit::Unknown; 8];
for (i, trit) in values.iter_mut().enumerate() {
let bits = (packed >> (i * 2)) & 0b11;
*trit = match bits {
0b00 => Trit::Unknown,
0b01 => Trit::True,
0b11 => Trit::False,
_ => Trit::Unknown, };
}
Self { values }
}
}
impl Default for Octet {
fn default() -> Self {
Self::neutral()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Quantizer {
base_threshold: f64,
}
impl Quantizer {
#[inline]
pub const fn new(base_threshold: f64) -> Self {
Self { base_threshold }
}
pub fn quantize(&self, value: f64, mood_modifier: f64) -> Trit {
let dynamic_threshold = (self.base_threshold - (mood_modifier * 0.1)).max(0.01);
if value > dynamic_threshold {
Trit::True
} else if value < -dynamic_threshold {
Trit::False
} else {
Trit::Unknown
}
}
#[inline]
pub const fn threshold(&self) -> f64 {
self.base_threshold
}
}
impl Default for Quantizer {
fn default() -> Self {
Self::new(0.33)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Cortex {
personality: Octet,
mood: f64,
quantizer: Quantizer,
retention: RetentionBuffer,
}
impl Cortex {
pub fn new(personality: Octet) -> Self {
Self {
personality,
mood: 0.0,
quantizer: Quantizer::default(),
retention: RetentionBuffer::default(),
}
}
pub fn with_threshold(personality: Octet, threshold: f64) -> Self {
Self {
personality,
mood: 0.0,
quantizer: Quantizer::new(threshold),
retention: RetentionBuffer::default(),
}
}
#[inline]
pub fn mood(&self) -> f64 {
self.mood
}
#[inline]
pub fn personality(&self) -> &Octet {
&self.personality
}
#[inline]
pub fn shift_mood(&mut self, delta: f64) {
self.mood = (self.mood + delta).clamp(-1.0, 1.0);
}
#[inline]
pub fn set_mood(&mut self, value: f64) {
self.mood = value.clamp(-1.0, 1.0);
}
#[inline]
pub fn evaluate(&self, event: &Octet) -> f64 {
self.personality.resonance(event)
}
#[inline]
pub fn decide(&self, value: f64) -> Trit {
self.quantizer.quantize(value, self.mood)
}
pub fn consciousness_state(&self, energy: f64, threshold: f64) -> Trit {
let delta = energy - threshold;
const BASE_SENSITIVITY: f64 = 5.0;
let sensitivity_modifier = 1.0 + (self.mood * 0.5);
let dynamic_gain = BASE_SENSITIVITY * sensitivity_modifier;
let amplified = delta * dynamic_gain;
self.quantizer.quantize(amplified, self.mood)
}
#[inline]
pub fn retention_mut(&mut self) -> &mut RetentionBuffer {
&mut self.retention
}
#[inline]
pub fn pending_removal_count(&self) -> usize {
self.retention.pending_count()
}
}
impl Default for Cortex {
fn default() -> Self {
Self::new(Octet::neutral())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RetentionBuffer {
pending_removals: std::collections::HashMap<usize, u8>,
default_ttl: u8,
}
impl RetentionBuffer {
pub fn new(ttl: u8) -> Self {
Self {
pending_removals: std::collections::HashMap::new(),
default_ttl: ttl,
}
}
pub fn mark_or_tick(&mut self, id: usize) -> bool {
let ttl = self.pending_removals.entry(id).or_insert(self.default_ttl);
if *ttl > 0 {
*ttl -= 1;
false } else {
self.pending_removals.remove(&id);
true }
}
pub fn restore(&mut self, id: usize) {
self.pending_removals.remove(&id);
}
#[inline]
pub fn is_pending(&self, id: usize) -> bool {
self.pending_removals.contains_key(&id)
}
#[inline]
pub fn remaining_ttl(&self, id: usize) -> Option<u8> {
self.pending_removals.get(&id).copied()
}
#[inline]
pub fn pending_count(&self) -> usize {
self.pending_removals.len()
}
pub fn clear(&mut self) {
self.pending_removals.clear();
}
#[inline]
pub fn default_ttl(&self) -> u8 {
self.default_ttl
}
}
impl Default for RetentionBuffer {
fn default() -> Self {
Self::new(3) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_trit_consensus() {
assert_eq!(Trit::True * Trit::True, Trit::True);
assert_eq!(Trit::False * Trit::False, Trit::True);
assert_eq!(Trit::True * Trit::False, Trit::False);
assert_eq!(Trit::False * Trit::True, Trit::False);
assert_eq!(Trit::Unknown * Trit::True, Trit::Unknown);
assert_eq!(Trit::Unknown * Trit::False, Trit::Unknown);
assert_eq!(Trit::Unknown * Trit::Unknown, Trit::Unknown);
}
#[test]
fn test_trit_inversion() {
assert_eq!(!Trit::True, Trit::False);
assert_eq!(!Trit::False, Trit::True);
assert_eq!(!Trit::Unknown, Trit::Unknown);
}
#[test]
fn test_trit_weight() {
assert_eq!(Trit::False.weight(), -1);
assert_eq!(Trit::Unknown.weight(), 0);
assert_eq!(Trit::True.weight(), 1);
}
#[test]
fn test_trit_from_i8() {
assert_eq!(Trit::from_i8_saturating(5), Trit::True);
assert_eq!(Trit::from_i8_saturating(1), Trit::True);
assert_eq!(Trit::from_i8_saturating(0), Trit::Unknown);
assert_eq!(Trit::from_i8_saturating(-1), Trit::False);
assert_eq!(Trit::from_i8_saturating(-100), Trit::False);
}
#[test]
fn test_octet_perfect_resonance() {
let p1 = Octet::new([Trit::True; 8]);
let p2 = Octet::new([Trit::True; 8]);
assert!((p1.resonance(&p2) - 1.0).abs() < f64::EPSILON);
}
#[test]
fn test_octet_perfect_opposition() {
let p1 = Octet::new([Trit::True; 8]);
let p2 = Octet::new([Trit::False; 8]);
assert!((p1.resonance(&p2) - (-1.0)).abs() < f64::EPSILON);
}
#[test]
fn test_octet_neutral_resonance() {
let p1 = Octet::neutral();
let p2 = Octet::new([Trit::True; 8]);
assert_eq!(p1.resonance(&p2), 0.0);
}
#[test]
fn test_octet_partial_resonance() {
let mut vals1 = [Trit::Unknown; 8];
vals1[0] = Trit::True;
vals1[1] = Trit::True;
vals1[2] = Trit::False;
vals1[3] = Trit::False;
let p1 = Octet::new(vals1);
let mut vals2 = [Trit::Unknown; 8];
vals2[0] = Trit::True; vals2[1] = Trit::False; vals2[2] = Trit::True; vals2[3] = Trit::False; let p2 = Octet::new(vals2);
assert_eq!(p1.resonance(&p2), 0.0);
}
#[test]
fn test_octet_dissonance() {
let p1 = Octet::new([Trit::True; 8]);
let p2 = Octet::new([Trit::False; 8]);
assert!((p1.dissonance(&p2) - 1.0).abs() < f64::EPSILON);
let p3 = Octet::new([Trit::True; 8]);
assert_eq!(p1.dissonance(&p3), 0.0);
}
#[test]
fn test_octet_pack_unpack() {
let original = Octet::new([
Trit::True,
Trit::False,
Trit::Unknown,
Trit::True,
Trit::False,
Trit::Unknown,
Trit::True,
Trit::False,
]);
let packed = original.pack();
let unpacked = Octet::unpack(packed);
assert_eq!(original, unpacked);
}
#[test]
fn test_octet_dimension_access() {
let mut o = Octet::neutral();
o.set(dimension::CURIOSITY, Trit::True);
o.set(dimension::AGGRESSION, Trit::False);
assert_eq!(o.get(dimension::CURIOSITY), Trit::True);
assert_eq!(o.get(dimension::AGGRESSION), Trit::False);
assert_eq!(o.get(dimension::EMPATHY), Trit::Unknown);
}
#[test]
fn test_quantizer_neutral_mood() {
let q = Quantizer::new(0.5);
assert_eq!(q.quantize(0.6, 0.0), Trit::True);
assert_eq!(q.quantize(0.4, 0.0), Trit::Unknown);
assert_eq!(q.quantize(-0.6, 0.0), Trit::False);
}
#[test]
fn test_quantizer_positive_mood() {
let q = Quantizer::new(0.5);
assert_eq!(q.quantize(0.45, 1.0), Trit::True);
assert_eq!(q.quantize(0.35, 1.0), Trit::Unknown);
}
#[test]
fn test_quantizer_negative_mood() {
let q = Quantizer::new(0.5);
assert_eq!(q.quantize(0.55, -1.0), Trit::Unknown);
assert_eq!(q.quantize(0.65, -1.0), Trit::True);
}
#[test]
fn test_quantizer_default() {
let q = Quantizer::default();
assert!((q.threshold() - 0.33).abs() < f64::EPSILON);
}
#[test]
fn test_cortex_creation() {
let cortex = Cortex::default();
assert_eq!(cortex.mood(), 0.0);
assert_eq!(*cortex.personality(), Octet::neutral());
}
#[test]
fn test_cortex_mood_shift() {
let mut cortex = Cortex::default();
cortex.shift_mood(0.5);
assert!((cortex.mood() - 0.5).abs() < f64::EPSILON);
cortex.shift_mood(0.8); assert!((cortex.mood() - 1.0).abs() < f64::EPSILON);
cortex.shift_mood(-2.5); assert!((cortex.mood() - (-1.0)).abs() < f64::EPSILON);
}
#[test]
fn test_cortex_mood_set() {
let mut cortex = Cortex::default();
cortex.set_mood(0.75);
assert!((cortex.mood() - 0.75).abs() < f64::EPSILON);
cortex.set_mood(2.0);
assert!((cortex.mood() - 1.0).abs() < f64::EPSILON);
}
#[test]
fn test_cortex_evaluate() {
let mut personality = Octet::neutral();
personality.set(dimension::CURIOSITY, Trit::True);
personality.set(dimension::PRESERVATION, Trit::True);
let cortex = Cortex::new(personality);
let mut event = Octet::neutral();
event.set(dimension::CURIOSITY, Trit::True);
assert!(cortex.evaluate(&event) > 0.0);
let mut conflict = Octet::neutral();
conflict.set(dimension::CURIOSITY, Trit::False);
conflict.set(dimension::PRESERVATION, Trit::False);
assert!(cortex.evaluate(&conflict) < 0.0);
}
#[test]
fn test_cortex_decide() {
let cortex = Cortex::default();
assert_eq!(cortex.decide(0.8), Trit::True);
assert_eq!(cortex.decide(0.2), Trit::Unknown);
assert_eq!(cortex.decide(-0.5), Trit::False);
}
#[test]
fn test_cortex_consciousness_state() {
let cortex = Cortex::default();
assert_eq!(cortex.consciousness_state(0.9, 0.5), Trit::True);
assert_eq!(cortex.consciousness_state(0.2, 0.5), Trit::False);
assert_eq!(cortex.consciousness_state(0.6, 0.5), Trit::True);
assert_eq!(cortex.consciousness_state(0.52, 0.5), Trit::Unknown);
assert_eq!(cortex.consciousness_state(0.95, 0.8), Trit::True);
}
#[test]
fn test_cortex_mood_affects_decision() {
let mut cortex = Cortex::with_threshold(Octet::neutral(), 0.5);
assert_eq!(cortex.decide(0.45), Trit::Unknown);
cortex.set_mood(1.0);
assert_eq!(cortex.decide(0.45), Trit::True);
cortex.set_mood(-1.0);
assert_eq!(cortex.decide(0.55), Trit::Unknown);
}
#[test]
fn test_retention_buffer_creation() {
let buffer = RetentionBuffer::new(5);
assert_eq!(buffer.default_ttl(), 5);
assert_eq!(buffer.pending_count(), 0);
}
#[test]
fn test_retention_buffer_mark_and_tick() {
let mut buffer = RetentionBuffer::new(3);
assert!(!buffer.mark_or_tick(42));
assert!(buffer.is_pending(42));
assert_eq!(buffer.remaining_ttl(42), Some(2));
assert!(!buffer.mark_or_tick(42));
assert_eq!(buffer.remaining_ttl(42), Some(1));
assert!(!buffer.mark_or_tick(42));
assert_eq!(buffer.remaining_ttl(42), Some(0));
assert!(buffer.mark_or_tick(42));
assert!(!buffer.is_pending(42));
}
#[test]
fn test_retention_buffer_restore() {
let mut buffer = RetentionBuffer::new(3);
buffer.mark_or_tick(100);
assert!(buffer.is_pending(100));
buffer.restore(100);
assert!(!buffer.is_pending(100));
assert_eq!(buffer.pending_count(), 0);
}
#[test]
fn test_retention_buffer_multiple_items() {
let mut buffer = RetentionBuffer::new(2);
buffer.mark_or_tick(1);
buffer.mark_or_tick(2);
buffer.mark_or_tick(3);
assert_eq!(buffer.pending_count(), 3);
buffer.restore(2);
assert_eq!(buffer.pending_count(), 2);
buffer.clear();
assert_eq!(buffer.pending_count(), 0);
}
#[test]
fn test_cortex_has_retention_buffer() {
let mut cortex = Cortex::default();
assert_eq!(cortex.pending_removal_count(), 0);
cortex.retention_mut().mark_or_tick(99);
assert_eq!(cortex.pending_removal_count(), 1);
cortex.retention_mut().restore(99);
assert_eq!(cortex.pending_removal_count(), 0);
}
}