Zulip Chat Archive
Stream: metaprogramming / tactics
Topic: Tactics for Sudoku
shortc1rcuit (Jul 26 2024 at 15:21):
(Question copied from #Is there code for X? )
I'm creating a project that lets you solve Sudokus in Lean 4 while proving each step of the solution. It is inspired by @Markus Himmel's Lean 3 sudoku project and @David Renshaw's Lean 4 chess puzzles. I want to create some tactics to reduce repetitive code. I've done a couple using macro_rules
but I think this one will need elab
.
Proving the value of a cell looks like this
--This tracks the current progress of the sudoku
def four_by_four_test : Progress := [[none, some 1, some 3, none ],
[some 2, none, none, none ],
[none, none, none, some 3],
[none, some 2, some 1, none ]]
/-
Grid is a function from Fin 4 × Fin 4 to ℕ.
We have this alongside the progress object as it's easier to reason about ℕ than Option ℕ
-/
theorem four_by_four_test_solve (g : Grid) (hg : SudokuRules g)
(hg_0_1 : g (0, 1) = 1) (hg_0_2 : g (0, 2) = 3) (hg_1_0 : g (1, 0) = 2)
(hg_2_3 : g (2, 3) = 3) (hg_3_1 : g (3, 1) = 2) (hg_3_2 : g (3, 2) = 1)
: Solvable g four_by_four_test := by
unfold four_by_four_test
have hg_1_3 : g (1, 3) = 1 := by
--Turns the goal into proving that all the other cells in row 1 can't be equal to 1
elimination row_elim
--Can't be 1 as there's a 2 here
· simp [hg_1_0]
--Can't be 1 as there's a one in the column
· exact col_conflict (by decide) hg_0_1
--Can't be 1 as there's a one in the column
· exact col_conflict (by decide) hg_3_2
--Updates the progress of the sudoku to include the value we just proved
apply Solvable.Set _ _ _ _ (by decide) hg_1_3
dsimp [Progress.set', List.get!, List.set]
sorry
I want this to instead look something like
def four_by_four_test : Progress := [[none, some 1, some 3, none ],
[some 2, none, none, none ],
[none, none, none, some 3],
[none, some 2, some 1, none ]]
theorem four_by_four_test_solve (g : Grid) (hg : SudokuRules g)
(hg_0_1 : g (0, 1) = 1) (hg_0_2 : g (0, 2) = 3) (hg_1_0 : g (1, 0) = 2)
(hg_2_3 : g (2, 3) = 3) (hg_3_1 : g (3, 1) = 2) (hg_3_2 : g (3, 2) = 1)
: Solvable g four_by_four_test := by
unfold four_by_four_test
set_cell (1, 3) 1
--set_cell should create the goal "g (1, 3) = 1"...
· elimination row_elim
· simp [hg_1_0]
· exact col_conflict (by decide) hg_0_1
· exact col_conflict (by decide) hg_3_2
--...add it as a hypothesis with a generated name and apply it to the sudoku progress
sorry
The name format should be something like "h[GRIDNAME]_[COORDINATES]".
My main questions are:
- How do you add in the new goal?
- How do you add the proven statement to the list of the hypotheses?
- How do you generate the name of the hypothesis?
(Sorry that this isn't a proper mwe; if I tried to make that I would have to send most of the project in this message. I've linked the github repository of the project if you want to look at the definitions.)
Thomas Murrills (Jul 29 2024 at 20:46):
Here are a couple of things that might help:
- You can make a new metavariable with
sideGoal ← mkFreshExprMVar <side goal type>
. (Make sure you’re usingwithMainContext
around everything first to carry over the context from the main goal!) (This doesn’t update the goal list you see in the infoview yet; it just gives you a metavariable you can carry around.) - To assert this goal as a hypothesis on the main goal
g ← getMainGoal
, you can writelet (_,newMainGoal) ← g.assertHypotheses #[{ userName := <your custom name>, type := <side goal type>, value := sideGoal }]
. Note that the side goal doesn’t have to be proven yet. - Then you can update the goal list to put the side goal first, with
replaceMainGoal [sideGoal.mvarId!, newMainGoal]
- To construct the custom hypothesis name from before, you might find
Name.appendIndexAfter
andgetNat
(for extracting numbers from syntax) useful.
Last updated: May 02 2025 at 03:31 UTC