Skip to content
Back to skills

Goedel Prover Formal Theorem Proving

ASecurity

Train language models for formal theorem proving via expert iteration with verifier-guided self-correction and checkpoint merging.

  • 6 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 9, 2026
ai-agentspythongo

Security analysis

A100/100

Scanned September 9, 2026

npx -y skills add ADu2021/skillXiv --skill goedel-prover-formal-theorem-proving --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Goedel Prover Formal Theorem Proving?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Goedel Prover Formal Theorem Proving
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/adu2021-goedel-prover-formal-theorem-proving/badge)](https://www.skillsdirectory.com/skills/adu2021-goedel-prover-formal-theorem-proving)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: goedel-prover-formal-theorem-proving
title: Goedel-Prover-V2 - Scaling Formal Theorem Proving with Expert Iteration
version: 0.0.2
engine: skillxiv-v0.0.2-claude-opus-4.6
license: MIT
url: https://arxiv.org/abs/2508.03613
keywords: [formal-verification, theorem-proving, lean, reinforcement-learning]
description: "Train language models for formal theorem proving via expert iteration with verifier-guided self-correction and checkpoint merging."
---

## Goedel-Prover-V2: Expert Iteration for Formal Theorem Proving

Goedel-Prover-V2 trains LLMs to prove mathematical theorems in the Lean proof assistant through expert iteration: iteratively sampling proofs, checking them against the Lean compiler, and using corrections as training data. The breakthrough is recognizing that verifier feedback (compiler errors) enables models to self-correct, eliminating need for human demonstrations beyond base training.

### Core Concept

Formal theorem proving requires exact syntax and logical correctness—tasks where LLMs typically fail without examples. Rather than requiring humans to write proofs, Goedel-Prover leverages the Lean compiler as an automatic teacher: generate a proof, get compiler feedback (error messages), revise, and learn from successful iterations. This "verifier-guided self-correction" is both more scalable and more aligned with actual proving workflows.

### Architecture Overview

- **Expert Iteration Pipeline**: Sample → Verify → Correct → Train loop with Lean compiler as oracle
- **Scaffolded Data Synthesis**: Generate synthetic theorems of increasing difficulty to create curriculum
- **Verifier-Guided Refinement**: Use Lean compiler error messages to iteratively fix proofs
- **Checkpoint Merging**: Average model checkpoints during training to preserve output diversity and prevent mode collapse in later RL stages
- **Multi-Scale Models**: Train 8B and 32B variants; smaller well-trained models outperform larger untrained ones

### Implementation Steps

**Step 1: Set Up Lean Environment and Proof Checker**

```python
import subprocess
import json
from typing import Tuple, Optional

class LeanProofChecker:
    """Interface to Lean compiler for proof verification."""

    def __init__(self, lean_path: str = "lean"):
        self.lean_path = lean_path

    def check_proof(self, theorem_statement: str, proof_code: str) -> Tuple[bool, str]:
        """
        Check if proof is valid in Lean.

        Returns: (is_valid, feedback)
        """
        full_code = f"""
theorem problem : {theorem_statement} := by
{proof_code}
"""
        try:
            result = subprocess.run(
                [self.lean_path, "--stdin"],
                input=full_code,
                capture_output=True,
                text=True,
                timeout=10
            )

            # Check if compilation succeeded
            if result.returncode == 0:
                return True, "Proof verified"
            else:
                # Extract error messages
                error_msg = result.stderr + result.stdout
                return False, error_msg

        except subprocess.TimeoutExpired:
            return False, "Proof checking timeout"
        except Exception as e:
            return False, str(e)

# Example
checker = LeanProofChecker()
is_valid, feedback = checker.check_proof(
    "∀ n : ℕ, n + 0 = n",
    "intro n\nsimp"
)
```

**Step 2: Implement Scaffolded Data Synthesis**

```python
def generate_synthetic_theorems(base_theorems: list, complexity_levels: int = 5) -> dict:
    """
    Generate theorems of increasing difficulty from base set.
    Curriculum learning: start with simple, progress to complex.
    """
    synthetic_data = {}

    for level in range(complexity_levels):
        theorems_at_level = []

        for base_theorem in base_theorems:
            # Level 0: Original theorems
            if level == 0:
                theorems_at_level.append(base_theorem)
            else:
                # Levels 1+: Generalize and extend theorems
                generalized = generalize_theorem(base_theorem, level)
                theorems_at_level.append(generalized)

        synthetic_data[f'level_{level}'] = theorems_at_level

    return synthetic_data

def generalize_theorem(theorem: str, complexity_level: int) -> str:
    """Make theorems more complex by adding parameters, conditions."""
    # Example: transform ∀ n, n+0=n into ∀ a b, a*(n+0) = a*n
    if complexity_level == 1:
        return theorem.replace("n", "(a + b * n)")
    elif complexity_level == 2:
        return theorem.replace("n", "(f (g n))")  # Compose functions
    else:
        return f"({theorem}) ∧ (proof of harder variant)"
```

**Step 3: Expert Iteration Loop**

```python
import random

class ExpertIteration:
    """Expert iteration: sample → check → correct → train."""

    def __init__(self, model, checker: LeanProofChecker, learning_rate=1e-5):
        self.model = model
        self.checker = checker
        self.training_data = []
        self.lr = learning_rate

    def sample_proofs(self, theorem: str, num_samples: int = 5) -> list:
        """Generate multiple proof attempts."""
        proofs = []

        for _ in range(num_samples):
            # Sample from model (use temperature > 0 for diversity)
            proof_text = self.model.generate(
                f"Prove: {theorem}\nProof:",
                temperature=0.8,
                max_tokens=500
            )
            proofs.append(proof_text)

        return proofs

    def verify_and_filter(self, theorem: str, proofs: list) -> Tuple[list, list]:
        """Check proofs, separate correct from incorrect."""
        correct_proofs = []
        incorrect_proofs = []

        for proof in proofs:
            is_valid, feedback = self.checker.check_proof(theorem, proof)

            if is_valid:
                correct_proofs.append((proof, feedback))
            else:
                incorrect_proofs.append((proof, feedback))

        return correct_proofs, incorrect_proofs

    def self_correct(self, theorem: str, incorrect_proofs: list) -> list:
        """
        Use compiler error messages to guide self-correction.
        Generate corrected proofs informed by error feedback.
        """
        corrected = []

        for wrong_proof, error_msg in incorrect_proofs:
            # Prompt model to fix proof given error
            correction_prompt = f"""
Original theorem: {theorem}
Failed proof:
{wrong_proof}

Lean compiler error:
{error_msg[:500]}  # Limit error length

Correct the proof:"""

            fixed_proof = self.model.generate(correction_prompt, max_tokens=500)
            is_valid, feedback = self.checker.check_proof(theorem, fixed_proof)

            if is_valid:
                corrected.append(fixed_proof)

        return corrected

    def train_on_successful_proofs(self, proofs: list, theorems: list):
        """
        Supervised fine-tuning on verified proofs.
        """
        for proof, theorem in zip(proofs, theorems):
            # Format as training example
            prompt = f"Prove: {theorem}\nProof:"
            # SFT: minimize cross-entropy of proof tokens
            loss = self.model.compute_loss(prompt, proof)
            loss.backward()

        self.model.optimizer.step()

    def run_iteration(self, theorems: list, num_samples: int = 5, max_iters: int = 3):
        """
        Run one expert iteration: sample → verify → correct → train.
        """
        all_correct = []

        for theorem in theorems:
            # Sample proofs
            proofs = self.sample_proofs(theorem, num_samples)

            # Verify
            correct, incorrect = self.verify_and_filter(theorem, proofs)
            all_correct.extend([p for p, _ in correct])

            # Self-correct (iterative refinement)
            for _ in range(max_iters):
                if not incorrect:
                    break

                corrected = self.self_correct(theorem, incorrect)
                all_correct.extend(corrected)

                # Re-verify remaining
                correct, incorrect = self.verify_and_filter(
                    theorem,
                    [p for p, _ in incorrect]
                )

        # Train on all successful proofs
        if all_correct:
            self.train_on_successful_proofs(all_correct, theorems)

        return len(all_correct)
```

**Step 4: Implement Checkpoint Merging**

```python
def merge_checkpoints(checkpoints: list, weights: list = None) -> dict:
    """
    Average model checkpoints to prevent mode collapse.
    RL training can reduce output diversity; averaging preserves it.
    """
    if weights is None:
        weights = [1.0 / len(checkpoints)] * len(checkpoints)

    merged_state = {}

    # Average weights across checkpoints
    for param_name in checkpoints[0].keys():
        merged_state[param_name] = sum(
            w * ckpt[param_name] for w, ckpt in zip(weights, checkpoints)
        )

    return merged_state

class CheckpointManager:
    """Manage checkpoints and periodic averaging."""

    def __init__(self, model, averaging_frequency: int = 100):
        self.model = model
        self.checkpoints = []
        self.averaging_frequency = averaging_frequency
        self.step = 0

    def save_checkpoint(self):
        """Save current model state."""
        self.checkpoints.append(self.model.state_dict().copy())

    def maybe_merge(self):
        """Periodically merge recent checkpoints."""
        self.step += 1

        if self.step % self.averaging_frequency == 0 and len(self.checkpoints) > 1:
            # Keep last 5 checkpoints, merge them
            recent = self.checkpoints[-5:]
            merged = merge_checkpoints(recent)
            self.model.load_state_dict(merged)

            # Clear old checkpoints
            self.checkpoints = [merged]
```

**Step 5: Full Training Pipeline**

```python
def train_goedel_prover(
    model,
    theorem_dataset: list,
    num_epochs: int = 3,
    samples_per_theorem: int = 5
):
    """
    Complete training pipeline: expert iteration with curriculum.
    """
    checker = LeanProofChecker()
    expert_iter = ExpertIteration(model, checker)
    checkpoint_mgr = CheckpointManager(model)

    # Sort by difficulty (curriculum)
    difficulties = compute_theorem_difficulty(theorem_dataset)
    sorted_theorems = sorted(zip(theorem_dataset, difficulties), key=lambda x: x[1])

    for epoch in range(num_epochs):
        total_proofs = 0

        for theorem, difficulty in sorted_theorems:
            # Adjust samples based on difficulty
            num_samples = max(3, samples_per_theorem - difficulty // 10)

            num_correct = expert_iter.run_iteration(
                [theorem],
                num_samples=num_samples,
                max_iters=3
            )

            total_proofs += num_correct

            # Periodic checkpoint averaging
            checkpoint_mgr.save_checkpoint()
            checkpoint_mgr.maybe_merge()

        print(f"Epoch {epoch}: {total_proofs} verified proofs")

def compute_theorem_difficulty(theorems: list) -> list:
    """Heuristic: theorem length correlates with difficulty."""
    return [len(t.split()) for t in theorems]
```

### Practical Guidance

**When to Use:**
- Formal verification tasks with checkable proofs (Lean, Coq, Isabelle)
- Scenarios with large theorem libraries for curriculum learning
- Applications where proof correctness is mandatory
- Cases where iterative refinement is preferred to human demonstrations

**When NOT to Use:**
- Informal mathematical reasoning without formal verification
- Real-time inference (proof generation is slow)
- Domains without reliable proof checkers
- Scenarios with <100 training theorems (insufficient curriculum)

**Hyperparameters:**

| Parameter | Default | Impact |
|-----------|---------|--------|
| `samples_per_theorem` | 5 | More samples = better coverage, higher compute cost |
| `max_correction_iters` | 3 | Iterations of self-correction; diminishing returns after 3 |
| `checkpoint_averaging_freq` | 100 | More frequent averaging = higher diversity, slower training |
| `curriculum_start_difficulty` | 0 | Begin with easiest theorems; increase gradually |

### Reference

**Paper**: Goedel-Prover-V2: Scaling Formal Theorem Proving (2508.03613)
- Expert iteration with verifier feedback
- 32B model achieves SOTA on formal theorem benchmarks
- Self-correction via compiler error messages
- Checkpoint merging prevents mode collapse

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…