From d8c73300e689a28fb4ed5c1b586a5b9bf2fc2078 Mon Sep 17 00:00:00 2001 From: Martin Bruse Date: Tue, 17 Feb 2026 08:13:05 +0000 Subject: [PATCH] =?UTF-8?q?feat(CI):=20handle=20multi-part=20Erd=C5=91s=20?= =?UTF-8?q?problems=20in=20status=20check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For problems with no single `erdos_{N}` theorem (e.g. multi-part problems with `erdos_{N}.parts.i`, `erdos_{N}_cycles`, etc.), collect all non-variant theorems and report open if any part is open. --- scripts/check_erdos_status.py | 54 ++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/scripts/check_erdos_status.py b/scripts/check_erdos_status.py index ccc678807..63b0af032 100644 --- a/scripts/check_erdos_status.py +++ b/scripts/check_erdos_status.py @@ -28,13 +28,12 @@ "ErdosProblems", ) -# Matches the category annotation line immediately before a main theorem. -# Captures the status word ("open" or "solved") and the problem number. -# The main theorem is `erdos_{N}` possibly followed by a suffix like `_statement`, -# but NOT containing a dot (which indicates a variant). +# Matches the category annotation line immediately before any erdos theorem. +# Captures the category, the problem number, and the full theorem name suffix. +# Used to find all theorems for a given problem number. CATEGORY_THEN_THEOREM = re.compile( r"@\[category research (open|solved|formally solved[^]]*),.*\]\s*\n" - r"theorem erdos_(\d+)\w*[\s:]", + r"theorem erdos_(\d+)([\w.]*)\s", re.MULTILINE, ) @@ -84,8 +83,19 @@ def lean_category(cat): return "solved" +def is_variant(suffix): + """Check if a theorem name suffix indicates a variant (not a main part).""" + # ".variants." anywhere in the suffix means it's a variant + return ".variants." in suffix or ".variant." in suffix + + def scan_lean_files(): - """Return dict mapping problem number (str) -> 'open', 'solved', or 'formally solved'.""" + """Return dict mapping problem number (str) -> 'open', 'solved', or 'formally solved'. + + For multi-part problems (no single `erdos_{N}` theorem), collects all + non-variant theorems. The problem is 'open' if any part is open, + 'formally solved' if all parts are formally solved, and 'solved' otherwise. + """ result = {} for fname in os.listdir(ERDOS_DIR): if not fname.endswith(".lean"): @@ -96,11 +106,35 @@ def scan_lean_files(): filepath = os.path.join(ERDOS_DIR, fname) with open(filepath) as f: content = f.read() - # Find the main theorem's category (first match for this problem number) + + # Collect all non-variant theorem categories for this problem number + main_categories = [] + has_exact_main = False + exact_main_cat = None for m in CATEGORY_THEN_THEOREM.finditer(content): - if m.group(2) == file_number: - result[file_number] = lean_category(m.group(1)) - break + if m.group(2) != file_number: + continue + suffix = m.group(3) # e.g. "", "_cycles", ".parts.i", ".variants.foo" + cat = lean_category(m.group(1)) + if suffix == "" or suffix == ":": + # Exact match: `erdos_{N}` with no suffix + has_exact_main = True + exact_main_cat = cat + elif not is_variant(suffix): + main_categories.append(cat) + + if has_exact_main: + # Single main theorem exists — use its category directly + result[file_number] = exact_main_cat + elif main_categories: + # Multi-part problem: open if any part is open + if "open" in main_categories: + result[file_number] = "open" + elif all(c == "formally solved" for c in main_categories): + result[file_number] = "formally solved" + else: + result[file_number] = "solved" + return result