From ee879174c5d5fc6cbff0cfbc12be85550ed2e583 Mon Sep 17 00:00:00 2001 From: FR Date: Tue, 4 Jun 2024 06:16:12 +0800 Subject: [PATCH 001/208] chore: remove `binder_predicate` (#817) It has been upstreamed to Lean4. --- Batteries/Util/ExtendedBinder.lean | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/Batteries/Util/ExtendedBinder.lean b/Batteries/Util/ExtendedBinder.lean index 33629b7cc0..d577e1d785 100644 --- a/Batteries/Util/ExtendedBinder.lean +++ b/Batteries/Util/ExtendedBinder.lean @@ -52,22 +52,3 @@ macro_rules -- TODO: merging the two macro_rules breaks expansion | `(∀ᵉ _ : $ty:term, $b) => `(∀ _ : $ty:term, $b) | `(∀ᵉ $x:ident : $ty:term, $b) => `(∀ $x:ident : $ty:term, $b) | `(∀ᵉ $x:binderIdent $p:binderPred, $b) => `(∀ $x:binderIdent $p:binderPred, $b) - -open Parser.Command in -/-- -Declares a binder predicate. For example: -``` -binder_predicate x " > " y:term => `($x > $y) -``` --/ -syntax (name := binderPredicate) (docComment)? (Parser.Term.attributes)? (attrKind)? - "binder_predicate" optNamedName optNamedPrio ppSpace ident (ppSpace macroArg)* " => " - term : command - -open Linter.MissingDocs Parser Term in -/-- Missing docs handler for `binder_predicate` -/ -@[missing_docs_handler binderPredicate] -def checkBinderPredicate : SimpleHandler := fun stx => do - if stx[0].isNone && stx[2][0][0].getKind != ``«local» then - if stx[4].isNone then lint stx[3] "binder predicate" - else lintNamed stx[4][0][3] "binder predicate" From 73e866007edd6d39e2d52b00d134265c30fddd45 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Tue, 4 Jun 2024 09:05:45 +0000 Subject: [PATCH 002/208] chore: bump to nightly-2024-06-04 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index d8ab8aadb7..cd1f5224ea 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-02 +leanprover/lean4:nightly-2024-06-04 From 63d7c6fad69f119fac842b4f7b77e6c2796b1251 Mon Sep 17 00:00:00 2001 From: Pietro Monticone <38562595+pitmonticone@users.noreply.github.com> Date: Wed, 5 Jun 2024 01:43:24 +0200 Subject: [PATCH 003/208] fix: typos in docstrings (#822) --- Batteries/Util/Cache.lean | 2 +- Batteries/Util/CheckTactic.lean | 2 +- Batteries/WF.lean | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Batteries/Util/Cache.lean b/Batteries/Util/Cache.lean index 1c25bb163c..edfac4fe97 100644 --- a/Batteries/Util/Cache.lean +++ b/Batteries/Util/Cache.lean @@ -132,7 +132,7 @@ the second will store declarations from imports (and will hopefully be "read-onl -/ @[reducible] def DiscrTreeCache (α : Type) : Type := DeclCache (DiscrTree α × DiscrTree α) -/-- Discrimation tree settings for the `DiscrTreeCache`. -/ +/-- Discrimination tree settings for the `DiscrTreeCache`. -/ def DiscrTreeCache.config : WhnfCoreConfig := {} /-- diff --git a/Batteries/Util/CheckTactic.lean b/Batteries/Util/CheckTactic.lean index cab01de05b..bc97e681cc 100644 --- a/Batteries/Util/CheckTactic.lean +++ b/Batteries/Util/CheckTactic.lean @@ -9,7 +9,7 @@ import Lean.Elab.Term /- This file is the home for commands to tactics behave as expected. -It currently includes two tactixs: +It currently includes two tactics: #check_tactic t ~> res diff --git a/Batteries/WF.lean b/Batteries/WF.lean index 8fef8ad188..7a702665ae 100644 --- a/Batteries/WF.lean +++ b/Batteries/WF.lean @@ -91,7 +91,7 @@ end Acc namespace WellFounded /-- Attaches to `x` the proof that `x` is accessible in the given well-founded relation. -This can be used in recursive function definitions to explicitly use a differerent relation +This can be used in recursive function definitions to explicitly use a different relation than the one inferred by default: ``` From 7110da53bf6da84198dba69ca90221c4798ade35 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 5 Jun 2024 02:46:27 +0100 Subject: [PATCH 004/208] chore: manifest out of date doesn't count as test noise (#818) * chore: manifest out of date doesn't count as test noise * still print manifest warning --- scripts/test.lean | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/test.lean b/scripts/test.lean index 43df619246..0a488eabd4 100644 --- a/scripts/test.lean +++ b/scripts/test.lean @@ -36,16 +36,20 @@ def main (args : List String) : IO Unit := do args := #["env", "lean", t.toString], env := #[("LEAN_ABORT_ON_PANIC", "1")] } let mut exitCode := out.exitCode + let stdout := out.stdout + let stderr := "\n".intercalate <| + -- We don't count manifest out of date warnings as noise. + out.stderr.splitOn "\n" |>.filter (!·.startsWith "warning: manifest out of date: ") if exitCode = 0 then - if out.stdout.isEmpty && out.stderr.isEmpty then + if stdout.isEmpty && stderr.isEmpty then IO.println s!"Test succeeded: {t}" else IO.println s!"Test succeeded with noisy output: {t}" unless allowNoisy do exitCode := 1 else IO.eprintln s!"Test failed: `lake env lean {t}` produced:" - unless out.stdout.isEmpty do IO.eprintln out.stdout - unless out.stderr.isEmpty do IO.eprintln out.stderr + unless stdout.isEmpty do IO.eprintln stdout + unless out.stderr.isEmpty do IO.eprintln out.stderr -- We still print the manifest warning. pure exitCode -- Wait on all the jobs and exit with 1 if any failed. let mut exitCode : UInt8 := 0 From 51e6e0d24db9341fb031288c298b7e6b56102253 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 5 Jun 2024 04:46:51 +0100 Subject: [PATCH 005/208] chore: bump toolchain to v4.8.0 (#824) --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 78f39e211a..ef1f67e9e6 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.8.0-rc2 +leanprover/lean4:v4.8.0 From 551ff2d7dffd7af914cdbd01abbd449fe3e3d428 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 5 Jun 2024 06:22:50 +0100 Subject: [PATCH 006/208] chore: split KMP for strings into separate file (#823) * chore: split KMP for strings into separate file * chore: split KMP for strings into separate file * fix copyright year * fix test --- Batteries/Data/String.lean | 1 + Batteries/Data/String/Basic.lean | 89 ------------------------ Batteries/Data/String/Matcher.lean | 107 +++++++++++++++++++++++++++++ test/kmp_matcher.lean | 2 +- 4 files changed, 109 insertions(+), 90 deletions(-) create mode 100644 Batteries/Data/String/Matcher.lean diff --git a/Batteries/Data/String.lean b/Batteries/Data/String.lean index d443cb05e4..210da57e06 100644 --- a/Batteries/Data/String.lean +++ b/Batteries/Data/String.lean @@ -1,2 +1,3 @@ import Batteries.Data.String.Basic import Batteries.Data.String.Lemmas +import Batteries.Data.String.Matcher diff --git a/Batteries/Data/String/Basic.lean b/Batteries/Data/String/Basic.lean index cbcc88693a..d06df6eefa 100644 --- a/Batteries/Data/String/Basic.lean +++ b/Batteries/Data/String/Basic.lean @@ -3,7 +3,6 @@ Copyright (c) 2022 Jannis Limperg. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jannis Limperg, James Gallicchio, F. G. Dorais -/ -import Batteries.Data.Array.Match instance : Coe String Substring := ⟨String.toSubstring⟩ @@ -12,63 +11,6 @@ namespace String protected theorem Pos.ne_zero_of_lt : {a b : Pos} → a < b → b ≠ 0 | _, _, hlt, rfl => Nat.not_lt_zero _ hlt -/-- Knuth-Morris-Pratt matcher type - -This type is used to keep data for running the Knuth-Morris-Pratt (KMP) string matching algorithm. -KMP is a linear time algorithm to locate all substrings of a string that match a given pattern. -Generating the algorithm data is also linear in the length of the pattern but the data can be -re-used to match the same pattern over different strings. - -The KMP data for a pattern string can be generated using `Matcher.ofString`. Then `Matcher.find?` -and `Matcher.findAll` can be used to run the algorithm on an input string. -``` -def m := Matcher.ofString "abba" - -#eval Option.isSome <| m.find? "AbbabbA" -- false -#eval Option.isSome <| m.find? "aabbaa" -- true - -#eval Array.size <| m.findAll "abbabba" -- 2 -#eval Array.size <| m.findAll "abbabbabba" -- 3 -``` --/ -structure Matcher extends Array.Matcher Char where - /-- The pattern for the matcher -/ - pattern : Substring - -/-- Make KMP matcher from pattern substring -/ -@[inline] def Matcher.ofSubstring (pattern : Substring) : Matcher where - toMatcher := Array.Matcher.ofStream pattern - pattern := pattern - -/-- Make KMP matcher from pattern string -/ -@[inline] def Matcher.ofString (pattern : String) : Matcher := - Matcher.ofSubstring pattern - -/-- The byte size of the string pattern for the matcher -/ -abbrev Matcher.patternSize (m : Matcher) : Nat := m.pattern.bsize - -/-- Find all substrings of `s` matching `m.pattern`. -/ -partial def Matcher.findAll (m : Matcher) (s : Substring) : Array Substring := - loop s m.toMatcher #[] -where - /-- Accumulator loop for `String.Matcher.findAll` -/ - loop (s : Substring) (am : Array.Matcher Char) (occs : Array Substring) : Array Substring := - match am.next? s with - | none => occs - | some (s, am) => - loop s am <| occs.push { s with - startPos := ⟨s.startPos.byteIdx - m.patternSize⟩ - stopPos := s.startPos } - -/-- Find the first substring of `s` matching `m.pattern`, or `none` if no such substring exists. -/ -def Matcher.find? (m : Matcher) (s : Substring) : Option Substring := - match m.next? s with - | none => none - | some (s, _) => - some { s with - startPos := ⟨s.startPos.byteIdx - m.patternSize⟩ - stopPos := s.startPos } - end String namespace Substring @@ -133,41 +75,10 @@ def dropSuffix? (s : Substring) (suff : Substring) : Option Substring := else none -/-- -Returns all the substrings of `s` that match `pattern`. --/ -@[inline] def findAllSubstr (s pattern : Substring) : Array Substring := - (String.Matcher.ofSubstring pattern).findAll s - -/-- -Returns the first substring of `s` that matches `pattern`, -or `none` if there is no such substring. --/ -@[inline] def findSubstr? (s pattern : Substring) : Option Substring := - (String.Matcher.ofSubstring pattern).find? s - -/-- -Returns true iff `pattern` occurs as a substring of `s`. --/ -@[inline] def containsSubstr (s pattern : Substring) : Bool := - s.findSubstr? pattern |>.isSome - end Substring namespace String -@[inherit_doc Substring.findAllSubstr] -abbrev findAllSubstr (s : String) (pattern : Substring) : Array Substring := - (String.Matcher.ofSubstring pattern).findAll s - -@[inherit_doc Substring.findSubstr?] -abbrev findSubstr? (s : String) (pattern : Substring) : Option Substring := - s.toSubstring.findSubstr? pattern - -@[inherit_doc Substring.containsSubstr] -abbrev containsSubstr (s : String) (pattern : Substring) : Bool := - s.toSubstring.containsSubstr pattern - /-- If `pre` is a prefix of `s`, i.e. `s = pre ++ t`, returns the remainder `t`. -/ diff --git a/Batteries/Data/String/Matcher.lean b/Batteries/Data/String/Matcher.lean new file mode 100644 index 0000000000..fe40f9dd8c --- /dev/null +++ b/Batteries/Data/String/Matcher.lean @@ -0,0 +1,107 @@ +/- +Copyright (c) 2023 F. G. Dorais. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: F. G. Dorais +-/ +import Batteries.Data.Array.Match +import Batteries.Data.String.Basic + +namespace String + +/-- Knuth-Morris-Pratt matcher type + +This type is used to keep data for running the Knuth-Morris-Pratt (KMP) string matching algorithm. +KMP is a linear time algorithm to locate all substrings of a string that match a given pattern. +Generating the algorithm data is also linear in the length of the pattern but the data can be +re-used to match the same pattern over different strings. + +The KMP data for a pattern string can be generated using `Matcher.ofString`. Then `Matcher.find?` +and `Matcher.findAll` can be used to run the algorithm on an input string. +``` +def m := Matcher.ofString "abba" + +#eval Option.isSome <| m.find? "AbbabbA" -- false +#eval Option.isSome <| m.find? "aabbaa" -- true + +#eval Array.size <| m.findAll "abbabba" -- 2 +#eval Array.size <| m.findAll "abbabbabba" -- 3 +``` +-/ +structure Matcher extends Array.Matcher Char where + /-- The pattern for the matcher -/ + pattern : Substring + +/-- Make KMP matcher from pattern substring -/ +@[inline] def Matcher.ofSubstring (pattern : Substring) : Matcher where + toMatcher := Array.Matcher.ofStream pattern + pattern := pattern + +/-- Make KMP matcher from pattern string -/ +@[inline] def Matcher.ofString (pattern : String) : Matcher := + Matcher.ofSubstring pattern + +/-- The byte size of the string pattern for the matcher -/ +abbrev Matcher.patternSize (m : Matcher) : Nat := m.pattern.bsize + +/-- Find all substrings of `s` matching `m.pattern`. -/ +partial def Matcher.findAll (m : Matcher) (s : Substring) : Array Substring := + loop s m.toMatcher #[] +where + /-- Accumulator loop for `String.Matcher.findAll` -/ + loop (s : Substring) (am : Array.Matcher Char) (occs : Array Substring) : Array Substring := + match am.next? s with + | none => occs + | some (s, am) => + loop s am <| occs.push { s with + startPos := ⟨s.startPos.byteIdx - m.patternSize⟩ + stopPos := s.startPos } + +/-- Find the first substring of `s` matching `m.pattern`, or `none` if no such substring exists. -/ +def Matcher.find? (m : Matcher) (s : Substring) : Option Substring := + match m.next? s with + | none => none + | some (s, _) => + some { s with + startPos := ⟨s.startPos.byteIdx - m.patternSize⟩ + stopPos := s.startPos } + +end String + +namespace Substring + +/-- +Returns all the substrings of `s` that match `pattern`. +-/ +@[inline] def findAllSubstr (s pattern : Substring) : Array Substring := + (String.Matcher.ofSubstring pattern).findAll s + +/-- +Returns the first substring of `s` that matches `pattern`, +or `none` if there is no such substring. +-/ +@[inline] def findSubstr? (s pattern : Substring) : Option Substring := + (String.Matcher.ofSubstring pattern).find? s + +/-- +Returns true iff `pattern` occurs as a substring of `s`. +-/ +@[inline] def containsSubstr (s pattern : Substring) : Bool := + s.findSubstr? pattern |>.isSome + +end Substring + +namespace String + +@[inherit_doc Substring.findAllSubstr] +abbrev findAllSubstr (s : String) (pattern : Substring) : Array Substring := + (String.Matcher.ofSubstring pattern).findAll s + +@[inherit_doc Substring.findSubstr?] +abbrev findSubstr? (s : String) (pattern : Substring) : Option Substring := + s.toSubstring.findSubstr? pattern + +@[inherit_doc Substring.containsSubstr] +abbrev containsSubstr (s : String) (pattern : Substring) : Bool := + s.toSubstring.containsSubstr pattern + +end String diff --git a/test/kmp_matcher.lean b/test/kmp_matcher.lean index ae44660af3..f61e42343f 100644 --- a/test/kmp_matcher.lean +++ b/test/kmp_matcher.lean @@ -1,4 +1,4 @@ -import Batteries.Data.String.Basic +import Batteries.Data.String.Matcher /-! Tests for Knuth-Morris-Pratt matching algorithm -/ From cfe1ff28446e035ce188201c85539f0dca8cb056 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Wed, 5 Jun 2024 09:06:14 +0000 Subject: [PATCH 007/208] chore: bump to nightly-2024-06-05 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index cd1f5224ea..63bd20987e 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-04 +leanprover/lean4:nightly-2024-06-05 From 05d49237e20945f99348a805a243407e3c20eb5e Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 5 Jun 2024 19:18:53 +1000 Subject: [PATCH 008/208] delete theorem; lhs not simpNF anymore --- Batteries/Data/ByteArray.lean | 3 --- 1 file changed, 3 deletions(-) diff --git a/Batteries/Data/ByteArray.lean b/Batteries/Data/ByteArray.lean index 4788ecbb36..f147eaf47b 100644 --- a/Batteries/Data/ByteArray.lean +++ b/Batteries/Data/ByteArray.lean @@ -14,9 +14,6 @@ theorem getElem_eq_data_getElem (a : ByteArray) (h : i < a.size) : a[i] = a.data /-! ### uget/uset -/ -@[simp] theorem ugetElem_eq_getElem (a : ByteArray) {i : USize} (h : i.toNat < a.size) : - a[i] = a[i.toNat] := rfl - @[simp] theorem uset_eq_set (a : ByteArray) {i : USize} (h : i.toNat < a.size) (v : UInt8) : a.uset i v h = a.set ⟨i.toNat, h⟩ v := rfl From 3062eb30b8d38e74c9e8917509bec58d1a91569a Mon Sep 17 00:00:00 2001 From: L Date: Wed, 5 Jun 2024 14:06:48 -0700 Subject: [PATCH 009/208] chore: add `@[simp]` for `Fin.foldl_zero` and `Fin.foldr_zero` (#820) --- Batteries/Data/Fin/Lemmas.lean | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Batteries/Data/Fin/Lemmas.lean b/Batteries/Data/Fin/Lemmas.lean index f8d2569a54..2cd8effde9 100644 --- a/Batteries/Data/Fin/Lemmas.lean +++ b/Batteries/Data/Fin/Lemmas.lean @@ -54,7 +54,7 @@ theorem foldl_loop (f : α → Fin (n+1) → α) (x) (h : m < n+1) : rw [foldl_loop_lt, foldl_loop_eq, foldl_loop_eq] termination_by n - m -theorem foldl_zero (f : α → Fin 0 → α) (x) : foldl 0 f x = x := rfl +@[simp] theorem foldl_zero (f : α → Fin 0 → α) (x) : foldl 0 f x = x := rfl theorem foldl_succ (f : α → Fin (n+1) → α) (x) : foldl (n+1) f x = foldl n (fun x i => f x i.succ) (f x 0) := foldl_loop .. @@ -78,6 +78,8 @@ theorem foldr_loop (f : Fin (n+1) → α → α) (x) (h : m+1 ≤ n+1) : | zero => simp [foldr_loop_zero, foldr_loop_succ] | succ m ih => rw [foldr_loop_succ, ih]; rfl +@[simp] theorem foldr_zero (f : Fin 0 → α → α) (x) : foldr 0 f x = x := rfl + theorem foldr_succ (f : Fin (n+1) → α → α) (x) : foldr (n+1) f x = f 0 (foldr n (fun i => f i.succ) x) := foldr_loop .. From 45c0a2fa40736902e6daa61af716abc303cd2dbc Mon Sep 17 00:00:00 2001 From: L Date: Wed, 5 Jun 2024 14:07:28 -0700 Subject: [PATCH 010/208] feat: add lemma `Fin.list_reverse` (#819) --- Batteries/Data/Fin/Lemmas.lean | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Batteries/Data/Fin/Lemmas.lean b/Batteries/Data/Fin/Lemmas.lean index 2cd8effde9..c11054ce58 100644 --- a/Batteries/Data/Fin/Lemmas.lean +++ b/Batteries/Data/Fin/Lemmas.lean @@ -36,6 +36,22 @@ protected theorem le_antisymm {x y : Fin n} (h1 : x ≤ y) (h2 : y ≤ x) : x = theorem list_succ (n) : list (n+1) = 0 :: (list n).map Fin.succ := by apply List.ext_get; simp; intro i; cases i <;> simp +theorem list_succ_last (n) : list (n+1) = (list n).map castSucc ++ [last n] := by + rw [list_succ] + induction n with + | zero => rfl + | succ n ih => + rw [list_succ, List.map_cons castSucc, ih] + simp [Function.comp_def, succ_castSucc] + +theorem list_reverse (n) : (list n).reverse = (list n).map rev := by + induction n with + | zero => rfl + | succ n ih => + conv => lhs; rw [list_succ_last] + conv => rhs; rw [list_succ] + simp [List.reverse_map, ih, Function.comp_def, rev_succ] + /-! ### foldl -/ theorem foldl_loop_lt (f : α → Fin n → α) (x) (h : m < n) : From 3b1555252d9369be7b0f39a0e0a07daa864e5b5b Mon Sep 17 00:00:00 2001 From: L Date: Wed, 5 Jun 2024 14:08:31 -0700 Subject: [PATCH 011/208] feat: add lemmas `Fin.foldl_rev`, `Fin.foldr_rev` (#821) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François G. Dorais --- Batteries/Data/Fin/Lemmas.lean | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Batteries/Data/Fin/Lemmas.lean b/Batteries/Data/Fin/Lemmas.lean index c11054ce58..7167efa0ed 100644 --- a/Batteries/Data/Fin/Lemmas.lean +++ b/Batteries/Data/Fin/Lemmas.lean @@ -75,6 +75,13 @@ termination_by n - m theorem foldl_succ (f : α → Fin (n+1) → α) (x) : foldl (n+1) f x = foldl n (fun x i => f x i.succ) (f x 0) := foldl_loop .. +theorem foldl_succ_last (f : α → Fin (n+1) → α) (x) : + foldl (n+1) f x = f (foldl n (f · ·.castSucc) x) (last n) := by + rw [foldl_succ] + induction n generalizing x with + | zero => rfl + | succ n ih => rw [foldl_succ, ih (f · ·.succ), foldl_succ]; simp [succ_castSucc] + theorem foldl_eq_foldl_list (f : α → Fin n → α) (x) : foldl n f x = (list n).foldl f x := by induction n generalizing x with | zero => rfl @@ -99,7 +106,28 @@ theorem foldr_loop (f : Fin (n+1) → α → α) (x) (h : m+1 ≤ n+1) : theorem foldr_succ (f : Fin (n+1) → α → α) (x) : foldr (n+1) f x = f 0 (foldr n (fun i => f i.succ) x) := foldr_loop .. +theorem foldr_succ_last (f : Fin (n+1) → α → α) (x) : + foldr (n+1) f x = foldr n (f ·.castSucc) (f (last n) x) := by + rw [foldr_succ] + induction n generalizing x with + | zero => rfl + | succ n ih => rw [foldr_succ, ih (f ·.succ), foldr_succ]; simp [succ_castSucc] + theorem foldr_eq_foldr_list (f : Fin n → α → α) (x) : foldr n f x = (list n).foldr f x := by induction n with | zero => rfl | succ n ih => rw [foldr_succ, ih, list_succ, List.foldr_cons, List.foldr_map] + +/-! ### foldl/foldr -/ + +theorem foldl_rev (f : Fin n → α → α) (x) : + foldl n (fun x i => f i.rev x) x = foldr n f x := by + induction n generalizing x with + | zero => rfl + | succ n ih => rw [foldl_succ, foldr_succ_last, ← ih]; simp [rev_succ] + +theorem foldr_rev (f : α → Fin n → α) (x) : + foldr n (fun i x => f x i.rev) x = foldl n f x := by + induction n generalizing x with + | zero => rfl + | succ n ih => rw [foldl_succ_last, foldr_succ, ← ih]; simp [rev_succ] From 5c9a12da6cc30b988af44a5ef48dc42eed64bd5a Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 6 Jun 2024 07:10:13 +1000 Subject: [PATCH 012/208] upstreamed lemma --- Batteries/Data/Fin/Lemmas.lean | 2 -- 1 file changed, 2 deletions(-) diff --git a/Batteries/Data/Fin/Lemmas.lean b/Batteries/Data/Fin/Lemmas.lean index be9c425d22..2b494f635c 100644 --- a/Batteries/Data/Fin/Lemmas.lean +++ b/Batteries/Data/Fin/Lemmas.lean @@ -110,8 +110,6 @@ theorem foldr_loop (f : Fin (n+1) → α → α) (x) (h : m+1 ≤ n+1) : theorem foldr_zero (f : Fin 0 → α → α) (x) : foldr 0 f x = x := foldr_loop_zero .. -@[simp] theorem foldr_zero (f : Fin 0 → α → α) (x) : foldr 0 f x = x := rfl - theorem foldr_succ (f : Fin (n+1) → α → α) (x) : foldr (n+1) f x = f 0 (foldr n (fun i => f i.succ) x) := foldr_loop .. From 6141f00e9b5a0b1c92ce971d99082f70345cc6c3 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 6 Jun 2024 07:12:56 +1000 Subject: [PATCH 013/208] unseal foldl --- Batteries/Data/Fin/Lemmas.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Batteries/Data/Fin/Lemmas.lean b/Batteries/Data/Fin/Lemmas.lean index 2b494f635c..dda80015c7 100644 --- a/Batteries/Data/Fin/Lemmas.lean +++ b/Batteries/Data/Fin/Lemmas.lean @@ -77,6 +77,7 @@ theorem foldl_zero (f : α → Fin 0 → α) (x) : foldl 0 f x = x := by simp [f theorem foldl_succ (f : α → Fin (n+1) → α) (x) : foldl (n+1) f x = foldl n (fun x i => f x i.succ) (f x 0) := foldl_loop .. +unseal Fin.foldl.loop in theorem foldl_succ_last (f : α → Fin (n+1) → α) (x) : foldl (n+1) f x = f (foldl n (f · ·.castSucc) x) (last n) := by rw [foldl_succ] @@ -113,6 +114,7 @@ theorem foldr_zero (f : Fin 0 → α → α) (x) : theorem foldr_succ (f : Fin (n+1) → α → α) (x) : foldr (n+1) f x = f 0 (foldr n (fun i => f i.succ) x) := foldr_loop .. +unseal Fin.foldr.loop in theorem foldr_succ_last (f : Fin (n+1) → α → α) (x) : foldr (n+1) f x = foldr n (f ·.castSucc) (f (last n) x) := by rw [foldr_succ] @@ -127,12 +129,14 @@ theorem foldr_eq_foldr_list (f : Fin n → α → α) (x) : foldr n f x = (list /-! ### foldl/foldr -/ +unseal Fin.foldl.loop Fin.foldr.loop in theorem foldl_rev (f : Fin n → α → α) (x) : foldl n (fun x i => f i.rev x) x = foldr n f x := by induction n generalizing x with | zero => rfl | succ n ih => rw [foldl_succ, foldr_succ_last, ← ih]; simp [rev_succ] +unseal Fin.foldl.loop Fin.foldr.loop in theorem foldr_rev (f : α → Fin n → α) (x) : foldr n (fun i x => f x i.rev) x = foldl n f x := by induction n generalizing x with From 66655c88ef8fd6dfada59c2d07822d94b0a02a38 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Thu, 6 Jun 2024 09:06:06 +0000 Subject: [PATCH 014/208] chore: bump to nightly-2024-06-06 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 63bd20987e..1b2d23c360 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-05 +leanprover/lean4:nightly-2024-06-06 From fb81a8f059f2dd78216229798e8a5285f1f095a2 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 6 Jun 2024 21:25:12 +1000 Subject: [PATCH 015/208] remove upstreamed string lemmas --- Batteries/Data/String/Lemmas.lean | 117 +----------------------------- 1 file changed, 4 insertions(+), 113 deletions(-) diff --git a/Batteries/Data/String/Lemmas.lean b/Batteries/Data/String/Lemmas.lean index dad9f5ee20..8a9376fe05 100644 --- a/Batteries/Data/String/Lemmas.lean +++ b/Batteries/Data/String/Lemmas.lean @@ -9,14 +9,9 @@ import Batteries.Data.String.Basic import Batteries.Tactic.Lint.Misc import Batteries.Tactic.SeqFocus -@[simp] theorem Char.length_toString (c : Char) : c.toString.length = 1 := rfl - namespace String -@[ext] theorem ext {s₁ s₂ : String} (h : s₁.data = s₂.data) : s₁ = s₂ := - show ⟨s₁.data⟩ = (⟨s₂.data⟩ : String) from h ▸ rfl - -theorem ext_iff {s₁ s₂ : String} : s₁ = s₂ ↔ s₁.data = s₂.data := ⟨fun h => h ▸ rfl, ext⟩ +attribute [ext] ext theorem lt_trans {s₁ s₂ s₃ : String} : s₁ < s₂ → s₂ < s₃ → s₁ < s₃ := List.lt_trans' (α := Char) Nat.lt_trans @@ -34,34 +29,10 @@ instance : Batteries.LTOrd String := .compareOfLessAndEq instance : Batteries.BEqOrd String := .compareOfLessAndEq String.lt_irrefl -@[simp] theorem default_eq : default = "" := rfl - -@[simp] theorem str_eq : str = push := rfl - @[simp] theorem mk_length (s : List Char) : (String.mk s).length = s.length := rfl -@[simp] theorem length_empty : "".length = 0 := rfl - -@[simp] theorem length_singleton (c : Char) : (String.singleton c).length = 1 := rfl - -@[simp] theorem length_push (c : Char) : (String.push s c).length = s.length + 1 := by - rw [push, mk_length, List.length_append, List.length_singleton, Nat.succ.injEq] - rfl - -@[simp] theorem length_pushn (c : Char) (n : Nat) : (pushn s c n).length = s.length + n := by - unfold pushn; induction n <;> simp [Nat.repeat, Nat.add_assoc, *] - -@[simp] theorem length_append (s t : String) : (s ++ t).length = s.length + t.length := by - simp only [length, append, List.length_append] - -@[simp] theorem data_push (s : String) (c : Char) : (s.push c).1 = s.1 ++ [c] := rfl - -@[simp] theorem data_append (s t : String) : (s ++ t).1 = s.1 ++ t.1 := rfl - attribute [simp] toList -- prefer `String.data` over `String.toList` in lemmas -theorem lt_iff (s t : String) : s < t ↔ s.1 < t.1 := .rfl - private theorem add_csize_pos : 0 < i + csize c := Nat.add_pos_right _ (csize_pos c) @@ -115,69 +86,13 @@ end namespace Pos -@[simp] theorem byteIdx_zero : (0 : Pos).byteIdx = 0 := rfl - -theorem byteIdx_mk (n : Nat) : byteIdx ⟨n⟩ = n := rfl - -@[simp] theorem mk_zero : ⟨0⟩ = (0 : Pos) := rfl - -@[simp] theorem mk_byteIdx (p : Pos) : ⟨p.byteIdx⟩ = p := rfl - -@[ext] theorem ext {i₁ i₂ : Pos} (h : i₁.byteIdx = i₂.byteIdx) : i₁ = i₂ := - show ⟨i₁.byteIdx⟩ = (⟨i₂.byteIdx⟩ : Pos) from h ▸ rfl - -theorem ext_iff {i₁ i₂ : Pos} : i₁ = i₂ ↔ i₁.byteIdx = i₂.byteIdx := ⟨fun h => h ▸ rfl, ext⟩ - -@[simp] theorem add_byteIdx (p₁ p₂ : Pos) : (p₁ + p₂).byteIdx = p₁.byteIdx + p₂.byteIdx := rfl - -theorem add_eq (p₁ p₂ : Pos) : p₁ + p₂ = ⟨p₁.byteIdx + p₂.byteIdx⟩ := rfl - -@[simp] theorem sub_byteIdx (p₁ p₂ : Pos) : (p₁ - p₂).byteIdx = p₁.byteIdx - p₂.byteIdx := rfl - -theorem sub_eq (p₁ p₂ : Pos) : p₁ - p₂ = ⟨p₁.byteIdx - p₂.byteIdx⟩ := rfl - -@[simp] theorem addChar_byteIdx (p : Pos) (c : Char) : (p + c).byteIdx = p.byteIdx + csize c := rfl - -theorem addChar_eq (p : Pos) (c : Char) : p + c = ⟨p.byteIdx + csize c⟩ := rfl - -theorem zero_addChar_byteIdx (c : Char) : ((0 : Pos) + c).byteIdx = csize c := by - simp only [addChar_byteIdx, byteIdx_zero, Nat.zero_add] - -theorem zero_addChar_eq (c : Char) : (0 : Pos) + c = ⟨csize c⟩ := by rw [← zero_addChar_byteIdx] - -theorem addChar_right_comm (p : Pos) (c₁ c₂ : Char) : p + c₁ + c₂ = p + c₂ + c₁ := by - apply ext - repeat rw [pos_add_char] - apply Nat.add_right_comm +attribute [ext] ext theorem lt_addChar (p : Pos) (c : Char) : p < p + c := Nat.lt_add_of_pos_right (csize_pos _) -theorem ne_of_lt {i₁ i₂ : Pos} (h : i₁ < i₂) : i₁ ≠ i₂ := mt ext_iff.1 (Nat.ne_of_lt h) - -theorem ne_of_gt {i₁ i₂ : Pos} (h : i₁ < i₂) : i₂ ≠ i₁ := (ne_of_lt h).symm - -@[simp] theorem addString_byteIdx (p : Pos) (s : String) : - (p + s).byteIdx = p.byteIdx + s.utf8ByteSize := rfl - -theorem addString_eq (p : Pos) (s : String) : p + s = ⟨p.byteIdx + s.utf8ByteSize⟩ := rfl - -theorem zero_addString_byteIdx (s : String) : ((0 : Pos) + s).byteIdx = s.utf8ByteSize := by - simp only [addString_byteIdx, byteIdx_zero, Nat.zero_add] - private theorem zero_ne_addChar {i : Pos} {c : Char} : 0 ≠ i + c := ne_of_lt add_csize_pos -theorem zero_addString_eq (s : String) : (0 : Pos) + s = ⟨s.utf8ByteSize⟩ := by - rw [← zero_addString_byteIdx] - -theorem le_iff {i₁ i₂ : Pos} : i₁ ≤ i₂ ↔ i₁.byteIdx ≤ i₂.byteIdx := .rfl - -@[simp] theorem mk_le_mk {i₁ i₂ : Nat} : Pos.mk i₁ ≤ Pos.mk i₂ ↔ i₁ ≤ i₂ := .rfl - -theorem lt_iff {i₁ i₂ : Pos} : i₁ < i₂ ↔ i₁.byteIdx < i₂.byteIdx := .rfl - -@[simp] theorem mk_lt_mk {i₁ i₂ : Nat} : Pos.mk i₁ < Pos.mk i₂ ↔ i₁ < i₂ := .rfl - /-- A string position is valid if it is equal to the UTF-8 length of an initial substring of `s`. -/ def Valid (s : String) (p : Pos) : Prop := ∃ cs cs', cs ++ cs' = s.1 ∧ p.1 = utf8Len cs @@ -262,8 +177,6 @@ theorem utf8GetAux?_of_valid (cs cs' : List Char) {i p : Nat} (hp : i + utf8Len theorem get?_of_valid (cs cs' : List Char) : get? ⟨cs ++ cs'⟩ ⟨utf8Len cs⟩ = cs'.head? := utf8GetAux?_of_valid _ _ (Nat.zero_add _) -@[simp] theorem get!_eq_get (s : String) (p : Pos) : get! s p = get s p := rfl - theorem utf8SetAux_of_valid (c' : Char) (cs cs' : List Char) {i p : Nat} (hp : i + utf8Len cs = p) : utf8SetAux c' (cs ++ cs') ⟨i⟩ ⟨p⟩ = cs ++ cs'.modifyHead fun _ => c' := by match cs, cs' with @@ -290,8 +203,6 @@ theorem next_of_valid' (cs cs' : List Char) : theorem next_of_valid (cs : List Char) (c : Char) (cs' : List Char) : next ⟨cs ++ c :: cs'⟩ ⟨utf8Len cs⟩ = ⟨utf8Len cs + csize c⟩ := next_of_valid' .. -theorem lt_next' (s : String) (p : Pos) : p < next s p := lt_next .. - @[simp] theorem atEnd_iff (s : String) (p : Pos) : atEnd s p ↔ s.endPos ≤ p := decide_eq_true_iff _ @@ -325,8 +236,6 @@ theorem prev_of_valid' (cs cs' : List Char) : | _, .inl rfl => rfl | _, .inr ⟨cs, c, rfl⟩ => simp [prev_of_valid] -@[simp] theorem prev_zero (s : String) : prev s 0 = 0 := rfl - theorem front_eq (s : String) : front s = s.1.headD default := by unfold front; exact get_of_valid [] s.1 @@ -340,10 +249,6 @@ theorem atEnd_of_valid (cs : List Char) (cs' : List Char) : rw [atEnd_iff] cases cs' <;> simp [Nat.lt_add_of_pos_right add_csize_pos] -@[simp] theorem get'_eq (s : String) (p : Pos) (h) : get' s p h = get s p := rfl - -@[simp] theorem next'_eq (s : String) (p : Pos) (h) : next' s p h = next s p := rfl - unseal posOfAux findAux in theorem posOfAux_eq (s c) : posOfAux s c = findAux s (· == c) := rfl @@ -518,16 +423,8 @@ theorem join_eq (ss : List String) : join ss = ⟨(ss.map data).join⟩ := go ss @[simp] theorem data_join (ss : List String) : (join ss).data = (ss.map data).join := by rw [join_eq] -theorem singleton_eq (c : Char) : singleton c = ⟨[c]⟩ := rfl - -@[simp] theorem data_singleton (c : Char) : (singleton c).data = [c] := rfl - -@[simp] theorem append_nil (s : String) : s ++ "" = s := ext (List.append_nil _) - -@[simp] theorem nil_append (s : String) : "" ++ s = s := rfl - -theorem append_assoc (s₁ s₂ s₃ : String) : (s₁ ++ s₂) ++ s₃ = s₁ ++ (s₂ ++ s₃) := - ext (List.append_assoc ..) +@[deprecated (since := "2024-06-06")] alias append_nil := append_empty +@[deprecated (since := "2024-06-06")] alias nil_append := empty_append namespace Iterator @@ -803,12 +700,6 @@ open String namespace Substring -@[simp] theorem prev_zero (s : Substring) : s.prev 0 = 0 := by simp [prev, Pos.add_eq] - -@[simp] theorem prevn_zero (s : Substring) : ∀ n, s.prevn n 0 = 0 - | 0 => rfl - | n+1 => by simp [prevn, prevn_zero s n] - /-- Validity for a substring. -/ structure Valid (s : Substring) : Prop where /-- The start position of a valid substring is valid. -/ From 6a63eb6a326181df29d95a84ce1f16c1145e66d8 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 7 Jun 2024 01:44:22 +0100 Subject: [PATCH 016/208] chore: merge bump/v4.9.0 branch (#826) * chore: adaptations for nightly-2024-05-06 (#783) * chore: adaptations for nightly-2024-05-11 (#794) * chore: adaptations for nightly-2024-05-11 * oops * fix test * suggestion from review * chore: adaptations for nightly-2024-06-06 (#825) * chore: adaptations for nightly-2024-06-06 * move to v4.9.0.-rc1 * suggestions from review --- Batteries/CodeAction/Deprecated.lean | 4 +- Batteries/Data/Array/Lemmas.lean | 754 --------------- Batteries/Data/ByteArray.lean | 3 - Batteries/Data/Fin/Basic.lean | 14 - Batteries/Data/Fin/Lemmas.lean | 32 +- Batteries/Data/List/Lemmas.lean | 1264 +------------------------ Batteries/Data/String/Lemmas.lean | 123 +-- Batteries/Lean/Delaborator.lean | 18 +- Batteries/Tactic/Instances.lean | 6 +- Batteries/Tactic/PrintDependents.lean | 4 +- Batteries/Tactic/PrintPrefix.lean | 8 +- Batteries/Tactic/ShowUnused.lean | 4 +- Batteries/WF.lean | 4 + lakefile.lean | 2 +- lean-toolchain | 2 +- test/list_sublists.lean | 2 +- 16 files changed, 48 insertions(+), 2196 deletions(-) diff --git a/Batteries/CodeAction/Deprecated.lean b/Batteries/CodeAction/Deprecated.lean index 1d74fea98c..f308992885 100644 --- a/Batteries/CodeAction/Deprecated.lean +++ b/Batteries/CodeAction/Deprecated.lean @@ -29,10 +29,10 @@ def deprecatedCodeActionProvider : CodeActionProvider := fun params snap => do let mut i := 0 let doc ← readDoc let mut msgs := #[] - for m in snap.msgLog.msgs do + for m in snap.msgLog.toList do if m.data.isDeprecationWarning then if h : _ then - msgs := msgs.push (snap.cmdState.messages.msgs[i]) + msgs := msgs.push (snap.cmdState.messages.toList[i]) i := i + 1 if msgs.isEmpty then return #[] let start := doc.meta.text.lspPosToUtf8Pos params.range.start diff --git a/Batteries/Data/Array/Lemmas.lean b/Batteries/Data/Array/Lemmas.lean index 01bd927b18..5a16a355e1 100644 --- a/Batteries/Data/Array/Lemmas.lean +++ b/Batteries/Data/Array/Lemmas.lean @@ -9,242 +9,8 @@ import Batteries.Data.Array.Basic import Batteries.Tactic.SeqFocus import Batteries.Util.ProofWanted -@[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 - -@[simp] theorem mkArray_data (n : Nat) (v : α) : (mkArray n v).data = List.replicate n v := rfl - -@[simp] theorem getElem_mkArray (n : Nat) (v : α) (h : i < (mkArray n v).size) : - (mkArray n v)[i] = v := by simp [Array.getElem_eq_data_get] - namespace Array -attribute [simp] isEmpty uget - -@[simp] theorem singleton_def (v : α) : singleton v = #[v] := rfl - -@[simp] theorem toArray_data : (a : Array α) → a.data.toArray = a - | ⟨l⟩ => ext' (data_toArray l) - -@[simp] theorem data_length {l : Array α} : l.data.length = l.size := rfl - -/-- # mem -/ - -theorem mem_data {a : α} {l : Array α} : a ∈ l.data ↔ a ∈ l := (mem_def _ _).symm - -theorem not_mem_nil (a : α) : ¬ a ∈ #[] := nofun - -/-- # get lemmas -/ - -theorem getElem?_mem {l : Array α} {i : Fin l.size} : l[i] ∈ l := by - erw [Array.mem_def, getElem_eq_data_get] - apply List.get_mem - -theorem getElem_fin_eq_data_get (a : Array α) (i : Fin _) : a[i] = a.data.get i := rfl - -@[simp] theorem ugetElem_eq_getElem (a : Array α) {i : USize} (h : i.toNat < a.size) : - a[i] = a[i.toNat] := 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_mem_data (a : Array α) (h : i < a.size) : a[i] ∈ a.data := by - simp only [getElem_eq_data_get, List.get_mem] - -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!_eq_get? [Inhabited α] (a : Array α) : a.get! n = (a.get? n).getD default := by - simp [get!_eq_getD] - -@[simp] theorem back_eq_back? [Inhabited α] (a : Array α) : a.back = a.back?.getD default := by - simp [back, back?] - -@[simp] theorem back?_push (a : Array α) : (a.push x).back? = some x := by - simp [back?, getElem?_eq_data_get?] - -theorem back_push [Inhabited α] (a : Array α) : (a.push x).back = x := by simp - -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 α} : (a.push x)[i]? = if i = a.size then some x else a[i]? := by - match Nat.lt_trichotomy i a.size with - | Or.inl g => - have h1 : i < a.size + 1 := by omega - have h2 : i ≠ a.size := by omega - simp [getElem?, size_push, g, h1, h2, get_push_lt] - | Or.inr (Or.inl heq) => - simp [heq, getElem?_pos, get_push_eq] - | Or.inr (Or.inr g) => - simp only [getElem?, size_push] - have h1 : ¬ (i < a.size) := by omega - have h2 : ¬ (i < a.size + 1) := by omega - have h3 : i ≠ a.size := by omega - simp [h1, h2, h3] - -@[simp] theorem get?_size {a : Array α} : a[a.size]? = none := by - simp only [getElem?, Nat.lt_irrefl, dite_false] - -@[simp] theorem data_set (a : Array α) (i v) : (a.set i v).data = a.data.set i.1 v := rfl - -theorem get_set_eq (a : Array α) (i : Fin a.size) (v : α) : - (a.set i v)[i.1] = v := by - simp only [set, getElem_eq_data_get, List.get_set_eq] - -theorem get?_set_eq (a : Array α) (i : Fin a.size) (v : α) : - (a.set i v)[i.1]? = v := by simp [getElem?_pos, i.2] - -@[simp] theorem get?_set_ne (a : Array α) (i : Fin a.size) {j : Nat} (v : α) - (h : i.1 ≠ j) : (a.set i v)[j]? = a[j]? := by - by_cases j < a.size <;> simp [getElem?_pos, getElem?_neg, *] - -theorem get?_set (a : Array α) (i : Fin a.size) (j : Nat) (v : α) : - (a.set i v)[j]? = if i.1 = j then some v else a[j]? := by - if h : i.1 = j then subst j; simp [*] else simp [*] - -theorem get_set (a : Array α) (i : Fin a.size) (j : Nat) (hj : j < a.size) (v : α) : - (a.set i v)[j]'(by simp [*]) = if i = j then v else a[j] := by - if h : i.1 = j then subst j; simp [*] else simp [*] - -@[simp] theorem get_set_ne (a : Array α) (i : Fin a.size) {j : Nat} (v : α) (hj : j < a.size) - (h : i.1 ≠ j) : (a.set i v)[j]'(by simp [*]) = a[j] := by - simp only [set, getElem_eq_data_get, List.get_set_ne _ h] - -theorem getElem_setD (a : Array α) (i : Nat) (v : α) (h : i < (setD a i v).size) : - (setD a i v)[i] = v := by - simp at h - simp only [setD, h, dite_true, get_set, ite_true] - -theorem set_set (a : Array α) (i : Fin a.size) (v v' : α) : - (a.set i v).set ⟨i, by simp [i.2]⟩ v' = a.set i v' := by simp [set, List.set_set] - -private theorem fin_cast_val (e : n = n') (i : Fin n) : e ▸ i = ⟨i.1, e ▸ i.2⟩ := by cases e; rfl - -theorem swap_def (a : Array α) (i j : Fin a.size) : - a.swap i j = (a.set i (a.get j)).set ⟨j.1, by simp [j.2]⟩ (a.get i) := by - simp [swap, fin_cast_val] - -theorem data_swap (a : Array α) (i j : Fin a.size) : - (a.swap i j).data = (a.data.set i (a.get j)).set j (a.get i) := by simp [swap_def] - -theorem get?_swap (a : Array α) (i j : Fin a.size) (k : Nat) : (a.swap i j)[k]? = - if j = k then some a[i.1] else if i = k then some a[j.1] else a[k]? := by - simp [swap_def, get?_set, ← getElem_fin_eq_data_get] - -@[simp] theorem swapAt_def (a : Array α) (i : Fin a.size) (v : α) : - a.swapAt i v = (a[i.1], a.set i v) := rfl - --- @[simp] -- FIXME: gives a weird linter error -theorem swapAt!_def (a : Array α) (i : Nat) (v : α) (h : i < a.size) : - a.swapAt! i v = (a[i], a.set ⟨i, h⟩ v) := by simp [swapAt!, h] - -@[simp] theorem data_pop (a : Array α) : a.pop.data = a.data.dropLast := by simp [pop] - -@[simp] theorem pop_empty : (#[] : Array α).pop = #[] := rfl - -@[simp] theorem pop_push (a : Array α) : (a.push x).pop = a := by simp [pop] - -@[simp] theorem getElem_pop (a : Array α) (i : Nat) (hi : i < a.pop.size) : - a.pop[i] = a[i]'(Nat.lt_of_lt_of_le (a.size_pop ▸ hi) (Nat.sub_le _ _)) := - List.get_dropLast .. - -theorem eq_empty_of_size_eq_zero {as : Array α} (h : as.size = 0) : as = #[] := by - apply ext - · simp [h] - · intros; contradiction - -theorem eq_push_pop_back_of_size_ne_zero [Inhabited α] {as : Array α} (h : as.size ≠ 0) : - as = as.pop.push as.back := by - apply ext - · simp [Nat.sub_add_cancel (Nat.zero_lt_of_ne_zero h)] - · intros i h h' - if hlt : i < as.pop.size then - rw [get_push_lt (h:=hlt), getElem_pop] - else - have heq : i = as.pop.size := - Nat.le_antisymm (size_pop .. ▸ Nat.le_pred_of_lt h) (Nat.le_of_not_gt hlt) - cases heq; rw [get_push_eq, back, ←size_pop, get!_eq_getD, getD, dif_pos h]; rfl - -theorem eq_push_of_size_ne_zero {as : Array α} (h : as.size ≠ 0) : - ∃ (bs : Array α) (c : α), as = bs.push c := - let _ : Inhabited α := ⟨as[0]⟩ - ⟨as.pop, as.back, eq_push_pop_back_of_size_ne_zero h⟩ - -theorem size_eq_length_data (as : Array α) : as.size = as.data.length := rfl - -@[simp] theorem size_swap! (a : Array α) (i j) : - (a.swap! i j).size = a.size := by unfold swap!; split <;> (try split) <;> simp [size_swap] - -@[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] - termination_by j - i - simp only [reverse]; split <;> simp [go] - -@[simp] theorem size_range {n : Nat} : (range n).size = n := by - unfold range - induction n with - | zero => simp [Nat.fold] - | succ k ih => rw [Nat.fold, flip]; simpa - -@[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 at * - rw [(go · (i+1) j)] - · rwa [Nat.add_right_comm i] - · simp [size_swap, h₂] - · intro k - rw [← getElem?_eq_data_get?, get?_swap] - simp [getElem?_eq_data_get?, getElem_eq_data_get, ← List.get?_eq_get, 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 - termination_by j - i - simp only [reverse]; split - · match a with | ⟨[]⟩ | ⟨[_]⟩ => rfl - · 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 ▸ ‹_›)] - theorem forIn_eq_data_forIn [Monad m] (as : Array α) (b : β) (f : α → β → m (ForInStep β)) : forIn as b f = forIn as.data b f := by @@ -262,41 +28,6 @@ theorem forIn_eq_data_forIn [Monad m] conv => lhs; simp only [forIn, Array.forIn] rw [loop (Nat.zero_add _)]; rfl -/-! ### foldl / foldr -/ - --- This proof is the pure version of `Array.SatisfiesM_foldlM`, --- reproduced to avoid a dependency on `SatisfiesM`. -theorem foldl_induction - {as : Array α} (motive : Nat → β → Prop) {init : β} (h0 : motive 0 init) {f : β → α → β} - (hf : ∀ i : Fin as.size, ∀ b, motive i.1 b → motive (i.1 + 1) (f b as[i])) : - motive as.size (as.foldl f init) := by - let rec go {i j b} (h₁ : j ≤ as.size) (h₂ : as.size ≤ i + j) (H : motive j b) : - (motive as.size) (foldlM.loop (m := Id) f as as.size (Nat.le_refl _) i j b) := by - unfold foldlM.loop; split - · next hj => - split - · cases Nat.not_le_of_gt (by simp [hj]) h₂ - · exact go hj (by rwa [Nat.succ_add] at h₂) (hf ⟨j, hj⟩ b H) - · next hj => exact Nat.le_antisymm h₁ (Nat.ge_of_not_lt hj) ▸ H - simpa [foldl, foldlM] using go (Nat.zero_le _) (Nat.le_refl _) h0 - --- This proof is the pure version of `Array.SatisfiesM_foldrM`, --- reproduced to avoid a dependency on `SatisfiesM`. -theorem foldr_induction - {as : Array α} (motive : Nat → β → Prop) {init : β} (h0 : motive as.size init) {f : α → β → β} - (hf : ∀ i : Fin as.size, ∀ b, motive (i.1 + 1) b → motive i.1 (f as[i] b)) : - motive 0 (as.foldr f init) := by - let rec go {i b} (hi : i ≤ as.size) (H : motive i b) : - (motive 0) (foldrM.fold (m := Id) f as 0 i hi b) := by - unfold foldrM.fold; simp; split - · next hi => exact (hi ▸ H) - · next hi => - split; {simp at hi} - · next i hi' => - exact go _ (hf ⟨i, hi'⟩ b H) - simp [foldr, foldrM]; split; {exact go _ h0} - · next h => exact (Nat.eq_zero_of_not_pos h ▸ h0) - /-! ### zipWith / zip -/ theorem zipWith_eq_zipWith_data (f : α → β → γ) (as : Array α) (bs : Array β) : @@ -353,186 +84,13 @@ theorem size_zip (as : Array α) (bs : Array β) : (as.zip bs).size = min as.size bs.size := as.size_zipWith bs Prod.mk -/-! ### map -/ - -@[simp] theorem mem_map {f : α → β} {l : Array α} : b ∈ l.map f ↔ ∃ a, a ∈ l ∧ f a = b := by - simp only [mem_def, map_data, List.mem_map] - -theorem mapM_eq_mapM_data [Monad m] [LawfulMonad m] (f : α → m β) (arr : Array α) : - arr.mapM f = return mk (← arr.data.mapM f) := by - rw [mapM_eq_foldlM, foldlM_eq_foldlM_data, ← List.foldrM_reverse] - conv => rhs; rw [← List.reverse_reverse arr.data] - induction arr.data.reverse with - | nil => simp; rfl - | cons a l ih => simp [ih]; simp [map_eq_pure_bind, push] - -theorem mapM_map_eq_foldl (as : Array α) (f : α → β) (i) : - mapM.map (m := Id) f as i b = as.foldl (start := i) (fun r a => r.push (f a)) b := by - unfold mapM.map - split <;> rename_i h - · simp only [Id.bind_eq] - dsimp [foldl, Id.run, foldlM] - rw [mapM_map_eq_foldl, dif_pos (by omega), foldlM.loop, dif_pos h] - -- Calling `split` here gives a bad goal. - have : size as - i = Nat.succ (size as - i - 1) := by omega - rw [this] - simp [foldl, foldlM, Id.run, Nat.sub_add_eq] - · dsimp [foldl, Id.run, foldlM] - rw [dif_pos (by omega), foldlM.loop, dif_neg h] - rfl -termination_by as.size - i - -theorem map_eq_foldl (as : Array α) (f : α → β) : - as.map f = as.foldl (fun r a => r.push (f a)) #[] := - mapM_map_eq_foldl _ _ _ - -theorem map_induction (as : Array α) (f : α → β) (motive : Nat → Prop) (h0 : motive 0) - (p : Fin as.size → β → Prop) (hs : ∀ i, motive i.1 → p i (f as[i]) ∧ motive (i+1)) : - motive as.size ∧ - ∃ eq : (as.map f).size = as.size, ∀ i h, p ⟨i, h⟩ ((as.map f)[i]) := by - have t := foldl_induction (as := as) (β := Array β) - (motive := fun i arr => motive i ∧ arr.size = i ∧ ∀ i h2, p i arr[i.1]) - (init := #[]) (f := fun r a => r.push (f a)) ?_ ?_ - obtain ⟨m, eq, w⟩ := t - · refine ⟨m, by simpa [map_eq_foldl] using eq, ?_⟩ - intro i h - simp [eq] at w - specialize w ⟨i, h⟩ trivial - simpa [map_eq_foldl] using w - · exact ⟨h0, rfl, nofun⟩ - · intro i b ⟨m, ⟨eq, w⟩⟩ - refine ⟨?_, ?_, ?_⟩ - · exact (hs _ m).2 - · simp_all - · intro j h - simp at h ⊢ - by_cases h' : j < size b - · rw [get_push] - simp_all - · rw [get_push, dif_neg h'] - simp only [show j = i by omega] - exact (hs _ m).1 - -theorem map_spec (as : Array α) (f : α → β) (p : Fin as.size → β → Prop) - (hs : ∀ i, p i (f as[i])) : - ∃ eq : (as.map f).size = as.size, ∀ i h, p ⟨i, h⟩ ((as.map f)[i]) := by - simpa using map_induction as f (fun _ => True) trivial p (by simp_all) - -@[simp] theorem getElem_map (f : α → β) (as : Array α) (i : Nat) (h) : - ((as.map f)[i]) = f (as[i]'(size_map .. ▸ h)) := by - have := map_spec as f (fun i b => b = f (as[i])) - simp only [implies_true, true_implies] at this - obtain ⟨eq, w⟩ := this - apply w - simp_all - -/-! ### mapIdx -/ - --- This could also be prove from `SatisfiesM_mapIdxM`. -theorem mapIdx_induction (as : Array α) (f : Fin as.size → α → β) - (motive : Nat → Prop) (h0 : motive 0) - (p : Fin as.size → β → Prop) - (hs : ∀ i, motive i.1 → p i (f i as[i]) ∧ motive (i + 1)) : - motive as.size ∧ ∃ eq : (Array.mapIdx as f).size = as.size, - ∀ i h, p ⟨i, h⟩ ((Array.mapIdx as f)[i]) := by - let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : ∀ i h h', p ⟨i, h⟩ bs[i]) (hm : motive j) : - let arr : Array β := Array.mapIdxM.map (m := Id) as f i j h bs - motive as.size ∧ ∃ eq : arr.size = as.size, ∀ i h, p ⟨i, h⟩ arr[i] := by - induction i generalizing j bs with simp [mapIdxM.map] - | zero => - have := (Nat.zero_add _).symm.trans h - exact ⟨this ▸ hm, h₁ ▸ this, fun _ _ => h₂ ..⟩ - | succ i ih => - apply @ih (bs.push (f ⟨j, by omega⟩ as[j])) (j + 1) (by omega) (by simpa using h₁) - · intro i i_lt h' - rw [get_push] - split - · apply h₂ - · simp only [size_push] at h' - obtain rfl : i = j := by omega - apply (hs ⟨i, by omega⟩ hm).1 - · exact (hs ⟨j, by omega⟩ hm).2 - simp [mapIdx, mapIdxM]; exact go rfl nofun h0 - -theorem mapIdx_spec (as : Array α) (f : Fin as.size → α → β) - (p : Fin as.size → β → Prop) (hs : ∀ i, p i (f i as[i])) : - ∃ eq : (Array.mapIdx as f).size = as.size, - ∀ i h, p ⟨i, h⟩ ((Array.mapIdx as f)[i]) := - (mapIdx_induction _ _ (fun _ => True) trivial p fun _ _ => ⟨hs .., trivial⟩).2 - -@[simp] theorem size_mapIdx (a : Array α) (f : Fin a.size → α → β) : (a.mapIdx f).size = a.size := - (mapIdx_spec (p := fun _ _ => True) (hs := fun _ => trivial)).1 - -@[simp] theorem size_zipWithIndex (as : Array α) : as.zipWithIndex.size = as.size := - Array.size_mapIdx _ _ - -@[simp] theorem getElem_mapIdx (a : Array α) (f : Fin a.size → α → β) (i : Nat) - (h : i < (mapIdx a f).size) : - haveI : i < a.size := by simp_all - (a.mapIdx f)[i] = f ⟨i, this⟩ a[i] := - (mapIdx_spec _ _ (fun i b => b = f i a[i]) fun _ => rfl).2 i _ - -/-! ### modify -/ - -@[simp] theorem size_modify (a : Array α) (i : Nat) (f : α → α) : (a.modify i f).size = a.size := by - unfold modify modifyM Id.run - split <;> simp - -theorem get_modify {arr : Array α} {x i} (h : i < arr.size) : - (arr.modify x f).get ⟨i, by simp [h]⟩ = - if x = i then f (arr.get ⟨i, h⟩) else arr.get ⟨i, h⟩ := by - simp [modify, modifyM, Id.run]; split - · simp [get_set _ _ _ h]; split <;> simp [*] - · rw [if_neg (mt (by rintro rfl; exact h) ‹_›)] - /-! ### filter -/ -@[simp] theorem filter_data (p : α → Bool) (l : Array α) : - (l.filter p).data = l.data.filter p := by - dsimp only [filter] - rw [foldl_eq_foldl_data] - generalize l.data = l - suffices ∀ a, (List.foldl (fun r a => if p a = true then push r a else r) a l).data = - a.data ++ List.filter p l by - simpa using this #[] - induction l with simp - | cons => split <;> simp [*] - -@[simp] theorem filter_filter (q) (l : Array α) : - filter p (filter q l) = filter (fun a => p a ∧ q a) l := by - apply ext' - simp only [filter_data, List.filter_filter] - theorem size_filter_le (p : α → Bool) (l : Array α) : (l.filter p).size ≤ l.size := by simp only [← data_length, filter_data] apply List.length_filter_le -@[simp] theorem mem_filter : x ∈ filter p as ↔ x ∈ as ∧ p x := by - simp only [mem_def, filter_data, List.mem_filter] - -theorem mem_of_mem_filter {a : α} {l} (h : a ∈ filter p l) : a ∈ l := - (mem_filter.mp h).1 - -/-! ### filterMap -/ - -@[simp] theorem filterMap_data (f : α → Option β) (l : Array α) : - (l.filterMap f).data = l.data.filterMap f := by - dsimp only [filterMap, filterMapM] - rw [foldlM_eq_foldlM_data] - generalize l.data = l - have this : ∀ a : Array β, (Id.run (List.foldlM (m := Id) ?_ a l)).data = - a.data ++ List.filterMap f l := ?_ - exact this #[] - induction l - · simp_all [Id.run] - · simp_all [Id.run] - split <;> simp_all - -@[simp] theorem mem_filterMap (f : α → Option β) (l : Array α) {b : β} : - b ∈ filterMap f l ↔ ∃ a, a ∈ l ∧ f a = some b := by - simp only [mem_def, filterMap_data, List.mem_filterMap] - /-! ### join -/ @[simp] theorem join_data {l : Array (Array α)} : l.join.data = (l.data.map data).join := by @@ -554,322 +112,10 @@ theorem mem_join : ∀ {L : Array (Array α)}, a ∈ L.join ↔ ∃ l, l ∈ L · rintro ⟨s, h₁, h₂⟩ refine ⟨s.data, ⟨⟨s, h₁, rfl⟩, h₂⟩⟩ -/-! ### empty -/ - -theorem size_empty : (#[] : Array α).size = 0 := rfl - -theorem empty_data : (#[] : Array α).data = [] := rfl - -/-! ### append -/ - -theorem push_eq_append_singleton (as : Array α) (x) : as.push x = as ++ #[x] := rfl - -@[simp] theorem mem_append {a : α} {s t : Array α} : a ∈ s ++ t ↔ a ∈ s ∨ a ∈ t := by - simp only [mem_def, append_data, List.mem_append] - -theorem size_append (as bs : Array α) : (as ++ bs).size = as.size + bs.size := by - simp only [size, append_data, List.length_append] - -theorem get_append_left {as bs : Array α} {h : i < (as ++ bs).size} (hlt : i < as.size) : - (as ++ bs)[i] = as[i] := by - simp only [getElem_eq_data_get] - have h' : i < (as.data ++ bs.data).length := by rwa [← data_length, append_data] at h - conv => rhs; rw [← List.get_append_left (bs:=bs.data) (h':=h')] - apply List.get_of_eq; rw [append_data] - -theorem get_append_right {as bs : Array α} {h : i < (as ++ bs).size} (hle : as.size ≤ i) - (hlt : i - as.size < bs.size := Nat.sub_lt_left_of_lt_add hle (size_append .. ▸ h)) : - (as ++ bs)[i] = bs[i - as.size] := by - simp only [getElem_eq_data_get] - have h' : i < (as.data ++ bs.data).length := by rwa [← data_length, append_data] at h - conv => rhs; rw [← List.get_append_right (h':=h') (h:=Nat.not_lt_of_ge hle)] - apply List.get_of_eq; rw [append_data] - -@[simp] theorem append_nil (as : Array α) : as ++ #[] = as := by - apply ext'; simp only [append_data, empty_data, List.append_nil] - -@[simp] theorem nil_append (as : Array α) : #[] ++ as = as := by - apply ext'; simp only [append_data, empty_data, List.nil_append] - -theorem append_assoc (as bs cs : Array α) : as ++ bs ++ cs = as ++ (bs ++ cs) := by - apply ext'; simp only [append_data, List.append_assoc] - -/-! ### extract -/ - -theorem extract_loop_zero (as bs : Array α) (start : Nat) : extract.loop as 0 start bs = bs := by - rw [extract.loop]; split <;> rfl - -theorem extract_loop_succ (as bs : Array α) (size start : Nat) (h : start < as.size) : - extract.loop as (size+1) start bs = extract.loop as size (start+1) (bs.push as[start]) := by - rw [extract.loop, dif_pos h]; rfl - -theorem extract_loop_of_ge (as bs : Array α) (size start : Nat) (h : start ≥ as.size) : - extract.loop as size start bs = bs := by - rw [extract.loop, dif_neg (Nat.not_lt_of_ge h)] - -theorem extract_loop_eq_aux (as bs : Array α) (size start : Nat) : - extract.loop as size start bs = bs ++ extract.loop as size start #[] := by - induction size using Nat.recAux generalizing start bs with - | zero => rw [extract_loop_zero, extract_loop_zero, append_nil] - | succ size ih => - if h : start < as.size then - rw [extract_loop_succ (h:=h), ih (bs.push _), push_eq_append_singleton] - rw [extract_loop_succ (h:=h), ih (#[].push _), push_eq_append_singleton, nil_append] - rw [append_assoc] - else - rw [extract_loop_of_ge (h:=Nat.le_of_not_lt h)] - rw [extract_loop_of_ge (h:=Nat.le_of_not_lt h)] - rw [append_nil] - -theorem extract_loop_eq (as bs : Array α) (size start : Nat) (h : start + size ≤ as.size) : - extract.loop as size start bs = bs ++ as.extract start (start + size) := by - simp [extract]; rw [extract_loop_eq_aux, Nat.min_eq_left h, Nat.add_sub_cancel_left] - -theorem size_extract_loop (as bs : Array α) (size start : Nat) : - (extract.loop as size start bs).size = bs.size + min size (as.size - start) := by - induction size using Nat.recAux generalizing start bs with - | zero => rw [extract_loop_zero, Nat.zero_min, Nat.add_zero] - | succ size ih => - if h : start < as.size then - rw [extract_loop_succ (h:=h), ih, size_push, Nat.add_assoc, ←Nat.add_min_add_left, - Nat.sub_succ, Nat.one_add, Nat.one_add, Nat.succ_pred_eq_of_pos (Nat.sub_pos_of_lt h)] - else - have h := Nat.le_of_not_gt h - rw [extract_loop_of_ge (h:=h), Nat.sub_eq_zero_of_le h, Nat.min_zero, Nat.add_zero] - -@[simp] theorem size_extract (as : Array α) (start stop : Nat) : - (as.extract start stop).size = min stop as.size - start := by - simp [extract]; rw [size_extract_loop, size_empty, Nat.zero_add, Nat.sub_min_sub_right, - Nat.min_assoc, Nat.min_self] - -theorem get_extract_loop_lt_aux (as bs : Array α) (size start : Nat) (hlt : i < bs.size) : - i < (extract.loop as size start bs).size := by - rw [size_extract_loop] - apply Nat.lt_of_lt_of_le hlt - exact Nat.le_add_right .. - -theorem get_extract_loop_lt (as bs : Array α) (size start : Nat) (hlt : i < bs.size) - (h := get_extract_loop_lt_aux as bs size start hlt) : - (extract.loop as size start bs)[i] = bs[i] := by - apply Eq.trans _ (get_append_left (bs:=extract.loop as size start #[]) hlt) - · rw [size_append]; exact Nat.lt_of_lt_of_le hlt (Nat.le_add_right ..) - · congr; rw [extract_loop_eq_aux] - -theorem get_extract_loop_ge_aux (as bs : Array α) (size start : Nat) (hge : i ≥ bs.size) - (h : i < (extract.loop as size start bs).size) : start + i - bs.size < as.size := by - have h : i < bs.size + (as.size - start) := by - apply Nat.lt_of_lt_of_le h - rw [size_extract_loop] - apply Nat.add_le_add_left - exact Nat.min_le_right .. - rw [Nat.add_sub_assoc hge] - apply Nat.add_lt_of_lt_sub' - exact Nat.sub_lt_left_of_lt_add hge h - -theorem get_extract_loop_ge (as bs : Array α) (size start : Nat) (hge : i ≥ bs.size) - (h : i < (extract.loop as size start bs).size) - (h' := get_extract_loop_ge_aux as bs size start hge h) : - (extract.loop as size start bs)[i] = as[start + i - bs.size] := by - induction size using Nat.recAux generalizing start bs with - | zero => - rw [size_extract_loop, Nat.zero_min, Nat.add_zero] at h - absurd h; exact Nat.not_lt_of_ge hge - | succ size ih => - have : start < as.size := by - apply Nat.lt_of_le_of_lt (Nat.le_add_right start (i - bs.size)) - rwa [← Nat.add_sub_assoc hge] - have : i < (extract.loop as size (start+1) (bs.push as[start])).size := by - rwa [← extract_loop_succ] - have heq : (extract.loop as (size+1) start bs)[i] = - (extract.loop as size (start+1) (bs.push as[start]))[i] := by - congr 1; rw [extract_loop_succ] - rw [heq] - if hi : bs.size = i then - cases hi - have h₁ : bs.size < (bs.push as[start]).size := by rw [size_push]; exact Nat.lt_succ_self .. - have h₂ : bs.size < (extract.loop as size (start+1) (bs.push as[start])).size := by - rw [size_extract_loop]; apply Nat.lt_of_lt_of_le h₁; exact Nat.le_add_right .. - have h : (extract.loop as size (start + 1) (push bs as[start]))[bs.size] = as[start] := by - rw [get_extract_loop_lt as (bs.push as[start]) size (start+1) h₁ h₂, get_push_eq] - rw [h]; congr; rw [Nat.add_sub_cancel] - else - have hge : bs.size + 1 ≤ i := Nat.lt_of_le_of_ne hge hi - rw [ih (bs.push as[start]) (start+1) ((size_push ..).symm ▸ hge)] - congr 1; rw [size_push, Nat.add_right_comm, Nat.add_sub_add_right] - -theorem get_extract_aux {as : Array α} {start stop : Nat} (h : i < (as.extract start stop).size) : - start + i < as.size := by - rw [size_extract] at h; apply Nat.add_lt_of_lt_sub'; apply Nat.lt_of_lt_of_le h - apply Nat.sub_le_sub_right; apply Nat.min_le_right - -@[simp] theorem get_extract {as : Array α} {start stop : Nat} - (h : i < (as.extract start stop).size) : - (as.extract start stop)[i] = as[start + i]'(get_extract_aux h) := - show (extract.loop as (min stop as.size - start) start #[])[i] - = as[start + i]'(get_extract_aux h) by rw [get_extract_loop_ge]; rfl; exact Nat.zero_le _ - -@[simp] theorem extract_all (as : Array α) : as.extract 0 as.size = as := by - apply ext - · rw [size_extract, Nat.min_self, Nat.sub_zero] - · intros; rw [get_extract]; congr; rw [Nat.zero_add] - -theorem extract_empty_of_stop_le_start (as : Array α) {start stop : Nat} (h : stop ≤ start) : - as.extract start stop = #[] := by - simp [extract]; rw [←Nat.sub_min_sub_right, Nat.sub_eq_zero_of_le h, Nat.zero_min, - extract_loop_zero] - -theorem extract_empty_of_size_le_start (as : Array α) {start stop : Nat} (h : as.size ≤ start) : - as.extract start stop = #[] := by - simp [extract]; rw [←Nat.sub_min_sub_right, Nat.sub_eq_zero_of_le h, Nat.min_zero, - extract_loop_zero] - -@[simp] theorem extract_empty (start stop : Nat) : (#[] : Array α).extract start stop = #[] := - extract_empty_of_size_le_start _ (Nat.zero_le _) - -/-! ### any -/ - --- Auxiliary for `any_iff_exists`. -theorem anyM_loop_iff_exists (p : α → Bool) (as : Array α) (start stop) (h : stop ≤ as.size) : - anyM.loop (m := Id) p as stop h start = true ↔ - ∃ i : Fin as.size, start ≤ ↑i ∧ ↑i < stop ∧ p as[i] = true := by - unfold anyM.loop - split <;> rename_i h₁ - · dsimp - split <;> rename_i h₂ - · simp only [true_iff] - refine ⟨⟨start, by omega⟩, by dsimp; omega, by dsimp; omega, h₂⟩ - · rw [anyM_loop_iff_exists] - constructor - · rintro ⟨i, ge, lt, h⟩ - have : start ≠ i := by rintro rfl; omega - exact ⟨i, by omega, lt, h⟩ - · rintro ⟨i, ge, lt, h⟩ - have : start ≠ i := by rintro rfl; erw [h] at h₂; simp_all - exact ⟨i, by omega, lt, h⟩ - · simp - omega -termination_by stop - start - --- This could also be proved from `SatisfiesM_anyM_iff_exists` in --- `Batteries.Data.Array.Init.Monadic`. -theorem any_iff_exists (p : α → Bool) (as : Array α) (start stop) : - any as p start stop ↔ ∃ i : Fin as.size, start ≤ i.1 ∧ i.1 < stop ∧ p as[i] := by - dsimp [any, anyM, Id.run] - split - · rw [anyM_loop_iff_exists]; rfl - · rw [anyM_loop_iff_exists] - constructor - · rintro ⟨i, ge, _, h⟩ - exact ⟨i, by omega, by omega, h⟩ - · rintro ⟨i, ge, _, h⟩ - exact ⟨i, by omega, by omega, h⟩ - -theorem any_eq_true (p : α → Bool) (as : Array α) : - any as p ↔ ∃ i : Fin as.size, p as[i] := by simp [any_iff_exists, Fin.isLt] - -theorem any_def {p : α → Bool} (as : Array α) : as.any p = as.data.any p := by - rw [Bool.eq_iff_iff, any_eq_true, List.any_eq_true]; simp only [List.mem_iff_get] - exact ⟨fun ⟨i, h⟩ => ⟨_, ⟨i, rfl⟩, h⟩, fun ⟨_, ⟨i, rfl⟩, h⟩ => ⟨i, h⟩⟩ - -/-! ### all -/ - -theorem all_eq_not_any_not (p : α → Bool) (as : Array α) (start stop) : - all as p start stop = !(any as (!p ·) start stop) := by - dsimp [all, allM] - rfl - -theorem all_iff_forall (p : α → Bool) (as : Array α) (start stop) : - all as p start stop ↔ ∀ i : Fin as.size, start ≤ i.1 ∧ i.1 < stop → p as[i] := by - rw [all_eq_not_any_not] - suffices ¬(any as (!p ·) start stop = true) ↔ - ∀ i : Fin as.size, start ≤ i.1 ∧ i.1 < stop → p as[i] by - simp_all - rw [any_iff_exists] - simp - -theorem all_eq_true (p : α → Bool) (as : Array α) : all as p ↔ ∀ i : Fin as.size, p as[i] := by - simp [all_iff_forall, Fin.isLt] - -theorem all_def {p : α → Bool} (as : Array α) : as.all p = as.data.all p := by - rw [Bool.eq_iff_iff, all_eq_true, List.all_eq_true]; simp only [List.mem_iff_get] - constructor - · rintro w x ⟨r, rfl⟩ - rw [← getElem_eq_data_get] - apply w - · intro w i - exact w as[i] ⟨i, (getElem_eq_data_get as i.2).symm⟩ - -theorem all_eq_true_iff_forall_mem {l : Array α} : l.all p ↔ ∀ x, x ∈ l → p x := by - simp only [all_def, List.all_eq_true, mem_def] - -/-! ### contains -/ - -theorem contains_def [DecidableEq α] {a : α} {as : Array α} : as.contains a ↔ a ∈ as := by - rw [mem_def, contains, any_def, List.any_eq_true]; simp [and_comm] - -instance [DecidableEq α] (a : α) (as : Array α) : Decidable (a ∈ as) := - decidable_of_iff _ contains_def - /-! ### erase -/ @[simp] proof_wanted erase_data [BEq α] {l : Array α} {a : α} : (l.erase a).data = l.data.erase a -/-! ### swap -/ - -@[simp] theorem get_swap_right (a : Array α) {i j : Fin a.size} : (a.swap i j)[j.val] = a[i] := - by simp only [swap, fin_cast_val, get_eq_getElem, getElem_set_eq, getElem_fin] - -@[simp] theorem get_swap_left (a : Array α) {i j : Fin a.size} : (a.swap i j)[i.val] = a[j] := - if he : ((Array.size_set _ _ _).symm ▸ j).val = i.val then by - simp only [←he, fin_cast_val, get_swap_right, getElem_fin] - else by - apply Eq.trans - · apply Array.get_set_ne - · simp only [size_set, Fin.is_lt] - · assumption - · simp [get_set_ne] - -@[simp] theorem get_swap_of_ne (a : Array α) {i j : Fin a.size} (hp : p < a.size) - (hi : p ≠ i) (hj : p ≠ j) : (a.swap i j)[p]'(a.size_swap .. |>.symm ▸ hp) = a[p] := by - apply Eq.trans - · have : ((a.size_set i (a.get j)).symm ▸ j).val = j.val := by simp only [fin_cast_val] - apply Array.get_set_ne - · simp only [this] - apply Ne.symm - · assumption - · apply Array.get_set_ne - · apply Ne.symm - · assumption - -theorem get_swap (a : Array α) (i j : Fin a.size) (k : Nat) (hk: k < a.size) : - (a.swap i j)[k]'(by simp_all) = if k = i then a[j] else if k = j then a[i] else a[k] := by - split - · simp_all only [get_swap_left] - · split <;> simp_all - -theorem get_swap' (a : Array α) (i j : Fin a.size) (k : Nat) (hk' : k < (a.swap i j).size) : - (a.swap i j)[k] = if k = i then a[j] else if k = j then a[i] else a[k]'(by simp_all) := by - apply get_swap - -@[simp] theorem swap_swap (a : Array α) {i j : Fin a.size} : - (a.swap i j).swap ⟨i.1, (a.size_swap ..).symm ▸i.2⟩ ⟨j.1, (a.size_swap ..).symm ▸j.2⟩ = a := by - apply ext - · simp only [size_swap] - · intros - simp only [get_swap'] - split - · simp_all - · split <;> simp_all - -theorem swap_comm (a : Array α) {i j : Fin a.size} : a.swap i j = a.swap j i := by - apply ext - · simp only [size_swap] - · intros - simp only [get_swap'] - split - · split <;> simp_all - · split <;> simp_all - /-! ### shrink -/ theorem size_shrink_loop (a : Array α) (n) : (shrink.loop n a).size = a.size - n := by diff --git a/Batteries/Data/ByteArray.lean b/Batteries/Data/ByteArray.lean index 4788ecbb36..f147eaf47b 100644 --- a/Batteries/Data/ByteArray.lean +++ b/Batteries/Data/ByteArray.lean @@ -14,9 +14,6 @@ theorem getElem_eq_data_getElem (a : ByteArray) (h : i < a.size) : a[i] = a.data /-! ### uget/uset -/ -@[simp] theorem ugetElem_eq_getElem (a : ByteArray) {i : USize} (h : i.toNat < a.size) : - a[i] = a[i.toNat] := rfl - @[simp] theorem uset_eq_set (a : ByteArray) {i : USize} (h : i.toNat < a.size) (v : UInt8) : a.uset i v h = a.set ⟨i.toNat, h⟩ v := rfl diff --git a/Batteries/Data/Fin/Basic.lean b/Batteries/Data/Fin/Basic.lean index 495344f90f..3632d4f254 100644 --- a/Batteries/Data/Fin/Basic.lean +++ b/Batteries/Data/Fin/Basic.lean @@ -14,17 +14,3 @@ def enum (n) : Array (Fin n) := Array.ofFn id /-- `list n` is the list of all elements of `Fin n` in order -/ def list (n) : List (Fin n) := (enum n).data - -/-- Folds over `Fin n` from the left: `foldl 3 f x = f (f (f x 0) 1) 2`. -/ -@[inline] def foldl (n) (f : α → Fin n → α) (init : α) : α := loop init 0 where - /-- Inner loop for `Fin.foldl`. `Fin.foldl.loop n f x i = f (f (f x i) ...) (n-1)` -/ - loop (x : α) (i : Nat) : α := - if h : i < n then loop (f x ⟨i, h⟩) (i+1) else x - termination_by n - i - -/-- Folds over `Fin n` from the right: `foldr 3 f x = f 0 (f 1 (f 2 x))`. -/ -@[inline] def foldr (n) (f : Fin n → α → α) (init : α) : α := loop ⟨n, Nat.le_refl n⟩ init where - /-- Inner loop for `Fin.foldr`. `Fin.foldr.loop n f i x = f 0 (f ... (f (i-1) x))` -/ - loop : {i // i ≤ n} → α → α - | ⟨0, _⟩, x => x - | ⟨i+1, h⟩, x => loop ⟨i, Nat.le_of_lt h⟩ (f ⟨i, h⟩ x) diff --git a/Batteries/Data/Fin/Lemmas.lean b/Batteries/Data/Fin/Lemmas.lean index 7167efa0ed..a310aa6f93 100644 --- a/Batteries/Data/Fin/Lemmas.lean +++ b/Batteries/Data/Fin/Lemmas.lean @@ -23,6 +23,8 @@ protected theorem le_antisymm {x y : Fin n} (h1 : x ≤ y) (h2 : y ≤ x) : x = @[simp] theorem size_enum (n) : (enum n).size = n := Array.size_ofFn .. +@[simp] theorem enum_zero : (enum 0) = #[] := by simp [enum, Array.ofFn, Array.ofFn.go] + @[simp] theorem getElem_enum (i) (h : i < (enum n).size) : (enum n)[i] = ⟨i, size_enum n ▸ h⟩ := Array.getElem_ofFn .. @@ -31,7 +33,7 @@ protected theorem le_antisymm {x y : Fin n} (h1 : x ≤ y) (h2 : y ≤ x) : x = @[simp] theorem get_list (i : Fin (list n).length) : (list n).get i = i.cast (length_list n) := by cases i; simp only [list]; rw [← Array.getElem_eq_data_get, getElem_enum, cast_mk] -@[simp] theorem list_zero : list 0 = [] := rfl +@[simp] theorem list_zero : list 0 = [] := by simp [list] theorem list_succ (n) : list (n+1) = 0 :: (list n).map Fin.succ := by apply List.ext_get; simp; intro i; cases i <;> simp @@ -70,7 +72,7 @@ theorem foldl_loop (f : α → Fin (n+1) → α) (x) (h : m < n+1) : rw [foldl_loop_lt, foldl_loop_eq, foldl_loop_eq] termination_by n - m -@[simp] theorem foldl_zero (f : α → Fin 0 → α) (x) : foldl 0 f x = x := rfl +@[simp] theorem foldl_zero (f : α → Fin 0 → α) (x) : foldl 0 f x = x := by simp [foldl, foldl.loop] theorem foldl_succ (f : α → Fin (n+1) → α) (x) : foldl (n+1) f x = foldl n (fun x i => f x i.succ) (f x 0) := foldl_loop .. @@ -79,43 +81,47 @@ theorem foldl_succ_last (f : α → Fin (n+1) → α) (x) : foldl (n+1) f x = f (foldl n (f · ·.castSucc) x) (last n) := by rw [foldl_succ] induction n generalizing x with - | zero => rfl + | zero => simp [foldl_succ, Fin.last] | succ n ih => rw [foldl_succ, ih (f · ·.succ), foldl_succ]; simp [succ_castSucc] theorem foldl_eq_foldl_list (f : α → Fin n → α) (x) : foldl n f x = (list n).foldl f x := by induction n generalizing x with - | zero => rfl + | zero => rw [foldl_zero, list_zero, List.foldl_nil] | succ n ih => rw [foldl_succ, ih, list_succ, List.foldl_cons, List.foldl_map] /-! ### foldr -/ -theorem foldr_loop_zero (f : Fin n → α → α) (x) : foldr.loop n f ⟨0, Nat.zero_le _⟩ x = x := rfl +unseal foldr.loop in +theorem foldr_loop_zero (f : Fin n → α → α) (x) : foldr.loop n f ⟨0, Nat.zero_le _⟩ x = x := + rfl +unseal foldr.loop in theorem foldr_loop_succ (f : Fin n → α → α) (x) (h : m < n) : - foldr.loop n f ⟨m+1, h⟩ x = foldr.loop n f ⟨m, Nat.le_of_lt h⟩ (f ⟨m, h⟩ x) := rfl + foldr.loop n f ⟨m+1, h⟩ x = foldr.loop n f ⟨m, Nat.le_of_lt h⟩ (f ⟨m, h⟩ x) := + rfl theorem foldr_loop (f : Fin (n+1) → α → α) (x) (h : m+1 ≤ n+1) : foldr.loop (n+1) f ⟨m+1, h⟩ x = f 0 (foldr.loop n (fun i => f i.succ) ⟨m, Nat.le_of_succ_le_succ h⟩ x) := by induction m generalizing x with | zero => simp [foldr_loop_zero, foldr_loop_succ] - | succ m ih => rw [foldr_loop_succ, ih]; rfl + | succ m ih => rw [foldr_loop_succ, ih, foldr_loop_succ, Fin.succ] -@[simp] theorem foldr_zero (f : Fin 0 → α → α) (x) : foldr 0 f x = x := rfl +@[simp] theorem foldr_zero (f : Fin 0 → α → α) (x) : + foldr 0 f x = x := foldr_loop_zero .. theorem foldr_succ (f : Fin (n+1) → α → α) (x) : foldr (n+1) f x = f 0 (foldr n (fun i => f i.succ) x) := foldr_loop .. theorem foldr_succ_last (f : Fin (n+1) → α → α) (x) : foldr (n+1) f x = foldr n (f ·.castSucc) (f (last n) x) := by - rw [foldr_succ] induction n generalizing x with - | zero => rfl + | zero => simp [foldr_succ, Fin.last] | succ n ih => rw [foldr_succ, ih (f ·.succ), foldr_succ]; simp [succ_castSucc] theorem foldr_eq_foldr_list (f : Fin n → α → α) (x) : foldr n f x = (list n).foldr f x := by induction n with - | zero => rfl + | zero => rw [foldr_zero, list_zero, List.foldr_nil] | succ n ih => rw [foldr_succ, ih, list_succ, List.foldr_cons, List.foldr_map] /-! ### foldl/foldr -/ @@ -123,11 +129,11 @@ theorem foldr_eq_foldr_list (f : Fin n → α → α) (x) : foldr n f x = (list theorem foldl_rev (f : Fin n → α → α) (x) : foldl n (fun x i => f i.rev x) x = foldr n f x := by induction n generalizing x with - | zero => rfl + | zero => simp | succ n ih => rw [foldl_succ, foldr_succ_last, ← ih]; simp [rev_succ] theorem foldr_rev (f : α → Fin n → α) (x) : foldr n (fun i x => f x i.rev) x = foldl n f x := by induction n generalizing x with - | zero => rfl + | zero => simp | succ n ih => rw [foldl_succ_last, foldr_succ, ← ih]; simp [rev_succ] diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index d23566b21f..6109b4c9be 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -12,396 +12,22 @@ namespace List open Nat -/-! # Basic properties of Lists -/ - -theorem cons_ne_nil (a : α) (l : List α) : a :: l ≠ [] := nofun - -@[simp] -theorem cons_ne_self (a : α) (l : List α) : a :: l ≠ l := mt (congrArg length) (Nat.succ_ne_self _) - -theorem head_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : h₁ = h₂ := (cons.inj H).1 - -theorem tail_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : t₁ = t₂ := (cons.inj H).2 - -theorem cons_inj (a : α) {l l' : List α} : a :: l = a :: l' ↔ l = l' := - ⟨tail_eq_of_cons_eq, congrArg _⟩ - -theorem cons_eq_cons {a b : α} {l l' : List α} : a :: l = b :: l' ↔ a = b ∧ l = l' := - List.cons.injEq .. ▸ .rfl - -theorem exists_cons_of_ne_nil : ∀ {l : List α}, l ≠ [] → ∃ b L, l = b :: L - | c :: l', _ => ⟨c, l', rfl⟩ - -/-! ### length -/ - -@[simp 1100] theorem length_singleton (a : α) : length [a] = 1 := rfl - -theorem length_pos_of_mem {a : α} : ∀ {l : List α}, a ∈ l → 0 < length l - | _::_, _ => Nat.zero_lt_succ _ - -theorem exists_mem_of_length_pos : ∀ {l : List α}, 0 < length l → ∃ a, a ∈ l - | _::_, _ => ⟨_, .head ..⟩ - -theorem length_pos_iff_exists_mem {l : List α} : 0 < length l ↔ ∃ a, a ∈ l := - ⟨exists_mem_of_length_pos, fun ⟨_, h⟩ => length_pos_of_mem h⟩ - -theorem exists_cons_of_length_pos : ∀ {l : List α}, 0 < l.length → ∃ h t, l = h :: t - | _::_, _ => ⟨_, _, rfl⟩ - -theorem length_pos_iff_exists_cons : - ∀ {l : List α}, 0 < l.length ↔ ∃ h t, l = h :: t := - ⟨exists_cons_of_length_pos, fun ⟨_, _, eq⟩ => eq ▸ Nat.succ_pos _⟩ - -theorem exists_cons_of_length_succ : - ∀ {l : List α}, l.length = n + 1 → ∃ h t, l = h :: t - | _::_, _ => ⟨_, _, rfl⟩ - -attribute [simp] length_eq_zero -- TODO: suggest to core - -@[simp] -theorem length_pos {l : List α} : 0 < length l ↔ l ≠ [] := - Nat.pos_iff_ne_zero.trans (not_congr length_eq_zero) - -theorem exists_mem_of_ne_nil (l : List α) (h : l ≠ []) : ∃ x, x ∈ l := - exists_mem_of_length_pos (length_pos.2 h) - -theorem length_eq_one {l : List α} : length l = 1 ↔ ∃ a, l = [a] := - ⟨fun h => match l, h with | [_], _ => ⟨_, rfl⟩, fun ⟨_, h⟩ => by simp [h]⟩ - /-! ### mem -/ -theorem mem_nil_iff (a : α) : a ∈ ([] : List α) ↔ False := by simp - @[simp] theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l := by simp [Array.mem_def] -theorem mem_singleton_self (a : α) : a ∈ [a] := mem_cons_self _ _ - -theorem eq_of_mem_singleton : a ∈ [b] → a = b - | .head .. => rfl - -@[simp 1100] theorem mem_singleton {a b : α} : a ∈ [b] ↔ a = b := - ⟨eq_of_mem_singleton, (by simp [·])⟩ - -theorem mem_of_mem_cons_of_mem : ∀ {a b : α} {l : List α}, a ∈ b :: l → b ∈ l → a ∈ l - | _, _, _, .head .., h | _, _, _, .tail _ h, _ => h - -theorem eq_or_ne_mem_of_mem {a b : α} {l : List α} (h' : a ∈ b :: l) : a = b ∨ (a ≠ b ∧ a ∈ l) := - (Classical.em _).imp_right fun h => ⟨h, (mem_cons.1 h').resolve_left h⟩ - -theorem ne_nil_of_mem {a : α} {l : List α} (h : a ∈ l) : l ≠ [] := by cases h <;> nofun - -theorem append_of_mem {a : α} {l : List α} : a ∈ l → ∃ s t : List α, l = s ++ a :: t - | .head l => ⟨[], l, rfl⟩ - | .tail b h => let ⟨s, t, h'⟩ := append_of_mem h; ⟨b::s, t, by rw [h', cons_append]⟩ - -theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {as : List α} : - elem a as = true ↔ a ∈ as := ⟨mem_of_elem_eq_true, elem_eq_true_of_mem⟩ - -@[simp] theorem elem_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) : - elem a as = decide (a ∈ as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff] - -theorem mem_of_ne_of_mem {a y : α} {l : List α} (h₁ : a ≠ y) (h₂ : a ∈ y :: l) : a ∈ l := - Or.elim (mem_cons.mp h₂) (absurd · h₁) (·) - -theorem ne_of_not_mem_cons {a b : α} {l : List α} : a ∉ b::l → a ≠ b := mt (· ▸ .head _) - -theorem not_mem_of_not_mem_cons {a b : α} {l : List α} : a ∉ b::l → a ∉ l := mt (.tail _) - -theorem not_mem_cons_of_ne_of_not_mem {a y : α} {l : List α} : a ≠ y → a ∉ l → a ∉ y::l := - mt ∘ mem_of_ne_of_mem - -theorem ne_and_not_mem_of_not_mem_cons {a y : α} {l : List α} : a ∉ y::l → a ≠ y ∧ a ∉ l := - fun p => ⟨ne_of_not_mem_cons p, not_mem_of_not_mem_cons p⟩ - /-! ### drop -/ @[simp] theorem drop_one : ∀ l : List α, drop 1 l = tail l | [] | _ :: _ => rfl -theorem drop_add : ∀ (m n) (l : List α), drop (m + n) l = drop m (drop n l) - | _, 0, _ => rfl - | _, _ + 1, [] => drop_nil.symm - | m, n + 1, _ :: _ => drop_add m n _ - -@[simp] -theorem drop_left : ∀ l₁ l₂ : List α, drop (length l₁) (l₁ ++ l₂) = l₂ - | [], _ => rfl - | _ :: l₁, l₂ => drop_left l₁ l₂ - -theorem drop_left' {l₁ l₂ : List α} {n} (h : length l₁ = n) : drop n (l₁ ++ l₂) = l₂ := by - rw [← h]; apply drop_left - -/-! ### isEmpty -/ - -@[simp] theorem isEmpty_nil : ([] : List α).isEmpty = true := rfl -@[simp] theorem isEmpty_cons : (x :: xs : List α).isEmpty = false := rfl - -/-! ### append -/ - -theorem append_eq_append : List.append l₁ l₂ = l₁ ++ l₂ := rfl - -theorem append_ne_nil_of_ne_nil_left (s t : List α) : s ≠ [] → s ++ t ≠ [] := by simp_all - -theorem append_ne_nil_of_ne_nil_right (s t : List α) : t ≠ [] → s ++ t ≠ [] := by simp_all - -@[simp] theorem nil_eq_append : [] = a ++ b ↔ a = [] ∧ b = [] := by - rw [eq_comm, append_eq_nil] - -theorem append_ne_nil_of_left_ne_nil (a b : List α) (h0 : a ≠ []) : a ++ b ≠ [] := by simp [*] - -theorem append_eq_cons : - a ++ b = x :: c ↔ (a = [] ∧ b = x :: c) ∨ (∃ a', a = x :: a' ∧ c = a' ++ b) := by - cases a with simp | cons a as => ?_ - exact ⟨fun h => ⟨as, by simp [h]⟩, fun ⟨a', ⟨aeq, aseq⟩, h⟩ => ⟨aeq, by rw [aseq, h]⟩⟩ - -theorem cons_eq_append : - x :: c = a ++ b ↔ (a = [] ∧ b = x :: c) ∨ (∃ a', a = x :: a' ∧ c = a' ++ b) := by - rw [eq_comm, append_eq_cons] - -theorem append_eq_append_iff {a b c d : List α} : - a ++ b = c ++ d ↔ (∃ a', c = a ++ a' ∧ b = a' ++ d) ∨ ∃ c', a = c ++ c' ∧ d = c' ++ b := by - induction a generalizing c with - | nil => simp_all - | cons a as ih => cases c <;> simp [eq_comm, and_assoc, ih, and_or_left] - -@[simp] theorem mem_append {a : α} {s t : List α} : a ∈ s ++ t ↔ a ∈ s ∨ a ∈ t := by - induction s <;> simp_all [or_assoc] - -theorem not_mem_append {a : α} {s t : List α} (h₁ : a ∉ s) (h₂ : a ∉ t) : a ∉ s ++ t := - mt mem_append.1 $ not_or.mpr ⟨h₁, h₂⟩ - -theorem mem_append_eq (a : α) (s t : List α) : (a ∈ s ++ t) = (a ∈ s ∨ a ∈ t) := - propext mem_append - -theorem mem_append_left {a : α} {l₁ : List α} (l₂ : List α) (h : a ∈ l₁) : a ∈ l₁ ++ l₂ := - mem_append.2 (Or.inl h) - -theorem mem_append_right {a : α} (l₁ : List α) {l₂ : List α} (h : a ∈ l₂) : a ∈ l₁ ++ l₂ := - mem_append.2 (Or.inr h) - -theorem mem_iff_append {a : α} {l : List α} : a ∈ l ↔ ∃ s t : List α, l = s ++ a :: t := - ⟨append_of_mem, fun ⟨s, t, e⟩ => e ▸ by simp⟩ - -/-! ### concat -/ - -theorem concat_nil (a : α) : concat [] a = [a] := - rfl - -theorem concat_cons (a b : α) (l : List α) : concat (a :: l) b = a :: concat l b := - rfl - -theorem init_eq_of_concat_eq {a : α} {l₁ l₂ : List α} : concat l₁ a = concat l₂ a → l₁ = l₂ := by - simp - -theorem last_eq_of_concat_eq {a b : α} {l : List α} : concat l a = concat l b → a = b := by - simp - -theorem concat_ne_nil (a : α) (l : List α) : concat l a ≠ [] := by simp - -theorem concat_append (a : α) (l₁ l₂ : List α) : concat l₁ a ++ l₂ = l₁ ++ a :: l₂ := by simp - -theorem append_concat (a : α) (l₁ l₂ : List α) : l₁ ++ concat l₂ a = concat (l₁ ++ l₂) a := by simp - -/-! ### map -/ - -theorem map_singleton (f : α → β) (a : α) : map f [a] = [f a] := rfl - -theorem exists_of_mem_map (h : b ∈ map f l) : ∃ a, a ∈ l ∧ f a = b := mem_map.1 h - -theorem forall_mem_map_iff {f : α → β} {l : List α} {P : β → Prop} : - (∀ i ∈ l.map f, P i) ↔ ∀ j ∈ l, P (f j) := by - simp - -@[simp] theorem map_eq_nil {f : α → β} {l : List α} : map f l = [] ↔ l = [] := by - constructor <;> exact fun _ => match l with | [] => rfl - /-! ### zipWith -/ -@[simp] theorem length_zipWith (f : α → β → γ) (l₁ l₂) : - length (zipWith f l₁ l₂) = min (length l₁) (length l₂) := by - induction l₁ generalizing l₂ <;> cases l₂ <;> - simp_all [succ_min_succ, Nat.zero_min, Nat.min_zero] - -@[simp] -theorem zipWith_map {μ} (f : γ → δ → μ) (g : α → γ) (h : β → δ) (l₁ : List α) (l₂ : List β) : - zipWith f (l₁.map g) (l₂.map h) = zipWith (fun a b => f (g a) (h b)) l₁ l₂ := by - induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all - -theorem zipWith_map_left (l₁ : List α) (l₂ : List β) (f : α → α') (g : α' → β → γ) : - zipWith g (l₁.map f) l₂ = zipWith (fun a b => g (f a) b) l₁ l₂ := by - induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all - -theorem zipWith_map_right (l₁ : List α) (l₂ : List β) (f : β → β') (g : α → β' → γ) : - zipWith g l₁ (l₂.map f) = zipWith (fun a b => g a (f b)) l₁ l₂ := by - induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all - -theorem zipWith_foldr_eq_zip_foldr {f : α → β → γ} (i : δ): - (zipWith f l₁ l₂).foldr g i = (zip l₁ l₂).foldr (fun p r => g (f p.1 p.2) r) i := by - induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all - -theorem zipWith_foldl_eq_zip_foldl {f : α → β → γ} (i : δ): - (zipWith f l₁ l₂).foldl g i = (zip l₁ l₂).foldl (fun r p => g r (f p.1 p.2)) i := by - induction l₁ generalizing i l₂ <;> cases l₂ <;> simp_all - -@[simp] -theorem zipWith_eq_nil_iff {f : α → β → γ} {l l'} : zipWith f l l' = [] ↔ l = [] ∨ l' = [] := by - cases l <;> cases l' <;> simp - -theorem map_zipWith {δ : Type _} (f : α → β) (g : γ → δ → α) (l : List γ) (l' : List δ) : - map f (zipWith g l l') = zipWith (fun x y => f (g x y)) l l' := by - induction l generalizing l' with - | nil => simp - | cons hd tl hl => - · cases l' - · simp - · simp [hl] - -theorem zipWith_distrib_take : (zipWith f l l').take n = zipWith f (l.take n) (l'.take n) := by - induction l generalizing l' n with - | nil => simp - | cons hd tl hl => - cases l' - · simp - · cases n - · simp - · simp [hl] - -theorem zipWith_distrib_drop : (zipWith f l l').drop n = zipWith f (l.drop n) (l'.drop n) := by - induction l generalizing l' n with - | nil => simp - | cons hd tl hl => - · cases l' - · simp - · cases n - · simp - · simp [hl] - theorem zipWith_distrib_tail : (zipWith f l l').tail = zipWith f l.tail l'.tail := by rw [← drop_one]; simp [zipWith_distrib_drop] -theorem zipWith_append (f : α → β → γ) (l la : List α) (l' lb : List β) - (h : l.length = l'.length) : - zipWith f (l ++ la) (l' ++ lb) = zipWith f l l' ++ zipWith f la lb := by - induction l generalizing l' with - | nil => - have : l' = [] := eq_nil_of_length_eq_zero (by simpa using h.symm) - simp [this] - | cons hl tl ih => - cases l' with - | nil => simp at h - | cons head tail => - simp only [length_cons, Nat.succ.injEq] at h - simp [ih _ h] - -/-! ### zip -/ - -@[simp] theorem length_zip (l₁ : List α) (l₂ : List β) : - length (zip l₁ l₂) = min (length l₁) (length l₂) := by - simp [zip] - -theorem zip_map (f : α → γ) (g : β → δ) : - ∀ (l₁ : List α) (l₂ : List β), zip (l₁.map f) (l₂.map g) = (zip l₁ l₂).map (Prod.map f g) - | [], l₂ => rfl - | l₁, [] => by simp only [map, zip_nil_right] - | a :: l₁, b :: l₂ => by - simp only [map, zip_cons_cons, zip_map, Prod.map]; constructor - -theorem zip_map_left (f : α → γ) (l₁ : List α) (l₂ : List β) : - zip (l₁.map f) l₂ = (zip l₁ l₂).map (Prod.map f id) := by rw [← zip_map, map_id] - -theorem zip_map_right (f : β → γ) (l₁ : List α) (l₂ : List β) : - zip l₁ (l₂.map f) = (zip l₁ l₂).map (Prod.map id f) := by rw [← zip_map, map_id] - -theorem zip_append : - ∀ {l₁ r₁ : List α} {l₂ r₂ : List β} (_h : length l₁ = length l₂), - zip (l₁ ++ r₁) (l₂ ++ r₂) = zip l₁ l₂ ++ zip r₁ r₂ - | [], r₁, l₂, r₂, h => by simp only [eq_nil_of_length_eq_zero h.symm]; rfl - | l₁, r₁, [], r₂, h => by simp only [eq_nil_of_length_eq_zero h]; rfl - | a :: l₁, r₁, b :: l₂, r₂, h => by - simp only [cons_append, zip_cons_cons, zip_append (Nat.succ.inj h)] - -theorem zip_map' (f : α → β) (g : α → γ) : - ∀ l : List α, zip (l.map f) (l.map g) = l.map fun a => (f a, g a) - | [] => rfl - | a :: l => by simp only [map, zip_cons_cons, zip_map'] - -theorem of_mem_zip {a b} : ∀ {l₁ : List α} {l₂ : List β}, (a, b) ∈ zip l₁ l₂ → a ∈ l₁ ∧ b ∈ l₂ - | _ :: l₁, _ :: l₂, h => by - cases h - case head => simp - case tail h => - · have := of_mem_zip h - exact ⟨Mem.tail _ this.1, Mem.tail _ this.2⟩ - -theorem map_fst_zip : - ∀ (l₁ : List α) (l₂ : List β), l₁.length ≤ l₂.length → map Prod.fst (zip l₁ l₂) = l₁ - | [], bs, _ => rfl - | _ :: as, _ :: bs, h => by - simp [Nat.succ_le_succ_iff] at h - show _ :: map Prod.fst (zip as bs) = _ :: as - rw [map_fst_zip as bs h] - | a :: as, [], h => by simp at h - -theorem map_snd_zip : - ∀ (l₁ : List α) (l₂ : List β), l₂.length ≤ l₁.length → map Prod.snd (zip l₁ l₂) = l₂ - | _, [], _ => by - rw [zip_nil_right] - rfl - | [], b :: bs, h => by simp at h - | a :: as, b :: bs, h => by - simp [Nat.succ_le_succ_iff] at h - show _ :: map Prod.snd (zip as bs) = _ :: bs - rw [map_snd_zip as bs h] - -/-! ### join -/ - -theorem mem_join : ∀ {L : List (List α)}, a ∈ L.join ↔ ∃ l, l ∈ L ∧ a ∈ l - | [] => by simp - | b :: l => by simp [mem_join, or_and_right, exists_or] - -theorem exists_of_mem_join : a ∈ join L → ∃ l, l ∈ L ∧ a ∈ l := mem_join.1 - -theorem mem_join_of_mem (lL : l ∈ L) (al : a ∈ l) : a ∈ join L := mem_join.2 ⟨l, lL, al⟩ - -/-! ### bind -/ - -theorem mem_bind {f : α → List β} {b} {l : List α} : b ∈ l.bind f ↔ ∃ a, a ∈ l ∧ b ∈ f a := by - simp [List.bind, mem_join] - exact ⟨fun ⟨_, ⟨a, h₁, rfl⟩, h₂⟩ => ⟨a, h₁, h₂⟩, fun ⟨a, h₁, h₂⟩ => ⟨_, ⟨a, h₁, rfl⟩, h₂⟩⟩ - -theorem exists_of_mem_bind {b : β} {l : List α} {f : α → List β} : - b ∈ List.bind l f → ∃ a, a ∈ l ∧ b ∈ f a := mem_bind.1 - -theorem mem_bind_of_mem {b : β} {l : List α} {f : α → List β} {a} (al : a ∈ l) (h : b ∈ f a) : - b ∈ List.bind l f := mem_bind.2 ⟨a, al, h⟩ - -theorem bind_map (f : β → γ) (g : α → List β) : - ∀ l : List α, map f (l.bind g) = l.bind fun a => (g a).map f - | [] => rfl - | a::l => by simp only [cons_bind, map_append, bind_map _ _ l] - -/-! ### set-theoretic notation of Lists -/ - -@[simp] theorem empty_eq : (∅ : List α) = [] := rfl - -/-! ### bounded quantifiers over Lists -/ - -theorem exists_mem_nil (p : α → Prop) : ¬∃ x ∈ @nil α, p x := nofun - -theorem forall_mem_nil (p : α → Prop) : ∀ x ∈ @nil α, p x := nofun - -theorem exists_mem_cons {p : α → Prop} {a : α} {l : List α} : - (∃ x ∈ a :: l, p x) ↔ p a ∨ ∃ x ∈ l, p x := by simp - -theorem forall_mem_singleton {p : α → Prop} {a : α} : (∀ x ∈ [a], p x) ↔ p a := by - simp only [mem_singleton, forall_eq] - -theorem forall_mem_append {p : α → Prop} {l₁ l₂ : List α} : - (∀ x ∈ l₁ ++ l₂, p x) ↔ (∀ x ∈ l₁, p x) ∧ (∀ x ∈ l₂, p x) := by - simp only [mem_append, or_imp, forall_and] - /-! ### List subset -/ theorem subset_def {l₁ l₂ : List α} : l₁ ⊆ l₂ ↔ ∀ {a : α}, a ∈ l₁ → a ∈ l₂ := .rfl @@ -452,48 +78,6 @@ theorem subset_nil {l : List α} : l ⊆ [] ↔ l = [] := theorem map_subset {l₁ l₂ : List α} (f : α → β) (H : l₁ ⊆ l₂) : map f l₁ ⊆ map f l₂ := fun x => by simp only [mem_map]; exact .imp fun a => .imp_left (@H _) -/-! ### replicate -/ - -theorem replicate_succ (a : α) (n) : replicate (n+1) a = a :: replicate n a := rfl - -theorem mem_replicate {a b : α} : ∀ {n}, b ∈ replicate n a ↔ n ≠ 0 ∧ b = a - | 0 => by simp - | n+1 => by simp [mem_replicate, Nat.succ_ne_zero] - -theorem eq_of_mem_replicate {a b : α} {n} (h : b ∈ replicate n a) : b = a := (mem_replicate.1 h).2 - -theorem eq_replicate_of_mem {a : α} : - ∀ {l : List α}, (∀ b ∈ l, b = a) → l = replicate l.length a - | [], _ => rfl - | b :: l, H => by - let ⟨rfl, H₂⟩ := forall_mem_cons.1 H - rw [length_cons, replicate, ← eq_replicate_of_mem H₂] - -theorem eq_replicate {a : α} {n} {l : List α} : - l = replicate n a ↔ length l = n ∧ ∀ b ∈ l, b = a := - ⟨fun h => h ▸ ⟨length_replicate .., fun _ => eq_of_mem_replicate⟩, - fun ⟨e, al⟩ => e ▸ eq_replicate_of_mem al⟩ - -/-! ### getLast -/ - -theorem getLast_cons' {a : α} {l : List α} : ∀ (h₁ : a :: l ≠ nil) (h₂ : l ≠ nil), - getLast (a :: l) h₁ = getLast l h₂ := by - induction l <;> intros; {contradiction}; rfl - -@[simp] theorem getLast_append {a : α} : ∀ (l : List α) h, getLast (l ++ [a]) h = a - | [], _ => rfl - | a::t, h => by - simp [getLast_cons' _ fun H => cons_ne_nil _ _ (append_eq_nil.1 H).2, getLast_append t] - -theorem getLast_concat : (h : concat l a ≠ []) → getLast (concat l a) h = a := - concat_eq_append .. ▸ getLast_append _ - -theorem eq_nil_or_concat : ∀ l : List α, l = [] ∨ ∃ L b, l = L ++ [b] - | [] => .inl rfl - | a::l => match l, eq_nil_or_concat l with - | _, .inl rfl => .inr ⟨[], a, rfl⟩ - | _, .inr ⟨L, b, rfl⟩ => .inr ⟨a::L, b, rfl⟩ - /-! ### sublists -/ @[simp] theorem nil_sublist : ∀ l : List α, [] <+ l @@ -646,19 +230,8 @@ theorem isSublist_iff_sublist [BEq α] [LawfulBEq α] {l₁ l₂ : List α} : instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+ l₂) := decidable_of_iff (l₁.isSublist l₂) isSublist_iff_sublist -/-! ### head -/ - -theorem head!_of_head? [Inhabited α] : ∀ {l : List α}, head? l = some a → head! l = a - | _a::_l, rfl => rfl - -theorem head?_eq_head : ∀ l h, @head? α l = some (head l h) - | _::_, _ => rfl - /-! ### tail -/ -@[simp] theorem tailD_eq_tail? (l l' : List α) : tailD l l' = (tail? l).getD l' := by - cases l <;> rfl - theorem tail_eq_tailD (l) : @tail α l = tailD l [] := by cases l <;> rfl theorem tail_eq_tail? (l) : @tail α l = (tail? l).getD [] := by simp [tail_eq_tailD] @@ -668,110 +241,10 @@ theorem tail_eq_tail? (l) : @tail α l = (tail? l).getD [] := by simp [tail_eq_t @[simp] theorem next?_nil : @next? α [] = none := rfl @[simp] theorem next?_cons (a l) : @next? α (a :: l) = some (a, l) := rfl -/-! ### getLast -/ - -@[simp] theorem getLastD_nil (a) : @getLastD α [] a = a := rfl -@[simp] theorem getLastD_cons (a b l) : @getLastD α (b::l) a = getLastD l b := by cases l <;> rfl - -theorem getLast_eq_getLastD (a l h) : @getLast α (a::l) h = getLastD l a := by - cases l <;> rfl - -theorem getLastD_eq_getLast? (a l) : @getLastD α l a = (getLast? l).getD a := by - cases l <;> rfl - -@[simp] theorem getLast_singleton (a h) : @getLast α [a] h = a := rfl - -theorem getLast!_cons [Inhabited α] : @getLast! α _ (a::l) = getLastD l a := by - simp [getLast!, getLast_eq_getLastD] - -theorem getLast?_cons : @getLast? α (a::l) = getLastD l a := by - simp [getLast?, getLast_eq_getLastD] - -@[simp] theorem getLast?_singleton (a : α) : getLast? [a] = a := rfl - -theorem getLast_mem : ∀ {l : List α} (h : l ≠ []), getLast l h ∈ l - | [], h => absurd rfl h - | [_], _ => .head .. - | _::a::l, _ => .tail _ <| getLast_mem (cons_ne_nil a l) - -theorem getLastD_mem_cons : ∀ (l : List α) (a : α), getLastD l a ∈ a::l - | [], _ => .head .. - | _::_, _ => .tail _ <| getLast_mem _ - -@[simp] theorem getLast?_reverse (l : List α) : l.reverse.getLast? = l.head? := by cases l <;> simp - -@[simp] theorem head?_reverse (l : List α) : l.reverse.head? = l.getLast? := by - rw [← getLast?_reverse, reverse_reverse] - -/-! ### dropLast -/ - -/-! NB: `dropLast` is the specification for `Array.pop`, so theorems about `List.dropLast` -are often used for theorems about `Array.pop`. -/ - -theorem dropLast_cons_of_ne_nil {α : Type u} {x : α} - {l : List α} (h : l ≠ []) : (x :: l).dropLast = x :: l.dropLast := by - simp [dropLast, h] - -@[simp] theorem dropLast_append_of_ne_nil {α : Type u} {l : List α} : - ∀ (l' : List α) (_ : l ≠ []), (l' ++ l).dropLast = l' ++ l.dropLast - | [], _ => by simp only [nil_append] - | a :: l', h => by - rw [cons_append, dropLast, dropLast_append_of_ne_nil l' h, cons_append] - simp [h] - -theorem dropLast_append_cons : dropLast (l₁ ++ b::l₂) = l₁ ++ dropLast (b::l₂) := by - simp only [ne_eq, not_false_eq_true, dropLast_append_of_ne_nil] - -@[simp 1100] theorem dropLast_concat : dropLast (l₁ ++ [b]) = l₁ := by simp - -@[simp] theorem length_dropLast : ∀ (xs : List α), xs.dropLast.length = xs.length - 1 - | [] => rfl - | x::xs => by simp - -@[simp] theorem get_dropLast : ∀ (xs : List α) (i : Fin xs.dropLast.length), - xs.dropLast.get i = xs.get ⟨i, Nat.lt_of_lt_of_le i.isLt (length_dropLast .. ▸ Nat.pred_le _)⟩ - | _::_::_, ⟨0, _⟩ => rfl - | _::_::_, ⟨i+1, _⟩ => get_dropLast _ ⟨i, _⟩ - -/-! ### nth element -/ +/-! ### get? -/ theorem get_eq_iff : List.get l n = x ↔ l.get? n.1 = some x := by simp [get?_eq_some] -@[simp] theorem get_cons_cons_one : (a₁ :: a₂ :: as).get (1 : Fin (as.length + 2)) = a₂ := rfl - -theorem get!_cons_succ [Inhabited α] (l : List α) (a : α) (n : Nat) : - (a::l).get! (n+1) = get! l n := rfl - -theorem get!_cons_zero [Inhabited α] (l : List α) (a : α) : (a::l).get! 0 = a := rfl - -theorem get!_nil [Inhabited α] (n : Nat) : [].get! n = (default : α) := rfl - -theorem get!_len_le [Inhabited α] : ∀ {l : List α} {n}, length l ≤ n → l.get! n = (default : α) - | [], _, _ => rfl - | _ :: l, _+1, h => get!_len_le (l := l) <| Nat.le_of_succ_le_succ h - -theorem get?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n, l.get? n = some a := - let ⟨⟨n, _⟩, e⟩ := get_of_mem h; ⟨n, e ▸ get?_eq_get _⟩ - -theorem get?_mem {l : List α} {n a} (e : l.get? n = some a) : a ∈ l := - let ⟨_, e⟩ := get?_eq_some.1 e; e ▸ get_mem .. - --- TODO(Mario): move somewhere else -theorem Fin.exists_iff (p : Fin n → Prop) : (∃ i, p i) ↔ ∃ i h, p ⟨i, h⟩ := - ⟨fun ⟨i, h⟩ => ⟨i.1, i.2, h⟩, fun ⟨i, hi, h⟩ => ⟨⟨i, hi⟩, h⟩⟩ - -theorem mem_iff_get? {a} {l : List α} : a ∈ l ↔ ∃ n, l.get? n = some a := by - simp [get?_eq_some, Fin.exists_iff, mem_iff_get] - -theorem get?_zero (l : List α) : l.get? 0 = l.head? := by cases l <;> rfl - -@[simp] theorem getElem_eq_get (l : List α) (i : Nat) (h) : l[i]'h = l.get ⟨i, h⟩ := rfl - -@[simp] theorem getElem?_eq_get? (l : List α) (i : Nat) : l[i]? = l.get? i := by - simp only [getElem?]; split - · exact (get?_eq_get ‹_›).symm - · exact (get?_eq_none.2 <| Nat.not_lt.1 ‹_›).symm - theorem get?_inj (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs.get? i = xs.get? j) : i = j := by induction xs generalizing i j with @@ -789,232 +262,8 @@ theorem get?_inj rw [mem_iff_get?] exact ⟨_, h₂⟩; exact ⟨_ , h₂.symm⟩ -/-- -If one has `get l i hi` in a formula and `h : l = l'`, one can not `rw h` in the formula as -`hi` gives `i < l.length` and not `i < l'.length`. The theorem `get_of_eq` can be used to make -such a rewrite, with `rw (get_of_eq h)`. --/ -theorem get_of_eq {l l' : List α} (h : l = l') (i : Fin l.length) : - get l i = get l' ⟨i, h ▸ i.2⟩ := by cases h; rfl - -@[simp] theorem get_singleton (a : α) : (n : Fin 1) → get [a] n = a - | ⟨0, _⟩ => rfl - -theorem get_mk_zero : ∀ {l : List α} (h : 0 < l.length), l.get ⟨0, h⟩ = l.head (length_pos.mp h) - | _::_, _ => rfl - -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 - rw [length_append] at h₂ - exact Nat.sub_lt_left_of_lt_add h₁ h₂ - -theorem get_append_right' {l₁ l₂ : List α} {n : Nat} (h₁ : l₁.length ≤ n) (h₂) : - (l₁ ++ l₂).get ⟨n, h₂⟩ = l₂.get ⟨n - l₁.length, get_append_right_aux h₁ h₂⟩ := -Option.some.inj <| by rw [← get?_eq_get, ← get?_eq_get, get?_append_right h₁] - -theorem get_of_append_proof {l : List α} - (eq : l = l₁ ++ a :: l₂) (h : l₁.length = n) : n < length l := eq ▸ h ▸ by simp_arith - -theorem get_of_append {l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.length = n) : - l.get ⟨n, get_of_append_proof eq h⟩ = a := Option.some.inj <| by - rw [← get?_eq_get, eq, get?_append_right (h ▸ Nat.le_refl _), h, Nat.sub_self]; rfl - -@[simp] theorem get_replicate (a : α) {n : Nat} (m : Fin _) : (replicate n a).get m = a := - eq_of_mem_replicate (get_mem _ _ _) - -@[simp] theorem getLastD_concat (a b l) : @getLastD α (l ++ [b]) a = b := by - rw [getLastD_eq_getLast?, getLast?_concat]; rfl - -theorem get_cons_length (x : α) (xs : List α) (n : Nat) (h : n = xs.length) : - (x :: xs).get ⟨n, by simp [h]⟩ = (x :: xs).getLast (cons_ne_nil x xs) := by - rw [getLast_eq_get]; cases h; rfl - -theorem get!_of_get? [Inhabited α] : ∀ {l : List α} {n}, get? l n = some a → get! l n = a - | _a::_, 0, rfl => rfl - | _::l, _+1, e => get!_of_get? (l := l) e - -@[simp] theorem get!_eq_getD [Inhabited α] : ∀ (l : List α) n, l.get! n = l.getD n default - | [], _ => rfl - | _a::_, 0 => rfl - | _a::l, n+1 => get!_eq_getD l n - -/-! ### take -/ - -alias take_succ_cons := take_cons_succ - -@[simp] theorem length_take : ∀ (i : Nat) (l : List α), length (take i l) = min i (length l) - | 0, l => by simp [Nat.zero_min] - | succ n, [] => by simp [Nat.min_zero] - | succ n, _ :: l => by simp [Nat.succ_min_succ, length_take] - -theorem length_take_le (n) (l : List α) : length (take n l) ≤ n := by simp [Nat.min_le_left] - -theorem length_take_le' (n) (l : List α) : length (take n l) ≤ l.length := - by simp [Nat.min_le_right] - -theorem length_take_of_le (h : n ≤ length l) : length (take n l) = n := by simp [Nat.min_eq_left h] - -theorem take_all_of_le {n} {l : List α} (h : length l ≤ n) : take n l = l := - take_length_le h - -@[simp] -theorem take_left : ∀ l₁ l₂ : List α, take (length l₁) (l₁ ++ l₂) = l₁ - | [], _ => rfl - | a :: l₁, l₂ => congrArg (cons a) (take_left l₁ l₂) - -theorem take_left' {l₁ l₂ : List α} {n} (h : length l₁ = n) : take n (l₁ ++ l₂) = l₁ := by - rw [← h]; apply take_left - -theorem take_take : ∀ (n m) (l : List α), take n (take m l) = take (min n m) l - | n, 0, l => by rw [Nat.min_zero, take_zero, take_nil] - | 0, m, l => by rw [Nat.zero_min, take_zero, take_zero] - | succ n, succ m, nil => by simp only [take_nil] - | succ n, succ m, a :: l => by - simp only [take, succ_min_succ, take_take n m l] - -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] - | succ n, succ m => by simp [succ_min_succ, take_replicate] - -theorem map_take (f : α → β) : - ∀ (L : List α) (i : Nat), (L.take i).map f = (L.map f).take i - | [], i => by simp - | _, 0 => by simp - | h :: t, n + 1 => by dsimp; rw [map_take f t n] - -/-- Taking the first `n` elements in `l₁ ++ l₂` is the same as appending the first `n` elements -of `l₁` to the first `n - l₁.length` elements of `l₂`. -/ -theorem take_append_eq_append_take {l₁ l₂ : List α} {n : Nat} : - take n (l₁ ++ l₂) = take n l₁ ++ take (n - l₁.length) l₂ := by - induction l₁ generalizing n; {simp} - cases n <;> simp [*] - -theorem take_append_of_le_length {l₁ l₂ : List α} {n : Nat} (h : n ≤ l₁.length) : - (l₁ ++ l₂).take n = l₁.take n := by - simp [take_append_eq_append_take, Nat.sub_eq_zero_of_le h] - -/-- Taking the first `l₁.length + i` elements in `l₁ ++ l₂` is the same as appending the first -`i` elements of `l₂` to `l₁`. -/ -theorem take_append {l₁ l₂ : List α} (i : Nat) : - take (l₁.length + i) (l₁ ++ l₂) = l₁ ++ take i l₂ := by - rw [take_append_eq_append_take, take_all_of_le (Nat.le_add_right _ _), Nat.add_sub_cancel_left] - -/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of -length `> i`. Version designed to rewrite from the big list to the small list. -/ -theorem get_take (L : List α) {i j : Nat} (hi : i < L.length) (hj : i < j) : - get L ⟨i, hi⟩ = get (L.take j) ⟨i, length_take .. ▸ Nat.lt_min.mpr ⟨hj, hi⟩⟩ := - get_of_eq (take_append_drop j L).symm _ ▸ get_append .. - -/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of -length `> i`. Version designed to rewrite from the small list to the big list. -/ -theorem get_take' (L : List α) {j i} : - get (L.take j) i = - get L ⟨i.1, Nat.lt_of_lt_of_le i.2 (length_take_le' _ _)⟩ := by - let ⟨i, hi⟩ := i; rw [length_take, Nat.lt_min] at hi; rw [get_take L _ hi.1] - -theorem get?_take {l : List α} {n m : Nat} (h : m < n) : (l.take n).get? m = l.get? m := by - induction n generalizing l m with - | zero => - exact absurd h (Nat.not_lt_of_le m.zero_le) - | succ _ hn => - cases l with - | nil => simp only [take_nil] - | cons hd tl => - cases m - · simp only [get?, take] - · simpa only using hn (Nat.lt_of_succ_lt_succ h) - -theorem get?_take_eq_none {l : List α} {n m : Nat} (h : n ≤ m) : - (l.take n).get? m = none := - get?_eq_none.mpr <| Nat.le_trans (length_take_le _ _) h - -theorem get?_take_eq_if {l : List α} {n m : Nat} : - (l.take n).get? m = if m < n then l.get? m else none := by - split - · next h => exact get?_take h - · next h => exact get?_take_eq_none (Nat.le_of_not_lt h) - -@[simp] -theorem nth_take_of_succ {l : List α} {n : Nat} : (l.take (n + 1)).get? n = l.get? n := - get?_take (Nat.lt_succ_self n) - -theorem take_succ {l : List α} {n : Nat} : l.take (n + 1) = l.take n ++ (l.get? n).toList := by - induction l generalizing n with - | nil => - simp only [Option.toList, get?, take_nil, append_nil] - | cons hd tl hl => - cases n - · simp only [Option.toList, get?, eq_self_iff_true, take, nil_append] - · simp only [hl, cons_append, get?, eq_self_iff_true, take] - -@[simp] -theorem take_eq_nil_iff {l : List α} {k : Nat} : l.take k = [] ↔ l = [] ∨ k = 0 := by - cases l <;> cases k <;> simp [Nat.succ_ne_zero] - -@[simp] -theorem take_eq_take : - ∀ {l : List α} {m n : Nat}, l.take m = l.take n ↔ min m l.length = min n l.length - | [], m, n => by simp [Nat.min_zero] - | _ :: xs, 0, 0 => by simp - | x :: xs, m + 1, 0 => by simp [Nat.zero_min, succ_min_succ] - | x :: xs, 0, n + 1 => by simp [Nat.zero_min, succ_min_succ] - | x :: xs, m + 1, n + 1 => by simp [succ_min_succ, take_eq_take] - -theorem take_add (l : List α) (m n : Nat) : l.take (m + n) = l.take m ++ (l.drop m).take n := by - suffices take (m + n) (take m l ++ drop m l) = take m l ++ take n (drop m l) by - rw [take_append_drop] at this - assumption - rw [take_append_eq_append_take, take_all_of_le, append_right_inj] - · simp only [take_eq_take, length_take, length_drop] - omega - apply Nat.le_trans (m := m) - · apply length_take_le - · apply Nat.le_add_right - -theorem take_eq_nil_of_eq_nil : ∀ {as : List α} {i}, as = [] → as.take i = [] - | _, _, rfl => take_nil - -theorem ne_nil_of_take_ne_nil {as : List α} {i : Nat} (h: as.take i ≠ []) : as ≠ [] := - mt take_eq_nil_of_eq_nil h - -theorem dropLast_eq_take (l : List α) : l.dropLast = l.take l.length.pred := by - cases l with - | nil => simp [dropLast] - | cons x l => - induction l generalizing x with - | nil => simp [dropLast] - | cons hd tl hl => simp [dropLast, hl] - -theorem dropLast_take {n : Nat} {l : List α} (h : n < l.length) : - (l.take n).dropLast = l.take n.pred := by - simp only [dropLast_eq_take, length_take, Nat.le_of_lt h, take_take, pred_le, Nat.min_eq_left] - -theorem map_eq_append_split {f : α → β} {l : List α} {s₁ s₂ : List β} - (h : map f l = s₁ ++ s₂) : ∃ l₁ l₂, l = l₁ ++ l₂ ∧ map f l₁ = s₁ ∧ map f l₂ = s₂ := by - have := h - rw [← take_append_drop (length s₁) l] at this ⊢ - rw [map_append] at this - refine ⟨_, _, rfl, append_inj this ?_⟩ - rw [length_map, length_take, Nat.min_eq_left] - rw [← length_map l f, h, length_append] - apply Nat.le_add_right - /-! ### drop -/ -@[simp] -theorem drop_eq_nil_iff_le {l : List α} {k : Nat} : l.drop k = [] ↔ l.length ≤ k := by - refine' ⟨fun h => _, drop_eq_nil_of_le⟩ - induction k generalizing l with - | zero => - simp only [drop] at h - simp [h] - | succ k hk => - cases l - · simp - · simp only [drop] at h - simpa [Nat.succ_le_succ_iff] using hk h - theorem tail_drop (l : List α) (n : Nat) : (l.drop n).tail = l.drop (n + 1) := by induction l generalizing n with | nil => simp @@ -1023,141 +272,6 @@ theorem tail_drop (l : List α) (n : Nat) : (l.drop n).tail = l.drop (n + 1) := · simp · simp [hl] -theorem drop_length_cons {l : List α} (h : l ≠ []) (a : α) : - (a :: l).drop l.length = [l.getLast h] := by - induction l generalizing a with - | nil => - cases h rfl - | cons y l ih => - simp only [drop, length] - by_cases h₁ : l = [] - · simp [h₁] - rw [getLast_cons' _ h₁] - exact ih h₁ y - -/-- Dropping the elements up to `n` in `l₁ ++ l₂` is the same as dropping the elements up to `n` -in `l₁`, dropping the elements up to `n - l₁.length` in `l₂`, and appending them. -/ -theorem drop_append_eq_append_drop {l₁ l₂ : List α} {n : Nat} : - drop n (l₁ ++ l₂) = drop n l₁ ++ drop (n - l₁.length) l₂ := by - induction l₁ generalizing n; · simp - cases n <;> simp [*] - -theorem drop_append_of_le_length {l₁ l₂ : List α} {n : Nat} (h : n ≤ l₁.length) : - (l₁ ++ l₂).drop n = l₁.drop n ++ l₂ := by - simp [drop_append_eq_append_drop, Nat.sub_eq_zero_of_le h] - - -/-- Dropping the elements up to `l₁.length + i` in `l₁ + l₂` is the same as dropping the elements -up to `i` in `l₂`. -/ -@[simp] -theorem drop_append {l₁ l₂ : List α} (i : Nat) : drop (l₁.length + i) (l₁ ++ l₂) = drop i l₂ := by - rw [drop_append_eq_append_drop, drop_eq_nil_of_le] <;> - simp [Nat.add_sub_cancel_left, Nat.le_add_right] - -theorem drop_sizeOf_le [SizeOf α] (l : List α) (n : Nat) : sizeOf (l.drop n) ≤ sizeOf l := by - induction l generalizing n with - | nil => rw [drop_nil]; apply Nat.le_refl - | cons _ _ lih => - induction n with - | zero => apply Nat.le_refl - | succ n => - exact Trans.trans (lih _) (Nat.le_add_left _ _) - -theorem lt_length_drop (L : List α) {i j : Nat} (h : i + j < L.length) : j < (L.drop i).length := by - have A : i < L.length := Nat.lt_of_le_of_lt (Nat.le.intro rfl) h - rw [(take_append_drop i L).symm] at h - simpa only [Nat.le_of_lt A, Nat.min_eq_left, Nat.add_lt_add_iff_left, length_take, - length_append] using h - -/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by -dropping the first `i` elements. Version designed to rewrite from the big list to the small list. -/ -theorem get_drop (L : List α) {i j : Nat} (h : i + j < L.length) : - get L ⟨i + j, h⟩ = get (L.drop i) ⟨j, lt_length_drop L h⟩ := by - have : i ≤ L.length := Nat.le_trans (Nat.le_add_right _ _) (Nat.le_of_lt h) - rw [get_of_eq (take_append_drop i L).symm ⟨i + j, h⟩, get_append_right'] <;> - simp [Nat.min_eq_left this, Nat.add_sub_cancel_left, Nat.le_add_right] - -/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by -dropping the first `i` elements. Version designed to rewrite from the small list to the big list. -/ -theorem get_drop' (L : List α) {i j} : - get (L.drop i) j = get L ⟨i + j, by - rw [Nat.add_comm] - exact Nat.add_lt_of_lt_sub (length_drop i L ▸ j.2)⟩ := by - rw [get_drop] - -@[simp] -theorem get?_drop (L : List α) (i j : Nat) : get? (L.drop i) j = get? L (i + j) := by - ext - simp only [get?_eq_some, get_drop', Option.mem_def] - constructor <;> intro ⟨h, ha⟩ - · exact ⟨_, ha⟩ - · refine ⟨?_, ha⟩ - rw [length_drop] - rw [Nat.add_comm] at h - apply Nat.lt_sub_of_add_lt h - -@[simp] theorem drop_drop (n : Nat) : ∀ (m) (l : List α), drop n (drop m l) = drop (n + m) l - | m, [] => by simp - | 0, l => by simp - | m + 1, a :: l => - calc - drop n (drop (m + 1) (a :: l)) = drop n (drop m l) := rfl - _ = drop (n + m) l := drop_drop n m l - _ = drop (n + (m + 1)) (a :: l) := rfl - -theorem take_drop : ∀ (m n : Nat) (l : List α), take n (drop m l) = drop m (take (m + n) l) - | 0, _, _ => by simp - | _, _, [] => by simp - | _+1, _, _ :: _ => by simpa [Nat.succ_add, take_succ_cons, drop_succ_cons] using take_drop .. - -theorem drop_take : ∀ (m n : Nat) (l : List α), drop n (take m l) = take (m - n) (drop n l) - | 0, _, _ => by simp - | _, 0, _ => by simp - | _, _, [] => by simp - | _+1, _+1, _ :: _ => by simpa [take_succ_cons, drop_succ_cons] using drop_take .. - -theorem map_drop (f : α → β) : - ∀ (L : List α) (i : Nat), (L.drop i).map f = (L.map f).drop i - | [], i => by simp - | L, 0 => by simp - | h :: t, n + 1 => by - dsimp - rw [map_drop f t] - -theorem reverse_take {α} {xs : List α} (n : Nat) (h : n ≤ xs.length) : - xs.reverse.take n = (xs.drop (xs.length - n)).reverse := by - induction xs generalizing n <;> - simp only [reverse_cons, drop, reverse_nil, Nat.zero_sub, length, take_nil] - next xs_hd xs_tl xs_ih => - cases Nat.lt_or_eq_of_le h with - | inl h' => - have h' := Nat.le_of_succ_le_succ h' - rw [take_append_of_le_length, xs_ih _ h'] - rw [show xs_tl.length + 1 - n = succ (xs_tl.length - n) from _, drop] - · rwa [succ_eq_add_one, Nat.sub_add_comm] - · rwa [length_reverse] - | inr h' => - subst h' - rw [length, Nat.sub_self, drop] - suffices xs_tl.length + 1 = (xs_tl.reverse ++ [xs_hd]).length by - rw [this, take_length, reverse_cons] - rw [length_append, length_reverse] - rfl - -@[simp] -theorem get_cons_drop : ∀ (l : List α) i, get l i :: drop (i + 1) l = drop i l - | _::_, ⟨0, _⟩ => rfl - | _::_, ⟨i+1, _⟩ => get_cons_drop _ ⟨i, _⟩ - -theorem drop_eq_get_cons {n} {l : List α} (h) : drop n l = get l ⟨n, h⟩ :: drop (n + 1) l := - (get_cons_drop _ ⟨n, h⟩).symm - -theorem drop_eq_nil_of_eq_nil : ∀ {as : List α} {i}, as = [] → as.drop i = [] - | _, _, rfl => drop_nil - -theorem ne_nil_of_drop_ne_nil {as : List α} {i : Nat} (h: as.drop i ≠ []) : as ≠ [] := - mt drop_eq_nil_of_eq_nil h - /-! ### modifyNth -/ theorem modifyNthTail_id : ∀ n (l : List α), l.modifyNthTail id n = l @@ -1282,32 +396,6 @@ 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_eq_nil (l : List α) (n : Nat) (a : α) : l.set n a = [] ↔ l = [] := by - cases l <;> cases n <;> simp only [set] - -theorem set_comm (a b : α) : ∀ {n m : Nat} (l : List α), n ≠ m → - (l.set n a).set m b = (l.set m b).set n a - | _, _, [], _ => by simp - | n+1, 0, _ :: _, _ => by simp [set] - | 0, m+1, _ :: _, _ => by simp [set] - | n+1, m+1, x :: t, h => - congrArg _ <| set_comm a b t fun h' => h <| Nat.succ_inj'.mpr h' - -@[simp] -theorem set_set (a b : α) : ∀ (l : List α) (n : Nat), (l.set n a).set n b = l.set n b - | [], _ => by simp - | _ :: _, 0 => by simp [set] - | _ :: _, _+1 => by simp [set, set_set] - -theorem get_set (a : α) {m n} (l : List α) (h) : - (set l m a).get ⟨n, h⟩ = if m = n then a else l.get ⟨n, length_set .. ▸ h⟩ := by - if h : m = n then subst m; simp else simp [h] - -theorem mem_or_eq_of_mem_set : ∀ {l : List α} {n : Nat} {a b : α}, a ∈ l.set n b → a ∈ l ∨ a = b - | _ :: _, 0, _, _, h => ((mem_cons ..).1 h).symm.imp_left (.tail _) - | _ :: _, _+1, _, _, .head .. => .inl (.head ..) - | _ :: _, _+1, _, _, .tail _ h => (mem_or_eq_of_mem_set h).imp_left (.tail _) - theorem drop_set_of_lt (a : α) {n m : Nat} (l : List α) (h : n < m) : (l.set n a).drop m = l.drop m := List.ext fun i => by rw [get?_drop, get?_drop, get?_set_ne _ _ (by omega)] @@ -1336,91 +424,6 @@ theorem length_eraseIdx : ∀ {l i}, i < length l → length (@eraseIdx α l i) @[simp] theorem length_tail (l : List α) : length (tail l) = length l - 1 := by cases l <;> rfl -/-! ### all / any -/ - -@[simp] theorem contains_nil [BEq α] : ([] : List α).contains a = false := rfl - -@[simp] theorem contains_cons [BEq α] : - (a :: as : List α).contains x = (x == a || as.contains x) := by - simp only [contains, elem] - split <;> simp_all - -theorem contains_eq_any_beq [BEq α] (l : List α) (a : α) : l.contains a = l.any (a == ·) := by - induction l with simp | cons b l => cases a == b <;> simp [*] - -theorem not_all_eq_any_not (l : List α) (p : α → Bool) : (!l.all p) = l.any fun a => !p a := by - induction l with simp | cons _ _ ih => rw [ih] - -theorem not_any_eq_all_not (l : List α) (p : α → Bool) : (!l.any p) = l.all fun a => !p a := by - induction l with simp | cons _ _ ih => rw [ih] - -theorem or_all_distrib_left (l : List α) (p : α → Bool) (q : Bool) : - (q || l.all p) = l.all fun a => q || p a := by - induction l with simp | cons _ _ ih => rw [Bool.or_and_distrib_left, ih] - -theorem or_all_distrib_right (l : List α) (p : α → Bool) (q : Bool) : - (l.all p || q) = l.all fun a => p a || q := by - induction l with simp | cons _ _ ih => rw [Bool.or_and_distrib_right, ih] - -theorem and_any_distrib_left (l : List α) (p : α → Bool) (q : Bool) : - (q && l.any p) = l.any fun a => q && p a := by - induction l with simp | cons _ _ ih => rw [Bool.and_or_distrib_left, ih] - -theorem and_any_distrib_right (l : List α) (p : α → Bool) (q : Bool) : - (l.any p && q) = l.any fun a => p a && q := by - induction l with simp | cons _ _ ih => rw [Bool.and_or_distrib_right, ih] - -theorem any_eq_not_all_not (l : List α) (p : α → Bool) : l.any p = !l.all (!p .) := by - simp only [not_all_eq_any_not, Bool.not_not] - -theorem all_eq_not_any_not (l : List α) (p : α → Bool) : l.all p = !l.any (!p .) := by - simp only [not_any_eq_all_not, Bool.not_not] - -/-! ### reverse -/ - -@[simp] theorem mem_reverseAux {x : α} : ∀ {as bs}, x ∈ reverseAux as bs ↔ x ∈ as ∨ x ∈ bs - | [], _ => ⟨.inr, fun | .inr h => h⟩ - | a :: _, _ => by rw [reverseAux, mem_cons, or_assoc, or_left_comm, mem_reverseAux, mem_cons] - -@[simp] theorem mem_reverse {x : α} {as : List α} : x ∈ reverse as ↔ x ∈ as := by simp [reverse] - -/-! ### insert -/ - -section insert -variable [BEq α] [LawfulBEq α] - -@[simp] theorem insert_of_mem {l : List α} (h : a ∈ l) : l.insert a = l := by - simp [List.insert, h] - -@[simp] theorem insert_of_not_mem {l : List α} (h : a ∉ l) : l.insert a = a :: l := by - simp [List.insert, h] - -@[simp] theorem mem_insert_iff {l : List α} : a ∈ l.insert b ↔ a = b ∨ a ∈ l := by - if h : b ∈ l then - rw [insert_of_mem h] - constructor; {apply Or.inr} - intro - | Or.inl h' => rw [h']; exact h - | Or.inr h' => exact h' - else rw [insert_of_not_mem h, mem_cons] - -@[simp 1100] theorem mem_insert_self (a : α) (l : List α) : a ∈ l.insert a := - mem_insert_iff.2 (Or.inl rfl) - -theorem mem_insert_of_mem {l : List α} (h : a ∈ l) : a ∈ l.insert b := - mem_insert_iff.2 (Or.inr h) - -theorem eq_or_mem_of_mem_insert {l : List α} (h : a ∈ l.insert b) : a = b ∨ a ∈ l := - mem_insert_iff.1 h - -@[simp] theorem length_insert_of_mem {l : List α} (h : a ∈ l) : - length (l.insert a) = length l := by rw [insert_of_mem h] - -@[simp] theorem length_insert_of_not_mem {l : List α} (h : a ∉ l) : - length (l.insert a) = length l + 1 := by rw [insert_of_not_mem h]; rfl - -end insert - /-! ### eraseP -/ @[simp] theorem eraseP_nil : [].eraseP p = [] := rfl @@ -1525,19 +528,6 @@ theorem eraseP_map (f : β → α) : ∀ (l : List β), (map f l).eraseP p = map section erase variable [BEq α] -@[simp] theorem erase_nil (a : α) : [].erase a = [] := rfl - -theorem erase_cons (a b : α) (l : List α) : - (b :: l).erase a = if b == a then l else b :: l.erase a := - if h : b == a then by simp [List.erase, h] - else by simp [List.erase, h, (beq_eq_false_iff_ne _ _).2 h] - -@[simp] theorem erase_cons_head [LawfulBEq α] (a : α) (l : List α) : (a :: l).erase a = l := by - simp [erase_cons] - -@[simp] theorem erase_cons_tail {a b : α} (l : List α) (h : ¬(b == a)) : - (b :: l).erase a = b :: l.erase a := by simp only [erase_cons, if_neg h] - theorem erase_eq_eraseP' (a : α) (l : List α) : l.erase a = l.eraseP (· == a) := by induction l · simp @@ -1550,12 +540,6 @@ theorem erase_eq_eraseP [LawfulBEq α] (a : α) : ∀ l : List α, l.erase a = | b :: l => by if h : a = b then simp [h] else simp [h, Ne.symm h, erase_eq_eraseP a l] -theorem erase_of_not_mem [LawfulBEq α] {a : α} : ∀ {l : List α}, a ∉ l → l.erase a = l - | [], _ => rfl - | b :: l, h => by - rw [mem_cons, not_or] at h - simp only [erase_cons, if_neg, erase_of_not_mem h.2, beq_iff_eq, Ne.symm h.1, not_false_eq_true] - theorem exists_erase_eq [LawfulBEq α] {a : α} {l : List α} (h : a ∈ l) : ∃ l₁ l₂, a ∉ l₁ ∧ l = l₁ ++ a :: l₂ ∧ l.erase a = l₁ ++ l₂ := by let ⟨_, l₁, l₂, h₁, e, h₂, h₃⟩ := exists_of_eraseP h (beq_self_eq_true _) @@ -1609,105 +593,12 @@ end erase /-! ### filter and partition -/ -@[simp] theorem filter_append {p : α → Bool} : - ∀ (l₁ l₂ : List α), filter p (l₁ ++ l₂) = filter p l₁ ++ filter p l₂ - | [], l₂ => rfl - | a :: l₁, l₂ => by simp [filter]; split <;> simp [filter_append l₁] - @[simp] theorem filter_sublist {p : α → Bool} : ∀ (l : List α), filter p l <+ l | [] => .slnil | a :: l => by rw [filter]; split <;> simp [Sublist.cons, Sublist.cons₂, filter_sublist l] -@[simp] theorem partition_eq_filter_filter (p : α → Bool) (l : List α) : - partition p l = (filter p l, filter (not ∘ p) l) := by simp [partition, aux] where - aux : ∀ l {as bs}, partition.loop p l (as, bs) = - (as.reverse ++ filter p l, bs.reverse ++ filter (not ∘ p) l) - | [] => by simp [partition.loop, filter] - | a :: l => by cases pa : p a <;> simp [partition.loop, pa, aux, filter, append_assoc] - -theorem filter_congr' {p q : α → Bool} : - ∀ {l : List α}, (∀ x ∈ l, p x ↔ q x) → filter p l = filter q l - | [], _ => rfl - | a :: l, h => by - rw [forall_mem_cons] at h; by_cases pa : p a - · simp [pa, h.1.1 pa, filter_congr' h.2] - · simp [pa, mt h.1.2 pa, filter_congr' h.2] - /-! ### filterMap -/ -@[simp] theorem filterMap_nil (f : α → Option β) : filterMap f [] = [] := rfl - -@[simp] theorem filterMap_cons (f : α → Option β) (a : α) (l : List α) : - filterMap f (a :: l) = - match f a with - | none => filterMap f l - | some b => b :: filterMap f l := rfl - -theorem filterMap_cons_none {f : α → Option β} (a : α) (l : List α) (h : f a = none) : - filterMap f (a :: l) = filterMap f l := by simp only [filterMap, h] - -theorem filterMap_cons_some (f : α → Option β) (a : α) (l : List α) {b : β} (h : f a = some b) : - filterMap f (a :: l) = b :: filterMap f l := by simp only [filterMap, h] - -theorem filterMap_append {α β : Type _} (l l' : List α) (f : α → Option β) : - filterMap f (l ++ l') = filterMap f l ++ filterMap f l' := by - induction l <;> simp; split <;> simp [*] - -@[simp] -theorem filterMap_eq_map (f : α → β) : filterMap (some ∘ f) = map f := by - funext l; induction l <;> simp [*] - -@[simp] -theorem filterMap_eq_filter (p : α → Bool) : - filterMap (Option.guard (p ·)) = filter p := by - funext l - induction l with - | nil => rfl - | cons a l IH => by_cases pa : p a <;> simp [Option.guard, pa, ← IH] - -theorem filterMap_filterMap (f : α → Option β) (g : β → Option γ) (l : List α) : - filterMap g (filterMap f l) = filterMap (fun x => (f x).bind g) l := by - induction l with - | nil => rfl - | cons a l IH => cases h : f a <;> simp [*] - -theorem map_filterMap (f : α → Option β) (g : β → γ) (l : List α) : - map g (filterMap f l) = filterMap (fun x => (f x).map g) l := by - simp only [← filterMap_eq_map, filterMap_filterMap, Option.map_eq_bind] - -@[simp] -theorem filterMap_map (f : α → β) (g : β → Option γ) (l : List α) : - filterMap g (map f l) = filterMap (g ∘ f) l := by - rw [← filterMap_eq_map, filterMap_filterMap]; rfl - -theorem filter_filterMap (f : α → Option β) (p : β → Bool) (l : List α) : - filter p (filterMap f l) = filterMap (fun x => (f x).filter p) l := by - rw [← filterMap_eq_filter, filterMap_filterMap] - congr; funext x; cases f x <;> simp [Option.filter, Option.guard] - -theorem filterMap_filter (p : α → Bool) (f : α → Option β) (l : List α) : - filterMap f (filter p l) = filterMap (fun x => if p x then f x else none) l := by - rw [← filterMap_eq_filter, filterMap_filterMap] - congr; funext x; by_cases h : p x <;> simp [Option.guard, h] - -@[simp] theorem filterMap_some (l : List α) : filterMap some l = l := by - erw [filterMap_eq_map, map_id] - -theorem map_filterMap_some_eq_filter_map_is_some (f : α → Option β) (l : List α) : - (l.filterMap f).map some = (l.map f).filter fun b => b.isSome := by - induction l <;> simp; split <;> simp [*] - -@[simp] theorem mem_filterMap (f : α → Option β) (l : List α) {b : β} : - b ∈ filterMap f l ↔ ∃ a, a ∈ l ∧ f a = some b := by - induction l <;> simp; split <;> simp [*, eq_comm] - -@[simp] theorem filterMap_join (f : α → Option β) (L : List (List α)) : - filterMap f (join L) = join (map (filterMap f) L) := by - induction L <;> simp [*, filterMap_append] - -theorem map_filterMap_of_inv (f : α → Option β) (g : β → α) (H : ∀ x : α, (f x).map g = some x) - (l : List α) : map g (filterMap f l) = l := by simp only [map_filterMap, H, filterMap_some] - theorem length_filter_le (p : α → Bool) (l : List α) : (l.filter p).length ≤ l.length := (filter_sublist _).length_le @@ -1723,13 +614,6 @@ protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) : theorem Sublist.filter (p : α → Bool) {l₁ l₂} (s : l₁ <+ l₂) : filter p l₁ <+ filter p l₂ := by rw [← filterMap_eq_filter]; apply s.filterMap -theorem map_filter (f : β → α) (l : List β) : filter p (map f l) = map f (filter (p ∘ f) l) := by - rw [← filterMap_eq_map, filter_filterMap, filterMap_filter]; rfl - -@[simp] theorem filter_filter (q) : ∀ l, filter p (filter q l) = filter (fun a => p a ∧ q a) l - | [] => rfl - | a :: l => by by_cases hp : p a <;> by_cases hq : q a <;> simp [hp, hq, filter_filter _ l] - @[simp] theorem filter_eq_self {l} : filter p l = l ↔ ∀ a ∈ l, p a := by induction l with simp @@ -1741,39 +625,6 @@ theorem filter_eq_self {l} : filter p l = l ↔ ∀ a ∈ l, p a := by theorem filter_length_eq_length {l} : (filter p l).length = l.length ↔ ∀ a ∈ l, p a := Iff.trans ⟨l.filter_sublist.eq_of_length, congrArg length⟩ filter_eq_self -/-! ### find? -/ - -theorem find?_cons_of_pos (l) (h : p a) : find? p (a :: l) = some a := - by simp [find?, h] - -theorem find?_cons_of_neg (l) (h : ¬p a) : find? p (a :: l) = find? p l := - by simp [find?, h] - -theorem find?_eq_none : find? p l = none ↔ ∀ x ∈ l, ¬ p x := by - induction l <;> simp [find?_cons]; split <;> simp [*] - -theorem find?_some : ∀ {l}, find? p l = some a → p a - | b :: l, H => by - by_cases h : p b <;> simp [find?, h] at H - · exact H ▸ h - · exact find?_some H - -@[simp] theorem mem_of_find?_eq_some : ∀ {l}, find? p l = some a → a ∈ l - | b :: l, H => by - by_cases h : p b <;> simp [find?, h] at H - · exact H ▸ .head _ - · exact .tail _ (mem_of_find?_eq_some H) - -/-! ### findSome? -/ - -theorem exists_of_findSome?_eq_some {l : List α} {f : α → Option β} (w : l.findSome? f = some b) : - ∃ a, a ∈ l ∧ f a = b := by - induction l with - | nil => simp_all - | cons h l ih => - simp_all only [findSome?_cons, mem_cons, exists_eq_or_imp] - split at w <;> simp_all - /-! ### findIdx -/ @[simp] theorem findIdx_nil {α : Type _} (p : α → Bool) : [].findIdx p = 0 := rfl @@ -2372,22 +1223,6 @@ theorem disjoint_take_drop : ∀ {l : List α}, l.Nodup → m ≤ n → Disjoint refine ⟨fun h => h₀ _ (mem_of_mem_drop h) rfl, ?_⟩ exact disjoint_take_drop h₁ (Nat.le_of_succ_le_succ h) -/-! ### takeWhile and dropWhile -/ - -@[simp] theorem takeWhile_append_dropWhile (p : α → Bool) : - ∀ (l : List α), takeWhile p l ++ dropWhile p l = l - | [] => rfl - | x :: xs => by simp [takeWhile, dropWhile]; cases p x <;> simp [takeWhile_append_dropWhile p xs] - -theorem dropWhile_append {xs ys : List α} : - (xs ++ ys).dropWhile p = - if (xs.dropWhile p).isEmpty then ys.dropWhile p else xs.dropWhile p ++ ys := by - induction xs with - | nil => simp - | cons h t ih => - simp only [cons_append, dropWhile_cons] - split <;> simp_all - /-! ### Chain -/ attribute [simp] Chain.nil @@ -2582,60 +1417,8 @@ theorem reverse_range' : ∀ s n : Nat, reverse (range' s n) = map (s + n - 1 - @[simp] theorem enum_map_fst (l : List α) : map Prod.fst (enum l) = range l.length := by simp only [enum, enumFrom_map_fst, range_eq_range'] -@[simp] theorem enumFrom_length : ∀ {n} {l : List α}, (enumFrom n l).length = l.length - | _, [] => rfl - | _, _ :: _ => congrArg Nat.succ enumFrom_length - -@[simp] theorem enum_length : (enum l).length = l.length := - enumFrom_length - /-! ### maximum? -/ -@[simp] theorem maximum?_nil [Max α] : ([] : List α).maximum? = none := rfl - --- We don't put `@[simp]` on `minimum?_cons`, --- because the definition in terms of `foldl` is not useful for proofs. -theorem maximum?_cons [Max α] {xs : List α} : (x :: xs).maximum? = foldl max x xs := rfl - -@[simp] theorem maximum?_eq_none_iff {xs : List α} [Max α] : xs.maximum? = none ↔ xs = [] := by - cases xs <;> simp [maximum?] - -theorem maximum?_mem [Max α] (min_eq_or : ∀ a b : α, max a b = a ∨ max a b = b) : - {xs : List α} → xs.maximum? = some a → a ∈ xs - | nil => by simp - | cons x xs => by - rw [maximum?]; rintro ⟨⟩ - induction xs generalizing x with simp at * - | cons y xs ih => - rcases ih (max x y) with h | h <;> simp [h] - simp [← or_assoc, min_eq_or x y] - -theorem maximum?_le_iff [Max α] [LE α] - (max_le_iff : ∀ a b c : α, max b c ≤ a ↔ b ≤ a ∧ c ≤ a) : - {xs : List α} → xs.maximum? = some a → ∀ x, a ≤ x ↔ ∀ b ∈ xs, b ≤ x - | nil => by simp - | cons x xs => by - rw [maximum?]; rintro ⟨⟩ y - induction xs generalizing x with - | nil => simp - | cons y xs ih => simp [ih, max_le_iff, and_assoc] - --- This could be refactored by designing appropriate typeclasses to replace `le_refl`, `max_eq_or`, --- and `le_min_iff`. -theorem maximum?_eq_some_iff [Max α] [LE α] [anti : Antisymm ((· : α) ≤ ·)] - (le_refl : ∀ a : α, a ≤ a) - (max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b) - (max_le_iff : ∀ a b c : α, max b c ≤ a ↔ b ≤ a ∧ c ≤ a) {xs : List α} : - xs.maximum? = some a ↔ a ∈ xs ∧ ∀ b ∈ xs, b ≤ a := by - refine ⟨fun h => ⟨maximum?_mem max_eq_or h, (maximum?_le_iff max_le_iff h _).1 (le_refl _)⟩, ?_⟩ - intro ⟨h₁, h₂⟩ - cases xs with - | nil => simp at h₁ - | cons x xs => - exact congrArg some <| anti.1 - (h₂ _ (maximum?_mem max_eq_or (xs := x::xs) rfl)) - ((maximum?_le_iff max_le_iff (xs := x::xs) rfl _).1 (le_refl _) _ h₁) - -- A specialization of `maximum?_eq_some_iff` to Nat. theorem maximum?_eq_some_iff' {xs : List Nat} : xs.maximum? = some a ↔ (a ∈ xs ∧ ∀ b ∈ xs, b ≤ a) := @@ -2719,7 +1502,7 @@ theorem merge_loop (s : α → α → Bool) (l r t) : | zero => rw [eq_nil_of_length_eq_zero (Nat.eq_zero_of_add_eq_zero_left hn)] rw [eq_nil_of_length_eq_zero (Nat.eq_zero_of_add_eq_zero_right hn)] - rfl + simp only [merge.loop, reverseAux] | succ n ih => match l, r with | [], r => simp only [merge_loop_nil_left]; rfl @@ -2779,46 +1562,3 @@ theorem mem_merge_left (s : α → α → Bool) (h : x ∈ l) : x ∈ merge s l theorem mem_merge_right (s : α → α → Bool) (h : x ∈ r) : x ∈ merge s l r := mem_merge.2 <| .inr h - -/-! ### lt -/ - -theorem lt_irrefl' [LT α] (lt_irrefl : ∀ x : α, ¬x < x) (l : List α) : ¬l < l := by - induction l with - | nil => nofun - | cons a l ih => intro - | .head _ _ h => exact lt_irrefl _ h - | .tail _ _ h => exact ih h - -theorem lt_trans' [LT α] [DecidableRel (@LT.lt α _)] - (lt_trans : ∀ {x y z : α}, x < y → y < z → x < z) - (le_trans : ∀ {x y z : α}, ¬x < y → ¬y < z → ¬x < z) - {l₁ l₂ l₃ : List α} (h₁ : l₁ < l₂) (h₂ : l₂ < l₃) : l₁ < l₃ := by - induction h₁ generalizing l₃ with - | nil => let _::_ := l₃; exact List.lt.nil .. - | @head a l₁ b l₂ ab => - match h₂ with - | .head l₂ l₃ bc => exact List.lt.head _ _ (lt_trans ab bc) - | .tail _ cb ih => - exact List.lt.head _ _ <| Decidable.by_contra (le_trans · cb ab) - | @tail a l₁ b l₂ ab ba h₁ ih2 => - match h₂ with - | .head l₂ l₃ bc => - exact List.lt.head _ _ <| Decidable.by_contra (le_trans ba · bc) - | .tail bc cb ih => - exact List.lt.tail (le_trans ab bc) (le_trans cb ba) (ih2 ih) - -theorem lt_antisymm' [LT α] - (lt_antisymm : ∀ {x y : α}, ¬x < y → ¬y < x → x = y) - {l₁ l₂ : List α} (h₁ : ¬l₁ < l₂) (h₂ : ¬l₂ < l₁) : l₁ = l₂ := by - induction l₁ generalizing l₂ with - | nil => - cases l₂ with - | nil => rfl - | cons b l₂ => cases h₁ (.nil ..) - | cons a l₁ ih => - cases l₂ with - | nil => cases h₂ (.nil ..) - | cons b l₂ => - have ab : ¬a < b := fun ab => h₁ (.head _ _ ab) - cases lt_antisymm ab (fun ba => h₂ (.head _ _ ba)) - rw [ih (fun ll => h₁ (.tail ab ab ll)) (fun ll => h₂ (.tail ab ab ll))] diff --git a/Batteries/Data/String/Lemmas.lean b/Batteries/Data/String/Lemmas.lean index 8deade2f9c..8a9376fe05 100644 --- a/Batteries/Data/String/Lemmas.lean +++ b/Batteries/Data/String/Lemmas.lean @@ -9,16 +9,9 @@ import Batteries.Data.String.Basic import Batteries.Tactic.Lint.Misc import Batteries.Tactic.SeqFocus -@[simp] theorem Char.length_toString (c : Char) : c.toString.length = 1 := rfl - namespace String -@[ext] theorem ext {s₁ s₂ : String} (h : s₁.data = s₂.data) : s₁ = s₂ := - show ⟨s₁.data⟩ = (⟨s₂.data⟩ : String) from h ▸ rfl - -theorem ext_iff {s₁ s₂ : String} : s₁ = s₂ ↔ s₁.data = s₂.data := ⟨fun h => h ▸ rfl, ext⟩ - -theorem lt_irrefl (s : String) : ¬s < s := List.lt_irrefl' (α := Char) (fun _ => Nat.lt_irrefl _) _ +attribute [ext] ext theorem lt_trans {s₁ s₂ s₃ : String} : s₁ < s₂ → s₂ < s₃ → s₁ < s₃ := List.lt_trans' (α := Char) Nat.lt_trans @@ -36,34 +29,10 @@ instance : Batteries.LTOrd String := .compareOfLessAndEq instance : Batteries.BEqOrd String := .compareOfLessAndEq String.lt_irrefl -@[simp] theorem default_eq : default = "" := rfl - -@[simp] theorem str_eq : str = push := rfl - @[simp] theorem mk_length (s : List Char) : (String.mk s).length = s.length := rfl -@[simp] theorem length_empty : "".length = 0 := rfl - -@[simp] theorem length_singleton (c : Char) : (String.singleton c).length = 1 := rfl - -@[simp] theorem length_push (c : Char) : (String.push s c).length = s.length + 1 := by - rw [push, mk_length, List.length_append, List.length_singleton, Nat.succ.injEq] - rfl - -@[simp] theorem length_pushn (c : Char) (n : Nat) : (pushn s c n).length = s.length + n := by - unfold pushn; induction n <;> simp [Nat.repeat, Nat.add_assoc, *] - -@[simp] theorem length_append (s t : String) : (s ++ t).length = s.length + t.length := by - simp only [length, append, List.length_append] - -@[simp] theorem data_push (s : String) (c : Char) : (s.push c).1 = s.1 ++ [c] := rfl - -@[simp] theorem data_append (s t : String) : (s ++ t).1 = s.1 ++ t.1 := rfl - attribute [simp] toList -- prefer `String.data` over `String.toList` in lemmas -theorem lt_iff (s t : String) : s < t ↔ s.1 < t.1 := .rfl - private theorem add_csize_pos : 0 < i + csize c := Nat.add_pos_right _ (csize_pos c) @@ -117,69 +86,13 @@ end namespace Pos -@[simp] theorem byteIdx_zero : (0 : Pos).byteIdx = 0 := rfl - -theorem byteIdx_mk (n : Nat) : byteIdx ⟨n⟩ = n := rfl - -@[simp] theorem mk_zero : ⟨0⟩ = (0 : Pos) := rfl - -@[simp] theorem mk_byteIdx (p : Pos) : ⟨p.byteIdx⟩ = p := rfl - -@[ext] theorem ext {i₁ i₂ : Pos} (h : i₁.byteIdx = i₂.byteIdx) : i₁ = i₂ := - show ⟨i₁.byteIdx⟩ = (⟨i₂.byteIdx⟩ : Pos) from h ▸ rfl - -theorem ext_iff {i₁ i₂ : Pos} : i₁ = i₂ ↔ i₁.byteIdx = i₂.byteIdx := ⟨fun h => h ▸ rfl, ext⟩ - -@[simp] theorem add_byteIdx (p₁ p₂ : Pos) : (p₁ + p₂).byteIdx = p₁.byteIdx + p₂.byteIdx := rfl - -theorem add_eq (p₁ p₂ : Pos) : p₁ + p₂ = ⟨p₁.byteIdx + p₂.byteIdx⟩ := rfl - -@[simp] theorem sub_byteIdx (p₁ p₂ : Pos) : (p₁ - p₂).byteIdx = p₁.byteIdx - p₂.byteIdx := rfl - -theorem sub_eq (p₁ p₂ : Pos) : p₁ - p₂ = ⟨p₁.byteIdx - p₂.byteIdx⟩ := rfl - -@[simp] theorem addChar_byteIdx (p : Pos) (c : Char) : (p + c).byteIdx = p.byteIdx + csize c := rfl - -theorem addChar_eq (p : Pos) (c : Char) : p + c = ⟨p.byteIdx + csize c⟩ := rfl - -theorem zero_addChar_byteIdx (c : Char) : ((0 : Pos) + c).byteIdx = csize c := by - simp only [addChar_byteIdx, byteIdx_zero, Nat.zero_add] - -theorem zero_addChar_eq (c : Char) : (0 : Pos) + c = ⟨csize c⟩ := by rw [← zero_addChar_byteIdx] - -theorem addChar_right_comm (p : Pos) (c₁ c₂ : Char) : p + c₁ + c₂ = p + c₂ + c₁ := by - apply ext - repeat rw [pos_add_char] - apply Nat.add_right_comm +attribute [ext] ext theorem lt_addChar (p : Pos) (c : Char) : p < p + c := Nat.lt_add_of_pos_right (csize_pos _) -theorem ne_of_lt {i₁ i₂ : Pos} (h : i₁ < i₂) : i₁ ≠ i₂ := mt ext_iff.1 (Nat.ne_of_lt h) - -theorem ne_of_gt {i₁ i₂ : Pos} (h : i₁ < i₂) : i₂ ≠ i₁ := (ne_of_lt h).symm - -@[simp] theorem addString_byteIdx (p : Pos) (s : String) : - (p + s).byteIdx = p.byteIdx + s.utf8ByteSize := rfl - -theorem addString_eq (p : Pos) (s : String) : p + s = ⟨p.byteIdx + s.utf8ByteSize⟩ := rfl - -theorem zero_addString_byteIdx (s : String) : ((0 : Pos) + s).byteIdx = s.utf8ByteSize := by - simp only [addString_byteIdx, byteIdx_zero, Nat.zero_add] - private theorem zero_ne_addChar {i : Pos} {c : Char} : 0 ≠ i + c := ne_of_lt add_csize_pos -theorem zero_addString_eq (s : String) : (0 : Pos) + s = ⟨s.utf8ByteSize⟩ := by - rw [← zero_addString_byteIdx] - -theorem le_iff {i₁ i₂ : Pos} : i₁ ≤ i₂ ↔ i₁.byteIdx ≤ i₂.byteIdx := .rfl - -@[simp] theorem mk_le_mk {i₁ i₂ : Nat} : Pos.mk i₁ ≤ Pos.mk i₂ ↔ i₁ ≤ i₂ := .rfl - -theorem lt_iff {i₁ i₂ : Pos} : i₁ < i₂ ↔ i₁.byteIdx < i₂.byteIdx := .rfl - -@[simp] theorem mk_lt_mk {i₁ i₂ : Nat} : Pos.mk i₁ < Pos.mk i₂ ↔ i₁ < i₂ := .rfl - /-- A string position is valid if it is equal to the UTF-8 length of an initial substring of `s`. -/ def Valid (s : String) (p : Pos) : Prop := ∃ cs cs', cs ++ cs' = s.1 ∧ p.1 = utf8Len cs @@ -264,8 +177,6 @@ theorem utf8GetAux?_of_valid (cs cs' : List Char) {i p : Nat} (hp : i + utf8Len theorem get?_of_valid (cs cs' : List Char) : get? ⟨cs ++ cs'⟩ ⟨utf8Len cs⟩ = cs'.head? := utf8GetAux?_of_valid _ _ (Nat.zero_add _) -@[simp] theorem get!_eq_get (s : String) (p : Pos) : get! s p = get s p := rfl - theorem utf8SetAux_of_valid (c' : Char) (cs cs' : List Char) {i p : Nat} (hp : i + utf8Len cs = p) : utf8SetAux c' (cs ++ cs') ⟨i⟩ ⟨p⟩ = cs ++ cs'.modifyHead fun _ => c' := by match cs, cs' with @@ -292,8 +203,6 @@ theorem next_of_valid' (cs cs' : List Char) : theorem next_of_valid (cs : List Char) (c : Char) (cs' : List Char) : next ⟨cs ++ c :: cs'⟩ ⟨utf8Len cs⟩ = ⟨utf8Len cs + csize c⟩ := next_of_valid' .. -theorem lt_next' (s : String) (p : Pos) : p < next s p := lt_next .. - @[simp] theorem atEnd_iff (s : String) (p : Pos) : atEnd s p ↔ s.endPos ≤ p := decide_eq_true_iff _ @@ -327,8 +236,6 @@ theorem prev_of_valid' (cs cs' : List Char) : | _, .inl rfl => rfl | _, .inr ⟨cs, c, rfl⟩ => simp [prev_of_valid] -@[simp] theorem prev_zero (s : String) : prev s 0 = 0 := rfl - theorem front_eq (s : String) : front s = s.1.headD default := by unfold front; exact get_of_valid [] s.1 @@ -342,16 +249,16 @@ theorem atEnd_of_valid (cs : List Char) (cs' : List Char) : rw [atEnd_iff] cases cs' <;> simp [Nat.lt_add_of_pos_right add_csize_pos] -@[simp] theorem get'_eq (s : String) (p : Pos) (h) : get' s p h = get s p := rfl - -@[simp] theorem next'_eq (s : String) (p : Pos) (h) : next' s p h = next s p := rfl - +unseal posOfAux findAux in theorem posOfAux_eq (s c) : posOfAux s c = findAux s (· == c) := rfl +unseal posOfAux findAux in theorem posOf_eq (s c) : posOf s c = find s (· == c) := rfl +unseal revPosOfAux revFindAux in theorem revPosOfAux_eq (s c) : revPosOfAux s c = revFindAux s (· == c) := rfl +unseal revPosOfAux revFindAux in theorem revPosOf_eq (s c) : revPosOf s c = revFind s (· == c) := rfl @[nolint unusedHavesSuffices] -- false positive from unfolding String.findAux @@ -516,16 +423,8 @@ theorem join_eq (ss : List String) : join ss = ⟨(ss.map data).join⟩ := go ss @[simp] theorem data_join (ss : List String) : (join ss).data = (ss.map data).join := by rw [join_eq] -theorem singleton_eq (c : Char) : singleton c = ⟨[c]⟩ := rfl - -@[simp] theorem data_singleton (c : Char) : (singleton c).data = [c] := rfl - -@[simp] theorem append_nil (s : String) : s ++ "" = s := ext (List.append_nil _) - -@[simp] theorem nil_append (s : String) : "" ++ s = s := rfl - -theorem append_assoc (s₁ s₂ s₃ : String) : (s₁ ++ s₂) ++ s₃ = s₁ ++ (s₂ ++ s₃) := - ext (List.append_assoc ..) +@[deprecated (since := "2024-06-06")] alias append_nil := append_empty +@[deprecated (since := "2024-06-06")] alias nil_append := empty_append namespace Iterator @@ -801,12 +700,6 @@ open String namespace Substring -@[simp] theorem prev_zero (s : Substring) : s.prev 0 = 0 := by simp [prev, Pos.add_eq] - -@[simp] theorem prevn_zero (s : Substring) : ∀ n, s.prevn n 0 = 0 - | 0 => rfl - | n+1 => by simp [prevn, prevn_zero s n] - /-- Validity for a substring. -/ structure Valid (s : Substring) : Prop where /-- The start position of a valid substring is valid. -/ diff --git a/Batteries/Lean/Delaborator.lean b/Batteries/Lean/Delaborator.lean index 98aa890e01..d722eef9d8 100644 --- a/Batteries/Lean/Delaborator.lean +++ b/Batteries/Lean/Delaborator.lean @@ -7,19 +7,7 @@ import Lean.PrettyPrinter open Lean PrettyPrinter Delaborator SubExpr -/-- Pretty print a const expression using `delabConst` and generate terminfo. -This function avoids inserting `@` if the constant is for a function whose first -argument is implicit, which is what the default `toMessageData` for `Expr` does. -Panics if `e` is not a constant. -/ +/-- Abbreviation for `Lean.MessageData.ofConst`. -/ +@[deprecated Lean.MessageData.ofConst] def Lean.ppConst (e : Expr) : MessageData := - if e.isConst then - .ofPPFormat { - pp := fun - | some ctx => ctx.runMetaM <| withOptions (pp.tagAppFns.set · true) <| - -- The pp.tagAppFns option causes the `delabConst` function to annotate - -- the constant with terminfo, which is necessary for seeing the type on mouse hover. - PrettyPrinter.ppExprWithInfos (delab := delabConst) e - | none => return f!"{e}" - } - else - panic! "not a constant" + Lean.MessageData.ofConst e diff --git a/Batteries/Tactic/Instances.lean b/Batteries/Tactic/Instances.lean index 703fed87cd..b243c4f153 100644 --- a/Batteries/Tactic/Instances.lean +++ b/Batteries/Tactic/Instances.lean @@ -45,11 +45,7 @@ elab (name := instancesCmd) tk:"#instances " stx:term : command => runTermElabM let mut msg := m!"\n" if e.priority != 1000 then -- evalPrio default := 1000 msg := msg ++ m!"(prio {e.priority}) " - msgs := msgs.push <| msg ++ .ofPPFormat { pp := fun - | some ctx => ctx.runMetaM <| withOptions (pp.tagAppFns.set · true) <| - PrettyPrinter.ppSignature c - | none => return f!"{c}" - } + msgs := msgs.push <| msg ++ MessageData.signature c for linst in ← getLocalInstances do if linst.className == className then msgs := msgs.push m!"(local) {linst.fvar} : {← inferType linst.fvar}" diff --git a/Batteries/Tactic/PrintDependents.lean b/Batteries/Tactic/PrintDependents.lean index d41c89201b..9c55a04ecd 100644 --- a/Batteries/Tactic/PrintDependents.lean +++ b/Batteries/Tactic/PrintDependents.lean @@ -99,7 +99,7 @@ elab tk:"#print" &"dependents" ids:(ppSpace colGt ident)* : command => do if let some ranges ← findDeclarationRanges? c then out := out.push (c, ranges.range.pos.1) let msg ← out.qsort (·.2 < ·.2) |>.mapM fun (c, _) => do - let mut msg := m!"{ppConst (← mkConstWithLevelParams c)}: " + let mut msg := m!"{MessageData.ofConst (← mkConstWithLevelParams c)}: " if init.result.contains c then msg := msg ++ m!"" else @@ -113,6 +113,6 @@ elab tk:"#print" &"dependents" ids:(ppSpace colGt ident)* : command => do | _ => #[] for c in RBTree.fromArray consts Name.cmp do if state.result.find? c = some true then - msg := msg ++ m!"{ppConst (← mkConstWithLevelParams c)} " + msg := msg ++ m!"{MessageData.ofConst (← mkConstWithLevelParams c)} " return msg logInfoAt tk (.joinSep msg.toList "\n") diff --git a/Batteries/Tactic/PrintPrefix.lean b/Batteries/Tactic/PrintPrefix.lean index 65314bb486..0046f0a4d7 100644 --- a/Batteries/Tactic/PrintPrefix.lean +++ b/Batteries/Tactic/PrintPrefix.lean @@ -79,13 +79,9 @@ private def matchingConstants (opts : PrintPrefixConfig) (pre : Name) let cinfos := cinfos.qsort fun p q => lexNameLt (reverseName p.name) (reverseName q.name) cinfos.mapM fun cinfo => do if opts.showTypes then - pure <| .ofPPFormat { pp := fun - | some ctx => ctx.runMetaM <| - withOptions (pp.tagAppFns.set · true) <| PrettyPrinter.ppSignature cinfo.name - | none => return f!"{cinfo.name}" -- should never happen - } ++ "\n" + pure <| MessageData.signature cinfo.name ++ "\n" else - pure m!"{ppConst (← mkConstWithLevelParams cinfo.name)}\n" + pure m!"{MessageData.ofConst (← mkConstWithLevelParams cinfo.name)}\n" /-- The command `#print prefix foo` will print all definitions that start with diff --git a/Batteries/Tactic/ShowUnused.lean b/Batteries/Tactic/ShowUnused.lean index 8f81c6fa59..25989a3da9 100644 --- a/Batteries/Tactic/ShowUnused.lean +++ b/Batteries/Tactic/ShowUnused.lean @@ -61,11 +61,11 @@ elab tk:"#show_unused" ids:(ppSpace colGt ident)* : command => do let pos := fileMap.toPosition <| (tk.getPos? <|> (← getRef).getPos?).getD 0 let pfx := m!"#show_unused (line {pos.line}) says:\n" let post := m!" is not used transitively by \ - {← ns.mapM (Lean.ppConst <$> mkConstWithLevelParams ·)}" + {← ns.mapM (MessageData.ofConst <$> mkConstWithLevelParams ·)}" for (c, range) in unused do logWarningAt (Syntax.ofRange range) <| .tagged Linter.linter.unusedVariables.name <| - m!"{pfx}{Lean.ppConst (← mkConstWithLevelParams c)}{post}" + m!"{pfx}{MessageData.ofConst (← mkConstWithLevelParams c)}{post}" if unused.isEmpty then logInfoAt tk "No unused definitions" else diff --git a/Batteries/WF.lean b/Batteries/WF.lean index 7a702665ae..73428fe3bd 100644 --- a/Batteries/WF.lean +++ b/Batteries/WF.lean @@ -53,6 +53,8 @@ instance wfRel {r : α → α → Prop} : WellFoundedRelation { val // Acc r val intro a (fun x h => t.inv h) (fun y hr => recC intro (t.inv hr)) termination_by Subtype.mk a t +unseal recC + private theorem recC_intro {motive : (a : α) → Acc r a → Sort v} (intro : (x : α) → (h : ∀ (y : α), r y x → Acc r y) → ((y : α) → (hr : r y x) → motive y (h y hr)) → motive x (intro x h)) @@ -120,6 +122,8 @@ Workaround until Lean has native support for this. -/ F x (fun y _ => fixC hwf F y) termination_by hwf.wrap x +unseal fixC + @[csimp] private theorem fix_eq_fixC : @fix = @fixC := rfl end WellFounded diff --git a/lakefile.lean b/lakefile.lean index 791f3a9c3c..a59342f68c 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -21,6 +21,6 @@ lean_exe runLinter where meta if get_config? doc |>.isSome then require «doc-gen4» from git "https://github.com/leanprover/doc-gen4" @ "main" -@[test_runner] +@[test_driver] lean_exe test where srcDir := "scripts" diff --git a/lean-toolchain b/lean-toolchain index ef1f67e9e6..0ba3faf807 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.8.0 +leanprover/lean4:v4.9.0-rc1 diff --git a/test/list_sublists.lean b/test/list_sublists.lean index 18eee40f2c..871e8a56e5 100644 --- a/test/list_sublists.lean +++ b/test/list_sublists.lean @@ -1,7 +1,7 @@ import Batteries.Data.List.Basic -- this times out with `sublistsFast` -set_option maxRecDepth 561 in +set_option maxRecDepth 562 in example : [1, 2, 3].sublists.sublists.length = 256 := rfl -- TODO(batteries#307): until we have the `csimp` lemma in batteries, From af2dda22771c59db026c48ac0aabc73b72b7a4de Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 7 Jun 2024 10:55:34 +1000 Subject: [PATCH 017/208] bad merge --- Batteries/Data/Fin/Lemmas.lean | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Batteries/Data/Fin/Lemmas.lean b/Batteries/Data/Fin/Lemmas.lean index 40113f1a16..a310aa6f93 100644 --- a/Batteries/Data/Fin/Lemmas.lean +++ b/Batteries/Data/Fin/Lemmas.lean @@ -77,7 +77,6 @@ termination_by n - m theorem foldl_succ (f : α → Fin (n+1) → α) (x) : foldl (n+1) f x = foldl n (fun x i => f x i.succ) (f x 0) := foldl_loop .. -unseal Fin.foldl.loop in theorem foldl_succ_last (f : α → Fin (n+1) → α) (x) : foldl (n+1) f x = f (foldl n (f · ·.castSucc) x) (last n) := by rw [foldl_succ] @@ -108,13 +107,12 @@ theorem foldr_loop (f : Fin (n+1) → α → α) (x) (h : m+1 ≤ n+1) : | zero => simp [foldr_loop_zero, foldr_loop_succ] | succ m ih => rw [foldr_loop_succ, ih, foldr_loop_succ, Fin.succ] -theorem foldr_zero (f : Fin 0 → α → α) (x) : +@[simp] theorem foldr_zero (f : Fin 0 → α → α) (x) : foldr 0 f x = x := foldr_loop_zero .. theorem foldr_succ (f : Fin (n+1) → α → α) (x) : foldr (n+1) f x = f 0 (foldr n (fun i => f i.succ) x) := foldr_loop .. -unseal Fin.foldr.loop in theorem foldr_succ_last (f : Fin (n+1) → α → α) (x) : foldr (n+1) f x = foldr n (f ·.castSucc) (f (last n) x) := by induction n generalizing x with @@ -128,14 +126,12 @@ theorem foldr_eq_foldr_list (f : Fin n → α → α) (x) : foldr n f x = (list /-! ### foldl/foldr -/ -unseal Fin.foldl.loop Fin.foldr.loop in theorem foldl_rev (f : Fin n → α → α) (x) : foldl n (fun x i => f i.rev x) x = foldr n f x := by induction n generalizing x with | zero => simp | succ n ih => rw [foldl_succ, foldr_succ_last, ← ih]; simp [rev_succ] -unseal Fin.foldl.loop Fin.foldr.loop in theorem foldr_rev (f : α → Fin n → α) (x) : foldr n (fun i x => f x i.rev) x = foldl n f x := by induction n generalizing x with From 8f8f75bef4adb7224a8a5cc1482f0d89af1c5b2b Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 7 Jun 2024 09:04:59 +0000 Subject: [PATCH 018/208] chore: bump to nightly-2024-06-07 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 1b2d23c360..a3a2c19b46 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-06 +leanprover/lean4:nightly-2024-06-07 From 1fe20328b3cf07890749dfc6f1cfd637ce6b6d5c Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Sat, 8 Jun 2024 05:47:37 +1000 Subject: [PATCH 019/208] in progress --- Batteries/Data/Fin/Lemmas.lean | 8 +++++-- Batteries/Data/List/Lemmas.lean | 37 ++++++++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/Batteries/Data/Fin/Lemmas.lean b/Batteries/Data/Fin/Lemmas.lean index a310aa6f93..21f14d8a96 100644 --- a/Batteries/Data/Fin/Lemmas.lean +++ b/Batteries/Data/Fin/Lemmas.lean @@ -30,8 +30,12 @@ protected theorem le_antisymm {x y : Fin n} (h1 : x ≤ y) (h2 : y ≤ x) : x = @[simp] theorem length_list (n) : (list n).length = n := by simp [list] -@[simp] theorem get_list (i : Fin (list n).length) : (list n).get i = i.cast (length_list n) := by - cases i; simp only [list]; rw [← Array.getElem_eq_data_get, getElem_enum, cast_mk] +@[simp] theorem getElem_list (i : Nat) (h : i < (list n).length) : + (list n)[i] = cast (length_list n) ⟨i, h⟩ := by + simp only [list]; rw [← Array.getElem_eq_data_getElem, getElem_enum, cast_mk] + +theorem get_list (i : Fin (list n).length) : (list n).get i = i.cast (length_list n) := by + simp [getElem_list] @[simp] theorem list_zero : list 0 = [] := by simp [list] diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 6109b4c9be..a65b0fb5c7 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -243,7 +243,9 @@ theorem tail_eq_tail? (l) : @tail α l = (tail? l).getD [] := by simp [tail_eq_t /-! ### get? -/ -theorem get_eq_iff : List.get l n = x ↔ l.get? n.1 = some x := by simp [get?_eq_some] +theorem get_eq_iff : List.get l n = x ↔ l.get? n.1 = some x := by + simp only [get_eq_getElem, get?_eq_getElem?, getElem?_eq_some] + exact ⟨fun h => ⟨n.2, h⟩, fun h => h.2⟩ theorem get?_inj (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs.get? i = xs.get? j) : i = j := by @@ -254,12 +256,14 @@ theorem get?_inj | 0, 0 => rfl | i+1, j+1 => simp; cases h₁ with | cons ha h₁ => exact ih (Nat.lt_of_succ_lt_succ h₀) h₁ h₂ - | i+1, 0 => ?_ | 0, j+1 => ?_ + | i+1, 0 => ?_ + | 0, j+1 => ?_ all_goals - simp at h₂ + simp only [get?_eq_getElem?, getElem?_cons_zero, getElem?_cons_succ] at h₂ cases h₁; rename_i h' h have := h x ?_ rfl; cases this rw [mem_iff_get?] + simp only [get?_eq_getElem?] exact ⟨_, h₂⟩; exact ⟨_ , h₂.symm⟩ /-! ### drop -/ @@ -274,6 +278,11 @@ theorem tail_drop (l : List α) (n : Nat) : (l.drop n).tail = l.drop (n + 1) := /-! ### modifyNth -/ +@[simp] theorem modifyNth_nil (f : α → α) (n) : [].modifyNth f n = [] := by cases n <;> rfl + +theorem modifyNth_zero_cons (f : α → α) (a : α) (l : List α) : + (a :: l).modifyNth f 0 = f a :: l := rfl + theorem modifyNthTail_id : ∀ n (l : List α), l.modifyNthTail id n = l | 0, _ => rfl | _+1, [] => rfl @@ -286,6 +295,16 @@ theorem eraseIdx_eq_modifyNthTail : ∀ n (l : List α), eraseIdx l n = modifyNt @[deprecated] alias removeNth_eq_nth_tail := eraseIdx_eq_modifyNthTail +theorem getElem?_modifyNth (f : α → α) : + ∀ n (l : List α) m, (modifyNth f n l)[m]? = (fun a => if n = m then f a else a) <$> l[m]? + | n, l, 0 => by cases l <;> cases n <;> simp + | n, [], _+1 => by cases n <;> rfl + | 0, _ :: l, m+1 => by cases h : l[m]? <;> simp [h, modifyNth, m.succ_ne_zero.symm] + | n+1, a :: l, m+1 => + (getElem?_modifyNth f n l m).trans <| by + cases h' : l[m]? <;> by_cases h : n = m <;> + simp [h, if_pos, if_neg, Option.map, mt Nat.succ.inj, not_false_iff, h'] + theorem get?_modifyNth (f : α → α) : ∀ n (l : List α) m, (modifyNth f n l).get? m = (fun a => if n = m then f a else a) <$> l.get? m | n, l, 0 => by cases l <;> cases n <;> rfl @@ -293,7 +312,7 @@ theorem get?_modifyNth (f : α → α) : | 0, _ :: l, m+1 => by cases h : l.get? m <;> simp [h, modifyNth, m.succ_ne_zero.symm] | n+1, a :: l, m+1 => (get?_modifyNth f n l m).trans <| by - cases h' : l.get? m <;> by_cases h : n = m <;> + cases h' : l[m]? <;> by_cases h : n = m <;> simp [h, if_pos, if_neg, Option.map, mt Nat.succ.inj, not_false_iff, h'] theorem modifyNthTail_length (f : List α → List α) (H : ∀ l, length (f l) = length l) : @@ -315,6 +334,10 @@ theorem exists_of_modifyNthTail (f : List α → List α) {n} {l : List α} (h : @[simp] theorem modify_get?_length (f : α → α) : ∀ n l, length (modifyNth f n l) = length l := modifyNthTail_length _ fun l => by cases l <;> rfl +@[simp] theorem getElem?_modifyNth_eq (f : α → α) (n) (l : List α) : + (modifyNth f n l)[n]? = f <$> l[n]? := by + simp only [get?_modifyNth, if_pos] + @[simp] theorem get?_modifyNth_eq (f : α → α) (n) (l : List α) : (modifyNth f n l).get? n = f <$> l.get? n := by simp only [get?_modifyNth, if_pos] @@ -359,7 +382,7 @@ theorem modifyNth_eq_set_get? (f : α → α) : | 0, l => by cases l <;> rfl | n+1, [] => rfl | n+1, b :: l => - (congrArg (cons _) (modifyNth_eq_set_get? ..)).trans <| by cases h : l.get? n <;> simp [h] + (congrArg (cons _) (modifyNth_eq_set_get? ..)).trans <| by cases h : l[n]? <;> simp [h] theorem modifyNth_eq_set_get (f : α → α) {n} {l : List α} (h) : l.modifyNth f n = l.set n (f (l.get ⟨n, h⟩)) := by @@ -373,6 +396,10 @@ theorem exists_of_set' {l : List α} (h : n < l.length) : ∃ l₁ l₂, l = l₁ ++ l.get ⟨n, h⟩ :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := have ⟨_, _, _, h₁, h₂, h₃⟩ := exists_of_set h; ⟨_, _, get_of_append h₁ h₂ ▸ h₁, h₂, h₃⟩ +@[simp] +theorem getElem?_set_eq (a : α) (n) (l : List α) : (set l n a)[n]? = (fun _ => a) <$> l[n]? := by + simp only [set_eq_modifyNth, get?_modifyNth_eq] + @[simp] 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] From f93c3a73709b3d550b09b0740716c0cbe7df085d Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 7 Jun 2024 20:56:24 +0100 Subject: [PATCH 020/208] feat: missing modifyNth simp lemmas (#830) --- Batteries/Data/List/Lemmas.lean | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 6109b4c9be..cd010a8150 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -274,6 +274,14 @@ theorem tail_drop (l : List α) (n : Nat) : (l.drop n).tail = l.drop (n + 1) := /-! ### modifyNth -/ +@[simp] theorem modifyNth_nil (f : α → α) (n) : [].modifyNth f n = [] := by cases n <;> rfl + +@[simp] theorem modifyNth_zero_cons (f : α → α) (a : α) (l : List α) : + (a :: l).modifyNth f 0 = f a :: l := rfl + +@[simp] theorem modifyNth_succ_cons (f : α → α) (a : α) (l : List α) (n) : + (a :: l).modifyNth f (n + 1) = a :: l.modifyNth f n := by rfl + theorem modifyNthTail_id : ∀ n (l : List α), l.modifyNthTail id n = l | 0, _ => rfl | _+1, [] => rfl From 3dc695cd00e9a3c1e8d9e7a71145eae3893c1495 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Sat, 8 Jun 2024 06:50:47 +1000 Subject: [PATCH 021/208] progress --- Batteries/Data/List/Lemmas.lean | 72 ++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index eb5a691338..354636d69b 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -340,9 +340,13 @@ theorem get?_modifyNth_eq (f : α → α) (n) (l : List α) : (modifyNth f n l).get? n = f <$> l.get? n := by simp only [get?_modifyNth, if_pos] -@[simp] theorem get?_modifyNth_ne (f : α → α) {m n} (l : List α) (h : m ≠ n) : +@[simp] theorem getElem?_modifyNth_ne (f : α → α) {m n} (l : List α) (h : m ≠ n) : + (modifyNth f m l)[n]? = l[n]? := by + simp only [getElem?_modifyNth, if_neg h, id_map'] + +theorem get?_modifyNth_ne (f : α → α) {m n} (l : List α) (h : m ≠ n) : (modifyNth f m l).get? n = l.get? n := by - simp only [get?_modifyNth, if_neg h, id_map'] + simp [h] theorem exists_of_modifyNth (f : α → α) {n} {l : List α} (h : n < l.length) : ∃ l₁ a l₂, l = l₁ ++ a :: l₂ ∧ l₁.length = n ∧ modifyNth f n l = l₁ ++ f a :: l₂ := @@ -396,38 +400,47 @@ theorem exists_of_set' {l : List α} (h : n < l.length) : @[simp] theorem getElem?_set_eq (a : α) (n) (l : List α) : (set l n a)[n]? = (fun _ => a) <$> l[n]? := by - simp only [set_eq_modifyNth, get?_modifyNth_eq] + simp only [set_eq_modifyNth, getElem?_modifyNth_eq] -@[simp] 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] + simp + +theorem getElem?_set_eq_of_lt (a : α) {n} {l : List α} (h : n < length l) : + (set l n a)[n]? = some a := by rw [getElem?_set_eq, getElem?_eq_getElem h]; rfl 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 @[simp] +theorem getElem?_set_ne (a : α) {m n} (l : List α) (h : m ≠ n) : (set l m a)[n]? = l[n]? := by + simp only [set_eq_modifyNth, getElem?_modifyNth_ne _ _ h] + 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] + simp [h] + +theorem getElem?_set (a : α) {m n} (l : List α) : + (set l m a)[n]? = if m = n then (fun _ => a) <$> l[n]? else l[n]? := by + by_cases m = n <;> simp [*] 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] + simp [getElem?_set] 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] + simp [getElem?_set, getElem?_eq_getElem 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 [getElem?_set]; split <;> subst_vars <;> simp [*, getElem?_eq_getElem h] theorem drop_set_of_lt (a : α) {n m : Nat} (l : List α) (h : n < m) : (l.set n a).drop m = l.drop m := - List.ext fun i => by rw [get?_drop, get?_drop, get?_set_ne _ _ (by omega)] + List.ext_get? fun i => by rw [get?_drop, get?_drop, get?_set_ne _ _ (by omega)] theorem take_set_of_lt (a : α) {n m : Nat} (l : List α) (h : m < n) : (l.set n a).take m = l.take m := - List.ext fun i => by + List.ext_get? fun i => by rw [get?_take_eq_if, get?_take_eq_if] split · next h' => rw [get?_set_ne _ _ (by omega)] @@ -1286,6 +1299,9 @@ protected theorem Pairwise.chain (p : Pairwise R (a :: l)) : Chain R a l := by /-! ### range', range -/ +theorem range'_succ (s n step) : range' s (n + 1) step = s :: range' (s + step) n step := by + simp [range', Nat.add_succ, Nat.mul_succ] + @[simp] theorem length_range' (s step) : ∀ n : Nat, length (range' s n step) = n | 0 => rfl | _ + 1 => congrArg succ (length_range' _ _ _) @@ -1348,16 +1364,26 @@ theorem range'_subset_right {s m n : Nat} (step0 : 0 < step) : theorem range'_subset_right_1 {s m n : Nat} : range' s m ⊆ range' s n ↔ m ≤ n := range'_subset_right (by decide) -theorem get?_range' (s step) : ∀ {m n : Nat}, m < n → get? (range' s n step) m = some (s + step * m) - | 0, n + 1, _ => rfl - | m + 1, n + 1, h => - (get?_range' (s + step) step (Nat.lt_of_add_lt_add_right h)).trans <| by +theorem getElem?_range' (s step) : + ∀ {m n : Nat}, m < n → (range' s n step)[m]? = some (s + step * m) + | 0, n + 1, _ => by simp [range'_succ] + | m + 1, n + 1, h => by + simp only [range'_succ, getElem?_cons_succ] + exact (getElem?_range' (s + step) step (Nat.lt_of_add_lt_add_right h)).trans <| by simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm] -@[simp] theorem get_range' {n m step} (i) (H : i < (range' n m step).length) : - get (range' n m step) ⟨i, H⟩ = n + step * i := +theorem get?_range' (s step) {m n : Nat} (h : m < n) : + get? (range' s n step) m = some (s + step * m) := by + simp [getElem?_range', h] + +@[simp] theorem getElem_range' {n m step} (i) (H : i < (range' n m step).length) : + (range' n m step)[i] = n + step * i := (get?_eq_some.1 <| get?_range' n step (by simpa using H)).2 +theorem get_range' {n m step} (i) (H : i < (range' n m step).length) : + get (range' n m step) ⟨i, H⟩ = n + step * i := by + simp + theorem range'_concat (s n : Nat) : range' s (n + 1) step = range' s n step ++ [s + step * n] := by rw [Nat.add_comm n 1]; exact (range'_append s n 1 step).symm @@ -1400,8 +1426,11 @@ theorem not_mem_range_self {n : Nat} : n ∉ range n := by simp theorem self_mem_range_succ (n : Nat) : n ∈ range (n + 1) := by simp +theorem getElem?_range {m n : Nat} (h : m < n) : (range n)[m]? = some m := by + simp [range_eq_range', getElem?_range' _ _ h] + theorem get?_range {m n : Nat} (h : m < n) : get? (range n) m = some m := by - simp [range_eq_range', get?_range' _ _ h] + simp [getElem?_range, h] theorem range_succ (n : Nat) : range (succ n) = range n ++ [n] := by simp only [range_eq_range', range'_1_concat, Nat.zero_add] @@ -1429,8 +1458,11 @@ theorem reverse_range' : ∀ s n : Nat, reverse (range' s n) = map (s + n - 1 - show s + (n + 1) - 1 = s + n from rfl, map, map_map] simp [reverse_range', Nat.sub_right_comm]; rfl -@[simp] theorem get_range {n} (i) (H : i < (range n).length) : get (range n) ⟨i, H⟩ = i := - Option.some.inj <| by rw [← get?_eq_get _, get?_range (by simpa using H)] +@[simp] theorem getElem_range {n} (i) (H : i < (range n).length) : (range n)[i] = i := + Option.some.inj <| by rw [← getElem?_eq_getElem _, getElem?_range (by simpa using H)] + +theorem get_range {n} (i) (H : i < (range n).length) : get (range n) ⟨i, H⟩ = i := by + simp /-! ### enum, enumFrom -/ From e4d1a815a803fecb83c5947e5f91e6f551788f7e Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sat, 8 Jun 2024 09:05:40 +0000 Subject: [PATCH 022/208] chore: bump to nightly-2024-06-08 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index a3a2c19b46..8a73558607 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-07 +leanprover/lean4:nightly-2024-06-08 From 1659998cdf16a6ce9f0c18fd7a1609f7315205ba Mon Sep 17 00:00:00 2001 From: L Date: Sat, 8 Jun 2024 14:29:35 -0700 Subject: [PATCH 023/208] feat: `measureRec` for strong induction use cases (#829) * feat: `Nat.strongRecOnMeasure` Co-Authored-By: Joachim Breitner --- Batteries/Data/Nat/Basic.lean | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Batteries/Data/Nat/Basic.lean b/Batteries/Data/Nat/Basic.lean index 9f7c7d8f36..a6e55a6ea2 100644 --- a/Batteries/Data/Nat/Basic.lean +++ b/Batteries/Data/Nat/Basic.lean @@ -28,6 +28,15 @@ protected def strongRec {motive : Nat → Sort _} (ind : ∀ n, (∀ m, m < n protected def strongRecOn (t : Nat) {motive : Nat → Sort _} (ind : ∀ n, (∀ m, m < n → motive m) → motive n) : motive t := Nat.strongRec ind t +/-- + Strong recursor via a `Nat`-valued measure +-/ +@[elab_as_elim] +def strongRecMeasure (f : α → Nat) {motive : α → Sort _} + (ind : ∀ x, (∀ y, f y < f x → motive y) → motive x) (x : α) : motive x := + ind x fun y _ => strongRecMeasure f ind y +termination_by f x + /-- Simple diagonal recursor for `Nat` -/ From 942f7c8497f3d8fbf925b4a33afb32203650d290 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sun, 9 Jun 2024 09:05:41 +0000 Subject: [PATCH 024/208] chore: bump to nightly-2024-06-09 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 8a73558607..d8c33b3609 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-08 +leanprover/lean4:nightly-2024-06-09 From 0e2013c1bfae2d5251dcd0e0c50299351cc55fc8 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 11 Jun 2024 15:23:29 +1000 Subject: [PATCH 025/208] fix --- Batteries/Data/List/Pairwise.lean | 2 +- lean-toolchain | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index 392f261bf2..65df1cf7a8 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -232,7 +232,7 @@ theorem sublist_eq_map_get (h : l' <+ l) : ∃ is : List (Fin l.length), | cons₂ _ _ IH => rcases IH with ⟨is,IH⟩ refine ⟨⟨0, by simp [Nat.zero_lt_succ]⟩ :: is.map (·.succ), ?_⟩ - simp [comp_def, pairwise_map, IH] + simp [comp_def, pairwise_map, IH, ← get_eq_getElem] theorem pairwise_iff_get : Pairwise R l ↔ ∀ (i j) (_hij : i < j), R (get l i) (get l j) := by rw [pairwise_iff_forall_sublist] diff --git a/lean-toolchain b/lean-toolchain index a3a2c19b46..78e5666991 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-07 +leanprover/lean4-pr-releases:pr-release-4400 From 066808f87108c59bff2d3588ad1eb6b3cafa2179 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 11 Jun 2024 15:34:25 +1000 Subject: [PATCH 026/208] chore: squeeze simps in HashMap.WF --- Batteries/Data/HashMap/WF.lean | 85 +++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index d535685691..fb2635b8fe 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -23,22 +23,25 @@ theorem update_data (self : Buckets α β) (i d h) : theorem exists_of_update (self : Buckets α β) (i d h) : ∃ l₁ l₂, self.1.data = l₁ ++ self.1[i] :: l₂ ∧ List.length l₁ = i.toNat ∧ (self.update i d h).1.data = l₁ ++ d :: l₂ := by - simp [Array.getElem_eq_data_get]; exact List.exists_of_set' h + simp only [Array.data_length, Array.ugetElem_eq_getElem, Array.getElem_eq_data_get] + exact List.exists_of_set' h theorem update_update (self : Buckets α β) (i d d' h h') : (self.update i d h).update i d' h' = self.update i d' h := by - simp [update]; congr 1; rw [Array.set_set] + simp only [update, Array.uset, Array.data_length] + congr 1 + rw [Array.set_set] theorem size_eq (data : Buckets α β) : size data = .sum (data.1.data.map (·.toList.length)) := rfl theorem mk_size (h) : (mk n h : Buckets α β).size = 0 := by - simp [Buckets.size_eq, Buckets.mk, mkArray]; clear h + simp only [mk, mkArray, size_eq]; clear h induction n <;> simp [*] theorem WF.mk' [BEq α] [Hashable α] (h) : (Buckets.mk n h : Buckets α β).WF := by refine ⟨fun _ h => ?_, fun i h => ?_⟩ - · simp [Buckets.mk, empty', mkArray, List.mem_replicate] at h + · simp only [Buckets.mk, mkArray, List.mem_replicate, ne_eq] at h simp [h, List.Pairwise.nil] · simp [Buckets.mk, empty', mkArray, Array.getElem_eq_data_get, AssocList.All] @@ -53,16 +56,19 @@ theorem WF.update [BEq α] [Hashable α] {buckets : Buckets α β} {i d h} (H : · exact match List.mem_or_eq_of_mem_set hl with | .inl hl => H.1 _ hl | .inr rfl => h₁ (H.1 _ (Array.getElem_mem_data ..)) - · revert hp; simp [update_data, Array.getElem_eq_data_get, List.get_set] + · revert hp + simp only [Array.getElem_eq_data_get, update_data, List.get_set, Array.data_length, update_size] split <;> intro hp · next eq => exact eq ▸ h₂ (H.2 _ _) _ hp - · simp at hi; exact H.2 i hi _ hp + · simp only [update_size, Array.data_length] at hi + exact H.2 i hi _ hp end Buckets theorem reinsertAux_size [Hashable α] (data : Buckets α β) (a : α) (b : β) : (reinsertAux data a b).size = data.size.succ := by - simp [Buckets.size_eq, reinsertAux] + simp only [reinsertAux, Array.data_length, Array.ugetElem_eq_getElem, Buckets.size_eq, + Nat.succ_eq_add_one] refine have ⟨l₁, l₂, h₁, _, eq⟩ := Buckets.exists_of_update ..; eq ▸ ?_ simp [h₁, Nat.succ_add]; rfl @@ -88,12 +94,13 @@ where · next H => refine (go (i+1) _ _ fun j hj => ?a).trans ?b <;> simp · case a => - simp [List.getD_eq_get?, List.get?_set]; split + simp only [List.getD_eq_get?, List.get?_set, Option.map_eq_map]; split · cases List.get? .. <;> rfl · next H => exact hs _ (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ hj) (Ne.symm H)) · case b => refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set' H; eq ▸ ?_ - simp [h₁, Buckets.size_eq] + simp only [Buckets.size_eq, h₁, List.map_append, List.map_cons, AssocList.toList, + List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length] rw [Nat.add_assoc, Nat.add_assoc, Nat.add_assoc]; congr 1 (conv => rhs; rw [Nat.add_left_comm]); congr 1 rw [← Array.getElem_eq_data_get] @@ -102,9 +109,10 @@ where · next H => rw [(_ : Nat.sum _ = 0), Nat.zero_add] rw [← (_ : source.data.map (fun _ => .nil) = source.data)] - · simp; induction source.data <;> simp [*] + · simp only [List.map_map] + induction source.data <;> simp [*] refine List.ext_get (by simp) fun j h₁ h₂ => ?_ - simp + simp only [List.get_map, Array.data_length] have := (hs j (Nat.lt_of_lt_of_le h₂ (Nat.not_lt.1 H))).symm rwa [List.getD_eq_get?, List.get?_eq_get, Option.getD_some] at this termination_by source.size - i @@ -126,7 +134,8 @@ theorem expand_WF.foldl [BEq α] [Hashable α] (rank : α → Nat) {l : List (α refine ih hl₁.2 hl₂.2 (reinsertAux_WF ht₁ fun _ h => (ht₂ _ (Array.getElem_mem_data ..) _ h).2.1) (fun _ h => ?_) - simp [reinsertAux, Buckets.update] at h + simp only [reinsertAux, Buckets.update, Array.uset, Array.data_length, + Array.ugetElem_eq_getElem, Array.data_set] at h match List.mem_or_eq_of_mem_set h with | .inl h => intro _ hf @@ -157,7 +166,9 @@ where · match List.mem_or_eq_of_mem_set hl with | .inl hl => exact hs₁ _ hl | .inr e => exact e ▸ .nil - · simp [Array.getElem_eq_data_get, List.get_set]; split + · simp only [Array.data_length, Array.size_set, Array.getElem_eq_data_get, Array.data_set, + List.get_set] + split · nofun · exact hs₂ _ (by simp_all) · let rank (k : α) := ((hash k).toUSize % source.size).toNat @@ -182,7 +193,7 @@ theorem insert_size [BEq α] [Hashable α] {m : Imp α β} {k v} · unfold Buckets.size refine have ⟨_, _, h₁, _, eq⟩ := Buckets.exists_of_update ..; eq ▸ ?_ simp [h, h₁, Buckets.size_eq, Nat.succ_add]; rfl - · rw [expand_size]; simp [h, expand, Buckets.size] + · rw [expand_size]; simp only [expand, h, Buckets.size, Array.data_length, Buckets.update_size] refine have ⟨_, _, h₁, _, eq⟩ := Buckets.exists_of_update ..; eq ▸ ?_ simp [h₁, Buckets.size_eq, Nat.succ_add]; rfl @@ -191,7 +202,8 @@ private theorem mem_replaceF {l : List (α × β)} {x : α × β} {p : α × β induction l with | nil => exact .inr | cons a l ih => - simp; generalize e : cond .. = z; revert e + simp only [List.replaceF, List.mem_cons] + generalize e : cond .. = z; revert e unfold cond; split <;> (intro h; subst h; simp) · intro | .inl eq => exact eq ▸ .inl rfl @@ -208,7 +220,7 @@ private theorem pairwise_replaceF [BEq α] [PartialEquivBEq α] induction l with | nil => simp [H] | cons a l ih => - simp at H ⊢ + simp only [List.pairwise_cons, List.replaceF] at H ⊢ generalize e : cond .. = z; unfold cond at e; revert e split <;> (intro h; subst h; simp) · next e => exact ⟨(H.1 · · ∘ PartialEquivBEq.trans e), H.2⟩ @@ -222,15 +234,17 @@ theorem insert_WF [BEq α] [Hashable α] {m : Imp α β} {k v} (h : m.buckets.WF) : (insert m k v).buckets.WF := by dsimp [insert, cond]; split · next h₁ => - simp at h₁; have ⟨x, hx₁, hx₂⟩ := h₁ + simp only [AssocList.contains_eq, List.any_eq_true] at h₁; have ⟨x, hx₁, hx₂⟩ := h₁ refine h.update (fun H => ?_) (fun H a h => ?_) - · simp; exact pairwise_replaceF H - · simp [AssocList.All] at H h ⊢ + · simp only [AssocList.toList_replace] + exact pairwise_replaceF H + · simp only [AssocList.All, Array.ugetElem_eq_getElem, AssocList.toList_replace] at H h ⊢ match mem_replaceF h with | .inl rfl => rfl | .inr h => exact H _ h · next h₁ => - rw [Bool.eq_false_iff] at h₁; simp at h₁ + rw [Bool.eq_false_iff] at h₁ + simp only [AssocList.contains_eq, ne_eq, List.any_eq_true, not_exists, not_and] at h₁ suffices _ by split <;> [exact this; refine expand_WF this] refine h.update (.cons ?_) (fun H a h => ?_) · exact fun a h h' => h₁ a h (PartialEquivBEq.symm h') @@ -243,12 +257,13 @@ theorem erase_size [BEq α] [Hashable α] {m : Imp α β} {k} (erase m k).size = (erase m k).buckets.size := by dsimp [erase, cond]; split · next H => - simp [h, Buckets.size] + simp only [h, Buckets.size] refine have ⟨_, _, h₁, _, eq⟩ := Buckets.exists_of_update ..; eq ▸ ?_ - simp [h, h₁, Buckets.size_eq] + simp only [h₁, Array.data_length, Array.ugetElem_eq_getElem, List.map_append, List.map_cons, + Nat.sum_append, Nat.sum_cons, AssocList.toList_erase] rw [(_ : List.length _ = _ + 1), Nat.add_right_comm]; {rfl} clear h₁ eq - simp [AssocList.contains_eq] at H + simp only [AssocList.contains_eq, List.any_eq_true] at H have ⟨a, h₁, h₂⟩ := H refine have ⟨_, _, _, _, _, h, eq⟩ := List.exists_of_eraseP h₁ h₂; eq ▸ ?_ simp [h]; rfl @@ -257,7 +272,7 @@ theorem erase_size [BEq α] [Hashable α] {m : Imp α β} {k} theorem erase_WF [BEq α] [Hashable α] {m : Imp α β} {k} (h : m.buckets.WF) : (erase m k).buckets.WF := by dsimp [erase, cond]; split - · refine h.update (fun H => ?_) (fun H a h => ?_) <;> simp at h ⊢ + · refine h.update (fun H => ?_) (fun H a h => ?_) <;> simp only [AssocList.toList_erase] at h ⊢ · exact H.sublist (List.eraseP_sublist _) · exact H _ (List.mem_of_mem_eraseP h) · exact h @@ -266,7 +281,7 @@ theorem modify_size [BEq α] [Hashable α] {m : Imp α β} {k} (h : m.size = m.buckets.size) : (modify m k f).size = (modify m k f).buckets.size := by dsimp [modify, cond]; rw [Buckets.update_update] - simp [h, Buckets.size] + simp only [h, Buckets.size] refine have ⟨_, _, h₁, _, eq⟩ := Buckets.exists_of_update ..; eq ▸ ?_ simp [h, h₁, Buckets.size_eq] @@ -275,7 +290,7 @@ theorem modify_WF [BEq α] [Hashable α] {m : Imp α β} {k} dsimp [modify, cond]; rw [Buckets.update_update] refine h.update (fun H => ?_) (fun H a h => ?_) <;> simp at h ⊢ · exact pairwise_replaceF H - · simp [AssocList.All] at H h ⊢ + · simp only [AssocList.All, Array.ugetElem_eq_getElem] at H h ⊢ match mem_replaceF h with | .inl rfl => rfl | .inr h => exact H _ h @@ -296,12 +311,13 @@ theorem WF_iff [BEq α] [Hashable α] {m : Imp α β} : theorem WF.mapVal {α β γ} {f : α → β → γ} [BEq α] [Hashable α] {m : Imp α β} (H : WF m) : WF (mapVal f m) := by have ⟨h₁, h₂⟩ := H.out - simp [Imp.mapVal, Buckets.mapVal, WF_iff, h₁]; refine ⟨?_, ?_, fun i h => ?_⟩ - · simp [Buckets.size]; congr; funext l; simp + simp only [Imp.mapVal, h₁, Buckets.mapVal, WF_iff]; refine ⟨?_, ?_, fun i h => ?_⟩ + · simp only [Buckets.size, Array.map_data, List.map_map]; congr; funext l; simp · simp only [Array.map_data, List.forall_mem_map_iff] simp only [AssocList.toList_mapVal, List.pairwise_map] exact fun _ => h₂.1 _ - · simp [AssocList.All] at h ⊢ + · simp only [Array.size_map, AssocList.All, Array.getElem_map, AssocList.toList_mapVal, + List.mem_map, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂] at h ⊢ intro a m apply h₂.2 _ _ _ m @@ -313,7 +329,11 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable induction l generalizing n acc with simp [filterMap.go, g₁, *] | cons a b l => match f a b with | none => rfl - | some c => simp; rw [Nat.add_right_comm]; rfl + | some c => + simp only [Option.map_some', List.reverse_cons, List.append_assoc, List.singleton_append, + List.length_cons, Nat.succ_eq_add_one, Prod.mk.injEq, true_and] + rw [Nat.add_right_comm] + rfl let g l := (g₁ l).reverse.toAssocList let M := StateT (ULift Nat) Id have H2 (l : List (AssocList α β)) n : @@ -334,7 +354,7 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable suffices ∀ bk sz (h : 0 < bk.length), m.buckets.val.mapM (m := M) (filterMap.go f .nil) ⟨0⟩ = (⟨bk⟩, ⟨sz⟩) → WF ⟨sz, ⟨bk⟩, h⟩ from this _ _ _ rfl - simp [Array.mapM_eq_mapM_data, bind, StateT.bind, H2, g] + simp only [Array.mapM_eq_mapM_data, bind, StateT.bind, H2, List.map_map, Nat.zero_add, g] intro bk sz h e'; cases e' refine .mk (by simp [Buckets.size]) ⟨?_, fun i h => ?_⟩ · simp only [List.forall_mem_map_iff, List.toList_toAssocList] @@ -345,7 +365,8 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable · simp only [Array.size_mk, List.length_map, Array.data_length, Array.getElem_eq_data_get, List.get_map] at h ⊢ have := H.out.2.2 _ h - simp [AssocList.All, g₁] at this ⊢ + simp only [AssocList.All, List.toList_toAssocList, List.mem_reverse, List.mem_filterMap, + Option.map_eq_some', forall_exists_index, and_imp, g₁] at this ⊢ rintro _ _ h' _ _ rfl exact this _ h' From 0d7203e65dfa66b4328b36b2ff3d65793f670c1e Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 11 Jun 2024 15:51:42 +1000 Subject: [PATCH 027/208] fixes --- Batteries/Data/HashMap/WF.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index fb2635b8fe..9f46cbd9b7 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -87,15 +87,15 @@ theorem expand_size [Hashable α] {buckets : Buckets α β} : · rw [Buckets.mk_size]; simp [Buckets.size] · nofun where - go (i source) (target : Buckets α β) (hs : ∀ j < i, source.data.getD j .nil = .nil) : + go (i source) (target : Buckets α β) (hs : ∀ j < i, source.data[j]?.getD .nil = .nil) : (expand.go i source target).size = .sum (source.data.map (·.toList.length)) + target.size := by unfold expand.go; split · next H => refine (go (i+1) _ _ fun j hj => ?a).trans ?b <;> simp · case a => - simp only [List.getD_eq_get?, List.get?_set, Option.map_eq_map]; split - · cases List.get? .. <;> rfl + simp [List.getD_eq_get?, List.getElem?_set, Option.map_eq_map]; split + · cases source.data[j]? <;> rfl · next H => exact hs _ (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ hj) (Ne.symm H)) · case b => refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set' H; eq ▸ ?_ @@ -114,7 +114,7 @@ where refine List.ext_get (by simp) fun j h₁ h₂ => ?_ simp only [List.get_map, Array.data_length] have := (hs j (Nat.lt_of_lt_of_le h₂ (Nat.not_lt.1 H))).symm - rwa [List.getD_eq_get?, List.get?_eq_get, Option.getD_some] at this + rwa [List.getElem?_eq_getElem] at this termination_by source.size - i theorem expand_WF.foldl [BEq α] [Hashable α] (rank : α → Nat) {l : List (α × β)} {i : Nat} From 17987b09743026f71b0508488d1904f49109d8a0 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 11 Jun 2024 06:52:19 +0100 Subject: [PATCH 028/208] chore: squeeze simps in HashMap.WF (#833) --- Batteries/Data/HashMap/WF.lean | 85 +++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index d535685691..fb2635b8fe 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -23,22 +23,25 @@ theorem update_data (self : Buckets α β) (i d h) : theorem exists_of_update (self : Buckets α β) (i d h) : ∃ l₁ l₂, self.1.data = l₁ ++ self.1[i] :: l₂ ∧ List.length l₁ = i.toNat ∧ (self.update i d h).1.data = l₁ ++ d :: l₂ := by - simp [Array.getElem_eq_data_get]; exact List.exists_of_set' h + simp only [Array.data_length, Array.ugetElem_eq_getElem, Array.getElem_eq_data_get] + exact List.exists_of_set' h theorem update_update (self : Buckets α β) (i d d' h h') : (self.update i d h).update i d' h' = self.update i d' h := by - simp [update]; congr 1; rw [Array.set_set] + simp only [update, Array.uset, Array.data_length] + congr 1 + rw [Array.set_set] theorem size_eq (data : Buckets α β) : size data = .sum (data.1.data.map (·.toList.length)) := rfl theorem mk_size (h) : (mk n h : Buckets α β).size = 0 := by - simp [Buckets.size_eq, Buckets.mk, mkArray]; clear h + simp only [mk, mkArray, size_eq]; clear h induction n <;> simp [*] theorem WF.mk' [BEq α] [Hashable α] (h) : (Buckets.mk n h : Buckets α β).WF := by refine ⟨fun _ h => ?_, fun i h => ?_⟩ - · simp [Buckets.mk, empty', mkArray, List.mem_replicate] at h + · simp only [Buckets.mk, mkArray, List.mem_replicate, ne_eq] at h simp [h, List.Pairwise.nil] · simp [Buckets.mk, empty', mkArray, Array.getElem_eq_data_get, AssocList.All] @@ -53,16 +56,19 @@ theorem WF.update [BEq α] [Hashable α] {buckets : Buckets α β} {i d h} (H : · exact match List.mem_or_eq_of_mem_set hl with | .inl hl => H.1 _ hl | .inr rfl => h₁ (H.1 _ (Array.getElem_mem_data ..)) - · revert hp; simp [update_data, Array.getElem_eq_data_get, List.get_set] + · revert hp + simp only [Array.getElem_eq_data_get, update_data, List.get_set, Array.data_length, update_size] split <;> intro hp · next eq => exact eq ▸ h₂ (H.2 _ _) _ hp - · simp at hi; exact H.2 i hi _ hp + · simp only [update_size, Array.data_length] at hi + exact H.2 i hi _ hp end Buckets theorem reinsertAux_size [Hashable α] (data : Buckets α β) (a : α) (b : β) : (reinsertAux data a b).size = data.size.succ := by - simp [Buckets.size_eq, reinsertAux] + simp only [reinsertAux, Array.data_length, Array.ugetElem_eq_getElem, Buckets.size_eq, + Nat.succ_eq_add_one] refine have ⟨l₁, l₂, h₁, _, eq⟩ := Buckets.exists_of_update ..; eq ▸ ?_ simp [h₁, Nat.succ_add]; rfl @@ -88,12 +94,13 @@ where · next H => refine (go (i+1) _ _ fun j hj => ?a).trans ?b <;> simp · case a => - simp [List.getD_eq_get?, List.get?_set]; split + simp only [List.getD_eq_get?, List.get?_set, Option.map_eq_map]; split · cases List.get? .. <;> rfl · next H => exact hs _ (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ hj) (Ne.symm H)) · case b => refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set' H; eq ▸ ?_ - simp [h₁, Buckets.size_eq] + simp only [Buckets.size_eq, h₁, List.map_append, List.map_cons, AssocList.toList, + List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length] rw [Nat.add_assoc, Nat.add_assoc, Nat.add_assoc]; congr 1 (conv => rhs; rw [Nat.add_left_comm]); congr 1 rw [← Array.getElem_eq_data_get] @@ -102,9 +109,10 @@ where · next H => rw [(_ : Nat.sum _ = 0), Nat.zero_add] rw [← (_ : source.data.map (fun _ => .nil) = source.data)] - · simp; induction source.data <;> simp [*] + · simp only [List.map_map] + induction source.data <;> simp [*] refine List.ext_get (by simp) fun j h₁ h₂ => ?_ - simp + simp only [List.get_map, Array.data_length] have := (hs j (Nat.lt_of_lt_of_le h₂ (Nat.not_lt.1 H))).symm rwa [List.getD_eq_get?, List.get?_eq_get, Option.getD_some] at this termination_by source.size - i @@ -126,7 +134,8 @@ theorem expand_WF.foldl [BEq α] [Hashable α] (rank : α → Nat) {l : List (α refine ih hl₁.2 hl₂.2 (reinsertAux_WF ht₁ fun _ h => (ht₂ _ (Array.getElem_mem_data ..) _ h).2.1) (fun _ h => ?_) - simp [reinsertAux, Buckets.update] at h + simp only [reinsertAux, Buckets.update, Array.uset, Array.data_length, + Array.ugetElem_eq_getElem, Array.data_set] at h match List.mem_or_eq_of_mem_set h with | .inl h => intro _ hf @@ -157,7 +166,9 @@ where · match List.mem_or_eq_of_mem_set hl with | .inl hl => exact hs₁ _ hl | .inr e => exact e ▸ .nil - · simp [Array.getElem_eq_data_get, List.get_set]; split + · simp only [Array.data_length, Array.size_set, Array.getElem_eq_data_get, Array.data_set, + List.get_set] + split · nofun · exact hs₂ _ (by simp_all) · let rank (k : α) := ((hash k).toUSize % source.size).toNat @@ -182,7 +193,7 @@ theorem insert_size [BEq α] [Hashable α] {m : Imp α β} {k v} · unfold Buckets.size refine have ⟨_, _, h₁, _, eq⟩ := Buckets.exists_of_update ..; eq ▸ ?_ simp [h, h₁, Buckets.size_eq, Nat.succ_add]; rfl - · rw [expand_size]; simp [h, expand, Buckets.size] + · rw [expand_size]; simp only [expand, h, Buckets.size, Array.data_length, Buckets.update_size] refine have ⟨_, _, h₁, _, eq⟩ := Buckets.exists_of_update ..; eq ▸ ?_ simp [h₁, Buckets.size_eq, Nat.succ_add]; rfl @@ -191,7 +202,8 @@ private theorem mem_replaceF {l : List (α × β)} {x : α × β} {p : α × β induction l with | nil => exact .inr | cons a l ih => - simp; generalize e : cond .. = z; revert e + simp only [List.replaceF, List.mem_cons] + generalize e : cond .. = z; revert e unfold cond; split <;> (intro h; subst h; simp) · intro | .inl eq => exact eq ▸ .inl rfl @@ -208,7 +220,7 @@ private theorem pairwise_replaceF [BEq α] [PartialEquivBEq α] induction l with | nil => simp [H] | cons a l ih => - simp at H ⊢ + simp only [List.pairwise_cons, List.replaceF] at H ⊢ generalize e : cond .. = z; unfold cond at e; revert e split <;> (intro h; subst h; simp) · next e => exact ⟨(H.1 · · ∘ PartialEquivBEq.trans e), H.2⟩ @@ -222,15 +234,17 @@ theorem insert_WF [BEq α] [Hashable α] {m : Imp α β} {k v} (h : m.buckets.WF) : (insert m k v).buckets.WF := by dsimp [insert, cond]; split · next h₁ => - simp at h₁; have ⟨x, hx₁, hx₂⟩ := h₁ + simp only [AssocList.contains_eq, List.any_eq_true] at h₁; have ⟨x, hx₁, hx₂⟩ := h₁ refine h.update (fun H => ?_) (fun H a h => ?_) - · simp; exact pairwise_replaceF H - · simp [AssocList.All] at H h ⊢ + · simp only [AssocList.toList_replace] + exact pairwise_replaceF H + · simp only [AssocList.All, Array.ugetElem_eq_getElem, AssocList.toList_replace] at H h ⊢ match mem_replaceF h with | .inl rfl => rfl | .inr h => exact H _ h · next h₁ => - rw [Bool.eq_false_iff] at h₁; simp at h₁ + rw [Bool.eq_false_iff] at h₁ + simp only [AssocList.contains_eq, ne_eq, List.any_eq_true, not_exists, not_and] at h₁ suffices _ by split <;> [exact this; refine expand_WF this] refine h.update (.cons ?_) (fun H a h => ?_) · exact fun a h h' => h₁ a h (PartialEquivBEq.symm h') @@ -243,12 +257,13 @@ theorem erase_size [BEq α] [Hashable α] {m : Imp α β} {k} (erase m k).size = (erase m k).buckets.size := by dsimp [erase, cond]; split · next H => - simp [h, Buckets.size] + simp only [h, Buckets.size] refine have ⟨_, _, h₁, _, eq⟩ := Buckets.exists_of_update ..; eq ▸ ?_ - simp [h, h₁, Buckets.size_eq] + simp only [h₁, Array.data_length, Array.ugetElem_eq_getElem, List.map_append, List.map_cons, + Nat.sum_append, Nat.sum_cons, AssocList.toList_erase] rw [(_ : List.length _ = _ + 1), Nat.add_right_comm]; {rfl} clear h₁ eq - simp [AssocList.contains_eq] at H + simp only [AssocList.contains_eq, List.any_eq_true] at H have ⟨a, h₁, h₂⟩ := H refine have ⟨_, _, _, _, _, h, eq⟩ := List.exists_of_eraseP h₁ h₂; eq ▸ ?_ simp [h]; rfl @@ -257,7 +272,7 @@ theorem erase_size [BEq α] [Hashable α] {m : Imp α β} {k} theorem erase_WF [BEq α] [Hashable α] {m : Imp α β} {k} (h : m.buckets.WF) : (erase m k).buckets.WF := by dsimp [erase, cond]; split - · refine h.update (fun H => ?_) (fun H a h => ?_) <;> simp at h ⊢ + · refine h.update (fun H => ?_) (fun H a h => ?_) <;> simp only [AssocList.toList_erase] at h ⊢ · exact H.sublist (List.eraseP_sublist _) · exact H _ (List.mem_of_mem_eraseP h) · exact h @@ -266,7 +281,7 @@ theorem modify_size [BEq α] [Hashable α] {m : Imp α β} {k} (h : m.size = m.buckets.size) : (modify m k f).size = (modify m k f).buckets.size := by dsimp [modify, cond]; rw [Buckets.update_update] - simp [h, Buckets.size] + simp only [h, Buckets.size] refine have ⟨_, _, h₁, _, eq⟩ := Buckets.exists_of_update ..; eq ▸ ?_ simp [h, h₁, Buckets.size_eq] @@ -275,7 +290,7 @@ theorem modify_WF [BEq α] [Hashable α] {m : Imp α β} {k} dsimp [modify, cond]; rw [Buckets.update_update] refine h.update (fun H => ?_) (fun H a h => ?_) <;> simp at h ⊢ · exact pairwise_replaceF H - · simp [AssocList.All] at H h ⊢ + · simp only [AssocList.All, Array.ugetElem_eq_getElem] at H h ⊢ match mem_replaceF h with | .inl rfl => rfl | .inr h => exact H _ h @@ -296,12 +311,13 @@ theorem WF_iff [BEq α] [Hashable α] {m : Imp α β} : theorem WF.mapVal {α β γ} {f : α → β → γ} [BEq α] [Hashable α] {m : Imp α β} (H : WF m) : WF (mapVal f m) := by have ⟨h₁, h₂⟩ := H.out - simp [Imp.mapVal, Buckets.mapVal, WF_iff, h₁]; refine ⟨?_, ?_, fun i h => ?_⟩ - · simp [Buckets.size]; congr; funext l; simp + simp only [Imp.mapVal, h₁, Buckets.mapVal, WF_iff]; refine ⟨?_, ?_, fun i h => ?_⟩ + · simp only [Buckets.size, Array.map_data, List.map_map]; congr; funext l; simp · simp only [Array.map_data, List.forall_mem_map_iff] simp only [AssocList.toList_mapVal, List.pairwise_map] exact fun _ => h₂.1 _ - · simp [AssocList.All] at h ⊢ + · simp only [Array.size_map, AssocList.All, Array.getElem_map, AssocList.toList_mapVal, + List.mem_map, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂] at h ⊢ intro a m apply h₂.2 _ _ _ m @@ -313,7 +329,11 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable induction l generalizing n acc with simp [filterMap.go, g₁, *] | cons a b l => match f a b with | none => rfl - | some c => simp; rw [Nat.add_right_comm]; rfl + | some c => + simp only [Option.map_some', List.reverse_cons, List.append_assoc, List.singleton_append, + List.length_cons, Nat.succ_eq_add_one, Prod.mk.injEq, true_and] + rw [Nat.add_right_comm] + rfl let g l := (g₁ l).reverse.toAssocList let M := StateT (ULift Nat) Id have H2 (l : List (AssocList α β)) n : @@ -334,7 +354,7 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable suffices ∀ bk sz (h : 0 < bk.length), m.buckets.val.mapM (m := M) (filterMap.go f .nil) ⟨0⟩ = (⟨bk⟩, ⟨sz⟩) → WF ⟨sz, ⟨bk⟩, h⟩ from this _ _ _ rfl - simp [Array.mapM_eq_mapM_data, bind, StateT.bind, H2, g] + simp only [Array.mapM_eq_mapM_data, bind, StateT.bind, H2, List.map_map, Nat.zero_add, g] intro bk sz h e'; cases e' refine .mk (by simp [Buckets.size]) ⟨?_, fun i h => ?_⟩ · simp only [List.forall_mem_map_iff, List.toList_toAssocList] @@ -345,7 +365,8 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable · simp only [Array.size_mk, List.length_map, Array.data_length, Array.getElem_eq_data_get, List.get_map] at h ⊢ have := H.out.2.2 _ h - simp [AssocList.All, g₁] at this ⊢ + simp only [AssocList.All, List.toList_toAssocList, List.mem_reverse, List.mem_filterMap, + Option.map_eq_some', forall_exists_index, and_imp, g₁] at this ⊢ rintro _ _ h' _ _ rfl exact this _ h' From 9f893b9583eb87f94f3dd45e19a147f9f72158b4 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 11 Jun 2024 16:12:21 +1000 Subject: [PATCH 029/208] . --- Batteries/Data/List/Lemmas.lean | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 354636d69b..3b6955e8fc 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -243,9 +243,12 @@ theorem tail_eq_tail? (l) : @tail α l = (tail? l).getD [] := by simp [tail_eq_t /-! ### get? -/ -theorem get_eq_iff : List.get l n = x ↔ l.get? n.1 = some x := by +theorem getElem_eq_iff {l : List α} {n : Nat} {h : n < l.length} : l[n] = x ↔ l[n]? = some x := by simp only [get_eq_getElem, get?_eq_getElem?, getElem?_eq_some] - exact ⟨fun h => ⟨n.2, h⟩, fun h => h.2⟩ + exact ⟨fun w => ⟨h, w⟩, fun h => h.2⟩ + +theorem get_eq_iff : List.get l n = x ↔ l.get? n.1 = some x := by + simp [getElem_eq_iff] theorem get?_inj (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs.get? i = xs.get? j) : i = j := by From 218e3a290a77d46367649513e5cbc9279805752c Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Tue, 11 Jun 2024 09:06:03 +0000 Subject: [PATCH 030/208] chore: bump to nightly-2024-06-11 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index d8c33b3609..c868e61f55 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-09 +leanprover/lean4:nightly-2024-06-11 From 24ab71f07ccb2356bcca24d24db9d81e33eee8d2 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 11 Jun 2024 20:01:43 +1000 Subject: [PATCH 031/208] deprecations --- Batteries/Data/Char.lean | 14 +++---------- Batteries/Data/String/Lemmas.lean | 34 ++++++++++++++++--------------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/Batteries/Data/Char.lean b/Batteries/Data/Char.lean index c94b35ac44..5a9110ae12 100644 --- a/Batteries/Data/Char.lean +++ b/Batteries/Data/Char.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jannis Limperg -/ import Batteries.Data.UInt +import Batteries.Tactic.Alias @[ext] theorem Char.ext : {a b : Char} → a.val = b.val → a = b | ⟨_,_⟩, ⟨_,_⟩, rfl => rfl @@ -21,16 +22,7 @@ instance : Batteries.LawfulOrd Char := .compareOfLessAndEq namespace String -private theorem csize_eq (c) : - csize c = 1 ∨ csize c = 2 ∨ csize c = 3 ∨ - csize c = 4 := by - simp only [csize, Char.utf8Size] - repeat (first | split | (solve | simp (config := {decide := true}))) - -theorem csize_pos (c) : 0 < csize c := by - rcases csize_eq c with _|_|_|_ <;> simp_all (config := {decide := true}) - -theorem csize_le_4 (c) : csize c ≤ 4 := by - rcases csize_eq c with _|_|_|_ <;> simp_all (config := {decide := true}) +@[deprecated (since := "2024-06-11")] alias csize_pos := Char.utf8Size_pos +@[deprecated (since := "2024-06-11")] alias csize_le_4 := Char.utf8Size_le_four end String diff --git a/Batteries/Data/String/Lemmas.lean b/Batteries/Data/String/Lemmas.lean index 8a9376fe05..0b779d30ad 100644 --- a/Batteries/Data/String/Lemmas.lean +++ b/Batteries/Data/String/Lemmas.lean @@ -33,13 +33,13 @@ instance : Batteries.BEqOrd String := .compareOfLessAndEq String.lt_irrefl attribute [simp] toList -- prefer `String.data` over `String.toList` in lemmas -private theorem add_csize_pos : 0 < i + csize c := - Nat.add_pos_right _ (csize_pos c) +private theorem add_csize_pos : 0 < i + Char.utf8Size c := + Nat.add_pos_right _ (Char.utf8Size_pos c) -private theorem ne_add_csize_add_self : i ≠ n + csize c + i := +private theorem ne_add_csize_add_self : i ≠ n + Char.utf8Size c + i := Nat.ne_of_lt (Nat.lt_add_of_pos_left add_csize_pos) -private theorem ne_self_add_add_csize : i ≠ i + (n + csize c) := +private theorem ne_self_add_add_csize : i ≠ i + (n + Char.utf8Size c) := Nat.ne_of_lt (Nat.lt_add_of_pos_right add_csize_pos) /-- The UTF-8 byte length of a list of characters. (This is intended for specification purposes.) -/ @@ -51,7 +51,7 @@ private theorem ne_self_add_add_csize : i ≠ i + (n + csize c) := @[simp] theorem utf8Len_nil : utf8Len [] = 0 := rfl -@[simp] theorem utf8Len_cons (c cs) : utf8Len (c :: cs) = utf8Len cs + csize c := rfl +@[simp] theorem utf8Len_cons (c cs) : utf8Len (c :: cs) = utf8Len cs + c.utf8Size := rfl @[simp] theorem utf8Len_append (cs₁ cs₂) : utf8Len (cs₁ ++ cs₂) = utf8Len cs₁ + utf8Len cs₂ := by induction cs₁ <;> simp [*, Nat.add_right_comm] @@ -88,7 +88,7 @@ namespace Pos attribute [ext] ext -theorem lt_addChar (p : Pos) (c : Char) : p < p + c := Nat.lt_add_of_pos_right (csize_pos _) +theorem lt_addChar (p : Pos) (c : Char) : p < p + c := Nat.lt_add_of_pos_right (Char.utf8Size_pos _) private theorem zero_ne_addChar {i : Pos} {c : Char} : 0 ≠ i + c := ne_of_lt add_csize_pos @@ -197,11 +197,11 @@ theorem modify_of_valid (cs cs' : List Char) : rw [modify, set_of_valid, get_of_valid]; cases cs' <;> rfl theorem next_of_valid' (cs cs' : List Char) : - next ⟨cs ++ cs'⟩ ⟨utf8Len cs⟩ = ⟨utf8Len cs + csize (cs'.headD default)⟩ := by + next ⟨cs ++ cs'⟩ ⟨utf8Len cs⟩ = ⟨utf8Len cs + (cs'.headD default).utf8Size⟩ := by simp only [next, get_of_valid]; rfl theorem next_of_valid (cs : List Char) (c : Char) (cs' : List Char) : - next ⟨cs ++ c :: cs'⟩ ⟨utf8Len cs⟩ = ⟨utf8Len cs + csize c⟩ := next_of_valid' .. + next ⟨cs ++ c :: cs'⟩ ⟨utf8Len cs⟩ = ⟨utf8Len cs + c.utf8Size⟩ := next_of_valid' .. @[simp] theorem atEnd_iff (s : String) (p : Pos) : atEnd s p ↔ s.endPos ≤ p := decide_eq_true_iff _ @@ -214,7 +214,7 @@ theorem valid_next {p : Pos} (h : p.Valid s) (h₂ : p < s.endPos) : (next s p). simpa using Pos.Valid.mk (cs ++ [c]) cs' theorem utf8PrevAux_of_valid {cs cs' : List Char} {c : Char} {i p : Nat} - (hp : i + (utf8Len cs + csize c) = p) : + (hp : i + (utf8Len cs + c.utf8Size) = p) : utf8PrevAux (cs ++ c :: cs') ⟨i⟩ ⟨p⟩ = ⟨i + utf8Len cs⟩ := by match cs with | [] => simp [utf8PrevAux, ← hp, Pos.addChar_eq] @@ -226,7 +226,7 @@ theorem utf8PrevAux_of_valid {cs cs' : List Char} {c : Char} {i p : Nat} simp [Nat.add_assoc, Nat.add_comm] theorem prev_of_valid (cs : List Char) (c : Char) (cs' : List Char) : - prev ⟨cs ++ c :: cs'⟩ ⟨utf8Len cs + csize c⟩ = ⟨utf8Len cs⟩ := by + prev ⟨cs ++ c :: cs'⟩ ⟨utf8Len cs + c.utf8Size⟩ = ⟨utf8Len cs⟩ := by simp [prev]; refine (if_neg (Pos.ne_of_gt add_csize_pos)).trans ?_ rw [utf8PrevAux_of_valid] <;> simp @@ -310,9 +310,9 @@ theorem firstDiffPos_loop_eq (l₁ l₂ r₁ r₂ stop p) show get ⟨l₂ ++ b :: r₂⟩ ⟨p⟩ = b by simp [hl₂, get_of_valid]] simp; split <;> simp subst b - rw [show next ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = ⟨utf8Len l₁ + csize a⟩ by simp [hl₁, next_of_valid]] + rw [show next ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = ⟨utf8Len l₁ + a.utf8Size⟩ by simp [hl₁, next_of_valid]] simpa [← hl₁, ← Nat.add_assoc, Nat.add_right_comm] using - firstDiffPos_loop_eq (l₁ ++ [a]) (l₂ ++ [a]) r₁ r₂ stop (p + csize a) + firstDiffPos_loop_eq (l₁ ++ [a]) (l₂ ++ [a]) r₁ r₂ stop (p + a.utf8Size) (by simp [hl₁]) (by simp [hl₂]) (by simp [hstop, ← Nat.add_assoc, Nat.add_right_comm]) · next h => rw [dif_neg] <;> simp [hstop, ← hl₁, ← hl₂, -Nat.not_lt, Nat.lt_min] @@ -758,7 +758,8 @@ theorem toIterator : ∀ {s}, ValidFor l m r s → s.toIterator.ValidFor l.rever theorem get : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → s.get ⟨utf8Len m₁⟩ = c | _, ⟨⟩ => by simpa using get_of_valid (l ++ m₁) (c :: m₂ ++ r) -theorem next : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → s.next ⟨utf8Len m₁⟩ = ⟨utf8Len m₁ + csize c⟩ +theorem next : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → + s.next ⟨utf8Len m₁⟩ = ⟨utf8Len m₁ + c.utf8Size⟩ | _, ⟨⟩ => by simp [Substring.next] rw [if_neg (mt Pos.ext_iff.1 ?a)] @@ -772,7 +773,8 @@ theorem next : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → s.next ⟨utf8Len theorem next_stop : ∀ {s}, ValidFor l m r s → s.next ⟨utf8Len m⟩ = ⟨utf8Len m⟩ | _, ⟨⟩ => by simp [Substring.next, Pos.add_eq] -theorem prev : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → s.prev ⟨utf8Len m₁ + csize c⟩ = ⟨utf8Len m₁⟩ +theorem prev : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → + s.prev ⟨utf8Len m₁ + c.utf8Size⟩ = ⟨utf8Len m₁⟩ | _, ⟨⟩ => by simp [Substring.prev] rw [if_neg (mt Pos.ext_iff.1 <| Ne.symm ?a)] @@ -916,7 +918,7 @@ theorem get : ∀ {s}, Valid s → s.toString.1 = m₁ ++ c :: m₂ → s.get simp [h.toString] at e; subst e; simp [h.get] theorem next : ∀ {s}, Valid s → s.toString.1 = m₁ ++ c :: m₂ → - s.next ⟨utf8Len m₁⟩ = ⟨utf8Len m₁ + csize c⟩ + s.next ⟨utf8Len m₁⟩ = ⟨utf8Len m₁ + c.utf8Size⟩ | _, h, e => by let ⟨l, m, r, h⟩ := h.validFor simp [h.toString] at e; subst e; simp [h.next] @@ -925,7 +927,7 @@ theorem next_stop : ∀ {s}, Valid s → s.next ⟨s.bsize⟩ = ⟨s.bsize⟩ | _, h => let ⟨l, m, r, h⟩ := h.validFor; by simp [h.bsize, h.next_stop] theorem prev : ∀ {s}, Valid s → s.toString.1 = m₁ ++ c :: m₂ → - s.prev ⟨utf8Len m₁ + csize c⟩ = ⟨utf8Len m₁⟩ + s.prev ⟨utf8Len m₁ + c.utf8Size⟩ = ⟨utf8Len m₁⟩ | _, h, e => by let ⟨l, m, r, h⟩ := h.validFor simp [h.toString] at e; subst e; simp [h.prev] From f96a34401de084c73c787ecb45b85d4fb47bb981 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 12 Jun 2024 02:26:30 +0100 Subject: [PATCH 032/208] chore(RBSet): consolidate API from mathlib (#834) --- Batteries/Data/RBMap/Basic.lean | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Batteries/Data/RBMap/Basic.lean b/Batteries/Data/RBMap/Basic.lean index ae60899f26..a9ba215ad9 100644 --- a/Batteries/Data/RBMap/Basic.lean +++ b/Batteries/Data/RBMap/Basic.lean @@ -678,6 +678,16 @@ instance [Repr α] : Repr (RBSet α cmp) where /-- `O(log n)`. Insert element `v` into the tree. -/ @[inline] def insert (t : RBSet α cmp) (v : α) : RBSet α cmp := ⟨t.1.insert cmp v, t.2.insert⟩ +/-- +Insert all elements from a collection into a `RBSet α cmp`. +-/ +def insertMany [ForIn Id ρ α] (s : RBSet α cmp) (as : ρ) : + RBSet α cmp := Id.run do + let mut s := s + for a in as do + s := s.insert a + return s + /-- `O(log n)`. Remove an element from the tree using a cut function. The `cut` function is used to locate an element in the tree: From 42b5dddbd6b2658fcfede9dad26cc47737edec2d Mon Sep 17 00:00:00 2001 From: L Date: Tue, 11 Jun 2024 23:15:19 -0700 Subject: [PATCH 033/208] fix(linter): "(invalid MessageData.lazy, missing context)" (#838) --- Batteries/Tactic/Lint/Frontend.lean | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Batteries/Tactic/Lint/Frontend.lean b/Batteries/Tactic/Lint/Frontend.lean index 4eff8b1450..072e23743f 100644 --- a/Batteries/Tactic/Lint/Frontend.lean +++ b/Batteries/Tactic/Lint/Frontend.lean @@ -125,9 +125,11 @@ def printWarning (declName : Name) (warning : MessageData) (useErrorFormat : Boo (filePath : System.FilePath := default) : CoreM MessageData := do if useErrorFormat then if let some range ← findDeclarationRanges? declName then - return m!"{filePath}:{range.range.pos.line}:{range.range.pos.column + 1}: error: { + let msg ← addMessageContextPartial + m!"{filePath}:{range.range.pos.line}:{range.range.pos.column + 1}: error: { ← mkConstWithLevelParams declName} {warning}" - pure m!"#check {← mkConstWithLevelParams declName} /- {warning} -/" + return msg + addMessageContextPartial m!"#check {← mkConstWithLevelParams declName} /- {warning} -/" /-- Formats a map of linter warnings using `print_warning`, sorted by line number. -/ def printWarnings (results : HashMap Name MessageData) (filePath : System.FilePath := default) From 46696580c21fbb17833fb7b4ad55ecce05e05957 Mon Sep 17 00:00:00 2001 From: L Date: Tue, 11 Jun 2024 23:15:19 -0700 Subject: [PATCH 034/208] fix(linter): "(invalid MessageData.lazy, missing context)" (#838) --- Batteries/Tactic/Lint/Frontend.lean | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Batteries/Tactic/Lint/Frontend.lean b/Batteries/Tactic/Lint/Frontend.lean index 4eff8b1450..072e23743f 100644 --- a/Batteries/Tactic/Lint/Frontend.lean +++ b/Batteries/Tactic/Lint/Frontend.lean @@ -125,9 +125,11 @@ def printWarning (declName : Name) (warning : MessageData) (useErrorFormat : Boo (filePath : System.FilePath := default) : CoreM MessageData := do if useErrorFormat then if let some range ← findDeclarationRanges? declName then - return m!"{filePath}:{range.range.pos.line}:{range.range.pos.column + 1}: error: { + let msg ← addMessageContextPartial + m!"{filePath}:{range.range.pos.line}:{range.range.pos.column + 1}: error: { ← mkConstWithLevelParams declName} {warning}" - pure m!"#check {← mkConstWithLevelParams declName} /- {warning} -/" + return msg + addMessageContextPartial m!"#check {← mkConstWithLevelParams declName} /- {warning} -/" /-- Formats a map of linter warnings using `print_warning`, sorted by line number. -/ def printWarnings (results : HashMap Name MessageData) (filePath : System.FilePath := default) From 5cd13303faea565653744eb284b05870c60da91a Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 12 Jun 2024 16:33:44 +1000 Subject: [PATCH 035/208] deprecations --- Batteries/Data/Array/Lemmas.lean | 2 +- Batteries/Data/HashMap/WF.lean | 16 +++++++++------- Batteries/Data/List/Lemmas.lean | 1 + 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Batteries/Data/Array/Lemmas.lean b/Batteries/Data/Array/Lemmas.lean index 5a16a355e1..3e4ce0a3ac 100644 --- a/Batteries/Data/Array/Lemmas.lean +++ b/Batteries/Data/Array/Lemmas.lean @@ -64,7 +64,7 @@ theorem zipWith_eq_zipWith_data (f : α → β → γ) (as : Array α) (bs : Arr let i_bs : Fin bs.data.length := ⟨i, hbs⟩ rw [h₁, List.append_assoc] congr - rw [← List.zipWith_append (h := by simp), getElem_eq_data_get, getElem_eq_data_get] + rw [← List.zipWith_append (h := by simp), getElem_eq_data_getElem, getElem_eq_data_getElem] show List.zipWith f ((List.get as.data i_as) :: List.drop (i_as + 1) as.data) ((List.get bs.data i_bs) :: List.drop (i_bs + 1) bs.data) = List.zipWith f (List.drop i as.data) (List.drop i bs.data) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index 9f46cbd9b7..18a3cd7646 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -23,7 +23,7 @@ theorem update_data (self : Buckets α β) (i d h) : theorem exists_of_update (self : Buckets α β) (i d h) : ∃ l₁ l₂, self.1.data = l₁ ++ self.1[i] :: l₂ ∧ List.length l₁ = i.toNat ∧ (self.update i d h).1.data = l₁ ++ d :: l₂ := by - simp only [Array.data_length, Array.ugetElem_eq_getElem, Array.getElem_eq_data_get] + simp only [Array.data_length, Array.ugetElem_eq_getElem, Array.getElem_eq_data_getElem] exact List.exists_of_set' h theorem update_update (self : Buckets α β) (i d d' h h') : @@ -43,7 +43,7 @@ theorem WF.mk' [BEq α] [Hashable α] (h) : (Buckets.mk n h : Buckets α β).WF refine ⟨fun _ h => ?_, fun i h => ?_⟩ · simp only [Buckets.mk, mkArray, List.mem_replicate, ne_eq] at h simp [h, List.Pairwise.nil] - · simp [Buckets.mk, empty', mkArray, Array.getElem_eq_data_get, AssocList.All] + · simp [Buckets.mk, empty', mkArray, Array.getElem_eq_data_getElem, AssocList.All] theorem WF.update [BEq α] [Hashable α] {buckets : Buckets α β} {i d h} (H : buckets.WF) (h₁ : ∀ [PartialEquivBEq α] [LawfulHashable α], @@ -57,7 +57,8 @@ theorem WF.update [BEq α] [Hashable α] {buckets : Buckets α β} {i d h} (H : | .inl hl => H.1 _ hl | .inr rfl => h₁ (H.1 _ (Array.getElem_mem_data ..)) · revert hp - simp only [Array.getElem_eq_data_get, update_data, List.get_set, Array.data_length, update_size] + simp only [Array.getElem_eq_data_getElem, update_data, List.getElem_set, Array.data_length, + update_size] split <;> intro hp · next eq => exact eq ▸ h₂ (H.2 _ _) _ hp · simp only [update_size, Array.data_length] at hi @@ -81,6 +82,7 @@ theorem reinsertAux_WF [BEq α] [Hashable α] {data : Buckets α β} {a : α} {b | _, _, .head .. => rfl | H, _, .tail _ h => H _ h +set_option linter.deprecated false in theorem expand_size [Hashable α] {buckets : Buckets α β} : (expand sz buckets).buckets.size = buckets.size := by rw [expand, go] @@ -166,8 +168,8 @@ where · match List.mem_or_eq_of_mem_set hl with | .inl hl => exact hs₁ _ hl | .inr e => exact e ▸ .nil - · simp only [Array.data_length, Array.size_set, Array.getElem_eq_data_get, Array.data_set, - List.get_set] + · simp only [Array.data_length, Array.size_set, Array.getElem_eq_data_getElem, Array.data_set, + List.getElem_set] split · nofun · exact hs₂ _ (by simp_all) @@ -362,8 +364,8 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable have := H.out.2.1 _ h rw [← List.pairwise_map (R := (¬ · == ·))] at this ⊢ exact this.sublist (H3 l.toList) - · simp only [Array.size_mk, List.length_map, Array.data_length, Array.getElem_eq_data_get, - List.get_map] at h ⊢ + · simp only [Array.size_mk, List.length_map, Array.data_length, Array.getElem_eq_data_getElem, + List.getElem_map] at h ⊢ have := H.out.2.2 _ h simp only [AssocList.All, List.toList_toAssocList, List.mem_reverse, List.mem_filterMap, Option.map_eq_some', forall_exists_index, and_imp, g₁] at this ⊢ diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 3b6955e8fc..6bceec22e6 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -397,6 +397,7 @@ theorem exists_of_set {l : List α} (h : n < l.length) : ∃ l₁ a l₂, l = l₁ ++ a :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := by rw [set_eq_modifyNth]; exact exists_of_modifyNth _ h +set_option linter.deprecated false in theorem exists_of_set' {l : List α} (h : n < l.length) : ∃ l₁ l₂, l = l₁ ++ l.get ⟨n, h⟩ :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := have ⟨_, _, _, h₁, h₂, h₃⟩ := exists_of_set h; ⟨_, _, get_of_append h₁ h₂ ▸ h₁, h₂, h₃⟩ From c5ca3f90b2bd4024d75aeda8dea065de9e6853b4 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Wed, 12 Jun 2024 09:05:17 +0000 Subject: [PATCH 036/208] chore: bump to nightly-2024-06-12 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index c868e61f55..2e64b81f61 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-11 +leanprover/lean4:nightly-2024-06-12 From 007a82fab9671c960ad260d4e4bf664b9fb884e3 Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Wed, 12 Jun 2024 14:15:41 +0200 Subject: [PATCH 037/208] chore(Tactic/Lint/Simp): make simpNF linter dsimp-aware (#839) * add test demonstrating undesired behaviour on dsimp lemmas * chore(Tactic/Lint/Simp): make simpNF linter dsimp-aware * test demonstrates correct behaviour on dsimp lemmas * process review comments * make formatLemmas dsimp-aware --- Batteries/Tactic/Lint/Simp.lean | 26 +++++++++++++++++++------- test/lint_simpNF.lean | 14 ++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Batteries/Tactic/Lint/Simp.lean b/Batteries/Tactic/Lint/Simp.lean index 44a858b340..3dc801fe0a 100644 --- a/Batteries/Tactic/Lint/Simp.lean +++ b/Batteries/Tactic/Lint/Simp.lean @@ -93,14 +93,14 @@ def decorateError (msg : MessageData) (k : MetaM α) : MetaM α := do try k catch e => throw (.error e.getRef m!"{msg}\n{e.toMessageData}") /-- Render the list of simp lemmas. -/ -def formatLemmas (usedSimps : Simp.UsedSimps) : MetaM MessageData := do +def formatLemmas (usedSimps : Simp.UsedSimps) (simpName : String) : MetaM MessageData := do let mut args := #[] let env ← getEnv for (thm, _) in usedSimps.toArray.qsort (·.2 < ·.2) do if let .decl declName := thm then if env.contains declName && declName != ``eq_self then args := args.push (← mkConstWithFreshMVarLevels declName) - return m!"simp only {args.toList}" + return m!"{simpName} only {args.toList}" /-- A linter for simp lemmas whose lhs is not in simp-normal form, and which hence never fire. -/ @[env_linter] def simpNF : Linter where @@ -112,17 +112,29 @@ https://leanprover-community.github.io/mathlib_docs/notes.html#simp-normal%20for unless ← isSimpTheorem declName do return none let ctx := { ← Simp.Context.mkDefault with config.decide := false } checkAllSimpTheoremInfos (← getConstInfo declName).type fun {lhs, rhs, isConditional, ..} => do + let isRfl ← isRflTheorem declName let ({ expr := lhs', proof? := prf1, .. }, prf1Stats) ← - decorateError "simplify fails on left-hand side:" <| simp lhs ctx + decorateError "simplify fails on left-hand side:" <| + if !isRfl then + simp lhs ctx + else do + let (e, s) ← dsimp lhs ctx + return (Simp.Result.mk e .none .true, s) if prf1Stats.usedTheorems.contains (.decl declName) then return none let ({ expr := rhs', .. }, stats) ← - decorateError "simplify fails on right-hand side:" <| simp rhs ctx (stats := prf1Stats) + decorateError "simplify fails on right-hand side:" <| + if !isRfl then + simp rhs ctx (stats := prf1Stats) + else do + let (e, s) ← dsimp rhs ctx (stats := prf1Stats) + return (Simp.Result.mk e .none .true, s) let lhs'EqRhs' ← isSimpEq lhs' rhs' (whnfFirst := false) let lhsInNF ← isSimpEq lhs' lhs + let simpName := if !isRfl then "simp" else "dsimp" if lhs'EqRhs' then if prf1.isNone then return none -- TODO: FP rewriting foo.eq_2 using `simp only [foo]` - return m!"simp can prove this: - by {← formatLemmas stats.usedTheorems} + return m!"{simpName} can prove this: + by {← formatLemmas stats.usedTheorems simpName} One of the lemmas above could be a duplicate. If that's not the case try reordering lemmas or adding @[priority]. " @@ -132,7 +144,7 @@ If that's not the case try reordering lemmas or adding @[priority]. to {lhs'} using - {← formatLemmas prf1Stats.usedTheorems} + {← formatLemmas prf1Stats.usedTheorems simpName} Try to change the left-hand side to the simplified term! " else if !isConditional && lhs == lhs' then diff --git a/test/lint_simpNF.lean b/test/lint_simpNF.lean index 8587e464bb..e06e067d18 100644 --- a/test/lint_simpNF.lean +++ b/test/lint_simpNF.lean @@ -27,4 +27,18 @@ theorem sumCompl_apply_symm_of_pos (p : α → Prop) [DecidablePred p] (a : α) (sumCompl p).symm a = Sum.inl ⟨a, h⟩ := dif_pos h +def foo (n : Nat) : Nat := if n = n then n else 0 + +@[simp] +theorem foo_eq_id : foo = id := by + funext n + simp [foo] + +-- The following `dsimp`-lemma is (correctly) not flagged by the linter +@[simp] +theorem foo_eq_ite (n : Nat) : foo n = if n = n then n else 0 := by + rfl + +end Equiv + #lint- only simpNF From 90835234905fbeb30b207efbd4cb42399cb9a0f0 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 13 Jun 2024 10:48:36 +1000 Subject: [PATCH 038/208] pairwise_iff_getElem --- Batteries/Data/List/Pairwise.lean | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index 65df1cf7a8..35725b33aa 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -234,19 +234,27 @@ theorem sublist_eq_map_get (h : l' <+ l) : ∃ is : List (Fin l.length), refine ⟨⟨0, by simp [Nat.zero_lt_succ]⟩ :: is.map (·.succ), ?_⟩ simp [comp_def, pairwise_map, IH, ← get_eq_getElem] -theorem pairwise_iff_get : Pairwise R l ↔ ∀ (i j) (_hij : i < j), R (get l i) (get l j) := by +theorem pairwise_iff_getElem : Pairwise R l ↔ + ∀ (i j : Nat) (_hi : i < l.length) (_hj : j < l.length) (_hij : i < j), R l[i] l[j] := by rw [pairwise_iff_forall_sublist] constructor <;> intro h - · intros i j h' + · intros i j hi hj h' apply h - apply map_get_sublist (is := [i, j]) - rw [Fin.lt_def] at h'; simp [h'] + simpa [h'] using map_get_sublist (is := [⟨i, hi⟩, ⟨j, hj⟩]) · intros a b h' have ⟨is, h', hij⟩ := sublist_eq_map_get h' rcases is with ⟨⟩ | ⟨a', ⟨⟩ | ⟨b', ⟨⟩⟩⟩ <;> simp at h' rcases h' with ⟨rfl, rfl⟩ apply h; simpa using hij +theorem pairwise_iff_get : Pairwise R l ↔ ∀ (i j) (_hij : i < j), R (get l i) (get l j) := by + rw [pairwise_iff_getElem] + constructor <;> intro h + · intros i j h' + exact h _ _ _ _ h' + · intros i j hi hj h' + exact h ⟨i, hi⟩ ⟨j, hj⟩ h' + theorem pairwise_replicate {α : Type _} {r : α → α → Prop} {x : α} (hx : r x x) : ∀ n : Nat, Pairwise r (List.replicate n x) | 0 => by simp From 0f5b28745722ab5f5168d2a418cabf8bee98f97a Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Thu, 13 Jun 2024 06:37:19 +0200 Subject: [PATCH 039/208] Revert "chore(Tactic/Lint/Simp): make simpNF linter dsimp-aware (#839)" (#841) This reverts commit 007a82fab9671c960ad260d4e4bf664b9fb884e3. --- Batteries/Tactic/Lint/Simp.lean | 26 +++++++------------------- test/lint_simpNF.lean | 14 -------------- 2 files changed, 7 insertions(+), 33 deletions(-) diff --git a/Batteries/Tactic/Lint/Simp.lean b/Batteries/Tactic/Lint/Simp.lean index 3dc801fe0a..44a858b340 100644 --- a/Batteries/Tactic/Lint/Simp.lean +++ b/Batteries/Tactic/Lint/Simp.lean @@ -93,14 +93,14 @@ def decorateError (msg : MessageData) (k : MetaM α) : MetaM α := do try k catch e => throw (.error e.getRef m!"{msg}\n{e.toMessageData}") /-- Render the list of simp lemmas. -/ -def formatLemmas (usedSimps : Simp.UsedSimps) (simpName : String) : MetaM MessageData := do +def formatLemmas (usedSimps : Simp.UsedSimps) : MetaM MessageData := do let mut args := #[] let env ← getEnv for (thm, _) in usedSimps.toArray.qsort (·.2 < ·.2) do if let .decl declName := thm then if env.contains declName && declName != ``eq_self then args := args.push (← mkConstWithFreshMVarLevels declName) - return m!"{simpName} only {args.toList}" + return m!"simp only {args.toList}" /-- A linter for simp lemmas whose lhs is not in simp-normal form, and which hence never fire. -/ @[env_linter] def simpNF : Linter where @@ -112,29 +112,17 @@ https://leanprover-community.github.io/mathlib_docs/notes.html#simp-normal%20for unless ← isSimpTheorem declName do return none let ctx := { ← Simp.Context.mkDefault with config.decide := false } checkAllSimpTheoremInfos (← getConstInfo declName).type fun {lhs, rhs, isConditional, ..} => do - let isRfl ← isRflTheorem declName let ({ expr := lhs', proof? := prf1, .. }, prf1Stats) ← - decorateError "simplify fails on left-hand side:" <| - if !isRfl then - simp lhs ctx - else do - let (e, s) ← dsimp lhs ctx - return (Simp.Result.mk e .none .true, s) + decorateError "simplify fails on left-hand side:" <| simp lhs ctx if prf1Stats.usedTheorems.contains (.decl declName) then return none let ({ expr := rhs', .. }, stats) ← - decorateError "simplify fails on right-hand side:" <| - if !isRfl then - simp rhs ctx (stats := prf1Stats) - else do - let (e, s) ← dsimp rhs ctx (stats := prf1Stats) - return (Simp.Result.mk e .none .true, s) + decorateError "simplify fails on right-hand side:" <| simp rhs ctx (stats := prf1Stats) let lhs'EqRhs' ← isSimpEq lhs' rhs' (whnfFirst := false) let lhsInNF ← isSimpEq lhs' lhs - let simpName := if !isRfl then "simp" else "dsimp" if lhs'EqRhs' then if prf1.isNone then return none -- TODO: FP rewriting foo.eq_2 using `simp only [foo]` - return m!"{simpName} can prove this: - by {← formatLemmas stats.usedTheorems simpName} + return m!"simp can prove this: + by {← formatLemmas stats.usedTheorems} One of the lemmas above could be a duplicate. If that's not the case try reordering lemmas or adding @[priority]. " @@ -144,7 +132,7 @@ If that's not the case try reordering lemmas or adding @[priority]. to {lhs'} using - {← formatLemmas prf1Stats.usedTheorems simpName} + {← formatLemmas prf1Stats.usedTheorems} Try to change the left-hand side to the simplified term! " else if !isConditional && lhs == lhs' then diff --git a/test/lint_simpNF.lean b/test/lint_simpNF.lean index e06e067d18..8587e464bb 100644 --- a/test/lint_simpNF.lean +++ b/test/lint_simpNF.lean @@ -27,18 +27,4 @@ theorem sumCompl_apply_symm_of_pos (p : α → Prop) [DecidablePred p] (a : α) (sumCompl p).symm a = Sum.inl ⟨a, h⟩ := dif_pos h -def foo (n : Nat) : Nat := if n = n then n else 0 - -@[simp] -theorem foo_eq_id : foo = id := by - funext n - simp [foo] - --- The following `dsimp`-lemma is (correctly) not flagged by the linter -@[simp] -theorem foo_eq_ite (n : Nat) : foo n = if n = n then n else 0 := by - rfl - -end Equiv - #lint- only simpNF From a223323f1040daa545ef8e7a1876209d90a0fcbc Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 13 Jun 2024 16:12:20 +1000 Subject: [PATCH 040/208] more deprecations --- Batteries/Data/Fin/Lemmas.lean | 1 + Batteries/Data/List/EraseIdx.lean | 24 +++++++++++----- Batteries/Data/List/Lemmas.lean | 47 ++++++++++++++++++++++--------- Batteries/Data/List/Pairwise.lean | 1 + 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/Batteries/Data/Fin/Lemmas.lean b/Batteries/Data/Fin/Lemmas.lean index 21f14d8a96..a223dca2b5 100644 --- a/Batteries/Data/Fin/Lemmas.lean +++ b/Batteries/Data/Fin/Lemmas.lean @@ -34,6 +34,7 @@ protected theorem le_antisymm {x y : Fin n} (h1 : x ≤ y) (h2 : y ≤ x) : x = (list n)[i] = cast (length_list n) ⟨i, h⟩ := by simp only [list]; rw [← Array.getElem_eq_data_getElem, getElem_enum, cast_mk] +@[deprecated getElem_list (since := "2024-06-12")] theorem get_list (i : Fin (list n).length) : (list n).get i = i.cast (length_list n) := by simp [getElem_list] diff --git a/Batteries/Data/List/EraseIdx.lean b/Batteries/Data/List/EraseIdx.lean index 31a595be57..6d96383a74 100644 --- a/Batteries/Data/List/EraseIdx.lean +++ b/Batteries/Data/List/EraseIdx.lean @@ -63,20 +63,30 @@ protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) : rw [Nat.not_lt] at hkl simp [eraseIdx_append_of_length_le hkl, eraseIdx_of_length_le hkl] -theorem mem_eraseIdx_iff_get {x : α} : - ∀ {l} {k}, x ∈ eraseIdx l k ↔ ∃ i : Fin l.length, ↑i ≠ k ∧ l.get i = x +theorem mem_eraseIdx_iff_getElem {x : α} : + ∀ {l} {k}, x ∈ eraseIdx l k ↔ ∃ i : Fin l.length, ↑i ≠ k ∧ l[i.1] = x | [], _ => by simp only [eraseIdx, Fin.exists_iff, not_mem_nil, false_iff] rintro ⟨i, h, -⟩ exact Nat.not_lt_zero _ h | a::l, 0 => by simp [Fin.exists_fin_succ, mem_iff_get] | a::l, k+1 => by - simp [Fin.exists_fin_succ, mem_eraseIdx_iff_get, @eq_comm _ a, k.succ_ne_zero.symm] + simp [Fin.exists_fin_succ, mem_eraseIdx_iff_getElem, @eq_comm _ a, k.succ_ne_zero.symm] + +theorem mem_eraseIdx_iff_get {x : α} {l} {k} : + x ∈ eraseIdx l k ↔ ∃ i : Fin l.length, ↑i ≠ k ∧ l.get i = x := by + simp [mem_eraseIdx_iff_getElem] + +theorem mem_eraseIdx_iff_getElem? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i ≠ k, l[i]? = some x := by + simp only [mem_eraseIdx_iff_getElem, getElem_eq_iff, Fin.exists_iff, exists_and_left] + refine exists_congr fun i => and_congr_right' ?_ + constructor + · rintro ⟨_, h⟩; exact h + · rintro h; + obtain ⟨h', -⟩ := getElem?_eq_some.1 h + exact ⟨h', h⟩ theorem mem_eraseIdx_iff_get? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i ≠ k, l.get? i = x := by - simp only [mem_eraseIdx_iff_get, Fin.exists_iff, exists_and_left, get_eq_iff, exists_prop] - refine exists_congr fun i => and_congr_right' <| and_iff_right_of_imp fun h => ?_ - obtain ⟨h, -⟩ := get?_eq_some.1 h - exact h + simp [mem_eraseIdx_iff_getElem?] end List diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 6bceec22e6..ffc03bf760 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -247,18 +247,21 @@ theorem getElem_eq_iff {l : List α} {n : Nat} {h : n < l.length} : l[n] = x ↔ simp only [get_eq_getElem, get?_eq_getElem?, getElem?_eq_some] exact ⟨fun w => ⟨h, w⟩, fun h => h.2⟩ +@[deprecated getElem_eq_iff (since := "2024-06-12")] theorem get_eq_iff : List.get l n = x ↔ l.get? n.1 = some x := by simp [getElem_eq_iff] -theorem get?_inj - (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs.get? i = xs.get? j) : i = j := by +theorem getElem?_inj + (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs[i]? = xs[j]?) : i = j := by induction xs generalizing i j with | nil => cases h₀ | cons x xs ih => match i, j with | 0, 0 => rfl | i+1, j+1 => simp; cases h₁ with - | cons ha h₁ => exact ih (Nat.lt_of_succ_lt_succ h₀) h₁ h₂ + | cons ha h₁ => + simp only [getElem?_cons_succ] at h₂ + exact ih (Nat.lt_of_succ_lt_succ h₀) h₁ h₂ | i+1, 0 => ?_ | 0, j+1 => ?_ all_goals @@ -269,6 +272,12 @@ theorem get?_inj simp only [get?_eq_getElem?] exact ⟨_, h₂⟩; exact ⟨_ , h₂.symm⟩ +@[deprecated getElem?_inj (since := "2024-06-12")] +theorem get?_inj + (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs.get? i = xs.get? j) : i = j := by + apply getElem?_inj h₀ h₁ + simp_all + /-! ### drop -/ theorem tail_drop (l : List α) (n : Nat) : (l.drop n).tail = l.drop (n + 1) := by @@ -312,6 +321,7 @@ theorem getElem?_modifyNth (f : α → α) : cases h' : l[m]? <;> by_cases h : n = m <;> simp [h, if_pos, if_neg, Option.map, mt Nat.succ.inj, not_false_iff, h'] +@[deprecated getElem?_modifyNth (since := "2024-06-12")] theorem get?_modifyNth (f : α → α) (n) (l : List α) (m) : (modifyNth f n l).get? m = (fun a => if n = m then f a else a) <$> l.get? m := by simp [getElem?_modifyNth] @@ -336,17 +346,19 @@ theorem exists_of_modifyNthTail (f : List α → List α) {n} {l : List α} (h : modifyNthTail_length _ fun l => by cases l <;> rfl @[simp] theorem getElem?_modifyNth_eq (f : α → α) (n) (l : List α) : - (modifyNth f n l)[n]? = f <$> l[n]? := by + (modifyNth f n l)[n]? = f <$> l[n]? := by simp only [getElem?_modifyNth, if_pos] +@[deprecated getElem?_modifyNth_eq (since := "2024-06-12")] theorem get?_modifyNth_eq (f : α → α) (n) (l : List α) : - (modifyNth f n l).get? n = f <$> l.get? n := by - simp only [get?_modifyNth, if_pos] + (modifyNth f n l).get? n = f <$> l.get? n := by + simp [getElem?_modifyNth_eq] @[simp] theorem getElem?_modifyNth_ne (f : α → α) {m n} (l : List α) (h : m ≠ n) : (modifyNth f m l)[n]? = l[n]? := by simp only [getElem?_modifyNth, if_neg h, id_map'] +@[deprecated getElem?_modifyNth_ne (since := "2024-06-12")] theorem get?_modifyNth_ne (f : α → α) {m n} (l : List α) (h : m ≠ n) : (modifyNth f m l).get? n = l.get? n := by simp [h] @@ -406,19 +418,23 @@ theorem exists_of_set' {l : List α} (h : n < l.length) : theorem getElem?_set_eq (a : α) (n) (l : List α) : (set l n a)[n]? = (fun _ => a) <$> l[n]? := by simp only [set_eq_modifyNth, getElem?_modifyNth_eq] +@[deprecated getElem?_set_eq (since := "2024-06-12")] theorem get?_set_eq (a : α) (n) (l : List α) : (set l n a).get? n = (fun _ => a) <$> l.get? n := by simp theorem getElem?_set_eq_of_lt (a : α) {n} {l : List α} (h : n < length l) : - (set l n a)[n]? = some a := by rw [getElem?_set_eq, getElem?_eq_getElem h]; rfl + (set l n a)[n]? = some a := by rw [getElem?_set_eq, getElem?_eq_getElem h]; rfl +@[deprecated getElem?_set_eq_of_lt (since := "2024-06-12")] 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 + (set l n a).get? n = some a := by + rw [get?_eq_getElem?,getElem?_set_eq, getElem?_eq_getElem h]; rfl @[simp] theorem getElem?_set_ne (a : α) {m n} (l : List α) (h : m ≠ n) : (set l m a)[n]? = l[n]? := by simp only [set_eq_modifyNth, getElem?_modifyNth_ne _ _ h] +@[deprecated getElem?_set_ne (since := "2024-06-12")] theorem get?_set_ne (a : α) {m n} (l : List α) (h : m ≠ n) : (set l m a).get? n = l.get? n := by simp [h] @@ -426,6 +442,7 @@ theorem getElem?_set (a : α) {m n} (l : List α) : (set l m a)[n]? = if m = n then (fun _ => a) <$> l[n]? else l[n]? := by by_cases m = n <;> simp [*] +@[deprecated getElem?_set (since := "2024-06-12")] 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 simp [getElem?_set] @@ -440,14 +457,14 @@ theorem get?_set_of_lt' (a : α) {m n} (l : List α) (h : m < length l) : theorem drop_set_of_lt (a : α) {n m : Nat} (l : List α) (h : n < m) : (l.set n a).drop m = l.drop m := - List.ext_get? fun i => by rw [get?_drop, get?_drop, get?_set_ne _ _ (by omega)] + List.ext_getElem? fun i => by rw [getElem?_drop, getElem?_drop, getElem?_set_ne _ _ (by omega)] theorem take_set_of_lt (a : α) {n m : Nat} (l : List α) (h : m < n) : (l.set n a).take m = l.take m := - List.ext_get? fun i => by - rw [get?_take_eq_if, get?_take_eq_if] + List.ext_getElem? fun i => by + rw [getElem?_take_eq_if, getElem?_take_eq_if] split - · next h' => rw [get?_set_ne _ _ (by omega)] + · next h' => rw [getElem?_set_ne _ _ (by omega)] · rfl /-! ### removeNth -/ @@ -1376,14 +1393,16 @@ theorem getElem?_range' (s step) : exact (getElem?_range' (s + step) step (Nat.lt_of_add_lt_add_right h)).trans <| by simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm] +@[deprecated getElem?_range' (since := "2024-06-12")] theorem get?_range' (s step) {m n : Nat} (h : m < n) : get? (range' s n step) m = some (s + step * m) := by simp [getElem?_range', h] @[simp] theorem getElem_range' {n m step} (i) (H : i < (range' n m step).length) : (range' n m step)[i] = n + step * i := - (get?_eq_some.1 <| get?_range' n step (by simpa using H)).2 + (getElem?_eq_some.1 <| getElem?_range' n step (by simpa using H)).2 +@[deprecated getElem_range' (since := "2024-06-12")] theorem get_range' {n m step} (i) (H : i < (range' n m step).length) : get (range' n m step) ⟨i, H⟩ = n + step * i := by simp @@ -1433,6 +1452,7 @@ theorem self_mem_range_succ (n : Nat) : n ∈ range (n + 1) := by simp theorem getElem?_range {m n : Nat} (h : m < n) : (range n)[m]? = some m := by simp [range_eq_range', getElem?_range' _ _ h] +@[deprecated getElem?_range (since := "2024-06-12")] theorem get?_range {m n : Nat} (h : m < n) : get? (range n) m = some m := by simp [getElem?_range, h] @@ -1465,6 +1485,7 @@ theorem reverse_range' : ∀ s n : Nat, reverse (range' s n) = map (s + n - 1 - @[simp] theorem getElem_range {n} (i) (H : i < (range n).length) : (range n)[i] = i := Option.some.inj <| by rw [← getElem?_eq_getElem _, getElem?_range (by simpa using H)] +@[deprecated getElem_range (since := "2024-06-12")] theorem get_range {n} (i) (H : i < (range n).length) : get (range n) ⟨i, H⟩ = i := by simp diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index 35725b33aa..d3aeb4dd8e 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -247,6 +247,7 @@ theorem pairwise_iff_getElem : Pairwise R l ↔ rcases h' with ⟨rfl, rfl⟩ apply h; simpa using hij +@[deprecated pairwise_iff_getElem (since := "2024-06-12")] theorem pairwise_iff_get : Pairwise R l ↔ ∀ (i j) (_hij : i < j), R (get l i) (get l j) := by rw [pairwise_iff_getElem] constructor <;> intro h From a30f8c9da225def16de48e6afd954cb7a67d6f01 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 13 Jun 2024 16:24:04 +1000 Subject: [PATCH 041/208] remove a deprecation --- Batteries/Data/List/Pairwise.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index d3aeb4dd8e..35725b33aa 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -247,7 +247,6 @@ theorem pairwise_iff_getElem : Pairwise R l ↔ rcases h' with ⟨rfl, rfl⟩ apply h; simpa using hij -@[deprecated pairwise_iff_getElem (since := "2024-06-12")] theorem pairwise_iff_get : Pairwise R l ↔ ∀ (i j) (_hij : i < j), R (get l i) (get l j) := by rw [pairwise_iff_getElem] constructor <;> intro h From 279b659ae6072fa8d75dd76b96be7ed3a848bdc1 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 13 Jun 2024 16:42:50 +1000 Subject: [PATCH 042/208] remove a nolint --- Batteries/Data/HashMap/WF.lean | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index 18a3cd7646..a421328007 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -82,7 +82,6 @@ theorem reinsertAux_WF [BEq α] [Hashable α] {data : Buckets α β} {a : α} {b | _, _, .head .. => rfl | H, _, .tail _ h => H _ h -set_option linter.deprecated false in theorem expand_size [Hashable α] {buckets : Buckets α β} : (expand sz buckets).buckets.size = buckets.size := by rw [expand, go] @@ -96,7 +95,7 @@ where · next H => refine (go (i+1) _ _ fun j hj => ?a).trans ?b <;> simp · case a => - simp [List.getD_eq_get?, List.getElem?_set, Option.map_eq_map]; split + simp [List.getD_eq_getElem?, List.getElem?_set, Option.map_eq_map]; split · cases source.data[j]? <;> rfl · next H => exact hs _ (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ hj) (Ne.symm H)) · case b => @@ -105,7 +104,7 @@ where List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length] rw [Nat.add_assoc, Nat.add_assoc, Nat.add_assoc]; congr 1 (conv => rhs; rw [Nat.add_left_comm]); congr 1 - rw [← Array.getElem_eq_data_get] + rw [List.get_eq_getElem, ← Array.getElem_eq_data_getElem] have := @reinsertAux_size α β _; simp [Buckets.size] at this induction source[i].toList generalizing target <;> simp [*, Nat.succ_add]; rfl · next H => @@ -113,8 +112,8 @@ where rw [← (_ : source.data.map (fun _ => .nil) = source.data)] · simp only [List.map_map] induction source.data <;> simp [*] - refine List.ext_get (by simp) fun j h₁ h₂ => ?_ - simp only [List.get_map, Array.data_length] + refine List.ext_getElem (by simp) fun j h₁ h₂ => ?_ + simp only [List.getElem_map, Array.data_length] have := (hs j (Nat.lt_of_lt_of_le h₂ (Nat.not_lt.1 H))).symm rwa [List.getElem?_eq_getElem] at this termination_by source.size - i From 31fe107428e55bfaa59cd124131c357c8747df0a Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 13 Jun 2024 16:45:02 +1000 Subject: [PATCH 043/208] deprecate more --- Batteries/Data/List/EraseIdx.lean | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Batteries/Data/List/EraseIdx.lean b/Batteries/Data/List/EraseIdx.lean index 6d96383a74..ca3cf2e716 100644 --- a/Batteries/Data/List/EraseIdx.lean +++ b/Batteries/Data/List/EraseIdx.lean @@ -73,6 +73,7 @@ theorem mem_eraseIdx_iff_getElem {x : α} : | a::l, k+1 => by simp [Fin.exists_fin_succ, mem_eraseIdx_iff_getElem, @eq_comm _ a, k.succ_ne_zero.symm] +@[deprecated mem_eraseIdx_iff_getElem (since := "2024-06-12")] theorem mem_eraseIdx_iff_get {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i : Fin l.length, ↑i ≠ k ∧ l.get i = x := by simp [mem_eraseIdx_iff_getElem] @@ -86,6 +87,7 @@ theorem mem_eraseIdx_iff_getElem? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ obtain ⟨h', -⟩ := getElem?_eq_some.1 h exact ⟨h', h⟩ +@[deprecated mem_eraseIdx_iff_getElem? (since := "2024-06-12")] theorem mem_eraseIdx_iff_get? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i ≠ k, l.get? i = x := by simp [mem_eraseIdx_iff_getElem?] From ac6e7dc0f89d015fc6cfeca3a590f787959bbd7a Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 13 Jun 2024 16:49:12 +1000 Subject: [PATCH 044/208] whitespace --- Batteries/Data/HashMap/WF.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index a421328007..9b77feb84e 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -101,7 +101,7 @@ where · case b => refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set' H; eq ▸ ?_ simp only [Buckets.size_eq, h₁, List.map_append, List.map_cons, AssocList.toList, - List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length] + List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length] rw [Nat.add_assoc, Nat.add_assoc, Nat.add_assoc]; congr 1 (conv => rhs; rw [Nat.add_left_comm]); congr 1 rw [List.get_eq_getElem, ← Array.getElem_eq_data_getElem] From d72b30ff09c2bb21fc2c4df846160c81016d4db0 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 13 Jun 2024 16:50:40 +1000 Subject: [PATCH 045/208] fix --- Batteries/Data/HashMap/WF.lean | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index 9b77feb84e..cc23bbf283 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -100,7 +100,8 @@ where · next H => exact hs _ (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ hj) (Ne.symm H)) · case b => refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set' H; eq ▸ ?_ - simp only [Buckets.size_eq, h₁, List.map_append, List.map_cons, AssocList.toList, + rw [h₁] + simp only [Buckets.size_eq, List.map_append, List.map_cons, AssocList.toList, List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length] rw [Nat.add_assoc, Nat.add_assoc, Nat.add_assoc]; congr 1 (conv => rhs; rw [Nat.add_left_comm]); congr 1 From af3285c3b6cc78326159dd766a8ace83d9896b7c Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 13 Jun 2024 16:51:39 +1000 Subject: [PATCH 046/208] better --- Batteries/Data/HashMap/WF.lean | 2 +- Batteries/Data/List/Lemmas.lean | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index cc23bbf283..c29ce4ca9b 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -105,7 +105,7 @@ where List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length] rw [Nat.add_assoc, Nat.add_assoc, Nat.add_assoc]; congr 1 (conv => rhs; rw [Nat.add_left_comm]); congr 1 - rw [List.get_eq_getElem, ← Array.getElem_eq_data_getElem] + rw [← Array.getElem_eq_data_getElem] have := @reinsertAux_size α β _; simp [Buckets.size] at this induction source[i].toList generalizing target <;> simp [*, Nat.succ_add]; rfl · next H => diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index ffc03bf760..14b7c35e6b 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -409,10 +409,9 @@ theorem exists_of_set {l : List α} (h : n < l.length) : ∃ l₁ a l₂, l = l₁ ++ a :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := by rw [set_eq_modifyNth]; exact exists_of_modifyNth _ h -set_option linter.deprecated false in theorem exists_of_set' {l : List α} (h : n < l.length) : - ∃ l₁ l₂, l = l₁ ++ l.get ⟨n, h⟩ :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := - have ⟨_, _, _, h₁, h₂, h₃⟩ := exists_of_set h; ⟨_, _, get_of_append h₁ h₂ ▸ h₁, h₂, h₃⟩ + ∃ l₁ l₂, l = l₁ ++ l[n] :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := + have ⟨_, _, _, h₁, h₂, h₃⟩ := exists_of_set h; ⟨_, _, getElem_of_append h₁ h₂ ▸ h₁, h₂, h₃⟩ @[simp] theorem getElem?_set_eq (a : α) (n) (l : List α) : (set l n a)[n]? = (fun _ => a) <$> l[n]? := by From c0b29c1d61dec54193988b7b46c1c90dfd334a1f Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 13 Jun 2024 18:45:52 +1000 Subject: [PATCH 047/208] deprecations --- Batteries/Data/Array/Lemmas.lean | 7 +++---- Batteries/Data/List/Lemmas.lean | 4 ++-- Batteries/Data/List/Pairwise.lean | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Batteries/Data/Array/Lemmas.lean b/Batteries/Data/Array/Lemmas.lean index 3e4ce0a3ac..cf069eb703 100644 --- a/Batteries/Data/Array/Lemmas.lean +++ b/Batteries/Data/Array/Lemmas.lean @@ -22,7 +22,7 @@ theorem forIn_eq_data_forIn [Monad m] have j_eq : j = size as - 1 - i := by simp [← ij, ← Nat.add_assoc] have : as.size - 1 - i < as.size := j_eq ▸ ij ▸ Nat.lt_succ_of_le (Nat.le_add_right ..) have : as[size as - 1 - i] :: as.data.drop (j + 1) = as.data.drop j := by - rw [j_eq]; exact List.get_cons_drop _ ⟨_, this⟩ + rw [j_eq]; exact List.getElem_cons_drop _ _ this simp only [← this, List.forIn_cons]; congr; funext x; congr; funext b rw [loop (i := i)]; rw [← ij, Nat.succ_add]; rfl conv => lhs; simp only [forIn, Array.forIn] @@ -65,11 +65,10 @@ theorem zipWith_eq_zipWith_data (f : α → β → γ) (as : Array α) (bs : Arr rw [h₁, List.append_assoc] congr rw [← List.zipWith_append (h := by simp), getElem_eq_data_getElem, getElem_eq_data_getElem] - show List.zipWith f ((List.get as.data i_as) :: List.drop (i_as + 1) as.data) + show List.zipWith f (as.data[i_as] :: List.drop (i_as + 1) as.data) ((List.get bs.data i_bs) :: List.drop (i_bs + 1) bs.data) = List.zipWith f (List.drop i as.data) (List.drop i bs.data) - simp only [List.get_cons_drop] - termination_by as.size - i + simp only [data_length, Fin.getElem_fin, List.getElem_cons_drop, List.get_eq_getElem] simp [zipWith, loop 0 #[] (by simp) (by simp)] theorem size_zipWith (as : Array α) (bs : Array β) (f : α → β → γ) : diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 14b7c35e6b..4db5a1c7a4 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -380,8 +380,8 @@ theorem modifyNth_eq_take_drop (f : α → α) : modifyNthTail_eq_take_drop _ rfl theorem modifyNth_eq_take_cons_drop (f : α → α) {n l} (h) : - modifyNth f n l = take n l ++ f (get l ⟨n, h⟩) :: drop (n + 1) l := by - rw [modifyNth_eq_take_drop, drop_eq_get_cons h]; rfl + modifyNth f n l = take n l ++ f l[n] :: drop (n + 1) l := by + rw [modifyNth_eq_take_drop, drop_eq_getElem_cons h]; rfl /-! ### set -/ diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index 35725b33aa..b808fe85e7 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -213,7 +213,7 @@ theorem map_get_sublist {l : List α} {is : List (Fin l.length)} (h : is.Pairwis simp; cases hl' have := IH h.of_cons (hd+1) _ rfl (pairwise_cons.mp h).1 specialize his hd (.head _) - have := (drop_eq_get_cons ..).symm ▸ this.cons₂ (get l hd) + have := (drop_eq_getElem_cons ..).symm ▸ this.cons₂ (get l hd) have := Sublist.append (nil_sublist (take hd l |>.drop n)) this rwa [nil_append, ← (drop_append_of_le_length ?_), take_append_drop] at this simp [Nat.min_eq_left (Nat.le_of_lt hd.isLt), his] From 15d42e1a92a80d0db5ca1c12123866ba392b9d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20G=2E=20Dorais?= Date: Thu, 13 Jun 2024 20:50:52 -0400 Subject: [PATCH 048/208] feat: ext lemma for `Thunk` (#842) --- Batteries.lean | 1 + Batteries/Data/Thunk.lean | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 Batteries/Data/Thunk.lean diff --git a/Batteries.lean b/Batteries.lean index f56659960b..dea5262d3b 100644 --- a/Batteries.lean +++ b/Batteries.lean @@ -35,6 +35,7 @@ import Batteries.Data.Range import Batteries.Data.Rat import Batteries.Data.String import Batteries.Data.Sum +import Batteries.Data.Thunk import Batteries.Data.UInt import Batteries.Data.UnionFind import Batteries.Lean.AttributeExtra diff --git a/Batteries/Data/Thunk.lean b/Batteries/Data/Thunk.lean new file mode 100644 index 0000000000..88c92c3784 --- /dev/null +++ b/Batteries/Data/Thunk.lean @@ -0,0 +1,10 @@ +/- +Copyright (c) 2024 François G. Dorais. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE +Authors: François G. Dorais, et al. +-/ + +namespace Thunk + +@[ext] protected theorem ext : {a b : Thunk α} → a.get = b.get → a = b + | {..}, {..}, heq => congrArg _ <| funext fun _ => heq From dddd1c7b2be975a272b2da88db02b9cf05c56433 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 14 Jun 2024 11:49:45 +1000 Subject: [PATCH 049/208] fix test --- test/congr.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/congr.lean b/test/congr.lean index 5303fbd74b..a71aed0315 100644 --- a/test/congr.lean +++ b/test/congr.lean @@ -38,7 +38,7 @@ section -- Adaptation note: the next two examples have always failed if `List.ext` was in scope, -- but until nightly-2024-04-24 (when `List.ext` was upstreamed), it wasn't in scope. -- In order to preserve the test behaviour we locally remove the `ext` attribute. -attribute [-ext] List.ext +attribute [-ext] List.ext_getElem? private opaque List.sum : List Nat → Nat From 7320758134c95cb5c9662e30c5eefac284729be3 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 14 Jun 2024 09:04:58 +0000 Subject: [PATCH 050/208] chore: bump to nightly-2024-06-14 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 2e64b81f61..483b83244f 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-12 +leanprover/lean4:nightly-2024-06-14 From eabfb398de8449334b0df2c7d005290c6936ba5d Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Sat, 15 Jun 2024 16:41:53 +1000 Subject: [PATCH 051/208] fix --- Batteries.lean | 1 - Batteries/CodeAction/Misc.lean | 1 - Batteries/Lean/Name.lean | 28 ---------------------------- Batteries/Tactic/PrintPrefix.lean | 1 - 4 files changed, 31 deletions(-) delete mode 100644 Batteries/Lean/Name.lean diff --git a/Batteries.lean b/Batteries.lean index dea5262d3b..21fc0307f2 100644 --- a/Batteries.lean +++ b/Batteries.lean @@ -58,7 +58,6 @@ import Batteries.Lean.Meta.SavedState import Batteries.Lean.Meta.Simp import Batteries.Lean.Meta.UnusedNames import Batteries.Lean.MonadBacktrack -import Batteries.Lean.Name import Batteries.Lean.NameMap import Batteries.Lean.NameMapAttribute import Batteries.Lean.PersistentHashMap diff --git a/Batteries/CodeAction/Misc.lean b/Batteries/CodeAction/Misc.lean index 1b5be55ce6..0bea77ff55 100644 --- a/Batteries/CodeAction/Misc.lean +++ b/Batteries/CodeAction/Misc.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro -/ import Lean.Elab.BuiltinTerm import Lean.Elab.BuiltinNotation -import Batteries.Lean.Name import Batteries.Lean.Position import Batteries.CodeAction.Attr import Lean.Meta.Tactic.TryThis diff --git a/Batteries/Lean/Name.lean b/Batteries/Lean/Name.lean deleted file mode 100644 index b5530e49d1..0000000000 --- a/Batteries/Lean/Name.lean +++ /dev/null @@ -1,28 +0,0 @@ -/- -Copyright (c) 2023 Mario Carneiro. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mario Carneiro --/ -import Lean.Data.Name - -namespace Lean.Name - -/-- -Returns true if this a part of name that is internal or dynamically -generated so that it may easily be changed. - -Generally, user code should not explicitly use internal names. --/ -def isInternalDetail : Name → Bool - | .str p s => - s.startsWith "_" - || matchPrefix s "eq_" - || matchPrefix s "match_" - || matchPrefix s "proof_" - || p.isInternalOrNum - | .num _ _ => true - | p => p.isInternalOrNum -where - /-- Check that a string begins with the given prefix, and then is only digit characters. -/ - matchPrefix (s : String) (pre : String) := - s.startsWith pre && (s |>.drop pre.length |>.all Char.isDigit) diff --git a/Batteries/Tactic/PrintPrefix.lean b/Batteries/Tactic/PrintPrefix.lean index 0046f0a4d7..63d2c3bbf5 100644 --- a/Batteries/Tactic/PrintPrefix.lean +++ b/Batteries/Tactic/PrintPrefix.lean @@ -3,7 +3,6 @@ Copyright (c) 2021 Shing Tak Lam. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Shing Tak Lam, Daniel Selsam, Mario Carneiro -/ -import Batteries.Lean.Name import Batteries.Lean.Util.EnvSearch import Batteries.Lean.Delaborator import Lean.Elab.Tactic.Config From 8d2100637a91776707ca22636ae8aa04dd5c1e8d Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sat, 15 Jun 2024 09:04:57 +0000 Subject: [PATCH 052/208] chore: bump to nightly-2024-06-15 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 483b83244f..a0bf3a31a1 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-14 +leanprover/lean4:nightly-2024-06-15 From ce81cce73d1deb58e6628784c21950a4f12a6ce6 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Sat, 15 Jun 2024 19:59:47 +1000 Subject: [PATCH 053/208] chore: remove docgen from the manifest --- lake-manifest.json | 49 ++-------------------------------------------- 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/lake-manifest.json b/lake-manifest.json index e33f34b1fa..68d5a83837 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -1,50 +1,5 @@ -{"version": 7, +{"version": "1.0.0", "packagesDir": ".lake/packages", - "packages": - [{"url": "https://github.com/xubaiw/CMark.lean", - "type": "git", - "subDir": null, - "rev": "0077cbbaa92abf855fc1c0413e158ffd8195ec77", - "name": "CMark", - "manifestFile": "lake-manifest.json", - "inputRev": "main", - "inherited": true, - "configFile": "lakefile.lean"}, - {"url": "https://github.com/fgdorais/lean4-unicode-basic", - "type": "git", - "subDir": null, - "rev": "280d75fdfe7be8eb337be7f1bf8479b4aac09f71", - "name": "UnicodeBasic", - "manifestFile": "lake-manifest.json", - "inputRev": "main", - "inherited": true, - "configFile": "lakefile.lean"}, - {"url": "https://github.com/mhuisi/lean4-cli", - "type": "git", - "subDir": null, - "rev": "39229f3630d734af7d9cfb5937ddc6b41d3aa6aa", - "name": "Cli", - "manifestFile": "lake-manifest.json", - "inputRev": "nightly", - "inherited": true, - "configFile": "lakefile.lean"}, - {"url": "https://github.com/hargonix/LeanInk", - "type": "git", - "subDir": null, - "rev": "2447df5cc6e48eb965c3c3fba87e46d353b5e9f1", - "name": "leanInk", - "manifestFile": "lake-manifest.json", - "inputRev": "doc-gen", - "inherited": true, - "configFile": "lakefile.lean"}, - {"url": "https://github.com/leanprover/doc-gen4", - "type": "git", - "subDir": null, - "rev": "b7fad51b87a5f8fb3a238dc820ec40ebfa2a636e", - "name": "«doc-gen4»", - "manifestFile": "lake-manifest.json", - "inputRev": "main", - "inherited": false, - "configFile": "lakefile.lean"}], + "packages": [], "name": "batteries", "lakeDir": ".lake"} From 2506c85498141bc8ab3ee745bcb06021c3ed9a80 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Sat, 15 Jun 2024 11:02:44 +0100 Subject: [PATCH 054/208] chore: remove docgen from the manifest (#846) --- lake-manifest.json | 49 ++-------------------------------------------- 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/lake-manifest.json b/lake-manifest.json index e33f34b1fa..68d5a83837 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -1,50 +1,5 @@ -{"version": 7, +{"version": "1.0.0", "packagesDir": ".lake/packages", - "packages": - [{"url": "https://github.com/xubaiw/CMark.lean", - "type": "git", - "subDir": null, - "rev": "0077cbbaa92abf855fc1c0413e158ffd8195ec77", - "name": "CMark", - "manifestFile": "lake-manifest.json", - "inputRev": "main", - "inherited": true, - "configFile": "lakefile.lean"}, - {"url": "https://github.com/fgdorais/lean4-unicode-basic", - "type": "git", - "subDir": null, - "rev": "280d75fdfe7be8eb337be7f1bf8479b4aac09f71", - "name": "UnicodeBasic", - "manifestFile": "lake-manifest.json", - "inputRev": "main", - "inherited": true, - "configFile": "lakefile.lean"}, - {"url": "https://github.com/mhuisi/lean4-cli", - "type": "git", - "subDir": null, - "rev": "39229f3630d734af7d9cfb5937ddc6b41d3aa6aa", - "name": "Cli", - "manifestFile": "lake-manifest.json", - "inputRev": "nightly", - "inherited": true, - "configFile": "lakefile.lean"}, - {"url": "https://github.com/hargonix/LeanInk", - "type": "git", - "subDir": null, - "rev": "2447df5cc6e48eb965c3c3fba87e46d353b5e9f1", - "name": "leanInk", - "manifestFile": "lake-manifest.json", - "inputRev": "doc-gen", - "inherited": true, - "configFile": "lakefile.lean"}, - {"url": "https://github.com/leanprover/doc-gen4", - "type": "git", - "subDir": null, - "rev": "b7fad51b87a5f8fb3a238dc820ec40ebfa2a636e", - "name": "«doc-gen4»", - "manifestFile": "lake-manifest.json", - "inputRev": "main", - "inherited": false, - "configFile": "lakefile.lean"}], + "packages": [], "name": "batteries", "lakeDir": ".lake"} From 194b50cb40f6aaf5596e378ec612f24985d5a1a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20G=2E=20Dorais?= Date: Sat, 15 Jun 2024 20:23:47 -0400 Subject: [PATCH 055/208] chore: bump toolchain to v4.9.0-rc2 (#847) --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 0ba3faf807..29c0cea43e 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.9.0-rc1 +leanprover/lean4:v4.9.0-rc2 From 47e4cc5c5800c07d9bf232173c9941fa5bf68589 Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Sun, 16 Jun 2024 00:31:19 +0000 Subject: [PATCH 056/208] Reapply "chore(Tactic/Lint/Simp): make simpNF linter dsimp-aware (#839)" (#841) (#844) This reverts commit 0f5b28745722ab5f5168d2a418cabf8bee98f97a. --- Batteries/Tactic/Lint/Simp.lean | 26 +++++++++++++++++++------- test/lint_simpNF.lean | 14 ++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Batteries/Tactic/Lint/Simp.lean b/Batteries/Tactic/Lint/Simp.lean index 44a858b340..3dc801fe0a 100644 --- a/Batteries/Tactic/Lint/Simp.lean +++ b/Batteries/Tactic/Lint/Simp.lean @@ -93,14 +93,14 @@ def decorateError (msg : MessageData) (k : MetaM α) : MetaM α := do try k catch e => throw (.error e.getRef m!"{msg}\n{e.toMessageData}") /-- Render the list of simp lemmas. -/ -def formatLemmas (usedSimps : Simp.UsedSimps) : MetaM MessageData := do +def formatLemmas (usedSimps : Simp.UsedSimps) (simpName : String) : MetaM MessageData := do let mut args := #[] let env ← getEnv for (thm, _) in usedSimps.toArray.qsort (·.2 < ·.2) do if let .decl declName := thm then if env.contains declName && declName != ``eq_self then args := args.push (← mkConstWithFreshMVarLevels declName) - return m!"simp only {args.toList}" + return m!"{simpName} only {args.toList}" /-- A linter for simp lemmas whose lhs is not in simp-normal form, and which hence never fire. -/ @[env_linter] def simpNF : Linter where @@ -112,17 +112,29 @@ https://leanprover-community.github.io/mathlib_docs/notes.html#simp-normal%20for unless ← isSimpTheorem declName do return none let ctx := { ← Simp.Context.mkDefault with config.decide := false } checkAllSimpTheoremInfos (← getConstInfo declName).type fun {lhs, rhs, isConditional, ..} => do + let isRfl ← isRflTheorem declName let ({ expr := lhs', proof? := prf1, .. }, prf1Stats) ← - decorateError "simplify fails on left-hand side:" <| simp lhs ctx + decorateError "simplify fails on left-hand side:" <| + if !isRfl then + simp lhs ctx + else do + let (e, s) ← dsimp lhs ctx + return (Simp.Result.mk e .none .true, s) if prf1Stats.usedTheorems.contains (.decl declName) then return none let ({ expr := rhs', .. }, stats) ← - decorateError "simplify fails on right-hand side:" <| simp rhs ctx (stats := prf1Stats) + decorateError "simplify fails on right-hand side:" <| + if !isRfl then + simp rhs ctx (stats := prf1Stats) + else do + let (e, s) ← dsimp rhs ctx (stats := prf1Stats) + return (Simp.Result.mk e .none .true, s) let lhs'EqRhs' ← isSimpEq lhs' rhs' (whnfFirst := false) let lhsInNF ← isSimpEq lhs' lhs + let simpName := if !isRfl then "simp" else "dsimp" if lhs'EqRhs' then if prf1.isNone then return none -- TODO: FP rewriting foo.eq_2 using `simp only [foo]` - return m!"simp can prove this: - by {← formatLemmas stats.usedTheorems} + return m!"{simpName} can prove this: + by {← formatLemmas stats.usedTheorems simpName} One of the lemmas above could be a duplicate. If that's not the case try reordering lemmas or adding @[priority]. " @@ -132,7 +144,7 @@ If that's not the case try reordering lemmas or adding @[priority]. to {lhs'} using - {← formatLemmas prf1Stats.usedTheorems} + {← formatLemmas prf1Stats.usedTheorems simpName} Try to change the left-hand side to the simplified term! " else if !isConditional && lhs == lhs' then diff --git a/test/lint_simpNF.lean b/test/lint_simpNF.lean index 8587e464bb..e06e067d18 100644 --- a/test/lint_simpNF.lean +++ b/test/lint_simpNF.lean @@ -27,4 +27,18 @@ theorem sumCompl_apply_symm_of_pos (p : α → Prop) [DecidablePred p] (a : α) (sumCompl p).symm a = Sum.inl ⟨a, h⟩ := dif_pos h +def foo (n : Nat) : Nat := if n = n then n else 0 + +@[simp] +theorem foo_eq_id : foo = id := by + funext n + simp [foo] + +-- The following `dsimp`-lemma is (correctly) not flagged by the linter +@[simp] +theorem foo_eq_ite (n : Nat) : foo n = if n = n then n else 0 := by + rfl + +end Equiv + #lint- only simpNF From cbb12953d9b4b7d9949c5ec326eee205b67277ae Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sun, 16 Jun 2024 09:06:26 +0000 Subject: [PATCH 057/208] chore: bump to nightly-2024-06-16 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index a0bf3a31a1..87a6d187d5 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-15 +leanprover/lean4:nightly-2024-06-16 From 8e9392bfd80b1efbfeb1c302ff852822aa54eea7 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Mon, 17 Jun 2024 02:36:41 +0000 Subject: [PATCH 058/208] Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/4469 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 87a6d187d5..65100ddc4e 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-16 +leanprover/lean4-pr-releases:pr-release-4469 From cbf18ed917c0f7ba1c4c06a0ad4f47a7ea1e6cc3 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 17 Jun 2024 12:47:03 +1000 Subject: [PATCH 059/208] remove upstreamed --- Batteries/Data/List/Lemmas.lean | 2 -- 1 file changed, 2 deletions(-) diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 4db5a1c7a4..38c81c4f1e 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -1458,8 +1458,6 @@ theorem get?_range {m n : Nat} (h : m < n) : get? (range n) m = some m := by theorem range_succ (n : Nat) : range (succ n) = range n ++ [n] := by simp only [range_eq_range', range'_1_concat, Nat.zero_add] -@[simp] theorem range_zero : range 0 = [] := rfl - theorem range_add (a b : Nat) : range (a + b) = range a ++ (range b).map (a + ·) := by rw [← range'_eq_map_range] simpa [range_eq_range', Nat.add_comm] using (range'_append_1 0 a b).symm From 4387d9efde55d2ec27a6e24da2cb0c7558fa8bde Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Mon, 17 Jun 2024 04:02:48 +0000 Subject: [PATCH 060/208] Trigger CI for https://github.com/leanprover/lean4/pull/4469 From cbe4f1209b02fa5c06b30798ab835b6b7a133ff1 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 17 Jun 2024 17:54:33 +1000 Subject: [PATCH 061/208] bump toolchain --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 87a6d187d5..c28f6ba51e 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-16 +leanprover/lean4:nightly-2024-06-17 From a962bdc0eea7d9ad6bfaf450ad0f94c3ebc69ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20G=2E=20Dorais?= Date: Mon, 17 Jun 2024 18:29:59 -0400 Subject: [PATCH 062/208] feat: add `BinaryHeap` (#849) Co-authored-by: Mario Carneiro --- Batteries.lean | 1 + Batteries/Data/BinaryHeap.lean | 176 +++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 Batteries/Data/BinaryHeap.lean diff --git a/Batteries.lean b/Batteries.lean index dea5262d3b..706e967883 100644 --- a/Batteries.lean +++ b/Batteries.lean @@ -15,6 +15,7 @@ import Batteries.Control.Lemmas import Batteries.Control.Nondet.Basic import Batteries.Data.Array import Batteries.Data.AssocList +import Batteries.Data.BinaryHeap import Batteries.Data.BinomialHeap import Batteries.Data.BitVec import Batteries.Data.Bool diff --git a/Batteries/Data/BinaryHeap.lean b/Batteries/Data/BinaryHeap.lean new file mode 100644 index 0000000000..b36ed97fd3 --- /dev/null +++ b/Batteries/Data/BinaryHeap.lean @@ -0,0 +1,176 @@ +/- +Copyright (c) 2021 Mario Carneiro. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro +-/ + +namespace Batteries + +/-- A max-heap data structure. -/ +structure BinaryHeap (α) (lt : α → α → Bool) where + /-- Backing array for `BinaryHeap`. -/ + arr : Array α + +namespace BinaryHeap + +/-- Core operation for binary heaps, expressed directly on arrays. +Given an array which is a max-heap, push item `i` down to restore the max-heap property. -/ +def heapifyDown (lt : α → α → Bool) (a : Array α) (i : Fin a.size) : + {a' : Array α // a'.size = a.size} := + let left := 2 * i.1 + 1 + let right := left + 1 + have left_le : i ≤ left := Nat.le_trans + (by rw [Nat.succ_mul, Nat.one_mul]; exact Nat.le_add_left i i) + (Nat.le_add_right ..) + have right_le : i ≤ right := Nat.le_trans left_le (Nat.le_add_right ..) + have i_le : i ≤ i := Nat.le_refl _ + have j : {j : Fin a.size // i ≤ j} := if h : left < a.size then + if lt (a.get i) (a.get ⟨left, h⟩) then ⟨⟨left, h⟩, left_le⟩ else ⟨i, i_le⟩ else ⟨i, i_le⟩ + have j := if h : right < a.size then + if lt (a.get j) (a.get ⟨right, h⟩) then ⟨⟨right, h⟩, right_le⟩ else j else j + if h : i.1 = j then ⟨a, rfl⟩ else + let a' := a.swap i j + let j' := ⟨j, by rw [a.size_swap i j]; exact j.1.2⟩ + have : a'.size - j < a.size - i := by + rw [a.size_swap i j]; exact Nat.sub_lt_sub_left i.2 <| Nat.lt_of_le_of_ne j.2 h + let ⟨a₂, h₂⟩ := heapifyDown lt a' j' + ⟨a₂, h₂.trans (a.size_swap i j)⟩ +termination_by a.size - i + +@[simp] theorem size_heapifyDown (lt : α → α → Bool) (a : Array α) (i : Fin a.size) : + (heapifyDown lt a i).1.size = a.size := (heapifyDown lt a i).2 + +/-- Core operation for binary heaps, expressed directly on arrays. +Construct a heap from an unsorted array, by heapifying all the elements. -/ +def mkHeap (lt : α → α → Bool) (a : Array α) : {a' : Array α // a'.size = a.size} := + loop (a.size / 2) a (Nat.div_le_self ..) +where + /-- Inner loop for `mkHeap`. -/ + loop : (i : Nat) → (a : Array α) → i ≤ a.size → {a' : Array α // a'.size = a.size} + | 0, a, _ => ⟨a, rfl⟩ + | i+1, a, h => + let h := Nat.lt_of_succ_le h + let a' := heapifyDown lt a ⟨i, h⟩ + let ⟨a₂, h₂⟩ := loop i a' ((heapifyDown ..).2.symm ▸ Nat.le_of_lt h) + ⟨a₂, h₂.trans a'.2⟩ + +@[simp] theorem size_mkHeap (lt : α → α → Bool) (a : Array α) : + (mkHeap lt a).1.size = a.size := (mkHeap lt a).2 + +/-- Core operation for binary heaps, expressed directly on arrays. +Given an array which is a max-heap, push item `i` up to restore the max-heap property. -/ +def heapifyUp (lt : α → α → Bool) (a : Array α) (i : Fin a.size) : + {a' : Array α // a'.size = a.size} := + if i0 : i.1 = 0 then ⟨a, rfl⟩ else + have : (i.1 - 1) / 2 < i := Nat.lt_of_le_of_lt (Nat.div_le_self ..) <| + Nat.sub_lt (Nat.pos_of_ne_zero i0) Nat.zero_lt_one + let j := ⟨(i.1 - 1) / 2, Nat.lt_trans this i.2⟩ + if lt (a.get j) (a.get i) then + let a' := a.swap i j + let ⟨a₂, h₂⟩ := heapifyUp lt a' ⟨j.1, by rw [a.size_swap i j]; exact j.2⟩ + ⟨a₂, h₂.trans (a.size_swap i j)⟩ + else ⟨a, rfl⟩ + +@[simp] theorem size_heapifyUp (lt : α → α → Bool) (a : Array α) (i : Fin a.size) : + (heapifyUp lt a i).1.size = a.size := (heapifyUp lt a i).2 + +/-- `O(1)`. Build a new empty heap. -/ +def empty (lt) : BinaryHeap α lt := ⟨#[]⟩ + +instance (lt) : Inhabited (BinaryHeap α lt) := ⟨empty _⟩ +instance (lt) : EmptyCollection (BinaryHeap α lt) := ⟨empty _⟩ + +/-- `O(1)`. Build a one-element heap. -/ +def singleton (lt) (x : α) : BinaryHeap α lt := ⟨#[x]⟩ + +/-- `O(1)`. Get the number of elements in a `BinaryHeap`. -/ +def size (self : BinaryHeap α lt) : Nat := self.1.size + +/-- `O(1)`. Get an element in the heap by index. -/ +def get (self : BinaryHeap α lt) (i : Fin self.size) : α := self.1.get i + +/-- `O(log n)`. Insert an element into a `BinaryHeap`, preserving the max-heap property. -/ +def insert (self : BinaryHeap α lt) (x : α) : BinaryHeap α lt where + arr := let n := self.size; + heapifyUp lt (self.1.push x) ⟨n, by rw [Array.size_push]; apply Nat.lt_succ_self⟩ + +@[simp] theorem size_insert (self : BinaryHeap α lt) (x : α) : + (self.insert x).size = self.size + 1 := by + simp [insert, size, size_heapifyUp] + +/-- `O(1)`. Get the maximum element in a `BinaryHeap`. -/ +def max (self : BinaryHeap α lt) : Option α := self.1.get? 0 + +/-- Auxiliary for `popMax`. -/ +def popMaxAux (self : BinaryHeap α lt) : {a' : BinaryHeap α lt // a'.size = self.size - 1} := + match e: self.1.size with + | 0 => ⟨self, by simp [size, e]⟩ + | n+1 => + have h0 := by rw [e]; apply Nat.succ_pos + have hn := by rw [e]; apply Nat.lt_succ_self + if hn0 : 0 < n then + let a := self.1.swap ⟨0, h0⟩ ⟨n, hn⟩ |>.pop + ⟨⟨heapifyDown lt a ⟨0, by rwa [Array.size_pop, Array.size_swap, e]⟩⟩, + by simp [size, a]⟩ + else + ⟨⟨self.1.pop⟩, by simp [size]⟩ + +/-- `O(log n)`. Remove the maximum element from a `BinaryHeap`. +Call `max` first to actually retrieve the maximum element. -/ +def popMax (self : BinaryHeap α lt) : BinaryHeap α lt := self.popMaxAux + +@[simp] theorem size_popMax (self : BinaryHeap α lt) : + self.popMax.size = self.size - 1 := self.popMaxAux.2 + +/-- `O(log n)`. Return and remove the maximum element from a `BinaryHeap`. -/ +def extractMax (self : BinaryHeap α lt) : Option α × BinaryHeap α lt := + (self.max, self.popMax) + +theorem size_pos_of_max {self : BinaryHeap α lt} (e : self.max = some x) : 0 < self.size := + Decidable.of_not_not fun h : ¬ 0 < self.1.size => by simp [BinaryHeap.max, Array.get?, h] at e + +/-- `O(log n)`. Equivalent to `extractMax (self.insert x)`, except that extraction cannot fail. -/ +def insertExtractMax (self : BinaryHeap α lt) (x : α) : α × BinaryHeap α lt := + match e: self.max with + | none => (x, self) + | some m => + if lt x m then + let a := self.1.set ⟨0, size_pos_of_max e⟩ x + (m, ⟨heapifyDown lt a ⟨0, by simp only [Array.size_set, a]; exact size_pos_of_max e⟩⟩) + else (x, self) + +/-- `O(log n)`. Equivalent to `(self.max, self.popMax.insert x)`. -/ +def replaceMax (self : BinaryHeap α lt) (x : α) : Option α × BinaryHeap α lt := + match e: self.max with + | none => (none, ⟨self.1.push x⟩) + | some m => + let a := self.1.set ⟨0, size_pos_of_max e⟩ x + (some m, ⟨heapifyDown lt a ⟨0, by simp only [Array.size_set, a]; exact size_pos_of_max e⟩⟩) + +/-- `O(log n)`. Replace the value at index `i` by `x`. Assumes that `x ≤ self.get i`. -/ +def decreaseKey (self : BinaryHeap α lt) (i : Fin self.size) (x : α) : BinaryHeap α lt where + arr := heapifyDown lt (self.1.set i x) ⟨i, by rw [self.1.size_set]; exact i.2⟩ + +/-- `O(log n)`. Replace the value at index `i` by `x`. Assumes that `self.get i ≤ x`. -/ +def increaseKey (self : BinaryHeap α lt) (i : Fin self.size) (x : α) : BinaryHeap α lt where + arr := heapifyUp lt (self.1.set i x) ⟨i, by rw [self.1.size_set]; exact i.2⟩ + +end Batteries.BinaryHeap + +/-- `O(n)`. Convert an unsorted array to a `BinaryHeap`. -/ +def Array.toBinaryHeap (lt : α → α → Bool) (a : Array α) : Batteries.BinaryHeap α lt where + arr := Batteries.BinaryHeap.mkHeap lt a + +/-- `O(n log n)`. Sort an array using a `BinaryHeap`. -/ +@[specialize] def Array.heapSort (a : Array α) (lt : α → α → Bool) : Array α := + loop (a.toBinaryHeap (flip lt)) #[] +where + /-- Inner loop for `heapSort`. -/ + loop (a : Batteries.BinaryHeap α (flip lt)) (out : Array α) : Array α := + match e: a.max with + | none => out + | some x => + have : a.popMax.size < a.size := by + simp; exact Nat.sub_lt (Batteries.BinaryHeap.size_pos_of_max e) Nat.zero_lt_one + loop a.popMax (out.push x) + termination_by a.size From bcfe93e45a67d4917a854e8b3bf2156427cb71e5 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Tue, 18 Jun 2024 09:05:09 +0000 Subject: [PATCH 063/208] chore: bump to nightly-2024-06-18 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index c28f6ba51e..dca89cb6d9 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-17 +leanprover/lean4:nightly-2024-06-18 From 646d29782536566c5e3024036e66c40eba2a1494 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 18 Jun 2024 19:09:39 +1000 Subject: [PATCH 064/208] fixes for upstreamed lemmas --- Batteries/Data/List/Lemmas.lean | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 726e45ed99..6f4430f75d 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -653,32 +653,13 @@ end erase /-! ### filterMap -/ -theorem length_filter_le (p : α → Bool) (l : List α) : - (l.filter p).length ≤ l.length := (filter_sublist _).length_le - -theorem length_filterMap_le (f : α → Option β) (l : List α) : - (filterMap f l).length ≤ l.length := by - rw [← length_map _ some, map_filterMap_some_eq_filter_map_is_some, ← length_map _ f] - apply length_filter_le - protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) : filterMap f l₁ <+ filterMap f l₂ := by - induction s <;> simp <;> split <;> simp [*, cons, cons₂] + induction s <;> simp [filterMap_cons] <;> split <;> simp [*, cons, cons₂] theorem Sublist.filter (p : α → Bool) {l₁ l₂} (s : l₁ <+ l₂) : filter p l₁ <+ filter p l₂ := by rw [← filterMap_eq_filter]; apply s.filterMap -@[simp] -theorem filter_eq_self {l} : filter p l = l ↔ ∀ a ∈ l, p a := by - induction l with simp - | cons a l ih => - cases h : p a <;> simp [*] - intro h; exact Nat.lt_irrefl _ (h ▸ length_filter_le p l) - -@[simp] -theorem filter_length_eq_length {l} : (filter p l).length = l.length ↔ ∀ a ∈ l, p a := - Iff.trans ⟨l.filter_sublist.eq_of_length, congrArg length⟩ filter_eq_self - /-! ### findIdx -/ @[simp] theorem findIdx_nil {α : Type _} (p : α → Bool) : [].findIdx p = 0 := rfl From e2902e85e43e095ba17b826f6db51ee533c0b0bc Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 18 Jun 2024 19:11:18 +1000 Subject: [PATCH 065/208] fix --- Batteries/Data/List/Perm.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index 49299089a5..b90242688a 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -155,8 +155,8 @@ theorem Perm.filterMap (f : α → Option β) {l₁ l₂ : List α} (p : l₁ ~ filterMap f l₁ ~ filterMap f l₂ := by induction p with | nil => simp - | cons x _p IH => cases h : f x <;> simp [h, filterMap, IH, Perm.cons] - | swap x y l₂ => cases hx : f x <;> cases hy : f y <;> simp [hx, hy, filterMap, swap] + | cons x _p IH => cases h : f x <;> simp [h, filterMap_cons, IH, Perm.cons] + | swap x y l₂ => cases hx : f x <;> cases hy : f y <;> simp [hx, hy, filterMap_cons, swap] | trans _p₁ _p₂ IH₁ IH₂ => exact IH₁.trans IH₂ theorem Perm.map (f : α → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) : map f l₁ ~ map f l₂ := From 369dcb939867823bb49d143463275beebc4dd532 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 18 Jun 2024 19:13:03 +1000 Subject: [PATCH 066/208] chore: robust proof in HashMap.WF.filterMap --- Batteries/Data/HashMap/WF.lean | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index c29ce4ca9b..f1d70ac399 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -328,7 +328,9 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable let g₁ (l : AssocList α β) := l.toList.filterMap (fun x => (f x.1 x.2).map (x.1, ·)) have H1 (l n acc) : filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, ⟨n.1 + (g₁ l).length⟩) := by - induction l generalizing n acc with simp [filterMap.go, g₁, *] + induction l generalizing n acc with simp only [filterMap.go, AssocList.toList, + List.filterMap_nil, List.reverse_nil, List.nil_append, AssocList.toList_toAssocList, + List.length_nil, Nat.add_zero, List.filterMap_cons, g₁, *] | cons a b l => match f a b with | none => rfl | some c => @@ -350,7 +352,7 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable induction l with | nil => exact .slnil | cons a l ih => - simp; exact match f a.1 a.2 with + simp only [List.filterMap_cons, List.map_cons]; exact match f a.1 a.2 with | none => .cons _ ih | some b => .cons₂ _ ih suffices ∀ bk sz (h : 0 < bk.length), From f34392984409936947306b26898091d7221cb1bf Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 18 Jun 2024 22:08:11 +0100 Subject: [PATCH 067/208] chore: robust proof in HashMap.WF.filterMap (#852) --- Batteries/Data/HashMap/WF.lean | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index fb2635b8fe..57b121c83c 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -326,7 +326,9 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable let g₁ (l : AssocList α β) := l.toList.filterMap (fun x => (f x.1 x.2).map (x.1, ·)) have H1 (l n acc) : filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, ⟨n.1 + (g₁ l).length⟩) := by - induction l generalizing n acc with simp [filterMap.go, g₁, *] + induction l generalizing n acc with simp only [filterMap.go, AssocList.toList, + List.filterMap_nil, List.reverse_nil, List.nil_append, AssocList.toList_toAssocList, + List.length_nil, Nat.add_zero, List.filterMap_cons, g₁, *] | cons a b l => match f a b with | none => rfl | some c => @@ -348,7 +350,7 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable induction l with | nil => exact .slnil | cons a l ih => - simp; exact match f a.1 a.2 with + simp only [List.filterMap_cons, List.map_cons]; exact match f a.1 a.2 with | none => .cons _ ih | some b => .cons₂ _ ih suffices ∀ bk sz (h : 0 < bk.length), From bded6b88a1ea6bebae3f7a47c0c70bfd870882f7 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Wed, 19 Jun 2024 09:05:43 +0000 Subject: [PATCH 068/208] chore: bump to nightly-2024-06-19 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index dca89cb6d9..4419c56e1c 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-18 +leanprover/lean4:nightly-2024-06-19 From 71436176bc50782f17a4f6e0f14606f690fcf0a9 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 20 Jun 2024 11:38:52 +1000 Subject: [PATCH 069/208] fixes --- Batteries/Data/HashMap/WF.lean | 2 +- Batteries/Data/List/Basic.lean | 5 +++-- Batteries/Data/List/Lemmas.lean | 27 ++++++++++++++------------- Batteries/Data/List/Pairwise.lean | 2 +- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index f1d70ac399..f6298d3322 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -37,7 +37,7 @@ theorem size_eq (data : Buckets α β) : theorem mk_size (h) : (mk n h : Buckets α β).size = 0 := by simp only [mk, mkArray, size_eq]; clear h - induction n <;> simp [*] + induction n <;> simp_all [List.replicate_succ] theorem WF.mk' [BEq α] [Hashable α] (h) : (Buckets.mk n h : Buckets α β).WF := by refine ⟨fun _ h => ?_, fun i h => ?_⟩ diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index aacd1c9f2c..5de42cfb24 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -313,7 +313,8 @@ def takeD : Nat → List α → α → List α @[simp] theorem takeD_succ (l) (a : α) : takeD (n+1) l a = l.head?.getD a :: takeD n l.tail a := by simp [takeD] -@[simp] theorem takeD_nil (n) (a : α) : takeD n [] a = replicate n a := by induction n <;> simp [*] +@[simp] theorem takeD_nil (n) (a : α) : takeD n [] a = replicate n a := by + induction n <;> simp [*, replicate_succ] /-- Tail-recursive version of `takeD`. -/ def takeDTR (n : Nat) (l : List α) (dflt : α) : List α := go n l #[] where @@ -325,7 +326,7 @@ def takeDTR (n : Nat) (l : List α) (dflt : α) : List α := go n l #[] where theorem takeDTR_go_eq : ∀ n l, takeDTR.go dflt n l acc = acc.data ++ takeD n l dflt | 0, _ => by simp [takeDTR.go] - | _+1, [] => by simp [takeDTR.go] + | _+1, [] => by simp [takeDTR.go, replicate_succ] | _+1, _::l => by simp [takeDTR.go, takeDTR_go_eq _ l] @[csimp] theorem takeD_eq_takeDTR : @takeD = @takeDTR := by diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 6f4430f75d..7de8778289 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -249,7 +249,7 @@ theorem getElem_eq_iff {l : List α} {n : Nat} {h : n < l.length} : l[n] = x ↔ @[deprecated getElem_eq_iff (since := "2024-06-12")] theorem get_eq_iff : List.get l n = x ↔ l.get? n.1 = some x := by - simp [getElem_eq_iff] + simp theorem getElem?_inj (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs[i]? = xs[j]?) : i = j := by @@ -724,7 +724,7 @@ theorem findIdx?_eq_some_iff (xs : List α) (p : α → Bool) : | nil => simp | cons x xs ih => simp only [findIdx?_cons, Nat.zero_add, findIdx?_succ, take_succ_cons, map_cons] - split <;> cases i <;> simp_all + split <;> cases i <;> simp_all [replicate_succ] theorem findIdx?_of_eq_some {xs : List α} {p : α → Bool} (w : xs.findIdx? p = some i) : match xs.get? i with | some a => p a | none => false := by @@ -1369,15 +1369,15 @@ theorem getElem?_range' (s step) : exact (getElem?_range' (s + step) step (Nat.lt_of_add_lt_add_right h)).trans <| by simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm] -@[deprecated getElem?_range' (since := "2024-06-12")] -theorem get?_range' (s step) {m n : Nat} (h : m < n) : - get? (range' s n step) m = some (s + step * m) := by - simp [getElem?_range', h] - @[simp] theorem getElem_range' {n m step} (i) (H : i < (range' n m step).length) : (range' n m step)[i] = n + step * i := (getElem?_eq_some.1 <| getElem?_range' n step (by simpa using H)).2 +@[deprecated getElem?_range' (since := "2024-06-12")] +theorem get?_range' (s step) {m n : Nat} (h : m < n) : + get? (range' s n step) m = some (s + step * m) := by + simp [h] + @[deprecated getElem_range' (since := "2024-06-12")] theorem get_range' {n m step} (i) (H : i < (range' n m step).length) : get (range' n m step) ⟨i, H⟩ = n + step * i := by @@ -1428,10 +1428,17 @@ theorem self_mem_range_succ (n : Nat) : n ∈ range (n + 1) := by simp theorem getElem?_range {m n : Nat} (h : m < n) : (range n)[m]? = some m := by simp [range_eq_range', getElem?_range' _ _ h] +@[simp] theorem getElem_range {n : Nat} (m) (h : m < (range n).length) : (range n)[m] = m := by + simp [range_eq_range'] + @[deprecated getElem?_range (since := "2024-06-12")] theorem get?_range {m n : Nat} (h : m < n) : get? (range n) m = some m := by simp [getElem?_range, h] +@[deprecated getElem_range (since := "2024-06-12")] +theorem get_range {n} (i) (H : i < (range n).length) : get (range n) ⟨i, H⟩ = i := by + simp + theorem range_succ (n : Nat) : range (succ n) = range n ++ [n] := by simp only [range_eq_range', range'_1_concat, Nat.zero_add] @@ -1456,12 +1463,6 @@ theorem reverse_range' : ∀ s n : Nat, reverse (range' s n) = map (s + n - 1 - show s + (n + 1) - 1 = s + n from rfl, map, map_map] simp [reverse_range', Nat.sub_right_comm]; rfl -@[simp] theorem getElem_range {n} (i) (H : i < (range n).length) : (range n)[i] = i := - Option.some.inj <| by rw [← getElem?_eq_getElem _, getElem?_range (by simpa using H)] - -@[deprecated getElem_range (since := "2024-06-12")] -theorem get_range {n} (i) (H : i < (range n).length) : get (range n) ⟨i, H⟩ = i := by - simp /-! ### enum, enumFrom -/ diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index b808fe85e7..8583a41f2b 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -258,7 +258,7 @@ theorem pairwise_iff_get : Pairwise R l ↔ ∀ (i j) (_hij : i < j), R (get l i theorem pairwise_replicate {α : Type _} {r : α → α → Prop} {x : α} (hx : r x x) : ∀ n : Nat, Pairwise r (List.replicate n x) | 0 => by simp - | n + 1 => by simp [mem_replicate, hx, pairwise_replicate hx n] + | n + 1 => by simp [mem_replicate, hx, pairwise_replicate hx n, replicate_succ] /-! ### Pairwise filtering -/ From 73c7f46f4c0eaa48e9538c9fd108d3ee5524868a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20G=2E=20Dorais?= Date: Thu, 20 Jun 2024 21:06:34 -0400 Subject: [PATCH 070/208] feat: add simps and `toNat` lemmas for `UIntX` types (#853) --- Batteries/Data/UInt.lean | 109 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) diff --git a/Batteries/Data/UInt.lean b/Batteries/Data/UInt.lean index 3151a25852..46fcb26b59 100644 --- a/Batteries/Data/UInt.lean +++ b/Batteries/Data/UInt.lean @@ -14,6 +14,12 @@ theorem UInt8.ext_iff {x y : UInt8} : x = y ↔ x.toNat = y.toNat := ⟨congrArg @[simp] theorem UInt8.val_val_eq_toNat (x : UInt8) : x.val.val = x.toNat := rfl +@[simp] theorem UInt8.val_ofNat (n) : + (no_index (OfNat.ofNat n) : UInt8).val = OfNat.ofNat n := rfl + +@[simp] theorem UInt8.toNat_ofNat (n) : + (no_index (OfNat.ofNat n) : UInt8).toNat = n % UInt8.size := rfl + theorem UInt8.toNat_lt (x : UInt8) : x.toNat < 2 ^ 8 := x.val.isLt @[simp] theorem UInt8.toUInt16_toNat (x : UInt8) : x.toUInt16.toNat = x.toNat := rfl @@ -22,6 +28,21 @@ theorem UInt8.toNat_lt (x : UInt8) : x.toNat < 2 ^ 8 := x.val.isLt @[simp] theorem UInt8.toUInt64_toNat (x : UInt8) : x.toUInt64.toNat = x.toNat := rfl +theorem UInt8.toNat_zero : (0 : UInt8).toNat = 0 := rfl + +theorem UInt8.toNat_add (x y : UInt8) : (x + y).toNat = (x.toNat + y.toNat) % UInt8.size := rfl + +theorem UInt8.toNat_sub (x y : UInt8) : + (x - y).toNat = (x.toNat + (UInt8.size - y.toNat)) % UInt8.size := rfl + +theorem UInt8.toNat_mul (x y : UInt8) : (x * y).toNat = (x.toNat * y.toNat) % UInt8.size := rfl + +theorem UInt8.toNat_div (x y : UInt8) : (x / y).toNat = x.toNat / y.toNat := rfl + +theorem UInt8.toNat_mod (x y : UInt8) : (x % y).toNat = x.toNat % y.toNat := rfl + +theorem UInt8.toNat_modn (x : UInt8) (n) : (x.modn n).toNat = x.toNat % n := rfl + theorem UInt8.le_antisymm_iff {x y : UInt8} : x = y ↔ x ≤ y ∧ y ≤ x := UInt8.ext_iff.trans Nat.le_antisymm_iff @@ -38,16 +59,37 @@ instance : Batteries.LawfulOrd UInt8 := .compareOfLessAndEq theorem UInt16.ext_iff {x y : UInt16} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, UInt16.ext⟩ -theorem UInt16.toNat_lt (x : UInt16) : x.toNat < 2 ^ 16 := x.val.isLt - @[simp] theorem UInt16.val_val_eq_toNat (x : UInt16) : x.val.val = x.toNat := rfl +@[simp] theorem UInt16.val_ofNat (n) : + (no_index (OfNat.ofNat n) : UInt16).val = OfNat.ofNat n := rfl + +@[simp] theorem UInt16.toNat_ofNat (n) : + (no_index (OfNat.ofNat n) : UInt16).toNat = n % UInt16.size := rfl + +theorem UInt16.toNat_lt (x : UInt16) : x.toNat < 2 ^ 16 := x.val.isLt + @[simp] theorem UInt16.toUInt8_toNat (x : UInt16) : x.toUInt8.toNat = x.toNat % 2 ^ 8 := rfl @[simp] theorem UInt16.toUInt32_toNat (x : UInt16) : x.toUInt32.toNat = x.toNat := rfl @[simp] theorem UInt16.toUInt64_toNat (x : UInt16) : x.toUInt64.toNat = x.toNat := rfl +theorem UInt16.toNat_zero : (0 : UInt16).toNat = 0 := rfl + +theorem UInt16.toNat_add (x y : UInt16) : (x + y).toNat = (x.toNat + y.toNat) % UInt16.size := rfl + +theorem UInt16.toNat_sub (x y : UInt16) : + (x - y).toNat = (x.toNat + (UInt16.size - y.toNat)) % UInt16.size := rfl + +theorem UInt16.toNat_mul (x y : UInt16) : (x * y).toNat = (x.toNat * y.toNat) % UInt16.size := rfl + +theorem UInt16.toNat_div (x y : UInt16) : (x / y).toNat = x.toNat / y.toNat := rfl + +theorem UInt16.toNat_mod (x y : UInt16) : (x % y).toNat = x.toNat % y.toNat := rfl + +theorem UInt16.toNat_modn (x : UInt16) (n) : (x.modn n).toNat = x.toNat % n := rfl + theorem UInt16.le_antisymm_iff {x y : UInt16} : x = y ↔ x ≤ y ∧ y ≤ x := UInt16.ext_iff.trans Nat.le_antisymm_iff @@ -66,6 +108,12 @@ theorem UInt32.ext_iff {x y : UInt32} : x = y ↔ x.toNat = y.toNat := ⟨congrA @[simp] theorem UInt32.val_val_eq_toNat (x : UInt32) : x.val.val = x.toNat := rfl +@[simp] theorem UInt32.val_ofNat (n) : + (no_index (OfNat.ofNat n) : UInt32).val = OfNat.ofNat n := rfl + +@[simp] theorem UInt32.toNat_ofNat (n) : + (no_index (OfNat.ofNat n) : UInt32).toNat = n % UInt32.size := rfl + theorem UInt32.toNat_lt (x : UInt32) : x.toNat < 2 ^ 32 := x.val.isLt @[simp] theorem UInt32.toUInt8_toNat (x : UInt32) : x.toUInt8.toNat = x.toNat % 2 ^ 8 := rfl @@ -74,6 +122,21 @@ theorem UInt32.toNat_lt (x : UInt32) : x.toNat < 2 ^ 32 := x.val.isLt @[simp] theorem UInt32.toUInt64_toNat (x : UInt32) : x.toUInt64.toNat = x.toNat := rfl +theorem UInt32.toNat_zero : (0 : UInt32).toNat = 0 := rfl + +theorem UInt32.toNat_add (x y : UInt32) : (x + y).toNat = (x.toNat + y.toNat) % UInt32.size := rfl + +theorem UInt32.toNat_sub (x y : UInt32) : + (x - y).toNat = (x.toNat + (UInt32.size - y.toNat)) % UInt32.size := rfl + +theorem UInt32.toNat_mul (x y : UInt32) : (x * y).toNat = (x.toNat * y.toNat) % UInt32.size := rfl + +theorem UInt32.toNat_div (x y : UInt32) : (x / y).toNat = x.toNat / y.toNat := rfl + +theorem UInt32.toNat_mod (x y : UInt32) : (x % y).toNat = x.toNat % y.toNat := rfl + +theorem UInt32.toNat_modn (x : UInt32) (n) : (x.modn n).toNat = x.toNat % n := rfl + theorem UInt32.le_antisymm_iff {x y : UInt32} : x = y ↔ x ≤ y ∧ y ≤ x := UInt32.ext_iff.trans Nat.le_antisymm_iff @@ -92,6 +155,12 @@ theorem UInt64.ext_iff {x y : UInt64} : x = y ↔ x.toNat = y.toNat := ⟨congrA @[simp] theorem UInt64.val_val_eq_toNat (x : UInt64) : x.val.val = x.toNat := rfl +@[simp] theorem UInt64.val_ofNat (n) : + (no_index (OfNat.ofNat n) : UInt64).val = OfNat.ofNat n := rfl + +@[simp] theorem UInt64.toNat_ofNat (n) : + (no_index (OfNat.ofNat n) : UInt64).toNat = n % UInt64.size := rfl + theorem UInt64.toNat_lt (x : UInt64) : x.toNat < 2 ^ 64 := x.val.isLt @[simp] theorem UInt64.toUInt8_toNat (x : UInt64) : x.toUInt8.toNat = x.toNat % 2 ^ 8 := rfl @@ -100,6 +169,21 @@ theorem UInt64.toNat_lt (x : UInt64) : x.toNat < 2 ^ 64 := x.val.isLt @[simp] theorem UInt64.toUInt32_toNat (x : UInt64) : x.toUInt32.toNat = x.toNat % 2 ^ 32 := rfl +theorem UInt64.toNat_zero : (0 : UInt64).toNat = 0 := rfl + +theorem UInt64.toNat_add (x y : UInt64) : (x + y).toNat = (x.toNat + y.toNat) % UInt64.size := rfl + +theorem UInt64.toNat_sub (x y : UInt64) : + (x - y).toNat = (x.toNat + (UInt64.size - y.toNat)) % UInt64.size := rfl + +theorem UInt64.toNat_mul (x y : UInt64) : (x * y).toNat = (x.toNat * y.toNat) % UInt64.size := rfl + +theorem UInt64.toNat_div (x y : UInt64) : (x / y).toNat = x.toNat / y.toNat := rfl + +theorem UInt64.toNat_mod (x y : UInt64) : (x % y).toNat = x.toNat % y.toNat := rfl + +theorem UInt64.toNat_modn (x : UInt64) (n) : (x.modn n).toNat = x.toNat % n := rfl + theorem UInt64.le_antisymm_iff {x y : UInt64} : x = y ↔ x ≤ y ∧ y ≤ x := UInt64.ext_iff.trans Nat.le_antisymm_iff @@ -118,6 +202,12 @@ theorem USize.ext_iff {x y : USize} : x = y ↔ x.toNat = y.toNat := ⟨congrArg @[simp] theorem USize.val_val_eq_toNat (x : USize) : x.val.val = x.toNat := rfl +@[simp] theorem USize.val_ofNat (n) : + (no_index (OfNat.ofNat n) : USize).val = OfNat.ofNat n := rfl + +@[simp] theorem USize.toNat_ofNat (n) : + (no_index (OfNat.ofNat n) : USize).toNat = n % USize.size := rfl + theorem USize.size_eq : USize.size = 2 ^ System.Platform.numBits := by have : 1 ≤ 2 ^ System.Platform.numBits := Nat.succ_le_of_lt (Nat.two_pow_pos _) rw [USize.size, Nat.sub_add_cancel this] @@ -140,6 +230,21 @@ theorem USize.toNat_lt (x : USize) : x.toNat < 2 ^ System.Platform.numBits := by @[simp] theorem UInt32.toUSize_toNat (x : UInt32) : x.toUSize.toNat = x.toNat := rfl +theorem USize.toNat_zero : (0 : USize).toNat = 0 := rfl + +theorem USize.toNat_add (x y : USize) : (x + y).toNat = (x.toNat + y.toNat) % USize.size := rfl + +theorem USize.toNat_sub (x y : USize) : + (x - y).toNat = (x.toNat + (USize.size - y.toNat)) % USize.size := rfl + +theorem USize.toNat_mul (x y : USize) : (x * y).toNat = (x.toNat * y.toNat) % USize.size := rfl + +theorem USize.toNat_div (x y : USize) : (x / y).toNat = x.toNat / y.toNat := rfl + +theorem USize.toNat_mod (x y : USize) : (x % y).toNat = x.toNat % y.toNat := rfl + +theorem USize.toNat_modn (x : USize) (n) : (x.modn n).toNat = x.toNat % n := rfl + theorem USize.le_antisymm_iff {x y : USize} : x = y ↔ x ≤ y ∧ y ≤ x := USize.ext_iff.trans Nat.le_antisymm_iff From fcf561b1c1674cf79fa5b2478d52ea71d66e4493 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 21 Jun 2024 11:15:20 +1000 Subject: [PATCH 071/208] fix UInt stuff --- Batteries/Data/UInt.lean | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Batteries/Data/UInt.lean b/Batteries/Data/UInt.lean index 46fcb26b59..a9ce1b561a 100644 --- a/Batteries/Data/UInt.lean +++ b/Batteries/Data/UInt.lean @@ -33,7 +33,7 @@ theorem UInt8.toNat_zero : (0 : UInt8).toNat = 0 := rfl theorem UInt8.toNat_add (x y : UInt8) : (x + y).toNat = (x.toNat + y.toNat) % UInt8.size := rfl theorem UInt8.toNat_sub (x y : UInt8) : - (x - y).toNat = (x.toNat + (UInt8.size - y.toNat)) % UInt8.size := rfl + (x - y).toNat = (UInt8.size - y.toNat + x.toNat) % UInt8.size := rfl theorem UInt8.toNat_mul (x y : UInt8) : (x * y).toNat = (x.toNat * y.toNat) % UInt8.size := rfl @@ -80,7 +80,7 @@ theorem UInt16.toNat_zero : (0 : UInt16).toNat = 0 := rfl theorem UInt16.toNat_add (x y : UInt16) : (x + y).toNat = (x.toNat + y.toNat) % UInt16.size := rfl theorem UInt16.toNat_sub (x y : UInt16) : - (x - y).toNat = (x.toNat + (UInt16.size - y.toNat)) % UInt16.size := rfl + (x - y).toNat = (UInt16.size - y.toNat + x.toNat) % UInt16.size := rfl theorem UInt16.toNat_mul (x y : UInt16) : (x * y).toNat = (x.toNat * y.toNat) % UInt16.size := rfl @@ -127,7 +127,7 @@ theorem UInt32.toNat_zero : (0 : UInt32).toNat = 0 := rfl theorem UInt32.toNat_add (x y : UInt32) : (x + y).toNat = (x.toNat + y.toNat) % UInt32.size := rfl theorem UInt32.toNat_sub (x y : UInt32) : - (x - y).toNat = (x.toNat + (UInt32.size - y.toNat)) % UInt32.size := rfl + (x - y).toNat = (UInt32.size - y.toNat + x.toNat) % UInt32.size := rfl theorem UInt32.toNat_mul (x y : UInt32) : (x * y).toNat = (x.toNat * y.toNat) % UInt32.size := rfl @@ -174,7 +174,7 @@ theorem UInt64.toNat_zero : (0 : UInt64).toNat = 0 := rfl theorem UInt64.toNat_add (x y : UInt64) : (x + y).toNat = (x.toNat + y.toNat) % UInt64.size := rfl theorem UInt64.toNat_sub (x y : UInt64) : - (x - y).toNat = (x.toNat + (UInt64.size - y.toNat)) % UInt64.size := rfl + (x - y).toNat = (UInt64.size - y.toNat + x.toNat) % UInt64.size := rfl theorem UInt64.toNat_mul (x y : UInt64) : (x * y).toNat = (x.toNat * y.toNat) % UInt64.size := rfl @@ -235,7 +235,7 @@ theorem USize.toNat_zero : (0 : USize).toNat = 0 := rfl theorem USize.toNat_add (x y : USize) : (x + y).toNat = (x.toNat + y.toNat) % USize.size := rfl theorem USize.toNat_sub (x y : USize) : - (x - y).toNat = (x.toNat + (USize.size - y.toNat)) % USize.size := rfl + (x - y).toNat = (USize.size - y.toNat + x.toNat) % USize.size := rfl theorem USize.toNat_mul (x y : USize) : (x * y).toNat = (x.toNat * y.toNat) % USize.size := rfl From 2d5e3afaf79fb9267c11cf25e91f68b5582eacf5 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 21 Jun 2024 09:05:02 +0000 Subject: [PATCH 072/208] chore: bump to nightly-2024-06-21 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 4419c56e1c..89967b9cbe 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-19 +leanprover/lean4:nightly-2024-06-21 From 6e7a5737b7238e98bed0dea283e75fc772849525 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 21 Jun 2024 20:32:41 +1000 Subject: [PATCH 073/208] fix --- Batteries/Data/Fin/Lemmas.lean | 2 +- Batteries/Data/List/Basic.lean | 2 +- Batteries/Data/List/Lemmas.lean | 2 +- Batteries/Data/List/Perm.lean | 2 +- Batteries/Lean/PersistentHashMap.lean | 9 --------- Batteries/Lean/PersistentHashSet.lean | 10 ---------- Batteries/Tactic/Lint/Simp.lean | 4 ++-- Batteries/Tactic/SqueezeScope.lean | 3 ++- 8 files changed, 8 insertions(+), 26 deletions(-) diff --git a/Batteries/Data/Fin/Lemmas.lean b/Batteries/Data/Fin/Lemmas.lean index a223dca2b5..4d4eb59a1a 100644 --- a/Batteries/Data/Fin/Lemmas.lean +++ b/Batteries/Data/Fin/Lemmas.lean @@ -57,7 +57,7 @@ theorem list_reverse (n) : (list n).reverse = (list n).map rev := by | succ n ih => conv => lhs; rw [list_succ_last] conv => rhs; rw [list_succ] - simp [List.reverse_map, ih, Function.comp_def, rev_succ] + simp [← List.map_reverse, ih, Function.comp_def, rev_succ] /-! ### foldl -/ diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index 5de42cfb24..a8c3fef85a 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -486,7 +486,7 @@ def initsTR (l : List α) : List (List α) := l.foldr (fun a arrs => (arrs.map fun t => a :: t).push []) #[[]] |>.toListRev @[csimp] theorem inits_eq_initsTR : @inits = @initsTR := by - funext α l; simp [initsTR]; induction l <;> simp [*, reverse_map] + funext α l; simp [initsTR]; induction l <;> simp [*, map_reverse] /-- `tails l` is the list of terminal segments of `l`. diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 7de8778289..71595fade8 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -1461,7 +1461,7 @@ theorem reverse_range' : ∀ s n : Nat, reverse (range' s n) = map (s + n - 1 - | s, n + 1 => by rw [range'_1_concat, reverse_append, range_succ_eq_map, show s + (n + 1) - 1 = s + n from rfl, map, map_map] - simp [reverse_range', Nat.sub_right_comm]; rfl + simp [reverse_range', Nat.sub_right_comm, Nat.sub_sub] /-! ### enum, enumFrom -/ diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index b90242688a..ab12db10b1 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -643,7 +643,7 @@ theorem Perm.union {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : theorem Perm.inter_right {l₁ l₂ : List α} (t₁ : List α) : l₁ ~ l₂ → l₁ ∩ t₁ ~ l₂ ∩ t₁ := .filter _ theorem Perm.inter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) : l ∩ t₁ = l ∩ t₂ := - filter_congr' fun a _ => by simpa using p.mem_iff (a := a) + filter_congr fun a _ => by simpa using p.mem_iff (a := a) theorem Perm.inter {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : l₁ ∩ t₁ ~ l₂ ∩ t₂ := p₂.inter_left l₂ ▸ p₁.inter_right t₁ diff --git a/Batteries/Lean/PersistentHashMap.lean b/Batteries/Lean/PersistentHashMap.lean index 5054e15758..b297f2fa52 100644 --- a/Batteries/Lean/PersistentHashMap.lean +++ b/Batteries/Lean/PersistentHashMap.lean @@ -10,15 +10,6 @@ namespace Lean.PersistentHashMap variable [BEq α] [Hashable α] -/-- -Similar to `insert`, but also returns a Boolean flag indicating whether an -existing entry has been replaced with `a => b`. --/ -def insert' (m : PersistentHashMap α β) (a : α) (b : β) : PersistentHashMap α β × Bool := - let oldSize := m.size - let m := m.insert a b - (m, m.size == oldSize) - /-- Builds a `PersistentHashMap` from a list of key-value pairs. Values of duplicated keys are replaced by their respective last occurrences. diff --git a/Batteries/Lean/PersistentHashSet.lean b/Batteries/Lean/PersistentHashSet.lean index 51e33e8487..0a8231d723 100644 --- a/Batteries/Lean/PersistentHashSet.lean +++ b/Batteries/Lean/PersistentHashSet.lean @@ -56,16 +56,6 @@ def all (s : PersistentHashSet α) (f : α → Bool) : Bool := instance : BEq (PersistentHashSet α) where beq s t := s.all (t.contains ·) && t.all (s.contains ·) -/-- -Similar to `insert`, but also returns a Boolean flag indicating whether an -existing entry has been replaced with `a => b`. --/ -@[inline] -def insert' (s : PersistentHashSet α) (a : α) : PersistentHashSet α × Bool := - let oldSize := s.size - let s := s.insert a - (s, s.size == oldSize) - /-- Insert all elements from a collection into a `PersistentHashSet`. -/ diff --git a/Batteries/Tactic/Lint/Simp.lean b/Batteries/Tactic/Lint/Simp.lean index 3dc801fe0a..9196e4ab74 100644 --- a/Batteries/Tactic/Lint/Simp.lean +++ b/Batteries/Tactic/Lint/Simp.lean @@ -96,7 +96,7 @@ def decorateError (msg : MessageData) (k : MetaM α) : MetaM α := do def formatLemmas (usedSimps : Simp.UsedSimps) (simpName : String) : MetaM MessageData := do let mut args := #[] let env ← getEnv - for (thm, _) in usedSimps.toArray.qsort (·.2 < ·.2) do + for (thm, _) in usedSimps.map.toArray.qsort (·.2 < ·.2) do if let .decl declName := thm then if env.contains declName && declName != ``eq_self then args := args.push (← mkConstWithFreshMVarLevels declName) @@ -120,7 +120,7 @@ https://leanprover-community.github.io/mathlib_docs/notes.html#simp-normal%20for else do let (e, s) ← dsimp lhs ctx return (Simp.Result.mk e .none .true, s) - if prf1Stats.usedTheorems.contains (.decl declName) then return none + if prf1Stats.usedTheorems.map.contains (.decl declName) then return none let ({ expr := rhs', .. }, stats) ← decorateError "simplify fails on right-hand side:" <| if !isRfl then diff --git a/Batteries/Tactic/SqueezeScope.lean b/Batteries/Tactic/SqueezeScope.lean index 78a1d2a540..442bf781c3 100644 --- a/Batteries/Tactic/SqueezeScope.lean +++ b/Batteries/Tactic/SqueezeScope.lean @@ -85,7 +85,8 @@ elab_rules : tactic throw e if let some new := new then for (_, stx, usedSimps) in new do - let usedSimps := usedSimps.foldl (fun s usedSimps => usedSimps.foldl .insert s) {} + let usedSimps := usedSimps.foldl + (fun s usedSimps => usedSimps.map.foldl (fun u o _ => u.insert o) s) {} let stx' ← mkSimpCallStx stx usedSimps TryThis.addSuggestion stx[0] stx' (origSpan? := stx) From 91a8b9e6286438b3cd79e7c174b1d0c6c8833192 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 21 Jun 2024 21:32:39 +1000 Subject: [PATCH 074/208] fix squeezesimp --- Batteries/Tactic/SqueezeScope.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Batteries/Tactic/SqueezeScope.lean b/Batteries/Tactic/SqueezeScope.lean index 442bf781c3..df289dc982 100644 --- a/Batteries/Tactic/SqueezeScope.lean +++ b/Batteries/Tactic/SqueezeScope.lean @@ -85,8 +85,8 @@ elab_rules : tactic throw e if let some new := new then for (_, stx, usedSimps) in new do - let usedSimps := usedSimps.foldl - (fun s usedSimps => usedSimps.map.foldl (fun u o _ => u.insert o) s) {} + let usedSimps := usedSimps.reverse.foldl + (fun s usedSimps => usedSimps.toArray.foldl .insert s) {} let stx' ← mkSimpCallStx stx usedSimps TryThis.addSuggestion stx[0] stx' (origSpan? := stx) From 1172deb5b03fd3082bd6b06f4afedea118a95b74 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sat, 22 Jun 2024 09:05:29 +0000 Subject: [PATCH 075/208] chore: bump to nightly-2024-06-22 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 89967b9cbe..1dac433b86 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-21 +leanprover/lean4:nightly-2024-06-22 From 53a71fba4f5c245166e9e597be29babdf8d69c12 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Sat, 22 Jun 2024 20:45:26 +1000 Subject: [PATCH 076/208] fix imports --- Batteries/Tactic/Alias.lean | 1 + Batteries/Tactic/NoMatch.lean | 1 + 2 files changed, 2 insertions(+) diff --git a/Batteries/Tactic/Alias.lean b/Batteries/Tactic/Alias.lean index b7eaeaf713..07b91dc76e 100644 --- a/Batteries/Tactic/Alias.lean +++ b/Batteries/Tactic/Alias.lean @@ -6,6 +6,7 @@ Authors: Mario Carneiro, David Renshaw, François G. Dorais import Lean.Elab.Command import Lean.Elab.DeclarationRange import Lean.Compiler.NoncomputableAttr +import Lean.DocString import Batteries.CodeAction.Deprecated /-! diff --git a/Batteries/Tactic/NoMatch.lean b/Batteries/Tactic/NoMatch.lean index 9dc517b33f..7efe68e7d2 100644 --- a/Batteries/Tactic/NoMatch.lean +++ b/Batteries/Tactic/NoMatch.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Lean.Elab.ElabRules +import Lean.DocString /-! Deprecation warnings for `match ⋯ with.`, `fun.`, `λ.`, and `intro.`. From d930b073451d7d35af79500963df24e2c85dc1b5 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Sat, 22 Jun 2024 20:52:32 +1000 Subject: [PATCH 077/208] lint --- Batteries/Lean/AttributeExtra.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Batteries/Lean/AttributeExtra.lean b/Batteries/Lean/AttributeExtra.lean index 7b8c92af3f..aeac0267c5 100644 --- a/Batteries/Lean/AttributeExtra.lean +++ b/Batteries/Lean/AttributeExtra.lean @@ -81,7 +81,7 @@ Registers a new parametric attribute. The `extra` field is a list of definitions which will be "pre-tagged" and are not subject to the usual restriction on tagging in the same file as the declaration. -/ -def registerParametricAttributeExtra [Inhabited α] (impl : ParametricAttributeImpl α) +def registerParametricAttributeExtra (impl : ParametricAttributeImpl α) (extra : List (Name × α)) : IO (ParametricAttributeExtra α) := do let attr ← registerParametricAttribute impl pure { attr, base := extra.foldl (fun s (a, b) => s.insert a b) {} } From 3055ff67f2dba9b6618931a1119966c50d0d323d Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sun, 23 Jun 2024 09:06:18 +0000 Subject: [PATCH 078/208] chore: bump to nightly-2024-06-23 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 1dac433b86..eebab7d43f 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-22 +leanprover/lean4:nightly-2024-06-23 From af507cff7f703fa66fce309a6949d7fc9e921e17 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Mon, 24 Jun 2024 09:06:41 +0000 Subject: [PATCH 079/208] chore: bump to nightly-2024-06-24 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index eebab7d43f..e478ca5a00 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-23 +leanprover/lean4:nightly-2024-06-24 From af65a4acf19dc297cc6c0c925d7126b6e6864d3d Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 24 Jun 2024 19:33:21 +1000 Subject: [PATCH 080/208] fix test --- test/absurd.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/absurd.lean b/test/absurd.lean index 4974467e5a..1817c0e715 100644 --- a/test/absurd.lean +++ b/test/absurd.lean @@ -43,5 +43,5 @@ h : p → False ⊢ p -/ #guard_msgs in -example (h : p → False) : 0 = 3 := by +example {p : Prop} (h : p → False) : 0 = 3 := by absurd h From da2d1d464eb2e99db4f39b850e89cee4d5f72fc8 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 25 Jun 2024 07:59:01 +0100 Subject: [PATCH 081/208] chore: bump toolchain to v4.9.0-rc3 (#858) --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 29c0cea43e..e5ea66000f 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.9.0-rc2 +leanprover/lean4:v4.9.0-rc3 From e9024756d0dc93dbe3e788c31fedebb699f4199a Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 25 Jun 2024 18:37:58 +1000 Subject: [PATCH 082/208] bump toolchain --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index e478ca5a00..1452d9a5a3 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-24 +leanprover/lean4:nightly-2024-06-25 From 686e90d51cd34c619739e9df73bc0bc81972aac6 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 25 Jun 2024 18:39:45 +1000 Subject: [PATCH 083/208] remove upstreamed lemma --- Batteries/Data/List/Lemmas.lean | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 71595fade8..44d9a5c18d 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -1474,16 +1474,6 @@ theorem reverse_range' : ∀ s n : Nat, reverse (range' s n) = map (s + n - 1 - @[simp] theorem enum_map_fst (l : List α) : map Prod.fst (enum l) = range l.length := by simp only [enum, enumFrom_map_fst, range_eq_range'] -/-! ### maximum? -/ - --- A specialization of `maximum?_eq_some_iff` to Nat. -theorem maximum?_eq_some_iff' {xs : List Nat} : - xs.maximum? = some a ↔ (a ∈ xs ∧ ∀ b ∈ xs, b ≤ a) := - maximum?_eq_some_iff - (le_refl := Nat.le_refl) - (max_eq_or := fun _ _ => Nat.max_def .. ▸ by split <;> simp) - (max_le_iff := fun _ _ _ => Nat.max_le) - /-! ### indexOf and indexesOf -/ theorem foldrIdx_start : From 93343d4debf6d7f07ec467e1e60801072e81f0ab Mon Sep 17 00:00:00 2001 From: damiano Date: Tue, 25 Jun 2024 14:05:27 +0100 Subject: [PATCH 084/208] chore: replace `Std` with `Batteries` and recycle a doc-string (#859) --- Batteries/Linter/UnnecessarySeqFocus.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Batteries/Linter/UnnecessarySeqFocus.lean b/Batteries/Linter/UnnecessarySeqFocus.lean index 3ebe54dcb4..566da1d490 100644 --- a/Batteries/Linter/UnnecessarySeqFocus.lean +++ b/Batteries/Linter/UnnecessarySeqFocus.lean @@ -7,7 +7,7 @@ import Lean.Elab.Command import Lean.Linter.Util import Batteries.Lean.AttributeExtra -namespace Std.Linter +namespace Batteries.Linter open Lean Elab Command Linter /-- @@ -147,7 +147,7 @@ partial def markUsedTactics : InfoTree → M ω Unit end -/-- The main entry point to the unused tactic linter. -/ +@[inherit_doc Batteries.Linter.linter.unnecessarySeqFocus] def unnecessarySeqFocusLinter : Linter where run := withSetOptionIn fun stx => do unless getLinterUnnecessarySeqFocus (← getOptions) && (← getInfoState).enabled do return From 555ec79bc6effe7009036184a5f73f7d8d4850ed Mon Sep 17 00:00:00 2001 From: damiano Date: Wed, 26 Jun 2024 00:21:42 +0100 Subject: [PATCH 085/208] chore: `unreachableTactic` -- replace a `Std` namespace with `Batteries` and add an `inherit_doc`. (#861) --- Batteries/Linter/UnreachableTactic.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Batteries/Linter/UnreachableTactic.lean b/Batteries/Linter/UnreachableTactic.lean index c4ea4dd10c..a4bedbe10c 100644 --- a/Batteries/Linter/UnreachableTactic.lean +++ b/Batteries/Linter/UnreachableTactic.lean @@ -7,7 +7,7 @@ import Lean.Elab.Command import Lean.Linter.Util import Batteries.Tactic.Unreachable -namespace Std.Linter +namespace Batteries.Linter open Lean Elab Command Linter /-- @@ -86,7 +86,7 @@ partial def eraseUsedTactics : InfoTree → M Unit end -/-- The main entry point to the unreachable tactic linter. -/ +@[inherit_doc Batteries.Linter.linter.unreachableTactic] def unreachableTacticLinter : Linter where run := withSetOptionIn fun stx => do unless getLinterUnreachableTactic (← getOptions) && (← getInfoState).enabled do return From 1c6b521b28f2c40a2c16b9498c93eb3080a86483 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Wed, 26 Jun 2024 09:05:43 +0000 Subject: [PATCH 086/208] chore: bump to nightly-2024-06-26 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 1452d9a5a3..f2fba0bb4e 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-25 +leanprover/lean4:nightly-2024-06-26 From b24f8d9e82cf133812e74df1adb6d049de74eeb0 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Thu, 27 Jun 2024 09:04:58 +0000 Subject: [PATCH 087/208] chore: bump to nightly-2024-06-27 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index f2fba0bb4e..d10f4100eb 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-26 +leanprover/lean4:nightly-2024-06-27 From ea44569f970c03c57782043ec8bf93fab7785479 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 28 Jun 2024 09:05:12 +0000 Subject: [PATCH 088/208] chore: bump to nightly-2024-06-28 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index d10f4100eb..21570398f9 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-27 +leanprover/lean4:nightly-2024-06-28 From 248f456b6df4fb29c5582747571bd1773f65acbb Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sat, 29 Jun 2024 09:05:26 +0000 Subject: [PATCH 089/208] chore: bump to nightly-2024-06-29 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 21570398f9..18d4545917 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-28 +leanprover/lean4:nightly-2024-06-29 From f956763cd9711389f32ba4a6d1f30f774cd1f4a1 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sun, 30 Jun 2024 09:05:44 +0000 Subject: [PATCH 090/208] chore: bump to nightly-2024-06-30 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 18d4545917..eade7d1f7a 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-29 +leanprover/lean4:nightly-2024-06-30 From 54bb04c3119f24fde14b9068c4b2e69db52a1450 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 1 Jul 2024 10:45:02 +1000 Subject: [PATCH 091/208] chore: bump toolchain to v4.9.0 (#865) --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index e5ea66000f..4ef27c472e 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.9.0-rc3 +leanprover/lean4:v4.9.0 From 4115b227caa6b6433c5ccf28c859a63607e5a29a Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 1 Jul 2024 11:07:57 +1000 Subject: [PATCH 092/208] chore: deal with nonterminal simps in String/Lemmas (#857) * chore: deal with nonterminal simps in String/Lemmas * fix * squeeze more simps * chore: avoid nonterminal simps in String/Lemmas (#864) * chore: bump toolchain to v4.9.0-rc3 (#858) * chore: replace `Std` with `Batteries` and recycle a doc-string (#859) * chore: `unreachableTactic` -- replace a `Std` namespace with `Batteries` and add an `inherit_doc`. (#861) * chore: avoid nonterminal simps in String/Lemmas Co-authored-by: Mario Carneiro Co-authored-by: Bulhwi Cha --------- Co-authored-by: Kim Morrison Co-authored-by: damiano Co-authored-by: Mario Carneiro --------- Co-authored-by: Mario Carneiro Co-authored-by: Bulhwi Cha Co-authored-by: damiano --- Batteries/Data/String/Lemmas.lean | 203 ++++++++++++++++++------------ 1 file changed, 126 insertions(+), 77 deletions(-) diff --git a/Batteries/Data/String/Lemmas.lean b/Batteries/Data/String/Lemmas.lean index 8a9376fe05..ad15234f51 100644 --- a/Batteries/Data/String/Lemmas.lean +++ b/Batteries/Data/String/Lemmas.lean @@ -8,6 +8,7 @@ import Batteries.Data.List.Lemmas import Batteries.Data.String.Basic import Batteries.Tactic.Lint.Misc import Batteries.Tactic.SeqFocus +import Batteries.Tactic.SqueezeScope namespace String @@ -135,10 +136,10 @@ theorem utf8GetAux_add_right_cancel (s : List Char) (i p n : Nat) : utf8GetAux s ⟨i + n⟩ ⟨p + n⟩ = utf8GetAux s ⟨i⟩ ⟨p⟩ := by apply utf8InductionOn s ⟨i⟩ ⟨p⟩ (motive := fun s i => utf8GetAux s ⟨i.byteIdx + n⟩ ⟨p + n⟩ = utf8GetAux s i ⟨p⟩) <;> - simp [utf8GetAux] + simp only [utf8GetAux, Char.reduceDefault, implies_true, ↓reduceIte, ne_eq, pos_add_char] intro c cs ⟨i⟩ h ih - simp [Pos.ext_iff, Pos.addChar_eq] at h ⊢ - simp [Nat.add_right_cancel_iff, h] + simp only [Pos.ext_iff, Pos.addChar_eq] at h ⊢ + simp only [Nat.add_right_cancel_iff, h, ↓reduceIte] rw [Nat.add_right_comm] exact ih @@ -151,8 +152,9 @@ theorem utf8GetAux_of_valid (cs cs' : List Char) {i p : Nat} (hp : i + utf8Len c | [], [] => rfl | [], c::cs' => simp [← hp, utf8GetAux] | c::cs, cs' => - simp [utf8GetAux, -List.headD_eq_head?]; rw [if_neg] - case hnc => simp [← hp, Pos.ext_iff]; exact ne_self_add_add_csize + simp only [utf8GetAux, List.append_eq, Char.reduceDefault, ↓Char.isValue] + rw [if_neg] + case hnc => simp only [← hp, utf8Len_cons, Pos.ext_iff]; exact ne_self_add_add_csize refine utf8GetAux_of_valid cs cs' ?_ simpa [Nat.add_assoc, Nat.add_comm] using hp @@ -169,7 +171,8 @@ theorem utf8GetAux?_of_valid (cs cs' : List Char) {i p : Nat} (hp : i + utf8Len | [], [] => rfl | [], c::cs' => simp [← hp, utf8GetAux?] | c::cs, cs' => - simp [utf8GetAux?]; rw [if_neg] + simp only [utf8GetAux?, List.append_eq] + rw [if_neg] case hnc => simp [← hp, Pos.ext_iff]; exact ne_self_add_add_csize refine utf8GetAux?_of_valid cs cs' ?_ simpa [Nat.add_assoc, Nat.add_comm] using hp @@ -183,7 +186,8 @@ theorem utf8SetAux_of_valid (c' : Char) (cs cs' : List Char) {i p : Nat} (hp : i | [], [] => rfl | [], c::cs' => simp [← hp, utf8SetAux] | c::cs, cs' => - simp [utf8SetAux]; rw [if_neg] + simp only [utf8SetAux, List.append_eq, List.cons_append] + rw [if_neg] case hnc => simp [← hp, Pos.ext_iff]; exact ne_self_add_add_csize refine congrArg (c::·) (utf8SetAux_of_valid c' cs cs' ?_) simpa [Nat.add_assoc, Nat.add_comm] using hp @@ -219,15 +223,19 @@ theorem utf8PrevAux_of_valid {cs cs' : List Char} {c : Char} {i p : Nat} match cs with | [] => simp [utf8PrevAux, ← hp, Pos.addChar_eq] | c'::cs => - simp [utf8PrevAux, Pos.addChar_eq, ← hp]; rw [if_neg] + simp only [utf8PrevAux, Pos.addChar_eq, ← hp, utf8Len_cons, List.append_eq] + rw [if_neg] case hnc => - simp [Pos.ext_iff]; rw [Nat.add_right_comm, Nat.add_left_comm]; apply ne_add_csize_add_self + simp only [Pos.ext_iff] + rw [Nat.add_right_comm, Nat.add_left_comm] + apply ne_add_csize_add_self refine (utf8PrevAux_of_valid (by simp [Nat.add_assoc, Nat.add_left_comm])).trans ?_ simp [Nat.add_assoc, Nat.add_comm] theorem prev_of_valid (cs : List Char) (c : Char) (cs' : List Char) : prev ⟨cs ++ c :: cs'⟩ ⟨utf8Len cs + csize c⟩ = ⟨utf8Len cs⟩ := by - simp [prev]; refine (if_neg (Pos.ne_of_gt add_csize_pos)).trans ?_ + simp only [prev] + refine (if_neg (Pos.ne_of_gt add_csize_pos)).trans ?_ rw [utf8PrevAux_of_valid] <;> simp theorem prev_of_valid' (cs cs' : List Char) : @@ -270,11 +278,16 @@ theorem findAux_of_valid (p) : ∀ l m r, unfold findAux List.takeWhile rw [dif_pos (by exact Nat.lt_add_of_pos_right add_csize_pos)] have h1 := get_of_valid l (c::m++r); have h2 := next_of_valid l c (m++r) - simp at h1 h2; simp [h1, h2] - cases p c <;> simp - have foo := findAux_of_valid p (l++[c]) m r; simp at foo - rw [Nat.add_right_comm, Nat.add_assoc] at foo - rw [foo, Nat.add_right_comm, Nat.add_assoc] + simp only [List.cons_append, Char.reduceDefault, List.headD_cons] at h1 h2 + simp only [List.append_assoc, List.cons_append, h1, utf8Len_cons, h2] + cases p c + · simp only [Bool.false_eq_true, ↓reduceIte, Bool.not_false, utf8Len_cons] + have foo := findAux_of_valid p (l++[c]) m r + simp only [List.append_assoc, List.singleton_append, List.cons_append, utf8Len_append, + utf8Len_cons, utf8Len_nil, Nat.zero_add, List.nil_append] at foo + rw [Nat.add_right_comm, Nat.add_assoc] at foo + rw [foo, Nat.add_right_comm, Nat.add_assoc] + · simp theorem find_of_valid (p s) : find s p = ⟨utf8Len (s.1.takeWhile (!p ·))⟩ := by simpa using findAux_of_valid p [] s.1 [] @@ -287,8 +300,10 @@ theorem revFindAux_of_valid (p) : ∀ l r, unfold revFindAux List.dropWhile rw [dif_neg (by exact Pos.ne_of_gt add_csize_pos)] have h1 := get_of_valid l.reverse (c::r); have h2 := prev_of_valid l.reverse c r - simp at h1 h2; simp [h1, h2] - cases p c <;> simp + simp only [utf8Len_reverse, Char.reduceDefault, List.headD_cons] at h1 h2 + simp only [List.reverse_cons, List.append_assoc, List.singleton_append, utf8Len_cons, h2, h1] + cases p c <;> simp only [Bool.false_eq_true, ↓reduceIte, Bool.not_false, Bool.not_true, + List.tail?_cons, Option.map_some'] exact revFindAux_of_valid p l (c::r) theorem revFind_of_valid (p s) : @@ -308,12 +323,15 @@ theorem firstDiffPos_loop_eq (l₁ l₂ r₁ r₂ stop p) refine Nat.lt_min.2 ⟨?_, ?_⟩ <;> exact Nat.lt_add_of_pos_right add_csize_pos, show get ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = a by simp [hl₁, get_of_valid], show get ⟨l₂ ++ b :: r₂⟩ ⟨p⟩ = b by simp [hl₂, get_of_valid]] - simp; split <;> simp - subst b - rw [show next ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = ⟨utf8Len l₁ + csize a⟩ by simp [hl₁, next_of_valid]] - simpa [← hl₁, ← Nat.add_assoc, Nat.add_right_comm] using - firstDiffPos_loop_eq (l₁ ++ [a]) (l₂ ++ [a]) r₁ r₂ stop (p + csize a) - (by simp [hl₁]) (by simp [hl₂]) (by simp [hstop, ← Nat.add_assoc, Nat.add_right_comm]) + simp only [bne_iff_ne, ne_eq, ite_not, decide_eq_true_eq] + split + · simp only [utf8Len_cons] + subst b + rw [show next ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = ⟨utf8Len l₁ + csize a⟩ by simp [hl₁, next_of_valid]] + simpa [← hl₁, ← Nat.add_assoc, Nat.add_right_comm] using + firstDiffPos_loop_eq (l₁ ++ [a]) (l₂ ++ [a]) r₁ r₂ stop (p + csize a) + (by simp [hl₁]) (by simp [hl₂]) (by simp [hstop, ← Nat.add_assoc, Nat.add_right_comm]) + · simp · next h => rw [dif_neg] <;> simp [hstop, ← hl₁, ← hl₂, -Nat.not_lt, Nat.lt_min] intro h₁ h₂ @@ -330,10 +348,11 @@ theorem firstDiffPos_eq (a b : String) : theorem extract.go₂_add_right_cancel (s : List Char) (i e n : Nat) : go₂ s ⟨i + n⟩ ⟨e + n⟩ = go₂ s ⟨i⟩ ⟨e⟩ := by apply utf8InductionOn s ⟨i⟩ ⟨e⟩ (motive := fun s i => - go₂ s ⟨i.byteIdx + n⟩ ⟨e + n⟩ = go₂ s i ⟨e⟩) <;> simp [go₂] + go₂ s ⟨i.byteIdx + n⟩ ⟨e + n⟩ = go₂ s i ⟨e⟩) + <;> simp only [ne_eq, go₂, pos_add_char, implies_true, ↓reduceIte] intro c cs ⟨i⟩ h ih - simp [Pos.ext_iff, Pos.addChar_eq] at h ⊢ - simp [Nat.add_right_cancel_iff, h] + simp only [Pos.ext_iff, Pos.addChar_eq] at h ⊢ + simp only [Nat.add_right_cancel_iff, h, ↓reduceIte, List.cons.injEq, true_and] rw [Nat.add_right_comm] exact ih @@ -341,32 +360,35 @@ theorem extract.go₂_append_left : ∀ (s t : List Char) (i e : Nat), e = utf8Len s + i → go₂ (s ++ t) ⟨i⟩ ⟨e⟩ = s | [], t, i, _, rfl => by cases t <;> simp [go₂] | c :: cs, t, i, _, rfl => by - simp [go₂, Pos.ext_iff, ne_add_csize_add_self, Pos.addChar_eq] + simp only [go₂, utf8Len_cons, Pos.ext_iff, ne_add_csize_add_self, ↓reduceIte, List.append_eq, + Pos.addChar_eq, List.cons.injEq, true_and] apply go₂_append_left; rw [Nat.add_right_comm, Nat.add_assoc] theorem extract.go₁_add_right_cancel (s : List Char) (i b e n : Nat) : go₁ s ⟨i + n⟩ ⟨b + n⟩ ⟨e + n⟩ = go₁ s ⟨i⟩ ⟨b⟩ ⟨e⟩ := by apply utf8InductionOn s ⟨i⟩ ⟨b⟩ (motive := fun s i => - go₁ s ⟨i.byteIdx + n⟩ ⟨b + n⟩ ⟨e + n⟩ = go₁ s i ⟨b⟩ ⟨e⟩) <;> - simp [go₁] + go₁ s ⟨i.byteIdx + n⟩ ⟨b + n⟩ ⟨e + n⟩ = go₁ s i ⟨b⟩ ⟨e⟩) + <;> simp only [ne_eq, go₁, pos_add_char, implies_true, ↓reduceIte] · intro c cs apply go₂_add_right_cancel · intro c cs ⟨i⟩ h ih - simp [Pos.ext_iff, Pos.addChar_eq] at h ih ⊢ - simp [Nat.add_right_cancel_iff, h] + simp only [Pos.ext_iff, Pos.addChar_eq] at h ih ⊢ + simp only [Nat.add_right_cancel_iff, h, ↓reduceIte] rw [Nat.add_right_comm] exact ih theorem extract.go₁_cons_addChar (c : Char) (cs : List Char) (b e : Pos) : go₁ (c :: cs) 0 (b + c) (e + c) = go₁ cs 0 b e := by - simp [go₁, Pos.ext_iff, Nat.ne_of_lt add_csize_pos] + simp only [go₁, Pos.ext_iff, Pos.byteIdx_zero, pos_add_char, Nat.ne_of_lt add_csize_pos, + ↓reduceIte] apply go₁_add_right_cancel theorem extract.go₁_append_right : ∀ (s t : List Char) (i b : Nat) (e : Pos), b = utf8Len s + i → go₁ (s ++ t) ⟨i⟩ ⟨b⟩ e = go₂ t ⟨b⟩ e | [], t, i, _, e, rfl => by cases t <;> simp [go₁, go₂] | c :: cs, t, i, _, e, rfl => by - simp [go₁, Pos.ext_iff, ne_add_csize_add_self, Pos.addChar_eq] + simp only [go₁, utf8Len_cons, Pos.ext_iff, ne_add_csize_add_self, ↓reduceIte, List.append_eq, + Pos.addChar_eq] apply go₁_append_right; rw [Nat.add_right_comm, Nat.add_assoc] theorem extract.go₁_zero_utf8Len (s : List Char) : go₁ s 0 0 ⟨utf8Len s⟩ = s := @@ -375,13 +397,15 @@ theorem extract.go₁_zero_utf8Len (s : List Char) : go₁ s 0 0 ⟨utf8Len s⟩ theorem extract_cons_addChar (c : Char) (cs : List Char) (b e : Pos) : extract ⟨c :: cs⟩ (b + c) (e + c) = extract ⟨cs⟩ b e := by - simp [extract, Nat.add_le_add_iff_right] + simp only [extract, pos_add_char, ge_iff_le, Nat.add_le_add_iff_right] split <;> [rfl; rw [extract.go₁_cons_addChar]] theorem extract_zero_endPos : ∀ (s : String), s.extract 0 (endPos s) = s | ⟨[]⟩ => rfl | ⟨c :: cs⟩ => by - simp [extract, Nat.ne_of_gt add_csize_pos]; congr + simp only [extract, Pos.byteIdx_zero, endPos_eq, utf8Len_cons, ge_iff_le, Nat.le_zero_eq, + Nat.ne_of_gt add_csize_pos, ↓reduceIte] + congr apply extract.go₁_zero_utf8Len theorem extract_of_valid (l m r : List Char) : @@ -396,11 +420,17 @@ theorem splitAux_of_valid (p l m r acc) : splitAux ⟨l ++ m ++ r⟩ p ⟨utf8Len l⟩ ⟨utf8Len l + utf8Len m⟩ acc = acc.reverse ++ (List.splitOnP.go p r m.reverse).map mk := by unfold splitAux - simp [by simpa using atEnd_of_valid (l ++ m) r]; split + simp only [List.append_assoc, atEnd_iff, endPos_eq, utf8Len_append, Pos.mk_le_mk, by + simpa using atEnd_of_valid (l ++ m) r, List.reverse_cons, dite_eq_ite] + split · subst r; simpa [List.splitOnP.go] using extract_of_valid l m [] · obtain ⟨c, r, rfl⟩ := r.exists_cons_of_ne_nil ‹_› - simp [by simpa using (⟨get_of_valid (l++m) (c::r), next_of_valid (l++m) c r, - extract_of_valid l m (c::r)⟩ : _∧_∧_), List.splitOnP.go] + simp only [by + simpa using + (⟨get_of_valid (l ++ m) (c :: r), next_of_valid (l ++ m) c r, + extract_of_valid l m (c :: r)⟩ : + _ ∧ _ ∧ _), + List.splitOnP.go, List.reverse_reverse] split · simpa [Nat.add_assoc] using splitAux_of_valid p (l++m++[c]) [] r (⟨m⟩::acc) · simpa [Nat.add_assoc] using splitAux_of_valid p l (m++[c]) r acc @@ -478,7 +508,7 @@ theorem pos_eq_zero {l r it} (h : ValidFor l r it) : it.2 = 0 ↔ l = [] := by simp [h.pos, Pos.ext_iff] theorem pos_eq_endPos {l r it} (h : ValidFor l r it) : it.2 = it.1.endPos ↔ r = [] := by - simp [h.pos, h.toString, Pos.ext_iff] + simp only [h.pos, h.toString, endPos_eq, utf8Len_reverseAux, Pos.ext_iff] exact (Nat.add_left_cancel_iff (m := 0)).trans <| eq_comm.trans utf8Len_eq_zero theorem curr : ∀ {it}, ValidFor l r it → it.curr = r.headD default @@ -494,15 +524,21 @@ theorem prev : ∀ {it}, ValidFor (c :: l) r it → ValidFor l (c :: r) it.prev | it, h => by cases h.out' have := prev_of_valid l.reverse c r - simp at this; simp [Iterator.prev, this] + simp only [utf8Len_reverse] at this + simp only [Iterator.prev, List.reverse_cons, List.append_assoc, List.singleton_append, + utf8Len_append, utf8Len_reverse, utf8Len_cons, utf8Len_nil, Nat.zero_add, this] exact .of_eq _ (by simp [List.reverseAux_eq]) (by simp) theorem prev_nil : ∀ {it}, ValidFor [] r it → ValidFor [] r it.prev - | it, h => by simp [Iterator.prev, h.toString, h.pos]; constructor + | it, h => by + simp only [Iterator.prev, h.toString, List.reverseAux_nil, h.pos, utf8Len_nil, + Pos.mk_zero, prev_zero] + constructor theorem atEnd : ∀ {it}, ValidFor l r it → (it.atEnd ↔ r = []) | it, h => by - simp [Iterator.atEnd, h.pos, h.toString] + simp only [Iterator.atEnd, h.pos, h.toString, endPos_eq, utf8Len_reverseAux, ge_iff_le, + decide_eq_true_eq] exact Nat.add_le_add_iff_left.trans <| Nat.le_zero.trans utf8Len_eq_zero theorem hasNext : ∀ {it}, ValidFor l r it → (it.hasNext ↔ r ≠ []) @@ -515,26 +551,29 @@ theorem setCurr' : ∀ {it}, ValidFor l r it → ValidFor l (r.modifyHead fun _ => c) (it.setCurr c) | it, h => by cases h.out' - simp [Iterator.setCurr] + simp only [setCurr, utf8Len_reverse] refine .of_eq _ ?_ (by simp) have := set_of_valid l.reverse r c - simp at this; simp [List.reverseAux_eq, this] + simp only [utf8Len_reverse] at this; simp [List.reverseAux_eq, this] theorem setCurr (h : ValidFor l (c :: r) it) : ValidFor l (c :: r) (it.setCurr c) := h.setCurr' theorem toEnd (h : ValidFor l r it) : ValidFor (r.reverse ++ l) [] it.toEnd := by - simp [Iterator.toEnd, h.toString] + simp only [Iterator.toEnd, h.toString, endPos_eq, utf8Len_reverseAux] exact .of_eq _ (by simp [List.reverseAux_eq]) (by simp [Nat.add_comm]) theorem toEnd' (it : Iterator) : ValidFor it.s.1.reverse [] it.toEnd := by - simp [Iterator.toEnd] + simp only [Iterator.toEnd] exact .of_eq _ (by simp [List.reverseAux_eq]) (by simp [endPos, utf8ByteSize]) theorem extract (h₁ : ValidFor l (m ++ r) it₁) (h₂ : ValidFor (m.reverse ++ l) r it₂) : it₁.extract it₂ = ⟨m⟩ := by cases h₁.out; cases h₂.out - simp [Iterator.extract, List.reverseAux_eq, Nat.not_lt.2 (Nat.le_add_left ..)] + simp only [Iterator.extract, List.reverseAux_eq, List.reverse_append, List.reverse_reverse, + List.append_assoc, ne_eq, not_true_eq_false, decide_False, utf8Len_append, utf8Len_reverse, + gt_iff_lt, pos_lt_eq, Nat.not_lt.2 (Nat.le_add_left ..), Bool.or_self, Bool.false_eq_true, + ↓reduceIte] simpa [Nat.add_comm] using extract_of_valid l.reverse m r theorem remainingToString {it} (h : ValidFor l r it) : it.remainingToString = ⟨r⟩ := by @@ -545,7 +584,7 @@ theorem nextn : ∀ {it}, ValidFor l r it → ∀ n, n ≤ r.length → ValidFor ((r.take n).reverse ++ l) (r.drop n) (it.nextn n) | it, h, 0, _ => by simp [h, Iterator.nextn] | it, h, n+1, hn => by - simp [h, Iterator.nextn] + simp only [Iterator.nextn] have a::r := r simpa using h.next.nextn _ (Nat.le_of_succ_le_succ hn) @@ -553,7 +592,7 @@ theorem prevn : ∀ {it}, ValidFor l r it → ∀ n, n ≤ l.length → ValidFor (l.drop n) ((l.take n).reverse ++ r) (it.prevn n) | it, h, 0, _ => by simp [h, Iterator.prevn] | it, h, n+1, hn => by - simp [h, Iterator.prevn] + simp only [Iterator.prevn] have a::l := l simpa using h.prev.prevn _ (Nat.le_of_succ_le_succ hn) @@ -608,7 +647,8 @@ theorem offsetOfPosAux_of_valid : ∀ l m r n, unfold offsetOfPosAux rw [if_neg (by exact Nat.not_le.2 (Nat.lt_add_of_pos_right add_csize_pos))] simp only [List.append_assoc, atEnd_of_valid l (c::m++r)] - simp [next_of_valid l c (m++r)] + simp only [List.cons_append, ↓reduceDite, utf8Len_cons, next_of_valid l c (m ++ r), + List.length_cons, Nat.succ_eq_add_one] simpa [← Nat.add_assoc, Nat.add_right_comm, Nat.succ_eq_add_one] using offsetOfPosAux_of_valid (l++[c]) m r (n + 1) @@ -622,7 +662,8 @@ theorem foldlAux_of_valid (f : α → Char → α) : ∀ l m r a, | l, c::m, r, a => by unfold foldlAux rw [dif_pos (by exact Nat.lt_add_of_pos_right add_csize_pos)] - simp [get_of_valid l (c::(m++r)), next_of_valid l c (m++r)] + simp only [List.append_assoc, List.cons_append, utf8Len_cons, next_of_valid l c (m ++ r), + get_of_valid l (c :: (m ++ r)), Char.reduceDefault, List.headD_cons, List.foldl_cons] simpa [← Nat.add_assoc, Nat.add_right_comm] using foldlAux_of_valid f (l++[c]) m r (f a c) theorem foldl_eq (f : α → Char → α) (s a) : foldl f a s = s.1.foldl f a := by @@ -635,8 +676,8 @@ theorem foldrAux_of_valid (f : Char → α → α) (l m r a) : induction m.reverse generalizing r a with (unfold foldrAux; simp) | cons c m IH => rw [if_pos (by exact Nat.lt_add_of_pos_right add_csize_pos)] - simp [← Nat.add_assoc, by simpa using prev_of_valid (l++m.reverse) c r] - simp [by simpa using get_of_valid (l++m.reverse) (c::r)] + simp only [← Nat.add_assoc, by simpa using prev_of_valid (l ++ m.reverse) c r] + simp only [by simpa using get_of_valid (l ++ m.reverse) (c :: r)] simpa using IH (c::r) (f c a) theorem foldr_eq (f : Char → α → α) (s a) : foldr f a s = s.1.foldr f a := by @@ -649,7 +690,9 @@ theorem anyAux_of_valid (p : Char → Bool) : ∀ l m r, | l, c::m, r => by unfold anyAux rw [dif_pos (by exact Nat.lt_add_of_pos_right add_csize_pos)] - simp [get_of_valid l (c::(m++r)), next_of_valid l c (m++r)] + simp only [List.append_assoc, List.cons_append, get_of_valid l (c :: (m ++ r)), + Char.reduceDefault, List.headD_cons, utf8Len_cons, next_of_valid l c (m ++ r), + Bool.if_true_left, Bool.decide_eq_true, List.any_cons] cases p c <;> simp simpa [← Nat.add_assoc, Nat.add_right_comm] using anyAux_of_valid p (l++[c]) m r @@ -672,7 +715,8 @@ theorem mapAux_of_valid (f : Char → Char) : ∀ l r, mapAux f ⟨utf8Len l⟩ | l, c::r => by unfold mapAux rw [dif_neg (by rw [atEnd_of_valid]; simp)] - simp [set_of_valid l (c::r), get_of_valid l (c::r), next_of_valid l (f c) r] + simp only [get_of_valid l (c :: r), Char.reduceDefault, List.headD_cons, + set_of_valid l (c :: r), List.modifyHead_cons, next_of_valid l (f c) r, List.map_cons] simpa using mapAux_of_valid f (l++[f c]) r theorem map_eq (f : Char → Char) (s) : map f s = ⟨s.1.map f⟩ := by @@ -690,7 +734,8 @@ theorem takeWhileAux_of_valid (p : Char → Bool) : ∀ l m r, | l, c::m, r => by unfold Substring.takeWhileAux List.takeWhile rw [dif_pos (by exact Nat.lt_add_of_pos_right add_csize_pos)] - simp [get_of_valid l (c::(m++r)), next_of_valid l c (m++r)] + simp only [List.append_assoc, List.cons_append, get_of_valid l (c :: (m ++ r)), + Char.reduceDefault, List.headD_cons, utf8Len_cons, next_of_valid l c (m ++ r)] cases p c <;> simp simpa [← Nat.add_assoc, Nat.add_right_comm] using takeWhileAux_of_valid p (l++[c]) m r @@ -752,7 +797,7 @@ theorem toString : ∀ {s}, ValidFor l m r s → s.toString = ⟨m⟩ theorem toIterator : ∀ {s}, ValidFor l m r s → s.toIterator.ValidFor l.reverse (m ++ r) | _, h => by - simp [Substring.toIterator] + simp only [Substring.toIterator] exact .of_eq _ (by simp [h.str, List.reverseAux_eq]) (by simp [h.startPos]) theorem get : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → s.get ⟨utf8Len m₁⟩ = c @@ -760,13 +805,13 @@ theorem get : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → s.get ⟨utf8Len m theorem next : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → s.next ⟨utf8Len m₁⟩ = ⟨utf8Len m₁ + csize c⟩ | _, ⟨⟩ => by - simp [Substring.next] + simp only [Substring.next, utf8Len_append, utf8Len_cons, List.append_assoc, List.cons_append] rw [if_neg (mt Pos.ext_iff.1 ?a)] case a => simpa [Nat.add_assoc, Nat.add_comm, Nat.add_left_comm] using @ne_add_csize_add_self (utf8Len l + utf8Len m₁) (utf8Len m₂) c have := next_of_valid (l ++ m₁) c (m₂ ++ r) - simp [Pos.add_eq] at this ⊢; rw [this] + simp only [List.append_assoc, utf8Len_append, Pos.add_eq] at this ⊢; rw [this] simp [Nat.add_assoc, Nat.add_sub_cancel_left] theorem next_stop : ∀ {s}, ValidFor l m r s → s.next ⟨utf8Len m⟩ = ⟨utf8Len m⟩ @@ -774,11 +819,11 @@ theorem next_stop : ∀ {s}, ValidFor l m r s → s.next ⟨utf8Len m⟩ = ⟨ut theorem prev : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → s.prev ⟨utf8Len m₁ + csize c⟩ = ⟨utf8Len m₁⟩ | _, ⟨⟩ => by - simp [Substring.prev] + simp only [Substring.prev, List.append_assoc, List.cons_append] rw [if_neg (mt Pos.ext_iff.1 <| Ne.symm ?a)] case a => simpa [Nat.add_comm] using @ne_add_csize_add_self (utf8Len l) (utf8Len m₁) c have := prev_of_valid (l ++ m₁) c (m₂ ++ r) - simp [Pos.add_eq, Nat.add_assoc] at this ⊢; rw [this] + simp only [List.append_assoc, utf8Len_append, Nat.add_assoc, Pos.add_eq] at this ⊢; rw [this] simp [Nat.add_sub_cancel_left] theorem nextn_stop : ∀ {s}, ValidFor l m r s → ∀ n, s.nextn n ⟨utf8Len m⟩ = ⟨utf8Len m⟩ @@ -789,7 +834,7 @@ theorem nextn : ∀ {s}, ValidFor l (m₁ ++ m₂) r s → ∀ n, s.nextn n ⟨utf8Len m₁⟩ = ⟨utf8Len m₁ + utf8Len (m₂.take n)⟩ | _, _, 0 => by simp [Substring.nextn] | s, h, n+1 => by - simp [Substring.nextn] + simp only [Substring.nextn] match m₂ with | [] => simp at h; simp [h.next_stop, h.nextn_stop] | c::m₂ => @@ -801,7 +846,7 @@ theorem prevn : ∀ {s}, ValidFor l (m₁.reverse ++ m₂) r s → ∀ n, s.prevn n ⟨utf8Len m₁⟩ = ⟨utf8Len (m₁.drop n)⟩ | _, _, 0 => by simp [Substring.prevn] | s, h, n+1 => by - simp [Substring.prevn] + simp only [Substring.prevn] match m₁ with | [] => simp | c::m₁ => @@ -814,8 +859,9 @@ theorem front : ∀ {s}, ValidFor l (c :: m) r s → s.front = c theorem drop : ∀ {s}, ValidFor l m r s → ∀ n, ValidFor (l ++ m.take n) (m.drop n) r (s.drop n) | s, h, n => by have : Substring.nextn {..} .. = _ := h.nextn (m₁ := []) n - simp at this; simp [Substring.drop, this] - simp [h.str, h.startPos, h.stopPos] + simp only [utf8Len_nil, Pos.mk_zero, Nat.zero_add] at this + simp only [Substring.drop, this] + simp only [h.str, List.append_assoc, h.startPos, h.stopPos] rw [← List.take_append_drop n m] at h refine .of_eq _ (by simp) (by simp) ?_ conv => lhs; rw [← List.take_append_drop n m] @@ -824,8 +870,9 @@ theorem drop : ∀ {s}, ValidFor l m r s → ∀ n, ValidFor (l ++ m.take n) (m. theorem take : ∀ {s}, ValidFor l m r s → ∀ n, ValidFor l (m.take n) (m.drop n ++ r) (s.take n) | s, h, n => by have : Substring.nextn {..} .. = _ := h.nextn (m₁ := []) n - simp at this; simp [Substring.take, this] - simp [h.str, h.startPos, h.stopPos] + simp at this + simp only [Substring.take, this] + simp only [h.str, List.append_assoc, h.startPos] rw [← List.take_append_drop n m] at h refine .of_eq _ ?_ (by simp) (by simp) conv => lhs; rw [← List.take_append_drop n m] @@ -839,14 +886,16 @@ theorem atEnd : ∀ {s}, ValidFor l m r s → (s.atEnd ⟨p⟩ ↔ p = utf8Len m theorem extract : ∀ {s}, ValidFor l m r s → ValidFor ml mm mr ⟨⟨m⟩, b, e⟩ → ∃ l' r', ValidFor l' mm r' (s.extract b e) | _, ⟨⟩, ⟨⟩ => by - simp [Substring.extract]; split + simp only [Substring.extract, ge_iff_le, Pos.mk_le_mk, List.append_assoc, utf8Len_append] + split · next h => rw [utf8Len_eq_zero.1 <| Nat.le_zero.1 <| Nat.add_le_add_iff_left.1 h] exact ⟨[], [], ⟨⟩⟩ · next h => refine ⟨l ++ ml, mr ++ r, .of_eq _ (by simp) ?_ ?_⟩ <;> - simp [Nat.min_eq_min] <;> rw [Nat.min_eq_right] <;> - try simp [Nat.add_le_add_iff_left, Nat.le_add_right] + simp only [Pos.add_byteIdx, Nat.min_eq_min, utf8Len_append] + <;> rw [Nat.min_eq_right] + <;> try simp [Nat.add_le_add_iff_left, Nat.le_add_right] rw [Nat.add_assoc] -- TODO: splitOn @@ -888,11 +937,11 @@ namespace Valid theorem validFor : ∀ {s}, Valid s → ∃ l m r, ValidFor l m r s | ⟨⟨_⟩, ⟨_⟩, ⟨_⟩⟩, ⟨⟨l, mr, rfl, rfl⟩, ⟨lm, r, e, rfl⟩, h⟩ => by - simp at * + simp only [utf8ByteSize.go_eq, Pos.mk_le_mk] at * have := (or_iff_right_iff_imp.2 fun h => ?x).1 (List.append_eq_append_iff.1 e) case x => match l, r, h with | _, _, ⟨m, rfl, rfl⟩ => ?_ - simp at h + simp only [utf8Len_append] at h cases utf8Len_eq_zero.1 <| Nat.le_zero.1 (Nat.le_of_add_le_add_left (c := 0) h) exact ⟨[], by simp⟩ match lm, mr, this with @@ -913,13 +962,13 @@ theorem isEmpty : ∀ {s}, Valid s → (s.isEmpty ↔ s.toString = "") theorem get : ∀ {s}, Valid s → s.toString.1 = m₁ ++ c :: m₂ → s.get ⟨utf8Len m₁⟩ = c | _, h, e => by let ⟨l, m, r, h⟩ := h.validFor - simp [h.toString] at e; subst e; simp [h.get] + simp only [h.toString] at e; subst e; simp [h.get] theorem next : ∀ {s}, Valid s → s.toString.1 = m₁ ++ c :: m₂ → s.next ⟨utf8Len m₁⟩ = ⟨utf8Len m₁ + csize c⟩ | _, h, e => by let ⟨l, m, r, h⟩ := h.validFor - simp [h.toString] at e; subst e; simp [h.next] + simp only [h.toString] at e; subst e; simp [h.next] theorem next_stop : ∀ {s}, Valid s → s.next ⟨s.bsize⟩ = ⟨s.bsize⟩ | _, h => let ⟨l, m, r, h⟩ := h.validFor; by simp [h.bsize, h.next_stop] @@ -928,7 +977,7 @@ theorem prev : ∀ {s}, Valid s → s.toString.1 = m₁ ++ c :: m₂ → s.prev ⟨utf8Len m₁ + csize c⟩ = ⟨utf8Len m₁⟩ | _, h, e => by let ⟨l, m, r, h⟩ := h.validFor - simp [h.toString] at e; subst e; simp [h.prev] + simp only [h.toString] at e; subst e; simp [h.prev] theorem nextn_stop : ∀ {s}, Valid s → ∀ n, s.nextn n ⟨s.bsize⟩ = ⟨s.bsize⟩ | _, h, n => let ⟨l, m, r, h⟩ := h.validFor; by simp [h.bsize, h.nextn_stop] @@ -937,13 +986,13 @@ theorem nextn : ∀ {s}, Valid s → s.toString.1 = m₁ ++ m₂ → ∀ n, s.nextn n ⟨utf8Len m₁⟩ = ⟨utf8Len m₁ + utf8Len (m₂.take n)⟩ | _, h, e => by let ⟨l, m, r, h⟩ := h.validFor - simp [h.toString] at e; subst e; simp [h.nextn] + simp only [h.toString] at e; subst e; simp [h.nextn] theorem prevn : ∀ {s}, Valid s → s.toString.1 = m₁.reverse ++ m₂ → ∀ n, s.prevn n ⟨utf8Len m₁⟩ = ⟨utf8Len (m₁.drop n)⟩ | _, h, e => by let ⟨l, m, r, h⟩ := h.validFor - simp [h.toString] at e; subst e; simp [h.prevn] + simp only [h.toString] at e; subst e; simp [h.prevn] theorem front : ∀ {s}, Valid s → s.toString.1 = c :: m → s.front = c | _, h => h.get (m₁ := []) From 2ead90d24b4fac3a05c9c4294daa39bd8686fb98 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 1 Jul 2024 11:11:41 +1000 Subject: [PATCH 093/208] chore: bump toolchain to v4.10.0-rc1, merging bump/v4.10.0 (#867) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: adaptations for nightly-2024-06-11 (#837) * chore: adaptation for nightly-2024-06-14 (#845) * fix(linter): "(invalid MessageData.lazy, missing context)" (#838) * chore(Tactic/Lint/Simp): make simpNF linter dsimp-aware (#839) * add test demonstrating undesired behaviour on dsimp lemmas * chore(Tactic/Lint/Simp): make simpNF linter dsimp-aware * test demonstrates correct behaviour on dsimp lemmas * process review comments * make formatLemmas dsimp-aware * Revert "chore(Tactic/Lint/Simp): make simpNF linter dsimp-aware (#839)" (#841) This reverts commit 007a82fab9671c960ad260d4e4bf664b9fb884e3. * feat: ext lemma for `Thunk` (#842) * chore: adaptations for nightly-2024-06-14 --------- Co-authored-by: L Co-authored-by: Johan Commelin Co-authored-by: François G. Dorais * chore: adaptations for nightly-2024-06-16 (#848) * chore: adaptations for nightly-2024-06-19 (#855) * chore: adaptations for nightly-2024-06-22 (#856) * chore: bump toolchain to v4.10.0-rc1 * chore: adaptations for nightly-2024-06-30 (#866) * chore: bump toolchain to v4.10.0-rc1 * chore: adaptations for nightly-2024-06-30 * fix --------- Co-authored-by: L Co-authored-by: Johan Commelin Co-authored-by: François G. Dorais --- Batteries.lean | 1 - Batteries/CodeAction/Misc.lean | 1 - Batteries/Data/Array/Lemmas.lean | 9 +- Batteries/Data/Char.lean | 14 +- Batteries/Data/Fin/Lemmas.lean | 11 +- Batteries/Data/HashMap/WF.lean | 36 ++--- Batteries/Data/List/Basic.lean | 7 +- Batteries/Data/List/EraseIdx.lean | 28 ++-- Batteries/Data/List/Lemmas.lean | 197 +++++++++++++++----------- Batteries/Data/List/Pairwise.lean | 22 ++- Batteries/Data/List/Perm.lean | 6 +- Batteries/Data/String/Lemmas.lean | 39 ++--- Batteries/Data/UInt.lean | 10 +- Batteries/Lean/AttributeExtra.lean | 2 +- Batteries/Lean/Name.lean | 28 ---- Batteries/Lean/PersistentHashMap.lean | 9 -- Batteries/Lean/PersistentHashSet.lean | 10 -- Batteries/Tactic/Alias.lean | 1 + Batteries/Tactic/Lint/Simp.lean | 4 +- Batteries/Tactic/NoMatch.lean | 1 + Batteries/Tactic/PrintPrefix.lean | 1 - Batteries/Tactic/SqueezeScope.lean | 3 +- lean-toolchain | 2 +- test/absurd.lean | 2 +- test/congr.lean | 2 +- 25 files changed, 229 insertions(+), 217 deletions(-) delete mode 100644 Batteries/Lean/Name.lean diff --git a/Batteries.lean b/Batteries.lean index 706e967883..2fac3bf121 100644 --- a/Batteries.lean +++ b/Batteries.lean @@ -59,7 +59,6 @@ import Batteries.Lean.Meta.SavedState import Batteries.Lean.Meta.Simp import Batteries.Lean.Meta.UnusedNames import Batteries.Lean.MonadBacktrack -import Batteries.Lean.Name import Batteries.Lean.NameMap import Batteries.Lean.NameMapAttribute import Batteries.Lean.PersistentHashMap diff --git a/Batteries/CodeAction/Misc.lean b/Batteries/CodeAction/Misc.lean index 1b5be55ce6..0bea77ff55 100644 --- a/Batteries/CodeAction/Misc.lean +++ b/Batteries/CodeAction/Misc.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro -/ import Lean.Elab.BuiltinTerm import Lean.Elab.BuiltinNotation -import Batteries.Lean.Name import Batteries.Lean.Position import Batteries.CodeAction.Attr import Lean.Meta.Tactic.TryThis diff --git a/Batteries/Data/Array/Lemmas.lean b/Batteries/Data/Array/Lemmas.lean index 5a16a355e1..cf069eb703 100644 --- a/Batteries/Data/Array/Lemmas.lean +++ b/Batteries/Data/Array/Lemmas.lean @@ -22,7 +22,7 @@ theorem forIn_eq_data_forIn [Monad m] have j_eq : j = size as - 1 - i := by simp [← ij, ← Nat.add_assoc] have : as.size - 1 - i < as.size := j_eq ▸ ij ▸ Nat.lt_succ_of_le (Nat.le_add_right ..) have : as[size as - 1 - i] :: as.data.drop (j + 1) = as.data.drop j := by - rw [j_eq]; exact List.get_cons_drop _ ⟨_, this⟩ + rw [j_eq]; exact List.getElem_cons_drop _ _ this simp only [← this, List.forIn_cons]; congr; funext x; congr; funext b rw [loop (i := i)]; rw [← ij, Nat.succ_add]; rfl conv => lhs; simp only [forIn, Array.forIn] @@ -64,12 +64,11 @@ theorem zipWith_eq_zipWith_data (f : α → β → γ) (as : Array α) (bs : Arr let i_bs : Fin bs.data.length := ⟨i, hbs⟩ rw [h₁, List.append_assoc] congr - rw [← List.zipWith_append (h := by simp), getElem_eq_data_get, getElem_eq_data_get] - show List.zipWith f ((List.get as.data i_as) :: List.drop (i_as + 1) as.data) + rw [← List.zipWith_append (h := by simp), getElem_eq_data_getElem, getElem_eq_data_getElem] + show List.zipWith f (as.data[i_as] :: List.drop (i_as + 1) as.data) ((List.get bs.data i_bs) :: List.drop (i_bs + 1) bs.data) = List.zipWith f (List.drop i as.data) (List.drop i bs.data) - simp only [List.get_cons_drop] - termination_by as.size - i + simp only [data_length, Fin.getElem_fin, List.getElem_cons_drop, List.get_eq_getElem] simp [zipWith, loop 0 #[] (by simp) (by simp)] theorem size_zipWith (as : Array α) (bs : Array β) (f : α → β → γ) : diff --git a/Batteries/Data/Char.lean b/Batteries/Data/Char.lean index c94b35ac44..5a9110ae12 100644 --- a/Batteries/Data/Char.lean +++ b/Batteries/Data/Char.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jannis Limperg -/ import Batteries.Data.UInt +import Batteries.Tactic.Alias @[ext] theorem Char.ext : {a b : Char} → a.val = b.val → a = b | ⟨_,_⟩, ⟨_,_⟩, rfl => rfl @@ -21,16 +22,7 @@ instance : Batteries.LawfulOrd Char := .compareOfLessAndEq namespace String -private theorem csize_eq (c) : - csize c = 1 ∨ csize c = 2 ∨ csize c = 3 ∨ - csize c = 4 := by - simp only [csize, Char.utf8Size] - repeat (first | split | (solve | simp (config := {decide := true}))) - -theorem csize_pos (c) : 0 < csize c := by - rcases csize_eq c with _|_|_|_ <;> simp_all (config := {decide := true}) - -theorem csize_le_4 (c) : csize c ≤ 4 := by - rcases csize_eq c with _|_|_|_ <;> simp_all (config := {decide := true}) +@[deprecated (since := "2024-06-11")] alias csize_pos := Char.utf8Size_pos +@[deprecated (since := "2024-06-11")] alias csize_le_4 := Char.utf8Size_le_four end String diff --git a/Batteries/Data/Fin/Lemmas.lean b/Batteries/Data/Fin/Lemmas.lean index a310aa6f93..4d4eb59a1a 100644 --- a/Batteries/Data/Fin/Lemmas.lean +++ b/Batteries/Data/Fin/Lemmas.lean @@ -30,8 +30,13 @@ protected theorem le_antisymm {x y : Fin n} (h1 : x ≤ y) (h2 : y ≤ x) : x = @[simp] theorem length_list (n) : (list n).length = n := by simp [list] -@[simp] theorem get_list (i : Fin (list n).length) : (list n).get i = i.cast (length_list n) := by - cases i; simp only [list]; rw [← Array.getElem_eq_data_get, getElem_enum, cast_mk] +@[simp] theorem getElem_list (i : Nat) (h : i < (list n).length) : + (list n)[i] = cast (length_list n) ⟨i, h⟩ := by + simp only [list]; rw [← Array.getElem_eq_data_getElem, getElem_enum, cast_mk] + +@[deprecated getElem_list (since := "2024-06-12")] +theorem get_list (i : Fin (list n).length) : (list n).get i = i.cast (length_list n) := by + simp [getElem_list] @[simp] theorem list_zero : list 0 = [] := by simp [list] @@ -52,7 +57,7 @@ theorem list_reverse (n) : (list n).reverse = (list n).map rev := by | succ n ih => conv => lhs; rw [list_succ_last] conv => rhs; rw [list_succ] - simp [List.reverse_map, ih, Function.comp_def, rev_succ] + simp [← List.map_reverse, ih, Function.comp_def, rev_succ] /-! ### foldl -/ diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index 57b121c83c..f6298d3322 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -23,7 +23,7 @@ theorem update_data (self : Buckets α β) (i d h) : theorem exists_of_update (self : Buckets α β) (i d h) : ∃ l₁ l₂, self.1.data = l₁ ++ self.1[i] :: l₂ ∧ List.length l₁ = i.toNat ∧ (self.update i d h).1.data = l₁ ++ d :: l₂ := by - simp only [Array.data_length, Array.ugetElem_eq_getElem, Array.getElem_eq_data_get] + simp only [Array.data_length, Array.ugetElem_eq_getElem, Array.getElem_eq_data_getElem] exact List.exists_of_set' h theorem update_update (self : Buckets α β) (i d d' h h') : @@ -37,13 +37,13 @@ theorem size_eq (data : Buckets α β) : theorem mk_size (h) : (mk n h : Buckets α β).size = 0 := by simp only [mk, mkArray, size_eq]; clear h - induction n <;> simp [*] + induction n <;> simp_all [List.replicate_succ] theorem WF.mk' [BEq α] [Hashable α] (h) : (Buckets.mk n h : Buckets α β).WF := by refine ⟨fun _ h => ?_, fun i h => ?_⟩ · simp only [Buckets.mk, mkArray, List.mem_replicate, ne_eq] at h simp [h, List.Pairwise.nil] - · simp [Buckets.mk, empty', mkArray, Array.getElem_eq_data_get, AssocList.All] + · simp [Buckets.mk, empty', mkArray, Array.getElem_eq_data_getElem, AssocList.All] theorem WF.update [BEq α] [Hashable α] {buckets : Buckets α β} {i d h} (H : buckets.WF) (h₁ : ∀ [PartialEquivBEq α] [LawfulHashable α], @@ -57,7 +57,8 @@ theorem WF.update [BEq α] [Hashable α] {buckets : Buckets α β} {i d h} (H : | .inl hl => H.1 _ hl | .inr rfl => h₁ (H.1 _ (Array.getElem_mem_data ..)) · revert hp - simp only [Array.getElem_eq_data_get, update_data, List.get_set, Array.data_length, update_size] + simp only [Array.getElem_eq_data_getElem, update_data, List.getElem_set, Array.data_length, + update_size] split <;> intro hp · next eq => exact eq ▸ h₂ (H.2 _ _) _ hp · simp only [update_size, Array.data_length] at hi @@ -87,23 +88,24 @@ theorem expand_size [Hashable α] {buckets : Buckets α β} : · rw [Buckets.mk_size]; simp [Buckets.size] · nofun where - go (i source) (target : Buckets α β) (hs : ∀ j < i, source.data.getD j .nil = .nil) : + go (i source) (target : Buckets α β) (hs : ∀ j < i, source.data[j]?.getD .nil = .nil) : (expand.go i source target).size = .sum (source.data.map (·.toList.length)) + target.size := by unfold expand.go; split · next H => refine (go (i+1) _ _ fun j hj => ?a).trans ?b <;> simp · case a => - simp only [List.getD_eq_get?, List.get?_set, Option.map_eq_map]; split - · cases List.get? .. <;> rfl + simp [List.getD_eq_getElem?, List.getElem?_set, Option.map_eq_map]; split + · cases source.data[j]? <;> rfl · next H => exact hs _ (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ hj) (Ne.symm H)) · case b => refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set' H; eq ▸ ?_ - simp only [Buckets.size_eq, h₁, List.map_append, List.map_cons, AssocList.toList, - List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length] + rw [h₁] + simp only [Buckets.size_eq, List.map_append, List.map_cons, AssocList.toList, + List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length] rw [Nat.add_assoc, Nat.add_assoc, Nat.add_assoc]; congr 1 (conv => rhs; rw [Nat.add_left_comm]); congr 1 - rw [← Array.getElem_eq_data_get] + rw [← Array.getElem_eq_data_getElem] have := @reinsertAux_size α β _; simp [Buckets.size] at this induction source[i].toList generalizing target <;> simp [*, Nat.succ_add]; rfl · next H => @@ -111,10 +113,10 @@ where rw [← (_ : source.data.map (fun _ => .nil) = source.data)] · simp only [List.map_map] induction source.data <;> simp [*] - refine List.ext_get (by simp) fun j h₁ h₂ => ?_ - simp only [List.get_map, Array.data_length] + refine List.ext_getElem (by simp) fun j h₁ h₂ => ?_ + simp only [List.getElem_map, Array.data_length] have := (hs j (Nat.lt_of_lt_of_le h₂ (Nat.not_lt.1 H))).symm - rwa [List.getD_eq_get?, List.get?_eq_get, Option.getD_some] at this + rwa [List.getElem?_eq_getElem] at this termination_by source.size - i theorem expand_WF.foldl [BEq α] [Hashable α] (rank : α → Nat) {l : List (α × β)} {i : Nat} @@ -166,8 +168,8 @@ where · match List.mem_or_eq_of_mem_set hl with | .inl hl => exact hs₁ _ hl | .inr e => exact e ▸ .nil - · simp only [Array.data_length, Array.size_set, Array.getElem_eq_data_get, Array.data_set, - List.get_set] + · simp only [Array.data_length, Array.size_set, Array.getElem_eq_data_getElem, Array.data_set, + List.getElem_set] split · nofun · exact hs₂ _ (by simp_all) @@ -364,8 +366,8 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable have := H.out.2.1 _ h rw [← List.pairwise_map (R := (¬ · == ·))] at this ⊢ exact this.sublist (H3 l.toList) - · simp only [Array.size_mk, List.length_map, Array.data_length, Array.getElem_eq_data_get, - List.get_map] at h ⊢ + · simp only [Array.size_mk, List.length_map, Array.data_length, Array.getElem_eq_data_getElem, + List.getElem_map] at h ⊢ have := H.out.2.2 _ h simp only [AssocList.All, List.toList_toAssocList, List.mem_reverse, List.mem_filterMap, Option.map_eq_some', forall_exists_index, and_imp, g₁] at this ⊢ diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index aacd1c9f2c..a8c3fef85a 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -313,7 +313,8 @@ def takeD : Nat → List α → α → List α @[simp] theorem takeD_succ (l) (a : α) : takeD (n+1) l a = l.head?.getD a :: takeD n l.tail a := by simp [takeD] -@[simp] theorem takeD_nil (n) (a : α) : takeD n [] a = replicate n a := by induction n <;> simp [*] +@[simp] theorem takeD_nil (n) (a : α) : takeD n [] a = replicate n a := by + induction n <;> simp [*, replicate_succ] /-- Tail-recursive version of `takeD`. -/ def takeDTR (n : Nat) (l : List α) (dflt : α) : List α := go n l #[] where @@ -325,7 +326,7 @@ def takeDTR (n : Nat) (l : List α) (dflt : α) : List α := go n l #[] where theorem takeDTR_go_eq : ∀ n l, takeDTR.go dflt n l acc = acc.data ++ takeD n l dflt | 0, _ => by simp [takeDTR.go] - | _+1, [] => by simp [takeDTR.go] + | _+1, [] => by simp [takeDTR.go, replicate_succ] | _+1, _::l => by simp [takeDTR.go, takeDTR_go_eq _ l] @[csimp] theorem takeD_eq_takeDTR : @takeD = @takeDTR := by @@ -485,7 +486,7 @@ def initsTR (l : List α) : List (List α) := l.foldr (fun a arrs => (arrs.map fun t => a :: t).push []) #[[]] |>.toListRev @[csimp] theorem inits_eq_initsTR : @inits = @initsTR := by - funext α l; simp [initsTR]; induction l <;> simp [*, reverse_map] + funext α l; simp [initsTR]; induction l <;> simp [*, map_reverse] /-- `tails l` is the list of terminal segments of `l`. diff --git a/Batteries/Data/List/EraseIdx.lean b/Batteries/Data/List/EraseIdx.lean index 31a595be57..ca3cf2e716 100644 --- a/Batteries/Data/List/EraseIdx.lean +++ b/Batteries/Data/List/EraseIdx.lean @@ -63,20 +63,32 @@ protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) : rw [Nat.not_lt] at hkl simp [eraseIdx_append_of_length_le hkl, eraseIdx_of_length_le hkl] -theorem mem_eraseIdx_iff_get {x : α} : - ∀ {l} {k}, x ∈ eraseIdx l k ↔ ∃ i : Fin l.length, ↑i ≠ k ∧ l.get i = x +theorem mem_eraseIdx_iff_getElem {x : α} : + ∀ {l} {k}, x ∈ eraseIdx l k ↔ ∃ i : Fin l.length, ↑i ≠ k ∧ l[i.1] = x | [], _ => by simp only [eraseIdx, Fin.exists_iff, not_mem_nil, false_iff] rintro ⟨i, h, -⟩ exact Nat.not_lt_zero _ h | a::l, 0 => by simp [Fin.exists_fin_succ, mem_iff_get] | a::l, k+1 => by - simp [Fin.exists_fin_succ, mem_eraseIdx_iff_get, @eq_comm _ a, k.succ_ne_zero.symm] - + simp [Fin.exists_fin_succ, mem_eraseIdx_iff_getElem, @eq_comm _ a, k.succ_ne_zero.symm] + +@[deprecated mem_eraseIdx_iff_getElem (since := "2024-06-12")] +theorem mem_eraseIdx_iff_get {x : α} {l} {k} : + x ∈ eraseIdx l k ↔ ∃ i : Fin l.length, ↑i ≠ k ∧ l.get i = x := by + simp [mem_eraseIdx_iff_getElem] + +theorem mem_eraseIdx_iff_getElem? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i ≠ k, l[i]? = some x := by + simp only [mem_eraseIdx_iff_getElem, getElem_eq_iff, Fin.exists_iff, exists_and_left] + refine exists_congr fun i => and_congr_right' ?_ + constructor + · rintro ⟨_, h⟩; exact h + · rintro h; + obtain ⟨h', -⟩ := getElem?_eq_some.1 h + exact ⟨h', h⟩ + +@[deprecated mem_eraseIdx_iff_getElem? (since := "2024-06-12")] theorem mem_eraseIdx_iff_get? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i ≠ k, l.get? i = x := by - simp only [mem_eraseIdx_iff_get, Fin.exists_iff, exists_and_left, get_eq_iff, exists_prop] - refine exists_congr fun i => and_congr_right' <| and_iff_right_of_imp fun h => ?_ - obtain ⟨h, -⟩ := get?_eq_some.1 h - exact h + simp [mem_eraseIdx_iff_getElem?] end List diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index cd010a8150..44d9a5c18d 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -243,25 +243,41 @@ theorem tail_eq_tail? (l) : @tail α l = (tail? l).getD [] := by simp [tail_eq_t /-! ### get? -/ -theorem get_eq_iff : List.get l n = x ↔ l.get? n.1 = some x := by simp [get?_eq_some] +theorem getElem_eq_iff {l : List α} {n : Nat} {h : n < l.length} : l[n] = x ↔ l[n]? = some x := by + simp only [get_eq_getElem, get?_eq_getElem?, getElem?_eq_some] + exact ⟨fun w => ⟨h, w⟩, fun h => h.2⟩ -theorem get?_inj - (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs.get? i = xs.get? j) : i = j := by +@[deprecated getElem_eq_iff (since := "2024-06-12")] +theorem get_eq_iff : List.get l n = x ↔ l.get? n.1 = some x := by + simp + +theorem getElem?_inj + (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs[i]? = xs[j]?) : i = j := by induction xs generalizing i j with | nil => cases h₀ | cons x xs ih => match i, j with | 0, 0 => rfl | i+1, j+1 => simp; cases h₁ with - | cons ha h₁ => exact ih (Nat.lt_of_succ_lt_succ h₀) h₁ h₂ - | i+1, 0 => ?_ | 0, j+1 => ?_ + | cons ha h₁ => + simp only [getElem?_cons_succ] at h₂ + exact ih (Nat.lt_of_succ_lt_succ h₀) h₁ h₂ + | i+1, 0 => ?_ + | 0, j+1 => ?_ all_goals - simp at h₂ + simp only [get?_eq_getElem?, getElem?_cons_zero, getElem?_cons_succ] at h₂ cases h₁; rename_i h' h have := h x ?_ rfl; cases this rw [mem_iff_get?] + simp only [get?_eq_getElem?] exact ⟨_, h₂⟩; exact ⟨_ , h₂.symm⟩ +@[deprecated getElem?_inj (since := "2024-06-12")] +theorem get?_inj + (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs.get? i = xs.get? j) : i = j := by + apply getElem?_inj h₀ h₁ + simp_all + /-! ### drop -/ theorem tail_drop (l : List α) (n : Nat) : (l.drop n).tail = l.drop (n + 1) := by @@ -294,15 +310,21 @@ theorem eraseIdx_eq_modifyNthTail : ∀ n (l : List α), eraseIdx l n = modifyNt @[deprecated] alias removeNth_eq_nth_tail := eraseIdx_eq_modifyNthTail -theorem get?_modifyNth (f : α → α) : - ∀ n (l : List α) m, (modifyNth f n l).get? m = (fun a => if n = m then f a else a) <$> l.get? m - | n, l, 0 => by cases l <;> cases n <;> rfl +theorem getElem?_modifyNth (f : α → α) : + ∀ n (l : List α) m, (modifyNth f n l)[m]? = (fun a => if n = m then f a else a) <$> l[m]? + | n, l, 0 => by cases l <;> cases n <;> simp | n, [], _+1 => by cases n <;> rfl - | 0, _ :: l, m+1 => by cases h : l.get? m <;> simp [h, modifyNth, m.succ_ne_zero.symm] - | n+1, a :: l, m+1 => - (get?_modifyNth f n l m).trans <| by - cases h' : l.get? m <;> by_cases h : n = m <;> - simp [h, if_pos, if_neg, Option.map, mt Nat.succ.inj, not_false_iff, h'] + | 0, _ :: l, m+1 => by cases h : l[m]? <;> simp [h, modifyNth, m.succ_ne_zero.symm] + | n+1, a :: l, m+1 => by + simp only [modifyNth_succ_cons, getElem?_cons_succ, Nat.reduceEqDiff, Option.map_eq_map] + refine (getElem?_modifyNth f n l m).trans ?_ + cases h' : l[m]? <;> by_cases h : n = m <;> + simp [h, if_pos, if_neg, Option.map, mt Nat.succ.inj, not_false_iff, h'] + +@[deprecated getElem?_modifyNth (since := "2024-06-12")] +theorem get?_modifyNth (f : α → α) (n) (l : List α) (m) : + (modifyNth f n l).get? m = (fun a => if n = m then f a else a) <$> l.get? m := by + simp [getElem?_modifyNth] theorem modifyNthTail_length (f : List α → List α) (H : ∀ l, length (f l) = length l) : ∀ n l, length (modifyNthTail f n l) = length l @@ -323,13 +345,23 @@ theorem exists_of_modifyNthTail (f : List α → List α) {n} {l : List α} (h : @[simp] theorem modify_get?_length (f : α → α) : ∀ n l, length (modifyNth f n l) = length l := modifyNthTail_length _ fun l => by cases l <;> rfl -@[simp] theorem get?_modifyNth_eq (f : α → α) (n) (l : List α) : - (modifyNth f n l).get? n = f <$> l.get? n := by - simp only [get?_modifyNth, if_pos] +@[simp] theorem getElem?_modifyNth_eq (f : α → α) (n) (l : List α) : + (modifyNth f n l)[n]? = f <$> l[n]? := by + simp only [getElem?_modifyNth, if_pos] + +@[deprecated getElem?_modifyNth_eq (since := "2024-06-12")] +theorem get?_modifyNth_eq (f : α → α) (n) (l : List α) : + (modifyNth f n l).get? n = f <$> l.get? n := by + simp [getElem?_modifyNth_eq] -@[simp] theorem get?_modifyNth_ne (f : α → α) {m n} (l : List α) (h : m ≠ n) : +@[simp] theorem getElem?_modifyNth_ne (f : α → α) {m n} (l : List α) (h : m ≠ n) : + (modifyNth f m l)[n]? = l[n]? := by + simp only [getElem?_modifyNth, if_neg h, id_map'] + +@[deprecated getElem?_modifyNth_ne (since := "2024-06-12")] +theorem get?_modifyNth_ne (f : α → α) {m n} (l : List α) (h : m ≠ n) : (modifyNth f m l).get? n = l.get? n := by - simp only [get?_modifyNth, if_neg h, id_map'] + simp [h] theorem exists_of_modifyNth (f : α → α) {n} {l : List α} (h : n < l.length) : ∃ l₁ a l₂, l = l₁ ++ a :: l₂ ∧ l₁.length = n ∧ modifyNth f n l = l₁ ++ f a :: l₂ := @@ -348,8 +380,8 @@ theorem modifyNth_eq_take_drop (f : α → α) : modifyNthTail_eq_take_drop _ rfl theorem modifyNth_eq_take_cons_drop (f : α → α) {n l} (h) : - modifyNth f n l = take n l ++ f (get l ⟨n, h⟩) :: drop (n + 1) l := by - rw [modifyNth_eq_take_drop, drop_eq_get_cons h]; rfl + modifyNth f n l = take n l ++ f l[n] :: drop (n + 1) l := by + rw [modifyNth_eq_take_drop, drop_eq_getElem_cons h]; rfl /-! ### set -/ @@ -367,7 +399,7 @@ theorem modifyNth_eq_set_get? (f : α → α) : | 0, l => by cases l <;> rfl | n+1, [] => rfl | n+1, b :: l => - (congrArg (cons _) (modifyNth_eq_set_get? ..)).trans <| by cases h : l.get? n <;> simp [h] + (congrArg (cons _) (modifyNth_eq_set_get? ..)).trans <| by cases h : l[n]? <;> simp [h] theorem modifyNth_eq_set_get (f : α → α) {n} {l : List α} (h) : l.modifyNth f n = l.set n (f (l.get ⟨n, h⟩)) := by @@ -378,42 +410,56 @@ theorem exists_of_set {l : List α} (h : n < l.length) : rw [set_eq_modifyNth]; exact exists_of_modifyNth _ h theorem exists_of_set' {l : List α} (h : n < l.length) : - ∃ l₁ l₂, l = l₁ ++ l.get ⟨n, h⟩ :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := - have ⟨_, _, _, h₁, h₂, h₃⟩ := exists_of_set h; ⟨_, _, get_of_append h₁ h₂ ▸ h₁, h₂, h₃⟩ + ∃ l₁ l₂, l = l₁ ++ l[n] :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := + have ⟨_, _, _, h₁, h₂, h₃⟩ := exists_of_set h; ⟨_, _, getElem_of_append h₁ h₂ ▸ h₁, h₂, h₃⟩ @[simp] +theorem getElem?_set_eq' (a : α) (n) (l : List α) : (set l n a)[n]? = (fun _ => a) <$> l[n]? := by + simp only [set_eq_modifyNth, getElem?_modifyNth_eq] + +@[deprecated getElem?_set_eq' (since := "2024-06-12")] 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] + simp +theorem getElem?_set_eq_of_lt (a : α) {n} {l : List α} (h : n < length l) : + (set l n a)[n]? = some a := by rw [getElem?_set_eq', getElem?_eq_getElem h]; rfl + +@[deprecated getElem?_set_eq_of_lt (since := "2024-06-12")] 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 + (set l n a).get? n = some a := by + rw [get?_eq_getElem?, getElem?_set_eq', getElem?_eq_getElem h]; rfl -@[simp] +@[deprecated getElem?_set_ne (since := "2024-06-12")] 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] + simp [h] +theorem getElem?_set' (a : α) {m n} (l : List α) : + (set l m a)[n]? = if m = n then (fun _ => a) <$> l[n]? else l[n]? := by + by_cases m = n <;> simp [*] + +@[deprecated getElem?_set (since := "2024-06-12")] 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] + simp [getElem?_set'] 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] + simp [getElem?_set', getElem?_eq_getElem 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 [getElem?_set]; split <;> subst_vars <;> simp [*, getElem?_eq_getElem h] theorem drop_set_of_lt (a : α) {n m : Nat} (l : List α) (h : n < m) : (l.set n a).drop m = l.drop m := - List.ext fun i => by rw [get?_drop, get?_drop, get?_set_ne _ _ (by omega)] + List.ext_getElem? fun i => by rw [getElem?_drop, getElem?_drop, getElem?_set_ne (by omega)] theorem take_set_of_lt (a : α) {n m : Nat} (l : List α) (h : m < n) : (l.set n a).take m = l.take m := - List.ext fun i => by - rw [get?_take_eq_if, get?_take_eq_if] + List.ext_getElem? fun i => by + rw [getElem?_take_eq_if, getElem?_take_eq_if] split - · next h' => rw [get?_set_ne _ _ (by omega)] + · next h' => rw [getElem?_set_ne (by omega)] · rfl /-! ### removeNth -/ @@ -607,32 +653,13 @@ end erase /-! ### filterMap -/ -theorem length_filter_le (p : α → Bool) (l : List α) : - (l.filter p).length ≤ l.length := (filter_sublist _).length_le - -theorem length_filterMap_le (f : α → Option β) (l : List α) : - (filterMap f l).length ≤ l.length := by - rw [← length_map _ some, map_filterMap_some_eq_filter_map_is_some, ← length_map _ f] - apply length_filter_le - protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) : filterMap f l₁ <+ filterMap f l₂ := by - induction s <;> simp <;> split <;> simp [*, cons, cons₂] + induction s <;> simp [filterMap_cons] <;> split <;> simp [*, cons, cons₂] theorem Sublist.filter (p : α → Bool) {l₁ l₂} (s : l₁ <+ l₂) : filter p l₁ <+ filter p l₂ := by rw [← filterMap_eq_filter]; apply s.filterMap -@[simp] -theorem filter_eq_self {l} : filter p l = l ↔ ∀ a ∈ l, p a := by - induction l with simp - | cons a l ih => - cases h : p a <;> simp [*] - intro h; exact Nat.lt_irrefl _ (h ▸ length_filter_le p l) - -@[simp] -theorem filter_length_eq_length {l} : (filter p l).length = l.length ↔ ∀ a ∈ l, p a := - Iff.trans ⟨l.filter_sublist.eq_of_length, congrArg length⟩ filter_eq_self - /-! ### findIdx -/ @[simp] theorem findIdx_nil {α : Type _} (p : α → Bool) : [].findIdx p = 0 := rfl @@ -697,7 +724,7 @@ theorem findIdx?_eq_some_iff (xs : List α) (p : α → Bool) : | nil => simp | cons x xs ih => simp only [findIdx?_cons, Nat.zero_add, findIdx?_succ, take_succ_cons, map_cons] - split <;> cases i <;> simp_all + split <;> cases i <;> simp_all [replicate_succ] theorem findIdx?_of_eq_some {xs : List α} {p : α → Bool} (w : xs.findIdx? p = some i) : match xs.get? i with | some a => p a | none => false := by @@ -1269,6 +1296,9 @@ protected theorem Pairwise.chain (p : Pairwise R (a :: l)) : Chain R a l := by /-! ### range', range -/ +theorem range'_succ (s n step) : range' s (n + 1) step = s :: range' (s + step) n step := by + simp [range', Nat.add_succ, Nat.mul_succ] + @[simp] theorem length_range' (s step) : ∀ n : Nat, length (range' s n step) = n | 0 => rfl | _ + 1 => congrArg succ (length_range' _ _ _) @@ -1331,15 +1361,27 @@ theorem range'_subset_right {s m n : Nat} (step0 : 0 < step) : theorem range'_subset_right_1 {s m n : Nat} : range' s m ⊆ range' s n ↔ m ≤ n := range'_subset_right (by decide) -theorem get?_range' (s step) : ∀ {m n : Nat}, m < n → get? (range' s n step) m = some (s + step * m) - | 0, n + 1, _ => rfl - | m + 1, n + 1, h => - (get?_range' (s + step) step (Nat.lt_of_add_lt_add_right h)).trans <| by +theorem getElem?_range' (s step) : + ∀ {m n : Nat}, m < n → (range' s n step)[m]? = some (s + step * m) + | 0, n + 1, _ => by simp [range'_succ] + | m + 1, n + 1, h => by + simp only [range'_succ, getElem?_cons_succ] + exact (getElem?_range' (s + step) step (Nat.lt_of_add_lt_add_right h)).trans <| by simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm] -@[simp] theorem get_range' {n m step} (i) (H : i < (range' n m step).length) : - get (range' n m step) ⟨i, H⟩ = n + step * i := - (get?_eq_some.1 <| get?_range' n step (by simpa using H)).2 +@[simp] theorem getElem_range' {n m step} (i) (H : i < (range' n m step).length) : + (range' n m step)[i] = n + step * i := + (getElem?_eq_some.1 <| getElem?_range' n step (by simpa using H)).2 + +@[deprecated getElem?_range' (since := "2024-06-12")] +theorem get?_range' (s step) {m n : Nat} (h : m < n) : + get? (range' s n step) m = some (s + step * m) := by + simp [h] + +@[deprecated getElem_range' (since := "2024-06-12")] +theorem get_range' {n m step} (i) (H : i < (range' n m step).length) : + get (range' n m step) ⟨i, H⟩ = n + step * i := by + simp theorem range'_concat (s n : Nat) : range' s (n + 1) step = range' s n step ++ [s + step * n] := by rw [Nat.add_comm n 1]; exact (range'_append s n 1 step).symm @@ -1383,14 +1425,23 @@ theorem not_mem_range_self {n : Nat} : n ∉ range n := by simp theorem self_mem_range_succ (n : Nat) : n ∈ range (n + 1) := by simp +theorem getElem?_range {m n : Nat} (h : m < n) : (range n)[m]? = some m := by + simp [range_eq_range', getElem?_range' _ _ h] + +@[simp] theorem getElem_range {n : Nat} (m) (h : m < (range n).length) : (range n)[m] = m := by + simp [range_eq_range'] + +@[deprecated getElem?_range (since := "2024-06-12")] theorem get?_range {m n : Nat} (h : m < n) : get? (range n) m = some m := by - simp [range_eq_range', get?_range' _ _ h] + simp [getElem?_range, h] + +@[deprecated getElem_range (since := "2024-06-12")] +theorem get_range {n} (i) (H : i < (range n).length) : get (range n) ⟨i, H⟩ = i := by + simp theorem range_succ (n : Nat) : range (succ n) = range n ++ [n] := by simp only [range_eq_range', range'_1_concat, Nat.zero_add] -@[simp] theorem range_zero : range 0 = [] := rfl - theorem range_add (a b : Nat) : range (a + b) = range a ++ (range b).map (a + ·) := by rw [← range'_eq_map_range] simpa [range_eq_range', Nat.add_comm] using (range'_append_1 0 a b).symm @@ -1410,10 +1461,8 @@ theorem reverse_range' : ∀ s n : Nat, reverse (range' s n) = map (s + n - 1 - | s, n + 1 => by rw [range'_1_concat, reverse_append, range_succ_eq_map, show s + (n + 1) - 1 = s + n from rfl, map, map_map] - simp [reverse_range', Nat.sub_right_comm]; rfl + simp [reverse_range', Nat.sub_right_comm, Nat.sub_sub] -@[simp] theorem get_range {n} (i) (H : i < (range n).length) : get (range n) ⟨i, H⟩ = i := - Option.some.inj <| by rw [← get?_eq_get _, get?_range (by simpa using H)] /-! ### enum, enumFrom -/ @@ -1425,16 +1474,6 @@ theorem reverse_range' : ∀ s n : Nat, reverse (range' s n) = map (s + n - 1 - @[simp] theorem enum_map_fst (l : List α) : map Prod.fst (enum l) = range l.length := by simp only [enum, enumFrom_map_fst, range_eq_range'] -/-! ### maximum? -/ - --- A specialization of `maximum?_eq_some_iff` to Nat. -theorem maximum?_eq_some_iff' {xs : List Nat} : - xs.maximum? = some a ↔ (a ∈ xs ∧ ∀ b ∈ xs, b ≤ a) := - maximum?_eq_some_iff - (le_refl := Nat.le_refl) - (max_eq_or := fun _ _ => Nat.max_def .. ▸ by split <;> simp) - (max_le_iff := fun _ _ _ => Nat.max_le) - /-! ### indexOf and indexesOf -/ theorem foldrIdx_start : diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index 392f261bf2..8583a41f2b 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -213,7 +213,7 @@ theorem map_get_sublist {l : List α} {is : List (Fin l.length)} (h : is.Pairwis simp; cases hl' have := IH h.of_cons (hd+1) _ rfl (pairwise_cons.mp h).1 specialize his hd (.head _) - have := (drop_eq_get_cons ..).symm ▸ this.cons₂ (get l hd) + have := (drop_eq_getElem_cons ..).symm ▸ this.cons₂ (get l hd) have := Sublist.append (nil_sublist (take hd l |>.drop n)) this rwa [nil_append, ← (drop_append_of_le_length ?_), take_append_drop] at this simp [Nat.min_eq_left (Nat.le_of_lt hd.isLt), his] @@ -232,25 +232,33 @@ theorem sublist_eq_map_get (h : l' <+ l) : ∃ is : List (Fin l.length), | cons₂ _ _ IH => rcases IH with ⟨is,IH⟩ refine ⟨⟨0, by simp [Nat.zero_lt_succ]⟩ :: is.map (·.succ), ?_⟩ - simp [comp_def, pairwise_map, IH] + simp [comp_def, pairwise_map, IH, ← get_eq_getElem] -theorem pairwise_iff_get : Pairwise R l ↔ ∀ (i j) (_hij : i < j), R (get l i) (get l j) := by +theorem pairwise_iff_getElem : Pairwise R l ↔ + ∀ (i j : Nat) (_hi : i < l.length) (_hj : j < l.length) (_hij : i < j), R l[i] l[j] := by rw [pairwise_iff_forall_sublist] constructor <;> intro h - · intros i j h' + · intros i j hi hj h' apply h - apply map_get_sublist (is := [i, j]) - rw [Fin.lt_def] at h'; simp [h'] + simpa [h'] using map_get_sublist (is := [⟨i, hi⟩, ⟨j, hj⟩]) · intros a b h' have ⟨is, h', hij⟩ := sublist_eq_map_get h' rcases is with ⟨⟩ | ⟨a', ⟨⟩ | ⟨b', ⟨⟩⟩⟩ <;> simp at h' rcases h' with ⟨rfl, rfl⟩ apply h; simpa using hij +theorem pairwise_iff_get : Pairwise R l ↔ ∀ (i j) (_hij : i < j), R (get l i) (get l j) := by + rw [pairwise_iff_getElem] + constructor <;> intro h + · intros i j h' + exact h _ _ _ _ h' + · intros i j hi hj h' + exact h ⟨i, hi⟩ ⟨j, hj⟩ h' + theorem pairwise_replicate {α : Type _} {r : α → α → Prop} {x : α} (hx : r x x) : ∀ n : Nat, Pairwise r (List.replicate n x) | 0 => by simp - | n + 1 => by simp [mem_replicate, hx, pairwise_replicate hx n] + | n + 1 => by simp [mem_replicate, hx, pairwise_replicate hx n, replicate_succ] /-! ### Pairwise filtering -/ diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index 49299089a5..ab12db10b1 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -155,8 +155,8 @@ theorem Perm.filterMap (f : α → Option β) {l₁ l₂ : List α} (p : l₁ ~ filterMap f l₁ ~ filterMap f l₂ := by induction p with | nil => simp - | cons x _p IH => cases h : f x <;> simp [h, filterMap, IH, Perm.cons] - | swap x y l₂ => cases hx : f x <;> cases hy : f y <;> simp [hx, hy, filterMap, swap] + | cons x _p IH => cases h : f x <;> simp [h, filterMap_cons, IH, Perm.cons] + | swap x y l₂ => cases hx : f x <;> cases hy : f y <;> simp [hx, hy, filterMap_cons, swap] | trans _p₁ _p₂ IH₁ IH₂ => exact IH₁.trans IH₂ theorem Perm.map (f : α → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) : map f l₁ ~ map f l₂ := @@ -643,7 +643,7 @@ theorem Perm.union {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : theorem Perm.inter_right {l₁ l₂ : List α} (t₁ : List α) : l₁ ~ l₂ → l₁ ∩ t₁ ~ l₂ ∩ t₁ := .filter _ theorem Perm.inter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) : l ∩ t₁ = l ∩ t₂ := - filter_congr' fun a _ => by simpa using p.mem_iff (a := a) + filter_congr fun a _ => by simpa using p.mem_iff (a := a) theorem Perm.inter {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : l₁ ∩ t₁ ~ l₂ ∩ t₂ := p₂.inter_left l₂ ▸ p₁.inter_right t₁ diff --git a/Batteries/Data/String/Lemmas.lean b/Batteries/Data/String/Lemmas.lean index ad15234f51..1ea4e4f788 100644 --- a/Batteries/Data/String/Lemmas.lean +++ b/Batteries/Data/String/Lemmas.lean @@ -34,13 +34,13 @@ instance : Batteries.BEqOrd String := .compareOfLessAndEq String.lt_irrefl attribute [simp] toList -- prefer `String.data` over `String.toList` in lemmas -private theorem add_csize_pos : 0 < i + csize c := - Nat.add_pos_right _ (csize_pos c) +private theorem add_csize_pos : 0 < i + Char.utf8Size c := + Nat.add_pos_right _ (Char.utf8Size_pos c) -private theorem ne_add_csize_add_self : i ≠ n + csize c + i := +private theorem ne_add_csize_add_self : i ≠ n + Char.utf8Size c + i := Nat.ne_of_lt (Nat.lt_add_of_pos_left add_csize_pos) -private theorem ne_self_add_add_csize : i ≠ i + (n + csize c) := +private theorem ne_self_add_add_csize : i ≠ i + (n + Char.utf8Size c) := Nat.ne_of_lt (Nat.lt_add_of_pos_right add_csize_pos) /-- The UTF-8 byte length of a list of characters. (This is intended for specification purposes.) -/ @@ -52,7 +52,7 @@ private theorem ne_self_add_add_csize : i ≠ i + (n + csize c) := @[simp] theorem utf8Len_nil : utf8Len [] = 0 := rfl -@[simp] theorem utf8Len_cons (c cs) : utf8Len (c :: cs) = utf8Len cs + csize c := rfl +@[simp] theorem utf8Len_cons (c cs) : utf8Len (c :: cs) = utf8Len cs + c.utf8Size := rfl @[simp] theorem utf8Len_append (cs₁ cs₂) : utf8Len (cs₁ ++ cs₂) = utf8Len cs₁ + utf8Len cs₂ := by induction cs₁ <;> simp [*, Nat.add_right_comm] @@ -89,7 +89,7 @@ namespace Pos attribute [ext] ext -theorem lt_addChar (p : Pos) (c : Char) : p < p + c := Nat.lt_add_of_pos_right (csize_pos _) +theorem lt_addChar (p : Pos) (c : Char) : p < p + c := Nat.lt_add_of_pos_right (Char.utf8Size_pos _) private theorem zero_ne_addChar {i : Pos} {c : Char} : 0 ≠ i + c := ne_of_lt add_csize_pos @@ -201,11 +201,11 @@ theorem modify_of_valid (cs cs' : List Char) : rw [modify, set_of_valid, get_of_valid]; cases cs' <;> rfl theorem next_of_valid' (cs cs' : List Char) : - next ⟨cs ++ cs'⟩ ⟨utf8Len cs⟩ = ⟨utf8Len cs + csize (cs'.headD default)⟩ := by + next ⟨cs ++ cs'⟩ ⟨utf8Len cs⟩ = ⟨utf8Len cs + (cs'.headD default).utf8Size⟩ := by simp only [next, get_of_valid]; rfl theorem next_of_valid (cs : List Char) (c : Char) (cs' : List Char) : - next ⟨cs ++ c :: cs'⟩ ⟨utf8Len cs⟩ = ⟨utf8Len cs + csize c⟩ := next_of_valid' .. + next ⟨cs ++ c :: cs'⟩ ⟨utf8Len cs⟩ = ⟨utf8Len cs + c.utf8Size⟩ := next_of_valid' .. @[simp] theorem atEnd_iff (s : String) (p : Pos) : atEnd s p ↔ s.endPos ≤ p := decide_eq_true_iff _ @@ -218,7 +218,7 @@ theorem valid_next {p : Pos} (h : p.Valid s) (h₂ : p < s.endPos) : (next s p). simpa using Pos.Valid.mk (cs ++ [c]) cs' theorem utf8PrevAux_of_valid {cs cs' : List Char} {c : Char} {i p : Nat} - (hp : i + (utf8Len cs + csize c) = p) : + (hp : i + (utf8Len cs + c.utf8Size) = p) : utf8PrevAux (cs ++ c :: cs') ⟨i⟩ ⟨p⟩ = ⟨i + utf8Len cs⟩ := by match cs with | [] => simp [utf8PrevAux, ← hp, Pos.addChar_eq] @@ -233,7 +233,7 @@ theorem utf8PrevAux_of_valid {cs cs' : List Char} {c : Char} {i p : Nat} simp [Nat.add_assoc, Nat.add_comm] theorem prev_of_valid (cs : List Char) (c : Char) (cs' : List Char) : - prev ⟨cs ++ c :: cs'⟩ ⟨utf8Len cs + csize c⟩ = ⟨utf8Len cs⟩ := by + prev ⟨cs ++ c :: cs'⟩ ⟨utf8Len cs + c.utf8Size⟩ = ⟨utf8Len cs⟩ := by simp only [prev] refine (if_neg (Pos.ne_of_gt add_csize_pos)).trans ?_ rw [utf8PrevAux_of_valid] <;> simp @@ -327,9 +327,9 @@ theorem firstDiffPos_loop_eq (l₁ l₂ r₁ r₂ stop p) split · simp only [utf8Len_cons] subst b - rw [show next ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = ⟨utf8Len l₁ + csize a⟩ by simp [hl₁, next_of_valid]] + rw [show next ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = ⟨utf8Len l₁ + a.utf8Size⟩ by simp [hl₁, next_of_valid]] simpa [← hl₁, ← Nat.add_assoc, Nat.add_right_comm] using - firstDiffPos_loop_eq (l₁ ++ [a]) (l₂ ++ [a]) r₁ r₂ stop (p + csize a) + firstDiffPos_loop_eq (l₁ ++ [a]) (l₂ ++ [a]) r₁ r₂ stop (p + a.utf8Size) (by simp [hl₁]) (by simp [hl₂]) (by simp [hstop, ← Nat.add_assoc, Nat.add_right_comm]) · simp · next h => @@ -647,9 +647,8 @@ theorem offsetOfPosAux_of_valid : ∀ l m r n, unfold offsetOfPosAux rw [if_neg (by exact Nat.not_le.2 (Nat.lt_add_of_pos_right add_csize_pos))] simp only [List.append_assoc, atEnd_of_valid l (c::m++r)] - simp only [List.cons_append, ↓reduceDite, utf8Len_cons, next_of_valid l c (m ++ r), - List.length_cons, Nat.succ_eq_add_one] - simpa [← Nat.add_assoc, Nat.add_right_comm, Nat.succ_eq_add_one] using + simp only [List.cons_append, utf8Len_cons, next_of_valid l c (m ++ r)] + simpa [← Nat.add_assoc, Nat.add_right_comm] using offsetOfPosAux_of_valid (l++[c]) m r (n + 1) theorem offsetOfPos_of_valid (l r) : offsetOfPos ⟨l ++ r⟩ ⟨utf8Len l⟩ = l.length := by @@ -803,7 +802,8 @@ theorem toIterator : ∀ {s}, ValidFor l m r s → s.toIterator.ValidFor l.rever theorem get : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → s.get ⟨utf8Len m₁⟩ = c | _, ⟨⟩ => by simpa using get_of_valid (l ++ m₁) (c :: m₂ ++ r) -theorem next : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → s.next ⟨utf8Len m₁⟩ = ⟨utf8Len m₁ + csize c⟩ +theorem next : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → + s.next ⟨utf8Len m₁⟩ = ⟨utf8Len m₁ + c.utf8Size⟩ | _, ⟨⟩ => by simp only [Substring.next, utf8Len_append, utf8Len_cons, List.append_assoc, List.cons_append] rw [if_neg (mt Pos.ext_iff.1 ?a)] @@ -817,7 +817,8 @@ theorem next : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → s.next ⟨utf8Len theorem next_stop : ∀ {s}, ValidFor l m r s → s.next ⟨utf8Len m⟩ = ⟨utf8Len m⟩ | _, ⟨⟩ => by simp [Substring.next, Pos.add_eq] -theorem prev : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → s.prev ⟨utf8Len m₁ + csize c⟩ = ⟨utf8Len m₁⟩ +theorem prev : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → + s.prev ⟨utf8Len m₁ + c.utf8Size⟩ = ⟨utf8Len m₁⟩ | _, ⟨⟩ => by simp only [Substring.prev, List.append_assoc, List.cons_append] rw [if_neg (mt Pos.ext_iff.1 <| Ne.symm ?a)] @@ -965,7 +966,7 @@ theorem get : ∀ {s}, Valid s → s.toString.1 = m₁ ++ c :: m₂ → s.get simp only [h.toString] at e; subst e; simp [h.get] theorem next : ∀ {s}, Valid s → s.toString.1 = m₁ ++ c :: m₂ → - s.next ⟨utf8Len m₁⟩ = ⟨utf8Len m₁ + csize c⟩ + s.next ⟨utf8Len m₁⟩ = ⟨utf8Len m₁ + c.utf8Size⟩ | _, h, e => by let ⟨l, m, r, h⟩ := h.validFor simp only [h.toString] at e; subst e; simp [h.next] @@ -974,7 +975,7 @@ theorem next_stop : ∀ {s}, Valid s → s.next ⟨s.bsize⟩ = ⟨s.bsize⟩ | _, h => let ⟨l, m, r, h⟩ := h.validFor; by simp [h.bsize, h.next_stop] theorem prev : ∀ {s}, Valid s → s.toString.1 = m₁ ++ c :: m₂ → - s.prev ⟨utf8Len m₁ + csize c⟩ = ⟨utf8Len m₁⟩ + s.prev ⟨utf8Len m₁ + c.utf8Size⟩ = ⟨utf8Len m₁⟩ | _, h, e => by let ⟨l, m, r, h⟩ := h.validFor simp only [h.toString] at e; subst e; simp [h.prev] diff --git a/Batteries/Data/UInt.lean b/Batteries/Data/UInt.lean index 46fcb26b59..a9ce1b561a 100644 --- a/Batteries/Data/UInt.lean +++ b/Batteries/Data/UInt.lean @@ -33,7 +33,7 @@ theorem UInt8.toNat_zero : (0 : UInt8).toNat = 0 := rfl theorem UInt8.toNat_add (x y : UInt8) : (x + y).toNat = (x.toNat + y.toNat) % UInt8.size := rfl theorem UInt8.toNat_sub (x y : UInt8) : - (x - y).toNat = (x.toNat + (UInt8.size - y.toNat)) % UInt8.size := rfl + (x - y).toNat = (UInt8.size - y.toNat + x.toNat) % UInt8.size := rfl theorem UInt8.toNat_mul (x y : UInt8) : (x * y).toNat = (x.toNat * y.toNat) % UInt8.size := rfl @@ -80,7 +80,7 @@ theorem UInt16.toNat_zero : (0 : UInt16).toNat = 0 := rfl theorem UInt16.toNat_add (x y : UInt16) : (x + y).toNat = (x.toNat + y.toNat) % UInt16.size := rfl theorem UInt16.toNat_sub (x y : UInt16) : - (x - y).toNat = (x.toNat + (UInt16.size - y.toNat)) % UInt16.size := rfl + (x - y).toNat = (UInt16.size - y.toNat + x.toNat) % UInt16.size := rfl theorem UInt16.toNat_mul (x y : UInt16) : (x * y).toNat = (x.toNat * y.toNat) % UInt16.size := rfl @@ -127,7 +127,7 @@ theorem UInt32.toNat_zero : (0 : UInt32).toNat = 0 := rfl theorem UInt32.toNat_add (x y : UInt32) : (x + y).toNat = (x.toNat + y.toNat) % UInt32.size := rfl theorem UInt32.toNat_sub (x y : UInt32) : - (x - y).toNat = (x.toNat + (UInt32.size - y.toNat)) % UInt32.size := rfl + (x - y).toNat = (UInt32.size - y.toNat + x.toNat) % UInt32.size := rfl theorem UInt32.toNat_mul (x y : UInt32) : (x * y).toNat = (x.toNat * y.toNat) % UInt32.size := rfl @@ -174,7 +174,7 @@ theorem UInt64.toNat_zero : (0 : UInt64).toNat = 0 := rfl theorem UInt64.toNat_add (x y : UInt64) : (x + y).toNat = (x.toNat + y.toNat) % UInt64.size := rfl theorem UInt64.toNat_sub (x y : UInt64) : - (x - y).toNat = (x.toNat + (UInt64.size - y.toNat)) % UInt64.size := rfl + (x - y).toNat = (UInt64.size - y.toNat + x.toNat) % UInt64.size := rfl theorem UInt64.toNat_mul (x y : UInt64) : (x * y).toNat = (x.toNat * y.toNat) % UInt64.size := rfl @@ -235,7 +235,7 @@ theorem USize.toNat_zero : (0 : USize).toNat = 0 := rfl theorem USize.toNat_add (x y : USize) : (x + y).toNat = (x.toNat + y.toNat) % USize.size := rfl theorem USize.toNat_sub (x y : USize) : - (x - y).toNat = (x.toNat + (USize.size - y.toNat)) % USize.size := rfl + (x - y).toNat = (USize.size - y.toNat + x.toNat) % USize.size := rfl theorem USize.toNat_mul (x y : USize) : (x * y).toNat = (x.toNat * y.toNat) % USize.size := rfl diff --git a/Batteries/Lean/AttributeExtra.lean b/Batteries/Lean/AttributeExtra.lean index 7b8c92af3f..aeac0267c5 100644 --- a/Batteries/Lean/AttributeExtra.lean +++ b/Batteries/Lean/AttributeExtra.lean @@ -81,7 +81,7 @@ Registers a new parametric attribute. The `extra` field is a list of definitions which will be "pre-tagged" and are not subject to the usual restriction on tagging in the same file as the declaration. -/ -def registerParametricAttributeExtra [Inhabited α] (impl : ParametricAttributeImpl α) +def registerParametricAttributeExtra (impl : ParametricAttributeImpl α) (extra : List (Name × α)) : IO (ParametricAttributeExtra α) := do let attr ← registerParametricAttribute impl pure { attr, base := extra.foldl (fun s (a, b) => s.insert a b) {} } diff --git a/Batteries/Lean/Name.lean b/Batteries/Lean/Name.lean deleted file mode 100644 index b5530e49d1..0000000000 --- a/Batteries/Lean/Name.lean +++ /dev/null @@ -1,28 +0,0 @@ -/- -Copyright (c) 2023 Mario Carneiro. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mario Carneiro --/ -import Lean.Data.Name - -namespace Lean.Name - -/-- -Returns true if this a part of name that is internal or dynamically -generated so that it may easily be changed. - -Generally, user code should not explicitly use internal names. --/ -def isInternalDetail : Name → Bool - | .str p s => - s.startsWith "_" - || matchPrefix s "eq_" - || matchPrefix s "match_" - || matchPrefix s "proof_" - || p.isInternalOrNum - | .num _ _ => true - | p => p.isInternalOrNum -where - /-- Check that a string begins with the given prefix, and then is only digit characters. -/ - matchPrefix (s : String) (pre : String) := - s.startsWith pre && (s |>.drop pre.length |>.all Char.isDigit) diff --git a/Batteries/Lean/PersistentHashMap.lean b/Batteries/Lean/PersistentHashMap.lean index 5054e15758..b297f2fa52 100644 --- a/Batteries/Lean/PersistentHashMap.lean +++ b/Batteries/Lean/PersistentHashMap.lean @@ -10,15 +10,6 @@ namespace Lean.PersistentHashMap variable [BEq α] [Hashable α] -/-- -Similar to `insert`, but also returns a Boolean flag indicating whether an -existing entry has been replaced with `a => b`. --/ -def insert' (m : PersistentHashMap α β) (a : α) (b : β) : PersistentHashMap α β × Bool := - let oldSize := m.size - let m := m.insert a b - (m, m.size == oldSize) - /-- Builds a `PersistentHashMap` from a list of key-value pairs. Values of duplicated keys are replaced by their respective last occurrences. diff --git a/Batteries/Lean/PersistentHashSet.lean b/Batteries/Lean/PersistentHashSet.lean index 51e33e8487..0a8231d723 100644 --- a/Batteries/Lean/PersistentHashSet.lean +++ b/Batteries/Lean/PersistentHashSet.lean @@ -56,16 +56,6 @@ def all (s : PersistentHashSet α) (f : α → Bool) : Bool := instance : BEq (PersistentHashSet α) where beq s t := s.all (t.contains ·) && t.all (s.contains ·) -/-- -Similar to `insert`, but also returns a Boolean flag indicating whether an -existing entry has been replaced with `a => b`. --/ -@[inline] -def insert' (s : PersistentHashSet α) (a : α) : PersistentHashSet α × Bool := - let oldSize := s.size - let s := s.insert a - (s, s.size == oldSize) - /-- Insert all elements from a collection into a `PersistentHashSet`. -/ diff --git a/Batteries/Tactic/Alias.lean b/Batteries/Tactic/Alias.lean index b7eaeaf713..07b91dc76e 100644 --- a/Batteries/Tactic/Alias.lean +++ b/Batteries/Tactic/Alias.lean @@ -6,6 +6,7 @@ Authors: Mario Carneiro, David Renshaw, François G. Dorais import Lean.Elab.Command import Lean.Elab.DeclarationRange import Lean.Compiler.NoncomputableAttr +import Lean.DocString import Batteries.CodeAction.Deprecated /-! diff --git a/Batteries/Tactic/Lint/Simp.lean b/Batteries/Tactic/Lint/Simp.lean index 3dc801fe0a..9196e4ab74 100644 --- a/Batteries/Tactic/Lint/Simp.lean +++ b/Batteries/Tactic/Lint/Simp.lean @@ -96,7 +96,7 @@ def decorateError (msg : MessageData) (k : MetaM α) : MetaM α := do def formatLemmas (usedSimps : Simp.UsedSimps) (simpName : String) : MetaM MessageData := do let mut args := #[] let env ← getEnv - for (thm, _) in usedSimps.toArray.qsort (·.2 < ·.2) do + for (thm, _) in usedSimps.map.toArray.qsort (·.2 < ·.2) do if let .decl declName := thm then if env.contains declName && declName != ``eq_self then args := args.push (← mkConstWithFreshMVarLevels declName) @@ -120,7 +120,7 @@ https://leanprover-community.github.io/mathlib_docs/notes.html#simp-normal%20for else do let (e, s) ← dsimp lhs ctx return (Simp.Result.mk e .none .true, s) - if prf1Stats.usedTheorems.contains (.decl declName) then return none + if prf1Stats.usedTheorems.map.contains (.decl declName) then return none let ({ expr := rhs', .. }, stats) ← decorateError "simplify fails on right-hand side:" <| if !isRfl then diff --git a/Batteries/Tactic/NoMatch.lean b/Batteries/Tactic/NoMatch.lean index 9dc517b33f..7efe68e7d2 100644 --- a/Batteries/Tactic/NoMatch.lean +++ b/Batteries/Tactic/NoMatch.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Lean.Elab.ElabRules +import Lean.DocString /-! Deprecation warnings for `match ⋯ with.`, `fun.`, `λ.`, and `intro.`. diff --git a/Batteries/Tactic/PrintPrefix.lean b/Batteries/Tactic/PrintPrefix.lean index 0046f0a4d7..63d2c3bbf5 100644 --- a/Batteries/Tactic/PrintPrefix.lean +++ b/Batteries/Tactic/PrintPrefix.lean @@ -3,7 +3,6 @@ Copyright (c) 2021 Shing Tak Lam. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Shing Tak Lam, Daniel Selsam, Mario Carneiro -/ -import Batteries.Lean.Name import Batteries.Lean.Util.EnvSearch import Batteries.Lean.Delaborator import Lean.Elab.Tactic.Config diff --git a/Batteries/Tactic/SqueezeScope.lean b/Batteries/Tactic/SqueezeScope.lean index 78a1d2a540..df289dc982 100644 --- a/Batteries/Tactic/SqueezeScope.lean +++ b/Batteries/Tactic/SqueezeScope.lean @@ -85,7 +85,8 @@ elab_rules : tactic throw e if let some new := new then for (_, stx, usedSimps) in new do - let usedSimps := usedSimps.foldl (fun s usedSimps => usedSimps.foldl .insert s) {} + let usedSimps := usedSimps.reverse.foldl + (fun s usedSimps => usedSimps.toArray.foldl .insert s) {} let stx' ← mkSimpCallStx stx usedSimps TryThis.addSuggestion stx[0] stx' (origSpan? := stx) diff --git a/lean-toolchain b/lean-toolchain index 4ef27c472e..d69d1ed200 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.9.0 +leanprover/lean4:v4.10.0-rc1 diff --git a/test/absurd.lean b/test/absurd.lean index 4974467e5a..1817c0e715 100644 --- a/test/absurd.lean +++ b/test/absurd.lean @@ -43,5 +43,5 @@ h : p → False ⊢ p -/ #guard_msgs in -example (h : p → False) : 0 = 3 := by +example {p : Prop} (h : p → False) : 0 = 3 := by absurd h diff --git a/test/congr.lean b/test/congr.lean index 5303fbd74b..a71aed0315 100644 --- a/test/congr.lean +++ b/test/congr.lean @@ -38,7 +38,7 @@ section -- Adaptation note: the next two examples have always failed if `List.ext` was in scope, -- but until nightly-2024-04-24 (when `List.ext` was upstreamed), it wasn't in scope. -- In order to preserve the test behaviour we locally remove the `ext` attribute. -attribute [-ext] List.ext +attribute [-ext] List.ext_getElem? private opaque List.sum : List Nat → Nat From bba0af6e930ebcbabfacf021b21dd881d58aaa9d Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 1 Jul 2024 16:20:32 +1000 Subject: [PATCH 094/208] chore: remove 'meta if' from lakefile (#869) --- lakefile.lean | 3 --- 1 file changed, 3 deletions(-) diff --git a/lakefile.lean b/lakefile.lean index a59342f68c..7ee5efafe6 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -18,9 +18,6 @@ lean_exe runLinter where srcDir := "scripts" supportInterpreter := true -meta if get_config? doc |>.isSome then -require «doc-gen4» from git "https://github.com/leanprover/doc-gen4" @ "main" - @[test_driver] lean_exe test where srcDir := "scripts" From 3bbfc984941dd25a4f9a08dffb968bae07f14cf4 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Mon, 1 Jul 2024 09:06:22 +0000 Subject: [PATCH 095/208] chore: bump to nightly-2024-07-01 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index eade7d1f7a..c73e540213 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-06-30 +leanprover/lean4:nightly-2024-07-01 From 43ed12be493fe4520677766aca695a4110e318e0 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 1 Jul 2024 21:09:28 +1000 Subject: [PATCH 096/208] . --- Batteries/Data/String/Lemmas.lean | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Batteries/Data/String/Lemmas.lean b/Batteries/Data/String/Lemmas.lean index ddfcf62ddd..1ea4e4f788 100644 --- a/Batteries/Data/String/Lemmas.lean +++ b/Batteries/Data/String/Lemmas.lean @@ -234,7 +234,8 @@ theorem utf8PrevAux_of_valid {cs cs' : List Char} {c : Char} {i p : Nat} theorem prev_of_valid (cs : List Char) (c : Char) (cs' : List Char) : prev ⟨cs ++ c :: cs'⟩ ⟨utf8Len cs + c.utf8Size⟩ = ⟨utf8Len cs⟩ := by - simp [prev]; refine (if_neg (Pos.ne_of_gt add_csize_pos)).trans ?_ + simp only [prev] + refine (if_neg (Pos.ne_of_gt add_csize_pos)).trans ?_ rw [utf8PrevAux_of_valid] <;> simp theorem prev_of_valid' (cs cs' : List Char) : @@ -322,12 +323,15 @@ theorem firstDiffPos_loop_eq (l₁ l₂ r₁ r₂ stop p) refine Nat.lt_min.2 ⟨?_, ?_⟩ <;> exact Nat.lt_add_of_pos_right add_csize_pos, show get ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = a by simp [hl₁, get_of_valid], show get ⟨l₂ ++ b :: r₂⟩ ⟨p⟩ = b by simp [hl₂, get_of_valid]] - simp; split <;> simp - subst b - rw [show next ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = ⟨utf8Len l₁ + a.utf8Size⟩ by simp [hl₁, next_of_valid]] - simpa [← hl₁, ← Nat.add_assoc, Nat.add_right_comm] using - firstDiffPos_loop_eq (l₁ ++ [a]) (l₂ ++ [a]) r₁ r₂ stop (p + a.utf8Size) - (by simp [hl₁]) (by simp [hl₂]) (by simp [hstop, ← Nat.add_assoc, Nat.add_right_comm]) + simp only [bne_iff_ne, ne_eq, ite_not, decide_eq_true_eq] + split + · simp only [utf8Len_cons] + subst b + rw [show next ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = ⟨utf8Len l₁ + a.utf8Size⟩ by simp [hl₁, next_of_valid]] + simpa [← hl₁, ← Nat.add_assoc, Nat.add_right_comm] using + firstDiffPos_loop_eq (l₁ ++ [a]) (l₂ ++ [a]) r₁ r₂ stop (p + a.utf8Size) + (by simp [hl₁]) (by simp [hl₂]) (by simp [hstop, ← Nat.add_assoc, Nat.add_right_comm]) + · simp · next h => rw [dif_neg] <;> simp [hstop, ← hl₁, ← hl₂, -Nat.not_lt, Nat.lt_min] intro h₁ h₂ From 141853159817b913f8da3da94c84f46f0a445bcd Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 1 Jul 2024 21:12:52 +1000 Subject: [PATCH 097/208] upstream --- Batteries/Data/Array/Basic.lean | 18 ------------ Batteries/Data/List.lean | 1 - Batteries/Data/List/Init/Attach.lean | 44 ---------------------------- Batteries/Data/List/Perm.lean | 3 -- Batteries/Data/Range/Lemmas.lean | 1 - 5 files changed, 67 deletions(-) delete mode 100644 Batteries/Data/List/Init/Attach.lean diff --git a/Batteries/Data/Array/Basic.lean b/Batteries/Data/Array/Basic.lean index 1dddea3c14..ad6b8129e6 100644 --- a/Batteries/Data/Array/Basic.lean +++ b/Batteries/Data/Array/Basic.lean @@ -3,7 +3,6 @@ Copyright (c) 2021 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino, Floris van Doorn, Jannis Limperg -/ -import Batteries.Data.List.Init.Attach import Batteries.Data.Array.Init.Lemmas /-! @@ -130,23 +129,6 @@ protected def maxI [ord : Ord α] [Inhabited α] (xs : Array α) (start := 0) (stop := xs.size) : α := xs.minI (ord := ord.opposite) start stop -/-- -Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of -`Array {x // P x}` is the same as the input `Array α`. --/ -@[inline] private unsafe def attachWithImpl - (xs : Array α) (P : α → Prop) (_ : ∀ x ∈ xs, P x) : Array {x // P x} := unsafeCast xs - -/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `xs` to produce a new array - with the same elements but in the type `{x // P x}`. -/ -@[implemented_by attachWithImpl] def attachWith - (xs : Array α) (P : α → Prop) (H : ∀ x ∈ xs, P x) : Array {x // P x} := - ⟨xs.data.attachWith P fun x h => H x (Array.Mem.mk h)⟩ - -/-- `O(1)`. "Attach" the proof that the elements of `xs` are in `xs` to produce a new array - with the same elements but in the type `{x // x ∈ xs}`. -/ -@[inline] def attach (xs : Array α) : Array {x // x ∈ xs} := xs.attachWith _ fun _ => id - /-- `O(|join L|)`. `join L` concatenates all the arrays in `L` into one array. * `join #[#[a], #[], #[b, c], #[d, e, f]] = #[a, b, c, d, e, f]` diff --git a/Batteries/Data/List.lean b/Batteries/Data/List.lean index d060ba89c8..998160b904 100644 --- a/Batteries/Data/List.lean +++ b/Batteries/Data/List.lean @@ -1,7 +1,6 @@ import Batteries.Data.List.Basic import Batteries.Data.List.Count import Batteries.Data.List.EraseIdx -import Batteries.Data.List.Init.Attach import Batteries.Data.List.Init.Lemmas import Batteries.Data.List.Lemmas import Batteries.Data.List.Pairwise diff --git a/Batteries/Data/List/Init/Attach.lean b/Batteries/Data/List/Init/Attach.lean deleted file mode 100644 index d2b2bf0990..0000000000 --- a/Batteries/Data/List/Init/Attach.lean +++ /dev/null @@ -1,44 +0,0 @@ -/- -Copyright (c) 2023 Mario Carneiro. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mario Carneiro --/ - -namespace List - -/-- `O(n)`. Partial map. If `f : Π a, P a → β` is a partial function defined on - `a : α` satisfying `P`, then `pmap f l h` is essentially the same as `map f l` - but is defined only when all members of `l` satisfy `P`, using the proof - to apply `f`. -/ -@[simp] def pmap {P : α → Prop} (f : ∀ a, P a → β) : ∀ l : List α, (H : ∀ a ∈ l, P a) → List β - | [], _ => [] - | a :: l, H => f a (forall_mem_cons.1 H).1 :: pmap f l (forall_mem_cons.1 H).2 - -/-- -Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of -`List {x // P x}` is the same as the input `List α`. -(Someday, the compiler might do this optimization automatically, but until then...) --/ -@[inline] private unsafe def attachWithImpl - (l : List α) (P : α → Prop) (_ : ∀ x ∈ l, P x) : List {x // P x} := unsafeCast l - -/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `l` to produce a new list - with the same elements but in the type `{x // P x}`. -/ -@[implemented_by attachWithImpl] def attachWith - (l : List α) (P : α → Prop) (H : ∀ x ∈ l, P x) : List {x // P x} := pmap Subtype.mk l H - -/-- `O(1)`. "Attach" the proof that the elements of `l` are in `l` to produce a new list - with the same elements but in the type `{x // x ∈ l}`. -/ -@[inline] def attach (l : List α) : List {x // x ∈ l} := attachWith l _ fun _ => id - -/-- Implementation of `pmap` using the zero-copy version of `attach`. -/ -@[inline] private def pmapImpl {P : α → Prop} (f : ∀ a, P a → β) (l : List α) (H : ∀ a ∈ l, P a) : - List β := (l.attachWith _ H).map fun ⟨x, h'⟩ => f x h' - -@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by - funext α β p f L h' - let rec go : ∀ L' (hL' : ∀ ⦃x⦄, x ∈ L' → p x), - pmap f L' hL' = map (fun ⟨x, hx⟩ => f x hx) (pmap Subtype.mk L' hL') - | nil, hL' => rfl - | cons _ L', hL' => congrArg _ <| go L' fun _ hx => hL' (.tail _ hx) - exact go L h' diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index ab12db10b1..49e45ecc8b 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -4,10 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ import Batteries.Tactic.Alias -import Batteries.Data.List.Init.Attach import Batteries.Data.List.Pairwise --- Adaptation note: nightly-2024-03-18. We should be able to remove this after nightly-2024-03-19. -import Lean.Elab.Tactic.Rfl /-! # List Permutations diff --git a/Batteries/Data/Range/Lemmas.lean b/Batteries/Data/Range/Lemmas.lean index 586f32a7e8..d71082848f 100644 --- a/Batteries/Data/Range/Lemmas.lean +++ b/Batteries/Data/Range/Lemmas.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro -/ import Batteries.Tactic.SeqFocus import Batteries.Data.List.Lemmas -import Batteries.Data.List.Init.Attach namespace Std.Range From 0682b7591187e8b13cd02fdc4e614bca2cd0f3a1 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 4 Jul 2024 09:43:31 +1000 Subject: [PATCH 098/208] chore: adaptations for nightly-2024-07-01 (#870) --- Batteries/Data/Array/Basic.lean | 18 ------------ Batteries/Data/List.lean | 1 - Batteries/Data/List/Init/Attach.lean | 44 ---------------------------- Batteries/Data/List/Perm.lean | 3 -- Batteries/Data/Range/Lemmas.lean | 1 - lean-toolchain | 2 +- 6 files changed, 1 insertion(+), 68 deletions(-) delete mode 100644 Batteries/Data/List/Init/Attach.lean diff --git a/Batteries/Data/Array/Basic.lean b/Batteries/Data/Array/Basic.lean index 1dddea3c14..ad6b8129e6 100644 --- a/Batteries/Data/Array/Basic.lean +++ b/Batteries/Data/Array/Basic.lean @@ -3,7 +3,6 @@ Copyright (c) 2021 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino, Floris van Doorn, Jannis Limperg -/ -import Batteries.Data.List.Init.Attach import Batteries.Data.Array.Init.Lemmas /-! @@ -130,23 +129,6 @@ protected def maxI [ord : Ord α] [Inhabited α] (xs : Array α) (start := 0) (stop := xs.size) : α := xs.minI (ord := ord.opposite) start stop -/-- -Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of -`Array {x // P x}` is the same as the input `Array α`. --/ -@[inline] private unsafe def attachWithImpl - (xs : Array α) (P : α → Prop) (_ : ∀ x ∈ xs, P x) : Array {x // P x} := unsafeCast xs - -/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `xs` to produce a new array - with the same elements but in the type `{x // P x}`. -/ -@[implemented_by attachWithImpl] def attachWith - (xs : Array α) (P : α → Prop) (H : ∀ x ∈ xs, P x) : Array {x // P x} := - ⟨xs.data.attachWith P fun x h => H x (Array.Mem.mk h)⟩ - -/-- `O(1)`. "Attach" the proof that the elements of `xs` are in `xs` to produce a new array - with the same elements but in the type `{x // x ∈ xs}`. -/ -@[inline] def attach (xs : Array α) : Array {x // x ∈ xs} := xs.attachWith _ fun _ => id - /-- `O(|join L|)`. `join L` concatenates all the arrays in `L` into one array. * `join #[#[a], #[], #[b, c], #[d, e, f]] = #[a, b, c, d, e, f]` diff --git a/Batteries/Data/List.lean b/Batteries/Data/List.lean index d060ba89c8..998160b904 100644 --- a/Batteries/Data/List.lean +++ b/Batteries/Data/List.lean @@ -1,7 +1,6 @@ import Batteries.Data.List.Basic import Batteries.Data.List.Count import Batteries.Data.List.EraseIdx -import Batteries.Data.List.Init.Attach import Batteries.Data.List.Init.Lemmas import Batteries.Data.List.Lemmas import Batteries.Data.List.Pairwise diff --git a/Batteries/Data/List/Init/Attach.lean b/Batteries/Data/List/Init/Attach.lean deleted file mode 100644 index d2b2bf0990..0000000000 --- a/Batteries/Data/List/Init/Attach.lean +++ /dev/null @@ -1,44 +0,0 @@ -/- -Copyright (c) 2023 Mario Carneiro. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mario Carneiro --/ - -namespace List - -/-- `O(n)`. Partial map. If `f : Π a, P a → β` is a partial function defined on - `a : α` satisfying `P`, then `pmap f l h` is essentially the same as `map f l` - but is defined only when all members of `l` satisfy `P`, using the proof - to apply `f`. -/ -@[simp] def pmap {P : α → Prop} (f : ∀ a, P a → β) : ∀ l : List α, (H : ∀ a ∈ l, P a) → List β - | [], _ => [] - | a :: l, H => f a (forall_mem_cons.1 H).1 :: pmap f l (forall_mem_cons.1 H).2 - -/-- -Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of -`List {x // P x}` is the same as the input `List α`. -(Someday, the compiler might do this optimization automatically, but until then...) --/ -@[inline] private unsafe def attachWithImpl - (l : List α) (P : α → Prop) (_ : ∀ x ∈ l, P x) : List {x // P x} := unsafeCast l - -/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `l` to produce a new list - with the same elements but in the type `{x // P x}`. -/ -@[implemented_by attachWithImpl] def attachWith - (l : List α) (P : α → Prop) (H : ∀ x ∈ l, P x) : List {x // P x} := pmap Subtype.mk l H - -/-- `O(1)`. "Attach" the proof that the elements of `l` are in `l` to produce a new list - with the same elements but in the type `{x // x ∈ l}`. -/ -@[inline] def attach (l : List α) : List {x // x ∈ l} := attachWith l _ fun _ => id - -/-- Implementation of `pmap` using the zero-copy version of `attach`. -/ -@[inline] private def pmapImpl {P : α → Prop} (f : ∀ a, P a → β) (l : List α) (H : ∀ a ∈ l, P a) : - List β := (l.attachWith _ H).map fun ⟨x, h'⟩ => f x h' - -@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by - funext α β p f L h' - let rec go : ∀ L' (hL' : ∀ ⦃x⦄, x ∈ L' → p x), - pmap f L' hL' = map (fun ⟨x, hx⟩ => f x hx) (pmap Subtype.mk L' hL') - | nil, hL' => rfl - | cons _ L', hL' => congrArg _ <| go L' fun _ hx => hL' (.tail _ hx) - exact go L h' diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index ab12db10b1..49e45ecc8b 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -4,10 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ import Batteries.Tactic.Alias -import Batteries.Data.List.Init.Attach import Batteries.Data.List.Pairwise --- Adaptation note: nightly-2024-03-18. We should be able to remove this after nightly-2024-03-19. -import Lean.Elab.Tactic.Rfl /-! # List Permutations diff --git a/Batteries/Data/Range/Lemmas.lean b/Batteries/Data/Range/Lemmas.lean index 586f32a7e8..d71082848f 100644 --- a/Batteries/Data/Range/Lemmas.lean +++ b/Batteries/Data/Range/Lemmas.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro -/ import Batteries.Tactic.SeqFocus import Batteries.Data.List.Lemmas -import Batteries.Data.List.Init.Attach namespace Std.Range diff --git a/lean-toolchain b/lean-toolchain index d69d1ed200..c73e540213 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.10.0-rc1 +leanprover/lean4:nightly-2024-07-01 From 114542a0395de4be93771c87b370723765f7a837 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 4 Jul 2024 11:21:01 +1000 Subject: [PATCH 099/208] Remove upstreamed --- Batteries/Data/Char.lean | 5 ----- lean-toolchain | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Batteries/Data/Char.lean b/Batteries/Data/Char.lean index 5a9110ae12..4f3c59ef0b 100644 --- a/Batteries/Data/Char.lean +++ b/Batteries/Data/Char.lean @@ -6,11 +6,6 @@ Authors: Jannis Limperg import Batteries.Data.UInt import Batteries.Tactic.Alias -@[ext] theorem Char.ext : {a b : Char} → a.val = b.val → a = b - | ⟨_,_⟩, ⟨_,_⟩, rfl => rfl - -theorem Char.ext_iff {x y : Char} : x = y ↔ x.val = y.val := ⟨congrArg _, Char.ext⟩ - theorem Char.le_antisymm_iff {x y : Char} : x = y ↔ x ≤ y ∧ y ≤ x := Char.ext_iff.trans UInt32.le_antisymm_iff diff --git a/lean-toolchain b/lean-toolchain index c73e540213..449ee76948 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-01 +leanprover/lean4:nightly-2024-07-03 From 41d25d65c6d8cf5dfae8e2685c3a353da653c322 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 4 Jul 2024 11:24:00 +1000 Subject: [PATCH 100/208] more --- Batteries/Data/HashMap/WF.lean | 4 ++-- Batteries/Data/List/Lemmas.lean | 13 ++++--------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index f6298d3322..bc565bc037 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -24,7 +24,7 @@ theorem exists_of_update (self : Buckets α β) (i d h) : ∃ l₁ l₂, self.1.data = l₁ ++ self.1[i] :: l₂ ∧ List.length l₁ = i.toNat ∧ (self.update i d h).1.data = l₁ ++ d :: l₂ := by simp only [Array.data_length, Array.ugetElem_eq_getElem, Array.getElem_eq_data_getElem] - exact List.exists_of_set' h + exact List.exists_of_set h theorem update_update (self : Buckets α β) (i d d' h h') : (self.update i d h).update i d' h' = self.update i d' h := by @@ -99,7 +99,7 @@ where · cases source.data[j]? <;> rfl · next H => exact hs _ (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ hj) (Ne.symm H)) · case b => - refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set' H; eq ▸ ?_ + refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set H; eq ▸ ?_ rw [h₁] simp only [Buckets.size_eq, List.map_append, List.map_cons, AssocList.toList, List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length] diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 44d9a5c18d..ea97429b67 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -405,14 +405,13 @@ theorem modifyNth_eq_set_get (f : α → α) {n} {l : List α} (h) : l.modifyNth f n = l.set n (f (l.get ⟨n, h⟩)) := by rw [modifyNth_eq_set_get?, get?_eq_get h]; rfl -theorem exists_of_set {l : List α} (h : n < l.length) : +-- The naming of `exists_of_set'` and `exists_of_set` have been swapped. +-- If no one complains, we will remove this version later. +@[deprecated exists_of_set (since := "2024-07-04")] +theorem exists_of_set' {l : List α} (h : n < l.length) : ∃ l₁ a l₂, l = l₁ ++ a :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := by rw [set_eq_modifyNth]; exact exists_of_modifyNth _ h -theorem exists_of_set' {l : List α} (h : n < l.length) : - ∃ l₁ l₂, l = l₁ ++ l[n] :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := - have ⟨_, _, _, h₁, h₂, h₃⟩ := exists_of_set h; ⟨_, _, getElem_of_append h₁ h₂ ▸ h₁, h₂, h₃⟩ - @[simp] theorem getElem?_set_eq' (a : α) (n) (l : List α) : (set l n a)[n]? = (fun _ => a) <$> l[n]? := by simp only [set_eq_modifyNth, getElem?_modifyNth_eq] @@ -450,10 +449,6 @@ 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 [getElem?_set]; split <;> subst_vars <;> simp [*, getElem?_eq_getElem h] -theorem drop_set_of_lt (a : α) {n m : Nat} (l : List α) (h : n < m) : - (l.set n a).drop m = l.drop m := - List.ext_getElem? fun i => by rw [getElem?_drop, getElem?_drop, getElem?_set_ne (by omega)] - theorem take_set_of_lt (a : α) {n m : Nat} (l : List α) (h : m < n) : (l.set n a).take m = l.take m := List.ext_getElem? fun i => by From dc4a6b1ac3cd502988e283d5c9c5fdf261125a07 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 4 Jul 2024 17:08:55 +1000 Subject: [PATCH 101/208] Revert 'chore: adaptations for nightly-2024-07-01 (#870)' (#872) * Revert 'chore: adaptations for nightly-2024-07-01 (#870)' * Revert 'chore: adaptations for nightly-2024-07-01 (#870)' --- Batteries/Data/Array/Basic.lean | 18 ++++++++++++ Batteries/Data/List.lean | 1 + Batteries/Data/List/Init/Attach.lean | 44 ++++++++++++++++++++++++++++ Batteries/Data/List/Perm.lean | 3 ++ Batteries/Data/Range/Lemmas.lean | 1 + lean-toolchain | 2 +- 6 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 Batteries/Data/List/Init/Attach.lean diff --git a/Batteries/Data/Array/Basic.lean b/Batteries/Data/Array/Basic.lean index ad6b8129e6..1dddea3c14 100644 --- a/Batteries/Data/Array/Basic.lean +++ b/Batteries/Data/Array/Basic.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino, Floris van Doorn, Jannis Limperg -/ +import Batteries.Data.List.Init.Attach import Batteries.Data.Array.Init.Lemmas /-! @@ -129,6 +130,23 @@ protected def maxI [ord : Ord α] [Inhabited α] (xs : Array α) (start := 0) (stop := xs.size) : α := xs.minI (ord := ord.opposite) start stop +/-- +Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of +`Array {x // P x}` is the same as the input `Array α`. +-/ +@[inline] private unsafe def attachWithImpl + (xs : Array α) (P : α → Prop) (_ : ∀ x ∈ xs, P x) : Array {x // P x} := unsafeCast xs + +/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `xs` to produce a new array + with the same elements but in the type `{x // P x}`. -/ +@[implemented_by attachWithImpl] def attachWith + (xs : Array α) (P : α → Prop) (H : ∀ x ∈ xs, P x) : Array {x // P x} := + ⟨xs.data.attachWith P fun x h => H x (Array.Mem.mk h)⟩ + +/-- `O(1)`. "Attach" the proof that the elements of `xs` are in `xs` to produce a new array + with the same elements but in the type `{x // x ∈ xs}`. -/ +@[inline] def attach (xs : Array α) : Array {x // x ∈ xs} := xs.attachWith _ fun _ => id + /-- `O(|join L|)`. `join L` concatenates all the arrays in `L` into one array. * `join #[#[a], #[], #[b, c], #[d, e, f]] = #[a, b, c, d, e, f]` diff --git a/Batteries/Data/List.lean b/Batteries/Data/List.lean index 998160b904..d060ba89c8 100644 --- a/Batteries/Data/List.lean +++ b/Batteries/Data/List.lean @@ -1,6 +1,7 @@ import Batteries.Data.List.Basic import Batteries.Data.List.Count import Batteries.Data.List.EraseIdx +import Batteries.Data.List.Init.Attach import Batteries.Data.List.Init.Lemmas import Batteries.Data.List.Lemmas import Batteries.Data.List.Pairwise diff --git a/Batteries/Data/List/Init/Attach.lean b/Batteries/Data/List/Init/Attach.lean new file mode 100644 index 0000000000..d2b2bf0990 --- /dev/null +++ b/Batteries/Data/List/Init/Attach.lean @@ -0,0 +1,44 @@ +/- +Copyright (c) 2023 Mario Carneiro. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro +-/ + +namespace List + +/-- `O(n)`. Partial map. If `f : Π a, P a → β` is a partial function defined on + `a : α` satisfying `P`, then `pmap f l h` is essentially the same as `map f l` + but is defined only when all members of `l` satisfy `P`, using the proof + to apply `f`. -/ +@[simp] def pmap {P : α → Prop} (f : ∀ a, P a → β) : ∀ l : List α, (H : ∀ a ∈ l, P a) → List β + | [], _ => [] + | a :: l, H => f a (forall_mem_cons.1 H).1 :: pmap f l (forall_mem_cons.1 H).2 + +/-- +Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of +`List {x // P x}` is the same as the input `List α`. +(Someday, the compiler might do this optimization automatically, but until then...) +-/ +@[inline] private unsafe def attachWithImpl + (l : List α) (P : α → Prop) (_ : ∀ x ∈ l, P x) : List {x // P x} := unsafeCast l + +/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `l` to produce a new list + with the same elements but in the type `{x // P x}`. -/ +@[implemented_by attachWithImpl] def attachWith + (l : List α) (P : α → Prop) (H : ∀ x ∈ l, P x) : List {x // P x} := pmap Subtype.mk l H + +/-- `O(1)`. "Attach" the proof that the elements of `l` are in `l` to produce a new list + with the same elements but in the type `{x // x ∈ l}`. -/ +@[inline] def attach (l : List α) : List {x // x ∈ l} := attachWith l _ fun _ => id + +/-- Implementation of `pmap` using the zero-copy version of `attach`. -/ +@[inline] private def pmapImpl {P : α → Prop} (f : ∀ a, P a → β) (l : List α) (H : ∀ a ∈ l, P a) : + List β := (l.attachWith _ H).map fun ⟨x, h'⟩ => f x h' + +@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by + funext α β p f L h' + let rec go : ∀ L' (hL' : ∀ ⦃x⦄, x ∈ L' → p x), + pmap f L' hL' = map (fun ⟨x, hx⟩ => f x hx) (pmap Subtype.mk L' hL') + | nil, hL' => rfl + | cons _ L', hL' => congrArg _ <| go L' fun _ hx => hL' (.tail _ hx) + exact go L h' diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index 49e45ecc8b..ab12db10b1 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -4,7 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ import Batteries.Tactic.Alias +import Batteries.Data.List.Init.Attach import Batteries.Data.List.Pairwise +-- Adaptation note: nightly-2024-03-18. We should be able to remove this after nightly-2024-03-19. +import Lean.Elab.Tactic.Rfl /-! # List Permutations diff --git a/Batteries/Data/Range/Lemmas.lean b/Batteries/Data/Range/Lemmas.lean index d71082848f..586f32a7e8 100644 --- a/Batteries/Data/Range/Lemmas.lean +++ b/Batteries/Data/Range/Lemmas.lean @@ -5,6 +5,7 @@ Authors: Mario Carneiro -/ import Batteries.Tactic.SeqFocus import Batteries.Data.List.Lemmas +import Batteries.Data.List.Init.Attach namespace Std.Range diff --git a/lean-toolchain b/lean-toolchain index c73e540213..d69d1ed200 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-01 +leanprover/lean4:v4.10.0-rc1 From e2cf122bda7439a3539a7e2ef14766e83f444876 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 5 Jul 2024 08:57:59 +1000 Subject: [PATCH 102/208] chore: adaptations for nightly-2024-07-01 (#873) --- Batteries/Data/Array/Basic.lean | 18 ------------ Batteries/Data/List.lean | 1 - Batteries/Data/List/Init/Attach.lean | 44 ---------------------------- Batteries/Data/List/Perm.lean | 3 -- Batteries/Data/Range/Lemmas.lean | 1 - lean-toolchain | 2 +- 6 files changed, 1 insertion(+), 68 deletions(-) delete mode 100644 Batteries/Data/List/Init/Attach.lean diff --git a/Batteries/Data/Array/Basic.lean b/Batteries/Data/Array/Basic.lean index 1dddea3c14..ad6b8129e6 100644 --- a/Batteries/Data/Array/Basic.lean +++ b/Batteries/Data/Array/Basic.lean @@ -3,7 +3,6 @@ Copyright (c) 2021 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino, Floris van Doorn, Jannis Limperg -/ -import Batteries.Data.List.Init.Attach import Batteries.Data.Array.Init.Lemmas /-! @@ -130,23 +129,6 @@ protected def maxI [ord : Ord α] [Inhabited α] (xs : Array α) (start := 0) (stop := xs.size) : α := xs.minI (ord := ord.opposite) start stop -/-- -Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of -`Array {x // P x}` is the same as the input `Array α`. --/ -@[inline] private unsafe def attachWithImpl - (xs : Array α) (P : α → Prop) (_ : ∀ x ∈ xs, P x) : Array {x // P x} := unsafeCast xs - -/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `xs` to produce a new array - with the same elements but in the type `{x // P x}`. -/ -@[implemented_by attachWithImpl] def attachWith - (xs : Array α) (P : α → Prop) (H : ∀ x ∈ xs, P x) : Array {x // P x} := - ⟨xs.data.attachWith P fun x h => H x (Array.Mem.mk h)⟩ - -/-- `O(1)`. "Attach" the proof that the elements of `xs` are in `xs` to produce a new array - with the same elements but in the type `{x // x ∈ xs}`. -/ -@[inline] def attach (xs : Array α) : Array {x // x ∈ xs} := xs.attachWith _ fun _ => id - /-- `O(|join L|)`. `join L` concatenates all the arrays in `L` into one array. * `join #[#[a], #[], #[b, c], #[d, e, f]] = #[a, b, c, d, e, f]` diff --git a/Batteries/Data/List.lean b/Batteries/Data/List.lean index d060ba89c8..998160b904 100644 --- a/Batteries/Data/List.lean +++ b/Batteries/Data/List.lean @@ -1,7 +1,6 @@ import Batteries.Data.List.Basic import Batteries.Data.List.Count import Batteries.Data.List.EraseIdx -import Batteries.Data.List.Init.Attach import Batteries.Data.List.Init.Lemmas import Batteries.Data.List.Lemmas import Batteries.Data.List.Pairwise diff --git a/Batteries/Data/List/Init/Attach.lean b/Batteries/Data/List/Init/Attach.lean deleted file mode 100644 index d2b2bf0990..0000000000 --- a/Batteries/Data/List/Init/Attach.lean +++ /dev/null @@ -1,44 +0,0 @@ -/- -Copyright (c) 2023 Mario Carneiro. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mario Carneiro --/ - -namespace List - -/-- `O(n)`. Partial map. If `f : Π a, P a → β` is a partial function defined on - `a : α` satisfying `P`, then `pmap f l h` is essentially the same as `map f l` - but is defined only when all members of `l` satisfy `P`, using the proof - to apply `f`. -/ -@[simp] def pmap {P : α → Prop} (f : ∀ a, P a → β) : ∀ l : List α, (H : ∀ a ∈ l, P a) → List β - | [], _ => [] - | a :: l, H => f a (forall_mem_cons.1 H).1 :: pmap f l (forall_mem_cons.1 H).2 - -/-- -Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of -`List {x // P x}` is the same as the input `List α`. -(Someday, the compiler might do this optimization automatically, but until then...) --/ -@[inline] private unsafe def attachWithImpl - (l : List α) (P : α → Prop) (_ : ∀ x ∈ l, P x) : List {x // P x} := unsafeCast l - -/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `l` to produce a new list - with the same elements but in the type `{x // P x}`. -/ -@[implemented_by attachWithImpl] def attachWith - (l : List α) (P : α → Prop) (H : ∀ x ∈ l, P x) : List {x // P x} := pmap Subtype.mk l H - -/-- `O(1)`. "Attach" the proof that the elements of `l` are in `l` to produce a new list - with the same elements but in the type `{x // x ∈ l}`. -/ -@[inline] def attach (l : List α) : List {x // x ∈ l} := attachWith l _ fun _ => id - -/-- Implementation of `pmap` using the zero-copy version of `attach`. -/ -@[inline] private def pmapImpl {P : α → Prop} (f : ∀ a, P a → β) (l : List α) (H : ∀ a ∈ l, P a) : - List β := (l.attachWith _ H).map fun ⟨x, h'⟩ => f x h' - -@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by - funext α β p f L h' - let rec go : ∀ L' (hL' : ∀ ⦃x⦄, x ∈ L' → p x), - pmap f L' hL' = map (fun ⟨x, hx⟩ => f x hx) (pmap Subtype.mk L' hL') - | nil, hL' => rfl - | cons _ L', hL' => congrArg _ <| go L' fun _ hx => hL' (.tail _ hx) - exact go L h' diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index ab12db10b1..49e45ecc8b 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -4,10 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ import Batteries.Tactic.Alias -import Batteries.Data.List.Init.Attach import Batteries.Data.List.Pairwise --- Adaptation note: nightly-2024-03-18. We should be able to remove this after nightly-2024-03-19. -import Lean.Elab.Tactic.Rfl /-! # List Permutations diff --git a/Batteries/Data/Range/Lemmas.lean b/Batteries/Data/Range/Lemmas.lean index 586f32a7e8..d71082848f 100644 --- a/Batteries/Data/Range/Lemmas.lean +++ b/Batteries/Data/Range/Lemmas.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro -/ import Batteries.Tactic.SeqFocus import Batteries.Data.List.Lemmas -import Batteries.Data.List.Init.Attach namespace Std.Range diff --git a/lean-toolchain b/lean-toolchain index d69d1ed200..c73e540213 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.10.0-rc1 +leanprover/lean4:nightly-2024-07-01 From 1b70d455a1b6a40b4baeaf7f73c7f26a8642970d Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 5 Jul 2024 09:05:58 +0000 Subject: [PATCH 103/208] chore: bump to nightly-2024-07-05 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 449ee76948..4d6c808eba 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-03 +leanprover/lean4:nightly-2024-07-05 From d002283658459366c6b21e8d85f761861dac24e6 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 5 Jul 2024 19:25:23 +0000 Subject: [PATCH 104/208] Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/4658 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 4d6c808eba..51bbd671fa 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-05 +leanprover/lean4-pr-releases:pr-release-4658 From 9cbf18e129b8721aa0841e04d89fcd36fbcf6de8 Mon Sep 17 00:00:00 2001 From: Joachim Breitner Date: Fri, 5 Jul 2024 22:42:25 +0200 Subject: [PATCH 105/208] chore: more autoDecls; adaption to https://github.com/leanprover/lean4/pull/4658 --- Batteries/Tactic/Lint/Basic.lean | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Batteries/Tactic/Lint/Basic.lean b/Batteries/Tactic/Lint/Basic.lean index 87cc925a06..948bab5456 100644 --- a/Batteries/Tactic/Lint/Basic.lean +++ b/Batteries/Tactic/Lint/Basic.lean @@ -42,6 +42,8 @@ def isAutoDecl (decl : Name) : CoreM Bool := do if env.isConstructor n && ["injEq", "inj", "sizeOf_spec"].any (· == s) then return true if let ConstantInfo.inductInfo _ := (← getEnv).find? n then + if s.startsWith "brecOn_" || s.startsWith "below_" || s.startsWith "binductionOn_" + || s.startsWith "ibelow_" then return true if [casesOnSuffix, recOnSuffix, brecOnSuffix, binductionOnSuffix, belowSuffix, "ibelow", "ndrec", "ndrecOn", "noConfusionType", "noConfusion", "ofNat", "toCtorIdx" ].any (· == s) then From db125c954a3469b04e0e789a168e13324e57e57e Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sun, 7 Jul 2024 09:05:28 +0000 Subject: [PATCH 106/208] chore: bump to nightly-2024-07-07 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 4d6c808eba..b354fd7a27 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-05 +leanprover/lean4:nightly-2024-07-07 From 9496541a88f4a9e906870434b1c7c12aa3524f00 Mon Sep 17 00:00:00 2001 From: Markus Himmel Date: Mon, 8 Jul 2024 17:31:05 +0200 Subject: [PATCH 107/208] chore: remove `proof_wanted` in HashMap.Lemmas (#874) --- Batteries/Data/HashMap/Lemmas.lean | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Batteries/Data/HashMap/Lemmas.lean b/Batteries/Data/HashMap/Lemmas.lean index 50efb40455..290f4c0cff 100644 --- a/Batteries/Data/HashMap/Lemmas.lean +++ b/Batteries/Data/HashMap/Lemmas.lean @@ -5,7 +5,13 @@ Authors: Scott Morrison -/ import Batteries.Data.HashMap.Basic import Batteries.Data.Array.Lemmas -import Batteries.Util.ProofWanted + +/-! +# Lemmas for `Batteries.HashMap` + +Note that Lean core provides an alternative hash map implementation, `Std.HashMap`, which comes with +more lemmas. See the module `Std.Data.HashMap.Lemmas`. +-/ namespace Batteries.HashMap @@ -21,5 +27,7 @@ end Imp @[simp] theorem empty_find? [BEq α] [Hashable α] {a : α} : (∅ : HashMap α β).find? a = none := by simp [find?, Imp.find?] -proof_wanted insert_find? [BEq α] [Hashable α] (m : HashMap α β) (a a' : α) (b : β) : - (m.insert a b).find? a' = if a' == a then some b else m.find? a' +-- `Std.HashMap` has this lemma (as `getElem?_insert`) and many more, so working on this +-- `proof_wanted` is likely not a good use of your time. +-- proof_wanted insert_find? [BEq α] [Hashable α] (m : HashMap α β) (a a' : α) (b : β) : +-- (m.insert a b).find? a' = if a' == a then some b else m.find? a' From 920a09209f3eff179ff2555e9809748f87606c62 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 9 Jul 2024 01:31:46 +1000 Subject: [PATCH 108/208] chore: remove nonterminal simps in UnionFind (#868) --- Batteries/Data/UnionFind/Basic.lean | 104 ++++++++++++++++++---------- 1 file changed, 68 insertions(+), 36 deletions(-) diff --git a/Batteries/Data/UnionFind/Basic.lean b/Batteries/Data/UnionFind/Basic.lean index 24966452c2..292f4285eb 100644 --- a/Batteries/Data/UnionFind/Basic.lean +++ b/Batteries/Data/UnionFind/Basic.lean @@ -46,13 +46,17 @@ theorem lt_of_parentD : parentD arr i ≠ i → i < arr.size := theorem parentD_set {arr : Array UFNode} {x v i} : parentD (arr.set x v) i = if x.1 = i then v.parent else parentD arr i := by - rw [parentD]; simp [Array.get_eq_getElem, parentD] - split <;> [split <;> simp [Array.get_set, *]; split <;> [(subst i; cases ‹¬_› x.2); rfl]] + rw [parentD]; simp only [Array.size_set, Array.get_eq_getElem, parentD] + split + · split <;> simp_all + · split <;> [(subst i; cases ‹¬_› x.2); rfl] theorem rankD_set {arr : Array UFNode} {x v i} : rankD (arr.set x v) i = if x.1 = i then v.rank else rankD arr i := by - rw [rankD]; simp [Array.get_eq_getElem, rankD] - split <;> [split <;> simp [Array.get_set, *]; split <;> [(subst i; cases ‹¬_› x.2); rfl]] + rw [rankD]; simp only [Array.size_set, Array.get_eq_getElem, rankD] + split + · split <;> simp_all + · split <;> [(subst i; cases ‹¬_› x.2); rfl] end UnionFind @@ -146,7 +150,7 @@ theorem rank'_lt_rankMax (self : UnionFind) (i : Fin self.size) : let rec go : ∀ {l} {x : UFNode}, x ∈ l → x.rank ≤ List.foldr (max ·.rank) 0 l | a::l, _, List.Mem.head _ => by dsimp; apply Nat.le_max_left | a::l, _, .tail _ h => by dsimp; exact Nat.le_trans (go h) (Nat.le_max_right ..) - simp [rankMax, Array.foldr_eq_foldr_data] + simp only [Array.get_eq_getElem, rankMax, Array.foldr_eq_foldr_data] exact Nat.lt_succ.2 <| go (self.arr.data.get_mem i.1 i.2) theorem rankD_lt_rankMax (self : UnionFind) (i : Nat) : @@ -156,11 +160,11 @@ theorem rankD_lt_rankMax (self : UnionFind) (i : Nat) : theorem lt_rankMax (self : UnionFind) (i : Nat) : self.rank i < self.rankMax := rankD_lt_rankMax .. theorem push_rankD (arr : Array UFNode) : rankD (arr.push ⟨arr.size, 0⟩) i = rankD arr i := by - simp [rankD, Array.get_eq_getElem, Array.get_push] + simp only [rankD, Array.size_push, Array.get_eq_getElem, Array.get_push, dite_eq_ite] split <;> split <;> first | simp | cases ‹¬_› (Nat.lt_succ_of_lt ‹_›) theorem push_parentD (arr : Array UFNode) : parentD (arr.push ⟨arr.size, 0⟩) i = parentD arr i := by - simp [parentD, Array.get_eq_getElem, Array.get_push] + simp only [parentD, Array.size_push, Array.get_eq_getElem, Array.get_push, dite_eq_ite] split <;> split <;> try simp · exact Nat.le_antisymm (Nat.ge_of_not_lt ‹_›) (Nat.le_of_lt_succ ‹_›) · cases ‹¬_› (Nat.lt_succ_of_lt ‹_›) @@ -169,9 +173,9 @@ theorem push_parentD (arr : Array UFNode) : parentD (arr.push ⟨arr.size, 0⟩) def push (self : UnionFind) : UnionFind where arr := self.arr.push ⟨self.arr.size, 0⟩ parentD_lt {i} := by - simp [push_parentD]; simp [parentD] + simp only [Array.size_push, push_parentD]; simp only [parentD, Array.get_eq_getElem] split <;> [exact fun _ => Nat.lt_succ_of_lt (self.parent'_lt _); exact id] - rankD_lt := by simp [push_parentD, push_rankD]; exact self.rank_lt + rankD_lt := by simp only [push_parentD, ne_eq, push_rankD]; exact self.rank_lt /-- Root of a union-find node. -/ def root (self : UnionFind) (x : Fin self.size) : Fin self.size := @@ -205,18 +209,23 @@ termination_by self.rankMax - self.rank x theorem parent_rootD (self : UnionFind) (x : Nat) : self.parent (self.rootD x) = self.rootD x := by - rw [rootD]; split <;> - [simp [parentD, parent_root, -Array.get_eq_getElem]; simp [parentD_of_not_lt, *]] + rw [rootD] + split + · simp [parentD, parent_root, -Array.get_eq_getElem] + · simp [parentD_of_not_lt, *] @[nolint unusedHavesSuffices] theorem rootD_parent (self : UnionFind) (x : Nat) : self.rootD (self.parent x) = self.rootD x := by - simp [rootD, parent_lt]; split <;> simp [parentD, parentD_of_not_lt, *, -Array.get_eq_getElem] - (conv => rhs; rw [root]); split - · rw [root, dif_pos] <;> simp [*, -Array.get_eq_getElem] - · simp + simp only [rootD, Array.data_length, parent_lt] + split + · simp only [parentD, ↓reduceDIte, *] + (conv => rhs; rw [root]); split + · rw [root, dif_pos] <;> simp_all + · simp + · simp only [not_false_eq_true, parentD_of_not_lt, *] theorem rootD_lt {self : UnionFind} {x : Nat} : self.rootD x < self.size ↔ x < self.size := by - simp [rootD]; split <;> simp [*] + simp only [rootD, Array.data_length]; split <;> simp [*] @[nolint unusedHavesSuffices] theorem rootD_eq_self {self : UnionFind} {x : Nat} : self.rootD x = x ↔ self.parent x = x := by @@ -273,7 +282,9 @@ termination_by self.rankMax - self.rank x @[nolint unusedHavesSuffices] theorem findAux_root {self : UnionFind} {x : Fin self.size} : (findAux self x).root = self.root x := by - rw [findAux, root]; simp; split <;> simp + rw [findAux, root] + simp only [Array.data_length, Array.get_eq_getElem, dite_eq_ite] + split <;> simp only have := Nat.sub_lt_sub_left (self.lt_rankMax x) (self.rank'_lt _ ‹_›) exact findAux_root termination_by self.rankMax - self.rank x @@ -286,7 +297,7 @@ theorem findAux_s {self : UnionFind} {x : Fin self.size} : rw [show self.rootD _ = (self.findAux ⟨_, self.parent'_lt x⟩).root from _] · rw [findAux]; split <;> rfl · rw [← rootD_parent, parent, parentD_eq] - simp [findAux_root, rootD] + simp only [rootD, Array.get_eq_getElem, Array.data_length, findAux_root] apply dif_pos exact parent'_lt .. @@ -299,7 +310,8 @@ theorem rankD_findAux {self : UnionFind} {x : Fin self.size} : rw [rankD_eq' (by simp [FindAux.size_eq, h]), Array.get_modify (by rwa [FindAux.size_eq])] split <;> simp [← rankD_eq, rankD_findAux (x := ⟨_, self.parent'_lt x⟩), -Array.get_eq_getElem] else - simp [rank, rankD]; rw [dif_neg (by rwa [FindAux.size_eq]), dif_neg h] + simp only [rankD, Array.data_length, Array.get_eq_getElem, rank] + rw [dif_neg (by rwa [FindAux.size_eq]), dif_neg h] termination_by self.rankMax - self.rank x theorem parentD_findAux {self : UnionFind} {x : Fin self.size} : @@ -311,7 +323,7 @@ theorem parentD_findAux {self : UnionFind} {x : Fin self.size} : · next h => rw [parentD]; split <;> rename_i h' · rw [Array.get_modify (by simpa using h')] - simp [@eq_comm _ i, -Array.get_eq_getElem] + simp only [Array.data_length, @eq_comm _ i] split <;> simp [← parentD_eq, -Array.get_eq_getElem] · rw [if_neg (mt (by rintro rfl; simp [FindAux.size_eq]) h')] rw [parentD, dif_neg]; simpa using h' @@ -330,9 +342,11 @@ theorem parentD_findAux_lt {self : UnionFind} {x : Fin self.size} (h : i < self. if h' : (self.arr.get x).parent = x then rw [findAux_s, if_pos h']; apply self.parentD_lt h else - rw [parentD_findAux]; split <;> [simp [rootD_lt]; skip] - have := Nat.sub_lt_sub_left (self.lt_rankMax x) (self.rank'_lt _ ‹_›) - apply parentD_findAux_lt h + rw [parentD_findAux] + split + · simp [rootD_lt] + · have := Nat.sub_lt_sub_left (self.lt_rankMax x) (self.rank'_lt _ ‹_›) + apply parentD_findAux_lt h termination_by self.rankMax - self.rank x theorem parentD_findAux_or (self : UnionFind) (x : Fin self.size) (i) : @@ -341,10 +355,12 @@ theorem parentD_findAux_or (self : UnionFind) (x : Fin self.size) (i) : if h' : (self.arr.get x).parent = x then rw [findAux_s, if_pos h']; exact .inr rfl else - rw [parentD_findAux]; split <;> [simp [*]; skip] - have := Nat.sub_lt_sub_left (self.lt_rankMax x) (self.rank'_lt _ ‹_›) - exact (parentD_findAux_or self ⟨_, self.parent'_lt x⟩ i).imp_left <| .imp_right fun h => by - simp only [h, ← parentD_eq, rootD_parent, Array.data_length] + rw [parentD_findAux] + split + · simp [*] + · have := Nat.sub_lt_sub_left (self.lt_rankMax x) (self.rank'_lt _ ‹_›) + exact (parentD_findAux_or self ⟨_, self.parent'_lt x⟩ i).imp_left <| .imp_right fun h => by + simp only [h, ← parentD_eq, rootD_parent, Array.data_length] termination_by self.rankMax - self.rank x theorem lt_rankD_findAux {self : UnionFind} {x : Fin self.size} : @@ -365,7 +381,9 @@ def find (self : UnionFind) (x : Fin self.size) : let r := self.findAux x { 1.arr := r.s 2.1.val := r.root - 1.parentD_lt := fun h => by simp [FindAux.size_eq] at *; exact parentD_findAux_lt h + 1.parentD_lt := fun h => by + simp only [Array.data_length, FindAux.size_eq] at * + exact parentD_findAux_lt h 1.rankD_lt := fun h => by rw [rankD_findAux, rankD_findAux]; exact lt_rankD_findAux h 2.1.isLt := show _ < r.s.size by rw [r.size_eq]; exact r.root.2 2.2 := by simp [size, r.size_eq] } @@ -398,7 +416,8 @@ def findD (self : UnionFind) (x : Nat) : UnionFind × Nat := @[simp] theorem find_parent_1 (self : UnionFind) (x : Fin self.size) : (self.find x).1.parent x = self.rootD x := by - simp [find, parent]; rw [parentD_findAux, if_pos rfl] + simp only [parent, Array.data_length, find] + rw [parentD_findAux, if_pos rfl] theorem find_parent_or (self : UnionFind) (x : Fin self.size) (i) : (self.find x).1.parent i = self.rootD i ∧ self.rootD i = self.rootD x ∨ @@ -449,7 +468,8 @@ theorem setParentBump_rankD_lt {arr : Array UFNode} {x y : Fin arr.size} simp [hP, hR, -Array.get_eq_getElem] at *; split <;> rename_i h₁ <;> [simp [← h₁]; skip] <;> split <;> rename_i h₂ <;> intro h · simp [h₂] at h - · simp [rankD_eq]; split <;> rename_i h₃ + · simp only [rankD_eq, Array.get_eq_getElem] + split <;> rename_i h₃ · rw [← h₃]; apply Nat.lt_succ_self · exact Nat.lt_of_le_of_ne H h₃ · cases h₂.1 @@ -469,13 +489,16 @@ theorem setParent_rankD_lt {arr : Array UFNode} {x y : Fin arr.size} (by simp [rankD_set, Nat.ne_of_lt h, rankD_eq, -Array.get_eq_getElem]) @[simp] theorem linkAux_size : (linkAux self x y).size = self.size := by - simp [linkAux]; split <;> [rfl; split] <;> [skip; split] <;> simp + simp only [linkAux, Array.get_eq_getElem] + split <;> [rfl; split] <;> [skip; split] <;> simp /-- Link a union-find node to a root node. -/ def link (self : UnionFind) (x y : Fin self.size) (yroot : self.parent y = y) : UnionFind where arr := linkAux self.arr x y parentD_lt h := by - simp at *; simp [linkAux]; split <;> [skip; split <;> [skip; split]] + simp only [Array.data_length, linkAux_size] at * + simp only [linkAux, Array.get_eq_getElem] + split <;> [skip; split <;> [skip; split]] · exact self.parentD_lt h · rw [parentD_set]; split <;> [exact x.2; exact self.parentD_lt h] · rw [parentD_set]; split @@ -484,12 +507,21 @@ def link (self : UnionFind) (x y : Fin self.size) (yroot : self.parent y = y) : · rw [parentD_set]; split <;> [exact y.2; exact self.parentD_lt h] rankD_lt := by rw [parent, parentD_eq] at yroot - simp [linkAux]; split <;> [skip; split <;> [skip; split]] + simp only [linkAux, Array.get_eq_getElem, ne_eq] + split <;> [skip; split <;> [skip; split]] · exact self.rankD_lt · exact setParent_rankD_lt ‹_› self.rankD_lt - · refine setParentBump_rankD_lt (.inr yroot) (Nat.le_of_eq ‹_›) self.rankD_lt - (by simp [parentD_set]; rintro rfl; simp [*, parentD_eq]) fun {i} => ?_ - simp [rankD_set]; split <;> simp [*]; rintro rfl; simp [rankD_eq, *] + · refine setParentBump_rankD_lt (.inr yroot) (Nat.le_of_eq ‹_›) self.rankD_lt (by + simp only [parentD_set, ite_eq_right_iff] + rintro rfl + simp [*, parentD_eq]) fun {i} => ?_ + simp only [rankD_set, Fin.eta, Array.get_eq_getElem] + split + · simp_all + · simp_all only [Array.get_eq_getElem, Array.data_length, Nat.lt_irrefl, not_false_eq_true, + and_true, ite_false, ite_eq_right_iff] + rintro rfl + simp [rankD_eq, *] · exact setParent_rankD_lt (Nat.lt_of_le_of_ne (Nat.not_lt.1 ‹_›) ‹_›) self.rankD_lt @[inherit_doc link] From 7391b9f9b06eca6fcc36d211db143ba7f84dbe29 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 9 Jul 2024 09:46:20 +1000 Subject: [PATCH 109/208] chore: add missing since dates to deprecations (#875) --- Batteries/Data/Array/Merge.lean | 14 ++++---- Batteries/Data/BitVec/Lemmas.lean | 9 ++--- Batteries/Data/Bool.lean | 6 ++-- Batteries/Data/Int/Order.lean | 2 +- Batteries/Data/List/Basic.lean | 10 +++--- Batteries/Data/List/Count.lean | 4 +-- Batteries/Data/List/Lemmas.lean | 6 ++-- Batteries/Data/List/Pairwise.lean | 2 +- Batteries/Data/Nat/Lemmas.lean | 16 +++++---- Batteries/Data/Option/Lemmas.lean | 4 +-- Batteries/Data/RBMap/Basic.lean | 12 +++---- Batteries/Lean/Delaborator.lean | 2 +- Batteries/Logic.lean | 2 +- Batteries/StdDeprecations.lean | 59 ++++++++++++++++--------------- 14 files changed, 74 insertions(+), 74 deletions(-) diff --git a/Batteries/Data/Array/Merge.lean b/Batteries/Data/Array/Merge.lean index 1486520565..aa83e0200b 100644 --- a/Batteries/Data/Array/Merge.lean +++ b/Batteries/Data/Array/Merge.lean @@ -27,7 +27,7 @@ where termination_by xs.size + ys.size - (i + j) set_option linter.unusedVariables false in -@[deprecated merge, inherit_doc merge] +@[deprecated merge (since := "2024-04-24"), inherit_doc merge] def mergeSortedPreservingDuplicates [ord : Ord α] (xs ys : Array α) : Array α := merge (compare · · |>.isLT) xs ys @@ -55,7 +55,7 @@ where | .eq => go (acc.push (merge x y)) (i + 1) (j + 1) termination_by xs.size + ys.size - (i + j) -@[deprecated] alias mergeSortedMergingDuplicates := mergeDedupWith +@[deprecated (since := "2024-04-24")] alias mergeSortedMergingDuplicates := mergeDedupWith /-- `O(|xs| + |ys|)`. Merge arrays `xs` and `ys`, which must be sorted according to `compare` and must @@ -64,7 +64,7 @@ not contain duplicates. If an element appears in both `xs` and `ys`, only one co @[inline] def mergeDedup [ord : Ord α] (xs ys : Array α) : Array α := mergeDedupWith (ord := ord) xs ys fun x _ => x -@[deprecated] alias mergeSortedDeduplicating := mergeDedup +@[deprecated (since := "2024-04-24")] alias mergeSortedDeduplicating := mergeDedup set_option linter.unusedVariables false in /-- @@ -83,7 +83,7 @@ where ys.foldl (init := xs) fun xs y => if xs.any (· == y) (stop := xsSize) then xs else xs.push y -@[deprecated] alias mergeUnsortedDeduplicating := mergeUnsortedDedup +@[deprecated (since := "2024-04-24")] alias mergeUnsortedDeduplicating := mergeUnsortedDedup /-- `O(|xs|)`. Replace each run `[x₁, ⋯, xₙ]` of equal elements in `xs` with @@ -101,7 +101,7 @@ where acc.push hd termination_by xs.size - i -@[deprecated] alias mergeAdjacentDuplicates := mergeAdjacentDups +@[deprecated (since := "2024-04-24")] alias mergeAdjacentDuplicates := mergeAdjacentDups /-- `O(|xs|)`. Deduplicate a sorted array. The array must be sorted with to an order which agrees with @@ -110,13 +110,13 @@ where def dedupSorted [eq : BEq α] (xs : Array α) : Array α := xs.mergeAdjacentDups (eq := eq) fun x _ => x -@[deprecated] alias deduplicateSorted := dedupSorted +@[deprecated (since := "2024-04-24")] alias deduplicateSorted := dedupSorted /-- `O(|xs| log |xs|)`. Sort and deduplicate an array. -/ def sortDedup [ord : Ord α] (xs : Array α) : Array α := have := ord.toBEq dedupSorted <| xs.qsort (compare · · |>.isLT) -@[deprecated] alias sortAndDeduplicate := sortDedup +@[deprecated (since := "2024-04-24")] alias sortAndDeduplicate := sortDedup end Array diff --git a/Batteries/Data/BitVec/Lemmas.lean b/Batteries/Data/BitVec/Lemmas.lean index e0e45b8cb0..2bcd3ce4aa 100644 --- a/Batteries/Data/BitVec/Lemmas.lean +++ b/Batteries/Data/BitVec/Lemmas.lean @@ -7,13 +7,10 @@ import Batteries.Tactic.Alias namespace BitVec -/-- Replaced 2024-02-07. -/ -@[deprecated] alias zero_is_unique := eq_nil +@[deprecated (since := "2024-02-07")] alias zero_is_unique := eq_nil /-! ### sub/neg -/ -/-- Replaced 2024-02-06. -/ -@[deprecated] alias sub_toNat := toNat_sub +@[deprecated (since := "2024-02-07")] alias sub_toNat := toNat_sub -/-- Replaced 2024-02-06. -/ -@[deprecated] alias neg_toNat := toNat_neg +@[deprecated (since := "2024-02-07")] alias neg_toNat := toNat_neg diff --git a/Batteries/Data/Bool.lean b/Batteries/Data/Bool.lean index ab48cbc578..b6c0c9b4e7 100644 --- a/Batteries/Data/Bool.lean +++ b/Batteries/Data/Bool.lean @@ -10,10 +10,10 @@ namespace Bool /-! ### injectivity lemmas -/ -@[deprecated] alias not_inj' := not_inj_iff +@[deprecated (since := "2023-10-27")] alias not_inj' := not_inj_iff -@[deprecated] alias and_or_inj_right' := and_or_inj_right_iff +@[deprecated (since := "2023-10-27")] alias and_or_inj_right' := and_or_inj_right_iff -@[deprecated] alias and_or_inj_left' := and_or_inj_left_iff +@[deprecated (since := "2023-10-27")] alias and_or_inj_left' := and_or_inj_left_iff end Bool diff --git a/Batteries/Data/Int/Order.lean b/Batteries/Data/Int/Order.lean index 3855f19885..daab75c612 100644 --- a/Batteries/Data/Int/Order.lean +++ b/Batteries/Data/Int/Order.lean @@ -7,4 +7,4 @@ import Batteries.Tactic.Alias namespace Int -@[deprecated] alias ofNat_natAbs_eq_of_nonneg := natAbs_of_nonneg +@[deprecated (since := "2024-01-24")] alias ofNat_natAbs_eq_of_nonneg := natAbs_of_nonneg diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index a8c3fef85a..2cff94c670 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -93,9 +93,9 @@ drop_while (· != 1) [0, 1, 2, 3] = [1, 2, 3] /-- Returns the index of the first element equal to `a`, or the length of the list otherwise. -/ def indexOf [BEq α] (a : α) : List α → Nat := findIdx (· == a) -@[deprecated] alias removeNth := eraseIdx -@[deprecated] alias removeNthTR := eraseIdxTR -@[deprecated] alias removeNth_eq_removeNthTR := eraseIdx_eq_eraseIdxTR +@[deprecated (since := "2024-05-06")] alias removeNth := eraseIdx +@[deprecated (since := "2024-05-06")] alias removeNthTR := eraseIdxTR +@[deprecated (since := "2024-05-06")] alias removeNth_eq_removeNthTR := eraseIdx_eq_eraseIdxTR /-- Replaces the first element of the list for which `f` returns `some` with the returned value. -/ @[simp] def replaceF (f : α → Option α) : List α → List α @@ -926,7 +926,7 @@ def range' : (start len : Nat) → (step : Nat := 1) → List Nat `ilast' x xs` returns the last element of `xs` if `xs` is non-empty; it returns `x` otherwise. Use `List.getLastD` instead. -/ -@[simp, deprecated getLastD] def ilast' {α} : α → List α → α +@[simp, deprecated getLastD (since := "2024-01-09")] def ilast' {α} : α → List α → α | a, [] => a | _, b :: l => ilast' b l @@ -934,7 +934,7 @@ Use `List.getLastD` instead. `last' xs` returns the last element of `xs` if `xs` is non-empty; it returns `none` otherwise. Use `List.getLast?` instead -/ -@[simp, deprecated getLast?] def last' {α} : List α → Option α +@[simp, deprecated getLast? (since := "2024-01-09")] def last' {α} : List α → Option α | [] => none | [a] => some a | _ :: l => last' l diff --git a/Batteries/Data/List/Count.lean b/Batteries/Data/List/Count.lean index 81548ff437..dfd1481052 100644 --- a/Batteries/Data/List/Count.lean +++ b/Batteries/Data/List/Count.lean @@ -196,11 +196,11 @@ theorem filter_beq (l : List α) (a : α) : l.filter (· == a) = replicate (coun theorem filter_eq (l : List α) (a : α) : l.filter (· = a) = replicate (count a l) a := filter_beq l a -@[deprecated filter_eq] +@[deprecated filter_eq (since := "2023-12-14")] theorem filter_eq' (l : List α) (a : α) : l.filter (a = ·) = replicate (count a l) a := by simpa only [eq_comm] using filter_eq l a -@[deprecated filter_beq] +@[deprecated filter_beq (since := "2023-12-14")] theorem filter_beq' (l : List α) (a : α) : l.filter (a == ·) = replicate (count a l) a := by simpa only [eq_comm (b := a)] using filter_eq l a diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 44d9a5c18d..1cf017c534 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -308,7 +308,7 @@ theorem eraseIdx_eq_modifyNthTail : ∀ n (l : List α), eraseIdx l n = modifyNt | n+1, [] => rfl | n+1, a :: l => congrArg (cons _) (eraseIdx_eq_modifyNthTail _ _) -@[deprecated] alias removeNth_eq_nth_tail := eraseIdx_eq_modifyNthTail +@[deprecated (since := "2024-05-06")] alias removeNth_eq_nth_tail := eraseIdx_eq_modifyNthTail theorem getElem?_modifyNth (f : α → α) : ∀ n (l : List α) m, (modifyNth f n l)[m]? = (fun a => if n = m then f a else a) <$> l[m]? @@ -472,7 +472,7 @@ theorem length_eraseIdx : ∀ {l i}, i < length l → length (@eraseIdx α l i) simp [eraseIdx, ← Nat.add_one] rw [length_eraseIdx this, Nat.sub_add_cancel (Nat.lt_of_le_of_lt (Nat.zero_le _) this)] -@[deprecated] alias length_removeNth := length_eraseIdx +@[deprecated (since := "2024-05-06")] alias length_removeNth := length_eraseIdx /-! ### tail -/ @@ -619,7 +619,7 @@ theorem erase_subset (a : α) (l : List α) : l.erase a ⊆ l := (erase_sublist theorem Sublist.erase (a : α) {l₁ l₂ : List α} (h : l₁ <+ l₂) : l₁.erase a <+ l₂.erase a := by simp only [erase_eq_eraseP']; exact h.eraseP -@[deprecated] alias sublist.erase := Sublist.erase +@[deprecated (since := "2024-04-22")] alias sublist.erase := Sublist.erase theorem mem_of_mem_erase {a b : α} {l : List α} (h : a ∈ l.erase b) : a ∈ l := erase_subset _ _ h diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index 8583a41f2b..83b935f8ae 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -188,7 +188,7 @@ theorem pairwise_iff_forall_sublist : l.Pairwise R ↔ (∀ {a b}, [a,b] <+ l intro a b hab apply h; exact hab.cons _ -@[deprecated pairwise_iff_forall_sublist] +@[deprecated pairwise_iff_forall_sublist (since := "2023-09-18")] theorem pairwise_of_reflexive_on_dupl_of_forall_ne [DecidableEq α] {l : List α} {r : α → α → Prop} (hr : ∀ a, 1 < count a l → r a a) (h : ∀ a ∈ l, ∀ b ∈ l, a ≠ b → r a b) : l.Pairwise r := by apply pairwise_iff_forall_sublist.mpr diff --git a/Batteries/Data/Nat/Lemmas.lean b/Batteries/Data/Nat/Lemmas.lean index 951f330e51..842ca09e95 100644 --- a/Batteries/Data/Nat/Lemmas.lean +++ b/Batteries/Data/Nat/Lemmas.lean @@ -151,19 +151,21 @@ protected def sum_trichotomy (a b : Nat) : a < b ⊕' a = b ⊕' b < a := /-! ## add -/ -@[deprecated] alias succ_add_eq_succ_add := Nat.succ_add_eq_add_succ +@[deprecated (since := "2023-11-25")] alias succ_add_eq_succ_add := Nat.succ_add_eq_add_succ /-! ## sub -/ -@[deprecated] protected alias le_of_le_of_sub_le_sub_right := Nat.le_of_sub_le_sub_right +@[deprecated (since := "2023-11-25")] +protected alias le_of_le_of_sub_le_sub_right := Nat.le_of_sub_le_sub_right -@[deprecated] protected alias le_of_le_of_sub_le_sub_left := Nat.le_of_sub_le_sub_left +@[deprecated (since := "2023-11-25")] +protected alias le_of_le_of_sub_le_sub_left := Nat.le_of_sub_le_sub_left /-! ### mul -/ -@[deprecated] protected alias mul_lt_mul := Nat.mul_lt_mul_of_lt_of_le' +@[deprecated (since := "2024-01-11")] protected alias mul_lt_mul := Nat.mul_lt_mul_of_lt_of_le' -@[deprecated] protected alias mul_lt_mul' := Nat.mul_lt_mul_of_le_of_lt +@[deprecated (since := "2024-01-11")] protected alias mul_lt_mul' := Nat.mul_lt_mul_of_le_of_lt /-! ### div/mod -/ @@ -182,5 +184,5 @@ protected def sum_trichotomy (a b : Nat) : a < b ⊕' a = b ⊕' b < a := @[simp] theorem sum_append : Nat.sum (l₁ ++ l₂) = Nat.sum l₁ + Nat.sum l₂ := by induction l₁ <;> simp [*, Nat.add_assoc] -@[deprecated] protected alias lt_connex := Nat.lt_or_gt_of_ne -@[deprecated] alias pow_two_pos := Nat.two_pow_pos -- deprecated 2024-02-09 +@[deprecated (since := "2024-03-05")] protected alias lt_connex := Nat.lt_or_gt_of_ne +@[deprecated (since := "2024-02-09")] alias pow_two_pos := Nat.two_pow_pos diff --git a/Batteries/Data/Option/Lemmas.lean b/Batteries/Data/Option/Lemmas.lean index a768a776ce..05a38b25a7 100644 --- a/Batteries/Data/Option/Lemmas.lean +++ b/Batteries/Data/Option/Lemmas.lean @@ -7,7 +7,7 @@ import Batteries.Tactic.Alias namespace Option -@[deprecated] alias to_list_some := toList_some -@[deprecated] alias to_list_none := toList_none +@[deprecated (since := "2024-03-05")] alias to_list_some := toList_some +@[deprecated (since := "2024-03-05")] alias to_list_none := toList_none end Option diff --git a/Batteries/Data/RBMap/Basic.lean b/Batteries/Data/RBMap/Basic.lean index a9ba215ad9..d1aff2dc3b 100644 --- a/Batteries/Data/RBMap/Basic.lean +++ b/Batteries/Data/RBMap/Basic.lean @@ -67,8 +67,8 @@ protected def max? : RBNode α → Option α | node _ _ v nil => some v | node _ _ _ r => r.max? -@[deprecated] protected alias min := RBNode.min? -@[deprecated] protected alias max := RBNode.max? +@[deprecated (since := "2024-04-17")] protected alias min := RBNode.min? +@[deprecated (since := "2024-04-17")] protected alias max := RBNode.max? /-- Fold a function in tree order along the nodes. `v₀` is used at `nil` nodes and @@ -669,8 +669,8 @@ instance : ToStream (RBSet α cmp) (RBNode.Stream α) := ⟨fun x => x.1.toStrea /-- `O(log n)`. Returns the entry `a` such that `a ≥ k` for all keys in the RBSet. -/ @[inline] protected def max? (t : RBSet α cmp) : Option α := t.1.max? -@[deprecated] protected alias min := RBSet.min? -@[deprecated] protected alias max := RBSet.max? +@[deprecated (since := "2024-04-17")] protected alias min := RBSet.min? +@[deprecated (since := "2024-04-17")] protected alias max := RBSet.max? instance [Repr α] : Repr (RBSet α cmp) where reprPrec m prec := Repr.addAppParen ("RBSet.ofList " ++ repr m.toList) prec @@ -1053,8 +1053,8 @@ instance : Stream (Values.Stream α β) β := ⟨Values.Stream.next?⟩ /-- `O(log n)`. Returns the key-value pair `(a, b)` such that `a ≥ k` for all keys in the RBMap. -/ @[inline] protected def max? : RBMap α β cmp → Option (α × β) := RBSet.max? -@[deprecated] protected alias min := RBMap.min? -@[deprecated] protected alias max := RBMap.max? +@[deprecated (since := "2024-04-17")] protected alias min := RBMap.min? +@[deprecated (since := "2024-04-17")] protected alias max := RBMap.max? instance [Repr α] [Repr β] : Repr (RBMap α β cmp) where reprPrec m prec := Repr.addAppParen ("RBMap.ofList " ++ repr m.toList) prec diff --git a/Batteries/Lean/Delaborator.lean b/Batteries/Lean/Delaborator.lean index d722eef9d8..e09f2198de 100644 --- a/Batteries/Lean/Delaborator.lean +++ b/Batteries/Lean/Delaborator.lean @@ -8,6 +8,6 @@ import Lean.PrettyPrinter open Lean PrettyPrinter Delaborator SubExpr /-- Abbreviation for `Lean.MessageData.ofConst`. -/ -@[deprecated Lean.MessageData.ofConst] +@[deprecated Lean.MessageData.ofConst (since := "2024-05-18")] def Lean.ppConst (e : Expr) : MessageData := Lean.MessageData.ofConst e diff --git a/Batteries/Logic.lean b/Batteries/Logic.lean index 10b5bd2fcb..d0fd84e688 100644 --- a/Batteries/Logic.lean +++ b/Batteries/Logic.lean @@ -10,7 +10,7 @@ import Batteries.Tactic.Lint.Misc instance {f : α → β} [DecidablePred p] : DecidablePred (p ∘ f) := inferInstanceAs <| DecidablePred fun x => p (f x) -@[deprecated] alias proofIrrel := proof_irrel +@[deprecated (since := "2024-03-15")] alias proofIrrel := proof_irrel /-! ## id -/ diff --git a/Batteries/StdDeprecations.lean b/Batteries/StdDeprecations.lean index 49357a0573..c705ee839d 100644 --- a/Batteries/StdDeprecations.lean +++ b/Batteries/StdDeprecations.lean @@ -21,35 +21,36 @@ but it would be much harder to generate the deprecations. Let's hope that people using the tactic implementations can work this out themselves. -/ -@[deprecated] alias Std.AssocList := Batteries.AssocList -@[deprecated] alias Std.HashMap := Batteries.HashMap -@[deprecated] alias Std.mkHashMap := Batteries.mkHashMap -@[deprecated] alias Std.DList := Batteries.DList -@[deprecated] alias Std.PairingHeapImp.Heap := Batteries.PairingHeapImp.Heap -@[deprecated] alias Std.TotalBLE := Batteries.TotalBLE -@[deprecated] alias Std.OrientedCmp := Batteries.OrientedCmp -@[deprecated] alias Std.TransCmp := Batteries.TransCmp -@[deprecated] alias Std.BEqCmp := Batteries.BEqCmp -@[deprecated] alias Std.LTCmp := Batteries.LTCmp -@[deprecated] alias Std.LECmp := Batteries.LECmp -@[deprecated] alias Std.LawfulCmp := Batteries.LawfulCmp -@[deprecated] alias Std.OrientedOrd := Batteries.OrientedOrd -@[deprecated] alias Std.TransOrd := Batteries.TransOrd -@[deprecated] alias Std.BEqOrd := Batteries.BEqOrd -@[deprecated] alias Std.LTOrd := Batteries.LTOrd -@[deprecated] alias Std.LEOrd := Batteries.LEOrd -@[deprecated] alias Std.LawfulOrd := Batteries.LawfulOrd -@[deprecated] alias Std.compareOfLessAndEq_eq_lt := Batteries.compareOfLessAndEq_eq_lt -@[deprecated] alias Std.RBColor := Batteries.RBColor -@[deprecated] alias Std.RBNode := Batteries.RBNode -@[deprecated] alias Std.RBSet := Batteries.RBSet -@[deprecated] alias Std.mkRBSet := Batteries.mkRBSet -@[deprecated] alias Std.RBMap := Batteries.RBMap -@[deprecated] alias Std.mkRBMap := Batteries.mkRBMap -@[deprecated] alias Std.BinomialHeap := Batteries.BinomialHeap -@[deprecated] alias Std.mkBinomialHeap := Batteries.mkBinomialHeap -@[deprecated] alias Std.UFNode := Batteries.UFNode -@[deprecated] alias Std.UnionFind := Batteries.UnionFind +@[deprecated (since := "2024-05-07")] alias Std.AssocList := Batteries.AssocList +@[deprecated (since := "2024-05-07")] alias Std.HashMap := Batteries.HashMap +@[deprecated (since := "2024-05-07")] alias Std.mkHashMap := Batteries.mkHashMap +@[deprecated (since := "2024-05-07")] alias Std.DList := Batteries.DList +@[deprecated (since := "2024-05-07")] alias Std.PairingHeapImp.Heap := Batteries.PairingHeapImp.Heap +@[deprecated (since := "2024-05-07")] alias Std.TotalBLE := Batteries.TotalBLE +@[deprecated (since := "2024-05-07")] alias Std.OrientedCmp := Batteries.OrientedCmp +@[deprecated (since := "2024-05-07")] alias Std.TransCmp := Batteries.TransCmp +@[deprecated (since := "2024-05-07")] alias Std.BEqCmp := Batteries.BEqCmp +@[deprecated (since := "2024-05-07")] alias Std.LTCmp := Batteries.LTCmp +@[deprecated (since := "2024-05-07")] alias Std.LECmp := Batteries.LECmp +@[deprecated (since := "2024-05-07")] alias Std.LawfulCmp := Batteries.LawfulCmp +@[deprecated (since := "2024-05-07")] alias Std.OrientedOrd := Batteries.OrientedOrd +@[deprecated (since := "2024-05-07")] alias Std.TransOrd := Batteries.TransOrd +@[deprecated (since := "2024-05-07")] alias Std.BEqOrd := Batteries.BEqOrd +@[deprecated (since := "2024-05-07")] alias Std.LTOrd := Batteries.LTOrd +@[deprecated (since := "2024-05-07")] alias Std.LEOrd := Batteries.LEOrd +@[deprecated (since := "2024-05-07")] alias Std.LawfulOrd := Batteries.LawfulOrd +@[deprecated (since := "2024-05-07")] +alias Std.compareOfLessAndEq_eq_lt := Batteries.compareOfLessAndEq_eq_lt +@[deprecated (since := "2024-05-07")] alias Std.RBColor := Batteries.RBColor +@[deprecated (since := "2024-05-07")] alias Std.RBNode := Batteries.RBNode +@[deprecated (since := "2024-05-07")] alias Std.RBSet := Batteries.RBSet +@[deprecated (since := "2024-05-07")] alias Std.mkRBSet := Batteries.mkRBSet +@[deprecated (since := "2024-05-07")] alias Std.RBMap := Batteries.RBMap +@[deprecated (since := "2024-05-07")] alias Std.mkRBMap := Batteries.mkRBMap +@[deprecated (since := "2024-05-07")] alias Std.BinomialHeap := Batteries.BinomialHeap +@[deprecated (since := "2024-05-07")] alias Std.mkBinomialHeap := Batteries.mkBinomialHeap +@[deprecated (since := "2024-05-07")] alias Std.UFNode := Batteries.UFNode +@[deprecated (since := "2024-05-07")] alias Std.UnionFind := Batteries.UnionFind -- Check that these generate usable deprecated hints -- when referring to names inside these namespaces. From 8bcae1a508ab673a743343f78048cfe5f27250f5 Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Sun, 23 Jun 2024 17:17:06 -0700 Subject: [PATCH 110/208] fixes for lean4#4543 (changes to `@[ext]`) --- Batteries/Data/String/Lemmas.lean | 6 ++++-- Batteries/Data/UInt.lean | 10 ---------- Batteries/Logic.lean | 3 +-- test/congr.lean | 2 -- 4 files changed, 5 insertions(+), 16 deletions(-) diff --git a/Batteries/Data/String/Lemmas.lean b/Batteries/Data/String/Lemmas.lean index 1ea4e4f788..5420651ba2 100644 --- a/Batteries/Data/String/Lemmas.lean +++ b/Batteries/Data/String/Lemmas.lean @@ -12,7 +12,8 @@ import Batteries.Tactic.SqueezeScope namespace String -attribute [ext] ext +-- TODO(kmill): add `@[ext]` attribute to `String.ext` in core. +attribute [ext (iff := false)] ext theorem lt_trans {s₁ s₂ s₃ : String} : s₁ < s₂ → s₂ < s₃ → s₁ < s₃ := List.lt_trans' (α := Char) Nat.lt_trans @@ -87,7 +88,8 @@ end namespace Pos -attribute [ext] ext +-- TODO(kmill): add `@[ext]` attribute to `String.Pos.ext` in core. +attribute [ext (iff := false)] ext theorem lt_addChar (p : Pos) (c : Char) : p < p + c := Nat.lt_add_of_pos_right (Char.utf8Size_pos _) diff --git a/Batteries/Data/UInt.lean b/Batteries/Data/UInt.lean index a9ce1b561a..44ebfd9b80 100644 --- a/Batteries/Data/UInt.lean +++ b/Batteries/Data/UInt.lean @@ -10,8 +10,6 @@ import Batteries.Classes.Order @[ext] theorem UInt8.ext : {x y : UInt8} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem UInt8.ext_iff {x y : UInt8} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, UInt8.ext⟩ - @[simp] theorem UInt8.val_val_eq_toNat (x : UInt8) : x.val.val = x.toNat := rfl @[simp] theorem UInt8.val_ofNat (n) : @@ -57,8 +55,6 @@ instance : Batteries.LawfulOrd UInt8 := .compareOfLessAndEq @[ext] theorem UInt16.ext : {x y : UInt16} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem UInt16.ext_iff {x y : UInt16} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, UInt16.ext⟩ - @[simp] theorem UInt16.val_val_eq_toNat (x : UInt16) : x.val.val = x.toNat := rfl @[simp] theorem UInt16.val_ofNat (n) : @@ -104,8 +100,6 @@ instance : Batteries.LawfulOrd UInt16 := .compareOfLessAndEq @[ext] theorem UInt32.ext : {x y : UInt32} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem UInt32.ext_iff {x y : UInt32} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, UInt32.ext⟩ - @[simp] theorem UInt32.val_val_eq_toNat (x : UInt32) : x.val.val = x.toNat := rfl @[simp] theorem UInt32.val_ofNat (n) : @@ -151,8 +145,6 @@ instance : Batteries.LawfulOrd UInt32 := .compareOfLessAndEq @[ext] theorem UInt64.ext : {x y : UInt64} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem UInt64.ext_iff {x y : UInt64} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, UInt64.ext⟩ - @[simp] theorem UInt64.val_val_eq_toNat (x : UInt64) : x.val.val = x.toNat := rfl @[simp] theorem UInt64.val_ofNat (n) : @@ -198,8 +190,6 @@ instance : Batteries.LawfulOrd UInt64 := .compareOfLessAndEq @[ext] theorem USize.ext : {x y : USize} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem USize.ext_iff {x y : USize} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, USize.ext⟩ - @[simp] theorem USize.val_val_eq_toNat (x : USize) : x.val.val = x.toNat := rfl @[simp] theorem USize.val_ofNat (n) : diff --git a/Batteries/Logic.lean b/Batteries/Logic.lean index d0fd84e688..1e67c68d62 100644 --- a/Batteries/Logic.lean +++ b/Batteries/Logic.lean @@ -60,8 +60,7 @@ theorem funext₃ {β : α → Sort _} {γ : ∀ a, β a → Sort _} {δ : ∀ a {f g : ∀ a b c, δ a b c} (h : ∀ a b c, f a b c = g a b c) : f = g := funext fun _ => funext₂ <| h _ -theorem Function.funext_iff {β : α → Sort u} {f₁ f₂ : ∀ x : α, β x} : f₁ = f₂ ↔ ∀ a, f₁ a = f₂ a := - ⟨congrFun, funext⟩ +protected alias Function.funext_iff := funext_iff theorem ne_of_apply_ne {α β : Sort _} (f : α → β) {x y : α} : f x ≠ f y → x ≠ y := mt <| congrArg _ diff --git a/test/congr.lean b/test/congr.lean index a71aed0315..065a899f99 100644 --- a/test/congr.lean +++ b/test/congr.lean @@ -19,8 +19,6 @@ example {α β γ δ} {F : ∀ {α β}, (α → β) → γ → δ} {f g : α → -- apply_assumption -- FIXME apply h -attribute [ext] Subtype.eq - example {α β : Type _} {f : _ → β} {x y : { x : { x : α // x = x } // x = x }} (h : x.1 = y.1) : f x = f y := by congr with : 1 From 8a09d5093af15b69775e17993d00406d0416243f Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 10 Jul 2024 00:00:08 +1000 Subject: [PATCH 111/208] fix --- Batteries.lean | 3 --- Batteries/Classes/BEq.lean | 18 ---------------- Batteries/Data/HashMap/Basic.lean | 1 - Batteries/Lean/SMap.lean | 17 ---------------- Batteries/Lean/Util/Path.lean | 34 ------------------------------- Batteries/Logic.lean | 8 +------- lean-toolchain | 2 +- scripts/runLinter.lean | 2 +- 8 files changed, 3 insertions(+), 82 deletions(-) delete mode 100644 Batteries/Classes/BEq.lean delete mode 100644 Batteries/Lean/SMap.lean delete mode 100644 Batteries/Lean/Util/Path.lean diff --git a/Batteries.lean b/Batteries.lean index 2fac3bf121..81878f133b 100644 --- a/Batteries.lean +++ b/Batteries.lean @@ -1,4 +1,3 @@ -import Batteries.Classes.BEq import Batteries.Classes.Cast import Batteries.Classes.Order import Batteries.Classes.RatCast @@ -64,12 +63,10 @@ import Batteries.Lean.NameMapAttribute import Batteries.Lean.PersistentHashMap import Batteries.Lean.PersistentHashSet import Batteries.Lean.Position -import Batteries.Lean.SMap import Batteries.Lean.Syntax import Batteries.Lean.System.IO import Batteries.Lean.TagAttribute import Batteries.Lean.Util.EnvSearch -import Batteries.Lean.Util.Path import Batteries.Linter import Batteries.Linter.UnnecessarySeqFocus import Batteries.Linter.UnreachableTactic diff --git a/Batteries/Classes/BEq.lean b/Batteries/Classes/BEq.lean deleted file mode 100644 index 98318f97c9..0000000000 --- a/Batteries/Classes/BEq.lean +++ /dev/null @@ -1,18 +0,0 @@ -/- -Copyright (c) 2022 Mario Carneiro. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mario Carneiro --/ - -/-! ## Boolean equality -/ - -/-- `PartialEquivBEq α` says that the `BEq` implementation is a -partial equivalence relation, that is: -* it is symmetric: `a == b → b == a` -* it is transitive: `a == b → b == c → a == c`. --/ -class PartialEquivBEq (α) [BEq α] : Prop where - /-- Symmetry for `BEq`. If `a == b` then `b == a`. -/ - symm : (a : α) == b → b == a - /-- Transitivity for `BEq`. If `a == b` and `b == c` then `a == c`. -/ - trans : (a : α) == b → b == c → a == c diff --git a/Batteries/Data/HashMap/Basic.lean b/Batteries/Data/HashMap/Basic.lean index 106fea1e4d..3419ba35ab 100644 --- a/Batteries/Data/HashMap/Basic.lean +++ b/Batteries/Data/HashMap/Basic.lean @@ -6,7 +6,6 @@ Authors: Leonardo de Moura, Mario Carneiro import Batteries.Data.AssocList import Batteries.Data.Nat.Basic import Batteries.Data.Array.Monadic -import Batteries.Classes.BEq namespace Batteries.HashMap diff --git a/Batteries/Lean/SMap.lean b/Batteries/Lean/SMap.lean deleted file mode 100644 index 44a660e2e0..0000000000 --- a/Batteries/Lean/SMap.lean +++ /dev/null @@ -1,17 +0,0 @@ -/- -Copyright (c) 2023 Scott Morrison. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Scott Morrison --/ -import Lean.Data.SMap - -/-! -# Extra functions on Lean.SMap --/ - -set_option autoImplicit true - -/-- Monadic fold over a staged map. -/ -def Lean.SMap.foldM {m : Type w → Type w} [Monad m] [BEq α] [Hashable α] - (f : σ → α → β → m σ) (init : σ) (map : SMap α β) : m σ := do - map.map₂.foldlM f (← map.map₁.foldM f init) diff --git a/Batteries/Lean/Util/Path.lean b/Batteries/Lean/Util/Path.lean deleted file mode 100644 index d9488c0dc8..0000000000 --- a/Batteries/Lean/Util/Path.lean +++ /dev/null @@ -1,34 +0,0 @@ -/- -Copyright (c) 2022 Gabriel Ebner. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Gabriel Ebner --/ -import Lean.Elab.Term - -/-! -# `compile_time_search_path%` term elaborator. - -Use this as `searchPathRef.set compile_time_search_path%`. --/ - -open Lean System - --- Ideally this instance would be constructed simply by `deriving instance ToExpr for FilePath` --- but for now we have decided not to upstream the `ToExpr` derive handler from `Mathlib`. --- https://leanprover.zulipchat.com/#narrow/stream/348111-std4/topic/ToExpr.20derive.20handler/near/386476438 -instance : ToExpr FilePath where - toTypeExpr := mkConst ``FilePath - toExpr path := mkApp (mkConst ``FilePath.mk) (toExpr path.1) - -/-- -Term elaborator that retrieves the current `SearchPath`. - -Typical usage is `searchPathRef.set compile_time_search_path%`. - -This must not be used in files that are potentially compiled on another machine and then -imported. -(That is, if used in an imported file it will embed the search path from whichever machine -compiled the `.olean`.) --/ -elab "compile_time_search_path%" : term => - return toExpr (← searchPathRef.get) diff --git a/Batteries/Logic.lean b/Batteries/Logic.lean index 1e67c68d62..5c6efe108a 100644 --- a/Batteries/Logic.lean +++ b/Batteries/Logic.lean @@ -16,10 +16,6 @@ instance {f : α → β} [DecidablePred p] : DecidablePred (p ∘ f) := theorem Function.id_def : @id α = fun x => x := rfl -/-! ## exists and forall -/ - -alias ⟨forall_not_of_not_exists, not_exists_of_forall_not⟩ := not_exists - /-! ## decidable -/ protected alias ⟨Decidable.exists_not_of_not_forall, _⟩ := Decidable.not_forall @@ -127,9 +123,7 @@ end Mem -- instance (priority := 10) {α} [Subsingleton α] : DecidableEq α -- | a, b => isTrue (Subsingleton.elim a b) --- @[simp] -- TODO(Mario): profile -theorem eq_iff_true_of_subsingleton [Subsingleton α] (x y : α) : x = y ↔ True := - iff_true_intro (Subsingleton.elim ..) +-- TODO(Mario): profile adding `@[simp]` to `eq_iff_true_of_subsingleton` /-- If all points are equal to a given point `x`, then `α` is a subsingleton. -/ theorem subsingleton_of_forall_eq (x : α) (h : ∀ y, y = x) : Subsingleton α := diff --git a/lean-toolchain b/lean-toolchain index b354fd7a27..b2ff4e8ac0 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-07 +leanprover/lean4:nightly-2024-07-09 diff --git a/scripts/runLinter.lean b/scripts/runLinter.lean index 87d8774ce9..f4d5002e2d 100644 --- a/scripts/runLinter.lean +++ b/scripts/runLinter.lean @@ -1,6 +1,6 @@ +import Lean.Util.SearchPath import Batteries.Tactic.Lint import Batteries.Data.Array.Basic -import Batteries.Lean.Util.Path open Lean Core Elab Command Std.Tactic.Lint open System (FilePath) From c0efc1fd2a0bec51bd55c5b17348af13d7419239 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 10 Jul 2024 02:30:09 +1000 Subject: [PATCH 112/208] chore: bump toolchain to v4.10.0-rc2 (#876) --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index d69d1ed200..6a4259fa56 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.10.0-rc1 +leanprover/lean4:v4.10.0-rc2 From 905081cf56230efae4bc7ed10f1add9a76661a34 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 10 Jul 2024 03:04:02 +1000 Subject: [PATCH 113/208] remove HashMap deprecation alias --- Batteries/StdDeprecations.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/Batteries/StdDeprecations.lean b/Batteries/StdDeprecations.lean index c705ee839d..f82b1739a7 100644 --- a/Batteries/StdDeprecations.lean +++ b/Batteries/StdDeprecations.lean @@ -22,7 +22,6 @@ Let's hope that people using the tactic implementations can work this out themse -/ @[deprecated (since := "2024-05-07")] alias Std.AssocList := Batteries.AssocList -@[deprecated (since := "2024-05-07")] alias Std.HashMap := Batteries.HashMap @[deprecated (since := "2024-05-07")] alias Std.mkHashMap := Batteries.mkHashMap @[deprecated (since := "2024-05-07")] alias Std.DList := Batteries.DList @[deprecated (since := "2024-05-07")] alias Std.PairingHeapImp.Heap := Batteries.PairingHeapImp.Heap From 8823504ed6a27c5b7589c73cebaa49ae91329529 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Wed, 10 Jul 2024 09:05:09 +0000 Subject: [PATCH 114/208] chore: bump to nightly-2024-07-10 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index b2ff4e8ac0..71dae0afae 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-09 +leanprover/lean4:nightly-2024-07-10 From 807aba8b570589a360df8e10302c32adc2712613 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 10 Jul 2024 23:39:33 +1000 Subject: [PATCH 115/208] adaptations --- Batteries/Data/HashMap/WF.lean | 2 +- Batteries/Data/List/Basic.lean | 77 --------- Batteries/Data/List/Lemmas.lean | 267 ------------------------------ Batteries/Data/List/Pairwise.lean | 5 - Batteries/Data/List/Perm.lean | 4 +- Batteries/Data/RBMap/Lemmas.lean | 1 - 6 files changed, 3 insertions(+), 353 deletions(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index bc565bc037..f7ee6ed1da 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -95,7 +95,7 @@ where · next H => refine (go (i+1) _ _ fun j hj => ?a).trans ?b <;> simp · case a => - simp [List.getD_eq_getElem?, List.getElem?_set, Option.map_eq_map]; split + simp [List.getD_eq_getElem?_getD, List.getElem?_set, Option.map_eq_map]; split · cases source.data[j]? <;> rfl · next H => exact hs _ (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ hj) (Ne.symm H)) · case b => diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index 2cff94c670..d000469cfe 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -10,16 +10,6 @@ namespace List /-! ## New definitions -/ -/-- -`l₁ ⊆ l₂` means that every element of `l₁` is also an element of `l₂`, ignoring multiplicity. --/ -protected def Subset (l₁ l₂ : List α) := ∀ ⦃a : α⦄, a ∈ l₁ → a ∈ l₂ - -instance : HasSubset (List α) := ⟨List.Subset⟩ - -instance [DecidableEq α] : DecidableRel (Subset : List α → List α → Prop) := - fun _ _ => decidableBAll _ _ - /-- Computes the "bag intersection" of `l₁` and `l₂`, that is, the collection of elements of `l₁` which are also in `l₂`. As each element @@ -139,26 +129,6 @@ Unlike `bagInter` this does not preserve multiplicity: `[1, 1].inter [1]` is `[1 instance [BEq α] : Inter (List α) := ⟨List.inter⟩ -/-- `l₁ <+ l₂`, or `Sublist l₁ l₂`, says that `l₁` is a (non-contiguous) subsequence of `l₂`. -/ -inductive Sublist {α} : List α → List α → Prop - /-- the base case: `[]` is a sublist of `[]` -/ - | slnil : Sublist [] [] - /-- If `l₁` is a subsequence of `l₂`, then it is also a subsequence of `a :: l₂`. -/ - | cons a : Sublist l₁ l₂ → Sublist l₁ (a :: l₂) - /-- If `l₁` is a subsequence of `l₂`, then `a :: l₁` is a subsequence of `a :: l₂`. -/ - | cons₂ a : Sublist l₁ l₂ → Sublist (a :: l₁) (a :: l₂) - -@[inherit_doc] scoped infixl:50 " <+ " => Sublist - -/-- True if the first list is a potentially non-contiguous sub-sequence of the second list. -/ -def isSublist [BEq α] : List α → List α → Bool - | [], _ => true - | _, [] => false - | l₁@(hd₁::tl₁), hd₂::tl₂ => - if hd₁ == hd₂ - then tl₁.isSublist tl₂ - else l₁.isSublist tl₂ - /-- Split a list at an index. ``` @@ -806,46 +776,6 @@ where rename_i a as b bs; unfold cond; cases R a b <;> simp [go as bs] exact (go as bs [] []).symm -section Pairwise - -variable (R : α → α → Prop) - -/-- -`Pairwise R l` means that all the elements with earlier indexes are -`R`-related to all the elements with later indexes. -``` -Pairwise R [1, 2, 3] ↔ R 1 2 ∧ R 1 3 ∧ R 2 3 -``` -For example if `R = (·≠·)` then it asserts `l` has no duplicates, -and if `R = (·<·)` then it asserts that `l` is (strictly) sorted. --/ -inductive Pairwise : List α → Prop - /-- All elements of the empty list are vacuously pairwise related. -/ - | nil : Pairwise [] - /-- `a :: l` is `Pairwise R` if `a` `R`-relates to every element of `l`, - and `l` is `Pairwise R`. -/ - | cons : ∀ {a : α} {l : List α}, (∀ a' ∈ l, R a a') → Pairwise l → Pairwise (a :: l) - -attribute [simp] Pairwise.nil - -variable {R} - -@[simp] theorem pairwise_cons : Pairwise R (a::l) ↔ (∀ a' ∈ l, R a a') ∧ Pairwise R l := - ⟨fun | .cons h₁ h₂ => ⟨h₁, h₂⟩, fun ⟨h₁, h₂⟩ => h₂.cons h₁⟩ - -instance instDecidablePairwise [DecidableRel R] : - (l : List α) → Decidable (Pairwise R l) - | [] => isTrue .nil - | hd :: tl => - match instDecidablePairwise tl with - | isTrue ht => - match decidableBAll (R hd) tl with - | isFalse hf => isFalse fun hf' => hf (pairwise_cons.1 hf').1 - | isTrue ht' => isTrue <| pairwise_cons.mpr (And.intro ht' ht) - | isFalse hf => isFalse fun | .cons _ ih => hf ih - -end Pairwise - /-- `pwFilter R l` is a maximal sublist of `l` which is `Pairwise R`. `pwFilter (·≠·)` is the erase duplicates function (cf. `eraseDup`), and `pwFilter (·<·)` finds @@ -881,13 +811,6 @@ def Chain' : List α → Prop end Chain -/-- `Nodup l` means that `l` has no duplicates, that is, any element appears at most - once in the List. It is defined as `Pairwise (≠)`. -/ -def Nodup : List α → Prop := Pairwise (· ≠ ·) - -instance nodupDecidable [DecidableEq α] : ∀ l : List α, Decidable (Nodup l) := - instDecidablePairwise - /-- `eraseDup l` removes duplicates from `l` (taking only the first occurrence). Defined as `pwFilter (≠)`. diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 3ba167f29d..32f49b761f 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -28,208 +28,6 @@ theorem drop_one : ∀ l : List α, drop 1 l = tail l theorem zipWith_distrib_tail : (zipWith f l l').tail = zipWith f l.tail l'.tail := by rw [← drop_one]; simp [zipWith_distrib_drop] -/-! ### List subset -/ - -theorem subset_def {l₁ l₂ : List α} : l₁ ⊆ l₂ ↔ ∀ {a : α}, a ∈ l₁ → a ∈ l₂ := .rfl - -@[simp] theorem nil_subset (l : List α) : [] ⊆ l := nofun - -@[simp] theorem Subset.refl (l : List α) : l ⊆ l := fun _ i => i - -theorem Subset.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ ⊆ l₂) (h₂ : l₂ ⊆ l₃) : l₁ ⊆ l₃ := - fun _ i => h₂ (h₁ i) - -instance : Trans (Membership.mem : α → List α → Prop) Subset Membership.mem := - ⟨fun h₁ h₂ => h₂ h₁⟩ - -instance : Trans (Subset : List α → List α → Prop) Subset Subset := - ⟨Subset.trans⟩ - -@[simp] theorem subset_cons (a : α) (l : List α) : l ⊆ a :: l := fun _ => Mem.tail _ - -theorem subset_of_cons_subset {a : α} {l₁ l₂ : List α} : a :: l₁ ⊆ l₂ → l₁ ⊆ l₂ := - fun s _ i => s (mem_cons_of_mem _ i) - -theorem subset_cons_of_subset (a : α) {l₁ l₂ : List α} : l₁ ⊆ l₂ → l₁ ⊆ a :: l₂ := - fun s _ i => .tail _ (s i) - -theorem cons_subset_cons {l₁ l₂ : List α} (a : α) (s : l₁ ⊆ l₂) : a :: l₁ ⊆ a :: l₂ := - fun _ => by simp only [mem_cons]; exact Or.imp_right (@s _) - -@[simp] theorem subset_append_left (l₁ l₂ : List α) : l₁ ⊆ l₁ ++ l₂ := fun _ => mem_append_left _ - -@[simp] theorem subset_append_right (l₁ l₂ : List α) : l₂ ⊆ l₁ ++ l₂ := fun _ => mem_append_right _ - -theorem subset_append_of_subset_left (l₂ : List α) : l ⊆ l₁ → l ⊆ l₁ ++ l₂ := -fun s => Subset.trans s <| subset_append_left _ _ - -theorem subset_append_of_subset_right (l₁ : List α) : l ⊆ l₂ → l ⊆ l₁ ++ l₂ := -fun s => Subset.trans s <| subset_append_right _ _ - -@[simp] theorem cons_subset : a :: l ⊆ m ↔ a ∈ m ∧ l ⊆ m := by - simp only [subset_def, mem_cons, or_imp, forall_and, forall_eq] - -@[simp] theorem append_subset {l₁ l₂ l : List α} : - l₁ ++ l₂ ⊆ l ↔ l₁ ⊆ l ∧ l₂ ⊆ l := by simp [subset_def, or_imp, forall_and] - -theorem subset_nil {l : List α} : l ⊆ [] ↔ l = [] := - ⟨fun h => match l with | [] => rfl | _::_ => (nomatch h (.head ..)), fun | rfl => Subset.refl _⟩ - -theorem map_subset {l₁ l₂ : List α} (f : α → β) (H : l₁ ⊆ l₂) : map f l₁ ⊆ map f l₂ := - fun x => by simp only [mem_map]; exact .imp fun a => .imp_left (@H _) - -/-! ### sublists -/ - -@[simp] theorem nil_sublist : ∀ l : List α, [] <+ l - | [] => .slnil - | a :: l => (nil_sublist l).cons a - -@[simp] theorem Sublist.refl : ∀ l : List α, l <+ l - | [] => .slnil - | a :: l => (Sublist.refl l).cons₂ a - -theorem Sublist.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ <+ l₂) (h₂ : l₂ <+ l₃) : l₁ <+ l₃ := by - induction h₂ generalizing l₁ with - | slnil => exact h₁ - | cons _ _ IH => exact (IH h₁).cons _ - | @cons₂ l₂ _ a _ IH => - generalize e : a :: l₂ = l₂' - match e ▸ h₁ with - | .slnil => apply nil_sublist - | .cons a' h₁' => cases e; apply (IH h₁').cons - | .cons₂ a' h₁' => cases e; apply (IH h₁').cons₂ - -instance : Trans (@Sublist α) Sublist Sublist := ⟨Sublist.trans⟩ - -@[simp] theorem sublist_cons (a : α) (l : List α) : l <+ a :: l := (Sublist.refl l).cons _ - -theorem sublist_of_cons_sublist : a :: l₁ <+ l₂ → l₁ <+ l₂ := - (sublist_cons a l₁).trans - -@[simp] theorem sublist_append_left : ∀ l₁ l₂ : List α, l₁ <+ l₁ ++ l₂ - | [], _ => nil_sublist _ - | _ :: l₁, l₂ => (sublist_append_left l₁ l₂).cons₂ _ - -@[simp] theorem sublist_append_right : ∀ l₁ l₂ : List α, l₂ <+ l₁ ++ l₂ - | [], _ => Sublist.refl _ - | _ :: l₁, l₂ => (sublist_append_right l₁ l₂).cons _ - -theorem sublist_append_of_sublist_left (s : l <+ l₁) : l <+ l₁ ++ l₂ := - s.trans <| sublist_append_left .. - -theorem sublist_append_of_sublist_right (s : l <+ l₂) : l <+ l₁ ++ l₂ := - s.trans <| sublist_append_right .. - -@[simp] -theorem cons_sublist_cons : a :: l₁ <+ a :: l₂ ↔ l₁ <+ l₂ := - ⟨fun | .cons _ s => sublist_of_cons_sublist s | .cons₂ _ s => s, .cons₂ _⟩ - -@[simp] theorem append_sublist_append_left : ∀ l, l ++ l₁ <+ l ++ l₂ ↔ l₁ <+ l₂ - | [] => Iff.rfl - | _ :: l => cons_sublist_cons.trans (append_sublist_append_left l) - -theorem Sublist.append_left : l₁ <+ l₂ → ∀ l, l ++ l₁ <+ l ++ l₂ := - fun h l => (append_sublist_append_left l).mpr h - -theorem Sublist.append_right : l₁ <+ l₂ → ∀ l, l₁ ++ l <+ l₂ ++ l - | .slnil, _ => Sublist.refl _ - | .cons _ h, _ => (h.append_right _).cons _ - | .cons₂ _ h, _ => (h.append_right _).cons₂ _ - -theorem sublist_or_mem_of_sublist (h : l <+ l₁ ++ a :: l₂) : l <+ l₁ ++ l₂ ∨ a ∈ l := by - induction l₁ generalizing l with - | nil => match h with - | .cons _ h => exact .inl h - | .cons₂ _ h => exact .inr (.head ..) - | cons b l₁ IH => - match h with - | .cons _ h => exact (IH h).imp_left (Sublist.cons _) - | .cons₂ _ h => exact (IH h).imp (Sublist.cons₂ _) (.tail _) - -theorem Sublist.reverse : l₁ <+ l₂ → l₁.reverse <+ l₂.reverse - | .slnil => Sublist.refl _ - | .cons _ h => by rw [reverse_cons]; exact sublist_append_of_sublist_left h.reverse - | .cons₂ _ h => by rw [reverse_cons, reverse_cons]; exact h.reverse.append_right _ - -@[simp] theorem reverse_sublist : l₁.reverse <+ l₂.reverse ↔ l₁ <+ l₂ := - ⟨fun h => l₁.reverse_reverse ▸ l₂.reverse_reverse ▸ h.reverse, Sublist.reverse⟩ - -@[simp] theorem append_sublist_append_right (l) : l₁ ++ l <+ l₂ ++ l ↔ l₁ <+ l₂ := - ⟨fun h => by - have := h.reverse - simp only [reverse_append, append_sublist_append_left, reverse_sublist] at this - exact this, - fun h => h.append_right l⟩ - -theorem Sublist.append (hl : l₁ <+ l₂) (hr : r₁ <+ r₂) : l₁ ++ r₁ <+ l₂ ++ r₂ := - (hl.append_right _).trans ((append_sublist_append_left _).2 hr) - -theorem Sublist.subset : l₁ <+ l₂ → l₁ ⊆ l₂ - | .slnil, _, h => h - | .cons _ s, _, h => .tail _ (s.subset h) - | .cons₂ .., _, .head .. => .head .. - | .cons₂ _ s, _, .tail _ h => .tail _ (s.subset h) - -instance : Trans (@Sublist α) Subset Subset := - ⟨fun h₁ h₂ => trans h₁.subset h₂⟩ - -instance : Trans Subset (@Sublist α) Subset := - ⟨fun h₁ h₂ => trans h₁ h₂.subset⟩ - -instance : Trans (Membership.mem : α → List α → Prop) Sublist Membership.mem := - ⟨fun h₁ h₂ => h₂.subset h₁⟩ - -theorem Sublist.length_le : l₁ <+ l₂ → length l₁ ≤ length l₂ - | .slnil => Nat.le_refl 0 - | .cons _l s => le_succ_of_le (length_le s) - | .cons₂ _ s => succ_le_succ (length_le s) - -@[simp] theorem sublist_nil {l : List α} : l <+ [] ↔ l = [] := - ⟨fun s => subset_nil.1 s.subset, fun H => H ▸ Sublist.refl _⟩ - -theorem Sublist.eq_of_length : l₁ <+ l₂ → length l₁ = length l₂ → l₁ = l₂ - | .slnil, _ => rfl - | .cons a s, h => nomatch Nat.not_lt.2 s.length_le (h ▸ lt_succ_self _) - | .cons₂ a s, h => by rw [s.eq_of_length (succ.inj h)] - -theorem Sublist.eq_of_length_le (s : l₁ <+ l₂) (h : length l₂ ≤ length l₁) : l₁ = l₂ := - s.eq_of_length <| Nat.le_antisymm s.length_le h - -@[simp] theorem singleton_sublist {a : α} {l} : [a] <+ l ↔ a ∈ l := by - refine ⟨fun h => h.subset (mem_singleton_self _), fun h => ?_⟩ - obtain ⟨_, _, rfl⟩ := append_of_mem h - exact ((nil_sublist _).cons₂ _).trans (sublist_append_right ..) - -@[simp] theorem replicate_sublist_replicate {m n} (a : α) : - replicate m a <+ replicate n a ↔ m ≤ n := by - refine ⟨fun h => ?_, fun h => ?_⟩ - · have := h.length_le; simp only [length_replicate] at this ⊢; exact this - · induction h with - | refl => apply Sublist.refl - | step => simp [*, replicate, Sublist.cons] - -theorem isSublist_iff_sublist [BEq α] [LawfulBEq α] {l₁ l₂ : List α} : - l₁.isSublist l₂ ↔ l₁ <+ l₂ := by - cases l₁ <;> cases l₂ <;> simp [isSublist] - case cons.cons hd₁ tl₁ hd₂ tl₂ => - if h_eq : hd₁ = hd₂ then - simp [h_eq, cons_sublist_cons, isSublist_iff_sublist] - else - simp only [beq_iff_eq, h_eq] - constructor - · intro h_sub - apply Sublist.cons - exact isSublist_iff_sublist.mp h_sub - · intro h_sub - cases h_sub - case cons h_sub => - exact isSublist_iff_sublist.mpr h_sub - case cons₂ => - contradiction - -instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+ l₂) := - decidable_of_iff (l₁.isSublist l₂) isSublist_iff_sublist - /-! ### tail -/ theorem tail_eq_tailD (l) : @tail α l = tailD l [] := by cases l <;> rfl @@ -251,27 +49,6 @@ theorem getElem_eq_iff {l : List α} {n : Nat} {h : n < l.length} : l[n] = x ↔ theorem get_eq_iff : List.get l n = x ↔ l.get? n.1 = some x := by simp -theorem getElem?_inj - (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs[i]? = xs[j]?) : i = j := by - induction xs generalizing i j with - | nil => cases h₀ - | cons x xs ih => - match i, j with - | 0, 0 => rfl - | i+1, j+1 => simp; cases h₁ with - | cons ha h₁ => - simp only [getElem?_cons_succ] at h₂ - exact ih (Nat.lt_of_succ_lt_succ h₀) h₁ h₂ - | i+1, 0 => ?_ - | 0, j+1 => ?_ - all_goals - simp only [get?_eq_getElem?, getElem?_cons_zero, getElem?_cons_succ] at h₂ - cases h₁; rename_i h' h - have := h x ?_ rfl; cases this - rw [mem_iff_get?] - simp only [get?_eq_getElem?] - exact ⟨_, h₂⟩; exact ⟨_ , h₂.symm⟩ - @[deprecated getElem?_inj (since := "2024-06-12")] theorem get?_inj (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs.get? i = xs.get? j) : i = j := by @@ -607,9 +384,6 @@ theorem erase_append_right [LawfulBEq α] {a : α} {l₁ : List α} (l₂ : List rw [erase_eq_eraseP, erase_eq_eraseP, eraseP_append_right] intros b h' h''; rw [eq_of_beq h''] at h; exact h h' -theorem erase_sublist (a : α) (l : List α) : l.erase a <+ l := - erase_eq_eraseP' a l ▸ eraseP_sublist l - theorem erase_subset (a : α) (l : List α) : l.erase a ⊆ l := (erase_sublist a l).subset theorem Sublist.erase (a : α) {l₁ l₂ : List α} (h : l₁ <+ l₂) : l₁.erase a <+ l₂.erase a := by @@ -640,21 +414,6 @@ theorem erase_comm [LawfulBEq α] (a b : α) (l : List α) : end erase -/-! ### filter and partition -/ - -@[simp] theorem filter_sublist {p : α → Bool} : ∀ (l : List α), filter p l <+ l - | [] => .slnil - | a :: l => by rw [filter]; split <;> simp [Sublist.cons, Sublist.cons₂, filter_sublist l] - -/-! ### filterMap -/ - -protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) : - filterMap f l₁ <+ filterMap f l₂ := by - induction s <;> simp [filterMap_cons] <;> split <;> simp [*, cons, cons₂] - -theorem Sublist.filter (p : α → Bool) {l₁ l₂} (s : l₁ <+ l₂) : filter p l₁ <+ filter p l₂ := by - rw [← filterMap_eq_filter]; apply s.filterMap - /-! ### findIdx -/ @[simp] theorem findIdx_nil {α : Type _} (p : α → Bool) : [].findIdx p = 0 := rfl @@ -758,32 +517,6 @@ theorem findIdx?_of_eq_none {xs : List α} {p : α → Bool} (w : xs.findIdx? p simp only [replicate, findIdx?_cons, Nat.zero_add, findIdx?_succ, Nat.zero_lt_succ, true_and] split <;> simp_all -/-! ### pairwise -/ - -theorem Pairwise.sublist : l₁ <+ l₂ → l₂.Pairwise R → l₁.Pairwise R - | .slnil, h => h - | .cons _ s, .cons _ h₂ => h₂.sublist s - | .cons₂ _ s, .cons h₁ h₂ => (h₂.sublist s).cons fun _ h => h₁ _ (s.subset h) - -theorem pairwise_map {l : List α} : - (l.map f).Pairwise R ↔ l.Pairwise fun a b => R (f a) (f b) := by - induction l - · simp - · simp only [map, pairwise_cons, forall_mem_map_iff, *] - -theorem pairwise_append {l₁ l₂ : List α} : - (l₁ ++ l₂).Pairwise R ↔ l₁.Pairwise R ∧ l₂.Pairwise R ∧ ∀ a ∈ l₁, ∀ b ∈ l₂, R a b := by - induction l₁ <;> simp [*, or_imp, forall_and, and_assoc, and_left_comm] - -theorem pairwise_reverse {l : List α} : - l.reverse.Pairwise R ↔ l.Pairwise (fun a b => R b a) := by - induction l <;> simp [*, pairwise_append, and_comm] - -theorem Pairwise.imp {α R S} (H : ∀ {a b}, R a b → S a b) : - ∀ {l : List α}, l.Pairwise R → l.Pairwise S - | _, .nil => .nil - | _, .cons h₁ h₂ => .cons (H ∘ h₁ ·) (h₂.imp H) - /-! ### replaceF -/ theorem replaceF_nil : [].replaceF p = [] := rfl diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index 83b935f8ae..f7eda7b68f 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -255,11 +255,6 @@ theorem pairwise_iff_get : Pairwise R l ↔ ∀ (i j) (_hij : i < j), R (get l i · intros i j hi hj h' exact h ⟨i, hi⟩ ⟨j, hj⟩ h' -theorem pairwise_replicate {α : Type _} {r : α → α → Prop} {x : α} (hx : r x x) : - ∀ n : Nat, Pairwise r (List.replicate n x) - | 0 => by simp - | n + 1 => by simp [mem_replicate, hx, pairwise_replicate hx n, replicate_succ] - /-! ### Pairwise filtering -/ @[simp] theorem pwFilter_nil [DecidableRel R] : pwFilter R [] = [] := rfl diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index 49e45ecc8b..035c5f10f5 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -437,12 +437,12 @@ theorem Nodup.perm_iff_eq_of_sublist {l₁ l₂ l : List α} (d : Nodup l) | .cons _ s₁ => exact IH d.2 s₁ h | .cons₂ _ s₁ => have := Subperm.subset ⟨_, h.symm, s₂⟩ (.head _) - exact (d.1 _ this rfl).elim + exact (d.1 this).elim | cons₂ a _ IH => match s₁ with | .cons _ s₁ => have := Subperm.subset ⟨_, h, s₁⟩ (.head _) - exact (d.1 _ this rfl).elim + exact (d.1 this).elim | .cons₂ _ s₁ => rw [IH d.2 s₁ h.cons_inv] section DecidableEq diff --git a/Batteries/Data/RBMap/Lemmas.lean b/Batteries/Data/RBMap/Lemmas.lean index 37f24ebea9..5577b3a1a7 100644 --- a/Batteries/Data/RBMap/Lemmas.lean +++ b/Batteries/Data/RBMap/Lemmas.lean @@ -152,7 +152,6 @@ theorem min?_eq_toList_head? {t : RBNode α} : t.min? = t.toList.head? := by | nil => rfl | node _ l _ _ ih => cases l <;> simp [RBNode.min?, ih] - next ll _ _ => cases toList ll <;> rfl theorem max?_eq_toList_getLast? {t : RBNode α} : t.max? = t.toList.getLast? := by rw [← min?_reverse, min?_eq_toList_head?]; simp From e281dfd3dc43502533ddb10312cf1904dd0b7b0e Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 10 Jul 2024 23:44:58 +1000 Subject: [PATCH 116/208] lint --- Batteries/Data/List/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index d000469cfe..723f6b6191 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -269,7 +269,7 @@ theorem insertNthTR_go_eq : ∀ n l, insertNthTR.go a n l acc = acc.data ++ inse @[csimp] theorem insertNth_eq_insertNthTR : @insertNth = @insertNthTR := by funext α f n l; simp [insertNthTR, insertNthTR_go_eq] -@[simp] theorem headD_eq_head? (l) (a : α) : headD l a = (head? l).getD a := by cases l <;> rfl +theorem headD_eq_head? (l) (a : α) : headD l a = (head? l).getD a := by cases l <;> rfl /-- Take `n` elements from a list `l`. If `l` has less than `n` elements, append `n - length l` From 178f8e16e67eac807b2ff18a13ab3715553619cb Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Thu, 11 Jul 2024 09:05:15 +0000 Subject: [PATCH 117/208] chore: bump to nightly-2024-07-11 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 71dae0afae..93df21fce6 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-10 +leanprover/lean4:nightly-2024-07-11 From 39e0ffedb7fe061bbb5602539efd13ea61906da9 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 11 Jul 2024 23:03:16 +1000 Subject: [PATCH 118/208] fix --- Batteries/Data/List/Basic.lean | 23 ----- Batteries/Data/List/Count.lean | 4 +- Batteries/Data/List/Lemmas.lean | 143 ------------------------------ Batteries/Data/List/Pairwise.lean | 4 +- Batteries/Data/List/Perm.lean | 2 +- 5 files changed, 5 insertions(+), 171 deletions(-) diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index 723f6b6191..de1ae7b9f2 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -629,29 +629,6 @@ theorem sections_eq_nil_of_isEmpty : ∀ {L}, L.any isEmpty → @sections α L = rw [Array.foldl_eq_foldl_data, Array.foldl_data_eq_bind]; rfl intros; apply Array.foldl_data_eq_map -/-- `eraseP p l` removes the first element of `l` satisfying the predicate `p`. -/ -def eraseP (p : α → Bool) : List α → List α - | [] => [] - | a :: l => bif p a then l else a :: eraseP p l - -/-- Tail-recursive version of `eraseP`. -/ -@[inline] def erasePTR (p : α → Bool) (l : List α) : List α := go l #[] where - /-- Auxiliary for `erasePTR`: `erasePTR.go p l xs acc = acc.toList ++ eraseP p xs`, - unless `xs` does not contain any elements satisfying `p`, where it returns `l`. -/ - @[specialize] go : List α → Array α → List α - | [], _ => l - | a :: l, acc => bif p a then acc.toListAppend l else go l (acc.push a) - -@[csimp] theorem eraseP_eq_erasePTR : @eraseP = @erasePTR := by - funext α p l; simp [erasePTR] - let rec go (acc) : ∀ xs, l = acc.data ++ xs → - erasePTR.go p l xs acc = acc.data ++ xs.eraseP p - | [] => fun h => by simp [erasePTR.go, eraseP, h] - | x::xs => by - simp [erasePTR.go, eraseP]; cases p x <;> simp - · intro h; rw [go _ xs]; {simp}; simp [h] - exact (go #[] _ rfl).symm - /-- `extractP p l` returns a pair of an element `a` of `l` satisfying the predicate `p`, and `l`, with `a` removed. If there is no such element `a` it returns `(none, l)`. diff --git a/Batteries/Data/List/Count.lean b/Batteries/Data/List/Count.lean index dfd1481052..a118a8a704 100644 --- a/Batteries/Data/List/Count.lean +++ b/Batteries/Data/List/Count.lean @@ -62,8 +62,8 @@ theorem countP_eq_length_filter (l) : countP p l = length (filter p l) := by | nil => rfl | cons x l ih => if h : p x - then rw [countP_cons_of_pos p l h, ih, filter_cons_of_pos l h, length] - else rw [countP_cons_of_neg p l h, ih, filter_cons_of_neg l h] + then rw [countP_cons_of_pos p l h, ih, filter_cons_of_pos h, length] + else rw [countP_cons_of_neg p l h, ih, filter_cons_of_neg h] theorem countP_le_length : countP p l ≤ l.length := by simp only [countP_eq_length_filter] diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 32f49b761f..0ed6e00abb 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -252,93 +252,6 @@ theorem length_eraseIdx : ∀ {l i}, i < length l → length (@eraseIdx α l i) /-! ### eraseP -/ -@[simp] theorem eraseP_nil : [].eraseP p = [] := rfl - -theorem eraseP_cons (a : α) (l : List α) : - (a :: l).eraseP p = bif p a then l else a :: l.eraseP p := rfl - -@[simp] theorem eraseP_cons_of_pos {l : List α} (p) (h : p a) : (a :: l).eraseP p = l := by - simp [eraseP_cons, h] - -@[simp] theorem eraseP_cons_of_neg {l : List α} (p) (h : ¬p a) : - (a :: l).eraseP p = a :: l.eraseP p := by simp [eraseP_cons, h] - -theorem eraseP_of_forall_not {l : List α} (h : ∀ a, a ∈ l → ¬p a) : l.eraseP p = l := by - induction l with - | nil => rfl - | cons _ _ ih => simp [h _ (.head ..), ih (forall_mem_cons.1 h).2] - -theorem exists_of_eraseP : ∀ {l : List α} {a} (al : a ∈ l) (pa : p a), - ∃ a l₁ l₂, (∀ b ∈ l₁, ¬p b) ∧ p a ∧ l = l₁ ++ a :: l₂ ∧ l.eraseP p = l₁ ++ l₂ - | b :: l, a, al, pa => - if pb : p b then - ⟨b, [], l, forall_mem_nil _, pb, by simp [pb]⟩ - else - match al with - | .head .. => nomatch pb pa - | .tail _ al => - let ⟨c, l₁, l₂, h₁, h₂, h₃, h₄⟩ := exists_of_eraseP al pa - ⟨c, b::l₁, l₂, (forall_mem_cons ..).2 ⟨pb, h₁⟩, - h₂, by rw [h₃, cons_append], by simp [pb, h₄]⟩ - -theorem exists_or_eq_self_of_eraseP (p) (l : List α) : - l.eraseP p = l ∨ - ∃ a l₁ l₂, (∀ b ∈ l₁, ¬p b) ∧ p a ∧ l = l₁ ++ a :: l₂ ∧ l.eraseP p = l₁ ++ l₂ := - if h : ∃ a ∈ l, p a then - let ⟨_, ha, pa⟩ := h - .inr (exists_of_eraseP ha pa) - else - .inl (eraseP_of_forall_not (h ⟨·, ·, ·⟩)) - -@[simp] theorem length_eraseP_of_mem (al : a ∈ l) (pa : p a) : - length (l.eraseP p) = Nat.pred (length l) := by - let ⟨_, l₁, l₂, _, _, e₁, e₂⟩ := exists_of_eraseP al pa - rw [e₂]; simp [length_append, e₁]; rfl - -theorem eraseP_append_left {a : α} (pa : p a) : - ∀ {l₁ : List α} l₂, a ∈ l₁ → (l₁++l₂).eraseP p = l₁.eraseP p ++ l₂ - | x :: xs, l₂, h => by - by_cases h' : p x <;> simp [h'] - rw [eraseP_append_left pa l₂ ((mem_cons.1 h).resolve_left (mt _ h'))] - intro | rfl => exact pa - -theorem eraseP_append_right : - ∀ {l₁ : List α} l₂, (∀ b ∈ l₁, ¬p b) → eraseP p (l₁++l₂) = l₁ ++ l₂.eraseP p - | [], l₂, _ => rfl - | x :: xs, l₂, h => by - simp [(forall_mem_cons.1 h).1, eraseP_append_right _ (forall_mem_cons.1 h).2] - -theorem eraseP_sublist (l : List α) : l.eraseP p <+ l := by - match exists_or_eq_self_of_eraseP p l with - | .inl h => rw [h]; apply Sublist.refl - | .inr ⟨c, l₁, l₂, _, _, h₃, h₄⟩ => rw [h₄, h₃]; simp - -theorem eraseP_subset (l : List α) : l.eraseP p ⊆ l := (eraseP_sublist l).subset - -protected theorem Sublist.eraseP : l₁ <+ l₂ → l₁.eraseP p <+ l₂.eraseP p - | .slnil => Sublist.refl _ - | .cons a s => by - by_cases h : p a <;> simp [h] - exacts [s.eraseP.trans (eraseP_sublist _), s.eraseP.cons _] - | .cons₂ a s => by - by_cases h : p a <;> simp [h] - exacts [s, s.eraseP] - -theorem mem_of_mem_eraseP {l : List α} : a ∈ l.eraseP p → a ∈ l := (eraseP_subset _ ·) - -@[simp] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a ∈ l.eraseP p ↔ a ∈ l := by - refine ⟨mem_of_mem_eraseP, fun al => ?_⟩ - match exists_or_eq_self_of_eraseP p l with - | .inl h => rw [h]; assumption - | .inr ⟨c, l₁, l₂, h₁, h₂, h₃, h₄⟩ => - rw [h₄]; rw [h₃] at al - have : a ≠ c := fun h => (h ▸ pa).elim h₂ - simp [this] at al; simp [al] - -theorem eraseP_map (f : β → α) : ∀ (l : List β), (map f l).eraseP p = map f (l.eraseP (p ∘ f)) - | [] => rfl - | b::l => by by_cases h : p (f b) <;> simp [h, eraseP_map f l, eraseP_cons_of_pos] - @[simp] theorem extractP_eq_find?_eraseP (l : List α) : extractP p l = (find? p l, eraseP p l) := by let rec go (acc) : ∀ xs, l = acc.data ++ xs → @@ -354,64 +267,8 @@ theorem eraseP_map (f : β → α) : ∀ (l : List β), (map f l).eraseP p = map section erase variable [BEq α] -theorem erase_eq_eraseP' (a : α) (l : List α) : l.erase a = l.eraseP (· == a) := by - induction l - · simp - · next b t ih => - rw [erase_cons, eraseP_cons, ih] - if h : b == a then simp [h] else simp [h] - -theorem erase_eq_eraseP [LawfulBEq α] (a : α) : ∀ l : List α, l.erase a = l.eraseP (a == ·) - | [] => rfl - | b :: l => by - if h : a = b then simp [h] else simp [h, Ne.symm h, erase_eq_eraseP a l] - -theorem exists_erase_eq [LawfulBEq α] {a : α} {l : List α} (h : a ∈ l) : - ∃ l₁ l₂, a ∉ l₁ ∧ l = l₁ ++ a :: l₂ ∧ l.erase a = l₁ ++ l₂ := by - let ⟨_, l₁, l₂, h₁, e, h₂, h₃⟩ := exists_of_eraseP h (beq_self_eq_true _) - rw [erase_eq_eraseP]; exact ⟨l₁, l₂, fun h => h₁ _ h (beq_self_eq_true _), eq_of_beq e ▸ h₂, h₃⟩ - -@[simp] theorem length_erase_of_mem [LawfulBEq α] {a : α} {l : List α} (h : a ∈ l) : - length (l.erase a) = Nat.pred (length l) := by - rw [erase_eq_eraseP]; exact length_eraseP_of_mem h (beq_self_eq_true a) - -theorem erase_append_left [LawfulBEq α] {l₁ : List α} (l₂) (h : a ∈ l₁) : - (l₁ ++ l₂).erase a = l₁.erase a ++ l₂ := by - simp [erase_eq_eraseP]; exact eraseP_append_left (beq_self_eq_true a) l₂ h - -theorem erase_append_right [LawfulBEq α] {a : α} {l₁ : List α} (l₂ : List α) (h : a ∉ l₁) : - (l₁ ++ l₂).erase a = (l₁ ++ l₂.erase a) := by - rw [erase_eq_eraseP, erase_eq_eraseP, eraseP_append_right] - intros b h' h''; rw [eq_of_beq h''] at h; exact h h' - -theorem erase_subset (a : α) (l : List α) : l.erase a ⊆ l := (erase_sublist a l).subset - -theorem Sublist.erase (a : α) {l₁ l₂ : List α} (h : l₁ <+ l₂) : l₁.erase a <+ l₂.erase a := by - simp only [erase_eq_eraseP']; exact h.eraseP @[deprecated (since := "2024-04-22")] alias sublist.erase := Sublist.erase -theorem mem_of_mem_erase {a b : α} {l : List α} (h : a ∈ l.erase b) : a ∈ l := erase_subset _ _ h - -@[simp] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a ≠ b) : - a ∈ l.erase b ↔ a ∈ l := - erase_eq_eraseP b l ▸ mem_eraseP_of_neg (mt eq_of_beq ab.symm) - -theorem erase_comm [LawfulBEq α] (a b : α) (l : List α) : - (l.erase a).erase b = (l.erase b).erase a := by - if ab : a == b then rw [eq_of_beq ab] else ?_ - if ha : a ∈ l then ?_ else - simp only [erase_of_not_mem ha, erase_of_not_mem (mt mem_of_mem_erase ha)] - if hb : b ∈ l then ?_ else - simp only [erase_of_not_mem hb, erase_of_not_mem (mt mem_of_mem_erase hb)] - match l, l.erase a, exists_erase_eq ha with - | _, _, ⟨l₁, l₂, ha', rfl, rfl⟩ => - if h₁ : b ∈ l₁ then - rw [erase_append_left _ h₁, erase_append_left _ h₁, - erase_append_right _ (mt mem_of_mem_erase ha'), erase_cons_head] - else - rw [erase_append_right _ h₁, erase_append_right _ h₁, erase_append_right _ ha', - erase_cons_tail _ ab, erase_cons_head] - end erase /-! ### findIdx -/ diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index f7eda7b68f..9393d316b9 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -134,10 +134,10 @@ theorem pairwise_filterMap (f : β → Option α) {l : List β} : | cons a l IH => ?_ match e : f a with | none => - rw [filterMap_cons_none _ _ e, pairwise_cons] + rw [filterMap_cons_none e, pairwise_cons] simp only [e, false_implies, implies_true, true_and, IH] | some b => - rw [filterMap_cons_some _ _ _ e] + rw [filterMap_cons_some e] simpa [IH, e] using fun _ => ⟨fun h a ha b hab => h _ _ ha hab, fun h a b ha hab => h _ ha _ hab⟩ diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index 035c5f10f5..4e988d6760 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -510,7 +510,7 @@ theorem erase_cons_subperm_cons_erase (a b : α) (l : List α) : rw [h, erase_cons_head]; apply subperm_cons_erase else have : ¬(a == b) = true := by simp only [beq_false_of_ne h, not_false_eq_true] - rw [erase_cons_tail _ this] + rw [erase_cons_tail this] theorem subperm_cons_diff {a : α} {l₁ l₂ : List α} : (a :: l₁).diff l₂ <+~ a :: l₁.diff l₂ := by induction l₂ with From d5260fa05f3d85c4c7570a79f1133f7521799f84 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 12 Jul 2024 09:05:05 +0000 Subject: [PATCH 119/208] chore: bump to nightly-2024-07-12 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 93df21fce6..9f1d2860a1 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-11 +leanprover/lean4:nightly-2024-07-12 From c7ba334ec6e39cc5a804729b535cafb710efdc35 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 15 Jul 2024 12:52:12 -0500 Subject: [PATCH 120/208] chore: adaptations for nightly-2024-07-10 (#878) --- Batteries.lean | 3 - Batteries/Classes/BEq.lean | 18 -- Batteries/Data/Array/Merge.lean | 14 +- Batteries/Data/BitVec/Lemmas.lean | 9 +- Batteries/Data/Bool.lean | 6 +- Batteries/Data/Char.lean | 5 - Batteries/Data/HashMap/Basic.lean | 1 - Batteries/Data/HashMap/Lemmas.lean | 14 +- Batteries/Data/HashMap/WF.lean | 6 +- Batteries/Data/Int/Order.lean | 2 +- Batteries/Data/List/Basic.lean | 89 +-------- Batteries/Data/List/Count.lean | 4 +- Batteries/Data/List/Lemmas.lean | 286 +--------------------------- Batteries/Data/List/Pairwise.lean | 7 +- Batteries/Data/List/Perm.lean | 4 +- Batteries/Data/Nat/Lemmas.lean | 16 +- Batteries/Data/Option/Lemmas.lean | 4 +- Batteries/Data/RBMap/Basic.lean | 12 +- Batteries/Data/RBMap/Lemmas.lean | 1 - Batteries/Data/String/Lemmas.lean | 6 +- Batteries/Data/UInt.lean | 10 - Batteries/Data/UnionFind/Basic.lean | 104 ++++++---- Batteries/Lean/Delaborator.lean | 2 +- Batteries/Lean/SMap.lean | 17 -- Batteries/Lean/Util/Path.lean | 34 ---- Batteries/Logic.lean | 13 +- Batteries/StdDeprecations.lean | 58 +++--- lean-toolchain | 2 +- scripts/runLinter.lean | 2 +- test/congr.lean | 2 - 30 files changed, 170 insertions(+), 581 deletions(-) delete mode 100644 Batteries/Classes/BEq.lean delete mode 100644 Batteries/Lean/SMap.lean delete mode 100644 Batteries/Lean/Util/Path.lean diff --git a/Batteries.lean b/Batteries.lean index 2fac3bf121..81878f133b 100644 --- a/Batteries.lean +++ b/Batteries.lean @@ -1,4 +1,3 @@ -import Batteries.Classes.BEq import Batteries.Classes.Cast import Batteries.Classes.Order import Batteries.Classes.RatCast @@ -64,12 +63,10 @@ import Batteries.Lean.NameMapAttribute import Batteries.Lean.PersistentHashMap import Batteries.Lean.PersistentHashSet import Batteries.Lean.Position -import Batteries.Lean.SMap import Batteries.Lean.Syntax import Batteries.Lean.System.IO import Batteries.Lean.TagAttribute import Batteries.Lean.Util.EnvSearch -import Batteries.Lean.Util.Path import Batteries.Linter import Batteries.Linter.UnnecessarySeqFocus import Batteries.Linter.UnreachableTactic diff --git a/Batteries/Classes/BEq.lean b/Batteries/Classes/BEq.lean deleted file mode 100644 index 98318f97c9..0000000000 --- a/Batteries/Classes/BEq.lean +++ /dev/null @@ -1,18 +0,0 @@ -/- -Copyright (c) 2022 Mario Carneiro. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mario Carneiro --/ - -/-! ## Boolean equality -/ - -/-- `PartialEquivBEq α` says that the `BEq` implementation is a -partial equivalence relation, that is: -* it is symmetric: `a == b → b == a` -* it is transitive: `a == b → b == c → a == c`. --/ -class PartialEquivBEq (α) [BEq α] : Prop where - /-- Symmetry for `BEq`. If `a == b` then `b == a`. -/ - symm : (a : α) == b → b == a - /-- Transitivity for `BEq`. If `a == b` and `b == c` then `a == c`. -/ - trans : (a : α) == b → b == c → a == c diff --git a/Batteries/Data/Array/Merge.lean b/Batteries/Data/Array/Merge.lean index 1486520565..aa83e0200b 100644 --- a/Batteries/Data/Array/Merge.lean +++ b/Batteries/Data/Array/Merge.lean @@ -27,7 +27,7 @@ where termination_by xs.size + ys.size - (i + j) set_option linter.unusedVariables false in -@[deprecated merge, inherit_doc merge] +@[deprecated merge (since := "2024-04-24"), inherit_doc merge] def mergeSortedPreservingDuplicates [ord : Ord α] (xs ys : Array α) : Array α := merge (compare · · |>.isLT) xs ys @@ -55,7 +55,7 @@ where | .eq => go (acc.push (merge x y)) (i + 1) (j + 1) termination_by xs.size + ys.size - (i + j) -@[deprecated] alias mergeSortedMergingDuplicates := mergeDedupWith +@[deprecated (since := "2024-04-24")] alias mergeSortedMergingDuplicates := mergeDedupWith /-- `O(|xs| + |ys|)`. Merge arrays `xs` and `ys`, which must be sorted according to `compare` and must @@ -64,7 +64,7 @@ not contain duplicates. If an element appears in both `xs` and `ys`, only one co @[inline] def mergeDedup [ord : Ord α] (xs ys : Array α) : Array α := mergeDedupWith (ord := ord) xs ys fun x _ => x -@[deprecated] alias mergeSortedDeduplicating := mergeDedup +@[deprecated (since := "2024-04-24")] alias mergeSortedDeduplicating := mergeDedup set_option linter.unusedVariables false in /-- @@ -83,7 +83,7 @@ where ys.foldl (init := xs) fun xs y => if xs.any (· == y) (stop := xsSize) then xs else xs.push y -@[deprecated] alias mergeUnsortedDeduplicating := mergeUnsortedDedup +@[deprecated (since := "2024-04-24")] alias mergeUnsortedDeduplicating := mergeUnsortedDedup /-- `O(|xs|)`. Replace each run `[x₁, ⋯, xₙ]` of equal elements in `xs` with @@ -101,7 +101,7 @@ where acc.push hd termination_by xs.size - i -@[deprecated] alias mergeAdjacentDuplicates := mergeAdjacentDups +@[deprecated (since := "2024-04-24")] alias mergeAdjacentDuplicates := mergeAdjacentDups /-- `O(|xs|)`. Deduplicate a sorted array. The array must be sorted with to an order which agrees with @@ -110,13 +110,13 @@ where def dedupSorted [eq : BEq α] (xs : Array α) : Array α := xs.mergeAdjacentDups (eq := eq) fun x _ => x -@[deprecated] alias deduplicateSorted := dedupSorted +@[deprecated (since := "2024-04-24")] alias deduplicateSorted := dedupSorted /-- `O(|xs| log |xs|)`. Sort and deduplicate an array. -/ def sortDedup [ord : Ord α] (xs : Array α) : Array α := have := ord.toBEq dedupSorted <| xs.qsort (compare · · |>.isLT) -@[deprecated] alias sortAndDeduplicate := sortDedup +@[deprecated (since := "2024-04-24")] alias sortAndDeduplicate := sortDedup end Array diff --git a/Batteries/Data/BitVec/Lemmas.lean b/Batteries/Data/BitVec/Lemmas.lean index e0e45b8cb0..2bcd3ce4aa 100644 --- a/Batteries/Data/BitVec/Lemmas.lean +++ b/Batteries/Data/BitVec/Lemmas.lean @@ -7,13 +7,10 @@ import Batteries.Tactic.Alias namespace BitVec -/-- Replaced 2024-02-07. -/ -@[deprecated] alias zero_is_unique := eq_nil +@[deprecated (since := "2024-02-07")] alias zero_is_unique := eq_nil /-! ### sub/neg -/ -/-- Replaced 2024-02-06. -/ -@[deprecated] alias sub_toNat := toNat_sub +@[deprecated (since := "2024-02-07")] alias sub_toNat := toNat_sub -/-- Replaced 2024-02-06. -/ -@[deprecated] alias neg_toNat := toNat_neg +@[deprecated (since := "2024-02-07")] alias neg_toNat := toNat_neg diff --git a/Batteries/Data/Bool.lean b/Batteries/Data/Bool.lean index ab48cbc578..b6c0c9b4e7 100644 --- a/Batteries/Data/Bool.lean +++ b/Batteries/Data/Bool.lean @@ -10,10 +10,10 @@ namespace Bool /-! ### injectivity lemmas -/ -@[deprecated] alias not_inj' := not_inj_iff +@[deprecated (since := "2023-10-27")] alias not_inj' := not_inj_iff -@[deprecated] alias and_or_inj_right' := and_or_inj_right_iff +@[deprecated (since := "2023-10-27")] alias and_or_inj_right' := and_or_inj_right_iff -@[deprecated] alias and_or_inj_left' := and_or_inj_left_iff +@[deprecated (since := "2023-10-27")] alias and_or_inj_left' := and_or_inj_left_iff end Bool diff --git a/Batteries/Data/Char.lean b/Batteries/Data/Char.lean index 5a9110ae12..4f3c59ef0b 100644 --- a/Batteries/Data/Char.lean +++ b/Batteries/Data/Char.lean @@ -6,11 +6,6 @@ Authors: Jannis Limperg import Batteries.Data.UInt import Batteries.Tactic.Alias -@[ext] theorem Char.ext : {a b : Char} → a.val = b.val → a = b - | ⟨_,_⟩, ⟨_,_⟩, rfl => rfl - -theorem Char.ext_iff {x y : Char} : x = y ↔ x.val = y.val := ⟨congrArg _, Char.ext⟩ - theorem Char.le_antisymm_iff {x y : Char} : x = y ↔ x ≤ y ∧ y ≤ x := Char.ext_iff.trans UInt32.le_antisymm_iff diff --git a/Batteries/Data/HashMap/Basic.lean b/Batteries/Data/HashMap/Basic.lean index 106fea1e4d..3419ba35ab 100644 --- a/Batteries/Data/HashMap/Basic.lean +++ b/Batteries/Data/HashMap/Basic.lean @@ -6,7 +6,6 @@ Authors: Leonardo de Moura, Mario Carneiro import Batteries.Data.AssocList import Batteries.Data.Nat.Basic import Batteries.Data.Array.Monadic -import Batteries.Classes.BEq namespace Batteries.HashMap diff --git a/Batteries/Data/HashMap/Lemmas.lean b/Batteries/Data/HashMap/Lemmas.lean index 50efb40455..290f4c0cff 100644 --- a/Batteries/Data/HashMap/Lemmas.lean +++ b/Batteries/Data/HashMap/Lemmas.lean @@ -5,7 +5,13 @@ Authors: Scott Morrison -/ import Batteries.Data.HashMap.Basic import Batteries.Data.Array.Lemmas -import Batteries.Util.ProofWanted + +/-! +# Lemmas for `Batteries.HashMap` + +Note that Lean core provides an alternative hash map implementation, `Std.HashMap`, which comes with +more lemmas. See the module `Std.Data.HashMap.Lemmas`. +-/ namespace Batteries.HashMap @@ -21,5 +27,7 @@ end Imp @[simp] theorem empty_find? [BEq α] [Hashable α] {a : α} : (∅ : HashMap α β).find? a = none := by simp [find?, Imp.find?] -proof_wanted insert_find? [BEq α] [Hashable α] (m : HashMap α β) (a a' : α) (b : β) : - (m.insert a b).find? a' = if a' == a then some b else m.find? a' +-- `Std.HashMap` has this lemma (as `getElem?_insert`) and many more, so working on this +-- `proof_wanted` is likely not a good use of your time. +-- proof_wanted insert_find? [BEq α] [Hashable α] (m : HashMap α β) (a a' : α) (b : β) : +-- (m.insert a b).find? a' = if a' == a then some b else m.find? a' diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index f6298d3322..f7ee6ed1da 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -24,7 +24,7 @@ theorem exists_of_update (self : Buckets α β) (i d h) : ∃ l₁ l₂, self.1.data = l₁ ++ self.1[i] :: l₂ ∧ List.length l₁ = i.toNat ∧ (self.update i d h).1.data = l₁ ++ d :: l₂ := by simp only [Array.data_length, Array.ugetElem_eq_getElem, Array.getElem_eq_data_getElem] - exact List.exists_of_set' h + exact List.exists_of_set h theorem update_update (self : Buckets α β) (i d d' h h') : (self.update i d h).update i d' h' = self.update i d' h := by @@ -95,11 +95,11 @@ where · next H => refine (go (i+1) _ _ fun j hj => ?a).trans ?b <;> simp · case a => - simp [List.getD_eq_getElem?, List.getElem?_set, Option.map_eq_map]; split + simp [List.getD_eq_getElem?_getD, List.getElem?_set, Option.map_eq_map]; split · cases source.data[j]? <;> rfl · next H => exact hs _ (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ hj) (Ne.symm H)) · case b => - refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set' H; eq ▸ ?_ + refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set H; eq ▸ ?_ rw [h₁] simp only [Buckets.size_eq, List.map_append, List.map_cons, AssocList.toList, List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length] diff --git a/Batteries/Data/Int/Order.lean b/Batteries/Data/Int/Order.lean index 3855f19885..daab75c612 100644 --- a/Batteries/Data/Int/Order.lean +++ b/Batteries/Data/Int/Order.lean @@ -7,4 +7,4 @@ import Batteries.Tactic.Alias namespace Int -@[deprecated] alias ofNat_natAbs_eq_of_nonneg := natAbs_of_nonneg +@[deprecated (since := "2024-01-24")] alias ofNat_natAbs_eq_of_nonneg := natAbs_of_nonneg diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index a8c3fef85a..723f6b6191 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -10,16 +10,6 @@ namespace List /-! ## New definitions -/ -/-- -`l₁ ⊆ l₂` means that every element of `l₁` is also an element of `l₂`, ignoring multiplicity. --/ -protected def Subset (l₁ l₂ : List α) := ∀ ⦃a : α⦄, a ∈ l₁ → a ∈ l₂ - -instance : HasSubset (List α) := ⟨List.Subset⟩ - -instance [DecidableEq α] : DecidableRel (Subset : List α → List α → Prop) := - fun _ _ => decidableBAll _ _ - /-- Computes the "bag intersection" of `l₁` and `l₂`, that is, the collection of elements of `l₁` which are also in `l₂`. As each element @@ -93,9 +83,9 @@ drop_while (· != 1) [0, 1, 2, 3] = [1, 2, 3] /-- Returns the index of the first element equal to `a`, or the length of the list otherwise. -/ def indexOf [BEq α] (a : α) : List α → Nat := findIdx (· == a) -@[deprecated] alias removeNth := eraseIdx -@[deprecated] alias removeNthTR := eraseIdxTR -@[deprecated] alias removeNth_eq_removeNthTR := eraseIdx_eq_eraseIdxTR +@[deprecated (since := "2024-05-06")] alias removeNth := eraseIdx +@[deprecated (since := "2024-05-06")] alias removeNthTR := eraseIdxTR +@[deprecated (since := "2024-05-06")] alias removeNth_eq_removeNthTR := eraseIdx_eq_eraseIdxTR /-- Replaces the first element of the list for which `f` returns `some` with the returned value. -/ @[simp] def replaceF (f : α → Option α) : List α → List α @@ -139,26 +129,6 @@ Unlike `bagInter` this does not preserve multiplicity: `[1, 1].inter [1]` is `[1 instance [BEq α] : Inter (List α) := ⟨List.inter⟩ -/-- `l₁ <+ l₂`, or `Sublist l₁ l₂`, says that `l₁` is a (non-contiguous) subsequence of `l₂`. -/ -inductive Sublist {α} : List α → List α → Prop - /-- the base case: `[]` is a sublist of `[]` -/ - | slnil : Sublist [] [] - /-- If `l₁` is a subsequence of `l₂`, then it is also a subsequence of `a :: l₂`. -/ - | cons a : Sublist l₁ l₂ → Sublist l₁ (a :: l₂) - /-- If `l₁` is a subsequence of `l₂`, then `a :: l₁` is a subsequence of `a :: l₂`. -/ - | cons₂ a : Sublist l₁ l₂ → Sublist (a :: l₁) (a :: l₂) - -@[inherit_doc] scoped infixl:50 " <+ " => Sublist - -/-- True if the first list is a potentially non-contiguous sub-sequence of the second list. -/ -def isSublist [BEq α] : List α → List α → Bool - | [], _ => true - | _, [] => false - | l₁@(hd₁::tl₁), hd₂::tl₂ => - if hd₁ == hd₂ - then tl₁.isSublist tl₂ - else l₁.isSublist tl₂ - /-- Split a list at an index. ``` @@ -299,7 +269,7 @@ theorem insertNthTR_go_eq : ∀ n l, insertNthTR.go a n l acc = acc.data ++ inse @[csimp] theorem insertNth_eq_insertNthTR : @insertNth = @insertNthTR := by funext α f n l; simp [insertNthTR, insertNthTR_go_eq] -@[simp] theorem headD_eq_head? (l) (a : α) : headD l a = (head? l).getD a := by cases l <;> rfl +theorem headD_eq_head? (l) (a : α) : headD l a = (head? l).getD a := by cases l <;> rfl /-- Take `n` elements from a list `l`. If `l` has less than `n` elements, append `n - length l` @@ -806,46 +776,6 @@ where rename_i a as b bs; unfold cond; cases R a b <;> simp [go as bs] exact (go as bs [] []).symm -section Pairwise - -variable (R : α → α → Prop) - -/-- -`Pairwise R l` means that all the elements with earlier indexes are -`R`-related to all the elements with later indexes. -``` -Pairwise R [1, 2, 3] ↔ R 1 2 ∧ R 1 3 ∧ R 2 3 -``` -For example if `R = (·≠·)` then it asserts `l` has no duplicates, -and if `R = (·<·)` then it asserts that `l` is (strictly) sorted. --/ -inductive Pairwise : List α → Prop - /-- All elements of the empty list are vacuously pairwise related. -/ - | nil : Pairwise [] - /-- `a :: l` is `Pairwise R` if `a` `R`-relates to every element of `l`, - and `l` is `Pairwise R`. -/ - | cons : ∀ {a : α} {l : List α}, (∀ a' ∈ l, R a a') → Pairwise l → Pairwise (a :: l) - -attribute [simp] Pairwise.nil - -variable {R} - -@[simp] theorem pairwise_cons : Pairwise R (a::l) ↔ (∀ a' ∈ l, R a a') ∧ Pairwise R l := - ⟨fun | .cons h₁ h₂ => ⟨h₁, h₂⟩, fun ⟨h₁, h₂⟩ => h₂.cons h₁⟩ - -instance instDecidablePairwise [DecidableRel R] : - (l : List α) → Decidable (Pairwise R l) - | [] => isTrue .nil - | hd :: tl => - match instDecidablePairwise tl with - | isTrue ht => - match decidableBAll (R hd) tl with - | isFalse hf => isFalse fun hf' => hf (pairwise_cons.1 hf').1 - | isTrue ht' => isTrue <| pairwise_cons.mpr (And.intro ht' ht) - | isFalse hf => isFalse fun | .cons _ ih => hf ih - -end Pairwise - /-- `pwFilter R l` is a maximal sublist of `l` which is `Pairwise R`. `pwFilter (·≠·)` is the erase duplicates function (cf. `eraseDup`), and `pwFilter (·<·)` finds @@ -881,13 +811,6 @@ def Chain' : List α → Prop end Chain -/-- `Nodup l` means that `l` has no duplicates, that is, any element appears at most - once in the List. It is defined as `Pairwise (≠)`. -/ -def Nodup : List α → Prop := Pairwise (· ≠ ·) - -instance nodupDecidable [DecidableEq α] : ∀ l : List α, Decidable (Nodup l) := - instDecidablePairwise - /-- `eraseDup l` removes duplicates from `l` (taking only the first occurrence). Defined as `pwFilter (≠)`. @@ -926,7 +849,7 @@ def range' : (start len : Nat) → (step : Nat := 1) → List Nat `ilast' x xs` returns the last element of `xs` if `xs` is non-empty; it returns `x` otherwise. Use `List.getLastD` instead. -/ -@[simp, deprecated getLastD] def ilast' {α} : α → List α → α +@[simp, deprecated getLastD (since := "2024-01-09")] def ilast' {α} : α → List α → α | a, [] => a | _, b :: l => ilast' b l @@ -934,7 +857,7 @@ Use `List.getLastD` instead. `last' xs` returns the last element of `xs` if `xs` is non-empty; it returns `none` otherwise. Use `List.getLast?` instead -/ -@[simp, deprecated getLast?] def last' {α} : List α → Option α +@[simp, deprecated getLast? (since := "2024-01-09")] def last' {α} : List α → Option α | [] => none | [a] => some a | _ :: l => last' l diff --git a/Batteries/Data/List/Count.lean b/Batteries/Data/List/Count.lean index 81548ff437..dfd1481052 100644 --- a/Batteries/Data/List/Count.lean +++ b/Batteries/Data/List/Count.lean @@ -196,11 +196,11 @@ theorem filter_beq (l : List α) (a : α) : l.filter (· == a) = replicate (coun theorem filter_eq (l : List α) (a : α) : l.filter (· = a) = replicate (count a l) a := filter_beq l a -@[deprecated filter_eq] +@[deprecated filter_eq (since := "2023-12-14")] theorem filter_eq' (l : List α) (a : α) : l.filter (a = ·) = replicate (count a l) a := by simpa only [eq_comm] using filter_eq l a -@[deprecated filter_beq] +@[deprecated filter_beq (since := "2023-12-14")] theorem filter_beq' (l : List α) (a : α) : l.filter (a == ·) = replicate (count a l) a := by simpa only [eq_comm (b := a)] using filter_eq l a diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 44d9a5c18d..32f49b761f 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -28,208 +28,6 @@ theorem drop_one : ∀ l : List α, drop 1 l = tail l theorem zipWith_distrib_tail : (zipWith f l l').tail = zipWith f l.tail l'.tail := by rw [← drop_one]; simp [zipWith_distrib_drop] -/-! ### List subset -/ - -theorem subset_def {l₁ l₂ : List α} : l₁ ⊆ l₂ ↔ ∀ {a : α}, a ∈ l₁ → a ∈ l₂ := .rfl - -@[simp] theorem nil_subset (l : List α) : [] ⊆ l := nofun - -@[simp] theorem Subset.refl (l : List α) : l ⊆ l := fun _ i => i - -theorem Subset.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ ⊆ l₂) (h₂ : l₂ ⊆ l₃) : l₁ ⊆ l₃ := - fun _ i => h₂ (h₁ i) - -instance : Trans (Membership.mem : α → List α → Prop) Subset Membership.mem := - ⟨fun h₁ h₂ => h₂ h₁⟩ - -instance : Trans (Subset : List α → List α → Prop) Subset Subset := - ⟨Subset.trans⟩ - -@[simp] theorem subset_cons (a : α) (l : List α) : l ⊆ a :: l := fun _ => Mem.tail _ - -theorem subset_of_cons_subset {a : α} {l₁ l₂ : List α} : a :: l₁ ⊆ l₂ → l₁ ⊆ l₂ := - fun s _ i => s (mem_cons_of_mem _ i) - -theorem subset_cons_of_subset (a : α) {l₁ l₂ : List α} : l₁ ⊆ l₂ → l₁ ⊆ a :: l₂ := - fun s _ i => .tail _ (s i) - -theorem cons_subset_cons {l₁ l₂ : List α} (a : α) (s : l₁ ⊆ l₂) : a :: l₁ ⊆ a :: l₂ := - fun _ => by simp only [mem_cons]; exact Or.imp_right (@s _) - -@[simp] theorem subset_append_left (l₁ l₂ : List α) : l₁ ⊆ l₁ ++ l₂ := fun _ => mem_append_left _ - -@[simp] theorem subset_append_right (l₁ l₂ : List α) : l₂ ⊆ l₁ ++ l₂ := fun _ => mem_append_right _ - -theorem subset_append_of_subset_left (l₂ : List α) : l ⊆ l₁ → l ⊆ l₁ ++ l₂ := -fun s => Subset.trans s <| subset_append_left _ _ - -theorem subset_append_of_subset_right (l₁ : List α) : l ⊆ l₂ → l ⊆ l₁ ++ l₂ := -fun s => Subset.trans s <| subset_append_right _ _ - -@[simp] theorem cons_subset : a :: l ⊆ m ↔ a ∈ m ∧ l ⊆ m := by - simp only [subset_def, mem_cons, or_imp, forall_and, forall_eq] - -@[simp] theorem append_subset {l₁ l₂ l : List α} : - l₁ ++ l₂ ⊆ l ↔ l₁ ⊆ l ∧ l₂ ⊆ l := by simp [subset_def, or_imp, forall_and] - -theorem subset_nil {l : List α} : l ⊆ [] ↔ l = [] := - ⟨fun h => match l with | [] => rfl | _::_ => (nomatch h (.head ..)), fun | rfl => Subset.refl _⟩ - -theorem map_subset {l₁ l₂ : List α} (f : α → β) (H : l₁ ⊆ l₂) : map f l₁ ⊆ map f l₂ := - fun x => by simp only [mem_map]; exact .imp fun a => .imp_left (@H _) - -/-! ### sublists -/ - -@[simp] theorem nil_sublist : ∀ l : List α, [] <+ l - | [] => .slnil - | a :: l => (nil_sublist l).cons a - -@[simp] theorem Sublist.refl : ∀ l : List α, l <+ l - | [] => .slnil - | a :: l => (Sublist.refl l).cons₂ a - -theorem Sublist.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ <+ l₂) (h₂ : l₂ <+ l₃) : l₁ <+ l₃ := by - induction h₂ generalizing l₁ with - | slnil => exact h₁ - | cons _ _ IH => exact (IH h₁).cons _ - | @cons₂ l₂ _ a _ IH => - generalize e : a :: l₂ = l₂' - match e ▸ h₁ with - | .slnil => apply nil_sublist - | .cons a' h₁' => cases e; apply (IH h₁').cons - | .cons₂ a' h₁' => cases e; apply (IH h₁').cons₂ - -instance : Trans (@Sublist α) Sublist Sublist := ⟨Sublist.trans⟩ - -@[simp] theorem sublist_cons (a : α) (l : List α) : l <+ a :: l := (Sublist.refl l).cons _ - -theorem sublist_of_cons_sublist : a :: l₁ <+ l₂ → l₁ <+ l₂ := - (sublist_cons a l₁).trans - -@[simp] theorem sublist_append_left : ∀ l₁ l₂ : List α, l₁ <+ l₁ ++ l₂ - | [], _ => nil_sublist _ - | _ :: l₁, l₂ => (sublist_append_left l₁ l₂).cons₂ _ - -@[simp] theorem sublist_append_right : ∀ l₁ l₂ : List α, l₂ <+ l₁ ++ l₂ - | [], _ => Sublist.refl _ - | _ :: l₁, l₂ => (sublist_append_right l₁ l₂).cons _ - -theorem sublist_append_of_sublist_left (s : l <+ l₁) : l <+ l₁ ++ l₂ := - s.trans <| sublist_append_left .. - -theorem sublist_append_of_sublist_right (s : l <+ l₂) : l <+ l₁ ++ l₂ := - s.trans <| sublist_append_right .. - -@[simp] -theorem cons_sublist_cons : a :: l₁ <+ a :: l₂ ↔ l₁ <+ l₂ := - ⟨fun | .cons _ s => sublist_of_cons_sublist s | .cons₂ _ s => s, .cons₂ _⟩ - -@[simp] theorem append_sublist_append_left : ∀ l, l ++ l₁ <+ l ++ l₂ ↔ l₁ <+ l₂ - | [] => Iff.rfl - | _ :: l => cons_sublist_cons.trans (append_sublist_append_left l) - -theorem Sublist.append_left : l₁ <+ l₂ → ∀ l, l ++ l₁ <+ l ++ l₂ := - fun h l => (append_sublist_append_left l).mpr h - -theorem Sublist.append_right : l₁ <+ l₂ → ∀ l, l₁ ++ l <+ l₂ ++ l - | .slnil, _ => Sublist.refl _ - | .cons _ h, _ => (h.append_right _).cons _ - | .cons₂ _ h, _ => (h.append_right _).cons₂ _ - -theorem sublist_or_mem_of_sublist (h : l <+ l₁ ++ a :: l₂) : l <+ l₁ ++ l₂ ∨ a ∈ l := by - induction l₁ generalizing l with - | nil => match h with - | .cons _ h => exact .inl h - | .cons₂ _ h => exact .inr (.head ..) - | cons b l₁ IH => - match h with - | .cons _ h => exact (IH h).imp_left (Sublist.cons _) - | .cons₂ _ h => exact (IH h).imp (Sublist.cons₂ _) (.tail _) - -theorem Sublist.reverse : l₁ <+ l₂ → l₁.reverse <+ l₂.reverse - | .slnil => Sublist.refl _ - | .cons _ h => by rw [reverse_cons]; exact sublist_append_of_sublist_left h.reverse - | .cons₂ _ h => by rw [reverse_cons, reverse_cons]; exact h.reverse.append_right _ - -@[simp] theorem reverse_sublist : l₁.reverse <+ l₂.reverse ↔ l₁ <+ l₂ := - ⟨fun h => l₁.reverse_reverse ▸ l₂.reverse_reverse ▸ h.reverse, Sublist.reverse⟩ - -@[simp] theorem append_sublist_append_right (l) : l₁ ++ l <+ l₂ ++ l ↔ l₁ <+ l₂ := - ⟨fun h => by - have := h.reverse - simp only [reverse_append, append_sublist_append_left, reverse_sublist] at this - exact this, - fun h => h.append_right l⟩ - -theorem Sublist.append (hl : l₁ <+ l₂) (hr : r₁ <+ r₂) : l₁ ++ r₁ <+ l₂ ++ r₂ := - (hl.append_right _).trans ((append_sublist_append_left _).2 hr) - -theorem Sublist.subset : l₁ <+ l₂ → l₁ ⊆ l₂ - | .slnil, _, h => h - | .cons _ s, _, h => .tail _ (s.subset h) - | .cons₂ .., _, .head .. => .head .. - | .cons₂ _ s, _, .tail _ h => .tail _ (s.subset h) - -instance : Trans (@Sublist α) Subset Subset := - ⟨fun h₁ h₂ => trans h₁.subset h₂⟩ - -instance : Trans Subset (@Sublist α) Subset := - ⟨fun h₁ h₂ => trans h₁ h₂.subset⟩ - -instance : Trans (Membership.mem : α → List α → Prop) Sublist Membership.mem := - ⟨fun h₁ h₂ => h₂.subset h₁⟩ - -theorem Sublist.length_le : l₁ <+ l₂ → length l₁ ≤ length l₂ - | .slnil => Nat.le_refl 0 - | .cons _l s => le_succ_of_le (length_le s) - | .cons₂ _ s => succ_le_succ (length_le s) - -@[simp] theorem sublist_nil {l : List α} : l <+ [] ↔ l = [] := - ⟨fun s => subset_nil.1 s.subset, fun H => H ▸ Sublist.refl _⟩ - -theorem Sublist.eq_of_length : l₁ <+ l₂ → length l₁ = length l₂ → l₁ = l₂ - | .slnil, _ => rfl - | .cons a s, h => nomatch Nat.not_lt.2 s.length_le (h ▸ lt_succ_self _) - | .cons₂ a s, h => by rw [s.eq_of_length (succ.inj h)] - -theorem Sublist.eq_of_length_le (s : l₁ <+ l₂) (h : length l₂ ≤ length l₁) : l₁ = l₂ := - s.eq_of_length <| Nat.le_antisymm s.length_le h - -@[simp] theorem singleton_sublist {a : α} {l} : [a] <+ l ↔ a ∈ l := by - refine ⟨fun h => h.subset (mem_singleton_self _), fun h => ?_⟩ - obtain ⟨_, _, rfl⟩ := append_of_mem h - exact ((nil_sublist _).cons₂ _).trans (sublist_append_right ..) - -@[simp] theorem replicate_sublist_replicate {m n} (a : α) : - replicate m a <+ replicate n a ↔ m ≤ n := by - refine ⟨fun h => ?_, fun h => ?_⟩ - · have := h.length_le; simp only [length_replicate] at this ⊢; exact this - · induction h with - | refl => apply Sublist.refl - | step => simp [*, replicate, Sublist.cons] - -theorem isSublist_iff_sublist [BEq α] [LawfulBEq α] {l₁ l₂ : List α} : - l₁.isSublist l₂ ↔ l₁ <+ l₂ := by - cases l₁ <;> cases l₂ <;> simp [isSublist] - case cons.cons hd₁ tl₁ hd₂ tl₂ => - if h_eq : hd₁ = hd₂ then - simp [h_eq, cons_sublist_cons, isSublist_iff_sublist] - else - simp only [beq_iff_eq, h_eq] - constructor - · intro h_sub - apply Sublist.cons - exact isSublist_iff_sublist.mp h_sub - · intro h_sub - cases h_sub - case cons h_sub => - exact isSublist_iff_sublist.mpr h_sub - case cons₂ => - contradiction - -instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+ l₂) := - decidable_of_iff (l₁.isSublist l₂) isSublist_iff_sublist - /-! ### tail -/ theorem tail_eq_tailD (l) : @tail α l = tailD l [] := by cases l <;> rfl @@ -251,27 +49,6 @@ theorem getElem_eq_iff {l : List α} {n : Nat} {h : n < l.length} : l[n] = x ↔ theorem get_eq_iff : List.get l n = x ↔ l.get? n.1 = some x := by simp -theorem getElem?_inj - (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs[i]? = xs[j]?) : i = j := by - induction xs generalizing i j with - | nil => cases h₀ - | cons x xs ih => - match i, j with - | 0, 0 => rfl - | i+1, j+1 => simp; cases h₁ with - | cons ha h₁ => - simp only [getElem?_cons_succ] at h₂ - exact ih (Nat.lt_of_succ_lt_succ h₀) h₁ h₂ - | i+1, 0 => ?_ - | 0, j+1 => ?_ - all_goals - simp only [get?_eq_getElem?, getElem?_cons_zero, getElem?_cons_succ] at h₂ - cases h₁; rename_i h' h - have := h x ?_ rfl; cases this - rw [mem_iff_get?] - simp only [get?_eq_getElem?] - exact ⟨_, h₂⟩; exact ⟨_ , h₂.symm⟩ - @[deprecated getElem?_inj (since := "2024-06-12")] theorem get?_inj (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs.get? i = xs.get? j) : i = j := by @@ -308,7 +85,7 @@ theorem eraseIdx_eq_modifyNthTail : ∀ n (l : List α), eraseIdx l n = modifyNt | n+1, [] => rfl | n+1, a :: l => congrArg (cons _) (eraseIdx_eq_modifyNthTail _ _) -@[deprecated] alias removeNth_eq_nth_tail := eraseIdx_eq_modifyNthTail +@[deprecated (since := "2024-05-06")] alias removeNth_eq_nth_tail := eraseIdx_eq_modifyNthTail theorem getElem?_modifyNth (f : α → α) : ∀ n (l : List α) m, (modifyNth f n l)[m]? = (fun a => if n = m then f a else a) <$> l[m]? @@ -405,14 +182,13 @@ theorem modifyNth_eq_set_get (f : α → α) {n} {l : List α} (h) : l.modifyNth f n = l.set n (f (l.get ⟨n, h⟩)) := by rw [modifyNth_eq_set_get?, get?_eq_get h]; rfl -theorem exists_of_set {l : List α} (h : n < l.length) : +-- The naming of `exists_of_set'` and `exists_of_set` have been swapped. +-- If no one complains, we will remove this version later. +@[deprecated exists_of_set (since := "2024-07-04")] +theorem exists_of_set' {l : List α} (h : n < l.length) : ∃ l₁ a l₂, l = l₁ ++ a :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := by rw [set_eq_modifyNth]; exact exists_of_modifyNth _ h -theorem exists_of_set' {l : List α} (h : n < l.length) : - ∃ l₁ l₂, l = l₁ ++ l[n] :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := - have ⟨_, _, _, h₁, h₂, h₃⟩ := exists_of_set h; ⟨_, _, getElem_of_append h₁ h₂ ▸ h₁, h₂, h₃⟩ - @[simp] theorem getElem?_set_eq' (a : α) (n) (l : List α) : (set l n a)[n]? = (fun _ => a) <$> l[n]? := by simp only [set_eq_modifyNth, getElem?_modifyNth_eq] @@ -450,10 +226,6 @@ 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 [getElem?_set]; split <;> subst_vars <;> simp [*, getElem?_eq_getElem h] -theorem drop_set_of_lt (a : α) {n m : Nat} (l : List α) (h : n < m) : - (l.set n a).drop m = l.drop m := - List.ext_getElem? fun i => by rw [getElem?_drop, getElem?_drop, getElem?_set_ne (by omega)] - theorem take_set_of_lt (a : α) {n m : Nat} (l : List α) (h : m < n) : (l.set n a).take m = l.take m := List.ext_getElem? fun i => by @@ -472,7 +244,7 @@ theorem length_eraseIdx : ∀ {l i}, i < length l → length (@eraseIdx α l i) simp [eraseIdx, ← Nat.add_one] rw [length_eraseIdx this, Nat.sub_add_cancel (Nat.lt_of_le_of_lt (Nat.zero_le _) this)] -@[deprecated] alias length_removeNth := length_eraseIdx +@[deprecated (since := "2024-05-06")] alias length_removeNth := length_eraseIdx /-! ### tail -/ @@ -612,14 +384,11 @@ theorem erase_append_right [LawfulBEq α] {a : α} {l₁ : List α} (l₂ : List rw [erase_eq_eraseP, erase_eq_eraseP, eraseP_append_right] intros b h' h''; rw [eq_of_beq h''] at h; exact h h' -theorem erase_sublist (a : α) (l : List α) : l.erase a <+ l := - erase_eq_eraseP' a l ▸ eraseP_sublist l - theorem erase_subset (a : α) (l : List α) : l.erase a ⊆ l := (erase_sublist a l).subset theorem Sublist.erase (a : α) {l₁ l₂ : List α} (h : l₁ <+ l₂) : l₁.erase a <+ l₂.erase a := by simp only [erase_eq_eraseP']; exact h.eraseP -@[deprecated] alias sublist.erase := Sublist.erase +@[deprecated (since := "2024-04-22")] alias sublist.erase := Sublist.erase theorem mem_of_mem_erase {a b : α} {l : List α} (h : a ∈ l.erase b) : a ∈ l := erase_subset _ _ h @@ -645,21 +414,6 @@ theorem erase_comm [LawfulBEq α] (a b : α) (l : List α) : end erase -/-! ### filter and partition -/ - -@[simp] theorem filter_sublist {p : α → Bool} : ∀ (l : List α), filter p l <+ l - | [] => .slnil - | a :: l => by rw [filter]; split <;> simp [Sublist.cons, Sublist.cons₂, filter_sublist l] - -/-! ### filterMap -/ - -protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) : - filterMap f l₁ <+ filterMap f l₂ := by - induction s <;> simp [filterMap_cons] <;> split <;> simp [*, cons, cons₂] - -theorem Sublist.filter (p : α → Bool) {l₁ l₂} (s : l₁ <+ l₂) : filter p l₁ <+ filter p l₂ := by - rw [← filterMap_eq_filter]; apply s.filterMap - /-! ### findIdx -/ @[simp] theorem findIdx_nil {α : Type _} (p : α → Bool) : [].findIdx p = 0 := rfl @@ -763,32 +517,6 @@ theorem findIdx?_of_eq_none {xs : List α} {p : α → Bool} (w : xs.findIdx? p simp only [replicate, findIdx?_cons, Nat.zero_add, findIdx?_succ, Nat.zero_lt_succ, true_and] split <;> simp_all -/-! ### pairwise -/ - -theorem Pairwise.sublist : l₁ <+ l₂ → l₂.Pairwise R → l₁.Pairwise R - | .slnil, h => h - | .cons _ s, .cons _ h₂ => h₂.sublist s - | .cons₂ _ s, .cons h₁ h₂ => (h₂.sublist s).cons fun _ h => h₁ _ (s.subset h) - -theorem pairwise_map {l : List α} : - (l.map f).Pairwise R ↔ l.Pairwise fun a b => R (f a) (f b) := by - induction l - · simp - · simp only [map, pairwise_cons, forall_mem_map_iff, *] - -theorem pairwise_append {l₁ l₂ : List α} : - (l₁ ++ l₂).Pairwise R ↔ l₁.Pairwise R ∧ l₂.Pairwise R ∧ ∀ a ∈ l₁, ∀ b ∈ l₂, R a b := by - induction l₁ <;> simp [*, or_imp, forall_and, and_assoc, and_left_comm] - -theorem pairwise_reverse {l : List α} : - l.reverse.Pairwise R ↔ l.Pairwise (fun a b => R b a) := by - induction l <;> simp [*, pairwise_append, and_comm] - -theorem Pairwise.imp {α R S} (H : ∀ {a b}, R a b → S a b) : - ∀ {l : List α}, l.Pairwise R → l.Pairwise S - | _, .nil => .nil - | _, .cons h₁ h₂ => .cons (H ∘ h₁ ·) (h₂.imp H) - /-! ### replaceF -/ theorem replaceF_nil : [].replaceF p = [] := rfl diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index 8583a41f2b..f7eda7b68f 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -188,7 +188,7 @@ theorem pairwise_iff_forall_sublist : l.Pairwise R ↔ (∀ {a b}, [a,b] <+ l intro a b hab apply h; exact hab.cons _ -@[deprecated pairwise_iff_forall_sublist] +@[deprecated pairwise_iff_forall_sublist (since := "2023-09-18")] theorem pairwise_of_reflexive_on_dupl_of_forall_ne [DecidableEq α] {l : List α} {r : α → α → Prop} (hr : ∀ a, 1 < count a l → r a a) (h : ∀ a ∈ l, ∀ b ∈ l, a ≠ b → r a b) : l.Pairwise r := by apply pairwise_iff_forall_sublist.mpr @@ -255,11 +255,6 @@ theorem pairwise_iff_get : Pairwise R l ↔ ∀ (i j) (_hij : i < j), R (get l i · intros i j hi hj h' exact h ⟨i, hi⟩ ⟨j, hj⟩ h' -theorem pairwise_replicate {α : Type _} {r : α → α → Prop} {x : α} (hx : r x x) : - ∀ n : Nat, Pairwise r (List.replicate n x) - | 0 => by simp - | n + 1 => by simp [mem_replicate, hx, pairwise_replicate hx n, replicate_succ] - /-! ### Pairwise filtering -/ @[simp] theorem pwFilter_nil [DecidableRel R] : pwFilter R [] = [] := rfl diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index 49e45ecc8b..035c5f10f5 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -437,12 +437,12 @@ theorem Nodup.perm_iff_eq_of_sublist {l₁ l₂ l : List α} (d : Nodup l) | .cons _ s₁ => exact IH d.2 s₁ h | .cons₂ _ s₁ => have := Subperm.subset ⟨_, h.symm, s₂⟩ (.head _) - exact (d.1 _ this rfl).elim + exact (d.1 this).elim | cons₂ a _ IH => match s₁ with | .cons _ s₁ => have := Subperm.subset ⟨_, h, s₁⟩ (.head _) - exact (d.1 _ this rfl).elim + exact (d.1 this).elim | .cons₂ _ s₁ => rw [IH d.2 s₁ h.cons_inv] section DecidableEq diff --git a/Batteries/Data/Nat/Lemmas.lean b/Batteries/Data/Nat/Lemmas.lean index 951f330e51..842ca09e95 100644 --- a/Batteries/Data/Nat/Lemmas.lean +++ b/Batteries/Data/Nat/Lemmas.lean @@ -151,19 +151,21 @@ protected def sum_trichotomy (a b : Nat) : a < b ⊕' a = b ⊕' b < a := /-! ## add -/ -@[deprecated] alias succ_add_eq_succ_add := Nat.succ_add_eq_add_succ +@[deprecated (since := "2023-11-25")] alias succ_add_eq_succ_add := Nat.succ_add_eq_add_succ /-! ## sub -/ -@[deprecated] protected alias le_of_le_of_sub_le_sub_right := Nat.le_of_sub_le_sub_right +@[deprecated (since := "2023-11-25")] +protected alias le_of_le_of_sub_le_sub_right := Nat.le_of_sub_le_sub_right -@[deprecated] protected alias le_of_le_of_sub_le_sub_left := Nat.le_of_sub_le_sub_left +@[deprecated (since := "2023-11-25")] +protected alias le_of_le_of_sub_le_sub_left := Nat.le_of_sub_le_sub_left /-! ### mul -/ -@[deprecated] protected alias mul_lt_mul := Nat.mul_lt_mul_of_lt_of_le' +@[deprecated (since := "2024-01-11")] protected alias mul_lt_mul := Nat.mul_lt_mul_of_lt_of_le' -@[deprecated] protected alias mul_lt_mul' := Nat.mul_lt_mul_of_le_of_lt +@[deprecated (since := "2024-01-11")] protected alias mul_lt_mul' := Nat.mul_lt_mul_of_le_of_lt /-! ### div/mod -/ @@ -182,5 +184,5 @@ protected def sum_trichotomy (a b : Nat) : a < b ⊕' a = b ⊕' b < a := @[simp] theorem sum_append : Nat.sum (l₁ ++ l₂) = Nat.sum l₁ + Nat.sum l₂ := by induction l₁ <;> simp [*, Nat.add_assoc] -@[deprecated] protected alias lt_connex := Nat.lt_or_gt_of_ne -@[deprecated] alias pow_two_pos := Nat.two_pow_pos -- deprecated 2024-02-09 +@[deprecated (since := "2024-03-05")] protected alias lt_connex := Nat.lt_or_gt_of_ne +@[deprecated (since := "2024-02-09")] alias pow_two_pos := Nat.two_pow_pos diff --git a/Batteries/Data/Option/Lemmas.lean b/Batteries/Data/Option/Lemmas.lean index a768a776ce..05a38b25a7 100644 --- a/Batteries/Data/Option/Lemmas.lean +++ b/Batteries/Data/Option/Lemmas.lean @@ -7,7 +7,7 @@ import Batteries.Tactic.Alias namespace Option -@[deprecated] alias to_list_some := toList_some -@[deprecated] alias to_list_none := toList_none +@[deprecated (since := "2024-03-05")] alias to_list_some := toList_some +@[deprecated (since := "2024-03-05")] alias to_list_none := toList_none end Option diff --git a/Batteries/Data/RBMap/Basic.lean b/Batteries/Data/RBMap/Basic.lean index a9ba215ad9..d1aff2dc3b 100644 --- a/Batteries/Data/RBMap/Basic.lean +++ b/Batteries/Data/RBMap/Basic.lean @@ -67,8 +67,8 @@ protected def max? : RBNode α → Option α | node _ _ v nil => some v | node _ _ _ r => r.max? -@[deprecated] protected alias min := RBNode.min? -@[deprecated] protected alias max := RBNode.max? +@[deprecated (since := "2024-04-17")] protected alias min := RBNode.min? +@[deprecated (since := "2024-04-17")] protected alias max := RBNode.max? /-- Fold a function in tree order along the nodes. `v₀` is used at `nil` nodes and @@ -669,8 +669,8 @@ instance : ToStream (RBSet α cmp) (RBNode.Stream α) := ⟨fun x => x.1.toStrea /-- `O(log n)`. Returns the entry `a` such that `a ≥ k` for all keys in the RBSet. -/ @[inline] protected def max? (t : RBSet α cmp) : Option α := t.1.max? -@[deprecated] protected alias min := RBSet.min? -@[deprecated] protected alias max := RBSet.max? +@[deprecated (since := "2024-04-17")] protected alias min := RBSet.min? +@[deprecated (since := "2024-04-17")] protected alias max := RBSet.max? instance [Repr α] : Repr (RBSet α cmp) where reprPrec m prec := Repr.addAppParen ("RBSet.ofList " ++ repr m.toList) prec @@ -1053,8 +1053,8 @@ instance : Stream (Values.Stream α β) β := ⟨Values.Stream.next?⟩ /-- `O(log n)`. Returns the key-value pair `(a, b)` such that `a ≥ k` for all keys in the RBMap. -/ @[inline] protected def max? : RBMap α β cmp → Option (α × β) := RBSet.max? -@[deprecated] protected alias min := RBMap.min? -@[deprecated] protected alias max := RBMap.max? +@[deprecated (since := "2024-04-17")] protected alias min := RBMap.min? +@[deprecated (since := "2024-04-17")] protected alias max := RBMap.max? instance [Repr α] [Repr β] : Repr (RBMap α β cmp) where reprPrec m prec := Repr.addAppParen ("RBMap.ofList " ++ repr m.toList) prec diff --git a/Batteries/Data/RBMap/Lemmas.lean b/Batteries/Data/RBMap/Lemmas.lean index 37f24ebea9..5577b3a1a7 100644 --- a/Batteries/Data/RBMap/Lemmas.lean +++ b/Batteries/Data/RBMap/Lemmas.lean @@ -152,7 +152,6 @@ theorem min?_eq_toList_head? {t : RBNode α} : t.min? = t.toList.head? := by | nil => rfl | node _ l _ _ ih => cases l <;> simp [RBNode.min?, ih] - next ll _ _ => cases toList ll <;> rfl theorem max?_eq_toList_getLast? {t : RBNode α} : t.max? = t.toList.getLast? := by rw [← min?_reverse, min?_eq_toList_head?]; simp diff --git a/Batteries/Data/String/Lemmas.lean b/Batteries/Data/String/Lemmas.lean index 1ea4e4f788..5420651ba2 100644 --- a/Batteries/Data/String/Lemmas.lean +++ b/Batteries/Data/String/Lemmas.lean @@ -12,7 +12,8 @@ import Batteries.Tactic.SqueezeScope namespace String -attribute [ext] ext +-- TODO(kmill): add `@[ext]` attribute to `String.ext` in core. +attribute [ext (iff := false)] ext theorem lt_trans {s₁ s₂ s₃ : String} : s₁ < s₂ → s₂ < s₃ → s₁ < s₃ := List.lt_trans' (α := Char) Nat.lt_trans @@ -87,7 +88,8 @@ end namespace Pos -attribute [ext] ext +-- TODO(kmill): add `@[ext]` attribute to `String.Pos.ext` in core. +attribute [ext (iff := false)] ext theorem lt_addChar (p : Pos) (c : Char) : p < p + c := Nat.lt_add_of_pos_right (Char.utf8Size_pos _) diff --git a/Batteries/Data/UInt.lean b/Batteries/Data/UInt.lean index a9ce1b561a..44ebfd9b80 100644 --- a/Batteries/Data/UInt.lean +++ b/Batteries/Data/UInt.lean @@ -10,8 +10,6 @@ import Batteries.Classes.Order @[ext] theorem UInt8.ext : {x y : UInt8} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem UInt8.ext_iff {x y : UInt8} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, UInt8.ext⟩ - @[simp] theorem UInt8.val_val_eq_toNat (x : UInt8) : x.val.val = x.toNat := rfl @[simp] theorem UInt8.val_ofNat (n) : @@ -57,8 +55,6 @@ instance : Batteries.LawfulOrd UInt8 := .compareOfLessAndEq @[ext] theorem UInt16.ext : {x y : UInt16} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem UInt16.ext_iff {x y : UInt16} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, UInt16.ext⟩ - @[simp] theorem UInt16.val_val_eq_toNat (x : UInt16) : x.val.val = x.toNat := rfl @[simp] theorem UInt16.val_ofNat (n) : @@ -104,8 +100,6 @@ instance : Batteries.LawfulOrd UInt16 := .compareOfLessAndEq @[ext] theorem UInt32.ext : {x y : UInt32} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem UInt32.ext_iff {x y : UInt32} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, UInt32.ext⟩ - @[simp] theorem UInt32.val_val_eq_toNat (x : UInt32) : x.val.val = x.toNat := rfl @[simp] theorem UInt32.val_ofNat (n) : @@ -151,8 +145,6 @@ instance : Batteries.LawfulOrd UInt32 := .compareOfLessAndEq @[ext] theorem UInt64.ext : {x y : UInt64} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem UInt64.ext_iff {x y : UInt64} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, UInt64.ext⟩ - @[simp] theorem UInt64.val_val_eq_toNat (x : UInt64) : x.val.val = x.toNat := rfl @[simp] theorem UInt64.val_ofNat (n) : @@ -198,8 +190,6 @@ instance : Batteries.LawfulOrd UInt64 := .compareOfLessAndEq @[ext] theorem USize.ext : {x y : USize} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem USize.ext_iff {x y : USize} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, USize.ext⟩ - @[simp] theorem USize.val_val_eq_toNat (x : USize) : x.val.val = x.toNat := rfl @[simp] theorem USize.val_ofNat (n) : diff --git a/Batteries/Data/UnionFind/Basic.lean b/Batteries/Data/UnionFind/Basic.lean index 24966452c2..292f4285eb 100644 --- a/Batteries/Data/UnionFind/Basic.lean +++ b/Batteries/Data/UnionFind/Basic.lean @@ -46,13 +46,17 @@ theorem lt_of_parentD : parentD arr i ≠ i → i < arr.size := theorem parentD_set {arr : Array UFNode} {x v i} : parentD (arr.set x v) i = if x.1 = i then v.parent else parentD arr i := by - rw [parentD]; simp [Array.get_eq_getElem, parentD] - split <;> [split <;> simp [Array.get_set, *]; split <;> [(subst i; cases ‹¬_› x.2); rfl]] + rw [parentD]; simp only [Array.size_set, Array.get_eq_getElem, parentD] + split + · split <;> simp_all + · split <;> [(subst i; cases ‹¬_› x.2); rfl] theorem rankD_set {arr : Array UFNode} {x v i} : rankD (arr.set x v) i = if x.1 = i then v.rank else rankD arr i := by - rw [rankD]; simp [Array.get_eq_getElem, rankD] - split <;> [split <;> simp [Array.get_set, *]; split <;> [(subst i; cases ‹¬_› x.2); rfl]] + rw [rankD]; simp only [Array.size_set, Array.get_eq_getElem, rankD] + split + · split <;> simp_all + · split <;> [(subst i; cases ‹¬_› x.2); rfl] end UnionFind @@ -146,7 +150,7 @@ theorem rank'_lt_rankMax (self : UnionFind) (i : Fin self.size) : let rec go : ∀ {l} {x : UFNode}, x ∈ l → x.rank ≤ List.foldr (max ·.rank) 0 l | a::l, _, List.Mem.head _ => by dsimp; apply Nat.le_max_left | a::l, _, .tail _ h => by dsimp; exact Nat.le_trans (go h) (Nat.le_max_right ..) - simp [rankMax, Array.foldr_eq_foldr_data] + simp only [Array.get_eq_getElem, rankMax, Array.foldr_eq_foldr_data] exact Nat.lt_succ.2 <| go (self.arr.data.get_mem i.1 i.2) theorem rankD_lt_rankMax (self : UnionFind) (i : Nat) : @@ -156,11 +160,11 @@ theorem rankD_lt_rankMax (self : UnionFind) (i : Nat) : theorem lt_rankMax (self : UnionFind) (i : Nat) : self.rank i < self.rankMax := rankD_lt_rankMax .. theorem push_rankD (arr : Array UFNode) : rankD (arr.push ⟨arr.size, 0⟩) i = rankD arr i := by - simp [rankD, Array.get_eq_getElem, Array.get_push] + simp only [rankD, Array.size_push, Array.get_eq_getElem, Array.get_push, dite_eq_ite] split <;> split <;> first | simp | cases ‹¬_› (Nat.lt_succ_of_lt ‹_›) theorem push_parentD (arr : Array UFNode) : parentD (arr.push ⟨arr.size, 0⟩) i = parentD arr i := by - simp [parentD, Array.get_eq_getElem, Array.get_push] + simp only [parentD, Array.size_push, Array.get_eq_getElem, Array.get_push, dite_eq_ite] split <;> split <;> try simp · exact Nat.le_antisymm (Nat.ge_of_not_lt ‹_›) (Nat.le_of_lt_succ ‹_›) · cases ‹¬_› (Nat.lt_succ_of_lt ‹_›) @@ -169,9 +173,9 @@ theorem push_parentD (arr : Array UFNode) : parentD (arr.push ⟨arr.size, 0⟩) def push (self : UnionFind) : UnionFind where arr := self.arr.push ⟨self.arr.size, 0⟩ parentD_lt {i} := by - simp [push_parentD]; simp [parentD] + simp only [Array.size_push, push_parentD]; simp only [parentD, Array.get_eq_getElem] split <;> [exact fun _ => Nat.lt_succ_of_lt (self.parent'_lt _); exact id] - rankD_lt := by simp [push_parentD, push_rankD]; exact self.rank_lt + rankD_lt := by simp only [push_parentD, ne_eq, push_rankD]; exact self.rank_lt /-- Root of a union-find node. -/ def root (self : UnionFind) (x : Fin self.size) : Fin self.size := @@ -205,18 +209,23 @@ termination_by self.rankMax - self.rank x theorem parent_rootD (self : UnionFind) (x : Nat) : self.parent (self.rootD x) = self.rootD x := by - rw [rootD]; split <;> - [simp [parentD, parent_root, -Array.get_eq_getElem]; simp [parentD_of_not_lt, *]] + rw [rootD] + split + · simp [parentD, parent_root, -Array.get_eq_getElem] + · simp [parentD_of_not_lt, *] @[nolint unusedHavesSuffices] theorem rootD_parent (self : UnionFind) (x : Nat) : self.rootD (self.parent x) = self.rootD x := by - simp [rootD, parent_lt]; split <;> simp [parentD, parentD_of_not_lt, *, -Array.get_eq_getElem] - (conv => rhs; rw [root]); split - · rw [root, dif_pos] <;> simp [*, -Array.get_eq_getElem] - · simp + simp only [rootD, Array.data_length, parent_lt] + split + · simp only [parentD, ↓reduceDIte, *] + (conv => rhs; rw [root]); split + · rw [root, dif_pos] <;> simp_all + · simp + · simp only [not_false_eq_true, parentD_of_not_lt, *] theorem rootD_lt {self : UnionFind} {x : Nat} : self.rootD x < self.size ↔ x < self.size := by - simp [rootD]; split <;> simp [*] + simp only [rootD, Array.data_length]; split <;> simp [*] @[nolint unusedHavesSuffices] theorem rootD_eq_self {self : UnionFind} {x : Nat} : self.rootD x = x ↔ self.parent x = x := by @@ -273,7 +282,9 @@ termination_by self.rankMax - self.rank x @[nolint unusedHavesSuffices] theorem findAux_root {self : UnionFind} {x : Fin self.size} : (findAux self x).root = self.root x := by - rw [findAux, root]; simp; split <;> simp + rw [findAux, root] + simp only [Array.data_length, Array.get_eq_getElem, dite_eq_ite] + split <;> simp only have := Nat.sub_lt_sub_left (self.lt_rankMax x) (self.rank'_lt _ ‹_›) exact findAux_root termination_by self.rankMax - self.rank x @@ -286,7 +297,7 @@ theorem findAux_s {self : UnionFind} {x : Fin self.size} : rw [show self.rootD _ = (self.findAux ⟨_, self.parent'_lt x⟩).root from _] · rw [findAux]; split <;> rfl · rw [← rootD_parent, parent, parentD_eq] - simp [findAux_root, rootD] + simp only [rootD, Array.get_eq_getElem, Array.data_length, findAux_root] apply dif_pos exact parent'_lt .. @@ -299,7 +310,8 @@ theorem rankD_findAux {self : UnionFind} {x : Fin self.size} : rw [rankD_eq' (by simp [FindAux.size_eq, h]), Array.get_modify (by rwa [FindAux.size_eq])] split <;> simp [← rankD_eq, rankD_findAux (x := ⟨_, self.parent'_lt x⟩), -Array.get_eq_getElem] else - simp [rank, rankD]; rw [dif_neg (by rwa [FindAux.size_eq]), dif_neg h] + simp only [rankD, Array.data_length, Array.get_eq_getElem, rank] + rw [dif_neg (by rwa [FindAux.size_eq]), dif_neg h] termination_by self.rankMax - self.rank x theorem parentD_findAux {self : UnionFind} {x : Fin self.size} : @@ -311,7 +323,7 @@ theorem parentD_findAux {self : UnionFind} {x : Fin self.size} : · next h => rw [parentD]; split <;> rename_i h' · rw [Array.get_modify (by simpa using h')] - simp [@eq_comm _ i, -Array.get_eq_getElem] + simp only [Array.data_length, @eq_comm _ i] split <;> simp [← parentD_eq, -Array.get_eq_getElem] · rw [if_neg (mt (by rintro rfl; simp [FindAux.size_eq]) h')] rw [parentD, dif_neg]; simpa using h' @@ -330,9 +342,11 @@ theorem parentD_findAux_lt {self : UnionFind} {x : Fin self.size} (h : i < self. if h' : (self.arr.get x).parent = x then rw [findAux_s, if_pos h']; apply self.parentD_lt h else - rw [parentD_findAux]; split <;> [simp [rootD_lt]; skip] - have := Nat.sub_lt_sub_left (self.lt_rankMax x) (self.rank'_lt _ ‹_›) - apply parentD_findAux_lt h + rw [parentD_findAux] + split + · simp [rootD_lt] + · have := Nat.sub_lt_sub_left (self.lt_rankMax x) (self.rank'_lt _ ‹_›) + apply parentD_findAux_lt h termination_by self.rankMax - self.rank x theorem parentD_findAux_or (self : UnionFind) (x : Fin self.size) (i) : @@ -341,10 +355,12 @@ theorem parentD_findAux_or (self : UnionFind) (x : Fin self.size) (i) : if h' : (self.arr.get x).parent = x then rw [findAux_s, if_pos h']; exact .inr rfl else - rw [parentD_findAux]; split <;> [simp [*]; skip] - have := Nat.sub_lt_sub_left (self.lt_rankMax x) (self.rank'_lt _ ‹_›) - exact (parentD_findAux_or self ⟨_, self.parent'_lt x⟩ i).imp_left <| .imp_right fun h => by - simp only [h, ← parentD_eq, rootD_parent, Array.data_length] + rw [parentD_findAux] + split + · simp [*] + · have := Nat.sub_lt_sub_left (self.lt_rankMax x) (self.rank'_lt _ ‹_›) + exact (parentD_findAux_or self ⟨_, self.parent'_lt x⟩ i).imp_left <| .imp_right fun h => by + simp only [h, ← parentD_eq, rootD_parent, Array.data_length] termination_by self.rankMax - self.rank x theorem lt_rankD_findAux {self : UnionFind} {x : Fin self.size} : @@ -365,7 +381,9 @@ def find (self : UnionFind) (x : Fin self.size) : let r := self.findAux x { 1.arr := r.s 2.1.val := r.root - 1.parentD_lt := fun h => by simp [FindAux.size_eq] at *; exact parentD_findAux_lt h + 1.parentD_lt := fun h => by + simp only [Array.data_length, FindAux.size_eq] at * + exact parentD_findAux_lt h 1.rankD_lt := fun h => by rw [rankD_findAux, rankD_findAux]; exact lt_rankD_findAux h 2.1.isLt := show _ < r.s.size by rw [r.size_eq]; exact r.root.2 2.2 := by simp [size, r.size_eq] } @@ -398,7 +416,8 @@ def findD (self : UnionFind) (x : Nat) : UnionFind × Nat := @[simp] theorem find_parent_1 (self : UnionFind) (x : Fin self.size) : (self.find x).1.parent x = self.rootD x := by - simp [find, parent]; rw [parentD_findAux, if_pos rfl] + simp only [parent, Array.data_length, find] + rw [parentD_findAux, if_pos rfl] theorem find_parent_or (self : UnionFind) (x : Fin self.size) (i) : (self.find x).1.parent i = self.rootD i ∧ self.rootD i = self.rootD x ∨ @@ -449,7 +468,8 @@ theorem setParentBump_rankD_lt {arr : Array UFNode} {x y : Fin arr.size} simp [hP, hR, -Array.get_eq_getElem] at *; split <;> rename_i h₁ <;> [simp [← h₁]; skip] <;> split <;> rename_i h₂ <;> intro h · simp [h₂] at h - · simp [rankD_eq]; split <;> rename_i h₃ + · simp only [rankD_eq, Array.get_eq_getElem] + split <;> rename_i h₃ · rw [← h₃]; apply Nat.lt_succ_self · exact Nat.lt_of_le_of_ne H h₃ · cases h₂.1 @@ -469,13 +489,16 @@ theorem setParent_rankD_lt {arr : Array UFNode} {x y : Fin arr.size} (by simp [rankD_set, Nat.ne_of_lt h, rankD_eq, -Array.get_eq_getElem]) @[simp] theorem linkAux_size : (linkAux self x y).size = self.size := by - simp [linkAux]; split <;> [rfl; split] <;> [skip; split] <;> simp + simp only [linkAux, Array.get_eq_getElem] + split <;> [rfl; split] <;> [skip; split] <;> simp /-- Link a union-find node to a root node. -/ def link (self : UnionFind) (x y : Fin self.size) (yroot : self.parent y = y) : UnionFind where arr := linkAux self.arr x y parentD_lt h := by - simp at *; simp [linkAux]; split <;> [skip; split <;> [skip; split]] + simp only [Array.data_length, linkAux_size] at * + simp only [linkAux, Array.get_eq_getElem] + split <;> [skip; split <;> [skip; split]] · exact self.parentD_lt h · rw [parentD_set]; split <;> [exact x.2; exact self.parentD_lt h] · rw [parentD_set]; split @@ -484,12 +507,21 @@ def link (self : UnionFind) (x y : Fin self.size) (yroot : self.parent y = y) : · rw [parentD_set]; split <;> [exact y.2; exact self.parentD_lt h] rankD_lt := by rw [parent, parentD_eq] at yroot - simp [linkAux]; split <;> [skip; split <;> [skip; split]] + simp only [linkAux, Array.get_eq_getElem, ne_eq] + split <;> [skip; split <;> [skip; split]] · exact self.rankD_lt · exact setParent_rankD_lt ‹_› self.rankD_lt - · refine setParentBump_rankD_lt (.inr yroot) (Nat.le_of_eq ‹_›) self.rankD_lt - (by simp [parentD_set]; rintro rfl; simp [*, parentD_eq]) fun {i} => ?_ - simp [rankD_set]; split <;> simp [*]; rintro rfl; simp [rankD_eq, *] + · refine setParentBump_rankD_lt (.inr yroot) (Nat.le_of_eq ‹_›) self.rankD_lt (by + simp only [parentD_set, ite_eq_right_iff] + rintro rfl + simp [*, parentD_eq]) fun {i} => ?_ + simp only [rankD_set, Fin.eta, Array.get_eq_getElem] + split + · simp_all + · simp_all only [Array.get_eq_getElem, Array.data_length, Nat.lt_irrefl, not_false_eq_true, + and_true, ite_false, ite_eq_right_iff] + rintro rfl + simp [rankD_eq, *] · exact setParent_rankD_lt (Nat.lt_of_le_of_ne (Nat.not_lt.1 ‹_›) ‹_›) self.rankD_lt @[inherit_doc link] diff --git a/Batteries/Lean/Delaborator.lean b/Batteries/Lean/Delaborator.lean index d722eef9d8..e09f2198de 100644 --- a/Batteries/Lean/Delaborator.lean +++ b/Batteries/Lean/Delaborator.lean @@ -8,6 +8,6 @@ import Lean.PrettyPrinter open Lean PrettyPrinter Delaborator SubExpr /-- Abbreviation for `Lean.MessageData.ofConst`. -/ -@[deprecated Lean.MessageData.ofConst] +@[deprecated Lean.MessageData.ofConst (since := "2024-05-18")] def Lean.ppConst (e : Expr) : MessageData := Lean.MessageData.ofConst e diff --git a/Batteries/Lean/SMap.lean b/Batteries/Lean/SMap.lean deleted file mode 100644 index 44a660e2e0..0000000000 --- a/Batteries/Lean/SMap.lean +++ /dev/null @@ -1,17 +0,0 @@ -/- -Copyright (c) 2023 Scott Morrison. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Scott Morrison --/ -import Lean.Data.SMap - -/-! -# Extra functions on Lean.SMap --/ - -set_option autoImplicit true - -/-- Monadic fold over a staged map. -/ -def Lean.SMap.foldM {m : Type w → Type w} [Monad m] [BEq α] [Hashable α] - (f : σ → α → β → m σ) (init : σ) (map : SMap α β) : m σ := do - map.map₂.foldlM f (← map.map₁.foldM f init) diff --git a/Batteries/Lean/Util/Path.lean b/Batteries/Lean/Util/Path.lean deleted file mode 100644 index d9488c0dc8..0000000000 --- a/Batteries/Lean/Util/Path.lean +++ /dev/null @@ -1,34 +0,0 @@ -/- -Copyright (c) 2022 Gabriel Ebner. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Gabriel Ebner --/ -import Lean.Elab.Term - -/-! -# `compile_time_search_path%` term elaborator. - -Use this as `searchPathRef.set compile_time_search_path%`. --/ - -open Lean System - --- Ideally this instance would be constructed simply by `deriving instance ToExpr for FilePath` --- but for now we have decided not to upstream the `ToExpr` derive handler from `Mathlib`. --- https://leanprover.zulipchat.com/#narrow/stream/348111-std4/topic/ToExpr.20derive.20handler/near/386476438 -instance : ToExpr FilePath where - toTypeExpr := mkConst ``FilePath - toExpr path := mkApp (mkConst ``FilePath.mk) (toExpr path.1) - -/-- -Term elaborator that retrieves the current `SearchPath`. - -Typical usage is `searchPathRef.set compile_time_search_path%`. - -This must not be used in files that are potentially compiled on another machine and then -imported. -(That is, if used in an imported file it will embed the search path from whichever machine -compiled the `.olean`.) --/ -elab "compile_time_search_path%" : term => - return toExpr (← searchPathRef.get) diff --git a/Batteries/Logic.lean b/Batteries/Logic.lean index 10b5bd2fcb..5c6efe108a 100644 --- a/Batteries/Logic.lean +++ b/Batteries/Logic.lean @@ -10,16 +10,12 @@ import Batteries.Tactic.Lint.Misc instance {f : α → β} [DecidablePred p] : DecidablePred (p ∘ f) := inferInstanceAs <| DecidablePred fun x => p (f x) -@[deprecated] alias proofIrrel := proof_irrel +@[deprecated (since := "2024-03-15")] alias proofIrrel := proof_irrel /-! ## id -/ theorem Function.id_def : @id α = fun x => x := rfl -/-! ## exists and forall -/ - -alias ⟨forall_not_of_not_exists, not_exists_of_forall_not⟩ := not_exists - /-! ## decidable -/ protected alias ⟨Decidable.exists_not_of_not_forall, _⟩ := Decidable.not_forall @@ -60,8 +56,7 @@ theorem funext₃ {β : α → Sort _} {γ : ∀ a, β a → Sort _} {δ : ∀ a {f g : ∀ a b c, δ a b c} (h : ∀ a b c, f a b c = g a b c) : f = g := funext fun _ => funext₂ <| h _ -theorem Function.funext_iff {β : α → Sort u} {f₁ f₂ : ∀ x : α, β x} : f₁ = f₂ ↔ ∀ a, f₁ a = f₂ a := - ⟨congrFun, funext⟩ +protected alias Function.funext_iff := funext_iff theorem ne_of_apply_ne {α β : Sort _} (f : α → β) {x y : α} : f x ≠ f y → x ≠ y := mt <| congrArg _ @@ -128,9 +123,7 @@ end Mem -- instance (priority := 10) {α} [Subsingleton α] : DecidableEq α -- | a, b => isTrue (Subsingleton.elim a b) --- @[simp] -- TODO(Mario): profile -theorem eq_iff_true_of_subsingleton [Subsingleton α] (x y : α) : x = y ↔ True := - iff_true_intro (Subsingleton.elim ..) +-- TODO(Mario): profile adding `@[simp]` to `eq_iff_true_of_subsingleton` /-- If all points are equal to a given point `x`, then `α` is a subsingleton. -/ theorem subsingleton_of_forall_eq (x : α) (h : ∀ y, y = x) : Subsingleton α := diff --git a/Batteries/StdDeprecations.lean b/Batteries/StdDeprecations.lean index 49357a0573..f82b1739a7 100644 --- a/Batteries/StdDeprecations.lean +++ b/Batteries/StdDeprecations.lean @@ -21,35 +21,35 @@ but it would be much harder to generate the deprecations. Let's hope that people using the tactic implementations can work this out themselves. -/ -@[deprecated] alias Std.AssocList := Batteries.AssocList -@[deprecated] alias Std.HashMap := Batteries.HashMap -@[deprecated] alias Std.mkHashMap := Batteries.mkHashMap -@[deprecated] alias Std.DList := Batteries.DList -@[deprecated] alias Std.PairingHeapImp.Heap := Batteries.PairingHeapImp.Heap -@[deprecated] alias Std.TotalBLE := Batteries.TotalBLE -@[deprecated] alias Std.OrientedCmp := Batteries.OrientedCmp -@[deprecated] alias Std.TransCmp := Batteries.TransCmp -@[deprecated] alias Std.BEqCmp := Batteries.BEqCmp -@[deprecated] alias Std.LTCmp := Batteries.LTCmp -@[deprecated] alias Std.LECmp := Batteries.LECmp -@[deprecated] alias Std.LawfulCmp := Batteries.LawfulCmp -@[deprecated] alias Std.OrientedOrd := Batteries.OrientedOrd -@[deprecated] alias Std.TransOrd := Batteries.TransOrd -@[deprecated] alias Std.BEqOrd := Batteries.BEqOrd -@[deprecated] alias Std.LTOrd := Batteries.LTOrd -@[deprecated] alias Std.LEOrd := Batteries.LEOrd -@[deprecated] alias Std.LawfulOrd := Batteries.LawfulOrd -@[deprecated] alias Std.compareOfLessAndEq_eq_lt := Batteries.compareOfLessAndEq_eq_lt -@[deprecated] alias Std.RBColor := Batteries.RBColor -@[deprecated] alias Std.RBNode := Batteries.RBNode -@[deprecated] alias Std.RBSet := Batteries.RBSet -@[deprecated] alias Std.mkRBSet := Batteries.mkRBSet -@[deprecated] alias Std.RBMap := Batteries.RBMap -@[deprecated] alias Std.mkRBMap := Batteries.mkRBMap -@[deprecated] alias Std.BinomialHeap := Batteries.BinomialHeap -@[deprecated] alias Std.mkBinomialHeap := Batteries.mkBinomialHeap -@[deprecated] alias Std.UFNode := Batteries.UFNode -@[deprecated] alias Std.UnionFind := Batteries.UnionFind +@[deprecated (since := "2024-05-07")] alias Std.AssocList := Batteries.AssocList +@[deprecated (since := "2024-05-07")] alias Std.mkHashMap := Batteries.mkHashMap +@[deprecated (since := "2024-05-07")] alias Std.DList := Batteries.DList +@[deprecated (since := "2024-05-07")] alias Std.PairingHeapImp.Heap := Batteries.PairingHeapImp.Heap +@[deprecated (since := "2024-05-07")] alias Std.TotalBLE := Batteries.TotalBLE +@[deprecated (since := "2024-05-07")] alias Std.OrientedCmp := Batteries.OrientedCmp +@[deprecated (since := "2024-05-07")] alias Std.TransCmp := Batteries.TransCmp +@[deprecated (since := "2024-05-07")] alias Std.BEqCmp := Batteries.BEqCmp +@[deprecated (since := "2024-05-07")] alias Std.LTCmp := Batteries.LTCmp +@[deprecated (since := "2024-05-07")] alias Std.LECmp := Batteries.LECmp +@[deprecated (since := "2024-05-07")] alias Std.LawfulCmp := Batteries.LawfulCmp +@[deprecated (since := "2024-05-07")] alias Std.OrientedOrd := Batteries.OrientedOrd +@[deprecated (since := "2024-05-07")] alias Std.TransOrd := Batteries.TransOrd +@[deprecated (since := "2024-05-07")] alias Std.BEqOrd := Batteries.BEqOrd +@[deprecated (since := "2024-05-07")] alias Std.LTOrd := Batteries.LTOrd +@[deprecated (since := "2024-05-07")] alias Std.LEOrd := Batteries.LEOrd +@[deprecated (since := "2024-05-07")] alias Std.LawfulOrd := Batteries.LawfulOrd +@[deprecated (since := "2024-05-07")] +alias Std.compareOfLessAndEq_eq_lt := Batteries.compareOfLessAndEq_eq_lt +@[deprecated (since := "2024-05-07")] alias Std.RBColor := Batteries.RBColor +@[deprecated (since := "2024-05-07")] alias Std.RBNode := Batteries.RBNode +@[deprecated (since := "2024-05-07")] alias Std.RBSet := Batteries.RBSet +@[deprecated (since := "2024-05-07")] alias Std.mkRBSet := Batteries.mkRBSet +@[deprecated (since := "2024-05-07")] alias Std.RBMap := Batteries.RBMap +@[deprecated (since := "2024-05-07")] alias Std.mkRBMap := Batteries.mkRBMap +@[deprecated (since := "2024-05-07")] alias Std.BinomialHeap := Batteries.BinomialHeap +@[deprecated (since := "2024-05-07")] alias Std.mkBinomialHeap := Batteries.mkBinomialHeap +@[deprecated (since := "2024-05-07")] alias Std.UFNode := Batteries.UFNode +@[deprecated (since := "2024-05-07")] alias Std.UnionFind := Batteries.UnionFind -- Check that these generate usable deprecated hints -- when referring to names inside these namespaces. diff --git a/lean-toolchain b/lean-toolchain index c73e540213..71dae0afae 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-01 +leanprover/lean4:nightly-2024-07-10 diff --git a/scripts/runLinter.lean b/scripts/runLinter.lean index 87d8774ce9..f4d5002e2d 100644 --- a/scripts/runLinter.lean +++ b/scripts/runLinter.lean @@ -1,6 +1,6 @@ +import Lean.Util.SearchPath import Batteries.Tactic.Lint import Batteries.Data.Array.Basic -import Batteries.Lean.Util.Path open Lean Core Elab Command Std.Tactic.Lint open System (FilePath) diff --git a/test/congr.lean b/test/congr.lean index a71aed0315..065a899f99 100644 --- a/test/congr.lean +++ b/test/congr.lean @@ -19,8 +19,6 @@ example {α β γ δ} {F : ∀ {α β}, (α → β) → γ → δ} {f g : α → -- apply_assumption -- FIXME apply h -attribute [ext] Subtype.eq - example {α β : Type _} {f : _ → β} {x y : { x : { x : α // x = x } // x = x }} (h : x.1 = y.1) : f x = f y := by congr with : 1 From c65cf2ed7aa172d4553db080506ba1242c2ccdd2 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 15 Jul 2024 20:18:51 +0100 Subject: [PATCH 121/208] chore: upstream most LazyList results from Mathlib (#835) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François G. Dorais --- Batteries/Data/LazyList.lean | 159 ++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 1 deletion(-) diff --git a/Batteries/Data/LazyList.lean b/Batteries/Data/LazyList.lean index 9deb41e77b..48edafaf45 100644 --- a/Batteries/Data/LazyList.lean +++ b/Batteries/Data/LazyList.lean @@ -1,8 +1,9 @@ /- Copyright (c) 2017 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Leonardo de Moura +Authors: Leonardo de Moura, Simon Hudon -/ +import Batteries.Data.Thunk /-! # Lazy lists @@ -117,4 +118,160 @@ partial def iterates (f : α → α) : α → LazyList α partial def iota (i : Nat) : LazyList Nat := iterates Nat.succ i + +instance decidableEq {α : Type u} [DecidableEq α] : DecidableEq (LazyList α) + | nil, nil => isTrue rfl + | cons x xs, cons y ys => + if h : x = y then + match decidableEq xs.get ys.get with + | isFalse h2 => by + apply isFalse; simp only [cons.injEq, not_and]; intro _ xs_ys; apply h2; rw [xs_ys] + | isTrue h2 => by apply isTrue; congr; ext; exact h2 + else by apply isFalse; simp only [cons.injEq, not_and]; intro; contradiction + | nil, cons _ _ => by apply isFalse; simp + | cons _ _, nil => by apply isFalse; simp + +/-- Traversal of lazy lists using an applicative effect. -/ +protected def traverse {m : Type u → Type u} [Applicative m] {α β : Type u} (f : α → m β) : + LazyList α → m (LazyList β) + | LazyList.nil => pure LazyList.nil + | LazyList.cons x xs => LazyList.cons <$> f x <*> Thunk.pure <$> xs.get.traverse f + +/-- `init xs`, if `xs` non-empty, drops the last element of the list. +Otherwise, return the empty list. -/ +def init {α} : LazyList α → LazyList α + | LazyList.nil => LazyList.nil + | LazyList.cons x xs => + let xs' := xs.get + match xs' with + | LazyList.nil => LazyList.nil + | LazyList.cons _ _ => LazyList.cons x (init xs') + +/-- Return the first object contained in the list that satisfies +predicate `p` -/ +def find {α} (p : α → Prop) [DecidablePred p] : LazyList α → Option α + | nil => none + | cons h t => if p h then some h else t.get.find p + +/-- `interleave xs ys` creates a list where elements of `xs` and `ys` alternate. -/ +def interleave {α} : LazyList α → LazyList α → LazyList α + | LazyList.nil, xs => xs + | a@(LazyList.cons _ _), LazyList.nil => a + | LazyList.cons x xs, LazyList.cons y ys => + LazyList.cons x (LazyList.cons y (interleave xs.get ys.get)) + +/-- `interleaveAll (xs::ys::zs::xss)` creates a list where elements of `xs`, `ys` +and `zs` and the rest alternate. Every other element of the resulting list is taken from +`xs`, every fourth is taken from `ys`, every eighth is taken from `zs` and so on. -/ +def interleaveAll {α} : List (LazyList α) → LazyList α + | [] => LazyList.nil + | x :: xs => interleave x (interleaveAll xs) + +/-- Monadic bind operation for `LazyList`. -/ +protected def bind {α β} : LazyList α → (α → LazyList β) → LazyList β + | LazyList.nil, _ => LazyList.nil + | LazyList.cons x xs, f => (f x).append (xs.get.bind f) + +/-- Reverse the order of a `LazyList`. +It is done by converting to a `List` first because reversal involves evaluating all +the list and if the list is all evaluated, `List` is a better representation for +it than a series of thunks. -/ +def reverse {α} (xs : LazyList α) : LazyList α := + ofList xs.toList.reverse + +instance : Monad LazyList where + pure := @LazyList.singleton + bind := @LazyList.bind + +-- Porting note: Added `Thunk.pure` to definition. +theorem append_nil {α} (xs : LazyList α) : xs.append (Thunk.pure LazyList.nil) = xs := by + induction xs using LazyList.rec with + | nil => simp only [Thunk.pure, append, Thunk.get] + | cons _ _ => simpa only [append, cons.injEq, true_and] + | mk _ ih => ext; apply ih + +theorem append_assoc {α} (xs ys zs : LazyList α) : + (xs.append ys).append zs = xs.append (ys.append zs) := by + induction xs using LazyList.rec with + | nil => simp only [append, Thunk.get] + | cons _ _ => simpa only [append, cons.injEq, true_and] + | mk _ ih => ext; apply ih + +-- Porting note: Rewrote proof of `append_bind`. +theorem append_bind {α β} (xs : LazyList α) (ys : Thunk (LazyList α)) (f : α → LazyList β) : + (xs.append ys).bind f = (xs.bind f).append (ys.get.bind f) := by + match xs with + | LazyList.nil => + simp only [append, Thunk.get, LazyList.bind] + | LazyList.cons x xs => + simp only [append, Thunk.get, LazyList.bind] + have := append_bind xs.get ys f + simp only [Thunk.get] at this + rw [this, append_assoc] + +-- TODO: upstream from mathlib +-- instance : LawfulMonad LazyList.{u} + +/-- Try applying function `f` to every element of a `LazyList` and +return the result of the first attempt that succeeds. -/ +def mfirst {m} [Alternative m] {α β} (f : α → m β) : LazyList α → m β + | nil => failure + | cons x xs => f x <|> xs.get.mfirst f + +/-- Membership in lazy lists -/ +protected def Mem {α} (x : α) : LazyList α → Prop + | nil => False + | cons y ys => x = y ∨ ys.get.Mem x + +instance {α} : Membership α (LazyList α) := + ⟨LazyList.Mem⟩ + +instance Mem.decidable {α} [DecidableEq α] (x : α) : ∀ xs : LazyList α, Decidable (x ∈ xs) + | LazyList.nil => by + apply Decidable.isFalse + simp [Membership.mem, LazyList.Mem] + | LazyList.cons y ys => + if h : x = y then by + apply Decidable.isTrue + simp only [Membership.mem, LazyList.Mem] + exact Or.inl h + else by + have := Mem.decidable x ys.get + have : (x ∈ ys.get) ↔ (x ∈ cons y ys) := by simp [(· ∈ ·), LazyList.Mem, h] + exact decidable_of_decidable_of_iff this + +@[simp] +theorem mem_nil {α} (x : α) : x ∈ @LazyList.nil α ↔ False := by + simp [Membership.mem, LazyList.Mem] + +@[simp] +theorem mem_cons {α} (x y : α) (ys : Thunk (LazyList α)) : + x ∈ @LazyList.cons α y ys ↔ x = y ∨ x ∈ ys.get := by + simp [Membership.mem, LazyList.Mem] + +theorem forall_mem_cons {α} {p : α → Prop} {a : α} {l : Thunk (LazyList α)} : + (∀ x ∈ @LazyList.cons _ a l, p x) ↔ p a ∧ ∀ x ∈ l.get, p x := by + simp only [Membership.mem, LazyList.Mem, or_imp, forall_and, forall_eq] + +/-! ### map for partial functions -/ + + +/-- Partial map. If `f : ∀ a, p a → β` is a partial function defined on + `a : α` satisfying `p`, then `pmap f l h` is essentially the same as `map f l` + but is defined only when all members of `l` satisfy `p`, using the proof + to apply `f`. -/ +@[simp] +def pmap {α β} {p : α → Prop} (f : ∀ a, p a → β) : ∀ l : LazyList α, (∀ a ∈ l, p a) → LazyList β + | LazyList.nil, _ => LazyList.nil + | LazyList.cons x xs, H => + LazyList.cons (f x (forall_mem_cons.1 H).1) (xs.get.pmap f (forall_mem_cons.1 H).2) + +/-- "Attach" the proof that the elements of `l` are in `l` to produce a new `LazyList` + with the same elements but in the type `{x // x ∈ l}`. -/ +def attach {α} (l : LazyList α) : LazyList { x // x ∈ l } := + pmap Subtype.mk l fun _ => id + +instance {α} [Repr α] : Repr (LazyList α) := + ⟨fun xs _ => repr xs.toList⟩ + end LazyList From 8011496fd710cc4c6fffe7438416a0fe59649bd0 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 15 Jul 2024 14:35:53 -0500 Subject: [PATCH 122/208] Revert "chore: upstream most LazyList results from Mathlib" (#882) --- Batteries/Data/LazyList.lean | 159 +---------------------------------- 1 file changed, 1 insertion(+), 158 deletions(-) diff --git a/Batteries/Data/LazyList.lean b/Batteries/Data/LazyList.lean index 48edafaf45..9deb41e77b 100644 --- a/Batteries/Data/LazyList.lean +++ b/Batteries/Data/LazyList.lean @@ -1,9 +1,8 @@ /- Copyright (c) 2017 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Leonardo de Moura, Simon Hudon +Authors: Leonardo de Moura -/ -import Batteries.Data.Thunk /-! # Lazy lists @@ -118,160 +117,4 @@ partial def iterates (f : α → α) : α → LazyList α partial def iota (i : Nat) : LazyList Nat := iterates Nat.succ i - -instance decidableEq {α : Type u} [DecidableEq α] : DecidableEq (LazyList α) - | nil, nil => isTrue rfl - | cons x xs, cons y ys => - if h : x = y then - match decidableEq xs.get ys.get with - | isFalse h2 => by - apply isFalse; simp only [cons.injEq, not_and]; intro _ xs_ys; apply h2; rw [xs_ys] - | isTrue h2 => by apply isTrue; congr; ext; exact h2 - else by apply isFalse; simp only [cons.injEq, not_and]; intro; contradiction - | nil, cons _ _ => by apply isFalse; simp - | cons _ _, nil => by apply isFalse; simp - -/-- Traversal of lazy lists using an applicative effect. -/ -protected def traverse {m : Type u → Type u} [Applicative m] {α β : Type u} (f : α → m β) : - LazyList α → m (LazyList β) - | LazyList.nil => pure LazyList.nil - | LazyList.cons x xs => LazyList.cons <$> f x <*> Thunk.pure <$> xs.get.traverse f - -/-- `init xs`, if `xs` non-empty, drops the last element of the list. -Otherwise, return the empty list. -/ -def init {α} : LazyList α → LazyList α - | LazyList.nil => LazyList.nil - | LazyList.cons x xs => - let xs' := xs.get - match xs' with - | LazyList.nil => LazyList.nil - | LazyList.cons _ _ => LazyList.cons x (init xs') - -/-- Return the first object contained in the list that satisfies -predicate `p` -/ -def find {α} (p : α → Prop) [DecidablePred p] : LazyList α → Option α - | nil => none - | cons h t => if p h then some h else t.get.find p - -/-- `interleave xs ys` creates a list where elements of `xs` and `ys` alternate. -/ -def interleave {α} : LazyList α → LazyList α → LazyList α - | LazyList.nil, xs => xs - | a@(LazyList.cons _ _), LazyList.nil => a - | LazyList.cons x xs, LazyList.cons y ys => - LazyList.cons x (LazyList.cons y (interleave xs.get ys.get)) - -/-- `interleaveAll (xs::ys::zs::xss)` creates a list where elements of `xs`, `ys` -and `zs` and the rest alternate. Every other element of the resulting list is taken from -`xs`, every fourth is taken from `ys`, every eighth is taken from `zs` and so on. -/ -def interleaveAll {α} : List (LazyList α) → LazyList α - | [] => LazyList.nil - | x :: xs => interleave x (interleaveAll xs) - -/-- Monadic bind operation for `LazyList`. -/ -protected def bind {α β} : LazyList α → (α → LazyList β) → LazyList β - | LazyList.nil, _ => LazyList.nil - | LazyList.cons x xs, f => (f x).append (xs.get.bind f) - -/-- Reverse the order of a `LazyList`. -It is done by converting to a `List` first because reversal involves evaluating all -the list and if the list is all evaluated, `List` is a better representation for -it than a series of thunks. -/ -def reverse {α} (xs : LazyList α) : LazyList α := - ofList xs.toList.reverse - -instance : Monad LazyList where - pure := @LazyList.singleton - bind := @LazyList.bind - --- Porting note: Added `Thunk.pure` to definition. -theorem append_nil {α} (xs : LazyList α) : xs.append (Thunk.pure LazyList.nil) = xs := by - induction xs using LazyList.rec with - | nil => simp only [Thunk.pure, append, Thunk.get] - | cons _ _ => simpa only [append, cons.injEq, true_and] - | mk _ ih => ext; apply ih - -theorem append_assoc {α} (xs ys zs : LazyList α) : - (xs.append ys).append zs = xs.append (ys.append zs) := by - induction xs using LazyList.rec with - | nil => simp only [append, Thunk.get] - | cons _ _ => simpa only [append, cons.injEq, true_and] - | mk _ ih => ext; apply ih - --- Porting note: Rewrote proof of `append_bind`. -theorem append_bind {α β} (xs : LazyList α) (ys : Thunk (LazyList α)) (f : α → LazyList β) : - (xs.append ys).bind f = (xs.bind f).append (ys.get.bind f) := by - match xs with - | LazyList.nil => - simp only [append, Thunk.get, LazyList.bind] - | LazyList.cons x xs => - simp only [append, Thunk.get, LazyList.bind] - have := append_bind xs.get ys f - simp only [Thunk.get] at this - rw [this, append_assoc] - --- TODO: upstream from mathlib --- instance : LawfulMonad LazyList.{u} - -/-- Try applying function `f` to every element of a `LazyList` and -return the result of the first attempt that succeeds. -/ -def mfirst {m} [Alternative m] {α β} (f : α → m β) : LazyList α → m β - | nil => failure - | cons x xs => f x <|> xs.get.mfirst f - -/-- Membership in lazy lists -/ -protected def Mem {α} (x : α) : LazyList α → Prop - | nil => False - | cons y ys => x = y ∨ ys.get.Mem x - -instance {α} : Membership α (LazyList α) := - ⟨LazyList.Mem⟩ - -instance Mem.decidable {α} [DecidableEq α] (x : α) : ∀ xs : LazyList α, Decidable (x ∈ xs) - | LazyList.nil => by - apply Decidable.isFalse - simp [Membership.mem, LazyList.Mem] - | LazyList.cons y ys => - if h : x = y then by - apply Decidable.isTrue - simp only [Membership.mem, LazyList.Mem] - exact Or.inl h - else by - have := Mem.decidable x ys.get - have : (x ∈ ys.get) ↔ (x ∈ cons y ys) := by simp [(· ∈ ·), LazyList.Mem, h] - exact decidable_of_decidable_of_iff this - -@[simp] -theorem mem_nil {α} (x : α) : x ∈ @LazyList.nil α ↔ False := by - simp [Membership.mem, LazyList.Mem] - -@[simp] -theorem mem_cons {α} (x y : α) (ys : Thunk (LazyList α)) : - x ∈ @LazyList.cons α y ys ↔ x = y ∨ x ∈ ys.get := by - simp [Membership.mem, LazyList.Mem] - -theorem forall_mem_cons {α} {p : α → Prop} {a : α} {l : Thunk (LazyList α)} : - (∀ x ∈ @LazyList.cons _ a l, p x) ↔ p a ∧ ∀ x ∈ l.get, p x := by - simp only [Membership.mem, LazyList.Mem, or_imp, forall_and, forall_eq] - -/-! ### map for partial functions -/ - - -/-- Partial map. If `f : ∀ a, p a → β` is a partial function defined on - `a : α` satisfying `p`, then `pmap f l h` is essentially the same as `map f l` - but is defined only when all members of `l` satisfy `p`, using the proof - to apply `f`. -/ -@[simp] -def pmap {α β} {p : α → Prop} (f : ∀ a, p a → β) : ∀ l : LazyList α, (∀ a ∈ l, p a) → LazyList β - | LazyList.nil, _ => LazyList.nil - | LazyList.cons x xs, H => - LazyList.cons (f x (forall_mem_cons.1 H).1) (xs.get.pmap f (forall_mem_cons.1 H).2) - -/-- "Attach" the proof that the elements of `l` are in `l` to produce a new `LazyList` - with the same elements but in the type `{x // x ∈ l}`. -/ -def attach {α} (l : LazyList α) : LazyList { x // x ∈ l } := - pmap Subtype.mk l fun _ => id - -instance {α} [Repr α] : Repr (LazyList α) := - ⟨fun xs _ => repr xs.toList⟩ - end LazyList From 937cd3219c0beffa7b623d2905707d1304da259e Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 15 Jul 2024 15:12:23 -0500 Subject: [PATCH 123/208] chore: upstream most LazyList results from Mathlib (attempt 2) (#883) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eric Wieser Co-authored-by: François G. Dorais --- Batteries/Data/LazyList.lean | 159 ++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 1 deletion(-) diff --git a/Batteries/Data/LazyList.lean b/Batteries/Data/LazyList.lean index 9deb41e77b..48edafaf45 100644 --- a/Batteries/Data/LazyList.lean +++ b/Batteries/Data/LazyList.lean @@ -1,8 +1,9 @@ /- Copyright (c) 2017 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Leonardo de Moura +Authors: Leonardo de Moura, Simon Hudon -/ +import Batteries.Data.Thunk /-! # Lazy lists @@ -117,4 +118,160 @@ partial def iterates (f : α → α) : α → LazyList α partial def iota (i : Nat) : LazyList Nat := iterates Nat.succ i + +instance decidableEq {α : Type u} [DecidableEq α] : DecidableEq (LazyList α) + | nil, nil => isTrue rfl + | cons x xs, cons y ys => + if h : x = y then + match decidableEq xs.get ys.get with + | isFalse h2 => by + apply isFalse; simp only [cons.injEq, not_and]; intro _ xs_ys; apply h2; rw [xs_ys] + | isTrue h2 => by apply isTrue; congr; ext; exact h2 + else by apply isFalse; simp only [cons.injEq, not_and]; intro; contradiction + | nil, cons _ _ => by apply isFalse; simp + | cons _ _, nil => by apply isFalse; simp + +/-- Traversal of lazy lists using an applicative effect. -/ +protected def traverse {m : Type u → Type u} [Applicative m] {α β : Type u} (f : α → m β) : + LazyList α → m (LazyList β) + | LazyList.nil => pure LazyList.nil + | LazyList.cons x xs => LazyList.cons <$> f x <*> Thunk.pure <$> xs.get.traverse f + +/-- `init xs`, if `xs` non-empty, drops the last element of the list. +Otherwise, return the empty list. -/ +def init {α} : LazyList α → LazyList α + | LazyList.nil => LazyList.nil + | LazyList.cons x xs => + let xs' := xs.get + match xs' with + | LazyList.nil => LazyList.nil + | LazyList.cons _ _ => LazyList.cons x (init xs') + +/-- Return the first object contained in the list that satisfies +predicate `p` -/ +def find {α} (p : α → Prop) [DecidablePred p] : LazyList α → Option α + | nil => none + | cons h t => if p h then some h else t.get.find p + +/-- `interleave xs ys` creates a list where elements of `xs` and `ys` alternate. -/ +def interleave {α} : LazyList α → LazyList α → LazyList α + | LazyList.nil, xs => xs + | a@(LazyList.cons _ _), LazyList.nil => a + | LazyList.cons x xs, LazyList.cons y ys => + LazyList.cons x (LazyList.cons y (interleave xs.get ys.get)) + +/-- `interleaveAll (xs::ys::zs::xss)` creates a list where elements of `xs`, `ys` +and `zs` and the rest alternate. Every other element of the resulting list is taken from +`xs`, every fourth is taken from `ys`, every eighth is taken from `zs` and so on. -/ +def interleaveAll {α} : List (LazyList α) → LazyList α + | [] => LazyList.nil + | x :: xs => interleave x (interleaveAll xs) + +/-- Monadic bind operation for `LazyList`. -/ +protected def bind {α β} : LazyList α → (α → LazyList β) → LazyList β + | LazyList.nil, _ => LazyList.nil + | LazyList.cons x xs, f => (f x).append (xs.get.bind f) + +/-- Reverse the order of a `LazyList`. +It is done by converting to a `List` first because reversal involves evaluating all +the list and if the list is all evaluated, `List` is a better representation for +it than a series of thunks. -/ +def reverse {α} (xs : LazyList α) : LazyList α := + ofList xs.toList.reverse + +instance : Monad LazyList where + pure := @LazyList.singleton + bind := @LazyList.bind + +-- Porting note: Added `Thunk.pure` to definition. +theorem append_nil {α} (xs : LazyList α) : xs.append (Thunk.pure LazyList.nil) = xs := by + induction xs using LazyList.rec with + | nil => simp only [Thunk.pure, append, Thunk.get] + | cons _ _ => simpa only [append, cons.injEq, true_and] + | mk _ ih => ext; apply ih + +theorem append_assoc {α} (xs ys zs : LazyList α) : + (xs.append ys).append zs = xs.append (ys.append zs) := by + induction xs using LazyList.rec with + | nil => simp only [append, Thunk.get] + | cons _ _ => simpa only [append, cons.injEq, true_and] + | mk _ ih => ext; apply ih + +-- Porting note: Rewrote proof of `append_bind`. +theorem append_bind {α β} (xs : LazyList α) (ys : Thunk (LazyList α)) (f : α → LazyList β) : + (xs.append ys).bind f = (xs.bind f).append (ys.get.bind f) := by + match xs with + | LazyList.nil => + simp only [append, Thunk.get, LazyList.bind] + | LazyList.cons x xs => + simp only [append, Thunk.get, LazyList.bind] + have := append_bind xs.get ys f + simp only [Thunk.get] at this + rw [this, append_assoc] + +-- TODO: upstream from mathlib +-- instance : LawfulMonad LazyList.{u} + +/-- Try applying function `f` to every element of a `LazyList` and +return the result of the first attempt that succeeds. -/ +def mfirst {m} [Alternative m] {α β} (f : α → m β) : LazyList α → m β + | nil => failure + | cons x xs => f x <|> xs.get.mfirst f + +/-- Membership in lazy lists -/ +protected def Mem {α} (x : α) : LazyList α → Prop + | nil => False + | cons y ys => x = y ∨ ys.get.Mem x + +instance {α} : Membership α (LazyList α) := + ⟨LazyList.Mem⟩ + +instance Mem.decidable {α} [DecidableEq α] (x : α) : ∀ xs : LazyList α, Decidable (x ∈ xs) + | LazyList.nil => by + apply Decidable.isFalse + simp [Membership.mem, LazyList.Mem] + | LazyList.cons y ys => + if h : x = y then by + apply Decidable.isTrue + simp only [Membership.mem, LazyList.Mem] + exact Or.inl h + else by + have := Mem.decidable x ys.get + have : (x ∈ ys.get) ↔ (x ∈ cons y ys) := by simp [(· ∈ ·), LazyList.Mem, h] + exact decidable_of_decidable_of_iff this + +@[simp] +theorem mem_nil {α} (x : α) : x ∈ @LazyList.nil α ↔ False := by + simp [Membership.mem, LazyList.Mem] + +@[simp] +theorem mem_cons {α} (x y : α) (ys : Thunk (LazyList α)) : + x ∈ @LazyList.cons α y ys ↔ x = y ∨ x ∈ ys.get := by + simp [Membership.mem, LazyList.Mem] + +theorem forall_mem_cons {α} {p : α → Prop} {a : α} {l : Thunk (LazyList α)} : + (∀ x ∈ @LazyList.cons _ a l, p x) ↔ p a ∧ ∀ x ∈ l.get, p x := by + simp only [Membership.mem, LazyList.Mem, or_imp, forall_and, forall_eq] + +/-! ### map for partial functions -/ + + +/-- Partial map. If `f : ∀ a, p a → β` is a partial function defined on + `a : α` satisfying `p`, then `pmap f l h` is essentially the same as `map f l` + but is defined only when all members of `l` satisfy `p`, using the proof + to apply `f`. -/ +@[simp] +def pmap {α β} {p : α → Prop} (f : ∀ a, p a → β) : ∀ l : LazyList α, (∀ a ∈ l, p a) → LazyList β + | LazyList.nil, _ => LazyList.nil + | LazyList.cons x xs, H => + LazyList.cons (f x (forall_mem_cons.1 H).1) (xs.get.pmap f (forall_mem_cons.1 H).2) + +/-- "Attach" the proof that the elements of `l` are in `l` to produce a new `LazyList` + with the same elements but in the type `{x // x ∈ l}`. -/ +def attach {α} (l : LazyList α) : LazyList { x // x ∈ l } := + pmap Subtype.mk l fun _ => id + +instance {α} [Repr α] : Repr (LazyList α) := + ⟨fun xs _ => repr xs.toList⟩ + end LazyList From 0ecb86339ec1a04c19d424250f24b71dc1f54788 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 15 Jul 2024 19:29:49 -0500 Subject: [PATCH 124/208] chore: adaptations for nightly-2024-07-11 (#879) --- Batteries/Data/List/Basic.lean | 23 ----- Batteries/Data/List/Count.lean | 4 +- Batteries/Data/List/Lemmas.lean | 148 ------------------------------ Batteries/Data/List/Pairwise.lean | 4 +- Batteries/Data/List/Perm.lean | 2 +- lean-toolchain | 2 +- 6 files changed, 6 insertions(+), 177 deletions(-) diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index 723f6b6191..de1ae7b9f2 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -629,29 +629,6 @@ theorem sections_eq_nil_of_isEmpty : ∀ {L}, L.any isEmpty → @sections α L = rw [Array.foldl_eq_foldl_data, Array.foldl_data_eq_bind]; rfl intros; apply Array.foldl_data_eq_map -/-- `eraseP p l` removes the first element of `l` satisfying the predicate `p`. -/ -def eraseP (p : α → Bool) : List α → List α - | [] => [] - | a :: l => bif p a then l else a :: eraseP p l - -/-- Tail-recursive version of `eraseP`. -/ -@[inline] def erasePTR (p : α → Bool) (l : List α) : List α := go l #[] where - /-- Auxiliary for `erasePTR`: `erasePTR.go p l xs acc = acc.toList ++ eraseP p xs`, - unless `xs` does not contain any elements satisfying `p`, where it returns `l`. -/ - @[specialize] go : List α → Array α → List α - | [], _ => l - | a :: l, acc => bif p a then acc.toListAppend l else go l (acc.push a) - -@[csimp] theorem eraseP_eq_erasePTR : @eraseP = @erasePTR := by - funext α p l; simp [erasePTR] - let rec go (acc) : ∀ xs, l = acc.data ++ xs → - erasePTR.go p l xs acc = acc.data ++ xs.eraseP p - | [] => fun h => by simp [erasePTR.go, eraseP, h] - | x::xs => by - simp [erasePTR.go, eraseP]; cases p x <;> simp - · intro h; rw [go _ xs]; {simp}; simp [h] - exact (go #[] _ rfl).symm - /-- `extractP p l` returns a pair of an element `a` of `l` satisfying the predicate `p`, and `l`, with `a` removed. If there is no such element `a` it returns `(none, l)`. diff --git a/Batteries/Data/List/Count.lean b/Batteries/Data/List/Count.lean index dfd1481052..a118a8a704 100644 --- a/Batteries/Data/List/Count.lean +++ b/Batteries/Data/List/Count.lean @@ -62,8 +62,8 @@ theorem countP_eq_length_filter (l) : countP p l = length (filter p l) := by | nil => rfl | cons x l ih => if h : p x - then rw [countP_cons_of_pos p l h, ih, filter_cons_of_pos l h, length] - else rw [countP_cons_of_neg p l h, ih, filter_cons_of_neg l h] + then rw [countP_cons_of_pos p l h, ih, filter_cons_of_pos h, length] + else rw [countP_cons_of_neg p l h, ih, filter_cons_of_neg h] theorem countP_le_length : countP p l ≤ l.length := by simp only [countP_eq_length_filter] diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 32f49b761f..b28b369029 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -252,93 +252,6 @@ theorem length_eraseIdx : ∀ {l i}, i < length l → length (@eraseIdx α l i) /-! ### eraseP -/ -@[simp] theorem eraseP_nil : [].eraseP p = [] := rfl - -theorem eraseP_cons (a : α) (l : List α) : - (a :: l).eraseP p = bif p a then l else a :: l.eraseP p := rfl - -@[simp] theorem eraseP_cons_of_pos {l : List α} (p) (h : p a) : (a :: l).eraseP p = l := by - simp [eraseP_cons, h] - -@[simp] theorem eraseP_cons_of_neg {l : List α} (p) (h : ¬p a) : - (a :: l).eraseP p = a :: l.eraseP p := by simp [eraseP_cons, h] - -theorem eraseP_of_forall_not {l : List α} (h : ∀ a, a ∈ l → ¬p a) : l.eraseP p = l := by - induction l with - | nil => rfl - | cons _ _ ih => simp [h _ (.head ..), ih (forall_mem_cons.1 h).2] - -theorem exists_of_eraseP : ∀ {l : List α} {a} (al : a ∈ l) (pa : p a), - ∃ a l₁ l₂, (∀ b ∈ l₁, ¬p b) ∧ p a ∧ l = l₁ ++ a :: l₂ ∧ l.eraseP p = l₁ ++ l₂ - | b :: l, a, al, pa => - if pb : p b then - ⟨b, [], l, forall_mem_nil _, pb, by simp [pb]⟩ - else - match al with - | .head .. => nomatch pb pa - | .tail _ al => - let ⟨c, l₁, l₂, h₁, h₂, h₃, h₄⟩ := exists_of_eraseP al pa - ⟨c, b::l₁, l₂, (forall_mem_cons ..).2 ⟨pb, h₁⟩, - h₂, by rw [h₃, cons_append], by simp [pb, h₄]⟩ - -theorem exists_or_eq_self_of_eraseP (p) (l : List α) : - l.eraseP p = l ∨ - ∃ a l₁ l₂, (∀ b ∈ l₁, ¬p b) ∧ p a ∧ l = l₁ ++ a :: l₂ ∧ l.eraseP p = l₁ ++ l₂ := - if h : ∃ a ∈ l, p a then - let ⟨_, ha, pa⟩ := h - .inr (exists_of_eraseP ha pa) - else - .inl (eraseP_of_forall_not (h ⟨·, ·, ·⟩)) - -@[simp] theorem length_eraseP_of_mem (al : a ∈ l) (pa : p a) : - length (l.eraseP p) = Nat.pred (length l) := by - let ⟨_, l₁, l₂, _, _, e₁, e₂⟩ := exists_of_eraseP al pa - rw [e₂]; simp [length_append, e₁]; rfl - -theorem eraseP_append_left {a : α} (pa : p a) : - ∀ {l₁ : List α} l₂, a ∈ l₁ → (l₁++l₂).eraseP p = l₁.eraseP p ++ l₂ - | x :: xs, l₂, h => by - by_cases h' : p x <;> simp [h'] - rw [eraseP_append_left pa l₂ ((mem_cons.1 h).resolve_left (mt _ h'))] - intro | rfl => exact pa - -theorem eraseP_append_right : - ∀ {l₁ : List α} l₂, (∀ b ∈ l₁, ¬p b) → eraseP p (l₁++l₂) = l₁ ++ l₂.eraseP p - | [], l₂, _ => rfl - | x :: xs, l₂, h => by - simp [(forall_mem_cons.1 h).1, eraseP_append_right _ (forall_mem_cons.1 h).2] - -theorem eraseP_sublist (l : List α) : l.eraseP p <+ l := by - match exists_or_eq_self_of_eraseP p l with - | .inl h => rw [h]; apply Sublist.refl - | .inr ⟨c, l₁, l₂, _, _, h₃, h₄⟩ => rw [h₄, h₃]; simp - -theorem eraseP_subset (l : List α) : l.eraseP p ⊆ l := (eraseP_sublist l).subset - -protected theorem Sublist.eraseP : l₁ <+ l₂ → l₁.eraseP p <+ l₂.eraseP p - | .slnil => Sublist.refl _ - | .cons a s => by - by_cases h : p a <;> simp [h] - exacts [s.eraseP.trans (eraseP_sublist _), s.eraseP.cons _] - | .cons₂ a s => by - by_cases h : p a <;> simp [h] - exacts [s, s.eraseP] - -theorem mem_of_mem_eraseP {l : List α} : a ∈ l.eraseP p → a ∈ l := (eraseP_subset _ ·) - -@[simp] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a ∈ l.eraseP p ↔ a ∈ l := by - refine ⟨mem_of_mem_eraseP, fun al => ?_⟩ - match exists_or_eq_self_of_eraseP p l with - | .inl h => rw [h]; assumption - | .inr ⟨c, l₁, l₂, h₁, h₂, h₃, h₄⟩ => - rw [h₄]; rw [h₃] at al - have : a ≠ c := fun h => (h ▸ pa).elim h₂ - simp [this] at al; simp [al] - -theorem eraseP_map (f : β → α) : ∀ (l : List β), (map f l).eraseP p = map f (l.eraseP (p ∘ f)) - | [] => rfl - | b::l => by by_cases h : p (f b) <;> simp [h, eraseP_map f l, eraseP_cons_of_pos] - @[simp] theorem extractP_eq_find?_eraseP (l : List α) : extractP p l = (find? p l, eraseP p l) := by let rec go (acc) : ∀ xs, l = acc.data ++ xs → @@ -351,69 +264,8 @@ theorem eraseP_map (f : β → α) : ∀ (l : List β), (map f l).eraseP p = map /-! ### erase -/ -section erase -variable [BEq α] - -theorem erase_eq_eraseP' (a : α) (l : List α) : l.erase a = l.eraseP (· == a) := by - induction l - · simp - · next b t ih => - rw [erase_cons, eraseP_cons, ih] - if h : b == a then simp [h] else simp [h] - -theorem erase_eq_eraseP [LawfulBEq α] (a : α) : ∀ l : List α, l.erase a = l.eraseP (a == ·) - | [] => rfl - | b :: l => by - if h : a = b then simp [h] else simp [h, Ne.symm h, erase_eq_eraseP a l] - -theorem exists_erase_eq [LawfulBEq α] {a : α} {l : List α} (h : a ∈ l) : - ∃ l₁ l₂, a ∉ l₁ ∧ l = l₁ ++ a :: l₂ ∧ l.erase a = l₁ ++ l₂ := by - let ⟨_, l₁, l₂, h₁, e, h₂, h₃⟩ := exists_of_eraseP h (beq_self_eq_true _) - rw [erase_eq_eraseP]; exact ⟨l₁, l₂, fun h => h₁ _ h (beq_self_eq_true _), eq_of_beq e ▸ h₂, h₃⟩ - -@[simp] theorem length_erase_of_mem [LawfulBEq α] {a : α} {l : List α} (h : a ∈ l) : - length (l.erase a) = Nat.pred (length l) := by - rw [erase_eq_eraseP]; exact length_eraseP_of_mem h (beq_self_eq_true a) - -theorem erase_append_left [LawfulBEq α] {l₁ : List α} (l₂) (h : a ∈ l₁) : - (l₁ ++ l₂).erase a = l₁.erase a ++ l₂ := by - simp [erase_eq_eraseP]; exact eraseP_append_left (beq_self_eq_true a) l₂ h - -theorem erase_append_right [LawfulBEq α] {a : α} {l₁ : List α} (l₂ : List α) (h : a ∉ l₁) : - (l₁ ++ l₂).erase a = (l₁ ++ l₂.erase a) := by - rw [erase_eq_eraseP, erase_eq_eraseP, eraseP_append_right] - intros b h' h''; rw [eq_of_beq h''] at h; exact h h' - -theorem erase_subset (a : α) (l : List α) : l.erase a ⊆ l := (erase_sublist a l).subset - -theorem Sublist.erase (a : α) {l₁ l₂ : List α} (h : l₁ <+ l₂) : l₁.erase a <+ l₂.erase a := by - simp only [erase_eq_eraseP']; exact h.eraseP @[deprecated (since := "2024-04-22")] alias sublist.erase := Sublist.erase -theorem mem_of_mem_erase {a b : α} {l : List α} (h : a ∈ l.erase b) : a ∈ l := erase_subset _ _ h - -@[simp] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a ≠ b) : - a ∈ l.erase b ↔ a ∈ l := - erase_eq_eraseP b l ▸ mem_eraseP_of_neg (mt eq_of_beq ab.symm) - -theorem erase_comm [LawfulBEq α] (a b : α) (l : List α) : - (l.erase a).erase b = (l.erase b).erase a := by - if ab : a == b then rw [eq_of_beq ab] else ?_ - if ha : a ∈ l then ?_ else - simp only [erase_of_not_mem ha, erase_of_not_mem (mt mem_of_mem_erase ha)] - if hb : b ∈ l then ?_ else - simp only [erase_of_not_mem hb, erase_of_not_mem (mt mem_of_mem_erase hb)] - match l, l.erase a, exists_erase_eq ha with - | _, _, ⟨l₁, l₂, ha', rfl, rfl⟩ => - if h₁ : b ∈ l₁ then - rw [erase_append_left _ h₁, erase_append_left _ h₁, - erase_append_right _ (mt mem_of_mem_erase ha'), erase_cons_head] - else - rw [erase_append_right _ h₁, erase_append_right _ h₁, erase_append_right _ ha', - erase_cons_tail _ ab, erase_cons_head] - -end erase - /-! ### findIdx -/ @[simp] theorem findIdx_nil {α : Type _} (p : α → Bool) : [].findIdx p = 0 := rfl diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index f7eda7b68f..9393d316b9 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -134,10 +134,10 @@ theorem pairwise_filterMap (f : β → Option α) {l : List β} : | cons a l IH => ?_ match e : f a with | none => - rw [filterMap_cons_none _ _ e, pairwise_cons] + rw [filterMap_cons_none e, pairwise_cons] simp only [e, false_implies, implies_true, true_and, IH] | some b => - rw [filterMap_cons_some _ _ _ e] + rw [filterMap_cons_some e] simpa [IH, e] using fun _ => ⟨fun h a ha b hab => h _ _ ha hab, fun h a b ha hab => h _ ha _ hab⟩ diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index 035c5f10f5..4e988d6760 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -510,7 +510,7 @@ theorem erase_cons_subperm_cons_erase (a b : α) (l : List α) : rw [h, erase_cons_head]; apply subperm_cons_erase else have : ¬(a == b) = true := by simp only [beq_false_of_ne h, not_false_eq_true] - rw [erase_cons_tail _ this] + rw [erase_cons_tail this] theorem subperm_cons_diff {a : α} {l₁ l₂ : List α} : (a :: l₁).diff l₂ <+~ a :: l₁.diff l₂ := by induction l₂ with diff --git a/lean-toolchain b/lean-toolchain index 71dae0afae..93df21fce6 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-10 +leanprover/lean4:nightly-2024-07-11 From f36b1fda643e8e736506304104d6e653c9d2d98d Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Tue, 16 Jul 2024 09:06:11 +0000 Subject: [PATCH 125/208] chore: bump to nightly-2024-07-16 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 9f1d2860a1..efa3d71d3e 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-12 +leanprover/lean4:nightly-2024-07-16 From 8d5a61e00a9444592f9bba67be0a7a5aeea16057 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 17 Jul 2024 00:46:25 +1000 Subject: [PATCH 126/208] fix merge --- lean-toolchain | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lean-toolchain b/lean-toolchain index c3d6e45066..93df21fce6 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1,5 +1 @@ -<<<<<<< HEAD leanprover/lean4:nightly-2024-07-11 -======= -leanprover/lean4:v4.10.0-rc2 ->>>>>>> origin/main From f36a59bcf70934a7cc023db986eb72f8a6eb9e19 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Wed, 17 Jul 2024 09:06:47 +0000 Subject: [PATCH 127/208] chore: bump to nightly-2024-07-17 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index efa3d71d3e..067c06f9e0 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-16 +leanprover/lean4:nightly-2024-07-17 From 8236a3610b3ed9d6161ce4d3239230499bb5dba0 Mon Sep 17 00:00:00 2001 From: grunweg Date: Wed, 17 Jul 2024 20:29:10 +0200 Subject: [PATCH 128/208] doc: fix outdated docstring (#880) --- Batteries/Tactic/Lint/Misc.lean | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Batteries/Tactic/Lint/Misc.lean b/Batteries/Tactic/Lint/Misc.lean index 4bb3f2125b..3f0e69f648 100644 --- a/Batteries/Tactic/Lint/Misc.lean +++ b/Batteries/Tactic/Lint/Misc.lean @@ -239,9 +239,7 @@ def findUnusedHaves (e : Expr) : MetaM (Array MessageData) := do | _ => return res.get -/-- A linter for checking that declarations don't have unused term mode have statements. We do not -tag this as `@[env_linter]` so that it is not in the default linter set as it is slow and an -uncommon problem. -/ +/-- A linter for checking that declarations don't have unused term mode have statements. -/ @[env_linter] def unusedHavesSuffices : Linter where noErrorsFound := "No declarations have unused term mode have statements." errorsFound := "THE FOLLOWING DECLARATIONS HAVE INEFFECTUAL TERM MODE HAVE/SUFFICES BLOCKS. \ From 27b7b8814b9bc4634fcf3ace2388b171784f76e3 Mon Sep 17 00:00:00 2001 From: grunweg Date: Wed, 17 Jul 2024 20:29:43 +0200 Subject: [PATCH 129/208] feat: allow configuring additional linters to run (#881) --- Batteries/Tactic/Lint/Frontend.lean | 38 ++++++++++++++++++----------- scripts/runLinter.lean | 2 +- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Batteries/Tactic/Lint/Frontend.lean b/Batteries/Tactic/Lint/Frontend.lean index 072e23743f..841c696af8 100644 --- a/Batteries/Tactic/Lint/Frontend.lean +++ b/Batteries/Tactic/Lint/Frontend.lean @@ -65,20 +65,28 @@ inductive LintVerbosity | high deriving Inhabited, DecidableEq, Repr -/-- `getChecks slow extra use_only` produces a list of linters. -`extras` is a list of names that should resolve to declarations with type `linter`. -If `useOnly` is true, it only uses the linters in `extra`. -Otherwise, it uses all linters in the environment tagged with `@[env_linter]`. +/-- `getChecks slow runOnly runAlways` produces a list of linters. +`runOnly` is an optional list of names that should resolve to declarations with type `NamedLinter`. +If populated, only these linters are run (regardless of the default configuration). +`runAlways` is an optional list of names that should resolve to declarations with type +`NamedLinter`. If populated, these linters are always run (regardless of their configuration). +Specifying a linter in `runAlways` but not `runOnly` is an error. +Otherwise, it uses all enabled linters in the environment tagged with `@[env_linter]`. If `slow` is false, it only uses the fast default tests. -/ -def getChecks (slow : Bool) (useOnly : Bool) : CoreM (Array NamedLinter) := do +def getChecks (slow : Bool) (runOnly : Option (List Name)) (runAlways : Option (List Name)) : + CoreM (Array NamedLinter) := do let mut result := #[] - unless useOnly do - for (name, declName, dflt) in batteriesLinterExt.getState (← getEnv) do - if dflt then - let linter ← getLinter name declName - if slow || linter.isFast then - let _ := Inhabited.mk linter - result := result.binInsert (·.name.lt ·.name) linter + for (name, declName, default) in batteriesLinterExt.getState (← getEnv) do + let shouldRun := match (runOnly, runAlways) with + | (some only, some always) => only.contains name && (always.contains name || default) + | (some only, none) => only.contains name + | (none, some always) => default || always.contains name + | _ => default + if shouldRun then + let linter ← getLinter name declName + if slow || linter.isFast then + let _ := Inhabited.mk linter + result := result.binInsert (·.name.lt ·.name) linter pure result -- Note: we have to use the same context as `runTermElabM` here so that the `simpNF` @@ -238,9 +246,11 @@ elab tk:"#lint" verbosity:("+" <|> "-")? fast:"*"? only:(&" only")? | some ⟨.node _ `token.«-» _⟩ => pure .low | _ => throwUnsupportedSyntax let fast := fast.isSome - let only := only.isSome + let onlyNames : Option (List Name) := match only.isSome with + | true => some (linters.map fun l => l.getId).toList + | false => none let linters ← liftCoreM do - let mut result ← getChecks (slow := !fast) only + let mut result ← getChecks (slow := !fast) (runOnly := onlyNames) none let linterState := batteriesLinterExt.getState (← getEnv) for id in linters do let name := id.getId.eraseMacroScopes diff --git a/scripts/runLinter.lean b/scripts/runLinter.lean index 87d8774ce9..3d98a1c902 100644 --- a/scripts/runLinter.lean +++ b/scripts/runLinter.lean @@ -57,7 +57,7 @@ unsafe def main (args : List String) : IO Unit := do let state := { env } Prod.fst <$> (CoreM.toIO · ctx state) do let decls ← getDeclsInPackage module.getRoot - let linters ← getChecks (slow := true) (useOnly := false) + let linters ← getChecks (slow := true) (runAlways := none) (runOnly := none) let results ← lintCore decls linters if update then writeJsonFile (α := NoLints) nolintsFile <| From f27beb10b53350d6c1257ba3a8899df369135cc3 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 17 Jul 2024 13:30:10 -0500 Subject: [PATCH 130/208] chore: test file for linting lean4 (#871) --- test/lint_lean.lean | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 test/lint_lean.lean diff --git a/test/lint_lean.lean b/test/lint_lean.lean new file mode 100644 index 0000000000..2b2f8b89e1 --- /dev/null +++ b/test/lint_lean.lean @@ -0,0 +1,47 @@ +import Batteries.Tactic.Lint + +/-! +This test file runs the environment linters set up in Batteries on the core Lean4 repository. + +Everything is commented out as it is too slow to run in regular Batteries CI +(and in any case there are many failures still), +but it is useful to run locally to see what the linters would catch. +-/ + +-- We can't apply `nolint` attributes to imported declarations, +-- but if we move the environment linters up to Lean, +-- these nolints should be installed there. +-- (And in the meantime you can "manually" ignore them!) +-- attribute [nolint dupNamespace] Lean.Elab.Tactic.Tactic +-- attribute [nolint dupNamespace] Lean.Parser.Parser Lean.Parser.Parser.rec Lean.Parser.Parser.mk +-- Lean.Parser.Parser.info Lean.Parser.Parser.fn + +/-! Failing lints that need work. -/ + +-- #lint only explicitVarsOfIff in all -- Found 109 errors + +-- Many fixed in https://github.com/leanprover/lean4/pull/4620 +-- and should be checked again. +-- #lint only simpNF in all -- Found 34 errors + +/-! Lints that fail, but that we're not intending to do anything about. -/ + +-- Mostly fixed in https://github.com/leanprover/lean4/pull/4621 +-- There are many false positives here. +-- To run this properly we would need to ignore all declarations with `@[extern]`. +-- #lint only unusedArguments in all -- Found 89 errors + +-- After https://github.com/leanprover/lean4/pull/4616, these are all intentional and have +-- `nolint` attributes above. +-- #lint only dupNamespace in all -- Found 6 errors + +-- After https://github.com/leanprover/lean4/pull/4619 all of these should be caused by `abbrev`. +-- Unless we decide to upstream something like `alias`, we're not planning on fixing these. +-- #lint only defLemma in all -- Found 31 errors + +/-! Lints that have succeeded in the past, and hopefully still do! -/ + +-- #lint only impossibleInstance in all -- Found 0 errors +-- #lint only simpVarHead in all -- Found 0 error +-- #lint only unusedHavesSuffices in all -- Found 0 errors +-- #lint only checkUnivs in all -- Found 0 errors From 0b6235a9b1e052771e6c9e29758bb463af08b427 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Thu, 18 Jul 2024 09:05:08 +0000 Subject: [PATCH 131/208] chore: bump to nightly-2024-07-18 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 067c06f9e0..dbcbd6c940 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-17 +leanprover/lean4:nightly-2024-07-18 From c9c4179b6ea828b268ff9bd7bfd2c98dc3521a44 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 19 Jul 2024 02:58:18 +1000 Subject: [PATCH 132/208] delete upstreamed (long ago) checktactic --- Batteries.lean | 1 - Batteries/Util/CheckTactic.lean | 124 -------------------------------- 2 files changed, 125 deletions(-) delete mode 100644 Batteries/Util/CheckTactic.lean diff --git a/Batteries.lean b/Batteries.lean index 81878f133b..8e1e6f1828 100644 --- a/Batteries.lean +++ b/Batteries.lean @@ -98,7 +98,6 @@ import Batteries.Tactic.Unreachable import Batteries.Tactic.Where import Batteries.Test.Internal.DummyLabelAttr import Batteries.Util.Cache -import Batteries.Util.CheckTactic import Batteries.Util.ExtendedBinder import Batteries.Util.LibraryNote import Batteries.Util.Pickle diff --git a/Batteries/Util/CheckTactic.lean b/Batteries/Util/CheckTactic.lean deleted file mode 100644 index bc97e681cc..0000000000 --- a/Batteries/Util/CheckTactic.lean +++ /dev/null @@ -1,124 +0,0 @@ -/- -Copyright (c) 2024 Lean FRO. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Joe Hendrix --/ -import Lean.Elab.Tactic.ElabTerm -import Lean.Elab.Term - -/- -This file is the home for commands to tactics behave as expected. - -It currently includes two tactics: - -#check_tactic t ~> res - - -only a #check_simp command that applies simp -IT --/ - -namespace Batteries.Tactic - -open Lean Elab Tactic -open Meta - -/-- -Type used to lift an arbitrary value into a type parameter so it can -appear in a proof goal. - -It is used by the #check_tactic command. --/ -private inductive CheckGoalType {α : Sort u} : (val : α) → Prop where -| intro : (val : α) → CheckGoalType val - -private def matchCheckGoalType (stx : Syntax) (goalType : Expr) : MetaM (Expr × Expr × Level) := do - let u ← mkFreshLevelMVar - let type ← mkFreshExprMVar (some (.sort u)) - let val ← mkFreshExprMVar (some type) - let extType := mkAppN (.const ``CheckGoalType [u]) #[type, val] - if !(← isDefEq goalType extType) then - throwErrorAt stx "Goal{indentExpr goalType}\nis expected to match {indentExpr extType}" - pure (val, type, u) - -/-- -`check_tactic_goal t` verifies that the goal has is equal to -`CheckGoalType t` with reducible transparency. It closes the goal if so -and otherwise reports an error. - -It is used by #check_tactic. --/ -local syntax (name := check_tactic_goal) "check_tactic_goal " term : tactic - -/-- -Implementation of `check_tactic_goal` --/ -@[tactic check_tactic_goal] private def evalCheckTacticGoal : Tactic := fun stx => - match stx with - | `(tactic| check_tactic_goal $exp) => - closeMainGoalUsing (checkUnassigned := false) fun goalType => do - let (val, type, u) ← matchCheckGoalType stx goalType - let expTerm ← elabTermEnsuringType exp type - if !(← Meta.withReducible <| isDefEq val expTerm) then - throwErrorAt stx - m!"Term reduces to{indentExpr val}\nbut is expected to reduce to {indentExpr expTerm}" - return mkAppN (.const ``CheckGoalType.intro [u]) #[type, val] - | _ => throwErrorAt stx "check_goal syntax error" - -/-- -`check_tactic_goal t` verifies that the goal has is equal to -`CheckGoalType t` with reducible transparency. It closes the goal if so -and otherwise reports an error. - -It is used by #check_tactic. --/ -local syntax (name := check_tactic_fails) "check_tactic_fails " tactic : tactic - -@[tactic check_tactic_fails] private def evalCheckTacticFails : Tactic := fun stx => do - let `(tactic| check_tactic_fails $tactic) := stx - | throwUnsupportedSyntax - closeMainGoalUsing (checkUnassigned := false) fun goalType => do - let (val, type, u) ← matchCheckGoalType stx goalType - Term.withoutErrToSorry <| withoutRecover do - match (← try (some <$> evalTactic tactic) catch _ => pure none) with - | none => - return mkAppN (.const ``CheckGoalType.intro [u]) #[type, val] - | some () => - let gls ← getGoals - let ppGoal (g : MVarId) := do - let (val, _type, _u) ← matchCheckGoalType stx (← g.getType) - pure m!"{indentExpr val}" - let msg ← - match gls with - | [] => pure m!"{tactic} expected to fail on {val}, but closed goal." - | [g] => - pure <| m!"{tactic} expected to fail on {val}, but returned: {←ppGoal g}" - | gls => - let app m g := do pure <| m ++ (←ppGoal g) - let init := m!"{tactic} expected to fail on {val}, but returned goals:" - gls.foldlM (init := init) app - throwErrorAt stx msg - -/-- -`#check_tactic t ~> r by commands` runs the tactic sequence `commands` -on a goal with t in the type and sees if the resulting expression has -reduced it to `r`. --/ -macro "#check_tactic " t:term "~>" result:term "by" tac:tactic : command => - `(command|example : CheckGoalType $t := by $tac; check_tactic_goal $result) - -/-- -`#check_simp t ~> r` checks `simp` reduces `t` to `r`. --/ -macro "#check_simp " t:term "~>" exp:term : command => - `(command|#check_tactic $t ~> $exp by simp) - -example (x : Nat) : CheckGoalType ((x + z) = x) := by - fail_if_success simp [] - exact (CheckGoalType.intro ((x + z) = x)) - -/-- -`#check_simp t !~>` checks `simp` fails to reduce `t`. --/ -macro "#check_simp " t:term "!~>" : command => - `(command|example : CheckGoalType $t := by check_tactic_fails simp) From 60d692bee32b40deb67a99e39f2881026e94352e Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 19 Jul 2024 03:02:22 +1000 Subject: [PATCH 133/208] cleanup import --- test/array.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/test/array.lean b/test/array.lean index 41338a8bd4..2ba3a29577 100644 --- a/test/array.lean +++ b/test/array.lean @@ -1,4 +1,3 @@ -import Batteries.Util.CheckTactic import Batteries.Data.Array section From 42f3261a3e5f3a100ddfe67e8bcd1c15e9ab4955 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 18 Jul 2024 12:13:08 -0500 Subject: [PATCH 134/208] chore: adaptations for nightly-2024-07-16 (#885) --- Batteries/StdDeprecations.lean | 1 - Batteries/Tactic/Lint/Basic.lean | 2 ++ lean-toolchain | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Batteries/StdDeprecations.lean b/Batteries/StdDeprecations.lean index c705ee839d..f82b1739a7 100644 --- a/Batteries/StdDeprecations.lean +++ b/Batteries/StdDeprecations.lean @@ -22,7 +22,6 @@ Let's hope that people using the tactic implementations can work this out themse -/ @[deprecated (since := "2024-05-07")] alias Std.AssocList := Batteries.AssocList -@[deprecated (since := "2024-05-07")] alias Std.HashMap := Batteries.HashMap @[deprecated (since := "2024-05-07")] alias Std.mkHashMap := Batteries.mkHashMap @[deprecated (since := "2024-05-07")] alias Std.DList := Batteries.DList @[deprecated (since := "2024-05-07")] alias Std.PairingHeapImp.Heap := Batteries.PairingHeapImp.Heap diff --git a/Batteries/Tactic/Lint/Basic.lean b/Batteries/Tactic/Lint/Basic.lean index 87cc925a06..948bab5456 100644 --- a/Batteries/Tactic/Lint/Basic.lean +++ b/Batteries/Tactic/Lint/Basic.lean @@ -42,6 +42,8 @@ def isAutoDecl (decl : Name) : CoreM Bool := do if env.isConstructor n && ["injEq", "inj", "sizeOf_spec"].any (· == s) then return true if let ConstantInfo.inductInfo _ := (← getEnv).find? n then + if s.startsWith "brecOn_" || s.startsWith "below_" || s.startsWith "binductionOn_" + || s.startsWith "ibelow_" then return true if [casesOnSuffix, recOnSuffix, brecOnSuffix, binductionOnSuffix, belowSuffix, "ibelow", "ndrec", "ndrecOn", "noConfusionType", "noConfusion", "ofNat", "toCtorIdx" ].any (· == s) then diff --git a/lean-toolchain b/lean-toolchain index 93df21fce6..efa3d71d3e 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-11 +leanprover/lean4:nightly-2024-07-16 From e3f572276935d70b8c8ea9273eef720afb71be29 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 19 Jul 2024 09:05:01 +0000 Subject: [PATCH 135/208] chore: bump to nightly-2024-07-19 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index dbcbd6c940..110c616b9b 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-18 +leanprover/lean4:nightly-2024-07-19 From ac82ca1064a77eb76d37ae2ab2d1cdeb942d57fe Mon Sep 17 00:00:00 2001 From: Shrys Date: Fri, 19 Jul 2024 23:10:01 +0200 Subject: [PATCH 136/208] feat: Array lemma for empty map added (#877) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François G. Dorais --- Batteries/Data/Array/Lemmas.lean | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Batteries/Data/Array/Lemmas.lean b/Batteries/Data/Array/Lemmas.lean index cf069eb703..f59644a0fa 100644 --- a/Batteries/Data/Array/Lemmas.lean +++ b/Batteries/Data/Array/Lemmas.lean @@ -126,3 +126,10 @@ theorem size_shrink_loop (a : Array α) (n) : (shrink.loop n a).size = a.size - theorem size_shrink (a : Array α) (n) : (a.shrink n).size = min a.size n := by simp [shrink, size_shrink_loop] omega + +/-! ### map -/ + +theorem mapM_empty [Monad m] (f : α → m β) : mapM f #[] = pure #[] := by + rw [mapM, mapM.map]; rfl + +@[simp] theorem map_empty (f : α → β) : map f #[] = #[] := mapM_empty .. From c4bfc926bcaf9209523078d21ad2ef6ab146279b Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sat, 20 Jul 2024 09:05:02 +0000 Subject: [PATCH 137/208] chore: bump to nightly-2024-07-20 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 110c616b9b..48954e35d3 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-19 +leanprover/lean4:nightly-2024-07-20 From 96b27cde75f38d9e3f07a00a017f4a445f4b0af0 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Mon, 22 Jul 2024 09:06:28 +0000 Subject: [PATCH 138/208] chore: bump to nightly-2024-07-22 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 48954e35d3..603577fd2b 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-20 +leanprover/lean4:nightly-2024-07-22 From d2b1546c5fc05a06426e3f6ee1cb020e71be5592 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 22 Jul 2024 14:15:43 -0500 Subject: [PATCH 139/208] chore: deprecate LazyList (#884) --- Batteries/Data/LazyList.lean | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Batteries/Data/LazyList.lean b/Batteries/Data/LazyList.lean index 48edafaf45..426cdd2248 100644 --- a/Batteries/Data/LazyList.lean +++ b/Batteries/Data/LazyList.lean @@ -4,10 +4,14 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Simon Hudon -/ import Batteries.Data.Thunk - /-! # Lazy lists +Deprecated. This module is deprecated and will be removed in the future. +Most use cases can use `MLList`. Without custom support from the kernel +(previously provided in Lean 3) this type is not very useful, +but was ported from Lean 3 anyway. + The type `LazyList α` is a lazy list with elements of type `α`. In the VM, these are potentially infinite lists where all elements after the first are computed on-demand. @@ -18,6 +22,7 @@ logically we can prove that `LazyList α` is isomorphic to `List α`.) /-- Lazy list. All elements (except the first) are computed lazily. -/ +@[deprecated "Consider using `MLList`." (since := "2024-07-15")] inductive LazyList (α : Type u) : Type u /-- The empty lazy list. -/ | nil : LazyList α @@ -25,6 +30,7 @@ inductive LazyList (α : Type u) : Type u | cons (hd : α) (tl : Thunk <| LazyList α) : LazyList α +set_option linter.deprecated false namespace LazyList From 983852f1637ef7fc35e7da36e68495e1060ff05c Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Tue, 23 Jul 2024 09:05:20 +0000 Subject: [PATCH 140/208] chore: bump to nightly-2024-07-23 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 603577fd2b..1f75cd931e 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-22 +leanprover/lean4:nightly-2024-07-23 From 93e66f13cb64c00a3167df0f540fbdb103624182 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 26 Jul 2024 09:06:32 +1000 Subject: [PATCH 141/208] bump toolchain --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 1f75cd931e..ad37d86963 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-23 +leanprover/lean4:nightly-2024-07-25 From e7897807913fafdab31b01b9f627550bcc96cff2 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 26 Jul 2024 10:48:35 +1000 Subject: [PATCH 142/208] chore: robustify for byAsSorry (#892) --- Batteries/CodeAction/Deprecated.lean | 2 +- Batteries/Data/List/Lemmas.lean | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Batteries/CodeAction/Deprecated.lean b/Batteries/CodeAction/Deprecated.lean index f308992885..ec6a2f11c2 100644 --- a/Batteries/CodeAction/Deprecated.lean +++ b/Batteries/CodeAction/Deprecated.lean @@ -32,7 +32,7 @@ def deprecatedCodeActionProvider : CodeActionProvider := fun params snap => do for m in snap.msgLog.toList do if m.data.isDeprecationWarning then if h : _ then - msgs := msgs.push (snap.cmdState.messages.toList[i]) + msgs := msgs.push (snap.cmdState.messages.toList[i]'h) i := i + 1 if msgs.isEmpty then return #[] let start := doc.meta.text.lspPosToUtf8Pos params.range.start diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 1cf017c534..b932b5ff71 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -379,7 +379,7 @@ theorem modifyNth_eq_take_drop (f : α → α) : ∀ n l, modifyNth f n l = take n l ++ modifyHead f (drop n l) := modifyNthTail_eq_take_drop _ rfl -theorem modifyNth_eq_take_cons_drop (f : α → α) {n l} (h) : +theorem modifyNth_eq_take_cons_drop (f : α → α) {n l} (h : n < length l) : modifyNth f n l = take n l ++ f l[n] :: drop (n + 1) l := by rw [modifyNth_eq_take_drop, drop_eq_getElem_cons h]; rfl From 418f8e0a183046602ac9d719ab7f56ee0fe9adc9 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 26 Jul 2024 09:05:09 +0000 Subject: [PATCH 143/208] chore: bump to nightly-2024-07-26 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index ad37d86963..b34774d04a 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-25 +leanprover/lean4:nightly-2024-07-26 From 1484b779684234f24d0a8a374813cbdb42e4ebea Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 26 Jul 2024 21:11:34 +1000 Subject: [PATCH 144/208] removing upstreamed --- Batteries/Data/List/Basic.lean | 24 ---- Batteries/Data/List/Lemmas.lean | 197 +------------------------------- Batteries/Data/Nat/Basic.lean | 3 - 3 files changed, 1 insertion(+), 223 deletions(-) diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index de1ae7b9f2..fba6f08f39 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -417,30 +417,6 @@ replacing `a → b` at the first value `a` in the list such that `f a = some b`. /-- `count a l` is the number of occurrences of `a` in `l`. -/ @[inline] def count [BEq α] (a : α) : List α → Nat := countP (· == a) -/-- -`IsPrefix l₁ l₂`, or `l₁ <+: l₂`, means that `l₁` is a prefix of `l₂`, -that is, `l₂` has the form `l₁ ++ t` for some `t`. --/ -def IsPrefix (l₁ : List α) (l₂ : List α) : Prop := ∃ t, l₁ ++ t = l₂ - -/-- -`IsSuffix l₁ l₂`, or `l₁ <:+ l₂`, means that `l₁` is a suffix of `l₂`, -that is, `l₂` has the form `t ++ l₁` for some `t`. --/ -def IsSuffix (l₁ : List α) (l₂ : List α) : Prop := ∃ t, t ++ l₁ = l₂ - -/-- -`IsInfix l₁ l₂`, or `l₁ <:+: l₂`, means that `l₁` is a contiguous -substring of `l₂`, that is, `l₂` has the form `s ++ l₁ ++ t` for some `s, t`. --/ -def IsInfix (l₁ : List α) (l₂ : List α) : Prop := ∃ s t, s ++ l₁ ++ t = l₂ - -@[inherit_doc] infixl:50 " <+: " => IsPrefix - -@[inherit_doc] infixl:50 " <:+ " => IsSuffix - -@[inherit_doc] infixl:50 " <:+: " => IsInfix - /-- `inits l` is the list of initial segments of `l`. ``` diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 46dc4a340b..1c9cae770b 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -26,7 +26,7 @@ theorem drop_one : ∀ l : List α, drop 1 l = tail l /-! ### zipWith -/ theorem zipWith_distrib_tail : (zipWith f l l').tail = zipWith f l.tail l'.tail := by - rw [← drop_one]; simp [zipWith_distrib_drop] + rw [← drop_one]; simp [drop_zipWith] /-! ### tail -/ @@ -629,201 +629,6 @@ theorem Sublist.erase_diff_erase_sublist {a : α} : end Diff -/-! ### prefix, suffix, infix -/ - -@[simp] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := ⟨l₂, rfl⟩ - -@[simp] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := ⟨l₁, rfl⟩ - -theorem infix_append (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ l₂ ++ l₃ := ⟨l₁, l₃, rfl⟩ - -@[simp] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by - rw [← List.append_assoc]; apply infix_append - -theorem IsPrefix.isInfix : l₁ <+: l₂ → l₁ <:+: l₂ := fun ⟨t, h⟩ => ⟨[], t, h⟩ - -theorem IsSuffix.isInfix : l₁ <:+ l₂ → l₁ <:+: l₂ := fun ⟨t, h⟩ => ⟨t, [], by rw [h, append_nil]⟩ - -theorem nil_prefix (l : List α) : [] <+: l := ⟨l, rfl⟩ - -theorem nil_suffix (l : List α) : [] <:+ l := ⟨l, append_nil _⟩ - -theorem nil_infix (l : List α) : [] <:+: l := (nil_prefix _).isInfix - -theorem prefix_refl (l : List α) : l <+: l := ⟨[], append_nil _⟩ - -theorem suffix_refl (l : List α) : l <:+ l := ⟨[], rfl⟩ - -theorem infix_refl (l : List α) : l <:+: l := (prefix_refl l).isInfix - -@[simp] theorem suffix_cons (a : α) : ∀ l, l <:+ a :: l := suffix_append [a] - -theorem infix_cons : l₁ <:+: l₂ → l₁ <:+: a :: l₂ := fun ⟨L₁, L₂, h⟩ => ⟨a :: L₁, L₂, h ▸ rfl⟩ - -theorem infix_concat : l₁ <:+: l₂ → l₁ <:+: concat l₂ a := fun ⟨L₁, L₂, h⟩ => - ⟨L₁, concat L₂ a, by simp [← h, concat_eq_append, append_assoc]⟩ - -theorem IsPrefix.trans : ∀ {l₁ l₂ l₃ : List α}, l₁ <+: l₂ → l₂ <+: l₃ → l₁ <+: l₃ - | _, _, _, ⟨r₁, rfl⟩, ⟨r₂, rfl⟩ => ⟨r₁ ++ r₂, (append_assoc _ _ _).symm⟩ - -theorem IsSuffix.trans : ∀ {l₁ l₂ l₃ : List α}, l₁ <:+ l₂ → l₂ <:+ l₃ → l₁ <:+ l₃ - | _, _, _, ⟨l₁, rfl⟩, ⟨l₂, rfl⟩ => ⟨l₂ ++ l₁, append_assoc _ _ _⟩ - -theorem IsInfix.trans : ∀ {l₁ l₂ l₃ : List α}, l₁ <:+: l₂ → l₂ <:+: l₃ → l₁ <:+: l₃ - | l, _, _, ⟨l₁, r₁, rfl⟩, ⟨l₂, r₂, rfl⟩ => ⟨l₂ ++ l₁, r₁ ++ r₂, by simp only [append_assoc]⟩ - -protected theorem IsInfix.sublist : l₁ <:+: l₂ → l₁ <+ l₂ - | ⟨_, _, h⟩ => h ▸ (sublist_append_right ..).trans (sublist_append_left ..) - -protected theorem IsInfix.subset (hl : l₁ <:+: l₂) : l₁ ⊆ l₂ := - hl.sublist.subset - -protected theorem IsPrefix.sublist (h : l₁ <+: l₂) : l₁ <+ l₂ := - h.isInfix.sublist - -protected theorem IsPrefix.subset (hl : l₁ <+: l₂) : l₁ ⊆ l₂ := - hl.sublist.subset - -protected theorem IsSuffix.sublist (h : l₁ <:+ l₂) : l₁ <+ l₂ := - h.isInfix.sublist - -protected theorem IsSuffix.subset (hl : l₁ <:+ l₂) : l₁ ⊆ l₂ := - hl.sublist.subset - -@[simp] theorem reverse_suffix : reverse l₁ <:+ reverse l₂ ↔ l₁ <+: l₂ := - ⟨fun ⟨r, e⟩ => ⟨reverse r, by rw [← reverse_reverse l₁, ← reverse_append, e, reverse_reverse]⟩, - fun ⟨r, e⟩ => ⟨reverse r, by rw [← reverse_append, e]⟩⟩ - -@[simp] theorem reverse_prefix : reverse l₁ <+: reverse l₂ ↔ l₁ <:+ l₂ := by - rw [← reverse_suffix]; simp only [reverse_reverse] - -@[simp] theorem reverse_infix : reverse l₁ <:+: reverse l₂ ↔ l₁ <:+: l₂ := by - refine ⟨fun ⟨s, t, e⟩ => ⟨reverse t, reverse s, ?_⟩, fun ⟨s, t, e⟩ => ⟨reverse t, reverse s, ?_⟩⟩ - · rw [← reverse_reverse l₁, append_assoc, ← reverse_append, ← reverse_append, e, - reverse_reverse] - · rw [append_assoc, ← reverse_append, ← reverse_append, e] - -theorem IsInfix.length_le (h : l₁ <:+: l₂) : l₁.length ≤ l₂.length := - h.sublist.length_le - -theorem IsPrefix.length_le (h : l₁ <+: l₂) : l₁.length ≤ l₂.length := - h.sublist.length_le - -theorem IsSuffix.length_le (h : l₁ <:+ l₂) : l₁.length ≤ l₂.length := - h.sublist.length_le - -@[simp] theorem infix_nil : l <:+: [] ↔ l = [] := ⟨(sublist_nil.1 ·.sublist), (· ▸ infix_refl _)⟩ - -@[simp] theorem prefix_nil : l <+: [] ↔ l = [] := ⟨(sublist_nil.1 ·.sublist), (· ▸ prefix_refl _)⟩ - -@[simp] theorem suffix_nil : l <:+ [] ↔ l = [] := ⟨(sublist_nil.1 ·.sublist), (· ▸ suffix_refl _)⟩ - -theorem infix_iff_prefix_suffix (l₁ l₂ : List α) : l₁ <:+: l₂ ↔ ∃ t, l₁ <+: t ∧ t <:+ l₂ := - ⟨fun ⟨_, t, e⟩ => ⟨l₁ ++ t, ⟨_, rfl⟩, e ▸ append_assoc .. ▸ ⟨_, rfl⟩⟩, - fun ⟨_, ⟨t, rfl⟩, s, e⟩ => ⟨s, t, append_assoc .. ▸ e⟩⟩ - -theorem IsInfix.eq_of_length (h : l₁ <:+: l₂) : l₁.length = l₂.length → l₁ = l₂ := - h.sublist.eq_of_length - -theorem IsPrefix.eq_of_length (h : l₁ <+: l₂) : l₁.length = l₂.length → l₁ = l₂ := - h.sublist.eq_of_length - -theorem IsSuffix.eq_of_length (h : l₁ <:+ l₂) : l₁.length = l₂.length → l₁ = l₂ := - h.sublist.eq_of_length - -theorem prefix_of_prefix_length_le : - ∀ {l₁ l₂ l₃ : List α}, l₁ <+: l₃ → l₂ <+: l₃ → length l₁ ≤ length l₂ → l₁ <+: l₂ - | [], l₂, _, _, _, _ => nil_prefix _ - | a :: l₁, b :: l₂, _, ⟨r₁, rfl⟩, ⟨r₂, e⟩, ll => by - injection e with _ e'; subst b - rcases prefix_of_prefix_length_le ⟨_, rfl⟩ ⟨_, e'⟩ (le_of_succ_le_succ ll) with ⟨r₃, rfl⟩ - exact ⟨r₃, rfl⟩ - -theorem prefix_or_prefix_of_prefix (h₁ : l₁ <+: l₃) (h₂ : l₂ <+: l₃) : l₁ <+: l₂ ∨ l₂ <+: l₁ := - (Nat.le_total (length l₁) (length l₂)).imp (prefix_of_prefix_length_le h₁ h₂) - (prefix_of_prefix_length_le h₂ h₁) - -theorem suffix_of_suffix_length_le - (h₁ : l₁ <:+ l₃) (h₂ : l₂ <:+ l₃) (ll : length l₁ ≤ length l₂) : l₁ <:+ l₂ := - reverse_prefix.1 <| - prefix_of_prefix_length_le (reverse_prefix.2 h₁) (reverse_prefix.2 h₂) (by simp [ll]) - -theorem suffix_or_suffix_of_suffix (h₁ : l₁ <:+ l₃) (h₂ : l₂ <:+ l₃) : l₁ <:+ l₂ ∨ l₂ <:+ l₁ := - (prefix_or_prefix_of_prefix (reverse_prefix.2 h₁) (reverse_prefix.2 h₂)).imp reverse_prefix.1 - reverse_prefix.1 - -theorem suffix_cons_iff : l₁ <:+ a :: l₂ ↔ l₁ = a :: l₂ ∨ l₁ <:+ l₂ := by - constructor - · rintro ⟨⟨hd, tl⟩, hl₃⟩ - · exact Or.inl hl₃ - · simp only [cons_append] at hl₃ - injection hl₃ with _ hl₄ - exact Or.inr ⟨_, hl₄⟩ - · rintro (rfl | hl₁) - · exact (a :: l₂).suffix_refl - · exact hl₁.trans (l₂.suffix_cons _) - -theorem infix_cons_iff : l₁ <:+: a :: l₂ ↔ l₁ <+: a :: l₂ ∨ l₁ <:+: l₂ := by - constructor - · rintro ⟨⟨hd, tl⟩, t, hl₃⟩ - · exact Or.inl ⟨t, hl₃⟩ - · simp only [cons_append] at hl₃ - injection hl₃ with _ hl₄ - exact Or.inr ⟨_, t, hl₄⟩ - · rintro (h | hl₁) - · exact h.isInfix - · exact infix_cons hl₁ - -theorem infix_of_mem_join : ∀ {L : List (List α)}, l ∈ L → l <:+: join L - | l' :: _, h => - match h with - | List.Mem.head .. => infix_append [] _ _ - | List.Mem.tail _ hlMemL => - IsInfix.trans (infix_of_mem_join hlMemL) <| (suffix_append _ _).isInfix - -theorem prefix_append_right_inj (l) : l ++ l₁ <+: l ++ l₂ ↔ l₁ <+: l₂ := - exists_congr fun r => by rw [append_assoc, append_right_inj] - -@[simp] -theorem prefix_cons_inj (a) : a :: l₁ <+: a :: l₂ ↔ l₁ <+: l₂ := - prefix_append_right_inj [a] - -theorem take_prefix (n) (l : List α) : take n l <+: l := - ⟨_, take_append_drop _ _⟩ - -theorem drop_suffix (n) (l : List α) : drop n l <:+ l := - ⟨_, take_append_drop _ _⟩ - -theorem take_sublist (n) (l : List α) : take n l <+ l := - (take_prefix n l).sublist - -theorem drop_sublist (n) (l : List α) : drop n l <+ l := - (drop_suffix n l).sublist - -theorem take_subset (n) (l : List α) : take n l ⊆ l := - (take_sublist n l).subset - -theorem drop_subset (n) (l : List α) : drop n l ⊆ l := - (drop_sublist n l).subset - -theorem mem_of_mem_take {l : List α} (h : a ∈ l.take n) : a ∈ l := - take_subset n l h - -theorem IsPrefix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) : - l₁.filter p <+: l₂.filter p := by - obtain ⟨xs, rfl⟩ := h - rw [filter_append]; apply prefix_append - -theorem IsSuffix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) : - l₁.filter p <:+ l₂.filter p := by - obtain ⟨xs, rfl⟩ := h - rw [filter_append]; apply suffix_append - -theorem IsInfix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) : - l₁.filter p <:+: l₂.filter p := by - obtain ⟨xs, ys, rfl⟩ := h - rw [filter_append, filter_append]; apply infix_append _ - /-! ### drop -/ theorem mem_of_mem_drop {n} {l : List α} (h : a ∈ l.drop n) : a ∈ l := drop_subset _ _ h diff --git a/Batteries/Data/Nat/Basic.lean b/Batteries/Data/Nat/Basic.lean index a6e55a6ea2..1d9658f49e 100644 --- a/Batteries/Data/Nat/Basic.lean +++ b/Batteries/Data/Nat/Basic.lean @@ -94,9 +94,6 @@ protected def casesDiagOn {motive : Nat → Nat → Sort _} (m n : Nat) Nat.recDiag zero_zero (fun _ _ => zero_succ _) (fun _ _ => succ_zero _) (fun _ _ _ => succ_succ _ _) m n -/-- Sum of a list of natural numbers. -/ -protected def sum (l : List Nat) : Nat := l.foldr (·+·) 0 - /-- Integer square root function. Implemented via Newton's method. -/ From 17bbd97f428b1af93e111b032745db55935227a0 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 26 Jul 2024 21:14:19 +1000 Subject: [PATCH 145/208] updates --- Batteries/Data/HashMap/WF.lean | 4 ++-- Batteries/Data/List/Count.lean | 2 +- Batteries/Data/List/EraseIdx.lean | 2 +- Batteries/Data/List/Lemmas.lean | 4 ++-- Batteries/Data/List/Perm.lean | 8 ++++---- Batteries/Data/Nat/Lemmas.lean | 4 ---- 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index f7ee6ed1da..e83e32e567 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -315,7 +315,7 @@ theorem WF.mapVal {α β γ} {f : α → β → γ} [BEq α] [Hashable α] have ⟨h₁, h₂⟩ := H.out simp only [Imp.mapVal, h₁, Buckets.mapVal, WF_iff]; refine ⟨?_, ?_, fun i h => ?_⟩ · simp only [Buckets.size, Array.map_data, List.map_map]; congr; funext l; simp - · simp only [Array.map_data, List.forall_mem_map_iff] + · simp only [Array.map_data, List.forall_mem_map] simp only [AssocList.toList_mapVal, List.pairwise_map] exact fun _ => h₂.1 _ · simp only [Array.size_map, AssocList.All, Array.getElem_map, AssocList.toList_mapVal, @@ -361,7 +361,7 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable simp only [Array.mapM_eq_mapM_data, bind, StateT.bind, H2, List.map_map, Nat.zero_add, g] intro bk sz h e'; cases e' refine .mk (by simp [Buckets.size]) ⟨?_, fun i h => ?_⟩ - · simp only [List.forall_mem_map_iff, List.toList_toAssocList] + · simp only [List.forall_mem_map, List.toList_toAssocList] refine fun l h => (List.pairwise_reverse.2 ?_).imp (mt PartialEquivBEq.symm) have := H.out.2.1 _ h rw [← List.pairwise_map (R := (¬ · == ·))] at this ⊢ diff --git a/Batteries/Data/List/Count.lean b/Batteries/Data/List/Count.lean index a118a8a704..3aece22185 100644 --- a/Batteries/Data/List/Count.lean +++ b/Batteries/Data/List/Count.lean @@ -152,7 +152,7 @@ theorem count_le_length (a : α) (l : List α) : count a l ≤ l.length := count theorem Sublist.count_le (h : l₁ <+ l₂) (a : α) : count a l₁ ≤ count a l₂ := h.countP_le _ theorem count_le_count_cons (a b : α) (l : List α) : count a l ≤ count a (b :: l) := - (sublist_cons _ _).count_le _ + (sublist_cons_self _ _).count_le _ theorem count_singleton (a : α) : count a [a] = 1 := by simp diff --git a/Batteries/Data/List/EraseIdx.lean b/Batteries/Data/List/EraseIdx.lean index ca3cf2e716..eb1648d630 100644 --- a/Batteries/Data/List/EraseIdx.lean +++ b/Batteries/Data/List/EraseIdx.lean @@ -50,7 +50,7 @@ theorem eraseIdx_append_of_length_le {l : List α} {k : Nat} (hk : length l ≤ eraseIdx (l ++ l') k = l ++ eraseIdx l' (k - length l) := by rw [eraseIdx_eq_take_drop_succ, eraseIdx_eq_take_drop_succ, take_append_eq_append_take, drop_append_eq_append_drop, - take_all_of_le hk, drop_eq_nil_of_le (by omega), nil_append, append_assoc] + take_of_length_le hk, drop_eq_nil_of_le (by omega), nil_append, append_assoc] congr omega diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 1c9cae770b..724b67a56a 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -437,10 +437,10 @@ theorem disjoint_of_subset_right (ss : l₂ ⊆ l) (d : Disjoint l₁ l) : Disjo fun _ m m₁ => d m (ss m₁) theorem disjoint_of_disjoint_cons_left {l₁ l₂} : Disjoint (a :: l₁) l₂ → Disjoint l₁ l₂ := -disjoint_of_subset_left (subset_cons _ _) + disjoint_of_subset_left (subset_cons_self _ _) theorem disjoint_of_disjoint_cons_right {l₁ l₂} : Disjoint l₁ (a :: l₂) → Disjoint l₁ l₂ := -disjoint_of_subset_right (subset_cons _ _) + disjoint_of_subset_right (subset_cons_self _ _) @[simp] theorem disjoint_nil_left (l : List α) : Disjoint [] l := fun a => (not_mem_nil a).elim diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index 4e988d6760..5c31720c7c 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -231,7 +231,7 @@ theorem Subperm.trans {l₁ l₂ l₃ : List α} (s₁₂ : l₁ <+~ l₂) (s₂ ⟨l₁', p₁, s₁.trans s₂⟩ theorem Subperm.cons_right {α : Type _} {l l' : List α} (x : α) (h : l <+~ l') : l <+~ x :: l' := - h.trans (sublist_cons x l').subperm + h.trans (sublist_cons_self x l').subperm theorem Subperm.length_le {l₁ l₂ : List α} : l₁ <+~ l₂ → length l₁ ≤ length l₂ | ⟨_l, p, s⟩ => p.length_eq ▸ s.length_le @@ -368,7 +368,7 @@ theorem perm_append_right_iff {l₁ l₂ : List α} (l) : l₁ ++ l ~ l₂ ++ l theorem subperm_cons (a : α) {l₁ l₂ : List α} : a :: l₁ <+~ a :: l₂ ↔ l₁ <+~ l₂ := by refine ⟨fun ⟨l, p, s⟩ => ?_, fun ⟨l, p, s⟩ => ⟨a :: l, p.cons a, s.cons₂ _⟩⟩ match s with - | .cons _ s' => exact (p.subperm_left.2 <| (sublist_cons _ _).subperm).trans s'.subperm + | .cons _ s' => exact (p.subperm_left.2 <| (sublist_cons_self _ _).subperm).trans s'.subperm | .cons₂ _ s' => exact ⟨_, p.cons_inv, s'⟩ /-- Weaker version of `Subperm.cons_left` -/ @@ -409,7 +409,7 @@ theorem Subperm.exists_of_length_lt {l₁ l₂ : List α} (s : l₁ <+~ l₂) (h | slnil => cases h | cons a s IH => match Nat.lt_or_eq_of_le (Nat.le_of_lt_succ h) with - | .inl h => exact (IH h).imp fun a s => s.trans (sublist_cons _ _).subperm + | .inl h => exact (IH h).imp fun a s => s.trans (sublist_cons_self _ _).subperm | .inr h => exact ⟨a, s.eq_of_length h ▸ .refl _⟩ | cons₂ b _ IH => exact (IH <| Nat.lt_of_succ_lt_succ h).imp fun a s => @@ -461,7 +461,7 @@ theorem subperm_cons_erase (a : α) (l : List α) : l <+~ a :: l.erase a := if h : a ∈ l then (perm_cons_erase h).subperm else - (erase_of_not_mem h).symm ▸ (sublist_cons _ _).subperm + (erase_of_not_mem h).symm ▸ (sublist_cons_self _ _).subperm theorem erase_subperm (a : α) (l : List α) : l.erase a <+~ l := (erase_sublist _ _).subperm diff --git a/Batteries/Data/Nat/Lemmas.lean b/Batteries/Data/Nat/Lemmas.lean index 842ca09e95..1c3edddeaf 100644 --- a/Batteries/Data/Nat/Lemmas.lean +++ b/Batteries/Data/Nat/Lemmas.lean @@ -177,10 +177,6 @@ protected alias le_of_le_of_sub_le_sub_left := Nat.le_of_sub_le_sub_left /-! ### sum -/ -@[simp] theorem sum_nil : Nat.sum [] = 0 := rfl - -@[simp] theorem sum_cons : Nat.sum (a :: l) = a + Nat.sum l := rfl - @[simp] theorem sum_append : Nat.sum (l₁ ++ l₂) = Nat.sum l₁ + Nat.sum l₂ := by induction l₁ <;> simp [*, Nat.add_assoc] From 94027ef349e1033b4957727b36f65031c1772600 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sat, 27 Jul 2024 09:04:50 +0000 Subject: [PATCH 146/208] chore: bump to nightly-2024-07-27 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index b34774d04a..5ee201a0cd 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-26 +leanprover/lean4:nightly-2024-07-27 From a2be1d95e23ded945cd7172723d60ea2f20fffb0 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 29 Jul 2024 21:17:43 +1000 Subject: [PATCH 147/208] bump toolchain --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 5ee201a0cd..4cf36d3e5d 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-27 +leanprover/lean4:nightly-2024-07-29 From 56bf1ca13e72d10f69fd0e62f04033123b871932 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 29 Jul 2024 21:25:19 +1000 Subject: [PATCH 148/208] remove upstreamed material --- Batteries/Data/List/Basic.lean | 78 ------- Batteries/Data/List/Count.lean | 211 +----------------- Batteries/Data/List/Lemmas.lean | 349 ------------------------------ Batteries/Data/List/Pairwise.lean | 158 -------------- Batteries/Data/String/Lemmas.lean | 9 +- 5 files changed, 6 insertions(+), 799 deletions(-) diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index fba6f08f39..43915cd733 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -27,15 +27,6 @@ protected def diff {α} [BEq α] : List α → List α → List α open Option Nat -/-- Get the tail of a nonempty list, or return `[]` for `[]`. -/ -def tail : List α → List α - | [] => [] - | _::as => as - --- FIXME: `@[simp]` on the definition simplifies even `tail l` -@[simp] theorem tail_nil : @tail α [] = [] := rfl -@[simp] theorem tail_cons : @tail α (a::as) = as := rfl - /-- Get the head and tail of a list, if it is nonempty. -/ @[inline] def next? : List α → Option (α × List α) | [] => none @@ -73,16 +64,6 @@ drop_while (· != 1) [0, 1, 2, 3] = [1, 2, 3] | [] => [] | x :: xs => bif p x then xs else after p xs -/-- Returns the index of the first element satisfying `p`, or the length of the list otherwise. -/ -@[inline] def findIdx (p : α → Bool) (l : List α) : Nat := go l 0 where - /-- Auxiliary for `findIdx`: `findIdx.go p l n = findIdx p l + n` -/ - @[specialize] go : List α → Nat → Nat - | [], n => n - | a :: l, n => bif p a then n else go l (n + 1) - -/-- Returns the index of the first element equal to `a`, or the length of the list otherwise. -/ -def indexOf [BEq α] (a : α) : List α → Nat := findIdx (· == a) - @[deprecated (since := "2024-05-06")] alias removeNth := eraseIdx @[deprecated (since := "2024-05-06")] alias removeNthTR := eraseIdxTR @[deprecated (since := "2024-05-06")] alias removeNth_eq_removeNthTR := eraseIdx_eq_eraseIdxTR @@ -302,19 +283,6 @@ theorem takeDTR_go_eq : ∀ n l, takeDTR.go dflt n l acc = acc.data ++ takeD n l @[csimp] theorem takeD_eq_takeDTR : @takeD = @takeDTR := by funext α f n l; simp [takeDTR, takeDTR_go_eq] -/-- -Pads `l : List α` with repeated occurrences of `a : α` until it is of length `n`. -If `l` is initially larger than `n`, just return `l`. --/ -def leftpad (n : Nat) (a : α) (l : List α) : List α := replicate (n - length l) a ++ l - -/-- Optimized version of `leftpad`. -/ -@[inline] def leftpadTR (n : Nat) (a : α) (l : List α) : List α := - replicateTR.loop a (n - length l) l - -@[csimp] theorem leftpad_eq_leftpadTR : @leftpad = @leftpadTR := by - funext α n a l; simp [leftpad, leftpadTR, replicateTR_loop_eq] - /-- Fold a function `f` over the list from the left, returning the list of partial results. ``` @@ -386,14 +354,6 @@ indexesOf a [a, b, a, a] = [0, 2, 3] -/ @[inline] def indexesOf [BEq α] (a : α) : List α → List Nat := findIdxs (· == a) -/-- Return the index of the first occurrence of an element satisfying `p`. -/ -def findIdx? (p : α → Bool) : List α → (start : Nat := 0) → Option Nat -| [], _ => none -| a :: l, i => if p a then some i else findIdx? p l (i + 1) - -/-- Return the index of the first occurrence of `a` in the list. -/ -@[inline] def indexOf? [BEq α] (a : α) : List α → Option Nat := findIdx? (· == a) - /-- `lookmap` is a combination of `lookup` and `filterMap`. `lookmap f l` will apply `f : α → Option α` to each element of the list, @@ -407,16 +367,6 @@ replacing `a → b` at the first value `a` in the list such that `f a = some b`. | some b => acc.toListAppend (b :: l) | none => go l (acc.push a) -/-- `countP p l` is the number of elements of `l` that satisfy `p`. -/ -@[inline] def countP (p : α → Bool) (l : List α) : Nat := go l 0 where - /-- Auxiliary for `countP`: `countP.go p l acc = countP p l + acc`. -/ - @[specialize] go : List α → Nat → Nat - | [], acc => acc - | x :: xs, acc => bif p x then go xs (acc + 1) else go xs acc - -/-- `count a l` is the number of occurrences of `a` in `l`. -/ -@[inline] def count [BEq α] (a : α) : List α → Nat := countP (· == a) - /-- `inits l` is the list of initial segments of `l`. ``` @@ -770,34 +720,6 @@ Defined as `pwFilter (≠)`. eraseDup [1, 0, 2, 2, 1] = [0, 2, 1] -/ @[inline] def eraseDup [BEq α] : List α → List α := pwFilter (· != ·) -/-- `range' start len step` is the list of numbers `[start, start+step, ..., start+(len-1)*step]`. - It is intended mainly for proving properties of `range` and `iota`. -/ -def range' : (start len : Nat) → (step : Nat := 1) → List Nat - | _, 0, _ => [] - | s, n+1, step => s :: range' (s+step) n step - -/-- Optimized version of `range'`. -/ -@[inline] def range'TR (s n : Nat) (step : Nat := 1) : List Nat := go n (s + step * n) [] where - /-- Auxiliary for `range'TR`: `range'TR.go n e = [e-n, ..., e-1] ++ acc`. -/ - go : Nat → Nat → List Nat → List Nat - | 0, _, acc => acc - | n+1, e, acc => go n (e-step) ((e-step) :: acc) - -@[csimp] theorem range'_eq_range'TR : @range' = @range'TR := by - funext s n step - let rec go (s) : ∀ n m, - range'TR.go step n (s + step * n) (range' (s + step * n) m step) = range' s (n + m) step - | 0, m => by simp [range'TR.go] - | n+1, m => by - simp [range'TR.go] - rw [Nat.mul_succ, ← Nat.add_assoc, Nat.add_sub_cancel, Nat.add_right_comm n] - exact go s n (m + 1) - exact (go s n 0).symm - -/-- Drop `none`s from a list, and replace each remaining `some a` with `a`. -/ -@[inline] def reduceOption {α} : List (Option α) → List α := - List.filterMap id - /-- `ilast' x xs` returns the last element of `xs` if `xs` is non-empty; it returns `x` otherwise. Use `List.getLastD` instead. diff --git a/Batteries/Data/List/Count.lean b/Batteries/Data/List/Count.lean index 3aece22185..036a76b4b8 100644 --- a/Batteries/Data/List/Count.lean +++ b/Batteries/Data/List/Count.lean @@ -19,111 +19,6 @@ open Nat namespace List -section countP - -variable (p q : α → Bool) - -@[simp] theorem countP_nil : countP p [] = 0 := rfl - -protected theorem countP_go_eq_add (l) : countP.go p l n = n + countP.go p l 0 := by - induction l generalizing n with - | nil => rfl - | cons head tail ih => - unfold countP.go - rw [ih (n := n + 1), ih (n := n), ih (n := 1)] - if h : p head then simp [h, Nat.add_assoc] else simp [h] - -@[simp] theorem countP_cons_of_pos (l) (pa : p a) : countP p (a :: l) = countP p l + 1 := by - have : countP.go p (a :: l) 0 = countP.go p l 1 := show cond .. = _ by rw [pa]; rfl - unfold countP - rw [this, Nat.add_comm, List.countP_go_eq_add] - -@[simp] theorem countP_cons_of_neg (l) (pa : ¬p a) : countP p (a :: l) = countP p l := by - simp [countP, countP.go, pa] - -theorem countP_cons (a : α) (l) : countP p (a :: l) = countP p l + if p a then 1 else 0 := by - by_cases h : p a <;> simp [h] - -theorem length_eq_countP_add_countP (l) : length l = countP p l + countP (fun a => ¬p a) l := by - induction l with - | nil => rfl - | cons x h ih => - if h : p x then - rw [countP_cons_of_pos _ _ h, countP_cons_of_neg _ _ _, length, ih] - · rw [Nat.add_assoc, Nat.add_comm _ 1, Nat.add_assoc] - · simp only [h, not_true_eq_false, decide_False, not_false_eq_true] - else - rw [countP_cons_of_pos (fun a => ¬p a) _ _, countP_cons_of_neg _ _ h, length, ih] - · rfl - · simp only [h, not_false_eq_true, decide_True] - -theorem countP_eq_length_filter (l) : countP p l = length (filter p l) := by - induction l with - | nil => rfl - | cons x l ih => - if h : p x - then rw [countP_cons_of_pos p l h, ih, filter_cons_of_pos h, length] - else rw [countP_cons_of_neg p l h, ih, filter_cons_of_neg h] - -theorem countP_le_length : countP p l ≤ l.length := by - simp only [countP_eq_length_filter] - apply length_filter_le - -@[simp] theorem countP_append (l₁ l₂) : countP p (l₁ ++ l₂) = countP p l₁ + countP p l₂ := by - simp only [countP_eq_length_filter, filter_append, length_append] - -theorem countP_pos : 0 < countP p l ↔ ∃ a ∈ l, p a := by - simp only [countP_eq_length_filter, length_pos_iff_exists_mem, mem_filter, exists_prop] - -theorem countP_eq_zero : countP p l = 0 ↔ ∀ a ∈ l, ¬p a := by - simp only [countP_eq_length_filter, length_eq_zero, filter_eq_nil] - -theorem countP_eq_length : countP p l = l.length ↔ ∀ a ∈ l, p a := by - rw [countP_eq_length_filter, filter_length_eq_length] - -theorem Sublist.countP_le (s : l₁ <+ l₂) : countP p l₁ ≤ countP p l₂ := by - simp only [countP_eq_length_filter] - apply s.filter _ |>.length_le - -theorem countP_filter (l : List α) : - countP p (filter q l) = countP (fun a => p a ∧ q a) l := by - simp only [countP_eq_length_filter, filter_filter] - -@[simp] theorem countP_true {l : List α} : (l.countP fun _ => true) = l.length := by - rw [countP_eq_length] - simp - -@[simp] theorem countP_false {l : List α} : (l.countP fun _ => false) = 0 := by - rw [countP_eq_zero] - simp - -@[simp] theorem countP_map (p : β → Bool) (f : α → β) : - ∀ l, countP p (map f l) = countP (p ∘ f) l - | [] => rfl - | a :: l => by rw [map_cons, countP_cons, countP_cons, countP_map p f l]; rfl - -variable {p q} - -theorem countP_mono_left (h : ∀ x ∈ l, p x → q x) : countP p l ≤ countP q l := by - induction l with - | nil => apply Nat.le_refl - | cons a l ihl => - rw [forall_mem_cons] at h - have ⟨ha, hl⟩ := h - simp [countP_cons] - cases h : p a - . simp - apply Nat.le_trans ?_ (Nat.le_add_right _ _) - apply ihl hl - . simp [ha h] - apply ihl hl - -theorem countP_congr (h : ∀ x ∈ l, p x ↔ q x) : countP p l = countP q l := - Nat.le_antisymm - (countP_mono_left fun x hx => (h x hx).1) - (countP_mono_left fun x hx => (h x hx).2) - -end countP /-! ### count -/ @@ -131,71 +26,10 @@ section count variable [DecidableEq α] -@[simp] theorem count_nil (a : α) : count a [] = 0 := rfl - -theorem count_cons (a b : α) (l : List α) : - count a (b :: l) = count a l + if a = b then 1 else 0 := by - simp [count, countP_cons, eq_comm (a := a)] - -@[simp] theorem count_cons_self (a : α) (l : List α) : count a (a :: l) = count a l + 1 := by - simp [count_cons] - -@[simp] theorem count_cons_of_ne (h : a ≠ b) (l : List α) : count a (b :: l) = count a l := by - simp [count_cons, h] - -theorem count_tail : ∀ (l : List α) (a : α) (h : l ≠ []), - l.tail.count a = l.count a - if a = l.head h then 1 else 0 - | head :: tail, a, h => by simp [count_cons] - -theorem count_le_length (a : α) (l : List α) : count a l ≤ l.length := countP_le_length _ - -theorem Sublist.count_le (h : l₁ <+ l₂) (a : α) : count a l₁ ≤ count a l₂ := h.countP_le _ - -theorem count_le_count_cons (a b : α) (l : List α) : count a l ≤ count a (b :: l) := - (sublist_cons_self _ _).count_le _ - -theorem count_singleton (a : α) : count a [a] = 1 := by simp - -theorem count_singleton' (a b : α) : count a [b] = if a = b then 1 else 0 := by simp [count_cons] - -@[simp] theorem count_append (a : α) : ∀ l₁ l₂, count a (l₁ ++ l₂) = count a l₁ + count a l₂ := - countP_append _ +theorem count_singleton' (a b : α) : count a [b] = if b = a then 1 else 0 := by simp [count_cons] theorem count_concat (a : α) (l : List α) : count a (concat l a) = succ (count a l) := by simp -@[simp] -theorem count_pos_iff_mem {a : α} {l : List α} : 0 < count a l ↔ a ∈ l := by - simp only [count, countP_pos, beq_iff_eq, exists_eq_right] - -@[simp 900] theorem count_eq_zero_of_not_mem {a : α} {l : List α} (h : a ∉ l) : count a l = 0 := - Decidable.byContradiction fun h' => h <| count_pos_iff_mem.1 (Nat.pos_of_ne_zero h') - -theorem not_mem_of_count_eq_zero {a : α} {l : List α} (h : count a l = 0) : a ∉ l := - fun h' => Nat.ne_of_lt (count_pos_iff_mem.2 h') h.symm - -theorem count_eq_zero {l : List α} : count a l = 0 ↔ a ∉ l := - ⟨not_mem_of_count_eq_zero, count_eq_zero_of_not_mem⟩ - -theorem count_eq_length {l : List α} : count a l = l.length ↔ ∀ b ∈ l, a = b := by - rw [count, countP_eq_length] - refine ⟨fun h b hb => Eq.symm ?_, fun h b hb => ?_⟩ - · simpa using h b hb - · rw [h b hb, beq_self_eq_true] - -@[simp] theorem count_replicate_self (a : α) (n : Nat) : count a (replicate n a) = n := - (count_eq_length.2 <| fun _ h => (eq_of_mem_replicate h).symm).trans (length_replicate ..) - -theorem count_replicate (a b : α) (n : Nat) : count a (replicate n b) = if a = b then n else 0 := by - split - exacts [‹a = b› ▸ count_replicate_self .., count_eq_zero.2 <| mt eq_of_mem_replicate ‹a ≠ b›] - -theorem filter_beq (l : List α) (a : α) : l.filter (· == a) = replicate (count a l) a := by - simp only [count, countP_eq_length_filter, eq_replicate, mem_filter, beq_iff_eq] - exact ⟨trivial, fun _ h => h.2⟩ - -theorem filter_eq (l : List α) (a : α) : l.filter (· = a) = replicate (count a l) a := - filter_beq l a - @[deprecated filter_eq (since := "2023-12-14")] theorem filter_eq' (l : List α) (a : α) : l.filter (a = ·) = replicate (count a l) a := by simpa only [eq_comm] using filter_eq l a @@ -203,46 +37,3 @@ theorem filter_eq' (l : List α) (a : α) : l.filter (a = ·) = replicate (count @[deprecated filter_beq (since := "2023-12-14")] theorem filter_beq' (l : List α) (a : α) : l.filter (a == ·) = replicate (count a l) a := by simpa only [eq_comm (b := a)] using filter_eq l a - -theorem le_count_iff_replicate_sublist {l : List α} : n ≤ count a l ↔ replicate n a <+ l := by - refine ⟨fun h => ?_, fun h => ?_⟩ - · exact ((replicate_sublist_replicate a).2 h).trans <| filter_eq l a ▸ filter_sublist _ - · simpa only [count_replicate_self] using h.count_le a - -theorem replicate_count_eq_of_count_eq_length {l : List α} (h : count a l = length l) : - replicate (count a l) a = l := - (le_count_iff_replicate_sublist.mp (Nat.le_refl _)).eq_of_length <| - (length_replicate (count a l) a).trans h - -@[simp] theorem count_filter {l : List α} (h : p a) : count a (filter p l) = count a l := by - rw [count, countP_filter]; congr; funext b - rw [(by rfl : (b == a) = decide (b = a)), decide_eq_decide] - simp; rintro rfl; exact h - -theorem count_le_count_map [DecidableEq β] (l : List α) (f : α → β) (x : α) : - count x l ≤ count (f x) (map f l) := by - rw [count, count, countP_map] - apply countP_mono_left; simp (config := { contextual := true }) - -theorem count_erase (a b : α) : - ∀ l : List α, count a (l.erase b) = count a l - if a = b then 1 else 0 - | [] => by simp - | c :: l => by - rw [erase_cons] - if hc : c = b then - have hc_beq := (beq_iff_eq _ _).mpr hc - rw [if_pos hc_beq, hc, count_cons, Nat.add_sub_cancel] - else - have hc_beq := beq_false_of_ne hc - simp only [hc_beq, if_false, count_cons, count_cons, count_erase a b l] - if ha : a = b then - rw [← ha, eq_comm] at hc - rw [if_pos ha, if_neg hc, Nat.add_zero, Nat.add_zero] - else - rw [if_neg ha, Nat.sub_zero, Nat.sub_zero] - -@[simp] theorem count_erase_self (a : α) (l : List α) : - count a (List.erase l a) = count a l - 1 := by rw [count_erase, if_pos rfl] - -@[simp] theorem count_erase_of_ne (ab : a ≠ b) (l : List α) : count a (l.erase b) = count a l := by - rw [count_erase, if_neg ab, Nat.sub_zero] diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 724b67a56a..add78e3096 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -17,23 +17,6 @@ open Nat @[simp] theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l := by simp [Array.mem_def] -/-! ### drop -/ - -@[simp] -theorem drop_one : ∀ l : List α, drop 1 l = tail l - | [] | _ :: _ => rfl - -/-! ### zipWith -/ - -theorem zipWith_distrib_tail : (zipWith f l l').tail = zipWith f l.tail l'.tail := by - rw [← drop_one]; simp [drop_zipWith] - -/-! ### tail -/ - -theorem tail_eq_tailD (l) : @tail α l = tailD l [] := by cases l <;> rfl - -theorem tail_eq_tail? (l) : @tail α l = (tail? l).getD [] := by simp [tail_eq_tailD] - /-! ### next? -/ @[simp] theorem next?_nil : @next? α [] = none := rfl @@ -41,10 +24,6 @@ theorem tail_eq_tail? (l) : @tail α l = (tail? l).getD [] := by simp [tail_eq_t /-! ### get? -/ -theorem getElem_eq_iff {l : List α} {n : Nat} {h : n < l.length} : l[n] = x ↔ l[n]? = some x := by - simp only [get_eq_getElem, get?_eq_getElem?, getElem?_eq_some] - exact ⟨fun w => ⟨h, w⟩, fun h => h.2⟩ - @[deprecated getElem_eq_iff (since := "2024-06-12")] theorem get_eq_iff : List.get l n = x ↔ l.get? n.1 = some x := by simp @@ -55,16 +34,6 @@ theorem get?_inj apply getElem?_inj h₀ h₁ simp_all -/-! ### drop -/ - -theorem tail_drop (l : List α) (n : Nat) : (l.drop n).tail = l.drop (n + 1) := by - induction l generalizing n with - | nil => simp - | cons hd tl hl => - cases n - · simp - · simp [hl] - /-! ### modifyNth -/ @[simp] theorem modifyNth_nil (f : α → α) (n) : [].modifyNth f n = [] := by cases n <;> rfl @@ -189,10 +158,6 @@ theorem exists_of_set' {l : List α} (h : n < l.length) : ∃ l₁ a l₂, l = l₁ ++ a :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := by rw [set_eq_modifyNth]; exact exists_of_modifyNth _ h -@[simp] -theorem getElem?_set_eq' (a : α) (n) (l : List α) : (set l n a)[n]? = (fun _ => a) <$> l[n]? := by - simp only [set_eq_modifyNth, getElem?_modifyNth_eq] - @[deprecated getElem?_set_eq' (since := "2024-06-12")] theorem get?_set_eq (a : α) (n) (l : List α) : (set l n a).get? n = (fun _ => a) <$> l.get? n := by simp @@ -209,10 +174,6 @@ theorem get?_set_eq_of_lt (a : α) {n} {l : List α} (h : n < length l) : theorem get?_set_ne (a : α) {m n} (l : List α) (h : m ≠ n) : (set l m a).get? n = l.get? n := by simp [h] -theorem getElem?_set' (a : α) {m n} (l : List α) : - (set l m a)[n]? = if m = n then (fun _ => a) <$> l[n]? else l[n]? := by - by_cases m = n <;> simp [*] - @[deprecated getElem?_set (since := "2024-06-12")] 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 @@ -226,30 +187,8 @@ 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 [getElem?_set]; split <;> subst_vars <;> simp [*, getElem?_eq_getElem h] -theorem take_set_of_lt (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_eq_if, getElem?_take_eq_if] - split - · next h' => rw [getElem?_set_ne (by omega)] - · rfl - -/-! ### removeNth -/ - -theorem length_eraseIdx : ∀ {l i}, i < length l → length (@eraseIdx α l i) = length l - 1 - | [], _, _ => rfl - | _::_, 0, _ => by simp [eraseIdx] - | x::xs, i+1, h => by - have : i < length xs := Nat.lt_of_succ_lt_succ h - simp [eraseIdx, ← Nat.add_one] - rw [length_eraseIdx this, Nat.sub_add_cancel (Nat.lt_of_le_of_lt (Nat.zero_le _) this)] - @[deprecated (since := "2024-05-06")] alias length_removeNth := length_eraseIdx -/-! ### tail -/ - -@[simp] theorem length_tail (l : List α) : length (tail l) = length l - 1 := by cases l <;> rfl - /-! ### eraseP -/ @[simp] theorem extractP_eq_find?_eraseP @@ -266,109 +205,6 @@ theorem length_eraseIdx : ∀ {l i}, i < length l → length (@eraseIdx α l i) @[deprecated (since := "2024-04-22")] alias sublist.erase := Sublist.erase -/-! ### findIdx -/ - -@[simp] theorem findIdx_nil {α : Type _} (p : α → Bool) : [].findIdx p = 0 := rfl - -theorem findIdx_cons (p : α → Bool) (b : α) (l : List α) : - (b :: l).findIdx p = bif p b then 0 else (l.findIdx p) + 1 := by - cases H : p b with - | true => simp [H, findIdx, findIdx.go] - | false => simp [H, findIdx, findIdx.go, findIdx_go_succ] -where - findIdx_go_succ (p : α → Bool) (l : List α) (n : Nat) : - List.findIdx.go p l (n + 1) = (findIdx.go p l n) + 1 := by - cases l with - | nil => unfold findIdx.go; exact Nat.succ_eq_add_one n - | cons head tail => - unfold findIdx.go - cases p head <;> simp only [cond_false, cond_true] - exact findIdx_go_succ p tail (n + 1) - -theorem findIdx_of_get?_eq_some {xs : List α} (w : xs.get? (xs.findIdx p) = some y) : p y := by - induction xs with - | nil => simp_all - | cons x xs ih => by_cases h : p x <;> simp_all [findIdx_cons] - -theorem findIdx_get {xs : List α} {w : xs.findIdx p < xs.length} : - p (xs.get ⟨xs.findIdx p, w⟩) := - xs.findIdx_of_get?_eq_some (get?_eq_get w) - -theorem findIdx_lt_length_of_exists {xs : List α} (h : ∃ x ∈ xs, p x) : - xs.findIdx p < xs.length := by - induction xs with - | nil => simp_all - | cons x xs ih => - by_cases p x - · simp_all only [forall_exists_index, and_imp, mem_cons, exists_eq_or_imp, true_or, - findIdx_cons, cond_true, length_cons] - apply Nat.succ_pos - · simp_all [findIdx_cons] - refine Nat.succ_lt_succ ?_ - obtain ⟨x', m', h'⟩ := h - exact ih x' m' h' - -theorem findIdx_get?_eq_get_of_exists {xs : List α} (h : ∃ x ∈ xs, p x) : - xs.get? (xs.findIdx p) = some (xs.get ⟨xs.findIdx p, xs.findIdx_lt_length_of_exists h⟩) := - get?_eq_get (findIdx_lt_length_of_exists h) - - /-! ### findIdx? -/ - -@[simp] theorem findIdx?_nil : ([] : List α).findIdx? p i = none := rfl - -@[simp] theorem findIdx?_cons : - (x :: xs).findIdx? p i = if p x then some i else findIdx? p xs (i + 1) := rfl - -@[simp] theorem findIdx?_succ : - (xs : List α).findIdx? p (i+1) = (xs.findIdx? p i).map fun i => i + 1 := by - induction xs generalizing i with simp - | cons _ _ _ => split <;> simp_all - -theorem findIdx?_eq_some_iff (xs : List α) (p : α → Bool) : - xs.findIdx? p = some i ↔ (xs.take (i + 1)).map p = replicate i false ++ [true] := by - induction xs generalizing i with - | nil => simp - | cons x xs ih => - simp only [findIdx?_cons, Nat.zero_add, findIdx?_succ, take_succ_cons, map_cons] - split <;> cases i <;> simp_all [replicate_succ] - -theorem findIdx?_of_eq_some {xs : List α} {p : α → Bool} (w : xs.findIdx? p = some i) : - match xs.get? i with | some a => p a | none => false := by - induction xs generalizing i with - | nil => simp_all - | cons x xs ih => - simp_all only [findIdx?_cons, Nat.zero_add, findIdx?_succ] - split at w <;> cases i <;> simp_all - -theorem findIdx?_of_eq_none {xs : List α} {p : α → Bool} (w : xs.findIdx? p = none) : - ∀ i, match xs.get? i with | some a => ¬ p a | none => true := by - intro i - induction xs generalizing i with - | nil => simp_all - | cons x xs ih => - simp_all only [Bool.not_eq_true, findIdx?_cons, Nat.zero_add, findIdx?_succ] - cases i with - | zero => - split at w <;> simp_all - | succ i => - simp only [get?_cons_succ] - apply ih - split at w <;> simp_all - -@[simp] theorem findIdx?_append : - (xs ++ ys : List α).findIdx? p = - (xs.findIdx? p <|> (ys.findIdx? p).map fun i => i + xs.length) := by - induction xs with simp - | cons _ _ _ => split <;> simp_all [Option.map_orElse, Option.map_map]; rfl - -@[simp] theorem findIdx?_replicate : - (replicate n a).findIdx? p = if 0 < n ∧ p a then some 0 else none := by - induction n with - | zero => simp - | succ n ih => - simp only [replicate, findIdx?_cons, Nat.zero_add, findIdx?_succ, Nat.zero_lt_succ, true_and] - split <;> simp_all - /-! ### replaceF -/ theorem replaceF_nil : [].replaceF p = [] := rfl @@ -476,16 +312,6 @@ theorem disjoint_of_disjoint_append_right_left (d : Disjoint l (l₁ ++ l₂)) : theorem disjoint_of_disjoint_append_right_right (d : Disjoint l (l₁ ++ l₂)) : Disjoint l l₂ := (disjoint_append_right.1 d).2 -/-! ### foldl / foldr -/ - -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 - induction l generalizing init <;> simp [*, H] - -theorem foldr_hom (f : β₁ → β₂) (g₁ : α → β₁ → β₁) (g₂ : α → β₂ → β₂) (l : List α) (init : β₁) - (H : ∀ x y, g₂ x (f y) = f (g₁ x y)) : l.foldr g₂ (f init) = f (l.foldr g₁ init) := by - induction l <;> simp [*, H] - /-! ### union -/ section union @@ -530,29 +356,14 @@ theorem leftpad_length (n : Nat) (a : α) (l : List α) : (leftpad n a l).length = max n l.length := by simp only [leftpad, length_append, length_replicate, Nat.sub_add_eq_max] -theorem leftpad_prefix (n : Nat) (a : α) (l : List α) : - replicate (n - length l) a <+: leftpad n a l := by - simp only [IsPrefix, leftpad] - exact Exists.intro l rfl - -theorem leftpad_suffix (n : Nat) (a : α) (l : List α) : l <:+ (leftpad n a l) := by - simp only [IsSuffix, leftpad] - exact Exists.intro (replicate (n - length l) a) rfl - /-! ### monadic operations -/ --- we use ForIn.forIn as the simp normal form -@[simp] theorem forIn_eq_forIn [Monad m] : @List.forIn α β m _ = forIn := rfl - theorem forIn_eq_bindList [Monad m] [LawfulMonad m] (f : α → β → m (ForInStep β)) (l : List α) (init : β) : forIn l init f = ForInStep.run <$> (ForInStep.yield init).bindList f l := by induction l generalizing init <;> simp [*, map_eq_pure_bind] congr; ext (b | b) <;> simp -@[simp] theorem forM_append [Monad m] [LawfulMonad m] (l₁ l₂ : List α) (f : α → m PUnit) : - (l₁ ++ l₂).forM f = (do l₁.forM f; l₂.forM f) := by induction l₁ <;> simp [*] - /-! ### diff -/ section Diff @@ -631,8 +442,6 @@ end Diff /-! ### drop -/ -theorem mem_of_mem_drop {n} {l : List α} (h : a ∈ l.drop n) : a ∈ l := drop_subset _ _ h - theorem disjoint_take_drop : ∀ {l : List α}, l.Nodup → m ≤ n → Disjoint (l.take m) (l.drop n) | [], _, _ => by simp | x :: xs, hl, h => by @@ -681,39 +490,6 @@ protected theorem Pairwise.chain (p : Pairwise R (a :: l)) : Chain R a l := by /-! ### range', range -/ -theorem range'_succ (s n step) : range' s (n + 1) step = s :: range' (s + step) n step := by - simp [range', Nat.add_succ, Nat.mul_succ] - -@[simp] theorem length_range' (s step) : ∀ n : Nat, length (range' s n step) = n - | 0 => rfl - | _ + 1 => congrArg succ (length_range' _ _ _) - -@[simp] theorem range'_eq_nil : range' s n step = [] ↔ n = 0 := by - rw [← length_eq_zero, length_range'] - -theorem mem_range' : ∀{n}, m ∈ range' s n step ↔ ∃ i < n, m = s + step * i - | 0 => by simp [range', Nat.not_lt_zero] - | n + 1 => by - have h (i) : i ≤ n ↔ i = 0 ∨ ∃ j, i = succ j ∧ j < n := by cases i <;> simp [Nat.succ_le] - simp [range', mem_range', Nat.lt_succ, h]; simp only [← exists_and_right, and_assoc] - rw [exists_comm]; simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm] - -@[simp] theorem mem_range'_1 : m ∈ range' s n ↔ s ≤ m ∧ m < s + n := by - simp [mem_range']; exact ⟨ - fun ⟨i, h, e⟩ => e ▸ ⟨Nat.le_add_right .., Nat.add_lt_add_left h _⟩, - fun ⟨h₁, h₂⟩ => ⟨m - s, Nat.sub_lt_left_of_lt_add h₁ h₂, (Nat.add_sub_cancel' h₁).symm⟩⟩ - -@[simp] -theorem map_add_range' (a) : ∀ s n step, map (a + ·) (range' s n step) = range' (a + s) n step - | _, 0, _ => rfl - | s, n + 1, step => by simp [range', map_add_range' _ (s + step) n step, Nat.add_assoc] - -theorem map_sub_range' (a s n : Nat) (h : a ≤ s) : - map (· - a) (range' s n step) = range' (s - a) n step := by - conv => lhs; rw [← Nat.add_sub_cancel' h] - rw [← map_add_range', map_map, (?_ : _∘_ = _), map_id] - funext x; apply Nat.add_sub_cancel_left - theorem chain_succ_range' : ∀ s n step : Nat, Chain (fun a b => b = a + step) s (range' (s + step) n step) | _, 0, _ => Chain.nil @@ -723,41 +499,6 @@ theorem chain_lt_range' (s n : Nat) {step} (h : 0 < step) : Chain (· < ·) s (range' (s + step) n step) := (chain_succ_range' s n step).imp fun _ _ e => e.symm ▸ Nat.lt_add_of_pos_right h -theorem range'_append : ∀ s m n step : Nat, - range' s m step ++ range' (s + step * m) n step = range' s (n + m) step - | s, 0, n, step => rfl - | s, m + 1, n, step => by - simpa [range', Nat.mul_succ, Nat.add_assoc, Nat.add_comm] - using range'_append (s + step) m n step - -@[simp] theorem range'_append_1 (s m n : Nat) : - range' s m ++ range' (s + m) n = range' s (n + m) := by simpa using range'_append s m n 1 - -theorem range'_sublist_right {s m n : Nat} : range' s m step <+ range' s n step ↔ m ≤ n := - ⟨fun h => by simpa only [length_range'] using h.length_le, - fun h => by rw [← Nat.sub_add_cancel h, ← range'_append]; apply sublist_append_left⟩ - -theorem range'_subset_right {s m n : Nat} (step0 : 0 < step) : - range' s m step ⊆ range' s n step ↔ m ≤ n := by - refine ⟨fun h => Nat.le_of_not_lt fun hn => ?_, fun h => (range'_sublist_right.2 h).subset⟩ - have ⟨i, h', e⟩ := mem_range'.1 <| h <| mem_range'.2 ⟨_, hn, rfl⟩ - exact Nat.ne_of_gt h' (Nat.eq_of_mul_eq_mul_left step0 (Nat.add_left_cancel e)) - -theorem range'_subset_right_1 {s m n : Nat} : range' s m ⊆ range' s n ↔ m ≤ n := - range'_subset_right (by decide) - -theorem getElem?_range' (s step) : - ∀ {m n : Nat}, m < n → (range' s n step)[m]? = some (s + step * m) - | 0, n + 1, _ => by simp [range'_succ] - | m + 1, n + 1, h => by - simp only [range'_succ, getElem?_cons_succ] - exact (getElem?_range' (s + step) step (Nat.lt_of_add_lt_add_right h)).trans <| by - simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm] - -@[simp] theorem getElem_range' {n m step} (i) (H : i < (range' n m step).length) : - (range' n m step)[i] = n + step * i := - (getElem?_eq_some.1 <| getElem?_range' n step (by simpa using H)).2 - @[deprecated getElem?_range' (since := "2024-06-12")] theorem get?_range' (s step) {m n : Nat} (h : m < n) : get? (range' s n step) m = some (s + step * m) := by @@ -768,54 +509,6 @@ theorem get_range' {n m step} (i) (H : i < (range' n m step).length) : get (range' n m step) ⟨i, H⟩ = n + step * i := by simp -theorem range'_concat (s n : Nat) : range' s (n + 1) step = range' s n step ++ [s + step * n] := by - rw [Nat.add_comm n 1]; exact (range'_append s n 1 step).symm - -theorem range'_1_concat (s n : Nat) : range' s (n + 1) = range' s n ++ [s + n] := by - simp [range'_concat] - -theorem range_loop_range' : ∀ s n : Nat, range.loop s (range' s n) = range' 0 (n + s) - | 0, n => rfl - | s + 1, n => by rw [← Nat.add_assoc, Nat.add_right_comm n s 1]; exact range_loop_range' s (n + 1) - -theorem range_eq_range' (n : Nat) : range n = range' 0 n := - (range_loop_range' n 0).trans <| by rw [Nat.zero_add] - -theorem range_succ_eq_map (n : Nat) : range (n + 1) = 0 :: map succ (range n) := by - rw [range_eq_range', range_eq_range', range', Nat.add_comm, ← map_add_range'] - congr; exact funext one_add - -theorem range'_eq_map_range (s n : Nat) : range' s n = map (s + ·) (range n) := by - rw [range_eq_range', map_add_range']; rfl - -@[simp] theorem length_range (n : Nat) : length (range n) = n := by - simp only [range_eq_range', length_range'] - -@[simp] theorem range_eq_nil {n : Nat} : range n = [] ↔ n = 0 := by - rw [← length_eq_zero, length_range] - -@[simp] -theorem range_sublist {m n : Nat} : range m <+ range n ↔ m ≤ n := by - simp only [range_eq_range', range'_sublist_right] - -@[simp] -theorem range_subset {m n : Nat} : range m ⊆ range n ↔ m ≤ n := by - simp only [range_eq_range', range'_subset_right, lt_succ_self] - -@[simp] -theorem mem_range {m n : Nat} : m ∈ range n ↔ m < n := by - simp only [range_eq_range', mem_range'_1, Nat.zero_le, true_and, Nat.zero_add] - -theorem not_mem_range_self {n : Nat} : n ∉ range n := by simp - -theorem self_mem_range_succ (n : Nat) : n ∈ range (n + 1) := by simp - -theorem getElem?_range {m n : Nat} (h : m < n) : (range n)[m]? = some m := by - simp [range_eq_range', getElem?_range' _ _ h] - -@[simp] theorem getElem_range {n : Nat} (m) (h : m < (range n).length) : (range n)[m] = m := by - simp [range_eq_range'] - @[deprecated getElem?_range (since := "2024-06-12")] theorem get?_range {m n : Nat} (h : m < n) : get? (range n) m = some m := by simp [getElem?_range, h] @@ -824,41 +517,6 @@ theorem get?_range {m n : Nat} (h : m < n) : get? (range n) m = some m := by theorem get_range {n} (i) (H : i < (range n).length) : get (range n) ⟨i, H⟩ = i := by simp -theorem range_succ (n : Nat) : range (succ n) = range n ++ [n] := by - simp only [range_eq_range', range'_1_concat, Nat.zero_add] - -theorem range_add (a b : Nat) : range (a + b) = range a ++ (range b).map (a + ·) := by - rw [← range'_eq_map_range] - simpa [range_eq_range', Nat.add_comm] using (range'_append_1 0 a b).symm - -theorem iota_eq_reverse_range' : ∀ n : Nat, iota n = reverse (range' 1 n) - | 0 => rfl - | n + 1 => by simp [iota, range'_concat, iota_eq_reverse_range' n, reverse_append, Nat.add_comm] - -@[simp] theorem length_iota (n : Nat) : length (iota n) = n := by simp [iota_eq_reverse_range'] - -@[simp] -theorem mem_iota {m n : Nat} : m ∈ iota n ↔ 1 ≤ m ∧ m ≤ n := by - simp [iota_eq_reverse_range', Nat.add_comm, Nat.lt_succ] - -theorem reverse_range' : ∀ s n : Nat, reverse (range' s n) = map (s + n - 1 - ·) (range n) - | s, 0 => rfl - | s, n + 1 => by - rw [range'_1_concat, reverse_append, range_succ_eq_map, - show s + (n + 1) - 1 = s + n from rfl, map, map_map] - simp [reverse_range', Nat.sub_right_comm, Nat.sub_sub] - - -/-! ### enum, enumFrom -/ - -@[simp] theorem enumFrom_map_fst (n) : - ∀ (l : List α), map Prod.fst (enumFrom n l) = range' n l.length - | [] => rfl - | _ :: _ => congrArg (cons _) (enumFrom_map_fst _ _) - -@[simp] theorem enum_map_fst (l : List α) : map Prod.fst (enum l) = range l.length := by - simp only [enum, enumFrom_map_fst, range_eq_range'] - /-! ### indexOf and indexesOf -/ theorem foldrIdx_start : @@ -898,13 +556,6 @@ theorem indexesOf_cons [BEq α] : (x :: xs : List α).indexesOf y = bif x == y then 0 :: (xs.indexesOf y).map (· + 1) else (xs.indexesOf y).map (· + 1) := by simp [indexesOf, findIdxs_cons] -@[simp] theorem indexOf_nil [BEq α] : ([] : List α).indexOf x = 0 := rfl - -theorem indexOf_cons [BEq α] : - (x :: xs : List α).indexOf y = bif x == y then 0 else xs.indexOf y + 1 := by - dsimp [indexOf] - simp [findIdx_cons] - theorem indexOf_mem_indexesOf [BEq α] [LawfulBEq α] {xs : List α} (m : x ∈ xs) : xs.indexOf x ∈ xs.indexesOf x := by induction xs with diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index 9393d316b9..dbc2a48e0e 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -30,164 +30,6 @@ namespace List /-! ### Pairwise -/ -theorem rel_of_pairwise_cons (p : (a :: l).Pairwise R) : ∀ {a'}, a' ∈ l → R a a' := - (pairwise_cons.1 p).1 _ - -theorem Pairwise.of_cons (p : (a :: l).Pairwise R) : Pairwise R l := - (pairwise_cons.1 p).2 - -theorem Pairwise.tail : ∀ {l : List α} (_p : Pairwise R l), Pairwise R l.tail - | [], h => h - | _ :: _, h => h.of_cons - -theorem Pairwise.drop : ∀ {l : List α} {n : Nat}, List.Pairwise R l → List.Pairwise R (l.drop n) - | _, 0, h => h - | [], _ + 1, _ => List.Pairwise.nil - | _ :: _, n + 1, h => Pairwise.drop (n := n) (pairwise_cons.mp h).right - -theorem Pairwise.imp_of_mem {S : α → α → Prop} - (H : ∀ {a b}, a ∈ l → b ∈ l → R a b → S a b) (p : Pairwise R l) : Pairwise S l := by - induction p with - | nil => constructor - | @cons a l r _ ih => - constructor - · exact fun x h => H (mem_cons_self ..) (mem_cons_of_mem _ h) <| r x h - · exact ih fun m m' => H (mem_cons_of_mem _ m) (mem_cons_of_mem _ m') - -theorem Pairwise.and (hR : Pairwise R l) (hS : Pairwise S l) : - l.Pairwise fun a b => R a b ∧ S a b := by - induction hR with - | nil => simp only [Pairwise.nil] - | cons R1 _ IH => - simp only [Pairwise.nil, pairwise_cons] at hS ⊢ - exact ⟨fun b bl => ⟨R1 b bl, hS.1 b bl⟩, IH hS.2⟩ - -theorem pairwise_and_iff : l.Pairwise (fun a b => R a b ∧ S a b) ↔ Pairwise R l ∧ Pairwise S l := - ⟨fun h => ⟨h.imp fun h => h.1, h.imp fun h => h.2⟩, fun ⟨hR, hS⟩ => hR.and hS⟩ - -theorem Pairwise.imp₂ (H : ∀ a b, R a b → S a b → T a b) - (hR : Pairwise R l) (hS : l.Pairwise S) : l.Pairwise T := - (hR.and hS).imp fun ⟨h₁, h₂⟩ => H _ _ h₁ h₂ - -theorem Pairwise.iff_of_mem {S : α → α → Prop} {l : List α} - (H : ∀ {a b}, a ∈ l → b ∈ l → (R a b ↔ S a b)) : Pairwise R l ↔ Pairwise S l := - ⟨Pairwise.imp_of_mem fun m m' => (H m m').1, Pairwise.imp_of_mem fun m m' => (H m m').2⟩ - -theorem Pairwise.iff {S : α → α → Prop} (H : ∀ a b, R a b ↔ S a b) {l : List α} : - Pairwise R l ↔ Pairwise S l := - Pairwise.iff_of_mem fun _ _ => H .. - -theorem pairwise_of_forall {l : List α} (H : ∀ x y, R x y) : Pairwise R l := by - induction l <;> simp [*] - -theorem Pairwise.and_mem {l : List α} : - Pairwise R l ↔ Pairwise (fun x y => x ∈ l ∧ y ∈ l ∧ R x y) l := - Pairwise.iff_of_mem <| by simp (config := { contextual := true }) - -theorem Pairwise.imp_mem {l : List α} : - Pairwise R l ↔ Pairwise (fun x y => x ∈ l → y ∈ l → R x y) l := - Pairwise.iff_of_mem <| by simp (config := { contextual := true }) - -theorem Pairwise.forall_of_forall_of_flip (h₁ : ∀ x ∈ l, R x x) (h₂ : Pairwise R l) - (h₃ : l.Pairwise (flip R)) : ∀ ⦃x⦄, x ∈ l → ∀ ⦃y⦄, y ∈ l → R x y := by - induction l with - | nil => exact forall_mem_nil _ - | cons a l ih => - rw [pairwise_cons] at h₂ h₃ - simp only [mem_cons] - rintro x (rfl | hx) y (rfl | hy) - · exact h₁ _ (l.mem_cons_self _) - · exact h₂.1 _ hy - · exact h₃.1 _ hx - · exact ih (fun x hx => h₁ _ <| mem_cons_of_mem _ hx) h₂.2 h₃.2 hx hy - -theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp - -theorem pairwise_pair {a b : α} : Pairwise R [a, b] ↔ R a b := by simp - -theorem pairwise_append_comm {R : α → α → Prop} (s : ∀ {x y}, R x y → R y x) {l₁ l₂ : List α} : - Pairwise R (l₁ ++ l₂) ↔ Pairwise R (l₂ ++ l₁) := by - have (l₁ l₂ : List α) (H : ∀ x : α, x ∈ l₁ → ∀ y : α, y ∈ l₂ → R x y) - (x : α) (xm : x ∈ l₂) (y : α) (ym : y ∈ l₁) : R x y := s (H y ym x xm) - simp only [pairwise_append, and_left_comm]; rw [Iff.intro (this l₁ l₂) (this l₂ l₁)] - -theorem pairwise_middle {R : α → α → Prop} (s : ∀ {x y}, R x y → R y x) {a : α} {l₁ l₂ : List α} : - Pairwise R (l₁ ++ a :: l₂) ↔ Pairwise R (a :: (l₁ ++ l₂)) := by - show Pairwise R (l₁ ++ ([a] ++ l₂)) ↔ Pairwise R ([a] ++ l₁ ++ l₂) - rw [← append_assoc, pairwise_append, @pairwise_append _ _ ([a] ++ l₁), pairwise_append_comm s] - simp only [mem_append, or_comm] - -theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b : α, S (f a) (f b) → R a b) - (p : Pairwise S (map f l)) : Pairwise R l := - (pairwise_map.1 p).imp (H _ _) - -theorem Pairwise.map {S : β → β → Prop} (f : α → β) (H : ∀ a b : α, R a b → S (f a) (f b)) - (p : Pairwise R l) : Pairwise S (map f l) := - pairwise_map.2 <| p.imp (H _ _) - -theorem pairwise_filterMap (f : β → Option α) {l : List β} : - Pairwise R (filterMap f l) ↔ Pairwise (fun a a' : β => ∀ b ∈ f a, ∀ b' ∈ f a', R b b') l := by - let _S (a a' : β) := ∀ b ∈ f a, ∀ b' ∈ f a', R b b' - simp only [Option.mem_def] - induction l with - | nil => simp only [filterMap, Pairwise.nil] - | cons a l IH => ?_ - match e : f a with - | none => - rw [filterMap_cons_none e, pairwise_cons] - simp only [e, false_implies, implies_true, true_and, IH] - | some b => - rw [filterMap_cons_some e] - simpa [IH, e] using fun _ => - ⟨fun h a ha b hab => h _ _ ha hab, fun h a b ha hab => h _ ha _ hab⟩ - -theorem Pairwise.filter_map {S : β → β → Prop} (f : α → Option β) - (H : ∀ a a' : α, R a a' → ∀ b ∈ f a, ∀ b' ∈ f a', S b b') {l : List α} (p : Pairwise R l) : - Pairwise S (filterMap f l) := - (pairwise_filterMap _).2 <| p.imp (H _ _) - -theorem pairwise_filter (p : α → Prop) [DecidablePred p] {l : List α} : - Pairwise R (filter p l) ↔ Pairwise (fun x y => p x → p y → R x y) l := by - rw [← filterMap_eq_filter, pairwise_filterMap] - simp - -theorem Pairwise.filter (p : α → Bool) : Pairwise R l → Pairwise R (filter p l) := - Pairwise.sublist (filter_sublist _) - -theorem pairwise_join {L : List (List α)} : - Pairwise R (join L) ↔ - (∀ l ∈ L, Pairwise R l) ∧ Pairwise (fun l₁ l₂ => ∀ x ∈ l₁, ∀ y ∈ l₂, R x y) L := by - induction L with - | nil => simp - | cons l L IH => - simp only [join, pairwise_append, IH, mem_join, exists_imp, and_imp, forall_mem_cons, - pairwise_cons, and_assoc, and_congr_right_iff] - rw [and_comm, and_congr_left_iff] - intros; exact ⟨fun h a b c d e => h c d e a b, fun h c d e a b => h a b c d e⟩ - -theorem pairwise_bind {R : β → β → Prop} {l : List α} {f : α → List β} : - List.Pairwise R (l.bind f) ↔ - (∀ a ∈ l, Pairwise R (f a)) ∧ Pairwise (fun a₁ a₂ => ∀ x ∈ f a₁, ∀ y ∈ f a₂, R x y) l := by - simp [List.bind, pairwise_join, pairwise_map] - -theorem pairwise_iff_forall_sublist : l.Pairwise R ↔ (∀ {a b}, [a,b] <+ l → R a b) := by - induction l with - | nil => simp - | cons hd tl IH => - rw [List.pairwise_cons] - constructor <;> intro h - · intro - | a, b, .cons _ hab => exact IH.mp h.2 hab - | _, b, .cons₂ _ hab => refine h.1 _ (hab.subset ?_); simp - · constructor - · intro x hx - apply h - rw [List.cons_sublist_cons, List.singleton_sublist] - exact hx - · apply IH.mpr - intro a b hab - apply h; exact hab.cons _ - @[deprecated pairwise_iff_forall_sublist (since := "2023-09-18")] theorem pairwise_of_reflexive_on_dupl_of_forall_ne [DecidableEq α] {l : List α} {r : α → α → Prop} (hr : ∀ a, 1 < count a l → r a a) (h : ∀ a ∈ l, ∀ b ∈ l, a ≠ b → r a b) : l.Pairwise r := by diff --git a/Batteries/Data/String/Lemmas.lean b/Batteries/Data/String/Lemmas.lean index 5420651ba2..2edec48bde 100644 --- a/Batteries/Data/String/Lemmas.lean +++ b/Batteries/Data/String/Lemmas.lean @@ -337,7 +337,7 @@ theorem firstDiffPos_loop_eq (l₁ l₂ r₁ r₂ stop p) · next h => rw [dif_neg] <;> simp [hstop, ← hl₁, ← hl₂, -Nat.not_lt, Nat.lt_min] intro h₁ h₂ - have : ∀ {cs}, p < p + utf8Len cs → cs ≠ [] := by rintro _ h rfl; simp at h + have : ∀ {cs}, 0 < utf8Len cs → cs ≠ [] := by rintro _ h rfl; simp at h obtain ⟨a, as, e₁⟩ := List.exists_cons_of_ne_nil (this h₁) obtain ⟨b, bs, e₂⟩ := List.exists_cons_of_ne_nil (this h₂) exact h _ _ _ _ e₁ e₂ @@ -422,8 +422,9 @@ theorem splitAux_of_valid (p l m r acc) : splitAux ⟨l ++ m ++ r⟩ p ⟨utf8Len l⟩ ⟨utf8Len l + utf8Len m⟩ acc = acc.reverse ++ (List.splitOnP.go p r m.reverse).map mk := by unfold splitAux - simp only [List.append_assoc, atEnd_iff, endPos_eq, utf8Len_append, Pos.mk_le_mk, by - simpa using atEnd_of_valid (l ++ m) r, List.reverse_cons, dite_eq_ite] + simp only [List.append_assoc, atEnd_iff, endPos_eq, utf8Len_append, Pos.mk_le_mk, + Nat.add_le_add_iff_left, by simpa using atEnd_of_valid (l ++ m) r, List.reverse_cons, + dite_eq_ite] split · subst r; simpa [List.splitOnP.go] using extract_of_valid l m [] · obtain ⟨c, r, rfl⟩ := r.exists_cons_of_ne_nil ‹_› @@ -676,7 +677,7 @@ theorem foldrAux_of_valid (f : Char → α → α) (l m r a) : rw [← m.reverse_reverse] induction m.reverse generalizing r a with (unfold foldrAux; simp) | cons c m IH => - rw [if_pos (by exact Nat.lt_add_of_pos_right add_csize_pos)] + rw [if_pos add_csize_pos] simp only [← Nat.add_assoc, by simpa using prev_of_valid (l ++ m.reverse) c r] simp only [by simpa using get_of_valid (l ++ m.reverse) (c :: r)] simpa using IH (c::r) (f c a) From 3dfb59cffd1fdeaa41a92588c0d57e9a70cba8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20G=2E=20Dorais?= Date: Mon, 29 Jul 2024 20:15:16 -0400 Subject: [PATCH 149/208] feat: some array lemma aliases (#891) --- Batteries/Data/Array/Lemmas.lean | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Batteries/Data/Array/Lemmas.lean b/Batteries/Data/Array/Lemmas.lean index f59644a0fa..753cbb4955 100644 --- a/Batteries/Data/Array/Lemmas.lean +++ b/Batteries/Data/Array/Lemmas.lean @@ -133,3 +133,15 @@ theorem mapM_empty [Monad m] (f : α → m β) : mapM f #[] = pure #[] := by rw [mapM, mapM.map]; rfl @[simp] theorem map_empty (f : α → β) : map f #[] = #[] := mapM_empty .. + +/-! ### mem -/ + +alias not_mem_empty := not_mem_nil + +theorem mem_singleton : a ∈ #[b] ↔ a = b := by simp + +/-! ### append -/ + +alias append_empty := append_nil + +alias empty_append := nil_append From 9a80c8d999f6171a7213aeafe719b392f3e0e583 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 30 Jul 2024 18:53:38 +1000 Subject: [PATCH 150/208] bump toolchain --- Batteries/Data/List/Lemmas.lean | 9 --------- lean-toolchain | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index add78e3096..92f2ec2974 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -347,15 +347,6 @@ theorem pair_mem_product {xs : List α} {ys : List β} {x : α} {y : β} : simp only [product, and_imp, mem_map, Prod.mk.injEq, exists_eq_right_right, mem_bind, iff_self] -/-! ### leftpad -/ - -/-- The length of the List returned by `List.leftpad n a l` is equal - to the larger of `n` and `l.length` -/ -@[simp] -theorem leftpad_length (n : Nat) (a : α) (l : List α) : - (leftpad n a l).length = max n l.length := by - simp only [leftpad, length_append, length_replicate, Nat.sub_add_eq_max] - /-! ### monadic operations -/ theorem forIn_eq_bindList [Monad m] [LawfulMonad m] diff --git a/lean-toolchain b/lean-toolchain index 4cf36d3e5d..bab681a281 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-29 +leanprover/lean4:nightly-2024-07-30 From 7f3ebd5843f1699ff1f815c2c985ebcc6fe5249e Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 31 Jul 2024 12:45:41 +1000 Subject: [PATCH 151/208] chore: adaptations for nightly-2024-07-31 --- Batteries/Data/List/EraseIdx.lean | 70 +++---------------------------- Batteries/Data/List/Pairwise.lean | 47 --------------------- 2 files changed, 5 insertions(+), 112 deletions(-) diff --git a/Batteries/Data/List/EraseIdx.lean b/Batteries/Data/List/EraseIdx.lean index eb1648d630..42b4bfacd1 100644 --- a/Batteries/Data/List/EraseIdx.lean +++ b/Batteries/Data/List/EraseIdx.lean @@ -17,75 +17,15 @@ namespace List universe u v variable {α : Type u} {β : Type v} -@[simp] theorem eraseIdx_zero (l : List α) : eraseIdx l 0 = tail l := by cases l <;> rfl - -theorem eraseIdx_eq_take_drop_succ : - ∀ (l : List α) (i : Nat), l.eraseIdx i = l.take i ++ l.drop (i + 1) - | nil, _ => by simp - | a::l, 0 => by simp - | a::l, i + 1 => by simp [eraseIdx_eq_take_drop_succ l i] - -theorem eraseIdx_sublist : ∀ (l : List α) (k : Nat), eraseIdx l k <+ l - | [], _ => by simp - | a::l, 0 => by simp - | a::l, k + 1 => by simp [eraseIdx_sublist l k] - -theorem eraseIdx_subset (l : List α) (k : Nat) : eraseIdx l k ⊆ l := (eraseIdx_sublist l k).subset - -@[simp] -theorem eraseIdx_eq_self : ∀ {l : List α} {k : Nat}, eraseIdx l k = l ↔ length l ≤ k - | [], _ => by simp - | a::l, 0 => by simp [(cons_ne_self _ _).symm] - | a::l, k + 1 => by simp [eraseIdx_eq_self] - -alias ⟨_, eraseIdx_of_length_le⟩ := eraseIdx_eq_self - -theorem eraseIdx_append_of_lt_length {l : List α} {k : Nat} (hk : k < length l) (l' : List α) : - eraseIdx (l ++ l') k = eraseIdx l k ++ l' := by - rw [eraseIdx_eq_take_drop_succ, take_append_of_le_length, drop_append_of_le_length, - eraseIdx_eq_take_drop_succ, append_assoc] - all_goals omega - -theorem eraseIdx_append_of_length_le {l : List α} {k : Nat} (hk : length l ≤ k) (l' : List α) : - eraseIdx (l ++ l') k = l ++ eraseIdx l' (k - length l) := by - rw [eraseIdx_eq_take_drop_succ, eraseIdx_eq_take_drop_succ, - take_append_eq_append_take, drop_append_eq_append_drop, - take_of_length_le hk, drop_eq_nil_of_le (by omega), nil_append, append_assoc] - congr - omega - -protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) : - eraseIdx l k <+: eraseIdx l' k := by - rcases h with ⟨t, rfl⟩ - if hkl : k < length l then - simp [eraseIdx_append_of_lt_length hkl] - else - rw [Nat.not_lt] at hkl - simp [eraseIdx_append_of_length_le hkl, eraseIdx_of_length_le hkl] - -theorem mem_eraseIdx_iff_getElem {x : α} : - ∀ {l} {k}, x ∈ eraseIdx l k ↔ ∃ i : Fin l.length, ↑i ≠ k ∧ l[i.1] = x - | [], _ => by - simp only [eraseIdx, Fin.exists_iff, not_mem_nil, false_iff] - rintro ⟨i, h, -⟩ - exact Nat.not_lt_zero _ h - | a::l, 0 => by simp [Fin.exists_fin_succ, mem_iff_get] - | a::l, k+1 => by - simp [Fin.exists_fin_succ, mem_eraseIdx_iff_getElem, @eq_comm _ a, k.succ_ne_zero.symm] - @[deprecated mem_eraseIdx_iff_getElem (since := "2024-06-12")] theorem mem_eraseIdx_iff_get {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i : Fin l.length, ↑i ≠ k ∧ l.get i = x := by - simp [mem_eraseIdx_iff_getElem] - -theorem mem_eraseIdx_iff_getElem? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i ≠ k, l[i]? = some x := by - simp only [mem_eraseIdx_iff_getElem, getElem_eq_iff, Fin.exists_iff, exists_and_left] - refine exists_congr fun i => and_congr_right' ?_ + simp only [mem_eraseIdx_iff_getElem, ne_eq, exists_and_left, get_eq_getElem] constructor - · rintro ⟨_, h⟩; exact h - · rintro h; - obtain ⟨h', -⟩ := getElem?_eq_some.1 h - exact ⟨h', h⟩ + · rintro ⟨i, h, w, rfl⟩ + exact ⟨⟨i, w⟩, h, rfl⟩ + · rintro ⟨i, h, rfl⟩ + exact ⟨i.1, h, i.2, rfl⟩ @[deprecated mem_eraseIdx_iff_getElem? (since := "2024-06-12")] theorem mem_eraseIdx_iff_get? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i ≠ k, l.get? i = x := by diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index dbc2a48e0e..dd94875ca9 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -42,53 +42,6 @@ theorem pairwise_of_reflexive_on_dupl_of_forall_ne [DecidableEq α] {l : List α apply h <;> try (apply hab.subset; simp) exact heq -/-- given a list `is` of monotonically increasing indices into `l`, getting each index - produces a sublist of `l`. -/ -theorem map_get_sublist {l : List α} {is : List (Fin l.length)} (h : is.Pairwise (·.val < ·.val)) : - is.map (get l) <+ l := by - suffices ∀ n l', l' = l.drop n → (∀ i ∈ is, n ≤ i) → map (get l) is <+ l' - from this 0 l (by simp) (by simp) - intro n l' hl' his - induction is generalizing n l' with - | nil => simp - | cons hd tl IH => - simp; cases hl' - have := IH h.of_cons (hd+1) _ rfl (pairwise_cons.mp h).1 - specialize his hd (.head _) - have := (drop_eq_getElem_cons ..).symm ▸ this.cons₂ (get l hd) - have := Sublist.append (nil_sublist (take hd l |>.drop n)) this - rwa [nil_append, ← (drop_append_of_le_length ?_), take_append_drop] at this - simp [Nat.min_eq_left (Nat.le_of_lt hd.isLt), his] - -/-- given a sublist `l' <+ l`, there exists a list of indices `is` such that - `l' = map (get l) is`. -/ -theorem sublist_eq_map_get (h : l' <+ l) : ∃ is : List (Fin l.length), - l' = map (get l) is ∧ is.Pairwise (· < ·) := by - induction h with - | slnil => exact ⟨[], by simp⟩ - | cons _ _ IH => - let ⟨is, IH⟩ := IH - refine ⟨is.map (·.succ), ?_⟩ - simp [comp, pairwise_map] - exact IH - | cons₂ _ _ IH => - rcases IH with ⟨is,IH⟩ - refine ⟨⟨0, by simp [Nat.zero_lt_succ]⟩ :: is.map (·.succ), ?_⟩ - simp [comp_def, pairwise_map, IH, ← get_eq_getElem] - -theorem pairwise_iff_getElem : Pairwise R l ↔ - ∀ (i j : Nat) (_hi : i < l.length) (_hj : j < l.length) (_hij : i < j), R l[i] l[j] := by - rw [pairwise_iff_forall_sublist] - constructor <;> intro h - · intros i j hi hj h' - apply h - simpa [h'] using map_get_sublist (is := [⟨i, hi⟩, ⟨j, hj⟩]) - · intros a b h' - have ⟨is, h', hij⟩ := sublist_eq_map_get h' - rcases is with ⟨⟩ | ⟨a', ⟨⟩ | ⟨b', ⟨⟩⟩⟩ <;> simp at h' - rcases h' with ⟨rfl, rfl⟩ - apply h; simpa using hij - theorem pairwise_iff_get : Pairwise R l ↔ ∀ (i j) (_hij : i < j), R (get l i) (get l j) := by rw [pairwise_iff_getElem] constructor <;> intro h From f96a8aaf795d50bb08d0f77d452980ef4d918f3e Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 31 Jul 2024 15:37:43 +1000 Subject: [PATCH 152/208] chore: backports for leanprover/lean4#4814 (#894) --- Batteries/Classes/Order.lean | 2 +- Batteries/Data/List/Lemmas.lean | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Batteries/Classes/Order.lean b/Batteries/Classes/Order.lean index f54f82eb24..8cbfae25b0 100644 --- a/Batteries/Classes/Order.lean +++ b/Batteries/Classes/Order.lean @@ -102,7 +102,7 @@ theorem cmp_congr_left (xy : cmp x y = .eq) : cmp x z = cmp y z := theorem cmp_congr_left' (xy : cmp x y = .eq) : cmp x = cmp y := funext fun _ => cmp_congr_left xy -theorem cmp_congr_right [TransCmp cmp] (yz : cmp y z = .eq) : cmp x y = cmp x z := by +theorem cmp_congr_right (yz : cmp y z = .eq) : cmp x y = cmp x z := by rw [← Ordering.swap_inj, symm, symm, cmp_congr_left yz] end TransCmp diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index b932b5ff71..533a140f45 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -912,7 +912,7 @@ section union variable [BEq α] -theorem union_def [BEq α] (l₁ l₂ : List α) : l₁ ∪ l₂ = foldr .insert l₂ l₁ := rfl +theorem union_def (l₁ l₂ : List α) : l₁ ∪ l₂ = foldr .insert l₂ l₁ := rfl @[simp] theorem nil_union (l : List α) : nil ∪ l = l := by simp [List.union_def, foldr] @@ -977,10 +977,11 @@ theorem forIn_eq_bindList [Monad m] [LawfulMonad m] section Diff variable [BEq α] -variable [LawfulBEq α] @[simp] theorem diff_nil (l : List α) : l.diff [] = l := rfl +variable [LawfulBEq α] + @[simp] theorem diff_cons (l₁ l₂ : List α) (a : α) : l₁.diff (a :: l₂) = (l₁.erase a).diff l₂ := by simp_all [List.diff, erase_of_not_mem] From d7fe7912e2a6528f4c7395cce1f828b930a806b3 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Wed, 31 Jul 2024 09:05:41 +0000 Subject: [PATCH 153/208] chore: bump to nightly-2024-07-31 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index bab681a281..6b49c0ee43 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-30 +leanprover/lean4:nightly-2024-07-31 From 0f3e143dffdc3a591662f3401ce1d7a3405227c0 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 31 Jul 2024 19:46:56 +1000 Subject: [PATCH 154/208] chore: bump toolchain to v4.10.0 (#900) --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 6a4259fa56..7f0ea50aaa 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.10.0-rc2 +leanprover/lean4:v4.10.0 From 41bc768e2224d6c75128a877f1d6e198859b3178 Mon Sep 17 00:00:00 2001 From: Bulhwi Cha Date: Thu, 1 Aug 2024 05:52:18 +0000 Subject: [PATCH 155/208] refactor: rename theorems about `Char.utf8Size` (#901) --- Batteries/Data/String/Lemmas.lean | 54 +++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/Batteries/Data/String/Lemmas.lean b/Batteries/Data/String/Lemmas.lean index 1ea4e4f788..e046783fee 100644 --- a/Batteries/Data/String/Lemmas.lean +++ b/Batteries/Data/String/Lemmas.lean @@ -34,14 +34,14 @@ instance : Batteries.BEqOrd String := .compareOfLessAndEq String.lt_irrefl attribute [simp] toList -- prefer `String.data` over `String.toList` in lemmas -private theorem add_csize_pos : 0 < i + Char.utf8Size c := +private theorem add_utf8Size_pos : 0 < i + Char.utf8Size c := Nat.add_pos_right _ (Char.utf8Size_pos c) -private theorem ne_add_csize_add_self : i ≠ n + Char.utf8Size c + i := - Nat.ne_of_lt (Nat.lt_add_of_pos_left add_csize_pos) +private theorem ne_add_utf8Size_add_self : i ≠ n + Char.utf8Size c + i := + Nat.ne_of_lt (Nat.lt_add_of_pos_left add_utf8Size_pos) -private theorem ne_self_add_add_csize : i ≠ i + (n + Char.utf8Size c) := - Nat.ne_of_lt (Nat.lt_add_of_pos_right add_csize_pos) +private theorem ne_self_add_add_utf8Size : i ≠ i + (n + Char.utf8Size c) := + Nat.ne_of_lt (Nat.lt_add_of_pos_right add_utf8Size_pos) /-- The UTF-8 byte length of a list of characters. (This is intended for specification purposes.) -/ @[inline] def utf8Len : List Char → Nat := utf8ByteSize.go @@ -64,7 +64,7 @@ private theorem ne_self_add_add_csize : i ≠ i + (n + Char.utf8Size c) := @[simp] theorem utf8Len_reverse (cs) : utf8Len cs.reverse = utf8Len cs := utf8Len_reverseAux .. @[simp] theorem utf8Len_eq_zero : utf8Len l = 0 ↔ l = [] := by - cases l <;> simp [Nat.ne_of_gt add_csize_pos] + cases l <;> simp [Nat.ne_of_gt add_utf8Size_pos] section open List @@ -92,7 +92,7 @@ attribute [ext] ext theorem lt_addChar (p : Pos) (c : Char) : p < p + c := Nat.lt_add_of_pos_right (Char.utf8Size_pos _) private theorem zero_ne_addChar {i : Pos} {c : Char} : 0 ≠ i + c := - ne_of_lt add_csize_pos + ne_of_lt add_utf8Size_pos /-- A string position is valid if it is equal to the UTF-8 length of an initial substring of `s`. -/ def Valid (s : String) (p : Pos) : Prop := @@ -154,7 +154,7 @@ theorem utf8GetAux_of_valid (cs cs' : List Char) {i p : Nat} (hp : i + utf8Len c | c::cs, cs' => simp only [utf8GetAux, List.append_eq, Char.reduceDefault, ↓Char.isValue] rw [if_neg] - case hnc => simp only [← hp, utf8Len_cons, Pos.ext_iff]; exact ne_self_add_add_csize + case hnc => simp only [← hp, utf8Len_cons, Pos.ext_iff]; exact ne_self_add_add_utf8Size refine utf8GetAux_of_valid cs cs' ?_ simpa [Nat.add_assoc, Nat.add_comm] using hp @@ -173,7 +173,7 @@ theorem utf8GetAux?_of_valid (cs cs' : List Char) {i p : Nat} (hp : i + utf8Len | c::cs, cs' => simp only [utf8GetAux?, List.append_eq] rw [if_neg] - case hnc => simp [← hp, Pos.ext_iff]; exact ne_self_add_add_csize + case hnc => simp [← hp, Pos.ext_iff]; exact ne_self_add_add_utf8Size refine utf8GetAux?_of_valid cs cs' ?_ simpa [Nat.add_assoc, Nat.add_comm] using hp @@ -188,7 +188,7 @@ theorem utf8SetAux_of_valid (c' : Char) (cs cs' : List Char) {i p : Nat} (hp : i | c::cs, cs' => simp only [utf8SetAux, List.append_eq, List.cons_append] rw [if_neg] - case hnc => simp [← hp, Pos.ext_iff]; exact ne_self_add_add_csize + case hnc => simp [← hp, Pos.ext_iff]; exact ne_self_add_add_utf8Size refine congrArg (c::·) (utf8SetAux_of_valid c' cs cs' ?_) simpa [Nat.add_assoc, Nat.add_comm] using hp @@ -228,14 +228,14 @@ theorem utf8PrevAux_of_valid {cs cs' : List Char} {c : Char} {i p : Nat} case hnc => simp only [Pos.ext_iff] rw [Nat.add_right_comm, Nat.add_left_comm] - apply ne_add_csize_add_self + apply ne_add_utf8Size_add_self refine (utf8PrevAux_of_valid (by simp [Nat.add_assoc, Nat.add_left_comm])).trans ?_ simp [Nat.add_assoc, Nat.add_comm] theorem prev_of_valid (cs : List Char) (c : Char) (cs' : List Char) : prev ⟨cs ++ c :: cs'⟩ ⟨utf8Len cs + c.utf8Size⟩ = ⟨utf8Len cs⟩ := by simp only [prev] - refine (if_neg (Pos.ne_of_gt add_csize_pos)).trans ?_ + refine (if_neg (Pos.ne_of_gt add_utf8Size_pos)).trans ?_ rw [utf8PrevAux_of_valid] <;> simp theorem prev_of_valid' (cs cs' : List Char) : @@ -255,7 +255,7 @@ theorem back_eq (s : String) : back s = s.1.getLastD default := by theorem atEnd_of_valid (cs : List Char) (cs' : List Char) : atEnd ⟨cs ++ cs'⟩ ⟨utf8Len cs⟩ ↔ cs' = [] := by rw [atEnd_iff] - cases cs' <;> simp [Nat.lt_add_of_pos_right add_csize_pos] + cases cs' <;> simp [Nat.lt_add_of_pos_right add_utf8Size_pos] unseal posOfAux findAux in theorem posOfAux_eq (s c) : posOfAux s c = findAux s (· == c) := rfl @@ -276,7 +276,7 @@ theorem findAux_of_valid (p) : ∀ l m r, | l, [], r => by unfold findAux List.takeWhile; simp | l, c::m, r => by unfold findAux List.takeWhile - rw [dif_pos (by exact Nat.lt_add_of_pos_right add_csize_pos)] + rw [dif_pos (by exact Nat.lt_add_of_pos_right add_utf8Size_pos)] have h1 := get_of_valid l (c::m++r); have h2 := next_of_valid l c (m++r) simp only [List.cons_append, Char.reduceDefault, List.headD_cons] at h1 h2 simp only [List.append_assoc, List.cons_append, h1, utf8Len_cons, h2] @@ -298,7 +298,7 @@ theorem revFindAux_of_valid (p) : ∀ l r, | [], r => by unfold revFindAux List.dropWhile; simp | c::l, r => by unfold revFindAux List.dropWhile - rw [dif_neg (by exact Pos.ne_of_gt add_csize_pos)] + rw [dif_neg (by exact Pos.ne_of_gt add_utf8Size_pos)] have h1 := get_of_valid l.reverse (c::r); have h2 := prev_of_valid l.reverse c r simp only [utf8Len_reverse, Char.reduceDefault, List.headD_cons] at h1 h2 simp only [List.reverse_cons, List.append_assoc, List.singleton_append, utf8Len_cons, h2, h1] @@ -320,7 +320,7 @@ theorem firstDiffPos_loop_eq (l₁ l₂ r₁ r₂ stop p) rw [ dif_pos <| by rw [hstop, ← hl₁, ← hl₂] - refine Nat.lt_min.2 ⟨?_, ?_⟩ <;> exact Nat.lt_add_of_pos_right add_csize_pos, + refine Nat.lt_min.2 ⟨?_, ?_⟩ <;> exact Nat.lt_add_of_pos_right add_utf8Size_pos, show get ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = a by simp [hl₁, get_of_valid], show get ⟨l₂ ++ b :: r₂⟩ ⟨p⟩ = b by simp [hl₂, get_of_valid]] simp only [bne_iff_ne, ne_eq, ite_not, decide_eq_true_eq] @@ -360,7 +360,7 @@ theorem extract.go₂_append_left : ∀ (s t : List Char) (i e : Nat), e = utf8Len s + i → go₂ (s ++ t) ⟨i⟩ ⟨e⟩ = s | [], t, i, _, rfl => by cases t <;> simp [go₂] | c :: cs, t, i, _, rfl => by - simp only [go₂, utf8Len_cons, Pos.ext_iff, ne_add_csize_add_self, ↓reduceIte, List.append_eq, + simp only [go₂, utf8Len_cons, Pos.ext_iff, ne_add_utf8Size_add_self, ↓reduceIte, List.append_eq, Pos.addChar_eq, List.cons.injEq, true_and] apply go₂_append_left; rw [Nat.add_right_comm, Nat.add_assoc] @@ -379,7 +379,7 @@ theorem extract.go₁_add_right_cancel (s : List Char) (i b e n : Nat) : theorem extract.go₁_cons_addChar (c : Char) (cs : List Char) (b e : Pos) : go₁ (c :: cs) 0 (b + c) (e + c) = go₁ cs 0 b e := by - simp only [go₁, Pos.ext_iff, Pos.byteIdx_zero, pos_add_char, Nat.ne_of_lt add_csize_pos, + simp only [go₁, Pos.ext_iff, Pos.byteIdx_zero, pos_add_char, Nat.ne_of_lt add_utf8Size_pos, ↓reduceIte] apply go₁_add_right_cancel @@ -387,7 +387,7 @@ theorem extract.go₁_append_right : ∀ (s t : List Char) (i b : Nat) (e : Pos) b = utf8Len s + i → go₁ (s ++ t) ⟨i⟩ ⟨b⟩ e = go₂ t ⟨b⟩ e | [], t, i, _, e, rfl => by cases t <;> simp [go₁, go₂] | c :: cs, t, i, _, e, rfl => by - simp only [go₁, utf8Len_cons, Pos.ext_iff, ne_add_csize_add_self, ↓reduceIte, List.append_eq, + simp only [go₁, utf8Len_cons, Pos.ext_iff, ne_add_utf8Size_add_self, ↓reduceIte, List.append_eq, Pos.addChar_eq] apply go₁_append_right; rw [Nat.add_right_comm, Nat.add_assoc] @@ -404,7 +404,7 @@ theorem extract_zero_endPos : ∀ (s : String), s.extract 0 (endPos s) = s | ⟨[]⟩ => rfl | ⟨c :: cs⟩ => by simp only [extract, Pos.byteIdx_zero, endPos_eq, utf8Len_cons, ge_iff_le, Nat.le_zero_eq, - Nat.ne_of_gt add_csize_pos, ↓reduceIte] + Nat.ne_of_gt add_utf8Size_pos, ↓reduceIte] congr apply extract.go₁_zero_utf8Len @@ -645,7 +645,7 @@ theorem offsetOfPosAux_of_valid : ∀ l m r n, | l, [], r, n => by unfold offsetOfPosAux; simp | l, c::m, r, n => by unfold offsetOfPosAux - rw [if_neg (by exact Nat.not_le.2 (Nat.lt_add_of_pos_right add_csize_pos))] + rw [if_neg (by exact Nat.not_le.2 (Nat.lt_add_of_pos_right add_utf8Size_pos))] simp only [List.append_assoc, atEnd_of_valid l (c::m++r)] simp only [List.cons_append, utf8Len_cons, next_of_valid l c (m ++ r)] simpa [← Nat.add_assoc, Nat.add_right_comm] using @@ -660,7 +660,7 @@ theorem foldlAux_of_valid (f : α → Char → α) : ∀ l m r a, | l, [], r, a => by unfold foldlAux; simp | l, c::m, r, a => by unfold foldlAux - rw [dif_pos (by exact Nat.lt_add_of_pos_right add_csize_pos)] + rw [dif_pos (by exact Nat.lt_add_of_pos_right add_utf8Size_pos)] simp only [List.append_assoc, List.cons_append, utf8Len_cons, next_of_valid l c (m ++ r), get_of_valid l (c :: (m ++ r)), Char.reduceDefault, List.headD_cons, List.foldl_cons] simpa [← Nat.add_assoc, Nat.add_right_comm] using foldlAux_of_valid f (l++[c]) m r (f a c) @@ -674,7 +674,7 @@ theorem foldrAux_of_valid (f : Char → α → α) (l m r a) : rw [← m.reverse_reverse] induction m.reverse generalizing r a with (unfold foldrAux; simp) | cons c m IH => - rw [if_pos (by exact Nat.lt_add_of_pos_right add_csize_pos)] + rw [if_pos (by exact Nat.lt_add_of_pos_right add_utf8Size_pos)] simp only [← Nat.add_assoc, by simpa using prev_of_valid (l ++ m.reverse) c r] simp only [by simpa using get_of_valid (l ++ m.reverse) (c :: r)] simpa using IH (c::r) (f c a) @@ -688,7 +688,7 @@ theorem anyAux_of_valid (p : Char → Bool) : ∀ l m r, | l, [], r => by unfold anyAux; simp | l, c::m, r => by unfold anyAux - rw [dif_pos (by exact Nat.lt_add_of_pos_right add_csize_pos)] + rw [dif_pos (by exact Nat.lt_add_of_pos_right add_utf8Size_pos)] simp only [List.append_assoc, List.cons_append, get_of_valid l (c :: (m ++ r)), Char.reduceDefault, List.headD_cons, utf8Len_cons, next_of_valid l c (m ++ r), Bool.if_true_left, Bool.decide_eq_true, List.any_cons] @@ -732,7 +732,7 @@ theorem takeWhileAux_of_valid (p : Char → Bool) : ∀ l m r, | l, [], r => by unfold Substring.takeWhileAux List.takeWhile; simp | l, c::m, r => by unfold Substring.takeWhileAux List.takeWhile - rw [dif_pos (by exact Nat.lt_add_of_pos_right add_csize_pos)] + rw [dif_pos (by exact Nat.lt_add_of_pos_right add_utf8Size_pos)] simp only [List.append_assoc, List.cons_append, get_of_valid l (c :: (m ++ r)), Char.reduceDefault, List.headD_cons, utf8Len_cons, next_of_valid l c (m ++ r)] cases p c <;> simp @@ -809,7 +809,7 @@ theorem next : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → rw [if_neg (mt Pos.ext_iff.1 ?a)] case a => simpa [Nat.add_assoc, Nat.add_comm, Nat.add_left_comm] using - @ne_add_csize_add_self (utf8Len l + utf8Len m₁) (utf8Len m₂) c + @ne_add_utf8Size_add_self (utf8Len l + utf8Len m₁) (utf8Len m₂) c have := next_of_valid (l ++ m₁) c (m₂ ++ r) simp only [List.append_assoc, utf8Len_append, Pos.add_eq] at this ⊢; rw [this] simp [Nat.add_assoc, Nat.add_sub_cancel_left] @@ -822,7 +822,7 @@ theorem prev : ∀ {s}, ValidFor l (m₁ ++ c :: m₂) r s → | _, ⟨⟩ => by simp only [Substring.prev, List.append_assoc, List.cons_append] rw [if_neg (mt Pos.ext_iff.1 <| Ne.symm ?a)] - case a => simpa [Nat.add_comm] using @ne_add_csize_add_self (utf8Len l) (utf8Len m₁) c + case a => simpa [Nat.add_comm] using @ne_add_utf8Size_add_self (utf8Len l) (utf8Len m₁) c have := prev_of_valid (l ++ m₁) c (m₂ ++ r) simp only [List.append_assoc, utf8Len_append, Nat.add_assoc, Pos.add_eq] at this ⊢; rw [this] simp [Nat.add_sub_cancel_left] From a09c33a6febd971fcce5cc28fc8ec7ef8396ceac Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 1 Aug 2024 20:30:09 +1000 Subject: [PATCH 156/208] fix --- Batteries/Data/String/Lemmas.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Batteries/Data/String/Lemmas.lean b/Batteries/Data/String/Lemmas.lean index b0d4cb48b8..9984d0fb52 100644 --- a/Batteries/Data/String/Lemmas.lean +++ b/Batteries/Data/String/Lemmas.lean @@ -677,7 +677,7 @@ theorem foldrAux_of_valid (f : Char → α → α) (l m r a) : rw [← m.reverse_reverse] induction m.reverse generalizing r a with (unfold foldrAux; simp) | cons c m IH => - rw [if_pos add_csize_pos] + rw [if_pos add_utf8Size_pos] simp only [← Nat.add_assoc, by simpa using prev_of_valid (l ++ m.reverse) c r] simp only [by simpa using get_of_valid (l ++ m.reverse) (c :: r)] simpa using IH (c::r) (f c a) From 7ec90768f7cefdf4f590ad784b27f484501ecfe8 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 2 Aug 2024 09:53:34 +1000 Subject: [PATCH 157/208] fix --- Batteries/Lean/Util/EnvSearch.lean | 3 +-- lean-toolchain | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Batteries/Lean/Util/EnvSearch.lean b/Batteries/Lean/Util/EnvSearch.lean index 9143c89511..d9419b8cbf 100644 --- a/Batteries/Lean/Util/EnvSearch.lean +++ b/Batteries/Lean/Util/EnvSearch.lean @@ -24,8 +24,7 @@ where /-- Check constant should be returned -/ @[nolint unusedArguments] check matches_ (_name : Name) cinfo := do - let include ← p cinfo - if include then + if ← p cinfo then pure $ matches_.push cinfo else pure matches_ diff --git a/lean-toolchain b/lean-toolchain index 6b49c0ee43..b4a321bc74 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-07-31 +leanprover/lean4:nightly-2024-08-01 From f910a1ff8498ff25924fbd64b1748a0bc2edd88b Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 2 Aug 2024 09:05:58 +0000 Subject: [PATCH 158/208] chore: bump to nightly-2024-08-02 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index b4a321bc74..c78c147de1 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-01 +leanprover/lean4:nightly-2024-08-02 From 632474de43337865198c7afed5c5e5377d0e776b Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sat, 3 Aug 2024 09:05:38 +0000 Subject: [PATCH 159/208] chore: bump to nightly-2024-08-03 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index c78c147de1..7e87556fbd 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-02 +leanprover/lean4:nightly-2024-08-03 From 021e272cb5cdcc82b7e1e760fe915ff2f64169ad Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 5 Aug 2024 12:16:22 +1000 Subject: [PATCH 160/208] chore: move to v4.11.0-rc1 (#907) --- Batteries.lean | 4 - Batteries/Classes/BEq.lean | 18 - Batteries/Data/Array/Basic.lean | 18 - Batteries/Data/Char.lean | 5 - Batteries/Data/HashMap/Basic.lean | 1 - Batteries/Data/HashMap/WF.lean | 10 +- Batteries/Data/List.lean | 1 - Batteries/Data/List/Basic.lean | 204 +----- Batteries/Data/List/Count.lean | 211 +----- Batteries/Data/List/EraseIdx.lean | 70 +- Batteries/Data/List/Init/Attach.lean | 44 -- Batteries/Data/List/Lemmas.lean | 985 +-------------------------- Batteries/Data/List/Pairwise.lean | 210 ------ Batteries/Data/List/Perm.lean | 17 +- Batteries/Data/Nat/Basic.lean | 3 - Batteries/Data/Nat/Lemmas.lean | 4 - Batteries/Data/RBMap/Lemmas.lean | 1 - Batteries/Data/Range/Lemmas.lean | 1 - Batteries/Data/String/Lemmas.lean | 15 +- Batteries/Data/UInt.lean | 10 - Batteries/Lean/SMap.lean | 17 - Batteries/Lean/Util/EnvSearch.lean | 3 +- Batteries/Lean/Util/Path.lean | 34 - Batteries/Logic.lean | 11 +- Batteries/StdDeprecations.lean | 1 - Batteries/Tactic/Lint/Basic.lean | 2 + Batteries/Util/CheckTactic.lean | 124 ---- lean-toolchain | 2 +- scripts/runLinter.lean | 2 +- test/array.lean | 1 - test/congr.lean | 2 - 31 files changed, 41 insertions(+), 1990 deletions(-) delete mode 100644 Batteries/Classes/BEq.lean delete mode 100644 Batteries/Data/List/Init/Attach.lean delete mode 100644 Batteries/Lean/SMap.lean delete mode 100644 Batteries/Lean/Util/Path.lean delete mode 100644 Batteries/Util/CheckTactic.lean diff --git a/Batteries.lean b/Batteries.lean index 2fac3bf121..8e1e6f1828 100644 --- a/Batteries.lean +++ b/Batteries.lean @@ -1,4 +1,3 @@ -import Batteries.Classes.BEq import Batteries.Classes.Cast import Batteries.Classes.Order import Batteries.Classes.RatCast @@ -64,12 +63,10 @@ import Batteries.Lean.NameMapAttribute import Batteries.Lean.PersistentHashMap import Batteries.Lean.PersistentHashSet import Batteries.Lean.Position -import Batteries.Lean.SMap import Batteries.Lean.Syntax import Batteries.Lean.System.IO import Batteries.Lean.TagAttribute import Batteries.Lean.Util.EnvSearch -import Batteries.Lean.Util.Path import Batteries.Linter import Batteries.Linter.UnnecessarySeqFocus import Batteries.Linter.UnreachableTactic @@ -101,7 +98,6 @@ import Batteries.Tactic.Unreachable import Batteries.Tactic.Where import Batteries.Test.Internal.DummyLabelAttr import Batteries.Util.Cache -import Batteries.Util.CheckTactic import Batteries.Util.ExtendedBinder import Batteries.Util.LibraryNote import Batteries.Util.Pickle diff --git a/Batteries/Classes/BEq.lean b/Batteries/Classes/BEq.lean deleted file mode 100644 index 98318f97c9..0000000000 --- a/Batteries/Classes/BEq.lean +++ /dev/null @@ -1,18 +0,0 @@ -/- -Copyright (c) 2022 Mario Carneiro. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mario Carneiro --/ - -/-! ## Boolean equality -/ - -/-- `PartialEquivBEq α` says that the `BEq` implementation is a -partial equivalence relation, that is: -* it is symmetric: `a == b → b == a` -* it is transitive: `a == b → b == c → a == c`. --/ -class PartialEquivBEq (α) [BEq α] : Prop where - /-- Symmetry for `BEq`. If `a == b` then `b == a`. -/ - symm : (a : α) == b → b == a - /-- Transitivity for `BEq`. If `a == b` and `b == c` then `a == c`. -/ - trans : (a : α) == b → b == c → a == c diff --git a/Batteries/Data/Array/Basic.lean b/Batteries/Data/Array/Basic.lean index 1dddea3c14..ad6b8129e6 100644 --- a/Batteries/Data/Array/Basic.lean +++ b/Batteries/Data/Array/Basic.lean @@ -3,7 +3,6 @@ Copyright (c) 2021 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino, Floris van Doorn, Jannis Limperg -/ -import Batteries.Data.List.Init.Attach import Batteries.Data.Array.Init.Lemmas /-! @@ -130,23 +129,6 @@ protected def maxI [ord : Ord α] [Inhabited α] (xs : Array α) (start := 0) (stop := xs.size) : α := xs.minI (ord := ord.opposite) start stop -/-- -Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of -`Array {x // P x}` is the same as the input `Array α`. --/ -@[inline] private unsafe def attachWithImpl - (xs : Array α) (P : α → Prop) (_ : ∀ x ∈ xs, P x) : Array {x // P x} := unsafeCast xs - -/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `xs` to produce a new array - with the same elements but in the type `{x // P x}`. -/ -@[implemented_by attachWithImpl] def attachWith - (xs : Array α) (P : α → Prop) (H : ∀ x ∈ xs, P x) : Array {x // P x} := - ⟨xs.data.attachWith P fun x h => H x (Array.Mem.mk h)⟩ - -/-- `O(1)`. "Attach" the proof that the elements of `xs` are in `xs` to produce a new array - with the same elements but in the type `{x // x ∈ xs}`. -/ -@[inline] def attach (xs : Array α) : Array {x // x ∈ xs} := xs.attachWith _ fun _ => id - /-- `O(|join L|)`. `join L` concatenates all the arrays in `L` into one array. * `join #[#[a], #[], #[b, c], #[d, e, f]] = #[a, b, c, d, e, f]` diff --git a/Batteries/Data/Char.lean b/Batteries/Data/Char.lean index 5a9110ae12..4f3c59ef0b 100644 --- a/Batteries/Data/Char.lean +++ b/Batteries/Data/Char.lean @@ -6,11 +6,6 @@ Authors: Jannis Limperg import Batteries.Data.UInt import Batteries.Tactic.Alias -@[ext] theorem Char.ext : {a b : Char} → a.val = b.val → a = b - | ⟨_,_⟩, ⟨_,_⟩, rfl => rfl - -theorem Char.ext_iff {x y : Char} : x = y ↔ x.val = y.val := ⟨congrArg _, Char.ext⟩ - theorem Char.le_antisymm_iff {x y : Char} : x = y ↔ x ≤ y ∧ y ≤ x := Char.ext_iff.trans UInt32.le_antisymm_iff diff --git a/Batteries/Data/HashMap/Basic.lean b/Batteries/Data/HashMap/Basic.lean index 106fea1e4d..3419ba35ab 100644 --- a/Batteries/Data/HashMap/Basic.lean +++ b/Batteries/Data/HashMap/Basic.lean @@ -6,7 +6,6 @@ Authors: Leonardo de Moura, Mario Carneiro import Batteries.Data.AssocList import Batteries.Data.Nat.Basic import Batteries.Data.Array.Monadic -import Batteries.Classes.BEq namespace Batteries.HashMap diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index f6298d3322..e83e32e567 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -24,7 +24,7 @@ theorem exists_of_update (self : Buckets α β) (i d h) : ∃ l₁ l₂, self.1.data = l₁ ++ self.1[i] :: l₂ ∧ List.length l₁ = i.toNat ∧ (self.update i d h).1.data = l₁ ++ d :: l₂ := by simp only [Array.data_length, Array.ugetElem_eq_getElem, Array.getElem_eq_data_getElem] - exact List.exists_of_set' h + exact List.exists_of_set h theorem update_update (self : Buckets α β) (i d d' h h') : (self.update i d h).update i d' h' = self.update i d' h := by @@ -95,11 +95,11 @@ where · next H => refine (go (i+1) _ _ fun j hj => ?a).trans ?b <;> simp · case a => - simp [List.getD_eq_getElem?, List.getElem?_set, Option.map_eq_map]; split + simp [List.getD_eq_getElem?_getD, List.getElem?_set, Option.map_eq_map]; split · cases source.data[j]? <;> rfl · next H => exact hs _ (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ hj) (Ne.symm H)) · case b => - refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set' H; eq ▸ ?_ + refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set H; eq ▸ ?_ rw [h₁] simp only [Buckets.size_eq, List.map_append, List.map_cons, AssocList.toList, List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length] @@ -315,7 +315,7 @@ theorem WF.mapVal {α β γ} {f : α → β → γ} [BEq α] [Hashable α] have ⟨h₁, h₂⟩ := H.out simp only [Imp.mapVal, h₁, Buckets.mapVal, WF_iff]; refine ⟨?_, ?_, fun i h => ?_⟩ · simp only [Buckets.size, Array.map_data, List.map_map]; congr; funext l; simp - · simp only [Array.map_data, List.forall_mem_map_iff] + · simp only [Array.map_data, List.forall_mem_map] simp only [AssocList.toList_mapVal, List.pairwise_map] exact fun _ => h₂.1 _ · simp only [Array.size_map, AssocList.All, Array.getElem_map, AssocList.toList_mapVal, @@ -361,7 +361,7 @@ theorem WF.filterMap {α β γ} {f : α → β → Option γ} [BEq α] [Hashable simp only [Array.mapM_eq_mapM_data, bind, StateT.bind, H2, List.map_map, Nat.zero_add, g] intro bk sz h e'; cases e' refine .mk (by simp [Buckets.size]) ⟨?_, fun i h => ?_⟩ - · simp only [List.forall_mem_map_iff, List.toList_toAssocList] + · simp only [List.forall_mem_map, List.toList_toAssocList] refine fun l h => (List.pairwise_reverse.2 ?_).imp (mt PartialEquivBEq.symm) have := H.out.2.1 _ h rw [← List.pairwise_map (R := (¬ · == ·))] at this ⊢ diff --git a/Batteries/Data/List.lean b/Batteries/Data/List.lean index d060ba89c8..998160b904 100644 --- a/Batteries/Data/List.lean +++ b/Batteries/Data/List.lean @@ -1,7 +1,6 @@ import Batteries.Data.List.Basic import Batteries.Data.List.Count import Batteries.Data.List.EraseIdx -import Batteries.Data.List.Init.Attach import Batteries.Data.List.Init.Lemmas import Batteries.Data.List.Lemmas import Batteries.Data.List.Pairwise diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index 2cff94c670..43915cd733 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -10,16 +10,6 @@ namespace List /-! ## New definitions -/ -/-- -`l₁ ⊆ l₂` means that every element of `l₁` is also an element of `l₂`, ignoring multiplicity. --/ -protected def Subset (l₁ l₂ : List α) := ∀ ⦃a : α⦄, a ∈ l₁ → a ∈ l₂ - -instance : HasSubset (List α) := ⟨List.Subset⟩ - -instance [DecidableEq α] : DecidableRel (Subset : List α → List α → Prop) := - fun _ _ => decidableBAll _ _ - /-- Computes the "bag intersection" of `l₁` and `l₂`, that is, the collection of elements of `l₁` which are also in `l₂`. As each element @@ -37,15 +27,6 @@ protected def diff {α} [BEq α] : List α → List α → List α open Option Nat -/-- Get the tail of a nonempty list, or return `[]` for `[]`. -/ -def tail : List α → List α - | [] => [] - | _::as => as - --- FIXME: `@[simp]` on the definition simplifies even `tail l` -@[simp] theorem tail_nil : @tail α [] = [] := rfl -@[simp] theorem tail_cons : @tail α (a::as) = as := rfl - /-- Get the head and tail of a list, if it is nonempty. -/ @[inline] def next? : List α → Option (α × List α) | [] => none @@ -83,16 +64,6 @@ drop_while (· != 1) [0, 1, 2, 3] = [1, 2, 3] | [] => [] | x :: xs => bif p x then xs else after p xs -/-- Returns the index of the first element satisfying `p`, or the length of the list otherwise. -/ -@[inline] def findIdx (p : α → Bool) (l : List α) : Nat := go l 0 where - /-- Auxiliary for `findIdx`: `findIdx.go p l n = findIdx p l + n` -/ - @[specialize] go : List α → Nat → Nat - | [], n => n - | a :: l, n => bif p a then n else go l (n + 1) - -/-- Returns the index of the first element equal to `a`, or the length of the list otherwise. -/ -def indexOf [BEq α] (a : α) : List α → Nat := findIdx (· == a) - @[deprecated (since := "2024-05-06")] alias removeNth := eraseIdx @[deprecated (since := "2024-05-06")] alias removeNthTR := eraseIdxTR @[deprecated (since := "2024-05-06")] alias removeNth_eq_removeNthTR := eraseIdx_eq_eraseIdxTR @@ -139,26 +110,6 @@ Unlike `bagInter` this does not preserve multiplicity: `[1, 1].inter [1]` is `[1 instance [BEq α] : Inter (List α) := ⟨List.inter⟩ -/-- `l₁ <+ l₂`, or `Sublist l₁ l₂`, says that `l₁` is a (non-contiguous) subsequence of `l₂`. -/ -inductive Sublist {α} : List α → List α → Prop - /-- the base case: `[]` is a sublist of `[]` -/ - | slnil : Sublist [] [] - /-- If `l₁` is a subsequence of `l₂`, then it is also a subsequence of `a :: l₂`. -/ - | cons a : Sublist l₁ l₂ → Sublist l₁ (a :: l₂) - /-- If `l₁` is a subsequence of `l₂`, then `a :: l₁` is a subsequence of `a :: l₂`. -/ - | cons₂ a : Sublist l₁ l₂ → Sublist (a :: l₁) (a :: l₂) - -@[inherit_doc] scoped infixl:50 " <+ " => Sublist - -/-- True if the first list is a potentially non-contiguous sub-sequence of the second list. -/ -def isSublist [BEq α] : List α → List α → Bool - | [], _ => true - | _, [] => false - | l₁@(hd₁::tl₁), hd₂::tl₂ => - if hd₁ == hd₂ - then tl₁.isSublist tl₂ - else l₁.isSublist tl₂ - /-- Split a list at an index. ``` @@ -299,7 +250,7 @@ theorem insertNthTR_go_eq : ∀ n l, insertNthTR.go a n l acc = acc.data ++ inse @[csimp] theorem insertNth_eq_insertNthTR : @insertNth = @insertNthTR := by funext α f n l; simp [insertNthTR, insertNthTR_go_eq] -@[simp] theorem headD_eq_head? (l) (a : α) : headD l a = (head? l).getD a := by cases l <;> rfl +theorem headD_eq_head? (l) (a : α) : headD l a = (head? l).getD a := by cases l <;> rfl /-- Take `n` elements from a list `l`. If `l` has less than `n` elements, append `n - length l` @@ -332,19 +283,6 @@ theorem takeDTR_go_eq : ∀ n l, takeDTR.go dflt n l acc = acc.data ++ takeD n l @[csimp] theorem takeD_eq_takeDTR : @takeD = @takeDTR := by funext α f n l; simp [takeDTR, takeDTR_go_eq] -/-- -Pads `l : List α` with repeated occurrences of `a : α` until it is of length `n`. -If `l` is initially larger than `n`, just return `l`. --/ -def leftpad (n : Nat) (a : α) (l : List α) : List α := replicate (n - length l) a ++ l - -/-- Optimized version of `leftpad`. -/ -@[inline] def leftpadTR (n : Nat) (a : α) (l : List α) : List α := - replicateTR.loop a (n - length l) l - -@[csimp] theorem leftpad_eq_leftpadTR : @leftpad = @leftpadTR := by - funext α n a l; simp [leftpad, leftpadTR, replicateTR_loop_eq] - /-- Fold a function `f` over the list from the left, returning the list of partial results. ``` @@ -416,14 +354,6 @@ indexesOf a [a, b, a, a] = [0, 2, 3] -/ @[inline] def indexesOf [BEq α] (a : α) : List α → List Nat := findIdxs (· == a) -/-- Return the index of the first occurrence of an element satisfying `p`. -/ -def findIdx? (p : α → Bool) : List α → (start : Nat := 0) → Option Nat -| [], _ => none -| a :: l, i => if p a then some i else findIdx? p l (i + 1) - -/-- Return the index of the first occurrence of `a` in the list. -/ -@[inline] def indexOf? [BEq α] (a : α) : List α → Option Nat := findIdx? (· == a) - /-- `lookmap` is a combination of `lookup` and `filterMap`. `lookmap f l` will apply `f : α → Option α` to each element of the list, @@ -437,40 +367,6 @@ replacing `a → b` at the first value `a` in the list such that `f a = some b`. | some b => acc.toListAppend (b :: l) | none => go l (acc.push a) -/-- `countP p l` is the number of elements of `l` that satisfy `p`. -/ -@[inline] def countP (p : α → Bool) (l : List α) : Nat := go l 0 where - /-- Auxiliary for `countP`: `countP.go p l acc = countP p l + acc`. -/ - @[specialize] go : List α → Nat → Nat - | [], acc => acc - | x :: xs, acc => bif p x then go xs (acc + 1) else go xs acc - -/-- `count a l` is the number of occurrences of `a` in `l`. -/ -@[inline] def count [BEq α] (a : α) : List α → Nat := countP (· == a) - -/-- -`IsPrefix l₁ l₂`, or `l₁ <+: l₂`, means that `l₁` is a prefix of `l₂`, -that is, `l₂` has the form `l₁ ++ t` for some `t`. --/ -def IsPrefix (l₁ : List α) (l₂ : List α) : Prop := ∃ t, l₁ ++ t = l₂ - -/-- -`IsSuffix l₁ l₂`, or `l₁ <:+ l₂`, means that `l₁` is a suffix of `l₂`, -that is, `l₂` has the form `t ++ l₁` for some `t`. --/ -def IsSuffix (l₁ : List α) (l₂ : List α) : Prop := ∃ t, t ++ l₁ = l₂ - -/-- -`IsInfix l₁ l₂`, or `l₁ <:+: l₂`, means that `l₁` is a contiguous -substring of `l₂`, that is, `l₂` has the form `s ++ l₁ ++ t` for some `s, t`. --/ -def IsInfix (l₁ : List α) (l₂ : List α) : Prop := ∃ s t, s ++ l₁ ++ t = l₂ - -@[inherit_doc] infixl:50 " <+: " => IsPrefix - -@[inherit_doc] infixl:50 " <:+ " => IsSuffix - -@[inherit_doc] infixl:50 " <:+: " => IsInfix - /-- `inits l` is the list of initial segments of `l`. ``` @@ -659,29 +555,6 @@ theorem sections_eq_nil_of_isEmpty : ∀ {L}, L.any isEmpty → @sections α L = rw [Array.foldl_eq_foldl_data, Array.foldl_data_eq_bind]; rfl intros; apply Array.foldl_data_eq_map -/-- `eraseP p l` removes the first element of `l` satisfying the predicate `p`. -/ -def eraseP (p : α → Bool) : List α → List α - | [] => [] - | a :: l => bif p a then l else a :: eraseP p l - -/-- Tail-recursive version of `eraseP`. -/ -@[inline] def erasePTR (p : α → Bool) (l : List α) : List α := go l #[] where - /-- Auxiliary for `erasePTR`: `erasePTR.go p l xs acc = acc.toList ++ eraseP p xs`, - unless `xs` does not contain any elements satisfying `p`, where it returns `l`. -/ - @[specialize] go : List α → Array α → List α - | [], _ => l - | a :: l, acc => bif p a then acc.toListAppend l else go l (acc.push a) - -@[csimp] theorem eraseP_eq_erasePTR : @eraseP = @erasePTR := by - funext α p l; simp [erasePTR] - let rec go (acc) : ∀ xs, l = acc.data ++ xs → - erasePTR.go p l xs acc = acc.data ++ xs.eraseP p - | [] => fun h => by simp [erasePTR.go, eraseP, h] - | x::xs => by - simp [erasePTR.go, eraseP]; cases p x <;> simp - · intro h; rw [go _ xs]; {simp}; simp [h] - exact (go #[] _ rfl).symm - /-- `extractP p l` returns a pair of an element `a` of `l` satisfying the predicate `p`, and `l`, with `a` removed. If there is no such element `a` it returns `(none, l)`. @@ -806,46 +679,6 @@ where rename_i a as b bs; unfold cond; cases R a b <;> simp [go as bs] exact (go as bs [] []).symm -section Pairwise - -variable (R : α → α → Prop) - -/-- -`Pairwise R l` means that all the elements with earlier indexes are -`R`-related to all the elements with later indexes. -``` -Pairwise R [1, 2, 3] ↔ R 1 2 ∧ R 1 3 ∧ R 2 3 -``` -For example if `R = (·≠·)` then it asserts `l` has no duplicates, -and if `R = (·<·)` then it asserts that `l` is (strictly) sorted. --/ -inductive Pairwise : List α → Prop - /-- All elements of the empty list are vacuously pairwise related. -/ - | nil : Pairwise [] - /-- `a :: l` is `Pairwise R` if `a` `R`-relates to every element of `l`, - and `l` is `Pairwise R`. -/ - | cons : ∀ {a : α} {l : List α}, (∀ a' ∈ l, R a a') → Pairwise l → Pairwise (a :: l) - -attribute [simp] Pairwise.nil - -variable {R} - -@[simp] theorem pairwise_cons : Pairwise R (a::l) ↔ (∀ a' ∈ l, R a a') ∧ Pairwise R l := - ⟨fun | .cons h₁ h₂ => ⟨h₁, h₂⟩, fun ⟨h₁, h₂⟩ => h₂.cons h₁⟩ - -instance instDecidablePairwise [DecidableRel R] : - (l : List α) → Decidable (Pairwise R l) - | [] => isTrue .nil - | hd :: tl => - match instDecidablePairwise tl with - | isTrue ht => - match decidableBAll (R hd) tl with - | isFalse hf => isFalse fun hf' => hf (pairwise_cons.1 hf').1 - | isTrue ht' => isTrue <| pairwise_cons.mpr (And.intro ht' ht) - | isFalse hf => isFalse fun | .cons _ ih => hf ih - -end Pairwise - /-- `pwFilter R l` is a maximal sublist of `l` which is `Pairwise R`. `pwFilter (·≠·)` is the erase duplicates function (cf. `eraseDup`), and `pwFilter (·<·)` finds @@ -881,47 +714,12 @@ def Chain' : List α → Prop end Chain -/-- `Nodup l` means that `l` has no duplicates, that is, any element appears at most - once in the List. It is defined as `Pairwise (≠)`. -/ -def Nodup : List α → Prop := Pairwise (· ≠ ·) - -instance nodupDecidable [DecidableEq α] : ∀ l : List α, Decidable (Nodup l) := - instDecidablePairwise - /-- `eraseDup l` removes duplicates from `l` (taking only the first occurrence). Defined as `pwFilter (≠)`. eraseDup [1, 0, 2, 2, 1] = [0, 2, 1] -/ @[inline] def eraseDup [BEq α] : List α → List α := pwFilter (· != ·) -/-- `range' start len step` is the list of numbers `[start, start+step, ..., start+(len-1)*step]`. - It is intended mainly for proving properties of `range` and `iota`. -/ -def range' : (start len : Nat) → (step : Nat := 1) → List Nat - | _, 0, _ => [] - | s, n+1, step => s :: range' (s+step) n step - -/-- Optimized version of `range'`. -/ -@[inline] def range'TR (s n : Nat) (step : Nat := 1) : List Nat := go n (s + step * n) [] where - /-- Auxiliary for `range'TR`: `range'TR.go n e = [e-n, ..., e-1] ++ acc`. -/ - go : Nat → Nat → List Nat → List Nat - | 0, _, acc => acc - | n+1, e, acc => go n (e-step) ((e-step) :: acc) - -@[csimp] theorem range'_eq_range'TR : @range' = @range'TR := by - funext s n step - let rec go (s) : ∀ n m, - range'TR.go step n (s + step * n) (range' (s + step * n) m step) = range' s (n + m) step - | 0, m => by simp [range'TR.go] - | n+1, m => by - simp [range'TR.go] - rw [Nat.mul_succ, ← Nat.add_assoc, Nat.add_sub_cancel, Nat.add_right_comm n] - exact go s n (m + 1) - exact (go s n 0).symm - -/-- Drop `none`s from a list, and replace each remaining `some a` with `a`. -/ -@[inline] def reduceOption {α} : List (Option α) → List α := - List.filterMap id - /-- `ilast' x xs` returns the last element of `xs` if `xs` is non-empty; it returns `x` otherwise. Use `List.getLastD` instead. diff --git a/Batteries/Data/List/Count.lean b/Batteries/Data/List/Count.lean index dfd1481052..036a76b4b8 100644 --- a/Batteries/Data/List/Count.lean +++ b/Batteries/Data/List/Count.lean @@ -19,111 +19,6 @@ open Nat namespace List -section countP - -variable (p q : α → Bool) - -@[simp] theorem countP_nil : countP p [] = 0 := rfl - -protected theorem countP_go_eq_add (l) : countP.go p l n = n + countP.go p l 0 := by - induction l generalizing n with - | nil => rfl - | cons head tail ih => - unfold countP.go - rw [ih (n := n + 1), ih (n := n), ih (n := 1)] - if h : p head then simp [h, Nat.add_assoc] else simp [h] - -@[simp] theorem countP_cons_of_pos (l) (pa : p a) : countP p (a :: l) = countP p l + 1 := by - have : countP.go p (a :: l) 0 = countP.go p l 1 := show cond .. = _ by rw [pa]; rfl - unfold countP - rw [this, Nat.add_comm, List.countP_go_eq_add] - -@[simp] theorem countP_cons_of_neg (l) (pa : ¬p a) : countP p (a :: l) = countP p l := by - simp [countP, countP.go, pa] - -theorem countP_cons (a : α) (l) : countP p (a :: l) = countP p l + if p a then 1 else 0 := by - by_cases h : p a <;> simp [h] - -theorem length_eq_countP_add_countP (l) : length l = countP p l + countP (fun a => ¬p a) l := by - induction l with - | nil => rfl - | cons x h ih => - if h : p x then - rw [countP_cons_of_pos _ _ h, countP_cons_of_neg _ _ _, length, ih] - · rw [Nat.add_assoc, Nat.add_comm _ 1, Nat.add_assoc] - · simp only [h, not_true_eq_false, decide_False, not_false_eq_true] - else - rw [countP_cons_of_pos (fun a => ¬p a) _ _, countP_cons_of_neg _ _ h, length, ih] - · rfl - · simp only [h, not_false_eq_true, decide_True] - -theorem countP_eq_length_filter (l) : countP p l = length (filter p l) := by - induction l with - | nil => rfl - | cons x l ih => - if h : p x - then rw [countP_cons_of_pos p l h, ih, filter_cons_of_pos l h, length] - else rw [countP_cons_of_neg p l h, ih, filter_cons_of_neg l h] - -theorem countP_le_length : countP p l ≤ l.length := by - simp only [countP_eq_length_filter] - apply length_filter_le - -@[simp] theorem countP_append (l₁ l₂) : countP p (l₁ ++ l₂) = countP p l₁ + countP p l₂ := by - simp only [countP_eq_length_filter, filter_append, length_append] - -theorem countP_pos : 0 < countP p l ↔ ∃ a ∈ l, p a := by - simp only [countP_eq_length_filter, length_pos_iff_exists_mem, mem_filter, exists_prop] - -theorem countP_eq_zero : countP p l = 0 ↔ ∀ a ∈ l, ¬p a := by - simp only [countP_eq_length_filter, length_eq_zero, filter_eq_nil] - -theorem countP_eq_length : countP p l = l.length ↔ ∀ a ∈ l, p a := by - rw [countP_eq_length_filter, filter_length_eq_length] - -theorem Sublist.countP_le (s : l₁ <+ l₂) : countP p l₁ ≤ countP p l₂ := by - simp only [countP_eq_length_filter] - apply s.filter _ |>.length_le - -theorem countP_filter (l : List α) : - countP p (filter q l) = countP (fun a => p a ∧ q a) l := by - simp only [countP_eq_length_filter, filter_filter] - -@[simp] theorem countP_true {l : List α} : (l.countP fun _ => true) = l.length := by - rw [countP_eq_length] - simp - -@[simp] theorem countP_false {l : List α} : (l.countP fun _ => false) = 0 := by - rw [countP_eq_zero] - simp - -@[simp] theorem countP_map (p : β → Bool) (f : α → β) : - ∀ l, countP p (map f l) = countP (p ∘ f) l - | [] => rfl - | a :: l => by rw [map_cons, countP_cons, countP_cons, countP_map p f l]; rfl - -variable {p q} - -theorem countP_mono_left (h : ∀ x ∈ l, p x → q x) : countP p l ≤ countP q l := by - induction l with - | nil => apply Nat.le_refl - | cons a l ihl => - rw [forall_mem_cons] at h - have ⟨ha, hl⟩ := h - simp [countP_cons] - cases h : p a - . simp - apply Nat.le_trans ?_ (Nat.le_add_right _ _) - apply ihl hl - . simp [ha h] - apply ihl hl - -theorem countP_congr (h : ∀ x ∈ l, p x ↔ q x) : countP p l = countP q l := - Nat.le_antisymm - (countP_mono_left fun x hx => (h x hx).1) - (countP_mono_left fun x hx => (h x hx).2) - -end countP /-! ### count -/ @@ -131,71 +26,10 @@ section count variable [DecidableEq α] -@[simp] theorem count_nil (a : α) : count a [] = 0 := rfl - -theorem count_cons (a b : α) (l : List α) : - count a (b :: l) = count a l + if a = b then 1 else 0 := by - simp [count, countP_cons, eq_comm (a := a)] - -@[simp] theorem count_cons_self (a : α) (l : List α) : count a (a :: l) = count a l + 1 := by - simp [count_cons] - -@[simp] theorem count_cons_of_ne (h : a ≠ b) (l : List α) : count a (b :: l) = count a l := by - simp [count_cons, h] - -theorem count_tail : ∀ (l : List α) (a : α) (h : l ≠ []), - l.tail.count a = l.count a - if a = l.head h then 1 else 0 - | head :: tail, a, h => by simp [count_cons] - -theorem count_le_length (a : α) (l : List α) : count a l ≤ l.length := countP_le_length _ - -theorem Sublist.count_le (h : l₁ <+ l₂) (a : α) : count a l₁ ≤ count a l₂ := h.countP_le _ - -theorem count_le_count_cons (a b : α) (l : List α) : count a l ≤ count a (b :: l) := - (sublist_cons _ _).count_le _ - -theorem count_singleton (a : α) : count a [a] = 1 := by simp - -theorem count_singleton' (a b : α) : count a [b] = if a = b then 1 else 0 := by simp [count_cons] - -@[simp] theorem count_append (a : α) : ∀ l₁ l₂, count a (l₁ ++ l₂) = count a l₁ + count a l₂ := - countP_append _ +theorem count_singleton' (a b : α) : count a [b] = if b = a then 1 else 0 := by simp [count_cons] theorem count_concat (a : α) (l : List α) : count a (concat l a) = succ (count a l) := by simp -@[simp] -theorem count_pos_iff_mem {a : α} {l : List α} : 0 < count a l ↔ a ∈ l := by - simp only [count, countP_pos, beq_iff_eq, exists_eq_right] - -@[simp 900] theorem count_eq_zero_of_not_mem {a : α} {l : List α} (h : a ∉ l) : count a l = 0 := - Decidable.byContradiction fun h' => h <| count_pos_iff_mem.1 (Nat.pos_of_ne_zero h') - -theorem not_mem_of_count_eq_zero {a : α} {l : List α} (h : count a l = 0) : a ∉ l := - fun h' => Nat.ne_of_lt (count_pos_iff_mem.2 h') h.symm - -theorem count_eq_zero {l : List α} : count a l = 0 ↔ a ∉ l := - ⟨not_mem_of_count_eq_zero, count_eq_zero_of_not_mem⟩ - -theorem count_eq_length {l : List α} : count a l = l.length ↔ ∀ b ∈ l, a = b := by - rw [count, countP_eq_length] - refine ⟨fun h b hb => Eq.symm ?_, fun h b hb => ?_⟩ - · simpa using h b hb - · rw [h b hb, beq_self_eq_true] - -@[simp] theorem count_replicate_self (a : α) (n : Nat) : count a (replicate n a) = n := - (count_eq_length.2 <| fun _ h => (eq_of_mem_replicate h).symm).trans (length_replicate ..) - -theorem count_replicate (a b : α) (n : Nat) : count a (replicate n b) = if a = b then n else 0 := by - split - exacts [‹a = b› ▸ count_replicate_self .., count_eq_zero.2 <| mt eq_of_mem_replicate ‹a ≠ b›] - -theorem filter_beq (l : List α) (a : α) : l.filter (· == a) = replicate (count a l) a := by - simp only [count, countP_eq_length_filter, eq_replicate, mem_filter, beq_iff_eq] - exact ⟨trivial, fun _ h => h.2⟩ - -theorem filter_eq (l : List α) (a : α) : l.filter (· = a) = replicate (count a l) a := - filter_beq l a - @[deprecated filter_eq (since := "2023-12-14")] theorem filter_eq' (l : List α) (a : α) : l.filter (a = ·) = replicate (count a l) a := by simpa only [eq_comm] using filter_eq l a @@ -203,46 +37,3 @@ theorem filter_eq' (l : List α) (a : α) : l.filter (a = ·) = replicate (count @[deprecated filter_beq (since := "2023-12-14")] theorem filter_beq' (l : List α) (a : α) : l.filter (a == ·) = replicate (count a l) a := by simpa only [eq_comm (b := a)] using filter_eq l a - -theorem le_count_iff_replicate_sublist {l : List α} : n ≤ count a l ↔ replicate n a <+ l := by - refine ⟨fun h => ?_, fun h => ?_⟩ - · exact ((replicate_sublist_replicate a).2 h).trans <| filter_eq l a ▸ filter_sublist _ - · simpa only [count_replicate_self] using h.count_le a - -theorem replicate_count_eq_of_count_eq_length {l : List α} (h : count a l = length l) : - replicate (count a l) a = l := - (le_count_iff_replicate_sublist.mp (Nat.le_refl _)).eq_of_length <| - (length_replicate (count a l) a).trans h - -@[simp] theorem count_filter {l : List α} (h : p a) : count a (filter p l) = count a l := by - rw [count, countP_filter]; congr; funext b - rw [(by rfl : (b == a) = decide (b = a)), decide_eq_decide] - simp; rintro rfl; exact h - -theorem count_le_count_map [DecidableEq β] (l : List α) (f : α → β) (x : α) : - count x l ≤ count (f x) (map f l) := by - rw [count, count, countP_map] - apply countP_mono_left; simp (config := { contextual := true }) - -theorem count_erase (a b : α) : - ∀ l : List α, count a (l.erase b) = count a l - if a = b then 1 else 0 - | [] => by simp - | c :: l => by - rw [erase_cons] - if hc : c = b then - have hc_beq := (beq_iff_eq _ _).mpr hc - rw [if_pos hc_beq, hc, count_cons, Nat.add_sub_cancel] - else - have hc_beq := beq_false_of_ne hc - simp only [hc_beq, if_false, count_cons, count_cons, count_erase a b l] - if ha : a = b then - rw [← ha, eq_comm] at hc - rw [if_pos ha, if_neg hc, Nat.add_zero, Nat.add_zero] - else - rw [if_neg ha, Nat.sub_zero, Nat.sub_zero] - -@[simp] theorem count_erase_self (a : α) (l : List α) : - count a (List.erase l a) = count a l - 1 := by rw [count_erase, if_pos rfl] - -@[simp] theorem count_erase_of_ne (ab : a ≠ b) (l : List α) : count a (l.erase b) = count a l := by - rw [count_erase, if_neg ab, Nat.sub_zero] diff --git a/Batteries/Data/List/EraseIdx.lean b/Batteries/Data/List/EraseIdx.lean index ca3cf2e716..42b4bfacd1 100644 --- a/Batteries/Data/List/EraseIdx.lean +++ b/Batteries/Data/List/EraseIdx.lean @@ -17,75 +17,15 @@ namespace List universe u v variable {α : Type u} {β : Type v} -@[simp] theorem eraseIdx_zero (l : List α) : eraseIdx l 0 = tail l := by cases l <;> rfl - -theorem eraseIdx_eq_take_drop_succ : - ∀ (l : List α) (i : Nat), l.eraseIdx i = l.take i ++ l.drop (i + 1) - | nil, _ => by simp - | a::l, 0 => by simp - | a::l, i + 1 => by simp [eraseIdx_eq_take_drop_succ l i] - -theorem eraseIdx_sublist : ∀ (l : List α) (k : Nat), eraseIdx l k <+ l - | [], _ => by simp - | a::l, 0 => by simp - | a::l, k + 1 => by simp [eraseIdx_sublist l k] - -theorem eraseIdx_subset (l : List α) (k : Nat) : eraseIdx l k ⊆ l := (eraseIdx_sublist l k).subset - -@[simp] -theorem eraseIdx_eq_self : ∀ {l : List α} {k : Nat}, eraseIdx l k = l ↔ length l ≤ k - | [], _ => by simp - | a::l, 0 => by simp [(cons_ne_self _ _).symm] - | a::l, k + 1 => by simp [eraseIdx_eq_self] - -alias ⟨_, eraseIdx_of_length_le⟩ := eraseIdx_eq_self - -theorem eraseIdx_append_of_lt_length {l : List α} {k : Nat} (hk : k < length l) (l' : List α) : - eraseIdx (l ++ l') k = eraseIdx l k ++ l' := by - rw [eraseIdx_eq_take_drop_succ, take_append_of_le_length, drop_append_of_le_length, - eraseIdx_eq_take_drop_succ, append_assoc] - all_goals omega - -theorem eraseIdx_append_of_length_le {l : List α} {k : Nat} (hk : length l ≤ k) (l' : List α) : - eraseIdx (l ++ l') k = l ++ eraseIdx l' (k - length l) := by - rw [eraseIdx_eq_take_drop_succ, eraseIdx_eq_take_drop_succ, - take_append_eq_append_take, drop_append_eq_append_drop, - take_all_of_le hk, drop_eq_nil_of_le (by omega), nil_append, append_assoc] - congr - omega - -protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) : - eraseIdx l k <+: eraseIdx l' k := by - rcases h with ⟨t, rfl⟩ - if hkl : k < length l then - simp [eraseIdx_append_of_lt_length hkl] - else - rw [Nat.not_lt] at hkl - simp [eraseIdx_append_of_length_le hkl, eraseIdx_of_length_le hkl] - -theorem mem_eraseIdx_iff_getElem {x : α} : - ∀ {l} {k}, x ∈ eraseIdx l k ↔ ∃ i : Fin l.length, ↑i ≠ k ∧ l[i.1] = x - | [], _ => by - simp only [eraseIdx, Fin.exists_iff, not_mem_nil, false_iff] - rintro ⟨i, h, -⟩ - exact Nat.not_lt_zero _ h - | a::l, 0 => by simp [Fin.exists_fin_succ, mem_iff_get] - | a::l, k+1 => by - simp [Fin.exists_fin_succ, mem_eraseIdx_iff_getElem, @eq_comm _ a, k.succ_ne_zero.symm] - @[deprecated mem_eraseIdx_iff_getElem (since := "2024-06-12")] theorem mem_eraseIdx_iff_get {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i : Fin l.length, ↑i ≠ k ∧ l.get i = x := by - simp [mem_eraseIdx_iff_getElem] - -theorem mem_eraseIdx_iff_getElem? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i ≠ k, l[i]? = some x := by - simp only [mem_eraseIdx_iff_getElem, getElem_eq_iff, Fin.exists_iff, exists_and_left] - refine exists_congr fun i => and_congr_right' ?_ + simp only [mem_eraseIdx_iff_getElem, ne_eq, exists_and_left, get_eq_getElem] constructor - · rintro ⟨_, h⟩; exact h - · rintro h; - obtain ⟨h', -⟩ := getElem?_eq_some.1 h - exact ⟨h', h⟩ + · rintro ⟨i, h, w, rfl⟩ + exact ⟨⟨i, w⟩, h, rfl⟩ + · rintro ⟨i, h, rfl⟩ + exact ⟨i.1, h, i.2, rfl⟩ @[deprecated mem_eraseIdx_iff_getElem? (since := "2024-06-12")] theorem mem_eraseIdx_iff_get? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i ≠ k, l.get? i = x := by diff --git a/Batteries/Data/List/Init/Attach.lean b/Batteries/Data/List/Init/Attach.lean deleted file mode 100644 index d2b2bf0990..0000000000 --- a/Batteries/Data/List/Init/Attach.lean +++ /dev/null @@ -1,44 +0,0 @@ -/- -Copyright (c) 2023 Mario Carneiro. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mario Carneiro --/ - -namespace List - -/-- `O(n)`. Partial map. If `f : Π a, P a → β` is a partial function defined on - `a : α` satisfying `P`, then `pmap f l h` is essentially the same as `map f l` - but is defined only when all members of `l` satisfy `P`, using the proof - to apply `f`. -/ -@[simp] def pmap {P : α → Prop} (f : ∀ a, P a → β) : ∀ l : List α, (H : ∀ a ∈ l, P a) → List β - | [], _ => [] - | a :: l, H => f a (forall_mem_cons.1 H).1 :: pmap f l (forall_mem_cons.1 H).2 - -/-- -Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of -`List {x // P x}` is the same as the input `List α`. -(Someday, the compiler might do this optimization automatically, but until then...) --/ -@[inline] private unsafe def attachWithImpl - (l : List α) (P : α → Prop) (_ : ∀ x ∈ l, P x) : List {x // P x} := unsafeCast l - -/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `l` to produce a new list - with the same elements but in the type `{x // P x}`. -/ -@[implemented_by attachWithImpl] def attachWith - (l : List α) (P : α → Prop) (H : ∀ x ∈ l, P x) : List {x // P x} := pmap Subtype.mk l H - -/-- `O(1)`. "Attach" the proof that the elements of `l` are in `l` to produce a new list - with the same elements but in the type `{x // x ∈ l}`. -/ -@[inline] def attach (l : List α) : List {x // x ∈ l} := attachWith l _ fun _ => id - -/-- Implementation of `pmap` using the zero-copy version of `attach`. -/ -@[inline] private def pmapImpl {P : α → Prop} (f : ∀ a, P a → β) (l : List α) (H : ∀ a ∈ l, P a) : - List β := (l.attachWith _ H).map fun ⟨x, h'⟩ => f x h' - -@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by - funext α β p f L h' - let rec go : ∀ L' (hL' : ∀ ⦃x⦄, x ∈ L' → p x), - pmap f L' hL' = map (fun ⟨x, hx⟩ => f x hx) (pmap Subtype.mk L' hL') - | nil, hL' => rfl - | cons _ L', hL' => congrArg _ <| go L' fun _ hx => hL' (.tail _ hx) - exact go L h' diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 533a140f45..2e97cb5264 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -17,225 +17,6 @@ open Nat @[simp] theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l := by simp [Array.mem_def] -/-! ### drop -/ - -@[simp] -theorem drop_one : ∀ l : List α, drop 1 l = tail l - | [] | _ :: _ => rfl - -/-! ### zipWith -/ - -theorem zipWith_distrib_tail : (zipWith f l l').tail = zipWith f l.tail l'.tail := by - rw [← drop_one]; simp [zipWith_distrib_drop] - -/-! ### List subset -/ - -theorem subset_def {l₁ l₂ : List α} : l₁ ⊆ l₂ ↔ ∀ {a : α}, a ∈ l₁ → a ∈ l₂ := .rfl - -@[simp] theorem nil_subset (l : List α) : [] ⊆ l := nofun - -@[simp] theorem Subset.refl (l : List α) : l ⊆ l := fun _ i => i - -theorem Subset.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ ⊆ l₂) (h₂ : l₂ ⊆ l₃) : l₁ ⊆ l₃ := - fun _ i => h₂ (h₁ i) - -instance : Trans (Membership.mem : α → List α → Prop) Subset Membership.mem := - ⟨fun h₁ h₂ => h₂ h₁⟩ - -instance : Trans (Subset : List α → List α → Prop) Subset Subset := - ⟨Subset.trans⟩ - -@[simp] theorem subset_cons (a : α) (l : List α) : l ⊆ a :: l := fun _ => Mem.tail _ - -theorem subset_of_cons_subset {a : α} {l₁ l₂ : List α} : a :: l₁ ⊆ l₂ → l₁ ⊆ l₂ := - fun s _ i => s (mem_cons_of_mem _ i) - -theorem subset_cons_of_subset (a : α) {l₁ l₂ : List α} : l₁ ⊆ l₂ → l₁ ⊆ a :: l₂ := - fun s _ i => .tail _ (s i) - -theorem cons_subset_cons {l₁ l₂ : List α} (a : α) (s : l₁ ⊆ l₂) : a :: l₁ ⊆ a :: l₂ := - fun _ => by simp only [mem_cons]; exact Or.imp_right (@s _) - -@[simp] theorem subset_append_left (l₁ l₂ : List α) : l₁ ⊆ l₁ ++ l₂ := fun _ => mem_append_left _ - -@[simp] theorem subset_append_right (l₁ l₂ : List α) : l₂ ⊆ l₁ ++ l₂ := fun _ => mem_append_right _ - -theorem subset_append_of_subset_left (l₂ : List α) : l ⊆ l₁ → l ⊆ l₁ ++ l₂ := -fun s => Subset.trans s <| subset_append_left _ _ - -theorem subset_append_of_subset_right (l₁ : List α) : l ⊆ l₂ → l ⊆ l₁ ++ l₂ := -fun s => Subset.trans s <| subset_append_right _ _ - -@[simp] theorem cons_subset : a :: l ⊆ m ↔ a ∈ m ∧ l ⊆ m := by - simp only [subset_def, mem_cons, or_imp, forall_and, forall_eq] - -@[simp] theorem append_subset {l₁ l₂ l : List α} : - l₁ ++ l₂ ⊆ l ↔ l₁ ⊆ l ∧ l₂ ⊆ l := by simp [subset_def, or_imp, forall_and] - -theorem subset_nil {l : List α} : l ⊆ [] ↔ l = [] := - ⟨fun h => match l with | [] => rfl | _::_ => (nomatch h (.head ..)), fun | rfl => Subset.refl _⟩ - -theorem map_subset {l₁ l₂ : List α} (f : α → β) (H : l₁ ⊆ l₂) : map f l₁ ⊆ map f l₂ := - fun x => by simp only [mem_map]; exact .imp fun a => .imp_left (@H _) - -/-! ### sublists -/ - -@[simp] theorem nil_sublist : ∀ l : List α, [] <+ l - | [] => .slnil - | a :: l => (nil_sublist l).cons a - -@[simp] theorem Sublist.refl : ∀ l : List α, l <+ l - | [] => .slnil - | a :: l => (Sublist.refl l).cons₂ a - -theorem Sublist.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ <+ l₂) (h₂ : l₂ <+ l₃) : l₁ <+ l₃ := by - induction h₂ generalizing l₁ with - | slnil => exact h₁ - | cons _ _ IH => exact (IH h₁).cons _ - | @cons₂ l₂ _ a _ IH => - generalize e : a :: l₂ = l₂' - match e ▸ h₁ with - | .slnil => apply nil_sublist - | .cons a' h₁' => cases e; apply (IH h₁').cons - | .cons₂ a' h₁' => cases e; apply (IH h₁').cons₂ - -instance : Trans (@Sublist α) Sublist Sublist := ⟨Sublist.trans⟩ - -@[simp] theorem sublist_cons (a : α) (l : List α) : l <+ a :: l := (Sublist.refl l).cons _ - -theorem sublist_of_cons_sublist : a :: l₁ <+ l₂ → l₁ <+ l₂ := - (sublist_cons a l₁).trans - -@[simp] theorem sublist_append_left : ∀ l₁ l₂ : List α, l₁ <+ l₁ ++ l₂ - | [], _ => nil_sublist _ - | _ :: l₁, l₂ => (sublist_append_left l₁ l₂).cons₂ _ - -@[simp] theorem sublist_append_right : ∀ l₁ l₂ : List α, l₂ <+ l₁ ++ l₂ - | [], _ => Sublist.refl _ - | _ :: l₁, l₂ => (sublist_append_right l₁ l₂).cons _ - -theorem sublist_append_of_sublist_left (s : l <+ l₁) : l <+ l₁ ++ l₂ := - s.trans <| sublist_append_left .. - -theorem sublist_append_of_sublist_right (s : l <+ l₂) : l <+ l₁ ++ l₂ := - s.trans <| sublist_append_right .. - -@[simp] -theorem cons_sublist_cons : a :: l₁ <+ a :: l₂ ↔ l₁ <+ l₂ := - ⟨fun | .cons _ s => sublist_of_cons_sublist s | .cons₂ _ s => s, .cons₂ _⟩ - -@[simp] theorem append_sublist_append_left : ∀ l, l ++ l₁ <+ l ++ l₂ ↔ l₁ <+ l₂ - | [] => Iff.rfl - | _ :: l => cons_sublist_cons.trans (append_sublist_append_left l) - -theorem Sublist.append_left : l₁ <+ l₂ → ∀ l, l ++ l₁ <+ l ++ l₂ := - fun h l => (append_sublist_append_left l).mpr h - -theorem Sublist.append_right : l₁ <+ l₂ → ∀ l, l₁ ++ l <+ l₂ ++ l - | .slnil, _ => Sublist.refl _ - | .cons _ h, _ => (h.append_right _).cons _ - | .cons₂ _ h, _ => (h.append_right _).cons₂ _ - -theorem sublist_or_mem_of_sublist (h : l <+ l₁ ++ a :: l₂) : l <+ l₁ ++ l₂ ∨ a ∈ l := by - induction l₁ generalizing l with - | nil => match h with - | .cons _ h => exact .inl h - | .cons₂ _ h => exact .inr (.head ..) - | cons b l₁ IH => - match h with - | .cons _ h => exact (IH h).imp_left (Sublist.cons _) - | .cons₂ _ h => exact (IH h).imp (Sublist.cons₂ _) (.tail _) - -theorem Sublist.reverse : l₁ <+ l₂ → l₁.reverse <+ l₂.reverse - | .slnil => Sublist.refl _ - | .cons _ h => by rw [reverse_cons]; exact sublist_append_of_sublist_left h.reverse - | .cons₂ _ h => by rw [reverse_cons, reverse_cons]; exact h.reverse.append_right _ - -@[simp] theorem reverse_sublist : l₁.reverse <+ l₂.reverse ↔ l₁ <+ l₂ := - ⟨fun h => l₁.reverse_reverse ▸ l₂.reverse_reverse ▸ h.reverse, Sublist.reverse⟩ - -@[simp] theorem append_sublist_append_right (l) : l₁ ++ l <+ l₂ ++ l ↔ l₁ <+ l₂ := - ⟨fun h => by - have := h.reverse - simp only [reverse_append, append_sublist_append_left, reverse_sublist] at this - exact this, - fun h => h.append_right l⟩ - -theorem Sublist.append (hl : l₁ <+ l₂) (hr : r₁ <+ r₂) : l₁ ++ r₁ <+ l₂ ++ r₂ := - (hl.append_right _).trans ((append_sublist_append_left _).2 hr) - -theorem Sublist.subset : l₁ <+ l₂ → l₁ ⊆ l₂ - | .slnil, _, h => h - | .cons _ s, _, h => .tail _ (s.subset h) - | .cons₂ .., _, .head .. => .head .. - | .cons₂ _ s, _, .tail _ h => .tail _ (s.subset h) - -instance : Trans (@Sublist α) Subset Subset := - ⟨fun h₁ h₂ => trans h₁.subset h₂⟩ - -instance : Trans Subset (@Sublist α) Subset := - ⟨fun h₁ h₂ => trans h₁ h₂.subset⟩ - -instance : Trans (Membership.mem : α → List α → Prop) Sublist Membership.mem := - ⟨fun h₁ h₂ => h₂.subset h₁⟩ - -theorem Sublist.length_le : l₁ <+ l₂ → length l₁ ≤ length l₂ - | .slnil => Nat.le_refl 0 - | .cons _l s => le_succ_of_le (length_le s) - | .cons₂ _ s => succ_le_succ (length_le s) - -@[simp] theorem sublist_nil {l : List α} : l <+ [] ↔ l = [] := - ⟨fun s => subset_nil.1 s.subset, fun H => H ▸ Sublist.refl _⟩ - -theorem Sublist.eq_of_length : l₁ <+ l₂ → length l₁ = length l₂ → l₁ = l₂ - | .slnil, _ => rfl - | .cons a s, h => nomatch Nat.not_lt.2 s.length_le (h ▸ lt_succ_self _) - | .cons₂ a s, h => by rw [s.eq_of_length (succ.inj h)] - -theorem Sublist.eq_of_length_le (s : l₁ <+ l₂) (h : length l₂ ≤ length l₁) : l₁ = l₂ := - s.eq_of_length <| Nat.le_antisymm s.length_le h - -@[simp] theorem singleton_sublist {a : α} {l} : [a] <+ l ↔ a ∈ l := by - refine ⟨fun h => h.subset (mem_singleton_self _), fun h => ?_⟩ - obtain ⟨_, _, rfl⟩ := append_of_mem h - exact ((nil_sublist _).cons₂ _).trans (sublist_append_right ..) - -@[simp] theorem replicate_sublist_replicate {m n} (a : α) : - replicate m a <+ replicate n a ↔ m ≤ n := by - refine ⟨fun h => ?_, fun h => ?_⟩ - · have := h.length_le; simp only [length_replicate] at this ⊢; exact this - · induction h with - | refl => apply Sublist.refl - | step => simp [*, replicate, Sublist.cons] - -theorem isSublist_iff_sublist [BEq α] [LawfulBEq α] {l₁ l₂ : List α} : - l₁.isSublist l₂ ↔ l₁ <+ l₂ := by - cases l₁ <;> cases l₂ <;> simp [isSublist] - case cons.cons hd₁ tl₁ hd₂ tl₂ => - if h_eq : hd₁ = hd₂ then - simp [h_eq, cons_sublist_cons, isSublist_iff_sublist] - else - simp only [beq_iff_eq, h_eq] - constructor - · intro h_sub - apply Sublist.cons - exact isSublist_iff_sublist.mp h_sub - · intro h_sub - cases h_sub - case cons h_sub => - exact isSublist_iff_sublist.mpr h_sub - case cons₂ => - contradiction - -instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+ l₂) := - decidable_of_iff (l₁.isSublist l₂) isSublist_iff_sublist - -/-! ### tail -/ - -theorem tail_eq_tailD (l) : @tail α l = tailD l [] := by cases l <;> rfl - -theorem tail_eq_tail? (l) : @tail α l = (tail? l).getD [] := by simp [tail_eq_tailD] - /-! ### next? -/ @[simp] theorem next?_nil : @next? α [] = none := rfl @@ -243,51 +24,16 @@ theorem tail_eq_tail? (l) : @tail α l = (tail? l).getD [] := by simp [tail_eq_t /-! ### get? -/ -theorem getElem_eq_iff {l : List α} {n : Nat} {h : n < l.length} : l[n] = x ↔ l[n]? = some x := by - simp only [get_eq_getElem, get?_eq_getElem?, getElem?_eq_some] - exact ⟨fun w => ⟨h, w⟩, fun h => h.2⟩ - @[deprecated getElem_eq_iff (since := "2024-06-12")] theorem get_eq_iff : List.get l n = x ↔ l.get? n.1 = some x := by simp -theorem getElem?_inj - (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs[i]? = xs[j]?) : i = j := by - induction xs generalizing i j with - | nil => cases h₀ - | cons x xs ih => - match i, j with - | 0, 0 => rfl - | i+1, j+1 => simp; cases h₁ with - | cons ha h₁ => - simp only [getElem?_cons_succ] at h₂ - exact ih (Nat.lt_of_succ_lt_succ h₀) h₁ h₂ - | i+1, 0 => ?_ - | 0, j+1 => ?_ - all_goals - simp only [get?_eq_getElem?, getElem?_cons_zero, getElem?_cons_succ] at h₂ - cases h₁; rename_i h' h - have := h x ?_ rfl; cases this - rw [mem_iff_get?] - simp only [get?_eq_getElem?] - exact ⟨_, h₂⟩; exact ⟨_ , h₂.symm⟩ - @[deprecated getElem?_inj (since := "2024-06-12")] theorem get?_inj (h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs.get? i = xs.get? j) : i = j := by apply getElem?_inj h₀ h₁ simp_all -/-! ### drop -/ - -theorem tail_drop (l : List α) (n : Nat) : (l.drop n).tail = l.drop (n + 1) := by - induction l generalizing n with - | nil => simp - | cons hd tl hl => - cases n - · simp - · simp [hl] - /-! ### modifyNth -/ @[simp] theorem modifyNth_nil (f : α → α) (n) : [].modifyNth f n = [] := by cases n <;> rfl @@ -405,18 +151,13 @@ theorem modifyNth_eq_set_get (f : α → α) {n} {l : List α} (h) : l.modifyNth f n = l.set n (f (l.get ⟨n, h⟩)) := by rw [modifyNth_eq_set_get?, get?_eq_get h]; rfl -theorem exists_of_set {l : List α} (h : n < l.length) : +-- The naming of `exists_of_set'` and `exists_of_set` have been swapped. +-- If no one complains, we will remove this version later. +@[deprecated exists_of_set (since := "2024-07-04")] +theorem exists_of_set' {l : List α} (h : n < l.length) : ∃ l₁ a l₂, l = l₁ ++ a :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := by rw [set_eq_modifyNth]; exact exists_of_modifyNth _ h -theorem exists_of_set' {l : List α} (h : n < l.length) : - ∃ l₁ l₂, l = l₁ ++ l[n] :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := - have ⟨_, _, _, h₁, h₂, h₃⟩ := exists_of_set h; ⟨_, _, getElem_of_append h₁ h₂ ▸ h₁, h₂, h₃⟩ - -@[simp] -theorem getElem?_set_eq' (a : α) (n) (l : List α) : (set l n a)[n]? = (fun _ => a) <$> l[n]? := by - simp only [set_eq_modifyNth, getElem?_modifyNth_eq] - @[deprecated getElem?_set_eq' (since := "2024-06-12")] theorem get?_set_eq (a : α) (n) (l : List α) : (set l n a).get? n = (fun _ => a) <$> l.get? n := by simp @@ -433,10 +174,6 @@ theorem get?_set_eq_of_lt (a : α) {n} {l : List α} (h : n < length l) : theorem get?_set_ne (a : α) {m n} (l : List α) (h : m ≠ n) : (set l m a).get? n = l.get? n := by simp [h] -theorem getElem?_set' (a : α) {m n} (l : List α) : - (set l m a)[n]? = if m = n then (fun _ => a) <$> l[n]? else l[n]? := by - by_cases m = n <;> simp [*] - @[deprecated getElem?_set (since := "2024-06-12")] 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 @@ -450,123 +187,10 @@ 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 [getElem?_set]; split <;> subst_vars <;> simp [*, getElem?_eq_getElem h] -theorem drop_set_of_lt (a : α) {n m : Nat} (l : List α) (h : n < m) : - (l.set n a).drop m = l.drop m := - List.ext_getElem? fun i => by rw [getElem?_drop, getElem?_drop, getElem?_set_ne (by omega)] - -theorem take_set_of_lt (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_eq_if, getElem?_take_eq_if] - split - · next h' => rw [getElem?_set_ne (by omega)] - · rfl - -/-! ### removeNth -/ - -theorem length_eraseIdx : ∀ {l i}, i < length l → length (@eraseIdx α l i) = length l - 1 - | [], _, _ => rfl - | _::_, 0, _ => by simp [eraseIdx] - | x::xs, i+1, h => by - have : i < length xs := Nat.lt_of_succ_lt_succ h - simp [eraseIdx, ← Nat.add_one] - rw [length_eraseIdx this, Nat.sub_add_cancel (Nat.lt_of_le_of_lt (Nat.zero_le _) this)] - @[deprecated (since := "2024-05-06")] alias length_removeNth := length_eraseIdx -/-! ### tail -/ - -@[simp] theorem length_tail (l : List α) : length (tail l) = length l - 1 := by cases l <;> rfl - /-! ### eraseP -/ -@[simp] theorem eraseP_nil : [].eraseP p = [] := rfl - -theorem eraseP_cons (a : α) (l : List α) : - (a :: l).eraseP p = bif p a then l else a :: l.eraseP p := rfl - -@[simp] theorem eraseP_cons_of_pos {l : List α} (p) (h : p a) : (a :: l).eraseP p = l := by - simp [eraseP_cons, h] - -@[simp] theorem eraseP_cons_of_neg {l : List α} (p) (h : ¬p a) : - (a :: l).eraseP p = a :: l.eraseP p := by simp [eraseP_cons, h] - -theorem eraseP_of_forall_not {l : List α} (h : ∀ a, a ∈ l → ¬p a) : l.eraseP p = l := by - induction l with - | nil => rfl - | cons _ _ ih => simp [h _ (.head ..), ih (forall_mem_cons.1 h).2] - -theorem exists_of_eraseP : ∀ {l : List α} {a} (al : a ∈ l) (pa : p a), - ∃ a l₁ l₂, (∀ b ∈ l₁, ¬p b) ∧ p a ∧ l = l₁ ++ a :: l₂ ∧ l.eraseP p = l₁ ++ l₂ - | b :: l, a, al, pa => - if pb : p b then - ⟨b, [], l, forall_mem_nil _, pb, by simp [pb]⟩ - else - match al with - | .head .. => nomatch pb pa - | .tail _ al => - let ⟨c, l₁, l₂, h₁, h₂, h₃, h₄⟩ := exists_of_eraseP al pa - ⟨c, b::l₁, l₂, (forall_mem_cons ..).2 ⟨pb, h₁⟩, - h₂, by rw [h₃, cons_append], by simp [pb, h₄]⟩ - -theorem exists_or_eq_self_of_eraseP (p) (l : List α) : - l.eraseP p = l ∨ - ∃ a l₁ l₂, (∀ b ∈ l₁, ¬p b) ∧ p a ∧ l = l₁ ++ a :: l₂ ∧ l.eraseP p = l₁ ++ l₂ := - if h : ∃ a ∈ l, p a then - let ⟨_, ha, pa⟩ := h - .inr (exists_of_eraseP ha pa) - else - .inl (eraseP_of_forall_not (h ⟨·, ·, ·⟩)) - -@[simp] theorem length_eraseP_of_mem (al : a ∈ l) (pa : p a) : - length (l.eraseP p) = Nat.pred (length l) := by - let ⟨_, l₁, l₂, _, _, e₁, e₂⟩ := exists_of_eraseP al pa - rw [e₂]; simp [length_append, e₁]; rfl - -theorem eraseP_append_left {a : α} (pa : p a) : - ∀ {l₁ : List α} l₂, a ∈ l₁ → (l₁++l₂).eraseP p = l₁.eraseP p ++ l₂ - | x :: xs, l₂, h => by - by_cases h' : p x <;> simp [h'] - rw [eraseP_append_left pa l₂ ((mem_cons.1 h).resolve_left (mt _ h'))] - intro | rfl => exact pa - -theorem eraseP_append_right : - ∀ {l₁ : List α} l₂, (∀ b ∈ l₁, ¬p b) → eraseP p (l₁++l₂) = l₁ ++ l₂.eraseP p - | [], l₂, _ => rfl - | x :: xs, l₂, h => by - simp [(forall_mem_cons.1 h).1, eraseP_append_right _ (forall_mem_cons.1 h).2] - -theorem eraseP_sublist (l : List α) : l.eraseP p <+ l := by - match exists_or_eq_self_of_eraseP p l with - | .inl h => rw [h]; apply Sublist.refl - | .inr ⟨c, l₁, l₂, _, _, h₃, h₄⟩ => rw [h₄, h₃]; simp - -theorem eraseP_subset (l : List α) : l.eraseP p ⊆ l := (eraseP_sublist l).subset - -protected theorem Sublist.eraseP : l₁ <+ l₂ → l₁.eraseP p <+ l₂.eraseP p - | .slnil => Sublist.refl _ - | .cons a s => by - by_cases h : p a <;> simp [h] - exacts [s.eraseP.trans (eraseP_sublist _), s.eraseP.cons _] - | .cons₂ a s => by - by_cases h : p a <;> simp [h] - exacts [s, s.eraseP] - -theorem mem_of_mem_eraseP {l : List α} : a ∈ l.eraseP p → a ∈ l := (eraseP_subset _ ·) - -@[simp] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a ∈ l.eraseP p ↔ a ∈ l := by - refine ⟨mem_of_mem_eraseP, fun al => ?_⟩ - match exists_or_eq_self_of_eraseP p l with - | .inl h => rw [h]; assumption - | .inr ⟨c, l₁, l₂, h₁, h₂, h₃, h₄⟩ => - rw [h₄]; rw [h₃] at al - have : a ≠ c := fun h => (h ▸ pa).elim h₂ - simp [this] at al; simp [al] - -theorem eraseP_map (f : β → α) : ∀ (l : List β), (map f l).eraseP p = map f (l.eraseP (p ∘ f)) - | [] => rfl - | b::l => by by_cases h : p (f b) <;> simp [h, eraseP_map f l, eraseP_cons_of_pos] - @[simp] theorem extractP_eq_find?_eraseP (l : List α) : extractP p l = (find? p l, eraseP p l) := by let rec go (acc) : ∀ xs, l = acc.data ++ xs → @@ -579,216 +203,8 @@ theorem eraseP_map (f : β → α) : ∀ (l : List β), (map f l).eraseP p = map /-! ### erase -/ -section erase -variable [BEq α] - -theorem erase_eq_eraseP' (a : α) (l : List α) : l.erase a = l.eraseP (· == a) := by - induction l - · simp - · next b t ih => - rw [erase_cons, eraseP_cons, ih] - if h : b == a then simp [h] else simp [h] - -theorem erase_eq_eraseP [LawfulBEq α] (a : α) : ∀ l : List α, l.erase a = l.eraseP (a == ·) - | [] => rfl - | b :: l => by - if h : a = b then simp [h] else simp [h, Ne.symm h, erase_eq_eraseP a l] - -theorem exists_erase_eq [LawfulBEq α] {a : α} {l : List α} (h : a ∈ l) : - ∃ l₁ l₂, a ∉ l₁ ∧ l = l₁ ++ a :: l₂ ∧ l.erase a = l₁ ++ l₂ := by - let ⟨_, l₁, l₂, h₁, e, h₂, h₃⟩ := exists_of_eraseP h (beq_self_eq_true _) - rw [erase_eq_eraseP]; exact ⟨l₁, l₂, fun h => h₁ _ h (beq_self_eq_true _), eq_of_beq e ▸ h₂, h₃⟩ - -@[simp] theorem length_erase_of_mem [LawfulBEq α] {a : α} {l : List α} (h : a ∈ l) : - length (l.erase a) = Nat.pred (length l) := by - rw [erase_eq_eraseP]; exact length_eraseP_of_mem h (beq_self_eq_true a) - -theorem erase_append_left [LawfulBEq α] {l₁ : List α} (l₂) (h : a ∈ l₁) : - (l₁ ++ l₂).erase a = l₁.erase a ++ l₂ := by - simp [erase_eq_eraseP]; exact eraseP_append_left (beq_self_eq_true a) l₂ h - -theorem erase_append_right [LawfulBEq α] {a : α} {l₁ : List α} (l₂ : List α) (h : a ∉ l₁) : - (l₁ ++ l₂).erase a = (l₁ ++ l₂.erase a) := by - rw [erase_eq_eraseP, erase_eq_eraseP, eraseP_append_right] - intros b h' h''; rw [eq_of_beq h''] at h; exact h h' - -theorem erase_sublist (a : α) (l : List α) : l.erase a <+ l := - erase_eq_eraseP' a l ▸ eraseP_sublist l - -theorem erase_subset (a : α) (l : List α) : l.erase a ⊆ l := (erase_sublist a l).subset - -theorem Sublist.erase (a : α) {l₁ l₂ : List α} (h : l₁ <+ l₂) : l₁.erase a <+ l₂.erase a := by - simp only [erase_eq_eraseP']; exact h.eraseP @[deprecated (since := "2024-04-22")] alias sublist.erase := Sublist.erase -theorem mem_of_mem_erase {a b : α} {l : List α} (h : a ∈ l.erase b) : a ∈ l := erase_subset _ _ h - -@[simp] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a ≠ b) : - a ∈ l.erase b ↔ a ∈ l := - erase_eq_eraseP b l ▸ mem_eraseP_of_neg (mt eq_of_beq ab.symm) - -theorem erase_comm [LawfulBEq α] (a b : α) (l : List α) : - (l.erase a).erase b = (l.erase b).erase a := by - if ab : a == b then rw [eq_of_beq ab] else ?_ - if ha : a ∈ l then ?_ else - simp only [erase_of_not_mem ha, erase_of_not_mem (mt mem_of_mem_erase ha)] - if hb : b ∈ l then ?_ else - simp only [erase_of_not_mem hb, erase_of_not_mem (mt mem_of_mem_erase hb)] - match l, l.erase a, exists_erase_eq ha with - | _, _, ⟨l₁, l₂, ha', rfl, rfl⟩ => - if h₁ : b ∈ l₁ then - rw [erase_append_left _ h₁, erase_append_left _ h₁, - erase_append_right _ (mt mem_of_mem_erase ha'), erase_cons_head] - else - rw [erase_append_right _ h₁, erase_append_right _ h₁, erase_append_right _ ha', - erase_cons_tail _ ab, erase_cons_head] - -end erase - -/-! ### filter and partition -/ - -@[simp] theorem filter_sublist {p : α → Bool} : ∀ (l : List α), filter p l <+ l - | [] => .slnil - | a :: l => by rw [filter]; split <;> simp [Sublist.cons, Sublist.cons₂, filter_sublist l] - -/-! ### filterMap -/ - -protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) : - filterMap f l₁ <+ filterMap f l₂ := by - induction s <;> simp [filterMap_cons] <;> split <;> simp [*, cons, cons₂] - -theorem Sublist.filter (p : α → Bool) {l₁ l₂} (s : l₁ <+ l₂) : filter p l₁ <+ filter p l₂ := by - rw [← filterMap_eq_filter]; apply s.filterMap - -/-! ### findIdx -/ - -@[simp] theorem findIdx_nil {α : Type _} (p : α → Bool) : [].findIdx p = 0 := rfl - -theorem findIdx_cons (p : α → Bool) (b : α) (l : List α) : - (b :: l).findIdx p = bif p b then 0 else (l.findIdx p) + 1 := by - cases H : p b with - | true => simp [H, findIdx, findIdx.go] - | false => simp [H, findIdx, findIdx.go, findIdx_go_succ] -where - findIdx_go_succ (p : α → Bool) (l : List α) (n : Nat) : - List.findIdx.go p l (n + 1) = (findIdx.go p l n) + 1 := by - cases l with - | nil => unfold findIdx.go; exact Nat.succ_eq_add_one n - | cons head tail => - unfold findIdx.go - cases p head <;> simp only [cond_false, cond_true] - exact findIdx_go_succ p tail (n + 1) - -theorem findIdx_of_get?_eq_some {xs : List α} (w : xs.get? (xs.findIdx p) = some y) : p y := by - induction xs with - | nil => simp_all - | cons x xs ih => by_cases h : p x <;> simp_all [findIdx_cons] - -theorem findIdx_get {xs : List α} {w : xs.findIdx p < xs.length} : - p (xs.get ⟨xs.findIdx p, w⟩) := - xs.findIdx_of_get?_eq_some (get?_eq_get w) - -theorem findIdx_lt_length_of_exists {xs : List α} (h : ∃ x ∈ xs, p x) : - xs.findIdx p < xs.length := by - induction xs with - | nil => simp_all - | cons x xs ih => - by_cases p x - · simp_all only [forall_exists_index, and_imp, mem_cons, exists_eq_or_imp, true_or, - findIdx_cons, cond_true, length_cons] - apply Nat.succ_pos - · simp_all [findIdx_cons] - refine Nat.succ_lt_succ ?_ - obtain ⟨x', m', h'⟩ := h - exact ih x' m' h' - -theorem findIdx_get?_eq_get_of_exists {xs : List α} (h : ∃ x ∈ xs, p x) : - xs.get? (xs.findIdx p) = some (xs.get ⟨xs.findIdx p, xs.findIdx_lt_length_of_exists h⟩) := - get?_eq_get (findIdx_lt_length_of_exists h) - - /-! ### findIdx? -/ - -@[simp] theorem findIdx?_nil : ([] : List α).findIdx? p i = none := rfl - -@[simp] theorem findIdx?_cons : - (x :: xs).findIdx? p i = if p x then some i else findIdx? p xs (i + 1) := rfl - -@[simp] theorem findIdx?_succ : - (xs : List α).findIdx? p (i+1) = (xs.findIdx? p i).map fun i => i + 1 := by - induction xs generalizing i with simp - | cons _ _ _ => split <;> simp_all - -theorem findIdx?_eq_some_iff (xs : List α) (p : α → Bool) : - xs.findIdx? p = some i ↔ (xs.take (i + 1)).map p = replicate i false ++ [true] := by - induction xs generalizing i with - | nil => simp - | cons x xs ih => - simp only [findIdx?_cons, Nat.zero_add, findIdx?_succ, take_succ_cons, map_cons] - split <;> cases i <;> simp_all [replicate_succ] - -theorem findIdx?_of_eq_some {xs : List α} {p : α → Bool} (w : xs.findIdx? p = some i) : - match xs.get? i with | some a => p a | none => false := by - induction xs generalizing i with - | nil => simp_all - | cons x xs ih => - simp_all only [findIdx?_cons, Nat.zero_add, findIdx?_succ] - split at w <;> cases i <;> simp_all - -theorem findIdx?_of_eq_none {xs : List α} {p : α → Bool} (w : xs.findIdx? p = none) : - ∀ i, match xs.get? i with | some a => ¬ p a | none => true := by - intro i - induction xs generalizing i with - | nil => simp_all - | cons x xs ih => - simp_all only [Bool.not_eq_true, findIdx?_cons, Nat.zero_add, findIdx?_succ] - cases i with - | zero => - split at w <;> simp_all - | succ i => - simp only [get?_cons_succ] - apply ih - split at w <;> simp_all - -@[simp] theorem findIdx?_append : - (xs ++ ys : List α).findIdx? p = - (xs.findIdx? p <|> (ys.findIdx? p).map fun i => i + xs.length) := by - induction xs with simp - | cons _ _ _ => split <;> simp_all [Option.map_orElse, Option.map_map]; rfl - -@[simp] theorem findIdx?_replicate : - (replicate n a).findIdx? p = if 0 < n ∧ p a then some 0 else none := by - induction n with - | zero => simp - | succ n ih => - simp only [replicate, findIdx?_cons, Nat.zero_add, findIdx?_succ, Nat.zero_lt_succ, true_and] - split <;> simp_all - -/-! ### pairwise -/ - -theorem Pairwise.sublist : l₁ <+ l₂ → l₂.Pairwise R → l₁.Pairwise R - | .slnil, h => h - | .cons _ s, .cons _ h₂ => h₂.sublist s - | .cons₂ _ s, .cons h₁ h₂ => (h₂.sublist s).cons fun _ h => h₁ _ (s.subset h) - -theorem pairwise_map {l : List α} : - (l.map f).Pairwise R ↔ l.Pairwise fun a b => R (f a) (f b) := by - induction l - · simp - · simp only [map, pairwise_cons, forall_mem_map_iff, *] - -theorem pairwise_append {l₁ l₂ : List α} : - (l₁ ++ l₂).Pairwise R ↔ l₁.Pairwise R ∧ l₂.Pairwise R ∧ ∀ a ∈ l₁, ∀ b ∈ l₂, R a b := by - induction l₁ <;> simp [*, or_imp, forall_and, and_assoc, and_left_comm] - -theorem pairwise_reverse {l : List α} : - l.reverse.Pairwise R ↔ l.Pairwise (fun a b => R b a) := by - induction l <;> simp [*, pairwise_append, and_comm] - -theorem Pairwise.imp {α R S} (H : ∀ {a b}, R a b → S a b) : - ∀ {l : List α}, l.Pairwise R → l.Pairwise S - | _, .nil => .nil - | _, .cons h₁ h₂ => .cons (H ∘ h₁ ·) (h₂.imp H) - /-! ### replaceF -/ theorem replaceF_nil : [].replaceF p = [] := rfl @@ -857,10 +273,10 @@ theorem disjoint_of_subset_right (ss : l₂ ⊆ l) (d : Disjoint l₁ l) : Disjo fun _ m m₁ => d m (ss m₁) theorem disjoint_of_disjoint_cons_left {l₁ l₂} : Disjoint (a :: l₁) l₂ → Disjoint l₁ l₂ := -disjoint_of_subset_left (subset_cons _ _) + disjoint_of_subset_left (subset_cons_self _ _) theorem disjoint_of_disjoint_cons_right {l₁ l₂} : Disjoint l₁ (a :: l₂) → Disjoint l₁ l₂ := -disjoint_of_subset_right (subset_cons _ _) + disjoint_of_subset_right (subset_cons_self _ _) @[simp] theorem disjoint_nil_left (l : List α) : Disjoint [] l := fun a => (not_mem_nil a).elim @@ -896,16 +312,6 @@ theorem disjoint_of_disjoint_append_right_left (d : Disjoint l (l₁ ++ l₂)) : theorem disjoint_of_disjoint_append_right_right (d : Disjoint l (l₁ ++ l₂)) : Disjoint l l₂ := (disjoint_append_right.1 d).2 -/-! ### foldl / foldr -/ - -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 - induction l generalizing init <;> simp [*, H] - -theorem foldr_hom (f : β₁ → β₂) (g₁ : α → β₁ → β₁) (g₂ : α → β₂ → β₂) (l : List α) (init : β₁) - (H : ∀ x y, g₂ x (f y) = f (g₁ x y)) : l.foldr g₂ (f init) = f (l.foldr g₁ init) := by - induction l <;> simp [*, H] - /-! ### union -/ section union @@ -941,38 +347,14 @@ theorem pair_mem_product {xs : List α} {ys : List β} {x : α} {y : β} : simp only [product, and_imp, mem_map, Prod.mk.injEq, exists_eq_right_right, mem_bind, iff_self] -/-! ### leftpad -/ - -/-- The length of the List returned by `List.leftpad n a l` is equal - to the larger of `n` and `l.length` -/ -@[simp] -theorem leftpad_length (n : Nat) (a : α) (l : List α) : - (leftpad n a l).length = max n l.length := by - simp only [leftpad, length_append, length_replicate, Nat.sub_add_eq_max] - -theorem leftpad_prefix (n : Nat) (a : α) (l : List α) : - replicate (n - length l) a <+: leftpad n a l := by - simp only [IsPrefix, leftpad] - exact Exists.intro l rfl - -theorem leftpad_suffix (n : Nat) (a : α) (l : List α) : l <:+ (leftpad n a l) := by - simp only [IsSuffix, leftpad] - exact Exists.intro (replicate (n - length l) a) rfl - /-! ### monadic operations -/ --- we use ForIn.forIn as the simp normal form -@[simp] theorem forIn_eq_forIn [Monad m] : @List.forIn α β m _ = forIn := rfl - theorem forIn_eq_bindList [Monad m] [LawfulMonad m] (f : α → β → m (ForInStep β)) (l : List α) (init : β) : forIn l init f = ForInStep.run <$> (ForInStep.yield init).bindList f l := by induction l generalizing init <;> simp [*, map_eq_pure_bind] congr; ext (b | b) <;> simp -@[simp] theorem forM_append [Monad m] [LawfulMonad m] (l₁ l₂ : List α) (f : α → m PUnit) : - (l₁ ++ l₂).forM f = (do l₁.forM f; l₂.forM f) := by induction l₁ <;> simp [*] - /-! ### diff -/ section Diff @@ -1050,205 +432,8 @@ theorem Sublist.erase_diff_erase_sublist {a : α} : end Diff -/-! ### prefix, suffix, infix -/ - -@[simp] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := ⟨l₂, rfl⟩ - -@[simp] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := ⟨l₁, rfl⟩ - -theorem infix_append (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ l₂ ++ l₃ := ⟨l₁, l₃, rfl⟩ - -@[simp] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by - rw [← List.append_assoc]; apply infix_append - -theorem IsPrefix.isInfix : l₁ <+: l₂ → l₁ <:+: l₂ := fun ⟨t, h⟩ => ⟨[], t, h⟩ - -theorem IsSuffix.isInfix : l₁ <:+ l₂ → l₁ <:+: l₂ := fun ⟨t, h⟩ => ⟨t, [], by rw [h, append_nil]⟩ - -theorem nil_prefix (l : List α) : [] <+: l := ⟨l, rfl⟩ - -theorem nil_suffix (l : List α) : [] <:+ l := ⟨l, append_nil _⟩ - -theorem nil_infix (l : List α) : [] <:+: l := (nil_prefix _).isInfix - -theorem prefix_refl (l : List α) : l <+: l := ⟨[], append_nil _⟩ - -theorem suffix_refl (l : List α) : l <:+ l := ⟨[], rfl⟩ - -theorem infix_refl (l : List α) : l <:+: l := (prefix_refl l).isInfix - -@[simp] theorem suffix_cons (a : α) : ∀ l, l <:+ a :: l := suffix_append [a] - -theorem infix_cons : l₁ <:+: l₂ → l₁ <:+: a :: l₂ := fun ⟨L₁, L₂, h⟩ => ⟨a :: L₁, L₂, h ▸ rfl⟩ - -theorem infix_concat : l₁ <:+: l₂ → l₁ <:+: concat l₂ a := fun ⟨L₁, L₂, h⟩ => - ⟨L₁, concat L₂ a, by simp [← h, concat_eq_append, append_assoc]⟩ - -theorem IsPrefix.trans : ∀ {l₁ l₂ l₃ : List α}, l₁ <+: l₂ → l₂ <+: l₃ → l₁ <+: l₃ - | _, _, _, ⟨r₁, rfl⟩, ⟨r₂, rfl⟩ => ⟨r₁ ++ r₂, (append_assoc _ _ _).symm⟩ - -theorem IsSuffix.trans : ∀ {l₁ l₂ l₃ : List α}, l₁ <:+ l₂ → l₂ <:+ l₃ → l₁ <:+ l₃ - | _, _, _, ⟨l₁, rfl⟩, ⟨l₂, rfl⟩ => ⟨l₂ ++ l₁, append_assoc _ _ _⟩ - -theorem IsInfix.trans : ∀ {l₁ l₂ l₃ : List α}, l₁ <:+: l₂ → l₂ <:+: l₃ → l₁ <:+: l₃ - | l, _, _, ⟨l₁, r₁, rfl⟩, ⟨l₂, r₂, rfl⟩ => ⟨l₂ ++ l₁, r₁ ++ r₂, by simp only [append_assoc]⟩ - -protected theorem IsInfix.sublist : l₁ <:+: l₂ → l₁ <+ l₂ - | ⟨_, _, h⟩ => h ▸ (sublist_append_right ..).trans (sublist_append_left ..) - -protected theorem IsInfix.subset (hl : l₁ <:+: l₂) : l₁ ⊆ l₂ := - hl.sublist.subset - -protected theorem IsPrefix.sublist (h : l₁ <+: l₂) : l₁ <+ l₂ := - h.isInfix.sublist - -protected theorem IsPrefix.subset (hl : l₁ <+: l₂) : l₁ ⊆ l₂ := - hl.sublist.subset - -protected theorem IsSuffix.sublist (h : l₁ <:+ l₂) : l₁ <+ l₂ := - h.isInfix.sublist - -protected theorem IsSuffix.subset (hl : l₁ <:+ l₂) : l₁ ⊆ l₂ := - hl.sublist.subset - -@[simp] theorem reverse_suffix : reverse l₁ <:+ reverse l₂ ↔ l₁ <+: l₂ := - ⟨fun ⟨r, e⟩ => ⟨reverse r, by rw [← reverse_reverse l₁, ← reverse_append, e, reverse_reverse]⟩, - fun ⟨r, e⟩ => ⟨reverse r, by rw [← reverse_append, e]⟩⟩ - -@[simp] theorem reverse_prefix : reverse l₁ <+: reverse l₂ ↔ l₁ <:+ l₂ := by - rw [← reverse_suffix]; simp only [reverse_reverse] - -@[simp] theorem reverse_infix : reverse l₁ <:+: reverse l₂ ↔ l₁ <:+: l₂ := by - refine ⟨fun ⟨s, t, e⟩ => ⟨reverse t, reverse s, ?_⟩, fun ⟨s, t, e⟩ => ⟨reverse t, reverse s, ?_⟩⟩ - · rw [← reverse_reverse l₁, append_assoc, ← reverse_append, ← reverse_append, e, - reverse_reverse] - · rw [append_assoc, ← reverse_append, ← reverse_append, e] - -theorem IsInfix.length_le (h : l₁ <:+: l₂) : l₁.length ≤ l₂.length := - h.sublist.length_le - -theorem IsPrefix.length_le (h : l₁ <+: l₂) : l₁.length ≤ l₂.length := - h.sublist.length_le - -theorem IsSuffix.length_le (h : l₁ <:+ l₂) : l₁.length ≤ l₂.length := - h.sublist.length_le - -@[simp] theorem infix_nil : l <:+: [] ↔ l = [] := ⟨(sublist_nil.1 ·.sublist), (· ▸ infix_refl _)⟩ - -@[simp] theorem prefix_nil : l <+: [] ↔ l = [] := ⟨(sublist_nil.1 ·.sublist), (· ▸ prefix_refl _)⟩ - -@[simp] theorem suffix_nil : l <:+ [] ↔ l = [] := ⟨(sublist_nil.1 ·.sublist), (· ▸ suffix_refl _)⟩ - -theorem infix_iff_prefix_suffix (l₁ l₂ : List α) : l₁ <:+: l₂ ↔ ∃ t, l₁ <+: t ∧ t <:+ l₂ := - ⟨fun ⟨_, t, e⟩ => ⟨l₁ ++ t, ⟨_, rfl⟩, e ▸ append_assoc .. ▸ ⟨_, rfl⟩⟩, - fun ⟨_, ⟨t, rfl⟩, s, e⟩ => ⟨s, t, append_assoc .. ▸ e⟩⟩ - -theorem IsInfix.eq_of_length (h : l₁ <:+: l₂) : l₁.length = l₂.length → l₁ = l₂ := - h.sublist.eq_of_length - -theorem IsPrefix.eq_of_length (h : l₁ <+: l₂) : l₁.length = l₂.length → l₁ = l₂ := - h.sublist.eq_of_length - -theorem IsSuffix.eq_of_length (h : l₁ <:+ l₂) : l₁.length = l₂.length → l₁ = l₂ := - h.sublist.eq_of_length - -theorem prefix_of_prefix_length_le : - ∀ {l₁ l₂ l₃ : List α}, l₁ <+: l₃ → l₂ <+: l₃ → length l₁ ≤ length l₂ → l₁ <+: l₂ - | [], l₂, _, _, _, _ => nil_prefix _ - | a :: l₁, b :: l₂, _, ⟨r₁, rfl⟩, ⟨r₂, e⟩, ll => by - injection e with _ e'; subst b - rcases prefix_of_prefix_length_le ⟨_, rfl⟩ ⟨_, e'⟩ (le_of_succ_le_succ ll) with ⟨r₃, rfl⟩ - exact ⟨r₃, rfl⟩ - -theorem prefix_or_prefix_of_prefix (h₁ : l₁ <+: l₃) (h₂ : l₂ <+: l₃) : l₁ <+: l₂ ∨ l₂ <+: l₁ := - (Nat.le_total (length l₁) (length l₂)).imp (prefix_of_prefix_length_le h₁ h₂) - (prefix_of_prefix_length_le h₂ h₁) - -theorem suffix_of_suffix_length_le - (h₁ : l₁ <:+ l₃) (h₂ : l₂ <:+ l₃) (ll : length l₁ ≤ length l₂) : l₁ <:+ l₂ := - reverse_prefix.1 <| - prefix_of_prefix_length_le (reverse_prefix.2 h₁) (reverse_prefix.2 h₂) (by simp [ll]) - -theorem suffix_or_suffix_of_suffix (h₁ : l₁ <:+ l₃) (h₂ : l₂ <:+ l₃) : l₁ <:+ l₂ ∨ l₂ <:+ l₁ := - (prefix_or_prefix_of_prefix (reverse_prefix.2 h₁) (reverse_prefix.2 h₂)).imp reverse_prefix.1 - reverse_prefix.1 - -theorem suffix_cons_iff : l₁ <:+ a :: l₂ ↔ l₁ = a :: l₂ ∨ l₁ <:+ l₂ := by - constructor - · rintro ⟨⟨hd, tl⟩, hl₃⟩ - · exact Or.inl hl₃ - · simp only [cons_append] at hl₃ - injection hl₃ with _ hl₄ - exact Or.inr ⟨_, hl₄⟩ - · rintro (rfl | hl₁) - · exact (a :: l₂).suffix_refl - · exact hl₁.trans (l₂.suffix_cons _) - -theorem infix_cons_iff : l₁ <:+: a :: l₂ ↔ l₁ <+: a :: l₂ ∨ l₁ <:+: l₂ := by - constructor - · rintro ⟨⟨hd, tl⟩, t, hl₃⟩ - · exact Or.inl ⟨t, hl₃⟩ - · simp only [cons_append] at hl₃ - injection hl₃ with _ hl₄ - exact Or.inr ⟨_, t, hl₄⟩ - · rintro (h | hl₁) - · exact h.isInfix - · exact infix_cons hl₁ - -theorem infix_of_mem_join : ∀ {L : List (List α)}, l ∈ L → l <:+: join L - | l' :: _, h => - match h with - | List.Mem.head .. => infix_append [] _ _ - | List.Mem.tail _ hlMemL => - IsInfix.trans (infix_of_mem_join hlMemL) <| (suffix_append _ _).isInfix - -theorem prefix_append_right_inj (l) : l ++ l₁ <+: l ++ l₂ ↔ l₁ <+: l₂ := - exists_congr fun r => by rw [append_assoc, append_right_inj] - -@[simp] -theorem prefix_cons_inj (a) : a :: l₁ <+: a :: l₂ ↔ l₁ <+: l₂ := - prefix_append_right_inj [a] - -theorem take_prefix (n) (l : List α) : take n l <+: l := - ⟨_, take_append_drop _ _⟩ - -theorem drop_suffix (n) (l : List α) : drop n l <:+ l := - ⟨_, take_append_drop _ _⟩ - -theorem take_sublist (n) (l : List α) : take n l <+ l := - (take_prefix n l).sublist - -theorem drop_sublist (n) (l : List α) : drop n l <+ l := - (drop_suffix n l).sublist - -theorem take_subset (n) (l : List α) : take n l ⊆ l := - (take_sublist n l).subset - -theorem drop_subset (n) (l : List α) : drop n l ⊆ l := - (drop_sublist n l).subset - -theorem mem_of_mem_take {l : List α} (h : a ∈ l.take n) : a ∈ l := - take_subset n l h - -theorem IsPrefix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) : - l₁.filter p <+: l₂.filter p := by - obtain ⟨xs, rfl⟩ := h - rw [filter_append]; apply prefix_append - -theorem IsSuffix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) : - l₁.filter p <:+ l₂.filter p := by - obtain ⟨xs, rfl⟩ := h - rw [filter_append]; apply suffix_append - -theorem IsInfix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) : - l₁.filter p <:+: l₂.filter p := by - obtain ⟨xs, ys, rfl⟩ := h - rw [filter_append, filter_append]; apply infix_append _ - /-! ### drop -/ -theorem mem_of_mem_drop {n} {l : List α} (h : a ∈ l.drop n) : a ∈ l := drop_subset _ _ h - theorem disjoint_take_drop : ∀ {l : List α}, l.Nodup → m ≤ n → Disjoint (l.take m) (l.drop n) | [], _, _ => by simp | x :: xs, hl, h => by @@ -1297,39 +482,6 @@ protected theorem Pairwise.chain (p : Pairwise R (a :: l)) : Chain R a l := by /-! ### range', range -/ -theorem range'_succ (s n step) : range' s (n + 1) step = s :: range' (s + step) n step := by - simp [range', Nat.add_succ, Nat.mul_succ] - -@[simp] theorem length_range' (s step) : ∀ n : Nat, length (range' s n step) = n - | 0 => rfl - | _ + 1 => congrArg succ (length_range' _ _ _) - -@[simp] theorem range'_eq_nil : range' s n step = [] ↔ n = 0 := by - rw [← length_eq_zero, length_range'] - -theorem mem_range' : ∀{n}, m ∈ range' s n step ↔ ∃ i < n, m = s + step * i - | 0 => by simp [range', Nat.not_lt_zero] - | n + 1 => by - have h (i) : i ≤ n ↔ i = 0 ∨ ∃ j, i = succ j ∧ j < n := by cases i <;> simp [Nat.succ_le] - simp [range', mem_range', Nat.lt_succ, h]; simp only [← exists_and_right, and_assoc] - rw [exists_comm]; simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm] - -@[simp] theorem mem_range'_1 : m ∈ range' s n ↔ s ≤ m ∧ m < s + n := by - simp [mem_range']; exact ⟨ - fun ⟨i, h, e⟩ => e ▸ ⟨Nat.le_add_right .., Nat.add_lt_add_left h _⟩, - fun ⟨h₁, h₂⟩ => ⟨m - s, Nat.sub_lt_left_of_lt_add h₁ h₂, (Nat.add_sub_cancel' h₁).symm⟩⟩ - -@[simp] -theorem map_add_range' (a) : ∀ s n step, map (a + ·) (range' s n step) = range' (a + s) n step - | _, 0, _ => rfl - | s, n + 1, step => by simp [range', map_add_range' _ (s + step) n step, Nat.add_assoc] - -theorem map_sub_range' (a s n : Nat) (h : a ≤ s) : - map (· - a) (range' s n step) = range' (s - a) n step := by - conv => lhs; rw [← Nat.add_sub_cancel' h] - rw [← map_add_range', map_map, (?_ : _∘_ = _), map_id] - funext x; apply Nat.add_sub_cancel_left - theorem chain_succ_range' : ∀ s n step : Nat, Chain (fun a b => b = a + step) s (range' (s + step) n step) | _, 0, _ => Chain.nil @@ -1339,41 +491,6 @@ theorem chain_lt_range' (s n : Nat) {step} (h : 0 < step) : Chain (· < ·) s (range' (s + step) n step) := (chain_succ_range' s n step).imp fun _ _ e => e.symm ▸ Nat.lt_add_of_pos_right h -theorem range'_append : ∀ s m n step : Nat, - range' s m step ++ range' (s + step * m) n step = range' s (n + m) step - | s, 0, n, step => rfl - | s, m + 1, n, step => by - simpa [range', Nat.mul_succ, Nat.add_assoc, Nat.add_comm] - using range'_append (s + step) m n step - -@[simp] theorem range'_append_1 (s m n : Nat) : - range' s m ++ range' (s + m) n = range' s (n + m) := by simpa using range'_append s m n 1 - -theorem range'_sublist_right {s m n : Nat} : range' s m step <+ range' s n step ↔ m ≤ n := - ⟨fun h => by simpa only [length_range'] using h.length_le, - fun h => by rw [← Nat.sub_add_cancel h, ← range'_append]; apply sublist_append_left⟩ - -theorem range'_subset_right {s m n : Nat} (step0 : 0 < step) : - range' s m step ⊆ range' s n step ↔ m ≤ n := by - refine ⟨fun h => Nat.le_of_not_lt fun hn => ?_, fun h => (range'_sublist_right.2 h).subset⟩ - have ⟨i, h', e⟩ := mem_range'.1 <| h <| mem_range'.2 ⟨_, hn, rfl⟩ - exact Nat.ne_of_gt h' (Nat.eq_of_mul_eq_mul_left step0 (Nat.add_left_cancel e)) - -theorem range'_subset_right_1 {s m n : Nat} : range' s m ⊆ range' s n ↔ m ≤ n := - range'_subset_right (by decide) - -theorem getElem?_range' (s step) : - ∀ {m n : Nat}, m < n → (range' s n step)[m]? = some (s + step * m) - | 0, n + 1, _ => by simp [range'_succ] - | m + 1, n + 1, h => by - simp only [range'_succ, getElem?_cons_succ] - exact (getElem?_range' (s + step) step (Nat.lt_of_add_lt_add_right h)).trans <| by - simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm] - -@[simp] theorem getElem_range' {n m step} (i) (H : i < (range' n m step).length) : - (range' n m step)[i] = n + step * i := - (getElem?_eq_some.1 <| getElem?_range' n step (by simpa using H)).2 - @[deprecated getElem?_range' (since := "2024-06-12")] theorem get?_range' (s step) {m n : Nat} (h : m < n) : get? (range' s n step) m = some (s + step * m) := by @@ -1384,54 +501,6 @@ theorem get_range' {n m step} (i) (H : i < (range' n m step).length) : get (range' n m step) ⟨i, H⟩ = n + step * i := by simp -theorem range'_concat (s n : Nat) : range' s (n + 1) step = range' s n step ++ [s + step * n] := by - rw [Nat.add_comm n 1]; exact (range'_append s n 1 step).symm - -theorem range'_1_concat (s n : Nat) : range' s (n + 1) = range' s n ++ [s + n] := by - simp [range'_concat] - -theorem range_loop_range' : ∀ s n : Nat, range.loop s (range' s n) = range' 0 (n + s) - | 0, n => rfl - | s + 1, n => by rw [← Nat.add_assoc, Nat.add_right_comm n s 1]; exact range_loop_range' s (n + 1) - -theorem range_eq_range' (n : Nat) : range n = range' 0 n := - (range_loop_range' n 0).trans <| by rw [Nat.zero_add] - -theorem range_succ_eq_map (n : Nat) : range (n + 1) = 0 :: map succ (range n) := by - rw [range_eq_range', range_eq_range', range', Nat.add_comm, ← map_add_range'] - congr; exact funext one_add - -theorem range'_eq_map_range (s n : Nat) : range' s n = map (s + ·) (range n) := by - rw [range_eq_range', map_add_range']; rfl - -@[simp] theorem length_range (n : Nat) : length (range n) = n := by - simp only [range_eq_range', length_range'] - -@[simp] theorem range_eq_nil {n : Nat} : range n = [] ↔ n = 0 := by - rw [← length_eq_zero, length_range] - -@[simp] -theorem range_sublist {m n : Nat} : range m <+ range n ↔ m ≤ n := by - simp only [range_eq_range', range'_sublist_right] - -@[simp] -theorem range_subset {m n : Nat} : range m ⊆ range n ↔ m ≤ n := by - simp only [range_eq_range', range'_subset_right, lt_succ_self] - -@[simp] -theorem mem_range {m n : Nat} : m ∈ range n ↔ m < n := by - simp only [range_eq_range', mem_range'_1, Nat.zero_le, true_and, Nat.zero_add] - -theorem not_mem_range_self {n : Nat} : n ∉ range n := by simp - -theorem self_mem_range_succ (n : Nat) : n ∈ range (n + 1) := by simp - -theorem getElem?_range {m n : Nat} (h : m < n) : (range n)[m]? = some m := by - simp [range_eq_range', getElem?_range' _ _ h] - -@[simp] theorem getElem_range {n : Nat} (m) (h : m < (range n).length) : (range n)[m] = m := by - simp [range_eq_range'] - @[deprecated getElem?_range (since := "2024-06-12")] theorem get?_range {m n : Nat} (h : m < n) : get? (range n) m = some m := by simp [getElem?_range, h] @@ -1440,41 +509,6 @@ theorem get?_range {m n : Nat} (h : m < n) : get? (range n) m = some m := by theorem get_range {n} (i) (H : i < (range n).length) : get (range n) ⟨i, H⟩ = i := by simp -theorem range_succ (n : Nat) : range (succ n) = range n ++ [n] := by - simp only [range_eq_range', range'_1_concat, Nat.zero_add] - -theorem range_add (a b : Nat) : range (a + b) = range a ++ (range b).map (a + ·) := by - rw [← range'_eq_map_range] - simpa [range_eq_range', Nat.add_comm] using (range'_append_1 0 a b).symm - -theorem iota_eq_reverse_range' : ∀ n : Nat, iota n = reverse (range' 1 n) - | 0 => rfl - | n + 1 => by simp [iota, range'_concat, iota_eq_reverse_range' n, reverse_append, Nat.add_comm] - -@[simp] theorem length_iota (n : Nat) : length (iota n) = n := by simp [iota_eq_reverse_range'] - -@[simp] -theorem mem_iota {m n : Nat} : m ∈ iota n ↔ 1 ≤ m ∧ m ≤ n := by - simp [iota_eq_reverse_range', Nat.add_comm, Nat.lt_succ] - -theorem reverse_range' : ∀ s n : Nat, reverse (range' s n) = map (s + n - 1 - ·) (range n) - | s, 0 => rfl - | s, n + 1 => by - rw [range'_1_concat, reverse_append, range_succ_eq_map, - show s + (n + 1) - 1 = s + n from rfl, map, map_map] - simp [reverse_range', Nat.sub_right_comm, Nat.sub_sub] - - -/-! ### enum, enumFrom -/ - -@[simp] theorem enumFrom_map_fst (n) : - ∀ (l : List α), map Prod.fst (enumFrom n l) = range' n l.length - | [] => rfl - | _ :: _ => congrArg (cons _) (enumFrom_map_fst _ _) - -@[simp] theorem enum_map_fst (l : List α) : map Prod.fst (enum l) = range l.length := by - simp only [enum, enumFrom_map_fst, range_eq_range'] - /-! ### indexOf and indexesOf -/ theorem foldrIdx_start : @@ -1514,13 +548,6 @@ theorem indexesOf_cons [BEq α] : (x :: xs : List α).indexesOf y = bif x == y then 0 :: (xs.indexesOf y).map (· + 1) else (xs.indexesOf y).map (· + 1) := by simp [indexesOf, findIdxs_cons] -@[simp] theorem indexOf_nil [BEq α] : ([] : List α).indexOf x = 0 := rfl - -theorem indexOf_cons [BEq α] : - (x :: xs : List α).indexOf y = bif x == y then 0 else xs.indexOf y + 1 := by - dsimp [indexOf] - simp [findIdx_cons] - theorem indexOf_mem_indexesOf [BEq α] [LawfulBEq α] {xs : List α} (m : x ∈ xs) : xs.indexOf x ∈ xs.indexesOf x := by induction xs with diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index 83b935f8ae..dd94875ca9 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -30,164 +30,6 @@ namespace List /-! ### Pairwise -/ -theorem rel_of_pairwise_cons (p : (a :: l).Pairwise R) : ∀ {a'}, a' ∈ l → R a a' := - (pairwise_cons.1 p).1 _ - -theorem Pairwise.of_cons (p : (a :: l).Pairwise R) : Pairwise R l := - (pairwise_cons.1 p).2 - -theorem Pairwise.tail : ∀ {l : List α} (_p : Pairwise R l), Pairwise R l.tail - | [], h => h - | _ :: _, h => h.of_cons - -theorem Pairwise.drop : ∀ {l : List α} {n : Nat}, List.Pairwise R l → List.Pairwise R (l.drop n) - | _, 0, h => h - | [], _ + 1, _ => List.Pairwise.nil - | _ :: _, n + 1, h => Pairwise.drop (n := n) (pairwise_cons.mp h).right - -theorem Pairwise.imp_of_mem {S : α → α → Prop} - (H : ∀ {a b}, a ∈ l → b ∈ l → R a b → S a b) (p : Pairwise R l) : Pairwise S l := by - induction p with - | nil => constructor - | @cons a l r _ ih => - constructor - · exact fun x h => H (mem_cons_self ..) (mem_cons_of_mem _ h) <| r x h - · exact ih fun m m' => H (mem_cons_of_mem _ m) (mem_cons_of_mem _ m') - -theorem Pairwise.and (hR : Pairwise R l) (hS : Pairwise S l) : - l.Pairwise fun a b => R a b ∧ S a b := by - induction hR with - | nil => simp only [Pairwise.nil] - | cons R1 _ IH => - simp only [Pairwise.nil, pairwise_cons] at hS ⊢ - exact ⟨fun b bl => ⟨R1 b bl, hS.1 b bl⟩, IH hS.2⟩ - -theorem pairwise_and_iff : l.Pairwise (fun a b => R a b ∧ S a b) ↔ Pairwise R l ∧ Pairwise S l := - ⟨fun h => ⟨h.imp fun h => h.1, h.imp fun h => h.2⟩, fun ⟨hR, hS⟩ => hR.and hS⟩ - -theorem Pairwise.imp₂ (H : ∀ a b, R a b → S a b → T a b) - (hR : Pairwise R l) (hS : l.Pairwise S) : l.Pairwise T := - (hR.and hS).imp fun ⟨h₁, h₂⟩ => H _ _ h₁ h₂ - -theorem Pairwise.iff_of_mem {S : α → α → Prop} {l : List α} - (H : ∀ {a b}, a ∈ l → b ∈ l → (R a b ↔ S a b)) : Pairwise R l ↔ Pairwise S l := - ⟨Pairwise.imp_of_mem fun m m' => (H m m').1, Pairwise.imp_of_mem fun m m' => (H m m').2⟩ - -theorem Pairwise.iff {S : α → α → Prop} (H : ∀ a b, R a b ↔ S a b) {l : List α} : - Pairwise R l ↔ Pairwise S l := - Pairwise.iff_of_mem fun _ _ => H .. - -theorem pairwise_of_forall {l : List α} (H : ∀ x y, R x y) : Pairwise R l := by - induction l <;> simp [*] - -theorem Pairwise.and_mem {l : List α} : - Pairwise R l ↔ Pairwise (fun x y => x ∈ l ∧ y ∈ l ∧ R x y) l := - Pairwise.iff_of_mem <| by simp (config := { contextual := true }) - -theorem Pairwise.imp_mem {l : List α} : - Pairwise R l ↔ Pairwise (fun x y => x ∈ l → y ∈ l → R x y) l := - Pairwise.iff_of_mem <| by simp (config := { contextual := true }) - -theorem Pairwise.forall_of_forall_of_flip (h₁ : ∀ x ∈ l, R x x) (h₂ : Pairwise R l) - (h₃ : l.Pairwise (flip R)) : ∀ ⦃x⦄, x ∈ l → ∀ ⦃y⦄, y ∈ l → R x y := by - induction l with - | nil => exact forall_mem_nil _ - | cons a l ih => - rw [pairwise_cons] at h₂ h₃ - simp only [mem_cons] - rintro x (rfl | hx) y (rfl | hy) - · exact h₁ _ (l.mem_cons_self _) - · exact h₂.1 _ hy - · exact h₃.1 _ hx - · exact ih (fun x hx => h₁ _ <| mem_cons_of_mem _ hx) h₂.2 h₃.2 hx hy - -theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp - -theorem pairwise_pair {a b : α} : Pairwise R [a, b] ↔ R a b := by simp - -theorem pairwise_append_comm {R : α → α → Prop} (s : ∀ {x y}, R x y → R y x) {l₁ l₂ : List α} : - Pairwise R (l₁ ++ l₂) ↔ Pairwise R (l₂ ++ l₁) := by - have (l₁ l₂ : List α) (H : ∀ x : α, x ∈ l₁ → ∀ y : α, y ∈ l₂ → R x y) - (x : α) (xm : x ∈ l₂) (y : α) (ym : y ∈ l₁) : R x y := s (H y ym x xm) - simp only [pairwise_append, and_left_comm]; rw [Iff.intro (this l₁ l₂) (this l₂ l₁)] - -theorem pairwise_middle {R : α → α → Prop} (s : ∀ {x y}, R x y → R y x) {a : α} {l₁ l₂ : List α} : - Pairwise R (l₁ ++ a :: l₂) ↔ Pairwise R (a :: (l₁ ++ l₂)) := by - show Pairwise R (l₁ ++ ([a] ++ l₂)) ↔ Pairwise R ([a] ++ l₁ ++ l₂) - rw [← append_assoc, pairwise_append, @pairwise_append _ _ ([a] ++ l₁), pairwise_append_comm s] - simp only [mem_append, or_comm] - -theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b : α, S (f a) (f b) → R a b) - (p : Pairwise S (map f l)) : Pairwise R l := - (pairwise_map.1 p).imp (H _ _) - -theorem Pairwise.map {S : β → β → Prop} (f : α → β) (H : ∀ a b : α, R a b → S (f a) (f b)) - (p : Pairwise R l) : Pairwise S (map f l) := - pairwise_map.2 <| p.imp (H _ _) - -theorem pairwise_filterMap (f : β → Option α) {l : List β} : - Pairwise R (filterMap f l) ↔ Pairwise (fun a a' : β => ∀ b ∈ f a, ∀ b' ∈ f a', R b b') l := by - let _S (a a' : β) := ∀ b ∈ f a, ∀ b' ∈ f a', R b b' - simp only [Option.mem_def] - induction l with - | nil => simp only [filterMap, Pairwise.nil] - | cons a l IH => ?_ - match e : f a with - | none => - rw [filterMap_cons_none _ _ e, pairwise_cons] - simp only [e, false_implies, implies_true, true_and, IH] - | some b => - rw [filterMap_cons_some _ _ _ e] - simpa [IH, e] using fun _ => - ⟨fun h a ha b hab => h _ _ ha hab, fun h a b ha hab => h _ ha _ hab⟩ - -theorem Pairwise.filter_map {S : β → β → Prop} (f : α → Option β) - (H : ∀ a a' : α, R a a' → ∀ b ∈ f a, ∀ b' ∈ f a', S b b') {l : List α} (p : Pairwise R l) : - Pairwise S (filterMap f l) := - (pairwise_filterMap _).2 <| p.imp (H _ _) - -theorem pairwise_filter (p : α → Prop) [DecidablePred p] {l : List α} : - Pairwise R (filter p l) ↔ Pairwise (fun x y => p x → p y → R x y) l := by - rw [← filterMap_eq_filter, pairwise_filterMap] - simp - -theorem Pairwise.filter (p : α → Bool) : Pairwise R l → Pairwise R (filter p l) := - Pairwise.sublist (filter_sublist _) - -theorem pairwise_join {L : List (List α)} : - Pairwise R (join L) ↔ - (∀ l ∈ L, Pairwise R l) ∧ Pairwise (fun l₁ l₂ => ∀ x ∈ l₁, ∀ y ∈ l₂, R x y) L := by - induction L with - | nil => simp - | cons l L IH => - simp only [join, pairwise_append, IH, mem_join, exists_imp, and_imp, forall_mem_cons, - pairwise_cons, and_assoc, and_congr_right_iff] - rw [and_comm, and_congr_left_iff] - intros; exact ⟨fun h a b c d e => h c d e a b, fun h c d e a b => h a b c d e⟩ - -theorem pairwise_bind {R : β → β → Prop} {l : List α} {f : α → List β} : - List.Pairwise R (l.bind f) ↔ - (∀ a ∈ l, Pairwise R (f a)) ∧ Pairwise (fun a₁ a₂ => ∀ x ∈ f a₁, ∀ y ∈ f a₂, R x y) l := by - simp [List.bind, pairwise_join, pairwise_map] - -theorem pairwise_iff_forall_sublist : l.Pairwise R ↔ (∀ {a b}, [a,b] <+ l → R a b) := by - induction l with - | nil => simp - | cons hd tl IH => - rw [List.pairwise_cons] - constructor <;> intro h - · intro - | a, b, .cons _ hab => exact IH.mp h.2 hab - | _, b, .cons₂ _ hab => refine h.1 _ (hab.subset ?_); simp - · constructor - · intro x hx - apply h - rw [List.cons_sublist_cons, List.singleton_sublist] - exact hx - · apply IH.mpr - intro a b hab - apply h; exact hab.cons _ - @[deprecated pairwise_iff_forall_sublist (since := "2023-09-18")] theorem pairwise_of_reflexive_on_dupl_of_forall_ne [DecidableEq α] {l : List α} {r : α → α → Prop} (hr : ∀ a, 1 < count a l → r a a) (h : ∀ a ∈ l, ∀ b ∈ l, a ≠ b → r a b) : l.Pairwise r := by @@ -200,53 +42,6 @@ theorem pairwise_of_reflexive_on_dupl_of_forall_ne [DecidableEq α] {l : List α apply h <;> try (apply hab.subset; simp) exact heq -/-- given a list `is` of monotonically increasing indices into `l`, getting each index - produces a sublist of `l`. -/ -theorem map_get_sublist {l : List α} {is : List (Fin l.length)} (h : is.Pairwise (·.val < ·.val)) : - is.map (get l) <+ l := by - suffices ∀ n l', l' = l.drop n → (∀ i ∈ is, n ≤ i) → map (get l) is <+ l' - from this 0 l (by simp) (by simp) - intro n l' hl' his - induction is generalizing n l' with - | nil => simp - | cons hd tl IH => - simp; cases hl' - have := IH h.of_cons (hd+1) _ rfl (pairwise_cons.mp h).1 - specialize his hd (.head _) - have := (drop_eq_getElem_cons ..).symm ▸ this.cons₂ (get l hd) - have := Sublist.append (nil_sublist (take hd l |>.drop n)) this - rwa [nil_append, ← (drop_append_of_le_length ?_), take_append_drop] at this - simp [Nat.min_eq_left (Nat.le_of_lt hd.isLt), his] - -/-- given a sublist `l' <+ l`, there exists a list of indices `is` such that - `l' = map (get l) is`. -/ -theorem sublist_eq_map_get (h : l' <+ l) : ∃ is : List (Fin l.length), - l' = map (get l) is ∧ is.Pairwise (· < ·) := by - induction h with - | slnil => exact ⟨[], by simp⟩ - | cons _ _ IH => - let ⟨is, IH⟩ := IH - refine ⟨is.map (·.succ), ?_⟩ - simp [comp, pairwise_map] - exact IH - | cons₂ _ _ IH => - rcases IH with ⟨is,IH⟩ - refine ⟨⟨0, by simp [Nat.zero_lt_succ]⟩ :: is.map (·.succ), ?_⟩ - simp [comp_def, pairwise_map, IH, ← get_eq_getElem] - -theorem pairwise_iff_getElem : Pairwise R l ↔ - ∀ (i j : Nat) (_hi : i < l.length) (_hj : j < l.length) (_hij : i < j), R l[i] l[j] := by - rw [pairwise_iff_forall_sublist] - constructor <;> intro h - · intros i j hi hj h' - apply h - simpa [h'] using map_get_sublist (is := [⟨i, hi⟩, ⟨j, hj⟩]) - · intros a b h' - have ⟨is, h', hij⟩ := sublist_eq_map_get h' - rcases is with ⟨⟩ | ⟨a', ⟨⟩ | ⟨b', ⟨⟩⟩⟩ <;> simp at h' - rcases h' with ⟨rfl, rfl⟩ - apply h; simpa using hij - theorem pairwise_iff_get : Pairwise R l ↔ ∀ (i j) (_hij : i < j), R (get l i) (get l j) := by rw [pairwise_iff_getElem] constructor <;> intro h @@ -255,11 +50,6 @@ theorem pairwise_iff_get : Pairwise R l ↔ ∀ (i j) (_hij : i < j), R (get l i · intros i j hi hj h' exact h ⟨i, hi⟩ ⟨j, hj⟩ h' -theorem pairwise_replicate {α : Type _} {r : α → α → Prop} {x : α} (hx : r x x) : - ∀ n : Nat, Pairwise r (List.replicate n x) - | 0 => by simp - | n + 1 => by simp [mem_replicate, hx, pairwise_replicate hx n, replicate_succ] - /-! ### Pairwise filtering -/ @[simp] theorem pwFilter_nil [DecidableRel R] : pwFilter R [] = [] := rfl diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index ab12db10b1..5c31720c7c 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -4,10 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ import Batteries.Tactic.Alias -import Batteries.Data.List.Init.Attach import Batteries.Data.List.Pairwise --- Adaptation note: nightly-2024-03-18. We should be able to remove this after nightly-2024-03-19. -import Lean.Elab.Tactic.Rfl /-! # List Permutations @@ -234,7 +231,7 @@ theorem Subperm.trans {l₁ l₂ l₃ : List α} (s₁₂ : l₁ <+~ l₂) (s₂ ⟨l₁', p₁, s₁.trans s₂⟩ theorem Subperm.cons_right {α : Type _} {l l' : List α} (x : α) (h : l <+~ l') : l <+~ x :: l' := - h.trans (sublist_cons x l').subperm + h.trans (sublist_cons_self x l').subperm theorem Subperm.length_le {l₁ l₂ : List α} : l₁ <+~ l₂ → length l₁ ≤ length l₂ | ⟨_l, p, s⟩ => p.length_eq ▸ s.length_le @@ -371,7 +368,7 @@ theorem perm_append_right_iff {l₁ l₂ : List α} (l) : l₁ ++ l ~ l₂ ++ l theorem subperm_cons (a : α) {l₁ l₂ : List α} : a :: l₁ <+~ a :: l₂ ↔ l₁ <+~ l₂ := by refine ⟨fun ⟨l, p, s⟩ => ?_, fun ⟨l, p, s⟩ => ⟨a :: l, p.cons a, s.cons₂ _⟩⟩ match s with - | .cons _ s' => exact (p.subperm_left.2 <| (sublist_cons _ _).subperm).trans s'.subperm + | .cons _ s' => exact (p.subperm_left.2 <| (sublist_cons_self _ _).subperm).trans s'.subperm | .cons₂ _ s' => exact ⟨_, p.cons_inv, s'⟩ /-- Weaker version of `Subperm.cons_left` -/ @@ -412,7 +409,7 @@ theorem Subperm.exists_of_length_lt {l₁ l₂ : List α} (s : l₁ <+~ l₂) (h | slnil => cases h | cons a s IH => match Nat.lt_or_eq_of_le (Nat.le_of_lt_succ h) with - | .inl h => exact (IH h).imp fun a s => s.trans (sublist_cons _ _).subperm + | .inl h => exact (IH h).imp fun a s => s.trans (sublist_cons_self _ _).subperm | .inr h => exact ⟨a, s.eq_of_length h ▸ .refl _⟩ | cons₂ b _ IH => exact (IH <| Nat.lt_of_succ_lt_succ h).imp fun a s => @@ -440,12 +437,12 @@ theorem Nodup.perm_iff_eq_of_sublist {l₁ l₂ l : List α} (d : Nodup l) | .cons _ s₁ => exact IH d.2 s₁ h | .cons₂ _ s₁ => have := Subperm.subset ⟨_, h.symm, s₂⟩ (.head _) - exact (d.1 _ this rfl).elim + exact (d.1 this).elim | cons₂ a _ IH => match s₁ with | .cons _ s₁ => have := Subperm.subset ⟨_, h, s₁⟩ (.head _) - exact (d.1 _ this rfl).elim + exact (d.1 this).elim | .cons₂ _ s₁ => rw [IH d.2 s₁ h.cons_inv] section DecidableEq @@ -464,7 +461,7 @@ theorem subperm_cons_erase (a : α) (l : List α) : l <+~ a :: l.erase a := if h : a ∈ l then (perm_cons_erase h).subperm else - (erase_of_not_mem h).symm ▸ (sublist_cons _ _).subperm + (erase_of_not_mem h).symm ▸ (sublist_cons_self _ _).subperm theorem erase_subperm (a : α) (l : List α) : l.erase a <+~ l := (erase_sublist _ _).subperm @@ -513,7 +510,7 @@ theorem erase_cons_subperm_cons_erase (a b : α) (l : List α) : rw [h, erase_cons_head]; apply subperm_cons_erase else have : ¬(a == b) = true := by simp only [beq_false_of_ne h, not_false_eq_true] - rw [erase_cons_tail _ this] + rw [erase_cons_tail this] theorem subperm_cons_diff {a : α} {l₁ l₂ : List α} : (a :: l₁).diff l₂ <+~ a :: l₁.diff l₂ := by induction l₂ with diff --git a/Batteries/Data/Nat/Basic.lean b/Batteries/Data/Nat/Basic.lean index a6e55a6ea2..1d9658f49e 100644 --- a/Batteries/Data/Nat/Basic.lean +++ b/Batteries/Data/Nat/Basic.lean @@ -94,9 +94,6 @@ protected def casesDiagOn {motive : Nat → Nat → Sort _} (m n : Nat) Nat.recDiag zero_zero (fun _ _ => zero_succ _) (fun _ _ => succ_zero _) (fun _ _ _ => succ_succ _ _) m n -/-- Sum of a list of natural numbers. -/ -protected def sum (l : List Nat) : Nat := l.foldr (·+·) 0 - /-- Integer square root function. Implemented via Newton's method. -/ diff --git a/Batteries/Data/Nat/Lemmas.lean b/Batteries/Data/Nat/Lemmas.lean index 842ca09e95..1c3edddeaf 100644 --- a/Batteries/Data/Nat/Lemmas.lean +++ b/Batteries/Data/Nat/Lemmas.lean @@ -177,10 +177,6 @@ protected alias le_of_le_of_sub_le_sub_left := Nat.le_of_sub_le_sub_left /-! ### sum -/ -@[simp] theorem sum_nil : Nat.sum [] = 0 := rfl - -@[simp] theorem sum_cons : Nat.sum (a :: l) = a + Nat.sum l := rfl - @[simp] theorem sum_append : Nat.sum (l₁ ++ l₂) = Nat.sum l₁ + Nat.sum l₂ := by induction l₁ <;> simp [*, Nat.add_assoc] diff --git a/Batteries/Data/RBMap/Lemmas.lean b/Batteries/Data/RBMap/Lemmas.lean index 37f24ebea9..5577b3a1a7 100644 --- a/Batteries/Data/RBMap/Lemmas.lean +++ b/Batteries/Data/RBMap/Lemmas.lean @@ -152,7 +152,6 @@ theorem min?_eq_toList_head? {t : RBNode α} : t.min? = t.toList.head? := by | nil => rfl | node _ l _ _ ih => cases l <;> simp [RBNode.min?, ih] - next ll _ _ => cases toList ll <;> rfl theorem max?_eq_toList_getLast? {t : RBNode α} : t.max? = t.toList.getLast? := by rw [← min?_reverse, min?_eq_toList_head?]; simp diff --git a/Batteries/Data/Range/Lemmas.lean b/Batteries/Data/Range/Lemmas.lean index 586f32a7e8..d71082848f 100644 --- a/Batteries/Data/Range/Lemmas.lean +++ b/Batteries/Data/Range/Lemmas.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro -/ import Batteries.Tactic.SeqFocus import Batteries.Data.List.Lemmas -import Batteries.Data.List.Init.Attach namespace Std.Range diff --git a/Batteries/Data/String/Lemmas.lean b/Batteries/Data/String/Lemmas.lean index e046783fee..9984d0fb52 100644 --- a/Batteries/Data/String/Lemmas.lean +++ b/Batteries/Data/String/Lemmas.lean @@ -12,7 +12,8 @@ import Batteries.Tactic.SqueezeScope namespace String -attribute [ext] ext +-- TODO(kmill): add `@[ext]` attribute to `String.ext` in core. +attribute [ext (iff := false)] ext theorem lt_trans {s₁ s₂ s₃ : String} : s₁ < s₂ → s₂ < s₃ → s₁ < s₃ := List.lt_trans' (α := Char) Nat.lt_trans @@ -87,7 +88,8 @@ end namespace Pos -attribute [ext] ext +-- TODO(kmill): add `@[ext]` attribute to `String.Pos.ext` in core. +attribute [ext (iff := false)] ext theorem lt_addChar (p : Pos) (c : Char) : p < p + c := Nat.lt_add_of_pos_right (Char.utf8Size_pos _) @@ -335,7 +337,7 @@ theorem firstDiffPos_loop_eq (l₁ l₂ r₁ r₂ stop p) · next h => rw [dif_neg] <;> simp [hstop, ← hl₁, ← hl₂, -Nat.not_lt, Nat.lt_min] intro h₁ h₂ - have : ∀ {cs}, p < p + utf8Len cs → cs ≠ [] := by rintro _ h rfl; simp at h + have : ∀ {cs}, 0 < utf8Len cs → cs ≠ [] := by rintro _ h rfl; simp at h obtain ⟨a, as, e₁⟩ := List.exists_cons_of_ne_nil (this h₁) obtain ⟨b, bs, e₂⟩ := List.exists_cons_of_ne_nil (this h₂) exact h _ _ _ _ e₁ e₂ @@ -420,8 +422,9 @@ theorem splitAux_of_valid (p l m r acc) : splitAux ⟨l ++ m ++ r⟩ p ⟨utf8Len l⟩ ⟨utf8Len l + utf8Len m⟩ acc = acc.reverse ++ (List.splitOnP.go p r m.reverse).map mk := by unfold splitAux - simp only [List.append_assoc, atEnd_iff, endPos_eq, utf8Len_append, Pos.mk_le_mk, by - simpa using atEnd_of_valid (l ++ m) r, List.reverse_cons, dite_eq_ite] + simp only [List.append_assoc, atEnd_iff, endPos_eq, utf8Len_append, Pos.mk_le_mk, + Nat.add_le_add_iff_left, by simpa using atEnd_of_valid (l ++ m) r, List.reverse_cons, + dite_eq_ite] split · subst r; simpa [List.splitOnP.go] using extract_of_valid l m [] · obtain ⟨c, r, rfl⟩ := r.exists_cons_of_ne_nil ‹_› @@ -674,7 +677,7 @@ theorem foldrAux_of_valid (f : Char → α → α) (l m r a) : rw [← m.reverse_reverse] induction m.reverse generalizing r a with (unfold foldrAux; simp) | cons c m IH => - rw [if_pos (by exact Nat.lt_add_of_pos_right add_utf8Size_pos)] + rw [if_pos add_utf8Size_pos] simp only [← Nat.add_assoc, by simpa using prev_of_valid (l ++ m.reverse) c r] simp only [by simpa using get_of_valid (l ++ m.reverse) (c :: r)] simpa using IH (c::r) (f c a) diff --git a/Batteries/Data/UInt.lean b/Batteries/Data/UInt.lean index a9ce1b561a..44ebfd9b80 100644 --- a/Batteries/Data/UInt.lean +++ b/Batteries/Data/UInt.lean @@ -10,8 +10,6 @@ import Batteries.Classes.Order @[ext] theorem UInt8.ext : {x y : UInt8} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem UInt8.ext_iff {x y : UInt8} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, UInt8.ext⟩ - @[simp] theorem UInt8.val_val_eq_toNat (x : UInt8) : x.val.val = x.toNat := rfl @[simp] theorem UInt8.val_ofNat (n) : @@ -57,8 +55,6 @@ instance : Batteries.LawfulOrd UInt8 := .compareOfLessAndEq @[ext] theorem UInt16.ext : {x y : UInt16} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem UInt16.ext_iff {x y : UInt16} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, UInt16.ext⟩ - @[simp] theorem UInt16.val_val_eq_toNat (x : UInt16) : x.val.val = x.toNat := rfl @[simp] theorem UInt16.val_ofNat (n) : @@ -104,8 +100,6 @@ instance : Batteries.LawfulOrd UInt16 := .compareOfLessAndEq @[ext] theorem UInt32.ext : {x y : UInt32} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem UInt32.ext_iff {x y : UInt32} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, UInt32.ext⟩ - @[simp] theorem UInt32.val_val_eq_toNat (x : UInt32) : x.val.val = x.toNat := rfl @[simp] theorem UInt32.val_ofNat (n) : @@ -151,8 +145,6 @@ instance : Batteries.LawfulOrd UInt32 := .compareOfLessAndEq @[ext] theorem UInt64.ext : {x y : UInt64} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem UInt64.ext_iff {x y : UInt64} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, UInt64.ext⟩ - @[simp] theorem UInt64.val_val_eq_toNat (x : UInt64) : x.val.val = x.toNat := rfl @[simp] theorem UInt64.val_ofNat (n) : @@ -198,8 +190,6 @@ instance : Batteries.LawfulOrd UInt64 := .compareOfLessAndEq @[ext] theorem USize.ext : {x y : USize} → x.toNat = y.toNat → x = y | ⟨⟨_,_⟩⟩, ⟨⟨_,_⟩⟩, rfl => rfl -theorem USize.ext_iff {x y : USize} : x = y ↔ x.toNat = y.toNat := ⟨congrArg _, USize.ext⟩ - @[simp] theorem USize.val_val_eq_toNat (x : USize) : x.val.val = x.toNat := rfl @[simp] theorem USize.val_ofNat (n) : diff --git a/Batteries/Lean/SMap.lean b/Batteries/Lean/SMap.lean deleted file mode 100644 index 44a660e2e0..0000000000 --- a/Batteries/Lean/SMap.lean +++ /dev/null @@ -1,17 +0,0 @@ -/- -Copyright (c) 2023 Scott Morrison. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Scott Morrison --/ -import Lean.Data.SMap - -/-! -# Extra functions on Lean.SMap --/ - -set_option autoImplicit true - -/-- Monadic fold over a staged map. -/ -def Lean.SMap.foldM {m : Type w → Type w} [Monad m] [BEq α] [Hashable α] - (f : σ → α → β → m σ) (init : σ) (map : SMap α β) : m σ := do - map.map₂.foldlM f (← map.map₁.foldM f init) diff --git a/Batteries/Lean/Util/EnvSearch.lean b/Batteries/Lean/Util/EnvSearch.lean index 9143c89511..d9419b8cbf 100644 --- a/Batteries/Lean/Util/EnvSearch.lean +++ b/Batteries/Lean/Util/EnvSearch.lean @@ -24,8 +24,7 @@ where /-- Check constant should be returned -/ @[nolint unusedArguments] check matches_ (_name : Name) cinfo := do - let include ← p cinfo - if include then + if ← p cinfo then pure $ matches_.push cinfo else pure matches_ diff --git a/Batteries/Lean/Util/Path.lean b/Batteries/Lean/Util/Path.lean deleted file mode 100644 index d9488c0dc8..0000000000 --- a/Batteries/Lean/Util/Path.lean +++ /dev/null @@ -1,34 +0,0 @@ -/- -Copyright (c) 2022 Gabriel Ebner. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Gabriel Ebner --/ -import Lean.Elab.Term - -/-! -# `compile_time_search_path%` term elaborator. - -Use this as `searchPathRef.set compile_time_search_path%`. --/ - -open Lean System - --- Ideally this instance would be constructed simply by `deriving instance ToExpr for FilePath` --- but for now we have decided not to upstream the `ToExpr` derive handler from `Mathlib`. --- https://leanprover.zulipchat.com/#narrow/stream/348111-std4/topic/ToExpr.20derive.20handler/near/386476438 -instance : ToExpr FilePath where - toTypeExpr := mkConst ``FilePath - toExpr path := mkApp (mkConst ``FilePath.mk) (toExpr path.1) - -/-- -Term elaborator that retrieves the current `SearchPath`. - -Typical usage is `searchPathRef.set compile_time_search_path%`. - -This must not be used in files that are potentially compiled on another machine and then -imported. -(That is, if used in an imported file it will embed the search path from whichever machine -compiled the `.olean`.) --/ -elab "compile_time_search_path%" : term => - return toExpr (← searchPathRef.get) diff --git a/Batteries/Logic.lean b/Batteries/Logic.lean index d0fd84e688..5c6efe108a 100644 --- a/Batteries/Logic.lean +++ b/Batteries/Logic.lean @@ -16,10 +16,6 @@ instance {f : α → β} [DecidablePred p] : DecidablePred (p ∘ f) := theorem Function.id_def : @id α = fun x => x := rfl -/-! ## exists and forall -/ - -alias ⟨forall_not_of_not_exists, not_exists_of_forall_not⟩ := not_exists - /-! ## decidable -/ protected alias ⟨Decidable.exists_not_of_not_forall, _⟩ := Decidable.not_forall @@ -60,8 +56,7 @@ theorem funext₃ {β : α → Sort _} {γ : ∀ a, β a → Sort _} {δ : ∀ a {f g : ∀ a b c, δ a b c} (h : ∀ a b c, f a b c = g a b c) : f = g := funext fun _ => funext₂ <| h _ -theorem Function.funext_iff {β : α → Sort u} {f₁ f₂ : ∀ x : α, β x} : f₁ = f₂ ↔ ∀ a, f₁ a = f₂ a := - ⟨congrFun, funext⟩ +protected alias Function.funext_iff := funext_iff theorem ne_of_apply_ne {α β : Sort _} (f : α → β) {x y : α} : f x ≠ f y → x ≠ y := mt <| congrArg _ @@ -128,9 +123,7 @@ end Mem -- instance (priority := 10) {α} [Subsingleton α] : DecidableEq α -- | a, b => isTrue (Subsingleton.elim a b) --- @[simp] -- TODO(Mario): profile -theorem eq_iff_true_of_subsingleton [Subsingleton α] (x y : α) : x = y ↔ True := - iff_true_intro (Subsingleton.elim ..) +-- TODO(Mario): profile adding `@[simp]` to `eq_iff_true_of_subsingleton` /-- If all points are equal to a given point `x`, then `α` is a subsingleton. -/ theorem subsingleton_of_forall_eq (x : α) (h : ∀ y, y = x) : Subsingleton α := diff --git a/Batteries/StdDeprecations.lean b/Batteries/StdDeprecations.lean index c705ee839d..f82b1739a7 100644 --- a/Batteries/StdDeprecations.lean +++ b/Batteries/StdDeprecations.lean @@ -22,7 +22,6 @@ Let's hope that people using the tactic implementations can work this out themse -/ @[deprecated (since := "2024-05-07")] alias Std.AssocList := Batteries.AssocList -@[deprecated (since := "2024-05-07")] alias Std.HashMap := Batteries.HashMap @[deprecated (since := "2024-05-07")] alias Std.mkHashMap := Batteries.mkHashMap @[deprecated (since := "2024-05-07")] alias Std.DList := Batteries.DList @[deprecated (since := "2024-05-07")] alias Std.PairingHeapImp.Heap := Batteries.PairingHeapImp.Heap diff --git a/Batteries/Tactic/Lint/Basic.lean b/Batteries/Tactic/Lint/Basic.lean index 87cc925a06..948bab5456 100644 --- a/Batteries/Tactic/Lint/Basic.lean +++ b/Batteries/Tactic/Lint/Basic.lean @@ -42,6 +42,8 @@ def isAutoDecl (decl : Name) : CoreM Bool := do if env.isConstructor n && ["injEq", "inj", "sizeOf_spec"].any (· == s) then return true if let ConstantInfo.inductInfo _ := (← getEnv).find? n then + if s.startsWith "brecOn_" || s.startsWith "below_" || s.startsWith "binductionOn_" + || s.startsWith "ibelow_" then return true if [casesOnSuffix, recOnSuffix, brecOnSuffix, binductionOnSuffix, belowSuffix, "ibelow", "ndrec", "ndrecOn", "noConfusionType", "noConfusion", "ofNat", "toCtorIdx" ].any (· == s) then diff --git a/Batteries/Util/CheckTactic.lean b/Batteries/Util/CheckTactic.lean deleted file mode 100644 index bc97e681cc..0000000000 --- a/Batteries/Util/CheckTactic.lean +++ /dev/null @@ -1,124 +0,0 @@ -/- -Copyright (c) 2024 Lean FRO. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Joe Hendrix --/ -import Lean.Elab.Tactic.ElabTerm -import Lean.Elab.Term - -/- -This file is the home for commands to tactics behave as expected. - -It currently includes two tactics: - -#check_tactic t ~> res - - -only a #check_simp command that applies simp -IT --/ - -namespace Batteries.Tactic - -open Lean Elab Tactic -open Meta - -/-- -Type used to lift an arbitrary value into a type parameter so it can -appear in a proof goal. - -It is used by the #check_tactic command. --/ -private inductive CheckGoalType {α : Sort u} : (val : α) → Prop where -| intro : (val : α) → CheckGoalType val - -private def matchCheckGoalType (stx : Syntax) (goalType : Expr) : MetaM (Expr × Expr × Level) := do - let u ← mkFreshLevelMVar - let type ← mkFreshExprMVar (some (.sort u)) - let val ← mkFreshExprMVar (some type) - let extType := mkAppN (.const ``CheckGoalType [u]) #[type, val] - if !(← isDefEq goalType extType) then - throwErrorAt stx "Goal{indentExpr goalType}\nis expected to match {indentExpr extType}" - pure (val, type, u) - -/-- -`check_tactic_goal t` verifies that the goal has is equal to -`CheckGoalType t` with reducible transparency. It closes the goal if so -and otherwise reports an error. - -It is used by #check_tactic. --/ -local syntax (name := check_tactic_goal) "check_tactic_goal " term : tactic - -/-- -Implementation of `check_tactic_goal` --/ -@[tactic check_tactic_goal] private def evalCheckTacticGoal : Tactic := fun stx => - match stx with - | `(tactic| check_tactic_goal $exp) => - closeMainGoalUsing (checkUnassigned := false) fun goalType => do - let (val, type, u) ← matchCheckGoalType stx goalType - let expTerm ← elabTermEnsuringType exp type - if !(← Meta.withReducible <| isDefEq val expTerm) then - throwErrorAt stx - m!"Term reduces to{indentExpr val}\nbut is expected to reduce to {indentExpr expTerm}" - return mkAppN (.const ``CheckGoalType.intro [u]) #[type, val] - | _ => throwErrorAt stx "check_goal syntax error" - -/-- -`check_tactic_goal t` verifies that the goal has is equal to -`CheckGoalType t` with reducible transparency. It closes the goal if so -and otherwise reports an error. - -It is used by #check_tactic. --/ -local syntax (name := check_tactic_fails) "check_tactic_fails " tactic : tactic - -@[tactic check_tactic_fails] private def evalCheckTacticFails : Tactic := fun stx => do - let `(tactic| check_tactic_fails $tactic) := stx - | throwUnsupportedSyntax - closeMainGoalUsing (checkUnassigned := false) fun goalType => do - let (val, type, u) ← matchCheckGoalType stx goalType - Term.withoutErrToSorry <| withoutRecover do - match (← try (some <$> evalTactic tactic) catch _ => pure none) with - | none => - return mkAppN (.const ``CheckGoalType.intro [u]) #[type, val] - | some () => - let gls ← getGoals - let ppGoal (g : MVarId) := do - let (val, _type, _u) ← matchCheckGoalType stx (← g.getType) - pure m!"{indentExpr val}" - let msg ← - match gls with - | [] => pure m!"{tactic} expected to fail on {val}, but closed goal." - | [g] => - pure <| m!"{tactic} expected to fail on {val}, but returned: {←ppGoal g}" - | gls => - let app m g := do pure <| m ++ (←ppGoal g) - let init := m!"{tactic} expected to fail on {val}, but returned goals:" - gls.foldlM (init := init) app - throwErrorAt stx msg - -/-- -`#check_tactic t ~> r by commands` runs the tactic sequence `commands` -on a goal with t in the type and sees if the resulting expression has -reduced it to `r`. --/ -macro "#check_tactic " t:term "~>" result:term "by" tac:tactic : command => - `(command|example : CheckGoalType $t := by $tac; check_tactic_goal $result) - -/-- -`#check_simp t ~> r` checks `simp` reduces `t` to `r`. --/ -macro "#check_simp " t:term "~>" exp:term : command => - `(command|#check_tactic $t ~> $exp by simp) - -example (x : Nat) : CheckGoalType ((x + z) = x) := by - fail_if_success simp [] - exact (CheckGoalType.intro ((x + z) = x)) - -/-- -`#check_simp t !~>` checks `simp` fails to reduce `t`. --/ -macro "#check_simp " t:term "!~>" : command => - `(command|example : CheckGoalType $t := by check_tactic_fails simp) diff --git a/lean-toolchain b/lean-toolchain index 7f0ea50aaa..64981ae5f5 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.10.0 +leanprover/lean4:v4.11.0-rc1 diff --git a/scripts/runLinter.lean b/scripts/runLinter.lean index 3d98a1c902..4f18be6b50 100644 --- a/scripts/runLinter.lean +++ b/scripts/runLinter.lean @@ -1,6 +1,6 @@ +import Lean.Util.SearchPath import Batteries.Tactic.Lint import Batteries.Data.Array.Basic -import Batteries.Lean.Util.Path open Lean Core Elab Command Std.Tactic.Lint open System (FilePath) diff --git a/test/array.lean b/test/array.lean index 41338a8bd4..2ba3a29577 100644 --- a/test/array.lean +++ b/test/array.lean @@ -1,4 +1,3 @@ -import Batteries.Util.CheckTactic import Batteries.Data.Array section diff --git a/test/congr.lean b/test/congr.lean index a71aed0315..065a899f99 100644 --- a/test/congr.lean +++ b/test/congr.lean @@ -19,8 +19,6 @@ example {α β γ δ} {F : ∀ {α β}, (α → β) → γ → δ} {f g : α → -- apply_assumption -- FIXME apply h -attribute [ext] Subtype.eq - example {α β : Type _} {f : _ → β} {x y : { x : { x : α // x = x } // x = x }} (h : x.1 = y.1) : f x = f y := by congr with : 1 From dc167d260ff7ee9849b436037add06bed15104be Mon Sep 17 00:00:00 2001 From: Austin Letson Date: Sun, 4 Aug 2024 22:57:37 -0400 Subject: [PATCH 161/208] chore: bump lean-action to v1 (#904) --- .github/workflows/build.yml | 3 +-- lakefile.lean | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 58ca29d3d1..15d72c6876 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,10 +18,9 @@ jobs: - id: lean-action name: build, test, and lint batteries - uses: leanprover/lean-action@v1-beta + uses: leanprover/lean-action@v1 with: build-args: '-Kwerror' - lint-module: 'Batteries' - name: Check that all files are imported run: lake env lean scripts/check_imports.lean diff --git a/lakefile.lean b/lakefile.lean index 7ee5efafe6..e55e8b2639 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -13,7 +13,7 @@ package batteries where @[default_target] lean_lib Batteries -@[default_target] +@[default_target, lint_driver] lean_exe runLinter where srcDir := "scripts" supportInterpreter := true From 38641f12b7c80911a36de6b6dd6911d601c4c417 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Mon, 5 Aug 2024 09:05:22 +0000 Subject: [PATCH 162/208] chore: bump to nightly-2024-08-05 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 7e87556fbd..8e8dd4666c 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-03 +leanprover/lean4:nightly-2024-08-05 From 603d79d447b9fb846bbdf1c44791cac56edf5640 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Thu, 8 Aug 2024 09:05:11 +0000 Subject: [PATCH 163/208] chore: bump to nightly-2024-08-08 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 8e8dd4666c..9f6eaf7908 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-05 +leanprover/lean4:nightly-2024-08-08 From b51c0d6233054421a9faf42a83853f99405442c6 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 8 Aug 2024 20:50:20 +1000 Subject: [PATCH 164/208] fixes --- Batteries/Lean/AttributeExtra.lean | 4 +++- Batteries/Lean/Meta/Inaccessible.lean | 2 +- Batteries/Linter/UnnecessarySeqFocus.lean | 4 ++-- Batteries/Linter/UnreachableTactic.lean | 2 +- Batteries/Tactic/Lint/Frontend.lean | 6 +++--- Batteries/Tactic/Lint/Misc.lean | 4 ++-- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Batteries/Lean/AttributeExtra.lean b/Batteries/Lean/AttributeExtra.lean index aeac0267c5..adb6c0ef1f 100644 --- a/Batteries/Lean/AttributeExtra.lean +++ b/Batteries/Lean/AttributeExtra.lean @@ -8,6 +8,8 @@ open Lean namespace Lean +open Std + /-- `TagAttributeExtra` works around a limitation of `TagAttribute`, which is that definitions must be tagged in the same file that declares the definition. @@ -94,7 +96,7 @@ or `none` if `decl` is not tagged. -/ def getParam? [Inhabited α] (attr : ParametricAttributeExtra α) (env : Environment) (decl : Name) : Option α := - attr.attr.getParam? env decl <|> attr.base.find? decl + attr.attr.getParam? env decl <|> attr.base[decl]? /-- Applies attribute `attr` to declaration `decl`, given a value for the parameter. -/ def setParam (attr : ParametricAttributeExtra α) diff --git a/Batteries/Lean/Meta/Inaccessible.lean b/Batteries/Lean/Meta/Inaccessible.lean index e308364616..fbc50a363e 100644 --- a/Batteries/Lean/Meta/Inaccessible.lean +++ b/Batteries/Lean/Meta/Inaccessible.lean @@ -5,7 +5,7 @@ Authors: Jannis Limperg -/ import Lean.Meta.InferType -open Lean Lean.Meta +open Lean Lean.Meta Std /-- Obtain the inaccessible fvars from the given local context. An fvar is diff --git a/Batteries/Linter/UnnecessarySeqFocus.lean b/Batteries/Linter/UnnecessarySeqFocus.lean index 566da1d490..f53fd05f51 100644 --- a/Batteries/Linter/UnnecessarySeqFocus.lean +++ b/Batteries/Linter/UnnecessarySeqFocus.lean @@ -8,7 +8,7 @@ import Lean.Linter.Util import Batteries.Lean.AttributeExtra namespace Batteries.Linter -open Lean Elab Command Linter +open Lean Elab Command Linter Std /-- Enables the 'unnecessary `<;>`' linter. This will warn whenever the `<;>` tactic combinator @@ -120,7 +120,7 @@ partial def markUsedTactics : InfoTree → M ω Unit | .node i c => do if let .ofTacticInfo i := i then if let some r := i.stx.getRange? true then - if let some entry := (← get).find? r then + if let some entry := (← get)[r]? then if i.stx.getKind == ``Parser.Tactic.«tactic_<;>_» then let isBad := do unless i.goalsBefore.length == 1 || !multigoalAttr.hasTag env i.stx[0].getKind do diff --git a/Batteries/Linter/UnreachableTactic.lean b/Batteries/Linter/UnreachableTactic.lean index a4bedbe10c..cd73649969 100644 --- a/Batteries/Linter/UnreachableTactic.lean +++ b/Batteries/Linter/UnreachableTactic.lean @@ -8,7 +8,7 @@ import Lean.Linter.Util import Batteries.Tactic.Unreachable namespace Batteries.Linter -open Lean Elab Command Linter +open Lean Elab Command Linter Std /-- Enables the 'unreachable tactic' linter. This will warn on any tactics that are never executed. diff --git a/Batteries/Tactic/Lint/Frontend.lean b/Batteries/Tactic/Lint/Frontend.lean index 841c696af8..2402005085 100644 --- a/Batteries/Tactic/Lint/Frontend.lean +++ b/Batteries/Tactic/Lint/Frontend.lean @@ -126,7 +126,7 @@ def sortResults (results : HashMap Name α) : CoreM <| Array (Name × α) := do for (n, _) in results.toArray do if let some range ← findDeclarationRanges? n then key := key.insert n <| range.range.pos.line - pure $ results.toArray.qsort fun (a, _) (b, _) => key.findD a 0 < key.findD b 0 + pure $ results.toArray.qsort fun (a, _) (b, _) => key.getD a 0 < key.getD b 0 /-- Formats a linter warning as `#check` command with comment. -/ def printWarning (declName : Name) (warning : MessageData) (useErrorFormat : Bool := false) @@ -158,7 +158,7 @@ def groupedByFilename (results : HashMap Name MessageData) (useErrorFormat : Boo let mod ← findModuleOf? declName let mod := mod.getD (← getEnv).mainModule grouped.insert mod <$> - match grouped.find? mod with + match grouped[mod]? with | some (fp, msgs) => pure (fp, msgs.insert declName msg) | none => do let fp ← if useErrorFormat then @@ -210,7 +210,7 @@ def getDeclsInCurrModule : CoreM (Array Name) := do /-- Get the list of all declarations in the environment. -/ def getAllDecls : CoreM (Array Name) := do pure $ (← getEnv).constants.map₁.fold (init := ← getDeclsInCurrModule) fun r k _ => r.push k - +#check ModuleIdx /-- Get the list of all declarations in the specified package. -/ def getDeclsInPackage (pkg : Name) : CoreM (Array Name) := do let env ← getEnv diff --git a/Batteries/Tactic/Lint/Misc.lean b/Batteries/Tactic/Lint/Misc.lean index 3f0e69f648..a0aa8bc884 100644 --- a/Batteries/Tactic/Lint/Misc.lean +++ b/Batteries/Tactic/Lint/Misc.lean @@ -12,7 +12,7 @@ import Lean.Util.Recognizers import Lean.DocString import Batteries.Tactic.Lint.Basic -open Lean Meta +open Lean Meta Std namespace Std.Tactic.Lint @@ -143,7 +143,7 @@ In pseudo-mathematical form, this returns `{{p : parameter | p ∈ u} | (u : lev FIXME: We use `Array Name` instead of `HashSet Name`, since `HashSet` does not have an equality instance. It will ignore `nm₀.proof_i` declarations. -/ -private def univParamsGrouped (e : Expr) (nm₀ : Name) : Lean.HashSet (Array Name) := +private def univParamsGrouped (e : Expr) (nm₀ : Name) : HashSet (Array Name) := runST fun σ => do let res ← ST.mkRef (σ := σ) {} e.forEach fun From 91b5badc9472b397204b83ab6a9d0844822cd6a4 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 8 Aug 2024 20:51:47 +1000 Subject: [PATCH 165/208] fix --- Batteries/Tactic/Lint/Frontend.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Batteries/Tactic/Lint/Frontend.lean b/Batteries/Tactic/Lint/Frontend.lean index 2402005085..9b8b986077 100644 --- a/Batteries/Tactic/Lint/Frontend.lean +++ b/Batteries/Tactic/Lint/Frontend.lean @@ -217,7 +217,7 @@ def getDeclsInPackage (pkg : Name) : CoreM (Array Name) := do let mut decls ← getDeclsInCurrModule let modules := env.header.moduleNames.map (pkg.isPrefixOf ·) return env.constants.map₁.fold (init := decls) fun decls declName _ => - if modules[env.const2ModIdx[declName].get! (α := Nat)]! then + if modules[env.const2ModIdx[declName]?.get! (α := Nat)]! then decls.push declName else decls From 25407e0648fb0f218fa7a6df836b77d18b1030d4 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 8 Aug 2024 20:52:43 +1000 Subject: [PATCH 166/208] chore: squeeze a simp in HashMap/WF --- Batteries/Data/HashMap/WF.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index e83e32e567..427e2a4537 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -224,7 +224,7 @@ private theorem pairwise_replaceF [BEq α] [PartialEquivBEq α] | cons a l ih => simp only [List.pairwise_cons, List.replaceF] at H ⊢ generalize e : cond .. = z; unfold cond at e; revert e - split <;> (intro h; subst h; simp) + split <;> (intro h; subst h; simp only [List.pairwise_cons]) · next e => exact ⟨(H.1 · · ∘ PartialEquivBEq.trans e), H.2⟩ · next e => refine ⟨fun a h => ?_, ih H.2⟩ From 970abecff9b025caa9f8ba4b19ee57217f2d601b Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 8 Aug 2024 21:00:50 +1000 Subject: [PATCH 167/208] fixes --- Batteries/Data/Array/Lemmas.lean | 5 +++++ Batteries/Data/UnionFind/Basic.lean | 3 ++- Batteries/Tactic/Lint/Frontend.lean | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Batteries/Data/Array/Lemmas.lean b/Batteries/Data/Array/Lemmas.lean index 753cbb4955..10102cb3cc 100644 --- a/Batteries/Data/Array/Lemmas.lean +++ b/Batteries/Data/Array/Lemmas.lean @@ -11,6 +11,11 @@ import Batteries.Util.ProofWanted namespace Array +theorem get_modify {arr : Array α} {x i} (h : i < arr.size) : + (arr.modify x f).get ⟨i, by simp [h]⟩ = + if x = i then f (arr.get ⟨i, h⟩) else arr.get ⟨i, h⟩ := by + simp [getElem_modify h] + theorem forIn_eq_data_forIn [Monad m] (as : Array α) (b : β) (f : α → β → m (ForInStep β)) : forIn as b f = forIn as.data b f := by diff --git a/Batteries/Data/UnionFind/Basic.lean b/Batteries/Data/UnionFind/Basic.lean index 292f4285eb..10b37105a3 100644 --- a/Batteries/Data/UnionFind/Basic.lean +++ b/Batteries/Data/UnionFind/Basic.lean @@ -307,7 +307,8 @@ theorem rankD_findAux {self : UnionFind} {x : Fin self.size} : rw [findAux_s]; split <;> [rfl; skip] have := Nat.sub_lt_sub_left (self.lt_rankMax x) (self.rank'_lt _ ‹_›) have := lt_of_parentD (by rwa [parentD_eq]) - rw [rankD_eq' (by simp [FindAux.size_eq, h]), Array.get_modify (by rwa [FindAux.size_eq])] + rw [rankD_eq' (by simp [FindAux.size_eq, h])] + rw [Array.get_modify (by rwa [FindAux.size_eq])] split <;> simp [← rankD_eq, rankD_findAux (x := ⟨_, self.parent'_lt x⟩), -Array.get_eq_getElem] else simp only [rankD, Array.data_length, Array.get_eq_getElem, rank] diff --git a/Batteries/Tactic/Lint/Frontend.lean b/Batteries/Tactic/Lint/Frontend.lean index 9b8b986077..27ff3bf3b2 100644 --- a/Batteries/Tactic/Lint/Frontend.lean +++ b/Batteries/Tactic/Lint/Frontend.lean @@ -210,7 +210,7 @@ def getDeclsInCurrModule : CoreM (Array Name) := do /-- Get the list of all declarations in the environment. -/ def getAllDecls : CoreM (Array Name) := do pure $ (← getEnv).constants.map₁.fold (init := ← getDeclsInCurrModule) fun r k _ => r.push k -#check ModuleIdx + /-- Get the list of all declarations in the specified package. -/ def getDeclsInPackage (pkg : Name) : CoreM (Array Name) := do let env ← getEnv From b7483cacd0924710dc5f537079407d0dddd7c661 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 8 Aug 2024 21:26:06 +1000 Subject: [PATCH 168/208] make HashSet about Std.HashSet --- Batteries/Lean/HashSet.lean | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Batteries/Lean/HashSet.lean b/Batteries/Lean/HashSet.lean index 0dedb7cd4f..7882358c40 100644 --- a/Batteries/Lean/HashSet.lean +++ b/Batteries/Lean/HashSet.lean @@ -4,9 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jannis Limperg -/ -import Lean.Data.HashSet +import Std.Data.HashSet -namespace Lean.HashSet +namespace Std.HashSet variable [BEq α] [Hashable α] @@ -66,10 +66,3 @@ def insert' (s : HashSet α) (a : α) : HashSet α × Bool := @[inline] protected def ofArray [BEq α] [Hashable α] (as : Array α) : HashSet α := HashSet.empty.insertMany as - -/-- -`O(n)`. Obtain a `HashSet` from a list. --/ -@[inline] -protected def ofList [BEq α] [Hashable α] (as : List α) : HashSet α := - HashSet.empty.insertMany as From f6e1701760d626ef83524d2be02c5f3c0b0f34a4 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 8 Aug 2024 21:44:13 +1000 Subject: [PATCH 169/208] fix test --- test/where.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/test/where.lean b/test/where.lean index 6fd098ce53..5f7a4bcfa3 100644 --- a/test/where.lean +++ b/test/where.lean @@ -2,6 +2,7 @@ import Batteries.Tactic.Where -- Return to pristine state set_option linter.missingDocs false +set_option internal.minimalSnapshots false /-- info: -- In root namespace with initial scope -/ #guard_msgs in #where From 9b5453767f2f0aa5b454de21dd47874514b53dec Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 8 Aug 2024 21:46:38 +1000 Subject: [PATCH 170/208] fix import script --- scripts/check_imports.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_imports.lean b/scripts/check_imports.lean index 94e778369f..55bf0e8342 100644 --- a/scripts/check_imports.lean +++ b/scripts/check_imports.lean @@ -70,7 +70,7 @@ def writeImportModule (path : FilePath) (imports : Array Name) : IO Unit := do /-- Check for imports and return true if warnings issued. -/ def checkMissingImports (modName : Name) (modData : ModuleData) (reqImports : Array Name) : LogIO Bool := do - let names : HashSet Name := HashSet.ofArray (modData.imports.map (·.module)) + let names : Std.HashSet Name := Std.HashSet.ofArray (modData.imports.map (·.module)) let mut warned := false for req in reqImports do if !names.contains req then From 518a0b511d1d638e262029de44a20205afb1128c Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 9 Aug 2024 09:06:04 +0000 Subject: [PATCH 171/208] chore: bump to nightly-2024-08-09 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 9f6eaf7908..5f8607c8c0 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-08 +leanprover/lean4:nightly-2024-08-09 From 9cf9bd609587e4b56ec6fc05b36e82065fada39e Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 9 Aug 2024 20:42:01 +1000 Subject: [PATCH 172/208] adaptations for 08-09 --- Batteries.lean | 1 - Batteries/Data/LazyList.lean | 2 +- Batteries/Data/Thunk.lean | 10 ---------- Batteries/Lean/AttributeExtra.lean | 4 +++- Batteries/Lean/HashMap.lean | 19 ++++--------------- Batteries/Lean/Meta/Inaccessible.lean | 2 +- Batteries/Linter/UnnecessarySeqFocus.lean | 2 +- Batteries/Linter/UnreachableTactic.lean | 4 ++-- 8 files changed, 12 insertions(+), 32 deletions(-) delete mode 100644 Batteries/Data/Thunk.lean diff --git a/Batteries.lean b/Batteries.lean index 8e1e6f1828..73fc4efa9b 100644 --- a/Batteries.lean +++ b/Batteries.lean @@ -35,7 +35,6 @@ import Batteries.Data.Range import Batteries.Data.Rat import Batteries.Data.String import Batteries.Data.Sum -import Batteries.Data.Thunk import Batteries.Data.UInt import Batteries.Data.UnionFind import Batteries.Lean.AttributeExtra diff --git a/Batteries/Data/LazyList.lean b/Batteries/Data/LazyList.lean index 426cdd2248..a9100fcd48 100644 --- a/Batteries/Data/LazyList.lean +++ b/Batteries/Data/LazyList.lean @@ -3,7 +3,7 @@ Copyright (c) 2017 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Simon Hudon -/ -import Batteries.Data.Thunk + /-! # Lazy lists diff --git a/Batteries/Data/Thunk.lean b/Batteries/Data/Thunk.lean deleted file mode 100644 index 88c92c3784..0000000000 --- a/Batteries/Data/Thunk.lean +++ /dev/null @@ -1,10 +0,0 @@ -/- -Copyright (c) 2024 François G. Dorais. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE -Authors: François G. Dorais, et al. --/ - -namespace Thunk - -@[ext] protected theorem ext : {a b : Thunk α} → a.get = b.get → a = b - | {..}, {..}, heq => congrArg _ <| funext fun _ => heq diff --git a/Batteries/Lean/AttributeExtra.lean b/Batteries/Lean/AttributeExtra.lean index adb6c0ef1f..99eb7da612 100644 --- a/Batteries/Lean/AttributeExtra.lean +++ b/Batteries/Lean/AttributeExtra.lean @@ -4,6 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Batteries.Lean.TagAttribute +import Std.Data.HashMap.Basic + open Lean namespace Lean @@ -75,7 +77,7 @@ structure ParametricAttributeExtra (α : Type) where /-- The underlying `ParametricAttribute`. -/ attr : ParametricAttribute α /-- A list of pre-tagged declarations with their values. -/ - base : HashMap Name α + base : Std.HashMap Name α deriving Inhabited /-- diff --git a/Batteries/Lean/HashMap.lean b/Batteries/Lean/HashMap.lean index a8e963cf94..0cb3b0f87d 100644 --- a/Batteries/Lean/HashMap.lean +++ b/Batteries/Lean/HashMap.lean @@ -4,22 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jannis Limperg -/ -import Lean.Data.HashMap - -namespace Lean.HashMap +import Std.Data.HashMap.Basic +namespace Std.HashMap variable [BEq α] [Hashable α] -instance : ForIn m (HashMap α β) (α × β) where - forIn m init f := do - let mut acc := init - for buckets in m.val.buckets.val do - for d in buckets do - match ← f d acc with - | .done b => return b - | .yield b => acc := b - return acc - /-- `O(|other|)` amortized. Merge two `HashMap`s. The values of keys which appear in both maps are combined using the monadic function `f`. @@ -28,7 +17,7 @@ The values of keys which appear in both maps are combined using the monadic func def mergeWithM {m α β} [BEq α] [Hashable α] [Monad m] (f : α → β → β → m β) (self other : HashMap α β) : m (HashMap α β) := other.foldM (init := self) fun map k v₂ => - match map.find? k with + match map[k]? with | none => return map.insert k v₂ | some v₁ => return map.insert k (← f k v₁ v₂) @@ -41,6 +30,6 @@ def mergeWith (f : α → β → β → β) (self other : HashMap α β) : HashM -- Implementing this function directly, rather than via `mergeWithM`, gives -- us less constrained universes. other.fold (init := self) fun map k v₂ => - match map.find? k with + match map[k]? with | none => map.insert k v₂ | some v₁ => map.insert k <| f k v₁ v₂ diff --git a/Batteries/Lean/Meta/Inaccessible.lean b/Batteries/Lean/Meta/Inaccessible.lean index fbc50a363e..a955d21f32 100644 --- a/Batteries/Lean/Meta/Inaccessible.lean +++ b/Batteries/Lean/Meta/Inaccessible.lean @@ -15,7 +15,7 @@ later fvar with the same user name. def Lean.LocalContext.inaccessibleFVars (lctx : LocalContext) : Array LocalDecl := let (result, _) := - lctx.foldr (β := Array LocalDecl × HashSet Name) + lctx.foldr (β := Array LocalDecl × Std.HashSet Name) (init := (Array.mkEmpty lctx.numIndices, {})) fun ldecl (result, seen) => if ldecl.isImplementationDetail then diff --git a/Batteries/Linter/UnnecessarySeqFocus.lean b/Batteries/Linter/UnnecessarySeqFocus.lean index f53fd05f51..dca3aac1d7 100644 --- a/Batteries/Linter/UnnecessarySeqFocus.lean +++ b/Batteries/Linter/UnnecessarySeqFocus.lean @@ -83,7 +83,7 @@ structure Entry where used : Bool /-- The monad for collecting used tactic syntaxes. -/ -abbrev M (ω) := StateRefT (HashMap String.Range Entry) (ST ω) +abbrev M (ω) := StateRefT (Std.HashMap String.Range Entry) (ST ω) /-- True if this is a `<;>` node in either `tactic` or `conv` classes. -/ @[inline] def isSeqFocus (k : SyntaxNodeKind) : Bool := diff --git a/Batteries/Linter/UnreachableTactic.lean b/Batteries/Linter/UnreachableTactic.lean index cd73649969..1e55702674 100644 --- a/Batteries/Linter/UnreachableTactic.lean +++ b/Batteries/Linter/UnreachableTactic.lean @@ -29,14 +29,14 @@ namespace UnreachableTactic def getLinterUnreachableTactic (o : Options) : Bool := getLinterValue linter.unreachableTactic o /-- The monad for collecting used tactic syntaxes. -/ -abbrev M := StateRefT (HashMap String.Range Syntax) IO +abbrev M := StateRefT (Std.HashMap String.Range Syntax) IO /-- A list of blacklisted syntax kinds, which are expected to have subterms that contain unevaluated tactics. -/ initialize ignoreTacticKindsRef : IO.Ref NameHashSet ← - IO.mkRef <| HashSet.empty + IO.mkRef <| Std.HashSet.empty |>.insert ``Parser.Term.binderTactic |>.insert ``Lean.Parser.Term.dynamicQuot |>.insert ``Lean.Parser.Tactic.quotSeq From 1279860a96b1d5550deb1609d712fe15759cf12a Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Sat, 10 Aug 2024 21:36:42 +1000 Subject: [PATCH 173/208] bump toolchain --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 5f8607c8c0..f915e32682 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-09 +leanprover/lean4:nightly-2024-08-10 From a13dba6e8361e194aa2b8899452bc52845dc1a69 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Sat, 10 Aug 2024 21:51:42 +1000 Subject: [PATCH 174/208] fix --- Batteries/Data/ByteArray.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Batteries/Data/ByteArray.lean b/Batteries/Data/ByteArray.lean index f147eaf47b..7dc2df7f10 100644 --- a/Batteries/Data/ByteArray.lean +++ b/Batteries/Data/ByteArray.lean @@ -132,7 +132,7 @@ private def ofFnAux (f : Fin n → UInt8) : ByteArray := go 0 (mkEmpty n) where termination_by n - i @[csimp] private theorem ofFn_eq_ofFnAux : @ofFn = @ofFnAux := by - funext n f; ext; simp [ofFnAux, Array.ofFn, ofFnAux_data, mkEmpty] + funext n f; ext1; simp [ofFnAux, Array.ofFn, ofFnAux_data, mkEmpty] where ofFnAux_data {n} (f : Fin n → UInt8) (i) {acc} : (ofFnAux.go f i acc).data = Array.ofFn.go f i acc.data := by From 52dafab1713d9550af13df2092a198428b0f3c9c Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sun, 11 Aug 2024 09:05:27 +0000 Subject: [PATCH 175/208] chore: bump to nightly-2024-08-11 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index f915e32682..1645171233 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-10 +leanprover/lean4:nightly-2024-08-11 From 7b244eafac9dd0d47735d0a9a3a906bfb4910246 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 12 Aug 2024 12:35:52 +1000 Subject: [PATCH 176/208] chore: shake Batteries (#903) --- Batteries/CodeAction/Attr.lean | 2 +- Batteries/CodeAction/Deprecated.lean | 1 - Batteries/Data/ByteArray.lean | 1 - Batteries/Data/HashMap/Lemmas.lean | 1 - Batteries/Data/HashMap/WF.lean | 3 ++- Batteries/Data/List/Pairwise.lean | 1 - Batteries/Data/Rat/Basic.lean | 1 - Batteries/Data/String/Lemmas.lean | 1 - Batteries/Data/UnionFind/Basic.lean | 2 +- Batteries/Lean/Meta/AssertHypotheses.lean | 2 +- Batteries/Lean/Meta/Basic.lean | 4 +--- Batteries/Lean/Meta/Clear.lean | 1 + Batteries/Lean/Meta/Inaccessible.lean | 2 +- Batteries/Lean/Position.lean | 1 - Batteries/Lean/System/IO.lean | 1 - Batteries/Logic.lean | 2 -- Batteries/StdDeprecations.lean | 8 ++++---- Batteries/Tactic/Case.lean | 2 +- Batteries/Tactic/Classical.lean | 2 +- Batteries/Tactic/Init.lean | 6 ++---- Batteries/Tactic/NoMatch.lean | 2 +- Batteries/Tactic/PrintDependents.lean | 1 - Batteries/Tactic/PrintPrefix.lean | 1 - Batteries/Tactic/SeqFocus.lean | 2 +- Batteries/Tactic/ShowUnused.lean | 1 - Batteries/Tactic/Unreachable.lean | 2 +- Batteries/Util/Cache.lean | 2 +- Batteries/Util/ExtendedBinder.lean | 2 -- Batteries/Util/LibraryNote.lean | 2 +- test/MLList.lean | 1 + 30 files changed, 22 insertions(+), 38 deletions(-) diff --git a/Batteries/CodeAction/Attr.lean b/Batteries/CodeAction/Attr.lean index ad5e0f62d3..79802d6932 100644 --- a/Batteries/CodeAction/Attr.lean +++ b/Batteries/CodeAction/Attr.lean @@ -3,7 +3,7 @@ Copyright (c) 2023 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Lean.Server.CodeActions +import Lean.Server.CodeActions.Basic /-! # Initial setup for code action attributes diff --git a/Batteries/CodeAction/Deprecated.lean b/Batteries/CodeAction/Deprecated.lean index ec6a2f11c2..ce98bcc5c6 100644 --- a/Batteries/CodeAction/Deprecated.lean +++ b/Batteries/CodeAction/Deprecated.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro -/ import Lean.Server.CodeActions import Batteries.CodeAction.Basic -import Batteries.Lean.Position /-! # Code action for @[deprecated] replacements diff --git a/Batteries/Data/ByteArray.lean b/Batteries/Data/ByteArray.lean index f147eaf47b..585563ec5a 100644 --- a/Batteries/Data/ByteArray.lean +++ b/Batteries/Data/ByteArray.lean @@ -3,7 +3,6 @@ Copyright (c) 2023 François G. Dorais. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: François G. Dorais -/ -import Batteries.Data.Array.Lemmas namespace ByteArray diff --git a/Batteries/Data/HashMap/Lemmas.lean b/Batteries/Data/HashMap/Lemmas.lean index 290f4c0cff..79107fc0bf 100644 --- a/Batteries/Data/HashMap/Lemmas.lean +++ b/Batteries/Data/HashMap/Lemmas.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ import Batteries.Data.HashMap.Basic -import Batteries.Data.Array.Lemmas /-! # Lemmas for `Batteries.HashMap` diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index e83e32e567..ae51625133 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -3,9 +3,10 @@ Copyright (c) 2022 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ +import Batteries.Tactic.SeqFocus import Batteries.Data.HashMap.Basic -import Batteries.Data.Array.Lemmas import Batteries.Data.Nat.Lemmas +import Batteries.Data.List.Lemmas namespace Batteries.HashMap namespace Imp diff --git a/Batteries/Data/List/Pairwise.lean b/Batteries/Data/List/Pairwise.lean index dd94875ca9..9df947bf4c 100644 --- a/Batteries/Data/List/Pairwise.lean +++ b/Batteries/Data/List/Pairwise.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, James Gallicchio -/ import Batteries.Data.List.Count -import Batteries.Data.Fin.Lemmas /-! # Pairwise relations on a list diff --git a/Batteries/Data/Rat/Basic.lean b/Batteries/Data/Rat/Basic.lean index 600e67981f..f96651d34c 100644 --- a/Batteries/Data/Rat/Basic.lean +++ b/Batteries/Data/Rat/Basic.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Batteries.Data.Nat.Gcd -import Batteries.Data.Int.DivMod import Batteries.Lean.Float /-! # Basics for the Rational Numbers -/ diff --git a/Batteries/Data/String/Lemmas.lean b/Batteries/Data/String/Lemmas.lean index 9984d0fb52..df338e03ff 100644 --- a/Batteries/Data/String/Lemmas.lean +++ b/Batteries/Data/String/Lemmas.lean @@ -8,7 +8,6 @@ import Batteries.Data.List.Lemmas import Batteries.Data.String.Basic import Batteries.Tactic.Lint.Misc import Batteries.Tactic.SeqFocus -import Batteries.Tactic.SqueezeScope namespace String diff --git a/Batteries/Data/UnionFind/Basic.lean b/Batteries/Data/UnionFind/Basic.lean index 292f4285eb..e0b4174112 100644 --- a/Batteries/Data/UnionFind/Basic.lean +++ b/Batteries/Data/UnionFind/Basic.lean @@ -3,8 +3,8 @@ Copyright (c) 2021 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Batteries.Data.Array.Lemmas import Batteries.Tactic.Lint.Misc +import Batteries.Tactic.SeqFocus namespace Batteries diff --git a/Batteries/Lean/Meta/AssertHypotheses.lean b/Batteries/Lean/Meta/AssertHypotheses.lean index a0905c6718..6275032063 100644 --- a/Batteries/Lean/Meta/AssertHypotheses.lean +++ b/Batteries/Lean/Meta/AssertHypotheses.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jannis Limperg -/ -import Batteries.Lean.Meta.Basic +import Lean.Meta.Tactic.Assert open Lean Lean.Meta diff --git a/Batteries/Lean/Meta/Basic.lean b/Batteries/Lean/Meta/Basic.lean index 3e72809893..d2c55af7ea 100644 --- a/Batteries/Lean/Meta/Basic.lean +++ b/Batteries/Lean/Meta/Basic.lean @@ -3,9 +3,7 @@ Copyright (c) 2022 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Jannis Limperg -/ -import Lean.Elab.Term -import Lean.Meta.Tactic.Apply -import Lean.Meta.Tactic.Replace +import Lean.Meta.Tactic.Intro open Lean Lean.Meta diff --git a/Batteries/Lean/Meta/Clear.lean b/Batteries/Lean/Meta/Clear.lean index 47caaaa4d3..66f38b7798 100644 --- a/Batteries/Lean/Meta/Clear.lean +++ b/Batteries/Lean/Meta/Clear.lean @@ -5,6 +5,7 @@ Authors: Jannis Limperg -/ import Batteries.Lean.Meta.Basic +import Lean.Meta.Tactic.Clear open Lean Lean.Meta diff --git a/Batteries/Lean/Meta/Inaccessible.lean b/Batteries/Lean/Meta/Inaccessible.lean index e308364616..e63c4ec4f7 100644 --- a/Batteries/Lean/Meta/Inaccessible.lean +++ b/Batteries/Lean/Meta/Inaccessible.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Jannis Limperg. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jannis Limperg -/ -import Lean.Meta.InferType +import Lean.Meta.Basic open Lean Lean.Meta diff --git a/Batteries/Lean/Position.lean b/Batteries/Lean/Position.lean index f2bc155886..49fdad203e 100644 --- a/Batteries/Lean/Position.lean +++ b/Batteries/Lean/Position.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Lean.Syntax -import Lean.Meta.Tactic.TryThis import Lean.Data.Lsp.Utf16 /-- Gets the LSP range of syntax `stx`. -/ diff --git a/Batteries/Lean/System/IO.lean b/Batteries/Lean/System/IO.lean index c4d6b6ce84..40dcda5365 100644 --- a/Batteries/Lean/System/IO.lean +++ b/Batteries/Lean/System/IO.lean @@ -3,7 +3,6 @@ Copyright (c) 2023 Scott Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ -import Batteries.Data.List.Lemmas /-! # Functions for manipulating a list of tasks diff --git a/Batteries/Logic.lean b/Batteries/Logic.lean index 5c6efe108a..03c82eb5ac 100644 --- a/Batteries/Logic.lean +++ b/Batteries/Logic.lean @@ -3,9 +3,7 @@ Copyright (c) 2014 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Jeremy Avigad, Floris van Doorn, Mario Carneiro -/ -import Batteries.Tactic.Init import Batteries.Tactic.Alias -import Batteries.Tactic.Lint.Misc instance {f : α → β} [DecidablePred p] : DecidablePred (p ∘ f) := inferInstanceAs <| DecidablePred fun x => p (f x) diff --git a/Batteries/StdDeprecations.lean b/Batteries/StdDeprecations.lean index f82b1739a7..cb49a3bdbf 100644 --- a/Batteries/StdDeprecations.lean +++ b/Batteries/StdDeprecations.lean @@ -4,12 +4,12 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ import Batteries.Tactic.Alias -import Batteries.Data.HashMap import Batteries.Data.DList import Batteries.Data.PairingHeap -import Batteries.Data.RBMap -import Batteries.Data.BinomialHeap -import Batteries.Data.UnionFind +import Batteries.Data.BinomialHeap.Basic +import Batteries.Data.HashMap.Basic +import Batteries.Data.RBMap.Basic +import Batteries.Data.UnionFind.Basic /-! # We set up deprecations for identifiers formerly in the `Std` namespace. diff --git a/Batteries/Tactic/Case.lean b/Batteries/Tactic/Case.lean index 60bd585244..375d351b05 100644 --- a/Batteries/Tactic/Case.lean +++ b/Batteries/Tactic/Case.lean @@ -3,7 +3,7 @@ Copyright (c) 2023 Kyle Miller. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ -import Lean.Elab.Tactic.Conv.Pattern +import Lean.Elab.Tactic.BuiltinTactic /-! # Extensions to the `case` tactic diff --git a/Batteries/Tactic/Classical.lean b/Batteries/Tactic/Classical.lean index 7d3e6eb3c0..a3bc78b0a4 100644 --- a/Batteries/Tactic/Classical.lean +++ b/Batteries/Tactic/Classical.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Lean.Elab.ElabRules +import Lean.Elab.Tactic.Basic /-! # `classical` tactic -/ diff --git a/Batteries/Tactic/Init.lean b/Batteries/Tactic/Init.lean index fed3c1ad99..db7894f633 100644 --- a/Batteries/Tactic/Init.lean +++ b/Batteries/Tactic/Init.lean @@ -3,16 +3,14 @@ Copyright (c) 2021 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Batteries.Lean.Meta.Basic -import Lean.Elab.Command -import Lean.Elab.Tactic.BuiltinTactic +import Lean.Elab.Tactic.ElabTerm /-! # Simple tactics that are used throughout Batteries. -/ namespace Batteries.Tactic -open Lean Parser.Tactic Elab Command Elab.Tactic Meta +open Lean Parser.Tactic Elab Elab.Tactic Meta /-- `_` in tactic position acts like the `done` tactic: it fails and gives the list diff --git a/Batteries/Tactic/NoMatch.lean b/Batteries/Tactic/NoMatch.lean index 7efe68e7d2..ee6acefaf0 100644 --- a/Batteries/Tactic/NoMatch.lean +++ b/Batteries/Tactic/NoMatch.lean @@ -3,8 +3,8 @@ Copyright (c) 2021 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Lean.Elab.ElabRules import Lean.DocString +import Lean.Elab.Tactic.Basic /-! Deprecation warnings for `match ⋯ with.`, `fun.`, `λ.`, and `intro.`. diff --git a/Batteries/Tactic/PrintDependents.lean b/Batteries/Tactic/PrintDependents.lean index 9c55a04ecd..e927713886 100644 --- a/Batteries/Tactic/PrintDependents.lean +++ b/Batteries/Tactic/PrintDependents.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro -/ import Lean.Elab.Command import Lean.Util.FoldConsts -import Batteries.Lean.Delaborator /-! # `#print dependents` command diff --git a/Batteries/Tactic/PrintPrefix.lean b/Batteries/Tactic/PrintPrefix.lean index 63d2c3bbf5..b83e7b0ad8 100644 --- a/Batteries/Tactic/PrintPrefix.lean +++ b/Batteries/Tactic/PrintPrefix.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Shing Tak Lam, Daniel Selsam, Mario Carneiro -/ import Batteries.Lean.Util.EnvSearch -import Batteries.Lean.Delaborator import Lean.Elab.Tactic.Config namespace Batteries.Tactic diff --git a/Batteries/Tactic/SeqFocus.lean b/Batteries/Tactic/SeqFocus.lean index 8972f77891..cbbe70a44a 100644 --- a/Batteries/Tactic/SeqFocus.lean +++ b/Batteries/Tactic/SeqFocus.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad -/ -import Lean.Elab.ElabRules +import Lean.Elab.Tactic.Basic open Lean Elab Meta Tactic diff --git a/Batteries/Tactic/ShowUnused.lean b/Batteries/Tactic/ShowUnused.lean index 25989a3da9..3797801cd8 100644 --- a/Batteries/Tactic/ShowUnused.lean +++ b/Batteries/Tactic/ShowUnused.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro -/ import Lean.Util.FoldConsts import Lean.Linter.UnusedVariables -import Batteries.Lean.Delaborator /-! # The `#show_unused` command diff --git a/Batteries/Tactic/Unreachable.lean b/Batteries/Tactic/Unreachable.lean index 76571dc850..4d6e6cf0a1 100644 --- a/Batteries/Tactic/Unreachable.lean +++ b/Batteries/Tactic/Unreachable.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Lean.Elab.ElabRules +import Lean.Elab.Tactic.Basic namespace Batteries.Tactic diff --git a/Batteries/Util/Cache.lean b/Batteries/Util/Cache.lean index edfac4fe97..866325df5a 100644 --- a/Batteries/Util/Cache.lean +++ b/Batteries/Util/Cache.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Gabriel Ebner. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ -import Batteries.Lean.Meta.DiscrTree +import Lean.Meta.DiscrTree /-! # Once-per-file cache for tactics diff --git a/Batteries/Util/ExtendedBinder.lean b/Batteries/Util/ExtendedBinder.lean index d577e1d785..c489c0a432 100644 --- a/Batteries/Util/ExtendedBinder.lean +++ b/Batteries/Util/ExtendedBinder.lean @@ -3,8 +3,6 @@ Copyright (c) 2021 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ -import Lean.Elab.MacroArgUtil -import Lean.Linter.MissingDocs /-! Defines an extended binder syntax supporting `∀ ε > 0, ...` etc. diff --git a/Batteries/Util/LibraryNote.lean b/Batteries/Util/LibraryNote.lean index eb08bf0b27..8c1d45f786 100644 --- a/Batteries/Util/LibraryNote.lean +++ b/Batteries/Util/LibraryNote.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Gabriel Ebner. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ -import Lean.Elab.ElabRules +import Lean.Elab.Command /-! # Define the `library_note` command. diff --git a/test/MLList.lean b/test/MLList.lean index 278d6dc83d..78f0299717 100644 --- a/test/MLList.lean +++ b/test/MLList.lean @@ -1,4 +1,5 @@ import Batteries.Data.MLList.IO +import Batteries.Data.List.Basic set_option linter.missingDocs false From d4dfc4ed5d432668b39f03eb69b7415d17156f05 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 12 Aug 2024 12:36:18 +1000 Subject: [PATCH 177/208] chore: squeeze a simp in HashMap/WF (#909) --- Batteries/Data/HashMap/WF.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Batteries/Data/HashMap/WF.lean b/Batteries/Data/HashMap/WF.lean index ae51625133..9f69994638 100644 --- a/Batteries/Data/HashMap/WF.lean +++ b/Batteries/Data/HashMap/WF.lean @@ -225,7 +225,7 @@ private theorem pairwise_replaceF [BEq α] [PartialEquivBEq α] | cons a l ih => simp only [List.pairwise_cons, List.replaceF] at H ⊢ generalize e : cond .. = z; unfold cond at e; revert e - split <;> (intro h; subst h; simp) + split <;> (intro h; subst h; simp only [List.pairwise_cons]) · next e => exact ⟨(H.1 · · ∘ PartialEquivBEq.trans e), H.2⟩ · next e => refine ⟨fun a h => ?_, ih H.2⟩ From 9d061071835140698abb6fd463634084af0b7069 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 12 Aug 2024 17:17:51 +1000 Subject: [PATCH 178/208] fix --- Batteries/Data/UnionFind/Basic.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Batteries/Data/UnionFind/Basic.lean b/Batteries/Data/UnionFind/Basic.lean index 55798b0615..7d36a6b0cb 100644 --- a/Batteries/Data/UnionFind/Basic.lean +++ b/Batteries/Data/UnionFind/Basic.lean @@ -5,6 +5,7 @@ Authors: Mario Carneiro -/ import Batteries.Tactic.Lint.Misc import Batteries.Tactic.SeqFocus +import Batteries.Data.Array.Lemmas namespace Batteries From ad26fe1ebccc9d5b7ca9111d5daf9b4488374415 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 12 Aug 2024 17:19:11 +1000 Subject: [PATCH 179/208] chore: bump toolchain to v4.11.0-rc2 (#911) --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 64981ae5f5..e7a4f40b89 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.11.0-rc1 +leanprover/lean4:v4.11.0-rc2 From a746d6719a22c46956ed9d8e2b19a8e44bb45726 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Mon, 12 Aug 2024 09:05:47 +0000 Subject: [PATCH 180/208] chore: bump to nightly-2024-08-12 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 1645171233..b971c9ea09 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-11 +leanprover/lean4:nightly-2024-08-12 From 2314fab43027b0219a88fbf9c39452bfd9b9e55f Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 13 Aug 2024 10:15:53 +1000 Subject: [PATCH 181/208] removed upstreamed --- Batteries/Data/UInt.lean | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/Batteries/Data/UInt.lean b/Batteries/Data/UInt.lean index 44ebfd9b80..a7c2a4cbaa 100644 --- a/Batteries/Data/UInt.lean +++ b/Batteries/Data/UInt.lean @@ -26,8 +26,6 @@ theorem UInt8.toNat_lt (x : UInt8) : x.toNat < 2 ^ 8 := x.val.isLt @[simp] theorem UInt8.toUInt64_toNat (x : UInt8) : x.toUInt64.toNat = x.toNat := rfl -theorem UInt8.toNat_zero : (0 : UInt8).toNat = 0 := rfl - theorem UInt8.toNat_add (x y : UInt8) : (x + y).toNat = (x.toNat + y.toNat) % UInt8.size := rfl theorem UInt8.toNat_sub (x y : UInt8) : @@ -35,12 +33,6 @@ theorem UInt8.toNat_sub (x y : UInt8) : theorem UInt8.toNat_mul (x y : UInt8) : (x * y).toNat = (x.toNat * y.toNat) % UInt8.size := rfl -theorem UInt8.toNat_div (x y : UInt8) : (x / y).toNat = x.toNat / y.toNat := rfl - -theorem UInt8.toNat_mod (x y : UInt8) : (x % y).toNat = x.toNat % y.toNat := rfl - -theorem UInt8.toNat_modn (x : UInt8) (n) : (x.modn n).toNat = x.toNat % n := rfl - theorem UInt8.le_antisymm_iff {x y : UInt8} : x = y ↔ x ≤ y ∧ y ≤ x := UInt8.ext_iff.trans Nat.le_antisymm_iff @@ -71,8 +63,6 @@ theorem UInt16.toNat_lt (x : UInt16) : x.toNat < 2 ^ 16 := x.val.isLt @[simp] theorem UInt16.toUInt64_toNat (x : UInt16) : x.toUInt64.toNat = x.toNat := rfl -theorem UInt16.toNat_zero : (0 : UInt16).toNat = 0 := rfl - theorem UInt16.toNat_add (x y : UInt16) : (x + y).toNat = (x.toNat + y.toNat) % UInt16.size := rfl theorem UInt16.toNat_sub (x y : UInt16) : @@ -80,12 +70,6 @@ theorem UInt16.toNat_sub (x y : UInt16) : theorem UInt16.toNat_mul (x y : UInt16) : (x * y).toNat = (x.toNat * y.toNat) % UInt16.size := rfl -theorem UInt16.toNat_div (x y : UInt16) : (x / y).toNat = x.toNat / y.toNat := rfl - -theorem UInt16.toNat_mod (x y : UInt16) : (x % y).toNat = x.toNat % y.toNat := rfl - -theorem UInt16.toNat_modn (x : UInt16) (n) : (x.modn n).toNat = x.toNat % n := rfl - theorem UInt16.le_antisymm_iff {x y : UInt16} : x = y ↔ x ≤ y ∧ y ≤ x := UInt16.ext_iff.trans Nat.le_antisymm_iff @@ -116,8 +100,6 @@ theorem UInt32.toNat_lt (x : UInt32) : x.toNat < 2 ^ 32 := x.val.isLt @[simp] theorem UInt32.toUInt64_toNat (x : UInt32) : x.toUInt64.toNat = x.toNat := rfl -theorem UInt32.toNat_zero : (0 : UInt32).toNat = 0 := rfl - theorem UInt32.toNat_add (x y : UInt32) : (x + y).toNat = (x.toNat + y.toNat) % UInt32.size := rfl theorem UInt32.toNat_sub (x y : UInt32) : @@ -125,12 +107,6 @@ theorem UInt32.toNat_sub (x y : UInt32) : theorem UInt32.toNat_mul (x y : UInt32) : (x * y).toNat = (x.toNat * y.toNat) % UInt32.size := rfl -theorem UInt32.toNat_div (x y : UInt32) : (x / y).toNat = x.toNat / y.toNat := rfl - -theorem UInt32.toNat_mod (x y : UInt32) : (x % y).toNat = x.toNat % y.toNat := rfl - -theorem UInt32.toNat_modn (x : UInt32) (n) : (x.modn n).toNat = x.toNat % n := rfl - theorem UInt32.le_antisymm_iff {x y : UInt32} : x = y ↔ x ≤ y ∧ y ≤ x := UInt32.ext_iff.trans Nat.le_antisymm_iff @@ -161,8 +137,6 @@ theorem UInt64.toNat_lt (x : UInt64) : x.toNat < 2 ^ 64 := x.val.isLt @[simp] theorem UInt64.toUInt32_toNat (x : UInt64) : x.toUInt32.toNat = x.toNat % 2 ^ 32 := rfl -theorem UInt64.toNat_zero : (0 : UInt64).toNat = 0 := rfl - theorem UInt64.toNat_add (x y : UInt64) : (x + y).toNat = (x.toNat + y.toNat) % UInt64.size := rfl theorem UInt64.toNat_sub (x y : UInt64) : @@ -170,12 +144,6 @@ theorem UInt64.toNat_sub (x y : UInt64) : theorem UInt64.toNat_mul (x y : UInt64) : (x * y).toNat = (x.toNat * y.toNat) % UInt64.size := rfl -theorem UInt64.toNat_div (x y : UInt64) : (x / y).toNat = x.toNat / y.toNat := rfl - -theorem UInt64.toNat_mod (x y : UInt64) : (x % y).toNat = x.toNat % y.toNat := rfl - -theorem UInt64.toNat_modn (x : UInt64) (n) : (x.modn n).toNat = x.toNat % n := rfl - theorem UInt64.le_antisymm_iff {x y : UInt64} : x = y ↔ x ≤ y ∧ y ≤ x := UInt64.ext_iff.trans Nat.le_antisymm_iff @@ -220,8 +188,6 @@ theorem USize.toNat_lt (x : USize) : x.toNat < 2 ^ System.Platform.numBits := by @[simp] theorem UInt32.toUSize_toNat (x : UInt32) : x.toUSize.toNat = x.toNat := rfl -theorem USize.toNat_zero : (0 : USize).toNat = 0 := rfl - theorem USize.toNat_add (x y : USize) : (x + y).toNat = (x.toNat + y.toNat) % USize.size := rfl theorem USize.toNat_sub (x y : USize) : @@ -229,12 +195,6 @@ theorem USize.toNat_sub (x y : USize) : theorem USize.toNat_mul (x y : USize) : (x * y).toNat = (x.toNat * y.toNat) % USize.size := rfl -theorem USize.toNat_div (x y : USize) : (x / y).toNat = x.toNat / y.toNat := rfl - -theorem USize.toNat_mod (x y : USize) : (x % y).toNat = x.toNat % y.toNat := rfl - -theorem USize.toNat_modn (x : USize) (n) : (x.modn n).toNat = x.toNat % n := rfl - theorem USize.le_antisymm_iff {x y : USize} : x = y ↔ x ≤ y ∧ y ≤ x := USize.ext_iff.trans Nat.le_antisymm_iff From a2c707b31a2a43d65980532dc4d24065d5cf9d37 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 13 Aug 2024 10:17:26 +1000 Subject: [PATCH 182/208] remove upstreamed --- Batteries/Data/Array/Lemmas.lean | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Batteries/Data/Array/Lemmas.lean b/Batteries/Data/Array/Lemmas.lean index 10102cb3cc..753cbb4955 100644 --- a/Batteries/Data/Array/Lemmas.lean +++ b/Batteries/Data/Array/Lemmas.lean @@ -11,11 +11,6 @@ import Batteries.Util.ProofWanted namespace Array -theorem get_modify {arr : Array α} {x i} (h : i < arr.size) : - (arr.modify x f).get ⟨i, by simp [h]⟩ = - if x = i then f (arr.get ⟨i, h⟩) else arr.get ⟨i, h⟩ := by - simp [getElem_modify h] - theorem forIn_eq_data_forIn [Monad m] (as : Array α) (b : β) (f : α → β → m (ForInStep β)) : forIn as b f = forIn as.data b f := by From 63fd566ce8e78913d6f33e77fc9f32d061cc55ca Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 13 Aug 2024 10:20:01 +1000 Subject: [PATCH 183/208] deprecation --- Batteries/Data/UnionFind/Basic.lean | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Batteries/Data/UnionFind/Basic.lean b/Batteries/Data/UnionFind/Basic.lean index 7d36a6b0cb..549c9e1cde 100644 --- a/Batteries/Data/UnionFind/Basic.lean +++ b/Batteries/Data/UnionFind/Basic.lean @@ -302,6 +302,7 @@ theorem findAux_s {self : UnionFind} {x : Fin self.size} : apply dif_pos exact parent'_lt .. +set_option linter.deprecated false in theorem rankD_findAux {self : UnionFind} {x : Fin self.size} : rankD (findAux self x).s i = self.rank i := by if h : i < self.size then @@ -316,6 +317,7 @@ theorem rankD_findAux {self : UnionFind} {x : Fin self.size} : rw [dif_neg (by rwa [FindAux.size_eq]), dif_neg h] termination_by self.rankMax - self.rank x +set_option linter.deprecated false in theorem parentD_findAux {self : UnionFind} {x : Fin self.size} : parentD (findAux self x).s i = if i = x then self.rootD x else parentD (self.findAux ⟨_, self.parent'_lt x⟩).s i := by From 99ea40700dbff3e13ec1bcbc042fded421427f0e Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Tue, 13 Aug 2024 09:06:16 +0000 Subject: [PATCH 184/208] chore: bump to nightly-2024-08-13 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index b971c9ea09..2ceed02775 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-12 +leanprover/lean4:nightly-2024-08-13 From 1d25ec7ec98d6d9fb526c997aa014bcabbad8b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20G=2E=20Dorais?= Date: Tue, 13 Aug 2024 15:34:09 -0400 Subject: [PATCH 185/208] fix: naming convention (#914) Many theorems have the reverse naming convention for `Array.data` and `ByteArray.data`. This fixes many of them but there are plenty more in Lean core. An unexpected upshot is that some corrected names are actually shorter! --- Batteries/Data/Array/Lemmas.lean | 20 +++++++++++-------- Batteries/Data/ByteArray.lean | 33 ++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/Batteries/Data/Array/Lemmas.lean b/Batteries/Data/Array/Lemmas.lean index 753cbb4955..dd4fe12424 100644 --- a/Batteries/Data/Array/Lemmas.lean +++ b/Batteries/Data/Array/Lemmas.lean @@ -11,7 +11,7 @@ import Batteries.Util.ProofWanted namespace Array -theorem forIn_eq_data_forIn [Monad m] +theorem forIn_eq_forIn_data [Monad m] (as : Array α) (b : β) (f : α → β → m (ForInStep β)) : forIn as b f = forIn as.data b f := by let rec loop : ∀ {i h b j}, j + i = as.size → @@ -27,10 +27,11 @@ theorem forIn_eq_data_forIn [Monad m] rw [loop (i := i)]; rw [← ij, Nat.succ_add]; rfl conv => lhs; simp only [forIn, Array.forIn] rw [loop (Nat.zero_add _)]; rfl +@[deprecated (since := "2024-08-13")] alias forIn_eq_data_forIn := forIn_eq_forIn_data /-! ### zipWith / zip -/ -theorem zipWith_eq_zipWith_data (f : α → β → γ) (as : Array α) (bs : Array β) : +theorem data_zipWith (f : α → β → γ) (as : Array α) (bs : Array β) : (as.zipWith bs f).data = as.data.zipWith f bs.data := by let rec loop : ∀ (i : Nat) cs, i ≤ as.size → i ≤ bs.size → (zipWithAux f as bs i cs).data = cs.data ++ (as.data.drop i).zipWith f (bs.data.drop i) := by @@ -70,14 +71,16 @@ theorem zipWith_eq_zipWith_data (f : α → β → γ) (as : Array α) (bs : Arr List.zipWith f (List.drop i as.data) (List.drop i bs.data) simp only [data_length, Fin.getElem_fin, List.getElem_cons_drop, List.get_eq_getElem] simp [zipWith, loop 0 #[] (by simp) (by simp)] +@[deprecated (since := "2024-08-13")] alias zipWith_eq_zipWith_data := data_zipWith theorem size_zipWith (as : Array α) (bs : Array β) (f : α → β → γ) : (as.zipWith bs f).size = min as.size bs.size := by - rw [size_eq_length_data, zipWith_eq_zipWith_data, List.length_zipWith] + rw [size_eq_length_data, data_zipWith, List.length_zipWith] -theorem zip_eq_zip_data (as : Array α) (bs : Array β) : +theorem data_zip (as : Array α) (bs : Array β) : (as.zip bs).data = as.data.zip bs.data := - zipWith_eq_zipWith_data Prod.mk as bs + data_zipWith Prod.mk as bs +@[deprecated (since := "2024-08-13")] alias zip_eq_zip_data := data_zip theorem size_zip (as : Array α) (bs : Array β) : (as.zip bs).size = min as.size bs.size := @@ -92,7 +95,7 @@ theorem size_filter_le (p : α → Bool) (l : Array α) : /-! ### join -/ -@[simp] theorem join_data {l : Array (Array α)} : l.join.data = (l.data.map data).join := by +@[simp] theorem data_join {l : Array (Array α)} : l.join.data = (l.data.map data).join := by dsimp [join] simp only [foldl_eq_foldl_data] generalize l.data = l @@ -101,9 +104,10 @@ theorem size_filter_le (p : α → Bool) (l : Array α) : induction l with | nil => simp | cons h => induction h.data <;> simp [*] +@[deprecated (since := "2024-08-13")] alias join_data := data_join theorem mem_join : ∀ {L : Array (Array α)}, a ∈ L.join ↔ ∃ l, l ∈ L ∧ a ∈ l := by - simp only [mem_def, join_data, List.mem_join, List.mem_map] + simp only [mem_def, data_join, List.mem_join, List.mem_map] intro l constructor · rintro ⟨_, ⟨s, m, rfl⟩, h⟩ @@ -113,7 +117,7 @@ theorem mem_join : ∀ {L : Array (Array α)}, a ∈ L.join ↔ ∃ l, l ∈ L /-! ### erase -/ -@[simp] proof_wanted erase_data [BEq α] {l : Array α} {a : α} : (l.erase a).data = l.data.erase a +@[simp] proof_wanted data_erase [BEq α] {l : Array α} {a : α} : (l.erase a).data = l.data.erase a /-! ### shrink -/ diff --git a/Batteries/Data/ByteArray.lean b/Batteries/Data/ByteArray.lean index 585563ec5a..a9653bf10c 100644 --- a/Batteries/Data/ByteArray.lean +++ b/Batteries/Data/ByteArray.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 François G. Dorais. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: François G. Dorais -/ +import Batteries.Tactic.Alias namespace ByteArray @@ -18,15 +19,18 @@ theorem getElem_eq_data_getElem (a : ByteArray) (h : i < a.size) : a[i] = a.data /-! ### empty -/ -@[simp] theorem mkEmpty_data (cap) : (mkEmpty cap).data = #[] := rfl +@[simp] theorem data_mkEmpty (cap) : (mkEmpty cap).data = #[] := rfl +@[deprecated (since := "2024-08-13")] alias mkEmpty_data := data_mkEmpty -@[simp] theorem empty_data : empty.data = #[] := rfl +@[simp] theorem data_empty : empty.data = #[] := rfl +@[deprecated (since := "2024-08-13")] alias empty_data := data_empty @[simp] theorem size_empty : empty.size = 0 := rfl /-! ### push -/ -@[simp] theorem push_data (a : ByteArray) (b : UInt8) : (a.push b).data = a.data.push b := rfl +@[simp] theorem data_push (a : ByteArray) (b : UInt8) : (a.push b).data = a.data.push b := rfl +@[deprecated (since := "2024-08-13")] alias push_data := data_push @[simp] theorem size_push (a : ByteArray) (b : UInt8) : (a.push b).size = a.size + 1 := Array.size_push .. @@ -40,8 +44,9 @@ theorem get_push_lt (a : ByteArray) (x : UInt8) (i : Nat) (h : i < a.size) : /-! ### set -/ -@[simp] theorem set_data (a : ByteArray) (i : Fin a.size) (v : UInt8) : +@[simp] theorem data_set (a : ByteArray) (i : Fin a.size) (v : UInt8) : (a.set i v).data = a.data.set i v := rfl +@[deprecated (since := "2024-08-13")] alias set_data := data_set @[simp] theorem size_set (a : ByteArray) (i : Fin a.size) (v : UInt8) : (a.set i v).size = a.size := @@ -60,20 +65,22 @@ theorem set_set (a : ByteArray) (i : Fin a.size) (v v' : UInt8) : /-! ### copySlice -/ -@[simp] theorem copySlice_data (a i b j len exact) : +@[simp] theorem data_copySlice (a i b j len exact) : (copySlice a i b j len exact).data = b.data.extract 0 j ++ a.data.extract i (i + len) ++ b.data.extract (j + min len (a.data.size - i)) b.data.size := rfl +@[deprecated (since := "2024-08-13")] alias copySlice_data := data_copySlice /-! ### append -/ @[simp] theorem append_eq (a b) : ByteArray.append a b = a ++ b := rfl -@[simp] theorem append_data (a b : ByteArray) : (a ++ b).data = a.data ++ b.data := by +@[simp] theorem data_append (a b : ByteArray) : (a ++ b).data = a.data ++ b.data := by rw [←append_eq]; simp [ByteArray.append, size] rw [Array.extract_empty_of_stop_le_start (h:=Nat.le_add_right ..), Array.append_nil] +@[deprecated (since := "2024-08-13")] alias append_data := data_append theorem size_append (a b : ByteArray) : (a ++ b).size = a.size + b.size := by - simp only [size, append_eq, append_data]; exact Array.size_append .. + simp only [size, append_eq, data_append]; exact Array.size_append .. theorem get_append_left {a b : ByteArray} (hlt : i < a.size) (h : i < (a ++ b).size := size_append .. ▸ Nat.lt_of_lt_of_le hlt (Nat.le_add_right ..)) : @@ -87,12 +94,13 @@ theorem get_append_right {a b : ByteArray} (hle : a.size ≤ i) (h : i < (a ++ b /-! ### extract -/ -@[simp] theorem extract_data (a : ByteArray) (start stop) : +@[simp] theorem data_extract (a : ByteArray) (start stop) : (a.extract start stop).data = a.data.extract start stop := by simp [extract] match Nat.le_total start stop with | .inl h => simp [h, Nat.add_sub_cancel'] | .inr h => simp [h, Nat.sub_eq_zero_of_le, Array.extract_empty_of_stop_le_start] +@[deprecated (since := "2024-08-13")] alias extract_data := data_extract @[simp] theorem size_extract (a : ByteArray) (start stop) : (a.extract start stop).size = min stop a.size - start := by @@ -113,7 +121,8 @@ theorem get_extract_aux {a : ByteArray} {start stop} (h : i < (a.extract start s def ofFn (f : Fin n → UInt8) : ByteArray where data := .ofFn f -@[simp] theorem ofFn_data (f : Fin n → UInt8) : (ofFn f).data = .ofFn f := rfl +@[simp] theorem data_ofFn (f : Fin n → UInt8) : (ofFn f).data = .ofFn f := rfl +@[deprecated (since := "2024-08-13")] alias ofFn_data := data_ofFn @[simp] theorem size_ofFn (f : Fin n → UInt8) : (ofFn f).size = n := by simp [size] @@ -131,9 +140,9 @@ private def ofFnAux (f : Fin n → UInt8) : ByteArray := go 0 (mkEmpty n) where termination_by n - i @[csimp] private theorem ofFn_eq_ofFnAux : @ofFn = @ofFnAux := by - funext n f; ext; simp [ofFnAux, Array.ofFn, ofFnAux_data, mkEmpty] + funext n f; ext; simp [ofFnAux, Array.ofFn, data_ofFnAux, mkEmpty] where - ofFnAux_data {n} (f : Fin n → UInt8) (i) {acc} : + data_ofFnAux {n} (f : Fin n → UInt8) (i) {acc} : (ofFnAux.go f i acc).data = Array.ofFn.go f i acc.data := by - rw [ofFnAux.go, Array.ofFn.go]; split; rw [ofFnAux_data f (i+1), push_data]; rfl + rw [ofFnAux.go, Array.ofFn.go]; split; rw [data_ofFnAux f (i+1), data_push]; rfl termination_by n - i From 010ac2c7495c943383e920f315c43d898dacc330 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 14 Aug 2024 12:25:47 +1000 Subject: [PATCH 186/208] fix --- Batteries/Data/ByteArray.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Batteries/Data/ByteArray.lean b/Batteries/Data/ByteArray.lean index 1122c85ef6..e051e01fd2 100644 --- a/Batteries/Data/ByteArray.lean +++ b/Batteries/Data/ByteArray.lean @@ -140,7 +140,7 @@ private def ofFnAux (f : Fin n → UInt8) : ByteArray := go 0 (mkEmpty n) where termination_by n - i @[csimp] private theorem ofFn_eq_ofFnAux : @ofFn = @ofFnAux := by - funext n f; ext1; simp [ofFnAux, Array.ofFn, ofFnAux_data, mkEmpty] + funext n f; ext1; simp [ofFnAux, Array.ofFn, data_ofFnAux, mkEmpty] where data_ofFnAux {n} (f : Fin n → UInt8) (i) {acc} : (ofFnAux.go f i acc).data = Array.ofFn.go f i acc.data := by From 5e5e54c4028f7b6bd086ebb72e5822794c64c35d Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 14 Aug 2024 18:08:56 +1000 Subject: [PATCH 187/208] chore: cleanup lexOrd_def (#915) --- Batteries/Classes/Order.lean | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Batteries/Classes/Order.lean b/Batteries/Classes/Order.lean index 8cbfae25b0..1296bd7a9d 100644 --- a/Batteries/Classes/Order.lean +++ b/Batteries/Classes/Order.lean @@ -278,11 +278,8 @@ instance [Ord β] [OrientedOrd β] (f : α → β) : OrientedCmp (compareOn f) w instance [Ord β] [TransOrd β] (f : α → β) : TransCmp (compareOn f) where le_trans := TransCmp.le_trans (α := β) --- FIXME: remove after lean4#3882 is merged theorem _root_.lexOrd_def [Ord α] [Ord β] : - (lexOrd : Ord (α × β)).compare = compareLex (compareOn (·.1)) (compareOn (·.2)) := by - funext a b - simp [lexOrd, compareLex, compareOn] + (lexOrd : Ord (α × β)).compare = compareLex (compareOn (·.1)) (compareOn (·.2)) := rfl section «non-canonical instances» -- Note: the following instances seem to cause lean to fail, see: From 3471b6f122cf39145a5c9f2c18360fbb134022c6 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Wed, 14 Aug 2024 09:05:30 +0000 Subject: [PATCH 188/208] chore: bump to nightly-2024-08-14 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 2ceed02775..4750fe1899 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-13 +leanprover/lean4:nightly-2024-08-14 From b649b901acf849611afc2630d416dc985395257b Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 16 Aug 2024 09:18:31 +1000 Subject: [PATCH 189/208] . --- Batteries/Data/List/Basic.lean | 2 +- lean-toolchain | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index 43915cd733..e2baae1123 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -544,7 +544,7 @@ theorem sections_eq_nil_of_isEmpty : ∀ {L}, L.any isEmpty → @sections α L = | l :: L, h => by simp only [any, foldr, Bool.or_eq_true] at h match l, h with - | [], .inl rfl => simp; induction sections L <;> simp [*] + | [], .inl rfl => simp | l, .inr h => simp [sections, sections_eq_nil_of_isEmpty h] @[csimp] theorem sections_eq_sectionsTR : @sections = @sectionsTR := by diff --git a/lean-toolchain b/lean-toolchain index 4750fe1899..6f00d6a70c 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-14 +leanprover/lean4:nightly-2024-08-15 From 0a94ff5ff294cc6dcdb5fc247487baf94669dff9 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 16 Aug 2024 09:38:44 +1000 Subject: [PATCH 190/208] fix test --- test/where.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/test/where.lean b/test/where.lean index 5f7a4bcfa3..6fd098ce53 100644 --- a/test/where.lean +++ b/test/where.lean @@ -2,7 +2,6 @@ import Batteries.Tactic.Where -- Return to pristine state set_option linter.missingDocs false -set_option internal.minimalSnapshots false /-- info: -- In root namespace with initial scope -/ #guard_msgs in #where From 686675fc70d3c70eaa8e2a2cb0fd4fd6365d69f2 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 16 Aug 2024 09:39:34 +1000 Subject: [PATCH 191/208] fix again --- test/where.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/test/where.lean b/test/where.lean index 6fd098ce53..a88f1ed8e5 100644 --- a/test/where.lean +++ b/test/where.lean @@ -2,6 +2,7 @@ import Batteries.Tactic.Where -- Return to pristine state set_option linter.missingDocs false +set_option internal.cmdlineSnapshots false /-- info: -- In root namespace with initial scope -/ #guard_msgs in #where From 91cf60cee20d61bd2012cae20ea6589432f5bf5a Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Fri, 16 Aug 2024 09:35:05 +0200 Subject: [PATCH 192/208] fix: flaky test (#889) --- test/MLList.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/MLList.lean b/test/MLList.lean index 78f0299717..ad53377237 100644 --- a/test/MLList.lean +++ b/test/MLList.lean @@ -19,7 +19,7 @@ def g (n : Nat) : MLList Lean.Meta.MetaM Nat := do /-! ### Test `MLList.ofTaskList`. -We generate three tasks which sleep for `100`, `10`, and `1` milliseconds respectively, +We generate three tasks which sleep for `100`, `50`, and `1` milliseconds respectively, and then verify that `MLList.ofTaskList` return their results in the order they complete. -/ @@ -29,9 +29,9 @@ def sleep (n : UInt32) : BaseIO (Task UInt32) := | .error _ => 0 def sleeps : MLList BaseIO UInt32 := .squash fun _ => do - let r ← [100,10,1].map sleep |>.traverse id + let r ← [100,50,1].map sleep |>.traverse id return .ofTaskList r -/-- info: [1, 10, 100] -/ +/-- info: [1, 50, 100] -/ #guard_msgs in #eval sleeps.force From b0587b2dc108d23519735a4595de4db92e2cf2ca Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 16 Aug 2024 17:35:32 +1000 Subject: [PATCH 193/208] chore: remove makefile (#918) --- GNUmakefile | 12 ------------ README.md | 4 +++- 2 files changed, 3 insertions(+), 13 deletions(-) delete mode 100644 GNUmakefile diff --git a/GNUmakefile b/GNUmakefile deleted file mode 100644 index 123c8af1a1..0000000000 --- a/GNUmakefile +++ /dev/null @@ -1,12 +0,0 @@ -.PHONY: all build test lint - -all: build test - -build: - lake build - -test: - lake test - -lint: - lake exe runLinter diff --git a/README.md b/README.md index f5f241fe22..ab8606d854 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,9 @@ Additionally, please make sure that you're using the version of Lean that the cu curl https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh -sSf | sh ``` If this also fails, follow the instructions under `Regular install` [here](https://leanprover-community.github.io/get_started.html). -* To build `batteries` run `lake build`. To build and run all tests, run `make`. +* To build `batteries` run `lake build`. +* To build and run all tests, run `lake test`. +* To run the environment linter, run `lake lint`. * If you added a new file, run the command `scripts/updateBatteries.sh` to update the imports. From a36e34fb3d00117ccde6ad6c3d5774b1e4f1f36e Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Fri, 16 Aug 2024 17:38:33 +1000 Subject: [PATCH 194/208] feat: faster splitAt (#919) --- Batteries/Data/List/Basic.lean | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index 43915cd733..7e6e034dc4 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -116,13 +116,13 @@ Split a list at an index. splitAt 2 [a, b, c] = ([a, b], [c]) ``` -/ -def splitAt (n : Nat) (l : List α) : List α × List α := go l n #[] where - /-- Auxiliary for `splitAt`: `splitAt.go l n xs acc = (acc.toList ++ take n xs, drop n xs)` +def splitAt (n : Nat) (l : List α) : List α × List α := go l n [] where + /-- Auxiliary for `splitAt`: `splitAt.go l n xs acc = (acc.reverse ++ take n xs, drop n xs)` if `n < length xs`, else `(l, [])`. -/ - go : List α → Nat → Array α → List α × List α + go : List α → Nat → List α → List α × List α | [], _, _ => (l, []) - | x :: xs, n+1, acc => go xs n (acc.push x) - | xs, _, acc => (acc.toList, xs) + | x :: xs, n+1, acc => go xs n (x :: acc) + | xs, _, acc => (acc.reverse, xs) /-- Split a list at an index. Ensures the left list always has the specified length @@ -132,13 +132,13 @@ splitAtD 2 [a, b, c] x = ([a, b], [c]) splitAtD 4 [a, b, c] x = ([a, b, c, x], []) ``` -/ -def splitAtD (n : Nat) (l : List α) (dflt : α) : List α × List α := go n l #[] where - /-- Auxiliary for `splitAtD`: `splitAtD.go dflt n l acc = (acc.toList ++ left, right)` +def splitAtD (n : Nat) (l : List α) (dflt : α) : List α × List α := go n l [] where + /-- Auxiliary for `splitAtD`: `splitAtD.go dflt n l acc = (acc.reverse ++ left, right)` if `splitAtD n l dflt = (left, right)`. -/ - go : Nat → List α → Array α → List α × List α - | n+1, x :: xs, acc => go n xs (acc.push x) - | 0, xs, acc => (acc.toList, xs) - | n, [], acc => (acc.toListAppend (replicate n dflt), []) + go : Nat → List α → List α → List α × List α + | n+1, x :: xs, acc => go n xs (x :: acc) + | 0, xs, acc => (acc, xs) + | n, [], acc => (acc.reverseAux (replicate n dflt), []) /-- Split a list at every element satisfying a predicate. The separators are not in the result. From 694e39de5f615c412404a174ab1d4286923cbc52 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 16 Aug 2024 09:06:12 +0000 Subject: [PATCH 195/208] chore: bump to nightly-2024-08-16 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 6f00d6a70c..68e968509a 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-15 +leanprover/lean4:nightly-2024-08-16 From 1f4c8fab70847b92df7efa5a35a0e7613217bd2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20G=2E=20Dorais?= Date: Fri, 16 Aug 2024 17:16:08 -0400 Subject: [PATCH 196/208] feat: add `ByteSubarray` (#851) --- Batteries.lean | 1 + Batteries/Data/ByteSubarray.lean | 105 +++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 Batteries/Data/ByteSubarray.lean diff --git a/Batteries.lean b/Batteries.lean index 8e1e6f1828..a585b2c6cf 100644 --- a/Batteries.lean +++ b/Batteries.lean @@ -19,6 +19,7 @@ import Batteries.Data.BinomialHeap import Batteries.Data.BitVec import Batteries.Data.Bool import Batteries.Data.ByteArray +import Batteries.Data.ByteSubarray import Batteries.Data.Char import Batteries.Data.DList import Batteries.Data.Fin diff --git a/Batteries/Data/ByteSubarray.lean b/Batteries/Data/ByteSubarray.lean new file mode 100644 index 0000000000..3844d1b1bc --- /dev/null +++ b/Batteries/Data/ByteSubarray.lean @@ -0,0 +1,105 @@ + +/- +Copyright (c) 2021 Mario Carneiro. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, François G. Dorais +-/ + +namespace Batteries + +/-- A subarray of a `ByteArray`. -/ +structure ByteSubarray where + /-- `O(1)`. Get data array of a `ByteSubarray`. -/ + array : ByteArray + /-- `O(1)`. Get start index of a `ByteSubarray`. -/ + start : Nat + /-- `O(1)`. Get stop index of a `ByteSubarray`. -/ + stop : Nat + /-- Start index is before stop index. -/ + start_le_stop : start ≤ stop + /-- Stop index is before end of data array. -/ + stop_le_array_size : stop ≤ array.size + +namespace ByteSubarray + +/-- `O(1)`. Get the size of a `ByteSubarray`. -/ +protected def size (self : ByteSubarray) := self.stop - self.start + +/-- `O(1)`. Test if a `ByteSubarray` is empty. -/ +protected def isEmpty (self : ByteSubarray) := self.start != self.stop + +theorem stop_eq_start_add_size (self : ByteSubarray) : self.stop = self.start + self.size := by + rw [ByteSubarray.size, Nat.add_sub_cancel' self.start_le_stop] + +/-- `O(n)`. Extract a `ByteSubarray` to a `ByteArray`. -/ +def toByteArray (self : ByteSubarray) : ByteArray := + self.array.extract self.start self.stop + +/-- `O(1)`. Get the element at index `i` from the start of a `ByteSubarray`. -/ +@[inline] def get (self : ByteSubarray) (i : Fin self.size) : UInt8 := + have : self.start + i.1 < self.array.size := by + apply Nat.lt_of_lt_of_le _ self.stop_le_array_size + rw [stop_eq_start_add_size] + apply Nat.add_lt_add_left i.is_lt self.start + self.array[self.start + i.1] + +instance : GetElem ByteSubarray Nat UInt8 fun self i => i < self.size where + getElem self i h := self.get ⟨i, h⟩ + +/-- `O(1)`. Pop the last element of a `ByteSubarray`. -/ +@[inline] def pop (self : ByteSubarray) : ByteSubarray := + if h : self.start = self.stop then self else + {self with + stop := self.stop - 1 + start_le_stop := Nat.le_pred_of_lt (Nat.lt_of_le_of_ne self.start_le_stop h) + stop_le_array_size := Nat.le_trans (Nat.pred_le _) self.stop_le_array_size + } + +/-- `O(1)`. Pop the first element of a `ByteSubarray`. -/ +@[inline] def popFront (self : ByteSubarray) : ByteSubarray := + if h : self.start = self.stop then self else + {self with + start := self.start + 1 + start_le_stop := Nat.succ_le_of_lt (Nat.lt_of_le_of_ne self.start_le_stop h) + } + +/-- Folds a monadic function over a `ByteSubarray` from left to right. -/ +@[inline] def foldlM [Monad m] (self : ByteSubarray) (f : β → UInt8 → m β) (init : β) : m β := + self.array.foldlM f init self.start self.stop + +/-- Folds a function over a `ByteSubarray` from left to right. -/ +@[inline] def foldl (self : ByteSubarray) (f : β → UInt8 → β) (init : β) : β := + self.foldlM (m:=Id) f init + +/-- Implementation of `forIn` for a `ByteSubarray`. -/ +@[specialize] +protected def forIn [Monad m] (self : ByteSubarray) (init : β) (f : UInt8 → β → m (ForInStep β)) : + m β := loop self.size (Nat.le_refl _) init +where + /-- Inner loop of the `forIn` implementation for `ByteSubarray`. -/ + loop (i : Nat) (h : i ≤ self.size) (b : β) : m β := do + match i, h with + | 0, _ => pure b + | i+1, h => + match (← f self[self.size - 1 - i] b) with + | ForInStep.done b => pure b + | ForInStep.yield b => loop i (Nat.le_of_succ_le h) b + +instance : ForIn m ByteSubarray UInt8 where + forIn := ByteSubarray.forIn + +instance : Stream ByteSubarray UInt8 where + next? s := s[0]? >>= fun x => (x, s.popFront) + +end Batteries.ByteSubarray + +/-- `O(1)`. Coerce a byte array into a byte slice. -/ +def ByteArray.toByteSubarray (array : ByteArray) : Batteries.ByteSubarray where + array := array + start := 0 + stop := array.size + start_le_stop := Nat.zero_le _ + stop_le_array_size := Nat.le_refl _ + +instance : Coe ByteArray Batteries.ByteSubarray where + coe := ByteArray.toByteSubarray From a2ef715a780564dfea52464d573f3ce5c7d6cf95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20G=2E=20Dorais?= Date: Fri, 16 Aug 2024 17:16:29 -0400 Subject: [PATCH 197/208] feat: lemmas `List.foldlM_map` and `List.foldrM_map` (#827) --- Batteries/Data/List/Lemmas.lean | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 2e97cb5264..3eea690ad6 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -637,3 +637,13 @@ theorem mem_merge_left (s : α → α → Bool) (h : x ∈ l) : x ∈ merge s l theorem mem_merge_right (s : α → α → Bool) (h : x ∈ r) : x ∈ merge s l r := mem_merge.2 <| .inr h + +/-! ### foldlM and foldrM -/ + +theorem foldlM_map [Monad m] (f : β₁ → β₂) (g : α → β₂ → m α) (l : List β₁) (init : α) : + (l.map f).foldlM g init = l.foldlM (fun x y => g x (f y)) init := by + induction l generalizing g init <;> simp [*] + +theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ → β₂) (g : β₂ → α → m α) (l : List β₁) + (init : α) : (l.map f).foldrM g init = l.foldrM (fun x y => g (f x) y) init := by + induction l generalizing g init <;> simp [*] From 5f405b1c0d74619b34501ff0c711cb882406800e Mon Sep 17 00:00:00 2001 From: Shrys Date: Sat, 17 Aug 2024 00:45:53 +0200 Subject: [PATCH 198/208] feat: statically sized Vector type (#793) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a static vector type to batteries akin to `Mathlib.Data.Vector` with a key difference: It is based on `Array` instead of `List` and is designed for efficient operations with while offering a static size. Co-authored-by: François G. Dorais Co-authored-by: Mario Carneiro --- Batteries.lean | 1 + Batteries/Data/Vector.lean | 2 + Batteries/Data/Vector/Basic.lean | 321 ++++++++++++++++++++++++++++++ Batteries/Data/Vector/Lemmas.lean | 47 +++++ 4 files changed, 371 insertions(+) create mode 100644 Batteries/Data/Vector.lean create mode 100644 Batteries/Data/Vector/Basic.lean create mode 100644 Batteries/Data/Vector/Lemmas.lean diff --git a/Batteries.lean b/Batteries.lean index a585b2c6cf..5fd8bc72ad 100644 --- a/Batteries.lean +++ b/Batteries.lean @@ -39,6 +39,7 @@ import Batteries.Data.Sum import Batteries.Data.Thunk import Batteries.Data.UInt import Batteries.Data.UnionFind +import Batteries.Data.Vector import Batteries.Lean.AttributeExtra import Batteries.Lean.Delaborator import Batteries.Lean.Except diff --git a/Batteries/Data/Vector.lean b/Batteries/Data/Vector.lean new file mode 100644 index 0000000000..f543f121ef --- /dev/null +++ b/Batteries/Data/Vector.lean @@ -0,0 +1,2 @@ +import Batteries.Data.Vector.Basic +import Batteries.Data.Vector.Lemmas diff --git a/Batteries/Data/Vector/Basic.lean b/Batteries/Data/Vector/Basic.lean new file mode 100644 index 0000000000..6fc8166b6d --- /dev/null +++ b/Batteries/Data/Vector/Basic.lean @@ -0,0 +1,321 @@ +/- +Copyright (c) 2024 Shreyas Srinivas. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Shreyas Srinivas, François G. Dorais +-/ + +import Batteries.Data.Array +import Batteries.Data.List.Basic +import Batteries.Data.List.Lemmas +import Batteries.Tactic.Lint.Misc + +/-! +## Vectors +`Vector α n` is an array with a statically fixed size `n`. +It combines the benefits of Lean's special support for `Arrays` +that offer `O(1)` accesses and in-place mutations for arrays with no more than one reference, +with static guarantees about the size of the underlying array. +-/ + +namespace Batteries + +/-- `Vector α n` is an `Array α` whose size is statically fixed to `n` -/ +structure Vector (α : Type u) (n : Nat) where + /-- Internally, a vector is stored as an array for fast access -/ + toArray : Array α + /-- `size_eq` fixes the size of `toArray` statically -/ + size_eq : toArray.size = n +deriving Repr, DecidableEq + +namespace Vector + +/-- Syntax for `Vector α n` -/ +syntax "#v[" withoutPosition(sepBy(term, ", ")) "]" : term + +open Lean in +macro_rules + | `(#v[ $elems,* ]) => `(Vector.mk (n := $(quote elems.getElems.size)) #[$elems,*] rfl) + +/-- Custom eliminator for `Vector α n` through `Array α` -/ +@[elab_as_elim] +def elimAsArray {motive : ∀ {n}, Vector α n → Sort u} (mk : ∀ a : Array α, motive ⟨a, rfl⟩) : + {n : Nat} → (v : Vector α n) → motive v + | _, ⟨a, rfl⟩ => mk a + +/-- Custom eliminator for `Vector α n` through `List α` -/ +@[elab_as_elim] +def elimAsList {motive : ∀ {n}, Vector α n → Sort u} (mk : ∀ a : List α, motive ⟨⟨a⟩, rfl⟩) : + {n : Nat} → (v : Vector α n) → motive v + | _, ⟨⟨a⟩, rfl⟩ => mk a + +/-- `Vector.size` gives the size of a vector. -/ +@[nolint unusedArguments] +def size (_ : Vector α n) : Nat := n + +/-- `Vector.empty` produces an empty vector -/ +def empty : Vector α 0 := ⟨Array.empty, rfl⟩ + +/-- Make an empty vector with pre-allocated capacity-/ +def mkEmpty (capacity : Nat) : Vector α 0 := ⟨Array.mkEmpty capacity, rfl⟩ + +/-- Makes a vector of size `n` with all cells containing `v` -/ +def mkVector (n : Nat) (v : α) : Vector α n := ⟨mkArray n v, Array.size_mkArray ..⟩ + +/-- Returns a vector of size `1` with a single element `v` -/ +def singleton (v : α) : Vector α 1 := mkVector 1 v + +/-- +The Inhabited instance for `Vector α n` with `[Inhabited α]` produces a vector of size `n` +with all its elements equal to the `default` element of type `α` +-/ +instance [Inhabited α] : Inhabited (Vector α n) where + default := mkVector n default + +/-- The list obtained from a vector. -/ +def toList (v : Vector α n) : List α := v.toArray.toList + +/-- nth element of a vector, indexed by a `Fin` type. -/ +def get (v : Vector α n) (i : Fin n) : α := v.toArray.get <| i.cast v.size_eq.symm + +/-- Vector lookup function that takes an index `i` of type `USize` -/ +def uget (v : Vector α n) (i : USize) (h : i.toNat < n) : α := v.toArray.uget i (v.size_eq.symm ▸ h) + +/-- `Vector α n` nstance for the `GetElem` typeclass. -/ +instance : GetElem (Vector α n) Nat α fun _ i => i < n where + getElem := fun x i h => get x ⟨i, h⟩ + +/-- +`getD v i v₀` gets the `iᵗʰ` element of v if valid. +Otherwise it returns `v₀` by default +-/ +def getD (v : Vector α n) (i : Nat) (v₀ : α) : α := Array.getD v.toArray i v₀ + +/-- +`v.back! v` gets the last element of the vector. +panics if `v` is empty. +-/ +abbrev back! [Inhabited α] (v : Vector α n) : α := v[n - 1]! + +/-- +`v.back?` gets the last element `x` of the array as `some x` +if it exists. Else the vector is empty and it returns `none` +-/ +abbrev back? (v : Vector α n) : Option α := v[n - 1]? + +/-- `Vector.head` produces the head of a vector -/ +abbrev head (v : Vector α (n+1)) := v[0] + +/-- `push v x` pushes `x` to the end of vector `v` in O(1) time -/ +def push (x : α) (v : Vector α n) : Vector α (n + 1) := + ⟨v.toArray.push x, by simp [v.size_eq]⟩ + +/-- `pop v` returns the vector with the last element removed -/ +def pop (v : Vector α n) : Vector α (n - 1) := + ⟨Array.pop v.toArray, by simp [v.size_eq]⟩ + +/-- +Sets an element in a vector using a Fin index. + +This will perform the update destructively provided that a has a reference count of 1 when called. +-/ +def set (v : Vector α n) (i : Fin n) (x : α) : Vector α n := + ⟨v.toArray.set (Fin.cast v.size_eq.symm i) x, by simp [v.size_eq]⟩ + +/-- +`setN v i h x` sets an element in a vector using a Nat index which is provably valid. +By default a proof by `get_elem_tactic` is provided. + +This will perform the update destructively provided that a has a reference count of 1 when called. +-/ +def setN (v : Vector α n) (i : Nat) (x : α) (h : i < n := by get_elem_tactic) : Vector α n := + v.set ⟨i, h⟩ x + +/-- +Sets an element in a vector, or do nothing if the index is out of bounds. + +This will perform the update destructively provided that a has a reference count of 1 when called. +-/ +def setD (v : Vector α n) (i : Nat) (x : α) : Vector α n := + ⟨v.toArray.setD i x, by simp [v.size_eq]⟩ + +/-- +Sets an element in an array, or panic if the index is out of bounds. + +This will perform the update destructively provided that a has a reference count of 1 when called. +-/ +def set! (v : Vector α n) (i : Nat) (x : α) : Vector α n := + ⟨v.toArray.set! i x, by simp [v.size_eq]⟩ + +/-- Appends a vector to another. -/ +def append : Vector α n → Vector α m → Vector α (n + m) + | ⟨a₁, _⟩, ⟨a₂, _⟩ => ⟨a₁ ++ a₂, by simp [Array.size_append, *]⟩ + +instance : HAppend (Vector α n) (Vector α m) (Vector α (n + m)) where + hAppend := append + +/-- Creates a vector from another with a provably equal length. -/ +protected def cast {n m : Nat} (h : n = m) : Vector α n → Vector α m + | ⟨x, p⟩ => ⟨x, h ▸ p⟩ + +/-- +`extract v start halt` Returns the slice of `v` from indices `start` to `stop` (exclusive). +If `start` is greater or equal to `stop`, the result is empty. +If `stop` is greater than the size of `v`, the size is used instead. +-/ +def extract (v : Vector α n) (start stop : Nat) : Vector α (min stop n - start) := + ⟨Array.extract v.toArray start stop, by simp [v.size_eq]⟩ + +/-- Maps a vector under a function. -/ +def map (f : α → β) (v : Vector α n) : Vector β n := + ⟨v.toArray.map f, by simp [v.size_eq]⟩ + +/-- Maps two vectors under a curried function of two variables. -/ +def zipWith : (a : Vector α n) → (b : Vector β n) → (f : α → β → φ) → Vector φ n + | ⟨a, h₁⟩, ⟨b, h₂⟩, f => ⟨Array.zipWith a b f, by simp [Array.size_zipWith, h₁, h₂]⟩ + +/-- Returns a vector of length `n` from a function on `Fin n`. -/ +def ofFn (f : Fin n → α) : Vector α n := ⟨Array.ofFn f, Array.size_ofFn ..⟩ + +/-- +Swaps two entries in a Vector. + +This will perform the update destructively provided that `v` has a reference count of 1 when called. +-/ +def swap (v : Vector α n) (i j : Fin n) : Vector α n := + ⟨v.toArray.swap (Fin.cast v.size_eq.symm i) (Fin.cast v.size_eq.symm j), by simp [v.size_eq]⟩ + +/-- +`swapN v i j hi hj` swaps two `Nat` indexed entries in a `Vector α n`. +Uses `get_elem_tactic` to supply proofs `hi` and `hj` respectively +that the indices `i` and `j` are in range. + +This will perform the update destructively provided that `v` has a reference count of 1 when called. +-/ +def swapN (v : Vector α n) (i j : Nat) + (hi : i < n := by get_elem_tactic) (hj : j < n := by get_elem_tactic) : Vector α n := + v.swap ⟨i, hi⟩ ⟨j, hj⟩ + +/-- +Swaps two entries in a `Vector α n`, or panics if either index is out of bounds. + +This will perform the update destructively provided that `v` has a reference count of 1 when called. +-/ +def swap! (v : Vector α n) (i j : Nat) : Vector α n := + ⟨Array.swap! v.toArray i j, by simp [v.size_eq]⟩ + +/-- +Swaps the entry with index `i : Fin n` in the vector for a new entry. +The old entry is returned with the modified vector. +-/ +def swapAt (v : Vector α n) (i : Fin n) (x : α) : α × Vector α n := + let res := v.toArray.swapAt (Fin.cast v.size_eq.symm i) x + (res.1, ⟨res.2, by simp [Array.swapAt_def, res, v.size_eq]⟩) + +/-- +Swaps the entry with index `i : Nat` in the vector for a new entry `x`. +The old entry is returned alongwith the modified vector. + +Automatically generates a proof of `i < n` with `get_elem_tactic` where feasible. +-/ +def swapAtN (v : Vector α n) (i : Nat) (x : α) (h : i < n := by get_elem_tactic) : α × Vector α n := + swapAt v ⟨i, h⟩ x + +/-- +`swapAt! v i x` swaps out the entry at index `i : Nat` in the vector for `x`, if the index is valid. +Otherwise it panics The old entry is returned with the modified vector. +-/ +@[inline] def swapAt! (v : Vector α n) (i : Nat) (x : α) : α × Vector α n := + if h : i < n then + swapAt v ⟨i, h⟩ x + else + have : Inhabited α := ⟨x⟩ + panic! s!"Index {i} is out of bounds" + +/-- `range n` returns the vector `#v[0,1,2,...,n-1]`. -/ +def range (n : Nat) : Vector Nat n := ⟨Array.range n, Array.size_range ..⟩ + +/-- +`shrink v m` shrinks the vector to the first `m` elements if `m < n`. +Returns `v` unchanged if `m ≥ n`. +-/ +def shrink (v : Vector α n) (m : Nat) : Vector α (min n m) := + ⟨v.toArray.shrink m, by simp [Array.size_shrink, v.size_eq]⟩ + +/-- +Drops the first (up to) `i` elements from a vector of length `n`. +If `m ≥ n`, the return value is empty. +-/ +def drop (i : Nat) (v : Vector α n) : Vector α (n - i) := + have : min n n - i = n - i := by rw [Nat.min_self] + Vector.cast this (extract v i n) + +/-- +Takes the first (up to) `i` elements from a vector of length `n`. + +-/ +alias take := shrink + +/-- +`isEqv` takes a given boolean property `p`. It returns `true` +if and only if `p a[i] b[i]` holds true for all valid indices `i`. +-/ +@[inline] def isEqv (a b : Vector α n) (p : α → α → Bool) : Bool := + Array.isEqvAux a.toArray b.toArray (a.size_eq.trans b.size_eq.symm) p 0 + +instance [BEq α] : BEq (Vector α n) := + ⟨fun a b => isEqv a b BEq.beq⟩ + +proof_wanted lawfulBEq [BEq α] [LawfulBEq α] : LawfulBEq (Vector α n) + +/-- `reverse v` reverses the vector `v`. -/ +def reverse (v : Vector α n) : Vector α n := + ⟨v.toArray.reverse, by simp [v.size_eq]⟩ + +/-- `O(|v| - i)`. `feraseIdx v i` removes the element at position `i` in vector `v`. -/ +def feraseIdx (v : Vector α n) (i : Fin n) : Vector α (n-1) := + ⟨v.toArray.feraseIdx (Fin.cast v.size_eq.symm i), by simp [Array.size_feraseIdx, v.size_eq]⟩ + +/-- `Vector.tail` produces the tail of the vector `v`. -/ +@[inline] def tail (v : Vector α n) : Vector α (n-1) := + match n with + | 0 => v + | _ + 1 => Vector.feraseIdx v 0 + +/-- +`O(|v| - i)`. `eraseIdx! v i` removes the element at position `i` from vector `v` of length `n`. +Panics if `i` is not less than `n`. +-/ +@[inline] def eraseIdx! (v : Vector α n) (i : Nat) : Vector α (n-1) := + if h : i < n then + feraseIdx v ⟨i,h⟩ + else + have : Inhabited (Vector α (n-1)) := ⟨v.tail⟩ + panic! s!"Index {i} is out of bounds" + +/-- +`eraseIdxN v i h` removes the element at position `i` from a vector of length `n`. +`h : i < n` has a default argument `by get_elem_tactic` which tries to supply a proof +that the index is valid. + +This function takes worst case O(n) time because it has to backshift all elements at positions +greater than i. +-/ +abbrev eraseIdxN (v : Vector α n) (i : Nat) (h : i < n := by get_elem_tactic) : Vector α (n - 1) := + v.feraseIdx ⟨i, h⟩ + +/-- +If `x` is an element of vector `v` at index `j`, then `indexOf? v x` returns `some j`. +Otherwise it returns `none`. +-/ +def indexOf? [BEq α] (v : Vector α n) (x : α) : Option (Fin n) := + match Array.indexOf? v.toArray x with + | some res => some (Fin.cast v.size_eq res) + | none => none + +/-- `isPrefixOf as bs` returns true iff vector `as` is a prefix of vector`bs` -/ +def isPrefixOf [BEq α] (as : Vector α m) (bs : Vector α n) : Bool := + Array.isPrefixOf as.toArray bs.toArray + +/-- `allDiff as i` returns `true` when all elements of `v` are distinct from each other` -/ +def allDiff [BEq α] (as : Vector α n) : Bool := + Array.allDiff as.toArray diff --git a/Batteries/Data/Vector/Lemmas.lean b/Batteries/Data/Vector/Lemmas.lean new file mode 100644 index 0000000000..02acccb8ce --- /dev/null +++ b/Batteries/Data/Vector/Lemmas.lean @@ -0,0 +1,47 @@ +/- +Copyright (c) 2024 Shreyas Srinivas. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Shreyas Srinivas, Francois Dorais +-/ + +import Batteries.Data.Vector.Basic +import Batteries.Data.List.Basic +import Batteries.Data.List.Lemmas +import Batteries.Data.Array.Lemmas + +/-! +## Vectors +Lemmas about `Vector α n` +-/ + +namespace Batteries + +namespace Vector + + +/-- An `empty` vector maps to a `empty` vector. -/ +@[simp] +theorem map_empty (f : α → β) : map f empty = empty := by + rw [map, empty, mk.injEq] + exact Array.map_empty f + +theorem toArray_injective : ∀ {v w : Vector α n}, v.toArray = w.toArray → v = w + | {..}, {..}, rfl => rfl + +/-- A vector of length `0` is an `empty` vector. -/ +protected theorem eq_empty (v : Vector α 0) : v = empty := by + apply Vector.toArray_injective + apply Array.eq_empty_of_size_eq_zero v.2 + +/-- +`Vector.ext` is an extensionality theorem. +Vectors `a` and `b` are equal to each other if their elements are equal for each valid index. +-/ +@[ext] +protected theorem ext {a b : Vector α n} (h : (i : Nat) → (_ : i < n) → a[i] = b[i]) : a = b := by + apply Vector.toArray_injective + apply Array.ext + · rw [a.size_eq, b.size_eq] + · intro i hi _ + rw [a.size_eq] at hi + exact h i hi From f2c939c3986ee3a6480b3811588a11ee008ab3b2 Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Sat, 17 Aug 2024 00:50:34 +0200 Subject: [PATCH 199/208] feat: RBMap lemmas (#739) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François G. Dorais --- Batteries/Data/RBMap/Lemmas.lean | 123 +++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/Batteries/Data/RBMap/Lemmas.lean b/Batteries/Data/RBMap/Lemmas.lean index 5577b3a1a7..43d31af8f7 100644 --- a/Batteries/Data/RBMap/Lemmas.lean +++ b/Batteries/Data/RBMap/Lemmas.lean @@ -1103,3 +1103,126 @@ theorem lowerBound?_lt {t : RBSet α cmp} [TransCmp cmp] lowerBoundP?_lt H hz end RBSet + +namespace RBMap + +-- @[simp] -- FIXME: RBSet.val_toList already triggers here, seems bad? +theorem val_toList {t : RBMap α β cmp} : t.1.toList = t.toList := rfl + +@[simp] theorem mkRBSet_eq : mkRBMap α β cmp = ∅ := rfl +@[simp] theorem empty_eq : @RBMap.empty α β cmp = ∅ := rfl +@[simp] theorem default_eq : (default : RBMap α β cmp) = ∅ := rfl +@[simp] theorem empty_toList : toList (∅ : RBMap α β cmp) = [] := rfl +@[simp] theorem single_toList : toList (single a b : RBMap α β cmp) = [(a, b)] := rfl + +theorem mem_toList {t : RBMap α β cmp} : x ∈ toList t ↔ x ∈ t.1 := RBNode.mem_toList + +theorem foldl_eq_foldl_toList {t : RBMap α β cmp} : + t.foldl f init = t.toList.foldl (fun r p => f r p.1 p.2) init := + RBNode.foldl_eq_foldl_toList + +theorem foldr_eq_foldr_toList {t : RBMap α β cmp} : + t.foldr f init = t.toList.foldr (fun p r => f p.1 p.2 r) init := + RBNode.foldr_eq_foldr_toList + +theorem foldlM_eq_foldlM_toList [Monad m] [LawfulMonad m] {t : RBMap α β cmp} : + t.foldlM (m := m) f init = t.toList.foldlM (fun r p => f r p.1 p.2) init := + RBNode.foldlM_eq_foldlM_toList + +theorem forM_eq_forM_toList [Monad m] [LawfulMonad m] {t : RBMap α β cmp} : + t.forM (m := m) f = t.toList.forM (fun p => f p.1 p.2) := + RBNode.forM_eq_forM_toList + +theorem forIn_eq_forIn_toList [Monad m] [LawfulMonad m] {t : RBMap α β cmp} : + forIn (m := m) t init f = forIn t.toList init f := RBNode.forIn_eq_forIn_toList + +theorem toStream_eq {t : RBMap α β cmp} : toStream t = t.1.toStream .nil := rfl + +@[simp] theorem toStream_toList {t : RBMap α β cmp} : (toStream t).toList = t.toList := + RBSet.toStream_toList + +theorem toList_sorted {t : RBMap α β cmp} : t.toList.Pairwise (RBNode.cmpLT (cmp ·.1 ·.1)) := + RBSet.toList_sorted + +theorem findEntry?_some_eq_eq {t : RBMap α β cmp} : t.findEntry? x = some (y, v) → cmp x y = .eq := + RBSet.findP?_some_eq_eq + +theorem findEntry?_some_mem_toList {t : RBMap α β cmp} (h : t.findEntry? x = some y) : + y ∈ toList t := RBSet.findP?_some_mem_toList h + +theorem find?_some_mem_toList {t : RBMap α β cmp} (h : t.find? x = some v) : + ∃ y, (y, v) ∈ toList t ∧ cmp x y = .eq := by + obtain ⟨⟨y, v⟩, h', rfl⟩ := Option.map_eq_some'.1 h + exact ⟨_, findEntry?_some_mem_toList h', findEntry?_some_eq_eq h'⟩ + +theorem mem_toList_unique [@TransCmp α cmp] {t : RBMap α β cmp} + (hx : x ∈ toList t) (hy : y ∈ toList t) (e : cmp x.1 y.1 = .eq) : x = y := + RBSet.mem_toList_unique hx hy e + +/-- A "representable cut" is one generated by `cmp a` for some `a`. This is always a valid cut. -/ +instance (cmp) (a : α) : IsStrictCut cmp (cmp a) where + le_lt_trans h₁ h₂ := TransCmp.lt_le_trans h₂ h₁ + le_gt_trans h₁ := Decidable.not_imp_not.1 (TransCmp.le_trans · h₁) + exact h := (TransCmp.cmp_congr_left h).symm + +instance (f : α → β) (cmp) [@TransCmp β cmp] (x : β) : + IsStrictCut (Ordering.byKey f cmp) (fun y => cmp x (f y)) where + le_lt_trans h₁ h₂ := TransCmp.lt_le_trans h₂ h₁ + le_gt_trans h₁ := Decidable.not_imp_not.1 (TransCmp.le_trans · h₁) + exact h := (TransCmp.cmp_congr_left h).symm + +theorem findEntry?_some [@TransCmp α cmp] {t : RBMap α β cmp} : + t.findEntry? x = some y ↔ y ∈ toList t ∧ cmp x y.1 = .eq := RBSet.findP?_some + +theorem find?_some [@TransCmp α cmp] {t : RBMap α β cmp} : + t.find? x = some v ↔ ∃ y, (y, v) ∈ toList t ∧ cmp x y = .eq := by + simp only [find?, findEntry?_some, Option.map_eq_some']; constructor + · rintro ⟨_, h, rfl⟩; exact ⟨_, h⟩ + · rintro ⟨b, h⟩; exact ⟨_, h, rfl⟩ + +theorem contains_iff_findEntry? {t : RBMap α β cmp} : + t.contains x ↔ ∃ v, t.findEntry? x = some v := Option.isSome_iff_exists + +theorem contains_iff_find? {t : RBMap α β cmp} : + t.contains x ↔ ∃ v, t.find? x = some v := by + simp [contains_iff_findEntry?, find?, and_comm, exists_comm] + +theorem size_eq (t : RBMap α β cmp) : t.size = t.toList.length := RBNode.size_eq + +theorem mem_toList_insert_self (v) (t : RBMap α β cmp) : (k, v) ∈ toList (t.insert k v) := + RBSet.mem_toList_insert_self .. + +theorem mem_toList_insert_of_mem (v) {t : RBMap α β cmp} (h : y ∈ toList t) : + y ∈ toList (t.insert k v) ∨ cmp k y.1 = .eq := RBSet.mem_toList_insert_of_mem _ h + +theorem mem_toList_insert [@TransCmp α cmp] {t : RBMap α β cmp} : + y ∈ toList (t.insert k v) ↔ (y ∈ toList t ∧ t.findEntry? k ≠ some y) ∨ y = (k, v) := + RBSet.mem_toList_insert + +theorem findEntry?_congr [@TransCmp α cmp] (t : RBMap α β cmp) (h : cmp k₁ k₂ = .eq) : + t.findEntry? k₁ = t.findEntry? k₂ := by simp [findEntry?, TransCmp.cmp_congr_left' h] + +theorem find?_congr [@TransCmp α cmp] (t : RBMap α β cmp) (h : cmp k₁ k₂ = .eq) : + t.find? k₁ = t.find? k₂ := by simp [find?, findEntry?_congr _ h] + +theorem findEntry?_insert_of_eq [@TransCmp α cmp] (t : RBMap α β cmp) (h : cmp k' k = .eq) : + (t.insert k v).findEntry? k' = some (k, v) := RBSet.findP?_insert_of_eq _ h + +theorem find?_insert_of_eq [@TransCmp α cmp] (t : RBMap α β cmp) (h : cmp k' k = .eq) : + (t.insert k v).find? k' = some v := by rw [find?, findEntry?_insert_of_eq _ h]; rfl + +theorem findEntry?_insert_of_ne [@TransCmp α cmp] (t : RBMap α β cmp) (h : cmp k' k ≠ .eq) : + (t.insert k v).findEntry? k' = t.findEntry? k' := RBSet.findP?_insert_of_ne _ h + +theorem find?_insert_of_ne [@TransCmp α cmp] (t : RBMap α β cmp) (h : cmp k' k ≠ .eq) : + (t.insert k v).find? k' = t.find? k' := by simp [find?, findEntry?_insert_of_ne _ h] + +theorem findEntry?_insert [@TransCmp α cmp] (t : RBMap α β cmp) (k v k') : + (t.insert k v).findEntry? k' = if cmp k' k = .eq then some (k, v) else t.findEntry? k' := + RBSet.findP?_insert .. + +theorem find?_insert [@TransCmp α cmp] (t : RBMap α β cmp) (k v k') : + (t.insert k v).find? k' = if cmp k' k = .eq then some v else t.find? k' := by + split <;> [exact find?_insert_of_eq t ‹_›; exact find?_insert_of_ne t ‹_›] + +end RBMap From f7aebca12535aff8577e927e7f5bfc185c26e0c4 Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Fri, 16 Aug 2024 19:04:06 -0400 Subject: [PATCH 200/208] fix: splitAtD reverse bug from #919 --- Batteries/Data/List/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index 7e6e034dc4..679e8c505d 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -137,7 +137,7 @@ def splitAtD (n : Nat) (l : List α) (dflt : α) : List α × List α := go n l if `splitAtD n l dflt = (left, right)`. -/ go : Nat → List α → List α → List α × List α | n+1, x :: xs, acc => go n xs (x :: acc) - | 0, xs, acc => (acc, xs) + | 0, xs, acc => (acc.reverse, xs) | n, [], acc => (acc.reverseAux (replicate n dflt), []) /-- From d3091570b4a34a4f77ef2cdc227838edf625dc85 Mon Sep 17 00:00:00 2001 From: damiano Date: Sat, 17 Aug 2024 01:37:12 +0200 Subject: [PATCH 201/208] feat: add lemma code-action (#625) Co-authored-by: F. G. Dorais --- Batteries.lean | 1 + Batteries/Tactic/Lemma.lean | 50 +++++++++++++++++++++++++++++++++++++ test/lemma_cmd.lean | 34 +++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 Batteries/Tactic/Lemma.lean create mode 100644 test/lemma_cmd.lean diff --git a/Batteries.lean b/Batteries.lean index 5fd8bc72ad..d607662196 100644 --- a/Batteries.lean +++ b/Batteries.lean @@ -82,6 +82,7 @@ import Batteries.Tactic.Congr import Batteries.Tactic.Exact import Batteries.Tactic.Init import Batteries.Tactic.Instances +import Batteries.Tactic.Lemma import Batteries.Tactic.Lint import Batteries.Tactic.Lint.Basic import Batteries.Tactic.Lint.Frontend diff --git a/Batteries/Tactic/Lemma.lean b/Batteries/Tactic/Lemma.lean new file mode 100644 index 0000000000..10fdec7a0e --- /dev/null +++ b/Batteries/Tactic/Lemma.lean @@ -0,0 +1,50 @@ +/- +Copyright (c) 2024 Johan Commelin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johan Commelin, Damiano Testa +-/ +import Lean.Meta.Tactic.TryThis + +/-! +# Control for `lemma` command + +The `lemma` command exists in `Mathlib`, but not in `Std`. + +This file enforces the convention by introducing a code-action +to replace `lemma` by `theorem`. +-/ + +namespace Batteries.Tactic.Lemma + +open Lean Elab.Command Meta.Tactic + +/-- Enables the use of `lemma` as a synonym for `theorem` -/ +register_option lang.lemmaCmd : Bool := { + defValue := false + descr := "enable the use of the `lemma` command as a synonym for `theorem`" +} + +/-- Check whether `lang.lemmaCmd` option is enabled -/ +def checkLangLemmaCmd (o : Options) : Bool := o.get `lang.lemmaCmd lang.lemmaCmd.defValue + +/-- `lemma` is not supported, please use `theorem` instead -/ +syntax (name := lemmaCmd) declModifiers + group("lemma " declId ppIndent(declSig) declVal) : command + +/-- Elaborator for the `lemma` command, if the option `lang.lemmaCmd` is false the command +emits a warning and code action instructing the user to use `theorem` instead.-/ +@[command_elab «lemmaCmd»] def elabLemma : CommandElab := fun stx => do + unless checkLangLemmaCmd (← getOptions) do + let lemmaStx := stx[1][0] + Elab.Command.liftTermElabM <| + TryThis.addSuggestion lemmaStx { suggestion := "theorem" } + logErrorAt lemmaStx + "`lemma` is not supported by default, please use `theorem` instead.\n\ + Use `set_option lang.lemmaCmd true` to enable the use of the `lemma` command in a file.\n\ + Use the command line option `-Dlang.lemmaCmd=true` to enable the use of `lemma` globally." + let out ← Elab.liftMacroM <| do + let stx := stx.modifyArg 1 fun stx => + let stx := stx.modifyArg 0 (mkAtomFrom · "theorem" (canonical := true)) + stx.setKind ``Parser.Command.theorem + pure <| stx.setKind ``Parser.Command.declaration + Elab.Command.elabCommand out diff --git a/test/lemma_cmd.lean b/test/lemma_cmd.lean new file mode 100644 index 0000000000..7952f5766f --- /dev/null +++ b/test/lemma_cmd.lean @@ -0,0 +1,34 @@ +import Batteries.Tactic.Lemma + +-- lemma disabled by default +/-- +info: Try this: theorem +--- +error: `lemma` is not supported by default, please use `theorem` instead. +Use `set_option lang.lemmaCmd true` to enable the use of the `lemma` command in a file. +Use the command line option `-Dlang.lemmaCmd=true` to enable the use of `lemma` globally. +-/ +#guard_msgs in +lemma test1 : 3 < 7 := by decide + +-- lemma enabled for one command +set_option lang.lemmaCmd true in +lemma test2 : 3 < 7 := by decide + +-- lemma disabled again +/-- +info: Try this: theorem +--- +error: `lemma` is not supported by default, please use `theorem` instead. +Use `set_option lang.lemmaCmd true` to enable the use of the `lemma` command in a file. +Use the command line option `-Dlang.lemmaCmd=true` to enable the use of `lemma` globally. +-/ +#guard_msgs in +lemma test3 : 3 < 7 := by decide + +-- lemma enabled for rest of file +set_option lang.lemmaCmd true + +lemma test4 : 3 < 7 := by decide + +lemma test5 : 3 < 7 := by decide From b1a2ec94f9752a45ca655ab48286a1d8d9df78b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20G=2E=20Dorais?= Date: Fri, 16 Aug 2024 20:27:21 -0400 Subject: [PATCH 202/208] feat: `List.insertP` and lemmas (#569) Co-authored-by: Mario Carneiro --- Batteries/Data/List/Basic.lean | 12 ++++++++++++ Batteries/Data/List/Lemmas.lean | 27 +++++++++++++++++++++++++++ Batteries/Data/List/Perm.lean | 11 +++++++++++ 3 files changed, 50 insertions(+) diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index 679e8c505d..2d6e73a14b 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -1180,6 +1180,18 @@ See `isSubperm_iff` for a characterization in terms of `List.Subperm`. -/ def isSubperm [BEq α] (l₁ l₂ : List α) : Bool := ∀ x ∈ l₁, count x l₁ ≤ count x l₂ +/-- +`O(|l|)`. Inserts `a` in `l` right before the first element such that `p` is true, or at the end of +the list if `p` always false on `l`. +-/ +def insertP (p : α → Bool) (a : α) (l : List α) : List α := + loop l [] +where + /-- Inner loop for `insertP`. Tail recursive. -/ + loop : List α → List α → List α + | [], r => reverseAux (a :: r) [] -- Note: `reverseAux` is tail recursive. + | b :: l, r => bif p b then reverseAux (a :: r) (b :: l) else loop l (b :: r) + /-- `O(|l| + |r|)`. Merge two lists using `s` as a switch. -/ diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 3eea690ad6..8d8b3e1cd6 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -562,10 +562,37 @@ theorem indexOf_mem_indexesOf [BEq α] [LawfulBEq α] {xs : List α} (m : x ∈ specialize ih m simpa +/-! ### insertP -/ + +theorem insertP_loop (a : α) (l r : List α) : + insertP.loop p a l r = reverseAux r (insertP p a l) := by + induction l generalizing r with simp [insertP, insertP.loop, cond] + | cons b l ih => rw [ih (b :: r), ih [b]]; split <;> rfl + +@[simp] theorem insertP_nil (p : α → Bool) (a) : insertP p a [] = [a] := rfl + +@[simp] theorem insertP_cons_pos (p : α → Bool) (a b l) (h : p b) : + insertP p a (b :: l) = a :: b :: l := by + simp only [insertP, insertP.loop, cond, h]; rfl + +@[simp] theorem insertP_cons_neg (p : α → Bool) (a b l) (h : ¬ p b) : + insertP p a (b :: l) = b :: insertP p a l := by + simp only [insertP, insertP.loop, cond, h]; exact insertP_loop .. + +@[simp] theorem length_insertP (p : α → Bool) (a l) : (insertP p a l).length = l.length + 1 := by + induction l with simp [insertP, insertP.loop, cond] + | cons _ _ ih => split <;> simp [insertP_loop, ih] + +@[simp] theorem mem_insertP (p : α → Bool) (a l) : a ∈ insertP p a l := by + induction l with simp [insertP, insertP.loop, cond] + | cons _ _ ih => split <;> simp [insertP_loop, ih] + theorem merge_loop_nil_left (s : α → α → Bool) (r t) : merge.loop s [] r t = reverseAux t r := by rw [merge.loop] +/-! ### merge -/ + theorem merge_loop_nil_right (s : α → α → Bool) (l t) : merge.loop s l [] t = reverseAux t l := by cases l <;> rw [merge.loop]; intro; contradiction diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index 5c31720c7c..ed2a18f5cf 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -700,6 +700,17 @@ theorem Perm.eraseP (f : α → Bool) {l₁ l₂ : List α} refine (IH₁ H).trans (IH₂ ((p₁.pairwise_iff ?_).1 H)) exact fun h h₁ h₂ => h h₂ h₁ +theorem perm_insertP (p : α → Bool) (a l) : insertP p a l ~ a :: l := by + induction l with simp [insertP, insertP.loop, cond] + | cons _ _ ih => + split + · exact Perm.refl .. + · rw [insertP_loop, reverseAux, reverseAux] + exact Perm.trans (Perm.cons _ ih) (Perm.swap ..) + +theorem Perm.insertP (p : α → Bool) (a) (h : l₁ ~ l₂) : insertP p a l₁ ~ insertP p a l₂ := + Perm.trans (perm_insertP ..) <| Perm.trans (Perm.cons _ h) <| Perm.symm (perm_insertP ..) + theorem perm_merge (s : α → α → Bool) (l r) : merge s l r ~ l ++ r := by match l, r with | [], r => simp From b5d4fc36e3ca6399faeee87ea16485e29be2ca04 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Sat, 17 Aug 2024 12:19:02 +1000 Subject: [PATCH 203/208] fix looping simp? --- Batteries/Data/RBMap/Lemmas.lean | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Batteries/Data/RBMap/Lemmas.lean b/Batteries/Data/RBMap/Lemmas.lean index 43d31af8f7..0a6d7d820a 100644 --- a/Batteries/Data/RBMap/Lemmas.lean +++ b/Batteries/Data/RBMap/Lemmas.lean @@ -1185,7 +1185,9 @@ theorem contains_iff_findEntry? {t : RBMap α β cmp} : theorem contains_iff_find? {t : RBMap α β cmp} : t.contains x ↔ ∃ v, t.find? x = some v := by - simp [contains_iff_findEntry?, find?, and_comm, exists_comm] + simp only [contains_iff_findEntry?, Prod.exists, find?, Option.map_eq_some', and_comm, + exists_eq_left] + rw [exists_comm] theorem size_eq (t : RBMap α β cmp) : t.size = t.toList.length := RBNode.size_eq From 65f464e6a5f30b2c2a58569f530c4677b371cec6 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Sat, 17 Aug 2024 12:34:20 +1000 Subject: [PATCH 204/208] chore: remove unnecessary case for splitAt.go (#921) --- Batteries/Data/List/Basic.lean | 4 +--- Batteries/Data/List/Lemmas.lean | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index 2d6e73a14b..fc2cecae44 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -117,10 +117,8 @@ splitAt 2 [a, b, c] = ([a, b], [c]) ``` -/ def splitAt (n : Nat) (l : List α) : List α × List α := go l n [] where - /-- Auxiliary for `splitAt`: `splitAt.go l n xs acc = (acc.reverse ++ take n xs, drop n xs)` - if `n < length xs`, else `(l, [])`. -/ + /-- Auxiliary for `splitAt`: `splitAt.go xs n acc = (acc.reverse ++ take n xs, drop n xs)`. -/ go : List α → Nat → List α → List α × List α - | [], _, _ => (l, []) | x :: xs, n+1, acc => go xs n (x :: acc) | xs, _, acc => (acc.reverse, xs) diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 8d8b3e1cd6..9e5f4e3ace 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -189,6 +189,22 @@ theorem get?_set_of_lt' (a : α) {m n} (l : List α) (h : m < length l) : @[deprecated (since := "2024-05-06")] alias length_removeNth := length_eraseIdx +/-! ### splitAt -/ + +theorem splitAt_go (n : Nat) (l acc : List α) : + splitAt.go l n acc = (acc.reverse ++ l.take n, l.drop n) := by + induction l generalizing n acc with + | nil => simp [splitAt.go] + | cons x xs ih => + cases n with + | zero => simp [splitAt.go] + | succ n => + rw [splitAt.go, take_succ_cons, drop_succ_cons, ih n (x :: acc), + reverse_cons, append_assoc, singleton_append] + +theorem splitAt_eq (n : Nat) (l : List α) : splitAt n l = (l.take n, l.drop n) := by + rw [splitAt, splitAt_go, reverse_nil, nil_append] + /-! ### eraseP -/ @[simp] theorem extractP_eq_find?_eraseP From a975dea2c4d8258a55b4f9861c537e2bb0f9ef63 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Sat, 17 Aug 2024 16:00:57 +1000 Subject: [PATCH 205/208] chore: restore splitAt pointer equality behaviour (#922) --- Batteries/Data/List/Basic.lean | 8 +++++++- Batteries/Data/List/Lemmas.lean | 9 ++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index fc2cecae44..ca8d6ca04b 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -117,8 +117,14 @@ splitAt 2 [a, b, c] = ([a, b], [c]) ``` -/ def splitAt (n : Nat) (l : List α) : List α × List α := go l n [] where - /-- Auxiliary for `splitAt`: `splitAt.go xs n acc = (acc.reverse ++ take n xs, drop n xs)`. -/ + /-- + Auxiliary for `splitAt`: + `splitAt.go l xs n acc = (acc.reverse ++ take n xs, drop n xs)` if `n < xs.length`, + and `(l, [])` otherwise. + -/ go : List α → Nat → List α → List α × List α + | [], _, _ => (l, []) -- This branch ensures the pointer equality of the result with the input + -- without any runtime branching cost. | x :: xs, n+1, acc => go xs n (x :: acc) | xs, _, acc => (acc.reverse, xs) diff --git a/Batteries/Data/List/Lemmas.lean b/Batteries/Data/List/Lemmas.lean index 9e5f4e3ace..74d44af907 100644 --- a/Batteries/Data/List/Lemmas.lean +++ b/Batteries/Data/List/Lemmas.lean @@ -192,18 +192,21 @@ theorem get?_set_of_lt' (a : α) {m n} (l : List α) (h : m < length l) : /-! ### splitAt -/ theorem splitAt_go (n : Nat) (l acc : List α) : - splitAt.go l n acc = (acc.reverse ++ l.take n, l.drop n) := by - induction l generalizing n acc with + splitAt.go l xs n acc = + if n < xs.length then (acc.reverse ++ xs.take n, xs.drop n) else (l, []) := by + induction xs generalizing n acc with | nil => simp [splitAt.go] | cons x xs ih => cases n with | zero => simp [splitAt.go] | succ n => rw [splitAt.go, take_succ_cons, drop_succ_cons, ih n (x :: acc), - reverse_cons, append_assoc, singleton_append] + reverse_cons, append_assoc, singleton_append, length_cons] + simp only [Nat.succ_lt_succ_iff] theorem splitAt_eq (n : Nat) (l : List α) : splitAt n l = (l.take n, l.drop n) := by rw [splitAt, splitAt_go, reverse_nil, nil_append] + split <;> simp_all [take_of_length_le, drop_of_length_le] /-! ### eraseP -/ From ecbdfba3f983b9c4319727712165f9a50029c2b2 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sat, 17 Aug 2024 09:05:00 +0000 Subject: [PATCH 206/208] chore: bump to nightly-2024-08-17 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 68e968509a..ea81516874 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-16 +leanprover/lean4:nightly-2024-08-17 From b8e756b7503843947a932352fe529477ec2fcae1 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 19 Aug 2024 12:05:26 +1000 Subject: [PATCH 207/208] upstream perm --- Batteries/Data/List/Basic.lean | 24 -- Batteries/Data/List/Perm.lean | 386 --------------------------------- 2 files changed, 410 deletions(-) diff --git a/Batteries/Data/List/Basic.lean b/Batteries/Data/List/Basic.lean index 5f03d3ba1e..f483934221 100644 --- a/Batteries/Data/List/Basic.lean +++ b/Batteries/Data/List/Basic.lean @@ -1145,30 +1145,6 @@ protected def traverse [Applicative F] (f : α → F β) : List α → F (List | [] => pure [] | x :: xs => List.cons <$> f x <*> List.traverse f xs -/-- -`Perm l₁ l₂` or `l₁ ~ l₂` asserts that `l₁` and `l₂` are permutations -of each other. This is defined by induction using pairwise swaps. --/ -inductive Perm : List α → List α → Prop - /-- `[] ~ []` -/ - | nil : Perm [] [] - /-- `l₁ ~ l₂ → x::l₁ ~ x::l₂` -/ - | cons (x : α) {l₁ l₂ : List α} : Perm l₁ l₂ → Perm (x :: l₁) (x :: l₂) - /-- `x::y::l ~ y::x::l` -/ - | swap (x y : α) (l : List α) : Perm (y :: x :: l) (x :: y :: l) - /-- `Perm` is transitive. -/ - | trans {l₁ l₂ l₃ : List α} : Perm l₁ l₂ → Perm l₂ l₃ → Perm l₁ l₃ - -@[inherit_doc] scoped infixl:50 " ~ " => Perm - -/-- -`O(|l₁| * |l₂|)`. Computes whether `l₁` is a permutation of `l₂`. See `isPerm_iff` for a -characterization in terms of `List.Perm`. --/ -def isPerm [BEq α] : List α → List α → Bool - | [], l₂ => l₂.isEmpty - | a :: l₁, l₂ => l₂.contains a && l₁.isPerm (l₂.erase a) - /-- `Subperm l₁ l₂`, denoted `l₁ <+~ l₂`, means that `l₁` is a sublist of a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects diff --git a/Batteries/Data/List/Perm.lean b/Batteries/Data/List/Perm.lean index ed2a18f5cf..b14878bf36 100644 --- a/Batteries/Data/List/Perm.lean +++ b/Batteries/Data/List/Perm.lean @@ -23,189 +23,6 @@ namespace List open Perm (swap) -@[simp, refl] protected theorem Perm.refl : ∀ l : List α, l ~ l - | [] => .nil - | x :: xs => (Perm.refl xs).cons x - -protected theorem Perm.rfl {l : List α} : l ~ l := .refl _ - -theorem Perm.of_eq (h : l₁ = l₂) : l₁ ~ l₂ := h ▸ .rfl - -protected theorem Perm.symm {l₁ l₂ : List α} (h : l₁ ~ l₂) : l₂ ~ l₁ := by - induction h with - | nil => exact nil - | cons _ _ ih => exact cons _ ih - | swap => exact swap .. - | trans _ _ ih₁ ih₂ => exact trans ih₂ ih₁ - -theorem perm_comm {l₁ l₂ : List α} : l₁ ~ l₂ ↔ l₂ ~ l₁ := ⟨Perm.symm, Perm.symm⟩ - -theorem Perm.swap' (x y : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : y :: x :: l₁ ~ x :: y :: l₂ := - (swap ..).trans <| p.cons _ |>.cons _ - -/-- -Similar to `Perm.recOn`, but the `swap` case is generalized to `Perm.swap'`, -where the tail of the lists are not necessarily the same. --/ -@[elab_as_elim] theorem Perm.recOnSwap' - {motive : (l₁ : List α) → (l₂ : List α) → l₁ ~ l₂ → Prop} {l₁ l₂ : List α} (p : l₁ ~ l₂) - (nil : motive [] [] .nil) - (cons : ∀ x {l₁ l₂}, (h : l₁ ~ l₂) → motive l₁ l₂ h → motive (x :: l₁) (x :: l₂) (.cons x h)) - (swap' : ∀ x y {l₁ l₂}, (h : l₁ ~ l₂) → motive l₁ l₂ h → - motive (y :: x :: l₁) (x :: y :: l₂) (.swap' _ _ h)) - (trans : ∀ {l₁ l₂ l₃}, (h₁ : l₁ ~ l₂) → (h₂ : l₂ ~ l₃) → motive l₁ l₂ h₁ → motive l₂ l₃ h₂ → - motive l₁ l₃ (.trans h₁ h₂)) : motive l₁ l₂ p := - have motive_refl l : motive l l (.refl l) := - List.recOn l nil fun x xs ih => cons x (.refl xs) ih - Perm.recOn p nil cons (fun x y l => swap' x y (.refl l) (motive_refl l)) trans - -theorem Perm.eqv (α) : Equivalence (@Perm α) := ⟨.refl, .symm, .trans⟩ - -instance isSetoid (α) : Setoid (List α) := .mk Perm (Perm.eqv α) - -theorem Perm.mem_iff {a : α} {l₁ l₂ : List α} (p : l₁ ~ l₂) : a ∈ l₁ ↔ a ∈ l₂ := by - induction p with - | nil => rfl - | cons _ _ ih => simp only [mem_cons, ih] - | swap => simp only [mem_cons, or_left_comm] - | trans _ _ ih₁ ih₂ => simp only [ih₁, ih₂] - -theorem Perm.subset {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁ ⊆ l₂ := fun _ => p.mem_iff.mp - -theorem Perm.append_right {l₁ l₂ : List α} (t₁ : List α) (p : l₁ ~ l₂) : l₁ ++ t₁ ~ l₂ ++ t₁ := by - induction p with - | nil => rfl - | cons _ _ ih => exact cons _ ih - | swap => exact swap .. - | trans _ _ ih₁ ih₂ => exact trans ih₁ ih₂ - -theorem Perm.append_left {t₁ t₂ : List α} : ∀ l : List α, t₁ ~ t₂ → l ++ t₁ ~ l ++ t₂ - | [], p => p - | x :: xs, p => (p.append_left xs).cons x - -theorem Perm.append {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : l₁ ++ t₁ ~ l₂ ++ t₂ := - (p₁.append_right t₁).trans (p₂.append_left l₂) - -theorem Perm.append_cons (a : α) {h₁ h₂ t₁ t₂ : List α} (p₁ : h₁ ~ h₂) (p₂ : t₁ ~ t₂) : - h₁ ++ a :: t₁ ~ h₂ ++ a :: t₂ := p₁.append (p₂.cons a) - -@[simp] theorem perm_middle {a : α} : ∀ {l₁ l₂ : List α}, l₁ ++ a :: l₂ ~ a :: (l₁ ++ l₂) - | [], _ => .refl _ - | b :: _, _ => (Perm.cons _ perm_middle).trans (swap a b _) - -@[simp] theorem perm_append_singleton (a : α) (l : List α) : l ++ [a] ~ a :: l := - perm_middle.trans <| by rw [append_nil] - -theorem perm_append_comm : ∀ {l₁ l₂ : List α}, l₁ ++ l₂ ~ l₂ ++ l₁ - | [], l₂ => by simp - | a :: t, l₂ => (perm_append_comm.cons _).trans perm_middle.symm - -theorem concat_perm (l : List α) (a : α) : concat l a ~ a :: l := by simp - -theorem Perm.length_eq {l₁ l₂ : List α} (p : l₁ ~ l₂) : length l₁ = length l₂ := by - induction p with - | nil => rfl - | cons _ _ ih => simp only [length_cons, ih] - | swap => rfl - | trans _ _ ih₁ ih₂ => simp only [ih₁, ih₂] - -theorem Perm.eq_nil {l : List α} (p : l ~ []) : l = [] := eq_nil_of_length_eq_zero p.length_eq - -theorem Perm.nil_eq {l : List α} (p : [] ~ l) : [] = l := p.symm.eq_nil.symm - -@[simp] theorem perm_nil {l₁ : List α} : l₁ ~ [] ↔ l₁ = [] := - ⟨fun p => p.eq_nil, fun e => e ▸ .rfl⟩ - -@[simp] theorem nil_perm {l₁ : List α} : [] ~ l₁ ↔ l₁ = [] := perm_comm.trans perm_nil - -theorem not_perm_nil_cons (x : α) (l : List α) : ¬[] ~ x :: l := (nomatch ·.symm.eq_nil) - -@[simp] theorem reverse_perm : ∀ l : List α, reverse l ~ l - | [] => .nil - | a :: l => reverse_cons .. ▸ (perm_append_singleton _ _).trans ((reverse_perm l).cons a) - -theorem perm_cons_append_cons {l l₁ l₂ : List α} (a : α) (p : l ~ l₁ ++ l₂) : - a :: l ~ l₁ ++ a :: l₂ := (p.cons a).trans perm_middle.symm - -@[simp] theorem perm_replicate {n : Nat} {a : α} {l : List α} : - l ~ replicate n a ↔ l = replicate n a := by - refine ⟨fun p => eq_replicate.2 ?_, fun h => h ▸ .rfl⟩ - exact ⟨p.length_eq.trans <| length_replicate .., fun _b m => eq_of_mem_replicate <| p.subset m⟩ - -@[simp] theorem replicate_perm {n : Nat} {a : α} {l : List α} : - replicate n a ~ l ↔ replicate n a = l := (perm_comm.trans perm_replicate).trans eq_comm - -@[simp] theorem perm_singleton {a : α} {l : List α} : l ~ [a] ↔ l = [a] := perm_replicate (n := 1) - -@[simp] theorem singleton_perm {a : α} {l : List α} : [a] ~ l ↔ [a] = l := replicate_perm (n := 1) - -alias ⟨Perm.eq_singleton,_⟩ := perm_singleton -alias ⟨Perm.singleton_eq,_⟩ := singleton_perm - -theorem singleton_perm_singleton {a b : α} : [a] ~ [b] ↔ a = b := by simp - -theorem perm_cons_erase [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) : l ~ a :: l.erase a := - let ⟨_l₁, _l₂, _, e₁, e₂⟩ := exists_erase_eq h - e₂ ▸ e₁ ▸ perm_middle - -theorem Perm.filterMap (f : α → Option β) {l₁ l₂ : List α} (p : l₁ ~ l₂) : - filterMap f l₁ ~ filterMap f l₂ := by - induction p with - | nil => simp - | cons x _p IH => cases h : f x <;> simp [h, filterMap_cons, IH, Perm.cons] - | swap x y l₂ => cases hx : f x <;> cases hy : f y <;> simp [hx, hy, filterMap_cons, swap] - | trans _p₁ _p₂ IH₁ IH₂ => exact IH₁.trans IH₂ - -theorem Perm.map (f : α → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) : map f l₁ ~ map f l₂ := - filterMap_eq_map f ▸ p.filterMap _ - -theorem Perm.pmap {p : α → Prop} (f : ∀ a, p a → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) {H₁ H₂} : - pmap f l₁ H₁ ~ pmap f l₂ H₂ := by - induction p with - | nil => simp - | cons x _p IH => simp [IH, Perm.cons] - | swap x y => simp [swap] - | trans _p₁ p₂ IH₁ IH₂ => exact IH₁.trans (IH₂ (H₁ := fun a m => H₂ a (p₂.subset m))) - -theorem Perm.filter (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) : - filter p l₁ ~ filter p l₂ := by rw [← filterMap_eq_filter]; apply s.filterMap - -theorem filter_append_perm (p : α → Bool) (l : List α) : - filter p l ++ filter (fun x => !p x) l ~ l := by - induction l with - | nil => rfl - | cons x l ih => - by_cases h : p x <;> simp [h] - · exact ih.cons x - · exact Perm.trans (perm_append_comm.trans (perm_append_comm.cons _)) (ih.cons x) - -theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p : l₂ ~ l₂') : - ∃ l₁', l₁' ~ l₁ ∧ l₁' <+ l₂' := by - induction p generalizing l₁ with - | nil => exact ⟨[], sublist_nil.mp s ▸ .rfl, nil_sublist _⟩ - | cons x _ IH => - match s with - | .cons _ s => let ⟨l₁', p', s'⟩ := IH s; exact ⟨l₁', p', s'.cons _⟩ - | .cons₂ _ s => let ⟨l₁', p', s'⟩ := IH s; exact ⟨x :: l₁', p'.cons x, s'.cons₂ _⟩ - | swap x y l' => - match s with - | .cons _ (.cons _ s) => exact ⟨_, .rfl, (s.cons _).cons _⟩ - | .cons _ (.cons₂ _ s) => exact ⟨x :: _, .rfl, (s.cons _).cons₂ _⟩ - | .cons₂ _ (.cons _ s) => exact ⟨y :: _, .rfl, (s.cons₂ _).cons _⟩ - | .cons₂ _ (.cons₂ _ s) => exact ⟨x :: y :: _, .swap .., (s.cons₂ _).cons₂ _⟩ - | trans _ _ IH₁ IH₂ => - let ⟨m₁, pm, sm⟩ := IH₁ s - let ⟨r₁, pr, sr⟩ := IH₂ sm - exact ⟨r₁, pr.trans pm, sr⟩ - -theorem Perm.sizeOf_eq_sizeOf [SizeOf α] {l₁ l₂ : List α} (h : l₁ ~ l₂) : - sizeOf l₁ = sizeOf l₂ := by - induction h with - | nil => rfl - | cons _ _ h_sz₁₂ => simp [h_sz₁₂] - | swap => simp [Nat.add_left_comm] - | trans _ _ h_sz₁₂ h_sz₂₃ => simp [h_sz₁₂, h_sz₂₃] - section Subperm theorem nil_subperm {l : List α} : [] <+~ l := ⟨[], Perm.nil, by simp⟩ @@ -256,115 +73,12 @@ theorem Subperm.filter (p : α → Bool) ⦃l l' : List α⦄ (h : l <+~ l') : end Subperm -theorem Sublist.exists_perm_append {l₁ l₂ : List α} : l₁ <+ l₂ → ∃ l, l₂ ~ l₁ ++ l - | Sublist.slnil => ⟨nil, .rfl⟩ - | Sublist.cons a s => - let ⟨l, p⟩ := Sublist.exists_perm_append s - ⟨a :: l, (p.cons a).trans perm_middle.symm⟩ - | Sublist.cons₂ a s => - let ⟨l, p⟩ := Sublist.exists_perm_append s - ⟨l, p.cons a⟩ - -theorem Perm.countP_eq (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) : - countP p l₁ = countP p l₂ := by - simp only [countP_eq_length_filter] - exact (s.filter _).length_eq - theorem Subperm.countP_le (p : α → Bool) {l₁ l₂ : List α} : l₁ <+~ l₂ → countP p l₁ ≤ countP p l₂ | ⟨_l, p', s⟩ => p'.countP_eq p ▸ s.countP_le p -theorem Perm.countP_congr {l₁ l₂ : List α} (s : l₁ ~ l₂) {p p' : α → Bool} - (hp : ∀ x ∈ l₁, p x = p' x) : l₁.countP p = l₂.countP p' := by - rw [← s.countP_eq p'] - clear s - induction l₁ with - | nil => rfl - | cons y s hs => - simp only [mem_cons, forall_eq_or_imp] at hp - simp only [countP_cons, hs hp.2, hp.1] - -theorem countP_eq_countP_filter_add (l : List α) (p q : α → Bool) : - l.countP p = (l.filter q).countP p + (l.filter fun a => !q a).countP p := - countP_append .. ▸ Perm.countP_eq _ (filter_append_perm _ _).symm - -theorem Perm.count_eq [DecidableEq α] {l₁ l₂ : List α} (p : l₁ ~ l₂) (a) : - count a l₁ = count a l₂ := p.countP_eq _ - theorem Subperm.count_le [DecidableEq α] {l₁ l₂ : List α} (s : l₁ <+~ l₂) (a) : count a l₁ ≤ count a l₂ := s.countP_le _ -theorem Perm.foldl_eq' {f : β → α → β} {l₁ l₂ : List α} (p : l₁ ~ l₂) - (comm : ∀ x ∈ l₁, ∀ y ∈ l₁, ∀ (z), f (f z x) y = f (f z y) x) - (init) : foldl f init l₁ = foldl f init l₂ := by - induction p using recOnSwap' generalizing init with - | nil => simp - | cons x _p IH => - simp only [foldl] - apply IH; intros; apply comm <;> exact .tail _ ‹_› - | swap' x y _p IH => - simp only [foldl] - rw [comm x (.tail _ <| .head _) y (.head _)] - apply IH; intros; apply comm <;> exact .tail _ (.tail _ ‹_›) - | trans p₁ _p₂ IH₁ IH₂ => - refine (IH₁ comm init).trans (IH₂ ?_ _) - intros; apply comm <;> apply p₁.symm.subset <;> assumption - -theorem Perm.rec_heq {β : List α → Sort _} {f : ∀ a l, β l → β (a :: l)} {b : β []} {l l' : List α} - (hl : l ~ l') (f_congr : ∀ {a l l' b b'}, l ~ l' → HEq b b' → HEq (f a l b) (f a l' b')) - (f_swap : ∀ {a a' l b}, HEq (f a (a' :: l) (f a' l b)) (f a' (a :: l) (f a l b))) : - HEq (@List.rec α β b f l) (@List.rec α β b f l') := by - induction hl with - | nil => rfl - | cons a h ih => exact f_congr h ih - | swap a a' l => exact f_swap - | trans _h₁ _h₂ ih₁ ih₂ => exact ih₁.trans ih₂ - -/-- Lemma used to destruct perms element by element. -/ -theorem perm_inv_core {a : α} {l₁ l₂ r₁ r₂ : List α} : - l₁ ++ a :: r₁ ~ l₂ ++ a :: r₂ → l₁ ++ r₁ ~ l₂ ++ r₂ := by - -- Necessary generalization for `induction` - suffices ∀ s₁ s₂ (_ : s₁ ~ s₂) {l₁ l₂ r₁ r₂}, - l₁ ++ a :: r₁ = s₁ → l₂ ++ a :: r₂ = s₂ → l₁ ++ r₁ ~ l₂ ++ r₂ from (this _ _ · rfl rfl) - intro s₁ s₂ p - induction p using Perm.recOnSwap' with intro l₁ l₂ r₁ r₂ e₁ e₂ - | nil => - simp at e₁ - | cons x p IH => - cases l₁ <;> cases l₂ <;> - dsimp at e₁ e₂ <;> injections <;> subst_vars - · exact p - · exact p.trans perm_middle - · exact perm_middle.symm.trans p - · exact (IH rfl rfl).cons _ - | swap' x y p IH => - obtain _ | ⟨y, _ | ⟨z, l₁⟩⟩ := l₁ - <;> obtain _ | ⟨u, _ | ⟨v, l₂⟩⟩ := l₂ - <;> dsimp at e₁ e₂ <;> injections <;> subst_vars - <;> try exact p.cons _ - · exact (p.trans perm_middle).cons u - · exact ((p.trans perm_middle).cons _).trans (swap _ _ _) - · exact (perm_middle.symm.trans p).cons y - · exact (swap _ _ _).trans ((perm_middle.symm.trans p).cons u) - · exact (IH rfl rfl).swap' _ _ - | trans p₁ p₂ IH₁ IH₂ => - subst e₁ e₂ - obtain ⟨l₂, r₂, rfl⟩ := append_of_mem (a := a) (p₁.subset (by simp)) - exact (IH₁ rfl rfl).trans (IH₂ rfl rfl) - -theorem Perm.cons_inv {a : α} {l₁ l₂ : List α} : a :: l₁ ~ a :: l₂ → l₁ ~ l₂ := - perm_inv_core (l₁ := []) (l₂ := []) - -@[simp] theorem perm_cons (a : α) {l₁ l₂ : List α} : a :: l₁ ~ a :: l₂ ↔ l₁ ~ l₂ := - ⟨.cons_inv, .cons a⟩ - -theorem perm_append_left_iff {l₁ l₂ : List α} : ∀ l, l ++ l₁ ~ l ++ l₂ ↔ l₁ ~ l₂ - | [] => .rfl - | a :: l => (perm_cons a).trans (perm_append_left_iff l) - -theorem perm_append_right_iff {l₁ l₂ : List α} (l) : l₁ ++ l ~ l₂ ++ l ↔ l₁ ~ l₂ := by - refine ⟨fun p => ?_, .append_right _⟩ - exact (perm_append_left_iff _).1 <| perm_append_comm.trans <| p.trans perm_append_comm - theorem subperm_cons (a : α) {l₁ l₂ : List α} : a :: l₁ <+~ a :: l₂ ↔ l₁ <+~ l₂ := by refine ⟨fun ⟨l, p, s⟩ => ?_, fun ⟨l, p, s⟩ => ⟨a :: l, p.cons a, s.cons₂ _⟩⟩ match s with @@ -449,14 +163,6 @@ section DecidableEq variable [DecidableEq α] -theorem Perm.erase (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.erase a ~ l₂.erase a := - if h₁ : a ∈ l₁ then - have h₂ : a ∈ l₂ := p.subset h₁ - .cons_inv <| (perm_cons_erase h₁).symm.trans <| p.trans (perm_cons_erase h₂) - else by - have h₂ : a ∉ l₂ := mt p.mem_iff.2 h₁ - rw [erase_of_not_mem h₁, erase_of_not_mem h₂]; exact p - theorem subperm_cons_erase (a : α) (l : List α) : l <+~ a :: l.erase a := if h : a ∈ l then (perm_cons_erase h).subperm @@ -522,28 +228,6 @@ theorem subperm_cons_diff {a : α} {l₁ l₂ : List α} : (a :: l₁).diff l₂ theorem subset_cons_diff {a : α} {l₁ l₂ : List α} : (a :: l₁).diff l₂ ⊆ a :: l₁.diff l₂ := subperm_cons_diff.subset -theorem cons_perm_iff_perm_erase {a : α} {l₁ l₂ : List α} : - a :: l₁ ~ l₂ ↔ a ∈ l₂ ∧ l₁ ~ l₂.erase a := by - refine ⟨fun h => ?_, fun ⟨m, h⟩ => (h.cons a).trans (perm_cons_erase m).symm⟩ - have : a ∈ l₂ := h.subset (mem_cons_self a l₁) - exact ⟨this, (h.trans <| perm_cons_erase this).cons_inv⟩ - -theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l₁ = count a l₂ := by - refine ⟨Perm.count_eq, fun H => ?_⟩ - induction l₁ generalizing l₂ with - | nil => - match l₂ with - | nil => rfl - | cons b l₂ => - specialize H b - simp at H - | cons a l₁ IH => - have : a ∈ l₂ := count_pos_iff_mem.mp (by rw [← H]; simp) - refine ((IH fun b => ?_).cons a).trans (perm_cons_erase this).symm - specialize H b - rw [(perm_cons_erase this).count_eq] at H - by_cases h : b = a <;> simpa [h] using H - /-- The list version of `add_tsub_cancel_of_le` for multisets. -/ theorem subperm_append_diff_self_of_count_le {l₁ l₂ : List α} (h : ∀ x ∈ l₁, count x l₁ ≤ count x l₂) : l₁ ++ l₂.diff l₁ ~ l₂ := by @@ -586,28 +270,6 @@ theorem Subperm.cons_left {l₁ l₂ : List α} (h : l₁ <+~ l₂) (x : α) (hx refine h y ?_ simpa [hy'] using hy -theorem isPerm_iff : ∀ {l₁ l₂ : List α}, l₁.isPerm l₂ ↔ l₁ ~ l₂ - | [], [] => by simp [isPerm, isEmpty] - | [], _ :: _ => by simp [isPerm, isEmpty, Perm.nil_eq] - | a :: l₁, l₂ => by simp [isPerm, isPerm_iff, cons_perm_iff_perm_erase] - -instance decidablePerm (l₁ l₂ : List α) : Decidable (l₁ ~ l₂) := decidable_of_iff _ isPerm_iff - -protected theorem Perm.insert (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : - l₁.insert a ~ l₂.insert a := by - if h : a ∈ l₁ then - simp [h, p.subset h, p] - else - have := p.cons a - simpa [h, mt p.mem_iff.2 h] using this - -theorem perm_insert_swap (x y : α) (l : List α) : - List.insert x (List.insert y l) ~ List.insert y (List.insert x l) := by - by_cases xl : x ∈ l <;> by_cases yl : y ∈ l <;> simp [xl, yl] - if xy : x = y then simp [xy] else - simp [List.insert, xl, yl, xy, Ne.symm xy] - constructor - theorem perm_insertNth {α} (x : α) (l : List α) {n} (h : n ≤ l.length) : insertNth n x l ~ x :: l := by induction l generalizing n with @@ -647,59 +309,11 @@ theorem Perm.inter {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : end DecidableEq -theorem Perm.pairwise_iff {R : α → α → Prop} (S : ∀ {x y}, R x y → R y x) : - ∀ {l₁ l₂ : List α} (_p : l₁ ~ l₂), Pairwise R l₁ ↔ Pairwise R l₂ := - suffices ∀ {l₁ l₂}, l₁ ~ l₂ → Pairwise R l₁ → Pairwise R l₂ - from fun p => ⟨this p, this p.symm⟩ - fun {l₁ l₂} p d => by - induction d generalizing l₂ with - | nil => rw [← p.nil_eq]; constructor - | cons h _ IH => - have : _ ∈ l₂ := p.subset (mem_cons_self _ _) - obtain ⟨s₂, t₂, rfl⟩ := append_of_mem this - have p' := (p.trans perm_middle).cons_inv - refine (pairwise_middle S).2 (pairwise_cons.2 ⟨fun b m => ?_, IH p'⟩) - exact h _ (p'.symm.subset m) - -theorem Pairwise.perm {R : α → α → Prop} {l l' : List α} (hR : l.Pairwise R) (hl : l ~ l') - (hsymm : ∀ {x y}, R x y → R y x) : l'.Pairwise R := (hl.pairwise_iff hsymm).mp hR - -theorem Perm.pairwise {R : α → α → Prop} {l l' : List α} (hl : l ~ l') (hR : l.Pairwise R) - (hsymm : ∀ {x y}, R x y → R y x) : l'.Pairwise R := hR.perm hl hsymm - -theorem Perm.nodup_iff {l₁ l₂ : List α} : l₁ ~ l₂ → (Nodup l₁ ↔ Nodup l₂) := - Perm.pairwise_iff <| @Ne.symm α - -theorem Perm.join {l₁ l₂ : List (List α)} (h : l₁ ~ l₂) : l₁.join ~ l₂.join := by - induction h with - | nil => rfl - | cons _ _ ih => simp only [join_cons, perm_append_left_iff, ih] - | swap => simp only [join_cons, ← append_assoc, perm_append_right_iff]; exact perm_append_comm .. - | trans _ _ ih₁ ih₂ => exact trans ih₁ ih₂ - -theorem Perm.bind_right {l₁ l₂ : List α} (f : α → List β) (p : l₁ ~ l₂) : l₁.bind f ~ l₂.bind f := - (p.map _).join - theorem Perm.join_congr : ∀ {l₁ l₂ : List (List α)} (_ : List.Forall₂ (· ~ ·) l₁ l₂), l₁.join ~ l₂.join | _, _, .nil => .rfl | _ :: _, _ :: _, .cons h₁ h₂ => h₁.append (Perm.join_congr h₂) -theorem Perm.eraseP (f : α → Bool) {l₁ l₂ : List α} - (H : Pairwise (fun a b => f a → f b → False) l₁) (p : l₁ ~ l₂) : eraseP f l₁ ~ eraseP f l₂ := by - induction p with - | nil => simp - | cons a p IH => - if h : f a then simp [h, p] - else simp [h]; exact IH (pairwise_cons.1 H).2 - | swap a b l => - by_cases h₁ : f a <;> by_cases h₂ : f b <;> simp [h₁, h₂] - · cases (pairwise_cons.1 H).1 _ (mem_cons.2 (Or.inl rfl)) h₂ h₁ - · apply swap - | trans p₁ _ IH₁ IH₂ => - refine (IH₁ H).trans (IH₂ ((p₁.pairwise_iff ?_).1 H)) - exact fun h h₁ h₂ => h h₂ h₁ - theorem perm_insertP (p : α → Bool) (a l) : insertP p a l ~ a :: l := by induction l with simp [insertP, insertP.loop, cond] | cons _ _ ih => From 7ca87f8a71a380218536910f9440a61ab0e230b9 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Mon, 19 Aug 2024 09:05:26 +0000 Subject: [PATCH 208/208] chore: bump to nightly-2024-08-19 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index ea81516874..407a840f65 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-08-17 +leanprover/lean4:nightly-2024-08-19