feat: added a Drift trait and a "default" ConstantDrift implementation
This commit is contained in:
60
README.md
60
README.md
@@ -11,6 +11,66 @@ Rust port of [TrueSkillThroughTime.py](https://github.com/glandfried/TrueSkillTh
|
||||
- [TrueSkill Through Time: Revisiting the History of Chess](https://www.microsoft.com/en-us/research/wp-content/uploads/2008/01/NIPS2007_0931.pdf)
|
||||
- [TrueSkill Through Time. The full scientific documentation](https://glandfried.github.io/publication/landfried2021-learning/)
|
||||
|
||||
## Drift
|
||||
|
||||
Skill drift models how a player's true skill can change between appearances. Each time a player reappears after a gap, their skill uncertainty is widened by the drift model before the new evidence is incorporated.
|
||||
|
||||
Drift is represented by the `Drift` trait:
|
||||
|
||||
```rust
|
||||
pub trait Drift: Copy + Debug {
|
||||
fn variance_delta(&self, elapsed: i64) -> f64;
|
||||
}
|
||||
```
|
||||
|
||||
`variance_delta` returns the amount to add to `σ²` given the elapsed time since the player last played. Internally, `Gaussian::forget` uses this to compute the new sigma: `σ_new = sqrt(σ² + variance_delta)`.
|
||||
|
||||
### ConstantDrift
|
||||
|
||||
The built-in `ConstantDrift` implements a linear random walk — skill uncertainty grows proportionally to time:
|
||||
|
||||
```
|
||||
variance_delta = elapsed * γ²
|
||||
```
|
||||
|
||||
This is the standard TrueSkill Through Time model. Use it by passing a `ConstantDrift(gamma)` when constructing a `Player`:
|
||||
|
||||
```rust
|
||||
use trueskill_tt::{Player, Gaussian, drift::ConstantDrift};
|
||||
|
||||
// gamma = 0.1 means skill can shift ~0.1 per time unit
|
||||
let player = Player::new(Gaussian::from_ms(0.0, 6.0), 1.0, ConstantDrift(0.1));
|
||||
```
|
||||
|
||||
### Custom drift
|
||||
|
||||
Implement `Drift` to express any other model. For example, a drift that saturates after a long absence (uncertainty grows with the square root of elapsed time instead of linearly):
|
||||
|
||||
```rust
|
||||
use trueskill_tt::drift::Drift;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct SqrtDrift {
|
||||
gamma: f64,
|
||||
}
|
||||
|
||||
impl Drift for SqrtDrift {
|
||||
fn variance_delta(&self, elapsed: i64) -> f64 {
|
||||
(elapsed as f64).sqrt() * self.gamma * self.gamma
|
||||
}
|
||||
}
|
||||
|
||||
let player = Player::new(Gaussian::from_ms(0.0, 6.0), 1.0, SqrtDrift { gamma: 0.5 });
|
||||
```
|
||||
|
||||
To use a custom drift type with `History`, use the `.drift()` builder method instead of `.gamma()`:
|
||||
|
||||
```rust
|
||||
let h = History::builder()
|
||||
.drift(SqrtDrift { gamma: 0.5 })
|
||||
.build();
|
||||
```
|
||||
|
||||
## Todo
|
||||
|
||||
- [x] Implement approx for Gaussian
|
||||
|
||||
Reference in New Issue
Block a user