Port from julia version instead
This commit is contained in:
437
src/history.rs
437
src/history.rs
@@ -1,54 +1,76 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use crate::{utils, Agent, Batch, Gaussian, Player, PlayerIndex, N_INF};
|
||||
use crate::{
|
||||
agent::{self, Agent},
|
||||
batch::Batch,
|
||||
gaussian::Gaussian,
|
||||
player::Player,
|
||||
sort_time, tuple_gt, tuple_max,
|
||||
};
|
||||
|
||||
pub struct History {
|
||||
size: usize,
|
||||
batches: Vec<Batch>,
|
||||
agents: HashMap<PlayerIndex, Agent>,
|
||||
// mu: f64,
|
||||
// sigma: f64,
|
||||
// beta: f64,
|
||||
// gamma: f64,
|
||||
p_draw: f64,
|
||||
agents: HashMap<String, Agent>,
|
||||
time: bool,
|
||||
pub epsilon: f64,
|
||||
pub iterations: usize,
|
||||
pub verbose: bool,
|
||||
mu: f64,
|
||||
sigma: f64,
|
||||
beta: f64,
|
||||
gamma: f64,
|
||||
p_draw: f64,
|
||||
online: bool,
|
||||
weights: Vec<Vec<Vec<f64>>>,
|
||||
epsilon: f64,
|
||||
iterations: usize,
|
||||
}
|
||||
|
||||
impl History {
|
||||
pub fn new(
|
||||
composition: &[Vec<Vec<PlayerIndex>>],
|
||||
results: &[Vec<u16>],
|
||||
times: &[f64],
|
||||
priors: HashMap<PlayerIndex, Player>,
|
||||
composition: Vec<Vec<Vec<&str>>>,
|
||||
results: Vec<Vec<f64>>,
|
||||
times: Vec<u64>,
|
||||
weights: Vec<Vec<Vec<f64>>>,
|
||||
priors: HashMap<String, Player>,
|
||||
mu: f64,
|
||||
sigma: f64,
|
||||
beta: f64,
|
||||
gamma: f64,
|
||||
p_draw: f64,
|
||||
online: bool,
|
||||
) -> Self {
|
||||
assert!(
|
||||
results.is_empty() || results.len() == composition.len(),
|
||||
"TODO: Add a comment here"
|
||||
);
|
||||
assert!(
|
||||
times.is_empty() || times.len() == composition.len(),
|
||||
"TODO: Add a comment here"
|
||||
);
|
||||
assert!(
|
||||
weights.is_empty() || weights.len() == composition.len(),
|
||||
"TODO: Add a comment here"
|
||||
);
|
||||
|
||||
let this_agent = composition
|
||||
.iter()
|
||||
.flatten()
|
||||
.flatten()
|
||||
.cloned()
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
let agents = this_agent
|
||||
.into_iter()
|
||||
.map(|a| {
|
||||
.map(|agent| {
|
||||
let player = priors
|
||||
.get(a)
|
||||
.get(agent)
|
||||
.cloned()
|
||||
.unwrap_or_else(|| Player::new(Gaussian::new(mu, sigma), beta, gamma, N_INF));
|
||||
.unwrap_or_else(|| Player::new(Gaussian::new(mu, sigma), beta, gamma));
|
||||
|
||||
(
|
||||
*a,
|
||||
agent.to_string(),
|
||||
Agent {
|
||||
player,
|
||||
message: N_INF,
|
||||
last_time: f64::NEG_INFINITY,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
})
|
||||
@@ -58,41 +80,45 @@ impl History {
|
||||
size: composition.len(),
|
||||
batches: Vec::new(),
|
||||
agents,
|
||||
p_draw,
|
||||
time: !times.is_empty(),
|
||||
epsilon: 1e-6,
|
||||
iterations: 30,
|
||||
verbose: true,
|
||||
mu,
|
||||
sigma,
|
||||
beta,
|
||||
gamma,
|
||||
p_draw,
|
||||
online,
|
||||
weights: weights.clone(),
|
||||
epsilon: 0.0,
|
||||
iterations: 10,
|
||||
};
|
||||
|
||||
this.trueskill(composition, results, times);
|
||||
this.trueskill(composition, results, times, weights, online);
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
fn trueskill(
|
||||
&mut self,
|
||||
composition: &[Vec<Vec<PlayerIndex>>],
|
||||
results: &[Vec<u16>],
|
||||
times: &[f64],
|
||||
composition: Vec<Vec<Vec<&str>>>,
|
||||
results: Vec<Vec<f64>>,
|
||||
times: Vec<u64>,
|
||||
weights: Vec<Vec<Vec<f64>>>,
|
||||
online: bool,
|
||||
) {
|
||||
let o = if self.time {
|
||||
utils::sort_time(times)
|
||||
sort_time(×, false)
|
||||
} else {
|
||||
(0..composition.len()).collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
let mut i = 0;
|
||||
let mut last = 0.0;
|
||||
|
||||
while i < self.size {
|
||||
let mut j = i + 1;
|
||||
let time = if self.time {
|
||||
times[o[i]]
|
||||
} else {
|
||||
i as f64 + 1.0
|
||||
};
|
||||
let t = if self.time { times[o[i]] } else { i as u64 + 1 };
|
||||
|
||||
while self.time && j < self.size && times[o[j]] == time {
|
||||
while self.time && j < self.size && times[o[j]] == t {
|
||||
j += 1;
|
||||
}
|
||||
|
||||
@@ -100,30 +126,67 @@ impl History {
|
||||
.map(|e| composition[o[e]].clone())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let results = (i..j).map(|e| results[o[e]].clone()).collect::<Vec<_>>();
|
||||
let results = if results.is_empty() {
|
||||
Vec::new()
|
||||
} else {
|
||||
(i..j).map(|e| results[o[e]].clone()).collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
let b = Batch::new(composition, results, time, &mut self.agents, self.p_draw);
|
||||
let weights = if weights.is_empty() {
|
||||
Vec::new()
|
||||
} else {
|
||||
(i..j).map(|e| weights[o[e]].clone()).collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
let b = Batch::new(
|
||||
composition,
|
||||
results,
|
||||
weights,
|
||||
t,
|
||||
self.p_draw,
|
||||
&mut self.agents,
|
||||
);
|
||||
|
||||
self.batches.push(b);
|
||||
|
||||
let idx = self.batches.len() - 1;
|
||||
|
||||
if online {
|
||||
let new = 100.0 * (i as f64 / self.size as f64);
|
||||
|
||||
if new != last {
|
||||
println!("{:.02}%", new);
|
||||
last = new;
|
||||
}
|
||||
|
||||
for skill in self.batches[idx].skills.values_mut() {
|
||||
skill.online = skill.forward;
|
||||
}
|
||||
|
||||
self.convergence(self.iterations, self.epsilon, false);
|
||||
}
|
||||
|
||||
let b = &mut self.batches[idx];
|
||||
|
||||
for a in b.skills.keys() {
|
||||
let agent = self.agents.get_mut(a).unwrap();
|
||||
|
||||
agent.last_time = if self.time { time } else { f64::INFINITY };
|
||||
agent.last_time = if self.time { t } else { u64::MAX };
|
||||
agent.message = b.forward_prior_out(a);
|
||||
}
|
||||
|
||||
i = j;
|
||||
}
|
||||
|
||||
if online {
|
||||
println!("100.00%");
|
||||
}
|
||||
}
|
||||
|
||||
fn iteration(&mut self) -> (f64, f64) {
|
||||
let mut step = (0.0, 0.0);
|
||||
|
||||
clean(self.agents.values_mut(), false);
|
||||
agent::clean(self.agents.values_mut(), false);
|
||||
|
||||
for j in (0..self.batches.len() - 1).rev() {
|
||||
for agent in self.batches[j + 1].skills.keys() {
|
||||
@@ -142,7 +205,7 @@ impl History {
|
||||
.fold(step, |step, (a, old)| tuple_max(step, old.delta(new[a])));
|
||||
}
|
||||
|
||||
clean(self.agents.values_mut(), false);
|
||||
agent::clean(self.agents.values_mut(), false);
|
||||
|
||||
for j in 1..self.batches.len() {
|
||||
for agent in self.batches[j - 1].skills.keys() {
|
||||
@@ -164,7 +227,7 @@ impl History {
|
||||
if self.batches.len() == 1 {
|
||||
let old = self.batches[0].posteriors();
|
||||
|
||||
self.batches[0].convergence(&mut self.agents);
|
||||
self.batches[0].iteration(0, &mut self.agents);
|
||||
|
||||
let new = self.batches[0].posteriors();
|
||||
|
||||
@@ -176,12 +239,17 @@ impl History {
|
||||
step
|
||||
}
|
||||
|
||||
pub fn convergence(&mut self) -> ((f64, f64), usize) {
|
||||
pub fn convergence(
|
||||
&mut self,
|
||||
iterations: usize,
|
||||
epsilon: f64,
|
||||
verbose: bool,
|
||||
) -> ((f64, f64), usize) {
|
||||
let mut step = (f64::INFINITY, f64::INFINITY);
|
||||
let mut i = 0;
|
||||
|
||||
while (step.0 > self.epsilon || step.1 > self.epsilon) && i < self.iterations {
|
||||
if self.verbose {
|
||||
while tuple_gt(step, epsilon) && i < iterations {
|
||||
if verbose {
|
||||
print!("Iteration = {}", i);
|
||||
}
|
||||
|
||||
@@ -189,20 +257,20 @@ impl History {
|
||||
|
||||
i += 1;
|
||||
|
||||
if self.verbose {
|
||||
if verbose {
|
||||
println!(", step = {:?}", step);
|
||||
}
|
||||
}
|
||||
|
||||
if self.verbose {
|
||||
if verbose {
|
||||
println!("End");
|
||||
}
|
||||
|
||||
(step, i)
|
||||
}
|
||||
|
||||
pub fn learning_curves(&self) -> HashMap<PlayerIndex, Vec<(f64, Gaussian)>> {
|
||||
let mut data: HashMap<PlayerIndex, Vec<(f64, Gaussian)>> = HashMap::new();
|
||||
pub fn learning_curves(&self) -> HashMap<String, Vec<(u64, Gaussian)>> {
|
||||
let mut data: HashMap<String, Vec<(u64, Gaussian)>> = HashMap::new();
|
||||
|
||||
for b in &self.batches {
|
||||
for agent in b.skills.keys() {
|
||||
@@ -211,266 +279,234 @@ impl History {
|
||||
if let Some(entry) = data.get_mut(agent) {
|
||||
entry.push(point);
|
||||
} else {
|
||||
data.insert(*agent, vec![point]);
|
||||
data.insert(agent.to_string(), vec![point]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data
|
||||
}
|
||||
|
||||
pub fn log_evidence(&self) -> f64 {
|
||||
self.batches
|
||||
.iter()
|
||||
.flat_map(|batch| batch.events.iter())
|
||||
.map(|event| event.evidence.ln())
|
||||
.sum()
|
||||
}
|
||||
}
|
||||
|
||||
fn clean<'a, A: Iterator<Item = &'a mut Agent>>(agents: A, last_time: bool) {
|
||||
for a in agents {
|
||||
a.message = N_INF;
|
||||
|
||||
if last_time {
|
||||
a.last_time = f64::NEG_INFINITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tuple_max(a: (f64, f64), b: (f64, f64)) -> (f64, f64) {
|
||||
(
|
||||
if a.0 > b.0 { a.0 } else { b.0 },
|
||||
if a.1 > b.1 { a.1 } else { b.1 },
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use approx::assert_ulps_eq;
|
||||
|
||||
use crate::{Game, BETA, GAMMA, MU, P_DRAW, SIGMA};
|
||||
use crate::{Game, Player, BETA, EPSILON, GAMMA, ITERATIONS, MU, P_DRAW, SIGMA};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_init() {
|
||||
let a = PlayerIndex::new(0);
|
||||
let b = PlayerIndex::new(1);
|
||||
let c = PlayerIndex::new(2);
|
||||
|
||||
let composition = vec![
|
||||
vec![vec![a], vec![b]],
|
||||
vec![vec![a], vec![c]],
|
||||
vec![vec![b], vec![c]],
|
||||
vec![vec!["a"], vec!["b"]],
|
||||
vec![vec!["a"], vec!["c"]],
|
||||
vec![vec!["b"], vec!["c"]],
|
||||
];
|
||||
let results = vec![vec![1, 0], vec![0, 1], vec![1, 0]];
|
||||
let results = vec![vec![1.0, 0.0], vec![0.0, 1.0], vec![1.0, 0.0]];
|
||||
|
||||
let mut priors = HashMap::new();
|
||||
|
||||
for k in [a, b, c] {
|
||||
let player = Player::new(
|
||||
Gaussian::new(25.0, 25.0 / 3.0),
|
||||
25.0 / 6.0,
|
||||
0.15 * 25.0 / 3.0,
|
||||
N_INF,
|
||||
for agent in ["a", "b", "c"] {
|
||||
priors.insert(
|
||||
agent.to_string(),
|
||||
Player::new(
|
||||
Gaussian::new(25.0, 25.0 / 3.0),
|
||||
25.0 / 6.0,
|
||||
0.15 * 25.0 / 3.0,
|
||||
),
|
||||
);
|
||||
|
||||
priors.insert(k, player);
|
||||
}
|
||||
|
||||
let mut h = History::new(
|
||||
&composition,
|
||||
&results,
|
||||
&[1.0, 2.0, 3.0],
|
||||
composition,
|
||||
results,
|
||||
vec![1, 2, 3],
|
||||
vec![],
|
||||
priors,
|
||||
MU,
|
||||
BETA,
|
||||
SIGMA,
|
||||
BETA,
|
||||
GAMMA,
|
||||
P_DRAW,
|
||||
false,
|
||||
);
|
||||
|
||||
let p0 = h.batches[0].posteriors();
|
||||
|
||||
assert_ulps_eq!(p0[&a].mu(), 29.205220743876975, epsilon = 0.000001);
|
||||
assert_ulps_eq!(p0[&a].sigma(), 7.194481422570443, epsilon = 0.000001);
|
||||
assert_ulps_eq!(p0["a"].mu, 29.205220743876975, epsilon = 0.000001);
|
||||
assert_ulps_eq!(p0["a"].sigma, 7.194481422570443, epsilon = 0.000001);
|
||||
|
||||
let observed = h.batches[1].skills[&a].forward.sigma();
|
||||
let observed = h.batches[1].skills["a"].forward.sigma;
|
||||
let gamma: f64 = 0.15 * 25.0 / 3.0;
|
||||
let expected = (gamma.powi(2) + h.batches[0].posterior(&a).sigma().powi(2)).sqrt();
|
||||
let expected = (gamma.powi(2) + h.batches[0].posterior("a").sigma.powi(2)).sqrt();
|
||||
|
||||
assert_ulps_eq!(observed, expected, epsilon = 0.000001);
|
||||
|
||||
let observed = h.batches[1].posterior(&a);
|
||||
let observed = h.batches[1].posterior("a");
|
||||
let p = Game::new(
|
||||
h.batches[1].within_priors(0, &mut h.agents),
|
||||
vec![0, 1],
|
||||
h.batches[1].within_priors(0, false, false, &mut h.agents),
|
||||
vec![0.0, 1.0],
|
||||
vec![],
|
||||
P_DRAW,
|
||||
)
|
||||
.posteriors();
|
||||
let expected = p[0][0];
|
||||
|
||||
assert_ulps_eq!(observed.mu(), expected.mu(), epsilon = 0.000001);
|
||||
assert_ulps_eq!(observed.sigma(), expected.sigma(), epsilon = 0.000001);
|
||||
assert_ulps_eq!(observed.mu, expected.mu, epsilon = 0.000001);
|
||||
assert_ulps_eq!(observed.sigma, expected.sigma, epsilon = 0.000001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_one_batch() {
|
||||
let a = PlayerIndex::new(0);
|
||||
let b = PlayerIndex::new(1);
|
||||
let c = PlayerIndex::new(2);
|
||||
|
||||
let composition = vec![
|
||||
vec![vec![a], vec![b]],
|
||||
vec![vec![b], vec![c]],
|
||||
vec![vec![c], vec![a]],
|
||||
vec![vec!["a"], vec!["b"]],
|
||||
vec![vec!["b"], vec!["c"]],
|
||||
vec![vec!["c"], vec!["a"]],
|
||||
];
|
||||
let results = vec![vec![1, 0], vec![1, 0], vec![1, 0]];
|
||||
let times = vec![1.0, 1.0, 1.0];
|
||||
let results = vec![vec![1.0, 0.0], vec![1.0, 0.0], vec![1.0, 0.0]];
|
||||
let times = vec![1, 1, 1];
|
||||
|
||||
let mut priors = HashMap::new();
|
||||
|
||||
for k in [a, b, c] {
|
||||
for k in ["a", "b", "c"] {
|
||||
let player = Player::new(
|
||||
Gaussian::new(25.0, 25.0 / 3.0),
|
||||
25.0 / 6.0,
|
||||
0.15 * 25.0 / 3.0,
|
||||
N_INF,
|
||||
);
|
||||
|
||||
priors.insert(k, player);
|
||||
priors.insert(k.to_string(), player);
|
||||
}
|
||||
|
||||
let mut h1 = History::new(
|
||||
&composition,
|
||||
&results,
|
||||
×,
|
||||
composition,
|
||||
results,
|
||||
times,
|
||||
vec![],
|
||||
priors,
|
||||
MU,
|
||||
BETA,
|
||||
SIGMA,
|
||||
BETA,
|
||||
GAMMA,
|
||||
P_DRAW,
|
||||
false,
|
||||
);
|
||||
|
||||
assert_ulps_eq!(
|
||||
h1.batches[0].posterior(&a).mu(),
|
||||
h1.batches[0].posterior("a").mu,
|
||||
22.904409330892914,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h1.batches[0].posterior(&a).sigma(),
|
||||
h1.batches[0].posterior("a").sigma,
|
||||
6.0103304390431,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h1.batches[0].posterior(&c).mu(),
|
||||
h1.batches[0].posterior("c").mu,
|
||||
25.110318212568806,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h1.batches[0].posterior(&c).sigma(),
|
||||
h1.batches[0].posterior("c").sigma,
|
||||
5.866311348102563,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
|
||||
let (_step, _i) = h1.convergence();
|
||||
let (_step, _i) = h1.convergence(ITERATIONS, EPSILON, false);
|
||||
|
||||
assert_ulps_eq!(
|
||||
h1.batches[0].posterior(&a).mu(),
|
||||
h1.batches[0].posterior("a").mu,
|
||||
25.00000000,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h1.batches[0].posterior(&a).sigma(),
|
||||
h1.batches[0].posterior("a").sigma,
|
||||
5.41921200,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h1.batches[0].posterior(&c).mu(),
|
||||
h1.batches[0].posterior("c").mu,
|
||||
25.00000000,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h1.batches[0].posterior(&c).sigma(),
|
||||
h1.batches[0].posterior("c").sigma,
|
||||
5.41921200,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
|
||||
let composition = vec![
|
||||
vec![vec![a], vec![b]],
|
||||
vec![vec![b], vec![c]],
|
||||
vec![vec![c], vec![a]],
|
||||
vec![vec!["a"], vec!["b"]],
|
||||
vec![vec!["b"], vec!["c"]],
|
||||
vec![vec!["c"], vec!["a"]],
|
||||
];
|
||||
let results = vec![vec![1, 0], vec![1, 0], vec![1, 0]];
|
||||
let times = vec![1.0, 2.0, 3.0];
|
||||
let results = vec![vec![1.0, 0.0], vec![1.0, 0.0], vec![1.0, 0.0]];
|
||||
let times = vec![1, 2, 3];
|
||||
|
||||
let mut priors = HashMap::new();
|
||||
|
||||
for k in [a, b, c] {
|
||||
let player = Player::new(
|
||||
Gaussian::new(25.0, 25.0 / 3.0),
|
||||
25.0 / 6.0,
|
||||
25.0 / 300.0,
|
||||
N_INF,
|
||||
);
|
||||
for k in ["a", "b", "c"] {
|
||||
let player = Player::new(Gaussian::new(25.0, 25.0 / 3.0), 25.0 / 6.0, 25.0 / 300.0);
|
||||
|
||||
priors.insert(k, player);
|
||||
priors.insert(k.to_string(), player);
|
||||
}
|
||||
|
||||
let mut h2 = History::new(
|
||||
&composition,
|
||||
&results,
|
||||
×,
|
||||
composition,
|
||||
results,
|
||||
times,
|
||||
vec![],
|
||||
priors,
|
||||
MU,
|
||||
BETA,
|
||||
SIGMA,
|
||||
BETA,
|
||||
GAMMA,
|
||||
P_DRAW,
|
||||
false,
|
||||
);
|
||||
|
||||
assert_ulps_eq!(
|
||||
h2.batches[2].posterior(&a).mu(),
|
||||
h2.batches[2].posterior("a").mu,
|
||||
22.90352227792141,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h2.batches[2].posterior(&a).sigma(),
|
||||
h2.batches[2].posterior("a").sigma,
|
||||
6.011017301320632,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h2.batches[2].posterior(&c).mu(),
|
||||
h2.batches[2].posterior("c").mu,
|
||||
25.110702468366718,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h2.batches[2].posterior(&c).sigma(),
|
||||
h2.batches[2].posterior("c").sigma,
|
||||
5.866811597660157,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
|
||||
let (_step, _i) = h2.convergence();
|
||||
let (_step, _i) = h2.convergence(ITERATIONS, EPSILON, false);
|
||||
|
||||
assert_ulps_eq!(
|
||||
h2.batches[2].posterior(&a).mu(),
|
||||
h2.batches[2].posterior("a").mu,
|
||||
24.99866831022851,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h2.batches[2].posterior(&a).sigma(),
|
||||
h2.batches[2].posterior("a").sigma,
|
||||
5.420053708148435,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h2.batches[2].posterior(&c).mu(),
|
||||
h2.batches[2].posterior("c").mu,
|
||||
25.000532179593538,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h2.batches[2].posterior(&c).sigma(),
|
||||
h2.batches[2].posterior("c").sigma,
|
||||
5.419827012784138,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
@@ -478,70 +514,63 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_learning_curves() {
|
||||
let a = PlayerIndex::new(0);
|
||||
let b = PlayerIndex::new(1);
|
||||
let c = PlayerIndex::new(2);
|
||||
|
||||
let composition = vec![
|
||||
vec![vec![a], vec![b]],
|
||||
vec![vec![b], vec![c]],
|
||||
vec![vec![c], vec![a]],
|
||||
vec![vec!["a"], vec!["b"]],
|
||||
vec![vec!["b"], vec!["c"]],
|
||||
vec![vec!["c"], vec!["a"]],
|
||||
];
|
||||
let results = vec![vec![1, 0], vec![1, 0], vec![1, 0]];
|
||||
let times = vec![5.0, 6.0, 7.0];
|
||||
let results = vec![vec![1.0, 0.0], vec![1.0, 0.0], vec![1.0, 0.0]];
|
||||
let times = vec![5, 6, 7];
|
||||
|
||||
let mut priors = HashMap::new();
|
||||
|
||||
for k in [a, b, c] {
|
||||
let player = Player::new(
|
||||
Gaussian::new(25.0, 25.0 / 3.0),
|
||||
25.0 / 6.0,
|
||||
25.0 / 300.0,
|
||||
N_INF,
|
||||
);
|
||||
for k in ["a", "b", "c"] {
|
||||
let player = Player::new(Gaussian::new(25.0, 25.0 / 3.0), 25.0 / 6.0, 25.0 / 300.0);
|
||||
|
||||
priors.insert(k, player);
|
||||
priors.insert(k.to_string(), player);
|
||||
}
|
||||
|
||||
let mut h = History::new(
|
||||
&composition,
|
||||
&results,
|
||||
×,
|
||||
composition,
|
||||
results,
|
||||
times,
|
||||
vec![],
|
||||
priors,
|
||||
MU,
|
||||
BETA,
|
||||
SIGMA,
|
||||
BETA,
|
||||
GAMMA,
|
||||
P_DRAW,
|
||||
false,
|
||||
);
|
||||
|
||||
h.convergence();
|
||||
h.convergence(ITERATIONS, EPSILON, false);
|
||||
|
||||
let lc = h.learning_curves();
|
||||
|
||||
let aj_e = lc[&a].len();
|
||||
let cj_e = lc[&c].len();
|
||||
let aj_e = lc["a"].len();
|
||||
let cj_e = lc["c"].len();
|
||||
|
||||
assert_eq!(lc[&a][0].0, 5.0);
|
||||
assert_eq!(lc[&a][aj_e - 1].0, 7.0);
|
||||
assert_eq!(lc["a"][0].0, 5);
|
||||
assert_eq!(lc["a"][aj_e - 1].0, 7);
|
||||
|
||||
assert_ulps_eq!(
|
||||
lc[&a][aj_e - 1].1.mu(),
|
||||
lc["a"][aj_e - 1].1.mu,
|
||||
24.99866831022851,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
lc[&a][aj_e - 1].1.sigma(),
|
||||
lc["a"][aj_e - 1].1.sigma,
|
||||
5.420053708148435,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
lc[&c][cj_e - 1].1.mu(),
|
||||
lc["c"][cj_e - 1].1.mu,
|
||||
25.000532179593538,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
lc[&c][cj_e - 1].1.sigma(),
|
||||
lc["c"][cj_e - 1].1.sigma,
|
||||
5.419827012784138,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
@@ -549,61 +578,59 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_env_ttt() {
|
||||
let a = PlayerIndex::new(0);
|
||||
let b = PlayerIndex::new(1);
|
||||
let c = PlayerIndex::new(2);
|
||||
|
||||
let composition = vec![
|
||||
vec![vec![a], vec![b]],
|
||||
vec![vec![a], vec![c]],
|
||||
vec![vec![b], vec![c]],
|
||||
vec![vec!["a"], vec!["b"]],
|
||||
vec![vec!["a"], vec!["c"]],
|
||||
vec![vec!["b"], vec!["c"]],
|
||||
];
|
||||
let results = vec![vec![1, 0], vec![0, 1], vec![1, 0]];
|
||||
let results = vec![vec![1.0, 0.0], vec![0.0, 1.0], vec![1.0, 0.0]];
|
||||
|
||||
let mut h = History::new(
|
||||
&composition,
|
||||
&results,
|
||||
&[],
|
||||
composition,
|
||||
results,
|
||||
vec![],
|
||||
vec![],
|
||||
HashMap::new(),
|
||||
25.0,
|
||||
25.0 / 3.0,
|
||||
25.0 / 6.0,
|
||||
25.0 / 300.0,
|
||||
0.0,
|
||||
false,
|
||||
);
|
||||
|
||||
let (_step, _i) = h.convergence();
|
||||
let (_step, _i) = h.convergence(ITERATIONS, EPSILON, false);
|
||||
|
||||
assert_eq!(h.batches[2].skills[&b].elapsed, 1.0);
|
||||
assert_eq!(h.batches[2].skills[&c].elapsed, 1.0);
|
||||
assert_eq!(h.batches[2].skills["b"].elapsed, 1);
|
||||
assert_eq!(h.batches[2].skills["c"].elapsed, 1);
|
||||
|
||||
assert_ulps_eq!(
|
||||
h.batches[0].posterior(&a).mu(),
|
||||
h.batches[0].posterior("a").mu,
|
||||
25.0002673,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h.batches[0].posterior(&a).sigma(),
|
||||
h.batches[0].posterior("a").sigma,
|
||||
5.41938162,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h.batches[0].posterior(&b).mu(),
|
||||
h.batches[0].posterior("b").mu,
|
||||
24.999465,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h.batches[0].posterior(&b).sigma(),
|
||||
h.batches[0].posterior("b").sigma,
|
||||
5.419425831,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h.batches[2].posterior(&b).mu(),
|
||||
h.batches[2].posterior("b").mu,
|
||||
25.00053219,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_ulps_eq!(
|
||||
h.batches[2].posterior(&b).sigma(),
|
||||
h.batches[2].posterior("b").sigma,
|
||||
5.419696790,
|
||||
epsilon = 0.000001
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user