83 lines
3.8 KiB
Python
83 lines
3.8 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""Generate Lean proofs with the paper's prompt and last-complete-block parser."""
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import argparse
|
||
|
|
import json
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
from prompt_utils import (
|
||
|
|
LEAN4_DEFAULT_HEADER, DEFAULT_GENERATION_TOP_P,
|
||
|
|
build_prover_prompt_for_example, default_generation_temperature,
|
||
|
|
default_generation_max_tokens, default_lean_stop_sequences,
|
||
|
|
parse_generated_lean, split_context_and_command,
|
||
|
|
)
|
||
|
|
|
||
|
|
DEFAULT_MODEL = 'EPFL-LARA/lean-standard-prover-qwen3-8b-reasoning-grpo'
|
||
|
|
FEEDBACK = False
|
||
|
|
REASONING = True
|
||
|
|
|
||
|
|
|
||
|
|
def build_prompt(source: str) -> str:
|
||
|
|
context, declaration, found = split_context_and_command(source)
|
||
|
|
if not found:
|
||
|
|
raise ValueError("Supply a Lean theorem, lemma, or example ending in 'by sorry'.")
|
||
|
|
example = {"formal_statement": declaration, "header": context or LEAN4_DEFAULT_HEADER}
|
||
|
|
_, prompt = build_prover_prompt_for_example(
|
||
|
|
example, use_informal_statement=False, is_deepseek=False,
|
||
|
|
tgat_prompt=FEEDBACK, reasoning=REASONING,
|
||
|
|
)
|
||
|
|
return prompt
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> None:
|
||
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
||
|
|
parser.add_argument("files", nargs="+", type=Path, help="Lean problem files, including imports and a theorem to complete")
|
||
|
|
parser.add_argument("--model", default=DEFAULT_MODEL)
|
||
|
|
parser.add_argument("--samples", type=int, default=1)
|
||
|
|
parser.add_argument("--temperature", type=float)
|
||
|
|
parser.add_argument("--top-p", type=float, default=DEFAULT_GENERATION_TOP_P)
|
||
|
|
parser.add_argument("--max-new-tokens", type=int, default=default_generation_max_tokens(False))
|
||
|
|
parser.add_argument("--tensor-parallel-size", type=int, default=1)
|
||
|
|
parser.add_argument("--seed", type=int, default=0)
|
||
|
|
parser.add_argument("--print-prompt", action="store_true", help="Show the exact raw prompt without loading the model")
|
||
|
|
args = parser.parse_args()
|
||
|
|
if args.samples < 1 or args.max_new_tokens < 1:
|
||
|
|
parser.error("--samples and --max-new-tokens must be positive")
|
||
|
|
prompts = [build_prompt(path.read_text(encoding="utf-8")) for path in args.files]
|
||
|
|
if args.print_prompt:
|
||
|
|
for prompt in prompts:
|
||
|
|
print(prompt, end="")
|
||
|
|
return
|
||
|
|
|
||
|
|
from vllm import LLM, SamplingParams
|
||
|
|
|
||
|
|
llm = LLM(model=args.model, tokenizer=args.model,
|
||
|
|
tensor_parallel_size=args.tensor_parallel_size, dtype="auto",
|
||
|
|
max_model_len=32768, trust_remote_code=False, seed=args.seed,
|
||
|
|
gpu_memory_utilization=0.90)
|
||
|
|
tokenizer = llm.get_tokenizer()
|
||
|
|
tokenized = [tokenizer.encode(prompt, add_special_tokens=False) for prompt in prompts]
|
||
|
|
if any(len(ids) >= 32768 for ids in tokenized):
|
||
|
|
raise ValueError("The problem prompt must leave space in the 32,768-token context for a proof.")
|
||
|
|
temperature = args.temperature if args.temperature is not None else default_generation_temperature(args.samples)
|
||
|
|
params = [SamplingParams(n=args.samples, temperature=temperature,
|
||
|
|
top_p=args.top_p,
|
||
|
|
max_tokens=min(args.max_new_tokens, 32768-len(ids)),
|
||
|
|
stop=default_lean_stop_sequences(False),
|
||
|
|
include_stop_str_in_output=True, seed=args.seed)
|
||
|
|
for ids in tokenized]
|
||
|
|
outputs = llm.generate([{"prompt_token_ids": ids} for ids in tokenized], params)
|
||
|
|
for path, output in zip(args.files, outputs, strict=True):
|
||
|
|
for i, completion in enumerate(output.outputs):
|
||
|
|
print(json.dumps({
|
||
|
|
"source": str(path), "sample_id": i,
|
||
|
|
"response": completion.text,
|
||
|
|
"lean_code": parse_generated_lean(completion.text, is_deepseek=False),
|
||
|
|
"finish_reason": completion.finish_reason,
|
||
|
|
}, ensure_ascii=False), flush=True)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|