use crate::cards::observation::Observation;
use crate::clustering::abstraction::Abstraction;
use crate::Probability;
use std::collections::BTreeMap;
use std::ops::AddAssign;
type Equity = Probability;
#[derive(Debug, Default, Clone)]
pub struct Histogram {
norm: usize,
weights: BTreeMap<Abstraction, usize>,
}
impl Histogram {
pub fn weight(&self, abstraction: &Abstraction) -> f32 {
self.weights.get(abstraction).copied().unwrap_or(0usize) as f32 / self.norm as f32
}
pub fn support(&self) -> Vec<&Abstraction> {
self.weights.keys().collect()
}
pub fn witness(mut self, abstraction: Abstraction) -> Self {
self.norm.add_assign(1usize);
self.weights
.entry(abstraction)
.or_insert(0usize)
.add_assign(1usize);
self
}
pub fn destroy(&mut self) {
self.norm = 0;
self.weights.clear();
}
pub fn absorb(&mut self, other: &Self) {
assert!(self.norm == other.norm);
self.norm += other.norm;
for (key, count) in other.weights.iter() {
self.weights
.entry(key.to_owned())
.or_insert(0usize)
.add_assign(count.to_owned());
}
}
pub fn equity(&self) -> Equity {
assert!(matches!(
self.weights.keys().next(),
Some(Abstraction::Equity(_))
));
self.posterior().iter().map(|(x, y)| x * y).sum()
}
pub fn posterior(&self) -> Vec<(Equity, Probability)> {
assert!(matches!(
self.weights.keys().next(),
Some(Abstraction::Equity(_))
));
self.weights
.iter()
.map(|(&key, &value)| (key, value as f32 / self.norm as f32))
.map(|(k, v)| (Equity::from(k), Probability::from(v)))
.collect()
}
}
impl From<Observation> for Histogram {
fn from(ref turn: Observation) -> Self {
assert!(turn.street() == crate::cards::street::Street::Turn);
turn.outnodes()
.into_iter()
.map(|river| Abstraction::from(river.equity()))
.collect::<Vec<Abstraction>>()
.into()
}
}
impl From<Vec<Abstraction>> for Histogram {
fn from(a: Vec<Abstraction>) -> Self {
a.into_iter()
.fold(Histogram::default(), |hist, abs| hist.witness(abs))
}
}
impl std::fmt::Display for Histogram {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ref distribution = self.posterior();
let n_x_bins = 32;
let ref mut bins = vec![0.0; n_x_bins];
for (key, value) in distribution {
let x = key * n_x_bins as f32;
let x = x.floor() as usize;
let x = x.min(n_x_bins - 1);
bins[x] += value;
}
writeln!(f)?;
let n_y_bins = 10;
for y in (1..=n_y_bins).rev() {
for bin in bins.iter().copied() {
if bin >= y as f32 / n_y_bins as f32 {
write!(f, "█")?;
} else if bin >= y as f32 / n_y_bins as f32 - 0.75 / n_y_bins as f32 {
write!(f, "▆")?;
} else if bin >= y as f32 / n_y_bins as f32 - 0.50 / n_y_bins as f32 {
write!(f, "▄")?;
} else if bin >= y as f32 / n_y_bins as f32 - 0.25 / n_y_bins as f32 {
write!(f, "▂")?;
} else {
write!(f, " ")?;
}
}
writeln!(f)?;
}
for _ in 0..n_x_bins {
write!(f, "-")?;
}
Ok(())
}
}