diff --git a/src/Init/Data/Array/Lemmas.lean b/src/Init/Data/Array/Lemmas.lean index f8cdb902eb..0f1ef6d3df 100644 --- a/src/Init/Data/Array/Lemmas.lean +++ b/src/Init/Data/Array/Lemmas.lean @@ -72,6 +72,9 @@ theorem toArray_eq : List.toArray as = xs ↔ as = xs.toList := by /-! ### size -/ +theorem size_singleton {x : α} : #[x].size = 1 := by + simp + theorem eq_empty_of_size_eq_zero (h : xs.size = 0) : xs = #[] := by cases xs simp_all @@ -3483,6 +3486,21 @@ theorem foldl_eq_foldr_reverse {xs : Array α} {f : β → α → β} {b} : theorem foldr_eq_foldl_reverse {xs : Array α} {f : α → β → β} {b} : xs.foldr f b = xs.reverse.foldl (fun x y => f y x) b := by simp +theorem foldl_eq_apply_foldr {xs : Array α} {f : α → α → α} + [Std.Associative f] [Std.LawfulRightIdentity f init] : + xs.foldl f x = f x (xs.foldr f init) := by + simp [← foldl_toList, ← foldr_toList, List.foldl_eq_apply_foldr] + +theorem foldr_eq_apply_foldl {xs : Array α} {f : α → α → α} + [Std.Associative f] [Std.LawfulLeftIdentity f init] : + xs.foldr f x = f (xs.foldl f init) x := by + simp [← foldl_toList, ← foldr_toList, List.foldr_eq_apply_foldl] + +theorem foldr_eq_foldl {xs : Array α} {f : α → α → α} + [Std.Associative f] [Std.LawfulIdentity f init] : + xs.foldr f init = xs.foldl f init := by + simp [foldl_eq_apply_foldr, Std.LawfulLeftIdentity.left_id] + @[simp] theorem foldr_push_eq_append {as : Array α} {bs : Array β} {f : α → β} (w : start = as.size) : as.foldr (fun a xs => Array.push xs (f a)) bs start 0 = bs ++ (as.map f).reverse := by subst w @@ -4335,16 +4353,33 @@ def sum_eq_sum_toList := @sum_toList @[simp, grind =] theorem sum_append [Zero α] [Add α] [Std.Associative (α := α) (· + ·)] - [Std.LeftIdentity (α := α) (· + ·) 0] [Std.LawfulLeftIdentity (α := α) (· + ·) 0] + [Std.LawfulLeftIdentity (α := α) (· + ·) 0] {as₁ as₂ : Array α} : (as₁ ++ as₂).sum = as₁.sum + as₂.sum := by simp [← sum_toList, List.sum_append] +@[simp, grind =] +theorem sum_singleton [Add α] [Zero α] [Std.LawfulRightIdentity (· + ·) (0 : α)] {x : α} : + #[x].sum = x := by + simp [Array.sum_eq_foldr, Std.LawfulRightIdentity.right_id x] + +@[simp, grind =] +theorem sum_push [Add α] [Zero α] [Std.Associative (α := α) (· + ·)] + [Std.LawfulIdentity (· + ·) (0 : α)] {xs : Array α} {x : α} : + (xs.push x).sum = xs.sum + x := by + simp [Array.sum_eq_foldr, Std.LawfulRightIdentity.right_id, Std.LawfulLeftIdentity.left_id, + ← Array.foldr_assoc] + @[simp, grind =] theorem sum_reverse [Zero α] [Add α] [Std.Associative (α := α) (· + ·)] [Std.Commutative (α := α) (· + ·)] [Std.LawfulLeftIdentity (α := α) (· + ·) 0] (xs : Array α) : xs.reverse.sum = xs.sum := by simp [← sum_toList, List.sum_reverse] +theorem sum_eq_foldl [Zero α] [Add α] [Std.Associative (α := α) (· + ·)] + [Std.LawfulIdentity (· + ·) (0 : α)] {xs : Array α} : + xs.sum = xs.foldl (init := 0) (· + ·) := by + simp [← sum_toList, List.sum_eq_foldl] + theorem foldl_toList_eq_flatMap {l : List α} {acc : Array β} {F : Array β → α → Array β} {G : α → List β} (H : ∀ acc a, (F acc a).toList = acc.toList ++ G a) : diff --git a/src/Init/Data/Array/Perm.lean b/src/Init/Data/Array/Perm.lean index 35036fafe7..b08ecedda8 100644 --- a/src/Init/Data/Array/Perm.lean +++ b/src/Init/Data/Array/Perm.lean @@ -126,6 +126,14 @@ theorem swap_perm {xs : Array α} {i j : Nat} (h₁ : i < xs.size) (h₂ : j < x simp only [swap, perm_iff_toList_perm, toList_set] apply set_set_perm +theorem Perm.pairwise_iff {R : α → α → Prop} (S : ∀ {x y}, R x y → R y x) {xs ys : Array α} + : ∀ _p : xs.Perm ys, xs.toList.Pairwise R ↔ ys.toList.Pairwise R := by + simpa only [perm_iff_toList_perm] using List.Perm.pairwise_iff S + +theorem Perm.pairwise {R : α → α → Prop} {xs ys : Array α} (hp : xs ~ ys) + (hR : xs.toList.Pairwise R) (hsymm : ∀ {x y}, R x y → R y x) : + ys.toList.Pairwise R := (hp.pairwise_iff hsymm).mp hR + namespace Perm set_option linter.indexVariables false in diff --git a/src/Init/Data/List/Lemmas.lean b/src/Init/Data/List/Lemmas.lean index fe08754e69..35ab2331f5 100644 --- a/src/Init/Data/List/Lemmas.lean +++ b/src/Init/Data/List/Lemmas.lean @@ -1838,6 +1838,11 @@ theorem sum_append [Add α] [Zero α] [Std.LawfulLeftIdentity (α := α) (· + [Std.Associative (α := α) (· + ·)] {l₁ l₂ : List α} : (l₁ ++ l₂).sum = l₁.sum + l₂.sum := by induction l₁ generalizing l₂ <;> simp_all [Std.Associative.assoc, Std.LawfulLeftIdentity.left_id] +@[simp, grind =] +theorem sum_singleton [Add α] [Zero α] [Std.LawfulRightIdentity (· + ·) (0 : α)] {x : α} : + [x].sum = x := by + simp [List.sum_eq_foldr, Std.LawfulRightIdentity.right_id x] + @[simp, grind =] theorem sum_reverse [Zero α] [Add α] [Std.Associative (α := α) (· + ·)] [Std.Commutative (α := α) (· + ·)] @@ -2727,6 +2732,31 @@ theorem foldr_assoc {op : α → α → α} [ha : Std.Associative op] : simp only [foldr_cons, ha.assoc] rw [foldr_assoc] +theorem foldl_eq_apply_foldr {xs : List α} {f : α → α → α} + [Std.Associative f] [Std.LawfulRightIdentity f init] : + xs.foldl f x = f x (xs.foldr f init) := by + induction xs generalizing x + · simp [Std.LawfulRightIdentity.right_id] + · simp [foldl_assoc, *] + +theorem foldr_eq_apply_foldl {xs : List α} {f : α → α → α} + [Std.Associative f] [Std.LawfulLeftIdentity f init] : + xs.foldr f x = f (xs.foldl f init) x := by + have : Std.Associative (fun x y => f y x) := ⟨by simp [Std.Associative.assoc]⟩ + have : Std.RightIdentity (fun x y => f y x) init := ⟨⟩ + have : Std.LawfulRightIdentity (fun x y => f y x) init := ⟨by simp [Std.LawfulLeftIdentity.left_id]⟩ + rw [← List.reverse_reverse (as := xs), foldr_reverse, foldl_eq_apply_foldr, foldl_reverse] + +theorem foldr_eq_foldl {xs : List α} {f : α → α → α} + [Std.Associative f] [Std.LawfulIdentity f init] : + xs.foldr f init = xs.foldl f init := by + simp [foldl_eq_apply_foldr, Std.LawfulLeftIdentity.left_id] + +theorem sum_eq_foldl [Zero α] [Add α] [Std.Associative (α := α) (· + ·)] + [Std.LawfulIdentity (· + ·) (0 : α)] {xs : List α} : + xs.sum = xs.foldl (init := 0) (· + ·) := by + simp [sum_eq_foldr, foldl_eq_apply_foldr, Std.LawfulLeftIdentity.left_id] + -- The argument `f : α₁ → α₂` is intentionally explicit, as it is sometimes not found by unification. theorem foldl_hom (f : α₁ → α₂) {g₁ : α₁ → β → α₁} {g₂ : α₂ → β → α₂} {l : List β} {init : α₁} (H : ∀ x y, g₂ (f x) y = f (g₁ x y)) : l.foldl g₂ (f init) = f (l.foldl g₁ init) := by diff --git a/src/Init/Data/Vector/Lemmas.lean b/src/Init/Data/Vector/Lemmas.lean index 984d66c1a2..47e211a7d3 100644 --- a/src/Init/Data/Vector/Lemmas.lean +++ b/src/Init/Data/Vector/Lemmas.lean @@ -101,6 +101,17 @@ theorem toArray_mk {xs : Array α} (h : xs.size = n) : (Vector.mk xs h).toArray @[simp] theorem foldr_mk {f : α → β → β} {b : β} {xs : Array α} (h : xs.size = n) : (Vector.mk xs h).foldr f b = xs.foldr f b := rfl +@[simp, grind =] theorem foldlM_toArray [Monad m] + {f : β → α → m β} {init : β} {xs : Vector α n} : + xs.toArray.foldlM f init = xs.foldlM f init := rfl + +@[simp, grind =] theorem foldrM_toArray [Monad m] + {f : α → β → m β} {init : β} {xs : Vector α n} : + xs.toArray.foldrM f init = xs.foldrM f init := rfl + +@[simp, grind =] theorem foldl_toArray (f : β → α → β) {init : β} {xs : Vector α n} : + xs.toArray.foldl f init = xs.foldl f init := rfl + @[simp] theorem drop_mk {xs : Array α} {h : xs.size = n} {i} : (Vector.mk xs h).drop i = Vector.mk (xs.extract i xs.size) (by simp [h]) := rfl @@ -514,17 +525,32 @@ protected theorem ext {xs ys : Vector α n} (h : (i : Nat) → (_ : i < n) → x @[grind =_] theorem toList_toArray {xs : Vector α n} : xs.toArray.toList = xs.toList := rfl +theorem toArray_toList {xs : Vector α n} : xs.toList.toArray = xs.toArray := rfl + +@[simp, grind =] theorem foldlM_toList [Monad m] + {f : β → α → m β} {init : β} {xs : Vector α n} : + xs.toList.foldlM f init = xs.foldlM f init := by + rw [← foldlM_toArray, ← toArray_toList, List.foldlM_toArray] + +@[simp, grind =] theorem foldl_toList (f : β → α → β) {init : β} {xs : Vector α n} : + xs.toList.foldl f init = xs.foldl f init := + List.foldl_eq_foldlM .. ▸ foldlM_toList .. + +@[simp, grind =] theorem foldrM_toList [Monad m] + {f : α → β → m β} {init : β} {xs : Vector α n} : + xs.toList.foldrM f init = xs.foldrM f init := by + rw [← foldrM_toArray, ← toArray_toList, List.foldrM_toArray] + +@[simp, grind =] theorem foldr_toList (f : α → β → β) {init : β} {xs : Vector α n} : + xs.toList.foldr f init = xs.foldr f init := + List.foldr_eq_foldrM .. ▸ foldrM_toList .. + @[simp, grind =] theorem toList_mk : (Vector.mk xs h).toList = xs.toList := rfl @[simp, grind =] theorem sum_toList [Add α] [Zero α] {xs : Vector α n} : xs.toList.sum = xs.sum := by rw [← toList_toArray, Array.sum_toList, sum_toArray] -@[simp, grind =] -theorem toList_zip {as : Vector α n} {bs : Vector β n} : - (Vector.zip as bs).toList = List.zip as.toList bs.toList := by - rw [mk_zip_mk, toList_mk, Array.toList_zip, toList_toArray, toList_toArray] - @[simp] theorem getElem_toList {xs : Vector α n} {i : Nat} (h : i < xs.toList.length) : xs.toList[i] = xs[i]'(by simpa using h) := by cases xs @@ -609,6 +635,11 @@ theorem toList_swap {xs : Vector α n} {i j} (hi hj) : @[simp] theorem toList_take {xs : Vector α n} {i} : (xs.take i).toList = xs.toList.take i := by simp [toList] +@[simp, grind =] +theorem toList_zip {as : Vector α n} {bs : Vector β n} : + (Vector.zip as bs).toList = List.zip as.toList bs.toList := by + rw [mk_zip_mk, toList_mk, Array.toList_zip, toList_toArray, toList_toArray] + @[simp] theorem toList_zipWith {f : α → β → γ} {as : Vector α n} {bs : Vector β n} : (Vector.zipWith f as bs).toList = List.zipWith f as.toList bs.toList := by rcases as with ⟨as, rfl⟩ @@ -703,6 +734,9 @@ protected theorem eq_empty {xs : Vector α 0} : xs = #v[] := by /-! ### size -/ +theorem size_singleton {x : α} : #v[x].size = 1 := by + simp + theorem eq_empty_of_size_eq_zero {xs : Vector α n} (h : n = 0) : xs = #v[].cast h.symm := by rcases xs with ⟨xs, rfl⟩ apply toArray_inj.1 @@ -2448,6 +2482,21 @@ theorem foldl_eq_foldr_reverse {xs : Vector α n} {f : β → α → β} {b} : theorem foldr_eq_foldl_reverse {xs : Vector α n} {f : α → β → β} {b} : xs.foldr f b = xs.reverse.foldl (fun x y => f y x) b := by simp +theorem foldl_eq_apply_foldr {xs : Vector α n} {f : α → α → α} + [Std.Associative f] [Std.LawfulRightIdentity f init] : + xs.foldl f x = f x (xs.foldr f init) := by + simp [← foldl_toList, ← foldr_toList, List.foldl_eq_apply_foldr] + +theorem foldr_eq_apply_foldl {xs : Vector α n} {f : α → α → α} + [Std.Associative f] [Std.LawfulLeftIdentity f init] : + xs.foldr f x = f (xs.foldl f init) x := by + simp [← foldl_toList, ← foldr_toList, List.foldr_eq_apply_foldl] + +theorem foldr_eq_foldl {xs : Vector α n} {f : α → α → α} + [Std.Associative f] [Std.LawfulIdentity f init] : + xs.foldr f init = xs.foldl f init := by + simp [foldl_eq_apply_foldr, Std.LawfulLeftIdentity.left_id] + theorem foldl_assoc {op : α → α → α} [ha : Std.Associative op] {xs : Vector α n} {a₁ a₂} : xs.foldl op (op a₁ a₂) = op a₁ (xs.foldl op a₂) := by rcases xs with ⟨xs, rfl⟩ @@ -3064,8 +3113,25 @@ theorem sum_append [Zero α] [Add α] [Std.Associative (α := α) (· + ·)] {as₁ as₂ : Vector α n} : (as₁ ++ as₂).sum = as₁.sum + as₂.sum := by simp [← sum_toList, List.sum_append] +@[simp, grind =] +theorem sum_singleton [Add α] [Zero α] [Std.LawfulRightIdentity (· + ·) (0 : α)] {x : α} : + #v[x].sum = x := by + simp [← sum_toList, Std.LawfulRightIdentity.right_id x] + +@[simp, grind =] +theorem sum_push [Add α] [Zero α] [Std.Associative (α := α) (· + ·)] + [Std.LawfulIdentity (· + ·) (0 : α)] {xs : Vector α n} {x : α} : + (xs.push x).sum = xs.sum + x := by + simp [← sum_toArray] + @[simp, grind =] theorem sum_reverse [Zero α] [Add α] [Std.Associative (α := α) (· + ·)] [Std.Commutative (α := α) (· + ·)] [Std.LawfulLeftIdentity (α := α) (· + ·) 0] (xs : Vector α n) : xs.reverse.sum = xs.sum := by simp [← sum_toList, List.sum_reverse] + +theorem sum_eq_foldl [Zero α] [Add α] + [Std.Associative (α := α) (· + ·)] [Std.LawfulIdentity (· + ·) (0 : α)] + {xs : Vector α n} : + xs.sum = xs.foldl (b := 0) (· + ·) := by + simp [← sum_toList, List.sum_eq_foldl] diff --git a/tests/lean/run/1921.lean b/tests/lean/run/1921.lean index 9df40ae8e5..7c7f0a02ee 100644 --- a/tests/lean/run/1921.lean +++ b/tests/lean/run/1921.lean @@ -1,4 +1,3 @@ -@[simp] theorem Array.size_singleton : #[a].size = 1 := rfl @[simp] theorem USize.not_size_le_one : ¬ USize.size ≤ 1 := by cases USize.size_eq <;> simp (config := { decide := true }) [*] def f := #[true].any id 0 USize.size