Repository navigation
Expand file tree
/
Copy pathbenchmark.py
More file actions
123 lines (110 loc) · 4.2 KB
/
Copy pathbenchmark.py
File metadata and controls
123 lines (110 loc) · 4.2 KB
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""Strict loader for Google DeepMind's released IMO-LeanProofBench CSV."""
from __future__ import annotations
import csv
import re
from pathlib import Path
from .problem import BenchmarkProblem
EXPECTED_COLUMNS = {
"Problem ID",
"Problem",
"Solution",
"Grading guidelines",
"Category",
"Level",
"Short Answer",
"Source",
"Lean Statement",
}
_DECLARATION_RE = re.compile(r"(?m)^(?:theorem|lemma)\s+")
_TERMINAL_PLACEHOLDER_RE = re.compile(r":=\s+by\s+sorry\s*\Z")
def _strip_lean_comments(text: str) -> str:
"""Remove nested block and line comments from a trusted header."""
output: list[str] = []
index = 0
block_depth = 0
line_comment = False
while index < len(text):
if line_comment:
if text[index] in "\r\n":
line_comment = False
output.append(text[index])
index += 1
continue
if block_depth:
if text.startswith("/-", index):
block_depth += 1
index += 2
elif text.startswith("-/", index):
block_depth -= 1
index += 2
else:
if text[index] in "\r\n":
output.append(text[index])
index += 1
continue
if text.startswith("--", index):
line_comment = True
index += 2
elif text.startswith("/-", index):
block_depth = 1
index += 2
else:
output.append(text[index])
index += 1
if block_depth:
raise ValueError("unterminated Lean block comment in benchmark header")
return "".join(output)
def _split_lean_statement(source: str, problem_id: str) -> tuple[str, str]:
match = _DECLARATION_RE.search(source)
if match is None:
raise ValueError(f"{problem_id}: Lean Statement has no theorem or lemma")
header = _strip_lean_comments(source[: match.start()]).strip()
statement = source[match.start() :].strip()
if not _TERMINAL_PLACEHOLDER_RE.search(statement):
raise ValueError(
f"{problem_id}: theorem must end with the exact `:= by sorry` placeholder"
)
# The shared compiler accepts only a frozen theorem ending in `:= sorry`
# and replaces exactly that terminal placeholder with the model's `by ...`
# proof body. This changes no theorem semantics.
statement = _TERMINAL_PLACEHOLDER_RE.sub(":= sorry", statement)
return header, statement
def load_imo_leanproofbench(
path: str | Path,
*,
subset: str = "basic",
) -> list[BenchmarkProblem]:
"""Load Basic or Advanced rows without exposing solutions to the model."""
normalized_subset = subset.strip().lower()
if normalized_subset not in {"basic", "advanced"}:
raise ValueError("subset must be basic or advanced")
target_prefix = f"PB-{normalized_subset.title()}-"
problems: list[BenchmarkProblem] = []
seen: set[str] = set()
with Path(path).open(newline="", encoding="utf-8") as handle:
reader = csv.DictReader(handle)
missing = sorted(EXPECTED_COLUMNS - set(reader.fieldnames or []))
if missing:
raise ValueError("IMO-LeanProofBench CSV is missing columns: " + ", ".join(missing))
for source_index, row in enumerate(reader):
problem_id = row["Problem ID"].strip()
if not problem_id.startswith(target_prefix):
continue
if problem_id in seen:
raise ValueError(f"duplicate IMO-LeanProofBench id: {problem_id}")
seen.add(problem_id)
header, statement = _split_lean_statement(row["Lean Statement"], problem_id)
problems.append(
BenchmarkProblem(
problem_id=problem_id,
split=normalized_subset,
formal_statement=statement,
header=header,
informal_statement=row["Problem"].strip(),
source_index=source_index,
category=row["Category"].strip() or None,
)
)
if not problems:
raise ValueError(f"IMO-LeanProofBench {normalized_subset} subset is empty")
return problems