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]]); 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| { criterion.bench_function("Batch::iteration", |b| {
b.iter(|| batch.iteration(0, &agents)) b.iter(|| batch.iteration(0, &agents))

View File

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

View File

@@ -7,39 +7,33 @@ use crate::{
}; };
#[derive(Debug)] #[derive(Debug)]
pub struct Game { pub struct Game<'a> {
teams: Vec<Vec<Player>>, teams: Vec<Vec<Player>>,
result: Vec<f64>, result: &'a [f64],
weights: Vec<Vec<f64>>, weights: &'a [Vec<f64>],
p_draw: f64, p_draw: f64,
pub(crate) likelihoods: Vec<Vec<Gaussian>>, pub(crate) likelihoods: Vec<Vec<Gaussian>>,
pub(crate) evidence: f64, pub(crate) evidence: f64,
} }
impl Game { impl<'a> Game<'a> {
pub fn new( pub fn new(
teams: Vec<Vec<Player>>, teams: Vec<Vec<Player>>,
mut result: Vec<f64>, result: &'a [f64],
mut weights: Vec<Vec<f64>>, weights: &'a [Vec<f64>],
p_draw: f64, p_draw: f64,
) -> Self { ) -> Self {
assert!( assert!(
(result.is_empty() || result.len() == teams.len()), (result.len() == teams.len()),
"result must be empty or the same length as teams" "result must have the same length as teams"
); );
assert!( assert!(
(weights.is_empty() || weights.len() == teams.len()), weights
"weights must be empty or the same length as teams"
);
assert!(
weights.is_empty()
|| weights
.iter() .iter()
.zip(teams.iter()) .zip(teams.iter())
.all(|(w, t)| w.len() == t.len()), .all(|(w, t)| w.len() == t.len()),
"weights must be empty or has the same dimensions as teams" "weights must have the same dimensions as teams"
); );
assert!( assert!(
@@ -49,24 +43,13 @@ impl Game {
assert!( assert!(
p_draw > 0.0 || { 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.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
r.windows(2).all(|w| w[0] != w[1]) r.windows(2).all(|w| w[0] != w[1])
}, },
"draw must be > 0.0 if there is teams with draw" "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 { let mut this = Self {
teams, teams,
result, result,
@@ -82,7 +65,7 @@ impl Game {
} }
fn likelihoods(&mut self) { fn likelihoods(&mut self) {
let o = sort_perm(&self.result, true); let o = sort_perm(self.result, true);
let mut team = o let mut team = o
.iter() .iter()
@@ -235,7 +218,8 @@ mod tests {
25.0 / 300.0, 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 p = g.posteriors();
let a = p[0][0]; 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_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_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 p = g.posteriors();
let a = p[0][0]; 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_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_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[0][0], N_INF);
assert_eq!(g.likelihoods[1][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 p = g.posteriors();
let a = p[0][0]; 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!(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); 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 p = g.posteriors();
let a = p[0][0]; 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!(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); 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 p = g.posteriors();
let a = p[0][0]; let a = p[0][0];
@@ -328,7 +317,8 @@ mod tests {
25.0 / 300.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 p = g.posteriors();
let a = p[0][0]; 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_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_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 p = g.posteriors();
let a = p[0][0]; let a = p[0][0];
@@ -368,10 +359,11 @@ mod tests {
25.0 / 300.0, 25.0 / 300.0,
); );
let w = [vec![1.0], vec![1.0], vec![1.0]];
let g = Game::new( let g = Game::new(
vec![vec![t_a], vec![t_b], vec![t_c]], vec![vec![t_a], vec![t_b], vec![t_c]],
vec![0.0, 0.0, 0.0], &[0.0, 0.0, 0.0],
vec![], &w,
0.25, 0.25,
); );
let p = g.posteriors(); 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_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_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( let g = Game::new(
vec![vec![t_a], vec![t_b], vec![t_c]], vec![vec![t_a], vec![t_b], vec![t_c]],
vec![0.0, 0.0, 0.0], &[0.0, 0.0, 0.0],
vec![], &w,
0.25, 0.25,
); );
let p = g.posteriors(); 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), 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(); let p = g.posteriors();
assert_ulps_eq!(p[0][0], Gaussian::from_ms(13.051, 2.864), epsilon = 1e-3); assert_ulps_eq!(p[0][0], Gaussian::from_ms(13.051, 2.864), epsilon = 1e-3);
@@ -447,7 +441,8 @@ mod tests {
0.0, 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(); let p = g.posteriors();
assert_ulps_eq!( assert_ulps_eq!(
@@ -464,7 +459,8 @@ mod tests {
let w_a = vec![1.0]; let w_a = vec![1.0];
let w_b = vec![0.7]; 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(); let p = g.posteriors();
assert_ulps_eq!( assert_ulps_eq!(
@@ -481,7 +477,8 @@ mod tests {
let w_a = vec![1.6]; let w_a = vec![1.6];
let w_b = vec![0.7]; 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(); let p = g.posteriors();
assert_ulps_eq!( 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_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_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(); let p = g.posteriors();
assert_ulps_eq!( 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_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_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(); let p = g.posteriors();
assert_ulps_eq!(p[0][0], p[1][0], epsilon = 1e-6); 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 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(); let p = g.posteriors();
assert_ulps_eq!( assert_ulps_eq!(
@@ -568,7 +568,8 @@ mod tests {
let w_a = vec![1.3, 1.5]; let w_a = vec![1.3, 1.5];
let w_b = vec![0.7, 0.4]; 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(); let p = g.posteriors();
assert_ulps_eq!( assert_ulps_eq!(
@@ -595,7 +596,8 @@ mod tests {
let w_a = vec![1.6, 0.2]; let w_a = vec![1.6, 0.2];
let w_b = vec![0.7, 2.4]; 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(); let p = g.posteriors();
assert_ulps_eq!( assert_ulps_eq!(
@@ -619,6 +621,7 @@ mod tests {
epsilon = 1e-6 epsilon = 1e-6
); );
let w = [vec![1.0, 1.0], vec![1.0]];
let g = Game::new( let g = Game::new(
vec![ vec![
t_a.clone(), t_a.clone(),
@@ -628,8 +631,8 @@ mod tests {
0.0, 0.0,
)], )],
], ],
vec![], &[1.0, 0.0],
vec![], &w,
0.0, 0.0,
); );
let post_2vs1 = g.posteriors(); let post_2vs1 = g.posteriors();
@@ -637,7 +640,8 @@ mod tests {
let w_a = vec![1.0, 1.0]; let w_a = vec![1.0, 1.0];
let w_b = vec![1.0, 0.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(); let p = g.posteriors();
assert_ulps_eq!(p[0][0], post_2vs1[0][0], epsilon = 1e-6); 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::{ use crate::{
agent::{self, Agent}, agent::{self, Agent},
@@ -267,17 +267,27 @@ impl History {
"(length(weights) > 0) & (length(composition) != length(weights))" "(length(weights) > 0) & (length(composition) != length(weights))"
); );
let mut unique = Vec::with_capacity(10);
let this_agent = composition let this_agent = composition
.iter() .iter()
.flatten() .flatten()
.flatten() .flatten()
.cloned() .filter(|idx| {
.collect::<HashSet<_>>(); if !unique.contains(idx) {
unique.push(*idx);
return true;
}
false
})
.collect::<Vec<_>>();
for agent in &this_agent { for agent in &this_agent {
if !self.agents.contains_key(agent) { if !self.agents.contains_key(agent) {
self.agents.insert( self.agents.insert(
*agent, **agent,
Agent { Agent {
player: priors.get(agent).cloned().unwrap_or_else(|| { player: priors.get(agent).cloned().unwrap_or_else(|| {
Player::new( Player::new(
@@ -473,8 +483,8 @@ mod tests {
let p = Game::new( let p = Game::new(
h.batches[1].events[0].within_priors(false, false, &h.batches[1].skills, &h.agents), h.batches[1].events[0].within_priors(false, false, &h.batches[1].skills, &h.agents),
vec![0.0, 1.0], &vec![0.0, 1.0],
vec![], &vec![vec![1.0], vec![1.0]],
P_DRAW, P_DRAW,
) )
.posteriors(); .posteriors();