refactor: one word per concept
Three vocabulary collisions, from #75. **"rating" meant three things**, one the opposite of the exported type. `Rating` is documented as static *configuration* — "this returns what it was told", against every other accessor's "what inference inferred". But `quality`'s parameter was `rating_groups: &[&[Gaussian]]` and its prose said "rating groups" four times, where "rating" means a *posterior* — the one thing `Rating` is documented not to be. Two error messages used it that way too. So a reader who learned `Rating = config` passed `Rating` values to `quality`, which takes `Gaussian`; and one who learned "rating = what comes out" was baffled that `h.rating(&k)` is not their skill. "rating" is now reserved for the type. `quality(teams: &[&[Gaussian]])`, and "every rating is finite" became "every posterior is finite". **"agent" was a private fourth name for a competitor** — ~200 identifiers against 236 uses of "competitor", and it leaked into two `pub` signatures on `TimeSlice`. Now that #73 has made those internal this is a pure rename, so the crate has one word for the entity throughout. **"player" survived in one public signature** — `free_for_all(players:)` plus two doc lines. Renamed, along with three internal closure bindings. Doc examples that use "player" as a *key* are left alone: that is a user's data, not the crate's vocabulary. The panic-message expectations in tests/quality.rs moved with the prose, which is the point of asserting on message text — the tests caught the rename rather than papering over it. Not touched: "performance" (always skill widened by beta), "skill", "member" and "team" are each used for exactly one thing already. Refs #75 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011hcFjNDmHXZF8URGLku5zZ
This commit is contained in:
+110
-90
@@ -268,7 +268,7 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> HistoryBuilder<
|
||||
History {
|
||||
size: 0,
|
||||
time_slices: Vec::new(),
|
||||
agents: CompetitorStore::new(),
|
||||
competitors: CompetitorStore::new(),
|
||||
keys: KeyTable::new(),
|
||||
mu: self.mu,
|
||||
sigma: self.sigma,
|
||||
@@ -391,7 +391,7 @@ pub struct History<
|
||||
> {
|
||||
size: usize,
|
||||
pub(crate) time_slices: Vec<TimeSlice<T>>,
|
||||
pub(crate) agents: CompetitorStore<T, D>,
|
||||
pub(crate) competitors: CompetitorStore<T, D>,
|
||||
keys: KeyTable<K>,
|
||||
mu: f64,
|
||||
sigma: f64,
|
||||
@@ -470,17 +470,18 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
return step;
|
||||
}
|
||||
|
||||
competitor::clean(self.agents.values_mut(), false);
|
||||
competitor::clean(self.competitors.values_mut(), false);
|
||||
|
||||
for j in (0..self.time_slices.len() - 1).rev() {
|
||||
for agent in self.time_slices[j + 1].skills.keys() {
|
||||
self.agents.get_mut(agent).unwrap().message =
|
||||
Some(self.time_slices[j + 1].backward_prior_out(&agent, &self.agents));
|
||||
for competitor in self.time_slices[j + 1].skills.keys() {
|
||||
self.competitors.get_mut(competitor).unwrap().message = Some(
|
||||
self.time_slices[j + 1].backward_prior_out(&competitor, &self.competitors),
|
||||
);
|
||||
}
|
||||
|
||||
let old = self.time_slices[j].posteriors();
|
||||
|
||||
self.time_slices[j].new_backward_info(&self.agents);
|
||||
self.time_slices[j].new_backward_info(&self.competitors);
|
||||
self.observer.on_slice_processed(
|
||||
&self.time_slices[j].time,
|
||||
j,
|
||||
@@ -494,17 +495,17 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
.fold(step, |step, (a, old)| tuple_max(step, old.delta(new[a])));
|
||||
}
|
||||
|
||||
competitor::clean(self.agents.values_mut(), false);
|
||||
competitor::clean(self.competitors.values_mut(), false);
|
||||
|
||||
for j in 1..self.time_slices.len() {
|
||||
for agent in self.time_slices[j - 1].skills.keys() {
|
||||
self.agents.get_mut(agent).unwrap().message =
|
||||
Some(self.time_slices[j - 1].forward_prior_out(&agent));
|
||||
for competitor in self.time_slices[j - 1].skills.keys() {
|
||||
self.competitors.get_mut(competitor).unwrap().message =
|
||||
Some(self.time_slices[j - 1].forward_prior_out(&competitor));
|
||||
}
|
||||
|
||||
let old = self.time_slices[j].posteriors();
|
||||
|
||||
self.time_slices[j].new_forward_info(&self.agents);
|
||||
self.time_slices[j].new_forward_info(&self.competitors);
|
||||
self.observer.on_slice_processed(
|
||||
&self.time_slices[j].time,
|
||||
j,
|
||||
@@ -521,7 +522,7 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
if self.time_slices.len() == 1 {
|
||||
let old = self.time_slices[0].posteriors();
|
||||
|
||||
self.time_slices[0].iteration(0, &self.agents);
|
||||
self.time_slices[0].iteration(0, &self.competitors);
|
||||
self.observer.on_slice_processed(
|
||||
&self.time_slices[0].time,
|
||||
0,
|
||||
@@ -676,7 +677,7 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
|
||||
let key = format!("{:?}", member.key);
|
||||
let idx = self.keys.get_or_create(&member.key);
|
||||
if self.agents.contains(idx) {
|
||||
if self.competitors.contains(idx) {
|
||||
return Err(InferenceError::AlreadyRegistered { key });
|
||||
}
|
||||
|
||||
@@ -699,7 +700,7 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
drift_scale: member.drift_scale,
|
||||
},
|
||||
);
|
||||
self.agents.insert(
|
||||
self.competitors.insert(
|
||||
idx,
|
||||
Competitor {
|
||||
rating,
|
||||
@@ -725,7 +726,9 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
Q: std::hash::Hash + Eq + ?Sized,
|
||||
{
|
||||
let idx = self.keys.get(key)?;
|
||||
self.agents.contains(idx).then(|| self.agents[idx].rating)
|
||||
self.competitors
|
||||
.contains(idx)
|
||||
.then(|| self.competitors[idx].rating)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@@ -771,8 +774,8 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
let mut data: HashMap<K, Vec<(T, Gaussian)>> = HashMap::new();
|
||||
|
||||
for (time, step) in self.filtered_pass() {
|
||||
for (agent, posterior) in step.posteriors {
|
||||
if let Some(key) = self.keys.key(agent).cloned() {
|
||||
for (competitor, posterior) in step.posteriors {
|
||||
if let Some(key) = self.keys.key(competitor).cloned() {
|
||||
data.entry(key).or_default().push((time, posterior));
|
||||
}
|
||||
}
|
||||
@@ -804,7 +807,7 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
.filter_map(|(time, step)| {
|
||||
step.posteriors
|
||||
.iter()
|
||||
.find(|(agent, _)| *agent == idx)
|
||||
.find(|(competitor, _)| *competitor == idx)
|
||||
.map(|&(_, posterior)| (time, posterior))
|
||||
})
|
||||
.collect()
|
||||
@@ -823,7 +826,7 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
// Bound before the closure so it captures the store rather than all of
|
||||
// `&self`: capturing `&History` would drag `KeyTable<K>` in and demand
|
||||
// `K: Sync` from every caller, which the key type need not satisfy.
|
||||
let agents = &self.agents;
|
||||
let competitors = &self.competitors;
|
||||
|
||||
#[cfg(feature = "rayon")]
|
||||
{
|
||||
@@ -831,7 +834,7 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
let per_slice: Vec<f64> = self
|
||||
.time_slices
|
||||
.par_iter()
|
||||
.map(|ts| ts.log_evidence(targets, forward, agents))
|
||||
.map(|ts| ts.log_evidence(targets, forward, competitors))
|
||||
.collect();
|
||||
per_slice.into_iter().sum()
|
||||
}
|
||||
@@ -839,7 +842,7 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
{
|
||||
self.time_slices
|
||||
.iter()
|
||||
.map(|ts| ts.log_evidence(targets, forward, agents))
|
||||
.map(|ts| ts.log_evidence(targets, forward, competitors))
|
||||
.sum()
|
||||
}
|
||||
}
|
||||
@@ -872,10 +875,10 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
let mut pass = Vec::with_capacity(self.time_slices.len());
|
||||
|
||||
for slice in &self.time_slices {
|
||||
let step = slice.filtered_step(&messages, &self.agents);
|
||||
let step = slice.filtered_step(&messages, &self.competitors);
|
||||
|
||||
for &(agent, posterior) in &step.posteriors {
|
||||
messages.insert(agent, posterior);
|
||||
for &(competitor, posterior) in &step.posteriors {
|
||||
messages.insert(competitor, posterior);
|
||||
}
|
||||
|
||||
pass.push((slice.time, step));
|
||||
@@ -1120,13 +1123,13 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
let mut n = 0usize;
|
||||
|
||||
for (slice_idx, slice) in self.time_slices.iter().enumerate() {
|
||||
for (agent, elapsed) in slice.appearances() {
|
||||
let rating = &self.agents[agent].rating;
|
||||
let row = match previous.get(&agent) {
|
||||
for (competitor, elapsed) in slice.appearances() {
|
||||
let rating = &self.competitors[competitor].rating;
|
||||
let row = match previous.get(&competitor) {
|
||||
None => {
|
||||
let row = n;
|
||||
n += 1;
|
||||
first_rows.push((row, agent));
|
||||
first_rows.push((row, competitor));
|
||||
row
|
||||
}
|
||||
Some(&prev) => {
|
||||
@@ -1143,16 +1146,17 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
}
|
||||
}
|
||||
};
|
||||
previous.insert(agent, row);
|
||||
latest.insert(agent, (row, slice_idx));
|
||||
at_slice.insert((agent, slice_idx), row);
|
||||
previous.insert(competitor, row);
|
||||
latest.insert(competitor, (row, slice_idx));
|
||||
at_slice.insert((competitor, slice_idx), row);
|
||||
}
|
||||
}
|
||||
|
||||
let mut lambda = vec![0.0; n * n];
|
||||
|
||||
for (row, agent) in first_rows {
|
||||
lambda[row * n + row] += 1.0 / self.agents[agent].rating.prior.sigma().powi(2);
|
||||
for (row, competitor) in first_rows {
|
||||
lambda[row * n + row] +=
|
||||
1.0 / self.competitors[competitor].rating.prior.sigma().powi(2);
|
||||
}
|
||||
for (a, b, drift) in drift_links {
|
||||
lambda[a * n + a] += 1.0 / drift;
|
||||
@@ -1161,7 +1165,7 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
lambda[b * n + a] -= 1.0 / drift;
|
||||
}
|
||||
for (slice_idx, slice) in self.time_slices.iter().enumerate() {
|
||||
for (contrast, noise) in slice.scored_contrasts(&self.agents) {
|
||||
for (contrast, noise) in slice.scored_contrasts(&self.competitors) {
|
||||
for (ia, ca) in &contrast {
|
||||
let ra = at_slice[&(*ia, slice_idx)];
|
||||
for (ib, cb) in &contrast {
|
||||
@@ -1511,7 +1515,7 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
let beta = self
|
||||
.keys
|
||||
.get(*key)
|
||||
.map_or(self.beta, |index| self.agents[index].rating.beta);
|
||||
.map_or(self.beta, |index| self.competitors[index].rating.beta);
|
||||
performance_noise += beta * beta;
|
||||
}
|
||||
}
|
||||
@@ -1795,8 +1799,8 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
// defect already rejected for `sigma` and `beta`. A non-finite gamma
|
||||
// poisons every posterior derived from it.
|
||||
for slice in &self.time_slices {
|
||||
for (agent, elapsed) in slice.appearances() {
|
||||
let drift = self.agents[agent]
|
||||
for (competitor, elapsed) in slice.appearances() {
|
||||
let drift = self.competitors[competitor]
|
||||
.rating
|
||||
.drift_variance_for_elapsed(elapsed);
|
||||
if !drift.is_finite() || drift < 0.0 {
|
||||
@@ -2006,14 +2010,14 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
let mut conflict_scan: Vec<Index> = priors.keys().copied().collect();
|
||||
conflict_scan.sort_unstable();
|
||||
|
||||
for agent in &conflict_scan {
|
||||
let batch = priors[agent];
|
||||
let held = self.declared.get(agent).copied().unwrap_or_default();
|
||||
for competitor in &conflict_scan {
|
||||
let batch = priors[competitor];
|
||||
let held = self.declared.get(competitor).copied().unwrap_or_default();
|
||||
|
||||
if let (Some(existing), Some(new)) = (held.prior, batch.prior) {
|
||||
if existing != new {
|
||||
return Err(InferenceError::ConflictingCompetitorConfig {
|
||||
competitor: agent.get(),
|
||||
competitor: competitor.get(),
|
||||
field: "prior",
|
||||
});
|
||||
}
|
||||
@@ -2021,15 +2025,15 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
if let (Some(existing), Some(new)) = (held.drift_scale, batch.drift_scale) {
|
||||
if existing != new {
|
||||
return Err(InferenceError::ConflictingCompetitorConfig {
|
||||
competitor: agent.get(),
|
||||
competitor: competitor.get(),
|
||||
field: "drift_scale",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (agent, batch) in &priors {
|
||||
let entry = self.declared.entry(*agent).or_default();
|
||||
for (competitor, batch) in &priors {
|
||||
let entry = self.declared.entry(*competitor).or_default();
|
||||
if batch.prior.is_some() {
|
||||
entry.prior = batch.prior;
|
||||
}
|
||||
@@ -2038,22 +2042,22 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
}
|
||||
}
|
||||
|
||||
competitor::clean(self.agents.values_mut(), true);
|
||||
competitor::clean(self.competitors.values_mut(), true);
|
||||
|
||||
let mut this_agent = Vec::with_capacity(1024);
|
||||
|
||||
for agent in composition.iter().flatten().flatten() {
|
||||
if this_agent.contains(agent) {
|
||||
for competitor in composition.iter().flatten().flatten() {
|
||||
if this_agent.contains(competitor) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this_agent.push(*agent);
|
||||
this_agent.push(*competitor);
|
||||
|
||||
// From `declared` rather than `priors`: a competitor configured by
|
||||
// `register` before any event has nothing in this batch's map.
|
||||
let config = self.declared.get(agent).copied().unwrap_or_default();
|
||||
let config = self.declared.get(competitor).copied().unwrap_or_default();
|
||||
|
||||
if self.agents.contains(*agent) {
|
||||
if self.competitors.contains(*competitor) {
|
||||
// Seeding a competitor the history already knows. This used to
|
||||
// be dropped on the floor: `remove` was only reached on the
|
||||
// create path, so a prior applied on a competitor's very first
|
||||
@@ -2062,7 +2066,7 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
continue;
|
||||
}
|
||||
|
||||
let rating = &mut self.agents.get_mut(*agent).unwrap().rating;
|
||||
let rating = &mut self.competitors.get_mut(*competitor).unwrap().rating;
|
||||
if let Some(prior) = config.prior {
|
||||
rating.prior = prior;
|
||||
}
|
||||
@@ -2082,7 +2086,7 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
// `clean` has just nulled every message, so the earliest
|
||||
// slice's forward is exactly the prior.
|
||||
for slice in &mut self.time_slices {
|
||||
if let Some(skill) = slice.skills.get_mut(*agent) {
|
||||
if let Some(skill) = slice.skills.get_mut(*competitor) {
|
||||
skill.forward = seeded;
|
||||
break;
|
||||
}
|
||||
@@ -2101,8 +2105,8 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
rating.drift_scale = scale;
|
||||
}
|
||||
|
||||
self.agents.insert(
|
||||
*agent,
|
||||
self.competitors.insert(
|
||||
*competitor,
|
||||
Competitor {
|
||||
rating,
|
||||
message: None,
|
||||
@@ -2144,20 +2148,20 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
let time_slice = &mut self.time_slices[k];
|
||||
|
||||
if k > 0 {
|
||||
time_slice.new_forward_info(&self.agents);
|
||||
time_slice.new_forward_info(&self.competitors);
|
||||
}
|
||||
|
||||
for agent_idx in &this_agent {
|
||||
if let Some(skill) = time_slice.skills.get_mut(*agent_idx) {
|
||||
skill.elapsed = time_slice::compute_elapsed(
|
||||
self.agents[*agent_idx].last_time.as_ref(),
|
||||
self.competitors[*agent_idx].last_time.as_ref(),
|
||||
&time_slice.time,
|
||||
);
|
||||
|
||||
let agent = self.agents.get_mut(*agent_idx).unwrap();
|
||||
let competitor = self.competitors.get_mut(*agent_idx).unwrap();
|
||||
|
||||
agent.last_time = Some(time_slice.time);
|
||||
agent.message = Some(time_slice.forward_prior_out(agent_idx));
|
||||
competitor.last_time = Some(time_slice.time);
|
||||
competitor.message = Some(time_slice.forward_prior_out(agent_idx));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2184,29 +2188,41 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
|
||||
if self.time_slices.len() > k && self.time_slices[k].time == t {
|
||||
let time_slice = &mut self.time_slices[k];
|
||||
time_slice.add_events(composition, results, weights, kinds_chunk, &self.agents);
|
||||
time_slice.add_events(
|
||||
composition,
|
||||
results,
|
||||
weights,
|
||||
kinds_chunk,
|
||||
&self.competitors,
|
||||
);
|
||||
|
||||
for agent_idx in time_slice.skills.keys() {
|
||||
let agent = self.agents.get_mut(agent_idx).unwrap();
|
||||
let competitor = self.competitors.get_mut(agent_idx).unwrap();
|
||||
|
||||
agent.last_time = Some(t);
|
||||
agent.message = Some(time_slice.forward_prior_out(&agent_idx));
|
||||
competitor.last_time = Some(t);
|
||||
competitor.message = Some(time_slice.forward_prior_out(&agent_idx));
|
||||
}
|
||||
|
||||
k += 1;
|
||||
} else {
|
||||
let mut time_slice = TimeSlice::new(t, self.p_draw, self.convergence);
|
||||
time_slice.add_events(composition, results, weights, kinds_chunk, &self.agents);
|
||||
time_slice.add_events(
|
||||
composition,
|
||||
results,
|
||||
weights,
|
||||
kinds_chunk,
|
||||
&self.competitors,
|
||||
);
|
||||
|
||||
self.time_slices.insert(k, time_slice);
|
||||
|
||||
let time_slice = &self.time_slices[k];
|
||||
|
||||
for agent_idx in time_slice.skills.keys() {
|
||||
let agent = self.agents.get_mut(agent_idx).unwrap();
|
||||
let competitor = self.competitors.get_mut(agent_idx).unwrap();
|
||||
|
||||
agent.last_time = Some(t);
|
||||
agent.message = Some(time_slice.forward_prior_out(&agent_idx));
|
||||
competitor.last_time = Some(t);
|
||||
competitor.message = Some(time_slice.forward_prior_out(&agent_idx));
|
||||
}
|
||||
|
||||
k += 1;
|
||||
@@ -2218,19 +2234,19 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
while self.time_slices.len() > k {
|
||||
let time_slice = &mut self.time_slices[k];
|
||||
|
||||
time_slice.new_forward_info(&self.agents);
|
||||
time_slice.new_forward_info(&self.competitors);
|
||||
|
||||
for agent_idx in &this_agent {
|
||||
if let Some(skill) = time_slice.skills.get_mut(*agent_idx) {
|
||||
skill.elapsed = time_slice::compute_elapsed(
|
||||
self.agents[*agent_idx].last_time.as_ref(),
|
||||
self.competitors[*agent_idx].last_time.as_ref(),
|
||||
&time_slice.time,
|
||||
);
|
||||
|
||||
let agent = self.agents.get_mut(*agent_idx).unwrap();
|
||||
let competitor = self.competitors.get_mut(*agent_idx).unwrap();
|
||||
|
||||
agent.last_time = Some(time_slice.time);
|
||||
agent.message = Some(time_slice.forward_prior_out(agent_idx));
|
||||
competitor.last_time = Some(time_slice.time);
|
||||
competitor.message = Some(time_slice.forward_prior_out(agent_idx));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2606,9 +2622,9 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> Joint<'_, T, D,
|
||||
if slice.time > time {
|
||||
break;
|
||||
}
|
||||
for (agent, _) in slice.appearances() {
|
||||
if let Some(row) = self.at_slice.get(&(agent, slice_idx)) {
|
||||
as_of.insert(agent, (*row, slice_idx));
|
||||
for (competitor, _) in slice.appearances() {
|
||||
if let Some(row) = self.at_slice.get(&(competitor, slice_idx)) {
|
||||
as_of.insert(competitor, (*row, slice_idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2657,7 +2673,7 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> Joint<'_, T, D,
|
||||
.keys
|
||||
.get(*key)
|
||||
.map_or(self.history.beta, |index| {
|
||||
self.history.agents[index].rating.beta
|
||||
self.history.competitors[index].rating.beta
|
||||
});
|
||||
noise += beta * beta;
|
||||
}
|
||||
@@ -2812,7 +2828,11 @@ mod tests {
|
||||
|
||||
let w = [vec![1.0], vec![1.0]];
|
||||
let p = Game::ranked_with_arena(
|
||||
h.time_slices[1].events[0].within_priors(false, &h.time_slices[1].skills, &h.agents),
|
||||
h.time_slices[1].events[0].within_priors(
|
||||
false,
|
||||
&h.time_slices[1].skills,
|
||||
&h.competitors,
|
||||
),
|
||||
&[0.0, 1.0],
|
||||
&w,
|
||||
P_DRAW,
|
||||
@@ -3731,7 +3751,7 @@ mod tests {
|
||||
|
||||
let mut max_diff: f64 = 0.0;
|
||||
for (key, capped_pts) in curves_capped.iter() {
|
||||
let full_pts = curves_full.get(key).expect("agent missing in full");
|
||||
let full_pts = curves_full.get(key).expect("competitor missing in full");
|
||||
for (capped, full) in capped_pts.iter().zip(full_pts.iter()) {
|
||||
max_diff = max_diff.max((capped.1.mu() - full.1.mu()).abs());
|
||||
max_diff = max_diff.max((capped.1.sigma() - full.1.sigma()).abs());
|
||||
@@ -3778,7 +3798,7 @@ mod tests {
|
||||
|
||||
let mut max_diff: f64 = 0.0;
|
||||
for (key, u_pts) in curves_u.iter() {
|
||||
let d_pts = curves_d.get(key).expect("agent missing in damped");
|
||||
let d_pts = curves_d.get(key).expect("competitor missing in damped");
|
||||
for (u, d) in u_pts.iter().zip(d_pts.iter()) {
|
||||
max_diff = max_diff.max((u.1.mu() - d.1.mu()).abs());
|
||||
max_diff = max_diff.max((u.1.sigma() - d.1.sigma()).abs());
|
||||
@@ -3824,10 +3844,10 @@ mod tests {
|
||||
let curves_a = h_a.learning_curves();
|
||||
let curves_b = h_b.learning_curves();
|
||||
for (key, a_pts) in curves_a.iter() {
|
||||
let b_pts = curves_b.get(key).expect("agent missing in path B");
|
||||
let b_pts = curves_b.get(key).expect("competitor missing in path B");
|
||||
for (a, b) in a_pts.iter().zip(b_pts.iter()) {
|
||||
assert_eq!(a.1.pi(), b.1.pi(), "mismatch at agent {key:?}");
|
||||
assert_eq!(a.1.tau(), b.1.tau(), "mismatch at agent {key:?}");
|
||||
assert_eq!(a.1.pi(), b.1.pi(), "mismatch at competitor {key:?}");
|
||||
assert_eq!(a.1.tau(), b.1.tau(), "mismatch at competitor {key:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3866,10 +3886,10 @@ mod tests {
|
||||
let curves_a = h_a.learning_curves();
|
||||
let curves_b = h_b.learning_curves();
|
||||
for (key, a_pts) in curves_a.iter() {
|
||||
let b_pts = curves_b.get(key).expect("agent missing in path B");
|
||||
let b_pts = curves_b.get(key).expect("competitor missing in path B");
|
||||
for (a, b) in a_pts.iter().zip(b_pts.iter()) {
|
||||
assert_eq!(a.1.pi(), b.1.pi(), "mismatch at agent {key:?}");
|
||||
assert_eq!(a.1.tau(), b.1.tau(), "mismatch at agent {key:?}");
|
||||
assert_eq!(a.1.pi(), b.1.pi(), "mismatch at competitor {key:?}");
|
||||
assert_eq!(a.1.tau(), b.1.tau(), "mismatch at competitor {key:?}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3889,7 +3909,7 @@ mod tests {
|
||||
let curves_c = h_c.learning_curves();
|
||||
let mut max_diff: f64 = 0.0;
|
||||
for (key, a_pts) in curves_a.iter() {
|
||||
let c_pts = curves_c.get(key).expect("agent missing in path C");
|
||||
let c_pts = curves_c.get(key).expect("competitor missing in path C");
|
||||
for (a, c) in a_pts.iter().zip(c_pts.iter()) {
|
||||
max_diff = max_diff.max((a.1.mu() - c.1.mu()).abs());
|
||||
max_diff = max_diff.max((a.1.sigma() - c.1.sigma()).abs());
|
||||
@@ -3931,10 +3951,10 @@ mod tests {
|
||||
let curves_a = h_a.learning_curves();
|
||||
let curves_b = h_b.learning_curves();
|
||||
for (key, a_pts) in curves_a.iter() {
|
||||
let b_pts = curves_b.get(key).expect("agent missing");
|
||||
let b_pts = curves_b.get(key).expect("competitor missing");
|
||||
for (a, b) in a_pts.iter().zip(b_pts.iter()) {
|
||||
assert_eq!(a.1.pi(), b.1.pi(), "mismatch at agent {key:?}");
|
||||
assert_eq!(a.1.tau(), b.1.tau(), "mismatch at agent {key:?}");
|
||||
assert_eq!(a.1.pi(), b.1.pi(), "mismatch at competitor {key:?}");
|
||||
assert_eq!(a.1.tau(), b.1.tau(), "mismatch at competitor {key:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user