pub fn confidence_bound(base: f32, gain: f32, openness: f32) -> f32 {
base + gain * openness
}
pub fn deffuant_step(x_i: f32, x_j: f32, epsilon: f32, mu: f32, weight: f32) -> f32 {
let d = x_j - x_i;
if d.abs() < epsilon {
mu * weight * d
} else {
0.0
}
}
pub fn anchor_step(rate: f32, stubbornness: f32, anchor: f32, x: f32) -> f32 {
rate * stubbornness * (anchor - x)
}
pub fn similarity_affinity_step(gain: f32, d: f32) -> f32 {
gain * (1.0 - d.abs())
}
pub fn conformity_step(
rate_per_day: f32,
agreeableness: f32,
n_in_contact: usize,
dt_days: f32,
group_mean: f32,
x: f32,
) -> f32 {
let n = n_in_contact as f32;
rate_per_day * agreeableness * (n / (n + 3.0)) * dt_days * (group_mean - x)
}
pub fn conformity_applies(group_mean: f32) -> bool {
group_mean.abs() > 0.3
}
pub fn weighted_mean(samples: impl IntoIterator<Item = (f32, f32)>) -> Option<f32> {
let (sum, weight) =
samples
.into_iter()
.fold((0.0_f32, 0.0_f32), |(s, w), (value, affinity)| {
let weight = (affinity + 1.0).max(0.1);
(s + weight * value, w + weight)
});
if weight > 0.0 {
Some(sum / weight)
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn influence_only_inside_the_confidence_bound() {
assert!(deffuant_step(0.1, 0.3, 0.5, 0.3, 1.0) > 0.0);
assert_eq!(deffuant_step(-0.6, 0.6, 0.5, 0.3, 1.0), 0.0);
}
#[test]
fn confidence_grows_with_openness() {
assert!((confidence_bound(0.2, 0.6, 0.5) - 0.5).abs() < 1e-6);
}
#[test]
fn anchor_pulls_stubborn_opinions_back() {
assert!(anchor_step(0.1, 1.0, 0.1, 0.9) < 0.0);
assert_eq!(anchor_step(0.1, 0.0, 0.1, 0.9), 0.0);
}
#[test]
fn disagreement_lowers_affinity() {
assert!(similarity_affinity_step(0.05, 0.1) > 0.0);
assert!(similarity_affinity_step(0.05, 1.5) < 0.0);
}
#[test]
fn weighted_mean_respects_affinity_and_empty_input() {
assert_eq!(weighted_mean(std::iter::empty()), None);
let m = weighted_mean([(1.0, 1.0), (0.0, -1.0)]).unwrap_or(f32::NAN);
assert!((m - 2.0 / 2.1).abs() < 1e-6);
}
#[test]
fn conformity_needs_a_strong_group_mean() {
assert!(conformity_applies(0.5));
assert!(!conformity_applies(0.2));
assert!(conformity_step(0.2, 1.0, 3, 1.0, 0.8, 0.0) > 0.0);
}
}