T0 + T1 + T2: engine redesign through new API surface #1
@@ -1,11 +1,11 @@
|
|||||||
use criterion::{Criterion, criterion_group, criterion_main};
|
use criterion::{Criterion, criterion_group, criterion_main};
|
||||||
use trueskill_tt::{
|
use trueskill_tt::{
|
||||||
BETA, GAMMA, IndexMap, MU, P_DRAW, SIGMA, agent::Agent, batch::Batch, drift::ConstantDrift,
|
BETA, GAMMA, KeyTable, MU, P_DRAW, SIGMA, agent::Agent, batch::Batch, drift::ConstantDrift,
|
||||||
gaussian::Gaussian, player::Player, storage::AgentStore,
|
gaussian::Gaussian, player::Player, storage::AgentStore,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn criterion_benchmark(criterion: &mut Criterion) {
|
fn criterion_benchmark(criterion: &mut Criterion) {
|
||||||
let mut index = IndexMap::new();
|
let mut index = KeyTable::new();
|
||||||
|
|
||||||
let a = index.get_or_create("a");
|
let a = index.get_or_create("a");
|
||||||
let b = index.get_or_create("b");
|
let b = index.get_or_create("b");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use plotters::prelude::*;
|
use plotters::prelude::*;
|
||||||
use time::{Date, Month};
|
use time::{Date, Month};
|
||||||
use trueskill_tt::{History, IndexMap};
|
use trueskill_tt::{History, KeyTable};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut csv = csv::Reader::open("examples/atp.csv").unwrap();
|
let mut csv = csv::Reader::open("examples/atp.csv").unwrap();
|
||||||
@@ -12,7 +12,7 @@ fn main() {
|
|||||||
let from = Date::from_calendar_date(1900, Month::January, 1).unwrap();
|
let from = Date::from_calendar_date(1900, Month::January, 1).unwrap();
|
||||||
let time_format = time::format_description::parse("[year]-[month]-[day]").unwrap();
|
let time_format = time::format_description::parse("[year]-[month]-[day]").unwrap();
|
||||||
|
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
for row in csv.records() {
|
for row in csv.records() {
|
||||||
if &row["double"] == "t" {
|
if &row["double"] == "t" {
|
||||||
|
|||||||
@@ -400,12 +400,12 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
IndexMap, agent::Agent, drift::ConstantDrift, player::Player, storage::AgentStore,
|
KeyTable, agent::Agent, drift::ConstantDrift, player::Player, storage::AgentStore,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_one_event_each() {
|
fn test_one_event_each() {
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
let a = index_map.get_or_create("a");
|
let a = index_map.get_or_create("a");
|
||||||
let b = index_map.get_or_create("b");
|
let b = index_map.get_or_create("b");
|
||||||
@@ -481,7 +481,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_same_strength() {
|
fn test_same_strength() {
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
let a = index_map.get_or_create("a");
|
let a = index_map.get_or_create("a");
|
||||||
let b = index_map.get_or_create("b");
|
let b = index_map.get_or_create("b");
|
||||||
@@ -560,7 +560,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_events() {
|
fn test_add_events() {
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
let a = index_map.get_or_create("a");
|
let a = index_map.get_or_create("a");
|
||||||
let b = index_map.get_or_create("b");
|
let b = index_map.get_or_create("b");
|
||||||
|
|||||||
@@ -437,13 +437,13 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
ConstantDrift, EPSILON, Game, Gaussian, ITERATIONS, IndexMap, P_DRAW, Player,
|
ConstantDrift, EPSILON, Game, Gaussian, ITERATIONS, KeyTable, P_DRAW, Player,
|
||||||
arena::ScratchArena,
|
arena::ScratchArena,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_init() {
|
fn test_init() {
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
let a = index_map.get_or_create("a");
|
let a = index_map.get_or_create("a");
|
||||||
let b = index_map.get_or_create("b");
|
let b = index_map.get_or_create("b");
|
||||||
@@ -513,7 +513,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_one_batch() {
|
fn test_one_batch() {
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
let a = index_map.get_or_create("a");
|
let a = index_map.get_or_create("a");
|
||||||
let b = index_map.get_or_create("b");
|
let b = index_map.get_or_create("b");
|
||||||
@@ -620,7 +620,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_learning_curves() {
|
fn test_learning_curves() {
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
let a = index_map.get_or_create("a");
|
let a = index_map.get_or_create("a");
|
||||||
let b = index_map.get_or_create("b");
|
let b = index_map.get_or_create("b");
|
||||||
@@ -674,7 +674,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_env_ttt() {
|
fn test_env_ttt() {
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
let a = index_map.get_or_create("a");
|
let a = index_map.get_or_create("a");
|
||||||
let b = index_map.get_or_create("b");
|
let b = index_map.get_or_create("b");
|
||||||
@@ -721,7 +721,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_teams() {
|
fn test_teams() {
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
let a = index_map.get_or_create("a");
|
let a = index_map.get_or_create("a");
|
||||||
let b = index_map.get_or_create("b");
|
let b = index_map.get_or_create("b");
|
||||||
@@ -811,7 +811,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_events() {
|
fn test_add_events() {
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
let a = index_map.get_or_create("a");
|
let a = index_map.get_or_create("a");
|
||||||
let b = index_map.get_or_create("b");
|
let b = index_map.get_or_create("b");
|
||||||
@@ -900,7 +900,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_only_add_events() {
|
fn test_only_add_events() {
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
let a = index_map.get_or_create("a");
|
let a = index_map.get_or_create("a");
|
||||||
let b = index_map.get_or_create("b");
|
let b = index_map.get_or_create("b");
|
||||||
@@ -989,7 +989,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_log_evidence() {
|
fn test_log_evidence() {
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
let a = index_map.get_or_create("a");
|
let a = index_map.get_or_create("a");
|
||||||
let b = index_map.get_or_create("b");
|
let b = index_map.get_or_create("b");
|
||||||
@@ -1048,7 +1048,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_events_with_time() {
|
fn test_add_events_with_time() {
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
let a = index_map.get_or_create("a");
|
let a = index_map.get_or_create("a");
|
||||||
let b = index_map.get_or_create("b");
|
let b = index_map.get_or_create("b");
|
||||||
@@ -1237,7 +1237,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_1vs1_weighted() {
|
fn test_1vs1_weighted() {
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = KeyTable::new();
|
||||||
|
|
||||||
let a = index_map.get_or_create("a");
|
let a = index_map.get_or_create("a");
|
||||||
let b = index_map.get_or_create("b");
|
let b = index_map.get_or_create("b");
|
||||||
|
|||||||
72
src/key_table.rs
Normal file
72
src/key_table.rs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
use std::{
|
||||||
|
borrow::{Borrow, ToOwned},
|
||||||
|
collections::HashMap,
|
||||||
|
hash::Hash,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::Index;
|
||||||
|
|
||||||
|
/// Maps user keys to internal `Index` handles.
|
||||||
|
///
|
||||||
|
/// Renamed from the former `IndexMap` to avoid colliding with the `indexmap`
|
||||||
|
/// crate. Power users can promote `&K` to `Index` via `get_or_create` and
|
||||||
|
/// skip the lookup on subsequent hot-path calls.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct KeyTable<K>(HashMap<K, Index>);
|
||||||
|
|
||||||
|
impl<K> KeyTable<K>
|
||||||
|
where
|
||||||
|
K: Eq + Hash,
|
||||||
|
{
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(HashMap::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get<Q: ?Sized + Hash + Eq + ToOwned<Owned = K>>(&self, k: &Q) -> Option<Index>
|
||||||
|
where
|
||||||
|
K: Borrow<Q>,
|
||||||
|
{
|
||||||
|
self.0.get(k).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_or_create<Q: ?Sized + Hash + Eq + ToOwned<Owned = K>>(&mut self, k: &Q) -> Index
|
||||||
|
where
|
||||||
|
K: Borrow<Q>,
|
||||||
|
{
|
||||||
|
if let Some(idx) = self.0.get(k) {
|
||||||
|
*idx
|
||||||
|
} else {
|
||||||
|
let idx = Index::from(self.0.len());
|
||||||
|
self.0.insert(k.to_owned(), idx);
|
||||||
|
idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn key(&self, idx: Index) -> Option<&K> {
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.find(|&(_, value)| *value == idx)
|
||||||
|
.map(|(key, _)| key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keys(&self) -> impl Iterator<Item = &K> {
|
||||||
|
self.0.keys()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K> Default for KeyTable<K>
|
||||||
|
where
|
||||||
|
K: Eq + Hash,
|
||||||
|
{
|
||||||
|
fn default() -> Self {
|
||||||
|
KeyTable::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/lib.rs
58
src/lib.rs
@@ -1,9 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
borrow::{Borrow, ToOwned},
|
|
||||||
cmp::Reverse,
|
cmp::Reverse,
|
||||||
collections::HashMap,
|
|
||||||
f64::consts::{FRAC_1_SQRT_2, FRAC_2_SQRT_PI, SQRT_2},
|
f64::consts::{FRAC_1_SQRT_2, FRAC_2_SQRT_PI, SQRT_2},
|
||||||
hash::Hash,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod agent;
|
pub mod agent;
|
||||||
@@ -17,6 +14,7 @@ pub(crate) mod factor;
|
|||||||
mod game;
|
mod game;
|
||||||
pub mod gaussian;
|
pub mod gaussian;
|
||||||
mod history;
|
mod history;
|
||||||
|
pub mod key_table;
|
||||||
mod matrix;
|
mod matrix;
|
||||||
pub mod player;
|
pub mod player;
|
||||||
pub(crate) mod schedule;
|
pub(crate) mod schedule;
|
||||||
@@ -27,6 +25,7 @@ pub use error::InferenceError;
|
|||||||
pub use game::Game;
|
pub use game::Game;
|
||||||
pub use gaussian::Gaussian;
|
pub use gaussian::Gaussian;
|
||||||
pub use history::History;
|
pub use history::History;
|
||||||
|
pub use key_table::KeyTable;
|
||||||
use matrix::Matrix;
|
use matrix::Matrix;
|
||||||
pub use player::Player;
|
pub use player::Player;
|
||||||
pub use schedule::ScheduleReport;
|
pub use schedule::ScheduleReport;
|
||||||
@@ -54,59 +53,6 @@ impl From<usize> for Index {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IndexMap<K>(HashMap<K, Index>);
|
|
||||||
|
|
||||||
impl<K> IndexMap<K>
|
|
||||||
where
|
|
||||||
K: Eq + Hash,
|
|
||||||
{
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self(HashMap::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get<Q: ?Sized + Hash + Eq + ToOwned<Owned = K>>(&self, k: &Q) -> Option<Index>
|
|
||||||
where
|
|
||||||
K: Borrow<Q>,
|
|
||||||
{
|
|
||||||
self.0.get(k).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_or_create<Q: ?Sized + Hash + Eq + ToOwned<Owned = K>>(&mut self, k: &Q) -> Index
|
|
||||||
where
|
|
||||||
K: Borrow<Q>,
|
|
||||||
{
|
|
||||||
if let Some(idx) = self.0.get(k) {
|
|
||||||
*idx
|
|
||||||
} else {
|
|
||||||
let idx = Index::from(self.0.len());
|
|
||||||
|
|
||||||
self.0.insert(k.to_owned(), idx);
|
|
||||||
|
|
||||||
idx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn key(&self, idx: Index) -> Option<&K> {
|
|
||||||
self.0
|
|
||||||
.iter()
|
|
||||||
.find(|&(_, value)| *value == idx)
|
|
||||||
.map(|(key, _)| key)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn keys(&self) -> impl Iterator<Item = &K> {
|
|
||||||
self.0.keys()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K> Default for IndexMap<K>
|
|
||||||
where
|
|
||||||
K: Eq + Hash,
|
|
||||||
{
|
|
||||||
fn default() -> Self {
|
|
||||||
IndexMap::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn erfc(x: f64) -> f64 {
|
fn erfc(x: f64) -> f64 {
|
||||||
let z = x.abs();
|
let z = x.abs();
|
||||||
let t = 1.0 / (1.0 + z / 2.0);
|
let t = 1.0 / (1.0 + z / 2.0);
|
||||||
|
|||||||
Reference in New Issue
Block a user