use std::ops::Deref;
use std::fmt;
use std::fmt::Formatter;
pub trait ProgressReporter {
#[inline(always)] fn begin(&mut self, _max: u16) {}
#[inline(always)] fn end(&mut self) {}
fn progress(&mut self, current: u16);
}
impl ProgressReporter for () {
#[inline(always)] fn progress(&mut self, _current: u16) {}
}
#[derive(Copy, Clone)]
pub struct PrintProgress;
impl ProgressReporter for PrintProgress {
fn begin(&mut self, max: u16) {
println!("Searching (max {}):", max);
}
fn end(&mut self) {
println!(" DONE");
}
fn progress(&mut self, current: u16) {
println!(" {}", current);
}
}
pub trait StatsCollector {
#[inline(always)] fn pre(&mut self) {}
#[inline(always)] fn etc(&mut self) {}
#[inline(always)] fn recursive(&mut self) {}
#[inline(always)] fn tt_read(&mut self) {}
#[inline(always)] fn const_db_read(&mut self) {}
#[inline(always)] fn db_skip(&mut self, _nimber: u8) {}
#[inline(always)] fn db_cut(&mut self, _nimber: u8) {}
#[inline(always)] fn unknown(&mut self) {}
#[inline(always)] fn exact(&mut self, _nimber: u8) {}
#[inline(always)] fn reset(&mut self) {}
}
#[derive(Copy, Clone)]
pub enum SearchPhase { Pre = 0, ETC = 1, Recursive = 2 }
impl SearchPhase {
#[inline(always)] fn pre(&mut self) { *self = Self::Pre; }
#[inline(always)] fn etc(&mut self) { *self = Self::ETC; }
#[inline(always)] fn recursive(&mut self) { *self = Self::Recursive; }
#[inline(always)] fn end(&mut self) { *self = Self::Recursive; }
}
impl Default for SearchPhase {
#[inline(always)] fn default() -> Self { Self::Pre }
}
#[derive(Copy, Clone)]
pub enum EventType {
Exact = 0, Unknown = 1, TTCut = 2, ConstDbCut = 3, TTSkip = 4, ConstDbSkip = 5, TTRead = 6, ConstDbRead = 7
}
impl EventType {
const NAMES: [&'static str; 8] = [ "exact value", "undetermined/cut", "cut by TT", "cut by const db",
"skipped by TT", "skipped by const db", "TT reads", "const db reads" ];
#[inline(always)]
fn db_cut(tt: bool) -> Self {
if tt { EventType::TTCut } else { EventType::ConstDbCut }
}
#[inline(always)]
fn db_skip(tt: bool) -> Self {
if tt { EventType::TTSkip } else { EventType::ConstDbSkip }
}
}
impl fmt::Display for EventType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad(Self::NAMES[*self as usize])
}
}
#[derive(Default, Copy, Clone)]
pub struct EventCounters {
events_count: [[u64; 3]; 8]
}
macro_rules! fs { () => ("{:17} {:>10} {:>10} {:>10} {:>10}") }
macro_rules! fs_title { () => ("{:>17} {:>10} {:>10} {:>10} {:>10}") }
impl EventCounters {
#[inline(always)]
pub fn register_event(&mut self, phase: SearchPhase, event: EventType) {
self.events_count[event as usize][phase as usize] += 1;
}
#[inline(always)]
pub fn number_of_events(&self, phase: SearchPhase, event: EventType) -> u64 {
self.events_count[event as usize][phase as usize]
}
pub fn nodes_visited(&self) -> u64 {
self.returns_in_phase(SearchPhase::Pre) + self.returns_in_phase(SearchPhase::ETC) + self.returns_in_phase(SearchPhase::Recursive)
}
pub fn tt_hits(&self, phase: SearchPhase) -> u64 {
self.number_of_events(phase, EventType::TTCut) + self.number_of_events(phase, EventType::TTSkip)
}
pub fn const_db_hits(&self, phase: SearchPhase) -> u64 {
self.number_of_events(phase, EventType::ConstDbCut) + self.number_of_events(phase, EventType::ConstDbSkip)
}
pub fn returns_in_phase(&self, phase: SearchPhase) -> u64 {
let p = phase as usize;
let e = &self.events_count;
e[EventType::Exact as usize][p] + e[EventType::Unknown as usize][p]
+ e[EventType::TTCut as usize][p] + e[EventType::ConstDbCut as usize][p]
}
pub fn events_of_type(&self, event_type: EventType) -> u64 {
self.events_count[event_type as usize].iter().sum()
}
pub fn reset(&mut self) {
*self = Default::default();
}
fn print_row<T: fmt::Display>(f: &mut fmt::Formatter<'_>, title: T, pre: u64, etc: u64, recursive: u64) -> fmt::Result {
writeln!(f, fs!(), title, pre, etc, recursive, pre+etc+recursive)
}
fn print_event_stats(&self, f: &mut fmt::Formatter<'_>, event: EventType) -> fmt::Result {
Self::print_row(f, event,
self.number_of_events(SearchPhase::Pre, event),
self.number_of_events(SearchPhase::ETC, event),
self.number_of_events(SearchPhase::Recursive, event))
}
fn print_summarize<T: fmt::Display>(f: &mut fmt::Formatter<'_>, title: T, pre: u64, etc: u64, recursive: u64) -> fmt::Result {
writeln!(f, fs_title!(), title, pre, etc, recursive, pre+etc+recursive)
}
}
impl fmt::Display for EventCounters {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, fs_title!(), "phase" , "pre", "ETC", "recursive", "total")?;
for r in &[EventType::Exact, EventType::Unknown, EventType::TTCut, EventType::ConstDbCut] {
self.print_event_stats(f, *r)?;
}
EventCounters::print_summarize(f, "total",
self.returns_in_phase(SearchPhase::Pre),
self.returns_in_phase(SearchPhase::ETC),
self.returns_in_phase(SearchPhase::Recursive)
)?;
writeln!(f)?;
Self::print_row(f, "TT hits",
self.tt_hits(SearchPhase::Pre),
self.tt_hits(SearchPhase::ETC),
self.tt_hits(SearchPhase::Recursive))?;
self.print_event_stats(f, EventType::TTRead)?;
Self::print_row(f, "const db hits",
self.const_db_hits(SearchPhase::Pre),
self.const_db_hits(SearchPhase::ETC),
self.const_db_hits(SearchPhase::Recursive))?;
self.print_event_stats(f, EventType::ConstDbRead)?;
Ok(())
}
}
impl std::ops::AddAssign for EventCounters {
fn add_assign(&mut self, rhs: Self) {
*self += &rhs;
}
}
impl std::ops::AddAssign<&Self> for EventCounters {
fn add_assign(&mut self, rhs: &Self) {
for (ts, tr) in self.events_count.iter_mut().zip(rhs.events_count.iter()) {
for (s, r) in ts.iter_mut().zip(tr.iter()) {
*s += r;
}
}
}
}
impl std::ops::Add for EventCounters {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
self + &rhs
}
}
impl std::ops::Add<&Self> for EventCounters {
type Output = Self;
fn add(mut self, rhs: &Self) -> Self::Output {
self += rhs; self
}
}
impl<'a> std::iter::Sum<&'a EventCounters> for EventCounters {
fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
let mut result = EventCounters::default();
for e in iter { result += e; };
result
}
}
#[derive(Default)]
pub struct EventStats {
events: EventCounters,
phase: SearchPhase,
read_was_from_tt: bool
}
impl Deref for EventStats {
type Target = EventCounters;
fn deref(&self) -> &Self::Target {
&self.events
}
}
impl fmt::Display for EventStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.events.fmt(f)
}
}
impl StatsCollector for EventStats {
#[inline(always)] fn pre(&mut self) { self.phase.pre(); }
#[inline(always)] fn etc(&mut self) { self.phase.etc(); }
#[inline(always)] fn recursive(&mut self) { self.phase.recursive(); }
#[inline]
fn tt_read(&mut self) {
self.events.register_event(self.phase, EventType::TTRead);
self.read_was_from_tt = true;
}
#[inline]
fn const_db_read(&mut self) {
self.events.register_event(self.phase, EventType::ConstDbRead);
self.read_was_from_tt = false;
}
#[inline]
fn db_skip(&mut self, _nimber: u8) {
self.events.register_event(self.phase, EventType::db_skip(self.read_was_from_tt));
}
#[inline]
fn db_cut(&mut self, _nimber: u8) {
self.events.register_event(self.phase, EventType::db_cut(self.read_was_from_tt));
self.phase.end();
}
#[inline]
fn unknown(&mut self) {
self.events.register_event(self.phase, EventType::Unknown);
self.phase.end();
}
#[inline]
fn exact(&mut self, _nimber: u8) {
self.events.register_event(self.phase, EventType::Exact);
self.phase.end();
}
#[inline]
fn reset(&mut self) {
self.events.reset();
}
}
#[derive(Default)]
pub struct EventStatsAtLevels {
events: Vec<EventCounters>,
phase: SearchPhase,
level: usize, read_was_from_tt: bool
}
#[inline] fn enlarge_to_index<T: Default>(vec: &mut Vec<T>, index: usize) -> &mut T {
if index >= vec.len() {
vec.resize_with(index+1, Default::default);
}
unsafe { vec.get_unchecked_mut(index) }
}
impl EventStatsAtLevels {
pub fn total(&self) -> EventCounters {
self.events.iter().sum()
}
fn register_event(&mut self, event: EventType) {
enlarge_to_index(&mut self.events, self.level-1).register_event(self.phase, event);
}
fn register_return_event(&mut self, event: EventType) {
self.register_event(event);
self.phase.end();
self.level -= 1;
}
}
impl StatsCollector for EventStatsAtLevels {
#[inline(always)]
fn pre(&mut self) {
self.phase.pre();
self.level += 1;
}
#[inline(always)] fn etc(&mut self) { self.phase.etc(); }
#[inline(always)] fn recursive(&mut self) { self.phase.recursive(); }
#[inline(always)]
fn tt_read(&mut self) {
self.register_event(EventType::TTRead);
self.read_was_from_tt = true;
}
#[inline(always)]
fn const_db_read(&mut self) {
self.register_event(EventType::ConstDbRead);
self.read_was_from_tt = false;
}
#[inline(always)]
fn db_skip(&mut self, _nimber: u8) {
self.register_event(EventType::db_skip(self.read_was_from_tt));
}
#[inline(always)]
fn db_cut(&mut self, _nimber: u8) {
self.register_return_event(EventType::db_cut(self.read_was_from_tt));
}
#[inline(always)]
fn unknown(&mut self) {
self.register_return_event(EventType::Unknown);
}
#[inline(always)]
fn exact(&mut self, _nimber: u8) {
self.register_return_event(EventType::Exact);
}
#[inline]
fn reset(&mut self) {
assert_eq!(self.level, 0);
self.events.clear();
}
}
macro_rules! fs_level { () => ("{:4} {:>10}") }
impl fmt::Display for EventStatsAtLevels {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.total().fmt(f)?;
writeln!(f)?;
writeln!(f, fs_level!(), "deep", "nodes")?;
for (i, e) in self.events.iter().enumerate() {
writeln!(f, fs_level!(), i, e.nodes_visited())?;
}
Ok(())
}
}
macro_rules! ncf { () => ("{:>6} {:>10} {:>10} {:>10}") }
#[derive(Default)]
struct NimberOccurrences {
calculated: u64,
tt: u64,
const_db: u64
}
#[derive(Default)]
pub struct NimberStats {
number_of_nimber: Vec<NimberOccurrences>,
read_was_from_tt: bool
}
impl NimberStats {
fn register_nimber_from_db(&mut self, nimber: u8) {
let c = enlarge_to_index(&mut self.number_of_nimber, nimber as usize);
if self.read_was_from_tt { c.tt += 1; } else { c.const_db += 1; }
}
fn write_header(f: &mut Formatter<'_>) -> fmt::Result {
write!(f, ncf!(), "nimber", "calculated", "from: TT", "const db")
}
fn write_nimber(&self, f: &mut Formatter<'_>, nimber: u8) -> fmt::Result {
write!(f, ncf!(), nimber,
self.number_of_nimber[nimber as usize].calculated,
self.number_of_nimber[nimber as usize].tt,
self.number_of_nimber[nimber as usize].const_db)
}
}
impl fmt::Display for NimberStats {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if self.number_of_nimber.len() == 0 { return Ok(()); }
Self::write_header(f)?;
if self.number_of_nimber.len() == 1 { return self.write_nimber(f, 1); }
write!(f, " ")?; Self::write_header(f)?; writeln!(f)?;
let half = (self.number_of_nimber.len()+1) / 2;
for i in 0..half {
self.write_nimber(f, i as u8)?;
let r = i + half;
if r < self.number_of_nimber.len() {
write!(f, " ")?; self.write_nimber(f, r as u8)?;
}
writeln!(f)?;
}
Ok(())
}
}
impl StatsCollector for NimberStats {
#[inline(always)] fn tt_read(&mut self) { self.read_was_from_tt = true; }
#[inline(always)] fn const_db_read(&mut self) { self.read_was_from_tt = false; }
#[inline(always)] fn db_skip(&mut self, nimber: u8) { self.register_nimber_from_db(nimber); }
#[inline(always)] fn db_cut(&mut self, nimber: u8) { self.register_nimber_from_db(nimber); }
#[inline(always)] fn exact(&mut self, nimber: u8) {
enlarge_to_index(&mut self.number_of_nimber, nimber as usize).calculated += 1;
}
#[inline(always)] fn reset(&mut self) { self.number_of_nimber.clear(); }
}
impl StatsCollector for () {}
impl<SC1: StatsCollector> StatsCollector for (SC1,) {
#[inline(always)] fn pre(&mut self) { self.0.pre(); }
#[inline(always)] fn etc(&mut self) { self.0.etc(); }
#[inline(always)] fn recursive(&mut self) { self.0.recursive(); }
#[inline(always)] fn tt_read(&mut self) { self.0.tt_read(); }
#[inline(always)] fn const_db_read(&mut self) { self.0.const_db_read(); }
#[inline(always)] fn db_skip(&mut self, nimber: u8) { self.0.db_skip(nimber); }
#[inline(always)] fn db_cut(&mut self, nimber: u8) { self.0.db_cut(nimber); }
#[inline(always)] fn unknown(&mut self) { self.0.unknown(); }
#[inline(always)] fn exact(&mut self, nimber: u8) { self.0.exact(nimber); }
#[inline(always)] fn reset(&mut self) { self.0.reset(); }
}
impl<SC1: StatsCollector, SC2: StatsCollector> StatsCollector for (SC1, SC2) {
#[inline(always)] fn pre(&mut self) { self.0.pre(); self.1.pre(); }
#[inline(always)] fn etc(&mut self) { self.0.etc(); self.1.etc(); }
#[inline(always)] fn recursive(&mut self) { self.0.recursive(); self.1.recursive(); }
#[inline(always)] fn tt_read(&mut self) { self.0.tt_read(); self.1.tt_read(); }
#[inline(always)] fn const_db_read(&mut self) { self.0.const_db_read(); self.1.const_db_read(); }
#[inline(always)] fn db_skip(&mut self, nimber: u8) { self.0.db_skip(nimber); self.1.db_skip(nimber); }
#[inline(always)] fn db_cut(&mut self, nimber: u8) { self.0.db_cut(nimber); self.1.db_cut(nimber); }
#[inline(always)] fn unknown(&mut self) { self.0.unknown(); self.1.unknown(); }
#[inline(always)] fn exact(&mut self, nimber: u8) { self.0.exact(nimber); self.1.exact(nimber); }
#[inline(always)] fn reset(&mut self) { self.0.reset(); self.1.reset(); }
}
impl<SC1: StatsCollector, SC2: StatsCollector, SC3: StatsCollector> StatsCollector for (SC1, SC2, SC3) {
#[inline] fn pre(&mut self) {
self.0.pre(); self.1.pre(); self.2.pre();
}
#[inline] fn etc(&mut self) {
self.0.etc(); self.1.etc(); self.2.etc();
}
#[inline] fn recursive(&mut self) {
self.0.recursive(); self.1.recursive(); self.2.recursive();
}
#[inline] fn tt_read(&mut self) {
self.0.tt_read(); self.1.tt_read(); self.2.tt_read();
}
#[inline] fn const_db_read(&mut self) {
self.0.const_db_read(); self.1.const_db_read(); self.2.const_db_read();
}
#[inline] fn db_skip(&mut self, nimber: u8) {
self.0.db_skip(nimber); self.1.db_skip(nimber); self.2.db_skip(nimber);
}
#[inline] fn db_cut(&mut self, nimber: u8) {
self.0.db_cut(nimber); self.1.db_cut(nimber); self.2.db_cut(nimber);
}
#[inline] fn unknown(&mut self) {
self.0.unknown(); self.1.unknown(); self.2.unknown();
}
#[inline] fn exact(&mut self, nimber: u8) {
self.0.exact(nimber); self.1.exact(nimber); self.2.exact(nimber);
}
#[inline] fn reset(&mut self) {
self.0.reset(); self.1.reset(); self.2.reset();
}
}
impl<SC1: StatsCollector, SC2: StatsCollector, SC3: StatsCollector, SC4: StatsCollector> StatsCollector for (SC1, SC2, SC3, SC4) {
#[inline] fn pre(&mut self) {
self.0.pre(); self.1.pre(); self.2.pre(); self.3.pre();
}
#[inline] fn etc(&mut self) {
self.0.etc(); self.1.etc(); self.2.etc(); self.3.etc();
}
#[inline] fn recursive(&mut self) {
self.0.recursive(); self.1.recursive(); self.2.recursive(); self.3.recursive();
}
#[inline] fn tt_read(&mut self) {
self.0.tt_read(); self.1.tt_read(); self.2.tt_read(); self.3.tt_read();
}
#[inline] fn const_db_read(&mut self) {
self.0.const_db_read(); self.1.const_db_read(); self.2.const_db_read(); self.3.const_db_read();
}
#[inline] fn db_skip(&mut self, nimber: u8) {
self.0.db_skip(nimber); self.1.db_skip(nimber); self.2.db_skip(nimber); self.3.db_skip(nimber);
}
#[inline] fn db_cut(&mut self, nimber: u8) {
self.0.db_cut(nimber); self.1.db_cut(nimber); self.2.db_cut(nimber); self.3.db_cut(nimber);
}
#[inline] fn unknown(&mut self) {
self.0.unknown(); self.1.unknown(); self.2.unknown(); self.3.unknown();
}
#[inline] fn exact(&mut self, nimber: u8) {
self.0.exact(nimber); self.1.exact(nimber); self.2.exact(nimber); self.3.exact(nimber);
}
#[inline] fn reset(&mut self) {
self.0.reset(); self.1.reset(); self.2.reset(); self.3.reset();
}
}