Skip to content

Commit

Permalink
fixed Abstrasction serialization; WIP naming and Profiler/Encoder/Tra…
Browse files Browse the repository at this point in the history
…iner relations
  • Loading branch information
krukah committed Oct 28, 2024
1 parent f0f3130 commit 950c288
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 51 deletions.
77 changes: 57 additions & 20 deletions src/clustering/abstraction.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::cards::hand::Hand;
use crate::cards::hole::Hole;
use crate::transport::support::Support;
use crate::Probability;
Expand All @@ -6,47 +7,57 @@ use std::u64;

/// Abstraction represents a lookup value for a given set of Observations.
///
/// - River: we use a i8 to represent the equity bucket, i.e. Equity(0) is the worst bucket, and Equity(50) is the best bucket.
/// - River: we use a u8 to represent the equity bucket, i.e. Equity(0) is the worst bucket, and Equity(50) is the best bucket.
/// - Pre-Flop: we do not use any abstraction, rather store the 169 strategically-unique hands as u64.
/// - Other Streets: we use a u64 to represent the hash signature of the centroid Histogram over lower layers of abstraction.
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, PartialOrd, Ord)]
pub enum Abstraction {
Equity(i8), // river
Random(u64), // flop, turn
Equity(u8), // river
Unique(u64), // flop, turn
Pocket(Hole), // preflop
}

impl Support for Abstraction {}

impl Abstraction {
pub const fn range() -> &'static [Self] {
&Self::BUCKETS
}
pub fn random() -> Self {
Self::Random(rand::random::<u64>())
Self::Unique(loop {
let x = rand::random::<u64>();
if x & EQUITY_TAG == EQUITY_TAG {
continue;
}
if x & POCKET_TAG == POCKET_TAG {
continue;
}
break x;
})
}
fn quantize(p: Probability) -> i8 {
(p * Probability::from(Self::N)).round() as i8
fn quantize(p: Probability) -> u8 {
(p * Probability::from(Self::N)).round() as u8
}
fn floatize(q: i8) -> Probability {
fn floatize(q: u8) -> Probability {
Probability::from(q) / Probability::from(Self::N)
}
const N: i8 = 63;

const N: u8 = 63;
const BUCKETS: [Self; Self::N as usize + 1] = Self::buckets();
const fn buckets() -> [Self; Self::N as usize + 1] {
let mut buckets = [Self::Equity(0); Self::N as usize + 1];
let mut i = 0;
while i <= Self::N {
buckets[i as usize] = Self::Equity(i as i8);
buckets[i as usize] = Self::Equity(i as u8);
i += 1;
}
buckets
}
pub const fn range() -> &'static [Self] {
&Self::BUCKETS
}
}

/// probability isomorphism
///
/// for river, we use a i8 to represent the equity bucket,
/// for river, we use a u8 to represent the equity bucket,
/// i.e. Equity(0) is the 0% equity bucket,
/// and Equity(N) is the 100% equity bucket.
impl From<Probability> for Abstraction {
Expand All @@ -60,27 +71,33 @@ impl From<Abstraction> for Probability {
fn from(abstraction: Abstraction) -> Self {
match abstraction {
Abstraction::Equity(n) => Abstraction::floatize(n),
Abstraction::Random(_) => unreachable!("no cluster into probability"),
Abstraction::Unique(_) => unreachable!("no cluster into probability"),
Abstraction::Pocket(_) => unreachable!("no preflop into probability"),
}
}
}

const EQUITY_TAG: u64 = 0xEEE;
const POCKET_TAG: u64 = 0xFFF;
/// u64 isomorphism
///
/// conversion to u64 for SQL storage.
impl From<Abstraction> for u64 {
fn from(a: Abstraction) -> Self {
match a {
Abstraction::Random(n) => n,
Abstraction::Equity(_) => unreachable!("no equity into u64"),
Abstraction::Pocket(_) => unreachable!("no preflop into u64"),
Abstraction::Unique(n) => n,
Abstraction::Equity(e) => (EQUITY_TAG << 52) | (e as u64 & 0xFF) << 44,
Abstraction::Pocket(h) => (POCKET_TAG << 52) | u64::from(Hand::from(h)),
}
}
}
impl From<u64> for Abstraction {
fn from(n: u64) -> Self {
Self::Random(n)
match n >> 52 {
EQUITY_TAG => Self::Equity(((n >> 44) & 0xFF) as u8),
POCKET_TAG => Self::Pocket(Hole::from(Hand::from(n & 0x000FFFFFFFFFFFFF))),
_ => Self::Unique(n),
}
}
}

Expand All @@ -94,7 +111,7 @@ impl From<Abstraction> for i64 {
}
impl From<i64> for Abstraction {
fn from(n: i64) -> Self {
Self::Random(n as u64)
Self::Unique(n as u64)
}
}

Expand All @@ -108,7 +125,7 @@ impl From<Hole> for Abstraction {
impl std::fmt::Display for Abstraction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Random(n) => write!(f, "{:016x}", n),
Self::Unique(n) => write!(f, "{:016x}", n),
Self::Equity(n) => write!(f, "Equity({:00.2})", Self::floatize(*n)),
Self::Pocket(h) => write!(f, "Pocket({})", h),
}
Expand All @@ -118,6 +135,8 @@ impl std::fmt::Display for Abstraction {
#[cfg(test)]
mod tests {
use super::*;
use crate::cards::observation::Observation;
use crate::cards::street::Street;

#[test]
fn is_quantize_inverse_floatize() {
Expand All @@ -136,4 +155,22 @@ mod tests {
assert!(q == i);
}
}

#[test]
fn bijective_u64_random() {
let random = Abstraction::random();
assert_eq!(random, Abstraction::from(u64::from(random)));
}

#[test]
fn bijective_u64_equity() {
let equity = Abstraction::Equity(Abstraction::N / 2);
assert_eq!(equity, Abstraction::from(u64::from(equity)));
}

#[test]
fn bijective_u64_pocket() {
let pocket = Abstraction::Pocket(Hole::from(Observation::from(Street::Pref)));
assert_eq!(pocket, Abstraction::from(u64::from(pocket)));
}
}
2 changes: 1 addition & 1 deletion src/clustering/equity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl Measure for Equity {
type Y = Abstraction; //::Equity(i8) variant
fn distance(&self, x: &Self::X, y: &Self::Y) -> f32 {
match (x, y) {
(Self::X::Equity(x), Self::Y::Equity(y)) => (x - y).abs() as f32,
(Self::X::Equity(x), Self::Y::Equity(y)) => (*x as f32 - *y as f32).abs(),
_ => unreachable!("only equity distance for equity abstractions. perhaps Self::X should be f32 to avoid this pattern match"),
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/clustering/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ impl Layer {
}

/// create a progress bar for kmeans clustering
fn progress(n: usize) -> indicatif::ProgressBar {
pub fn progress(n: usize) -> indicatif::ProgressBar {
let tick = std::time::Duration::from_secs(5);
let style = "[{elapsed}] {spinner} {wide_bar} ETA {eta}";
let style = indicatif::ProgressStyle::with_template(style).unwrap();
Expand Down
4 changes: 2 additions & 2 deletions src/clustering/metric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl Measure for Metric {
type Y = Abstraction;
fn distance(&self, x: &Self::X, y: &Self::Y) -> f32 {
match (x, y) {
(Self::X::Random(_), Self::Y::Random(_)) => self.lookup(x, y),
(Self::X::Unique(_), Self::Y::Unique(_)) => self.lookup(x, y),
(Self::X::Equity(_), Self::Y::Equity(_)) => Equity.distance(x, y),
(Self::X::Pocket(_), Self::Y::Pocket(_)) => unreachable!("no preflop distance"),
_ => unreachable!(),
Expand All @@ -43,7 +43,7 @@ impl Coupling for Metric {
impl Metric {
pub fn emd(&self, source: &Histogram, target: &Histogram) -> f32 {
match source.peek() {
Abstraction::Random(_) => self.greedy(source, target),
Abstraction::Unique(_) => self.greedy(source, target),
Abstraction::Equity(_) => Equity::variation(source, target),
Abstraction::Pocket(_) => unreachable!("no preflop emd"),
}
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ fn main() {
// The k-means earth mover's distance hand-clustering algorithm.
clustering::encoding::Encoder::learn();
// Monet Carlo counter-factual regret minimization. External sampling, alternating regret updates, linear weighting schedules.
mccfr::minimizer::Blueprint::load().train();
mccfr::minimizer::Trainer::load().train();
// After 100s of CPU-days of training in the arena, the CPU is ready to see you.
play::game::Game::play();
}
Expand Down Expand Up @@ -77,7 +77,7 @@ fn logging() {
.expect("time moves slow")
.as_secs();
let file = simplelog::WriteLogger::new(
log::LevelFilter::Trace,
log::LevelFilter::Info,
config.clone(),
std::fs::File::create(format!("logs/{}.log", time)).expect("create log file"),
);
Expand Down
Loading

0 comments on commit 950c288

Please sign in to comment.