Pantograph/docs/goal.ipynb

318 lines
7.7 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"id": "c5106980-4850-4bea-a333-5a1b2e4d1dc5",
"metadata": {},
"source": [
"# Goals and Tactics\n",
"\n",
"Executing tactics in Pantograph is simple. To start a proof, call the\n",
"`Server.goal_start` function and supply an expression."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "3257de2b-41ca-4cfe-b66c-1ef4781c98b0",
"metadata": {},
"outputs": [],
"source": [
"from pantograph import Server\n",
"from pantograph.expr import TacticHave, TacticCalc, TacticExpr"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "6783d478-d8c7-4c4e-a56e-8170384297ef",
"metadata": {},
"outputs": [],
"source": [
"server = Server()\n",
"state0 = server.goal_start(\"forall (p q: Prop), Or p q -> Or q p\")"
]
},
{
"cell_type": "markdown",
"id": "bfe5a9df-33c2-4538-a9ce-fc0e02c92ff2",
"metadata": {},
"source": [
"This creates a *goal state*, which consists of a finite number of goals. In this\n",
"case since it is the beginning of a state, it has only one goal."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "eefc9094-9574-4f92-9aa2-c39beb85389b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"⊢ forall (p q: Prop), Or p q -> Or q p\n"
]
}
],
"source": [
"print(state0)"
]
},
{
"cell_type": "markdown",
"id": "26dbe212-e09e-42dd-ab15-65ee2fba6234",
"metadata": {},
"source": [
"To execute a tactic on a goal state, use `Server.goal_tactic`. This function\n",
"takes a goal id and a tactic. Most Lean tactics are strings."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "c907dbb6-4d6a-4aa7-b173-60220165ba9e",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"a : Prop\n",
"⊢ ∀ (q : Prop), a q → q a\n"
]
}
],
"source": [
"state1 = server.goal_tactic(state0, goal_id=0, tactic=\"intro a\")\n",
"print(state1)"
]
},
{
"cell_type": "markdown",
"id": "9978fdcf-a12b-4f22-9551-5e04c262e5e0",
"metadata": {},
"source": [
"Executing a tactic produces a new goal state. If this goal state has no goals,\n",
"the proof is complete. You can recover the usual form of a goal with `str()`"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "16595c5e-2285-49d5-8340-397ad1e6c9e7",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'a : Prop\\n⊢ ∀ (q : Prop), a q → q a'"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"str(state1.goals[0])"
]
},
{
"cell_type": "markdown",
"id": "67f2a75d-6851-4393-bac9-a091400f1906",
"metadata": {},
"source": [
"## Error Handling and GC\n",
"\n",
"When a tactic fails, it throws an exception:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "c9784ba2-3810-4f80-a6c4-33d5eef3003e",
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[\"tactic 'assumption' failed\\na : Prop\\n⊢ ∀ (q : Prop), a q → q a\"]\n"
]
}
],
"source": [
"try:\n",
" state2 = server.goal_tactic(state1, goal_id=0, tactic=\"assumption\")\n",
" print(\"Should not reach this\")\n",
"except Exception as e:\n",
" print(e)"
]
},
{
"cell_type": "markdown",
"id": "1ae60d9e-8656-4f26-b495-d04bced250fc",
"metadata": {},
"source": [
"A state with no goals is considered solved"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "1cb96b19-d3bb-4533-abeb-a7dbc5bc8c3e",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"GoalState(state_id=5, goals=[], _sentinel=[0, 1])"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"state0 = server.goal_start(\"forall (p : Prop), p -> p\")\n",
"state1 = server.goal_tactic(state0, goal_id=0, tactic=\"intro\")\n",
"state2 = server.goal_tactic(state1, goal_id=0, tactic=\"intro h\")\n",
"state3 = server.goal_tactic(state2, goal_id=0, tactic=\"exact h\")\n",
"state3"
]
},
{
"cell_type": "markdown",
"id": "a2945e71-e583-4ae0-9c0f-83035f0492f2",
"metadata": {},
"source": [
"Execute `server.gc()` once in a while to delete unused goals."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "d53624ff-c720-4847-98f7-28e109eb76e7",
"metadata": {},
"outputs": [],
"source": [
"server.gc()"
]
},
{
"cell_type": "markdown",
"id": "0b59e05e-7d8c-4fad-b8ca-375ea995ea5b",
"metadata": {},
"source": [
"## Special Tactics\n",
"\n",
"Lean has special provisions for some tactics. This includes `have`, `let`,\n",
"`calc`. To execute one of these tactics, create a `TacticHave`, `TacticLet`,\n",
"`TacticCalc` instance and feed it into `server.goal_tactic`.\n",
"\n",
"Technically speaking `have` and `let` are not tactics in Lean, so their execution requires special attention."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "526d620b-064f-4ec0-a7b2-6a1ef3c6f6e7",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"⊢ 2 = 1 + 1\n",
"h : 2 = 1 + 1\n",
"⊢ 1 + 1 = 2\n"
]
}
],
"source": [
"state0 = server.goal_start(\"1 + 1 = 2\")\n",
"state1 = server.goal_tactic(state0, goal_id=0, tactic=TacticHave(branch=\"2 = 1 + 1\", binder_name=\"h\"))\n",
"print(state1)"
]
},
{
"cell_type": "markdown",
"id": "c415d436-ed0d-475f-bf5e-b8dc63954c7e",
"metadata": {},
"source": [
"The `TacticExpr` \"tactic\" parses an expression and assigns it to the current\n",
"goal. This leverages Lean's type unification system and is as expressive as\n",
"Lean expressions. Many proofs in Mathlib4 are written in a mixture of expression\n",
"and tactic forms."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "e1f06441-4d77-45a7-a1c3-b800b96a8105",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n"
]
}
],
"source": [
"state0 = server.goal_start(\"forall (p : Prop), p -> p\")\n",
"state1 = server.goal_tactic(state0, goal_id=0, tactic=\"intro p\")\n",
"state2 = server.goal_tactic(state1, goal_id=0, tactic=TacticExpr(\"fun h => h\"))\n",
"print(state2)"
]
},
{
"cell_type": "markdown",
"id": "d6bcd026-507b-4b1c-8dee-006df53636b0",
"metadata": {},
"source": [
"To execute the `conv` tactic, use `server.goal_conv_begin` to enter conv mode on\n",
"one goal, and use `server.goal_conv_end` to exit from conv mode. Pantograph will\n",
"provide interactive feedback upon every tactic executed in `conv` mode."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2b0b27c6-0c69-4255-aed1-c0713c227ccc",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}