1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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()
|