Zulip Chat Archive
Stream: lean4
Topic: Why is it necessary to run `simp_all` twice?
Asei Inoue (Nov 20 2025 at 12:15):
import Std.Tactic.Do
import Batteries
open Std
variable {α : Type} (A : Array α)
variable [LT α] [DecidableLT α]
@[grind =]
def ICan'tBelieveItCanSort := Id.run do
let N := A.size
let mut A := A.toVector
for hi : i in [:N] do
for hj : j in [:N] do
if A[i] < A[j] then
A := A.swap i j
return A.toArray
open Std.Do
set_option mvcgen.warning false
theorem ICan'tBelieveItCanSort_perm (arr : Array α) : Array.Perm (ICan'tBelieveItCanSort arr) arr := by
generalize h : ICan'tBelieveItCanSort arr = x
apply Id.of_wp_run_eq h
mvcgen invariants
· ⇓⟨_cursor, vec⟩ => ⌜Array.Perm arr vec.toArray⌝
· ⇓⟨_cursor, vec⟩ => ⌜Array.Perm arr vec.toArray⌝
with grind [Array.Perm.trans, Array.Perm.symm, Array.swap_perm]
@[simp, grind =]
theorem Vector.toArray_extract_size {α : Type} {n : Nat} (v : Vector α n) :
v.toArray.extract 0 n = v.toArray := by
grind
variable [LE α] [IsLinearOrder α] [LawfulOrderLT α]
@[grind! =>]
theorem cursor_pos_le_length (n : Nat) (xs : [0:n].toList.Cursor) : xs.pos ≤ n := by
have : xs.prefix.length + xs.suffix.length = n := by
simp [← List.length_append, xs.property]
grind only
@[simp]
theorem lemm (n cur : Nat) (pref suff : List Nat) (h : [:n].toList = pref ++ cur :: suff) :
pref.length = cur := by
grind
theorem sorted : ICan'tBelieveItCanSort A |>.Pairwise (· ≤ ·) := by
generalize h : ICan'tBelieveItCanSort A = x
apply Id.of_wp_run_eq h
mvcgen invariants
· ⇓⟨xs, A'⟩ => ⌜A'.take xs.pos |>.toArray.Pairwise (· ≤ ·)⌝
· ⇓⟨xs, A'⟩ => by
expose_names
exact ⌜(A'.take cur |>.toArray.Pairwise (· ≤ ·)) ∧ ∀ i (_ : i < xs.pos), A'[i]'(by grind) ≤ A'[cur]'(by grind)⌝
case vc1.step.isTrue =>
expose_names
simp_all [Array.pairwise_iff_getElem]
grind
case vc2 =>
grind
case vc3 =>
expose_names
simp_all
simp_all -- why twice `simp_all` is needed here?
-- why simp lemma `pref.length = cur` is not applied?
guard_hyp h_2 : Array.Pairwise (fun x1 x2 => x1 ≤ x2) (b.toArray.extract 0 pref.length)
grind
case vc4.step.post.success =>
simp_all [Array.pairwise_iff_getElem]
grind
case vc5 =>
grind
case vc6 =>
grind
Asei Inoue (Nov 20 2025 at 12:18):
I have two question:
- in case
vc3, why does the result change when I runsimp_alltwice? I thoughtsimp_allwas a tactic that simplifies “until nothing more can be simplified,” but is that not the case? - in case
vc3, why simp lemmapref.length = curis not applied?
Aaron Liu (Nov 20 2025 at 12:19):
Could be an instance of lean4#8300
Asei Inoue (Nov 20 2025 at 12:35):
I figured out why lemm isn’t being used by simp. It seems that simp is failing to automatically supply the argument h.
Kenny Lau (Nov 20 2025 at 12:39):
well, it isn't supposed to
Last updated: Dec 20 2025 at 21:32 UTC