After the full Phase 3 5-grammar A/B (HE+ 164 + LCB v6 50, n=214 problems
× 5 conditions = 1070 generations), bounded-thinking.yml is updated to
recommend the DeepSeek scratchpad grammar (PLAN/NOTE×0-15/VERDICT FSM at
tools/grammar-eval/deepseek-scratchpad.gbnf) as the default.
Phase 3 results (combined HE+ + LCB v6, all FSM-enforced):
- DeepSeek scratchpad: 87.4% Pass@1 (+1 net vs andthattoo, +4pp on LCB)
- andthattoo G/A/E: 86.9% (the originally-published technique)
- Holiday tagline: 86.4%
- PROMPT_TERSE (no FSM): 82.2% (Phase 2's n=30 win was subset-selection bias)
- FREE (no constraint): 78.0% (baseline)
Phase 1 reproducibility is exact: HE+ FSM Δ +4.3pp / LCB v6 Δ +24.0pp,
both match Phase 1's published numbers — validates the bench harness.
Compose ships unchanged engine-side (same vLLM image, same Genesis stack,
same TQ3 KV, same MTP n=3, same enable_in_reasoning flag). Only the
docstring's recommended-grammar pointer + the on-disk grammar files in
tools/grammar-eval/ change. Three grammars are now validated and available
client-side via extra_body={"structured_outputs": {"grammar": ...}}:
- DeepSeek scratchpad (default, best LCB)
- andthattoo G/A/E (originally-published, ~4× tighter think budget)
- Holiday tagline (extreme 24-token compression, wins LCB by 4pp too)
Combined-accuracy spread is within noise (0.5pp at n=214), so we ship one
compose rather than three siblings — choice is at the client, not at the
compose level.
Bug fix bundled: tools/grammar-eval/subset-bench.py --full --include-lcb
mode now correctly threads dataset kind through run_condition so LCB
problems use mod.run_tests_livecodebench instead of HE+ assertion-based
testing. Without this, the Phase 3 LCB shard crashed with KeyError:
'prompt' on the HE→LCB transition.
This wraps active research on bounded-thinking. Reopen if upstream FSM-
regress cluster behavior changes (Genesis pin bump, vLLM grammar engine
swap, model-family change), or if user demand surfaces for a sibling
compose pinning a non-default grammar.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
492 lines
21 KiB
Python
Executable File
492 lines
21 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""30-prompt HE+ grammar A/B bench: FREE vs current FSM vs Holiday tagline."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import importlib.util
|
|
import json
|
|
import pathlib
|
|
import random
|
|
import re
|
|
import statistics
|
|
import sys
|
|
import time
|
|
from types import SimpleNamespace
|
|
|
|
|
|
REPO_ROOT = pathlib.Path(__file__).resolve().parents[2]
|
|
DEFAULT_STRUCTURED_COT_DIR = pathlib.Path("/home/wasif/structured-cot")
|
|
DEFAULT_PRIOR = DEFAULT_STRUCTURED_COT_DIR / "runs/full-humaneval-2026-04-30/results.jsonl"
|
|
DEFAULT_CURRENT_GRAMMAR = DEFAULT_STRUCTURED_COT_DIR / "grammars/fsm_grammar_no_open.gbnf"
|
|
DEFAULT_TAGLINE_GRAMMAR = REPO_ROOT / "tools/grammar-eval/holiday-tagline.gbnf"
|
|
DEFAULT_DEEPSEEK_GRAMMAR = REPO_ROOT / "tools/grammar-eval/deepseek-scratchpad.gbnf"
|
|
|
|
TARGET_REGRESSIONS = [97, 101, 108, 129, 137, 151]
|
|
CURRENT_RE = re.compile(r"^GOAL: [^\n]+\nAPPROACH: [^\n]+\nEDGE: [^\n]+$")
|
|
TAGLINE_RE = re.compile(
|
|
r"^Q=(solve|prove|route|debug|patch|code|calc|compare|explain)\n"
|
|
r"M=(case|enum|check|derive|edit|test|trace|rank)\n"
|
|
r"K=[A-Za-z][A-Za-z0-9_.!-]{0,18}(,[A-Za-z][A-Za-z0-9_.!-]{0,18}){0,4}\n"
|
|
r"R=[A-Za-z][A-Za-z0-9_.!-]{0,18}(,[A-Za-z][A-Za-z0-9_.!-]{0,18}){0,4}\n"
|
|
r"V=(ok|fail|done|blocked|candidate|verify)$",
|
|
re.S,
|
|
)
|
|
DEEPSEEK_RE = re.compile(
|
|
r"^PLAN: [^\n]+\n"
|
|
r"(NOTE: [^\n]+\n){0,15}"
|
|
r"VERDICT: [^\n]+$",
|
|
re.S,
|
|
)
|
|
|
|
HOLIDAY_SYSTEM = (
|
|
"You are an expert Python programmer. Think only inside the required "
|
|
"tagline fields. Q is intent, M is method, K and R are comma-separated "
|
|
"keywords with no spaces, V is status. After </think>, write correct, "
|
|
"efficient, well-tested code in a ```python ... ``` fenced block."
|
|
)
|
|
DEEPSEEK_SYSTEM = (
|
|
"You are an expert Python programmer. Think only inside the required "
|
|
"scratchpad fields. Start with PLAN: stating your approach in one line. "
|
|
"Use NOTE: lines (zero to fifteen of them) to track problem-specific "
|
|
"values, edge cases, intermediate steps — write at most one observation "
|
|
"per line. End with VERDICT: stating your conclusion in one line. After "
|
|
"</think>, write correct, efficient, well-tested code in a "
|
|
"```python ... ``` fenced block."
|
|
)
|
|
|
|
CONDITIONS = ("free", "current", "holiday", "deepseek", "prompt_terse")
|
|
LABELS = {
|
|
"free": "FREE",
|
|
"current": "GOAL/APPROACH/EDGE",
|
|
"holiday": "Holiday tagline",
|
|
"deepseek": "DeepSeek scratchpad",
|
|
"prompt_terse": "PROMPT_TERSE",
|
|
}
|
|
|
|
|
|
def load_harness(path: pathlib.Path):
|
|
script = path / "fsm_vs_free_eval.py"
|
|
if not script.exists():
|
|
raise SystemExit(f"missing structured-cot harness: {script}")
|
|
spec = importlib.util.spec_from_file_location("fsm_vs_free_eval", script)
|
|
assert spec and spec.loader
|
|
mod = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(mod)
|
|
return mod
|
|
|
|
|
|
def read_prior(path: pathlib.Path) -> list[dict]:
|
|
rows = []
|
|
if path.exists():
|
|
with path.open() as f:
|
|
rows = [json.loads(line) for line in f if line.strip()]
|
|
return rows
|
|
|
|
|
|
def task_num(task_id: str) -> int:
|
|
return int(str(task_id).split("/")[-1])
|
|
|
|
|
|
def choose_subset(prior_rows: list[dict], seed: int) -> tuple[list[int], dict[int, str]]:
|
|
selected = list(TARGET_REGRESSIONS)
|
|
buckets = {n: "target_regress" for n in selected}
|
|
|
|
wins = [
|
|
task_num(r["task_id"])
|
|
for r in prior_rows
|
|
if r.get("free", {}).get("pass") is False and r.get("fsm", {}).get("pass") is True
|
|
]
|
|
if not wins:
|
|
wins = [10, 22, 36, 39]
|
|
for n in wins[:4]:
|
|
if n not in buckets:
|
|
selected.append(n)
|
|
buckets[n] = "current_win"
|
|
|
|
rng = random.Random(seed)
|
|
candidates = [n for n in range(164) if n not in buckets]
|
|
for n in rng.sample(candidates, 30 - len(selected)):
|
|
selected.append(n)
|
|
buckets[n] = "random"
|
|
return selected, buckets
|
|
|
|
|
|
def grammar_violation(condition: str, think: str) -> str:
|
|
think = re.sub(r"^<think>\n?", "", think or "")
|
|
think = re.sub(r"\n?</think>.*$", "", think, flags=re.S).strip()
|
|
if condition == "current" and not CURRENT_RE.match(think):
|
|
return "current_shape_mismatch"
|
|
if condition == "holiday" and not TAGLINE_RE.match(think):
|
|
return "holiday_shape_mismatch"
|
|
if condition == "deepseek" and not DEEPSEEK_RE.match(think):
|
|
return "deepseek_shape_mismatch"
|
|
return ""
|
|
|
|
|
|
def generate(mod, client, args, condition: str, user_prompt: str, grammars: dict[str, str]) -> tuple[str, int]:
|
|
if condition == "free":
|
|
return mod.generate_free(client, args.model, user_prompt, args.max_tokens)
|
|
if condition == "prompt_terse":
|
|
return mod.generate_prompt_terse(client, args.model, user_prompt, args.max_tokens)
|
|
if condition == "current":
|
|
grammar = grammars["current"]
|
|
prompt = mod.fsm_user_prompt_for_grammar(user_prompt, grammar)
|
|
return mod.generate_fsm(
|
|
client,
|
|
args.model,
|
|
prompt,
|
|
grammar,
|
|
args.max_tokens,
|
|
mod.fsm_system_prompt_for_grammar(grammar),
|
|
)
|
|
if condition == "holiday":
|
|
grammar = grammars["holiday"]
|
|
prompt = mod.fsm_user_prompt_for_grammar(user_prompt, grammar)
|
|
return mod.generate_fsm(client, args.model, prompt, grammar, args.max_tokens, HOLIDAY_SYSTEM)
|
|
if condition == "deepseek":
|
|
grammar = grammars["deepseek"]
|
|
prompt = mod.fsm_user_prompt_for_grammar(user_prompt, grammar)
|
|
return mod.generate_fsm(client, args.model, prompt, grammar, args.max_tokens, DEEPSEEK_SYSTEM)
|
|
raise ValueError(condition)
|
|
|
|
|
|
def run_condition(mod, client, args, prob: dict, condition: str, grammars: dict[str, str], dataset: str = "humaneval") -> dict:
|
|
harness_dataset = "livecodebench" if dataset == "lcb_v6" else dataset
|
|
entry_point = prob.get("entry_point") or "candidate"
|
|
user_prompt = mod.build_user_prompt(prob, harness_dataset)
|
|
t0 = time.time()
|
|
try:
|
|
text, total_tokens = generate(mod, client, args, condition, user_prompt, grammars)
|
|
gen_ms = round((time.time() - t0) * 1000)
|
|
think = mod.extract_think(text)
|
|
code, extraction = mod.extract_code_with_info(text)
|
|
think_tokens = mod.count_tokens(think, args.tokenizer)
|
|
output_tokens = max(int(total_tokens) - think_tokens, 0)
|
|
violation = grammar_violation(condition, think)
|
|
entry_found = mod._entry_point_found(code, harness_dataset, entry_point, prob)
|
|
if extraction["extraction_issue"] == "empty_code":
|
|
passed, err = False, "empty_code"
|
|
elif harness_dataset == "livecodebench":
|
|
passed, err = mod.run_tests_livecodebench(code, prob, args.timeout)
|
|
else:
|
|
passed, err = mod.run_tests(code, prob.get("test", ""), entry_point, args.timeout)
|
|
wall_ms = round((time.time() - t0) * 1000)
|
|
return {
|
|
"verdict": "pass" if passed else "fail",
|
|
"pass": bool(passed),
|
|
"err": (err or "")[:300],
|
|
"think_token_count": think_tokens,
|
|
"output_token_count": output_tokens,
|
|
"total_tokens": int(total_tokens),
|
|
"grammar_violations": violation,
|
|
"wall_time_ms": wall_ms,
|
|
"generation_wall_time_ms": gen_ms,
|
|
"extracted_think": think[:500],
|
|
"extracted_code": code[:500],
|
|
"raw_response": text if args.save_raw else "",
|
|
"entry_point_found": bool(entry_found),
|
|
**extraction,
|
|
}
|
|
except Exception as e:
|
|
return {
|
|
"verdict": "fail",
|
|
"pass": False,
|
|
"err": f"{type(e).__name__}: {e}"[:300],
|
|
"think_token_count": 0,
|
|
"output_token_count": 0,
|
|
"total_tokens": 0,
|
|
"grammar_violations": f"generation_error:{type(e).__name__}",
|
|
"wall_time_ms": round((time.time() - t0) * 1000),
|
|
"generation_wall_time_ms": round((time.time() - t0) * 1000),
|
|
"entry_point_found": False,
|
|
"extraction_method": "not_run",
|
|
"extraction_issue": "generation_error",
|
|
}
|
|
|
|
|
|
def mean(xs: list[float]) -> float:
|
|
return sum(xs) / len(xs) if xs else 0.0
|
|
|
|
|
|
def condition_summary(results: list[dict], condition: str) -> dict:
|
|
rows = [r["conditions"][condition] for r in results]
|
|
thinks = [r.get("think_token_count", 0) for r in rows]
|
|
return {
|
|
"pass_count": sum(1 for r in rows if r.get("pass")),
|
|
"n": len(rows),
|
|
"pass_rate": mean([1.0 if r.get("pass") else 0.0 for r in rows]),
|
|
"mean_think_tokens": mean(thinks),
|
|
"median_think_tokens": statistics.median(thinks) if thinks else 0,
|
|
}
|
|
|
|
|
|
def ids_where(results: list[dict], pred) -> list[str]:
|
|
return [r["task_id"] for r in results if pred(r)]
|
|
|
|
|
|
def write_summary(out_dir: pathlib.Path, results: list[dict], args, selected: list[int]) -> None:
|
|
summaries = {c: condition_summary(results, c) for c in CONDITIONS}
|
|
target_ids = {f"HumanEval/{n}" for n in TARGET_REGRESSIONS}
|
|
target_rows = [r for r in results if r["task_id"] in target_ids]
|
|
holiday_target_pass = [r["task_id"] for r in target_rows if r["conditions"]["holiday"].get("pass")]
|
|
holiday_rescues_current = ids_where(
|
|
results,
|
|
lambda r: not r["conditions"]["current"].get("pass") and r["conditions"]["holiday"].get("pass"),
|
|
)
|
|
holiday_new_failures = ids_where(
|
|
results,
|
|
lambda r: r["conditions"]["current"].get("pass") and not r["conditions"]["holiday"].get("pass"),
|
|
)
|
|
deepseek_target_pass = [r["task_id"] for r in target_rows if r["conditions"]["deepseek"].get("pass")]
|
|
deepseek_rescues_current = ids_where(
|
|
results,
|
|
lambda r: not r["conditions"]["current"].get("pass") and r["conditions"]["deepseek"].get("pass"),
|
|
)
|
|
deepseek_new_failures = ids_where(
|
|
results,
|
|
lambda r: r["conditions"]["current"].get("pass") and not r["conditions"]["deepseek"].get("pass"),
|
|
)
|
|
|
|
lines = [
|
|
"# Grammar A/B subset bench",
|
|
"",
|
|
f"- Endpoint: `{args.base_url}`",
|
|
f"- Model: `{args.model}`",
|
|
f"- Subset seed: `{args.seed}`",
|
|
f"- Target prior HE+ regressions: {', '.join(f'HE/{n}' for n in TARGET_REGRESSIONS)}",
|
|
f"- Holiday target prior-regressions passed: **{len(holiday_target_pass)}/6**",
|
|
f"- Holiday rescues vs current in this run: **{len(holiday_rescues_current)}**",
|
|
f"- Holiday new failures vs current in this run: **{len(holiday_new_failures)}**",
|
|
f"- DeepSeek target prior-regressions passed: **{len(deepseek_target_pass)}/6**",
|
|
f"- DeepSeek rescues vs current in this run: **{len(deepseek_rescues_current)}**",
|
|
f"- DeepSeek new failures vs current in this run: **{len(deepseek_new_failures)}**",
|
|
"",
|
|
"| Grammar | Pass@1 (30) | Mean think tokens | Median think tokens | Failures rescued vs current | New failures introduced |",
|
|
"|---|---:|---:|---:|---|---|",
|
|
]
|
|
for condition in CONDITIONS:
|
|
s = summaries[condition]
|
|
if condition == "current":
|
|
rescues = "baseline"
|
|
new = "baseline"
|
|
else:
|
|
rescues_ids = ids_where(
|
|
results,
|
|
lambda r, c=condition: not r["conditions"]["current"].get("pass")
|
|
and r["conditions"][c].get("pass"),
|
|
)
|
|
new_ids = ids_where(
|
|
results,
|
|
lambda r, c=condition: r["conditions"]["current"].get("pass")
|
|
and not r["conditions"][c].get("pass"),
|
|
)
|
|
rescues = ", ".join(rescues_ids) if rescues_ids else "-"
|
|
new = ", ".join(new_ids) if new_ids else "-"
|
|
lines.append(
|
|
f"| {LABELS[condition]} | {s['pass_count']}/{s['n']} ({s['pass_rate']*100:.1f}%) "
|
|
f"| {s['mean_think_tokens']:.0f} | {s['median_think_tokens']:.0f} | {rescues} | {new} |"
|
|
)
|
|
|
|
best_target = max(len(holiday_target_pass), len(deepseek_target_pass))
|
|
if best_target >= 3:
|
|
winners = []
|
|
if len(holiday_target_pass) >= 3:
|
|
winners.append("Holiday")
|
|
if len(deepseek_target_pass) >= 3:
|
|
winners.append("DeepSeek")
|
|
verdict = (
|
|
f"Run phase 3: {' and '.join(winners)} rescued enough of the prior "
|
|
"regression cluster to justify a full HE+164 + LCB v6 bench."
|
|
)
|
|
elif best_target >= 1:
|
|
verdict = "Marginal signal: document the result, inspect rescued cases manually, and defer phase 3 unless quality looks clearly better."
|
|
else:
|
|
verdict = "Stop: neither Holiday nor DeepSeek rescued the targeted HE+ regression cluster."
|
|
lines += [
|
|
"",
|
|
"## Target details",
|
|
"",
|
|
f"- Holiday target passes: {', '.join(holiday_target_pass) if holiday_target_pass else '-'}",
|
|
f"- Holiday rescues vs current: {', '.join(holiday_rescues_current) if holiday_rescues_current else '-'}",
|
|
f"- Holiday new failures vs current: {', '.join(holiday_new_failures) if holiday_new_failures else '-'}",
|
|
f"- DeepSeek target passes: {', '.join(deepseek_target_pass) if deepseek_target_pass else '-'}",
|
|
f"- DeepSeek rescues vs current: {', '.join(deepseek_rescues_current) if deepseek_rescues_current else '-'}",
|
|
f"- DeepSeek new failures vs current: {', '.join(deepseek_new_failures) if deepseek_new_failures else '-'}",
|
|
"",
|
|
"## Next step",
|
|
"",
|
|
verdict,
|
|
"",
|
|
]
|
|
(out_dir / "summary.md").write_text("\n".join(lines))
|
|
args_json = {k: str(v) if isinstance(v, pathlib.Path) else v for k, v in vars(args).items()}
|
|
(out_dir / "summary.json").write_text(
|
|
json.dumps(
|
|
{
|
|
"args": args_json,
|
|
"selected_problem_nums": selected,
|
|
"condition_summaries": summaries,
|
|
"holiday_target_prior_regression_passes": holiday_target_pass,
|
|
"holiday_rescues_vs_current": holiday_rescues_current,
|
|
"holiday_new_failures_vs_current": holiday_new_failures,
|
|
"deepseek_target_prior_regression_passes": deepseek_target_pass,
|
|
"deepseek_rescues_vs_current": deepseek_rescues_current,
|
|
"deepseek_new_failures_vs_current": deepseek_new_failures,
|
|
"next_step": verdict,
|
|
},
|
|
indent=2,
|
|
)
|
|
)
|
|
print("\n".join(lines[:21]))
|
|
print(f"\nSaved -> {out_dir / 'results.jsonl'}")
|
|
print(f"Saved -> {out_dir / 'summary.md'}")
|
|
|
|
|
|
def load_problems_for_dataset(mod, dataset: str, n: int):
|
|
if dataset == "humaneval":
|
|
return mod.load_benchmark("humaneval", n)
|
|
if dataset == "lcb_v6":
|
|
ns = SimpleNamespace(lcb_version="release_v6", date_cutoff="2025-01-01", platform="leetcode")
|
|
return mod.load_benchmark("livecodebench", n, ns)
|
|
raise ValueError(f"unknown dataset: {dataset}")
|
|
|
|
|
|
def dataset_kind(task_id: str) -> str:
|
|
return task_id.split("/")[0]
|
|
|
|
|
|
def main() -> int:
|
|
p = argparse.ArgumentParser()
|
|
p.add_argument("--base-url", default="http://localhost:8020/v1")
|
|
p.add_argument("--model", default="qwen3.6-27b-autoround")
|
|
p.add_argument("--tokenizer", default="/opt/ai/github/qwen36-dual-3090/models/qwen3.6-27b-autoround-int4")
|
|
p.add_argument("--structured-cot-dir", type=pathlib.Path, default=DEFAULT_STRUCTURED_COT_DIR)
|
|
p.add_argument("--prior-results", type=pathlib.Path, default=DEFAULT_PRIOR)
|
|
p.add_argument("--current-grammar", type=pathlib.Path, default=DEFAULT_CURRENT_GRAMMAR)
|
|
p.add_argument("--holiday-grammar", type=pathlib.Path, default=DEFAULT_TAGLINE_GRAMMAR)
|
|
p.add_argument("--deepseek-grammar", type=pathlib.Path, default=DEFAULT_DEEPSEEK_GRAMMAR)
|
|
p.add_argument("--out-dir", type=pathlib.Path, default=REPO_ROOT / f"results/grammar-ab-{time.strftime('%Y%m%d-%H%M%S')}")
|
|
p.add_argument("--seed", type=int, default=42)
|
|
p.add_argument("--max-tokens", type=int, default=4096)
|
|
p.add_argument("--request-timeout", type=float, default=600.0)
|
|
p.add_argument("--timeout", type=int, default=30, help="Per-test execution timeout.")
|
|
p.add_argument("--save-raw", action="store_true", help="Store full raw responses in results.jsonl.")
|
|
p.add_argument("--list-only", action="store_true", help="Print the selected 30-problem subset and exit.")
|
|
p.add_argument("--full", action="store_true",
|
|
help="Phase-3 mode: run all 164 HumanEval+ problems (skip the 30-subset selection).")
|
|
p.add_argument("--include-lcb", action="store_true",
|
|
help="Phase-3 mode: also run LiveCodeBench v6 50 (release_v6, leetcode, 2025-01-01 cutoff).")
|
|
p.add_argument("--he-start", type=int, default=0, help="Phase-3 slicing: HE+ problem index range start (inclusive).")
|
|
p.add_argument("--he-end", type=int, default=164, help="Phase-3 slicing: HE+ problem index range end (exclusive).")
|
|
p.add_argument("--lcb-start", type=int, default=0, help="Phase-3 slicing: LCB v6 problem index range start (inclusive).")
|
|
p.add_argument("--lcb-end", type=int, default=50, help="Phase-3 slicing: LCB v6 problem index range end (exclusive).")
|
|
p.add_argument("--label", default="", help="Optional shard tag (e.g. 'gpu0', 'gpu1') prepended to log lines.")
|
|
args = p.parse_args()
|
|
|
|
mod = load_harness(args.structured_cot_dir)
|
|
grammars = {
|
|
"current": args.current_grammar.read_text(),
|
|
"holiday": args.holiday_grammar.read_text(),
|
|
"deepseek": args.deepseek_grammar.read_text(),
|
|
}
|
|
client_args = SimpleNamespace(
|
|
base_url=args.base_url,
|
|
api_key_env="DUMMY_KEY",
|
|
request_timeout=args.request_timeout,
|
|
)
|
|
client = mod.make_client(client_args)
|
|
args.out_dir.mkdir(parents=True, exist_ok=True)
|
|
tag = f"[{args.label}] " if args.label else ""
|
|
|
|
if args.full:
|
|
he_problems = load_problems_for_dataset(mod, "humaneval", 164)
|
|
he_by_num = {task_num(p["task_id"]): p for p in he_problems}
|
|
he_indices = list(range(args.he_start, min(args.he_end, 164)))
|
|
|
|
lcb_problems = []
|
|
lcb_indices = []
|
|
if args.include_lcb:
|
|
lcb_problems = load_problems_for_dataset(mod, "lcb_v6", 50)
|
|
lcb_indices = list(range(args.lcb_start, min(args.lcb_end, len(lcb_problems))))
|
|
|
|
plan = (
|
|
[("humaneval", he_by_num[n]) for n in he_indices if n in he_by_num] +
|
|
[("lcb_v6", lcb_problems[i]) for i in lcb_indices]
|
|
)
|
|
if args.list_only:
|
|
for ds, prob in plan:
|
|
print(f"{ds}\t{prob['task_id']}")
|
|
return 0
|
|
|
|
results = []
|
|
for i, (ds, prob) in enumerate(plan, start=1):
|
|
row = {
|
|
"task_id": prob["task_id"],
|
|
"dataset": ds,
|
|
"subset_bucket": "phase3_full",
|
|
"conditions": {},
|
|
}
|
|
print(f"{tag}[grammar-full] [{i:03d}/{len(plan)}] {prob['task_id']} ({ds})")
|
|
for condition in CONDITIONS:
|
|
t0 = time.time()
|
|
result = run_condition(mod, client, args, prob, condition, grammars, dataset=ds)
|
|
row["conditions"][condition] = result
|
|
print(
|
|
f"{tag}[grammar-full] {LABELS[condition]:<20s} {result['verdict']:<4s} "
|
|
f"think={result['think_token_count']:<4d} total={result['total_tokens']:<4d} "
|
|
f"wall={round(time.time() - t0):>4d}s violation={result['grammar_violations'] or '-'}",
|
|
flush=True,
|
|
)
|
|
results.append(row)
|
|
with (args.out_dir / "results.jsonl").open("a") as f:
|
|
f.write(json.dumps(row) + "\n")
|
|
|
|
meta = {
|
|
"phase": "phase3_full",
|
|
"args": {k: str(v) if isinstance(v, pathlib.Path) else v for k, v in vars(args).items()},
|
|
"he_indices": he_indices,
|
|
"lcb_indices": lcb_indices,
|
|
"plan_size": len(plan),
|
|
}
|
|
(args.out_dir / "shard-meta.json").write_text(json.dumps(meta, indent=2))
|
|
print(f"{tag}[grammar-full] shard complete -> {args.out_dir}")
|
|
return 0
|
|
|
|
# ---- 30-subset Phase-2 path (default) ----
|
|
prior_rows = read_prior(args.prior_results)
|
|
selected, buckets = choose_subset(prior_rows, args.seed)
|
|
if args.list_only:
|
|
for n in selected:
|
|
print(f"HumanEval/{n}\t{buckets[n]}")
|
|
return 0
|
|
|
|
problems = load_problems_for_dataset(mod, "humaneval", 164)
|
|
by_num = {task_num(p["task_id"]): p for p in problems}
|
|
|
|
results = []
|
|
for i, n in enumerate(selected, start=1):
|
|
prob = by_num[n]
|
|
row = {"task_id": prob["task_id"], "subset_bucket": buckets[n], "conditions": {}}
|
|
print(f"{tag}[grammar-ab] [{i:02d}/{len(selected)}] {prob['task_id']} ({buckets[n]})")
|
|
for condition in CONDITIONS:
|
|
t0 = time.time()
|
|
result = run_condition(mod, client, args, prob, condition, grammars)
|
|
row["conditions"][condition] = result
|
|
print(
|
|
f"{tag}[grammar-ab] {LABELS[condition]:<20s} {result['verdict']:<4s} "
|
|
f"think={result['think_token_count']:<4d} total={result['total_tokens']:<4d} "
|
|
f"wall={round(time.time() - t0):>4d}s violation={result['grammar_violations'] or '-'}",
|
|
flush=True,
|
|
)
|
|
results.append(row)
|
|
with (args.out_dir / "results.jsonl").open("a") as f:
|
|
f.write(json.dumps(row) + "\n")
|
|
|
|
write_summary(args.out_dir, results, args, selected)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|