Skip to content

Commit 950c288

Browse files
committed
fixed Abstrasction serialization; WIP naming and Profiler/Encoder/Trainer relations
1 parent f0f3130 commit 950c288

File tree

8 files changed

+111
-51
lines changed

8 files changed

+111
-51
lines changed

src/clustering/abstraction.rs

+57-20
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::cards::hand::Hand;
12
use crate::cards::hole::Hole;
23
use crate::transport::support::Support;
34
use crate::Probability;
@@ -6,47 +7,57 @@ use std::u64;
67

78
/// Abstraction represents a lookup value for a given set of Observations.
89
///
9-
/// - 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.
10+
/// - 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.
1011
/// - Pre-Flop: we do not use any abstraction, rather store the 169 strategically-unique hands as u64.
1112
/// - Other Streets: we use a u64 to represent the hash signature of the centroid Histogram over lower layers of abstraction.
1213
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, PartialOrd, Ord)]
1314
pub enum Abstraction {
14-
Equity(i8), // river
15-
Random(u64), // flop, turn
15+
Equity(u8), // river
16+
Unique(u64), // flop, turn
1617
Pocket(Hole), // preflop
1718
}
1819

1920
impl Support for Abstraction {}
2021

2122
impl Abstraction {
22-
pub const fn range() -> &'static [Self] {
23-
&Self::BUCKETS
24-
}
2523
pub fn random() -> Self {
26-
Self::Random(rand::random::<u64>())
24+
Self::Unique(loop {
25+
let x = rand::random::<u64>();
26+
if x & EQUITY_TAG == EQUITY_TAG {
27+
continue;
28+
}
29+
if x & POCKET_TAG == POCKET_TAG {
30+
continue;
31+
}
32+
break x;
33+
})
2734
}
28-
fn quantize(p: Probability) -> i8 {
29-
(p * Probability::from(Self::N)).round() as i8
35+
fn quantize(p: Probability) -> u8 {
36+
(p * Probability::from(Self::N)).round() as u8
3037
}
31-
fn floatize(q: i8) -> Probability {
38+
fn floatize(q: u8) -> Probability {
3239
Probability::from(q) / Probability::from(Self::N)
3340
}
34-
const N: i8 = 63;
41+
42+
const N: u8 = 63;
3543
const BUCKETS: [Self; Self::N as usize + 1] = Self::buckets();
3644
const fn buckets() -> [Self; Self::N as usize + 1] {
3745
let mut buckets = [Self::Equity(0); Self::N as usize + 1];
3846
let mut i = 0;
3947
while i <= Self::N {
40-
buckets[i as usize] = Self::Equity(i as i8);
48+
buckets[i as usize] = Self::Equity(i as u8);
4149
i += 1;
4250
}
4351
buckets
4452
}
53+
pub const fn range() -> &'static [Self] {
54+
&Self::BUCKETS
55+
}
4556
}
4657

4758
/// probability isomorphism
4859
///
49-
/// for river, we use a i8 to represent the equity bucket,
60+
/// for river, we use a u8 to represent the equity bucket,
5061
/// i.e. Equity(0) is the 0% equity bucket,
5162
/// and Equity(N) is the 100% equity bucket.
5263
impl From<Probability> for Abstraction {
@@ -60,27 +71,33 @@ impl From<Abstraction> for Probability {
6071
fn from(abstraction: Abstraction) -> Self {
6172
match abstraction {
6273
Abstraction::Equity(n) => Abstraction::floatize(n),
63-
Abstraction::Random(_) => unreachable!("no cluster into probability"),
74+
Abstraction::Unique(_) => unreachable!("no cluster into probability"),
6475
Abstraction::Pocket(_) => unreachable!("no preflop into probability"),
6576
}
6677
}
6778
}
6879

80+
const EQUITY_TAG: u64 = 0xEEE;
81+
const POCKET_TAG: u64 = 0xFFF;
6982
/// u64 isomorphism
7083
///
7184
/// conversion to u64 for SQL storage.
7285
impl From<Abstraction> for u64 {
7386
fn from(a: Abstraction) -> Self {
7487
match a {
75-
Abstraction::Random(n) => n,
76-
Abstraction::Equity(_) => unreachable!("no equity into u64"),
77-
Abstraction::Pocket(_) => unreachable!("no preflop into u64"),
88+
Abstraction::Unique(n) => n,
89+
Abstraction::Equity(e) => (EQUITY_TAG << 52) | (e as u64 & 0xFF) << 44,
90+
Abstraction::Pocket(h) => (POCKET_TAG << 52) | u64::from(Hand::from(h)),
7891
}
7992
}
8093
}
8194
impl From<u64> for Abstraction {
8295
fn from(n: u64) -> Self {
83-
Self::Random(n)
96+
match n >> 52 {
97+
EQUITY_TAG => Self::Equity(((n >> 44) & 0xFF) as u8),
98+
POCKET_TAG => Self::Pocket(Hole::from(Hand::from(n & 0x000FFFFFFFFFFFFF))),
99+
_ => Self::Unique(n),
100+
}
84101
}
85102
}
86103

@@ -94,7 +111,7 @@ impl From<Abstraction> for i64 {
94111
}
95112
impl From<i64> for Abstraction {
96113
fn from(n: i64) -> Self {
97-
Self::Random(n as u64)
114+
Self::Unique(n as u64)
98115
}
99116
}
100117

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

122141
#[test]
123142
fn is_quantize_inverse_floatize() {
@@ -136,4 +155,22 @@ mod tests {
136155
assert!(q == i);
137156
}
138157
}
158+
159+
#[test]
160+
fn bijective_u64_random() {
161+
let random = Abstraction::random();
162+
assert_eq!(random, Abstraction::from(u64::from(random)));
163+
}
164+
165+
#[test]
166+
fn bijective_u64_equity() {
167+
let equity = Abstraction::Equity(Abstraction::N / 2);
168+
assert_eq!(equity, Abstraction::from(u64::from(equity)));
169+
}
170+
171+
#[test]
172+
fn bijective_u64_pocket() {
173+
let pocket = Abstraction::Pocket(Hole::from(Observation::from(Street::Pref)));
174+
assert_eq!(pocket, Abstraction::from(u64::from(pocket)));
175+
}
139176
}

src/clustering/equity.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ impl Measure for Equity {
2020
type Y = Abstraction; //::Equity(i8) variant
2121
fn distance(&self, x: &Self::X, y: &Self::Y) -> f32 {
2222
match (x, y) {
23-
(Self::X::Equity(x), Self::Y::Equity(y)) => (x - y).abs() as f32,
23+
(Self::X::Equity(x), Self::Y::Equity(y)) => (*x as f32 - *y as f32).abs(),
2424
_ => unreachable!("only equity distance for equity abstractions. perhaps Self::X should be f32 to avoid this pattern match"),
2525
}
2626
}

src/clustering/layer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ impl Layer {
304304
}
305305

306306
/// create a progress bar for kmeans clustering
307-
fn progress(n: usize) -> indicatif::ProgressBar {
307+
pub fn progress(n: usize) -> indicatif::ProgressBar {
308308
let tick = std::time::Duration::from_secs(5);
309309
let style = "[{elapsed}] {spinner} {wide_bar} ETA {eta}";
310310
let style = indicatif::ProgressStyle::with_template(style).unwrap();

src/clustering/metric.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl Measure for Metric {
1818
type Y = Abstraction;
1919
fn distance(&self, x: &Self::X, y: &Self::Y) -> f32 {
2020
match (x, y) {
21-
(Self::X::Random(_), Self::Y::Random(_)) => self.lookup(x, y),
21+
(Self::X::Unique(_), Self::Y::Unique(_)) => self.lookup(x, y),
2222
(Self::X::Equity(_), Self::Y::Equity(_)) => Equity.distance(x, y),
2323
(Self::X::Pocket(_), Self::Y::Pocket(_)) => unreachable!("no preflop distance"),
2424
_ => unreachable!(),
@@ -43,7 +43,7 @@ impl Coupling for Metric {
4343
impl Metric {
4444
pub fn emd(&self, source: &Histogram, target: &Histogram) -> f32 {
4545
match source.peek() {
46-
Abstraction::Random(_) => self.greedy(source, target),
46+
Abstraction::Unique(_) => self.greedy(source, target),
4747
Abstraction::Equity(_) => Equity::variation(source, target),
4848
Abstraction::Pocket(_) => unreachable!("no preflop emd"),
4949
}

src/main.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ fn main() {
66
// The k-means earth mover's distance hand-clustering algorithm.
77
clustering::encoding::Encoder::learn();
88
// Monet Carlo counter-factual regret minimization. External sampling, alternating regret updates, linear weighting schedules.
9-
mccfr::minimizer::Blueprint::load().train();
9+
mccfr::minimizer::Trainer::load().train();
1010
// After 100s of CPU-days of training in the arena, the CPU is ready to see you.
1111
play::game::Game::play();
1212
}
@@ -77,7 +77,7 @@ fn logging() {
7777
.expect("time moves slow")
7878
.as_secs();
7979
let file = simplelog::WriteLogger::new(
80-
log::LevelFilter::Trace,
80+
log::LevelFilter::Info,
8181
config.clone(),
8282
std::fs::File::create(format!("logs/{}.log", time)).expect("create log file"),
8383
);

0 commit comments

Comments
 (0)