diff --git a/src/agent.rs b/src/agent.rs index 22edda7..43bdcff 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -1,5 +1,6 @@ use crate::{gaussian::Gaussian, player::Player, N_INF}; +#[derive(Debug)] pub(crate) struct Agent { pub(crate) player: Player, pub(crate) message: Gaussian, diff --git a/src/batch.rs b/src/batch.rs index b89a943..1a87e8e 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -4,6 +4,7 @@ use crate::{ agent::Agent, game::Game, gaussian::Gaussian, player::Player, tuple_gt, tuple_max, N_INF, }; +#[derive(Debug)] pub(crate) struct Skill { pub(crate) forward: Gaussian, backward: Gaussian, @@ -52,7 +53,8 @@ impl Event { } } -pub(crate) struct Batch { +#[derive(Debug)] +pub struct Batch { pub(crate) events: Vec, pub(crate) skills: HashMap, pub(crate) time: u64, @@ -220,7 +222,7 @@ impl Batch { self.iteration(from, agents); } - pub(crate) fn posterior(&self, agent: &str) -> Gaussian { + pub fn posterior(&self, agent: &str) -> Gaussian { let skill = &self.skills[agent]; skill.likelihood * skill.backward * skill.forward diff --git a/src/game.rs b/src/game.rs index a5dc8dc..fdb2097 100644 --- a/src/game.rs +++ b/src/game.rs @@ -227,6 +227,8 @@ impl Game { #[cfg(test)] mod tests { + use ::approx::assert_ulps_eq; + use crate::{Gaussian, Player, GAMMA}; use super::*; @@ -406,4 +408,97 @@ mod tests { assert_eq!(c.mu, 28.555920328820527); assert_eq!(c.sigma, 1.8856891308577184); } + + #[test] + fn test_1vs1_weighted() { + let w_a = vec![1.0]; + let w_b = vec![2.0]; + + let t_a = vec![Player::new( + Gaussian::new(25.0, 25.0 / 3.0), + 25.0 / 6.0, + 0.0, + )]; + let t_b = vec![Player::new( + Gaussian::new(25.0, 25.0 / 3.0), + 25.0 / 6.0, + 0.0, + )]; + + let g = Game::new(vec![t_a.clone(), t_b.clone()], vec![], vec![w_a, w_b], 0.0); + let p = g.posteriors(); + + assert_ulps_eq!( + p[0][0], + Gaussian::new(30.625173, 7.765472), + epsilon = 0.000001 + ); + assert_ulps_eq!( + p[1][0], + Gaussian::new(13.749653, 5.733840), + epsilon = 0.000001 + ); + + let w_a = vec![1.0]; + let w_b = vec![0.7]; + + let g = Game::new(vec![t_a.clone(), t_b.clone()], vec![], vec![w_a, w_b], 0.0); + let p = g.posteriors(); + + assert_ulps_eq!( + p[0][0], + Gaussian::new(27.630080, 7.206676), + epsilon = 0.000001 + ); + assert_ulps_eq!( + p[1][0], + Gaussian::new(23.158943, 7.801628), + epsilon = 0.000001 + ); + + let w_a = vec![1.6]; + let w_b = vec![0.7]; + + let g = Game::new(vec![t_a, t_b], vec![], vec![w_a, w_b], 0.0); + let p = g.posteriors(); + + assert_ulps_eq!( + p[0][0], + Gaussian::new(26.142438, 7.573088), + epsilon = 0.000001 + ); + assert_ulps_eq!( + p[1][0], + Gaussian::new(24.500183, 8.193278), + epsilon = 0.000001 + ); + + let w_a = vec![1.0]; + let w_b = vec![0.0]; + + let t_a = vec![Player::new(Gaussian::new(2.0, 6.0), 1.0, 0.0)]; + let t_b = vec![Player::new(Gaussian::new(2.0, 6.0), 1.0, 0.0)]; + + let g = Game::new(vec![t_a, t_b], vec![], vec![w_a, w_b], 0.0); + let p = g.posteriors(); + + assert_ulps_eq!( + p[0][0], + Gaussian::new(5.557176746, 4.0527906913), + epsilon = 0.000001 + ); + assert_ulps_eq!(p[1][0], Gaussian::new(2.0, 6.0), epsilon = 0.000001); + // NOTA: trueskill original tiene probelmas en la aproximación: post[2][1].mu = 1.999644 + + let w_a = vec![1.0]; + let w_b = vec![-1.0]; + + let t_a = vec![Player::new(Gaussian::new(2.0, 6.0), 1.0, 0.0)]; + let t_b = vec![Player::new(Gaussian::new(2.0, 6.0), 1.0, 0.0)]; + + let g = Game::new(vec![t_a, t_b], vec![], vec![w_a, w_b], 0.0); + let p = g.posteriors(); + + assert_ulps_eq!(p[0][0], p[0][0], epsilon = 0.000001); + } } diff --git a/src/history.rs b/src/history.rs index 485ed70..0a29eff 100644 --- a/src/history.rs +++ b/src/history.rs @@ -10,7 +10,7 @@ use crate::{ pub struct History { size: usize, - batches: Vec, + pub batches: Vec, agents: HashMap, time: bool, mu: f64, @@ -445,7 +445,7 @@ impl History { while self.time && self.batches.len() > k { let b = &mut self.batches[k]; - b.new_backward_info(&mut self.agents); + b.new_forward_info(&mut self.agents); let intersect = this_agent .iter() @@ -1029,5 +1029,98 @@ mod tests { h.batches[0].posterior("b"), epsilon = 0.000001 ); + + // --------------------------------------- + + let composition = vec![ + vec![vec!["a"], vec!["b"]], + vec![vec!["c"], vec!["a"]], + vec![vec!["b"], vec!["c"]], + ]; + + let mut h = History::new( + composition.clone(), + vec![], + vec![0, 10, 20], + vec![], + HashMap::new(), + 0.0, + 2.0, + 1.0, + 0.0, + 0.0, + false, + ); + + h.convergence(ITERATIONS, EPSILON, false); + + h.add_events(composition, vec![], vec![15, 10, 0], vec![], HashMap::new()); + + assert_eq!(h.batches.len(), 4); + + assert_eq!( + h.batches + .iter() + .map(|batch| batch.events.len()) + .collect::>(), + vec![2, 2, 1, 1] + ); + + assert_eq!( + h.batches + .iter() + .map(|b| b.get_composition()) + .collect::>(), + vec![ + vec![vec![vec!["a"], vec!["b"]], vec![vec!["b"], vec!["c"]]], + vec![vec![vec!["c"], vec!["a"]], vec![vec!["c"], vec!["a"]]], + vec![vec![vec!["a"], vec!["b"]]], + vec![vec![vec!["b"], vec!["c"]]] + ] + ); + + assert_eq!( + h.batches + .iter() + .map(|b| b.get_results()) + .collect::>(), + vec![ + vec![vec![1.0, 0.0], vec![1.0, 0.0]], + vec![vec![1.0, 0.0], vec![1.0, 0.0]], + vec![vec![1.0, 0.0]], + vec![vec![1.0, 0.0]] + ] + ); + + let end = h.batches.len() - 1; + + assert_eq!(h.batches[0].skills["c"].elapsed, 0); + assert_eq!(h.batches[end].skills["c"].elapsed, 10); + + assert_eq!(h.batches[0].skills["a"].elapsed, 0); + assert_eq!(h.batches[2].skills["a"].elapsed, 5); + + assert_eq!(h.batches[0].skills["b"].elapsed, 0); + assert_eq!(h.batches[end].skills["b"].elapsed, 5); + + h.convergence(ITERATIONS, EPSILON, false); + + assert_ulps_eq!( + h.batches[0].posterior("b"), + h.batches[end].posterior("b"), + epsilon = 0.000001 + ); + + assert_ulps_eq!( + h.batches[0].posterior("c"), + h.batches[end].posterior("c"), + epsilon = 0.000001 + ); + + assert_ulps_eq!( + h.batches[0].posterior("c"), + h.batches[0].posterior("b"), + epsilon = 0.000001 + ); } }