Compare commits

...

1 Commits

Author SHA1 Message Date
Kim Morrison
5482be4298 feat: align List/Array/Vector.insertIdx lemmas 2025-02-04 23:01:12 +11:00
11 changed files with 384 additions and 5 deletions

View File

@@ -26,3 +26,4 @@ import Init.Data.Array.Lex
import Init.Data.Array.Range
import Init.Data.Array.Erase
import Init.Data.Array.Zip
import Init.Data.Array.InsertIdx

View File

@@ -953,7 +953,11 @@ def eraseP (as : Array α) (p : α → Bool) : Array α :=
| none => as
| some i => as.eraseIdx i
/-- Insert element `a` at position `i`. -/
/-- Insert element `a` at position `i`.
This function takes worst case O(n) time because
it has to swap the inserted element into place.
-/
@[inline] def insertIdx (as : Array α) (i : Nat) (a : α) (_ : i as.size := by get_elem_tactic) : Array α :=
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
loop (as : Array α) (j : Fin as.size) :=

View File

@@ -0,0 +1,129 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Array.Lemmas
import Init.Data.List.Nat.InsertIdx
/-!
# insertIdx
Proves various lemmas about `Array.insertIdx`.
-/
open Function
open Nat
namespace Array
universe u
variable {α : Type u}
section InsertIdx
variable {a : α}
@[simp] theorem toList_insertIdx (a : Array α) (i x) (h) :
(a.insertIdx i x h).toList = a.toList.insertIdx i x := by
rcases a with a
simp
@[simp]
theorem insertIdx_zero (s : Array α) (x : α) : s.insertIdx 0 x = #[x] ++ s := by
cases s
simp
@[simp] theorem size_insertIdx {as : Array α} (h : n as.size) : (as.insertIdx n a).size = as.size + 1 := by
cases as
simp [List.length_insertIdx, h]
theorem eraseIdx_insertIdx (i : Nat) (l : Array α) (h : i l.size) :
(l.insertIdx i a).eraseIdx i (by simp; omega) = l := by
cases l
simp_all
theorem insertIdx_eraseIdx_of_ge {as : Array α}
(w₁ : i < as.size) (w₂ : j (as.eraseIdx i).size) (h : i j) :
(as.eraseIdx i).insertIdx j a =
(as.insertIdx (j + 1) a (by simp at w₂; omega)).eraseIdx i (by simp_all; omega) := by
cases as
simpa using List.insertIdx_eraseIdx_of_ge _ _ _ (by simpa) (by simpa)
theorem insertIdx_eraseIdx_of_le {as : Array α}
(w₁ : i < as.size) (w₂ : j (as.eraseIdx i).size) (h : j i) :
(as.eraseIdx i).insertIdx j a =
(as.insertIdx j a (by simp at w₂; omega)).eraseIdx (i + 1) (by simp_all) := by
cases as
simpa using List.insertIdx_eraseIdx_of_le _ _ _ (by simpa) (by simpa)
theorem insertIdx_comm (a b : α) (i j : Nat) (l : Array α) (_ : i j) (_ : j l.size) :
(l.insertIdx i a).insertIdx (j + 1) b (by simpa) =
(l.insertIdx j b).insertIdx i a (by simp; omega) := by
cases l
simpa using List.insertIdx_comm a b i j _ (by simpa) (by simpa)
theorem mem_insertIdx {l : Array α} {h : i l.size} : a l.insertIdx i b h a = b a l := by
cases l
simpa using List.mem_insertIdx (by simpa)
@[simp]
theorem insertIdx_size_self (l : Array α) (x : α) : l.insertIdx l.size x = l.push x := by
cases l
simp
theorem getElem_insertIdx {as : Array α} {x : α} {i k : Nat} (w : i as.size) (h : k < (as.insertIdx i x).size) :
(as.insertIdx i x)[k] =
if h₁ : k < i then
as[k]'(by simp [size_insertIdx] at h; omega)
else
if h₂ : k = i then
x
else
as[k-1]'(by simp [size_insertIdx] at h; omega) := by
cases as
simp [List.getElem_insertIdx, w]
theorem getElem_insertIdx_of_lt {as : Array α} {x : α} {i k : Nat} (w : i as.size) (h : k < i) :
(as.insertIdx i x)[k]'(by simp; omega) = as[k] := by
simp [getElem_insertIdx, w, h]
theorem getElem_insertIdx_self {as : Array α} {x : α} {i : Nat} (w : i as.size) :
(as.insertIdx i x)[i]'(by simp; omega) = x := by
simp [getElem_insertIdx, w]
theorem getElem_insertIdx_of_gt {as : Array α} {x : α} {i k : Nat} (w : k as.size) (h : k > i) :
(as.insertIdx i x)[k]'(by simp; omega) = as[k - 1]'(by omega) := by
simp [getElem_insertIdx, w, h]
rw [dif_neg (by omega), dif_neg (by omega)]
theorem getElem?_insertIdx {l : Array α} {x : α} {i k : Nat} (h : i l.size) :
(l.insertIdx i x)[k]? =
if k < i then
l[k]?
else
if k = i then
if k l.size then some x else none
else
l[k-1]? := by
cases l
simp [List.getElem?_insertIdx, h]
theorem getElem?_insertIdx_of_lt {l : Array α} {x : α} {i k : Nat} (w : i l.size) (h : k < i) :
(l.insertIdx i x)[k]? = l[k]? := by
rw [getElem?_insertIdx, if_pos h]
theorem getElem?_insertIdx_self {l : Array α} {x : α} {i : Nat} (w : i l.size) :
(l.insertIdx i x)[i]? = some x := by
rw [getElem?_insertIdx, if_neg (by omega), if_pos rfl, if_pos w]
theorem getElem?_insertIdx_of_ge {l : Array α} {x : α} {i k : Nat} (w : i < k) (h : k l.size) :
(l.insertIdx i x)[k]? = l[k - 1]? := by
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
end InsertIdx
end Array

View File

@@ -52,6 +52,7 @@ theorem length_insertIdx_of_le_length (h : n ≤ length as) : length (insertIdx
theorem length_insertIdx_of_length_lt (h : length as < n) : length (insertIdx n a as) = length as := by
simp [length_insertIdx, h]
@[simp]
theorem eraseIdx_insertIdx (n : Nat) (l : List α) : (l.insertIdx n a).eraseIdx n = l := by
rw [eraseIdx_eq_modifyTailIdx, insertIdx, modifyTailIdx_modifyTailIdx_self]
exact modifyTailIdx_id _ _
@@ -150,7 +151,7 @@ theorem getElem_insertIdx_self {l : List α} {x : α} {n : Nat} (hn : n < (inser
· simp only [insertIdx_succ_cons, length_cons, length_insertIdx, Nat.add_lt_add_iff_right] at hn ih
simpa using ih hn
theorem getElem_insertIdx_of_ge {l : List α} {x : α} {n k : Nat} (hn : n + 1 k)
theorem getElem_insertIdx_of_gt {l : List α} {x : α} {n k : Nat} (hn : n < k)
(hk : k < (insertIdx n x l).length) :
(insertIdx n x l)[k] = l[k - 1]'(by simp [length_insertIdx] at hk; split at hk <;> omega) := by
induction l generalizing n k with
@@ -177,6 +178,9 @@ theorem getElem_insertIdx_of_ge {l : List α} {x : α} {n k : Nat} (hn : n + 1
| zero => omega
| succ k => simp
@[deprecated getElem_insertIdx_of_gt (since := "2025-02-04")]
abbrev getElem_insertIdx_of_ge := @getElem_insertIdx_of_gt
theorem getElem_insertIdx {l : List α} {x : α} {n k : Nat} (h : k < (insertIdx n x l).length) :
(insertIdx n x l)[k] =
if h₁ : k < n then
@@ -191,7 +195,7 @@ theorem getElem_insertIdx {l : List α} {x : α} {n k : Nat} (h : k < (insertIdx
· split <;> rename_i h₂
· subst h₂
rw [getElem_insertIdx_self h]
· rw [getElem_insertIdx_of_ge (by omega)]
· rw [getElem_insertIdx_of_gt (by omega)]
theorem getElem?_insertIdx {l : List α} {x : α} {n k : Nat} :
(insertIdx n x l)[k]? =
@@ -233,10 +237,13 @@ theorem getElem?_insertIdx_self {l : List α} {x : α} {n : Nat} :
rw [getElem?_insertIdx, if_neg (by omega)]
simp
theorem getElem?_insertIdx_of_ge {l : List α} {x : α} {n k : Nat} (h : n + 1 k) :
theorem getElem?_insertIdx_of_gt {l : List α} {x : α} {n k : Nat} (h : n < k) :
(insertIdx n x l)[k]? = l[k - 1]? := by
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
@[deprecated getElem?_insertIdx_of_gt (since := "2025-02-04")]
abbrev getElem?_insertIdx_of_ge := @getElem?_insertIdx_of_gt
end InsertIdx
end List

View File

@@ -101,7 +101,7 @@ theorem take_take : ∀ (n m) (l : List α), take n (take m l) = take (min n m)
| succ n, succ m, a :: l => by
simp only [take, succ_min_succ, take_take n m l]
theorem take_set_of_lt (a : α) {n m : Nat} (l : List α) (h : m < n) :
theorem take_set_of_le (a : α) {n m : Nat} (l : List α) (h : m n) :
(l.set n a).take m = l.take m :=
List.ext_getElem? fun i => by
rw [getElem?_take, getElem?_take]
@@ -109,6 +109,9 @@ theorem take_set_of_lt (a : α) {n m : Nat} (l : List α) (h : m < n) :
· next h' => rw [getElem?_set_ne (by omega)]
· rfl
@[deprecated take_set_of_le (since := "2025-02-04")]
abbrev take_set_of_lt := @take_set_of_le
@[simp] theorem take_replicate (a : α) : n m : Nat, take n (replicate m a) = replicate (min n m) a
| n, 0 => by simp [Nat.min_zero]
| 0, m => by simp [Nat.zero_min]
@@ -165,6 +168,10 @@ theorem take_add (l : List α) (m n : Nat) : l.take (m + n) = l.take m ++ (l.dro
theorem take_one {l : List α} : l.take 1 = l.head?.toList := by
induction l <;> simp
theorem take_eq_append_getElem_of_pos {n} {l : List α} (h₁ : 0 < n) (h₂ : n < l.length) : l.take n = l.take (n - 1) ++ [l[n - 1]] :=
match n, h₁ with
| n + 1, _ => take_succ_eq_append_getElem (n := n) (by omega)
theorem dropLast_take {n : Nat} {l : List α} (h : n < l.length) :
(l.take n).dropLast = l.take (n - 1) := by
simp only [dropLast_eq_take, length_take, Nat.le_of_lt h, Nat.min_eq_left, take_take, sub_le]
@@ -359,6 +366,10 @@ theorem drop_take : ∀ (m n : Nat) (l : List α), drop n (take m l) = take (m -
congr 1
omega
@[simp] theorem drop_take_self : drop n (take n l) = [] := by
rw [drop_take]
simp
theorem take_reverse {α} {xs : List α} {n : Nat} :
xs.reverse.take n = (xs.drop (xs.length - n)).reverse := by
by_cases h : n xs.length

View File

@@ -183,6 +183,9 @@ theorem take_concat_get (l : List α) (i : Nat) (h : i < l.length) :
(l.take i) ++ [l[i]] = l.take (i+1) := by
simpa using take_concat_get l i h
theorem take_succ_eq_append_getElem {n} {l : List α} (h : n < l.length) : l.take (n + 1) = l.take n ++ [l[n]] :=
(take_append_getElem _ _ h).symm
@[simp] theorem take_append_getLast (l : List α) (h : l []) :
(l.take (l.length - 1)) ++ [l.getLast h] = l := by
rw [getLast_eq_getElem]

View File

@@ -7,6 +7,7 @@ prelude
import Init.Data.List.Impl
import Init.Data.List.Nat.Erase
import Init.Data.List.Monadic
import Init.Data.List.Nat.InsertIdx
import Init.Data.Array.Lex.Basic
/-! ### Lemmas about `List.toArray`.
@@ -555,4 +556,65 @@ decreasing_by
rw [idxOf?_eq_map_finIdxOf?_val]
split <;> simp_all
private theorem insertIdx_loop_toArray (i : Nat) (l : List α) (j : Nat) (hj : j < l.toArray.size) (h : i j) :
insertIdx.loop i l.toArray j, hj = (l.take i ++ l[j] :: (l.take j).drop i ++ l.drop (j + 1)).toArray := by
rw [insertIdx.loop]
simp only [size_toArray] at hj
split <;> rename_i h'
· simp only at h'
have w : j - 1 + 1 = j := by omega
simp only [append_assoc, cons_append]
rw [insertIdx_loop_toArray _ _ _ _ (by omega)]
simp only [swap_toArray, w, append_assoc, cons_append, mk.injEq]
rw [List.take_set_of_le _ _ (by omega)]
rw [List.drop_eq_getElem_cons (n := j) (by simpa)]
rw [List.getElem_set_self]
rw [List.drop_set_of_lt _ _ (by omega)]
rw [List.drop_set_of_lt _ _ (by omega)]
rw [List.getElem_set_ne (by omega)]
rw [List.getElem_set_self]
rw [List.take_set_of_le (m := j - 1) _ _ (by omega)]
rw [List.take_set_of_le (m := j - 1) _ _ (by omega)]
rw [List.take_eq_append_getElem_of_pos (n := j) (l := l) (by omega) hj]
rw [List.drop_append_of_le_length (by simp; omega)]
simp only [append_assoc, cons_append, nil_append, append_cancel_right_eq]
cases i with
| zero => simp
| succ i => rw [List.take_set_of_le _ _ (by omega)]
· simp only [Nat.not_lt] at h'
have : i = j := by omega
subst this
simp
@[simp] theorem insertIdx_toArray (l : List α) (i : Nat) (a : α) (h : i l.toArray.size):
l.toArray.insertIdx i a = (l.insertIdx i a).toArray := by
rw [Array.insertIdx]
rw [insertIdx_loop_toArray (h := h)]
ext j h₁ h₂
· simp at h
simp [length_insertIdx, h]
omega
· simp [length_insertIdx] at h₁ h₂
simp [getElem_insertIdx]
split <;> rename_i h₃
· rw [getElem_append_left (by simp; split at h₂ <;> omega)]
simp only [getElem_take]
rw [getElem_append_left]
· rw [getElem_append_right (by simp; omega)]
rw [getElem_cons]
simp
split <;> rename_i h₄
· rw [dif_pos (by omega)]
· rw [dif_neg (by omega)]
congr
omega
@[simp] theorem insertIdxIfInBounds_toArray (l : List α) (i : Nat) (a : α) :
l.toArray.insertIdxIfInBounds i a = (l.insertIdx i a).toArray := by
rw [Array.insertIdxIfInBounds]
split <;> rename_i h'
· simp
· simp only [size_toArray, Nat.not_le] at h'
rw [List.insertIdx_of_length_lt (h := h')]
end List

View File

@@ -15,3 +15,4 @@ import Init.Data.Vector.OfFn
import Init.Data.Vector.Range
import Init.Data.Vector.Erase
import Init.Data.Vector.Monadic
import Init.Data.Vector.InsertIdx

View File

@@ -7,6 +7,7 @@ Authors: Shreyas Srinivas, François G. Dorais, Kim Morrison
prelude
import Init.Data.Array.Lemmas
import Init.Data.Array.MapIdx
import Init.Data.Array.InsertIdx
import Init.Data.Range
import Init.Data.Stream
@@ -355,6 +356,19 @@ instance [BEq α] : BEq (Vector α n) where
have : Inhabited (Vector α (n-1)) := v.pop
panic! "index out of bounds"
/-- Insert an element into a vector using a `Nat` index and a tactic provided proof. -/
@[inline] def insertIdx (v : Vector α n) (i : Nat) (x : α) (h : i n := by get_elem_tactic) :
Vector α (n+1) :=
v.toArray.insertIdx i x (v.size_toArray.symm h), by simp [Array.size_insertIdx]
/-- Insert an element into a vector using a `Nat` index. Panics if the index is out of bounds. -/
@[inline] def insertIdx! (v : Vector α n) (i : Nat) (x : α) : Vector α (n+1) :=
if _ : i n then
v.insertIdx i x
else
have : Inhabited (Vector α (n+1)) := v.push x
panic! "index out of bounds"
/-- Delete the first element of a vector. Returns the empty vector if the input vector is empty. -/
@[inline] def tail (v : Vector α n) : Vector α (n-1) :=
if _ : 0 < n then

View File

@@ -0,0 +1,126 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Vector.Lemmas
import Init.Data.Array.InsertIdx
/-!
# insertIdx
Proves various lemmas about `Vector.insertIdx`.
-/
open Function
open Nat
namespace Vector
universe u
variable {α : Type u}
section InsertIdx
variable {a : α}
@[simp]
theorem insertIdx_zero (s : Vector α n) (x : α) : s.insertIdx 0 x = (#v[x] ++ s).cast (by omega) := by
cases s
simp
theorem eraseIdx_insertIdx (i : Nat) (l : Vector α n) (h : i n) :
(l.insertIdx i a).eraseIdx i = l := by
rcases l with l, rfl
simp_all [Array.eraseIdx_insertIdx]
theorem insertIdx_eraseIdx_of_ge {as : Vector α n}
(w₁ : i < n) (w₂ : j n - 1) (h : i j) :
(as.eraseIdx i).insertIdx j a =
((as.insertIdx (j + 1) a).eraseIdx i).cast (by omega) := by
rcases as with as, rfl
simpa using Array.insertIdx_eraseIdx_of_ge (by simpa) (by simpa) (by simpa)
theorem insertIdx_eraseIdx_of_le {as : Vector α n}
(w₁ : i < n) (w₂ : j n - 1) (h : j i) :
(as.eraseIdx i).insertIdx j a =
((as.insertIdx j a).eraseIdx (i + 1)).cast (by omega) := by
rcases as with as, rfl
simpa using Array.insertIdx_eraseIdx_of_le (by simpa) (by simpa) (by simpa)
theorem insertIdx_comm (a b : α) (i j : Nat) (l : Vector α n) (_ : i j) (_ : j n) :
(l.insertIdx i a).insertIdx (j + 1) b =
(l.insertIdx j b).insertIdx i a := by
rcases l with l, rfl
simpa using Array.insertIdx_comm a b i j _ (by simpa) (by simpa)
theorem mem_insertIdx {l : Vector α n} {h : i n} : a l.insertIdx i b h a = b a l := by
rcases l with l, rfl
simpa using Array.mem_insertIdx
@[simp]
theorem insertIdx_size_self (l : Vector α n) (x : α) : l.insertIdx n x = l.push x := by
rcases l with l, rfl
simp
theorem getElem_insertIdx {as : Vector α n} {x : α} {i k : Nat} (w : i n) (h : k < n + 1) :
(as.insertIdx i x)[k] =
if h₁ : k < i then
as[k]
else
if h₂ : k = i then
x
else
as[k-1] := by
rcases as with as, rfl
simp [Array.getElem_insertIdx, w]
theorem getElem_insertIdx_of_lt {as : Vector α n} {x : α} {i k : Nat} (w : i n) (h : k < i) :
(as.insertIdx i x)[k] = as[k] := by
rcases as with as, rfl
simp [Array.getElem_insertIdx, w, h]
theorem getElem_insertIdx_self {as : Vector α n} {x : α} {i : Nat} (w : i n) :
(as.insertIdx i x)[i] = x := by
rcases as with as, rfl
simp [Array.getElem_insertIdx, w]
theorem getElem_insertIdx_of_gt {as : Vector α n} {x : α} {i k : Nat} (w : k n) (h : k > i) :
(as.insertIdx i x)[k] = as[k - 1] := by
rcases as with as, rfl
simp [Array.getElem_insertIdx, w, h]
rw [dif_neg (by omega), dif_neg (by omega)]
theorem getElem?_insertIdx {l : Vector α n} {x : α} {i k : Nat} (h : i n) :
(l.insertIdx i x)[k]? =
if k < i then
l[k]?
else
if k = i then
if k l.size then some x else none
else
l[k-1]? := by
rcases l with l, rfl
simp [Array.getElem?_insertIdx, h]
theorem getElem?_insertIdx_of_lt {l : Vector α n} {x : α} {i k : Nat} (w : i n) (h : k < i) :
(l.insertIdx i x)[k]? = l[k]? := by
rcases l with l, rfl
rw [getElem?_insertIdx, if_pos h]
theorem getElem?_insertIdx_self {l : Vector α n} {x : α} {i : Nat} (w : i n) :
(l.insertIdx i x)[i]? = some x := by
rcases l with l, rfl
rw [getElem?_insertIdx, if_neg (by omega), if_pos rfl, if_pos w]
theorem getElem?_insertIdx_of_ge {l : Vector α n} {x : α} {i k : Nat} (w : i < k) (h : k n) :
(l.insertIdx i x)[k]? = l[k - 1]? := by
rcases l with l, rfl
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
end InsertIdx
end Vector

View File

@@ -95,6 +95,13 @@ theorem toArray_mk (a : Array α) (h : a.size = n) : (Vector.mk a h).toArray = a
(Vector.mk a h).eraseIdx! i = Vector.mk (a.eraseIdx i) (by simp [h, hi]) := by
simp [Vector.eraseIdx!, hi]
@[simp] theorem insertIdx_mk (a : Array α) (h : a.size = n) (i x) (h') :
(Vector.mk a h).insertIdx i x h' = Vector.mk (a.insertIdx i x) (by simp [h, h']) := rfl
@[simp] theorem insertIdx!_mk (a : Array α) (h : a.size = n) (i x) (hi : i n) :
(Vector.mk a h).insertIdx! i x = Vector.mk (a.insertIdx i x) (by simp [h, hi]) := by
simp [Vector.insertIdx!, hi]
@[simp] theorem cast_mk (a : Array α) (h : a.size = n) (h' : n = m) :
(Vector.mk a h).cast h' = Vector.mk a (by simp [h, h']) := rfl
@@ -272,6 +279,13 @@ abbrev zipWithIndex_mk := @zipIdx_mk
(a.eraseIdx! i).toArray = a.toArray.eraseIdx! i := by
cases a; simp_all [Array.eraseIdx!]
@[simp] theorem toArray_insertIdx (a : Vector α n) (i x) (h) :
(a.insertIdx i x h).toArray = a.toArray.insertIdx i x (by simp [h]) := rfl
@[simp] theorem toArray_insertIdx! (a : Vector α n) (i x) (hi : i n) :
(a.insertIdx! i x).toArray = a.toArray.insertIdx! i x := by
cases a; simp_all [Array.insertIdx!]
@[simp] theorem toArray_cast (a : Vector α n) (h : n = m) :
(a.cast h).toArray = a.toArray := rfl
@@ -494,6 +508,13 @@ theorem toList_eraseIdx (a : Vector α n) (i) (h) :
(a.eraseIdx! i).toList = a.toList.eraseIdx i := by
cases a; simp_all [Array.eraseIdx!]
theorem toList_insertIdx (a : Vector α n) (i x) (h) :
(a.insertIdx i x h).toList = a.toList.insertIdx i x := by simp
theorem toList_insertIdx! (a : Vector α n) (i x) (hi : i n) :
(a.insertIdx! i x).toList = a.toList.insertIdx i x := by
cases a; simp_all [Array.insertIdx!]
theorem toList_cast (a : Vector α n) (h : n = m) :
(a.cast h).toList = a.toList := rfl