Zulip Chat Archive
Stream: lean4
Topic: Simplifying match and projection
pandaman (Nov 20 2023 at 08:09):
Hi. I have the following function:
def f {α : Type} (arr : Array α) (i j : Nat) : { m : Nat // i ≤ m ∧ m ≤ j } × Array α := sorry
When proving a theorem involving the function, I wanted to simplify a term with match
and the projection like this, but simp
couldn't process it.
theorem motive {α : Type} (arr : Array α) (i j : Nat) :
(match f arr i (j - 1) with
| (⟨mid, ⟨hmid₁, hmid₂⟩⟩, arr) => (⟨mid, ⟨hmid₁, Nat.le_trans hmid₂ (Nat.sub_le ..)⟩⟩, arr)
: { mid : Nat // i ≤ mid ∧ mid ≤ j } × Array α).snd = (f arr i (j - 1)).snd := by
-- simp made no progress
sorry
It seems that the ⟨hmid₁, hmid₂⟩
part is the culprit, so this version worked:
theorem motive' {α : Type} (arr : Array α) (i j : Nat) :
(match f arr i (j - 1) with
| (⟨mid, hm⟩, arr) => (⟨mid, ⟨hm.left, Nat.le_trans hm.right (Nat.sub_le ..)⟩⟩, arr)
: { mid : Nat // i ≤ mid ∧ mid ≤ j } × Array α).snd = (f arr i (j - 1)).snd := by
simp
Out of curiosity, I would like to know
- Why the first version didn't work?
- If we don't want to change the definition, how we can make the first version work?
Thanks!
pandaman (Nov 21 2023 at 12:27):
A similar instance of the issue (sorry, couldn't minimize this). Consider the following definition of quickSortImpl
.
abbrev Vec (α : Type) (n : Nat) := { arr : Array α // arr.size = n }
def partition {α : Type} [Ord α]
{n : Nat} (arr : Vec α n) (first last : Nat)
(fl : first ≤ last) (ln : last < n) :
{ mid : Nat // first ≤ mid ∧ mid ≤ last } × Vec α n := sorry
def quickSortImpl {α : Type} [Ord α]
{n : Nat} (arr : Vec α n) (first last : Nat) (ln : last < n) :
Vec α n :=
if lt : first < last then
match partition arr first last (Nat.le_of_lt lt) ln with
| (⟨mid, ⟨hmid₁, hmid₂⟩⟩, arr) =>
-- Lemmas
have : mid - 1 - first < last - first := sorry
have : last - (mid + 1) < last - first := sorry
have : mid - 1 < n := sorry
-- Recursion
let arr := quickSortImpl arr first (mid - 1) (by assumption)
quickSortImpl arr (mid + 1) last ln
else
arr
termination_by _ => last - first
When proving a theorem about the function, I got a term like this, which simp
cannot proceed with destructuring the match
:
-- def P (arr : Vec α n) : Prop := sorry
-- I want to show this
P (match partition arr first last (_ : first ≤ last) ln with
| ({ val := mid, property := (_ : first ≤ mid ∧ mid ≤ last) }, arr) =>
quickSortImpl (quickSortImpl arr first (mid - 1) (_ : mid - 1 < n)) (mid + 1) last ln)
However, when I removed the use of match
in quickSortImpl
, somehow I could get a nicer term:
-- Given this definition
def quickSortImpl {α : Type} [Ord α]
{n : Nat} (arr : Vec α n) (first last : Nat) (ln : last < n) :
Vec α n :=
if lt : first < last then
-- Do not use match
let parted := partition arr first last (Nat.le_of_lt lt) ln
let mid := parted.1.val
let hm := parted.1.property
let arr := parted.2
-- Lemmas
have : mid - 1 - first < last - first := termination_lemma lt hm.1 hm.2
have : last - (mid + 1) < last - first := Nat.sub_lt_sub_left lt (Nat.lt_of_le_of_lt hm.1 (Nat.lt_succ_self ..))
have : mid - 1 < n := Nat.lt_of_le_of_lt (Nat.sub_le ..) (Nat.lt_of_le_of_lt hm.2 ln)
-- Recursion
let arr := quickSortImpl arr first (mid - 1) (by assumption)
quickSortImpl arr (mid + 1) last ln
else
arr
-- I got this, which I could prove by recursion on P.
P (quickSortImpl
(quickSortImpl (partition arr first last (_ : first ≤ last) ln).snd first
((partition arr first last (_ : first ≤ last) ln).fst.val - 1)
(_ : (partition arr first last (_ : first ≤ last) ln).fst.val - 1 < n))
((partition arr first last (_ : first ≤ last) ln).fst.val + 1) last ln)
pandaman (Nov 21 2023 at 12:29):
Is this kind of use of match
to deconstruct nested data structures not recommended?
Last updated: Dec 20 2023 at 11:08 UTC