Crates.io | bentobox |
lib.rs | bentobox |
version | 0.1.1 |
source | src |
created_at | 2023-10-11 18:55:07.166733 |
updated_at | 2023-10-11 18:56:23.461746 |
description | A fast, allocation-free Monte Carlo model of a top-N podium finish in racing events. |
homepage | |
repository | https://github.com/obsidiandynamics/bentobox |
max_upload_size | |
id | 1000552 |
size | 34,221 |
bentobox
A fast, allocation-free Monte Carlo model of a top-N podium finish in racing events. Derives probabilities for placing in arbitrary positions given only win probabilities. Also derives joint probability of multiple runners with arbitrary (exact and top-N) placings.
Circa 20M simulations/sec on a top-4 podium over 14 runners using the tinyrand RNG. Roughly 80% of time is spent in the RNG routine.
Sourced from examples/multi.rs
.
use bentobox::mc;
use bentobox::probs::SliceExt;
use bentobox::selection::Selection;
use tinyrand::StdRand;
use bentobox::capture::{CaptureMut, Capture};
// probs taken from a popular website
let mut probs = vec![
1.0 / 11.0,
1.0 / 41.0,
1.0 / 18.0,
1.0 / 12.0,
1.0 / 91.0,
1.0 / 101.0,
1.0 / 4.8,
1.0 / 14.0,
1.0 / 2.9,
1.0 / 91.0,
1.0 / 9.0,
1.0 / 91.0,
1.0 / 5.0,
1.0 / 21.0,
];
// force probs to sum to 1 and extract the approximate overround used (multiplicative method assumed)
let overround = probs.normalize();
println!("fair probs: {probs:?}");
println!("overround: {overround:.3}");
// create an MC engine for reuse
let mut engine = mc::MonteCarloEngine::default()
.with_iterations(10_000)
.with_probabilities(Capture::Borrowed(&probs))
.with_podium_places(4)
.with_rand(CaptureMut::Owned(StdRand::default()));
// simulate top-N rankings for all runners
// NOTE: rankings and runner numbers are zero-based
for runner in 0..probs.len() {
println!("runner: {runner}");
for rank in 0..4 {
let frac = engine.simulate(&vec![Selection::Top { runner, rank }]);
println!(
" rank: 0~{rank}, prob: {}, fair price: {:.3}, market odds: {:.3}",
frac.quotient(),
1.0 / frac.quotient(),
1.0 / frac.quotient() / overround
);
}
}
// simulate a same-race multi for a chosen selection vector
let selections = vec![
Selection::Top { runner: 0, rank: 0 },
Selection::Top { runner: 1, rank: 1 },
Selection::Top { runner: 2, rank: 2 },
];
let frac = engine.simulate(&selections);
println!(
"probability of {selections:?}: {}, fair price: {:.3}, market odds: {:.3}",
frac.quotient(),
1.0 / frac.quotient(),
1.0 / frac.quotient() / overround
);