use crate::enums::Species;
pub const AROUSAL_WEIGHT_HUMAN: f32 = 0.3;
pub const AROUSAL_WEIGHT_ANIMAL: f32 = 0.4;
pub const AROUSAL_WEIGHT_ROBOTIC: f32 = 0.0;
pub const AROUSAL_THRESHOLD: f32 = 0.2;
pub const AROUSAL_CEILING: f32 = 0.9;
pub const EXTREME_AROUSAL_IMPAIRMENT: f32 = 0.3;
pub const NEGATIVITY_BIAS_MULTIPLIER: f32 = 1.1;
#[must_use]
pub fn arousal_weight_for_species(species: &Species) -> f32 {
match species {
Species::Human => AROUSAL_WEIGHT_HUMAN,
Species::Dog | Species::Cat | Species::Mouse => AROUSAL_WEIGHT_ANIMAL,
Species::Elephant | Species::Chimpanzee | Species::Dolphin | Species::Crow => {
AROUSAL_WEIGHT_HUMAN
}
Species::Horse => AROUSAL_WEIGHT_ANIMAL,
Species::Custom { .. } => AROUSAL_WEIGHT_HUMAN,
}
}
#[must_use]
pub fn compute_arousal_modulated_salience(
base_salience: f32,
arousal: f32,
valence: f32,
is_trauma: bool,
species: &Species,
) -> f32 {
let arousal_weight = arousal_weight_for_species(species);
let effective_arousal = arousal.abs();
if effective_arousal < AROUSAL_THRESHOLD {
return apply_negativity_bias(base_salience, valence);
}
if effective_arousal > AROUSAL_CEILING && !is_trauma {
let impaired = base_salience * (1.0 - EXTREME_AROUSAL_IMPAIRMENT);
return apply_negativity_bias(impaired.clamp(0.0, 1.0), valence);
}
let room_for_improvement = 1.0 - base_salience;
let enhancement = effective_arousal * arousal_weight * room_for_improvement;
let enhanced = base_salience + enhancement;
apply_negativity_bias(enhanced.clamp(0.0, 1.0), valence)
}
fn apply_negativity_bias(salience: f32, valence: f32) -> f32 {
if valence < 0.0 {
(salience * NEGATIVITY_BIAS_MULTIPLIER).clamp(0.0, 1.0)
} else {
salience
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn arousal_weight_human() {
let weight = arousal_weight_for_species(&Species::Human);
assert!((weight - AROUSAL_WEIGHT_HUMAN).abs() < f32::EPSILON);
}
#[test]
fn arousal_weight_animal() {
let dog_weight = arousal_weight_for_species(&Species::Dog);
assert!((dog_weight - AROUSAL_WEIGHT_ANIMAL).abs() < f32::EPSILON);
let cat_weight = arousal_weight_for_species(&Species::Cat);
assert!((cat_weight - AROUSAL_WEIGHT_ANIMAL).abs() < f32::EPSILON);
}
#[test]
fn arousal_weight_horse_uses_animal_weight() {
let horse_weight = arousal_weight_for_species(&Species::Horse);
assert!((horse_weight - AROUSAL_WEIGHT_ANIMAL).abs() < f32::EPSILON);
}
#[test]
fn arousal_weight_custom_uses_human() {
let custom = Species::custom("Custom", 80, 25, 1.0);
let weight = arousal_weight_for_species(&custom);
assert!((weight - AROUSAL_WEIGHT_HUMAN).abs() < f32::EPSILON);
}
#[test]
fn arousal_boosts_salience() {
let salience = compute_arousal_modulated_salience(0.5, 0.7, 0.0, false, &Species::Human);
assert!(salience > 0.5);
}
#[test]
fn arousal_threshold_below_no_effect() {
let salience = compute_arousal_modulated_salience(
0.5,
0.1, 0.0,
false,
&Species::Human,
);
assert!((salience - 0.5).abs() < 0.01);
}
#[test]
fn arousal_ceiling_impairs_encoding() {
let normal =
compute_arousal_modulated_salience(0.5, 0.7, 0.0, false, &Species::Human);
let extreme = compute_arousal_modulated_salience(
0.5,
0.95, 0.0,
false,
&Species::Human,
);
assert!(extreme < normal);
}
#[test]
fn trauma_events_bypass_yerkes_dodson() {
let non_trauma =
compute_arousal_modulated_salience(0.5, 0.95, 0.0, false, &Species::Human);
let trauma = compute_arousal_modulated_salience(0.5, 0.95, 0.0, true, &Species::Human);
assert!(trauma > non_trauma);
}
#[test]
fn negativity_bias_increases_salience() {
let neutral = compute_arousal_modulated_salience(
0.5,
0.5,
0.0, false,
&Species::Human,
);
let negative = compute_arousal_modulated_salience(
0.5,
0.5,
-0.5, false,
&Species::Human,
);
assert!(negative > neutral);
}
#[test]
fn entity_model_arousal_weight() {
let human_salience =
compute_arousal_modulated_salience(0.5, 0.6, 0.0, false, &Species::Human);
let dog_salience =
compute_arousal_modulated_salience(0.5, 0.6, 0.0, false, &Species::Dog);
assert!(dog_salience > human_salience);
}
#[test]
fn salience_clamped_to_one() {
let salience = compute_arousal_modulated_salience(
0.9,
0.8,
-0.5, false,
&Species::Human,
);
assert!(salience <= 1.0);
}
#[test]
fn salience_clamped_to_zero() {
let salience =
compute_arousal_modulated_salience(0.1, 0.95, 0.0, false, &Species::Human);
assert!(salience >= 0.0);
}
#[test]
fn negative_arousal_uses_absolute() {
let salience = compute_arousal_modulated_salience(
0.5,
-0.7, 0.0,
false,
&Species::Human,
);
assert!(salience > 0.5);
}
#[test]
fn constants_have_expected_values() {
assert!((AROUSAL_WEIGHT_HUMAN - 0.3).abs() < f32::EPSILON);
assert!((AROUSAL_WEIGHT_ANIMAL - 0.4).abs() < f32::EPSILON);
assert!(AROUSAL_WEIGHT_ROBOTIC.abs() < f32::EPSILON);
assert!((AROUSAL_THRESHOLD - 0.2).abs() < f32::EPSILON);
assert!((AROUSAL_CEILING - 0.9).abs() < f32::EPSILON);
assert!((NEGATIVITY_BIAS_MULTIPLIER - 1.1).abs() < f32::EPSILON);
}
#[test]
fn elephant_uses_human_weight() {
let weight = arousal_weight_for_species(&Species::Elephant);
assert!((weight - AROUSAL_WEIGHT_HUMAN).abs() < f32::EPSILON);
}
#[test]
fn chimpanzee_uses_human_weight() {
let weight = arousal_weight_for_species(&Species::Chimpanzee);
assert!((weight - AROUSAL_WEIGHT_HUMAN).abs() < f32::EPSILON);
}
}