diff --git a/src/lib.rs b/src/lib.rs index ac73872..194ec27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,34 +72,29 @@ fn draw_margin(p: f64, beta: f64, total_players: f64) -> f64 { math::icdf((p + 1.0) / 2.0) * total_players.sqrt() * beta } -pub fn rate(rating_groups: &[(R, u16)], ranks: &[u16]) -> Vec +pub fn rate(ratings: &[(R, u16)], ranks: &[u16]) -> Vec where R: Rateable, { // TODO Validate rating_groups is orderded in teams. // TODO Validate that teams are orderd after rank. - let flatten_ratings = rating_groups - .iter() - .map(|group| &group.0) - .collect::>(); - - let size = flatten_ratings.len(); - let tau_sqr = TAU.powi(2); let beta_sqr = BETA.powi(2); let mut variable_arena = VariableArena::new(); - // --------------------------------------- - - let ratings = rating_groups; - let rating_count = ratings.len(); let team_count = ranks.len(); let rating_vars = (0..rating_count).map(|_| variable_arena.create()).collect::>(); - let perf_vars = (0..rating_count).map(|_| variable_arena.create()).collect::>(); + let perf_vars = ratings + .iter() + .map(|(_, team)| { + (variable_arena.create(), *team) + }) + .collect::>(); + let team_perf_vars = (0..team_count).map(|_| variable_arena.create()).collect::>(); let team_diff_vars = (0..team_count - 1).map(|_| variable_arena.create()).collect::>(); @@ -107,7 +102,7 @@ where let rating_layer = rating_vars .iter() - .zip(flatten_ratings.iter()) + .zip(ratings.iter().map(|(rating, _)| rating)) .map(|(rating_var, rating)| { let gaussian = Gaussian::from_mu_sigma(rating.mu(), (rating.sigma().powi(2) + tau_sqr).sqrt()); @@ -124,7 +119,7 @@ where let perf_layer = rating_vars .iter() - .zip(perf_vars.iter()) + .zip(perf_vars.iter().map(|(variable, _)| variable)) .map(|(rating_var, perf)| { factor_id += 1; @@ -138,165 +133,111 @@ where }) .collect::>(); - // let team_perf_layer = team_perf_vars.iter(); + let team_perf_layer = team_perf_vars + .iter() + .enumerate() + .map(|(i, variable)| { + factor_id += 1; - /* - def build_team_perf_layer(): - for team, team_perf_var in enumerate(team_perf_vars): - if team > 0: - start = team_sizes[team - 1] - else: - start = 0 - end = team_sizes[team] - child_perf_vars = perf_vars[start:end] - coeffs = flatten_weights[start:end] - yield SumFactor(team_perf_var, child_perf_vars, coeffs) - */ + let team = perf_vars + .iter() + .filter(|(_, team)| *team as usize == i) + .map(|(variable, _)| *variable) + .collect::>(); - // --------------------------------------- + let team_count = team.len(); - let mut ss = Vec::new(); - let mut ps = Vec::new(); - let mut ts = Vec::new(); - let mut ds = Vec::new(); + SumFactor::new( + &mut variable_arena, + factor_id, + *variable, + team, + vec![1.0; team_count], + ) + }) + .collect::>(); - for _ in 0..size { - ss.push(variable_arena.create()); - ps.push(variable_arena.create()); - ts.push(variable_arena.create()); - } + let team_diff_layer = team_diff_vars + .iter() + .zip(team_perf_vars.windows(2)) + .map(|(variable, teams)| { + factor_id += 1; - for _ in 0..size - 1 { - ds.push(variable_arena.create()); - } + SumFactor::new( + &mut variable_arena, + factor_id, + *variable, + teams.to_vec(), + vec![1.0, -1.0], + ) - let mut factor_id = 0; - - let mut skill = Vec::new(); - - for (i, rating) in flatten_ratings.iter().enumerate() { - let variable = ss[i]; - let gaussian = - Gaussian::from_mu_sigma(rating.mu(), (rating.sigma().powi(2) + tau_sqr).sqrt()); - - skill.push(PriorFactor::new( - &mut variable_arena, - factor_id, - variable, - gaussian, - )); - - factor_id += 1; - } - - let mut skill_to_perf = Vec::new();; - - for i in 0..size { - skill_to_perf.push(LikelihoodFactor::new( - &mut variable_arena, - factor_id, - ss[i], - ps[i], - beta_sqr, - )); - - factor_id += 1; - } - - let mut perf_to_team = Vec::new();; - - for i in 0..size { - perf_to_team.push(SumFactor::new( - &mut variable_arena, - factor_id, - ts[i], - vec![ps[i]], - vec![1.0], - )); - - factor_id += 1; - } - - let mut team_diff = Vec::new();; - - for i in 0..size - 1 { - team_diff.push(SumFactor::new( - &mut variable_arena, - factor_id, - ds[i], - vec![ts[i], ts[i + 1]], - vec![1.0, -1.0], - )); - - factor_id += 1; - } - - let mut trunc = Vec::new(); + }) + .collect::>(); let epsilon = draw_margin(DRAW_PROBABILITY, BETA, 2.0); - for i in 0..size - 1 { - trunc.push(TruncateFactor::new( - &mut variable_arena, - factor_id, - ds[i], - epsilon, - ranks[i] == ranks[i + 1], - )); + let trunc_layer = team_diff_vars + .iter() + .enumerate() + .map(|(i, variable)| { + factor_id += 1; - factor_id += 1; - } + TruncateFactor::new( + &mut variable_arena, + factor_id, + *variable, + epsilon, + ranks[i] == ranks[i + 1], + ) - for factor in &skill { + }) + .collect::>();; + + for factor in &rating_layer { factor.start(&mut variable_arena); } - for factor in &skill_to_perf { + for factor in &perf_layer { factor.update_value(&mut variable_arena); } - for factor in &perf_to_team { + for factor in &team_perf_layer { factor.update_sum(&mut variable_arena); } for _ in 0..5 { - for factor in &team_diff { + for factor in &team_diff_layer { factor.update_sum(&mut variable_arena); } - for factor in &trunc { + for factor in &trunc_layer { factor.update(&mut variable_arena); } - for factor in &team_diff { + for factor in &team_diff_layer { factor.update_term(&mut variable_arena, 0); factor.update_term(&mut variable_arena, 1); } } - for factor in &perf_to_team { + for factor in &team_perf_layer { factor.update_term(&mut variable_arena, 0); } - for factor in &skill_to_perf { + for factor in &perf_layer { factor.update_mean(&mut variable_arena); } - let mut ratings = Vec::new(); - - for i in 0..size { - let value = variable_arena - .get(ss[i]) - .map(|variable| variable.get_value()) - .unwrap(); - - ratings.push(Rating { - mu: value.mu(), - sigma: value.sigma(), - }); - } - - ratings + rating_vars + .iter() + .map(|variable| variable_arena.get(*variable).unwrap().get_value()) + .map(|value| { + Rating { + mu: value.mu(), + sigma: value.sigma(), + } + }) + .collect::>() } pub fn quality(rating_groups: &[&[R]]) -> f64