diff --git a/.gitignore b/.gitignore index c0191f7..8b588ef 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ .env .swp profile.json -*.pgcopy \ No newline at end of file +*.pgcopy diff --git a/src/clustering/abstractor.rs b/src/clustering/abstractor.rs index 905eb81..f5de215 100644 --- a/src/clustering/abstractor.rs +++ b/src/clustering/abstractor.rs @@ -1,10 +1,8 @@ use crate::cards::isomorphism::Isomorphism; use crate::cards::observation::Observation; -// use crate::cards::observation::Observation as Equivalence; use crate::cards::street::Street; use crate::clustering::abstraction::Abstraction; use crate::clustering::histogram::Histogram; -// use crate::clustering::progress::Progress; use std::collections::BTreeMap; /// this is the output of the clustering module @@ -22,6 +20,9 @@ impl Abstractor { let mut map = BTreeMap::default(); map.extend(Self::load(Street::Turn).0); map.extend(Self::load(Street::Flop).0); + // TODO + // extend map with preflop + // alternatively, handle lossless preflop abstractions in Self::abstraction Self(map) } @@ -43,6 +44,15 @@ impl Abstractor { } /// lookup the pre-computed abstraction for the outer observation pub fn abstraction(&self, outer: &Isomorphism) -> Abstraction { + // TODO + // match on street + // river => compute equity on the fly** + // turn | flop => lookup + // preflop => isomorphism into Hole + // + // ** this is expensive ? + // ** could implement mc_equity to not iterate over villain cards exhaustively ? + // ** should check benchmarks to see how much this matters self.0 .get(outer) .cloned() diff --git a/src/clustering/metric.rs b/src/clustering/metric.rs index a5db4c3..78d269e 100644 --- a/src/clustering/metric.rs +++ b/src/clustering/metric.rs @@ -1,6 +1,5 @@ use crate::clustering::abstraction::Abstraction; use crate::clustering::histogram::Histogram; -// use crate::clustering::progress::Progress; use crate::clustering::xor::Pair; use std::collections::BTreeMap; @@ -24,7 +23,7 @@ impl Metric { /// we only have the luxury of this efficient O(N) calculation on Street::Turn, /// where the support is over the Abstraction::Equity(i8) variant. pub fn emd(&self, source: &Histogram, target: &Histogram) -> f32 { - match target.peek() { + match source.peek() { Abstraction::Equity(_) => Self::difference(source, target), Abstraction::Random(_) => self.wasserstein(source, target), Abstraction::Pocket(_) => unreachable!("no preflop emd"), diff --git a/src/clustering/sampling.rs b/src/clustering/sampling.rs index 0d2ad79..6038db5 100644 --- a/src/clustering/sampling.rs +++ b/src/clustering/sampling.rs @@ -3,11 +3,11 @@ use super::abstractor::Abstractor; use crate::cards::isomorphism::Isomorphism; use crate::mccfr::bucket::Bucket; use crate::mccfr::bucket::Path; -use crate::mccfr::data::Vertex; use crate::mccfr::edge::Edge; use crate::mccfr::node::Node; use crate::mccfr::player::Player; use crate::mccfr::profile::Profile; +use crate::mccfr::spot::Spot; use crate::play::game::Game; use crate::Probability; use rand::distributions::Distribution; @@ -35,7 +35,7 @@ impl Sampler { /// compared to chance sampling, internal sampling, or full tree sampling. /// /// i think this could also be modified into a recursive CFR calcuation - pub fn sample(&self, node: &Node, profile: &Profile) -> Vec<(Vertex, Edge)> { + pub fn sample(&self, node: &Node, profile: &Profile) -> Vec<(Spot, Edge)> { let mut children = self.children(node); // terminal nodes have no children and we sample all possible actions for the traverser if node.player() == profile.walker() || children.is_empty() { @@ -68,7 +68,7 @@ impl Sampler { /// produce the children of a Node. /// we may need some Trainer-level references to produce children - fn children(&self, node: &Node) -> Vec<(Vertex, Edge)> { + fn children(&self, node: &Node) -> Vec<(Spot, Edge)> { let ref game = node.datum().game(); let ref past = node.history().into_iter().collect::>(); game.children() @@ -79,16 +79,16 @@ impl Sampler { } /// extend a path with an Edge /// wrap the (Game, Bucket) in a Data - fn explore(&self, game: Game, edge: Edge, history: &Vec<&Edge>) -> (Vertex, Edge) { + fn explore(&self, game: Game, edge: Edge, history: &Vec<&Edge>) -> (Spot, Edge) { let mut history = history.clone(); history.push(&edge); (self.data(game, history), edge) } /// generate a Bucket from Game /// wrap the (Game, Bucket) in a Data - fn data(&self, game: Game, path: Vec<&Edge>) -> Vertex { + fn data(&self, game: Game, path: Vec<&Edge>) -> Spot { let bucket = self.bucket(&game, &path); - Vertex::from((game, bucket)) + Spot::from((game, bucket)) } /// inddd fn bucket(&self, game: &Game, path: &Vec<&Edge>) -> Bucket { diff --git a/src/mccfr/mod.rs b/src/mccfr/mod.rs index f540c56..a559e77 100644 --- a/src/mccfr/mod.rs +++ b/src/mccfr/mod.rs @@ -1,10 +1,10 @@ pub mod bucket; -pub mod data; pub mod edge; pub mod info; pub mod memory; pub mod node; pub mod player; pub mod profile; +pub mod spot; pub mod trainer; pub mod tree; diff --git a/src/mccfr/node.rs b/src/mccfr/node.rs index b1cf7ba..0bf90f7 100644 --- a/src/mccfr/node.rs +++ b/src/mccfr/node.rs @@ -1,7 +1,7 @@ use super::bucket::Bucket; use super::player::Player; -use crate::mccfr::data::Vertex; use crate::mccfr::edge::Edge; +use crate::mccfr::spot::Spot; use crate::play::continuation::Transition; use crate::Utility; use petgraph::graph::DiGraph; @@ -13,11 +13,11 @@ use std::ptr::NonNull; pub struct Node { graph: NonNull>, index: NodeIndex, - datum: Vertex, + datum: Spot, } -impl From<(NodeIndex, NonNull>, Vertex)> for Node { - fn from((index, graph, datum): (NodeIndex, NonNull>, Vertex)) -> Self { +impl From<(NodeIndex, NonNull>, Spot)> for Node { + fn from((index, graph, datum): (NodeIndex, NonNull>, Spot)) -> Self { Self { index, graph, @@ -28,7 +28,7 @@ impl From<(NodeIndex, NonNull>, Vertex)> for Node { /// collection of these three is what you would get in a Node, which may be too restrictive for a lot of the use so we'll se impl Node { - pub fn datum(&self) -> &Vertex { + pub fn datum(&self) -> &Spot { &self.datum } pub fn index(&self) -> NodeIndex { diff --git a/src/mccfr/data.rs b/src/mccfr/spot.rs similarity index 91% rename from src/mccfr/data.rs rename to src/mccfr/spot.rs index 489da90..242ced8 100644 --- a/src/mccfr/data.rs +++ b/src/mccfr/spot.rs @@ -4,18 +4,18 @@ use crate::mccfr::player::Player; use crate::play::continuation::Transition; use crate::play::game::Game; -pub struct Vertex { +pub struct Spot { game: Game, bucket: Bucket, } -impl From<(Game, Bucket)> for Vertex { +impl From<(Game, Bucket)> for Spot { fn from((game, bucket): (Game, Bucket)) -> Self { Self { game, bucket } } } -impl Vertex { +impl Spot { pub fn game(&self) -> &Game { &self.game } diff --git a/src/mccfr/trainer.rs b/src/mccfr/trainer.rs index 5ef34bb..f5a9305 100644 --- a/src/mccfr/trainer.rs +++ b/src/mccfr/trainer.rs @@ -1,8 +1,8 @@ -use super::data::Vertex; use super::edge::Edge; use super::node::Node; use super::player::Player; use super::profile::Profile; +use super::spot::Spot; use super::tree::Tree; use crate::clustering::sampling::Sampler; use petgraph::graph::NodeIndex; @@ -72,7 +72,7 @@ impl Explorer { /// recursively build the Tree from the given Node, according to the distribution defined by Profile. /// we assert the Tree property of every non-root Node having exactly one parent Edge /// we construct the appropriate references in self.attach() to ensure safety. - fn dfs(&mut self, head: Vertex, edge: Edge, root: NodeIndex) { + fn dfs(&mut self, head: Spot, edge: Edge, root: NodeIndex) { let head = self.witness(head); let head = self.tree.graph_mut().add_node(head); let edge = self.tree.graph_mut().add_edge(root, head, edge); @@ -87,7 +87,7 @@ impl Explorer { /// attach a Node to the Tree, /// update the Profile to witness the new Node /// update the InfoPartition to witness the new Node. - fn witness(&mut self, data: Vertex) -> Node { + fn witness(&mut self, data: Spot) -> Node { let player = data.player().clone(); let graph = self.tree.graph_ptr(); let count = self.tree.graph_ref().node_count(); @@ -106,13 +106,13 @@ impl Explorer { /// Game::root() -> Observation -> Abstraction /// /// NOT deterministic, hole cards are thread_rng - fn root(&self) -> Vertex { + fn root(&self) -> Spot { use crate::mccfr::bucket::Bucket; use crate::play::game::Game; let node = Game::root(); let path = self.sampler.path_abstraction(&Vec::new()); let abstraction = self.sampler.card_abstraction(&node); let bucket = Bucket::from((path, abstraction)); - Vertex::from((node, bucket)) + Spot::from((node, bucket)) } }