Skip to content

Commit

Permalink
feat: Data.Array.Basic <- mathlib4
Browse files Browse the repository at this point in the history
  • Loading branch information
digama0 committed Sep 16, 2022
1 parent 795295e commit 23f8577
Show file tree
Hide file tree
Showing 4 changed files with 294 additions and 4 deletions.
1 change: 1 addition & 0 deletions Std.lean
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Std.Classes.SetNotation
import Std.Data.Array.Basic
import Std.Data.Array.Init.Basic
import Std.Data.Array.Init.Lemmas
import Std.Data.Array.Lemmas
import Std.Data.BinomialHeap
import Std.Data.DList
import Std.Data.Int.Basic
Expand Down
256 changes: 256 additions & 0 deletions Std/Data/Array/Lemmas.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
/-
Copyright (c) 2021 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Gabriel Ebner
-/
import Std.Data.Nat.Lemmas
import Std.Data.List.Lemmas
import Std.Tactic.HaveI
import Std.Tactic.Simpa

local macro_rules | `($x[$i]'$h) => `(getElem $x $i $h)

@[simp] theorem getElem_fin [GetElem Cont Nat Elem Dom] (a : Cont) (i : Fin n) (h : Dom a i) :
a[i] = a[i.1] := rfl

@[simp] theorem getElem?_fin [GetElem Cont Nat Elem Dom] (a : Cont) (i : Fin n)
[Decidable (Dom a i)] : a[i]? = a[i.1]? := rfl

@[simp] theorem getElem!_fin [GetElem Cont Nat Elem Dom] (a : Cont) (i : Fin n)
[Decidable (Dom a i)] [Inhabited Elem] : a[i]! = a[i.1]! := rfl

theorem getElem?_pos [GetElem Cont Idx Elem Dom]
(a : Cont) (i : Idx) (h : Dom a i) [Decidable (Dom a i)] : a[i]? = a[i] := dif_pos h

theorem getElem?_neg [GetElem Cont Idx Elem Dom]
(a : Cont) (i : Idx) (h : ¬Dom a i) [Decidable (Dom a i)] : a[i]? = none := dif_neg h

namespace Array

@[simp] theorem toArray_data : (a : Array α) → a.data.toArray = a
| ⟨l⟩ => ext' (data_toArray l)

@[simp] theorem get_eq_getElem (a : Array α) (i : Nat) (h) : a.get ⟨i, h⟩ = a[i] := rfl
@[simp] theorem getElem_fin_eq_getElem (a : Array α) (i : Fin a.size) : a[i] = a[i.1] := rfl
@[simp] theorem getElem?_fin_eq_get? (a : Array α) (i : Fin a.size) : a[i]? = a.get? i := rfl
@[simp] theorem get?_eq_getElem? (a : Array α) (i : Nat) : a.get? i = a[i]? := rfl
theorem getElem_fin_eq_data_get (a : Array α) (i : Fin _) : a[i] = a.data.get i := rfl

theorem getElem?_eq_getElem (a : Array α) (i : Nat) (h : i < a.size) : a[i]? = a[i] :=
getElem?_pos ..

theorem get?_len_le (a : Array α) (i : Nat) (h : a.size ≤ i) : a[i]? = none := by
simp [getElem?_neg, h]

theorem getElem_eq_data_get (a : Array α) (h : i < a.size) : a[i] = a.data.get ⟨i, h⟩ := by
by_cases i < a.size <;> simp [*] <;> rfl

theorem getElem?_eq_data_get? (a : Array α) (i : Nat) : a[i]? = a.data.get? i := by
by_cases i < a.size <;> simp_all [getElem?_pos, getElem?_neg, List.get?_eq_get, eq_comm] <;> rfl

theorem get?_eq_data_get? (a : Array α) (i : Nat) : a.get? i = a.data.get? i :=
getElem?_eq_data_get? ..

theorem get_push_lt (a : Array α) (x : α) (i : Nat) (h : i < a.size) :
haveI : i < (a.push x).size := by simp [*, Nat.lt_succ, Nat.le_of_lt]
(a.push x)[i] = a[i] := by
simp only [push, getElem_eq_data_get, List.concat_eq_append, List.get_append, h]

@[simp] theorem get_push_eq (a : Array α) (x : α) : (a.push x)[a.size] = x := by
simp only [push, getElem_eq_data_get, List.concat_eq_append]
rw [List.get_append_right] <;> simp [getElem_eq_data_get]

theorem get?_push_lt (a : Array α) (x : α) (i : Nat) (h : i < a.size) :
(a.push x)[i]? = some a[i] := by
rw [getElem?_pos, get_push_lt]

theorem get?_push_eq (a : Array α) (x : α) : (a.push x)[a.size]? = some x := by
rw [getElem?_pos, get_push_eq]

theorem get_push (a : Array α) (x : α) (i : Nat) (h : i < (a.push x).size) :
(a.push x)[i] = if h : i < a.size then a[i] else x := by
if h : i < a.size then
simp [get_push_lt, h]
else
have : i = a.size := by apply Nat.le_antisymm <;> simp_all [Nat.lt_succ]
simp [get_push_lt, this]

@[simp] theorem get_set_eq (a : Array α) (i : Nat) (h : i < a.size) (v : α) :
(a.set ⟨i, h⟩ v)[i]'(by simp [*]) = v := by
simp only [set, getElem_eq_data_get, List.get_set_eq]

@[simp] theorem get_set_ne (a : Array α) {i j : Nat} (v : α) (hi : i < a.size) (hj : j < a.size)
(h : i ≠ j) : (a.set ⟨i, hi⟩ v)[j]'(by simp [*]) = a[j] := by
simp only [set, getElem_eq_data_get, List.get_set_ne h]

@[simp] theorem get?_set_eq (a : Array α) (i : Nat) (h : i < a.size) (v : α) :
(a.set ⟨i, h⟩ v)[i]? = v := by
simp [getElem?_pos, *]

@[simp] theorem get?_set_ne (a : Array α) {i j : Nat} (v : α) (hi : i < a.size)
(h : i ≠ j) : (a.set ⟨i, hi⟩ v)[j]? = a[j]? := by
by_cases j < a.size <;> simp [getElem?_pos, getElem?_neg, *]

theorem get?_set (a : Array α) (i j : Nat) (hi : i < a.size) (v : α) :
(a.set ⟨i, hi⟩ v)[j]? = if i = j then some v else a[j]? := by
by_cases i = j <;> simp [*]

theorem get_set (a : Array α) (i j : Nat) (hi : i < a.size) (hj : j < a.size) (v : α) :
(a.set ⟨i, hi⟩ v)[j]'(by simp [*]) = if i = j then v else a[j] := by
by_cases i = j <;> simp [*]

theorem SatisfiesM_mapIdxM [Monad m] [LawfulMonad m] (as : Array α) (f : Fin as.size → α → m β)
(p : Fin as.size → α → β → Prop) (hp : ∀ i a, SatisfiesM (p i a) (f i a)) :
SatisfiesM (fun arr => ∃ eq : arr.size = as.size, ∀ i h, p ⟨i, h⟩ (as[i]'h) (arr[i]'(eq ▸ h)))
(Array.mapIdxM as f) := by
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : ∀ i h h', p ⟨i, h⟩ (as[i]'h) bs[i]) :
SatisfiesM (fun arr => ∃ eq : arr.size = as.size, ∀ i h, p ⟨i, h⟩ (as[i]'h) (arr[i]'(eq ▸ h)))
(Array.mapIdxM.map as f i j h bs) := by
induction i generalizing j bs with simp [mapIdxM.map]
| zero => exact .pure ⟨h₁ ▸ (Nat.zero_add _).symm.trans h, fun _ _ => h₂ ..⟩
| succ i ih =>
refine (hp _ _).bind fun b hb => ih (by simp [h₁]) fun i hi hi' => ?_
simp at hi'; simp [get_push]; split
case _ h => exact h₂ _ _ h
case _ h => cases h₁.symm ▸ (Nat.le_or_eq_or_le_succ hi').resolve_left h; exact hb
simp [mapIdxM]; exact go rfl fun.

@[simp] theorem size_mapIdx (a : Array α) (f : Fin a.size → α → β) : (a.mapIdx f).size = a.size :=
(SatisfiesM_Id_eq.1 (SatisfiesM_mapIdxM _ _ _ fun _ _ => .trivial)).1

@[simp] theorem getElem_mapIdx (a : Array α) (f : Fin a.size → α → β) (i : Nat) (h) :
haveI : i < a.size := by simp_all
(a.mapIdx f)[i]'h = f ⟨i, this⟩ a[i] := by
have := SatisfiesM_mapIdxM a f (fun i a b => b = f i a) fun _ _ => SatisfiesM_Id_eq.2 rfl
exact (SatisfiesM_Id_eq.1 this).2 i _

@[simp] theorem size_swap! (a : Array α) (i j) (hi : i < a.size) (hj : j < a.size) :
(a.swap! i j).size = a.size := by simp [swap!, hi, hj]

theorem size_reverse_rev (mid i) (a : Array α) (h : mid ≤ a.size) :
(Array.reverse.rev a.size mid a i).size = a.size :=
if hi : i < mid then by
unfold Array.reverse.rev
have : i < a.size := Nat.lt_of_lt_of_le hi h
have : a.size - i - 1 < a.size := Nat.sub_lt_self i.zero_lt_succ this
have := Array.size_reverse_rev mid (i+1) (a.swap! i (a.size - i - 1))
simp_all
else by
unfold Array.reverse.rev
simp [dif_neg hi]
termination_by _ => mid - i

@[simp] theorem size_reverse (a : Array α) : a.reverse.size = a.size := by
have := size_reverse_rev (a.size / 2) 0 a (Nat.div_le_self ..)
simp only [reverse, this]

theorem reverse'.termination {i j : Nat} (h : i < j) : j - 1 - (i + 1) < j - i := by
rw [Nat.sub_sub, Nat.add_comm]
exact Nat.lt_of_le_of_lt (Nat.pred_le _) (Nat.sub_succ_lt_self _ _ h)

/-- Reverse of an array. TODO: remove when this lands in core -/
def reverse' (as : Array α) : Array α :=
if h : as.size ≤ 1 then
as
else
loop as 0 ⟨as.size - 1, Nat.pred_lt (mt (fun h : as.size = 0 => h ▸ by decide) h)⟩
where
/-- Reverses the subsegment `as[i:j+1]` (that is, indices `i` to `j` inclusive) of `as`. -/
loop (as : Array α) (i : Nat) (j : Fin as.size) :=
if h : i < j then
have := reverse'.termination h
let as := as.swap ⟨i, Nat.lt_trans h j.2⟩ j
have : j-1 < as.size := by rw [size_swap]; exact Nat.lt_of_le_of_lt (Nat.pred_le _) j.2
loop as (i+1) ⟨j-1, this⟩
else
as
termination_by _ => j - i

private theorem fin_cast_val (e : n = n') (i : Fin n) : (e ▸ i).1 = i.1 := by cases e; rfl

@[simp] theorem size_reverse' (a : Array α) : a.reverse'.size = a.size := by
let rec go (as : Array α) (i j) : (reverse'.loop as i j).size = as.size := by
rw [reverse'.loop]
if h : i < j then
have := reverse'.termination h
simp [(go · (i+1) ⟨j-1, ·⟩), h]
else simp [h]
simp only [reverse']; split <;> simp [go]
termination_by _ => j - i

@[simp] theorem reverse'_data (a : Array α) : a.reverse'.data = a.data.reverse := by
let rec go (as : Array α) (i j hj)
(h : i + j + 1 = a.size) (h₂ : as.size = a.size)
(H : ∀ k, as.data.get? k = if i ≤ k ∧ k ≤ j then a.data.get? k else a.data.reverse.get? k)
(k) : (reverse'.loop as i ⟨j, hj⟩).data.get? k = a.data.reverse.get? k := by
rw [reverse'.loop]; dsimp; split <;> rename_i h₁
· have := reverse'.termination h₁
match j with | j+1 => ?_
simp [Nat.add_sub_cancel] at *
simp; rw [(go · (i+1) j)]
· rwa [Nat.add_right_comm i]
· simp [size_swap, h₂]
· intro k
rw [swap, ← getElem?_eq_data_get?, get?_set, get?_set]
simp [getElem?_eq_data_get?, getElem_eq_data_get, ← List.get?_eq_get, fin_cast_val, H,
Nat.le_of_lt h₁]
split <;> rename_i h₂
· simp [← h₂, Nat.not_le.2 (Nat.lt_succ_self _)]
exact (List.get?_reverse' _ _ (Eq.trans (by simp_arith) h)).symm
split <;> rename_i h₃
· simp [← h₃, Nat.not_le.2 (Nat.lt_succ_self _)]
exact (List.get?_reverse' _ _ (Eq.trans (by simp_arith) h)).symm
simp only [Nat.succ_le, Nat.lt_iff_le_and_ne.trans (and_iff_left h₃),
Nat.lt_succ.symm.trans (Nat.lt_iff_le_and_ne.trans (and_iff_left (Ne.symm h₂)))]
· rw [H]; split <;> rename_i h₂
· cases Nat.le_antisymm (Nat.not_lt.1 h₁) (Nat.le_trans h₂.1 h₂.2)
cases Nat.le_antisymm h₂.1 h₂.2
exact (List.get?_reverse' _ _ h).symm
· rfl
simp only [reverse']; split
case _ h => match a, h with | ⟨[]⟩, _ | ⟨[_]⟩, _ => rfl
case _ =>
have := Nat.sub_add_cancel (Nat.le_of_not_le ‹_›)
refine List.ext <| go _ _ _ _ (by simp [this]) rfl fun k => ?_
split; {rfl}; rename_i h
simp [← show k < _ + 1 ↔ _ from Nat.lt_succ (n := a.size - 1), this] at h
rw [List.get?_eq_none.2 ‹_›, List.get?_eq_none.2 (a.data.length_reverse ▸ ‹_›)]
termination_by _ => j - i

@[simp] theorem size_ofFn_go {n} (f : Fin n → α) (i acc) :
(ofFn.go f i acc).size = acc.size + (n - i) := by
if hin : i < n then
unfold ofFn.go
have : 1 + (n - (i + 1)) = n - i :=
Nat.sub_sub .. ▸ Nat.add_sub_cancel' (Nat.le_sub_of_add_le (Nat.add_comm .. ▸ hin))
rw [dif_pos hin, size_ofFn_go f (i+1), size_push, Nat.add_assoc, this]
else
have : n - i = 0 := Nat.sub_eq_zero_of_le (Nat.le_of_not_lt hin)
unfold ofFn.go
simp [hin, this]
termination_by size_ofFn_go n f i acc => n - i

@[simp] theorem size_ofFn (f : Fin n → α) : (ofFn f).size = n := by simp [ofFn]

theorem getElem_ofFn_go (f : Fin n → α) (i) {acc k}
(hki : k < n) (hin : i ≤ n) (hi : i = acc.size)
(hacc : ∀ j, ∀ hj : j < acc.size, acc[j] = f ⟨j, Nat.lt_of_lt_of_le hj (hi ▸ hin)⟩) :
haveI : acc.size + (n - acc.size) = n := Nat.add_sub_cancel' (hi ▸ hin)
(ofFn.go f i acc)[k]'(by simp [*]) = f ⟨k, hki⟩ := by
unfold ofFn.go
if hin : i < n then
have : 1 + (n - (i + 1)) = n - i :=
Nat.sub_sub .. ▸ Nat.add_sub_cancel' (Nat.le_sub_of_add_le (Nat.add_comm .. ▸ hin))
simp only [dif_pos hin]
rw [getElem_ofFn_go f (i+1) _ hin (by simp [*]) (fun j hj => ?hacc)]
cases (Nat.lt_or_eq_of_le <| Nat.le_of_lt_succ (by simpa using hj)) with
| inl hj => simp [get_push, hj, hacc j hj]
| inr hj => simp [get_push, *]
else
simp [hin, hacc k (Nat.lt_of_lt_of_le hki (Nat.le_of_not_lt (hi ▸ hin)))]
termination_by _ _ i _ _ _ _ _ _ => n - i

@[simp] theorem getElem_ofFn (f : Fin n → α) (i : Nat) (h) :
(ofFn f)[i] = f ⟨i, size_ofFn f ▸ h⟩ :=
getElem_ofFn_go _ _ _ (by simp) (by simp) fun.
31 changes: 29 additions & 2 deletions Std/Data/List/Lemmas.lean
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ theorem get?_append_right : ∀ {l₁ l₂ : List α} {n : Nat}, l₁.length ≤
| [], _, n, _ => rfl
| a :: l, _, n+1, h₁ => by
rw [cons_append]; simp
rw [Nat.add_sub_add_right, get?_append_right (Nat.lt_succ_iff.mp h₁)]
rw [Nat.add_sub_add_right, get?_append_right (Nat.lt_succ.1 h₁)]

theorem get_append_right_aux {l₁ l₂ : List α} {n : Nat}
(h₁ : l₁.length ≤ n) (h₂ : n < (l₁ ++ l₂).length) : n - l₁.length < l₂.length := by
Expand Down Expand Up @@ -534,6 +534,21 @@ theorem ext_get {l₁ l₂ : List α} (hl : length l₁ = length l₂)
have h₁ := Nat.le_of_not_lt h₁
rw [get?_len_le h₁, get?_len_le]; rwa [← hl]

theorem get?_reverse' : ∀ {l : List α} (i j), i + j + 1 = length l →
get? l.reverse i = get? l j
| [], _, _, _ => rfl
| a::l, i, 0, h => by simp at h; simp [h, get?_append_right]
| a::l, i, j+1, h => by
have := Nat.succ.inj h; simp at this ⊢
rw [get?_append, get?_reverse' _ j this]
rw [length_reverse, ← this]; apply Nat.lt_add_of_pos_right (Nat.succ_pos _)

theorem get?_reverse {l : List α} (i) (h : i < length l) :
get? l.reverse i = get? l (l.length - 1 - i) :=
get?_reverse' _ _ <| by
rw [Nat.add_sub_of_le (Nat.le_pred_of_lt h),
Nat.sub_add_cancel (Nat.lt_of_le_of_lt (Nat.zero_le _) h)]

/-! ### modify nth -/

theorem modifyNthTail_id : ∀ n (l : List α), l.modifyNthTail id n = l
Expand Down Expand Up @@ -589,12 +604,24 @@ theorem modifyNth_eq_set (f : α → α) :
theorem get?_set_eq (a : α) (n) (l : List α) : (set l n a).get? n = (fun _ => a) <$> l.get? n := by
simp only [set_eq_modifyNth, get?_modifyNth_eq]

theorem get?_set_of_lt (a : α) {n} {l : List α} (h : n < length l) :
theorem get?_set_eq_of_lt (a : α) {n} {l : List α} (h : n < length l) :
(set l n a).get? n = some a := by rw [get?_set_eq, get?_eq_get h]; rfl

theorem get?_set_ne (a : α) {m n} (l : List α) (h : m ≠ n) : (set l m a).get? n = l.get? n := by
simp only [set_eq_modifyNth, get?_modifyNth_ne _ _ h]

theorem get?_set (a : α) {m n} (l : List α) :
(set l m a).get? n = if m = n then (fun _ => a) <$> l.get? n else l.get? n := by
by_cases m = n <;> simp [*, get?_set_eq, get?_set_ne]

theorem get?_set_of_lt (a : α) {m n} (l : List α) (h : n < length l) :
(set l m a).get? n = if m = n then some a else l.get? n := by
simp [get?_set, get?_eq_get h]

theorem get?_set_of_lt' (a : α) {m n} (l : List α) (h : m < length l) :
(set l m a).get? n = if m = n then some a else l.get? n := by
simp [get?_set]; split <;> subst_vars <;> simp [*, get?_eq_get h]

@[simp] theorem set_nil (n : Nat) (a : α) : [].set n a = [] := rfl

@[simp] theorem set_succ (x : α) (xs : List α) (n : Nat) (a : α) :
Expand Down
10 changes: 8 additions & 2 deletions Std/Data/Nat/Lemmas.lean
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ attribute [simp] Nat.pred_zero Nat.pred_succ

theorem ne_of_gt {a b : Nat} (h : b < a) : a ≠ b := (ne_of_lt h).symm

theorem succ_le {n m : Nat} : succ n ≤ m ↔ n < m := .rfl

protected theorem le_of_not_le {a b : Nat} : ¬ a ≤ b → b ≤ a := (Nat.le_total a b).resolve_left

protected theorem pos_of_ne_zero {n : Nat} : n ≠ 00 < n := (eq_zero_or_pos n).resolve_left
Expand All @@ -39,6 +41,10 @@ protected theorem pos_iff_ne_zero {n : Nat} : 0 < n ↔ n ≠ 0 := ⟨ne_of_gt,
protected theorem lt_iff_le_not_le {m n : Nat} : m < n ↔ m ≤ n ∧ ¬ n ≤ m :=
fun h => ⟨Nat.le_of_lt h, Nat.not_le_of_gt h⟩, fun h => Nat.gt_of_not_le h.2

protected theorem lt_iff_le_and_ne {m n : Nat} : m < n ↔ m ≤ n ∧ m ≠ n :=
Nat.lt_iff_le_not_le.trans (and_congr_right fun h =>
not_congr ⟨Nat.le_antisymm h, fun e => e ▸ Nat.le_refl _⟩)

@[simp] protected theorem not_le {a b : Nat} : ¬ a ≤ b ↔ b < a :=
⟨Nat.gt_of_not_le, Nat.not_le_of_gt⟩

Expand Down Expand Up @@ -342,10 +348,10 @@ protected theorem le_or_le (a b : Nat) : a ≤ b ∨ b ≤ a := (Nat.lt_or_ge _
protected theorem lt_or_eq_of_le {n m : Nat} (h : n ≤ m) : n < m ∨ n = m :=
(Nat.lt_or_ge _ _).imp_right (Nat.le_antisymm h)

theorem le_zero_iff {i : Nat} : i ≤ 0 ↔ i = 0 :=
theorem le_zero {i : Nat} : i ≤ 0 ↔ i = 0 :=
⟨Nat.eq_zero_of_le_zero, fun h => h ▸ Nat.le_refl i⟩

theorem lt_succ_iff {m n : Nat} : m < succ n ↔ m ≤ n :=
theorem lt_succ {m n : Nat} : m < succ n ↔ m ≤ n :=
⟨le_of_lt_succ, lt_succ_of_le⟩

/- subtraction -/
Expand Down

0 comments on commit 23f8577

Please sign in to comment.