summaryrefslogtreecommitdiff
path: root/src/gap_pipeline/prompts.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/gap_pipeline/prompts.py')
-rw-r--r--src/gap_pipeline/prompts.py513
1 files changed, 224 insertions, 289 deletions
diff --git a/src/gap_pipeline/prompts.py b/src/gap_pipeline/prompts.py
index 667a47a..2ba87cf 100644
--- a/src/gap_pipeline/prompts.py
+++ b/src/gap_pipeline/prompts.py
@@ -1,338 +1,273 @@
-"""Prompts and strict JSON contracts for the GAP pipeline."""
+"""Verbatim prompts recovered from the original GAP/Putnam source.
+
+Do not edit prompt literals in this file. ``tests/test_prompts.py`` pins their
+SHA-256 digests against the recovered source files.
+"""
from __future__ import annotations
import json
-from .models import (
- CanonicalItem,
- KernelCandidate,
- MethodPlan,
- ProofDAG,
- ReplacementSpec,
-)
-
-
-DAG_SYSTEM = """You are a mathematical proof-structure parser.
-Convert a supplied reference solution into a directed acyclic graph. Each node
-must be one locally checkable intermediate claim. Edges point from prerequisites
-to claims that use them. Preserve every essential proof step and do not invent
-new mathematics. Return JSON only."""
-
-
-def dag_user(item: CanonicalItem) -> str:
- return f"""ITEM ID: {item.item_id}
-
-PROBLEM:
-{item.problem}
-
-REFERENCE SOLUTION:
-{item.solution}
-
-Return:
-{{
- "nodes": [
- {{
- "node_id": "n1",
- "claim": "concrete intermediate mathematical claim",
- "derivation": "why this claim follows",
- "dependencies": [],
- "source_span": "corresponding reference-solution text",
- "mathematical_objects": ["objects used at this node"]
- }}
- ],
- "terminal_node_id": "node containing the requested conclusion"
-}}
-
-Requirements:
-- every dependency must refer to an earlier logical prerequisite;
-- the graph must be acyclic and connected to the terminal conclusion;
-- leaf nodes must expose the initial mathematical objects that could be
- replaced to produce a genuinely new setting;
-- retain all essential cases, guards, and endpoint checks."""
-
-
-METHOD_SYSTEM = """You abstract concrete proof steps into a reusable proof plan.
-For every DAG node, produce a content-light method label that says what operation
-or lemma is used without copying the node's particular constants or object names.
-Keep exactly the DAG's topological order and node IDs. Return JSON only."""
-
-
-def method_user(dag: ProofDAG) -> str:
- return f"""PROOF DAG:
-{dag.model_dump_json(indent=2)}
-
-Return:
-{{
- "steps": [
- {{
- "node_id": "n1",
- "method_label": "content-free operation or lemma",
- "input_roles": ["abstract role consumed by this step"],
- "output_role": "abstract role produced by this step",
- "invariants": ["conditions that must remain true"]
- }}
- ],
- "terminal_node_id": "{dag.terminal_node_id}"
-}}
-
-Do not merge, omit, reorder, or add nodes."""
-
-
-REPLACEMENT_SYSTEM = """You design one guarded replacement at a leaf of a proof
-DAG. The replacement must create a genuinely different mathematical setting
-while allowing the exact method-label plan to remain executable. Prefer a
-replacement that does not trivialize the problem. State every guard and cite
-concrete evidence from the source inequalities or assumptions. Return JSON only."""
-
-
-def replacement_user(
- item: CanonicalItem,
- dag: ProofDAG,
- plan: MethodPlan,
- *,
- difficulty_instruction: str,
-) -> str:
- return f"""ORIGINAL PROBLEM:
-{item.problem}
-
-ORIGINAL SOLUTION:
-{item.solution}
-
-PROOF DAG:
-{dag.model_dump_json(indent=2)}
-
-METHOD PLAN:
-{plan.model_dump_json(indent=2)}
-
-DIFFICULTY INSTRUCTION:
-{difficulty_instruction}
-
-Return:
-{{
- "target_node_id": "a leaf node ID",
- "original_object": "leaf object being replaced",
- "replacement_object": "new object or setting",
- "guard_conditions": ["condition required for every downstream step"],
- "guard_evidence": ["source-derived evidence that the guard is satisfiable"],
- "expected_downstream_changes": ["concrete changes expected during diffusion"],
- "rationale": "why the same plan remains valid and the task is not trivialized"
-}}"""
-
-
-DIFFUSION_SYSTEM = """You re-instantiate a fixed method plan after one guarded
-leaf replacement. Propagate the replacement through every dependent DAG node.
-You must keep exactly the original node order, dependency structure, and method
-labels. All algebra, cases, domains, and endpoint checks must be valid in the
-new setting. Return JSON only."""
-
+from .models import CanonicalItem, KernelCandidate, KernelPlan
-def diffusion_user(
- item: CanonicalItem,
- dag: ProofDAG,
- plan: MethodPlan,
- replacement: ReplacementSpec,
-) -> str:
- return f"""ORIGINAL PROBLEM:
-{item.problem}
-
-ORIGINAL REFERENCE SOLUTION:
-{item.solution}
-
-PROOF DAG:
-{dag.model_dump_json(indent=2)}
-FIXED METHOD PLAN:
-{plan.model_dump_json(indent=2)}
+# Source: PutnamVariants@c3bed737370df2dbf73afd66bf6e86d4ece82d68
+# scripts/o3_kernel_variant.py
+KERNEL_PLAN_SYSTEM = "You are an IMO medalist & pedagogue."
+KERNEL_PLAN_PROMPT = """
+You are a competition-math expert.
-GUARDED REPLACEMENT:
-{replacement.model_dump_json(indent=2)}
+(1) Read the Putnam problem and its official solution below.
+(2) List the MINIMAL chain of lemmas / techniques essential to the solution.
+(3) Identify every numerical or structural element that could be changed
+ *without* altering that chain of reasoning. Denote them as MUTABLE_SLOTS.
-Return:
+Return **one JSON object only**:
{{
- "node_instantiations": [
- {{
- "node_id": "same node ID",
- "method_label": "exact corresponding method label",
- "instantiated_claim": "new concrete claim",
- "instantiated_derivation": "valid derivation in the new setting",
- "dependencies": ["same dependency IDs"]
- }}
- ],
- "regenerated_proof": "complete rigorous proof in the new setting",
- "terminal_answer": "terminal conclusion established by that proof"
+ "core_steps": ["..."], // 1–5 concise phrases
+ "mutable_slots": {{
+ "slot1": {{"description": "...", "original": "..."}},
+ "slot2": {{"description": "...", "original": "..."}}
+ }}
}}
-The sequence and labels must match exactly. Do not write a problem statement
-yet; work forward from the replacement to a correct terminal answer."""
-
-
-QUESTION_SYSTEM = """You reverse-engineer a self-contained competition
-mathematics problem from a fully regenerated proof and terminal answer. State
-exactly the assumptions used by the proof, ask exactly for its terminal
-conclusion, and do not expose the solution strategy. Return JSON only."""
+PROBLEM:
+<<<{question}>>>
+SOLUTION:
+<<<{solution}>>>
+"""
-def question_user(
- item: CanonicalItem,
- dag: ProofDAG,
- plan: MethodPlan,
- replacement: ReplacementSpec,
- diffused_payload: dict,
-) -> str:
- return f"""SOURCE PROBLEM (style reference only):
-{item.problem}
+KERNEL_GENERATE_SYSTEM = "You are a creative yet rigorous math professor."
+KERNEL_GENERATE_PROMPT = """
+We previously extracted:
-FIXED METHOD PLAN:
-{plan.model_dump_json(indent=2)}
+CORE_STEPS = {core}
+MUTABLE_SLOTS = {slots}
-REPLACEMENT:
-{replacement.model_dump_json(indent=2)}
+Here is the ORIGINAL problem for reference:
+<<<{orig_q}>>>
-REGENERATED PROOF:
-{json.dumps(diffused_payload, ensure_ascii=False, indent=2)}
+And its OFFICIAL solution:
+<<<{orig_s}>>>
-Return:
+Create ONE *new* Putnam-level problem that
+ • still requires exactly the chain CORE_STEPS to solve,
+ • alters *every* MUTABLE_SLOT in a significant way.
+Return JSON only:
{{
- "problem": "self-contained candidate problem",
- "proof": "the complete regenerated proof",
- "terminal_answer": "answer requested by the candidate problem",
- "node_instantiations": {json.dumps(diffused_payload.get("node_instantiations", []), ensure_ascii=False)},
- "replacement": {replacement.model_dump_json()}
+ "question": "...", // full statement (LaTeX-friendly)
+ "solution": "..." // complete proof with new data
}}
-
-The problem must be genuinely different from the source and must neither omit
-an assumption used by the proof nor add an assumption that trivializes it."""
+"""
-# Four-field verifier JSON contract used by the GAP pipeline.
-JUDGE_SYSTEM = """You are a verification judge for a kernel-variant generation
-pipeline. You must decide whether a CANDIDATE variant problem and its CANDIDATE
-proof are mathematically equivalent to the ORIGINAL problem under the given
-METHOD-LABEL sequence (the abstract proof plan).
+# Source: paper Appendix F.3, Listing 4.
+JUDGE_SYSTEM_PROMPT = """You are a verification judge for a kernel-variant generation pipeline. You must decide whether a CANDIDATE variant problem and its CANDIDATE proof are mathematically equivalent to the ORIGINAL problem under the given METHOD-LABEL sequence (the abstract proof plan).
Your job is verification, not solving. You receive:
- the ORIGINAL problem statement and reference solution,
-- the abstract METHOD-LABEL sequence,
+- the abstract METHOD-LABEL sequence (a list of content-free steps),
- the SLOT replacement that was applied,
-- the CANDIDATE variant statement and regenerated proof.
-
-Check step by step that:
-1. Every candidate step instantiates the corresponding method label.
-2. The candidate proof is valid, with no unjustified leap.
-3. The candidate problem is well posed and its requested terminal answer
- matches the regenerated proof.
-4. The candidate is genuinely different but uses the same plan.
-
-Return one JSON object only."""
+- the CANDIDATE variant statement and the CANDIDATE regenerated proof.
+You must check, step by step, that:
+1. Every CANDIDATE step instantiates the corresponding METHOD label with the new operands.
+2. The CANDIDATE proof is mathematically valid: each step follows from the previous one, with no unjustified leap.
+3. The CANDIDATE problem statement is well-posed and has a unique terminal answer matching the regenerated proof.
+4. The CANDIDATE variant is genuinely different from the ORIGINAL (the slot replacement actually changed the instance) but uses the same plan.
-def judge_user(
- item: CanonicalItem,
- plan: MethodPlan,
- candidate: KernelCandidate,
- *,
- judge_id: int,
- iteration: int,
-) -> str:
- return f"""JUDGE REPLICATE: {judge_id}
-ITERATION: {iteration}
+Output a single JSON object with exactly these fields."""
-ORIGINAL PROBLEM:
-{item.problem}
+JUDGE_USER_TEMPLATE = """ORIGINAL PROBLEM:
+{original_problem}
ORIGINAL REFERENCE SOLUTION:
-{item.solution}
+{original_solution}
-METHOD-LABEL SEQUENCE:
-{plan.model_dump_json(indent=2)}
+METHOD-LABEL SEQUENCE (abstract plan):
+{method_labels}
SLOT REPLACEMENT:
-{candidate.replacement.model_dump_json(indent=2)}
+{slot_replacement}
CANDIDATE VARIANT PROBLEM:
-{candidate.problem}
+{candidate_problem}
CANDIDATE REGENERATED PROOF:
-{candidate.proof}
-
-CANDIDATE NODE INSTANTIATIONS:
-{json.dumps([node.model_dump() for node in candidate.node_instantiations], ensure_ascii=False, indent=2)}
+{candidate_proof}
Return:
-{{
- "verdict": "accept or reject",
- "step_by_step_check": "for every METHOD label, state whether the candidate step instantiates it correctly",
- "blocking_issues": "logical gap, computation error, ill-posed statement, or plan deviation; empty if accepted",
- "patch_suggestion": "minimal correction if rejected; empty if accepted"
-}}
-
-The step-by-step check must explicitly cover every method-plan node."""
-
-
-REPAIR_SYSTEM = """You repair a rejected kernel candidate. Apply only the
-minimal changes needed to address all blocking issues while preserving the
-guarded replacement, DAG node order, dependencies, and exact method-label
-sequence. Return the complete corrected candidate as JSON only."""
+{{"verdict": "accept" or "reject",
+ "step_by_step_check": "for each METHOD label, state whether the CANDIDATE step instantiates it correctly",
+ "blocking_issues": "list any logical gap, computation error, ill-posed statement, or plan deviation",
+ "patch_suggestion": "if reject, propose a minimal patch (a corrected proof step or a corrected slot value); leave empty if accept"}}"""
+
+FIX_SYSTEM_PROMPT = """You are a mathematical expert tasked with fixing kernel variant problems.
+Based on the review feedback, correct the identified issues while maintaining the problem's essence.
+
+Guidelines:
+- Fix mathematical errors while preserving the problem's structure
+- Ensure the corrected version is well-posed and solvable
+- Keep solutions detailed and pedagogically clear
+- Maintain similar difficulty level to the original problem
+
+Provide COMPLETE corrected versions, not just patches."""
+
+FIX_USER_TEMPLATE = """Based on the review feedback, please fix this kernel variant:
+
+CURRENT PROBLEM:
+{kv_question}
+
+CURRENT SOLUTION:
+{kv_solution}
+
+REVIEW FEEDBACK:
+Problem Issues: {problem_issues}
+Solution Issues: {solution_issues}
+
+ORIGINAL PROBLEM (for reference):
+{orig_question}
+
+ORIGINAL SOLUTION (for reference):
+{orig_solution}
+
+Please provide corrected versions. Return JSON with:
+{{"corrected_question": "complete corrected problem statement",
+ "corrected_solution": "complete corrected solution",\x20
+ "changes_made": "summary of key changes made"}}"""
+
+
+# Source: PutnamVariants@c3bed737370df2dbf73afd66bf6e86d4ece82d68
+# scripts/o3_rename_vars.py
+SURFACE_SYSTEM_BASE = "You are a meticulous LaTeX editor."
+SURFACE_TASK_COMMON = """
+Given:
+ • A Putnam problem statement and its official solution (LaTeX-like);
+ • Two symbol lists: vars (unknowns) and params (given constants).
+
+Rename every symbol in *vars* and *params* with a unique English identifier:
+ – all-lowercase letters, ≥8 chars, no underscore/space;
+ – same original symbol → same new name everywhere;
+ – different symbols → different new names;
+ – NEVER touch sci_consts (\\pi,e,i,…) or numeric constants;
+ – do NOT alter any other text or LaTeX markup.
+"""
+SURFACE_TASK_DESCRIPTIVE = """
+Each new identifier **should describe the symbol's mathematical role**.
+"""
+SURFACE_TASK_CONFUSING = """
+Each new identifier **should *not* match the symbol's role**; choose plausible
+but misleading nouns so the name sounds related but not matching the true meaning, such as replace Area with Radius.
+"""
+SURFACE_TASK_MISLEADING = """
+Each new identifier **should describe the *opposite* concept**. Pick names that
+directly contradict the symbol's actual meaning, e.g. rename a parallel vector
+to orthogonalvector.
+"""
+SURFACE_TASK_GARBLED = """
+Each new identifier **should look like random gibberish**: at least eight
+lowercase letters with no apparent meaning such as qzxwvtnp or hjgrksla.
+"""
+SURFACE_RETURN_SPEC = """
+Return exactly **one JSON object** and nothing else:
+{"map":{"old":"new",...},"question":"...","solution":"..."}
+"""
+SURFACE_USER_TEMPLATE = """Problem:
+<<<
+{question}
+>>>
+
+Solution:
+<<<
+{solution}
+>>>
+
+vars = {vars}
+params = {params}
+"""
+
+SURFACE_TASKS = {
+ "descriptive_long": SURFACE_TASK_DESCRIPTIVE,
+ "descriptive_long_confusing": SURFACE_TASK_CONFUSING,
+ "descriptive_long_misleading": SURFACE_TASK_MISLEADING,
+ "garbled_string": SURFACE_TASK_GARBLED,
+}
+
+
+def kernel_plan_user(item: CanonicalItem) -> str:
+ return KERNEL_PLAN_PROMPT.format(
+ question=item.problem,
+ solution=item.solution,
+ )
+
+
+def kernel_generate_user(item: CanonicalItem, plan: KernelPlan) -> str:
+ return KERNEL_GENERATE_PROMPT.format(
+ core=json.dumps(plan.core_steps, ensure_ascii=False),
+ slots=json.dumps(
+ {
+ key: value.model_dump(mode="json")
+ for key, value in plan.mutable_slots.items()
+ },
+ ensure_ascii=False,
+ ),
+ orig_q=item.problem,
+ orig_s=item.solution,
+ )
-def repair_user(
+def judge_user(
item: CanonicalItem,
- dag: ProofDAG,
- plan: MethodPlan,
+ plan: KernelPlan,
candidate: KernelCandidate,
- issues: list[dict],
) -> str:
- return f"""ORIGINAL PROBLEM:
-{item.problem}
-
-PROOF DAG:
-{dag.model_dump_json(indent=2)}
-
-FIXED METHOD PLAN:
-{plan.model_dump_json(indent=2)}
-
-CURRENT CANDIDATE:
-{candidate.model_dump_json(indent=2)}
-
-JUDGE FEEDBACK:
-{json.dumps(issues, ensure_ascii=False, indent=2)}
-
-Return the complete corrected object with fields:
-problem, proof, terminal_answer, node_instantiations, replacement.
-Do not change the replacement unless a judge proves it violates a guard; if it
-must change, retain the same target leaf and explain the corrected guards in
-the replacement rationale."""
-
-
-SURFACE_NAME_SYSTEM = """You propose identifier replacements for a mathematical
-problem. A replacement must be a single ASCII identifier beginning with a
-letter, must not collide with supplied identifiers, and must fit the requested
-family. Return JSON only."""
+ return JUDGE_USER_TEMPLATE.format(
+ original_problem=item.problem,
+ original_solution=item.solution,
+ method_labels=json.dumps(plan.core_steps, ensure_ascii=False),
+ slot_replacement=json.dumps(
+ {
+ key: value.model_dump(mode="json")
+ for key, value in plan.mutable_slots.items()
+ },
+ ensure_ascii=False,
+ ),
+ candidate_problem=candidate.question,
+ candidate_proof=candidate.solution,
+ )
-def surface_name_user(
+def fix_user(
+ item: CanonicalItem,
+ candidate: KernelCandidate,
*,
- symbol: str,
- role: str,
- family: str,
- context: str,
- forbidden: list[str],
+ problem_issues: str,
+ solution_issues: str,
) -> str:
- descriptions = {
- "descriptive_long": "a semantically helpful descriptive identifier",
- "descriptive_long_confusing": "2-5 unrelated common words concatenated",
- "descriptive_long_misleading": (
- "mathematical jargon suggesting a different role"
- ),
- "garbled_string": "a 4-16 character semantically meaningless string",
- }
- return f"""SYMBOL: {symbol}
-ROLE: {role}
-FAMILY: {family} ({descriptions[family]})
-CONTEXT:
-{context}
-FORBIDDEN IDENTIFIERS:
-{json.dumps(forbidden)}
-
-Return {{"replacement": "one valid identifier", "rationale": "brief reason"}}."""
+ return FIX_USER_TEMPLATE.format(
+ kv_question=candidate.question,
+ kv_solution=candidate.solution,
+ problem_issues=problem_issues,
+ solution_issues=solution_issues,
+ orig_question=item.problem,
+ orig_solution=item.solution,
+ )
+
+
+def surface_system(family: str) -> str:
+ return (
+ SURFACE_SYSTEM_BASE
+ + SURFACE_TASK_COMMON
+ + SURFACE_TASKS[family]
+ + SURFACE_RETURN_SPEC
+ )
+
+
+def surface_user(item: CanonicalItem) -> str:
+ return SURFACE_USER_TEMPLATE.format(
+ question=item.problem,
+ solution=item.solution,
+ vars=item.variables,
+ params=item.parameters,
+ )