Remove unnecessary allocations

This commit is contained in:
Anders Olsson
2023-10-24 16:10:40 +02:00
parent 59c256edad
commit d152e356f1
4 changed files with 108 additions and 83 deletions

View File

@@ -51,7 +51,8 @@ fn criterion_benchmark(criterion: &mut Criterion) {
weights.push(vec![vec![1.0], vec![1.0]]);
}
let mut batch = Batch::new(composition, results, weights, 1, P_DRAW, &agents);
let mut batch = Batch::new(1, P_DRAW);
batch.add_events(composition, results, weights, &agents);
criterion.bench_function("Batch::iteration", |b| {
b.iter(|| batch.iteration(0, &agents))

View File

@@ -1,4 +1,4 @@
use std::collections::{HashMap, HashSet};
use std::collections::HashMap;
use crate::{
agent::Agent, game::Game, gaussian::Gaussian, player::Player, tuple_gt, tuple_max, Index, N_INF,
@@ -116,29 +116,34 @@ impl Batch {
}
}
pub(crate) fn add_events(
pub fn add_events(
&mut self,
composition: Vec<Vec<Vec<Index>>>,
results: Vec<Vec<f64>>,
weights: Vec<Vec<Vec<f64>>>,
agents: &HashMap<Index, Agent>,
) {
let this_agent = composition
.iter()
.flatten()
.flatten()
.cloned()
.collect::<HashSet<_>>();
let mut unique = Vec::with_capacity(10);
let this_agent = composition.iter().flatten().flatten().filter(|idx| {
if !unique.contains(idx) {
unique.push(*idx);
return true;
}
false
});
for idx in this_agent {
let elapsed = compute_elapsed(agents[&idx].last_time, self.time);
if let Some(skill) = self.skills.get_mut(&idx) {
if let Some(skill) = self.skills.get_mut(idx) {
skill.elapsed = elapsed;
skill.forward = agents[&idx].receive(elapsed);
} else {
self.skills.insert(
idx,
*idx,
Skill {
forward: agents[&idx].receive(elapsed),
elapsed,
@@ -172,14 +177,19 @@ impl Batch {
})
.collect::<Vec<_>>();
let weights = if weights.is_empty() {
teams
.iter()
.map(|team| vec![1.0; team.items.len()])
.collect::<Vec<_>>()
} else {
weights[e].clone()
};
Event {
teams,
evidence: 0.0,
weights: if weights.is_empty() {
Vec::new()
} else {
weights[e].clone()
},
weights,
}
});
@@ -202,7 +212,7 @@ impl Batch {
let teams = event.within_priors(false, false, &self.skills, agents);
let result = event.outputs();
let g = Game::new(teams, result, event.weights.clone(), self.p_draw);
let g = Game::new(teams, &result, &event.weights, self.p_draw);
for (t, team) in event.teams.iter_mut().enumerate() {
for (i, item) in team.items.iter_mut().enumerate() {
@@ -291,8 +301,8 @@ impl Batch {
.map(|(_, event)| {
Game::new(
event.within_priors(online, forward, &self.skills, agents),
event.outputs(),
event.weights.clone(),
&event.outputs(),
&event.weights,
self.p_draw,
)
.evidence
@@ -316,8 +326,8 @@ impl Batch {
.map(|(_, event)| {
Game::new(
event.within_priors(online, forward, &self.skills, agents),
event.outputs(),
event.weights.clone(),
&event.outputs(),
&event.weights,
self.p_draw,
)
.evidence

View File

@@ -7,39 +7,33 @@ use crate::{
};
#[derive(Debug)]
pub struct Game {
pub struct Game<'a> {
teams: Vec<Vec<Player>>,
result: Vec<f64>,
weights: Vec<Vec<f64>>,
result: &'a [f64],
weights: &'a [Vec<f64>],
p_draw: f64,
pub(crate) likelihoods: Vec<Vec<Gaussian>>,
pub(crate) evidence: f64,
}
impl Game {
impl<'a> Game<'a> {
pub fn new(
teams: Vec<Vec<Player>>,
mut result: Vec<f64>,
mut weights: Vec<Vec<f64>>,
result: &'a [f64],
weights: &'a [Vec<f64>],
p_draw: f64,
) -> Self {
assert!(
(result.is_empty() || result.len() == teams.len()),
"result must be empty or the same length as teams"
(result.len() == teams.len()),
"result must have the same length as teams"
);
assert!(
(weights.is_empty() || weights.len() == teams.len()),
"weights must be empty or the same length as teams"
);
assert!(
weights.is_empty()
|| weights
.iter()
.zip(teams.iter())
.all(|(w, t)| w.len() == t.len()),
"weights must be empty or has the same dimensions as teams"
weights
.iter()
.zip(teams.iter())
.all(|(w, t)| w.len() == t.len()),
"weights must have the same dimensions as teams"
);
assert!(
@@ -49,24 +43,13 @@ impl Game {
assert!(
p_draw > 0.0 || {
let mut r = result.clone();
let mut r = result.to_vec();
r.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
r.windows(2).all(|w| w[0] != w[1])
},
"draw must be > 0.0 if there is teams with draw"
);
if result.is_empty() {
result = (0..teams.len()).rev().map(|i| i as f64).collect::<Vec<_>>();
}
if weights.is_empty() {
weights = teams
.iter()
.map(|team| vec![1.0; team.len()])
.collect::<Vec<_>>();
}
let mut this = Self {
teams,
result,
@@ -82,7 +65,7 @@ impl Game {
}
fn likelihoods(&mut self) {
let o = sort_perm(&self.result, true);
let o = sort_perm(self.result, true);
let mut team = o
.iter()
@@ -235,7 +218,8 @@ mod tests {
25.0 / 300.0,
);
let g = Game::new(vec![vec![t_a], vec![t_b]], vec![0.0, 1.0], vec![], 0.0);
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);
let p = g.posteriors();
let a = p[0][0];
@@ -247,7 +231,8 @@ mod tests {
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 g = Game::new(vec![vec![t_a], vec![t_b]], vec![0.0, 1.0], vec![], 0.0);
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);
let p = g.posteriors();
let a = p[0][0];
@@ -259,7 +244,8 @@ mod tests {
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 g = Game::new(vec![vec![t_a], vec![t_b]], vec![0.0, 1.0], vec![], 0.0);
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);
assert_eq!(g.likelihoods[0][0], N_INF);
assert_eq!(g.likelihoods[1][0], N_INF);
@@ -285,7 +271,8 @@ mod tests {
)],
];
let g = Game::new(teams.clone(), vec![1.0, 2.0, 0.0], vec![], 0.0);
let w = [vec![1.0], vec![1.0], vec![1.0]];
let g = Game::new(teams.clone(), &[1.0, 2.0, 0.0], &w, 0.0);
let p = g.posteriors();
let a = p[0][0];
@@ -294,7 +281,8 @@ mod tests {
assert_ulps_eq!(a, Gaussian::from_ms(25.000000, 6.238469), epsilon = 1e-6);
assert_ulps_eq!(b, Gaussian::from_ms(31.311358, 6.698818), epsilon = 1e-6);
let g = Game::new(teams.clone(), vec![], vec![], 0.0);
let w = [vec![1.0], vec![1.0], vec![1.0]];
let g = Game::new(teams.clone(), &[2.0, 1.0, 0.0], &w, 0.0);
let p = g.posteriors();
let a = p[0][0];
@@ -303,7 +291,8 @@ mod tests {
assert_ulps_eq!(a, Gaussian::from_ms(31.311358, 6.698818), epsilon = 1e-6);
assert_ulps_eq!(b, Gaussian::from_ms(25.000000, 6.238469), epsilon = 1e-6);
let g = Game::new(teams, vec![1.0, 2.0, 0.0], vec![], 0.5);
let w = [vec![1.0], vec![1.0], vec![1.0]];
let g = Game::new(teams, &[1.0, 2.0, 0.0], &w, 0.5);
let p = g.posteriors();
let a = p[0][0];
@@ -328,7 +317,8 @@ mod tests {
25.0 / 300.0,
);
let g = Game::new(vec![vec![t_a], vec![t_b]], vec![0.0, 0.0], vec![], 0.25);
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);
let p = g.posteriors();
let a = p[0][0];
@@ -340,7 +330,8 @@ mod tests {
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 g = Game::new(vec![vec![t_a], vec![t_b]], vec![0.0, 0.0], vec![], 0.25);
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);
let p = g.posteriors();
let a = p[0][0];
@@ -368,10 +359,11 @@ mod tests {
25.0 / 300.0,
);
let w = [vec![1.0], vec![1.0], vec![1.0]];
let g = Game::new(
vec![vec![t_a], vec![t_b], vec![t_c]],
vec![0.0, 0.0, 0.0],
vec![],
&[0.0, 0.0, 0.0],
&w,
0.25,
);
let p = g.posteriors();
@@ -388,10 +380,11 @@ mod tests {
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 w = [vec![1.0], vec![1.0], vec![1.0]];
let g = Game::new(
vec![vec![t_a], vec![t_b], vec![t_c]],
vec![0.0, 0.0, 0.0],
vec![],
&[0.0, 0.0, 0.0],
&w,
0.25,
);
let p = g.posteriors();
@@ -421,7 +414,8 @@ mod tests {
Player::new(Gaussian::from_ms(16., 3.0), 25.0 / 6.0, 25.0 / 300.0),
];
let g = Game::new(vec![t_a, t_b, t_c], vec![1.0, 0.0, 0.0], vec![], 0.25);
let w = [vec![1.0, 1.0], vec![1.0], vec![1.0, 1.0]];
let g = Game::new(vec![t_a, t_b, t_c], &[1.0, 0.0, 0.0], &w, 0.25);
let p = g.posteriors();
assert_ulps_eq!(p[0][0], Gaussian::from_ms(13.051, 2.864), epsilon = 1e-3);
@@ -447,7 +441,8 @@ mod tests {
0.0,
)];
let g = Game::new(vec![t_a.clone(), t_b.clone()], vec![], vec![w_a, w_b], 0.0);
let w = [w_a, w_b];
let g = Game::new(vec![t_a.clone(), t_b.clone()], &[1.0, 0.0], &w, 0.0);
let p = g.posteriors();
assert_ulps_eq!(
@@ -464,7 +459,8 @@ mod tests {
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 w = [w_a, w_b];
let g = Game::new(vec![t_a.clone(), t_b.clone()], &[1.0, 0.0], &w, 0.0);
let p = g.posteriors();
assert_ulps_eq!(
@@ -481,7 +477,8 @@ mod tests {
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 w = [w_a, w_b];
let g = Game::new(vec![t_a, t_b], &[1.0, 0.0], &w, 0.0);
let p = g.posteriors();
assert_ulps_eq!(
@@ -501,7 +498,8 @@ mod tests {
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 g = Game::new(vec![t_a, t_b], vec![], vec![w_a, w_b], 0.0);
let w = [w_a, w_b];
let g = Game::new(vec![t_a, t_b], &[1.0, 0.0], &w, 0.0);
let p = g.posteriors();
assert_ulps_eq!(
@@ -521,7 +519,8 @@ mod tests {
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 g = Game::new(vec![t_a, t_b], vec![], vec![w_a, w_b], 0.0);
let w = [w_a, w_b];
let g = Game::new(vec![t_a, t_b], &[1.0, 0.0], &w, 0.0);
let p = g.posteriors();
assert_ulps_eq!(p[0][0], p[1][0], epsilon = 1e-6);
@@ -541,7 +540,8 @@ mod tests {
];
let w_b = vec![0.9, 0.6];
let g = Game::new(vec![t_a.clone(), t_b.clone()], vec![], vec![w_a, w_b], 0.0);
let w = [w_a, w_b];
let g = Game::new(vec![t_a.clone(), t_b.clone()], &[1.0, 0.0], &w, 0.0);
let p = g.posteriors();
assert_ulps_eq!(
@@ -568,7 +568,8 @@ mod tests {
let w_a = vec![1.3, 1.5];
let w_b = vec![0.7, 0.4];
let g = Game::new(vec![t_a.clone(), t_b.clone()], vec![], vec![w_a, w_b], 0.0);
let w = [w_a, w_b];
let g = Game::new(vec![t_a.clone(), t_b.clone()], &[1.0, 0.0], &w, 0.0);
let p = g.posteriors();
assert_ulps_eq!(
@@ -595,7 +596,8 @@ mod tests {
let w_a = vec![1.6, 0.2];
let w_b = vec![0.7, 2.4];
let g = Game::new(vec![t_a.clone(), t_b.clone()], vec![], vec![w_a, w_b], 0.0);
let w = [w_a, w_b];
let g = Game::new(vec![t_a.clone(), t_b.clone()], &[1.0, 0.0], &w, 0.0);
let p = g.posteriors();
assert_ulps_eq!(
@@ -619,6 +621,7 @@ mod tests {
epsilon = 1e-6
);
let w = [vec![1.0, 1.0], vec![1.0]];
let g = Game::new(
vec![
t_a.clone(),
@@ -628,8 +631,8 @@ mod tests {
0.0,
)],
],
vec![],
vec![],
&[1.0, 0.0],
&w,
0.0,
);
let post_2vs1 = g.posteriors();
@@ -637,7 +640,8 @@ mod tests {
let w_a = vec![1.0, 1.0];
let w_b = vec![1.0, 0.0];
let g = Game::new(vec![t_a, t_b.clone()], vec![], vec![w_a, w_b], 0.0);
let w = [w_a, w_b];
let g = Game::new(vec![t_a, t_b.clone()], &[1.0, 0.0], &w, 0.0);
let p = g.posteriors();
assert_ulps_eq!(p[0][0], post_2vs1[0][0], epsilon = 1e-6);

View File

@@ -1,4 +1,4 @@
use std::collections::{HashMap, HashSet};
use std::collections::HashMap;
use crate::{
agent::{self, Agent},
@@ -267,17 +267,27 @@ impl History {
"(length(weights) > 0) & (length(composition) != length(weights))"
);
let mut unique = Vec::with_capacity(10);
let this_agent = composition
.iter()
.flatten()
.flatten()
.cloned()
.collect::<HashSet<_>>();
.filter(|idx| {
if !unique.contains(idx) {
unique.push(*idx);
return true;
}
false
})
.collect::<Vec<_>>();
for agent in &this_agent {
if !self.agents.contains_key(agent) {
self.agents.insert(
*agent,
**agent,
Agent {
player: priors.get(agent).cloned().unwrap_or_else(|| {
Player::new(
@@ -473,8 +483,8 @@ mod tests {
let p = Game::new(
h.batches[1].events[0].within_priors(false, false, &h.batches[1].skills, &h.agents),
vec![0.0, 1.0],
vec![],
&vec![0.0, 1.0],
&vec![vec![1.0], vec![1.0]],
P_DRAW,
)
.posteriors();