feat: added a Drift trait and a "default" ConstantDrift implementation

This commit is contained in:
2026-03-16 12:06:04 +01:00
parent 853f177fa8
commit a1f282a1c8
14 changed files with 423 additions and 127 deletions

View File

@@ -1,23 +1,29 @@
use crate::{gaussian::Gaussian, player::Player, N_INF};
use crate::{
N_INF,
drift::{ConstantDrift, Drift},
gaussian::Gaussian,
player::Player,
};
#[derive(Debug)]
pub struct Agent {
pub player: Player,
pub struct Agent<D: Drift = ConstantDrift> {
pub player: Player<D>,
pub message: Gaussian,
pub last_time: i64,
}
impl Agent {
impl<D: Drift> Agent<D> {
pub(crate) fn receive(&self, elapsed: i64) -> Gaussian {
if self.message != N_INF {
self.message.forget(self.player.gamma, elapsed)
self.message
.forget(self.player.drift.variance_delta(elapsed))
} else {
self.player.prior
}
}
}
impl Default for Agent {
impl Default for Agent<ConstantDrift> {
fn default() -> Self {
Self {
player: Player::default(),
@@ -27,7 +33,10 @@ impl Default for Agent {
}
}
pub(crate) fn clean<'a, A: Iterator<Item = &'a mut Agent>>(agents: A, last_time: bool) {
pub(crate) fn clean<'a, D: Drift + 'a, A: Iterator<Item = &'a mut Agent<D>>>(
agents: A,
last_time: bool,
) {
for a in agents {
a.message = N_INF;

View File

@@ -1,7 +1,8 @@
use std::collections::HashMap;
use crate::{
agent::Agent, game::Game, gaussian::Gaussian, player::Player, tuple_gt, tuple_max, Index, N_INF,
Index, N_INF, agent::Agent, drift::Drift, game::Game, gaussian::Gaussian, player::Player,
tuple_gt, tuple_max,
};
#[derive(Debug)]
@@ -38,22 +39,22 @@ struct Item {
}
impl Item {
fn within_prior(
fn within_prior<D: Drift>(
&self,
online: bool,
forward: bool,
skills: &HashMap<Index, Skill>,
agents: &HashMap<Index, Agent>,
) -> Player {
agents: &HashMap<Index, Agent<D>>,
) -> Player<D> {
let r = &agents[&self.agent].player;
let skill = &skills[&self.agent];
if online {
Player::new(skill.online, r.beta, r.gamma)
Player::new(skill.online, r.beta, r.drift)
} else if forward {
Player::new(skill.forward, r.beta, r.gamma)
Player::new(skill.forward, r.beta, r.drift)
} else {
Player::new(skill.posterior() / self.likelihood, r.beta, r.gamma)
Player::new(skill.posterior() / self.likelihood, r.beta, r.drift)
}
}
}
@@ -79,13 +80,13 @@ impl Event {
.collect::<Vec<_>>()
}
pub(crate) fn within_priors(
pub(crate) fn within_priors<D: Drift>(
&self,
online: bool,
forward: bool,
skills: &HashMap<Index, Skill>,
agents: &HashMap<Index, Agent>,
) -> Vec<Vec<Player>> {
agents: &HashMap<Index, Agent<D>>,
) -> Vec<Vec<Player<D>>> {
self.teams
.iter()
.map(|team| {
@@ -116,12 +117,12 @@ impl Batch {
}
}
pub fn add_events(
pub fn add_events<D: Drift>(
&mut self,
composition: Vec<Vec<Vec<Index>>>,
results: Vec<Vec<f64>>,
weights: Vec<Vec<Vec<f64>>>,
agents: &HashMap<Index, Agent>,
agents: &HashMap<Index, Agent<D>>,
) {
let mut unique = Vec::with_capacity(10);
@@ -207,7 +208,7 @@ impl Batch {
.collect::<HashMap<_, _>>()
}
pub fn iteration(&mut self, from: usize, agents: &HashMap<Index, Agent>) {
pub fn iteration<D: Drift>(&mut self, from: usize, agents: &HashMap<Index, Agent<D>>) {
for event in self.events.iter_mut().skip(from) {
let teams = event.within_priors(false, false, &self.skills, agents);
let result = event.outputs();
@@ -229,7 +230,7 @@ impl Batch {
}
#[allow(dead_code)]
pub(crate) fn convergence(&mut self, agents: &HashMap<Index, Agent>) -> usize {
pub(crate) fn convergence<D: Drift>(&mut self, agents: &HashMap<Index, Agent<D>>) -> usize {
let epsilon = 1e-6;
let iterations = 20;
@@ -259,18 +260,18 @@ impl Batch {
skill.forward * skill.likelihood
}
pub(crate) fn backward_prior_out(
pub(crate) fn backward_prior_out<D: Drift>(
&self,
agent: &Index,
agents: &HashMap<Index, Agent>,
agents: &HashMap<Index, Agent<D>>,
) -> Gaussian {
let skill = &self.skills[agent];
let n = skill.likelihood * skill.backward;
n.forget(agents[agent].player.gamma, skill.elapsed)
n.forget(agents[agent].player.drift.variance_delta(skill.elapsed))
}
pub(crate) fn new_backward_info(&mut self, agents: &HashMap<Index, Agent>) {
pub(crate) fn new_backward_info<D: Drift>(&mut self, agents: &HashMap<Index, Agent<D>>) {
for (agent, skill) in self.skills.iter_mut() {
skill.backward = agents[agent].message;
}
@@ -278,7 +279,7 @@ impl Batch {
self.iteration(0, agents);
}
pub(crate) fn new_forward_info(&mut self, agents: &HashMap<Index, Agent>) {
pub(crate) fn new_forward_info<D: Drift>(&mut self, agents: &HashMap<Index, Agent<D>>) {
for (agent, skill) in self.skills.iter_mut() {
skill.forward = agents[agent].receive(skill.elapsed);
}
@@ -286,12 +287,12 @@ impl Batch {
self.iteration(0, agents);
}
pub(crate) fn log_evidence(
pub(crate) fn log_evidence<D: Drift>(
&self,
online: bool,
targets: &[Index],
forward: bool,
agents: &HashMap<Index, Agent>,
agents: &HashMap<Index, Agent<D>>,
) -> f64 {
if targets.is_empty() {
if online || forward {
@@ -390,7 +391,7 @@ pub(crate) fn compute_elapsed(last_time: i64, actual_time: i64) -> i64 {
mod tests {
use approx::assert_ulps_eq;
use crate::{agent::Agent, player::Player, IndexMap};
use crate::{IndexMap, agent::Agent, drift::ConstantDrift, player::Player};
use super::*;
@@ -414,7 +415,7 @@ mod tests {
player: Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
),
..Default::default()
},
@@ -490,7 +491,7 @@ mod tests {
player: Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
),
..Default::default()
},
@@ -569,7 +570,7 @@ mod tests {
player: Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
),
..Default::default()
},

14
src/drift.rs Normal file
View File

@@ -0,0 +1,14 @@
use std::fmt::Debug;
pub trait Drift: Copy + Debug {
fn variance_delta(&self, elapsed: i64) -> f64;
}
#[derive(Clone, Copy, Debug)]
pub struct ConstantDrift(pub f64);
impl Drift for ConstantDrift {
fn variance_delta(&self, elapsed: i64) -> f64 {
elapsed as f64 * self.0 * self.0
}
}

View File

@@ -1,14 +1,16 @@
use crate::{
approx, compute_margin, evidence,
N_INF, N00, approx, compute_margin,
drift::Drift,
evidence,
gaussian::Gaussian,
message::{DiffMessage, TeamMessage},
player::Player,
sort_perm, tuple_gt, tuple_max, N00, N_INF,
sort_perm, tuple_gt, tuple_max,
};
#[derive(Debug)]
pub struct Game<'a> {
teams: Vec<Vec<Player>>,
pub struct Game<'a, D: Drift> {
teams: Vec<Vec<Player<D>>>,
result: &'a [f64],
weights: &'a [Vec<f64>],
p_draw: f64,
@@ -16,9 +18,9 @@ pub struct Game<'a> {
pub(crate) evidence: f64,
}
impl<'a> Game<'a> {
impl<'a, D: Drift> Game<'a, D> {
pub fn new(
teams: Vec<Vec<Player>>,
teams: Vec<Vec<Player<D>>>,
result: &'a [f64],
weights: &'a [Vec<f64>],
p_draw: f64,
@@ -176,7 +178,7 @@ impl<'a> Game<'a> {
.zip(w.iter())
.map(|(p, &w)| {
((m - performance.exclude(p.performance() * w)) * (1.0 / w))
.forget(p.beta, 1)
.forget(p.beta.powi(2))
})
.collect::<Vec<_>>()
})
@@ -201,7 +203,7 @@ impl<'a> Game<'a> {
mod tests {
use ::approx::assert_ulps_eq;
use crate::{Gaussian, Player, GAMMA, N_INF};
use crate::{ConstantDrift, GAMMA, Gaussian, N_INF, Player};
use super::*;
@@ -210,12 +212,12 @@ mod tests {
let t_a = Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
);
let t_b = Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
);
let w = [vec![1.0], vec![1.0]];
@@ -228,8 +230,16 @@ mod tests {
assert_ulps_eq!(a, Gaussian::from_ms(20.794779, 7.194481), epsilon = 1e-6);
assert_ulps_eq!(b, Gaussian::from_ms(29.205220, 7.194481), epsilon = 1e-6);
let t_a = Player::new(Gaussian::from_ms(29.0, 1.0), 25.0 / 6.0, GAMMA);
let t_b = Player::new(Gaussian::from_ms(25.0, 25.0 / 3.0), 25.0 / 6.0, GAMMA);
let t_a = Player::new(
Gaussian::from_ms(29.0, 1.0),
25.0 / 6.0,
ConstantDrift(GAMMA),
);
let t_b = Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
ConstantDrift(GAMMA),
);
let w = [vec![1.0], vec![1.0]];
let g = Game::new(vec![vec![t_a], vec![t_b]], &[0.0, 1.0], &w, 0.0);
@@ -241,8 +251,8 @@ mod tests {
assert_ulps_eq!(a, Gaussian::from_ms(28.896475, 0.996604), epsilon = 1e-6);
assert_ulps_eq!(b, Gaussian::from_ms(32.189211, 6.062063), epsilon = 1e-6);
let t_a = Player::new(Gaussian::from_ms(1.139, 0.531), 1.0, 0.2125);
let t_b = Player::new(Gaussian::from_ms(15.568, 0.51), 1.0, 0.2125);
let t_a = Player::new(Gaussian::from_ms(1.139, 0.531), 1.0, ConstantDrift(0.2125));
let t_b = Player::new(Gaussian::from_ms(15.568, 0.51), 1.0, ConstantDrift(0.2125));
let w = [vec![1.0], vec![1.0]];
let g = Game::new(vec![vec![t_a], vec![t_b]], &[0.0, 1.0], &w, 0.0);
@@ -257,17 +267,17 @@ mod tests {
vec![Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
)],
vec![Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
)],
vec![Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
)],
];
@@ -309,12 +319,12 @@ mod tests {
let t_a = Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
);
let t_b = Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
);
let w = [vec![1.0], vec![1.0]];
@@ -327,8 +337,16 @@ mod tests {
assert_ulps_eq!(a, Gaussian::from_ms(24.999999, 6.469480), epsilon = 1e-6);
assert_ulps_eq!(b, Gaussian::from_ms(24.999999, 6.469480), epsilon = 1e-6);
let t_a = Player::new(Gaussian::from_ms(25.0, 3.0), 25.0 / 6.0, 25.0 / 300.0);
let t_b = Player::new(Gaussian::from_ms(29.0, 2.0), 25.0 / 6.0, 25.0 / 300.0);
let t_a = Player::new(
Gaussian::from_ms(25.0, 3.0),
25.0 / 6.0,
ConstantDrift(25.0 / 300.0),
);
let t_b = Player::new(
Gaussian::from_ms(29.0, 2.0),
25.0 / 6.0,
ConstantDrift(25.0 / 300.0),
);
let w = [vec![1.0], vec![1.0]];
let g = Game::new(vec![vec![t_a], vec![t_b]], &[0.0, 0.0], &w, 0.25);
@@ -346,17 +364,17 @@ mod tests {
let t_a = Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
);
let t_b = Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
);
let t_c = Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
);
let w = [vec![1.0], vec![1.0], vec![1.0]];
@@ -376,9 +394,21 @@ mod tests {
assert_ulps_eq!(b, Gaussian::from_ms(25.000000, 5.707423), epsilon = 1e-6);
assert_ulps_eq!(c, Gaussian::from_ms(24.999999, 5.729068), epsilon = 1e-6);
let t_a = Player::new(Gaussian::from_ms(25.0, 3.0), 25.0 / 6.0, 25.0 / 300.0);
let t_b = Player::new(Gaussian::from_ms(25.0, 3.0), 25.0 / 6.0, 25.0 / 300.0);
let t_c = Player::new(Gaussian::from_ms(29.0, 2.0), 25.0 / 6.0, 25.0 / 300.0);
let t_a = Player::new(
Gaussian::from_ms(25.0, 3.0),
25.0 / 6.0,
ConstantDrift(25.0 / 300.0),
);
let t_b = Player::new(
Gaussian::from_ms(25.0, 3.0),
25.0 / 6.0,
ConstantDrift(25.0 / 300.0),
);
let t_c = Player::new(
Gaussian::from_ms(29.0, 2.0),
25.0 / 6.0,
ConstantDrift(25.0 / 300.0),
);
let w = [vec![1.0], vec![1.0], vec![1.0]];
let g = Game::new(
@@ -401,17 +431,33 @@ mod tests {
#[test]
fn test_2vs1vs2_mixed() {
let t_a = vec![
Player::new(Gaussian::from_ms(12.0, 3.0), 25.0 / 6.0, 25.0 / 300.0),
Player::new(Gaussian::from_ms(18.0, 3.0), 25.0 / 6.0, 25.0 / 300.0),
Player::new(
Gaussian::from_ms(12.0, 3.0),
25.0 / 6.0,
ConstantDrift(25.0 / 300.0),
),
Player::new(
Gaussian::from_ms(18.0, 3.0),
25.0 / 6.0,
ConstantDrift(25.0 / 300.0),
),
];
let t_b = vec![Player::new(
Gaussian::from_ms(30.0, 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
)];
let t_c = vec![
Player::new(Gaussian::from_ms(14.0, 3.0), 25.0 / 6.0, 25.0 / 300.0),
Player::new(Gaussian::from_ms(16., 3.0), 25.0 / 6.0, 25.0 / 300.0),
Player::new(
Gaussian::from_ms(14.0, 3.0),
25.0 / 6.0,
ConstantDrift(25.0 / 300.0),
),
Player::new(
Gaussian::from_ms(16., 3.0),
25.0 / 6.0,
ConstantDrift(25.0 / 300.0),
),
];
let w = [vec![1.0, 1.0], vec![1.0], vec![1.0, 1.0]];
@@ -433,12 +479,12 @@ mod tests {
let t_a = vec![Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
0.0,
ConstantDrift(0.0),
)];
let t_b = vec![Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
0.0,
ConstantDrift(0.0),
)];
let w = [w_a, w_b];
@@ -495,8 +541,16 @@ mod tests {
let w_a = vec![1.0];
let w_b = vec![0.0];
let t_a = vec![Player::new(Gaussian::from_ms(2.0, 6.0), 1.0, 0.0)];
let t_b = vec![Player::new(Gaussian::from_ms(2.0, 6.0), 1.0, 0.0)];
let t_a = vec![Player::new(
Gaussian::from_ms(2.0, 6.0),
1.0,
ConstantDrift(0.0),
)];
let t_b = vec![Player::new(
Gaussian::from_ms(2.0, 6.0),
1.0,
ConstantDrift(0.0),
)];
let w = [w_a, w_b];
let g = Game::new(vec![t_a, t_b], &[1.0, 0.0], &w, 0.0);
@@ -516,8 +570,16 @@ mod tests {
let w_a = vec![1.0];
let w_b = vec![-1.0];
let t_a = vec![Player::new(Gaussian::from_ms(2.0, 6.0), 1.0, 0.0)];
let t_b = vec![Player::new(Gaussian::from_ms(2.0, 6.0), 1.0, 0.0)];
let t_a = vec![Player::new(
Gaussian::from_ms(2.0, 6.0),
1.0,
ConstantDrift(0.0),
)];
let t_b = vec![Player::new(
Gaussian::from_ms(2.0, 6.0),
1.0,
ConstantDrift(0.0),
)];
let w = [w_a, w_b];
let g = Game::new(vec![t_a, t_b], &[1.0, 0.0], &w, 0.0);
@@ -529,14 +591,30 @@ mod tests {
#[test]
fn test_2vs2_weighted() {
let t_a = vec![
Player::new(Gaussian::from_ms(25.0, 25.0 / 3.0), 25.0 / 6.0, 0.0),
Player::new(Gaussian::from_ms(25.0, 25.0 / 3.0), 25.0 / 6.0, 0.0),
Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
ConstantDrift(0.0),
),
Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
ConstantDrift(0.0),
),
];
let w_a = vec![0.4, 0.8];
let t_b = vec![
Player::new(Gaussian::from_ms(25.0, 25.0 / 3.0), 25.0 / 6.0, 0.0),
Player::new(Gaussian::from_ms(25.0, 25.0 / 3.0), 25.0 / 6.0, 0.0),
Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
ConstantDrift(0.0),
),
Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
ConstantDrift(0.0),
),
];
let w_b = vec![0.9, 0.6];
@@ -628,7 +706,7 @@ mod tests {
vec![Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
0.0,
ConstantDrift(0.0),
)],
],
&[1.0, 0.0],

View File

@@ -40,10 +40,10 @@ impl Gaussian {
}
}
pub(crate) fn forget(&self, gamma: f64, t: i64) -> Self {
pub(crate) fn forget(&self, variance_delta: f64) -> Self {
Self {
mu: self.mu,
sigma: (self.sigma.powi(2) + t as f64 * gamma.powi(2)).sqrt(),
sigma: (self.sigma.powi(2) + variance_delta).sqrt(),
}
}
}

View File

@@ -1,25 +1,27 @@
use std::collections::HashMap;
use crate::{
BETA, GAMMA, Index, MU, N_INF, P_DRAW, SIGMA,
agent::{self, Agent},
batch::{self, Batch},
drift::{ConstantDrift, Drift},
gaussian::Gaussian,
player::Player,
sort_time, tuple_gt, tuple_max, Index, BETA, GAMMA, MU, P_DRAW, SIGMA,
sort_time, tuple_gt, tuple_max,
};
#[derive(Clone)]
pub struct HistoryBuilder {
pub struct HistoryBuilder<D: Drift = ConstantDrift> {
time: bool,
mu: f64,
sigma: f64,
beta: f64,
gamma: f64,
drift: D,
p_draw: f64,
online: bool,
}
impl HistoryBuilder {
impl<D: Drift> HistoryBuilder<D> {
pub fn time(mut self, time: bool) -> Self {
self.time = time;
self
@@ -40,9 +42,16 @@ impl HistoryBuilder {
self
}
pub fn gamma(mut self, gamma: f64) -> Self {
self.gamma = gamma;
self
pub fn drift<D2: Drift>(self, drift: D2) -> HistoryBuilder<D2> {
HistoryBuilder {
drift,
time: self.time,
mu: self.mu,
sigma: self.sigma,
beta: self.beta,
p_draw: self.p_draw,
online: self.online,
}
}
pub fn p_draw(mut self, p_draw: f64) -> Self {
@@ -55,7 +64,7 @@ impl HistoryBuilder {
self
}
pub fn build(self) -> History {
pub fn build(self) -> History<D> {
History {
size: 0,
batches: Vec::new(),
@@ -64,41 +73,48 @@ impl HistoryBuilder {
mu: self.mu,
sigma: self.sigma,
beta: self.beta,
gamma: self.gamma,
drift: self.drift,
p_draw: self.p_draw,
online: self.online,
}
}
}
impl Default for HistoryBuilder {
impl HistoryBuilder<ConstantDrift> {
pub fn gamma(mut self, gamma: f64) -> Self {
self.drift = ConstantDrift(gamma);
self
}
}
impl Default for HistoryBuilder<ConstantDrift> {
fn default() -> Self {
Self {
time: true,
mu: MU,
sigma: SIGMA,
beta: BETA,
gamma: GAMMA,
drift: ConstantDrift(GAMMA),
p_draw: P_DRAW,
online: false,
}
}
}
pub struct History {
pub struct History<D: Drift = ConstantDrift> {
size: usize,
pub(crate) batches: Vec<Batch>,
agents: HashMap<Index, Agent>,
agents: HashMap<Index, Agent<D>>,
time: bool,
mu: f64,
sigma: f64,
beta: f64,
gamma: f64,
drift: D,
p_draw: f64,
online: bool,
}
impl Default for History {
impl Default for History<ConstantDrift> {
fn default() -> Self {
Self {
size: 0,
@@ -108,18 +124,20 @@ impl Default for History {
mu: MU,
sigma: SIGMA,
beta: BETA,
gamma: GAMMA,
drift: ConstantDrift(GAMMA),
p_draw: P_DRAW,
online: false,
}
}
}
impl History {
pub fn builder() -> HistoryBuilder {
impl History<ConstantDrift> {
pub fn builder() -> HistoryBuilder<ConstantDrift> {
HistoryBuilder::default()
}
}
impl<D: Drift> History<D> {
fn iteration(&mut self) -> (f64, f64) {
let mut step = (0.0, 0.0);
@@ -247,7 +265,7 @@ impl History {
results: Vec<Vec<f64>>,
times: Vec<i64>,
weights: Vec<Vec<Vec<f64>>>,
mut priors: HashMap<Index, Player>,
mut priors: HashMap<Index, Player<D>>,
) {
assert!(times.is_empty() || self.time, "length(times)>0 but !h.time");
assert!(
@@ -286,10 +304,11 @@ impl History {
Player::new(
Gaussian::from_ms(self.mu, self.sigma),
self.beta,
self.gamma,
self.drift,
)
}),
..Default::default()
message: N_INF,
last_time: i64::MIN,
},
);
}
@@ -414,7 +433,7 @@ impl History {
mod tests {
use approx::assert_ulps_eq;
use crate::{Game, Gaussian, IndexMap, Player, EPSILON, ITERATIONS, P_DRAW};
use crate::{ConstantDrift, EPSILON, Game, Gaussian, ITERATIONS, IndexMap, P_DRAW, Player};
use super::*;
@@ -441,7 +460,7 @@ mod tests {
Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
0.15 * 25.0 / 3.0,
ConstantDrift(0.15 * 25.0 / 3.0),
),
);
}
@@ -503,7 +522,7 @@ mod tests {
Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
0.15 * 25.0 / 3.0,
ConstantDrift(0.15 * 25.0 / 3.0),
),
);
}
@@ -552,7 +571,7 @@ mod tests {
Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
),
);
}
@@ -610,7 +629,7 @@ mod tests {
Player::new(
Gaussian::from_ms(25.0, 25.0 / 3.0),
25.0 / 6.0,
25.0 / 300.0,
ConstantDrift(25.0 / 300.0),
),
);
}

View File

@@ -8,6 +8,7 @@ pub mod agent;
#[cfg(feature = "approx")]
mod approx;
pub mod batch;
pub mod drift;
mod game;
pub mod gaussian;
mod history;
@@ -15,6 +16,7 @@ mod matrix;
mod message;
pub mod player;
pub use drift::{ConstantDrift, Drift};
pub use game::Game;
pub use gaussian::Gaussian;
pub use history::History;

View File

@@ -1,5 +1,4 @@
use crate::gaussian::Gaussian;
use crate::N_INF;
use crate::{N_INF, gaussian::Gaussian};
pub(crate) struct TeamMessage {
pub(crate) prior: Gaussian,

View File

@@ -1,35 +1,32 @@
use crate::{gaussian::Gaussian, BETA, GAMMA};
use crate::{
BETA, GAMMA,
drift::{ConstantDrift, Drift},
gaussian::Gaussian,
};
#[derive(Clone, Copy, Debug)]
pub struct Player {
pub struct Player<D: Drift = ConstantDrift> {
pub(crate) prior: Gaussian,
pub(crate) beta: f64,
pub(crate) gamma: f64,
// pub(crate) draw: Gaussian,
pub(crate) drift: D,
}
impl Player {
pub fn new(prior: Gaussian, beta: f64, gamma: f64) -> Self {
Self {
prior,
beta,
gamma,
// draw: N_INF,
}
impl<D: Drift> Player<D> {
pub fn new(prior: Gaussian, beta: f64, drift: D) -> Self {
Self { prior, beta, drift }
}
pub(crate) fn performance(&self) -> Gaussian {
self.prior.forget(self.beta, 1)
self.prior.forget(self.beta.powi(2))
}
}
impl Default for Player {
impl Default for Player<ConstantDrift> {
fn default() -> Self {
Self {
prior: Gaussian::default(),
beta: BETA,
gamma: GAMMA,
// draw: N_INF,
drift: ConstantDrift(GAMMA),
}
}
}