viva_emotion/dynamics
Dynamics - How emotions evolve over time
Ornstein-Uhlenbeck Process
Based on Oravecz et al. (2009, 2011) for affective dynamics:
dX(t) = θ(μ - X(t))dt + σdW(t)
Where:
- θ (decay_rate): mean-reversion speed, typical 0.1-0.3
- μ (baseline): equilibrium point (personality)
- σ (volatility): noise amplitude
- dW: Wiener increment (Gaussian noise)
Asymptotic variance: Var_∞ = σ²/(2θ) With θ=0.1, σ=0.02: Var_∞ ≈ 0.002, fluctuations ≈ ±0.045
Cusp Catastrophe
Based on Thom (1975) catastrophe theory, using viva_math/cusp:
V(x) = x⁴/4 + αx²/2 + βx
Bistability region: Δ = -4α³ - 27β² > 0 (validated by DeepSeek R1)
Mapping to PAD:
- α = cusp_threshold × arousal (splitting factor)
- β = pleasure (normal factor)
- High arousal + low dominance triggers catastrophic flip
References
- Oravecz, Tuerlinckx & Vandekerckhove (2009). Psychometrika, 74(3), 395-418.
- Oravecz et al. (2011). Psychological Methods, 16(4), 468-490.
- Thom (1975). Structural Stability and Morphogenesis. Benjamin.
- viva_math/cusp - Validated by DeepSeek R1 671B (2025)
Types
Configuration for emotional dynamics
pub type DynamicsConfig {
DynamicsConfig(
decay_rate: Float,
baseline: pad.Pad,
volatility: Float,
cusp_threshold: Float,
cusp_dominance_trigger: Float,
cusp_pleasure_trigger: Float,
cusp_flip_pleasure_damp: Float,
cusp_flip_arousal_damp: Float,
cusp_flip_dominance_boost: Float,
coupling_pa: Float,
coupling_pd: Float,
coupling_ap: Float,
coupling_da: Float,
)
}
Constructors
-
DynamicsConfig( decay_rate: Float, baseline: pad.Pad, volatility: Float, cusp_threshold: Float, cusp_dominance_trigger: Float, cusp_pleasure_trigger: Float, cusp_flip_pleasure_damp: Float, cusp_flip_arousal_damp: Float, cusp_flip_dominance_boost: Float, coupling_pa: Float, coupling_pd: Float, coupling_ap: Float, coupling_da: Float, )Arguments
- decay_rate
-
Base decay rate (theta in O-U)
- baseline
-
Target state (mu in O-U) - personality baseline
- volatility
-
Volatility scale (sigma in O-U) - multiplied with injected noise
- cusp_threshold
-
Cusp alpha threshold for bistability
- cusp_dominance_trigger
-
Dominance threshold for cusp trigger (default -0.3)
- cusp_pleasure_trigger
-
Pleasure threshold for cusp trigger (default -0.5)
- cusp_flip_pleasure_damp
-
Dampening factor for pleasure flip (default 0.7)
- cusp_flip_arousal_damp
-
Dampening factor for arousal after flip (default 0.8)
- cusp_flip_dominance_boost
-
Dominance recovery after flip (default 0.2)
- coupling_pa
-
P-A coupling: arousal influence on pleasure dynamics (default 0.0) Positive = high arousal amplifies pleasure change
- coupling_pd
-
P-D coupling: dominance influence on pleasure dynamics (default 0.05) Based on Bakker et al. (2014) P-D correlation ≈ 0.85
- coupling_ap
-
A-P coupling: pleasure influence on arousal dynamics (default 0.0)
- coupling_da
-
D-A coupling: arousal influence on dominance dynamics (default -0.03) High arousal reduces dominance (feeling less in control) Based on Yik (2011) arousal-dominance interaction
Values
pub fn check_cusp(
state: pad.Pad,
config: DynamicsConfig,
) -> #(pad.Pad, Bool)
Check for cusp catastrophe and apply if triggered Returns new state (possibly jumped) and whether jump occurred
pub fn cusp_potential(
x: Float,
alpha: Float,
beta: Float,
) -> Float
Cusp catastrophe potential (delegated to viva_math/cusp) V(x) = x^4/4 + alphax^2/2 + betax
pub fn evolve(
state: pad.Pad,
config: DynamicsConfig,
dt: Float,
) -> pad.Pad
Evolve PAD state using coupled Ornstein-Uhlenbeck process
Extended model with inter-dimensional coupling:
dP = θ(μ_p - P)dt + c_pa × A × dt + c_pd × D × dt
dA = θ(μ_a - A)dt + c_ap × P × dt
dD = θ(μ_d - D)dt + c_da × A × dt
Where c_da = -0.03 (Yik 2011): high arousal reduces dominance
Higher arousal = slower decay (emotions persist when excited)
pub fn evolve_with_noise(
state: pad.Pad,
config: DynamicsConfig,
dt: Float,
noise: pad.Pad,
) -> pad.Pad
Evolve with injected noise (stochastic O-U process)
Noise Requirements
For mathematically correct Euler-Maruyama discretization,
each component of noise should be sampled from N(0,1):
noise.pleasure ~ N(0, 1)
noise.arousal ~ N(0, 1)
noise.dominance ~ N(0, 1)
The scaling σ × √dt is applied internally.
Deterministic Mode
For testing/replay, pass pad.neutral() (all zeros) as noise.
This gives fully deterministic mean-reversion behavior.
Warning
If noise has non-Gaussian distribution (e.g., uniform [-1,1]), the statistical properties of the O-U process will be incorrect. The asymptotic variance Var_∞ = σ²/(2θ) assumes Gaussian noise.
pub fn is_bistable(alpha: Float, beta: Float) -> Bool
Check if system is in bistable region (delegated to viva_math/cusp) Uses validated formula: Δ = -4α³ - 27β² > 0
pub fn tick(
state: pad.Pad,
config: DynamicsConfig,
dt: Float,
) -> #(pad.Pad, Bool)
Full dynamics tick: evolve + check cusp (deterministic)
pub fn tick_with_noise(
state: pad.Pad,
config: DynamicsConfig,
dt: Float,
noise: pad.Pad,
) -> #(pad.Pad, Bool)
Full dynamics tick with noise injection Pass pad.neutral() as noise for deterministic/reproducible behavior