feat: always run clean_wf, even before decreasing_by (#5016)
Previously, the tactic state shown at `decreasing_by` would leak lots of details about the translation, and mention `invImage`, `PSigma` etc. This is not nice. So this introduces `clean_wf`, which is like `simp_wf` but using `simp`'s `only` mode, and runs this unconditionally. This should clean up the goal to a reasonable extent. Previously `simp_wf` was an unrestricted `simp […]` call, but we probably don’t want arbitrary simplification to happen at this point, so this now became `simp only` call. For backwards compatibility, `decreasing_with` begins with `try simp`. The `simp_wf` tactic is still available to not break too much existing code; it’s docstring suggests to no longer use it. With `set_option cleanDecreasingByGoal false` one can disable the use of `clean_wf`. I hope this is only needed for debugging and understanding. Migration advise: If your `decreasing_by` proof begins with `simp_wf`, either remove that (if the proof still goes through), or replace with `simp`. I am a bit anxious about running even `simp only` unconditionally here, as it may do more than some user might want, e.g. because of options like `zetaDelta := true`. We'll see if we need to reign in this tactic some more. I wonder if in corner cases the `simp_wf` tactic might be able to close the goal, and if that is a problem. If so, we may have to promote simp’s internal `mayCloseGoal` parameter to a simp configuration option and use that here. fixes #4928
This commit is contained in:
parent
a43356591c
commit
d1174e10e6
21 changed files with 170 additions and 99 deletions
|
|
@ -8,11 +8,26 @@ import Init.SizeOf
|
|||
import Init.MetaTypes
|
||||
import Init.WF
|
||||
|
||||
/-- Unfold definitions commonly used in well founded relation definitions.
|
||||
This is primarily intended for internal use in `decreasing_tactic`. -/
|
||||
/--
|
||||
Unfold definitions commonly used in well founded relation definitions.
|
||||
|
||||
Since Lean 4.12, Lean unfolds these definitions automatically before presenting the goal to the
|
||||
user, and this tactic should no longer be necessary. Calls to `simp_wf` can be removed or replaced
|
||||
by plain calls to `simp`.
|
||||
-/
|
||||
macro "simp_wf" : tactic =>
|
||||
`(tactic| try simp (config := { unfoldPartialApp := true, zetaDelta := true }) [invImage, InvImage, Prod.lex, sizeOfWFRel, measure, Nat.lt_wfRel, WellFoundedRelation.rel])
|
||||
|
||||
/--
|
||||
This tactic is used internally by lean before presenting the proof obligations from a well-founded
|
||||
definition to the user via `decreasing_by`. It is not necessary to use this tactic manuall.
|
||||
-/
|
||||
macro "clean_wf" : tactic =>
|
||||
`(tactic| simp
|
||||
(config := { unfoldPartialApp := true, zetaDelta := true, failIfUnchanged := false })
|
||||
only [invImage, InvImage, Prod.lex, sizeOfWFRel, measure, Nat.lt_wfRel,
|
||||
WellFoundedRelation.rel, sizeOf_nat])
|
||||
|
||||
/-- Extensible helper tactic for `decreasing_tactic`. This handles the "base case"
|
||||
reasoning after applying lexicographic order lemmas.
|
||||
It can be extended by adding more macro definitions, e.g.
|
||||
|
|
@ -36,12 +51,13 @@ macro_rules | `(tactic| decreasing_trivial_pre_omega) => `(tactic| apply Nat.pre
|
|||
macro_rules | `(tactic| decreasing_trivial_pre_omega) => `(tactic| apply Nat.pred_lt; assumption) -- i-1 < i if i ≠ 0
|
||||
|
||||
|
||||
/-- Constructs a proof of decreasing along a well founded relation, by applying
|
||||
lexicographic order lemmas and using `ts` to solve the base case. If it fails,
|
||||
/-- Constructs a proof of decreasing along a well founded relation, by simplifying, then applying
|
||||
lexicographic order lemmas and finally using `ts` to solve the base case. If it fails,
|
||||
it prints a message to help the user diagnose an ill-founded recursive definition. -/
|
||||
macro "decreasing_with " ts:tacticSeq : tactic =>
|
||||
`(tactic|
|
||||
(simp_wf
|
||||
(clean_wf -- remove after next stage0 update
|
||||
try simp
|
||||
repeat (first | apply Prod.Lex.right | apply Prod.Lex.left)
|
||||
repeat (first | apply PSigma.Lex.right | apply PSigma.Lex.left)
|
||||
first
|
||||
|
|
|
|||
25
src/Lean/Elab/PreDefinition/WF/Basic.lean
Normal file
25
src/Lean/Elab/PreDefinition/WF/Basic.lean
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Joachim Breitner
|
||||
-/
|
||||
|
||||
prelude
|
||||
import Lean.Elab.Tactic.Basic
|
||||
|
||||
namespace Lean.Elab.WF
|
||||
|
||||
register_builtin_option cleanDecreasingByGoal : Bool := {
|
||||
defValue := true
|
||||
descr := "Cleans up internal implementation details in the proof goals presented by \
|
||||
`decreasing_by`, using the `clean_wf` tactic. Can be disabled for debugging \
|
||||
purposes. Please report an issue if you have to disable this option."
|
||||
}
|
||||
|
||||
open Lean Elab Tactic
|
||||
|
||||
def applyCleanWfTactic : TacticM Unit := do
|
||||
if cleanDecreasingByGoal.get (← getOptions) then
|
||||
Tactic.evalTactic (← `(tactic| all_goals clean_wf))
|
||||
|
||||
end Lean.Elab.WF
|
||||
|
|
@ -14,6 +14,7 @@ import Lean.Elab.RecAppSyntax
|
|||
import Lean.Elab.PreDefinition.Basic
|
||||
import Lean.Elab.PreDefinition.Structural.Basic
|
||||
import Lean.Elab.PreDefinition.Structural.BRecOn
|
||||
import Lean.Elab.PreDefinition.WF.Basic
|
||||
import Lean.Data.Array
|
||||
|
||||
namespace Lean.Elab.WF
|
||||
|
|
@ -142,6 +143,7 @@ private partial def processPSigmaCasesOn (x F val : Expr) (k : (F : Expr) → (v
|
|||
|
||||
private def applyDefaultDecrTactic (mvarId : MVarId) : TermElabM Unit := do
|
||||
let remainingGoals ← Tactic.run mvarId do
|
||||
applyCleanWfTactic
|
||||
Tactic.evalTactic (← `(tactic| decreasing_tactic))
|
||||
unless remainingGoals.isEmpty do
|
||||
Term.reportUnsolvedGoals remainingGoals
|
||||
|
|
@ -202,6 +204,7 @@ def solveDecreasingGoals (argsPacker : ArgsPacker) (decrTactics : Array (Option
|
|||
goals.forM fun goal => pushInfoTree (.hole goal)
|
||||
let remainingGoals ← Tactic.run goals[0]! do
|
||||
Tactic.setGoals goals.toList
|
||||
applyCleanWfTactic
|
||||
Tactic.withTacticInfoContext decrTactic.ref do
|
||||
Tactic.evalTactic decrTactic.tactic
|
||||
unless remainingGoals.isEmpty do
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import Lean.Elab.RecAppSyntax
|
|||
import Lean.Elab.PreDefinition.Basic
|
||||
import Lean.Elab.PreDefinition.Structural.Basic
|
||||
import Lean.Elab.PreDefinition.TerminationArgument
|
||||
import Lean.Elab.PreDefinition.WF.Basic
|
||||
import Lean.Data.Array
|
||||
|
||||
|
||||
|
|
@ -445,6 +446,7 @@ def evalRecCall (decrTactic? : Option DecreasingBy) (callerMeasures calleeMeasur
|
|||
else do
|
||||
Lean.Elab.Term.TermElabM.run' do Term.withoutErrToSorry do
|
||||
let remainingGoals ← Tactic.run mvarId do Tactic.withoutRecover do
|
||||
applyCleanWfTactic
|
||||
let tacticStx : Syntax ←
|
||||
match decrTactic? with
|
||||
| none => pure (← `(tactic| decreasing_tactic)).raw
|
||||
|
|
|
|||
|
|
@ -19,11 +19,9 @@ namespace Ex1
|
|||
def foo (n m : Nat) : Nat := foo n (dec2 m) + foo (dec1 n) 100
|
||||
termination_by (n, m)
|
||||
decreasing_by
|
||||
· simp_wf
|
||||
apply Prod.Lex.right
|
||||
· apply Prod.Lex.right
|
||||
apply dec2_lt
|
||||
· simp_wf
|
||||
apply Prod.Lex.left
|
||||
· apply Prod.Lex.left
|
||||
apply dec1_lt
|
||||
|
||||
end Ex1
|
||||
|
|
@ -35,11 +33,9 @@ namespace Ex2
|
|||
-- so this tactic script fails.
|
||||
def foo (n m : Nat) : Nat := foo n (dec2 m) + foo (dec1 n) 100 -- Error
|
||||
decreasing_by
|
||||
· simp_wf
|
||||
apply Prod.Lex.right
|
||||
· apply Prod.Lex.right
|
||||
apply dec2_lt
|
||||
· simp_wf
|
||||
apply Prod.Lex.left
|
||||
· apply Prod.Lex.left
|
||||
apply dec1_lt
|
||||
|
||||
end Ex2
|
||||
|
|
@ -49,7 +45,6 @@ namespace Ex3
|
|||
def foo (n m : Nat) : Nat := foo n (dec2 m) + foo (dec1 n) 100
|
||||
termination_by (n, m)
|
||||
decreasing_by all_goals
|
||||
simp_wf
|
||||
first
|
||||
| apply Prod.Lex.right
|
||||
apply dec2_lt
|
||||
|
|
@ -62,10 +57,9 @@ namespace Ex4
|
|||
|
||||
-- Multiple goals, no termination_By
|
||||
-- This does work, because the tactic is flexible enough
|
||||
-- (Not a recommended way; complex `decrasing_by` should go along with `termination_by`.)
|
||||
-- (Not a recommended way; complex `decreasing_by` should go along with `termination_by`.)
|
||||
def foo (n m : Nat) : Nat := foo n (dec2 m) + foo (dec1 n) 100 -- Error
|
||||
decreasing_by all_goals
|
||||
simp_wf
|
||||
first
|
||||
| apply Prod.Lex.right
|
||||
apply dec2_lt
|
||||
|
|
@ -108,8 +102,7 @@ namespace Ex8
|
|||
def foo (n m : Nat) : Nat := foo n (dec2 m) + foo (dec1 n) 100
|
||||
termination_by (n, m)
|
||||
decreasing_by -- Error
|
||||
· simp_wf
|
||||
apply Prod.Lex.right
|
||||
· apply Prod.Lex.right
|
||||
apply dec2_lt
|
||||
|
||||
end Ex8
|
||||
|
|
@ -120,8 +113,7 @@ namespace Ex9
|
|||
-- Shows guess-lex matrix
|
||||
def foo (n m : Nat) : Nat := foo n (dec2 m) + foo (dec1 n) 100 -- Error
|
||||
decreasing_by
|
||||
· simp_wf
|
||||
apply Prod.Lex.right
|
||||
· apply Prod.Lex.right
|
||||
apply dec2_lt
|
||||
|
||||
end Ex9
|
||||
|
|
@ -132,7 +124,6 @@ namespace Ex10
|
|||
-- (If it would it would produce the wrong termination order and then we should see errors)
|
||||
def foo (n m : Nat) : Nat := foo (n - 1) (dec2 m)
|
||||
decreasing_by all_goals
|
||||
· simp_wf
|
||||
apply dec2_lt
|
||||
· apply dec2_lt
|
||||
|
||||
end Ex10
|
||||
|
|
|
|||
|
|
@ -1,45 +1,45 @@
|
|||
decreasing_by.lean:36:0-43:17: error: Could not find a decreasing measure.
|
||||
decreasing_by.lean:34:0-39:17: error: Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
n m
|
||||
1) 36:29-43 = ?
|
||||
2) 36:46-62 ? _
|
||||
1) 34:29-43 = ?
|
||||
2) 34:46-62 ? _
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
decreasing_by.lean:66:0-73:19: error: Could not find a decreasing measure.
|
||||
decreasing_by.lean:61:0-67:19: error: Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
n m
|
||||
1) 66:29-43 = ?
|
||||
2) 66:46-62 ? _
|
||||
1) 61:29-43 = ?
|
||||
2) 61:46-62 ? _
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
decreasing_by.lean:81:13-83:3: error: unexpected token 'end'; expected '{' or tactic
|
||||
decreasing_by.lean:81:0-81:13: error: unsolved goals
|
||||
decreasing_by.lean:75:13-77:3: error: unexpected token 'end'; expected '{' or tactic
|
||||
decreasing_by.lean:75:0-75:13: error: unsolved goals
|
||||
n m : Nat
|
||||
⊢ (invImage (fun x => PSigma.casesOn x fun n m => (n, m)) Prod.instWellFoundedRelation).1 ⟨n, dec2 m⟩ ⟨n, m⟩
|
||||
⊢ Prod.Lex (fun a₁ a₂ => a₁ < a₂) (fun a₁ a₂ => a₁ < a₂) (n, dec2 m) (n, m)
|
||||
|
||||
n m : Nat
|
||||
⊢ (invImage (fun x => PSigma.casesOn x fun n m => (n, m)) Prod.instWellFoundedRelation).1 ⟨dec1 n, 100⟩ ⟨n, m⟩
|
||||
decreasing_by.lean:91:0-91:22: error: unsolved goals
|
||||
⊢ Prod.Lex (fun a₁ a₂ => a₁ < a₂) (fun a₁ a₂ => a₁ < a₂) (dec1 n, 100) (n, m)
|
||||
decreasing_by.lean:85:0-85:22: error: unsolved goals
|
||||
case a
|
||||
n m : Nat
|
||||
⊢ (invImage (fun x => PSigma.casesOn x fun n m => (n, m)) Prod.instWellFoundedRelation).1 ⟨n, dec2 m⟩ ⟨n, m⟩
|
||||
⊢ Prod.Lex (fun a₁ a₂ => a₁ < a₂) (fun a₁ a₂ => a₁ < a₂) (n, dec2 m) (n, m)
|
||||
|
||||
n m : Nat
|
||||
⊢ (invImage (fun x => PSigma.casesOn x fun n m => (n, m)) Prod.instWellFoundedRelation).1 ⟨dec1 n, 100⟩ ⟨n, m⟩
|
||||
decreasing_by.lean:99:0-100:22: error: Could not find a decreasing measure.
|
||||
⊢ Prod.Lex (fun a₁ a₂ => a₁ < a₂) (fun a₁ a₂ => a₁ < a₂) (dec1 n, 100) (n, m)
|
||||
decreasing_by.lean:93:0-94:22: error: Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
n m
|
||||
1) 99:29-43 = ?
|
||||
2) 99:46-62 ? _
|
||||
1) 93:29-43 = ?
|
||||
2) 93:46-62 ? _
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
decreasing_by.lean:110:0-113:17: error: unsolved goals
|
||||
decreasing_by.lean:104:0-106:17: error: unsolved goals
|
||||
n m : Nat
|
||||
⊢ (invImage (fun x => PSigma.casesOn x fun n m => (n, m)) Prod.instWellFoundedRelation).1 ⟨dec1 n, 100⟩ ⟨n, m⟩
|
||||
decreasing_by.lean:121:0-125:17: error: Could not find a decreasing measure.
|
||||
⊢ Prod.Lex (fun a₁ a₂ => a₁ < a₂) (fun a₁ a₂ => a₁ < a₂) (dec1 n, 100) (n, m)
|
||||
decreasing_by.lean:114:0-117:17: error: Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
n m
|
||||
1) 121:29-43 = ?
|
||||
2) 121:46-62 ? _
|
||||
1) 114:29-43 = ?
|
||||
2) 114:46-62 ? _
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
|
|
|
|||
|
|
@ -207,10 +207,10 @@ def foo : Nat → Nat
|
|||
| n+1 =>
|
||||
if h : n < 42 then bar (42 - n) else 0
|
||||
-- termination_by x1 => x1
|
||||
decreasing_by simp_wf; simp [OddNat3]; omega
|
||||
decreasing_by simp; omega
|
||||
def bar (o : OddNat3) : Nat := if h : @id Nat o < 41 then foo (41 - @id Nat o) else 0
|
||||
-- termination_by sizeOf o
|
||||
decreasing_by simp_wf; simp [id] at *; omega
|
||||
decreasing_by simp [id] at *; omega
|
||||
end
|
||||
end MutualNotNat2
|
||||
|
||||
|
|
@ -228,11 +228,11 @@ def foo : Nat → Nat
|
|||
| n+1 =>
|
||||
if h : n < 42 then bar (42 - n) else 0
|
||||
-- termination_by x1 => x1
|
||||
decreasing_by simp_wf; simp [OddNat3]; omega
|
||||
decreasing_by simp; omega
|
||||
def bar : OddNat3 → Nat
|
||||
| Nat.zero => 0
|
||||
| n+1 => if h : n < 41 then foo (40 - n) else 0
|
||||
-- termination_by x1 => sizeOf x1
|
||||
decreasing_by simp_wf; omega
|
||||
decreasing_by simp; omega
|
||||
end
|
||||
end MutualNotNat3
|
||||
|
|
|
|||
|
|
@ -56,11 +56,10 @@ def distinct (xs : Array Nat) : Bool :=
|
|||
loop 0 0
|
||||
|
||||
-- This examples shows a limitation of our current `decreasing_tactic`.
|
||||
-- Guesslex infers
|
||||
-- termination_by (Array.size xs - i, i)
|
||||
-- but because `decreasing_with` is using
|
||||
-- Guesslex infers `termination_by (Array.size xs - i, i)` but because `decreasing_with` is using
|
||||
-- repeat (first | apply Prod.Lex.right | apply Prod.Lex.left)
|
||||
-- it cannot solve this goal. But if we leave the Prod.Lex-handling to omega, it works
|
||||
-- it cannot solve this goal. But if we leave the Prod.Lex-handling to omega, it works.
|
||||
-- See https://github.com/leanprover/lean4/issues/3906
|
||||
def weird (xs : Array Nat) (i : Nat) : Bool :=
|
||||
if _ : i < xs.size then
|
||||
if _ : 0 < i then
|
||||
|
|
@ -72,7 +71,8 @@ def weird (xs : Array Nat) (i : Nat) : Bool :=
|
|||
weird xs (i+1)
|
||||
else
|
||||
true
|
||||
decreasing_by all_goals simp_wf; omega
|
||||
decreasing_by all_goals (try simp only [Array.size_pop]); omega
|
||||
|
||||
|
||||
/--
|
||||
This checks
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ def prod (x y z : Nat) : Nat :=
|
|||
-- termination_by (y, 1, 0)
|
||||
decreasing_by
|
||||
all_goals
|
||||
simp_wf
|
||||
search_lex solve
|
||||
| decreasing_trivial
|
||||
| apply Nat.bitwise_rec_lemma; assumption
|
||||
|
|
@ -50,19 +49,13 @@ decreasing_by
|
|||
def oprod (x y z : Nat) := eprod x (y - 1) (z + x)
|
||||
-- termination_by (y, 0, 1)
|
||||
decreasing_by
|
||||
simp_wf
|
||||
try -- the need for `try` here is fishy
|
||||
-- the proof with explicit `termination_by` does not need it, so it should not throw
|
||||
-- GuessLex off, but without `try` it does
|
||||
-- This appeared after #4522, which made Nat.sub_le a simp lemma
|
||||
search_lex solve
|
||||
| decreasing_trivial
|
||||
| apply Nat.bitwise_rec_lemma; assumption
|
||||
search_lex solve
|
||||
| decreasing_trivial
|
||||
| apply Nat.bitwise_rec_lemma; assumption
|
||||
|
||||
def eprod (x y z : Nat) := if y = 0 then z else prod (2 * x) (y / 2) z
|
||||
-- termination_by (y, 0, 0)
|
||||
decreasing_by
|
||||
simp_wf
|
||||
search_lex solve
|
||||
| decreasing_trivial
|
||||
| apply Nat.bitwise_rec_lemma; assumption
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ Tactic is run (ideally only twice)
|
|||
Tactic is run (ideally only twice)
|
||||
Tactic is run (ideally only once, in most general context)
|
||||
n : Nat
|
||||
⊢ (invImage (fun x => x) instWellFoundedRelationOfSizeOf).1 n n.succ
|
||||
⊢ n < n.succ
|
||||
Tactic is run (ideally only twice, in most general context)
|
||||
Tactic is run (ideally only twice, in most general context)
|
||||
n : Nat
|
||||
⊢ sizeOf n < sizeOf n.succ
|
||||
n m : Nat
|
||||
⊢ (invImage (fun x => PSigma.casesOn x fun a a_1 => a) instWellFoundedRelationOfSizeOf).1 ⟨n, m + 1⟩ ⟨n.succ, m⟩
|
||||
⊢ n < n.succ
|
||||
n m : Nat ⊢ n < n.succ
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ mutual
|
|||
| n, false => n + g n
|
||||
termination_by n b => (n, if b then 2 else 1)
|
||||
decreasing_by
|
||||
all_goals simp_wf
|
||||
· apply Prod.Lex.right; decide
|
||||
· apply Prod.Lex.right; decide
|
||||
|
||||
|
|
@ -17,7 +16,6 @@ mutual
|
|||
n
|
||||
termination_by (n, 0)
|
||||
decreasing_by
|
||||
all_goals simp_wf
|
||||
apply Prod.Lex.left
|
||||
apply Nat.pred_lt
|
||||
done -- should fail
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
mutwf1.lean:23:2-23:6: error: unsolved goals
|
||||
mutwf1.lean:21:2-21:6: error: unsolved goals
|
||||
case h.a
|
||||
n : Nat
|
||||
h : n ≠ 0
|
||||
⊢ n.sub 0 ≠ 0
|
||||
mutwf1.lean:33:22-33:29: error: failed to prove termination, possible solutions:
|
||||
mutwf1.lean:31:22-31:29: error: failed to prove termination, possible solutions:
|
||||
- Use `have`-expressions to prove the remaining goals
|
||||
- Use `termination_by` to specify a different well-founded relation
|
||||
- Use `decreasing_by` to specify your own tactic for discharging this kind of goal
|
||||
|
|
|
|||
69
tests/lean/run/4928.lean
Normal file
69
tests/lean/run/4928.lean
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/--
|
||||
error: tactic 'fail' failed
|
||||
x y : Nat
|
||||
⊢ x - 1 < x
|
||||
-/
|
||||
#guard_msgs in
|
||||
def g (x : Nat) (y : Nat) : Nat := g (x - 1) y
|
||||
termination_by x
|
||||
decreasing_by fail
|
||||
|
||||
/--
|
||||
error: tactic 'fail' failed
|
||||
x : List Nat
|
||||
y : Nat
|
||||
⊢ sizeOf x.tail < sizeOf x
|
||||
-/
|
||||
#guard_msgs in
|
||||
def h (x : List Nat) (y : Nat) : Nat := h x.tail y
|
||||
termination_by x
|
||||
decreasing_by fail
|
||||
|
||||
/--
|
||||
error: tactic 'fail' failed
|
||||
x : List Nat
|
||||
y : Nat
|
||||
⊢ x.tail.length < x.length
|
||||
-/
|
||||
#guard_msgs in
|
||||
def f (x : List Nat) (y : Nat) : Nat := f x.tail y
|
||||
termination_by x.length
|
||||
decreasing_by fail
|
||||
|
||||
/--
|
||||
error: tactic 'fail' failed
|
||||
x : List Nat
|
||||
y : Nat
|
||||
⊢ x.tail.length < x.length
|
||||
-/
|
||||
#guard_msgs in
|
||||
mutual
|
||||
def f1 (x : List Nat) (y : Nat) : Nat := f2 x.tail y
|
||||
termination_by x.length
|
||||
decreasing_by fail
|
||||
def f2 (x : List Nat) (y : Nat) : Nat := f1 x.tail y
|
||||
termination_by x.length
|
||||
decreasing_by fail
|
||||
end
|
||||
|
||||
/--
|
||||
error: tactic 'fail' failed
|
||||
x : List Nat
|
||||
y : Nat
|
||||
⊢ (invImage
|
||||
(fun x =>
|
||||
PSum.casesOn x (fun _x => PSigma.casesOn _x fun x y => x.length) fun _x =>
|
||||
PSigma.casesOn _x fun x y => x.length)
|
||||
instWellFoundedRelationOfSizeOf).1
|
||||
(PSum.inr ⟨x.tail, y⟩) (PSum.inl ⟨x, y⟩)
|
||||
-/
|
||||
#guard_msgs in
|
||||
set_option cleanDecreasingByGoal false in
|
||||
mutual
|
||||
def g1 (x : List Nat) (y : Nat) : Nat := g2 x.tail y
|
||||
termination_by x.length
|
||||
decreasing_by fail
|
||||
def g2 (x : List Nat) (y : Nat) : Nat := g1 x.tail y
|
||||
termination_by x.length
|
||||
decreasing_by fail
|
||||
end
|
||||
|
|
@ -495,9 +495,7 @@ def sum_below (n : Nat) (f : (i : Nat) → below n i → Nat) :=
|
|||
def foo (n : Nat) :=
|
||||
1 + sum_below n (fun i _ => foo i)
|
||||
termination_by n
|
||||
decreasing_by
|
||||
simp_wf
|
||||
simp [below_lt, *]
|
||||
decreasing_by simp [below_lt, *]
|
||||
|
||||
/--
|
||||
info: GramSchmidt.foo.induct (motive : Nat → Prop) (case1 : ∀ (x : Nat), (∀ (i : Nat), below x i → motive i) → motive x)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ def zero_out (arr : Array Nat) (i : Nat) : Array Nat :=
|
|||
else
|
||||
arr
|
||||
termination_by arr.size - i
|
||||
decreasing_by simp_wf; apply Nat.sub_succ_lt_self _ _ h
|
||||
decreasing_by simp; apply Nat.sub_succ_lt_self _ _ h
|
||||
|
||||
-- set_option trace.Elab.definition true
|
||||
theorem size_zero_out (arr : Array Nat) (i : Nat) : (zero_out arr i).size = arr.size := by
|
||||
|
|
@ -14,4 +14,4 @@ theorem size_zero_out (arr : Array Nat) (i : Nat) : (zero_out arr i).size = arr.
|
|||
rw [Array.size_set]
|
||||
· rfl
|
||||
termination_by arr.size - i
|
||||
decreasing_by simp_wf; apply Nat.sub_succ_lt_self; assumption
|
||||
decreasing_by simp; apply Nat.sub_succ_lt_self; assumption
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ mutual
|
|||
| n, a, b => g a n b |>.1
|
||||
termination_by n _ _ => (n, 2)
|
||||
decreasing_by
|
||||
simp_wf
|
||||
apply Prod.Lex.right
|
||||
decide
|
||||
|
||||
|
|
@ -14,7 +13,6 @@ mutual
|
|||
| a, n, b => (h a b n, a)
|
||||
termination_by _ n _ => (n, 1)
|
||||
decreasing_by
|
||||
simp_wf
|
||||
apply Prod.Lex.right
|
||||
decide
|
||||
|
||||
|
|
@ -23,7 +21,6 @@ mutual
|
|||
| a, b, n+1 => f n a b
|
||||
termination_by _ _ n => (n, 0)
|
||||
decreasing_by
|
||||
simp_wf
|
||||
apply Prod.Lex.left
|
||||
apply Nat.lt_succ_self
|
||||
end
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ def List.permutationsAux.rec' {C : List α → List α → Sort v} (H0 : ∀ is,
|
|||
| t :: ts, is =>
|
||||
H1 t ts is (permutationsAux.rec' H0 H1 ts (t :: is)) (permutationsAux.rec' H0 H1 is [])
|
||||
termination_by ts is => (length ts + length is, length ts)
|
||||
decreasing_by all_goals simp_wf; omega
|
||||
decreasing_by all_goals simp; omega
|
||||
|
||||
example {x y w z : Nat} (h : Prod.Lex (· < ·) (· < ·) (x + 1, y + 1) (w, z)) :
|
||||
Prod.Lex (· < ·) (· < ·) (x, y) (w, z) := by omega
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@ def len : List α → Nat
|
|||
termination_by xs => xs.length
|
||||
decreasing_by
|
||||
all_goals
|
||||
simp_wf
|
||||
have := splitList_length (fst ++ snd) (by simp_arith [h₁]) h₁
|
||||
subst h₂
|
||||
simp_arith [eq_of_heq h₃] at this |- ; simp [this]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ def g (i j : Nat) : Nat :=
|
|||
| Nat.succ j => h i j
|
||||
termination_by (i + j, 0)
|
||||
decreasing_by
|
||||
simp_wf
|
||||
· apply Prod.Lex.left
|
||||
apply Nat.lt_succ_self
|
||||
|
||||
|
|
@ -16,7 +15,6 @@ def h (i j : Nat) : Nat :=
|
|||
| Nat.succ j => g i j
|
||||
termination_by (i + j, 1)
|
||||
decreasing_by
|
||||
all_goals simp_wf
|
||||
· apply Prod.Lex.right
|
||||
decide
|
||||
· apply Prod.Lex.left
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ mutual
|
|||
| n, a, b => g a n b |>.1
|
||||
termination_by n _ _ => (n, 2)
|
||||
decreasing_by
|
||||
simp_wf
|
||||
apply Prod.Lex.right
|
||||
decide
|
||||
|
||||
|
|
@ -13,7 +12,6 @@ mutual
|
|||
| a, n, b => (h a b n, a)
|
||||
termination_by _ n _ => (n, 1)
|
||||
decreasing_by
|
||||
simp_wf
|
||||
apply Prod.Lex.right
|
||||
decide
|
||||
|
||||
|
|
@ -22,7 +20,6 @@ mutual
|
|||
| a, b, n+1 => f n a b
|
||||
termination_by _ _ n => (n, 0)
|
||||
decreasing_by
|
||||
simp_wf
|
||||
apply Prod.Lex.left
|
||||
apply Nat.lt_succ_self
|
||||
end
|
||||
|
|
|
|||
|
|
@ -55,20 +55,6 @@ def Ctx.extend (x : α) : HList Γ → HList (α :: Γ) :=
|
|||
def Ctx.drop : HList (α :: Γ) → HList Γ
|
||||
| HList.cons a as => as
|
||||
|
||||
macro_rules
|
||||
| `(tactic| decreasing_tactic) =>
|
||||
`(tactic|
|
||||
(simp_wf
|
||||
repeat (first | apply PSigma.Lex.right | apply PSigma.Lex.left)
|
||||
simp [Nat.add_comm (n := 1), Nat.succ_add, Nat.mul_succ]
|
||||
try apply Nat.lt_succ_of_le
|
||||
repeat apply Nat.le_step
|
||||
first
|
||||
| repeat first | apply Nat.le_add_left | apply Nat.le_add_right_of_le
|
||||
| assumption
|
||||
all_goals apply Nat.le_refl
|
||||
))
|
||||
|
||||
@[simp]
|
||||
def Stmt.mapCtx (f : HList Γ' → HList Γ) : Stmt m ω Γ Δ b c β → Stmt m ω Γ' Δ b c β
|
||||
| expr e => expr (e ∘ f)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue