robopoker/clustering/
histogram.rs1use crate::cards::observation::Observation;
2use crate::clustering::abstraction::Abstraction;
3use crate::Probability;
4use std::collections::BTreeMap;
5use std::ops::AddAssign;
6
7type Equity = Probability;
8
9#[derive(Debug, Default, Clone)]
14pub struct Histogram {
15 norm: usize,
16 weights: BTreeMap<Abstraction, usize>,
17}
18
19impl Histogram {
20 pub fn weight(&self, abstraction: &Abstraction) -> f32 {
21 self.weights.get(abstraction).copied().unwrap_or(0usize) as f32 / self.norm as f32
22 }
23
24 pub fn support(&self) -> Vec<&Abstraction> {
28 self.weights.keys().collect()
29 }
30
31 pub fn witness(mut self, abstraction: Abstraction) -> Self {
35 self.norm.add_assign(1usize);
36 self.weights
37 .entry(abstraction)
38 .or_insert(0usize)
39 .add_assign(1usize);
40 self
41 }
42
43 pub fn destroy(&mut self) {
47 self.norm = 0;
48 self.weights.clear();
49 }
50
51 pub fn absorb(&mut self, other: &Self) {
56 assert!(self.norm == other.norm);
57 self.norm += other.norm;
58 for (key, count) in other.weights.iter() {
59 self.weights
60 .entry(key.to_owned())
61 .or_insert(0usize)
62 .add_assign(count.to_owned());
63 }
64 }
65
66 pub fn equity(&self) -> Equity {
73 assert!(matches!(
74 self.weights.keys().next(),
75 Some(Abstraction::Equity(_))
76 ));
77 self.posterior().iter().map(|(x, y)| x * y).sum()
78 }
79
80 pub fn posterior(&self) -> Vec<(Equity, Probability)> {
91 assert!(matches!(
92 self.weights.keys().next(),
93 Some(Abstraction::Equity(_))
94 ));
95 self.weights
96 .iter()
97 .map(|(&key, &value)| (key, value as f32 / self.norm as f32))
98 .map(|(k, v)| (Equity::from(k), Probability::from(v)))
99 .collect()
100 }
101}
102
103impl From<Observation> for Histogram {
104 fn from(ref turn: Observation) -> Self {
105 assert!(turn.street() == crate::cards::street::Street::Turn);
106 turn.outnodes()
107 .into_iter()
108 .map(|river| Abstraction::from(river.equity()))
109 .collect::<Vec<Abstraction>>()
110 .into()
111 }
112}
113
114impl From<Vec<Abstraction>> for Histogram {
115 fn from(a: Vec<Abstraction>) -> Self {
116 a.into_iter()
117 .fold(Histogram::default(), |hist, abs| hist.witness(abs))
118 }
119}
120
121impl std::fmt::Display for Histogram {
122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123 let ref distribution = self.posterior();
126 let n_x_bins = 32;
128 let ref mut bins = vec![0.0; n_x_bins];
129 for (key, value) in distribution {
130 let x = key * n_x_bins as f32;
131 let x = x.floor() as usize;
132 let x = x.min(n_x_bins - 1);
133 bins[x] += value;
134 }
135 writeln!(f)?;
137 let n_y_bins = 10;
138 for y in (1..=n_y_bins).rev() {
139 for bin in bins.iter().copied() {
140 if bin >= y as f32 / n_y_bins as f32 {
141 write!(f, "█")?;
142 } else if bin >= y as f32 / n_y_bins as f32 - 0.75 / n_y_bins as f32 {
143 write!(f, "▆")?;
144 } else if bin >= y as f32 / n_y_bins as f32 - 0.50 / n_y_bins as f32 {
145 write!(f, "▄")?;
146 } else if bin >= y as f32 / n_y_bins as f32 - 0.25 / n_y_bins as f32 {
147 write!(f, "▂")?;
148 } else {
149 write!(f, " ")?;
150 }
151 }
152 writeln!(f)?;
153 }
154 for _ in 0..n_x_bins {
156 write!(f, "-")?;
157 }
158 Ok(())
160 }
161}