diff options
Diffstat (limited to 'src/eval_tune/compare_ecm_nodes.py')
| -rw-r--r-- | src/eval_tune/compare_ecm_nodes.py | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/src/eval_tune/compare_ecm_nodes.py b/src/eval_tune/compare_ecm_nodes.py new file mode 100644 index 0000000..73408ef --- /dev/null +++ b/src/eval_tune/compare_ecm_nodes.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +"""Pair up per-problem node counts from two ECM sd=N stdout logs (same +input file, same order) and report a median/geomean ratio plus win/loss +counts -- robust to the handful of huge forced-mate outliers that would +otherwise dominate a raw sum. Mate-hunt problems (last iterated depth +line containing MATE) are reported separately since their node count is +chaotic w.r.t. move-ordering and not representative of typical +branching-factor efficiency. +""" +import re +import statistics +import sys + +SEARCHED_RE = re.compile(r"Searched for\s+[\d.]+ seconds, saw (\d+) nodes") +DEPTH_LINE_RE = re.compile(r"^\s*\d+[+]?\s+(\S+)\s+[\d:.]+\s+(\d+)\s") + + +def parse(path): + """Return list of (node_count, is_mate) per completed problem, in order.""" + results = [] + last_score = None + with open(path) as f: + for line in f: + m = DEPTH_LINE_RE.match(line) + if m: + last_score = m.group(1) + continue + m = SEARCHED_RE.search(line) + if m: + is_mate = bool(last_score and "MATE" in last_score) + results.append((int(m.group(1)), is_mate)) + last_score = None + return results + + +def main(): + base_path, cand_path = sys.argv[1], sys.argv[2] + base = parse(base_path) + cand = parse(cand_path) + n = min(len(base), len(cand)) + base, cand = base[:n], cand[:n] + + normal_ratios = [] + mate_ratios = [] + wins = losses = ties = 0 + mate_wins = mate_losses = mate_ties = 0 + + for (bn, bmate), (cn, cmate) in zip(base, cand): + ratio = cn / bn if bn else 1.0 + is_mate = bmate or cmate + bucket = mate_ratios if is_mate else normal_ratios + bucket.append(ratio) + if is_mate: + if cn < bn: mate_wins += 1 + elif cn > bn: mate_losses += 1 + else: mate_ties += 1 + else: + if cn < bn: wins += 1 + elif cn > bn: losses += 1 + else: ties += 1 + + print(f"Paired problems: {n}") + print() + print(f"=== Non-mate problems (n={len(normal_ratios)}) ===") + if normal_ratios: + print(f" median candidate/baseline node ratio: {statistics.median(normal_ratios):.4f}") + print(f" geomean ratio: {statistics.geometric_mean(normal_ratios):.4f}") + print(f" wins (candidate fewer nodes): {wins}") + print(f" losses (candidate more nodes): {losses}") + print(f" ties: {ties}") + print() + print(f"=== Mate-hunt problems (n={len(mate_ratios)}) -- reported separately, chaotic ===") + if mate_ratios: + print(f" median ratio: {statistics.median(mate_ratios):.4f}") + print(f" wins: {mate_wins} losses: {mate_losses} ties: {mate_ties}") + + +if __name__ == "__main__": + main() |
