mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-19 11:24:07 +00:00
Compare commits
56 Commits
Array.toLi
...
HashSet.of
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2513be6a09 | ||
|
|
c25d206647 | ||
|
|
078e9b6d77 | ||
|
|
a745e33123 | ||
|
|
7740a38a71 | ||
|
|
9568f305d8 | ||
|
|
b1179d5cc3 | ||
|
|
e6145a6937 | ||
|
|
d47ae99721 | ||
|
|
0aac83fe40 | ||
|
|
8c6ac845b1 | ||
|
|
b714a96034 | ||
|
|
4e0f6b8b45 | ||
|
|
979c5a4d6a | ||
|
|
2079bdcbca | ||
|
|
1a2217d47e | ||
|
|
3ef67c468a | ||
|
|
4c439c73a7 | ||
|
|
5eea8355ba | ||
|
|
60bb451d45 | ||
|
|
f989520d2b | ||
|
|
626dda9358 | ||
|
|
5f789e63fa | ||
|
|
438061a924 | ||
|
|
ec98c92ba6 | ||
|
|
2080fc0221 | ||
|
|
b34379554d | ||
|
|
273b7540b2 | ||
|
|
b875627198 | ||
|
|
adfd6c090e | ||
|
|
da0d309d65 | ||
|
|
87fdd7809f | ||
|
|
8fd6e46a9c | ||
|
|
0602b805c8 | ||
|
|
0b7debe376 | ||
|
|
f5146c6edb | ||
|
|
461283ecf4 | ||
|
|
27bf7367ca | ||
|
|
d4cc934149 | ||
|
|
b88cdf6a3e | ||
|
|
325a058893 | ||
|
|
f869018447 | ||
|
|
c1da100997 | ||
|
|
6c97c4ce37 | ||
|
|
c209d0d745 | ||
|
|
5bc199ea1c | ||
|
|
cb4a73a487 | ||
|
|
92e1f168b2 | ||
|
|
a58520da16 | ||
|
|
8f899bf5bd | ||
|
|
7a5a08960a | ||
|
|
5a9cfa0aec | ||
|
|
c79b09fdbd | ||
|
|
0b9a4bd65e | ||
|
|
e41e305479 | ||
|
|
b1a03a471f |
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -5,6 +5,7 @@
|
||||
* Include the link to your `RFC` or `bug` issue in the description.
|
||||
* If the issue does not already have approval from a developer, submit the PR as draft.
|
||||
* The PR title/description will become the commit message. Keep it up-to-date as the PR evolves.
|
||||
* A toolchain of the form `leanprover/lean4-pr-releases:pr-release-NNNN` for Linux and M-series Macs will be generated upon build. To generate binaries for Windows and Intel-based Macs as well, write a comment containing `release-ci` on its own line.
|
||||
* If you rebase your PR onto `nightly-with-mathlib` then CI will test Mathlib against your PR.
|
||||
* You can manage the `awaiting-review`, `awaiting-author`, and `WIP` labels yourself, by writing a comment containing one of these labels on its own line.
|
||||
* Remove this section, up to and including the `---` before submitting.
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -114,7 +114,7 @@ jobs:
|
||||
elif [[ "${{ github.event_name }}" != "pull_request" ]]; then
|
||||
check_level=1
|
||||
else
|
||||
labels="$(gh api repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/pulls/${{ github.event.pull_request.number }}) --jq '.labels'"
|
||||
labels="$(gh api repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/pulls/${{ github.event.pull_request.number }} --jq '.labels')"
|
||||
if echo "$labels" | grep -q "release-ci"; then
|
||||
check_level=2
|
||||
elif echo "$labels" | grep -q "merge-ci"; then
|
||||
|
||||
14
.github/workflows/labels-from-comments.yml
vendored
14
.github/workflows/labels-from-comments.yml
vendored
@@ -1,6 +1,7 @@
|
||||
# This workflow allows any user to add one of the `awaiting-review`, `awaiting-author`, or `WIP` labels,
|
||||
# by commenting on the PR or issue.
|
||||
# Other labels from this set are removed automatically at the same time.
|
||||
# This workflow allows any user to add one of the `awaiting-review`, `awaiting-author`, `WIP`,
|
||||
# or `release-ci` labels by commenting on the PR or issue.
|
||||
# If any labels from the set {`awaiting-review`, `awaiting-author`, `WIP`} are added, other labels
|
||||
# from that set are removed automatically at the same time.
|
||||
|
||||
name: Label PR based on Comment
|
||||
|
||||
@@ -10,7 +11,7 @@ on:
|
||||
|
||||
jobs:
|
||||
update-label:
|
||||
if: github.event.issue.pull_request != null && (contains(github.event.comment.body, 'awaiting-review') || contains(github.event.comment.body, 'awaiting-author') || contains(github.event.comment.body, 'WIP'))
|
||||
if: github.event.issue.pull_request != null && (contains(github.event.comment.body, 'awaiting-review') || contains(github.event.comment.body, 'awaiting-author') || contains(github.event.comment.body, 'WIP') || contains(github.event.comment.body, 'release-ci'))
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -25,6 +26,7 @@ jobs:
|
||||
const awaitingReview = commentLines.includes('awaiting-review');
|
||||
const awaitingAuthor = commentLines.includes('awaiting-author');
|
||||
const wip = commentLines.includes('WIP');
|
||||
const releaseCI = commentLines.includes('release-ci');
|
||||
|
||||
if (awaitingReview || awaitingAuthor || wip) {
|
||||
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: 'awaiting-review' }).catch(() => {});
|
||||
@@ -41,3 +43,7 @@ jobs:
|
||||
if (wip) {
|
||||
await github.rest.issues.addLabels({ owner, repo, issue_number, labels: ['WIP'] });
|
||||
}
|
||||
|
||||
if (releaseCI) {
|
||||
await github.rest.issues.addLabels({ owner, repo, issue_number, labels: ['release-ci'] });
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ Important instances include
|
||||
* `Option`, where `failure := none` and `<|>` returns the left-most `some`.
|
||||
* Parser combinators typically provide an `Applicative` instance for error-handling and
|
||||
backtracking.
|
||||
|
||||
|
||||
Error recovery and state can interact subtly. For example, the implementation of `Alternative` for `OptionT (StateT σ Id)` keeps modifications made to the state while recovering from failure, while `StateT σ (OptionT Id)` discards them.
|
||||
-/
|
||||
-- NB: List instance is in mathlib. Once upstreamed, add
|
||||
|
||||
@@ -817,14 +817,12 @@ variable {a b c d : Prop}
|
||||
theorem iff_iff_implies_and_implies {a b : Prop} : (a ↔ b) ↔ (a → b) ∧ (b → a) :=
|
||||
Iff.intro (fun h => And.intro h.mp h.mpr) (fun h => Iff.intro h.left h.right)
|
||||
|
||||
theorem Iff.refl (a : Prop) : a ↔ a :=
|
||||
@[refl] theorem Iff.refl (a : Prop) : a ↔ a :=
|
||||
Iff.intro (fun h => h) (fun h => h)
|
||||
|
||||
protected theorem Iff.rfl {a : Prop} : a ↔ a :=
|
||||
Iff.refl a
|
||||
|
||||
macro_rules | `(tactic| rfl) => `(tactic| exact Iff.rfl)
|
||||
|
||||
theorem Iff.of_eq (h : a = b) : a ↔ b := h ▸ Iff.rfl
|
||||
|
||||
theorem Iff.trans (h₁ : a ↔ b) (h₂ : b ↔ c) : a ↔ c :=
|
||||
|
||||
@@ -39,3 +39,5 @@ import Init.Data.BEq
|
||||
import Init.Data.Subtype
|
||||
import Init.Data.ULift
|
||||
import Init.Data.PLift
|
||||
import Init.Data.Zero
|
||||
import Init.Data.NeZero
|
||||
|
||||
@@ -20,7 +20,7 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
|
||||
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)⟩
|
||||
⟨xs.toList.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}`. -/
|
||||
|
||||
@@ -16,10 +16,11 @@ universe u v w
|
||||
namespace Array
|
||||
variable {α : Type u}
|
||||
|
||||
@[deprecated Array.toList (since := "2024-09-10")] abbrev Array.data := @Array.toList
|
||||
|
||||
@[extern "lean_mk_array"]
|
||||
def mkArray {α : Type u} (n : Nat) (v : α) : Array α := {
|
||||
data := List.replicate n v
|
||||
}
|
||||
def mkArray {α : Type u} (n : Nat) (v : α) : Array α where
|
||||
toList := List.replicate n v
|
||||
|
||||
/--
|
||||
`ofFn f` with `f : Fin n → α` returns the list whose ith element is `f i`.
|
||||
@@ -134,9 +135,8 @@ def swapAt! (a : Array α) (i : Nat) (v : α) : α × Array α :=
|
||||
panic! ("index " ++ toString i ++ " out of bounds")
|
||||
|
||||
@[extern "lean_array_pop"]
|
||||
def pop (a : Array α) : Array α := {
|
||||
data := a.data.dropLast
|
||||
}
|
||||
def pop (a : Array α) : Array α where
|
||||
toList := a.toList.dropLast
|
||||
|
||||
def shrink (a : Array α) (n : Nat) : Array α :=
|
||||
let rec loop
|
||||
@@ -499,10 +499,10 @@ def elem [BEq α] (a : α) (as : Array α) : Bool :=
|
||||
(true, r)
|
||||
|
||||
/-- Convert a `Array α` into an `List α`. This is O(n) in the size of the array. -/
|
||||
-- This function is exported to C, where it is called by `Array.data`
|
||||
-- This function is exported to C, where it is called by `Array.toList`
|
||||
-- (the projection) to implement this functionality.
|
||||
@[export lean_array_to_list]
|
||||
def toList (as : Array α) : List α :=
|
||||
@[export lean_array_to_list_impl]
|
||||
def toListImpl (as : Array α) : List α :=
|
||||
as.foldr List.cons []
|
||||
|
||||
/-- Prepends an `Array α` onto the front of a list. Equivalent to `as.toList ++ l`. -/
|
||||
@@ -793,30 +793,32 @@ def toListLitAux (a : Array α) (n : Nat) (hsz : a.size = n) : ∀ (i : Nat), i
|
||||
def toArrayLit (a : Array α) (n : Nat) (hsz : a.size = n) : Array α :=
|
||||
List.toArray <| toListLitAux a n hsz n (hsz ▸ Nat.le_refl _) []
|
||||
|
||||
theorem ext' {as bs : Array α} (h : as.data = bs.data) : as = bs := by
|
||||
theorem ext' {as bs : Array α} (h : as.toList = bs.toList) : as = bs := by
|
||||
cases as; cases bs; simp at h; rw [h]
|
||||
|
||||
@[simp] theorem toArrayAux_eq (as : List α) (acc : Array α) : (as.toArrayAux acc).data = acc.data ++ as := by
|
||||
@[simp] theorem toArrayAux_eq (as : List α) (acc : Array α) : (as.toArrayAux acc).toList = acc.toList ++ as := by
|
||||
induction as generalizing acc <;> simp [*, List.toArrayAux, Array.push, List.append_assoc, List.concat_eq_append]
|
||||
|
||||
@[simp] theorem data_toArray (as : List α) : as.toArray.data = as := by
|
||||
@[simp] theorem toList_toArray (as : List α) : as.toArray.toList = as := by
|
||||
simp [List.toArray, Array.mkEmpty]
|
||||
|
||||
@[deprecated toList_toArray (since := "2024-09-09")] abbrev data_toArray := @toList_toArray
|
||||
|
||||
@[simp] theorem size_toArray (as : List α) : as.toArray.size = as.length := by simp [size]
|
||||
|
||||
theorem toArrayLit_eq (as : Array α) (n : Nat) (hsz : as.size = n) : as = toArrayLit as n hsz := by
|
||||
apply ext'
|
||||
simp [toArrayLit, data_toArray]
|
||||
simp [toArrayLit, toList_toArray]
|
||||
have hle : n ≤ as.size := hsz ▸ Nat.le_refl _
|
||||
have hge : as.size ≤ n := hsz ▸ Nat.le_refl _
|
||||
have := go n hle
|
||||
rw [List.drop_eq_nil_of_le hge] at this
|
||||
rw [this]
|
||||
where
|
||||
getLit_eq (as : Array α) (i : Nat) (h₁ : as.size = n) (h₂ : i < n) : as.getLit i h₁ h₂ = getElem as.data i ((id (α := as.data.length = n) h₁) ▸ h₂) :=
|
||||
getLit_eq (as : Array α) (i : Nat) (h₁ : as.size = n) (h₂ : i < n) : as.getLit i h₁ h₂ = getElem as.toList i ((id (α := as.toList.length = n) h₁) ▸ h₂) :=
|
||||
rfl
|
||||
|
||||
go (i : Nat) (hi : i ≤ as.size) : toListLitAux as n hsz i hi (as.data.drop i) = as.data := by
|
||||
go (i : Nat) (hi : i ≤ as.size) : toListLitAux as n hsz i hi (as.toList.drop i) = as.toList := by
|
||||
induction i <;> simp [getLit_eq, List.get_drop_eq_drop, toListLitAux, List.drop, *]
|
||||
|
||||
def isPrefixOfAux [BEq α] (as bs : Array α) (hle : as.size ≤ bs.size) (i : Nat) : Bool :=
|
||||
|
||||
@@ -15,76 +15,106 @@ This file contains some theorems about `Array` and `List` needed for `Init.Data.
|
||||
|
||||
namespace Array
|
||||
|
||||
theorem foldlM_eq_foldlM_data.aux [Monad m]
|
||||
theorem foldlM_eq_foldlM_toList.aux [Monad m]
|
||||
(f : β → α → m β) (arr : Array α) (i j) (H : arr.size ≤ i + j) (b) :
|
||||
foldlM.loop f arr arr.size (Nat.le_refl _) i j b = (arr.data.drop j).foldlM f b := by
|
||||
foldlM.loop f arr arr.size (Nat.le_refl _) i j b = (arr.toList.drop j).foldlM f b := by
|
||||
unfold foldlM.loop
|
||||
split; split
|
||||
· cases Nat.not_le_of_gt ‹_› (Nat.zero_add _ ▸ H)
|
||||
· rename_i i; rw [Nat.succ_add] at H
|
||||
simp [foldlM_eq_foldlM_data.aux f arr i (j+1) H]
|
||||
simp [foldlM_eq_foldlM_toList.aux f arr i (j+1) H]
|
||||
rw (config := {occs := .pos [2]}) [← List.get_drop_eq_drop _ _ ‹_›]
|
||||
rfl
|
||||
· rw [List.drop_of_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
||||
|
||||
theorem foldlM_eq_foldlM_data [Monad m]
|
||||
theorem foldlM_eq_foldlM_toList [Monad m]
|
||||
(f : β → α → m β) (init : β) (arr : Array α) :
|
||||
arr.foldlM f init = arr.data.foldlM f init := by
|
||||
simp [foldlM, foldlM_eq_foldlM_data.aux]
|
||||
arr.foldlM f init = arr.toList.foldlM f init := by
|
||||
simp [foldlM, foldlM_eq_foldlM_toList.aux]
|
||||
|
||||
theorem foldl_eq_foldl_data (f : β → α → β) (init : β) (arr : Array α) :
|
||||
arr.foldl f init = arr.data.foldl f init :=
|
||||
List.foldl_eq_foldlM .. ▸ foldlM_eq_foldlM_data ..
|
||||
theorem foldl_eq_foldl_toList (f : β → α → β) (init : β) (arr : Array α) :
|
||||
arr.foldl f init = arr.toList.foldl f init :=
|
||||
List.foldl_eq_foldlM .. ▸ foldlM_eq_foldlM_toList ..
|
||||
|
||||
theorem foldrM_eq_reverse_foldlM_data.aux [Monad m]
|
||||
theorem foldrM_eq_reverse_foldlM_toList.aux [Monad m]
|
||||
(f : α → β → m β) (arr : Array α) (init : β) (i h) :
|
||||
(arr.data.take i).reverse.foldlM (fun x y => f y x) init = foldrM.fold f arr 0 i h init := by
|
||||
(arr.toList.take i).reverse.foldlM (fun x y => f y x) init = foldrM.fold f arr 0 i h init := by
|
||||
unfold foldrM.fold
|
||||
match i with
|
||||
| 0 => simp [List.foldlM, List.take]
|
||||
| i+1 => rw [← List.take_concat_get _ _ h]; simp [← (aux f arr · i)]; rfl
|
||||
|
||||
theorem foldrM_eq_reverse_foldlM_data [Monad m] (f : α → β → m β) (init : β) (arr : Array α) :
|
||||
arr.foldrM f init = arr.data.reverse.foldlM (fun x y => f y x) init := by
|
||||
theorem foldrM_eq_reverse_foldlM_toList [Monad m] (f : α → β → m β) (init : β) (arr : Array α) :
|
||||
arr.foldrM f init = arr.toList.reverse.foldlM (fun x y => f y x) init := by
|
||||
have : arr = #[] ∨ 0 < arr.size :=
|
||||
match arr with | ⟨[]⟩ => .inl rfl | ⟨a::l⟩ => .inr (Nat.zero_lt_succ _)
|
||||
match arr, this with | _, .inl rfl => rfl | arr, .inr h => ?_
|
||||
simp [foldrM, h, ← foldrM_eq_reverse_foldlM_data.aux, List.take_length]
|
||||
simp [foldrM, h, ← foldrM_eq_reverse_foldlM_toList.aux, List.take_length]
|
||||
|
||||
theorem foldrM_eq_foldrM_data [Monad m]
|
||||
theorem foldrM_eq_foldrM_toList [Monad m]
|
||||
(f : α → β → m β) (init : β) (arr : Array α) :
|
||||
arr.foldrM f init = arr.data.foldrM f init := by
|
||||
rw [foldrM_eq_reverse_foldlM_data, List.foldlM_reverse]
|
||||
arr.foldrM f init = arr.toList.foldrM f init := by
|
||||
rw [foldrM_eq_reverse_foldlM_toList, List.foldlM_reverse]
|
||||
|
||||
theorem foldr_eq_foldr_data (f : α → β → β) (init : β) (arr : Array α) :
|
||||
arr.foldr f init = arr.data.foldr f init :=
|
||||
List.foldr_eq_foldrM .. ▸ foldrM_eq_foldrM_data ..
|
||||
theorem foldr_eq_foldr_toList (f : α → β → β) (init : β) (arr : Array α) :
|
||||
arr.foldr f init = arr.toList.foldr f init :=
|
||||
List.foldr_eq_foldrM .. ▸ foldrM_eq_foldrM_toList ..
|
||||
|
||||
@[simp] theorem push_data (arr : Array α) (a : α) : (arr.push a).data = arr.data ++ [a] := by
|
||||
@[simp] theorem push_toList (arr : Array α) (a : α) : (arr.push a).toList = arr.toList ++ [a] := by
|
||||
simp [push, List.concat_eq_append]
|
||||
|
||||
@[simp] theorem toListAppend_eq (arr : Array α) (l) : arr.toListAppend l = arr.data ++ l := by
|
||||
simp [toListAppend, foldr_eq_foldr_data]
|
||||
@[simp] theorem toListAppend_eq (arr : Array α) (l) : arr.toListAppend l = arr.toList ++ l := by
|
||||
simp [toListAppend, foldr_eq_foldr_toList]
|
||||
|
||||
@[simp] theorem toList_eq (arr : Array α) : arr.toList = arr.data := by
|
||||
simp [toList, foldr_eq_foldr_data]
|
||||
@[simp] theorem toListImpl_eq (arr : Array α) : arr.toListImpl = arr.toList := by
|
||||
simp [toListImpl, foldr_eq_foldr_toList]
|
||||
|
||||
@[simp] theorem pop_data (arr : Array α) : arr.pop.data = arr.data.dropLast := rfl
|
||||
@[simp] theorem pop_toList (arr : Array α) : arr.pop.toList = arr.toList.dropLast := rfl
|
||||
|
||||
@[simp] theorem append_eq_append (arr arr' : Array α) : arr.append arr' = arr ++ arr' := rfl
|
||||
|
||||
@[simp] theorem append_data (arr arr' : Array α) :
|
||||
(arr ++ arr').data = arr.data ++ arr'.data := by
|
||||
@[simp] theorem append_toList (arr arr' : Array α) :
|
||||
(arr ++ arr').toList = arr.toList ++ arr'.toList := by
|
||||
rw [← append_eq_append]; unfold Array.append
|
||||
rw [foldl_eq_foldl_data]
|
||||
induction arr'.data generalizing arr <;> simp [*]
|
||||
rw [foldl_eq_foldl_toList]
|
||||
induction arr'.toList generalizing arr <;> simp [*]
|
||||
|
||||
@[simp] theorem appendList_eq_append
|
||||
(arr : Array α) (l : List α) : arr.appendList l = arr ++ l := rfl
|
||||
|
||||
@[simp] theorem appendList_data (arr : Array α) (l : List α) :
|
||||
(arr ++ l).data = arr.data ++ l := by
|
||||
@[simp] theorem appendList_toList (arr : Array α) (l : List α) :
|
||||
(arr ++ l).toList = arr.toList ++ l := by
|
||||
rw [← appendList_eq_append]; unfold Array.appendList
|
||||
induction l generalizing arr <;> simp [*]
|
||||
|
||||
@[deprecated foldlM_eq_foldlM_toList (since := "2024-09-09")]
|
||||
abbrev foldlM_eq_foldlM_data := @foldlM_eq_foldlM_toList
|
||||
|
||||
@[deprecated foldl_eq_foldl_toList (since := "2024-09-09")]
|
||||
abbrev foldl_eq_foldl_data := @foldl_eq_foldl_toList
|
||||
|
||||
@[deprecated foldrM_eq_reverse_foldlM_toList (since := "2024-09-09")]
|
||||
abbrev foldrM_eq_reverse_foldlM_data := @foldrM_eq_reverse_foldlM_toList
|
||||
|
||||
@[deprecated foldrM_eq_foldrM_toList (since := "2024-09-09")]
|
||||
abbrev foldrM_eq_foldrM_data := @foldrM_eq_foldrM_toList
|
||||
|
||||
@[deprecated foldr_eq_foldr_toList (since := "2024-09-09")]
|
||||
abbrev foldr_eq_foldr_data := @foldr_eq_foldr_toList
|
||||
|
||||
@[deprecated push_toList (since := "2024-09-09")]
|
||||
abbrev push_data := @push_toList
|
||||
|
||||
@[deprecated toListImpl_eq (since := "2024-09-09")]
|
||||
abbrev toList_eq := @toListImpl_eq
|
||||
|
||||
@[deprecated pop_toList (since := "2024-09-09")]
|
||||
abbrev pop_data := @pop_toList
|
||||
|
||||
@[deprecated append_toList (since := "2024-09-09")]
|
||||
abbrev append_data := @append_toList
|
||||
|
||||
@[deprecated appendList_toList (since := "2024-09-09")]
|
||||
abbrev appendList_data := @appendList_toList
|
||||
|
||||
end Array
|
||||
|
||||
@@ -23,25 +23,34 @@ attribute [simp] data_toArray uset
|
||||
|
||||
@[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 toArray_toList : (a : Array α) → a.toList.toArray = a
|
||||
| ⟨l⟩ => ext' (toList_toArray l)
|
||||
|
||||
@[simp] theorem data_length {l : Array α} : l.data.length = l.size := rfl
|
||||
@[deprecated toArray_toList (since := "2024-09-09")]
|
||||
abbrev toArray_data := @toArray_toList
|
||||
|
||||
@[simp] theorem toList_length {l : Array α} : l.toList.length = l.size := rfl
|
||||
|
||||
@[deprecated toList_length (since := "2024-09-09")]
|
||||
abbrev data_length := @toList_length
|
||||
|
||||
@[simp] theorem mkEmpty_eq (α n) : @mkEmpty α n = #[] := rfl
|
||||
|
||||
@[simp] theorem size_mk (as : List α) : (Array.mk as).size = as.length := by simp [size]
|
||||
|
||||
theorem getElem_eq_data_getElem (a : Array α) (h : i < a.size) : a[i] = a.data[i] := by
|
||||
theorem getElem_eq_toList_getElem (a : Array α) (h : i < a.size) : a[i] = a.toList[i] := by
|
||||
by_cases i < a.size <;> (try simp [*]) <;> rfl
|
||||
|
||||
@[deprecated getElem_eq_data_getElem (since := "2024-06-12")]
|
||||
theorem getElem_eq_data_get (a : Array α) (h : i < a.size) : a[i] = a.data.get ⟨i, h⟩ := by
|
||||
simp [getElem_eq_data_getElem]
|
||||
@[deprecated getElem_eq_toList_getElem (since := "2024-09-09")]
|
||||
abbrev getElem_eq_data_getElem := @getElem_eq_toList_getElem
|
||||
|
||||
@[deprecated getElem_eq_toList_getElem (since := "2024-06-12")]
|
||||
theorem getElem_eq_toList_get (a : Array α) (h : i < a.size) : a[i] = a.toList.get ⟨i, h⟩ := by
|
||||
simp [getElem_eq_toList_getElem]
|
||||
|
||||
theorem foldrM_push [Monad m] (f : α → β → m β) (init : β) (arr : Array α) (a : α) :
|
||||
(arr.push a).foldrM f init = f a init >>= arr.foldrM f := by
|
||||
simp [foldrM_eq_reverse_foldlM_data, -size_push]
|
||||
simp [foldrM_eq_reverse_foldlM_toList, -size_push]
|
||||
|
||||
@[simp] theorem foldrM_push' [Monad m] (f : α → β → m β) (init : β) (arr : Array α) (a : α) :
|
||||
(arr.push a).foldrM f init (start := arr.size + 1) = f a init >>= arr.foldrM f := by
|
||||
@@ -56,17 +65,17 @@ theorem foldr_push (f : α → β → β) (init : β) (arr : Array α) (a : α)
|
||||
/-- A more efficient version of `arr.toList.reverse`. -/
|
||||
@[inline] def toListRev (arr : Array α) : List α := arr.foldl (fun l t => t :: l) []
|
||||
|
||||
@[simp] theorem toListRev_eq (arr : Array α) : arr.toListRev = arr.data.reverse := by
|
||||
rw [toListRev, foldl_eq_foldl_data, ← List.foldr_reverse, List.foldr_cons_nil]
|
||||
@[simp] theorem toListRev_eq (arr : Array α) : arr.toListRev = arr.toList.reverse := by
|
||||
rw [toListRev, foldl_eq_foldl_toList, ← List.foldr_reverse, List.foldr_cons_nil]
|
||||
|
||||
theorem get_push_lt (a : Array α) (x : α) (i : Nat) (h : i < a.size) :
|
||||
have : i < (a.push x).size := by simp [*, Nat.lt_succ_of_le, Nat.le_of_lt]
|
||||
(a.push x)[i] = a[i] := by
|
||||
simp only [push, getElem_eq_data_getElem, List.concat_eq_append, List.getElem_append_left, h]
|
||||
simp only [push, getElem_eq_toList_getElem, List.concat_eq_append, List.getElem_append_left, h]
|
||||
|
||||
@[simp] theorem get_push_eq (a : Array α) (x : α) : (a.push x)[a.size] = x := by
|
||||
simp only [push, getElem_eq_data_getElem, List.concat_eq_append]
|
||||
rw [List.getElem_append_right] <;> simp [getElem_eq_data_getElem, Nat.zero_lt_one]
|
||||
simp only [push, getElem_eq_toList_getElem, List.concat_eq_append]
|
||||
rw [List.getElem_append_right] <;> simp [getElem_eq_toList_getElem, Nat.zero_lt_one]
|
||||
|
||||
theorem get_push (a : Array α) (x : α) (i : Nat) (h : i < (a.push x).size) :
|
||||
(a.push x)[i] = if h : i < a.size then a[i] else x := by
|
||||
@@ -77,27 +86,31 @@ theorem get_push (a : Array α) (x : α) (i : Nat) (h : i < (a.push x).size) :
|
||||
|
||||
theorem mapM_eq_foldlM [Monad m] [LawfulMonad m] (f : α → m β) (arr : Array α) :
|
||||
arr.mapM f = arr.foldlM (fun bs a => bs.push <$> f a) #[] := by
|
||||
rw [mapM, aux, foldlM_eq_foldlM_data]; rfl
|
||||
rw [mapM, aux, foldlM_eq_foldlM_toList]; rfl
|
||||
where
|
||||
aux (i r) :
|
||||
mapM.map f arr i r = (arr.data.drop i).foldlM (fun bs a => bs.push <$> f a) r := by
|
||||
mapM.map f arr i r = (arr.toList.drop i).foldlM (fun bs a => bs.push <$> f a) r := by
|
||||
unfold mapM.map; split
|
||||
· rw [← List.get_drop_eq_drop _ i ‹_›]
|
||||
simp only [aux (i + 1), map_eq_pure_bind, data_length, List.foldlM_cons, bind_assoc, pure_bind]
|
||||
simp only [aux (i + 1), map_eq_pure_bind, toList_length, List.foldlM_cons, bind_assoc,
|
||||
pure_bind]
|
||||
rfl
|
||||
· rw [List.drop_of_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
||||
termination_by arr.size - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
|
||||
@[simp] theorem map_data (f : α → β) (arr : Array α) : (arr.map f).data = arr.data.map f := by
|
||||
@[simp] theorem map_toList (f : α → β) (arr : Array α) : (arr.map f).toList = arr.toList.map f := by
|
||||
rw [map, mapM_eq_foldlM]
|
||||
apply congrArg data (foldl_eq_foldl_data (fun bs a => push bs (f a)) #[] arr) |>.trans
|
||||
have H (l arr) : List.foldl (fun bs a => push bs (f a)) arr l = ⟨arr.data ++ l.map f⟩ := by
|
||||
apply congrArg toList (foldl_eq_foldl_toList (fun bs a => push bs (f a)) #[] arr) |>.trans
|
||||
have H (l arr) : List.foldl (fun bs a => push bs (f a)) arr l = ⟨arr.toList ++ l.map f⟩ := by
|
||||
induction l generalizing arr <;> simp [*]
|
||||
simp [H]
|
||||
|
||||
@[deprecated map_toList (since := "2024-09-09")]
|
||||
abbrev map_data := @map_toList
|
||||
|
||||
@[simp] theorem size_map (f : α → β) (arr : Array α) : (arr.map f).size = arr.size := by
|
||||
simp only [← data_length]
|
||||
simp only [← toList_length]
|
||||
simp
|
||||
|
||||
@[simp] theorem appendList_nil (arr : Array α) : arr ++ ([] : List α) = arr := Array.ext' (by simp)
|
||||
@@ -105,16 +118,22 @@ where
|
||||
@[simp] theorem appendList_cons (arr : Array α) (a : α) (l : List α) :
|
||||
arr ++ (a :: l) = arr.push a ++ l := Array.ext' (by simp)
|
||||
|
||||
theorem foldl_data_eq_bind (l : List α) (acc : Array β)
|
||||
theorem foldl_toList_eq_bind (l : List α) (acc : Array β)
|
||||
(F : Array β → α → Array β) (G : α → List β)
|
||||
(H : ∀ acc a, (F acc a).data = acc.data ++ G a) :
|
||||
(l.foldl F acc).data = acc.data ++ l.bind G := by
|
||||
(H : ∀ acc a, (F acc a).toList = acc.toList ++ G a) :
|
||||
(l.foldl F acc).toList = acc.toList ++ l.bind G := by
|
||||
induction l generalizing acc <;> simp [*, List.bind]
|
||||
|
||||
theorem foldl_data_eq_map (l : List α) (acc : Array β) (G : α → β) :
|
||||
(l.foldl (fun acc a => acc.push (G a)) acc).data = acc.data ++ l.map G := by
|
||||
@[deprecated foldl_toList_eq_bind (since := "2024-09-09")]
|
||||
abbrev foldl_data_eq_bind := @foldl_toList_eq_bind
|
||||
|
||||
theorem foldl_toList_eq_map (l : List α) (acc : Array β) (G : α → β) :
|
||||
(l.foldl (fun acc a => acc.push (G a)) acc).toList = acc.toList ++ l.map G := by
|
||||
induction l generalizing acc <;> simp [*]
|
||||
|
||||
@[deprecated foldl_toList_eq_map (since := "2024-09-09")]
|
||||
abbrev foldl_data_eq_map := @foldl_toList_eq_map
|
||||
|
||||
theorem size_uset (a : Array α) (v i h) : (uset a i v h).size = a.size := by simp
|
||||
|
||||
theorem anyM_eq_anyM_loop [Monad m] (p : α → m Bool) (as : Array α) (start stop) :
|
||||
@@ -125,9 +144,12 @@ theorem anyM_stop_le_start [Monad m] (p : α → m Bool) (as : Array α) (start
|
||||
(h : min stop as.size ≤ start) : anyM p as start stop = pure false := by
|
||||
rw [anyM_eq_anyM_loop, anyM.loop, dif_neg (Nat.not_lt.2 h)]
|
||||
|
||||
theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.data :=
|
||||
theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
|
||||
⟨fun | .mk h => h, Array.Mem.mk⟩
|
||||
|
||||
@[simp] theorem not_mem_empty (a : α) : ¬(a ∈ #[]) := by
|
||||
simp [mem_def]
|
||||
|
||||
/-! # get -/
|
||||
|
||||
@[simp] theorem get_eq_getElem (a : Array α) (i : Fin _) : a.get i = a[i.1] := rfl
|
||||
@@ -164,11 +186,11 @@ theorem get!_eq_getD [Inhabited α] (a : Array α) : a.get! n = a.getD n default
|
||||
@[simp] theorem getElem_set_eq (a : Array α) (i : Fin a.size) (v : α) {j : Nat}
|
||||
(eq : i.val = j) (p : j < (a.set i v).size) :
|
||||
(a.set i v)[j]'p = v := by
|
||||
simp [set, getElem_eq_data_getElem, ←eq]
|
||||
simp [set, getElem_eq_toList_getElem, ←eq]
|
||||
|
||||
@[simp] theorem getElem_set_ne (a : Array α) (i : Fin a.size) (v : α) {j : Nat} (pj : j < (a.set i v).size)
|
||||
(h : i.val ≠ j) : (a.set i v)[j]'pj = a[j]'(size_set a i v ▸ pj) := by
|
||||
simp only [set, getElem_eq_data_getElem, List.getElem_set_ne h]
|
||||
simp only [set, getElem_eq_toList_getElem, List.getElem_set_ne h]
|
||||
|
||||
theorem getElem_set (a : Array α) (i : Fin a.size) (v : α) (j : Nat)
|
||||
(h : j < (a.set i v).size) :
|
||||
@@ -249,14 +271,20 @@ termination_by n - i
|
||||
|
||||
/-- # mkArray -/
|
||||
|
||||
@[simp] theorem mkArray_data (n : Nat) (v : α) : (mkArray n v).data = List.replicate n v := rfl
|
||||
@[simp] theorem toList_mkArray (n : Nat) (v : α) : (mkArray n v).toList = List.replicate n v := rfl
|
||||
|
||||
@[deprecated toList_mkArray (since := "2024-09-09")]
|
||||
abbrev mkArray_data := @toList_mkArray
|
||||
|
||||
@[simp] theorem getElem_mkArray (n : Nat) (v : α) (h : i < (mkArray n v).size) :
|
||||
(mkArray n v)[i] = v := by simp [Array.getElem_eq_data_getElem]
|
||||
(mkArray n v)[i] = v := by simp [Array.getElem_eq_toList_getElem]
|
||||
|
||||
/-- # mem -/
|
||||
|
||||
theorem mem_data {a : α} {l : Array α} : a ∈ l.data ↔ a ∈ l := mem_def.symm
|
||||
theorem mem_toList {a : α} {l : Array α} : a ∈ l.toList ↔ a ∈ l := mem_def.symm
|
||||
|
||||
@[deprecated mem_toList (since := "2024-09-09")]
|
||||
abbrev mem_data := @mem_toList
|
||||
|
||||
theorem not_mem_nil (a : α) : ¬ a ∈ #[] := nofun
|
||||
|
||||
@@ -290,10 +318,13 @@ theorem lt_of_getElem {x : α} {a : Array α} {idx : Nat} {hidx : idx < a.size}
|
||||
hidx
|
||||
|
||||
theorem getElem?_mem {l : Array α} {i : Fin l.size} : l[i] ∈ l := by
|
||||
erw [Array.mem_def, getElem_eq_data_getElem]
|
||||
erw [Array.mem_def, getElem_eq_toList_getElem]
|
||||
apply List.get_mem
|
||||
|
||||
theorem getElem_fin_eq_data_get (a : Array α) (i : Fin _) : a[i] = a.data.get i := rfl
|
||||
theorem getElem_fin_eq_toList_get (a : Array α) (i : Fin _) : a[i] = a.toList.get i := rfl
|
||||
|
||||
@[deprecated getElem_fin_eq_toList_get (since := "2024-09-09")]
|
||||
abbrev getElem_fin_eq_data_get := @getElem_fin_eq_toList_get
|
||||
|
||||
@[simp] theorem ugetElem_eq_getElem (a : Array α) {i : USize} (h : i.toNat < a.size) :
|
||||
a[i] = a[i.toNat] := rfl
|
||||
@@ -304,14 +335,23 @@ theorem getElem?_eq_getElem (a : Array α) (i : Nat) (h : i < a.size) : a[i]? =
|
||||
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_getElem, List.getElem_mem]
|
||||
theorem getElem_mem_toList (a : Array α) (h : i < a.size) : a[i] ∈ a.toList := by
|
||||
simp only [getElem_eq_toList_getElem, List.getElem_mem]
|
||||
|
||||
theorem getElem?_eq_data_get? (a : Array α) (i : Nat) : a[i]? = a.data.get? i := by
|
||||
@[deprecated getElem_mem_toList (since := "2024-09-09")]
|
||||
abbrev getElem_mem_data := @getElem_mem_toList
|
||||
|
||||
theorem getElem?_eq_toList_get? (a : Array α) (i : Nat) : a[i]? = a.toList.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? ..
|
||||
@[deprecated getElem?_eq_toList_get? (since := "2024-09-09")]
|
||||
abbrev getElem?_eq_data_get? := @getElem?_eq_toList_get?
|
||||
|
||||
theorem get?_eq_toList_get? (a : Array α) (i : Nat) : a.get? i = a.toList.get? i :=
|
||||
getElem?_eq_toList_get? ..
|
||||
|
||||
@[deprecated get?_eq_toList_get? (since := "2024-09-09")]
|
||||
abbrev get?_eq_data_get? := @get?_eq_toList_get?
|
||||
|
||||
theorem get!_eq_get? [Inhabited α] (a : Array α) : a.get! n = (a.get? n).getD default := by
|
||||
simp [get!_eq_getD]
|
||||
@@ -320,7 +360,7 @@ theorem get!_eq_get? [Inhabited α] (a : Array α) : a.get! n = (a.get? n).getD
|
||||
simp [back, back?]
|
||||
|
||||
@[simp] theorem back?_push (a : Array α) : (a.push x).back? = some x := by
|
||||
simp [back?, getElem?_eq_data_get?]
|
||||
simp [back?, getElem?_eq_toList_get?]
|
||||
|
||||
theorem back_push [Inhabited α] (a : Array α) : (a.push x).back = x := by simp
|
||||
|
||||
@@ -349,11 +389,14 @@ theorem get?_push {a : Array α} : (a.push x)[i]? = if i = a.size then some x el
|
||||
@[simp] theorem get?_size {a : Array α} : a[a.size]? = none := by
|
||||
simp only [getElem?_def, 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
|
||||
@[simp] theorem toList_set (a : Array α) (i v) : (a.set i v).toList = a.toList.set i.1 v := rfl
|
||||
|
||||
@[deprecated toList_set (since := "2024-09-09")]
|
||||
abbrev data_set := @toList_set
|
||||
|
||||
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_getElem, List.getElem_set_self]
|
||||
simp only [set, getElem_eq_toList_getElem, List.getElem_set_self]
|
||||
|
||||
theorem get?_set_eq (a : Array α) (i : Fin a.size) (v : α) :
|
||||
(a.set i v)[i.1]? = v := by simp [getElem?_pos, i.2]
|
||||
@@ -372,7 +415,7 @@ theorem get_set (a : Array α) (i : Fin a.size) (j : Nat) (hj : j < a.size) (v :
|
||||
|
||||
@[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_getElem, List.getElem_set_ne h]
|
||||
simp only [set, getElem_eq_toList_getElem, List.getElem_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
|
||||
@@ -388,12 +431,15 @@ 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 toList_swap (a : Array α) (i j : Fin a.size) :
|
||||
(a.swap i j).toList = (a.toList.set i (a.get j)).set j (a.get i) := by simp [swap_def]
|
||||
|
||||
@[deprecated toList_swap (since := "2024-09-09")]
|
||||
abbrev data_swap := @toList_swap
|
||||
|
||||
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 [swap_def, get?_set, ← getElem_fin_eq_toList_get]
|
||||
|
||||
@[simp] theorem swapAt_def (a : Array α) (i : Fin a.size) (v : α) :
|
||||
a.swapAt i v = (a[i.1], a.set i v) := rfl
|
||||
@@ -402,7 +448,10 @@ theorem get?_swap (a : Array α) (i j : Fin a.size) (k : Nat) : (a.swap i j)[k]?
|
||||
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 toList_pop (a : Array α) : a.pop.toList = a.toList.dropLast := by simp [pop]
|
||||
|
||||
@[deprecated toList_pop (since := "2024-09-09")]
|
||||
abbrev data_pop := @toList_pop
|
||||
|
||||
@[simp] theorem pop_empty : (#[] : Array α).pop = #[] := rfl
|
||||
|
||||
@@ -434,7 +483,10 @@ theorem eq_push_of_size_ne_zero {as : Array α} (h : as.size ≠ 0) :
|
||||
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
|
||||
theorem size_eq_length_toList (as : Array α) : as.size = as.toList.length := rfl
|
||||
|
||||
@[deprecated size_eq_length_toList (since := "2024-09-09")]
|
||||
abbrev size_eq_length_data := @size_eq_length_toList
|
||||
|
||||
@[simp] theorem size_swap! (a : Array α) (i j) :
|
||||
(a.swap! i j).size = a.size := by unfold swap!; split <;> (try split) <;> simp [size_swap]
|
||||
@@ -458,19 +510,22 @@ theorem size_eq_length_data (as : Array α) : as.size = as.data.length := rfl
|
||||
simp only [mkEmpty_eq, size_push] at *
|
||||
omega
|
||||
|
||||
@[simp] theorem data_range (n : Nat) : (range n).data = List.range n := by
|
||||
@[simp] theorem toList_range (n : Nat) : (range n).toList = List.range n := by
|
||||
induction n <;> simp_all [range, Nat.fold, flip, List.range_succ]
|
||||
|
||||
@[deprecated toList_range (since := "2024-09-09")]
|
||||
abbrev data_range := @toList_range
|
||||
|
||||
@[simp]
|
||||
theorem getElem_range {n : Nat} {x : Nat} (h : x < (Array.range n).size) : (Array.range n)[x] = x := by
|
||||
simp [getElem_eq_data_getElem]
|
||||
simp [getElem_eq_toList_getElem]
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[simp] theorem reverse_data (a : Array α) : a.reverse.data = a.data.reverse := by
|
||||
@[simp] theorem reverse_toList (a : Array α) : a.reverse.toList = a.toList.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
|
||||
(H : ∀ k, as.toList.get? k = if i ≤ k ∧ k ≤ j then a.toList.get? k else a.toList.reverse.get? k)
|
||||
(k) : (reverse.loop as i ⟨j, hj⟩).toList.get? k = a.toList.reverse.get? k := by
|
||||
rw [reverse.loop]; dsimp; split <;> rename_i h₁
|
||||
· have p := reverse.termination h₁
|
||||
match j with | j+1 => ?_
|
||||
@@ -479,8 +534,9 @@ set_option linter.deprecated false in
|
||||
· rwa [Nat.add_right_comm i]
|
||||
· simp [size_swap, h₂]
|
||||
· intro k
|
||||
rw [← getElem?_eq_data_get?, get?_swap]
|
||||
simp only [H, getElem_eq_data_get, ← List.get?_eq_get, Nat.le_of_lt h₁, getElem?_eq_data_get?]
|
||||
rw [← getElem?_eq_toList_get?, get?_swap]
|
||||
simp only [H, getElem_eq_toList_get, ← List.get?_eq_get, Nat.le_of_lt h₁,
|
||||
getElem?_eq_toList_get?]
|
||||
split <;> rename_i h₂
|
||||
· simp only [← h₂, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, and_false]
|
||||
exact (List.get?_reverse' (j+1) i (Eq.trans (by simp_arith) h)).symm
|
||||
@@ -505,7 +561,7 @@ set_option linter.deprecated false in
|
||||
· rename_i h
|
||||
simp only [← show k < _ + 1 ↔ _ from Nat.lt_succ (n := a.size - 1), this, Nat.zero_le,
|
||||
true_and, Nat.not_lt] at h
|
||||
rw [List.get?_eq_none.2 ‹_›, List.get?_eq_none.2 (a.data.length_reverse ▸ ‹_›)]
|
||||
rw [List.get?_eq_none.2 ‹_›, List.get?_eq_none.2 (a.toList.length_reverse ▸ ‹_›)]
|
||||
|
||||
/-! ### foldl / foldr -/
|
||||
|
||||
@@ -545,16 +601,19 @@ theorem foldr_induction
|
||||
/-! ### 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]
|
||||
simp only [mem_def, map_toList, 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
|
||||
theorem mapM_eq_mapM_toList [Monad m] [LawfulMonad m] (f : α → m β) (arr : Array α) :
|
||||
arr.mapM f = return mk (← arr.toList.mapM f) := by
|
||||
rw [mapM_eq_foldlM, foldlM_eq_foldlM_toList, ← List.foldrM_reverse]
|
||||
conv => rhs; rw [← List.reverse_reverse arr.toList]
|
||||
induction arr.toList.reverse with
|
||||
| nil => simp; rfl
|
||||
| cons a l ih => simp [ih]; simp [map_eq_pure_bind, push]
|
||||
|
||||
@[deprecated mapM_eq_mapM_toList (since := "2024-09-09")]
|
||||
abbrev mapM_eq_mapM_data := @mapM_eq_mapM_toList
|
||||
|
||||
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
|
||||
@@ -691,86 +750,95 @@ theorem get_modify {arr : Array α} {x i} (h : i < arr.size) :
|
||||
|
||||
/-! ### filter -/
|
||||
|
||||
@[simp] theorem filter_data (p : α → Bool) (l : Array α) :
|
||||
(l.filter p).data = l.data.filter p := by
|
||||
@[simp] theorem filter_toList (p : α → Bool) (l : Array α) :
|
||||
(l.filter p).toList = l.toList.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
|
||||
rw [foldl_eq_foldl_toList]
|
||||
generalize l.toList = l
|
||||
suffices ∀ a, (List.foldl (fun r a => if p a = true then push r a else r) a l).toList =
|
||||
a.toList ++ List.filter p l by
|
||||
simpa using this #[]
|
||||
induction l with simp
|
||||
| cons => split <;> simp [*]
|
||||
|
||||
@[deprecated filter_toList (since := "2024-09-09")]
|
||||
abbrev filter_data := @filter_toList
|
||||
|
||||
@[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]
|
||||
simp only [filter_toList, List.filter_filter]
|
||||
|
||||
@[simp] theorem mem_filter : x ∈ filter p as ↔ x ∈ as ∧ p x := by
|
||||
simp only [mem_def, filter_data, List.mem_filter]
|
||||
simp only [mem_def, filter_toList, 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
|
||||
@[simp] theorem filterMap_toList (f : α → Option β) (l : Array α) :
|
||||
(l.filterMap f).toList = l.toList.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 := ?_
|
||||
rw [foldlM_eq_foldlM_toList]
|
||||
generalize l.toList = l
|
||||
have this : ∀ a : Array β, (Id.run (List.foldlM (m := Id) ?_ a l)).toList =
|
||||
a.toList ++ List.filterMap f l := ?_
|
||||
exact this #[]
|
||||
induction l
|
||||
· simp_all [Id.run]
|
||||
· simp_all [Id.run, List.filterMap_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[deprecated filterMap_toList (since := "2024-09-09")]
|
||||
abbrev filterMap_data := @filterMap_toList
|
||||
|
||||
@[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]
|
||||
simp only [mem_def, filterMap_toList, List.mem_filterMap]
|
||||
|
||||
/-! ### empty -/
|
||||
|
||||
theorem size_empty : (#[] : Array α).size = 0 := rfl
|
||||
|
||||
theorem empty_data : (#[] : Array α).data = [] := rfl
|
||||
theorem toList_empty : (#[] : Array α).toList = [] := rfl
|
||||
|
||||
@[deprecated toList_empty (since := "2024-09-09")]
|
||||
abbrev empty_data := @toList_empty
|
||||
|
||||
/-! ### 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]
|
||||
simp only [mem_def, append_toList, 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]
|
||||
simp only [size, append_toList, 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_getElem]
|
||||
have h' : i < (as.data ++ bs.data).length := by rwa [← data_length, append_data] at h
|
||||
conv => rhs; rw [← List.getElem_append_left (bs := bs.data) (h' := h')]
|
||||
apply List.get_of_eq; rw [append_data]
|
||||
simp only [getElem_eq_toList_getElem]
|
||||
have h' : i < (as.toList ++ bs.toList).length := by rwa [← toList_length, append_toList] at h
|
||||
conv => rhs; rw [← List.getElem_append_left (bs := bs.toList) (h' := h')]
|
||||
apply List.get_of_eq; rw [append_toList]
|
||||
|
||||
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_getElem]
|
||||
have h' : i < (as.data ++ bs.data).length := by rwa [← data_length, append_data] at h
|
||||
conv => rhs; rw [← List.getElem_append_right (h' := h') (h := Nat.not_lt_of_ge hle)]
|
||||
apply List.get_of_eq; rw [append_data]
|
||||
simp only [getElem_eq_toList_getElem]
|
||||
have h' : i < (as.toList ++ bs.toList).length := by rwa [← toList_length, append_toList] at h
|
||||
conv => rhs; rw [← List.getElem_append_right (h₁ := hle) (h₂ := h')]
|
||||
apply List.get_of_eq; rw [append_toList]
|
||||
|
||||
@[simp] theorem append_nil (as : Array α) : as ++ #[] = as := by
|
||||
apply ext'; simp only [append_data, empty_data, List.append_nil]
|
||||
apply ext'; simp only [append_toList, toList_empty, List.append_nil]
|
||||
|
||||
@[simp] theorem nil_append (as : Array α) : #[] ++ as = as := by
|
||||
apply ext'; simp only [append_data, empty_data, List.nil_append]
|
||||
apply ext'; simp only [append_toList, toList_empty, 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]
|
||||
apply ext'; simp only [append_toList, List.append_assoc]
|
||||
|
||||
/-! ### extract -/
|
||||
|
||||
@@ -944,7 +1012,7 @@ theorem any_iff_exists {p : α → Bool} {as : Array α} {start stop} :
|
||||
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
|
||||
theorem any_def {p : α → Bool} (as : Array α) : as.any p = as.toList.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⟩⟩
|
||||
|
||||
@@ -967,14 +1035,14 @@ theorem all_iff_forall {p : α → Bool} {as : Array α} {start stop} :
|
||||
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
|
||||
theorem all_def {p : α → Bool} (as : Array α) : as.all p = as.toList.all p := by
|
||||
rw [Bool.eq_iff_iff, all_eq_true, List.all_eq_true]; simp only [List.mem_iff_getElem]
|
||||
constructor
|
||||
· rintro w x ⟨r, h, rfl⟩
|
||||
rw [← getElem_eq_data_getElem]
|
||||
rw [← getElem_eq_toList_getElem]
|
||||
exact w ⟨r, h⟩
|
||||
· intro w i
|
||||
exact w as[i] ⟨i, i.2, (getElem_eq_data_getElem as i.2).symm⟩
|
||||
exact w as[i] ⟨i, i.2, (getElem_eq_toList_getElem 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]
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Array
|
||||
-- NB: This is defined as a structure rather than a plain def so that a lemma
|
||||
-- like `sizeOf_lt_of_mem` will not apply with no actual arrays around.
|
||||
structure Mem (as : Array α) (a : α) : Prop where
|
||||
val : a ∈ as.data
|
||||
val : a ∈ as.toList
|
||||
|
||||
instance : Membership α (Array α) where
|
||||
mem := Mem
|
||||
|
||||
@@ -10,8 +10,8 @@ import Init.Data.List.Nat.TakeDrop
|
||||
namespace Array
|
||||
|
||||
theorem exists_of_uset (self : Array α) (i d h) :
|
||||
∃ l₁ l₂, self.data = l₁ ++ self[i] :: l₂ ∧ List.length l₁ = i.toNat ∧
|
||||
(self.uset i d h).data = l₁ ++ d :: l₂ := by
|
||||
simpa [Array.getElem_eq_data_getElem] using List.exists_of_set _
|
||||
∃ l₁ l₂, self.toList = l₁ ++ self[i] :: l₂ ∧ List.length l₁ = i.toNat ∧
|
||||
(self.uset i d h).toList = l₁ ++ d :: l₂ := by
|
||||
simpa [Array.getElem_eq_toList_getElem] using List.exists_of_set _
|
||||
|
||||
end Array
|
||||
|
||||
@@ -64,7 +64,7 @@ protected def ofNatLt {n : Nat} (i : Nat) (p : i < 2^n) : BitVec n where
|
||||
/-- The `BitVec` with value `i mod 2^n`. -/
|
||||
@[match_pattern]
|
||||
protected def ofNat (n : Nat) (i : Nat) : BitVec n where
|
||||
toFin := Fin.ofNat' i (Nat.two_pow_pos n)
|
||||
toFin := Fin.ofNat' (2^n) i
|
||||
|
||||
instance instOfNat : OfNat (BitVec n) i where ofNat := .ofNat n i
|
||||
instance natCastInst : NatCast (BitVec w) := ⟨BitVec.ofNat w⟩
|
||||
|
||||
@@ -31,13 +31,13 @@ namespace BitVec
|
||||
simp only [Bool.and_eq_false_imp, decide_eq_true_eq]
|
||||
omega
|
||||
|
||||
theorem lt_of_getLsbD (x : BitVec w) (i : Nat) : getLsbD x i = true → i < w := by
|
||||
theorem lt_of_getLsbD {x : BitVec w} {i : Nat} : getLsbD x i = true → i < w := by
|
||||
if h : i < w then
|
||||
simp [h]
|
||||
else
|
||||
simp [Nat.ge_of_not_lt h]
|
||||
|
||||
theorem lt_of_getMsbD (x : BitVec w) (i : Nat) : getMsbD x i = true → i < w := by
|
||||
theorem lt_of_getMsbD {x : BitVec w} {i : Nat} : getMsbD x i = true → i < w := by
|
||||
if h : i < w then
|
||||
simp [h]
|
||||
else
|
||||
@@ -245,7 +245,7 @@ theorem ofBool_eq_iff_eq : ∀ {b b' : Bool}, BitVec.ofBool b = BitVec.ofBool b'
|
||||
@[simp, bv_toNat] theorem toNat_ofNat (x w : Nat) : (BitVec.ofNat w x).toNat = x % 2^w := by
|
||||
simp [BitVec.toNat, BitVec.ofNat, Fin.ofNat']
|
||||
|
||||
@[simp] theorem toFin_ofNat (x : Nat) : toFin (BitVec.ofNat w x) = Fin.ofNat' x (Nat.two_pow_pos w) := rfl
|
||||
@[simp] theorem toFin_ofNat (x : Nat) : toFin (BitVec.ofNat w x) = Fin.ofNat' (2^w) x := rfl
|
||||
|
||||
-- Remark: we don't use `[simp]` here because simproc` subsumes it for literals.
|
||||
-- If `x` and `n` are not literals, applying this theorem eagerly may not be a good idea.
|
||||
@@ -546,7 +546,7 @@ theorem msb_truncate (x : BitVec w) : (x.truncate (k + 1)).msb = x.getLsbD k :=
|
||||
(x.zeroExtend l).zeroExtend k = x.zeroExtend k := by
|
||||
ext i
|
||||
simp only [getLsbD_zeroExtend, Fin.is_lt, decide_True, Bool.true_and]
|
||||
have p := lt_of_getLsbD x i
|
||||
have p := lt_of_getLsbD (x := x) (i := i)
|
||||
revert p
|
||||
cases getLsbD x i <;> simp; omega
|
||||
|
||||
@@ -592,6 +592,12 @@ theorem truncate_one {x : BitVec w} :
|
||||
ext i
|
||||
simp [show i = 0 by omega]
|
||||
|
||||
@[simp] theorem truncate_ofNat_of_le (h : v ≤ w) (x : Nat) : truncate v (BitVec.ofNat w x) = BitVec.ofNat v x := by
|
||||
apply BitVec.eq_of_toNat_eq
|
||||
simp only [toNat_truncate, toNat_ofNat]
|
||||
rw [Nat.mod_mod_of_dvd]
|
||||
exact Nat.pow_dvd_pow_iff_le_right'.mpr h
|
||||
|
||||
/-! ## extractLsb -/
|
||||
|
||||
@[simp]
|
||||
@@ -826,7 +832,7 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
|
||||
BitVec.toNat_ofNat _ _
|
||||
|
||||
@[simp] theorem toFin_shiftLeft {n : Nat} (x : BitVec w) :
|
||||
BitVec.toFin (x <<< n) = Fin.ofNat' (x.toNat <<< n) (Nat.two_pow_pos w) := rfl
|
||||
BitVec.toFin (x <<< n) = Fin.ofNat' (2^w) (x.toNat <<< n) := rfl
|
||||
|
||||
@[simp]
|
||||
theorem shiftLeft_zero_eq (x : BitVec w) : x <<< 0 = x := by
|
||||
@@ -1027,7 +1033,7 @@ theorem sshiftRight_eq_of_msb_true {x : BitVec w} {s : Nat} (h : x.msb = true) :
|
||||
· simp only [hi, decide_False, Bool.not_false, Bool.true_and, Bool.iff_and_self,
|
||||
decide_eq_true_eq]
|
||||
intros hlsb
|
||||
apply BitVec.lt_of_getLsbD _ _ hlsb
|
||||
apply BitVec.lt_of_getLsbD hlsb
|
||||
· by_cases hi : i ≥ w
|
||||
· simp [hi]
|
||||
· simp only [sshiftRight_eq_of_msb_true hmsb, getLsbD_not, getLsbD_ushiftRight, Bool.not_and,
|
||||
@@ -1228,7 +1234,7 @@ theorem msb_append {x : BitVec w} {y : BitVec v} :
|
||||
@[simp] theorem zero_width_append (x : BitVec 0) (y : BitVec v) : x ++ y = cast (by omega) y := by
|
||||
ext
|
||||
rw [getLsbD_append]
|
||||
simpa using lt_of_getLsbD _ _
|
||||
simpa using lt_of_getLsbD
|
||||
|
||||
@[simp] theorem cast_append_right (h : w + v = w + v') (x : BitVec w) (y : BitVec v) :
|
||||
cast h (x ++ y) = x ++ cast (by omega) y := by
|
||||
@@ -1259,6 +1265,18 @@ theorem truncate_append {x : BitVec w} {y : BitVec v} :
|
||||
· have t' : i - v < k - v := by omega
|
||||
simp [t, t']
|
||||
|
||||
@[simp] theorem truncate_append_of_eq {x : BitVec v} {y : BitVec w} (h : w' = w) : truncate (v' + w') (x ++ y) = truncate v' x ++ truncate w' y := by
|
||||
subst h
|
||||
ext i
|
||||
simp only [getLsbD_zeroExtend, Fin.is_lt, decide_True, getLsbD_append, cond_eq_if,
|
||||
decide_eq_true_eq, Bool.true_and, zeroExtend_eq]
|
||||
split
|
||||
· simp_all
|
||||
· simp_all only [Bool.iff_and_self, decide_eq_true_eq]
|
||||
intro h
|
||||
have := BitVec.lt_of_getLsbD h
|
||||
omega
|
||||
|
||||
@[simp] theorem truncate_cons {x : BitVec w} : (cons a x).truncate w = x := by
|
||||
simp [cons, truncate_append]
|
||||
|
||||
@@ -1508,7 +1526,7 @@ theorem ofNat_sub_ofNat {n} (x y : Nat) : BitVec.ofNat n x - BitVec.ofNat n y =
|
||||
simp [Neg.neg, BitVec.neg]
|
||||
|
||||
@[simp] theorem toFin_neg (x : BitVec n) :
|
||||
(-x).toFin = Fin.ofNat' (2^n - x.toNat) (Nat.two_pow_pos _) :=
|
||||
(-x).toFin = Fin.ofNat' (2^n) (2^n - x.toNat) :=
|
||||
rfl
|
||||
|
||||
theorem sub_toAdd {n} (x y : BitVec n) : x - y = x + - y := by
|
||||
@@ -1631,12 +1649,49 @@ theorem ofInt_mul {n} (x y : Int) : BitVec.ofInt n (x * y) =
|
||||
@[simp] theorem ofNat_lt_ofNat {n} (x y : Nat) : BitVec.ofNat n x < BitVec.ofNat n y ↔ x % 2^n < y % 2^n := by
|
||||
simp [lt_def]
|
||||
|
||||
protected theorem lt_of_le_ne (x y : BitVec n) (h1 : x <= y) (h2 : ¬ x = y) : x < y := by
|
||||
revert h1 h2
|
||||
let ⟨x, lt⟩ := x
|
||||
let ⟨y, lt⟩ := y
|
||||
simp
|
||||
exact Nat.lt_of_le_of_ne
|
||||
@[simp] protected theorem not_le {x y : BitVec n} : ¬ x ≤ y ↔ y < x := by
|
||||
simp [le_def, lt_def]
|
||||
|
||||
@[simp] protected theorem not_lt {x y : BitVec n} : ¬ x < y ↔ y ≤ x := by
|
||||
simp [le_def, lt_def]
|
||||
|
||||
@[simp] protected theorem le_refl (x : BitVec n) : x ≤ x := by
|
||||
simp [le_def]
|
||||
|
||||
@[simp] protected theorem lt_irrefl (x : BitVec n) : ¬x < x := by
|
||||
simp [lt_def]
|
||||
|
||||
protected theorem le_trans {x y z : BitVec n} : x ≤ y → y ≤ z → x ≤ z := by
|
||||
simp only [le_def]
|
||||
apply Nat.le_trans
|
||||
|
||||
protected theorem lt_trans {x y z : BitVec n} : x < y → y < z → x < z := by
|
||||
simp only [lt_def]
|
||||
apply Nat.lt_trans
|
||||
|
||||
protected theorem le_total (x y : BitVec n) : x ≤ y ∨ y ≤ x := by
|
||||
simp only [le_def]
|
||||
apply Nat.le_total
|
||||
|
||||
protected theorem le_antisymm {x y : BitVec n} : x ≤ y → y ≤ x → x = y := by
|
||||
simp only [le_def, BitVec.toNat_eq]
|
||||
apply Nat.le_antisymm
|
||||
|
||||
protected theorem lt_asymm {x y : BitVec n} : x < y → ¬ y < x := by
|
||||
simp only [lt_def]
|
||||
apply Nat.lt_asymm
|
||||
|
||||
protected theorem lt_of_le_ne {x y : BitVec n} : x ≤ y → ¬ x = y → x < y := by
|
||||
simp only [lt_def, le_def, BitVec.toNat_eq]
|
||||
apply Nat.lt_of_le_of_ne
|
||||
|
||||
protected theorem ne_of_lt {x y : BitVec n} : x < y → x ≠ y := by
|
||||
simp only [lt_def, ne_eq, toNat_eq]
|
||||
apply Nat.ne_of_lt
|
||||
|
||||
protected theorem umod_lt (x : BitVec n) {y : BitVec n} : 0 < y → x.umod y < y := by
|
||||
simp only [ofNat_eq_ofNat, lt_def, toNat_ofNat, Nat.zero_mod, umod, toNat_ofNatLt]
|
||||
apply Nat.mod_lt
|
||||
|
||||
/-! ### ofBoolList -/
|
||||
|
||||
@@ -2009,4 +2064,20 @@ theorem getLsbD_intMax (w : Nat) : (intMax w).getLsbD i = decide (i + 1 < w) :=
|
||||
· simp [h]
|
||||
· rw [Nat.sub_add_cancel (Nat.two_pow_pos (w - 1)), Nat.two_pow_pred_mod_two_pow (by omega)]
|
||||
|
||||
|
||||
/-! ### Non-overflow theorems -/
|
||||
|
||||
/--
|
||||
If `y ≤ x`, then the subtraction `(x - y)` does not overflow.
|
||||
Thus, `(x - y).toNat = x.toNat - y.toNat`
|
||||
-/
|
||||
theorem toNat_sub_of_le {x y : BitVec n} (h : y ≤ x) :
|
||||
(x - y).toNat = x.toNat - y.toNat := by
|
||||
simp only [toNat_sub]
|
||||
rw [BitVec.le_def] at h
|
||||
by_cases h' : x.toNat = y.toNat
|
||||
· rw [h', Nat.sub_self, Nat.sub_add_cancel (by omega), Nat.mod_self]
|
||||
· have : 2 ^ n - y.toNat + x.toNat = 2 ^ n + (x.toNat - y.toNat) := by omega
|
||||
rw [this, Nat.add_mod_left, Nat.mod_eq_of_lt (by omega)]
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -6,16 +6,11 @@ Authors: F. G. Dorais
|
||||
prelude
|
||||
import Init.NotationExtra
|
||||
|
||||
/-- Boolean exclusive or -/
|
||||
abbrev xor : Bool → Bool → Bool := bne
|
||||
|
||||
namespace Bool
|
||||
|
||||
/- Namespaced versions that can be used instead of prefixing `_root_` -/
|
||||
@[inherit_doc not] protected abbrev not := not
|
||||
@[inherit_doc or] protected abbrev or := or
|
||||
@[inherit_doc and] protected abbrev and := and
|
||||
@[inherit_doc xor] protected abbrev xor := xor
|
||||
/-- Boolean exclusive or -/
|
||||
abbrev xor : Bool → Bool → Bool := bne
|
||||
|
||||
instance (p : Bool → Prop) [inst : DecidablePred p] : Decidable (∀ x, p x) :=
|
||||
match inst true, inst false with
|
||||
@@ -597,7 +592,7 @@ theorem decide_beq_decide (p q : Prop) [dpq : Decidable (p ↔ q)] [dp : Decidab
|
||||
|
||||
end Bool
|
||||
|
||||
export Bool (cond_eq_if)
|
||||
export Bool (cond_eq_if xor and or not)
|
||||
|
||||
/-! ### decide -/
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ This differs from addition, which wraps around:
|
||||
(2 : Fin 3) + 1 = (0 : Fin 3)
|
||||
```
|
||||
-/
|
||||
def succ : Fin n → Fin n.succ
|
||||
def succ : Fin n → Fin (n + 1)
|
||||
| ⟨i, h⟩ => ⟨i+1, Nat.succ_lt_succ h⟩
|
||||
|
||||
variable {n : Nat}
|
||||
@@ -39,16 +39,20 @@ variable {n : Nat}
|
||||
/--
|
||||
Returns `a` modulo `n + 1` as a `Fin n.succ`.
|
||||
-/
|
||||
protected def ofNat {n : Nat} (a : Nat) : Fin n.succ :=
|
||||
protected def ofNat {n : Nat} (a : Nat) : Fin (n + 1) :=
|
||||
⟨a % (n+1), Nat.mod_lt _ (Nat.zero_lt_succ _)⟩
|
||||
|
||||
/--
|
||||
Returns `a` modulo `n` as a `Fin n`.
|
||||
|
||||
The assumption `n > 0` ensures that `Fin n` is nonempty.
|
||||
The assumption `NeZero n` ensures that `Fin n` is nonempty.
|
||||
-/
|
||||
protected def ofNat' {n : Nat} (a : Nat) (h : n > 0) : Fin n :=
|
||||
⟨a % n, Nat.mod_lt _ h⟩
|
||||
protected def ofNat' (n : Nat) [NeZero n] (a : Nat) : Fin n :=
|
||||
⟨a % n, Nat.mod_lt _ (pos_of_neZero n)⟩
|
||||
|
||||
-- We intend to deprecate `Fin.ofNat` in favor of `Fin.ofNat'` (and later rename).
|
||||
-- This is waiting on https://github.com/leanprover/lean4/pull/5323
|
||||
-- attribute [deprecated Fin.ofNat' (since := "2024-09-16")] Fin.ofNat
|
||||
|
||||
private theorem mlt {b : Nat} : {a : Nat} → a < n → b % n < n
|
||||
| 0, h => Nat.mod_lt _ h
|
||||
@@ -141,10 +145,10 @@ instance : ShiftLeft (Fin n) where
|
||||
instance : ShiftRight (Fin n) where
|
||||
shiftRight := Fin.shiftRight
|
||||
|
||||
instance instOfNat : OfNat (Fin (no_index (n+1))) i where
|
||||
ofNat := Fin.ofNat i
|
||||
instance instOfNat {n : Nat} [NeZero n] {i : Nat} : OfNat (Fin n) i where
|
||||
ofNat := Fin.ofNat' n i
|
||||
|
||||
instance : Inhabited (Fin (no_index (n+1))) where
|
||||
instance instInhabited {n : Nat} [NeZero n] : Inhabited (Fin n) where
|
||||
default := 0
|
||||
|
||||
@[simp] theorem zero_eta : (⟨0, Nat.zero_lt_succ _⟩ : Fin (n + 1)) = 0 := rfl
|
||||
|
||||
@@ -51,10 +51,10 @@ theorem eq_mk_iff_val_eq {a : Fin n} {k : Nat} {hk : k < n} :
|
||||
|
||||
theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
|
||||
|
||||
@[simp] theorem val_ofNat' (a : Nat) (is_pos : n > 0) :
|
||||
(Fin.ofNat' a is_pos).val = a % n := rfl
|
||||
@[simp] theorem val_ofNat' (n : Nat) [NeZero n] (a : Nat) :
|
||||
(Fin.ofNat' n a).val = a % n := rfl
|
||||
|
||||
@[simp] theorem ofNat'_val_eq_self (x : Fin n) (h) : (Fin.ofNat' x h) = x := by
|
||||
@[simp] theorem ofNat'_val_eq_self [NeZero n](x : Fin n) : (Fin.ofNat' n x) = x := by
|
||||
ext
|
||||
rw [val_ofNat', Nat.mod_eq_of_lt]
|
||||
exact x.2
|
||||
@@ -750,13 +750,13 @@ theorem addCases_right {m n : Nat} {motive : Fin (m + n) → Sort _} {left right
|
||||
|
||||
/-! ### add -/
|
||||
|
||||
@[simp] theorem ofNat'_add (x : Nat) (lt : 0 < n) (y : Fin n) :
|
||||
Fin.ofNat' x lt + y = Fin.ofNat' (x + y.val) lt := by
|
||||
@[simp] theorem ofNat'_add [NeZero n] (x : Nat) (y : Fin n) :
|
||||
Fin.ofNat' n x + y = Fin.ofNat' n (x + y.val) := by
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat', Fin.add_def]
|
||||
|
||||
@[simp] theorem add_ofNat' (x : Fin n) (y : Nat) (lt : 0 < n) :
|
||||
x + Fin.ofNat' y lt = Fin.ofNat' (x.val + y) lt := by
|
||||
@[simp] theorem add_ofNat' [NeZero n] (x : Fin n) (y : Nat) :
|
||||
x + Fin.ofNat' n y = Fin.ofNat' n (x.val + y) := by
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat', Fin.add_def]
|
||||
|
||||
@@ -765,13 +765,13 @@ theorem addCases_right {m n : Nat} {motive : Fin (m + n) → Sort _} {left right
|
||||
protected theorem coe_sub (a b : Fin n) : ((a - b : Fin n) : Nat) = ((n - b) + a) % n := by
|
||||
cases a; cases b; rfl
|
||||
|
||||
@[simp] theorem ofNat'_sub (x : Nat) (lt : 0 < n) (y : Fin n) :
|
||||
Fin.ofNat' x lt - y = Fin.ofNat' ((n - y.val) + x) lt := by
|
||||
@[simp] theorem ofNat'_sub [NeZero n] (x : Nat) (y : Fin n) :
|
||||
Fin.ofNat' n x - y = Fin.ofNat' n ((n - y.val) + x) := by
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat', Fin.sub_def]
|
||||
|
||||
@[simp] theorem sub_ofNat' (x : Fin n) (y : Nat) (lt : 0 < n) :
|
||||
x - Fin.ofNat' y lt = Fin.ofNat' ((n - y % n) + x.val) lt := by
|
||||
@[simp] theorem sub_ofNat' [NeZero n] (x : Fin n) (y : Nat) :
|
||||
x - Fin.ofNat' n y = Fin.ofNat' n ((n - y % n) + x.val) := by
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat', Fin.sub_def]
|
||||
|
||||
|
||||
@@ -16,83 +16,99 @@ There are three main conventions for integer division,
|
||||
referred here as the E, F, T rounding conventions.
|
||||
All three pairs satisfy the identity `x % y + (x / y) * y = x` unconditionally,
|
||||
and satisfy `x / 0 = 0` and `x % 0 = x`.
|
||||
|
||||
### Historical notes
|
||||
In early versions of Lean, the typeclasses provided by `/` and `%`
|
||||
were defined in terms of `tdiv` and `tmod`, and these were named simply as `div` and `mod`.
|
||||
|
||||
However we decided it was better to use `ediv` and `emod`,
|
||||
as they are consistent with the conventions used in SMTLib, and Mathlib,
|
||||
and often mathematical reasoning is easier with these conventions.
|
||||
|
||||
At that time, we did not rename `div` and `mod` to `tdiv` and `tmod` (along with all their lemma).
|
||||
In September 2024, we decided to do this rename (with deprecations in place),
|
||||
and later we intend to rename `ediv` and `emod` to `div` and `mod`, as nearly all users will only
|
||||
ever need to use these functions and their associated lemmas.
|
||||
-/
|
||||
|
||||
/-! ### T-rounding division -/
|
||||
|
||||
/--
|
||||
`div` uses the [*"T-rounding"*][t-rounding]
|
||||
`tdiv` uses the [*"T-rounding"*][t-rounding]
|
||||
(**T**runcation-rounding) convention, meaning that it rounds toward
|
||||
zero. Also note that division by zero is defined to equal zero.
|
||||
|
||||
The relation between integer division and modulo is found in
|
||||
`Int.mod_add_div` which states that
|
||||
`a % b + b * (a / b) = a`, unconditionally.
|
||||
`Int.tmod_add_tdiv` which states that
|
||||
`tmod a b + b * (tdiv a b) = a`, unconditionally.
|
||||
|
||||
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862 [theo
|
||||
mod_add_div]:
|
||||
https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.mod_add_div#doc
|
||||
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862
|
||||
[theo tmod_add_tdiv]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.tmod_add_tdiv#doc
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
#eval (7 : Int).div (0 : Int) -- 0
|
||||
#eval (0 : Int).div (7 : Int) -- 0
|
||||
#eval (7 : Int).tdiv (0 : Int) -- 0
|
||||
#eval (0 : Int).tdiv (7 : Int) -- 0
|
||||
|
||||
#eval (12 : Int).div (6 : Int) -- 2
|
||||
#eval (12 : Int).div (-6 : Int) -- -2
|
||||
#eval (-12 : Int).div (6 : Int) -- -2
|
||||
#eval (-12 : Int).div (-6 : Int) -- 2
|
||||
#eval (12 : Int).tdiv (6 : Int) -- 2
|
||||
#eval (12 : Int).tdiv (-6 : Int) -- -2
|
||||
#eval (-12 : Int).tdiv (6 : Int) -- -2
|
||||
#eval (-12 : Int).tdiv (-6 : Int) -- 2
|
||||
|
||||
#eval (12 : Int).div (7 : Int) -- 1
|
||||
#eval (12 : Int).div (-7 : Int) -- -1
|
||||
#eval (-12 : Int).div (7 : Int) -- -1
|
||||
#eval (-12 : Int).div (-7 : Int) -- 1
|
||||
#eval (12 : Int).tdiv (7 : Int) -- 1
|
||||
#eval (12 : Int).tdiv (-7 : Int) -- -1
|
||||
#eval (-12 : Int).tdiv (7 : Int) -- -1
|
||||
#eval (-12 : Int).tdiv (-7 : Int) -- 1
|
||||
```
|
||||
|
||||
Implemented by efficient native code.
|
||||
-/
|
||||
@[extern "lean_int_div"]
|
||||
def div : (@& Int) → (@& Int) → Int
|
||||
def tdiv : (@& Int) → (@& Int) → Int
|
||||
| ofNat m, ofNat n => ofNat (m / n)
|
||||
| ofNat m, -[n +1] => -ofNat (m / succ n)
|
||||
| -[m +1], ofNat n => -ofNat (succ m / n)
|
||||
| -[m +1], -[n +1] => ofNat (succ m / succ n)
|
||||
|
||||
@[deprecated tdiv (since := "2024-09-11")] abbrev div := tdiv
|
||||
|
||||
/-- Integer modulo. This function uses the
|
||||
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention
|
||||
to pair with `Int.div`, meaning that `a % b + b * (a / b) = a`
|
||||
unconditionally (see [`Int.mod_add_div`][theo mod_add_div]). In
|
||||
to pair with `Int.tdiv`, meaning that `tmod a b + b * (tdiv a b) = a`
|
||||
unconditionally (see [`Int.tmod_add_tdiv`][theo tmod_add_tdiv]). In
|
||||
particular, `a % 0 = a`.
|
||||
|
||||
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862
|
||||
[theo mod_add_div]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.mod_add_div#doc
|
||||
[theo tmod_add_tdiv]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.tmod_add_tdiv#doc
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
#eval (7 : Int).mod (0 : Int) -- 7
|
||||
#eval (0 : Int).mod (7 : Int) -- 0
|
||||
#eval (7 : Int).tmod (0 : Int) -- 7
|
||||
#eval (0 : Int).tmod (7 : Int) -- 0
|
||||
|
||||
#eval (12 : Int).mod (6 : Int) -- 0
|
||||
#eval (12 : Int).mod (-6 : Int) -- 0
|
||||
#eval (-12 : Int).mod (6 : Int) -- 0
|
||||
#eval (-12 : Int).mod (-6 : Int) -- 0
|
||||
#eval (12 : Int).tmod (6 : Int) -- 0
|
||||
#eval (12 : Int).tmod (-6 : Int) -- 0
|
||||
#eval (-12 : Int).tmod (6 : Int) -- 0
|
||||
#eval (-12 : Int).tmod (-6 : Int) -- 0
|
||||
|
||||
#eval (12 : Int).mod (7 : Int) -- 5
|
||||
#eval (12 : Int).mod (-7 : Int) -- 5
|
||||
#eval (-12 : Int).mod (7 : Int) -- -5
|
||||
#eval (-12 : Int).mod (-7 : Int) -- -5
|
||||
#eval (12 : Int).tmod (7 : Int) -- 5
|
||||
#eval (12 : Int).tmod (-7 : Int) -- 5
|
||||
#eval (-12 : Int).tmod (7 : Int) -- -5
|
||||
#eval (-12 : Int).tmod (-7 : Int) -- -5
|
||||
```
|
||||
|
||||
Implemented by efficient native code. -/
|
||||
@[extern "lean_int_mod"]
|
||||
def mod : (@& Int) → (@& Int) → Int
|
||||
def tmod : (@& Int) → (@& Int) → Int
|
||||
| ofNat m, ofNat n => ofNat (m % n)
|
||||
| ofNat m, -[n +1] => ofNat (m % succ n)
|
||||
| -[m +1], ofNat n => -ofNat (succ m % n)
|
||||
| -[m +1], -[n +1] => -ofNat (succ m % succ n)
|
||||
|
||||
@[deprecated tmod (since := "2024-09-11")] abbrev mod := tmod
|
||||
|
||||
/-! ### F-rounding division
|
||||
This pair satisfies `fdiv x y = floor (x / y)`.
|
||||
-/
|
||||
@@ -233,7 +249,9 @@ instance : Mod Int where
|
||||
|
||||
@[simp, norm_cast] theorem ofNat_ediv (m n : Nat) : (↑(m / n) : Int) = ↑m / ↑n := rfl
|
||||
|
||||
theorem ofNat_div (m n : Nat) : ↑(m / n) = div ↑m ↑n := rfl
|
||||
theorem ofNat_tdiv (m n : Nat) : ↑(m / n) = tdiv ↑m ↑n := rfl
|
||||
|
||||
@[deprecated ofNat_tdiv (since := "2024-09-11")] abbrev ofNat_div := ofNat_tdiv
|
||||
|
||||
theorem ofNat_fdiv : ∀ m n : Nat, ↑(m / n) = fdiv ↑m ↑n
|
||||
| 0, _ => by simp [fdiv]
|
||||
|
||||
@@ -137,12 +137,12 @@ theorem eq_one_of_mul_eq_one_left {a b : Int} (H : 0 ≤ b) (H' : a * b = 1) : b
|
||||
| ofNat _ => show ofNat _ = _ by simp
|
||||
| -[_+1] => rfl
|
||||
|
||||
@[simp] protected theorem zero_div : ∀ b : Int, div 0 b = 0
|
||||
@[simp] protected theorem zero_tdiv : ∀ b : Int, tdiv 0 b = 0
|
||||
| ofNat _ => show ofNat _ = _ by simp
|
||||
| -[_+1] => show -ofNat _ = _ by simp
|
||||
|
||||
unseal Nat.div in
|
||||
@[simp] protected theorem div_zero : ∀ a : Int, div a 0 = 0
|
||||
@[simp] protected theorem tdiv_zero : ∀ a : Int, tdiv a 0 = 0
|
||||
| ofNat _ => show ofNat _ = _ by simp
|
||||
| -[_+1] => rfl
|
||||
|
||||
@@ -156,16 +156,17 @@ unseal Nat.div in
|
||||
|
||||
/-! ### div equivalences -/
|
||||
|
||||
theorem div_eq_ediv : ∀ {a b : Int}, 0 ≤ a → 0 ≤ b → a.div b = a / b
|
||||
theorem tdiv_eq_ediv : ∀ {a b : Int}, 0 ≤ a → 0 ≤ b → a.tdiv b = a / b
|
||||
| 0, _, _, _ | _, 0, _, _ => by simp
|
||||
| succ _, succ _, _, _ => rfl
|
||||
|
||||
|
||||
theorem fdiv_eq_ediv : ∀ (a : Int) {b : Int}, 0 ≤ b → fdiv a b = a / b
|
||||
| 0, _, _ | -[_+1], 0, _ => by simp
|
||||
| succ _, ofNat _, _ | -[_+1], succ _, _ => rfl
|
||||
|
||||
theorem fdiv_eq_div {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : fdiv a b = div a b :=
|
||||
div_eq_ediv Ha Hb ▸ fdiv_eq_ediv _ Hb
|
||||
theorem fdiv_eq_tdiv {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : fdiv a b = tdiv a b :=
|
||||
tdiv_eq_ediv Ha Hb ▸ fdiv_eq_ediv _ Hb
|
||||
|
||||
/-! ### mod zero -/
|
||||
|
||||
@@ -175,9 +176,9 @@ theorem fdiv_eq_div {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : fdiv a b = div a
|
||||
| ofNat _ => congrArg ofNat <| Nat.mod_zero _
|
||||
| -[_+1] => congrArg negSucc <| Nat.mod_zero _
|
||||
|
||||
@[simp] theorem zero_mod (b : Int) : mod 0 b = 0 := by cases b <;> simp [mod]
|
||||
@[simp] theorem zero_tmod (b : Int) : tmod 0 b = 0 := by cases b <;> simp [tmod]
|
||||
|
||||
@[simp] theorem mod_zero : ∀ a : Int, mod a 0 = a
|
||||
@[simp] theorem tmod_zero : ∀ a : Int, tmod a 0 = a
|
||||
| ofNat _ => congrArg ofNat <| Nat.mod_zero _
|
||||
| -[_+1] => congrArg (fun n => -ofNat n) <| Nat.mod_zero _
|
||||
|
||||
@@ -221,7 +222,7 @@ theorem ediv_add_emod' (a b : Int) : a / b * b + a % b = a := by
|
||||
theorem emod_def (a b : Int) : a % b = a - b * (a / b) := by
|
||||
rw [← Int.add_sub_cancel (a % b), emod_add_ediv]
|
||||
|
||||
theorem mod_add_div : ∀ a b : Int, mod a b + b * (a.div b) = a
|
||||
theorem tmod_add_tdiv : ∀ a b : Int, tmod a b + b * (a.tdiv b) = a
|
||||
| ofNat _, ofNat _ => congrArg ofNat (Nat.mod_add_div ..)
|
||||
| ofNat m, -[n+1] => by
|
||||
show (m % succ n + -↑(succ n) * -↑(m / succ n) : Int) = m
|
||||
@@ -238,17 +239,17 @@ theorem mod_add_div : ∀ a b : Int, mod a b + b * (a.div b) = a
|
||||
rw [Int.neg_mul, ← Int.neg_add]
|
||||
exact congrArg (-ofNat ·) (Nat.mod_add_div ..)
|
||||
|
||||
theorem div_add_mod (a b : Int) : b * a.div b + mod a b = a := by
|
||||
rw [Int.add_comm]; apply mod_add_div ..
|
||||
theorem tdiv_add_tmod (a b : Int) : b * a.tdiv b + tmod a b = a := by
|
||||
rw [Int.add_comm]; apply tmod_add_tdiv ..
|
||||
|
||||
theorem mod_add_div' (m k : Int) : mod m k + m.div k * k = m := by
|
||||
rw [Int.mul_comm]; apply mod_add_div
|
||||
theorem tmod_add_tdiv' (m k : Int) : tmod m k + m.tdiv k * k = m := by
|
||||
rw [Int.mul_comm]; apply tmod_add_tdiv
|
||||
|
||||
theorem div_add_mod' (m k : Int) : m.div k * k + mod m k = m := by
|
||||
rw [Int.mul_comm]; apply div_add_mod
|
||||
theorem tdiv_add_tmod' (m k : Int) : m.tdiv k * k + tmod m k = m := by
|
||||
rw [Int.mul_comm]; apply tdiv_add_tmod
|
||||
|
||||
theorem mod_def (a b : Int) : mod a b = a - b * a.div b := by
|
||||
rw [← Int.add_sub_cancel (mod a b), mod_add_div]
|
||||
theorem tmod_def (a b : Int) : tmod a b = a - b * a.tdiv b := by
|
||||
rw [← Int.add_sub_cancel (tmod a b), tmod_add_tdiv]
|
||||
|
||||
theorem fmod_add_fdiv : ∀ a b : Int, a.fmod b + b * a.fdiv b = a
|
||||
| 0, ofNat _ | 0, -[_+1] => congrArg ofNat <| by simp
|
||||
@@ -278,11 +279,11 @@ theorem fmod_def (a b : Int) : a.fmod b = a - b * a.fdiv b := by
|
||||
theorem fmod_eq_emod (a : Int) {b : Int} (hb : 0 ≤ b) : fmod a b = a % b := by
|
||||
simp [fmod_def, emod_def, fdiv_eq_ediv _ hb]
|
||||
|
||||
theorem mod_eq_emod {a b : Int} (ha : 0 ≤ a) (hb : 0 ≤ b) : mod a b = a % b := by
|
||||
simp [emod_def, mod_def, div_eq_ediv ha hb]
|
||||
theorem tmod_eq_emod {a b : Int} (ha : 0 ≤ a) (hb : 0 ≤ b) : tmod a b = a % b := by
|
||||
simp [emod_def, tmod_def, tdiv_eq_ediv ha hb]
|
||||
|
||||
theorem fmod_eq_mod {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : fmod a b = mod a b :=
|
||||
mod_eq_emod Ha Hb ▸ fmod_eq_emod _ Hb
|
||||
theorem fmod_eq_tmod {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : fmod a b = tmod a b :=
|
||||
tmod_eq_emod Ha Hb ▸ fmod_eq_emod _ Hb
|
||||
|
||||
/-! ### `/` ediv -/
|
||||
|
||||
@@ -297,7 +298,7 @@ theorem ediv_neg' {a b : Int} (Ha : a < 0) (Hb : 0 < b) : a / b < 0 :=
|
||||
|
||||
protected theorem div_def (a b : Int) : a / b = Int.ediv a b := rfl
|
||||
|
||||
theorem negSucc_ediv (m : Nat) {b : Int} (H : 0 < b) : -[m+1] / b = -(div m b + 1) :=
|
||||
theorem negSucc_ediv (m : Nat) {b : Int} (H : 0 < b) : -[m+1] / b = -(ediv m b + 1) :=
|
||||
match b, eq_succ_of_zero_lt H with
|
||||
| _, ⟨_, rfl⟩ => rfl
|
||||
|
||||
@@ -305,6 +306,22 @@ theorem ediv_nonneg {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : 0 ≤ a / b :=
|
||||
match a, b, eq_ofNat_of_zero_le Ha, eq_ofNat_of_zero_le Hb with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => ofNat_zero_le _
|
||||
|
||||
theorem ediv_nonneg_of_nonpos_of_nonpos {a b : Int} (Ha : a ≤ 0) (Hb : b ≤ 0) : 0 ≤ a / b := by
|
||||
match a, b with
|
||||
| ofNat a, b =>
|
||||
match Int.le_antisymm Ha (ofNat_zero_le a) with
|
||||
| h1 =>
|
||||
rw [h1, zero_ediv]
|
||||
exact Int.le_refl 0
|
||||
| a, ofNat b =>
|
||||
match Int.le_antisymm Hb (ofNat_zero_le b) with
|
||||
| h1 =>
|
||||
rw [h1, Int.ediv_zero]
|
||||
exact Int.le_refl 0
|
||||
| negSucc a, negSucc b =>
|
||||
rw [Int.div_def, ediv]
|
||||
exact le_add_one (ediv_nonneg (ofNat_zero_le a) (Int.le_trans (ofNat_zero_le b) (le.intro 1 rfl)))
|
||||
|
||||
theorem ediv_nonpos {a b : Int} (Ha : 0 ≤ a) (Hb : b ≤ 0) : a / b ≤ 0 :=
|
||||
Int.nonpos_of_neg_nonneg <| Int.ediv_neg .. ▸ Int.ediv_nonneg Ha (Int.neg_nonneg_of_nonpos Hb)
|
||||
|
||||
@@ -796,191 +813,191 @@ theorem ediv_eq_ediv_of_mul_eq_mul {a b c d : Int}
|
||||
Int.ediv_eq_of_eq_mul_right H3 <| by
|
||||
rw [← Int.mul_ediv_assoc _ H2]; exact (Int.ediv_eq_of_eq_mul_left H4 H5.symm).symm
|
||||
|
||||
/-! ### div -/
|
||||
/-! ### tdiv -/
|
||||
|
||||
@[simp] protected theorem div_one : ∀ a : Int, a.div 1 = a
|
||||
@[simp] protected theorem tdiv_one : ∀ a : Int, a.tdiv 1 = a
|
||||
| (n:Nat) => congrArg ofNat (Nat.div_one _)
|
||||
| -[n+1] => by simp [Int.div, neg_ofNat_succ]; rfl
|
||||
| -[n+1] => by simp [Int.tdiv, neg_ofNat_succ]; rfl
|
||||
|
||||
unseal Nat.div in
|
||||
@[simp] protected theorem div_neg : ∀ a b : Int, a.div (-b) = -(a.div b)
|
||||
@[simp] protected theorem tdiv_neg : ∀ a b : Int, a.tdiv (-b) = -(a.tdiv b)
|
||||
| ofNat m, 0 => show ofNat (m / 0) = -↑(m / 0) by rw [Nat.div_zero]; rfl
|
||||
| ofNat m, -[n+1] | -[m+1], succ n => (Int.neg_neg _).symm
|
||||
| ofNat m, succ n | -[m+1], 0 | -[m+1], -[n+1] => rfl
|
||||
|
||||
unseal Nat.div in
|
||||
@[simp] protected theorem neg_div : ∀ a b : Int, (-a).div b = -(a.div b)
|
||||
@[simp] protected theorem neg_tdiv : ∀ a b : Int, (-a).tdiv b = -(a.tdiv b)
|
||||
| 0, n => by simp [Int.neg_zero]
|
||||
| succ m, (n:Nat) | -[m+1], 0 | -[m+1], -[n+1] => rfl
|
||||
| succ m, -[n+1] | -[m+1], succ n => (Int.neg_neg _).symm
|
||||
|
||||
protected theorem neg_div_neg (a b : Int) : (-a).div (-b) = a.div b := by
|
||||
simp [Int.div_neg, Int.neg_div, Int.neg_neg]
|
||||
protected theorem neg_tdiv_neg (a b : Int) : (-a).tdiv (-b) = a.tdiv b := by
|
||||
simp [Int.tdiv_neg, Int.neg_tdiv, Int.neg_neg]
|
||||
|
||||
protected theorem div_nonneg {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : 0 ≤ a.div b :=
|
||||
protected theorem tdiv_nonneg {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : 0 ≤ a.tdiv b :=
|
||||
match a, b, eq_ofNat_of_zero_le Ha, eq_ofNat_of_zero_le Hb with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => ofNat_zero_le _
|
||||
|
||||
protected theorem div_nonpos {a b : Int} (Ha : 0 ≤ a) (Hb : b ≤ 0) : a.div b ≤ 0 :=
|
||||
Int.nonpos_of_neg_nonneg <| Int.div_neg .. ▸ Int.div_nonneg Ha (Int.neg_nonneg_of_nonpos Hb)
|
||||
protected theorem tdiv_nonpos {a b : Int} (Ha : 0 ≤ a) (Hb : b ≤ 0) : a.tdiv b ≤ 0 :=
|
||||
Int.nonpos_of_neg_nonneg <| Int.tdiv_neg .. ▸ Int.tdiv_nonneg Ha (Int.neg_nonneg_of_nonpos Hb)
|
||||
|
||||
theorem div_eq_zero_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a.div b = 0 :=
|
||||
theorem tdiv_eq_zero_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a.tdiv b = 0 :=
|
||||
match a, b, eq_ofNat_of_zero_le H1, eq_succ_of_zero_lt (Int.lt_of_le_of_lt H1 H2) with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => congrArg Nat.cast <| Nat.div_eq_of_lt <| ofNat_lt.1 H2
|
||||
|
||||
@[simp] protected theorem mul_div_cancel (a : Int) {b : Int} (H : b ≠ 0) : (a * b).div b = a :=
|
||||
have : ∀ {a b : Nat}, (b : Int) ≠ 0 → (div (a * b) b : Int) = a := fun H => by
|
||||
rw [← ofNat_mul, ← ofNat_div,
|
||||
@[simp] protected theorem mul_tdiv_cancel (a : Int) {b : Int} (H : b ≠ 0) : (a * b).tdiv b = a :=
|
||||
have : ∀ {a b : Nat}, (b : Int) ≠ 0 → (tdiv (a * b) b : Int) = a := fun H => by
|
||||
rw [← ofNat_mul, ← ofNat_tdiv,
|
||||
Nat.mul_div_cancel _ <| Nat.pos_of_ne_zero <| Int.ofNat_ne_zero.1 H]
|
||||
match a, b, a.eq_nat_or_neg, b.eq_nat_or_neg with
|
||||
| _, _, ⟨a, .inl rfl⟩, ⟨b, .inl rfl⟩ => this H
|
||||
| _, _, ⟨a, .inl rfl⟩, ⟨b, .inr rfl⟩ => by
|
||||
rw [Int.mul_neg, Int.neg_div, Int.div_neg, Int.neg_neg,
|
||||
rw [Int.mul_neg, Int.neg_tdiv, Int.tdiv_neg, Int.neg_neg,
|
||||
this (Int.neg_ne_zero.1 H)]
|
||||
| _, _, ⟨a, .inr rfl⟩, ⟨b, .inl rfl⟩ => by rw [Int.neg_mul, Int.neg_div, this H]
|
||||
| _, _, ⟨a, .inr rfl⟩, ⟨b, .inl rfl⟩ => by rw [Int.neg_mul, Int.neg_tdiv, this H]
|
||||
| _, _, ⟨a, .inr rfl⟩, ⟨b, .inr rfl⟩ => by
|
||||
rw [Int.neg_mul_neg, Int.div_neg, this (Int.neg_ne_zero.1 H)]
|
||||
rw [Int.neg_mul_neg, Int.tdiv_neg, this (Int.neg_ne_zero.1 H)]
|
||||
|
||||
@[simp] protected theorem mul_div_cancel_left (b : Int) (H : a ≠ 0) : (a * b).div a = b :=
|
||||
Int.mul_comm .. ▸ Int.mul_div_cancel _ H
|
||||
@[simp] protected theorem mul_tdiv_cancel_left (b : Int) (H : a ≠ 0) : (a * b).tdiv a = b :=
|
||||
Int.mul_comm .. ▸ Int.mul_tdiv_cancel _ H
|
||||
|
||||
@[simp] protected theorem div_self {a : Int} (H : a ≠ 0) : a.div a = 1 := by
|
||||
have := Int.mul_div_cancel 1 H; rwa [Int.one_mul] at this
|
||||
@[simp] protected theorem tdiv_self {a : Int} (H : a ≠ 0) : a.tdiv a = 1 := by
|
||||
have := Int.mul_tdiv_cancel 1 H; rwa [Int.one_mul] at this
|
||||
|
||||
theorem mul_div_cancel_of_mod_eq_zero {a b : Int} (H : a.mod b = 0) : b * (a.div b) = a := by
|
||||
have := mod_add_div a b; rwa [H, Int.zero_add] at this
|
||||
theorem mul_tdiv_cancel_of_tmod_eq_zero {a b : Int} (H : a.tmod b = 0) : b * (a.tdiv b) = a := by
|
||||
have := tmod_add_tdiv a b; rwa [H, Int.zero_add] at this
|
||||
|
||||
theorem div_mul_cancel_of_mod_eq_zero {a b : Int} (H : a.mod b = 0) : a.div b * b = a := by
|
||||
rw [Int.mul_comm, mul_div_cancel_of_mod_eq_zero H]
|
||||
theorem tdiv_mul_cancel_of_tmod_eq_zero {a b : Int} (H : a.tmod b = 0) : a.tdiv b * b = a := by
|
||||
rw [Int.mul_comm, mul_tdiv_cancel_of_tmod_eq_zero H]
|
||||
|
||||
theorem dvd_of_mod_eq_zero {a b : Int} (H : mod b a = 0) : a ∣ b :=
|
||||
⟨b.div a, (mul_div_cancel_of_mod_eq_zero H).symm⟩
|
||||
theorem dvd_of_tmod_eq_zero {a b : Int} (H : tmod b a = 0) : a ∣ b :=
|
||||
⟨b.tdiv a, (mul_tdiv_cancel_of_tmod_eq_zero H).symm⟩
|
||||
|
||||
protected theorem mul_div_assoc (a : Int) : ∀ {b c : Int}, c ∣ b → (a * b).div c = a * (b.div c)
|
||||
protected theorem mul_tdiv_assoc (a : Int) : ∀ {b c : Int}, c ∣ b → (a * b).tdiv c = a * (b.tdiv c)
|
||||
| _, c, ⟨d, rfl⟩ =>
|
||||
if cz : c = 0 then by simp [cz, Int.mul_zero] else by
|
||||
rw [Int.mul_left_comm, Int.mul_div_cancel_left _ cz, Int.mul_div_cancel_left _ cz]
|
||||
rw [Int.mul_left_comm, Int.mul_tdiv_cancel_left _ cz, Int.mul_tdiv_cancel_left _ cz]
|
||||
|
||||
protected theorem mul_div_assoc' (b : Int) {a c : Int} (h : c ∣ a) :
|
||||
(a * b).div c = a.div c * b := by
|
||||
rw [Int.mul_comm, Int.mul_div_assoc _ h, Int.mul_comm]
|
||||
protected theorem mul_tdiv_assoc' (b : Int) {a c : Int} (h : c ∣ a) :
|
||||
(a * b).tdiv c = a.tdiv c * b := by
|
||||
rw [Int.mul_comm, Int.mul_tdiv_assoc _ h, Int.mul_comm]
|
||||
|
||||
theorem div_dvd_div : ∀ {a b c : Int}, a ∣ b → b ∣ c → b.div a ∣ c.div a
|
||||
theorem tdiv_dvd_tdiv : ∀ {a b c : Int}, a ∣ b → b ∣ c → b.tdiv a ∣ c.tdiv a
|
||||
| a, _, _, ⟨b, rfl⟩, ⟨c, rfl⟩ => by
|
||||
by_cases az : a = 0
|
||||
· simp [az]
|
||||
· rw [Int.mul_div_cancel_left _ az, Int.mul_assoc, Int.mul_div_cancel_left _ az]
|
||||
· rw [Int.mul_tdiv_cancel_left _ az, Int.mul_assoc, Int.mul_tdiv_cancel_left _ az]
|
||||
apply Int.dvd_mul_right
|
||||
|
||||
@[simp] theorem natAbs_div (a b : Int) : natAbs (a.div b) = (natAbs a).div (natAbs b) :=
|
||||
@[simp] theorem natAbs_tdiv (a b : Int) : natAbs (a.tdiv b) = (natAbs a).div (natAbs b) :=
|
||||
match a, b, eq_nat_or_neg a, eq_nat_or_neg b with
|
||||
| _, _, ⟨_, .inl rfl⟩, ⟨_, .inl rfl⟩ => rfl
|
||||
| _, _, ⟨_, .inl rfl⟩, ⟨_, .inr rfl⟩ => by rw [Int.div_neg, natAbs_neg, natAbs_neg]; rfl
|
||||
| _, _, ⟨_, .inr rfl⟩, ⟨_, .inl rfl⟩ => by rw [Int.neg_div, natAbs_neg, natAbs_neg]; rfl
|
||||
| _, _, ⟨_, .inr rfl⟩, ⟨_, .inr rfl⟩ => by rw [Int.neg_div_neg, natAbs_neg, natAbs_neg]; rfl
|
||||
| _, _, ⟨_, .inl rfl⟩, ⟨_, .inr rfl⟩ => by rw [Int.tdiv_neg, natAbs_neg, natAbs_neg]; rfl
|
||||
| _, _, ⟨_, .inr rfl⟩, ⟨_, .inl rfl⟩ => by rw [Int.neg_tdiv, natAbs_neg, natAbs_neg]; rfl
|
||||
| _, _, ⟨_, .inr rfl⟩, ⟨_, .inr rfl⟩ => by rw [Int.neg_tdiv_neg, natAbs_neg, natAbs_neg]; rfl
|
||||
|
||||
protected theorem div_eq_of_eq_mul_right {a b c : Int}
|
||||
(H1 : b ≠ 0) (H2 : a = b * c) : a.div b = c := by rw [H2, Int.mul_div_cancel_left _ H1]
|
||||
protected theorem tdiv_eq_of_eq_mul_right {a b c : Int}
|
||||
(H1 : b ≠ 0) (H2 : a = b * c) : a.tdiv b = c := by rw [H2, Int.mul_tdiv_cancel_left _ H1]
|
||||
|
||||
protected theorem eq_div_of_mul_eq_right {a b c : Int}
|
||||
(H1 : a ≠ 0) (H2 : a * b = c) : b = c.div a :=
|
||||
(Int.div_eq_of_eq_mul_right H1 H2.symm).symm
|
||||
protected theorem eq_tdiv_of_mul_eq_right {a b c : Int}
|
||||
(H1 : a ≠ 0) (H2 : a * b = c) : b = c.tdiv a :=
|
||||
(Int.tdiv_eq_of_eq_mul_right H1 H2.symm).symm
|
||||
|
||||
/-! ### (t-)mod -/
|
||||
|
||||
theorem ofNat_mod (m n : Nat) : (↑(m % n) : Int) = mod m n := rfl
|
||||
theorem ofNat_tmod (m n : Nat) : (↑(m % n) : Int) = tmod m n := rfl
|
||||
|
||||
@[simp] theorem mod_one (a : Int) : mod a 1 = 0 := by
|
||||
simp [mod_def, Int.div_one, Int.one_mul, Int.sub_self]
|
||||
@[simp] theorem tmod_one (a : Int) : tmod a 1 = 0 := by
|
||||
simp [tmod_def, Int.tdiv_one, Int.one_mul, Int.sub_self]
|
||||
|
||||
theorem mod_eq_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : mod a b = a := by
|
||||
rw [mod_eq_emod H1 (Int.le_trans H1 (Int.le_of_lt H2)), emod_eq_of_lt H1 H2]
|
||||
theorem tmod_eq_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : tmod a b = a := by
|
||||
rw [tmod_eq_emod H1 (Int.le_trans H1 (Int.le_of_lt H2)), emod_eq_of_lt H1 H2]
|
||||
|
||||
theorem mod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : mod a b < b :=
|
||||
theorem tmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : tmod a b < b :=
|
||||
match a, b, eq_succ_of_zero_lt H with
|
||||
| ofNat _, _, ⟨n, rfl⟩ => ofNat_lt.2 <| Nat.mod_lt _ n.succ_pos
|
||||
| -[_+1], _, ⟨n, rfl⟩ => Int.lt_of_le_of_lt
|
||||
(Int.neg_nonpos_of_nonneg <| Int.ofNat_nonneg _) (ofNat_pos.2 n.succ_pos)
|
||||
|
||||
theorem mod_nonneg : ∀ {a : Int} (b : Int), 0 ≤ a → 0 ≤ mod a b
|
||||
theorem tmod_nonneg : ∀ {a : Int} (b : Int), 0 ≤ a → 0 ≤ tmod a b
|
||||
| ofNat _, -[_+1], _ | ofNat _, ofNat _, _ => ofNat_nonneg _
|
||||
|
||||
@[simp] theorem mod_neg (a b : Int) : mod a (-b) = mod a b := by
|
||||
rw [mod_def, mod_def, Int.div_neg, Int.neg_mul_neg]
|
||||
@[simp] theorem tmod_neg (a b : Int) : tmod a (-b) = tmod a b := by
|
||||
rw [tmod_def, tmod_def, Int.tdiv_neg, Int.neg_mul_neg]
|
||||
|
||||
@[simp] theorem mul_mod_left (a b : Int) : (a * b).mod b = 0 :=
|
||||
@[simp] theorem mul_tmod_left (a b : Int) : (a * b).tmod b = 0 :=
|
||||
if h : b = 0 then by simp [h, Int.mul_zero] else by
|
||||
rw [Int.mod_def, Int.mul_div_cancel _ h, Int.mul_comm, Int.sub_self]
|
||||
rw [Int.tmod_def, Int.mul_tdiv_cancel _ h, Int.mul_comm, Int.sub_self]
|
||||
|
||||
@[simp] theorem mul_mod_right (a b : Int) : (a * b).mod a = 0 := by
|
||||
rw [Int.mul_comm, mul_mod_left]
|
||||
@[simp] theorem mul_tmod_right (a b : Int) : (a * b).tmod a = 0 := by
|
||||
rw [Int.mul_comm, mul_tmod_left]
|
||||
|
||||
theorem mod_eq_zero_of_dvd : ∀ {a b : Int}, a ∣ b → mod b a = 0
|
||||
| _, _, ⟨_, rfl⟩ => mul_mod_right ..
|
||||
theorem tmod_eq_zero_of_dvd : ∀ {a b : Int}, a ∣ b → tmod b a = 0
|
||||
| _, _, ⟨_, rfl⟩ => mul_tmod_right ..
|
||||
|
||||
theorem dvd_iff_mod_eq_zero {a b : Int} : a ∣ b ↔ mod b a = 0 :=
|
||||
⟨mod_eq_zero_of_dvd, dvd_of_mod_eq_zero⟩
|
||||
theorem dvd_iff_tmod_eq_zero {a b : Int} : a ∣ b ↔ tmod b a = 0 :=
|
||||
⟨tmod_eq_zero_of_dvd, dvd_of_tmod_eq_zero⟩
|
||||
|
||||
@[simp] theorem neg_mul_mod_right (a b : Int) : (-(a * b)).mod a = 0 := by
|
||||
rw [← dvd_iff_mod_eq_zero, Int.dvd_neg]
|
||||
@[simp] theorem neg_mul_tmod_right (a b : Int) : (-(a * b)).tmod a = 0 := by
|
||||
rw [← dvd_iff_tmod_eq_zero, Int.dvd_neg]
|
||||
exact Int.dvd_mul_right a b
|
||||
|
||||
@[simp] theorem neg_mul_mod_left (a b : Int) : (-(a * b)).mod b = 0 := by
|
||||
rw [← dvd_iff_mod_eq_zero, Int.dvd_neg]
|
||||
@[simp] theorem neg_mul_tmod_left (a b : Int) : (-(a * b)).tmod b = 0 := by
|
||||
rw [← dvd_iff_tmod_eq_zero, Int.dvd_neg]
|
||||
exact Int.dvd_mul_left a b
|
||||
|
||||
protected theorem div_mul_cancel {a b : Int} (H : b ∣ a) : a.div b * b = a :=
|
||||
div_mul_cancel_of_mod_eq_zero (mod_eq_zero_of_dvd H)
|
||||
protected theorem tdiv_mul_cancel {a b : Int} (H : b ∣ a) : a.tdiv b * b = a :=
|
||||
tdiv_mul_cancel_of_tmod_eq_zero (tmod_eq_zero_of_dvd H)
|
||||
|
||||
protected theorem mul_div_cancel' {a b : Int} (H : a ∣ b) : a * b.div a = b := by
|
||||
rw [Int.mul_comm, Int.div_mul_cancel H]
|
||||
protected theorem mul_tdiv_cancel' {a b : Int} (H : a ∣ b) : a * b.tdiv a = b := by
|
||||
rw [Int.mul_comm, Int.tdiv_mul_cancel H]
|
||||
|
||||
protected theorem eq_mul_of_div_eq_right {a b c : Int}
|
||||
(H1 : b ∣ a) (H2 : a.div b = c) : a = b * c := by rw [← H2, Int.mul_div_cancel' H1]
|
||||
protected theorem eq_mul_of_tdiv_eq_right {a b c : Int}
|
||||
(H1 : b ∣ a) (H2 : a.tdiv b = c) : a = b * c := by rw [← H2, Int.mul_tdiv_cancel' H1]
|
||||
|
||||
@[simp] theorem mod_self {a : Int} : a.mod a = 0 := by
|
||||
have := mul_mod_left 1 a; rwa [Int.one_mul] at this
|
||||
@[simp] theorem tmod_self {a : Int} : a.tmod a = 0 := by
|
||||
have := mul_tmod_left 1 a; rwa [Int.one_mul] at this
|
||||
|
||||
@[simp] theorem neg_mod_self (a : Int) : (-a).mod a = 0 := by
|
||||
rw [← dvd_iff_mod_eq_zero, Int.dvd_neg]
|
||||
@[simp] theorem neg_tmod_self (a : Int) : (-a).tmod a = 0 := by
|
||||
rw [← dvd_iff_tmod_eq_zero, Int.dvd_neg]
|
||||
exact Int.dvd_refl a
|
||||
|
||||
theorem lt_div_add_one_mul_self (a : Int) {b : Int} (H : 0 < b) : a < (a.div b + 1) * b := by
|
||||
theorem lt_tdiv_add_one_mul_self (a : Int) {b : Int} (H : 0 < b) : a < (a.tdiv b + 1) * b := by
|
||||
rw [Int.add_mul, Int.one_mul, Int.mul_comm]
|
||||
exact Int.lt_add_of_sub_left_lt <| Int.mod_def .. ▸ mod_lt_of_pos _ H
|
||||
exact Int.lt_add_of_sub_left_lt <| Int.tmod_def .. ▸ tmod_lt_of_pos _ H
|
||||
|
||||
protected theorem div_eq_iff_eq_mul_right {a b c : Int}
|
||||
(H : b ≠ 0) (H' : b ∣ a) : a.div b = c ↔ a = b * c :=
|
||||
⟨Int.eq_mul_of_div_eq_right H', Int.div_eq_of_eq_mul_right H⟩
|
||||
protected theorem tdiv_eq_iff_eq_mul_right {a b c : Int}
|
||||
(H : b ≠ 0) (H' : b ∣ a) : a.tdiv b = c ↔ a = b * c :=
|
||||
⟨Int.eq_mul_of_tdiv_eq_right H', Int.tdiv_eq_of_eq_mul_right H⟩
|
||||
|
||||
protected theorem div_eq_iff_eq_mul_left {a b c : Int}
|
||||
(H : b ≠ 0) (H' : b ∣ a) : a.div b = c ↔ a = c * b := by
|
||||
rw [Int.mul_comm]; exact Int.div_eq_iff_eq_mul_right H H'
|
||||
protected theorem tdiv_eq_iff_eq_mul_left {a b c : Int}
|
||||
(H : b ≠ 0) (H' : b ∣ a) : a.tdiv b = c ↔ a = c * b := by
|
||||
rw [Int.mul_comm]; exact Int.tdiv_eq_iff_eq_mul_right H H'
|
||||
|
||||
protected theorem eq_mul_of_div_eq_left {a b c : Int}
|
||||
(H1 : b ∣ a) (H2 : a.div b = c) : a = c * b := by
|
||||
rw [Int.mul_comm, Int.eq_mul_of_div_eq_right H1 H2]
|
||||
protected theorem eq_mul_of_tdiv_eq_left {a b c : Int}
|
||||
(H1 : b ∣ a) (H2 : a.tdiv b = c) : a = c * b := by
|
||||
rw [Int.mul_comm, Int.eq_mul_of_tdiv_eq_right H1 H2]
|
||||
|
||||
protected theorem div_eq_of_eq_mul_left {a b c : Int}
|
||||
(H1 : b ≠ 0) (H2 : a = c * b) : a.div b = c :=
|
||||
Int.div_eq_of_eq_mul_right H1 (by rw [Int.mul_comm, H2])
|
||||
protected theorem tdiv_eq_of_eq_mul_left {a b c : Int}
|
||||
(H1 : b ≠ 0) (H2 : a = c * b) : a.tdiv b = c :=
|
||||
Int.tdiv_eq_of_eq_mul_right H1 (by rw [Int.mul_comm, H2])
|
||||
|
||||
protected theorem eq_zero_of_div_eq_zero {d n : Int} (h : d ∣ n) (H : n.div d = 0) : n = 0 := by
|
||||
rw [← Int.mul_div_cancel' h, H, Int.mul_zero]
|
||||
protected theorem eq_zero_of_tdiv_eq_zero {d n : Int} (h : d ∣ n) (H : n.tdiv d = 0) : n = 0 := by
|
||||
rw [← Int.mul_tdiv_cancel' h, H, Int.mul_zero]
|
||||
|
||||
@[simp] protected theorem div_left_inj {a b d : Int}
|
||||
(hda : d ∣ a) (hdb : d ∣ b) : a.div d = b.div d ↔ a = b := by
|
||||
refine ⟨fun h => ?_, congrArg (div · d)⟩
|
||||
rw [← Int.mul_div_cancel' hda, ← Int.mul_div_cancel' hdb, h]
|
||||
@[simp] protected theorem tdiv_left_inj {a b d : Int}
|
||||
(hda : d ∣ a) (hdb : d ∣ b) : a.tdiv d = b.tdiv d ↔ a = b := by
|
||||
refine ⟨fun h => ?_, congrArg (tdiv · d)⟩
|
||||
rw [← Int.mul_tdiv_cancel' hda, ← Int.mul_tdiv_cancel' hdb, h]
|
||||
|
||||
theorem div_sign : ∀ a b, a.div (sign b) = a * sign b
|
||||
theorem tdiv_sign : ∀ a b, a.tdiv (sign b) = a * sign b
|
||||
| _, succ _ => by simp [sign, Int.mul_one]
|
||||
| _, 0 => by simp [sign, Int.mul_zero]
|
||||
| _, -[_+1] => by simp [sign, Int.mul_neg, Int.mul_one]
|
||||
|
||||
protected theorem sign_eq_div_abs (a : Int) : sign a = a.div (natAbs a) :=
|
||||
protected theorem sign_eq_tdiv_abs (a : Int) : sign a = a.tdiv (natAbs a) :=
|
||||
if az : a = 0 then by simp [az] else
|
||||
(Int.div_eq_of_eq_mul_left (ofNat_ne_zero.2 <| natAbs_ne_zero.2 az)
|
||||
(Int.tdiv_eq_of_eq_mul_left (ofNat_ne_zero.2 <| natAbs_ne_zero.2 az)
|
||||
(sign_mul_natAbs _).symm).symm
|
||||
|
||||
/-! ### fdiv -/
|
||||
@@ -1033,7 +1050,7 @@ theorem fmod_eq_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a.fmod b = a :=
|
||||
rw [fmod_eq_emod _ (Int.le_trans H1 (Int.le_of_lt H2)), emod_eq_of_lt H1 H2]
|
||||
|
||||
theorem fmod_nonneg {a b : Int} (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a.fmod b :=
|
||||
fmod_eq_mod ha hb ▸ mod_nonneg _ ha
|
||||
fmod_eq_tmod ha hb ▸ tmod_nonneg _ ha
|
||||
|
||||
theorem fmod_nonneg' (a : Int) {b : Int} (hb : 0 < b) : 0 ≤ a.fmod b :=
|
||||
fmod_eq_emod _ (Int.le_of_lt hb) ▸ emod_nonneg _ (Int.ne_of_lt hb).symm
|
||||
@@ -1053,10 +1070,10 @@ theorem fmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a.fmod b < b :=
|
||||
|
||||
/-! ### Theorems crossing div/mod versions -/
|
||||
|
||||
theorem div_eq_ediv_of_dvd {a b : Int} (h : b ∣ a) : a.div b = a / b := by
|
||||
theorem tdiv_eq_ediv_of_dvd {a b : Int} (h : b ∣ a) : a.tdiv b = a / b := by
|
||||
by_cases b0 : b = 0
|
||||
· simp [b0]
|
||||
· rw [Int.div_eq_iff_eq_mul_left b0 h, ← Int.ediv_eq_iff_eq_mul_left b0 h]
|
||||
· rw [Int.tdiv_eq_iff_eq_mul_left b0 h, ← Int.ediv_eq_iff_eq_mul_left b0 h]
|
||||
|
||||
theorem fdiv_eq_ediv_of_dvd : ∀ {a b : Int}, b ∣ a → a.fdiv b = a / b
|
||||
| _, b, ⟨c, rfl⟩ => by
|
||||
@@ -1268,3 +1285,65 @@ theorem bmod_natAbs_plus_one (x : Int) (w : 1 < x.natAbs) : bmod x (x.natAbs + 1
|
||||
all_goals decide
|
||||
· exact ofNat_nonneg x
|
||||
· exact succ_ofNat_pos (x + 1)
|
||||
|
||||
/-! ### Deprecations -/
|
||||
|
||||
@[deprecated Int.zero_tdiv (since := "2024-09-11")] protected abbrev zero_div := @Int.zero_tdiv
|
||||
@[deprecated Int.tdiv_zero (since := "2024-09-11")] protected abbrev div_zero := @Int.tdiv_zero
|
||||
@[deprecated tdiv_eq_ediv (since := "2024-09-11")] abbrev div_eq_ediv := @tdiv_eq_ediv
|
||||
@[deprecated fdiv_eq_tdiv (since := "2024-09-11")] abbrev fdiv_eq_div := @fdiv_eq_tdiv
|
||||
@[deprecated zero_tmod (since := "2024-09-11")] abbrev zero_mod := @zero_tmod
|
||||
@[deprecated tmod_zero (since := "2024-09-11")] abbrev mod_zero := @tmod_zero
|
||||
@[deprecated tmod_add_tdiv (since := "2024-09-11")] abbrev mod_add_div := @tmod_add_tdiv
|
||||
@[deprecated tdiv_add_tmod (since := "2024-09-11")] abbrev div_add_mod := @tdiv_add_tmod
|
||||
@[deprecated tmod_add_tdiv' (since := "2024-09-11")] abbrev mod_add_div' := @tmod_add_tdiv'
|
||||
@[deprecated tdiv_add_tmod' (since := "2024-09-11")] abbrev div_add_mod' := @tdiv_add_tmod'
|
||||
@[deprecated tmod_def (since := "2024-09-11")] abbrev mod_def := @tmod_def
|
||||
@[deprecated tmod_eq_emod (since := "2024-09-11")] abbrev mod_eq_emod := @tmod_eq_emod
|
||||
@[deprecated fmod_eq_tmod (since := "2024-09-11")] abbrev fmod_eq_mod := @fmod_eq_tmod
|
||||
@[deprecated Int.tdiv_one (since := "2024-09-11")] protected abbrev div_one := @Int.tdiv_one
|
||||
@[deprecated Int.tdiv_neg (since := "2024-09-11")] protected abbrev div_neg := @Int.tdiv_neg
|
||||
@[deprecated Int.neg_tdiv (since := "2024-09-11")] protected abbrev neg_div := @Int.neg_tdiv
|
||||
@[deprecated Int.neg_tdiv_neg (since := "2024-09-11")] protected abbrev neg_div_neg := @Int.neg_tdiv_neg
|
||||
@[deprecated Int.tdiv_nonneg (since := "2024-09-11")] protected abbrev div_nonneg := @Int.tdiv_nonneg
|
||||
@[deprecated Int.tdiv_nonpos (since := "2024-09-11")] protected abbrev div_nonpos := @Int.tdiv_nonpos
|
||||
@[deprecated Int.tdiv_eq_zero_of_lt (since := "2024-09-11")] abbrev div_eq_zero_of_lt := @Int.tdiv_eq_zero_of_lt
|
||||
@[deprecated Int.mul_tdiv_cancel (since := "2024-09-11")] protected abbrev mul_div_cancel := @Int.mul_tdiv_cancel
|
||||
@[deprecated Int.mul_tdiv_cancel_left (since := "2024-09-11")] protected abbrev mul_div_cancel_left := @Int.mul_tdiv_cancel_left
|
||||
@[deprecated Int.tdiv_self (since := "2024-09-11")] protected abbrev div_self := @Int.tdiv_self
|
||||
@[deprecated Int.mul_tdiv_cancel_of_tmod_eq_zero (since := "2024-09-11")] abbrev mul_div_cancel_of_mod_eq_zero := @Int.mul_tdiv_cancel_of_tmod_eq_zero
|
||||
@[deprecated Int.tdiv_mul_cancel_of_tmod_eq_zero (since := "2024-09-11")] abbrev div_mul_cancel_of_mod_eq_zero := @Int.tdiv_mul_cancel_of_tmod_eq_zero
|
||||
@[deprecated Int.dvd_of_tmod_eq_zero (since := "2024-09-11")] abbrev dvd_of_mod_eq_zero := @Int.dvd_of_tmod_eq_zero
|
||||
@[deprecated Int.mul_tdiv_assoc (since := "2024-09-11")] protected abbrev mul_div_assoc := @Int.mul_tdiv_assoc
|
||||
@[deprecated Int.mul_tdiv_assoc' (since := "2024-09-11")] protected abbrev mul_div_assoc' := @Int.mul_tdiv_assoc'
|
||||
@[deprecated Int.tdiv_dvd_tdiv (since := "2024-09-11")] abbrev div_dvd_div := @Int.tdiv_dvd_tdiv
|
||||
@[deprecated Int.natAbs_tdiv (since := "2024-09-11")] abbrev natAbs_div := @Int.natAbs_tdiv
|
||||
@[deprecated Int.tdiv_eq_of_eq_mul_right (since := "2024-09-11")] protected abbrev div_eq_of_eq_mul_right := @Int.tdiv_eq_of_eq_mul_right
|
||||
@[deprecated Int.eq_tdiv_of_mul_eq_right (since := "2024-09-11")] protected abbrev eq_div_of_mul_eq_right := @Int.eq_tdiv_of_mul_eq_right
|
||||
@[deprecated Int.ofNat_tmod (since := "2024-09-11")] abbrev ofNat_mod := @Int.ofNat_tmod
|
||||
@[deprecated Int.tmod_one (since := "2024-09-11")] abbrev mod_one := @Int.tmod_one
|
||||
@[deprecated Int.tmod_eq_of_lt (since := "2024-09-11")] abbrev mod_eq_of_lt := @Int.tmod_eq_of_lt
|
||||
@[deprecated Int.tmod_lt_of_pos (since := "2024-09-11")] abbrev mod_lt_of_pos := @Int.tmod_lt_of_pos
|
||||
@[deprecated Int.tmod_nonneg (since := "2024-09-11")] abbrev mod_nonneg := @Int.tmod_nonneg
|
||||
@[deprecated Int.tmod_neg (since := "2024-09-11")] abbrev mod_neg := @Int.tmod_neg
|
||||
@[deprecated Int.mul_tmod_left (since := "2024-09-11")] abbrev mul_mod_left := @Int.mul_tmod_left
|
||||
@[deprecated Int.mul_tmod_right (since := "2024-09-11")] abbrev mul_mod_right := @Int.mul_tmod_right
|
||||
@[deprecated Int.tmod_eq_zero_of_dvd (since := "2024-09-11")] abbrev mod_eq_zero_of_dvd := @Int.tmod_eq_zero_of_dvd
|
||||
@[deprecated Int.dvd_iff_tmod_eq_zero (since := "2024-09-11")] abbrev dvd_iff_mod_eq_zero := @Int.dvd_iff_tmod_eq_zero
|
||||
@[deprecated Int.neg_mul_tmod_right (since := "2024-09-11")] abbrev neg_mul_mod_right := @Int.neg_mul_tmod_right
|
||||
@[deprecated Int.neg_mul_tmod_left (since := "2024-09-11")] abbrev neg_mul_mod_left := @Int.neg_mul_tmod_left
|
||||
@[deprecated Int.tdiv_mul_cancel (since := "2024-09-11")] protected abbrev div_mul_cancel := @Int.tdiv_mul_cancel
|
||||
@[deprecated Int.mul_tdiv_cancel' (since := "2024-09-11")] protected abbrev mul_div_cancel' := @Int.mul_tdiv_cancel'
|
||||
@[deprecated Int.eq_mul_of_tdiv_eq_right (since := "2024-09-11")] protected abbrev eq_mul_of_div_eq_right := @Int.eq_mul_of_tdiv_eq_right
|
||||
@[deprecated Int.tmod_self (since := "2024-09-11")] abbrev mod_self := @Int.tmod_self
|
||||
@[deprecated Int.neg_tmod_self (since := "2024-09-11")] abbrev neg_mod_self := @Int.neg_tmod_self
|
||||
@[deprecated Int.lt_tdiv_add_one_mul_self (since := "2024-09-11")] abbrev lt_div_add_one_mul_self := @Int.lt_tdiv_add_one_mul_self
|
||||
@[deprecated Int.tdiv_eq_iff_eq_mul_right (since := "2024-09-11")] protected abbrev div_eq_iff_eq_mul_right := @Int.tdiv_eq_iff_eq_mul_right
|
||||
@[deprecated Int.tdiv_eq_iff_eq_mul_left (since := "2024-09-11")] protected abbrev div_eq_iff_eq_mul_left := @Int.tdiv_eq_iff_eq_mul_left
|
||||
@[deprecated Int.eq_mul_of_tdiv_eq_left (since := "2024-09-11")] protected abbrev eq_mul_of_div_eq_left := @Int.eq_mul_of_tdiv_eq_left
|
||||
@[deprecated Int.tdiv_eq_of_eq_mul_left (since := "2024-09-11")] protected abbrev div_eq_of_eq_mul_left := @Int.tdiv_eq_of_eq_mul_left
|
||||
@[deprecated Int.eq_zero_of_tdiv_eq_zero (since := "2024-09-11")] protected abbrev eq_zero_of_div_eq_zero := @Int.eq_zero_of_tdiv_eq_zero
|
||||
@[deprecated Int.tdiv_left_inj (since := "2024-09-11")] protected abbrev div_left_inj := @Int.tdiv_left_inj
|
||||
@[deprecated Int.tdiv_sign (since := "2024-09-11")] abbrev div_sign := @Int.tdiv_sign
|
||||
@[deprecated Int.sign_eq_tdiv_abs (since := "2024-09-11")] protected abbrev sign_eq_div_abs := @Int.sign_eq_tdiv_abs
|
||||
@[deprecated Int.tdiv_eq_ediv_of_dvd (since := "2024-09-11")] abbrev div_eq_ediv_of_dvd := @Int.tdiv_eq_ediv_of_dvd
|
||||
|
||||
@@ -48,6 +48,8 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
|
||||
|
||||
@[simp] theorem attach_nil : ([] : List α).attach = [] := rfl
|
||||
|
||||
@[simp] theorem attachWith_nil : ([] : List α).attachWith P H = [] := rfl
|
||||
|
||||
@[simp]
|
||||
theorem pmap_eq_map (p : α → Prop) (f : α → β) (l : List α) (H) :
|
||||
@pmap _ _ p (fun a _ => f a) l H = map f l := by
|
||||
@@ -81,7 +83,12 @@ theorem attach_congr {l₁ l₂ : List α} (h : l₁ = l₂) :
|
||||
subst h
|
||||
simp
|
||||
|
||||
@[simp] theorem attach_cons (x : α) (xs : List α) :
|
||||
theorem attachWith_congr {l₁ l₂ : List α} (w : l₁ = l₂) {P : α → Prop} {H : ∀ x ∈ l₁, P x} :
|
||||
l₁.attachWith P H = l₂.attachWith P fun x h => H _ (w ▸ h) := by
|
||||
subst w
|
||||
simp
|
||||
|
||||
@[simp] theorem attach_cons {x : α} {xs : List α} :
|
||||
(x :: xs).attach =
|
||||
⟨x, mem_cons_self x xs⟩ :: xs.attach.map fun ⟨y, h⟩ => ⟨y, mem_cons_of_mem x h⟩ := by
|
||||
simp only [attach, attachWith, pmap, map_pmap, cons.injEq, true_and]
|
||||
@@ -89,6 +96,12 @@ theorem attach_congr {l₁ l₂ : List α} (h : l₁ = l₂) :
|
||||
intros a _ m' _
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem attachWith_cons {x : α} {xs : List α} {p : α → Prop} (h : ∀ a ∈ x :: xs, p a) :
|
||||
(x :: xs).attachWith p h = ⟨x, h x (mem_cons_self x xs)⟩ ::
|
||||
xs.attachWith p (fun a ha ↦ h a (mem_cons_of_mem x ha)) :=
|
||||
rfl
|
||||
|
||||
theorem pmap_eq_map_attach {p : α → Prop} (f : ∀ a, p a → β) (l H) :
|
||||
pmap f l H = l.attach.map fun x => f x.1 (H _ x.2) := by
|
||||
rw [attach, attachWith, map_pmap]; exact pmap_congr_left l fun _ _ _ _ => rfl
|
||||
@@ -104,15 +117,37 @@ theorem attach_map_val (l : List α) (f : α → β) : (l.attach.map fun i => f
|
||||
theorem attach_map_subtype_val (l : List α) : l.attach.map Subtype.val = l :=
|
||||
(attach_map_coe _ _).trans (List.map_id _)
|
||||
|
||||
theorem attachWith_map_coe {p : α → Prop} (f : α → β) (l : List α) (H : ∀ a ∈ l, p a) :
|
||||
((l.attachWith p H).map fun (i : { i // p i}) => f i) = l.map f := by
|
||||
rw [attachWith, map_pmap]; exact pmap_eq_map _ _ _ _
|
||||
|
||||
theorem attachWith_map_val {p : α → Prop} (f : α → β) (l : List α) (H : ∀ a ∈ l, p a) :
|
||||
((l.attachWith p H).map fun i => f i.val) = l.map f :=
|
||||
attachWith_map_coe _ _ _
|
||||
|
||||
@[simp]
|
||||
theorem attachWith_map_subtype_val {p : α → Prop} (l : List α) (H : ∀ a ∈ l, p a) :
|
||||
(l.attachWith p H).map Subtype.val = l :=
|
||||
(attachWith_map_coe _ _ _).trans (List.map_id _)
|
||||
|
||||
theorem countP_attach (l : List α) (p : α → Bool) :
|
||||
l.attach.countP (fun a : {x // x ∈ l} => p a) = l.countP p := by
|
||||
simp only [← Function.comp_apply (g := Subtype.val), ← countP_map, attach_map_subtype_val]
|
||||
|
||||
theorem countP_attachWith {p : α → Prop} (l : List α) (H : ∀ a ∈ l, p a) (q : α → Bool) :
|
||||
(l.attachWith p H).countP (fun a : {x // p x} => q a) = l.countP q := by
|
||||
simp only [← Function.comp_apply (g := Subtype.val), ← countP_map, attachWith_map_subtype_val]
|
||||
|
||||
@[simp]
|
||||
theorem count_attach [DecidableEq α] (l : List α) (a : {x // x ∈ l}) :
|
||||
l.attach.count a = l.count ↑a :=
|
||||
Eq.trans (countP_congr fun _ _ => by simp [Subtype.ext_iff]) <| countP_attach _ _
|
||||
|
||||
@[simp]
|
||||
theorem count_attachWith [DecidableEq α] {p : α → Prop} (l : List α) (H : ∀ a ∈ l, p a) (a : {x // p x}) :
|
||||
(l.attachWith p H).count a = l.count ↑a :=
|
||||
Eq.trans (countP_congr fun _ _ => by simp [Subtype.ext_iff]) <| countP_attachWith _ _ _
|
||||
|
||||
@[simp]
|
||||
theorem mem_attach (l : List α) : ∀ x, x ∈ l.attach
|
||||
| ⟨a, h⟩ => by
|
||||
@@ -137,7 +172,11 @@ theorem length_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H} : length (pm
|
||||
· simp only [*, pmap, length]
|
||||
|
||||
@[simp]
|
||||
theorem length_attach (L : List α) : L.attach.length = L.length :=
|
||||
theorem length_attach {L : List α} : L.attach.length = L.length :=
|
||||
length_pmap
|
||||
|
||||
@[simp]
|
||||
theorem length_attachWith {p : α → Prop} {l H} : length (l.attachWith p H) = length l :=
|
||||
length_pmap
|
||||
|
||||
@[simp]
|
||||
@@ -155,6 +194,15 @@ theorem attach_eq_nil_iff {l : List α} : l.attach = [] ↔ l = [] :=
|
||||
theorem attach_ne_nil_iff {l : List α} : l.attach ≠ [] ↔ l ≠ [] :=
|
||||
pmap_ne_nil_iff _ _
|
||||
|
||||
@[simp]
|
||||
theorem attachWith_eq_nil_iff {l : List α} {P : α → Prop} {H : ∀ a ∈ l, P a} :
|
||||
l.attachWith P H = [] ↔ l = [] :=
|
||||
pmap_eq_nil_iff
|
||||
|
||||
theorem attachWith_ne_nil_iff {l : List α} {P : α → Prop} {H : ∀ a ∈ l, P a} :
|
||||
l.attachWith P H ≠ [] ↔ l ≠ [] :=
|
||||
pmap_ne_nil_iff _ _
|
||||
|
||||
@[deprecated pmap_eq_nil_iff (since := "2024-09-06")] abbrev pmap_eq_nil := @pmap_eq_nil_iff
|
||||
@[deprecated pmap_ne_nil_iff (since := "2024-09-06")] abbrev pmap_ne_nil := @pmap_ne_nil_iff
|
||||
@[deprecated attach_eq_nil_iff (since := "2024-09-06")] abbrev attach_eq_nil := @attach_eq_nil_iff
|
||||
@@ -187,7 +235,7 @@ theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h
|
||||
(hn : n < (pmap f l h).length) :
|
||||
(pmap f l h)[n] =
|
||||
f (l[n]'(@length_pmap _ _ p f l h ▸ hn))
|
||||
(h _ (getElem_mem l n (@length_pmap _ _ p f l h ▸ hn))) := by
|
||||
(h _ (getElem_mem (@length_pmap _ _ p f l h ▸ hn))) := by
|
||||
induction l generalizing n with
|
||||
| nil =>
|
||||
simp only [length, pmap] at hn
|
||||
@@ -205,34 +253,26 @@ theorem get_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h :
|
||||
simp only [get_eq_getElem]
|
||||
simp [getElem_pmap]
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_attachWith {xs : List α} {i : Nat} {P : α → Prop} {H : ∀ a ∈ xs, P a} :
|
||||
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (getElem?_mem a)) :=
|
||||
getElem?_pmap ..
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_attach {xs : List α} {i : Nat} :
|
||||
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => getElem?_mem a) := by
|
||||
induction xs generalizing i with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
rcases i with ⟨i⟩
|
||||
· simp only [attach_cons, Option.pmap]
|
||||
split <;> simp_all
|
||||
· simp only [attach_cons, getElem?_cons_succ, getElem?_map, ih]
|
||||
simp only [Option.pmap]
|
||||
split <;> split <;> simp_all
|
||||
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => getElem?_mem a) :=
|
||||
getElem?_attachWith
|
||||
|
||||
@[simp]
|
||||
theorem getElem_attachWith {xs : List α} {P : α → Prop} {H : ∀ a ∈ xs, P a}
|
||||
{i : Nat} (h : i < (xs.attachWith P H).length) :
|
||||
(xs.attachWith P H)[i] = ⟨xs[i]'(by simpa using h), H _ (getElem_mem (by simpa using h))⟩ :=
|
||||
getElem_pmap ..
|
||||
|
||||
@[simp]
|
||||
theorem getElem_attach {xs : List α} {i : Nat} (h : i < xs.attach.length) :
|
||||
xs.attach[i] = ⟨xs[i]'(by simpa using h), getElem_mem xs i (by simpa using h)⟩ := by
|
||||
apply Option.some.inj
|
||||
rw [← getElem?_eq_getElem]
|
||||
rw [getElem?_attach]
|
||||
simp only [Option.pmap]
|
||||
split <;> rename_i h' _
|
||||
· simp at h
|
||||
simp at h'
|
||||
exfalso
|
||||
exact Nat.lt_irrefl _ (Nat.lt_of_le_of_lt h' h)
|
||||
· simp only [Option.some.injEq, Subtype.mk.injEq]
|
||||
apply Option.some.inj
|
||||
rw [← getElem?_eq_getElem, h']
|
||||
xs.attach[i] = ⟨xs[i]'(by simpa using h), getElem_mem (by simpa using h)⟩ :=
|
||||
getElem_attachWith h
|
||||
|
||||
@[simp] theorem head?_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
@@ -250,11 +290,23 @@ theorem getElem_attach {xs : List α} {i : Nat} (h : i < xs.attach.length) :
|
||||
| nil => simp at h
|
||||
| cons x xs ih => simp [head_pmap, ih]
|
||||
|
||||
@[simp] theorem head?_attachWith {P : α → Prop} {xs : List α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.attachWith P H).head? = xs.head?.pbind (fun a h => some ⟨a, H _ (mem_of_mem_head? h)⟩) := by
|
||||
cases xs <;> simp_all
|
||||
|
||||
@[simp] theorem head_attachWith {P : α → Prop} {xs : List α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} (h : xs.attachWith P H ≠ []) :
|
||||
(xs.attachWith P H).head h = ⟨xs.head (by simpa using h), H _ (head_mem _)⟩ := by
|
||||
cases xs with
|
||||
| nil => simp at h
|
||||
| cons x xs => simp [head_attachWith, h]
|
||||
|
||||
@[simp] theorem head?_attach (xs : List α) :
|
||||
xs.attach.head? = xs.head?.pbind (fun a h => some ⟨a, mem_of_mem_head? h⟩) := by
|
||||
cases xs <;> simp_all
|
||||
|
||||
theorem head_attach {xs : List α} (h) :
|
||||
@[simp] theorem head_attach {xs : List α} (h) :
|
||||
xs.attach.head h = ⟨xs.head (by simpa using h), head_mem (by simpa using h)⟩ := by
|
||||
cases xs with
|
||||
| nil => simp at h
|
||||
@@ -264,6 +316,32 @@ theorem attach_map {l : List α} (f : α → β) :
|
||||
(l.map f).attach = l.attach.map (fun ⟨x, h⟩ => ⟨f x, mem_map_of_mem f h⟩) := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
theorem attachWith_map {l : List α} (f : α → β) {P : β → Prop} {H : ∀ (b : β), b ∈ l.map f → P b} :
|
||||
(l.map f).attachWith P H = (l.attachWith (P ∘ f) (fun a h => H _ (mem_map_of_mem f h))).map
|
||||
fun ⟨x, h⟩ => ⟨f x, h⟩ := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
theorem map_attachWith {l : List α} {P : α → Prop} {H : ∀ (a : α), a ∈ l → P a}
|
||||
(f : { x // P x } → β) :
|
||||
(l.attachWith P H).map f =
|
||||
l.pmap (fun a (h : a ∈ l ∧ P a) => f ⟨a, H _ h.1⟩) (fun a h => ⟨h, H a h⟩) := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons x xs ih =>
|
||||
simp only [attachWith_cons, map_cons, ih, pmap, cons.injEq, true_and]
|
||||
apply pmap_congr_left
|
||||
simp
|
||||
|
||||
/-- See also `pmap_eq_map_attach` for writing `pmap` in terms of `map` and `attach`. -/
|
||||
theorem map_attach {l : List α} (f : { x // x ∈ l } → β) :
|
||||
l.attach.map f = l.pmap (fun a h => f ⟨a, h⟩) (fun _ => id) := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons x xs ih =>
|
||||
simp only [attach_cons, map_cons, map_map, Function.comp_apply, pmap, cons.injEq, true_and, ih]
|
||||
apply pmap_congr_left
|
||||
simp
|
||||
|
||||
theorem attach_filterMap {l : List α} {f : α → Option β} :
|
||||
(l.filterMap f).attach = l.attach.filterMap
|
||||
fun ⟨x, h⟩ => (f x).pbind (fun b m => some ⟨b, mem_filterMap.mpr ⟨x, h, m⟩⟩) := by
|
||||
@@ -304,6 +382,9 @@ theorem attach_filter {l : List α} (p : α → Bool) :
|
||||
ext1
|
||||
split <;> simp
|
||||
|
||||
-- We are still missing here `attachWith_filterMap` and `attachWith_filter`.
|
||||
-- Also missing are `filterMap_attach`, `filter_attach`, `filterMap_attachWith` and `filter_attachWith`.
|
||||
|
||||
theorem pmap_pmap {p : α → Prop} {q : β → Prop} (g : ∀ a, p a → β) (f : ∀ b, q b → γ) (l H₁ H₂) :
|
||||
pmap f (pmap g l H₁) H₂ =
|
||||
pmap (α := { x // x ∈ l }) (fun a h => f (g a h) (H₂ (g a h) (mem_pmap_of_mem a.2))) l.attach
|
||||
@@ -334,6 +415,12 @@ theorem pmap_append' {p : α → Prop} (f : ∀ a : α, p a → β) (l₁ l₂ :
|
||||
congr 1 <;>
|
||||
exact pmap_congr_left _ fun _ _ _ _ => rfl
|
||||
|
||||
@[simp] theorem attachWith_append {P : α → Prop} {xs ys : List α}
|
||||
{H : ∀ (a : α), a ∈ xs ++ ys → P a} :
|
||||
(xs ++ ys).attachWith P H = xs.attachWith P (fun a h => H a (mem_append_of_mem_left ys h)) ++
|
||||
ys.attachWith P (fun a h => H a (mem_append_of_mem_right xs h)) := by
|
||||
simp only [attachWith, attach_append, map_pmap, pmap_append]
|
||||
|
||||
@[simp] theorem pmap_reverse {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||
(H : ∀ (a : α), a ∈ xs.reverse → P a) :
|
||||
xs.reverse.pmap f H = (xs.pmap f (fun a h => H a (by simpa using h))).reverse := by
|
||||
@@ -344,6 +431,17 @@ theorem reverse_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : List
|
||||
(xs.pmap f H).reverse = xs.reverse.pmap f (fun a h => H a (by simpa using h)) := by
|
||||
rw [pmap_reverse]
|
||||
|
||||
@[simp] theorem attachWith_reverse {P : α → Prop} {xs : List α}
|
||||
{H : ∀ (a : α), a ∈ xs.reverse → P a} :
|
||||
xs.reverse.attachWith P H =
|
||||
(xs.attachWith P (fun a h => H a (by simpa using h))).reverse :=
|
||||
pmap_reverse ..
|
||||
|
||||
theorem reverse_attachWith {P : α → Prop} {xs : List α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).reverse = (xs.reverse.attachWith P (fun a h => H a (by simpa using h))) :=
|
||||
reverse_pmap ..
|
||||
|
||||
@[simp] theorem attach_reverse (xs : List α) :
|
||||
xs.reverse.attach = xs.attach.reverse.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
simp only [attach, attachWith, reverse_pmap, map_pmap]
|
||||
@@ -358,17 +456,6 @@ theorem reverse_attach (xs : List α) :
|
||||
intros
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem getLast?_attach {xs : List α} :
|
||||
xs.attach.getLast? = xs.getLast?.pbind fun a h => some ⟨a, mem_of_getLast?_eq_some h⟩ := by
|
||||
rw [getLast?_eq_head?_reverse, reverse_attach, head?_map, head?_attach]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem getLast_attach {xs : List α} (h : xs.attach ≠ []) :
|
||||
xs.attach.getLast h = ⟨xs.getLast (by simpa using h), getLast_mem (by simpa using h)⟩ := by
|
||||
simp only [getLast_eq_head_reverse, reverse_attach, head_map, head_attach]
|
||||
|
||||
@[simp] theorem getLast?_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).getLast? = xs.attach.getLast?.map fun ⟨a, m⟩ => f a (H a m) := by
|
||||
@@ -383,4 +470,26 @@ theorem getLast_attach {xs : List α} (h : xs.attach ≠ []) :
|
||||
simp only [getLast_eq_head_reverse]
|
||||
simp only [reverse_pmap, head_pmap, head_reverse]
|
||||
|
||||
@[simp] theorem getLast?_attachWith {P : α → Prop} {xs : List α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).getLast? = xs.getLast?.pbind (fun a h => some ⟨a, H _ (mem_of_getLast?_eq_some h)⟩) := by
|
||||
rw [getLast?_eq_head?_reverse, reverse_attachWith, head?_attachWith]
|
||||
simp
|
||||
|
||||
@[simp] theorem getLast_attachWith {P : α → Prop} {xs : List α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} (h : xs.attachWith P H ≠ []) :
|
||||
(xs.attachWith P H).getLast h = ⟨xs.getLast (by simpa using h), H _ (getLast_mem _)⟩ := by
|
||||
simp only [getLast_eq_head_reverse, reverse_attachWith, head_attachWith, head_map]
|
||||
|
||||
@[simp]
|
||||
theorem getLast?_attach {xs : List α} :
|
||||
xs.attach.getLast? = xs.getLast?.pbind fun a h => some ⟨a, mem_of_getLast?_eq_some h⟩ := by
|
||||
rw [getLast?_eq_head?_reverse, reverse_attach, head?_map, head?_attach]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem getLast_attach {xs : List α} (h : xs.attach ≠ []) :
|
||||
xs.attach.getLast h = ⟨xs.getLast (by simpa using h), getLast_mem (by simpa using h)⟩ := by
|
||||
simp only [getLast_eq_head_reverse, reverse_attach, head_map, head_attach]
|
||||
|
||||
end List
|
||||
|
||||
@@ -1588,6 +1588,14 @@ such that adjacent elements are related by `R`.
|
||||
| [] => []
|
||||
| a::as => loop as a [] []
|
||||
where
|
||||
/--
|
||||
The arguments of `groupBy.loop l ag g gs` represent the following:
|
||||
|
||||
- `l : List α` are the elements which we still need to group.
|
||||
- `ag : α` is the previous element for which a comparison was performed.
|
||||
- `g : List α` is the group currently being assembled, in **reverse order**.
|
||||
- `gs : List (List α)` is all of the groups that have been completed, in **reverse order**.
|
||||
-/
|
||||
@[specialize] loop : List α → α → List α → List (List α) → List (List α)
|
||||
| a::as, ag, g, gs => match R ag a with
|
||||
| true => loop as a (ag::g) gs
|
||||
|
||||
@@ -155,7 +155,7 @@ def mapMono (as : List α) (f : α → α) : List α :=
|
||||
|
||||
/-! ## Additional lemmas required for bootstrapping `Array`. -/
|
||||
|
||||
theorem getElem_append_left (as bs : List α) (h : i < as.length) {h'} : (as ++ bs)[i] = as[i] := by
|
||||
theorem getElem_append_left {as bs : List α} (h : i < as.length) {h'} : (as ++ bs)[i] = as[i] := by
|
||||
induction as generalizing i with
|
||||
| nil => trivial
|
||||
| cons a as ih =>
|
||||
@@ -163,12 +163,14 @@ theorem getElem_append_left (as bs : List α) (h : i < as.length) {h'} : (as ++
|
||||
| zero => rfl
|
||||
| succ i => apply ih
|
||||
|
||||
theorem getElem_append_right (as bs : List α) (h : ¬ i < as.length) {h' h''} : (as ++ bs)[i]'h' = bs[i - as.length]'h'' := by
|
||||
theorem getElem_append_right {as bs : List α} {i : Nat} (h₁ : as.length ≤ i) {h₂} :
|
||||
(as ++ bs)[i]'h₂ =
|
||||
bs[i - as.length]'(by rw [length_append] at h₂; exact Nat.sub_lt_left_of_lt_add h₁ h₂) := by
|
||||
induction as generalizing i with
|
||||
| nil => trivial
|
||||
| cons a as ih =>
|
||||
cases i with simp [get, Nat.succ_sub_succ] <;> simp [Nat.succ_sub_succ] at h
|
||||
| succ i => apply ih; simp [h]
|
||||
cases i with simp [get, Nat.succ_sub_succ] <;> simp [Nat.succ_sub_succ] at h₁
|
||||
| succ i => apply ih; simp [h₁]
|
||||
|
||||
theorem get_last {as : List α} {i : Fin (length (as ++ [a]))} (h : ¬ i.1 < as.length) : (as ++ [a] : List _).get i = a := by
|
||||
cases i; rename_i i h'
|
||||
|
||||
@@ -119,12 +119,12 @@ 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] theorem countP_true : (countP fun (_ : α) => true) = length := by
|
||||
funext l
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_false {l : List α} : (l.countP fun _ => false) = 0 := by
|
||||
rw [countP_eq_zero]
|
||||
@[simp] theorem countP_false : (countP fun (_ : α) => false) = Function.const _ 0 := by
|
||||
funext l
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_map (p : β → Bool) (f : α → β) :
|
||||
|
||||
@@ -539,7 +539,7 @@ theorem findIdx_lt_length {p : α → Bool} {xs : List α} :
|
||||
|
||||
/-- `p` does not hold for elements with indices less than `xs.findIdx p`. -/
|
||||
theorem not_of_lt_findIdx {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs.findIdx p) :
|
||||
¬p (xs[i]'(Nat.le_trans h (findIdx_le_length p))) := by
|
||||
p (xs[i]'(Nat.le_trans h (findIdx_le_length p))) = false := by
|
||||
revert i
|
||||
induction xs with
|
||||
| nil => intro i h; rw [findIdx_nil] at h; simp at h
|
||||
@@ -547,10 +547,14 @@ theorem not_of_lt_findIdx {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs
|
||||
intro i h
|
||||
have ho := h
|
||||
rw [findIdx_cons] at h
|
||||
have npx : ¬p x := by intro y; rw [y, cond_true] at h; simp at h
|
||||
have npx : p x = false := by
|
||||
apply eq_false_of_ne_true
|
||||
intro y
|
||||
rw [y, cond_true] at h
|
||||
simp at h
|
||||
simp [npx, cond_false] at h
|
||||
cases i.eq_zero_or_pos with
|
||||
| inl e => simpa only [e, Fin.zero_eta, get_cons_zero]
|
||||
| inl e => simpa [e, Fin.zero_eta, get_cons_zero]
|
||||
| inr e =>
|
||||
have ipm := Nat.succ_pred_eq_of_pos e
|
||||
have ilt := Nat.le_trans ho (findIdx_le_length p)
|
||||
@@ -560,11 +564,11 @@ theorem not_of_lt_findIdx {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs
|
||||
|
||||
/-- If `¬ p xs[j]` for all `j < i`, then `i ≤ xs.findIdx p`. -/
|
||||
theorem le_findIdx_of_not {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs.length)
|
||||
(h2 : ∀ j (hji : j < i), ¬p (xs[j]'(Nat.lt_trans hji h))) : i ≤ xs.findIdx p := by
|
||||
(h2 : ∀ j (hji : j < i), p (xs[j]'(Nat.lt_trans hji h)) = false) : i ≤ xs.findIdx p := by
|
||||
apply Decidable.byContradiction
|
||||
intro f
|
||||
simp only [Nat.not_le] at f
|
||||
exact absurd (@findIdx_getElem _ p xs (Nat.lt_trans f h)) (h2 (xs.findIdx p) f)
|
||||
exact absurd (@findIdx_getElem _ p xs (Nat.lt_trans f h)) (by simpa using h2 (xs.findIdx p) f)
|
||||
|
||||
/-- If `¬ p xs[j]` for all `j ≤ i`, then `i < xs.findIdx p`. -/
|
||||
theorem lt_findIdx_of_not {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs.length)
|
||||
@@ -576,19 +580,18 @@ theorem lt_findIdx_of_not {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs
|
||||
|
||||
/-- `xs.findIdx p = i` iff `p xs[i]` and `¬ p xs [j]` for all `j < i`. -/
|
||||
theorem findIdx_eq {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs.length) :
|
||||
xs.findIdx p = i ↔ p xs[i] ∧ ∀ j (hji : j < i), ¬p (xs[j]'(Nat.lt_trans hji h)) := by
|
||||
xs.findIdx p = i ↔ p xs[i] ∧ ∀ j (hji : j < i), p (xs[j]'(Nat.lt_trans hji h)) = false := by
|
||||
refine ⟨fun f ↦ ⟨f ▸ (@findIdx_getElem _ p xs (f ▸ h)), fun _ hji ↦ not_of_lt_findIdx (f ▸ hji)⟩,
|
||||
fun ⟨h1, h2⟩ ↦ ?_⟩
|
||||
fun ⟨_, h2⟩ ↦ ?_⟩
|
||||
apply Nat.le_antisymm _ (le_findIdx_of_not h h2)
|
||||
apply Decidable.byContradiction
|
||||
intro h3
|
||||
simp at h3
|
||||
exact not_of_lt_findIdx h3 h1
|
||||
simp_all [not_of_lt_findIdx h3]
|
||||
|
||||
theorem findIdx_append (p : α → Bool) (l₁ l₂ : List α) :
|
||||
(l₁ ++ l₂).findIdx p =
|
||||
if l₁.findIdx p < l₁.length then l₁.findIdx p else l₂.findIdx p + l₁.length := by
|
||||
simp
|
||||
if ∃ x, x ∈ l₁ ∧ p x = true then l₁.findIdx p else l₂.findIdx p + l₁.length := by
|
||||
induction l₁ with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
@@ -624,11 +627,24 @@ theorem IsPrefix.findIdx_eq_of_findIdx_lt_length {l₁ l₂ : List α} {p : α
|
||||
@[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 :
|
||||
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
|
||||
|
||||
@[simp] theorem findIdx?_start_succ :
|
||||
(xs : List α).findIdx? p (i+1) = (xs.findIdx? p 0).map fun k => k + (i + 1) := by
|
||||
induction xs generalizing i with
|
||||
| nil => simp
|
||||
| cons _ _ _ =>
|
||||
simp only [findIdx?_succ, findIdx?_cons, Nat.zero_add]
|
||||
split
|
||||
· simp_all
|
||||
· simp_all only [findIdx?_succ, Bool.not_eq_true, Option.map_map, Nat.zero_add]
|
||||
congr
|
||||
ext
|
||||
simp only [Nat.add_comm i, Function.comp_apply, Nat.add_assoc]
|
||||
|
||||
@[simp]
|
||||
theorem findIdx?_eq_none_iff {xs : List α} {p : α → Bool} :
|
||||
xs.findIdx? p = none ↔ ∀ x, x ∈ xs → p x = false := by
|
||||
@@ -680,6 +696,16 @@ theorem findIdx?_eq_none_iff_findIdx_eq {xs : List α} {p : α → Bool} :
|
||||
xs.findIdx? p = none ↔ xs.findIdx p = xs.length := by
|
||||
simp
|
||||
|
||||
theorem findIdx?_eq_guard_findIdx_lt {xs : List α} {p : α → Bool} :
|
||||
xs.findIdx? p = Option.guard (fun i => i < xs.length) (xs.findIdx p) := by
|
||||
match h : xs.findIdx? p with
|
||||
| none =>
|
||||
simp only [findIdx?_eq_none_iff] at h
|
||||
simp [findIdx_eq_length_of_false h, Option.guard]
|
||||
| some i =>
|
||||
simp only [findIdx?_eq_some_iff_findIdx_eq] at h
|
||||
simp [h]
|
||||
|
||||
theorem findIdx?_eq_some_iff_getElem {xs : List α} {p : α → Bool} {i : Nat} :
|
||||
xs.findIdx? p = some i ↔
|
||||
∃ h : i < xs.length, p xs[i] ∧ ∀ j (hji : j < i), ¬p (xs[j]'(Nat.lt_trans hji h)) := by
|
||||
|
||||
@@ -57,8 +57,8 @@ The following operations are given `@[csimp]` replacements below:
|
||||
|
||||
@[csimp] theorem set_eq_setTR : @set = @setTR := by
|
||||
funext α l n a; simp [setTR]
|
||||
let rec go (acc) : ∀ xs n, l = acc.data ++ xs →
|
||||
setTR.go l a xs n acc = acc.data ++ xs.set n a
|
||||
let rec go (acc) : ∀ xs n, l = acc.toList ++ xs →
|
||||
setTR.go l a xs n acc = acc.toList ++ xs.set n a
|
||||
| [], _ => fun h => by simp [setTR.go, set, h]
|
||||
| x::xs, 0 => by simp [setTR.go, set]
|
||||
| x::xs, n+1 => fun h => by simp only [setTR.go, set]; rw [go _ xs] <;> simp [h]
|
||||
@@ -77,10 +77,11 @@ The following operations are given `@[csimp]` replacements below:
|
||||
|
||||
@[csimp] theorem filterMap_eq_filterMapTR : @List.filterMap = @filterMapTR := by
|
||||
funext α β f l
|
||||
let rec go : ∀ as acc, filterMapTR.go f as acc = acc.data ++ as.filterMap f
|
||||
let rec go : ∀ as acc, filterMapTR.go f as acc = acc.toList ++ as.filterMap f
|
||||
| [], acc => by simp [filterMapTR.go, filterMap]
|
||||
| a::as, acc => by
|
||||
simp only [filterMapTR.go, go as, Array.push_data, append_assoc, singleton_append, filterMap]
|
||||
simp only [filterMapTR.go, go as, Array.push_toList, append_assoc, singleton_append,
|
||||
filterMap]
|
||||
split <;> simp [*]
|
||||
exact (go l #[]).symm
|
||||
|
||||
@@ -90,7 +91,7 @@ The following operations are given `@[csimp]` replacements below:
|
||||
@[specialize] def foldrTR (f : α → β → β) (init : β) (l : List α) : β := l.toArray.foldr f init
|
||||
|
||||
@[csimp] theorem foldr_eq_foldrTR : @foldr = @foldrTR := by
|
||||
funext α β f init l; simp [foldrTR, Array.foldr_eq_foldr_data, -Array.size_toArray]
|
||||
funext α β f init l; simp [foldrTR, Array.foldr_eq_foldr_toList, -Array.size_toArray]
|
||||
|
||||
/-! ### bind -/
|
||||
|
||||
@@ -103,7 +104,7 @@ The following operations are given `@[csimp]` replacements below:
|
||||
|
||||
@[csimp] theorem bind_eq_bindTR : @List.bind = @bindTR := by
|
||||
funext α β as f
|
||||
let rec go : ∀ as acc, bindTR.go f as acc = acc.data ++ as.bind f
|
||||
let rec go : ∀ as acc, bindTR.go f as acc = acc.toList ++ as.bind f
|
||||
| [], acc => by simp [bindTR.go, bind]
|
||||
| x::xs, acc => by simp [bindTR.go, bind, go xs]
|
||||
exact (go as #[]).symm
|
||||
@@ -131,7 +132,7 @@ The following operations are given `@[csimp]` replacements below:
|
||||
|
||||
@[csimp] theorem take_eq_takeTR : @take = @takeTR := by
|
||||
funext α n l; simp [takeTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs → takeTR.go l xs n acc = acc.data ++ xs.take n from
|
||||
suffices ∀ xs acc, l = acc.toList ++ xs → takeTR.go l xs n acc = acc.toList ++ xs.take n from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs generalizing n with intro acc
|
||||
| nil => cases n <;> simp [take, takeTR.go]
|
||||
@@ -152,13 +153,13 @@ The following operations are given `@[csimp]` replacements below:
|
||||
|
||||
@[csimp] theorem takeWhile_eq_takeWhileTR : @takeWhile = @takeWhileTR := by
|
||||
funext α p l; simp [takeWhileTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs →
|
||||
takeWhileTR.go p l xs acc = acc.data ++ xs.takeWhile p from
|
||||
suffices ∀ xs acc, l = acc.toList ++ xs →
|
||||
takeWhileTR.go p l xs acc = acc.toList ++ xs.takeWhile p from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs with intro acc
|
||||
| nil => simp [takeWhile, takeWhileTR.go]
|
||||
| cons x xs IH =>
|
||||
simp only [takeWhileTR.go, Array.toList_eq, takeWhile]
|
||||
simp only [takeWhileTR.go, Array.toListImpl_eq, takeWhile]
|
||||
split
|
||||
· intro h; rw [IH] <;> simp_all
|
||||
· simp [*]
|
||||
@@ -185,8 +186,8 @@ The following operations are given `@[csimp]` replacements below:
|
||||
|
||||
@[csimp] theorem replace_eq_replaceTR : @List.replace = @replaceTR := by
|
||||
funext α _ l b c; simp [replaceTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs →
|
||||
replaceTR.go l b c xs acc = acc.data ++ xs.replace b c from
|
||||
suffices ∀ xs acc, l = acc.toList ++ xs →
|
||||
replaceTR.go l b c xs acc = acc.toList ++ xs.replace b c from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs with intro acc
|
||||
| nil => simp [replace, replaceTR.go]
|
||||
@@ -208,7 +209,7 @@ The following operations are given `@[csimp]` replacements below:
|
||||
|
||||
@[csimp] theorem erase_eq_eraseTR : @List.erase = @eraseTR := by
|
||||
funext α _ l a; simp [eraseTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs → eraseTR.go l a xs acc = acc.data ++ xs.erase a from
|
||||
suffices ∀ xs acc, l = acc.toList ++ xs → eraseTR.go l a xs acc = acc.toList ++ xs.erase a from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs with intro acc h
|
||||
| nil => simp [List.erase, eraseTR.go, h]
|
||||
@@ -228,8 +229,8 @@ The following operations are given `@[csimp]` replacements below:
|
||||
|
||||
@[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
|
||||
let rec go (acc) : ∀ xs, l = acc.toList ++ xs →
|
||||
erasePTR.go p l xs acc = acc.toList ++ xs.eraseP p
|
||||
| [] => fun h => by simp [erasePTR.go, eraseP, h]
|
||||
| x::xs => by
|
||||
simp [erasePTR.go, eraseP]; cases p x <;> simp
|
||||
@@ -249,7 +250,7 @@ The following operations are given `@[csimp]` replacements below:
|
||||
|
||||
@[csimp] theorem eraseIdx_eq_eraseIdxTR : @eraseIdx = @eraseIdxTR := by
|
||||
funext α l n; simp [eraseIdxTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs → eraseIdxTR.go l xs n acc = acc.data ++ xs.eraseIdx n from
|
||||
suffices ∀ xs acc, l = acc.toList ++ xs → eraseIdxTR.go l xs n acc = acc.toList ++ xs.eraseIdx n from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs generalizing n with intro acc h
|
||||
| nil => simp [eraseIdx, eraseIdxTR.go, h]
|
||||
@@ -273,7 +274,7 @@ The following operations are given `@[csimp]` replacements below:
|
||||
|
||||
@[csimp] theorem zipWith_eq_zipWithTR : @zipWith = @zipWithTR := by
|
||||
funext α β γ f as bs
|
||||
let rec go : ∀ as bs acc, zipWithTR.go f as bs acc = acc.data ++ as.zipWith f bs
|
||||
let rec go : ∀ as bs acc, zipWithTR.go f as bs acc = acc.toList ++ as.zipWith f bs
|
||||
| [], _, acc | _::_, [], acc => by simp [zipWithTR.go, zipWith]
|
||||
| a::as, b::bs, acc => by simp [zipWithTR.go, zipWith, go as bs]
|
||||
exact (go as bs #[]).symm
|
||||
@@ -295,7 +296,7 @@ def enumFromTR (n : Nat) (l : List α) : List (Nat × α) :=
|
||||
| a::as, n => by
|
||||
rw [← show _ + as.length = n + (a::as).length from Nat.succ_add .., foldr, go as]
|
||||
simp [enumFrom, f]
|
||||
rw [Array.foldr_eq_foldr_data]
|
||||
rw [Array.foldr_eq_foldr_toList]
|
||||
simp [go]
|
||||
|
||||
/-! ## Other list operations -/
|
||||
@@ -321,7 +322,7 @@ where
|
||||
| [_] => simp
|
||||
| x::y::xs =>
|
||||
let rec go {acc x} : ∀ xs,
|
||||
intercalateTR.go sep.toArray x xs acc = acc.data ++ join (intersperse sep (x::xs))
|
||||
intercalateTR.go sep.toArray x xs acc = acc.toList ++ join (intersperse sep (x::xs))
|
||||
| [] => by simp [intercalateTR.go]
|
||||
| _::_ => by simp [intercalateTR.go, go]
|
||||
simp [intersperse, go]
|
||||
|
||||
@@ -109,6 +109,9 @@ theorem cons_eq_cons {a b : α} {l l' : List α} : a :: l = b :: l' ↔ a = b
|
||||
theorem exists_cons_of_ne_nil : ∀ {l : List α}, l ≠ [] → ∃ b L, l = b :: L
|
||||
| c :: l', _ => ⟨c, l', rfl⟩
|
||||
|
||||
theorem singleton_inj {α : Type _} {a b : α} : [a] = [b] ↔ a = b := by
|
||||
simp
|
||||
|
||||
/-! ### length -/
|
||||
|
||||
theorem eq_nil_of_length_eq_zero (_ : length l = 0) : l = [] := match l with | [] => rfl
|
||||
@@ -480,9 +483,9 @@ theorem getElem?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n : Nat, l[n]? = s
|
||||
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 getElem_mem : ∀ (l : List α) n (h : n < l.length), l[n]'h ∈ l
|
||||
theorem getElem_mem : ∀ {l : List α} {n} (h : n < l.length), l[n]'h ∈ l
|
||||
| _ :: _, 0, _ => .head ..
|
||||
| _ :: l, _+1, _ => .tail _ (getElem_mem l ..)
|
||||
| _ :: l, _+1, _ => .tail _ (getElem_mem (l := l) ..)
|
||||
|
||||
theorem get_mem : ∀ (l : List α) n h, get l ⟨n, h⟩ ∈ l
|
||||
| _ :: _, 0, _ => .head ..
|
||||
@@ -524,7 +527,7 @@ theorem forall_getElem {l : List α} {p : α → Prop} :
|
||||
· simpa
|
||||
· apply w
|
||||
simp only [getElem_cons_succ]
|
||||
exact getElem_mem l n (lt_of_succ_lt_succ h)
|
||||
exact getElem_mem (lt_of_succ_lt_succ h)
|
||||
|
||||
@[simp] theorem decide_mem_cons [BEq α] [LawfulBEq α] {l : List α} :
|
||||
decide (y ∈ a :: l) = (y == a || decide (y ∈ l)) := by
|
||||
@@ -572,17 +575,25 @@ theorem any_eq {l : List α} : l.any p = decide (∃ x, x ∈ l ∧ p x) := by i
|
||||
|
||||
theorem all_eq {l : List α} : l.all p = decide (∀ x, x ∈ l → p x) := by induction l <;> simp [*]
|
||||
|
||||
@[simp] theorem any_decide {l : List α} {p : α → Prop} [DecidablePred p] :
|
||||
l.any p = decide (∃ x, x ∈ l ∧ p x) := by
|
||||
theorem decide_exists_mem {l : List α} {p : α → Prop} [DecidablePred p] :
|
||||
decide (∃ x, x ∈ l ∧ p x) = l.any p := by
|
||||
simp [any_eq]
|
||||
|
||||
@[simp] theorem all_decide {l : List α} {p : α → Prop} [DecidablePred p] :
|
||||
l.all p = decide (∀ x, x ∈ l → p x) := by
|
||||
theorem decide_forall_mem {l : List α} {p : α → Prop} [DecidablePred p] :
|
||||
decide (∀ x, x ∈ l → p x) = l.all p := by
|
||||
simp [all_eq]
|
||||
|
||||
@[simp] theorem any_eq_true {l : List α} : l.any p = true ↔ ∃ x, x ∈ l ∧ p x := by simp [any_eq]
|
||||
@[simp] theorem any_eq_true {l : List α} : l.any p = true ↔ ∃ x, x ∈ l ∧ p x := by
|
||||
simp only [any_eq, decide_eq_true_eq]
|
||||
|
||||
@[simp] theorem all_eq_true {l : List α} : l.all p = true ↔ ∀ x, x ∈ l → p x := by simp [all_eq]
|
||||
@[simp] theorem all_eq_true {l : List α} : l.all p = true ↔ ∀ x, x ∈ l → p x := by
|
||||
simp only [all_eq, decide_eq_true_eq]
|
||||
|
||||
@[simp] theorem any_eq_false {l : List α} : l.any p = false ↔ ∀ x, x ∈ l → ¬p x := by
|
||||
simp [any_eq]
|
||||
|
||||
@[simp] theorem all_eq_false {l : List α} : l.all p = false ↔ ∃ x, x ∈ l ∧ ¬p x := by
|
||||
simp [all_eq]
|
||||
|
||||
/-! ### set -/
|
||||
|
||||
@@ -721,6 +732,45 @@ theorem mem_or_eq_of_mem_set : ∀ {l : List α} {n : Nat} {a b : α}, a ∈ l.s
|
||||
|
||||
-- See also `set_eq_take_append_cons_drop` in `Init.Data.List.TakeDrop`.
|
||||
|
||||
/-! ### BEq -/
|
||||
|
||||
@[simp] theorem reflBEq_iff [BEq α] : ReflBEq (List α) ↔ ReflBEq α := by
|
||||
constructor
|
||||
· intro h
|
||||
constructor
|
||||
intro a
|
||||
suffices ([a] == [a]) = true by
|
||||
simpa only [List.instBEq, List.beq, Bool.and_true]
|
||||
simp
|
||||
· intro h
|
||||
constructor
|
||||
intro a
|
||||
induction a with
|
||||
| nil => simp only [List.instBEq, List.beq]
|
||||
| cons a as ih =>
|
||||
simp [List.instBEq, List.beq]
|
||||
exact ih
|
||||
|
||||
@[simp] theorem lawfulBEq_iff [BEq α] : LawfulBEq (List α) ↔ LawfulBEq α := by
|
||||
constructor
|
||||
· intro h
|
||||
constructor
|
||||
· intro a b h
|
||||
apply singleton_inj.1
|
||||
apply eq_of_beq
|
||||
simp only [List.instBEq, List.beq]
|
||||
simpa
|
||||
· intro a
|
||||
suffices ([a] == [a]) = true by
|
||||
simpa only [List.instBEq, List.beq, Bool.and_true]
|
||||
simp
|
||||
· intro h
|
||||
constructor
|
||||
· intro a b h
|
||||
simpa using h
|
||||
· intro a
|
||||
simp
|
||||
|
||||
/-! ### Lexicographic ordering -/
|
||||
|
||||
protected theorem lt_irrefl [LT α] (lt_irrefl : ∀ x : α, ¬x < x) (l : List α) : ¬l < l := by
|
||||
@@ -921,6 +971,10 @@ theorem getLast_mem : ∀ {l : List α} (h : l ≠ []), getLast l h ∈ l
|
||||
| [_], _ => .head ..
|
||||
| _::a::l, _ => .tail _ <| getLast_mem (cons_ne_nil a l)
|
||||
|
||||
theorem getLast_mem_getLast? : ∀ {l : List α} (h : l ≠ []), getLast l h ∈ getLast? l
|
||||
| [], h => by contradiction
|
||||
| a :: l, _ => rfl
|
||||
|
||||
theorem getLastD_mem_cons : ∀ (l : List α) (a : α), getLastD l a ∈ a::l
|
||||
| [], _ => .head ..
|
||||
| _::_, _ => .tail _ <| getLast_mem _
|
||||
@@ -1018,6 +1072,10 @@ theorem mem_of_mem_head? : ∀ {l : List α} {a : α}, a ∈ l.head? → a ∈ l
|
||||
cases h
|
||||
exact mem_cons_self a l
|
||||
|
||||
theorem head_mem_head? : ∀ {l : List α} (h : l ≠ []), head l h ∈ head? l
|
||||
| [], h => by contradiction
|
||||
| a :: l, _ => rfl
|
||||
|
||||
theorem head?_concat {a : α} : (l ++ [a]).head? = l.head?.getD a := by
|
||||
cases l <;> simp
|
||||
|
||||
@@ -1044,6 +1102,9 @@ 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]
|
||||
|
||||
theorem mem_of_mem_tail {a : α} {l : List α} (h : a ∈ tail l) : a ∈ l := by
|
||||
induction l <;> simp_all
|
||||
|
||||
/-! ## Basic operations -/
|
||||
|
||||
/-! ### map -/
|
||||
@@ -1496,10 +1557,11 @@ theorem filterMap_eq_cons_iff {l} {b} {bs} :
|
||||
|
||||
/-! ### append -/
|
||||
|
||||
theorem getElem_append : ∀ {l₁ l₂ : List α} (n : Nat) (h : n < l₁.length),
|
||||
(l₁ ++ l₂)[n]'(length_append .. ▸ Nat.lt_add_right _ h) = l₁[n]
|
||||
| a :: l, _, 0, h => rfl
|
||||
| a :: l, _, n+1, h => by simp only [get, cons_append]; apply getElem_append
|
||||
theorem getElem_append {l₁ l₂ : List α} (n : Nat) (h) :
|
||||
(l₁ ++ l₂)[n] = if h' : n < l₁.length then l₁[n] else l₂[n - l₁.length]'(by simp at h h'; exact Nat.sub_lt_left_of_lt_add h' h) := by
|
||||
split <;> rename_i h'
|
||||
· rw [getElem_append_left h']
|
||||
· rw [getElem_append_right (by simpa using h')]
|
||||
|
||||
theorem getElem?_append_left {l₁ l₂ : List α} {n : Nat} (hn : n < l₁.length) :
|
||||
(l₁ ++ l₂)[n]? = l₁[n]? := by
|
||||
@@ -1525,12 +1587,13 @@ theorem get?_append_right {l₁ l₂ : List α} {n : Nat} (h : l₁.length ≤ n
|
||||
(l₁ ++ l₂).get? n = l₂.get? (n - l₁.length) := by
|
||||
simp [getElem?_append_right, h]
|
||||
|
||||
theorem getElem_append_right' {l₁ l₂ : List α} {n : Nat} (h₁ : l₁.length ≤ n) (h₂) :
|
||||
(l₁ ++ l₂)[n]'h₂ =
|
||||
l₂[n - l₁.length]'(by rw [length_append] at h₂; exact Nat.sub_lt_left_of_lt_add h₁ h₂) :=
|
||||
Option.some.inj <| by rw [← getElem?_eq_getElem, ← getElem?_eq_getElem, getElem?_append_right h₁]
|
||||
/-- Variant of `getElem_append_left` useful for rewriting from the small list to the big list. -/
|
||||
theorem getElem_append_left' (l₂ : List α) {l₁ : List α} {n : Nat} (hn : n < l₁.length) :
|
||||
l₁[n] = (l₁ ++ l₂)[n]'(by simpa using Nat.lt_add_right l₂.length hn) := by
|
||||
rw [getElem_append_left] <;> simp
|
||||
|
||||
theorem getElem_append_right'' (l₁ : List α) {l₂ : List α} {n : Nat} (hn : n < l₂.length) :
|
||||
/-- Variant of `getElem_append_right` useful for rewriting from the small list to the big list. -/
|
||||
theorem getElem_append_right' (l₁ : List α) {l₂ : List α} {n : Nat} (hn : n < l₂.length) :
|
||||
l₂[n] = (l₁ ++ l₂)[n + l₁.length]'(by simpa [Nat.add_comm] using Nat.add_lt_add_left hn _) := by
|
||||
rw [getElem_append_right] <;> simp [*, le_add_left]
|
||||
|
||||
@@ -1541,7 +1604,7 @@ theorem get_append_right_aux {l₁ l₂ : List α} {n : Nat}
|
||||
exact Nat.sub_lt_left_of_lt_add h₁ h₂
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated getElem_append_right' (since := "2024-06-12")]
|
||||
@[deprecated getElem_append_right (since := "2024-06-12")]
|
||||
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₁]
|
||||
@@ -1633,7 +1696,7 @@ theorem get_append_left (as bs : List α) (h : i < as.length) {h'} :
|
||||
simp [getElem_append_left, h, h']
|
||||
|
||||
@[deprecated getElem_append_right (since := "2024-06-12")]
|
||||
theorem get_append_right (as bs : List α) (h : ¬ i < as.length) {h' h''} :
|
||||
theorem get_append_right (as bs : List α) (h : as.length ≤ i) {h' h''} :
|
||||
(as ++ bs).get ⟨i, h'⟩ = bs.get ⟨i - as.length, h''⟩ := by
|
||||
simp [getElem_append_right, h, h', h'']
|
||||
|
||||
@@ -2312,6 +2375,47 @@ theorem bind_replicate {β} (f : α → List β) : (replicate n a).bind f = (rep
|
||||
@[simp] theorem isEmpty_replicate : (replicate n a).isEmpty = decide (n = 0) := by
|
||||
cases n <;> simp [replicate_succ]
|
||||
|
||||
/-- Every list is either empty, a non-empty `replicate`, or begins with a non-empty `replicate`
|
||||
followed by a different element. -/
|
||||
theorem eq_replicate_or_eq_replicate_append_cons {α : Type _} (l : List α) :
|
||||
(l = []) ∨ (∃ n a, l = replicate n a ∧ 0 < n) ∨
|
||||
(∃ n a b l', l = replicate n a ++ b :: l' ∧ 0 < n ∧ a ≠ b) := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x l ih =>
|
||||
right
|
||||
rcases ih with rfl | ⟨n, a, rfl, h⟩ | ⟨n, a, b, l', rfl, h⟩
|
||||
· left
|
||||
exact ⟨1, x, rfl, by decide⟩
|
||||
· by_cases h' : x = a
|
||||
· subst h'
|
||||
left
|
||||
exact ⟨n + 1, x, rfl, by simp⟩
|
||||
· right
|
||||
refine ⟨1, x, a, replicate (n - 1) a, ?_, by decide, h'⟩
|
||||
match n with | n + 1 => simp [replicate_succ]
|
||||
· right
|
||||
by_cases h' : x = a
|
||||
· subst h'
|
||||
refine ⟨n + 1, x, b, l', by simp [replicate_succ], by simp, h.2⟩
|
||||
· refine ⟨1, x, a, replicate (n - 1) a ++ b :: l', ?_, by decide, h'⟩
|
||||
match n with | n + 1 => simp [replicate_succ]
|
||||
|
||||
/-- An induction principle for lists based on contiguous runs of identical elements. -/
|
||||
-- A `Sort _` valued version would require a different design. (And associated `@[simp]` lemmas.)
|
||||
theorem replicateRecOn {α : Type _} {p : List α → Prop} (m : List α)
|
||||
(h0 : p []) (hr : ∀ a n, 0 < n → p (replicate n a))
|
||||
(hi : ∀ a b n l, a ≠ b → 0 < n → p (b :: l) → p (replicate n a ++ b :: l)) : p m := by
|
||||
rcases eq_replicate_or_eq_replicate_append_cons m with
|
||||
rfl | ⟨n, a, rfl, hn⟩ | ⟨n, a, b, l', w, hn, h⟩
|
||||
· exact h0
|
||||
· exact hr _ _ hn
|
||||
· have : (b :: l').length < m.length := by
|
||||
simpa [w] using Nat.lt_add_of_pos_left hn
|
||||
subst w
|
||||
exact hi _ _ _ _ h hn (replicateRecOn (b :: l') h0 hr hi)
|
||||
termination_by m.length
|
||||
|
||||
/-! ### reverse -/
|
||||
|
||||
@[simp] theorem length_reverse (as : List α) : (as.reverse).length = as.length := by
|
||||
|
||||
@@ -176,7 +176,7 @@ theorem pairwise_le_range (n : Nat) : Pairwise (· ≤ ·) (range n) :=
|
||||
theorem take_range (m n : Nat) : take m (range n) = range (min m n) := by
|
||||
apply List.ext_getElem
|
||||
· simp
|
||||
· simp (config := { contextual := true }) [← getElem_take, Nat.lt_min]
|
||||
· simp (config := { contextual := true }) [getElem_take, Nat.lt_min]
|
||||
|
||||
theorem nodup_range (n : Nat) : Nodup (range n) := by
|
||||
simp (config := {decide := true}) only [range_eq_range', nodup_range']
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, M
|
||||
prelude
|
||||
import Init.Data.List.Zip
|
||||
import Init.Data.List.Sublist
|
||||
import Init.Data.List.Find
|
||||
import Init.Data.Nat.Lemmas
|
||||
|
||||
/-!
|
||||
@@ -35,23 +36,23 @@ theorem length_take_of_le (h : n ≤ length l) : length (take n l) = n := by sim
|
||||
|
||||
/-- 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 getElem_take (L : List α) {i j : Nat} (hi : i < L.length) (hj : i < j) :
|
||||
theorem getElem_take' (L : List α) {i j : Nat} (hi : i < L.length) (hj : i < j) :
|
||||
L[i] = (L.take j)[i]'(length_take .. ▸ Nat.lt_min.mpr ⟨hj, hi⟩) :=
|
||||
getElem_of_eq (take_append_drop j L).symm _ ▸ getElem_append ..
|
||||
getElem_of_eq (take_append_drop j L).symm _ ▸ getElem_append_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 small list to the big list. -/
|
||||
theorem getElem_take' (L : List α) {j i : Nat} {h : i < (L.take j).length} :
|
||||
theorem getElem_take (L : List α) {j i : Nat} {h : i < (L.take j).length} :
|
||||
(L.take j)[i] =
|
||||
L[i]'(Nat.lt_of_lt_of_le h (length_take_le' _ _)) := by
|
||||
rw [length_take, Nat.lt_min] at h; rw [getElem_take L _ h.1]
|
||||
rw [length_take, Nat.lt_min] at h; rw [getElem_take' L _ h.1]
|
||||
|
||||
/-- 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. -/
|
||||
@[deprecated getElem_take (since := "2024-06-12")]
|
||||
@[deprecated getElem_take' (since := "2024-06-12")]
|
||||
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⟩⟩ := by
|
||||
simp [getElem_take _ hi hj]
|
||||
simp [getElem_take' _ hi hj]
|
||||
|
||||
/-- 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. -/
|
||||
@@ -59,7 +60,7 @@ 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
|
||||
simp [getElem_take']
|
||||
simp [getElem_take]
|
||||
|
||||
theorem getElem?_take_eq_none {l : List α} {n m : Nat} (h : n ≤ m) :
|
||||
(l.take n)[m]? = none :=
|
||||
@@ -109,7 +110,7 @@ theorem getLast?_take {l : List α} : (l.take n).getLast? = if n = 0 then none e
|
||||
|
||||
theorem getLast_take {l : List α} (h : l.take n ≠ []) :
|
||||
(l.take n).getLast h = l[n - 1]?.getD (l.getLast (by simp_all)) := by
|
||||
rw [getLast_eq_getElem, getElem_take']
|
||||
rw [getLast_eq_getElem, getElem_take]
|
||||
simp [length_take, Nat.min_def]
|
||||
simp at h
|
||||
split
|
||||
@@ -190,20 +191,12 @@ theorem dropLast_take {n : Nat} {l : List α} (h : n < l.length) :
|
||||
(l.take n).dropLast = l.take (n - 1) := by
|
||||
simp only [dropLast_eq_take, length_take, Nat.le_of_lt h, Nat.min_eq_left, take_take, sub_le]
|
||||
|
||||
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
|
||||
@[deprecated map_eq_append_iff (since := "2024-09-05")] abbrev map_eq_append_split := @map_eq_append_iff
|
||||
|
||||
theorem take_prefix_take_left (l : List α) {m n : Nat} (h : m ≤ n) : take m l <+: take n l := by
|
||||
rw [isPrefix_iff]
|
||||
intro i w
|
||||
rw [getElem?_take_of_lt, getElem_take', getElem?_eq_getElem]
|
||||
rw [getElem?_take_of_lt, getElem_take, getElem?_eq_getElem]
|
||||
simp only [length_take] at w
|
||||
exact Nat.lt_of_lt_of_le (Nat.lt_of_lt_of_le w (Nat.min_le_left _ _)) h
|
||||
|
||||
@@ -226,8 +219,9 @@ dropping the first `i` elements. Version designed to rewrite from the big list t
|
||||
theorem getElem_drop' (L : List α) {i j : Nat} (h : i + j < L.length) :
|
||||
L[i + j] = (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 [getElem_of_eq (take_append_drop i L).symm h, getElem_append_right'] <;>
|
||||
simp [Nat.min_eq_left this, Nat.add_sub_cancel_left, Nat.le_add_right]
|
||||
rw [getElem_of_eq (take_append_drop i L).symm h, getElem_append_right]
|
||||
· simp [Nat.min_eq_left this, Nat.add_sub_cancel_left]
|
||||
· simp [Nat.min_eq_left this, 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 big list to the small list. -/
|
||||
@@ -268,6 +262,26 @@ theorem getElem?_drop (L : List α) (i j : Nat) : (L.drop i)[j]? = L[i + j]? :=
|
||||
theorem get?_drop (L : List α) (i j : Nat) : get? (L.drop i) j = get? L (i + j) := by
|
||||
simp
|
||||
|
||||
theorem mem_take_iff_getElem {l : List α} {a : α} :
|
||||
a ∈ l.take n ↔ ∃ (i : Nat) (hm : i < min n l.length), l[i] = a := by
|
||||
rw [mem_iff_getElem]
|
||||
constructor
|
||||
· rintro ⟨i, hm, rfl⟩
|
||||
simp at hm
|
||||
refine ⟨i, by omega, by rw [getElem_take]⟩
|
||||
· rintro ⟨i, hm, rfl⟩
|
||||
refine ⟨i, by simpa, by rw [getElem_take]⟩
|
||||
|
||||
theorem mem_drop_iff_getElem {l : List α} {a : α} :
|
||||
a ∈ l.drop n ↔ ∃ (i : Nat) (hm : i + n < l.length), l[n + i] = a := by
|
||||
rw [mem_iff_getElem]
|
||||
constructor
|
||||
· rintro ⟨i, hm, rfl⟩
|
||||
simp at hm
|
||||
refine ⟨i, by omega, by rw [getElem_drop]⟩
|
||||
· rintro ⟨i, hm, rfl⟩
|
||||
refine ⟨i, by simp; omega, by rw [getElem_drop]⟩
|
||||
|
||||
theorem head?_drop (l : List α) (n : Nat) :
|
||||
(l.drop n).head? = l[n]? := by
|
||||
rw [head?_eq_getElem?, getElem?_drop, Nat.add_zero]
|
||||
@@ -288,7 +302,7 @@ theorem getLast?_drop {l : List α} : (l.drop n).getLast? = if l.length ≤ n th
|
||||
|
||||
theorem getLast_drop {l : List α} (h : l.drop n ≠ []) :
|
||||
(l.drop n).getLast h = l.getLast (ne_nil_of_length_pos (by simp at h; omega)) := by
|
||||
simp only [ne_eq, drop_eq_nil_iff_le] at h
|
||||
simp only [ne_eq, drop_eq_nil_iff] at h
|
||||
apply Option.some_inj.1
|
||||
simp only [← getLast?_eq_getLast, getLast?_drop, ite_eq_right_iff]
|
||||
omega
|
||||
@@ -435,6 +449,64 @@ theorem reverse_drop {l : List α} {n : Nat} :
|
||||
rw [w, take_zero, drop_of_length_le, reverse_nil]
|
||||
omega
|
||||
|
||||
/-! ### findIdx -/
|
||||
|
||||
theorem false_of_mem_take_findIdx {xs : List α} {p : α → Bool} (h : x ∈ xs.take (xs.findIdx p)) :
|
||||
p x = false := by
|
||||
simp only [mem_take_iff_getElem, forall_exists_index] at h
|
||||
obtain ⟨i, h, rfl⟩ := h
|
||||
exact not_of_lt_findIdx (by omega)
|
||||
|
||||
@[simp] theorem findIdx_take {xs : List α} {n : Nat} {p : α → Bool} :
|
||||
(xs.take n).findIdx p = min n (xs.findIdx p) := by
|
||||
induction xs generalizing n with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
cases n
|
||||
· simp
|
||||
· simp only [take_succ_cons, findIdx_cons, ih, cond_eq_if]
|
||||
split
|
||||
· simp
|
||||
· rw [Nat.add_min_add_right]
|
||||
|
||||
@[simp] theorem findIdx?_take {xs : List α} {n : Nat} {p : α → Bool} :
|
||||
(xs.take n).findIdx? p = (xs.findIdx? p).bind (Option.guard (fun i => i < n)) := by
|
||||
induction xs generalizing n with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
cases n
|
||||
· simp
|
||||
· simp only [take_succ_cons, findIdx?_cons]
|
||||
split
|
||||
· simp
|
||||
· simp [ih, Option.guard_comp, Option.bind_map]
|
||||
|
||||
@[simp] theorem min_findIdx_findIdx {xs : List α} {p q : α → Bool} :
|
||||
min (xs.findIdx p) (xs.findIdx q) = xs.findIdx (fun a => p a || q a) := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp [findIdx_cons, cond_eq_if, Bool.not_eq_eq_eq_not, Bool.not_true]
|
||||
split <;> split <;> simp_all [Nat.add_min_add_right]
|
||||
|
||||
/-! ### takeWhile -/
|
||||
|
||||
theorem takeWhile_eq_take_findIdx_not {xs : List α} {p : α → Bool} :
|
||||
takeWhile p xs = take (xs.findIdx (fun a => !p a)) xs := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [takeWhile_cons, ih, findIdx_cons, cond_eq_if, Bool.not_eq_eq_eq_not, Bool.not_true]
|
||||
split <;> simp_all
|
||||
|
||||
theorem dropWhile_eq_drop_findIdx_not {xs : List α} {p : α → Bool} :
|
||||
dropWhile p xs = drop (xs.findIdx (fun a => !p a)) xs := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [dropWhile_cons, ih, findIdx_cons, cond_eq_if, Bool.not_eq_eq_eq_not, Bool.not_true]
|
||||
split <;> simp_all
|
||||
|
||||
/-! ### rotateLeft -/
|
||||
|
||||
@[simp] theorem rotateLeft_replicate (n) (a : α) : rotateLeft (replicate m a) n = replicate m a := by
|
||||
|
||||
@@ -22,17 +22,18 @@ namespace List
|
||||
This version is not tail-recursive,
|
||||
but it is replaced at runtime by `mergeTR` using a `@[csimp]` lemma.
|
||||
-/
|
||||
def merge (le : α → α → Bool) : List α → List α → List α
|
||||
def merge (xs ys : List α) (le : α → α → Bool := by exact fun a b => a ≤ b) : List α :=
|
||||
match xs, ys with
|
||||
| [], ys => ys
|
||||
| xs, [] => xs
|
||||
| x :: xs, y :: ys =>
|
||||
if le x y then
|
||||
x :: merge le xs (y :: ys)
|
||||
x :: merge xs (y :: ys) le
|
||||
else
|
||||
y :: merge le (x :: xs) ys
|
||||
y :: merge (x :: xs) ys le
|
||||
|
||||
@[simp] theorem nil_merge (ys : List α) : merge le [] ys = ys := by simp [merge]
|
||||
@[simp] theorem merge_right (xs : List α) : merge le xs [] = xs := by
|
||||
@[simp] theorem nil_merge (ys : List α) : merge [] ys le = ys := by simp [merge]
|
||||
@[simp] theorem merge_right (xs : List α) : merge xs [] le = xs := by
|
||||
induction xs with
|
||||
| nil => simp [merge]
|
||||
| cons x xs ih => simp [merge, ih]
|
||||
@@ -45,6 +46,7 @@ def splitInTwo (l : { l : List α // l.length = n }) :
|
||||
let r := splitAt ((n+1)/2) l.1
|
||||
(⟨r.1, by simp [r, splitAt_eq, l.2]; omega⟩, ⟨r.2, by simp [r, splitAt_eq, l.2]; omega⟩)
|
||||
|
||||
set_option linter.unusedVariables false in
|
||||
/--
|
||||
Simplified implementation of stable merge sort.
|
||||
|
||||
@@ -56,16 +58,15 @@ It is replaced at runtime in the compiler by `mergeSortTR₂` using a `@[csimp]`
|
||||
Because we want the sort to be stable,
|
||||
it is essential that we split the list in two contiguous sublists.
|
||||
-/
|
||||
def mergeSort (le : α → α → Bool) : List α → List α
|
||||
| [] => []
|
||||
| [a] => [a]
|
||||
| a :: b :: xs =>
|
||||
def mergeSort : ∀ (xs : List α) (le : α → α → Bool := by exact fun a b => a ≤ b), List α
|
||||
| [], _ => []
|
||||
| [a], _ => [a]
|
||||
| a :: b :: xs, le =>
|
||||
let lr := splitInTwo ⟨a :: b :: xs, rfl⟩
|
||||
have := by simpa using lr.2.2
|
||||
have := by simpa using lr.1.2
|
||||
merge le (mergeSort le lr.1) (mergeSort le lr.2)
|
||||
termination_by l => l.length
|
||||
|
||||
merge (mergeSort lr.1 le) (mergeSort lr.2 le) le
|
||||
termination_by xs => xs.length
|
||||
|
||||
/--
|
||||
Given an ordering relation `le : α → α → Bool`,
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace List.MergeSort.Internal
|
||||
/--
|
||||
`O(min |l| |r|)`. Merge two lists using `le` as a switch.
|
||||
-/
|
||||
def mergeTR (le : α → α → Bool) (l₁ l₂ : List α) : List α :=
|
||||
def mergeTR (l₁ l₂ : List α) (le : α → α → Bool) : List α :=
|
||||
go l₁ l₂ []
|
||||
where go : List α → List α → List α → List α
|
||||
| [], l₂, acc => reverseAux acc l₂
|
||||
@@ -49,7 +49,7 @@ where go : List α → List α → List α → List α
|
||||
else
|
||||
go (x :: xs) ys (y :: acc)
|
||||
|
||||
theorem mergeTR_go_eq : mergeTR.go le l₁ l₂ acc = acc.reverse ++ merge le l₁ l₂ := by
|
||||
theorem mergeTR_go_eq : mergeTR.go le l₁ l₂ acc = acc.reverse ++ merge l₁ l₂ le := by
|
||||
induction l₁ generalizing l₂ acc with
|
||||
| nil => simp [mergeTR.go, merge, reverseAux_eq]
|
||||
| cons x l₁ ih₁ =>
|
||||
@@ -97,14 +97,14 @@ This version uses the tail-recurive `mergeTR` function as a subroutine.
|
||||
This is not the final version we use at runtime, as `mergeSortTR₂` is faster.
|
||||
This definition is useful as an intermediate step in proving the `@[csimp]` lemma for `mergeSortTR₂`.
|
||||
-/
|
||||
def mergeSortTR (le : α → α → Bool) (l : List α) : List α :=
|
||||
def mergeSortTR (l : List α) (le : α → α → Bool := by exact fun a b => a ≤ b) : List α :=
|
||||
run ⟨l, rfl⟩
|
||||
where run : {n : Nat} → { l : List α // l.length = n } → List α
|
||||
| 0, ⟨[], _⟩ => []
|
||||
| 1, ⟨[a], _⟩ => [a]
|
||||
| n+2, xs =>
|
||||
let (l, r) := splitInTwo xs
|
||||
mergeTR le (run l) (run r)
|
||||
mergeTR (run l) (run r) le
|
||||
|
||||
/--
|
||||
Split a list in two equal parts, reversing the first part.
|
||||
@@ -130,7 +130,7 @@ Faster version of `mergeSortTR`, which avoids unnecessary list reversals.
|
||||
-- Per the benchmark in `tests/bench/mergeSort/`
|
||||
-- (which averages over 4 use cases: already sorted lists, reverse sorted lists, almost sorted lists, and random lists),
|
||||
-- for lists of length 10^6, `mergeSortTR₂` is about 20% faster than `mergeSortTR`.
|
||||
def mergeSortTR₂ (le : α → α → Bool) (l : List α) : List α :=
|
||||
def mergeSortTR₂ (l : List α) (le : α → α → Bool := by exact fun a b => a ≤ b) : List α :=
|
||||
run ⟨l, rfl⟩
|
||||
where
|
||||
run : {n : Nat} → { l : List α // l.length = n } → List α
|
||||
@@ -138,13 +138,13 @@ where
|
||||
| 1, ⟨[a], _⟩ => [a]
|
||||
| n+2, xs =>
|
||||
let (l, r) := splitRevInTwo xs
|
||||
mergeTR le (run' l) (run r)
|
||||
mergeTR (run' l) (run r) le
|
||||
run' : {n : Nat} → { l : List α // l.length = n } → List α
|
||||
| 0, ⟨[], _⟩ => []
|
||||
| 1, ⟨[a], _⟩ => [a]
|
||||
| n+2, xs =>
|
||||
let (l, r) := splitRevInTwo' xs
|
||||
mergeTR le (run' r) (run l)
|
||||
mergeTR (run' r) (run l) le
|
||||
|
||||
theorem splitRevInTwo'_fst (l : { l : List α // l.length = n }) :
|
||||
(splitRevInTwo' l).1 = ⟨(splitInTwo ⟨l.1.reverse, by simpa using l.2⟩).2.1, by have := l.2; simp; omega⟩ := by
|
||||
@@ -166,7 +166,7 @@ theorem splitRevInTwo_snd (l : { l : List α // l.length = n }) :
|
||||
(splitRevInTwo l).2 = ⟨(splitInTwo l).2.1, by have := l.2; simp; omega⟩ := by
|
||||
simp only [splitRevInTwo, splitRevAt_eq, reverse_take, splitInTwo_snd]
|
||||
|
||||
theorem mergeSortTR_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → mergeSortTR.run le l = mergeSort le l.1
|
||||
theorem mergeSortTR_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → mergeSortTR.run le l = mergeSort l.1 le
|
||||
| 0, ⟨[], _⟩
|
||||
| 1, ⟨[a], _⟩ => by simp [mergeSortTR.run, mergeSort]
|
||||
| n+2, ⟨a :: b :: l, h⟩ => by
|
||||
@@ -183,7 +183,7 @@ theorem mergeSort_eq_mergeSortTR : @mergeSort = @mergeSortTR := by
|
||||
-- This mutual block is unfortunately quite slow to elaborate.
|
||||
set_option maxHeartbeats 400000 in
|
||||
mutual
|
||||
theorem mergeSortTR₂_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → mergeSortTR₂.run le l = mergeSort le l.1
|
||||
theorem mergeSortTR₂_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → mergeSortTR₂.run le l = mergeSort l.1 le
|
||||
| 0, ⟨[], _⟩
|
||||
| 1, ⟨[a], _⟩ => by simp [mergeSortTR₂.run, mergeSort]
|
||||
| n+2, ⟨a :: b :: l, h⟩ => by
|
||||
@@ -195,7 +195,7 @@ theorem mergeSortTR₂_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.
|
||||
rw [reverse_reverse]
|
||||
termination_by n => n
|
||||
|
||||
theorem mergeSortTR₂_run'_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → (w : l' = l.1.reverse) → mergeSortTR₂.run' le l = mergeSort le l'
|
||||
theorem mergeSortTR₂_run'_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → (w : l' = l.1.reverse) → mergeSortTR₂.run' le l = mergeSort l' le
|
||||
| 0, ⟨[], _⟩, w
|
||||
| 1, ⟨[a], _⟩, w => by simp_all [mergeSortTR₂.run', mergeSort]
|
||||
| n+2, ⟨a :: b :: l, h⟩, w => by
|
||||
|
||||
@@ -23,11 +23,6 @@ import Init.Data.Bool
|
||||
|
||||
namespace List
|
||||
|
||||
-- We enable this instance locally so we can write `Pairwise le` instead of `Pairwise (le · ·)` everywhere.
|
||||
attribute [local instance] boolRelToRel
|
||||
|
||||
variable {le : α → α → Bool}
|
||||
|
||||
/-! ### splitInTwo -/
|
||||
|
||||
@[simp] theorem splitInTwo_fst (l : { l : List α // l.length = n }) :
|
||||
@@ -89,6 +84,8 @@ theorem splitInTwo_fst_le_splitInTwo_snd {l : { l : List α // l.length = n }} (
|
||||
|
||||
/-! ### enumLE -/
|
||||
|
||||
variable {le : α → α → Bool}
|
||||
|
||||
theorem enumLE_trans (trans : ∀ a b c, le a b → le b c → le a c)
|
||||
(a b c : Nat × α) : enumLE le a b → enumLE le b c → enumLE le a c := by
|
||||
simp only [enumLE]
|
||||
@@ -129,7 +126,7 @@ theorem enumLE_total (total : ∀ a b, !le a b → le b a)
|
||||
/-! ### merge -/
|
||||
|
||||
theorem merge_stable : ∀ (xs ys) (_ : ∀ x y, x ∈ xs → y ∈ ys → x.1 ≤ y.1),
|
||||
(merge (enumLE le) xs ys).map (·.2) = merge le (xs.map (·.2)) (ys.map (·.2))
|
||||
(merge xs ys (enumLE le)).map (·.2) = merge (xs.map (·.2)) (ys.map (·.2)) le
|
||||
| [], ys, _ => by simp [merge]
|
||||
| xs, [], _ => by simp [merge]
|
||||
| (i, x) :: xs, (j, y) :: ys, h => by
|
||||
@@ -147,7 +144,7 @@ theorem merge_stable : ∀ (xs ys) (_ : ∀ x y, x ∈ xs → y ∈ ys → x.1
|
||||
The elements of `merge le xs ys` are exactly the elements of `xs` and `ys`.
|
||||
-/
|
||||
-- We subsequently prove that `mergeSort_perm : merge le xs ys ~ xs ++ ys`.
|
||||
theorem mem_merge {a : α} {xs ys : List α} : a ∈ merge le xs ys ↔ a ∈ xs ∨ a ∈ ys := by
|
||||
theorem mem_merge {a : α} {xs ys : List α} : a ∈ merge xs ys le ↔ a ∈ xs ∨ a ∈ ys := by
|
||||
induction xs generalizing ys with
|
||||
| nil => simp [merge]
|
||||
| cons x xs ih =>
|
||||
@@ -161,6 +158,9 @@ theorem mem_merge {a : α} {xs ys : List α} : a ∈ merge le xs ys ↔ a ∈ xs
|
||||
apply or_congr_left
|
||||
simp only [or_comm (a := a = y), or_assoc]
|
||||
|
||||
-- We enable this instance locally so we can write `Pairwise le` instead of `Pairwise (le · ·)` everywhere.
|
||||
attribute [local instance] boolRelToRel
|
||||
|
||||
/--
|
||||
If the ordering relation `le` is transitive and total (i.e. `le a b ∨ le b a` for all `a, b`)
|
||||
then the `merge` of two sorted lists is sorted.
|
||||
@@ -168,7 +168,7 @@ then the `merge` of two sorted lists is sorted.
|
||||
theorem sorted_merge
|
||||
(trans : ∀ (a b c : α), le a b → le b c → le a c)
|
||||
(total : ∀ (a b : α), !le a b → le b a)
|
||||
(l₁ l₂ : List α) (h₁ : l₁.Pairwise le) (h₂ : l₂.Pairwise le) : (merge le l₁ l₂).Pairwise le := by
|
||||
(l₁ l₂ : List α) (h₁ : l₁.Pairwise le) (h₂ : l₂.Pairwise le) : (merge l₁ l₂ le).Pairwise le := by
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil => simpa only [merge]
|
||||
| cons x l₁ ih₁ =>
|
||||
@@ -195,7 +195,7 @@ theorem sorted_merge
|
||||
· exact ih₂ h₂.tail
|
||||
|
||||
theorem merge_of_le : ∀ {xs ys : List α} (_ : ∀ a b, a ∈ xs → b ∈ ys → le a b),
|
||||
merge le xs ys = xs ++ ys
|
||||
merge xs ys le = xs ++ ys
|
||||
| [], ys, _
|
||||
| xs, [], _ => by simp [merge]
|
||||
| x :: xs, y :: ys, h => by
|
||||
@@ -206,7 +206,7 @@ theorem merge_of_le : ∀ {xs ys : List α} (_ : ∀ a b, a ∈ xs → b ∈ ys
|
||||
· exact h x y (mem_cons_self _ _) (mem_cons_self _ _)
|
||||
|
||||
variable (le) in
|
||||
theorem merge_perm_append : ∀ {xs ys : List α}, merge le xs ys ~ xs ++ ys
|
||||
theorem merge_perm_append : ∀ {xs ys : List α}, merge xs ys le ~ xs ++ ys
|
||||
| [], ys => by simp [merge]
|
||||
| xs, [] => by simp [merge]
|
||||
| x :: xs, y :: ys => by
|
||||
@@ -222,24 +222,23 @@ theorem merge_perm_append : ∀ {xs ys : List α}, merge le xs ys ~ xs ++ ys
|
||||
|
||||
@[simp] theorem mergeSort_singleton (a : α) : [a].mergeSort r = [a] := by rw [List.mergeSort]
|
||||
|
||||
variable (le) in
|
||||
theorem mergeSort_perm : ∀ (l : List α), mergeSort le l ~ l
|
||||
| [] => by simp [mergeSort]
|
||||
| [a] => by simp [mergeSort]
|
||||
| a :: b :: xs => by
|
||||
theorem mergeSort_perm : ∀ (l : List α) (le), mergeSort l le ~ l
|
||||
| [], _ => by simp [mergeSort]
|
||||
| [a], _ => by simp [mergeSort]
|
||||
| a :: b :: xs, le => by
|
||||
simp only [mergeSort]
|
||||
have : (splitInTwo ⟨a :: b :: xs, rfl⟩).1.1.length < xs.length + 1 + 1 := by simp [splitInTwo_fst]; omega
|
||||
have : (splitInTwo ⟨a :: b :: xs, rfl⟩).2.1.length < xs.length + 1 + 1 := by simp [splitInTwo_snd]; omega
|
||||
exact (merge_perm_append le).trans
|
||||
(((mergeSort_perm _).append (mergeSort_perm _)).trans
|
||||
(((mergeSort_perm _ _).append (mergeSort_perm _ _)).trans
|
||||
(Perm.of_eq (splitInTwo_fst_append_splitInTwo_snd _)))
|
||||
termination_by l => l.length
|
||||
|
||||
@[simp] theorem mergeSort_length (l : List α) : (mergeSort le l).length = l.length :=
|
||||
(mergeSort_perm le l).length_eq
|
||||
@[simp] theorem mergeSort_length (l : List α) : (mergeSort l le).length = l.length :=
|
||||
(mergeSort_perm l le).length_eq
|
||||
|
||||
@[simp] theorem mem_mergeSort {a : α} {l : List α} : a ∈ mergeSort le l ↔ a ∈ l :=
|
||||
(mergeSort_perm le l).mem_iff
|
||||
@[simp] theorem mem_mergeSort {a : α} {l : List α} : a ∈ mergeSort l le ↔ a ∈ l :=
|
||||
(mergeSort_perm l le).mem_iff
|
||||
|
||||
/--
|
||||
The result of `mergeSort` is sorted,
|
||||
@@ -251,7 +250,7 @@ The comparison function need not be irreflexive, i.e. `le a b` and `le b a` is a
|
||||
theorem sorted_mergeSort
|
||||
(trans : ∀ (a b c : α), le a b → le b c → le a c)
|
||||
(total : ∀ (a b : α), !le a b → le b a) :
|
||||
(l : List α) → (mergeSort le l).Pairwise le
|
||||
(l : List α) → (mergeSort l le).Pairwise le
|
||||
| [] => by simp [mergeSort]
|
||||
| [a] => by simp [mergeSort]
|
||||
| a :: b :: xs => by
|
||||
@@ -268,7 +267,7 @@ termination_by l => l.length
|
||||
/--
|
||||
If the input list is already sorted, then `mergeSort` does not change the list.
|
||||
-/
|
||||
theorem mergeSort_of_sorted : ∀ {l : List α} (_ : Pairwise le l), mergeSort le l = l
|
||||
theorem mergeSort_of_sorted : ∀ {l : List α} (_ : Pairwise le l), mergeSort l le = l
|
||||
| [], _ => by simp [mergeSort]
|
||||
| [a], _ => by simp [mergeSort]
|
||||
| a :: b :: xs, h => by
|
||||
@@ -294,10 +293,10 @@ See also:
|
||||
* `pair_sublist_mergeSort`: if `[a, b] <+ l` and `le a b`, then `[a, b] <+ mergeSort le l`)
|
||||
-/
|
||||
theorem mergeSort_enum {l : List α} :
|
||||
(mergeSort (enumLE le) (l.enum)).map (·.2) = mergeSort le l :=
|
||||
(mergeSort (l.enum) (enumLE le)).map (·.2) = mergeSort l le :=
|
||||
go 0 l
|
||||
where go : ∀ (i : Nat) (l : List α),
|
||||
(mergeSort (enumLE le) (l.enumFrom i)).map (·.2) = mergeSort le l
|
||||
(mergeSort (l.enumFrom i) (enumLE le)).map (·.2) = mergeSort l le
|
||||
| _, []
|
||||
| _, [a] => by simp [mergeSort]
|
||||
| _, a :: b :: xs => by
|
||||
@@ -320,24 +319,24 @@ theorem mergeSort_cons {le : α → α → Bool}
|
||||
(trans : ∀ (a b c : α), le a b → le b c → le a c)
|
||||
(total : ∀ (a b : α), !le a b → le b a)
|
||||
(a : α) (l : List α) :
|
||||
∃ l₁ l₂, mergeSort le (a :: l) = l₁ ++ a :: l₂ ∧ mergeSort le l = l₁ ++ l₂ ∧
|
||||
∃ l₁ l₂, mergeSort (a :: l) le = l₁ ++ a :: l₂ ∧ mergeSort l le = l₁ ++ l₂ ∧
|
||||
∀ b, b ∈ l₁ → !le a b := by
|
||||
rw [← mergeSort_enum]
|
||||
rw [enum_cons]
|
||||
have nd : Nodup ((a :: l).enum.map (·.1)) := by rw [enum_map_fst]; exact nodup_range _
|
||||
have m₁ : (0, a) ∈ mergeSort (enumLE le) ((a :: l).enum) :=
|
||||
have m₁ : (0, a) ∈ mergeSort ((a :: l).enum) (enumLE le) :=
|
||||
mem_mergeSort.mpr (mem_cons_self _ _)
|
||||
obtain ⟨l₁, l₂, h⟩ := append_of_mem m₁
|
||||
have s := sorted_mergeSort (enumLE_trans trans) (enumLE_total total) ((a :: l).enum)
|
||||
rw [h] at s
|
||||
have p := mergeSort_perm (enumLE le) ((a :: l).enum)
|
||||
have p := mergeSort_perm ((a :: l).enum) (enumLE le)
|
||||
rw [h] at p
|
||||
refine ⟨l₁.map (·.2), l₂.map (·.2), ?_, ?_, ?_⟩
|
||||
· simpa using congrArg (·.map (·.2)) h
|
||||
· rw [← mergeSort_enum.go 1, ← map_append]
|
||||
congr 1
|
||||
have q : mergeSort (enumLE le) (enumFrom 1 l) ~ l₁ ++ l₂ :=
|
||||
(mergeSort_perm (enumLE le) (enumFrom 1 l)).trans
|
||||
have q : mergeSort (enumFrom 1 l) (enumLE le) ~ l₁ ++ l₂ :=
|
||||
(mergeSort_perm (enumFrom 1 l) (enumLE le)).trans
|
||||
(p.symm.trans perm_middle).cons_inv
|
||||
apply Perm.eq_of_sorted (le := enumLE le)
|
||||
· rintro ⟨i, a⟩ ⟨j, b⟩ ha hb
|
||||
@@ -379,7 +378,7 @@ theorem sublist_mergeSort
|
||||
(trans : ∀ (a b c : α), le a b → le b c → le a c)
|
||||
(total : ∀ (a b : α), !le a b → le b a) :
|
||||
∀ {c : List α} (_ : c.Pairwise le) (_ : c <+ l),
|
||||
c <+ mergeSort le l
|
||||
c <+ mergeSort l le
|
||||
| _, _, .slnil => nil_sublist _
|
||||
| c, hc, @Sublist.cons _ _ l a h => by
|
||||
obtain ⟨l₁, l₂, h₁, h₂, -⟩ := mergeSort_cons trans total a l
|
||||
@@ -409,7 +408,7 @@ then `[a, b]` is still a sublist of `mergeSort le l`.
|
||||
theorem pair_sublist_mergeSort
|
||||
(trans : ∀ (a b c : α), le a b → le b c → le a c)
|
||||
(total : ∀ (a b : α), !le a b → le b a)
|
||||
(hab : le a b) (h : [a, b] <+ l) : [a, b] <+ mergeSort le l :=
|
||||
(hab : le a b) (h : [a, b] <+ l) : [a, b] <+ mergeSort l le :=
|
||||
sublist_mergeSort trans total (pairwise_pair.mpr hab) h
|
||||
|
||||
@[deprecated (since := "2024-09-02")] abbrev mergeSort_stable_pair := @pair_sublist_mergeSort
|
||||
|
||||
@@ -667,7 +667,7 @@ theorem IsSuffix.length_le (h : l₁ <:+ l₂) : l₁.length ≤ l₂.length :=
|
||||
theorem IsPrefix.getElem {x y : List α} (h : x <+: y) {n} (hn : n < x.length) :
|
||||
x[n] = y[n]'(Nat.le_trans hn h.length_le) := by
|
||||
obtain ⟨_, rfl⟩ := h
|
||||
exact (List.getElem_append n hn).symm
|
||||
exact (List.getElem_append_left hn).symm
|
||||
|
||||
-- See `Init.Data.List.Nat.Sublist` for `IsSuffix.getElem`.
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ prelude
|
||||
import Init.Data.List.Lemmas
|
||||
|
||||
/-!
|
||||
# Lemmas about `List.zip`, `List.zipWith`, `List.zipWithAll`, and `List.unzip`.
|
||||
# Lemmas about `List.take` and `List.drop`.
|
||||
-/
|
||||
|
||||
namespace List
|
||||
@@ -129,7 +129,7 @@ theorem drop_tail (l : List α) (n : Nat) : l.tail.drop n = l.drop (n + 1) := by
|
||||
rw [← drop_drop, drop_one]
|
||||
|
||||
@[simp]
|
||||
theorem drop_eq_nil_iff_le {l : List α} {k : Nat} : l.drop k = [] ↔ l.length ≤ k := by
|
||||
theorem drop_eq_nil_iff {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 =>
|
||||
@@ -141,6 +141,8 @@ theorem drop_eq_nil_iff_le {l : List α} {k : Nat} : l.drop k = [] ↔ l.length
|
||||
· simp only [drop] at h
|
||||
simpa [Nat.succ_le_succ_iff] using hk h
|
||||
|
||||
@[deprecated drop_eq_nil_iff (since := "2024-09-10")] abbrev drop_eq_nil_iff_le := @drop_eq_nil_iff
|
||||
|
||||
@[simp]
|
||||
theorem take_eq_nil_iff {l : List α} {k : Nat} : l.take k = [] ↔ k = 0 ∨ l = [] := by
|
||||
cases l <;> cases k <;> simp [Nat.succ_ne_zero]
|
||||
|
||||
@@ -5,6 +5,8 @@ Authors: Floris van Doorn, Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.SimpLemmas
|
||||
import Init.Data.NeZero
|
||||
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
universe u
|
||||
|
||||
@@ -356,6 +358,8 @@ theorem eq_zero_or_pos : ∀ (n : Nat), n = 0 ∨ n > 0
|
||||
|
||||
protected theorem pos_of_ne_zero {n : Nat} : n ≠ 0 → 0 < n := (eq_zero_or_pos n).resolve_left
|
||||
|
||||
theorem pos_of_neZero (n : Nat) [NeZero n] : 0 < n := Nat.pos_of_ne_zero (NeZero.ne _)
|
||||
|
||||
theorem lt.base (n : Nat) : n < succ n := Nat.le_refl (succ n)
|
||||
|
||||
theorem lt_succ_self (n : Nat) : n < succ n := lt.base n
|
||||
@@ -510,6 +514,10 @@ protected theorem add_lt_add_left {n m : Nat} (h : n < m) (k : Nat) : k + n < k
|
||||
protected theorem add_lt_add_right {n m : Nat} (h : n < m) (k : Nat) : n + k < m + k :=
|
||||
Nat.add_comm k m ▸ Nat.add_comm k n ▸ Nat.add_lt_add_left h k
|
||||
|
||||
protected theorem lt_add_of_pos_left (h : 0 < k) : n < k + n := by
|
||||
rw [Nat.add_comm]
|
||||
exact Nat.add_lt_add_left h n
|
||||
|
||||
protected theorem lt_add_of_pos_right (h : 0 < k) : n < n + k :=
|
||||
Nat.add_lt_add_left h n
|
||||
|
||||
@@ -714,6 +722,8 @@ protected theorem zero_ne_one : 0 ≠ (1 : Nat) :=
|
||||
|
||||
theorem succ_ne_zero (n : Nat) : succ n ≠ 0 := by simp
|
||||
|
||||
instance instNeZeroSucc {n : Nat} : NeZero (n + 1) := ⟨succ_ne_zero n⟩
|
||||
|
||||
/-! # mul + order -/
|
||||
|
||||
theorem mul_le_mul_left {n m : Nat} (k : Nat) (h : n ≤ m) : k * n ≤ k * m :=
|
||||
@@ -784,6 +794,9 @@ theorem pos_pow_of_pos {n : Nat} (m : Nat) (h : 0 < n) : 0 < n^m :=
|
||||
| zero => cases h
|
||||
| succ n => simp [Nat.pow_succ]
|
||||
|
||||
instance {n m : Nat} [NeZero n] : NeZero (n^m) :=
|
||||
⟨Nat.ne_zero_iff_zero_lt.mpr (Nat.pos_pow_of_pos m (pos_of_neZero _))⟩
|
||||
|
||||
/-! # min/max -/
|
||||
|
||||
/--
|
||||
|
||||
@@ -226,12 +226,12 @@ private theorem succ_mod_two : succ x % 2 = 1 - x % 2 := by
|
||||
simp [Nat.mod_eq (x+2) 2, p, hyp]
|
||||
cases Nat.mod_two_eq_zero_or_one x with | _ p => simp [p]
|
||||
|
||||
private theorem testBit_succ_zero : testBit (x + 1) 0 = not (testBit x 0) := by
|
||||
private theorem testBit_succ_zero : testBit (x + 1) 0 = !(testBit x 0) := by
|
||||
simp [testBit_to_div_mod, succ_mod_two]
|
||||
cases Nat.mod_two_eq_zero_or_one x with | _ p =>
|
||||
simp [p]
|
||||
|
||||
theorem testBit_two_pow_add_eq (x i : Nat) : testBit (2^i + x) i = not (testBit x i) := by
|
||||
theorem testBit_two_pow_add_eq (x i : Nat) : testBit (2^i + x) i = !(testBit x i) := by
|
||||
simp [testBit_to_div_mod, add_div_left, Nat.two_pow_pos, succ_mod_two]
|
||||
cases mod_two_eq_zero_or_one (x / 2 ^ i) with
|
||||
| _ p => simp [p]
|
||||
@@ -476,16 +476,20 @@ theorem and_lt_two_pow (x : Nat) {y n : Nat} (right : y < 2^n) : (x &&& y) < 2^n
|
||||
exact pow_le_pow_of_le_right Nat.zero_lt_two i_ge_n
|
||||
simp [testBit_and, yf]
|
||||
|
||||
@[simp] theorem and_pow_two_is_mod (x n : Nat) : x &&& (2^n-1) = x % 2^n := by
|
||||
@[simp] theorem and_pow_two_sub_one_eq_mod (x n : Nat) : x &&& 2^n - 1 = x % 2^n := by
|
||||
apply eq_of_testBit_eq
|
||||
intro i
|
||||
simp only [testBit_and, testBit_mod_two_pow]
|
||||
cases testBit x i <;> simp
|
||||
|
||||
theorem and_pow_two_identity {x : Nat} (lt : x < 2^n) : x &&& 2^n-1 = x := by
|
||||
rw [and_pow_two_is_mod]
|
||||
@[deprecated and_pow_two_sub_one_eq_mod (since := "2024-09-11")] abbrev and_pow_two_is_mod := @and_pow_two_sub_one_eq_mod
|
||||
|
||||
theorem and_pow_two_sub_one_of_lt_two_pow {x : Nat} (lt : x < 2^n) : x &&& 2^n - 1 = x := by
|
||||
rw [and_pow_two_sub_one_eq_mod]
|
||||
apply Nat.mod_eq_of_lt lt
|
||||
|
||||
@[deprecated and_pow_two_sub_one_of_lt_two_pow (since := "2024-09-11")] abbrev and_two_pow_identity := @and_pow_two_sub_one_of_lt_two_pow
|
||||
|
||||
@[simp] theorem and_mod_two_eq_one : (a &&& b) % 2 = 1 ↔ a % 2 = 1 ∧ b % 2 = 1 := by
|
||||
simp only [mod_two_eq_one_iff_testBit_zero]
|
||||
rw [testBit_and]
|
||||
|
||||
@@ -84,9 +84,6 @@ protected theorem add_lt_add_of_lt_of_le {a b c d : Nat} (hlt : a < b) (hle : c
|
||||
a + c < b + d :=
|
||||
Nat.lt_of_le_of_lt (Nat.add_le_add_left hle _) (Nat.add_lt_add_right hlt _)
|
||||
|
||||
protected theorem lt_add_of_pos_left : 0 < k → n < k + n := by
|
||||
rw [Nat.add_comm]; exact Nat.lt_add_of_pos_right
|
||||
|
||||
protected theorem pos_of_lt_add_right (h : n < n + k) : 0 < k :=
|
||||
Nat.lt_of_add_lt_add_left h
|
||||
|
||||
@@ -577,6 +574,15 @@ theorem mul_mod (a b n : Nat) : a * b % n = (a % n) * (b % n) % n := by
|
||||
theorem add_mod (a b n : Nat) : (a + b) % n = ((a % n) + (b % n)) % n := by
|
||||
rw [add_mod_mod, mod_add_mod]
|
||||
|
||||
@[simp] theorem self_sub_mod (n k : Nat) [NeZero k] : (n - k) % n = n - k := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n =>
|
||||
rw [mod_eq_of_lt]
|
||||
cases k with
|
||||
| zero => simp_all
|
||||
| succ k => omega
|
||||
|
||||
/-! ### pow -/
|
||||
|
||||
theorem pow_succ' {m n : Nat} : m ^ n.succ = m * m ^ n := by
|
||||
|
||||
38
src/Init/Data/NeZero.lean
Normal file
38
src/Init/Data/NeZero.lean
Normal file
@@ -0,0 +1,38 @@
|
||||
/-
|
||||
Copyright (c) 2021 Eric Rodriguez. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Eric Rodriguez
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Zero
|
||||
|
||||
|
||||
/-!
|
||||
# `NeZero` typeclass
|
||||
|
||||
We create a typeclass `NeZero n` which carries around the fact that `(n : R) ≠ 0`.
|
||||
|
||||
## Main declarations
|
||||
|
||||
* `NeZero`: `n ≠ 0` as a typeclass.
|
||||
-/
|
||||
|
||||
|
||||
variable {R : Type _} [Zero R]
|
||||
|
||||
/-- A type-class version of `n ≠ 0`. -/
|
||||
class NeZero (n : R) : Prop where
|
||||
/-- The proposition that `n` is not zero. -/
|
||||
out : n ≠ 0
|
||||
|
||||
theorem NeZero.ne (n : R) [h : NeZero n] : n ≠ 0 :=
|
||||
h.out
|
||||
|
||||
theorem NeZero.ne' (n : R) [h : NeZero n] : 0 ≠ n :=
|
||||
h.out.symm
|
||||
|
||||
theorem neZero_iff {n : R} : NeZero n ↔ n ≠ 0 :=
|
||||
⟨fun h ↦ h.out, NeZero.mk⟩
|
||||
|
||||
@[simp] theorem neZero_zero_iff_false {α : Type _} [Zero α] : NeZero (0 : α) ↔ False :=
|
||||
⟨fun h ↦ h.ne rfl, fun h ↦ h.elim⟩
|
||||
@@ -6,6 +6,7 @@ Authors: Mario Carneiro
|
||||
prelude
|
||||
import Init.Data.Option.BasicAux
|
||||
import Init.Data.Option.Instances
|
||||
import Init.Data.BEq
|
||||
import Init.Classical
|
||||
import Init.Ext
|
||||
|
||||
@@ -13,7 +14,7 @@ namespace Option
|
||||
|
||||
theorem mem_iff {a : α} {b : Option α} : a ∈ b ↔ b = some a := .rfl
|
||||
|
||||
@[simp] theorem mem_some {a b : α} : a ∈ some b ↔ a = b := by simp [mem_iff, eq_comm]
|
||||
@[simp] theorem mem_some {a b : α} : a ∈ some b ↔ b = a := by simp [mem_iff]
|
||||
|
||||
theorem mem_some_self (a : α) : a ∈ some a := mem_some.2 rfl
|
||||
|
||||
@@ -247,6 +248,12 @@ theorem isSome_filter_of_isSome (p : α → Bool) (o : Option α) (h : (o.filter
|
||||
theorem bind_map_comm {α β} {x : Option (Option α)} {f : α → β} :
|
||||
x.bind (Option.map f) = (x.map (Option.map f)).bind id := by cases x <;> simp
|
||||
|
||||
theorem bind_map {f : α → β} {g : β → Option γ} {x : Option α} :
|
||||
(x.map f).bind g = x.bind (g ∘ f) := by cases x <;> simp
|
||||
|
||||
@[simp] theorem map_bind {f : α → Option β} {g : β → γ} {x : Option α} :
|
||||
(x.bind f).map g = x.bind (Option.map g ∘ f) := by cases x <;> simp
|
||||
|
||||
theorem join_map_eq_map_join {f : α → β} {x : Option (Option α)} :
|
||||
(x.map (Option.map f)).join = x.join.map f := by cases x <;> simp
|
||||
|
||||
@@ -277,6 +284,27 @@ theorem map_orElse {x y : Option α} : (x <|> y).map f = (x.map f <|> y.map f) :
|
||||
@[simp] theorem guard_pos [DecidablePred p] (h : p a) : Option.guard p a = some a := by
|
||||
simp [Option.guard, h]
|
||||
|
||||
@[congr] theorem guard_congr {f g : α → Prop} [DecidablePred f] [DecidablePred g]
|
||||
(h : ∀ a, f a ↔ g a):
|
||||
guard f = guard g := by
|
||||
funext a
|
||||
simp [guard, h]
|
||||
|
||||
@[simp] theorem guard_false {α} :
|
||||
guard (fun (_ : α) => False) = fun _ => none := by
|
||||
funext a
|
||||
simp [guard]
|
||||
|
||||
@[simp] theorem guard_true {α} :
|
||||
guard (fun (_ : α) => True) = some := by
|
||||
funext a
|
||||
simp [guard]
|
||||
|
||||
theorem guard_comp {p : α → Prop} [DecidablePred p] {f : β → α} :
|
||||
guard p ∘ f = Option.map f ∘ guard (p ∘ f) := by
|
||||
ext1 b
|
||||
simp [guard]
|
||||
|
||||
theorem liftOrGet_eq_or_eq {f : α → α → α} (h : ∀ a b, f a b = a ∨ f a b = b) :
|
||||
∀ o₁ o₂, liftOrGet f o₁ o₂ = o₁ ∨ liftOrGet f o₁ o₂ = o₂
|
||||
| none, none => .inl rfl
|
||||
@@ -384,6 +412,37 @@ variable [BEq α]
|
||||
@[simp] theorem some_beq_none (a : α) : ((some a : Option α) == none) = false := rfl
|
||||
@[simp] theorem some_beq_some {a b : α} : (some a == some b) = (a == b) := rfl
|
||||
|
||||
@[simp] theorem reflBEq_iff : ReflBEq (Option α) ↔ ReflBEq α := by
|
||||
constructor
|
||||
· intro h
|
||||
constructor
|
||||
intro a
|
||||
suffices (some a == some a) = true by
|
||||
simpa only [some_beq_some]
|
||||
simp
|
||||
· intro h
|
||||
constructor
|
||||
· rintro (_ | a) <;> simp
|
||||
|
||||
@[simp] theorem lawfulBEq_iff : LawfulBEq (Option α) ↔ LawfulBEq α := by
|
||||
constructor
|
||||
· intro h
|
||||
constructor
|
||||
· intro a b h
|
||||
apply Option.some.inj
|
||||
apply eq_of_beq
|
||||
simpa
|
||||
· intro a
|
||||
suffices (some a == some a) = true by
|
||||
simpa only [some_beq_some]
|
||||
simp
|
||||
· intro h
|
||||
constructor
|
||||
· intro a b h
|
||||
simpa using h
|
||||
· intro a
|
||||
simp
|
||||
|
||||
end beq
|
||||
|
||||
/-! ### ite -/
|
||||
@@ -405,6 +464,38 @@ section ite
|
||||
(x ∈ if p then l else none) ↔ p ∧ x ∈ l := by
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem dite_none_left_eq_some {p : Prop} [Decidable p] {b : ¬p → Option β} :
|
||||
(if h : p then none else b h) = some a ↔ ∃ h, b h = some a := by
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem dite_none_right_eq_some {p : Prop} [Decidable p] {b : p → Option α} :
|
||||
(if h : p then b h else none) = some a ↔ ∃ h, b h = some a := by
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem some_eq_dite_none_left {p : Prop} [Decidable p] {b : ¬p → Option β} :
|
||||
some a = (if h : p then none else b h) ↔ ∃ h, some a = b h := by
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem some_eq_dite_none_right {p : Prop} [Decidable p] {b : p → Option α} :
|
||||
some a = (if h : p then b h else none) ↔ ∃ h, some a = b h := by
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem ite_none_left_eq_some {p : Prop} [Decidable p] {b : Option β} :
|
||||
(if p then none else b) = some a ↔ ¬ p ∧ b = some a := by
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem ite_none_right_eq_some {p : Prop} [Decidable p] {b : Option α} :
|
||||
(if p then b else none) = some a ↔ p ∧ b = some a := by
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem some_eq_ite_none_left {p : Prop} [Decidable p] {b : Option β} :
|
||||
some a = (if p then none else b) ↔ ¬ p ∧ some a = b := by
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem some_eq_ite_none_right {p : Prop} [Decidable p] {b : Option α} :
|
||||
some a = (if p then b else none) ↔ p ∧ some a = b := by
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem isSome_dite {p : Prop} [Decidable p] {b : p → β} :
|
||||
(if h : p then some (b h) else none).isSome = true ↔ p := by
|
||||
split <;> simpa
|
||||
|
||||
@@ -290,11 +290,17 @@ instance (a b : UInt64) : Decidable (a ≤ b) := UInt64.decLe a b
|
||||
instance : Max UInt64 := maxOfLe
|
||||
instance : Min UInt64 := minOfLe
|
||||
|
||||
-- This instance would interfere with the global instance `NeZero (n + 1)`,
|
||||
-- so we only enable it locally.
|
||||
@[local instance]
|
||||
private def instNeZeroUSizeSize : NeZero USize.size := ⟨add_one_ne_zero _⟩
|
||||
|
||||
@[deprecated (since := "2024-09-16")]
|
||||
theorem usize_size_gt_zero : USize.size > 0 :=
|
||||
Nat.zero_lt_succ ..
|
||||
|
||||
@[extern "lean_usize_of_nat"]
|
||||
def USize.ofNat (n : @& Nat) : USize := ⟨Fin.ofNat' n usize_size_gt_zero⟩
|
||||
def USize.ofNat (n : @& Nat) : USize := ⟨Fin.ofNat' _ n⟩
|
||||
abbrev Nat.toUSize := USize.ofNat
|
||||
@[extern "lean_usize_to_nat"]
|
||||
def USize.toNat (n : USize) : Nat := n.val.val
|
||||
|
||||
17
src/Init/Data/Zero.lean
Normal file
17
src/Init/Data/Zero.lean
Normal file
@@ -0,0 +1,17 @@
|
||||
/-
|
||||
Copyright (c) 2021 Gabriel Ebner. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Gabriel Ebner, Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Core
|
||||
|
||||
/-!
|
||||
Instances converting between `Zero α` and `OfNat α (nat_lit 0)`.
|
||||
-/
|
||||
|
||||
instance (priority := 300) Zero.toOfNat0 {α} [Zero α] : OfNat α (nat_lit 0) where
|
||||
ofNat := ‹Zero α›.1
|
||||
|
||||
instance (priority := 200) Zero.ofOfNat0 {α} [OfNat α (nat_lit 0)] : Zero α where
|
||||
zero := 0
|
||||
@@ -1014,7 +1014,7 @@ with `Or : Prop → Prop → Prop`, which is the propositional connective).
|
||||
It is `@[macro_inline]` because it has C-like short-circuiting behavior:
|
||||
if `x` is true then `y` is not evaluated.
|
||||
-/
|
||||
@[macro_inline] def or (x y : Bool) : Bool :=
|
||||
@[macro_inline] def Bool.or (x y : Bool) : Bool :=
|
||||
match x with
|
||||
| true => true
|
||||
| false => y
|
||||
@@ -1025,7 +1025,7 @@ with `And : Prop → Prop → Prop`, which is the propositional connective).
|
||||
It is `@[macro_inline]` because it has C-like short-circuiting behavior:
|
||||
if `x` is false then `y` is not evaluated.
|
||||
-/
|
||||
@[macro_inline] def and (x y : Bool) : Bool :=
|
||||
@[macro_inline] def Bool.and (x y : Bool) : Bool :=
|
||||
match x with
|
||||
| false => false
|
||||
| true => y
|
||||
@@ -1034,10 +1034,12 @@ if `x` is false then `y` is not evaluated.
|
||||
`not x`, or `!x`, is the boolean "not" operation (not to be confused
|
||||
with `Not : Prop → Prop`, which is the propositional connective).
|
||||
-/
|
||||
@[inline] def not : Bool → Bool
|
||||
@[inline] def Bool.not : Bool → Bool
|
||||
| true => false
|
||||
| false => true
|
||||
|
||||
export Bool (or and not)
|
||||
|
||||
/--
|
||||
The type of natural numbers, starting at zero. It is defined as an
|
||||
inductive type freely generated by "zero is a natural number" and
|
||||
@@ -1304,6 +1306,11 @@ class HShiftRight (α : Type u) (β : Type v) (γ : outParam (Type w)) where
|
||||
this is equivalent to `a / 2 ^ b`. -/
|
||||
hShiftRight : α → β → γ
|
||||
|
||||
/-- A type with a zero element. -/
|
||||
class Zero (α : Type u) where
|
||||
/-- The zero element of the type. -/
|
||||
zero : α
|
||||
|
||||
/-- The homogeneous version of `HAdd`: `a + b : α` where `a b : α`. -/
|
||||
class Add (α : Type u) where
|
||||
/-- `a + b` computes the sum of `a` and `b`. See `HAdd`. -/
|
||||
@@ -2568,17 +2575,17 @@ structure Array (α : Type u) where
|
||||
/--
|
||||
Converts a `Array α` into an `List α`.
|
||||
|
||||
At runtime, this projection is implemented by `Array.toList` and is O(n) in the length of the
|
||||
At runtime, this projection is implemented by `Array.toListImpl` and is O(n) in the length of the
|
||||
array. -/
|
||||
data : List α
|
||||
toList : List α
|
||||
|
||||
attribute [extern "lean_array_data"] Array.data
|
||||
attribute [extern "lean_array_to_list"] Array.toList
|
||||
attribute [extern "lean_array_mk"] Array.mk
|
||||
|
||||
/-- Construct a new empty array with initial capacity `c`. -/
|
||||
@[extern "lean_mk_empty_array_with_capacity"]
|
||||
def Array.mkEmpty {α : Type u} (c : @& Nat) : Array α where
|
||||
data := List.nil
|
||||
toList := List.nil
|
||||
|
||||
/-- Construct a new empty array. -/
|
||||
def Array.empty {α : Type u} : Array α := mkEmpty 0
|
||||
@@ -2586,12 +2593,12 @@ def Array.empty {α : Type u} : Array α := mkEmpty 0
|
||||
/-- Get the size of an array. This is a cached value, so it is O(1) to access. -/
|
||||
@[reducible, extern "lean_array_get_size"]
|
||||
def Array.size {α : Type u} (a : @& Array α) : Nat :=
|
||||
a.data.length
|
||||
a.toList.length
|
||||
|
||||
/-- Access an element from an array without bounds checks, using a `Fin` index. -/
|
||||
@[extern "lean_array_fget"]
|
||||
def Array.get {α : Type u} (a : @& Array α) (i : @& Fin a.size) : α :=
|
||||
a.data.get i
|
||||
a.toList.get i
|
||||
|
||||
/-- Access an element from an array, or return `v₀` if the index is out of bounds. -/
|
||||
@[inline] abbrev Array.getD (a : Array α) (i : Nat) (v₀ : α) : α :=
|
||||
@@ -2608,7 +2615,7 @@ Push an element onto the end of an array. This is amortized O(1) because
|
||||
-/
|
||||
@[extern "lean_array_push"]
|
||||
def Array.push {α : Type u} (a : Array α) (v : α) : Array α where
|
||||
data := List.concat a.data v
|
||||
toList := List.concat a.toList v
|
||||
|
||||
/-- Create array `#[]` -/
|
||||
def Array.mkArray0 {α : Type u} : Array α :=
|
||||
@@ -2654,7 +2661,7 @@ count of 1 when called.
|
||||
-/
|
||||
@[extern "lean_array_fset"]
|
||||
def Array.set (a : Array α) (i : @& Fin a.size) (v : α) : Array α where
|
||||
data := a.data.set i.val v
|
||||
toList := a.toList.set i.val v
|
||||
|
||||
/--
|
||||
Set an element in an array, or do nothing if the index is out of bounds.
|
||||
|
||||
@@ -556,6 +556,9 @@ This is the same as `decidable_of_iff` but the iff is flipped. -/
|
||||
instance Decidable.predToBool (p : α → Prop) [DecidablePred p] :
|
||||
CoeDep (α → Prop) p (α → Bool) := ⟨fun b => decide <| p b⟩
|
||||
|
||||
instance [DecidablePred p] : DecidablePred (p ∘ f) :=
|
||||
fun x => inferInstanceAs (Decidable (p (f x)))
|
||||
|
||||
/-- Prove that `a` is decidable by constructing a boolean `b` and a proof that `b ↔ a`.
|
||||
(This is sometimes taken as an alternate definition of decidability.) -/
|
||||
def decidable_of_bool : ∀ (b : Bool), (b ↔ a) → Decidable a
|
||||
|
||||
@@ -91,7 +91,7 @@ private def isBorrowParamAux (x : VarId) (ys : Array Arg) (consumeParamPred : Na
|
||||
| Arg.var y => x == y && !consumeParamPred i
|
||||
|
||||
private def isBorrowParam (x : VarId) (ys : Array Arg) (ps : Array Param) : Bool :=
|
||||
isBorrowParamAux x ys fun i => not ps[i]!.borrow
|
||||
isBorrowParamAux x ys fun i => ! ps[i]!.borrow
|
||||
|
||||
/--
|
||||
Return `n`, the number of times `x` is consumed.
|
||||
@@ -124,7 +124,7 @@ private def addIncBeforeAux (ctx : Context) (xs : Array Arg) (consumeParamPred :
|
||||
addInc ctx x b numIncs
|
||||
|
||||
private def addIncBefore (ctx : Context) (xs : Array Arg) (ps : Array Param) (b : FnBody) (liveVarsAfter : LiveVarSet) : FnBody :=
|
||||
addIncBeforeAux ctx xs (fun i => not ps[i]!.borrow) b liveVarsAfter
|
||||
addIncBeforeAux ctx xs (fun i => ! ps[i]!.borrow) b liveVarsAfter
|
||||
|
||||
/-- See `addIncBeforeAux`/`addIncBefore` for the procedure that inserts `inc` operations before an application. -/
|
||||
private def addDecAfterFullApp (ctx : Context) (xs : Array Arg) (ps : Array Param) (b : FnBody) (bLiveVars : LiveVarSet) : FnBody :=
|
||||
|
||||
@@ -317,8 +317,8 @@ variable {m : Type → Type w} [Monad m]
|
||||
anyMAux p t.root <||> t.tail.anyM p
|
||||
|
||||
@[inline] def allM (a : PersistentArray α) (p : α → m Bool) : m Bool := do
|
||||
let b ← anyM a (fun v => do let b ← p v; pure (not b))
|
||||
pure (not b)
|
||||
let b ← anyM a (fun v => do let b ← p v; pure (!b))
|
||||
pure (!b)
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ instance : Repr Rat where
|
||||
|
||||
@[inline] def Rat.normalize (a : Rat) : Rat :=
|
||||
let n := Nat.gcd a.num.natAbs a.den
|
||||
if n == 1 then a else { num := a.num.div n, den := a.den / n }
|
||||
if n == 1 then a else { num := a.num.tdiv n, den := a.den / n }
|
||||
|
||||
def mkRat (num : Int) (den : Nat) : Rat :=
|
||||
if den == 0 then { num := 0 } else Rat.normalize { num, den }
|
||||
@@ -53,7 +53,7 @@ protected def lt (a b : Rat) : Bool :=
|
||||
protected def mul (a b : Rat) : Rat :=
|
||||
let g1 := Nat.gcd a.den b.num.natAbs
|
||||
let g2 := Nat.gcd a.num.natAbs b.den
|
||||
{ num := (a.num.div g2)*(b.num.div g1)
|
||||
{ num := (a.num.tdiv g2)*(b.num.tdiv g1)
|
||||
den := (b.den / g2)*(a.den / g1) }
|
||||
|
||||
protected def inv (a : Rat) : Rat :=
|
||||
@@ -78,7 +78,7 @@ protected def add (a b : Rat) : Rat :=
|
||||
if g1 == 1 then
|
||||
{ num, den }
|
||||
else
|
||||
{ num := num.div g1, den := den / g1 }
|
||||
{ num := num.tdiv g1, den := den / g1 }
|
||||
|
||||
protected def sub (a b : Rat) : Rat :=
|
||||
let g := Nat.gcd a.den b.den
|
||||
@@ -91,7 +91,7 @@ protected def sub (a b : Rat) : Rat :=
|
||||
if g1 == 1 then
|
||||
{ num, den }
|
||||
else
|
||||
{ num := num.div g1, den := den / g1 }
|
||||
{ num := num.tdiv g1, den := den / g1 }
|
||||
|
||||
protected def neg (a : Rat) : Rat :=
|
||||
{ a with num := - a.num }
|
||||
@@ -100,14 +100,14 @@ protected def floor (a : Rat) : Int :=
|
||||
if a.den == 1 then
|
||||
a.num
|
||||
else
|
||||
let r := a.num.mod a.den
|
||||
let r := a.num.tmod a.den
|
||||
if a.num < 0 then r - 1 else r
|
||||
|
||||
protected def ceil (a : Rat) : Int :=
|
||||
if a.den == 1 then
|
||||
a.num
|
||||
else
|
||||
let r := a.num.mod a.den
|
||||
let r := a.num.tmod a.den
|
||||
if a.num > 0 then r + 1 else r
|
||||
|
||||
instance : LT Rat where
|
||||
|
||||
@@ -1594,10 +1594,13 @@ private def elabAtom : TermElab := fun stx expectedType? => do
|
||||
@[builtin_term_elab dotIdent] def elabDotIdent : TermElab := elabAtom
|
||||
@[builtin_term_elab explicitUniv] def elabExplicitUniv : TermElab := elabAtom
|
||||
@[builtin_term_elab pipeProj] def elabPipeProj : TermElab
|
||||
| `($e |>.$f $args*), expectedType? =>
|
||||
| `($e |>.%$tk$f $args*), expectedType? =>
|
||||
universeConstraintsCheckpoint do
|
||||
let (namedArgs, args, ellipsis) ← expandArgs args
|
||||
elabAppAux (← `($e |>.$f)) namedArgs args (ellipsis := ellipsis) expectedType?
|
||||
let mut stx ← `($e |>.%$tk$f)
|
||||
if let (some startPos, some stopPos) := (e.raw.getPos?, f.raw.getTailPos?) then
|
||||
stx := ⟨stx.raw.setInfo <| .synthetic (canonical := true) startPos stopPos⟩
|
||||
elabAppAux stx namedArgs args (ellipsis := ellipsis) expectedType?
|
||||
| _, _ => throwUnsupportedSyntax
|
||||
|
||||
@[builtin_term_elab explicit] def elabExplicit : TermElab := fun stx expectedType? =>
|
||||
|
||||
@@ -15,145 +15,109 @@ open Lean.Json
|
||||
open Lean.Parser.Term
|
||||
open Lean.Meta
|
||||
|
||||
def mkToJsonHeader (indVal : InductiveVal) : TermElabM Header := do
|
||||
mkHeader ``ToJson 1 indVal
|
||||
|
||||
def mkFromJsonHeader (indVal : InductiveVal) : TermElabM Header := do
|
||||
let header ← mkHeader ``FromJson 0 indVal
|
||||
let jsonArg ← `(bracketedBinderF|(json : Json))
|
||||
return {header with
|
||||
binders := header.binders.push jsonArg}
|
||||
|
||||
def mkJsonField (n : Name) : CoreM (Bool × Term) := do
|
||||
let .str .anonymous s := n | throwError "invalid json field name {n}"
|
||||
let s₁ := s.dropRightWhile (· == '?')
|
||||
return (s != s₁, Syntax.mkStrLit s₁)
|
||||
|
||||
def mkToJsonInstance (declName : Name) : CommandElabM Bool := do
|
||||
if isStructure (← getEnv) declName then
|
||||
let cmds ← liftTermElabM do
|
||||
let ctx ← mkContext "toJson" declName
|
||||
let header ← mkHeader ``ToJson 1 ctx.typeInfos[0]!
|
||||
let fields := getStructureFieldsFlattened (← getEnv) declName (includeSubobjectFields := false)
|
||||
let fields ← fields.mapM fun field => do
|
||||
let (isOptField, nm) ← mkJsonField field
|
||||
let target := mkIdent header.targetNames[0]!
|
||||
if isOptField then ``(opt $nm ($target).$(mkIdent field))
|
||||
else ``([($nm, toJson ($target).$(mkIdent field))])
|
||||
let cmd ← `(private def $(mkIdent ctx.auxFunNames[0]!):ident $header.binders:bracketedBinder* : Json :=
|
||||
mkObj <| List.join [$fields,*])
|
||||
return #[cmd] ++ (← mkInstanceCmds ctx ``ToJson #[declName])
|
||||
cmds.forM elabCommand
|
||||
return true
|
||||
else
|
||||
let indVal ← getConstInfoInduct declName
|
||||
let cmds ← liftTermElabM do
|
||||
let ctx ← mkContext "toJson" declName
|
||||
let toJsonFuncId := mkIdent ctx.auxFunNames[0]!
|
||||
-- Return syntax to JSONify `id`, either via `ToJson` or recursively
|
||||
-- if `id`'s type is the type we're deriving for.
|
||||
let mkToJson (id : Ident) (type : Expr) : TermElabM Term := do
|
||||
def mkToJsonBodyForStruct (header : Header) (indName : Name) : TermElabM Term := do
|
||||
let fields := getStructureFieldsFlattened (← getEnv) indName (includeSubobjectFields := false)
|
||||
let fields ← fields.mapM fun field => do
|
||||
let (isOptField, nm) ← mkJsonField field
|
||||
let target := mkIdent header.targetNames[0]!
|
||||
if isOptField then ``(opt $nm $target.$(mkIdent field))
|
||||
else ``([($nm, toJson ($target).$(mkIdent field))])
|
||||
`(mkObj <| List.join [$fields,*])
|
||||
|
||||
def mkToJsonBodyForInduct (ctx : Context) (header : Header) (indName : Name) : TermElabM Term := do
|
||||
let indVal ← getConstInfoInduct indName
|
||||
let toJsonFuncId := mkIdent ctx.auxFunNames[0]!
|
||||
-- Return syntax to JSONify `id`, either via `ToJson` or recursively
|
||||
-- if `id`'s type is the type we're deriving for.
|
||||
let mkToJson (id : Ident) (type : Expr) : TermElabM Term := do
|
||||
if type.isAppOf indVal.name then `($toJsonFuncId:ident $id:ident)
|
||||
else ``(toJson $id:ident)
|
||||
let header ← mkHeader ``ToJson 1 ctx.typeInfos[0]!
|
||||
let discrs ← mkDiscrs header indVal
|
||||
let alts ← mkAlts indVal fun ctor args userNames => do
|
||||
let ctorStr := ctor.name.eraseMacroScopes.getString!
|
||||
match args, userNames with
|
||||
| #[], _ => ``(toJson $(quote ctorStr))
|
||||
| #[(x, t)], none => ``(mkObj [($(quote ctorStr), $(← mkToJson x t))])
|
||||
| xs, none =>
|
||||
let xs ← xs.mapM fun (x, t) => mkToJson x t
|
||||
``(mkObj [($(quote ctorStr), Json.arr #[$[$xs:term],*])])
|
||||
| xs, some userNames =>
|
||||
let xs ← xs.mapIdxM fun idx (x, t) => do
|
||||
`(($(quote userNames[idx]!.eraseMacroScopes.getString!), $(← mkToJson x t)))
|
||||
``(mkObj [($(quote ctorStr), mkObj [$[$xs:term],*])])
|
||||
let auxTerm ← `(match $[$discrs],* with $alts:matchAlt*)
|
||||
let auxCmd ←
|
||||
if ctx.usePartial then
|
||||
let letDecls ← mkLocalInstanceLetDecls ctx ``ToJson header.argNames
|
||||
let auxTerm ← mkLet letDecls auxTerm
|
||||
`(private partial def $toJsonFuncId:ident $header.binders:bracketedBinder* : Json := $auxTerm)
|
||||
else
|
||||
`(private def $toJsonFuncId:ident $header.binders:bracketedBinder* : Json := $auxTerm)
|
||||
return #[auxCmd] ++ (← mkInstanceCmds ctx ``ToJson #[declName])
|
||||
cmds.forM elabCommand
|
||||
return true
|
||||
let discrs ← mkDiscrs header indVal
|
||||
let alts ← mkAlts indVal fun ctor args userNames => do
|
||||
let ctorStr := ctor.name.eraseMacroScopes.getString!
|
||||
match args, userNames with
|
||||
| #[], _ => ``(toJson $(quote ctorStr))
|
||||
| #[(x, t)], none => ``(mkObj [($(quote ctorStr), $(← mkToJson x t))])
|
||||
| xs, none =>
|
||||
let xs ← xs.mapM fun (x, t) => mkToJson x t
|
||||
``(mkObj [($(quote ctorStr), Json.arr #[$[$xs:term],*])])
|
||||
| xs, some userNames =>
|
||||
let xs ← xs.mapIdxM fun idx (x, t) => do
|
||||
`(($(quote userNames[idx]!.eraseMacroScopes.getString!), $(← mkToJson x t)))
|
||||
``(mkObj [($(quote ctorStr), mkObj [$[$xs:term],*])])
|
||||
`(match $[$discrs],* with $alts:matchAlt*)
|
||||
|
||||
where
|
||||
mkAlts
|
||||
(indVal : InductiveVal)
|
||||
(rhs : ConstructorVal → Array (Ident × Expr) → Option (Array Name) → TermElabM Term) : TermElabM (Array (TSyntax ``matchAlt)) := do
|
||||
indVal.ctors.toArray.mapM fun ctor => do
|
||||
let ctorInfo ← getConstInfoCtor ctor
|
||||
forallTelescopeReducing ctorInfo.type fun xs _ => do
|
||||
let mut patterns := #[]
|
||||
-- add `_` pattern for indices
|
||||
for _ in [:indVal.numIndices] do
|
||||
patterns := patterns.push (← `(_))
|
||||
let mut ctorArgs := #[]
|
||||
-- add `_` for inductive parameters, they are inaccessible
|
||||
for _ in [:indVal.numParams] do
|
||||
ctorArgs := ctorArgs.push (← `(_))
|
||||
-- bound constructor arguments and their types
|
||||
let mut binders := #[]
|
||||
let mut userNames := #[]
|
||||
for i in [:ctorInfo.numFields] do
|
||||
let x := xs[indVal.numParams + i]!
|
||||
let localDecl ← x.fvarId!.getDecl
|
||||
if !localDecl.userName.hasMacroScopes then
|
||||
userNames := userNames.push localDecl.userName
|
||||
let a := mkIdent (← mkFreshUserName `a)
|
||||
binders := binders.push (a, localDecl.type)
|
||||
ctorArgs := ctorArgs.push a
|
||||
patterns := patterns.push (← `(@$(mkIdent ctorInfo.name):ident $ctorArgs:term*))
|
||||
let rhs ← rhs ctorInfo binders (if userNames.size == binders.size then some userNames else none)
|
||||
`(matchAltExpr| | $[$patterns:term],* => $rhs:term)
|
||||
(rhs : ConstructorVal → Array (Ident × Expr) → Option (Array Name) → TermElabM Term): TermElabM (Array (TSyntax ``matchAlt)) := do
|
||||
let mut alts := #[]
|
||||
for ctorName in indVal.ctors do
|
||||
let ctorInfo ← getConstInfoCtor ctorName
|
||||
let alt ← forallTelescopeReducing ctorInfo.type fun xs _ => do
|
||||
let mut patterns := #[]
|
||||
-- add `_` pattern for indices
|
||||
for _ in [:indVal.numIndices] do
|
||||
patterns := patterns.push (← `(_))
|
||||
let mut ctorArgs := #[]
|
||||
-- add `_` for inductive parameters, they are inaccessible
|
||||
for _ in [:indVal.numParams] do
|
||||
ctorArgs := ctorArgs.push (← `(_))
|
||||
-- bound constructor arguments and their types
|
||||
let mut binders := #[]
|
||||
let mut userNames := #[]
|
||||
for i in [:ctorInfo.numFields] do
|
||||
let x := xs[indVal.numParams + i]!
|
||||
let localDecl ← x.fvarId!.getDecl
|
||||
if !localDecl.userName.hasMacroScopes then
|
||||
userNames := userNames.push localDecl.userName
|
||||
let a := mkIdent (← mkFreshUserName `a)
|
||||
binders := binders.push (a, localDecl.type)
|
||||
ctorArgs := ctorArgs.push a
|
||||
patterns := patterns.push (← `(@$(mkIdent ctorInfo.name):ident $ctorArgs:term*))
|
||||
let rhs ← rhs ctorInfo binders (if userNames.size == binders.size then some userNames else none)
|
||||
`(matchAltExpr| | $[$patterns:term],* => $rhs:term)
|
||||
alts := alts.push alt
|
||||
return alts
|
||||
|
||||
def mkFromJsonInstance (declName : Name) : CommandElabM Bool := do
|
||||
if isStructure (← getEnv) declName then
|
||||
let cmds ← liftTermElabM do
|
||||
let ctx ← mkContext "fromJson" declName
|
||||
let header ← mkHeader ``FromJson 0 ctx.typeInfos[0]!
|
||||
let fields := getStructureFieldsFlattened (← getEnv) declName (includeSubobjectFields := false)
|
||||
let getters ← fields.mapM (fun field => do
|
||||
let getter ← `(getObjValAs? j _ $(Prod.snd <| ← mkJsonField field))
|
||||
let getter ← `(doElem| Except.mapError (fun s => (toString $(quote declName)) ++ "." ++ (toString $(quote field)) ++ ": " ++ s) <| $getter)
|
||||
return getter
|
||||
)
|
||||
let fields := fields.map mkIdent
|
||||
let cmd ← `(private def $(mkIdent ctx.auxFunNames[0]!):ident $header.binders:bracketedBinder* (j : Json)
|
||||
: Except String $(← mkInductiveApp ctx.typeInfos[0]! header.argNames) := do
|
||||
$[let $fields:ident ← $getters]*
|
||||
return { $[$fields:ident := $(id fields)],* })
|
||||
return #[cmd] ++ (← mkInstanceCmds ctx ``FromJson #[declName])
|
||||
cmds.forM elabCommand
|
||||
return true
|
||||
else
|
||||
let indVal ← getConstInfoInduct declName
|
||||
let cmds ← liftTermElabM do
|
||||
let ctx ← mkContext "fromJson" declName
|
||||
let header ← mkHeader ``FromJson 0 ctx.typeInfos[0]!
|
||||
let fromJsonFuncId := mkIdent ctx.auxFunNames[0]!
|
||||
let alts ← mkAlts indVal fromJsonFuncId
|
||||
let mut auxTerm ← alts.foldrM (fun xs x => `(Except.orElseLazy $xs (fun _ => $x))) (← `(Except.error "no inductive constructor matched"))
|
||||
if ctx.usePartial then
|
||||
let letDecls ← mkLocalInstanceLetDecls ctx ``FromJson header.argNames
|
||||
auxTerm ← mkLet letDecls auxTerm
|
||||
-- FromJson is not structurally recursive even non-nested recursive inductives,
|
||||
-- so we also use `partial` then.
|
||||
let auxCmd ←
|
||||
if ctx.usePartial || indVal.isRec then
|
||||
`(private partial def $fromJsonFuncId:ident $header.binders:bracketedBinder* (json : Json)
|
||||
: Except String $(← mkInductiveApp ctx.typeInfos[0]! header.argNames) :=
|
||||
$auxTerm)
|
||||
else
|
||||
`(private def $fromJsonFuncId:ident $header.binders:bracketedBinder* (json : Json)
|
||||
: Except String $(← mkInductiveApp ctx.typeInfos[0]! header.argNames) :=
|
||||
$auxTerm)
|
||||
return #[auxCmd] ++ (← mkInstanceCmds ctx ``FromJson #[declName])
|
||||
cmds.forM elabCommand
|
||||
return true
|
||||
def mkFromJsonBodyForStruct (indName : Name) : TermElabM Term := do
|
||||
let fields := getStructureFieldsFlattened (← getEnv) indName (includeSubobjectFields := false)
|
||||
let getters ← fields.mapM (fun field => do
|
||||
let getter ← `(getObjValAs? json _ $(Prod.snd <| ← mkJsonField field))
|
||||
let getter ← `(doElem| Except.mapError (fun s => (toString $(quote indName)) ++ "." ++ (toString $(quote field)) ++ ": " ++ s) <| $getter)
|
||||
return getter
|
||||
)
|
||||
let fields := fields.map mkIdent
|
||||
`(do
|
||||
$[let $fields:ident ← $getters]*
|
||||
return { $[$fields:ident := $(id fields)],* })
|
||||
|
||||
def mkFromJsonBodyForInduct (ctx : Context) (indName : Name) : TermElabM Term := do
|
||||
let indVal ← getConstInfoInduct indName
|
||||
let alts ← mkAlts indVal
|
||||
let auxTerm ← alts.foldrM (fun xs x => `(Except.orElseLazy $xs (fun _ => $x))) (← `(Except.error "no inductive constructor matched"))
|
||||
`($auxTerm)
|
||||
where
|
||||
mkAlts (indVal : InductiveVal) (fromJsonFuncId : Ident) : TermElabM (Array Term) := do
|
||||
let alts ←
|
||||
indVal.ctors.toArray.mapM fun ctor => do
|
||||
let ctorInfo ← getConstInfoCtor ctor
|
||||
forallTelescopeReducing ctorInfo.type fun xs _ => do
|
||||
let mut binders := #[]
|
||||
mkAlts (indVal : InductiveVal) : TermElabM (Array Term) := do
|
||||
let mut alts := #[]
|
||||
for ctorName in indVal.ctors do
|
||||
let ctorInfo ← getConstInfoCtor ctorName
|
||||
let alt ← do forallTelescopeReducing ctorInfo.type fun xs _ => do
|
||||
let mut binders := #[]
|
||||
let mut userNames := #[]
|
||||
for i in [:ctorInfo.numFields] do
|
||||
let x := xs[indVal.numParams + i]!
|
||||
@@ -162,7 +126,7 @@ where
|
||||
userNames := userNames.push localDecl.userName
|
||||
let a := mkIdent (← mkFreshUserName `a)
|
||||
binders := binders.push (a, localDecl.type)
|
||||
|
||||
let fromJsonFuncId := mkIdent ctx.auxFunNames[0]!
|
||||
-- Return syntax to parse `id`, either via `FromJson` or recursively
|
||||
-- if `id`'s type is the type we're deriving for.
|
||||
let mkFromJson (idx : Nat) (type : Expr) : TermElabM (TSyntax ``doExpr) :=
|
||||
@@ -175,23 +139,111 @@ where
|
||||
else
|
||||
``(none)
|
||||
let stx ←
|
||||
`((Json.parseTagged json $(quote ctor.eraseMacroScopes.getString!) $(quote ctorInfo.numFields) $(quote userNamesOpt)).bind
|
||||
`((Json.parseTagged json $(quote ctorName.eraseMacroScopes.getString!) $(quote ctorInfo.numFields) $(quote userNamesOpt)).bind
|
||||
(fun jsons => do
|
||||
$[let $identNames:ident ← $fromJsons:doExpr]*
|
||||
return $(mkIdent ctor):ident $identNames*))
|
||||
return $(mkIdent ctorName):ident $identNames*))
|
||||
pure (stx, ctorInfo.numFields)
|
||||
alts := alts.push alt
|
||||
-- the smaller cases, especially the ones without fields are likely faster
|
||||
let alts := alts.qsort (fun (_, x) (_, y) => x < y)
|
||||
return alts.map Prod.fst
|
||||
let alts' := alts.qsort (fun (_, x) (_, y) => x < y)
|
||||
return alts'.map Prod.fst
|
||||
|
||||
def mkToJsonBody (ctx : Context) (header : Header) (e : Expr): TermElabM Term := do
|
||||
let indName := e.getAppFn.constName!
|
||||
if isStructure (← getEnv) indName then
|
||||
mkToJsonBodyForStruct header indName
|
||||
else
|
||||
mkToJsonBodyForInduct ctx header indName
|
||||
|
||||
def mkToJsonAuxFunction (ctx : Context) (i : Nat) : TermElabM Command := do
|
||||
let auxFunName := ctx.auxFunNames[i]!
|
||||
let header ← mkToJsonHeader ctx.typeInfos[i]!
|
||||
let binders := header.binders
|
||||
Term.elabBinders binders fun _ => do
|
||||
let type ← Term.elabTerm header.targetType none
|
||||
let mut body ← mkToJsonBody ctx header type
|
||||
if ctx.usePartial then
|
||||
let letDecls ← mkLocalInstanceLetDecls ctx ``ToJson header.argNames
|
||||
body ← mkLet letDecls body
|
||||
`(private partial def $(mkIdent auxFunName):ident $binders:bracketedBinder* : Json := $body:term)
|
||||
else
|
||||
`(private def $(mkIdent auxFunName):ident $binders:bracketedBinder* : Json := $body:term)
|
||||
|
||||
def mkFromJsonBody (ctx : Context) (e : Expr) : TermElabM Term := do
|
||||
let indName := e.getAppFn.constName!
|
||||
if isStructure (← getEnv) indName then
|
||||
mkFromJsonBodyForStruct indName
|
||||
else
|
||||
mkFromJsonBodyForInduct ctx indName
|
||||
|
||||
def mkFromJsonAuxFunction (ctx : Context) (i : Nat) : TermElabM Command := do
|
||||
let auxFunName := ctx.auxFunNames[i]!
|
||||
let indval := ctx.typeInfos[i]!
|
||||
let header ← mkFromJsonHeader indval --TODO fix header info
|
||||
let binders := header.binders
|
||||
Term.elabBinders binders fun _ => do
|
||||
let type ← Term.elabTerm header.targetType none
|
||||
let mut body ← mkFromJsonBody ctx type
|
||||
if ctx.usePartial || indval.isRec then
|
||||
let letDecls ← mkLocalInstanceLetDecls ctx ``FromJson header.argNames
|
||||
body ← mkLet letDecls body
|
||||
`(private partial def $(mkIdent auxFunName):ident $binders:bracketedBinder* : Except String $(← mkInductiveApp ctx.typeInfos[i]! header.argNames) := $body:term)
|
||||
else
|
||||
`(private def $(mkIdent auxFunName):ident $binders:bracketedBinder* : Except String $(← mkInductiveApp ctx.typeInfos[i]! header.argNames) := $body:term)
|
||||
|
||||
|
||||
def mkToJsonMutualBlock (ctx : Context) : TermElabM Command := do
|
||||
let mut auxDefs := #[]
|
||||
for i in [:ctx.typeInfos.size] do
|
||||
auxDefs := auxDefs.push (← mkToJsonAuxFunction ctx i)
|
||||
`(mutual
|
||||
$auxDefs:command*
|
||||
end)
|
||||
|
||||
def mkFromJsonMutualBlock (ctx : Context) : TermElabM Command := do
|
||||
let mut auxDefs := #[]
|
||||
for i in [:ctx.typeInfos.size] do
|
||||
auxDefs := auxDefs.push (← mkFromJsonAuxFunction ctx i)
|
||||
`(mutual
|
||||
$auxDefs:command*
|
||||
end)
|
||||
|
||||
private def mkToJsonInstance (declName : Name) : TermElabM (Array Command) := do
|
||||
let ctx ← mkContext "toJson" declName
|
||||
let cmds := #[← mkToJsonMutualBlock ctx] ++ (← mkInstanceCmds ctx ``ToJson #[declName])
|
||||
trace[Elab.Deriving.toJson] "\n{cmds}"
|
||||
return cmds
|
||||
|
||||
private def mkFromJsonInstance (declName : Name) : TermElabM (Array Command) := do
|
||||
let ctx ← mkContext "fromJson" declName
|
||||
let cmds := #[← mkFromJsonMutualBlock ctx] ++ (← mkInstanceCmds ctx ``FromJson #[declName])
|
||||
trace[Elab.Deriving.fromJson] "\n{cmds}"
|
||||
return cmds
|
||||
|
||||
def mkToJsonInstanceHandler (declNames : Array Name) : CommandElabM Bool := do
|
||||
declNames.foldlM (fun b n => andM (pure b) (mkToJsonInstance n)) true
|
||||
if (← declNames.allM isInductive) && declNames.size > 0 then
|
||||
for declName in declNames do
|
||||
let cmds ← liftTermElabM <| mkToJsonInstance declName
|
||||
cmds.forM elabCommand
|
||||
return true
|
||||
else
|
||||
return false
|
||||
|
||||
def mkFromJsonInstanceHandler (declNames : Array Name) : CommandElabM Bool := do
|
||||
declNames.foldlM (fun b n => andM (pure b) (mkFromJsonInstance n)) true
|
||||
if (← declNames.allM isInductive) && declNames.size > 0 then
|
||||
for declName in declNames do
|
||||
let cmds ← liftTermElabM <| mkFromJsonInstance declName
|
||||
cmds.forM elabCommand
|
||||
return true
|
||||
else
|
||||
return false
|
||||
|
||||
builtin_initialize
|
||||
registerDerivingHandler ``ToJson mkToJsonInstanceHandler
|
||||
registerDerivingHandler ``FromJson mkFromJsonInstanceHandler
|
||||
|
||||
registerTraceClass `Elab.Deriving.toJson
|
||||
registerTraceClass `Elab.Deriving.fromJson
|
||||
|
||||
end Lean.Elab.Deriving.FromToJson
|
||||
|
||||
@@ -21,7 +21,7 @@ builtin_initialize
|
||||
let some id := id?
|
||||
| throwError "invalid `[inherit_doc]` attribute, could not infer doc source"
|
||||
let declName ← Elab.realizeGlobalConstNoOverloadWithInfo id
|
||||
if (← findSimpleDocString? (← getEnv) decl).isSome then
|
||||
if (← findSimpleDocString? (← getEnv) decl (includeBuiltin := false)).isSome then
|
||||
logWarning m!"{← mkConstWithLevelParams decl} already has a doc string"
|
||||
let some doc ← findSimpleDocString? (← getEnv) declName
|
||||
| logWarningAt id m!"{← mkConstWithLevelParams declName} does not have a doc string"
|
||||
|
||||
@@ -643,7 +643,7 @@ where
|
||||
| .proj _ _ b => return p.updateProj! (← go b)
|
||||
| .mdata k b =>
|
||||
if inaccessible? p |>.isSome then
|
||||
return mkMData k (← withReader (fun _ => false) (go b))
|
||||
return mkMData k (← withReader (fun _ => true) (go b))
|
||||
else if let some (stx, p) := patternWithRef? p then
|
||||
Elab.withInfoContext' (go p) fun p => do
|
||||
/- If `p` is a free variable and we are not inside of an "inaccessible" pattern, this `p` is a binder. -/
|
||||
|
||||
@@ -599,7 +599,7 @@ partial def solve {m} {α} [Monad m] (measures : Array α)
|
||||
all_le := false
|
||||
break
|
||||
-- No progress here? Try the next measure
|
||||
if not (has_lt && all_le) then continue
|
||||
if !(has_lt && all_le) then continue
|
||||
-- We found a suitable measure, remove it from the list (mild optimization)
|
||||
let measures' := measures.eraseIdx measureIdx
|
||||
return ← go measures' todo (acc.push measure)
|
||||
|
||||
@@ -56,7 +56,7 @@ partial def of (t : Expr) : M (Option ReifiedBVLogical) := do
|
||||
let expr := mkApp2 (mkConst ``BoolExpr.const) (mkConst ``BVPred) (toExpr Bool.false)
|
||||
let proof := return mkRefl (mkConst ``Bool.false)
|
||||
return some ⟨boolExpr, proof, expr⟩
|
||||
| not subExpr =>
|
||||
| Bool.not subExpr =>
|
||||
let some sub ← of subExpr | return none
|
||||
let boolExpr := .not sub.bvExpr
|
||||
let expr := mkApp2 (mkConst ``BoolExpr.not) (mkConst ``BVPred) sub.expr
|
||||
@@ -65,9 +65,9 @@ partial def of (t : Expr) : M (Option ReifiedBVLogical) := do
|
||||
let subProof ← sub.evalsAtAtoms
|
||||
return mkApp3 (mkConst ``Std.Tactic.BVDecide.Reflect.Bool.not_congr) subExpr subEvalExpr subProof
|
||||
return some ⟨boolExpr, proof, expr⟩
|
||||
| or lhsExpr rhsExpr => gateReflection lhsExpr rhsExpr .or ``Std.Tactic.BVDecide.Reflect.Bool.or_congr
|
||||
| and lhsExpr rhsExpr => gateReflection lhsExpr rhsExpr .and ``Std.Tactic.BVDecide.Reflect.Bool.and_congr
|
||||
| xor lhsExpr rhsExpr => gateReflection lhsExpr rhsExpr .xor ``Std.Tactic.BVDecide.Reflect.Bool.xor_congr
|
||||
| Bool.or lhsExpr rhsExpr => gateReflection lhsExpr rhsExpr .or ``Std.Tactic.BVDecide.Reflect.Bool.or_congr
|
||||
| Bool.and lhsExpr rhsExpr => gateReflection lhsExpr rhsExpr .and ``Std.Tactic.BVDecide.Reflect.Bool.and_congr
|
||||
| Bool.xor lhsExpr rhsExpr => gateReflection lhsExpr rhsExpr .xor ``Std.Tactic.BVDecide.Reflect.Bool.xor_congr
|
||||
| BEq.beq α _ lhsExpr rhsExpr =>
|
||||
match_expr α with
|
||||
| Bool => gateReflection lhsExpr rhsExpr .beq ``Std.Tactic.BVDecide.Reflect.Bool.beq_congr
|
||||
|
||||
@@ -405,7 +405,8 @@ private partial def blameDecideReductionFailure (inst : Expr) : MetaM Expr := do
|
||||
if r.isAppOf ``isTrue then
|
||||
-- Success!
|
||||
-- While we have a proof from reduction, we do not embed it in the proof term,
|
||||
-- and instead we let the kernel recompute it during type checking from the following more efficient term.
|
||||
-- and instead we let the kernel recompute it during type checking from the following more
|
||||
-- efficient term. The kernel handles the unification `e =?= true` specially.
|
||||
let rflPrf ← mkEqRefl (toExpr true)
|
||||
return mkApp3 (Lean.mkConst ``of_decide_eq_true) expectedType s rflPrf
|
||||
else
|
||||
|
||||
@@ -1439,7 +1439,7 @@ def resolveLocalName (n : Name) : TermElabM (Option (Expr × List String)) := do
|
||||
let localDecl? := lctx.decls.findSomeRev? fun localDecl? => do
|
||||
let localDecl ← localDecl?
|
||||
if localDecl.isAuxDecl then
|
||||
guard (not skipAuxDecl)
|
||||
guard (!skipAuxDecl)
|
||||
if let some fullDeclName := auxDeclToFullName.find? localDecl.fvarId then
|
||||
matchAuxRecDecl? localDecl fullDeclName givenNameView
|
||||
else
|
||||
@@ -1497,7 +1497,7 @@ def resolveLocalName (n : Name) : TermElabM (Option (Expr × List String)) := do
|
||||
foo := 10
|
||||
```
|
||||
-/
|
||||
match findLocalDecl? givenNameView (skipAuxDecl := globalDeclFound && not projs.isEmpty) with
|
||||
match findLocalDecl? givenNameView (skipAuxDecl := globalDeclFound && !projs.isEmpty) with
|
||||
| some decl => return some (decl.toExpr, projs)
|
||||
| none => match n with
|
||||
| .str pre s => loop pre (s::projs) globalDeclFoundNext
|
||||
|
||||
@@ -1016,7 +1016,15 @@ private def registerNamePrefixes : Environment → Name → Environment
|
||||
|
||||
@[export lean_environment_add]
|
||||
private def add (env : Environment) (cinfo : ConstantInfo) : Environment :=
|
||||
let env := registerNamePrefixes env cinfo.name
|
||||
let name := cinfo.name
|
||||
let env := match name with
|
||||
| .str _ s =>
|
||||
if s.get 0 == '_' then
|
||||
-- Do not register namespaces that only contain internal declarations.
|
||||
env
|
||||
else
|
||||
registerNamePrefixes env name
|
||||
| _ => env
|
||||
env.addAux cinfo
|
||||
|
||||
@[export lean_display_stats]
|
||||
|
||||
@@ -322,7 +322,8 @@ where
|
||||
stx := newStx
|
||||
diagnostics := old.diagnostics
|
||||
cancelTk? := ctx.newCancelTk
|
||||
result? := some { oldSuccess with
|
||||
result? := some {
|
||||
parserState := newParserState
|
||||
processedSnap := (← oldSuccess.processedSnap.bindIO (sync := true) fun oldProcessed => do
|
||||
if let some oldProcSuccess := oldProcessed.result? then
|
||||
-- also wait on old command parse snapshot as parsing is cheap and may allow for
|
||||
@@ -330,8 +331,11 @@ where
|
||||
oldProcSuccess.firstCmdSnap.bindIO (sync := true) fun oldCmd => do
|
||||
let prom ← IO.Promise.new
|
||||
let _ ← IO.asTask (parseCmd oldCmd newParserState oldProcSuccess.cmdState prom ctx)
|
||||
return .pure { oldProcessed with result? := some { oldProcSuccess with
|
||||
firstCmdSnap := { range? := none, task := prom.result } } }
|
||||
return .pure {
|
||||
diagnostics := oldProcessed.diagnostics
|
||||
result? := some {
|
||||
cmdState := oldProcSuccess.cmdState
|
||||
firstCmdSnap := { range? := none, task := prom.result } } }
|
||||
else
|
||||
return .pure oldProcessed) } }
|
||||
else return old
|
||||
|
||||
@@ -82,7 +82,7 @@ where
|
||||
return (a, b)
|
||||
else if a.getAppNumArgs != b.getAppNumArgs then
|
||||
return (a, b)
|
||||
else if not (← isDefEq a.getAppFn b.getAppFn) then
|
||||
else if !(← isDefEq a.getAppFn b.getAppFn) then
|
||||
return (a, b)
|
||||
else
|
||||
let fType ← inferType a.getAppFn
|
||||
|
||||
@@ -211,7 +211,7 @@ private def ignoreArg (a : Expr) (i : Nat) (infos : Array ParamInfo) : MetaM Boo
|
||||
if info.isInstImplicit then
|
||||
return true
|
||||
else if info.isImplicit || info.isStrictImplicit then
|
||||
return not (← isType a)
|
||||
return !(← isType a)
|
||||
else
|
||||
isProof a
|
||||
else
|
||||
|
||||
@@ -418,7 +418,7 @@ This method assumes that for any `xs[i]` and `xs[j]` where `i < j`, we have that
|
||||
where the index is the position in the local context.
|
||||
-/
|
||||
private partial def mkLambdaFVarsWithLetDeps (xs : Array Expr) (v : Expr) : MetaM (Option Expr) := do
|
||||
if not (← hasLetDeclsInBetween) then
|
||||
if !(← hasLetDeclsInBetween) then
|
||||
mkLambdaFVars xs v (etaReduce := true)
|
||||
else
|
||||
let ys ← addLetDeps
|
||||
|
||||
@@ -77,7 +77,7 @@ private def ignoreArg (a : Expr) (i : Nat) (infos : Array ParamInfo) : MetaM Boo
|
||||
if info.isInstImplicit then
|
||||
return true
|
||||
else if info.isImplicit || info.isStrictImplicit then
|
||||
return not (← isType a)
|
||||
return !(← isType a)
|
||||
else
|
||||
isProof a
|
||||
else
|
||||
|
||||
@@ -438,9 +438,11 @@ def buildInductionCase (oldIH newIH : FVarId) (isRecCall : Expr → Option Expr)
|
||||
let mvar ← mkFreshExprSyntheticOpaqueMVar goal (tag := `hyp)
|
||||
let mut mvarId := mvar.mvarId!
|
||||
mvarId ← assertIHs IHs mvarId
|
||||
trace[Meta.FunInd] "Goal before cleanup:{mvarId}"
|
||||
for fvarId in toClear do
|
||||
mvarId ← mvarId.clear fvarId
|
||||
mvarId ← mvarId.cleanup (toPreserve := toPreserve)
|
||||
trace[Meta.FunInd] "Goal after cleanup (toClear := {toClear.map mkFVar}) (toPreserve := {toPreserve.map mkFVar}):{mvarId}"
|
||||
modify (·.push mvarId)
|
||||
let mvar ← instantiateMVars mvar
|
||||
pure mvar
|
||||
|
||||
@@ -77,8 +77,9 @@ builtin_dsimproc [simp, seval] reduceFinMk (Fin.mk _ _) := fun e => do
|
||||
let_expr Fin.mk n v _ ← e | return .continue
|
||||
let some n ← evalNat n |>.run | return .continue
|
||||
let some v ← getNatValue? v | return .continue
|
||||
if h : n > 0 then
|
||||
return .done <| toExpr (Fin.ofNat' v h)
|
||||
if h : n ≠ 0 then
|
||||
have : NeZero n := ⟨h⟩
|
||||
return .done <| toExpr (Fin.ofNat' n v)
|
||||
else
|
||||
return .continue
|
||||
|
||||
|
||||
@@ -71,8 +71,8 @@ builtin_dsimproc [simp, seval] reduceMul ((_ * _ : Int)) := reduceBin ``HMul.hMu
|
||||
builtin_dsimproc [simp, seval] reduceSub ((_ - _ : Int)) := reduceBin ``HSub.hSub 6 (· - ·)
|
||||
builtin_dsimproc [simp, seval] reduceDiv ((_ / _ : Int)) := reduceBin ``HDiv.hDiv 6 (· / ·)
|
||||
builtin_dsimproc [simp, seval] reduceMod ((_ % _ : Int)) := reduceBin ``HMod.hMod 6 (· % ·)
|
||||
builtin_dsimproc [simp, seval] reduceTDiv (div _ _) := reduceBin ``Int.div 2 Int.div
|
||||
builtin_dsimproc [simp, seval] reduceTMod (mod _ _) := reduceBin ``Int.mod 2 Int.mod
|
||||
builtin_dsimproc [simp, seval] reduceTDiv (tdiv _ _) := reduceBin ``Int.div 2 Int.tdiv
|
||||
builtin_dsimproc [simp, seval] reduceTMod (tmod _ _) := reduceBin ``Int.mod 2 Int.tmod
|
||||
builtin_dsimproc [simp, seval] reduceFDiv (fdiv _ _) := reduceBin ``Int.fdiv 2 Int.fdiv
|
||||
builtin_dsimproc [simp, seval] reduceFMod (fmod _ _) := reduceBin ``Int.fmod 2 Int.fmod
|
||||
builtin_dsimproc [simp, seval] reduceBdiv (bdiv _ _) := reduceBinIntNatOp ``bdiv bdiv
|
||||
|
||||
@@ -145,7 +145,7 @@ def errorAtSavedPosFn (msg : String) (delta : Bool) : ParserFn := fun c s =>
|
||||
/-- Generate an error at the position saved with the `withPosition` combinator.
|
||||
If `delta == true`, then it reports at saved position+1.
|
||||
This useful to make sure a parser consumed at least one character. -/
|
||||
def errorAtSavedPos (msg : String) (delta : Bool) : Parser := {
|
||||
@[builtin_doc] def errorAtSavedPos (msg : String) (delta : Bool) : Parser := {
|
||||
fn := errorAtSavedPosFn msg delta
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ def orelseFn (p q : ParserFn) : ParserFn :=
|
||||
NOTE: In order for the pretty printer to retrace an `orelse`, `p` must be a call to `node` or some other parser
|
||||
producing a single node kind. Nested `orelse` calls are flattened for this, i.e. `(node k1 p1 <|> node k2 p2) <|> ...`
|
||||
is fine as well. -/
|
||||
def orelse (p q : Parser) : Parser where
|
||||
@[builtin_doc] def orelse (p q : Parser) : Parser where
|
||||
info := orelseInfo p.info q.info
|
||||
fn := orelseFn p.fn q.fn
|
||||
|
||||
@@ -295,7 +295,7 @@ This is important for the `p <|> q` combinator, because it is not backtracking,
|
||||
`p` fails after consuming some tokens. To get backtracking behavior, use `atomic(p) <|> q` instead.
|
||||
|
||||
This parser has the same arity as `p` - it produces the same result as `p`. -/
|
||||
def atomic : Parser → Parser := withFn atomicFn
|
||||
@[builtin_doc] def atomic : Parser → Parser := withFn atomicFn
|
||||
|
||||
/-- Information about the state of the parse prior to the failing parser's execution -/
|
||||
structure RecoveryContext where
|
||||
@@ -335,7 +335,7 @@ state immediately after the failure.
|
||||
|
||||
The interactions between <|> and `recover'` are subtle, especially for syntactic
|
||||
categories that admit user extension. Consider avoiding it in these cases. -/
|
||||
def recover' (parser : Parser) (handler : RecoveryContext → Parser) : Parser where
|
||||
@[builtin_doc] def recover' (parser : Parser) (handler : RecoveryContext → Parser) : Parser where
|
||||
info := parser.info
|
||||
fn := recoverFn parser.fn fun s => handler s |>.fn
|
||||
|
||||
@@ -347,7 +347,7 @@ If `handler` fails itself, then no recovery is performed.
|
||||
|
||||
The interactions between <|> and `recover` are subtle, especially for syntactic
|
||||
categories that admit user extension. Consider avoiding it in these cases. -/
|
||||
def recover (parser handler : Parser) : Parser := recover' parser fun _ => handler
|
||||
@[builtin_doc] def recover (parser handler : Parser) : Parser := recover' parser fun _ => handler
|
||||
|
||||
def optionalFn (p : ParserFn) : ParserFn := fun c s =>
|
||||
let iniSz := s.stackSize
|
||||
@@ -378,7 +378,7 @@ position to the original state on success. So for example `lookahead("=>")` will
|
||||
next token is `"=>"`, without actually consuming this token.
|
||||
|
||||
This parser has arity 0 - it does not capture anything. -/
|
||||
def lookahead : Parser → Parser := withFn lookaheadFn
|
||||
@[builtin_doc] def lookahead : Parser → Parser := withFn lookaheadFn
|
||||
|
||||
def notFollowedByFn (p : ParserFn) (msg : String) : ParserFn := fun c s =>
|
||||
let iniSz := s.stackSize
|
||||
@@ -394,7 +394,7 @@ def notFollowedByFn (p : ParserFn) (msg : String) : ParserFn := fun c s =>
|
||||
if `p` succeeds then it fails with the message `"unexpected foo"`.
|
||||
|
||||
This parser has arity 0 - it does not capture anything. -/
|
||||
def notFollowedBy (p : Parser) (msg : String) : Parser where
|
||||
@[builtin_doc] def notFollowedBy (p : Parser) (msg : String) : Parser where
|
||||
fn := notFollowedByFn p.fn msg
|
||||
|
||||
partial def manyAux (p : ParserFn) : ParserFn := fun c s => Id.run do
|
||||
@@ -1143,7 +1143,7 @@ def checkWsBeforeFn (errorMsg : String) : ParserFn := fun _ s =>
|
||||
For example, the parser `"foo" ws "+"` parses `foo +` or `foo/- -/+` but not `foo+`.
|
||||
|
||||
This parser has arity 0 - it does not capture anything. -/
|
||||
def checkWsBefore (errorMsg : String := "space before") : Parser where
|
||||
@[builtin_doc] def checkWsBefore (errorMsg : String := "space before") : Parser where
|
||||
info := epsilonInfo
|
||||
fn := checkWsBeforeFn errorMsg
|
||||
|
||||
@@ -1160,7 +1160,7 @@ def checkLinebreakBeforeFn (errorMsg : String) : ParserFn := fun _ s =>
|
||||
(The line break may be inside a comment.)
|
||||
|
||||
This parser has arity 0 - it does not capture anything. -/
|
||||
def checkLinebreakBefore (errorMsg : String := "line break") : Parser where
|
||||
@[builtin_doc] def checkLinebreakBefore (errorMsg : String := "line break") : Parser where
|
||||
info := epsilonInfo
|
||||
fn := checkLinebreakBeforeFn errorMsg
|
||||
|
||||
@@ -1180,7 +1180,7 @@ This is almost the same as `"foo+"`, but using this parser will make `foo+` a to
|
||||
problems for the use of `"foo"` and `"+"` as separate tokens in other parsers.
|
||||
|
||||
This parser has arity 0 - it does not capture anything. -/
|
||||
def checkNoWsBefore (errorMsg : String := "no space before") : Parser := {
|
||||
@[builtin_doc] def checkNoWsBefore (errorMsg : String := "no space before") : Parser := {
|
||||
info := epsilonInfo
|
||||
fn := checkNoWsBeforeFn errorMsg
|
||||
}
|
||||
@@ -1430,7 +1430,7 @@ position (see `withPosition`). This can be used to do whitespace sensitive synta
|
||||
a `by` block or `do` block, where all the lines have to line up.
|
||||
|
||||
This parser has arity 0 - it does not capture anything. -/
|
||||
def checkColEq (errorMsg : String := "checkColEq") : Parser where
|
||||
@[builtin_doc] def checkColEq (errorMsg : String := "checkColEq") : Parser where
|
||||
fn := checkColEqFn errorMsg
|
||||
|
||||
def checkColGeFn (errorMsg : String) : ParserFn := fun c s =>
|
||||
@@ -1449,7 +1449,7 @@ certain indentation scope. For example it is used in the lean grammar for `else
|
||||
that the `else` is not less indented than the `if` it matches with.
|
||||
|
||||
This parser has arity 0 - it does not capture anything. -/
|
||||
def checkColGe (errorMsg : String := "checkColGe") : Parser where
|
||||
@[builtin_doc] def checkColGe (errorMsg : String := "checkColGe") : Parser where
|
||||
fn := checkColGeFn errorMsg
|
||||
|
||||
def checkColGtFn (errorMsg : String) : ParserFn := fun c s =>
|
||||
@@ -1473,7 +1473,7 @@ Here, the `revert` tactic is followed by a list of `colGt ident`, because otherw
|
||||
interpret `exact` as an identifier and try to revert a variable named `exact`.
|
||||
|
||||
This parser has arity 0 - it does not capture anything. -/
|
||||
def checkColGt (errorMsg : String := "checkColGt") : Parser where
|
||||
@[builtin_doc] def checkColGt (errorMsg : String := "checkColGt") : Parser where
|
||||
fn := checkColGtFn errorMsg
|
||||
|
||||
def checkLineEqFn (errorMsg : String) : ParserFn := fun c s =>
|
||||
@@ -1491,7 +1491,7 @@ different lines. For example, `else if` is parsed using `lineEq` to ensure that
|
||||
are on the same line.
|
||||
|
||||
This parser has arity 0 - it does not capture anything. -/
|
||||
def checkLineEq (errorMsg : String := "checkLineEq") : Parser where
|
||||
@[builtin_doc] def checkLineEq (errorMsg : String := "checkLineEq") : Parser where
|
||||
fn := checkLineEqFn errorMsg
|
||||
|
||||
/-- `withPosition(p)` runs `p` while setting the "saved position" to the current position.
|
||||
@@ -1507,7 +1507,7 @@ The saved position is only available in the read-only state, which is why this i
|
||||
after the `withPosition(..)` block the saved position will be restored to its original value.
|
||||
|
||||
This parser has the same arity as `p` - it just forwards the results of `p`. -/
|
||||
def withPosition : Parser → Parser := withFn fun f c s =>
|
||||
@[builtin_doc] def withPosition : Parser → Parser := withFn fun f c s =>
|
||||
adaptCacheableContextFn ({ · with savedPos? := s.pos }) f c s
|
||||
|
||||
def withPositionAfterLinebreak : Parser → Parser := withFn fun f c s =>
|
||||
@@ -1519,7 +1519,7 @@ parsers like `colGt` will have no effect. This is usually used by bracketing con
|
||||
`(...)` so that the user can locally override whitespace sensitivity.
|
||||
|
||||
This parser has the same arity as `p` - it just forwards the results of `p`. -/
|
||||
def withoutPosition (p : Parser) : Parser :=
|
||||
@[builtin_doc] def withoutPosition (p : Parser) : Parser :=
|
||||
adaptCacheableContext ({ · with savedPos? := none }) p
|
||||
|
||||
/-- `withForbidden tk p` runs `p` with `tk` as a "forbidden token". This means that if the token
|
||||
@@ -1529,7 +1529,7 @@ stop there, making `tk` effectively a lowest-precedence operator. This is used f
|
||||
would be treated as an application.
|
||||
|
||||
This parser has the same arity as `p` - it just forwards the results of `p`. -/
|
||||
def withForbidden (tk : Token) (p : Parser) : Parser :=
|
||||
@[builtin_doc] def withForbidden (tk : Token) (p : Parser) : Parser :=
|
||||
adaptCacheableContext ({ · with forbiddenTk? := tk }) p
|
||||
|
||||
/-- `withoutForbidden(p)` runs `p` disabling the "forbidden token" (see `withForbidden`), if any.
|
||||
@@ -1537,7 +1537,7 @@ This is usually used by bracketing constructs like `(...)` because there is no p
|
||||
inside these nested constructs.
|
||||
|
||||
This parser has the same arity as `p` - it just forwards the results of `p`. -/
|
||||
def withoutForbidden (p : Parser) : Parser :=
|
||||
@[builtin_doc] def withoutForbidden (p : Parser) : Parser :=
|
||||
adaptCacheableContext ({ · with forbiddenTk? := none }) p
|
||||
|
||||
def eoiFn : ParserFn := fun c s =>
|
||||
@@ -1692,7 +1692,7 @@ def termParser (prec : Nat := 0) : Parser :=
|
||||
-- ==================
|
||||
|
||||
/-- Fail if previous token is immediately followed by ':'. -/
|
||||
def checkNoImmediateColon : Parser := {
|
||||
@[builtin_doc] def checkNoImmediateColon : Parser := {
|
||||
fn := fun c s =>
|
||||
let prev := s.stxStack.back
|
||||
if checkTailNoWs prev then
|
||||
@@ -1756,7 +1756,7 @@ def unicodeSymbol (sym asciiSym : String) : Parser :=
|
||||
Define parser for `$e` (if `anonymous == true`) and `$e:name`.
|
||||
`kind` is embedded in the antiquotation's kind, and checked at syntax `match` unless `isPseudoKind` is true.
|
||||
Antiquotations can be escaped as in `$$e`, which produces the syntax tree for `$e`. -/
|
||||
def mkAntiquot (name : String) (kind : SyntaxNodeKind) (anonymous := true) (isPseudoKind := false) : Parser :=
|
||||
@[builtin_doc] def mkAntiquot (name : String) (kind : SyntaxNodeKind) (anonymous := true) (isPseudoKind := false) : Parser :=
|
||||
let kind := kind ++ (if isPseudoKind then `pseudo else .anonymous) ++ `antiquot
|
||||
let nameP := node `antiquotName <| checkNoWsBefore ("no space before ':" ++ name ++ "'") >> symbol ":" >> nonReservedSymbol name
|
||||
-- if parsing the kind fails and `anonymous` is true, check that we're not ignoring a different
|
||||
@@ -1781,7 +1781,7 @@ def withAntiquotFn (antiquotP p : ParserFn) (isCatAntiquot := false) : ParserFn
|
||||
p c s
|
||||
|
||||
/-- Optimized version of `mkAntiquot ... <|> p`. -/
|
||||
def withAntiquot (antiquotP p : Parser) : Parser := {
|
||||
@[builtin_doc] def withAntiquot (antiquotP p : Parser) : Parser := {
|
||||
fn := withAntiquotFn antiquotP.fn p.fn
|
||||
info := orelseInfo antiquotP.info p.info
|
||||
}
|
||||
@@ -1791,7 +1791,7 @@ def withoutInfo (p : Parser) : Parser := {
|
||||
}
|
||||
|
||||
/-- Parse `$[p]suffix`, e.g. `$[p],*`. -/
|
||||
def mkAntiquotSplice (kind : SyntaxNodeKind) (p suffix : Parser) : Parser :=
|
||||
@[builtin_doc] def mkAntiquotSplice (kind : SyntaxNodeKind) (p suffix : Parser) : Parser :=
|
||||
let kind := kind ++ `antiquot_scope
|
||||
leadingNode kind maxPrec <| atomic <|
|
||||
setExpected [] "$" >>
|
||||
@@ -1808,7 +1808,7 @@ private def withAntiquotSuffixSpliceFn (kind : SyntaxNodeKind) (suffix : ParserF
|
||||
s.mkNode (kind ++ `antiquot_suffix_splice) (s.stxStack.size - 2)
|
||||
|
||||
/-- Parse `suffix` after an antiquotation, e.g. `$x,*`, and put both into a new node. -/
|
||||
def withAntiquotSuffixSplice (kind : SyntaxNodeKind) (p suffix : Parser) : Parser where
|
||||
@[builtin_doc] def withAntiquotSuffixSplice (kind : SyntaxNodeKind) (p suffix : Parser) : Parser where
|
||||
info := andthenInfo p.info suffix.info
|
||||
fn c s :=
|
||||
let s := p.fn c s
|
||||
|
||||
@@ -78,7 +78,7 @@ All modifiers are optional, and have to come in the listed order.
|
||||
`nestedDeclModifiers` is the same as `declModifiers`, but attributes are printed
|
||||
on the same line as the declaration. It is used for declarations nested inside other syntax,
|
||||
such as inductive constructors, structure projections, and `let rec` / `where` definitions. -/
|
||||
def declModifiers (inline : Bool) := leading_parser
|
||||
@[builtin_doc] def declModifiers (inline : Bool) := leading_parser
|
||||
optional docComment >>
|
||||
optional (Term.«attributes» >> if inline then skip else ppDedent ppLine) >>
|
||||
optional visibility >>
|
||||
@@ -86,13 +86,16 @@ def declModifiers (inline : Bool) := leading_parser
|
||||
optional «unsafe» >>
|
||||
optional («partial» <|> «nonrec»)
|
||||
/-- `declId` matches `foo` or `foo.{u,v}`: an identifier possibly followed by a list of universe names -/
|
||||
def declId := leading_parser
|
||||
-- @[builtin_doc] -- FIXME: suppress the hover
|
||||
def declId := leading_parser
|
||||
ident >> optional (".{" >> sepBy1 (recover ident (skipUntil (fun c => c.isWhitespace || c ∈ [',', '}']))) ", " >> "}")
|
||||
/-- `declSig` matches the signature of a declaration with required type: a list of binders and then `: type` -/
|
||||
def declSig := leading_parser
|
||||
-- @[builtin_doc] -- FIXME: suppress the hover
|
||||
def declSig := leading_parser
|
||||
many (ppSpace >> (Term.binderIdent <|> Term.bracketedBinder)) >> Term.typeSpec
|
||||
/-- `optDeclSig` matches the signature of a declaration with optional type: a list of binders and then possibly `: type` -/
|
||||
def optDeclSig := leading_parser
|
||||
-- @[builtin_doc] -- FIXME: suppress the hover
|
||||
def optDeclSig := leading_parser
|
||||
many (ppSpace >> (Term.binderIdent <|> Term.bracketedBinder)) >> Term.optType
|
||||
/-- Right-hand side of a `:=` in a declaration, a term. -/
|
||||
def declBody : Parser :=
|
||||
@@ -141,11 +144,11 @@ def whereStructInst := leading_parser
|
||||
* a sequence of `| pat => expr` (a declaration by equations), shorthand for a `match`
|
||||
* `where` and then a sequence of `field := value` initializers, shorthand for a structure constructor
|
||||
-/
|
||||
def declVal :=
|
||||
@[builtin_doc] def declVal :=
|
||||
-- Remark: we should not use `Term.whereDecls` at `declVal`
|
||||
-- because `Term.whereDecls` is defined using `Term.letRecDecl` which may contain attributes.
|
||||
-- Issue #753 shows an example that fails to be parsed when we used `Term.whereDecls`.
|
||||
withAntiquot (mkAntiquot "declVal" `Lean.Parser.Command.declVal (isPseudoKind := true)) <|
|
||||
withAntiquot (mkAntiquot "declVal" decl_name% (isPseudoKind := true)) <|
|
||||
declValSimple <|> declValEqns <|> whereStructInst
|
||||
def «abbrev» := leading_parser
|
||||
"abbrev " >> declId >> ppIndent optDeclSig >> declVal
|
||||
@@ -193,9 +196,10 @@ inductive List (α : Type u) where
|
||||
```
|
||||
A list of elements of type `α` is either the empty list, `nil`,
|
||||
or an element `head : α` followed by a list `tail : List α`.
|
||||
For more information about [inductive types](https://lean-lang.org/theorem_proving_in_lean4/inductive_types.html).
|
||||
See [Inductive types](https://lean-lang.org/theorem_proving_in_lean4/inductive_types.html)
|
||||
for more information.
|
||||
-/
|
||||
def «inductive» := leading_parser
|
||||
@[builtin_doc] def «inductive» := leading_parser
|
||||
"inductive " >> recover declId skipUntilWsOrDelim >> ppIndent optDeclSig >> optional (symbol " :=" <|> " where") >>
|
||||
many ctor >> optional (ppDedent ppLine >> computedFields) >> optDeriving
|
||||
def classInductive := leading_parser
|
||||
@@ -544,7 +548,7 @@ def openSimple := leading_parser
|
||||
def openScoped := leading_parser
|
||||
" scoped" >> many1 (ppSpace >> checkColGt >> ident)
|
||||
/-- `openDecl` is the body of an `open` declaration (see `open`) -/
|
||||
def openDecl :=
|
||||
@[builtin_doc] def openDecl :=
|
||||
withAntiquot (mkAntiquot "openDecl" `Lean.Parser.Command.openDecl (isPseudoKind := true)) <|
|
||||
openHiding <|> openRenaming <|> openOnly <|> openSimple <|> openScoped
|
||||
/-- Makes names from other namespaces visible without writing the namespace prefix.
|
||||
|
||||
@@ -30,7 +30,7 @@ def doSeqBracketed := leading_parser
|
||||
do elements that take blocks. It can either have the form `"{" (doElem ";"?)* "}"` or
|
||||
`many1Indent (doElem ";"?)`, where `many1Indent` ensures that all the items are at
|
||||
the same or higher indentation level as the first line. -/
|
||||
def doSeq :=
|
||||
@[builtin_doc] def doSeq :=
|
||||
withAntiquot (mkAntiquot "doSeq" decl_name% (isPseudoKind := true)) <|
|
||||
doSeqBracketed <|> doSeqIndent
|
||||
/-- `termBeforeDo` is defined as `withForbidden("do", term)`, which will parse a term but
|
||||
|
||||
@@ -31,7 +31,7 @@ it to parse correctly. `ident?` will not work; one must write `(ident)?` instead
|
||||
This parser has arity 1: it produces a `nullKind` node containing either zero arguments
|
||||
(for the `none` case) or the list of arguments produced by `p`.
|
||||
(In particular, if `p` has arity 0 then the two cases are not differentiated!) -/
|
||||
@[run_builtin_parser_attribute_hooks] def optional (p : Parser) : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc] def optional (p : Parser) : Parser :=
|
||||
optionalNoAntiquot (withAntiquotSpliceAndSuffix `optional p (symbol "?"))
|
||||
|
||||
/-- The parser `many(p)`, or `p*`, repeats `p` until it fails, and returns the list of results.
|
||||
@@ -41,7 +41,7 @@ automatically replaced by `group(p)` to ensure that it produces exactly 1 value.
|
||||
|
||||
This parser has arity 1: it produces a `nullKind` node containing one argument for each
|
||||
invocation of `p` (or `group(p)`). -/
|
||||
@[run_builtin_parser_attribute_hooks] def many (p : Parser) : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc] def many (p : Parser) : Parser :=
|
||||
manyNoAntiquot (withAntiquotSpliceAndSuffix `many p (symbol "*"))
|
||||
|
||||
/-- The parser `many1(p)`, or `p+`, repeats `p` until it fails, and returns the list of results.
|
||||
@@ -56,7 +56,7 @@ automatically replaced by `group(p)` to ensure that it produces exactly 1 value.
|
||||
|
||||
This parser has arity 1: it produces a `nullKind` node containing one argument for each
|
||||
invocation of `p` (or `group(p)`). -/
|
||||
@[run_builtin_parser_attribute_hooks] def many1 (p : Parser) : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc] def many1 (p : Parser) : Parser :=
|
||||
many1NoAntiquot (withAntiquotSpliceAndSuffix `many p (symbol "*"))
|
||||
|
||||
/-- The parser `ident` parses a single identifier, possibly with namespaces, such as `foo` or
|
||||
@@ -70,18 +70,18 @@ using disallowed characters in identifiers such as `«foo.bar».baz` or `«hello
|
||||
|
||||
This parser has arity 1: it produces a `Syntax.ident` node containing the parsed identifier.
|
||||
You can use `TSyntax.getId` to extract the name from the resulting syntax object. -/
|
||||
@[run_builtin_parser_attribute_hooks] def ident : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc] def ident : Parser :=
|
||||
withAntiquot (mkAntiquot "ident" identKind) identNoAntiquot
|
||||
|
||||
-- `optional (checkNoWsBefore >> "." >> checkNoWsBefore >> ident)`
|
||||
-- can never fully succeed but ensures that the identifier
|
||||
-- produces a partial syntax that contains the dot.
|
||||
-- The partial syntax is sometimes useful for dot-auto-completion.
|
||||
@[run_builtin_parser_attribute_hooks] def identWithPartialTrailingDot :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc] def identWithPartialTrailingDot :=
|
||||
ident >> optional (checkNoWsBefore >> "." >> checkNoWsBefore >> ident)
|
||||
|
||||
-- `ident` and `rawIdent` produce the same syntax tree, so we reuse the antiquotation kind name
|
||||
@[run_builtin_parser_attribute_hooks] def rawIdent : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc] def rawIdent : Parser :=
|
||||
withAntiquot (mkAntiquot "ident" identKind) rawIdentNoAntiquot
|
||||
|
||||
/-- The parser `hygieneInfo` parses no text, but captures the current macro scope information
|
||||
@@ -96,7 +96,7 @@ for more information about macro hygiene.
|
||||
|
||||
This parser has arity 1: it produces a `Syntax.ident` node containing the parsed identifier.
|
||||
You can use `TSyntax.getHygieneInfo` to extract the name from the resulting syntax object. -/
|
||||
@[run_builtin_parser_attribute_hooks] def hygieneInfo : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc] def hygieneInfo : Parser :=
|
||||
withAntiquot (mkAntiquot "hygieneInfo" hygieneInfoKind (anonymous := false)) hygieneInfoNoAntiquot
|
||||
|
||||
/-- The parser `num` parses a numeric literal in several bases:
|
||||
@@ -109,7 +109,7 @@ You can use `TSyntax.getHygieneInfo` to extract the name from the resulting synt
|
||||
This parser has arity 1: it produces a `numLitKind` node containing an atom with the text of the
|
||||
literal.
|
||||
You can use `TSyntax.getNat` to extract the number from the resulting syntax object. -/
|
||||
@[run_builtin_parser_attribute_hooks] def numLit : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc] def numLit : Parser :=
|
||||
withAntiquot (mkAntiquot "num" numLitKind) numLitNoAntiquot
|
||||
|
||||
/-- The parser `scientific` parses a scientific-notation literal, such as `1.3e-24`.
|
||||
@@ -117,7 +117,7 @@ You can use `TSyntax.getNat` to extract the number from the resulting syntax obj
|
||||
This parser has arity 1: it produces a `scientificLitKind` node containing an atom with the text
|
||||
of the literal.
|
||||
You can use `TSyntax.getScientific` to extract the parts from the resulting syntax object. -/
|
||||
@[run_builtin_parser_attribute_hooks] def scientificLit : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc] def scientificLit : Parser :=
|
||||
withAntiquot (mkAntiquot "scientific" scientificLitKind) scientificLitNoAntiquot
|
||||
|
||||
/-- The parser `str` parses a string literal, such as `"foo"` or `"\r\n"`. Strings can contain
|
||||
@@ -127,7 +127,7 @@ Newlines in a string are interpreted literally.
|
||||
This parser has arity 1: it produces a `strLitKind` node containing an atom with the raw
|
||||
literal (including the quote marks and without interpreting the escapes).
|
||||
You can use `TSyntax.getString` to decode the string from the resulting syntax object. -/
|
||||
@[run_builtin_parser_attribute_hooks] def strLit : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc] def strLit : Parser :=
|
||||
withAntiquot (mkAntiquot "str" strLitKind) strLitNoAntiquot
|
||||
|
||||
/-- The parser `char` parses a character literal, such as `'a'` or `'\n'`. Character literals can
|
||||
@@ -138,7 +138,7 @@ like `∈`, but must evaluate to a single unicode codepoint, so `'♥'` is allow
|
||||
This parser has arity 1: it produces a `charLitKind` node containing an atom with the raw
|
||||
literal (including the quote marks and without interpreting the escapes).
|
||||
You can use `TSyntax.getChar` to decode the string from the resulting syntax object. -/
|
||||
@[run_builtin_parser_attribute_hooks] def charLit : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc] def charLit : Parser :=
|
||||
withAntiquot (mkAntiquot "char" charLitKind) charLitNoAntiquot
|
||||
|
||||
/-- The parser `name` parses a name literal like `` `foo``. The syntax is the same as for identifiers
|
||||
@@ -147,7 +147,7 @@ You can use `TSyntax.getChar` to decode the string from the resulting syntax obj
|
||||
This parser has arity 1: it produces a `nameLitKind` node containing the raw literal
|
||||
(including the backquote).
|
||||
You can use `TSyntax.getName` to extract the name from the resulting syntax object. -/
|
||||
@[run_builtin_parser_attribute_hooks] def nameLit : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc] def nameLit : Parser :=
|
||||
withAntiquot (mkAntiquot "name" nameLitKind) nameLitNoAntiquot
|
||||
|
||||
/-- The parser `group(p)` parses the same thing as `p`, but it wraps the results in a `groupKind`
|
||||
@@ -156,7 +156,7 @@ node.
|
||||
This parser always has arity 1, even if `p` does not. Parsers like `p*` are automatically
|
||||
rewritten to `group(p)*` if `p` does not have arity 1, so that the results from separate invocations
|
||||
of `p` can be differentiated. -/
|
||||
@[run_builtin_parser_attribute_hooks, inline] def group (p : Parser) : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc, inline] def group (p : Parser) : Parser :=
|
||||
node groupKind p
|
||||
|
||||
/-- The parser `many1Indent(p)` is equivalent to `withPosition((colGe p)+)`. This has the effect of
|
||||
@@ -165,7 +165,7 @@ the same or more than the first parse.
|
||||
|
||||
This parser has arity 1, and returns a list of the results from `p`.
|
||||
`p` is "auto-grouped" if it is not arity 1. -/
|
||||
@[run_builtin_parser_attribute_hooks, inline] def many1Indent (p : Parser) : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc, inline] def many1Indent (p : Parser) : Parser :=
|
||||
withPosition $ many1 (checkColGe "irrelevant" >> p)
|
||||
|
||||
/-- The parser `manyIndent(p)` is equivalent to `withPosition((colGe p)*)`. This has the effect of
|
||||
@@ -174,14 +174,14 @@ the same or more than the first parse.
|
||||
|
||||
This parser has arity 1, and returns a list of the results from `p`.
|
||||
`p` is "auto-grouped" if it is not arity 1. -/
|
||||
@[run_builtin_parser_attribute_hooks, inline] def manyIndent (p : Parser) : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc, inline] def manyIndent (p : Parser) : Parser :=
|
||||
withPosition $ many (checkColGe "irrelevant" >> p)
|
||||
|
||||
@[inline] def sepByIndent (p : Parser) (sep : String) (psep : Parser := symbol sep) (allowTrailingSep : Bool := false) : Parser :=
|
||||
@[builtin_doc, inline] def sepByIndent (p : Parser) (sep : String) (psep : Parser := symbol sep) (allowTrailingSep : Bool := false) : Parser :=
|
||||
let p := withAntiquotSpliceAndSuffix `sepBy p (symbol "*")
|
||||
withPosition $ sepBy (checkColGe "irrelevant" >> p) sep (psep <|> checkColEq "irrelevant" >> checkLinebreakBefore >> pushNone) allowTrailingSep
|
||||
|
||||
@[inline] def sepBy1Indent (p : Parser) (sep : String) (psep : Parser := symbol sep) (allowTrailingSep : Bool := false) : Parser :=
|
||||
@[builtin_doc, inline] def sepBy1Indent (p : Parser) (sep : String) (psep : Parser := symbol sep) (allowTrailingSep : Bool := false) : Parser :=
|
||||
let p := withAntiquotSpliceAndSuffix `sepBy p (symbol "*")
|
||||
withPosition $ sepBy1 (checkColGe "irrelevant" >> p) sep (psep <|> checkColEq "irrelevant" >> checkLinebreakBefore >> pushNone) allowTrailingSep
|
||||
|
||||
@@ -205,32 +205,33 @@ def sepByIndent.formatter (p : Formatter) (_sep : String) (pSep : Formatter) : F
|
||||
|
||||
attribute [run_builtin_parser_attribute_hooks] sepByIndent sepBy1Indent
|
||||
|
||||
@[run_builtin_parser_attribute_hooks] abbrev notSymbol (s : String) : Parser :=
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc] abbrev notSymbol (s : String) : Parser :=
|
||||
notFollowedBy (symbol s) s
|
||||
|
||||
/-- No-op parser combinator that annotates subtrees to be ignored in syntax patterns. -/
|
||||
@[inline, run_builtin_parser_attribute_hooks] def patternIgnore : Parser → Parser := node `patternIgnore
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc, inline]
|
||||
def patternIgnore : Parser → Parser := node `patternIgnore
|
||||
|
||||
/-- No-op parser that advises the pretty printer to emit a non-breaking space. -/
|
||||
@[inline] def ppHardSpace : Parser := skip
|
||||
@[builtin_doc, inline] def ppHardSpace : Parser := skip
|
||||
/-- No-op parser that advises the pretty printer to emit a space/soft line break. -/
|
||||
@[inline] def ppSpace : Parser := skip
|
||||
@[builtin_doc, inline] def ppSpace : Parser := skip
|
||||
/-- No-op parser that advises the pretty printer to emit a hard line break. -/
|
||||
@[inline] def ppLine : Parser := skip
|
||||
@[builtin_doc, inline] def ppLine : Parser := skip
|
||||
/-- No-op parser combinator that advises the pretty printer to emit a `Format.fill` node. -/
|
||||
@[inline] def ppRealFill : Parser → Parser := id
|
||||
@[builtin_doc, inline] def ppRealFill : Parser → Parser := id
|
||||
/-- No-op parser combinator that advises the pretty printer to emit a `Format.group` node. -/
|
||||
@[inline] def ppRealGroup : Parser → Parser := id
|
||||
@[builtin_doc, inline] def ppRealGroup : Parser → Parser := id
|
||||
/-- No-op parser combinator that advises the pretty printer to indent the given syntax without grouping it. -/
|
||||
@[inline] def ppIndent : Parser → Parser := id
|
||||
@[builtin_doc, inline] def ppIndent : Parser → Parser := id
|
||||
/--
|
||||
No-op parser combinator that advises the pretty printer to group and indent the given syntax.
|
||||
By default, only syntax categories are grouped. -/
|
||||
@[inline] def ppGroup (p : Parser) : Parser := ppRealFill (ppIndent p)
|
||||
@[builtin_doc, inline] def ppGroup (p : Parser) : Parser := ppRealFill (ppIndent p)
|
||||
/--
|
||||
No-op parser combinator that advises the pretty printer to dedent the given syntax.
|
||||
Dedenting can in particular be used to counteract automatic indentation. -/
|
||||
@[inline] def ppDedent : Parser → Parser := id
|
||||
@[builtin_doc, inline] def ppDedent : Parser → Parser := id
|
||||
|
||||
/--
|
||||
No-op parser combinator that allows the pretty printer to omit the group and
|
||||
@@ -242,19 +243,19 @@ attribute [run_builtin_parser_attribute_hooks] sepByIndent sepBy1Indent
|
||||
trivial
|
||||
```
|
||||
-/
|
||||
@[inline] def ppAllowUngrouped : Parser := skip
|
||||
@[builtin_doc, inline] def ppAllowUngrouped : Parser := skip
|
||||
|
||||
/--
|
||||
No-op parser combinator that advises the pretty printer to dedent the given syntax,
|
||||
if it was grouped by the category parser.
|
||||
Dedenting can in particular be used to counteract automatic indentation. -/
|
||||
@[inline] def ppDedentIfGrouped : Parser → Parser := id
|
||||
@[builtin_doc, inline] def ppDedentIfGrouped : Parser → Parser := id
|
||||
|
||||
/--
|
||||
No-op parser combinator that prints a line break.
|
||||
The line break is soft if the combinator is followed
|
||||
by an ungrouped parser (see ppAllowUngrouped), otherwise hard. -/
|
||||
@[inline] def ppHardLineUnlessUngrouped : Parser := skip
|
||||
@[builtin_doc, inline] def ppHardLineUnlessUngrouped : Parser := skip
|
||||
|
||||
end Parser
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ This parser has arity 1, and returns a `interpolatedStrKind` with an odd number
|
||||
alternating between chunks of literal text and results from `p`. The literal chunks contain
|
||||
uninterpreted substrings of the input. For example, `"foo\n{2 + 2}"` would have three arguments:
|
||||
an atom `"foo\n{`, the parsed `2 + 2` term, and then the atom `}"`. -/
|
||||
def interpolatedStr (p : Parser) : Parser :=
|
||||
@[builtin_doc] def interpolatedStr (p : Parser) : Parser :=
|
||||
withAntiquot (mkAntiquot "interpolatedStr" interpolatedStrKind) $ interpolatedStrNoAntiquot p
|
||||
|
||||
end Lean.Parser
|
||||
|
||||
@@ -24,6 +24,7 @@ a regular comment (that is, as whitespace); it is parsed and forms part of the s
|
||||
|
||||
A `docComment` node contains a `/--` atom and then the remainder of the comment, `foo -/` in this
|
||||
example. Use `TSyntax.getDocString` to extract the body text from a doc string syntax node. -/
|
||||
-- @[builtin_doc] -- FIXME: suppress the hover
|
||||
def docComment := leading_parser
|
||||
ppDedent $ "/--" >> ppSpace >> commentBody >> ppLine
|
||||
end Command
|
||||
@@ -49,7 +50,7 @@ example := by
|
||||
skip
|
||||
```
|
||||
is legal, but `by skip skip` is not - it must be written as `by skip; skip`. -/
|
||||
@[run_builtin_parser_attribute_hooks]
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc]
|
||||
def sepByIndentSemicolon (p : Parser) : Parser :=
|
||||
sepByIndent p "; " (allowTrailingSep := true)
|
||||
|
||||
@@ -62,7 +63,7 @@ example := by
|
||||
skip
|
||||
```
|
||||
is legal, but `by skip skip` is not - it must be written as `by skip; skip`. -/
|
||||
@[run_builtin_parser_attribute_hooks]
|
||||
@[run_builtin_parser_attribute_hooks, builtin_doc]
|
||||
def sepBy1IndentSemicolon (p : Parser) : Parser :=
|
||||
sepBy1Indent p "; " (allowTrailingSep := true)
|
||||
|
||||
@@ -70,22 +71,22 @@ builtin_initialize
|
||||
register_parser_alias sepByIndentSemicolon
|
||||
register_parser_alias sepBy1IndentSemicolon
|
||||
|
||||
def tacticSeq1Indented : Parser := leading_parser
|
||||
@[builtin_doc] def tacticSeq1Indented : Parser := leading_parser
|
||||
sepBy1IndentSemicolon tacticParser
|
||||
/-- The syntax `{ tacs }` is an alternative syntax for `· tacs`.
|
||||
It runs the tactics in sequence, and fails if the goal is not solved. -/
|
||||
def tacticSeqBracketed : Parser := leading_parser
|
||||
@[builtin_doc] def tacticSeqBracketed : Parser := leading_parser
|
||||
"{" >> sepByIndentSemicolon tacticParser >> ppDedent (ppLine >> "}")
|
||||
|
||||
/-- A sequence of tactics in brackets, or a delimiter-free indented sequence of tactics.
|
||||
Delimiter-free indentation is determined by the *first* tactic of the sequence. -/
|
||||
def tacticSeq := leading_parser
|
||||
@[builtin_doc] def tacticSeq := leading_parser
|
||||
tacticSeqBracketed <|> tacticSeq1Indented
|
||||
|
||||
/-- Same as [`tacticSeq`] but requires delimiter-free tactic sequence to have strict indentation.
|
||||
The strict indentation requirement only apply to *nested* `by`s, as top-level `by`s do not have a
|
||||
position set. -/
|
||||
def tacticSeqIndentGt := withAntiquot (mkAntiquot "tacticSeq" ``tacticSeq) <| node ``tacticSeq <|
|
||||
@[builtin_doc] def tacticSeqIndentGt := withAntiquot (mkAntiquot "tacticSeq" ``tacticSeq) <| node ``tacticSeq <|
|
||||
tacticSeqBracketed <|> (checkColGt "indented tactic sequence" >> tacticSeq1Indented)
|
||||
|
||||
/- Raw sequence for quotation and grouping -/
|
||||
@@ -206,7 +207,7 @@ def fromTerm := leading_parser
|
||||
def showRhs := fromTerm <|> byTactic'
|
||||
/-- A `sufficesDecl` represents everything that comes after the `suffices` keyword:
|
||||
an optional `x :`, then a term `ty`, then `from val` or `by tac`. -/
|
||||
def sufficesDecl := leading_parser
|
||||
@[builtin_doc] def sufficesDecl := leading_parser
|
||||
(atomic (group (binderIdent >> " : ")) <|> hygieneInfo) >> termParser >> ppSpace >> showRhs
|
||||
@[builtin_term_parser] def «suffices» := leading_parser:leadPrec
|
||||
withPosition ("suffices " >> sufficesDecl) >> optSemicolon termParser
|
||||
@@ -272,7 +273,7 @@ open Lean.PrettyPrinter Parenthesizer Syntax.MonadTraverser in
|
||||
Explicit binder, like `(x y : A)` or `(x y)`.
|
||||
Default values can be specified using `(x : A := v)` syntax, and tactics using `(x : A := by tac)`.
|
||||
-/
|
||||
def explicitBinder (requireType := false) := leading_parser ppGroup <|
|
||||
@[builtin_doc] def explicitBinder (requireType := false) := leading_parser ppGroup <|
|
||||
"(" >> withoutPosition (many1 binderIdent >> binderType requireType >> optional (binderTactic <|> binderDefault)) >> ")"
|
||||
/--
|
||||
Implicit binder, like `{x y : A}` or `{x y}`.
|
||||
@@ -283,7 +284,7 @@ by unification.
|
||||
|
||||
In `@` explicit mode, implicit binders behave like explicit binders.
|
||||
-/
|
||||
def implicitBinder (requireType := false) := leading_parser ppGroup <|
|
||||
@[builtin_doc] def implicitBinder (requireType := false) := leading_parser ppGroup <|
|
||||
"{" >> withoutPosition (many1 binderIdent >> binderType requireType) >> "}"
|
||||
def strictImplicitLeftBracket := atomic (group (symbol "{" >> "{")) <|> "⦃"
|
||||
def strictImplicitRightBracket := atomic (group (symbol "}" >> "}")) <|> "⦄"
|
||||
@@ -300,7 +301,7 @@ and `h hs` has type `p y`.
|
||||
In contrast, if `h' : ∀ {x : A}, x ∈ s → p x`, then `h` by itself elaborates to have type `?m ∈ s → p ?m`
|
||||
with `?m` a fresh metavariable.
|
||||
-/
|
||||
def strictImplicitBinder (requireType := false) := leading_parser ppGroup <|
|
||||
@[builtin_doc] def strictImplicitBinder (requireType := false) := leading_parser ppGroup <|
|
||||
strictImplicitLeftBracket >> many1 binderIdent >>
|
||||
binderType requireType >> strictImplicitRightBracket
|
||||
/--
|
||||
@@ -310,7 +311,7 @@ and solved for by typeclass inference for the specified class `C`.
|
||||
In `@` explicit mode, if `_` is used for an an instance-implicit parameter, then it is still solved for by typeclass inference;
|
||||
use `(_)` to inhibit this and have it be solved for by unification instead, like an implicit argument.
|
||||
-/
|
||||
def instBinder := leading_parser ppGroup <|
|
||||
@[builtin_doc] def instBinder := leading_parser ppGroup <|
|
||||
"[" >> withoutPosition (optIdent >> termParser) >> "]"
|
||||
/-- A `bracketedBinder` matches any kind of binder group that uses some kind of brackets:
|
||||
* An explicit binder like `(x y : A)`
|
||||
@@ -318,7 +319,7 @@ def instBinder := leading_parser ppGroup <|
|
||||
* A strict implicit binder, `⦃y z : A⦄` or its ASCII alternative `{{y z : A}}`
|
||||
* An instance binder `[A]` or `[x : A]` (multiple variables are not allowed here)
|
||||
-/
|
||||
def bracketedBinder (requireType := false) :=
|
||||
@[builtin_doc] def bracketedBinder (requireType := false) :=
|
||||
withAntiquot (mkAntiquot "bracketedBinder" decl_name% (isPseudoKind := true)) <|
|
||||
explicitBinder requireType <|> strictImplicitBinder requireType <|>
|
||||
implicitBinder requireType <|> instBinder
|
||||
@@ -366,7 +367,7 @@ def matchAlts (rhsParser : Parser := termParser) : Parser :=
|
||||
|
||||
/-- `matchDiscr` matches a "match discriminant", either `h : tm` or `tm`, used in `match` as
|
||||
`match h1 : e1, e2, h3 : e3 with ...`. -/
|
||||
def matchDiscr := leading_parser
|
||||
@[builtin_doc] def matchDiscr := leading_parser
|
||||
optional (atomic (ident >> " : ")) >> termParser
|
||||
|
||||
def trueVal := leading_parser nonReservedSymbol "true"
|
||||
@@ -497,7 +498,7 @@ def letEqnsDecl := leading_parser (withAnonymousAntiquot := false)
|
||||
`let pat := e` (where `pat` is an arbitrary term) or `let f | pat1 => e1 | pat2 => e2 ...`
|
||||
(a pattern matching declaration), except for the `let` keyword itself.
|
||||
`let rec` declarations are not handled here. -/
|
||||
def letDecl := leading_parser (withAnonymousAntiquot := false)
|
||||
@[builtin_doc] def letDecl := leading_parser (withAnonymousAntiquot := false)
|
||||
-- Remark: we disable anonymous antiquotations here to make sure
|
||||
-- anonymous antiquotations (e.g., `$x`) are not `letDecl`
|
||||
notFollowedBy (nonReservedSymbol "rec") "rec" >>
|
||||
@@ -556,7 +557,7 @@ def haveEqnsDecl := leading_parser (withAnonymousAntiquot := false)
|
||||
/-- `haveDecl` matches the body of a have declaration: `have := e`, `have f x1 x2 := e`,
|
||||
`have pat := e` (where `pat` is an arbitrary term) or `have f | pat1 => e1 | pat2 => e2 ...`
|
||||
(a pattern matching declaration), except for the `have` keyword itself. -/
|
||||
def haveDecl := leading_parser (withAnonymousAntiquot := false)
|
||||
@[builtin_doc] def haveDecl := leading_parser (withAnonymousAntiquot := false)
|
||||
haveIdDecl <|> (ppSpace >> letPatDecl) <|> haveEqnsDecl
|
||||
@[builtin_term_parser] def «have» := leading_parser:leadPrec
|
||||
withPosition ("have" >> haveDecl) >> optSemicolon termParser
|
||||
@@ -570,7 +571,7 @@ def haveDecl := leading_parser (withAnonymousAntiquot := false)
|
||||
def «scoped» := leading_parser "scoped "
|
||||
def «local» := leading_parser "local "
|
||||
/-- `attrKind` matches `("scoped" <|> "local")?`, used before an attribute like `@[local simp]`. -/
|
||||
def attrKind := leading_parser optional («scoped» <|> «local»)
|
||||
@[builtin_doc] def attrKind := leading_parser optional («scoped» <|> «local»)
|
||||
def attrInstance := ppGroup $ leading_parser attrKind >> attrParser
|
||||
|
||||
def attributes := leading_parser
|
||||
@@ -607,13 +608,13 @@ If omitted, a termination argument will be inferred. If written as `termination_
|
||||
the inferrred termination argument will be suggested.
|
||||
|
||||
-/
|
||||
def terminationBy := leading_parser
|
||||
@[builtin_doc] def terminationBy := leading_parser
|
||||
"termination_by " >>
|
||||
optional (nonReservedSymbol "structural ") >>
|
||||
optional (atomic (many (ppSpace >> Term.binderIdent) >> " => ")) >>
|
||||
termParser
|
||||
|
||||
@[inherit_doc terminationBy]
|
||||
@[inherit_doc terminationBy, builtin_doc]
|
||||
def terminationBy? := leading_parser
|
||||
"termination_by?"
|
||||
|
||||
@@ -626,13 +627,13 @@ By default, the tactic `decreasing_tactic` is used.
|
||||
Forces the use of well-founded recursion and is hence incompatible with
|
||||
`termination_by structural`.
|
||||
-/
|
||||
def decreasingBy := leading_parser
|
||||
@[builtin_doc] def decreasingBy := leading_parser
|
||||
ppDedent ppLine >> "decreasing_by " >> Tactic.tacticSeqIndentGt
|
||||
|
||||
/--
|
||||
Termination hints are `termination_by` and `decreasing_by`, in that order.
|
||||
-/
|
||||
def suffix := leading_parser
|
||||
@[builtin_doc] def suffix := leading_parser
|
||||
optional (ppDedent ppLine >> (terminationBy? <|> terminationBy)) >> optional decreasingBy
|
||||
|
||||
end Termination
|
||||
@@ -640,9 +641,10 @@ namespace Term
|
||||
|
||||
/-- `letRecDecl` matches the body of a let-rec declaration: a doc comment, attributes, and then
|
||||
a let declaration without the `let` keyword, such as `/-- foo -/ @[simp] bar := 1`. -/
|
||||
def letRecDecl := leading_parser
|
||||
@[builtin_doc] def letRecDecl := leading_parser
|
||||
optional Command.docComment >> optional «attributes» >> letDecl >> Termination.suffix
|
||||
/-- `letRecDecls` matches `letRecDecl,+`, a comma-separated list of let-rec declarations (see `letRecDecl`). -/
|
||||
-- @[builtin_doc] -- FIXME: suppress the hover
|
||||
def letRecDecls := leading_parser
|
||||
sepBy1 letRecDecl ", "
|
||||
@[builtin_term_parser]
|
||||
|
||||
@@ -7,6 +7,7 @@ prelude
|
||||
import Lean.Data.Trie
|
||||
import Lean.Syntax
|
||||
import Lean.Message
|
||||
import Lean.DocString.Extension
|
||||
|
||||
namespace Lean.Parser
|
||||
|
||||
@@ -428,7 +429,7 @@ def withCacheFn (parserName : Name) (p : ParserFn) : ParserFn := fun c s => Id.r
|
||||
panic! s!"withCacheFn: unexpected stack growth {s.stxStack.raw}"
|
||||
{ s with cache.parserCache := s.cache.parserCache.insert key ⟨s.stxStack.back, s.lhsPrec, s.pos, s.errorMsg⟩ }
|
||||
|
||||
@[inherit_doc withCacheFn]
|
||||
@[inherit_doc withCacheFn, builtin_doc]
|
||||
def withCache (parserName : Name) : Parser → Parser := withFn (withCacheFn parserName)
|
||||
|
||||
def ParserFn.run (p : ParserFn) (ictx : InputContext) (pmctx : ParserModuleContext) (tokens : TokenTable) (s : ParserState) : ParserState :=
|
||||
|
||||
@@ -137,7 +137,7 @@ def isNonConstFun (motive : Expr) : MetaM Bool := do
|
||||
| _ => return motive.hasLooseBVars
|
||||
|
||||
def isSimpleHOFun (motive : Expr) : MetaM Bool :=
|
||||
return not (← returnsPi motive) && not (← isNonConstFun motive)
|
||||
return !(← returnsPi motive) && !(← isNonConstFun motive)
|
||||
|
||||
def isType2Type (motive : Expr) : MetaM Bool := do
|
||||
match ← inferType motive with
|
||||
@@ -278,7 +278,7 @@ where
|
||||
inspectAux (fType mType : Expr) (i : Nat) (args mvars : Array Expr) := do
|
||||
let fType ← whnf fType
|
||||
let mType ← whnf mType
|
||||
if not (i < args.size) then return ()
|
||||
if !(i < args.size) then return ()
|
||||
match fType, mType with
|
||||
| Expr.forallE _ fd fb _, Expr.forallE _ _ mb _ => do
|
||||
-- TODO: do I need to check (← okBottomUp? args[i] mvars[i] fuel).isSafe here?
|
||||
@@ -324,7 +324,7 @@ def withKnowing (knowsType knowsLevel : Bool) (x : AnalyzeM α) : AnalyzeM α :=
|
||||
builtin_initialize analyzeFailureId : InternalExceptionId ← registerInternalExceptionId `analyzeFailure
|
||||
|
||||
def checkKnowsType : AnalyzeM Unit := do
|
||||
if not (← read).knowsType then
|
||||
if !(← read).knowsType then
|
||||
throw $ Exception.internal analyzeFailureId
|
||||
|
||||
def annotateBoolAt (n : Name) (pos : Pos) : AnalyzeM Unit := do
|
||||
@@ -425,7 +425,7 @@ mutual
|
||||
funBinders := mkArray args.size false
|
||||
}
|
||||
|
||||
if not rest.isEmpty then
|
||||
if !rest.isEmpty then
|
||||
-- Note: this shouldn't happen for type-correct terms
|
||||
if !args.isEmpty then
|
||||
analyzeAppStaged (mkAppN f args) rest
|
||||
@@ -501,11 +501,11 @@ mutual
|
||||
collectHigherOrders := do
|
||||
let { args, mvars, bInfos, ..} ← read
|
||||
for i in [:args.size] do
|
||||
if not (bInfos[i]! == BinderInfo.implicit || bInfos[i]! == BinderInfo.strictImplicit) then continue
|
||||
if not (← isHigherOrder (← inferType args[i]!)) then continue
|
||||
if !(bInfos[i]! == BinderInfo.implicit || bInfos[i]! == BinderInfo.strictImplicit) then continue
|
||||
if !(← isHigherOrder (← inferType args[i]!)) then continue
|
||||
if getPPAnalyzeTrustId (← getOptions) && isIdLike args[i]! then continue
|
||||
|
||||
if getPPAnalyzeTrustKnownFOType2TypeHOFuns (← getOptions) && not (← valUnknown mvars[i]!)
|
||||
if getPPAnalyzeTrustKnownFOType2TypeHOFuns (← getOptions) && !(← valUnknown mvars[i]!)
|
||||
&& (← isType2Type (args[i]!)) && (← isFOLike (args[i]!)) then continue
|
||||
|
||||
tryUnify args[i]! mvars[i]!
|
||||
@@ -602,7 +602,7 @@ mutual
|
||||
| _ => annotateNamedArg (← mvarName mvars[i]!)
|
||||
else annotateBool `pp.analysis.skip; provided := false
|
||||
modify fun s => { s with provideds := s.provideds.set! i provided }
|
||||
if (← get).provideds[i]! then withKnowing (not (← typeUnknown mvars[i]!)) true analyze
|
||||
if (← get).provideds[i]! then withKnowing (!(← typeUnknown mvars[i]!)) true analyze
|
||||
tryUnify mvars[i]! args[i]!
|
||||
|
||||
maybeSetExplicit := do
|
||||
|
||||
@@ -235,7 +235,6 @@ private def normPrivateName? (declName : Name) : MetaM (Option Name) := do
|
||||
Remark: `danglingDot == true` when the completion point is an identifier followed by `.`.
|
||||
-/
|
||||
private def matchDecl? (ns : Name) (id : Name) (danglingDot : Bool) (declName : Name) : MetaM (Option (Name × Float)) := do
|
||||
-- dbg_trace "{ns}, {id}, {declName}, {danglingDot}"
|
||||
let some declName ← normPrivateName? declName
|
||||
| return none
|
||||
if !ns.isPrefixOf declName then
|
||||
@@ -324,16 +323,24 @@ def completeNamespaces (ctx : ContextInfo) (id : Name) (danglingDot : Bool) : M
|
||||
|
||||
private def idCompletionCore
|
||||
(ctx : ContextInfo)
|
||||
(stx : Syntax)
|
||||
(id : Name)
|
||||
(hoverInfo : HoverInfo)
|
||||
(danglingDot : Bool)
|
||||
: M Unit := do
|
||||
let mut id := id.eraseMacroScopes
|
||||
let mut id := id
|
||||
if id.hasMacroScopes then
|
||||
if stx.getHeadInfo matches .original .. then
|
||||
id := id.eraseMacroScopes
|
||||
else
|
||||
-- Identifier is synthetic and has macro scopes => no completions
|
||||
-- Erasing the macro scopes does not make sense in this case because the identifier name
|
||||
-- is some random synthetic string.
|
||||
return
|
||||
let mut danglingDot := danglingDot
|
||||
if let HoverInfo.inside delta := hoverInfo then
|
||||
id := truncate id delta
|
||||
danglingDot := false
|
||||
-- dbg_trace ">> id {id} : {expectedType?}"
|
||||
if id.isAtomic then
|
||||
-- search for matches in the local context
|
||||
for localDecl in (← getLCtx) do
|
||||
@@ -419,12 +426,13 @@ private def idCompletion
|
||||
(params : CompletionParams)
|
||||
(ctx : ContextInfo)
|
||||
(lctx : LocalContext)
|
||||
(stx : Syntax)
|
||||
(id : Name)
|
||||
(hoverInfo : HoverInfo)
|
||||
(danglingDot : Bool)
|
||||
: IO (Option CompletionList) :=
|
||||
runM params ctx lctx do
|
||||
idCompletionCore ctx id hoverInfo danglingDot
|
||||
idCompletionCore ctx stx id hoverInfo danglingDot
|
||||
|
||||
private def unfoldeDefinitionGuarded? (e : Expr) : MetaM (Option Expr) :=
|
||||
try unfoldDefinition? e catch _ => pure none
|
||||
@@ -525,10 +533,10 @@ private def dotCompletion
|
||||
if nameSet.isEmpty then
|
||||
let stx := info.stx
|
||||
if stx.isIdent then
|
||||
idCompletionCore ctx stx.getId hoverInfo (danglingDot := false)
|
||||
idCompletionCore ctx stx stx.getId hoverInfo (danglingDot := false)
|
||||
else if stx.getKind == ``Lean.Parser.Term.completion && stx[0].isIdent then
|
||||
-- TODO: truncation when there is a dangling dot
|
||||
idCompletionCore ctx stx[0].getId HoverInfo.after (danglingDot := true)
|
||||
idCompletionCore ctx stx stx[0].getId HoverInfo.after (danglingDot := true)
|
||||
else
|
||||
failure
|
||||
return
|
||||
@@ -658,6 +666,50 @@ private def tacticCompletion (params : CompletionParams) (ctx : ContextInfo) : I
|
||||
}, 1)
|
||||
return some { items := sortCompletionItems items, isIncomplete := true }
|
||||
|
||||
/--
|
||||
If there are `Info`s that contain `hoverPos` and have a nonempty `LocalContext`,
|
||||
yields the closest one of those `Info`s.
|
||||
Otherwise, yields the closest `Info` that contains `hoverPos` and has an empty `LocalContext`.
|
||||
-/
|
||||
private def findClosestInfoWithLocalContextAt?
|
||||
(hoverPos : String.Pos)
|
||||
(infoTree : InfoTree)
|
||||
: Option (ContextInfo × Info) :=
|
||||
infoTree.visitM (m := Id) (postNode := choose) |>.join
|
||||
where
|
||||
choose
|
||||
(ctx : ContextInfo)
|
||||
(info : Info)
|
||||
(_ : PersistentArray InfoTree)
|
||||
(childValues : List (Option (Option (ContextInfo × Info))))
|
||||
: Option (ContextInfo × Info) :=
|
||||
let bestChildValue := childValues.map (·.join) |>.foldl (init := none) fun v best =>
|
||||
if isBetter v best then
|
||||
v
|
||||
else
|
||||
best
|
||||
if info.occursInOrOnBoundary hoverPos && isBetter (ctx, info) bestChildValue then
|
||||
(ctx, info)
|
||||
else
|
||||
bestChildValue
|
||||
|
||||
isBetter (a b : Option (ContextInfo × Info)) : Bool :=
|
||||
match a, b with
|
||||
| none, none => false
|
||||
| some _, none => true
|
||||
| none, some _ => false
|
||||
| some (_, ia), some (_, ib) =>
|
||||
if !ia.lctx.isEmpty && ib.lctx.isEmpty then
|
||||
true
|
||||
else if ia.lctx.isEmpty && !ib.lctx.isEmpty then
|
||||
false
|
||||
else if ia.isSmaller ib then
|
||||
true
|
||||
else if ib.isSmaller ia then
|
||||
false
|
||||
else
|
||||
false
|
||||
|
||||
private def findCompletionInfoAt?
|
||||
(fileMap : FileMap)
|
||||
(hoverPos : String.Pos)
|
||||
@@ -667,9 +719,32 @@ private def findCompletionInfoAt?
|
||||
match infoTree.foldInfo (init := none) (choose hoverLine) with
|
||||
| some (hoverInfo, ctx, Info.ofCompletionInfo info) =>
|
||||
some (hoverInfo, ctx, info)
|
||||
| _ =>
|
||||
-- TODO try to extract id from `fileMap` and some `ContextInfo` from `InfoTree`
|
||||
none
|
||||
| _ => do
|
||||
-- No completion info => Attempt providing identifier completions
|
||||
let some (ctx, info) := findClosestInfoWithLocalContextAt? hoverPos infoTree
|
||||
| none
|
||||
let some stack := info.stx.findStack? (·.getRange?.any (·.contains hoverPos (includeStop := true)))
|
||||
| none
|
||||
let stack := stack.dropWhile fun (stx, _) => !(stx matches `($_:ident) || stx matches `($_:ident.))
|
||||
let some (stx, _) := stack.head?
|
||||
| none
|
||||
let isDotIdCompletion := stack.any fun (stx, _) => stx matches `(.$_:ident)
|
||||
if isDotIdCompletion then
|
||||
-- An identifier completion is never useful in a dotId completion context.
|
||||
none
|
||||
let some (id, danglingDot) :=
|
||||
match stx with
|
||||
| `($id:ident) => some (id.getId, false)
|
||||
| `($id:ident.) => some (id.getId, true)
|
||||
| _ => none
|
||||
| none
|
||||
let tailPos := stx.getTailPos?.get!
|
||||
let hoverInfo :=
|
||||
if hoverPos < tailPos then
|
||||
HoverInfo.inside (tailPos - hoverPos).byteIdx
|
||||
else
|
||||
HoverInfo.after
|
||||
some (hoverInfo, ctx, .id stx id danglingDot info.lctx none)
|
||||
where
|
||||
choose
|
||||
(hoverLine : Nat)
|
||||
@@ -679,37 +754,48 @@ where
|
||||
: Option (HoverInfo × ContextInfo × Info) :=
|
||||
if !info.isCompletion then
|
||||
best?
|
||||
else if info.occursInside? hoverPos |>.isSome then
|
||||
let headPos := info.pos?.get!
|
||||
else if info.occursInOrOnBoundary hoverPos then
|
||||
let headPos := info.pos?.get!
|
||||
let tailPos := info.tailPos?.get!
|
||||
let hoverInfo :=
|
||||
if hoverPos < tailPos then
|
||||
HoverInfo.inside (hoverPos - headPos).byteIdx
|
||||
else
|
||||
HoverInfo.after
|
||||
let ⟨headPosLine, _⟩ := fileMap.toPosition headPos
|
||||
let ⟨tailPosLine, _⟩ := fileMap.toPosition info.tailPos?.get!
|
||||
if headPosLine != hoverLine || headPosLine != tailPosLine then
|
||||
best?
|
||||
else match best? with
|
||||
| none => (HoverInfo.inside (hoverPos - headPos).byteIdx, ctx, info)
|
||||
| some (HoverInfo.after, _, _) => (HoverInfo.inside (hoverPos - headPos).byteIdx, ctx, info)
|
||||
| none => (hoverInfo, ctx, info)
|
||||
| some (_, _, best) =>
|
||||
if info.isSmaller best then
|
||||
(HoverInfo.inside (hoverPos - headPos).byteIdx, ctx, info)
|
||||
else
|
||||
best?
|
||||
else if let some (HoverInfo.inside _, _, _) := best? then
|
||||
-- We assume the "inside matches" have precedence over "before ones".
|
||||
best?
|
||||
else if info.occursDirectlyBefore hoverPos then
|
||||
let pos := info.tailPos?.get!
|
||||
let ⟨line, _⟩ := fileMap.toPosition pos
|
||||
if line != hoverLine then best?
|
||||
else match best? with
|
||||
| none => (HoverInfo.after, ctx, info)
|
||||
| some (_, _, best) =>
|
||||
if info.isSmaller best then
|
||||
(HoverInfo.after, ctx, info)
|
||||
if isBetter info best then
|
||||
(hoverInfo, ctx, info)
|
||||
else
|
||||
best?
|
||||
else
|
||||
best?
|
||||
|
||||
isBetter : Info → Info → Bool
|
||||
| i₁@(.ofCompletionInfo ci₁), i₂@(.ofCompletionInfo ci₂) =>
|
||||
-- Use the smallest info available and prefer non-id completion over id completions as a
|
||||
-- tie-breaker.
|
||||
-- This is necessary because the elaborator sometimes generates both for the same range.
|
||||
-- If two infos are equivalent, always prefer the first one.
|
||||
if i₁.isSmaller i₂ then
|
||||
true
|
||||
else if i₂.isSmaller i₁ then
|
||||
false
|
||||
else if !(ci₁ matches .id ..) && ci₂ matches .id .. then
|
||||
true
|
||||
else if ci₁ matches .id .. && !(ci₂ matches .id ..) then
|
||||
false
|
||||
else
|
||||
true
|
||||
| .ofCompletionInfo _, _ => true
|
||||
| _, .ofCompletionInfo _ => false
|
||||
| _, _ => true
|
||||
|
||||
/--
|
||||
Assigns the `CompletionItem.sortText?` for all items in `completions` according to their order
|
||||
in `completions`. This is necessary because clients will use their own sort order if the server
|
||||
@@ -740,8 +826,8 @@ partial def find?
|
||||
match info with
|
||||
| .dot info .. =>
|
||||
dotCompletion params ctx info hoverInfo
|
||||
| .id _ id danglingDot lctx .. =>
|
||||
idCompletion params ctx lctx id hoverInfo danglingDot
|
||||
| .id stx id danglingDot lctx .. =>
|
||||
idCompletion params ctx lctx stx id hoverInfo danglingDot
|
||||
| .dotId _ id lctx expectedType? =>
|
||||
dotIdCompletion params ctx lctx id expectedType?
|
||||
| .fieldId _ id lctx structName =>
|
||||
|
||||
@@ -141,10 +141,12 @@ def Info.stx : Info → Syntax
|
||||
| ofOmissionInfo i => i.stx
|
||||
|
||||
def Info.lctx : Info → LocalContext
|
||||
| Info.ofTermInfo i => i.lctx
|
||||
| Info.ofFieldInfo i => i.lctx
|
||||
| Info.ofOmissionInfo i => i.lctx
|
||||
| _ => LocalContext.empty
|
||||
| .ofTermInfo i => i.lctx
|
||||
| .ofFieldInfo i => i.lctx
|
||||
| .ofOmissionInfo i => i.lctx
|
||||
| .ofMacroExpansionInfo i => i.lctx
|
||||
| .ofCompletionInfo i => i.lctx
|
||||
| _ => LocalContext.empty
|
||||
|
||||
def Info.pos? (i : Info) : Option String.Pos :=
|
||||
i.stx.getPos? (canonicalOnly := true)
|
||||
@@ -165,7 +167,7 @@ def Info.size? (i : Info) : Option String.Pos := do
|
||||
|
||||
-- `Info` without position information are considered to have "infinite" size
|
||||
def Info.isSmaller (i₁ i₂ : Info) : Bool :=
|
||||
match i₁.size?, i₂.pos? with
|
||||
match i₁.size?, i₂.size? with
|
||||
| some sz₁, some sz₂ => sz₁ < sz₂
|
||||
| some _, none => true
|
||||
| _, _ => false
|
||||
@@ -181,6 +183,13 @@ def Info.occursInside? (i : Info) (hoverPos : String.Pos) : Option String.Pos :=
|
||||
guard (headPos ≤ hoverPos && hoverPos < tailPos)
|
||||
return hoverPos - headPos
|
||||
|
||||
def Info.occursInOrOnBoundary (i : Info) (hoverPos : String.Pos) : Bool := Id.run do
|
||||
let some headPos := i.pos?
|
||||
| return false
|
||||
let some tailPos := i.tailPos?
|
||||
| return false
|
||||
return headPos <= hoverPos && hoverPos <= tailPos
|
||||
|
||||
def InfoTree.smallestInfo? (p : Info → Bool) (t : InfoTree) : Option (ContextInfo × Info) :=
|
||||
let ts := t.deepestNodes fun ctx i _ => if p i then some (ctx, i) else none
|
||||
|
||||
|
||||
@@ -48,7 +48,8 @@ instance : ToExpr (Fin n) where
|
||||
toExpr a :=
|
||||
let r := mkRawNatLit a.val
|
||||
mkApp3 (.const ``OfNat.ofNat [0]) (.app (mkConst ``Fin) (toExpr n)) r
|
||||
(mkApp2 (.const ``Fin.instOfNat []) (mkNatLit (n-1)) r)
|
||||
(mkApp3 (.const ``Fin.instOfNat []) (toExpr n)
|
||||
(.app (.const ``Nat.instNeZeroSucc []) (mkNatLit (n-1))) r)
|
||||
|
||||
instance : ToExpr (BitVec n) where
|
||||
toTypeExpr := .app (mkConst ``BitVec) (toExpr n)
|
||||
|
||||
@@ -152,6 +152,18 @@ variable {β : Type v}
|
||||
|
||||
end
|
||||
|
||||
@[inline, inherit_doc Raw.getKey?] def getKey? (m : DHashMap α β) (a : α) : Option α :=
|
||||
Raw₀.getKey? ⟨m.1, m.2.size_buckets_pos⟩ a
|
||||
|
||||
@[inline, inherit_doc Raw.getKey] def getKey (m : DHashMap α β) (a : α) (h : a ∈ m) : α :=
|
||||
Raw₀.getKey ⟨m.1, m.2.size_buckets_pos⟩ a h
|
||||
|
||||
@[inline, inherit_doc Raw.getKey!] def getKey! [Inhabited α] (m : DHashMap α β) (a : α) : α :=
|
||||
Raw₀.getKey! ⟨m.1, m.2.size_buckets_pos⟩ a
|
||||
|
||||
@[inline, inherit_doc Raw.getKeyD] def getKeyD (m : DHashMap α β) (a : α) (fallback : α) : α :=
|
||||
Raw₀.getKeyD ⟨m.1, m.2.size_buckets_pos⟩ a fallback
|
||||
|
||||
@[inline, inherit_doc Raw.size] def size (m : DHashMap α β) : Nat :=
|
||||
m.1.size
|
||||
|
||||
@@ -248,6 +260,10 @@ instance [BEq α] [Hashable α] : ForIn m (DHashMap α β) ((a : α) × β a) wh
|
||||
DHashMap α (fun _ => Unit) :=
|
||||
Const.insertManyUnit ∅ l
|
||||
|
||||
@[inline, inherit_doc Raw.Const.unitOfArray] def Const.unitOfArray [BEq α] [Hashable α] (l : Array α) :
|
||||
DHashMap α (fun _ => Unit) :=
|
||||
Const.insertManyUnit ∅ l
|
||||
|
||||
@[inherit_doc Raw.Internal.numBuckets] def Internal.numBuckets
|
||||
(m : DHashMap α β) : Nat :=
|
||||
Raw.Internal.numBuckets m.1
|
||||
|
||||
@@ -102,16 +102,31 @@ def getCast [BEq α] [LawfulBEq α] (a : α) : (l : AssocList α β) → l.conta
|
||||
| cons k v es, h => if hka : k == a then cast (congrArg β (eq_of_beq hka)) v
|
||||
else es.getCast a (by rw [← h, contains, Bool.of_not_eq_true hka, Bool.false_or])
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getKey [BEq α] (a : α) : (l : AssocList α β) → l.contains a → α
|
||||
| cons k _ es, h => if hka : k == a then k
|
||||
else es.getKey a (by rw [← h, contains, Bool.of_not_eq_true hka, Bool.false_or])
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getCast! [BEq α] [LawfulBEq α] (a : α) [Inhabited (β a)] : AssocList α β → β a
|
||||
| nil => panic! "key is not present in hash table"
|
||||
| cons k v es => if h : k == a then cast (congrArg β (eq_of_beq h)) v else es.getCast! a
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getKey? [BEq α] (a : α) : AssocList α β → Option α
|
||||
| nil => none
|
||||
| cons k _ es => if k == a then some k else es.getKey? a
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def get! {β : Type v} [BEq α] [Inhabited β] (a : α) : AssocList α (fun _ => β) → β
|
||||
| nil => panic! "key is not present in hash table"
|
||||
| cons k v es => bif k == a then v else es.get! a
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getKey! [BEq α] [Inhabited α] (a : α) : AssocList α β → α
|
||||
| nil => panic! "key is not present in hash table"
|
||||
| cons k _ es => if k == a then k else es.getKey! a
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getCastD [BEq α] [LawfulBEq α] (a : α) (fallback : β a) : AssocList α β → β a
|
||||
| nil => fallback
|
||||
@@ -123,6 +138,11 @@ def getD {β : Type v} [BEq α] (a : α) (fallback : β) : AssocList α (fun _ =
|
||||
| nil => fallback
|
||||
| cons k v es => bif k == a then v else es.getD a fallback
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getKeyD [BEq α] (a : α) (fallback : α) : AssocList α β → α
|
||||
| nil => fallback
|
||||
| cons k _ es => if k == a then k else es.getKeyD a fallback
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def replace [BEq α] (a : α) (b : β a) : AssocList α β → AssocList α β
|
||||
| nil => nil
|
||||
|
||||
@@ -112,6 +112,32 @@ theorem get!_eq {β : Type v} [BEq α] [Inhabited β] {l : AssocList α (fun _ =
|
||||
· simp_all [get!, List.getValue!, List.getValue!, List.getValue?_cons,
|
||||
Bool.apply_cond Option.get!]
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_eq [BEq α] {l : AssocList α β} {a : α} :
|
||||
l.getKey? a = List.getKey? a l.toList := by
|
||||
induction l <;> simp_all [getKey?]
|
||||
|
||||
@[simp]
|
||||
theorem getKey_eq [BEq α] {l : AssocList α β} {a : α} {h} :
|
||||
l.getKey a h = List.getKey a l.toList (contains_eq.symm.trans h) := by
|
||||
induction l
|
||||
· simp [contains] at h
|
||||
· next k v t ih => simp only [getKey, toList_cons, List.getKey_cons, ih]
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_eq [BEq α] {l : AssocList α β} {a fallback : α} :
|
||||
l.getKeyD a fallback = List.getKeyD a l.toList fallback := by
|
||||
induction l
|
||||
· simp [getKeyD, List.getKeyD]
|
||||
· simp_all [getKeyD, List.getKeyD, Bool.apply_cond (fun x => Option.getD x fallback)]
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_eq [BEq α] [Inhabited α] {l : AssocList α β} {a : α} :
|
||||
l.getKey! a = List.getKey! a l.toList := by
|
||||
induction l
|
||||
· simp [getKey!, List.getKey!]
|
||||
· simp_all [getKey!, List.getKey!, Bool.apply_cond Option.get!]
|
||||
|
||||
@[simp]
|
||||
theorem toList_replace [BEq α] {l : AssocList α β} {a : α} {b : β a} :
|
||||
(l.replace a b).toList = replaceEntry a b l.toList := by
|
||||
|
||||
@@ -100,9 +100,9 @@ Here is a summary of the steps required to add and verify a new operation:
|
||||
* Connect the implementation on lists and associative lists in `Internal.AssocList.Lemmas` via a
|
||||
lemma `AssocList.operation_eq`.
|
||||
3. Write the model implementation
|
||||
* Write the model implementation `Raw₀.operationₘ` in `Internal.List.Model`
|
||||
* Write the model implementation `Raw₀.operationₘ` in `Internal.Model`
|
||||
* Prove that the model implementation is equal to the actual implementation in
|
||||
`Internal.List.Model` via a lemma `operation_eq_operationₘ`.
|
||||
`Internal.Model` via a lemma `operation_eq_operationₘ`.
|
||||
4. Verify the model implementation
|
||||
* In `Internal.WF`, prove `operationₘ_eq_List.operation` (for access operations) or
|
||||
`wfImp_operationₘ` and `toListModel_operationₘ`
|
||||
@@ -121,18 +121,18 @@ Here is a summary of the steps required to add and verify a new operation:
|
||||
might also have to prove that your list operation is invariant under permutation and add that to
|
||||
the tactic.
|
||||
7. State and prove the user-facing lemmas
|
||||
* Restate all of your lemmas for `DHashMap.Raw` in `DHashMap.Lemmas` and prove them using the
|
||||
* Restate all of your lemmas for `DHashMap.Raw` in `DHashMap.RawLemmas` and prove them using the
|
||||
provided tactic after hooking in your `operation_eq` and `operation_val` from step 5.
|
||||
* Restate all of your lemmas for `DHashMap` in `DHashMap.Lemmas` and prove them by reducing to
|
||||
`Raw₀`.
|
||||
* Restate all of your lemmas for `HashMap.Raw` in `HashMap.Lemmas` and prove them by reducing to
|
||||
* Restate all of your lemmas for `HashMap.Raw` in `HashMap.RawLemmas` and prove them by reducing to
|
||||
`DHashMap.Raw`.
|
||||
* Restate all of your lemmas for `HashMap` in `HashMap.Lemmas` and prove them by reducing to
|
||||
`DHashMap`.
|
||||
* Restate all of your lemmas for `HashSet.Raw` in `HashSet.Lemmas` and prove them by reducing to
|
||||
`DHashSet.Raw`.
|
||||
* Restate all of your lemmas for `HashSet.Raw` in `HashSet.RawLemmas` and prove them by reducing to
|
||||
`HashMap.Raw`.
|
||||
* Restate all of your lemmas for `HashSet` in `HashSet.Lemmas` and prove them by reducing to
|
||||
`DHashSet`.
|
||||
`HashMap`.
|
||||
|
||||
This sounds like a lot of work (and it is if you have to add a lot of user-facing lemmas), but the
|
||||
framework is set up in such a way that each step is really easy and the proofs are all really short
|
||||
@@ -156,7 +156,7 @@ namespace DHashMap.Internal
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def toListModel (buckets : Array (AssocList α β)) : List ((a : α) × β a) :=
|
||||
buckets.data.bind AssocList.toList
|
||||
buckets.toList.bind AssocList.toList
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
@[inline] def computeSize (buckets : Array (AssocList α β)) : Nat :=
|
||||
@@ -420,6 +420,30 @@ variable {β : Type v}
|
||||
|
||||
end
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
@[inline] def getKey? [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) : Option α :=
|
||||
let ⟨⟨_, buckets⟩, h⟩ := m
|
||||
let ⟨i, h⟩ := mkIdx buckets.size h (hash a)
|
||||
buckets[i].getKey? a
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
@[inline] def getKey [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) (hma : m.contains a) : α :=
|
||||
let ⟨⟨_, buckets⟩, h⟩ := m
|
||||
let idx := mkIdx buckets.size h (hash a)
|
||||
buckets[idx.1].getKey a hma
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
@[inline] def getKeyD [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) (fallback : α) : α :=
|
||||
let ⟨⟨_, buckets⟩, h⟩ := m
|
||||
let idx := mkIdx buckets.size h (hash a)
|
||||
buckets[idx.1].getKeyD a fallback
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
@[inline] def getKey! [BEq α] [Hashable α] [Inhabited α] (m : Raw₀ α β) (a : α) : α :=
|
||||
let ⟨⟨_, buckets⟩, h⟩ := m
|
||||
let idx := mkIdx buckets.size h (hash a)
|
||||
buckets[idx.1].getKey! a
|
||||
|
||||
end Raw₀
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
|
||||
@@ -526,6 +526,111 @@ theorem getValue!_eq_getValueD_default [BEq α] [Inhabited β] {l : List ((_ :
|
||||
|
||||
end
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getKey? [BEq α] (a : α) : List ((a : α) × β a) → Option α
|
||||
| [] => none
|
||||
| ⟨k, _⟩ :: l => bif k == a then some k else getKey? a l
|
||||
|
||||
@[simp] theorem getKey?_nil [BEq α] {a : α} :
|
||||
getKey? a ([] : List ((a : α) × β a)) = none := rfl
|
||||
|
||||
@[simp] theorem getKey?_cons [BEq α] {l : List ((a : α) × β a)} {k a : α} {v : β k} :
|
||||
getKey? a (⟨k, v⟩ :: l) = bif k == a then some k else getKey? a l := rfl
|
||||
|
||||
theorem getKey?_cons_of_true [BEq α] {l : List ((a : α) × β a)} {k a : α} {v : β k} (h : k == a) :
|
||||
getKey? a (⟨k, v⟩ :: l) = some k := by
|
||||
simp [h]
|
||||
|
||||
theorem getKey?_cons_of_false [BEq α] {l : List ((a : α) × β a)} {k a : α} {v : β k}
|
||||
(h : (k == a) = false) : getKey? a (⟨k, v⟩ :: l) = getKey? a l := by
|
||||
simp [h]
|
||||
|
||||
theorem getKey?_eq_getEntry? [BEq α] {l : List ((a : α) × β a)} {a : α} :
|
||||
getKey? a l = (getEntry? a l).map (·.1) := by
|
||||
induction l using assoc_induction
|
||||
· simp
|
||||
· next k v l ih =>
|
||||
cases h : k == a
|
||||
· rw [getEntry?_cons_of_false h, getKey?_cons_of_false h, ih]
|
||||
· rw [getEntry?_cons_of_true h, getKey?_cons_of_true h, Option.map_some']
|
||||
|
||||
theorem containsKey_eq_isSome_getKey? [BEq α] {l : List ((a : α) × β a)} {a : α} :
|
||||
containsKey a l = (getKey? a l).isSome := by
|
||||
simp [containsKey_eq_isSome_getEntry?, getKey?_eq_getEntry?]
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getKey [BEq α] (a : α) (l : List ((a : α) × β a)) (h : containsKey a l) : α :=
|
||||
(getKey? a l).get <| containsKey_eq_isSome_getKey?.symm.trans h
|
||||
|
||||
theorem getKey?_eq_some_getKey [BEq α] {l : List ((a : α) × β a)} {a : α} (h : containsKey a l) :
|
||||
getKey? a l = some (getKey a l h) := by
|
||||
simp [getKey]
|
||||
|
||||
theorem getKey_cons [BEq α] {l : List ((a : α) × β a)} {k a : α} {v : β k} {h} :
|
||||
getKey a (⟨k, v⟩ :: l) h = if h' : k == a then k
|
||||
else getKey a l (containsKey_of_containsKey_cons (k := k) h (Bool.eq_false_iff.2 h')) := by
|
||||
rw [← Option.some_inj, ← getKey?_eq_some_getKey, getKey?_cons, apply_dite Option.some,
|
||||
cond_eq_if]
|
||||
split
|
||||
· rfl
|
||||
· exact getKey?_eq_some_getKey _
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getKeyD [BEq α] (a : α) (l : List ((a : α) × β a)) (fallback : α) : α :=
|
||||
(getKey? a l).getD fallback
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_nil [BEq α] {a fallback : α} :
|
||||
getKeyD a ([] : List ((a : α) × β a)) fallback = fallback := rfl
|
||||
|
||||
theorem getKeyD_eq_getKey? [BEq α] {l : List ((a : α) × β a)} {a fallback : α} :
|
||||
getKeyD a l fallback = (getKey? a l).getD fallback := rfl
|
||||
|
||||
theorem getKeyD_eq_fallback [BEq α] [EquivBEq α] {l : List ((a : α) × β a)} {a fallback : α}
|
||||
(h : containsKey a l = false) : getKeyD a l fallback = fallback := by
|
||||
rw [containsKey_eq_isSome_getKey?, Bool.eq_false_iff, ne_eq,
|
||||
Option.not_isSome_iff_eq_none] at h
|
||||
rw [getKeyD_eq_getKey?, h, Option.getD_none]
|
||||
|
||||
theorem getKey_eq_getKeyD [BEq α] [EquivBEq α] {l : List ((a : α) × β a)} {a fallback : α}
|
||||
(h : containsKey a l = true) :
|
||||
getKey a l h = getKeyD a l fallback := by
|
||||
rw [getKeyD_eq_getKey?, getKey, Option.get_eq_getD]
|
||||
|
||||
theorem getKey?_eq_some_getKeyD [BEq α] [EquivBEq α] {l : List ((a : α) × β a)} {a fallback : α}
|
||||
(h : containsKey a l = true) :
|
||||
getKey? a l = some (getKeyD a l fallback) := by
|
||||
rw [getKey?_eq_some_getKey h, getKey_eq_getKeyD]
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getKey! [BEq α] [Inhabited α] (a : α) (l : List ((a : α) × β a)) : α :=
|
||||
(getKey? a l).get!
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_nil [BEq α] [Inhabited α] {a : α} :
|
||||
getKey! a ([] : List ((a : α) × β a)) = default := rfl
|
||||
|
||||
theorem getKey!_eq_getKey? [BEq α] [Inhabited α] {l : List ((a : α) × β a)} {a : α} :
|
||||
getKey! a l = (getKey? a l).get! := rfl
|
||||
|
||||
theorem getKey!_eq_default [BEq α] [Inhabited α] {l : List ((a : α) × β a)} {a : α}
|
||||
(h : containsKey a l = false) : getKey! a l = default := by
|
||||
rw [containsKey_eq_isSome_getKey?, Bool.eq_false_iff, ne_eq,
|
||||
Option.not_isSome_iff_eq_none] at h
|
||||
rw [getKey!_eq_getKey?, h, Option.get!_none]
|
||||
|
||||
theorem getKey_eq_getKey! [BEq α] [Inhabited α] {l : List ((a : α) × β a)} {a : α}
|
||||
(h : containsKey a l = true) : getKey a l h = getKey! a l := by
|
||||
rw [getKey!_eq_getKey?, getKey, Option.get_eq_get!]
|
||||
|
||||
theorem getKey?_eq_some_getKey! [BEq α] [Inhabited α] {l : List ((a : α) × β a)} {a : α}
|
||||
(h : containsKey a l = true) :
|
||||
getKey? a l = some (getKey! a l) := by
|
||||
rw [getKey?_eq_some_getKey h, getKey_eq_getKey!]
|
||||
|
||||
theorem getKey!_eq_getKeyD_default [BEq α] [EquivBEq α] [Inhabited α] {l : List ((a : α) × β a)}
|
||||
{a : α} : getKey! a l = getKeyD a l default := rfl
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def replaceEntry [BEq α] (k : α) (v : β k) : List ((a : α) × β a) → List ((a : α) × β a)
|
||||
| [] => []
|
||||
@@ -643,6 +748,18 @@ theorem getValueCast?_replaceEntry [BEq α] [LawfulBEq α] {l : List ((a : α)
|
||||
· rw [Option.dmap_congr (getEntry?_replaceEntry_of_false (Bool.eq_false_iff.2 h)),
|
||||
getValueCast?_eq_getEntry?]
|
||||
|
||||
theorem getKey?_replaceEntry [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)} {a k : α}
|
||||
{v : β k} : getKey? a (replaceEntry k v l) =
|
||||
if containsKey k l ∧ k == a then some k else getKey? a l := by
|
||||
rw [getKey?_eq_getEntry?]
|
||||
split
|
||||
· next h => simp [getEntry?_replaceEntry_of_true h.1 h.2]
|
||||
· next h =>
|
||||
simp only [Decidable.not_and_iff_or_not_not] at h
|
||||
rcases h with h|h
|
||||
· rw [getEntry?_replaceEntry_of_containsKey_eq_false (Bool.eq_false_iff.2 h), getKey?_eq_getEntry?]
|
||||
· rw [getEntry?_replaceEntry_of_false (Bool.eq_false_iff.2 h), getKey?_eq_getEntry?]
|
||||
|
||||
@[simp]
|
||||
theorem containsKey_replaceEntry [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)} {a k : α}
|
||||
{v : β k} : containsKey a (replaceEntry k v l) = containsKey a l := by
|
||||
@@ -974,6 +1091,39 @@ theorem getValueD_insertEntry_self {β : Type v} [BEq α] [EquivBEq α] {l : Lis
|
||||
{k : α} {fallback v : β} : getValueD k (insertEntry k v l) fallback = v := by
|
||||
simp [getValueD_insertEntry, BEq.refl]
|
||||
|
||||
theorem getKey?_insertEntry [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)} {k a : α}
|
||||
{v : β k} : getKey? a (insertEntry k v l) = if k == a then some k else getKey? a l := by
|
||||
cases hl : containsKey k l
|
||||
· simp [insertEntry_of_containsKey_eq_false hl]
|
||||
· rw [insertEntry_of_containsKey hl, getKey?_replaceEntry, hl]
|
||||
split <;> simp_all
|
||||
|
||||
theorem getKey?_insertEntry_self [BEq α] [EquivBEq α] {l : List ((a : α) × β a)} {k : α}
|
||||
{v : β k} : getKey? k (insertEntry k v l) = some k := by
|
||||
simp [getKey?_insertEntry]
|
||||
|
||||
theorem getKey?_eq_none [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)} {a : α}
|
||||
(h : containsKey a l = false) : getKey? a l = none := by
|
||||
rwa [← Option.not_isSome_iff_eq_none, ← containsKey_eq_isSome_getKey?, Bool.not_eq_true]
|
||||
|
||||
theorem getKey!_insertEntry [BEq α] [EquivBEq α] [Inhabited α] {l : List ((a : α) × β a)}
|
||||
{k a : α} {v : β k} : getKey! a (insertEntry k v l) =
|
||||
if k == a then k else getKey! a l := by
|
||||
simp [getKey!_eq_getKey?, getKey?_insertEntry, apply_ite Option.get!]
|
||||
|
||||
theorem getKey!_insertEntry_self [BEq α] [EquivBEq α] [Inhabited α] {l : List ((a : α) × β a)}
|
||||
{k : α} {v : β k} : getKey! k (insertEntry k v l) = k := by
|
||||
rw [getKey!_insertEntry, if_pos BEq.refl]
|
||||
|
||||
theorem getKeyD_insertEntry [BEq α] [EquivBEq α] {l : List ((a : α) × β a)} {k a fallback : α}
|
||||
{v : β k} : getKeyD a (insertEntry k v l) fallback =
|
||||
if k == a then k else getKeyD a l fallback := by
|
||||
simp [getKeyD_eq_getKey?, getKey?_insertEntry, apply_ite (fun x => Option.getD x fallback)]
|
||||
|
||||
theorem getKeyD_insertEntry_self [BEq α] [EquivBEq α] {l : List ((a : α) × β a)} {k fallback : α}
|
||||
{v : β k} : getKeyD k (insertEntry k v l) fallback = k := by
|
||||
rw [getKeyD_insertEntry, if_pos BEq.refl]
|
||||
|
||||
@[local simp]
|
||||
theorem containsKey_insertEntry [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)} {k a : α}
|
||||
{v : β k} : containsKey a (insertEntry k v l) = ((k == a) || containsKey a l) := by
|
||||
@@ -1017,6 +1167,17 @@ theorem getValue_insertEntry_self {β : Type v} [BEq α] [EquivBEq α] {l : List
|
||||
{v : β} : getValue k (insertEntry k v l) containsKey_insertEntry_self = v := by
|
||||
simp [getValue_insertEntry]
|
||||
|
||||
theorem getKey_insertEntry [BEq α] [EquivBEq α] {l : List ((a : α) × β a)} {k a : α}
|
||||
{v : β k} {h} : getKey a (insertEntry k v l) h =
|
||||
if h' : k == a then k
|
||||
else getKey a l (containsKey_of_containsKey_insertEntry h (Bool.eq_false_iff.2 h')) := by
|
||||
rw [← Option.some_inj, ← getKey?_eq_some_getKey, apply_dite Option.some, getKey?_insertEntry]
|
||||
simp only [← getKey?_eq_some_getKey, dite_eq_ite]
|
||||
|
||||
theorem getKey_insertEntry_self [BEq α] [EquivBEq α] {l : List ((a : α) × β a)} {k : α}
|
||||
{v : β k} : getKey k (insertEntry k v l) containsKey_insertEntry_self = k := by
|
||||
simp [getKey_insertEntry]
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def insertEntryIfNew [BEq α] (k : α) (v : β k) (l : List ((a : α) × β a)) : List ((a : α) × β a) :=
|
||||
bif containsKey k l then l else ⟨k, v⟩ :: l
|
||||
@@ -1135,6 +1296,32 @@ theorem getValueD_insertEntryIfNew {β : Type v} [BEq α] [PartialEquivBEq α] {
|
||||
simp [getValueD_eq_getValue?, getValue?_insertEntryIfNew,
|
||||
apply_ite (fun x => Option.getD x fallback)]
|
||||
|
||||
theorem getKey?_insertEntryIfNew [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)} {k a : α}
|
||||
{v : β k} : getKey? a (insertEntryIfNew k v l) =
|
||||
if k == a ∧ containsKey k l = false then some k else getKey? a l := by
|
||||
cases h : containsKey k l
|
||||
· rw [insertEntryIfNew_of_containsKey_eq_false h]
|
||||
split <;> simp_all
|
||||
· simp [insertEntryIfNew_of_containsKey h]
|
||||
|
||||
theorem getKey_insertEntryIfNew [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)}
|
||||
{k a : α} {v : β k} {h} : getKey a (insertEntryIfNew k v l) h =
|
||||
if h' : k == a ∧ containsKey k l = false then k
|
||||
else getKey a l (containsKey_of_containsKey_insertEntryIfNew' h h') := by
|
||||
rw [← Option.some_inj, ← getKey?_eq_some_getKey, apply_dite Option.some,
|
||||
getKey?_insertEntryIfNew, ← dite_eq_ite]
|
||||
simp [← getKey?_eq_some_getKey]
|
||||
|
||||
theorem getKey!_insertEntryIfNew [BEq α] [PartialEquivBEq α] [Inhabited α]
|
||||
{l : List ((a : α) × β a)} {k a : α} {v : β k} : getKey! a (insertEntryIfNew k v l) =
|
||||
if k == a ∧ containsKey k l = false then k else getKey! a l := by
|
||||
simp [getKey!_eq_getKey?, getKey?_insertEntryIfNew, apply_ite Option.get!]
|
||||
|
||||
theorem getKeyD_insertEntryIfNew [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)}
|
||||
{k a fallback : α} {v : β k} : getKeyD a (insertEntryIfNew k v l) fallback =
|
||||
if k == a ∧ containsKey k l = false then k else getKeyD a l fallback := by
|
||||
simp [getKeyD_eq_getKey?, getKey?_insertEntryIfNew, apply_ite (fun x => Option.getD x fallback)]
|
||||
|
||||
theorem length_insertEntryIfNew [BEq α] {l : List ((a : α) × β a)} {k : α} {v : β k} :
|
||||
(insertEntryIfNew k v l).length = if containsKey k l then l.length else l.length + 1 := by
|
||||
simp [insertEntryIfNew, Bool.apply_cond List.length]
|
||||
@@ -1253,6 +1440,36 @@ theorem getValue?_eraseKey [BEq α] [PartialEquivBEq α] {l : List ((_ : α) ×
|
||||
|
||||
end
|
||||
|
||||
theorem getKey?_eraseKey [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)} {k a : α}
|
||||
(hl : DistinctKeys l) :
|
||||
getKey? a (eraseKey k l) = if k == a then none else getKey? a l := by
|
||||
rw [getKey?_eq_getEntry?, getEntry?_eraseKey hl]
|
||||
by_cases h : k == a
|
||||
. simp [h]
|
||||
. simp [h, getKey?_eq_getEntry?]
|
||||
|
||||
theorem getKey?_eraseKey_self [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)} {k : α}
|
||||
(hl : DistinctKeys l) : getKey? k (eraseKey k l) = none := by
|
||||
simp [getKey?_eq_getEntry?, getEntry?_eraseKey_self hl]
|
||||
|
||||
theorem getKey!_eraseKey [BEq α] [PartialEquivBEq α] [Inhabited α] {l : List ((a : α) × β a)}
|
||||
{k a : α} (hl : DistinctKeys l) :
|
||||
getKey! a (eraseKey k l) = if k == a then default else getKey! a l := by
|
||||
simp [getKey!_eq_getKey?, getKey?_eraseKey hl, apply_ite Option.get!]
|
||||
|
||||
theorem getKey!_eraseKey_self [BEq α] [PartialEquivBEq α] [Inhabited α] {l : List ((a : α) × β a)}
|
||||
{k : α} (hl : DistinctKeys l) : getKey! k (eraseKey k l) = default := by
|
||||
simp [getKey!_eq_getKey?, getKey?_eraseKey_self hl]
|
||||
|
||||
theorem getKeyD_eraseKey [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)} {k a fallback : α}
|
||||
(hl : DistinctKeys l) :
|
||||
getKeyD a (eraseKey k l) fallback = if k == a then fallback else getKeyD a l fallback := by
|
||||
simp [getKeyD_eq_getKey?, getKey?_eraseKey hl, apply_ite (fun x => Option.getD x fallback)]
|
||||
|
||||
theorem getKeyD_eraseKey_self [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)}
|
||||
{k fallback : α} (hl : DistinctKeys l) : getKeyD k (eraseKey k l) fallback = fallback := by
|
||||
simp [getKeyD_eq_getKey?, getKey?_eraseKey_self hl]
|
||||
|
||||
theorem containsKey_eraseKey_self [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)} {k : α}
|
||||
(h : DistinctKeys l) : containsKey k (eraseKey k l) = false := by
|
||||
simp [containsKey_eq_isSome_getEntry?, getEntry?_eraseKey_self h]
|
||||
@@ -1340,6 +1557,13 @@ theorem getValue_eraseKey {β : Type v} [BEq α] [PartialEquivBEq α] {l : List
|
||||
rw [← Option.some_inj, ← getValue?_eq_some_getValue, getValue?_eraseKey hl, h.1]
|
||||
simp [← getValue?_eq_some_getValue]
|
||||
|
||||
theorem getKey_eraseKey [BEq α] [EquivBEq α] {l : List ((a : α) × β a)} {k a : α} {h}
|
||||
(hl : DistinctKeys l) : getKey a (eraseKey k l) h =
|
||||
getKey a l (containsKey_of_containsKey_eraseKey hl h) := by
|
||||
rw [containsKey_eraseKey hl, Bool.and_eq_true, Bool.not_eq_true'] at h
|
||||
rw [← Option.some_inj, ← getKey?_eq_some_getKey, getKey?_eraseKey hl, h.1]
|
||||
simp [← getKey?_eq_some_getKey]
|
||||
|
||||
theorem getEntry?_of_perm [BEq α] [PartialEquivBEq α] {l l' : List ((a : α) × β a)} {a : α}
|
||||
(hl : DistinctKeys l) (h : Perm l l') : getEntry? a l = getEntry? a l' := by
|
||||
induction h
|
||||
@@ -1412,6 +1636,26 @@ theorem getValueD_of_perm [BEq α] [PartialEquivBEq α] {l l' : List ((_ : α)
|
||||
|
||||
end
|
||||
|
||||
theorem getKey?_of_perm [BEq α] [PartialEquivBEq α] {l l' : List ((a : α) × β a)} {a : α}
|
||||
(hl : DistinctKeys l) (h : Perm l l') : getKey? a l = getKey? a l' := by
|
||||
rw [getKey?_eq_getEntry?, getKey?_eq_getEntry?, getEntry?_of_perm hl h]
|
||||
|
||||
theorem getKey_of_perm [BEq α] [PartialEquivBEq α] {l l' : List ((a : α) × β a)} {a : α} {h'}
|
||||
(hl : DistinctKeys l) (h : Perm l l') :
|
||||
getKey a l h' = getKey a l' ((containsKey_of_perm h).symm.trans h') := by
|
||||
rw [← Option.some_inj, ← getKey?_eq_some_getKey, ← getKey?_eq_some_getKey,
|
||||
getKey?_of_perm hl h]
|
||||
|
||||
theorem getKey!_of_perm [BEq α] [PartialEquivBEq α] [Inhabited α] {l l' : List ((a : α) × β a)}
|
||||
{a : α} (hl : DistinctKeys l) (h : Perm l l') :
|
||||
getKey! a l = getKey! a l' := by
|
||||
simp only [getKey!_eq_getKey?, getKey?_of_perm hl h]
|
||||
|
||||
theorem getKeyD_of_perm [BEq α] [PartialEquivBEq α] {l l' : List ((a : α) × β a)} {a fallback : α}
|
||||
(hl : DistinctKeys l) (h : Perm l l') :
|
||||
getKeyD a l fallback = getKeyD a l' fallback := by
|
||||
simp only [getKeyD_eq_getKey?, getKey?_of_perm hl h]
|
||||
|
||||
theorem perm_cons_getEntry [BEq α] {l : List ((a : α) × β a)} {a : α} (h : containsKey a l) :
|
||||
∃ l', Perm l (getEntry a l h :: l') := by
|
||||
induction l using assoc_induction
|
||||
@@ -1521,6 +1765,18 @@ theorem getValueCast_append_of_containsKey_eq_false [BEq α] [LawfulBEq α]
|
||||
rw [← Option.some_inj, ← getValueCast?_eq_some_getValueCast, ← getValueCast?_eq_some_getValueCast,
|
||||
getValueCast?_append_of_containsKey_eq_false hl']
|
||||
|
||||
theorem getKey?_append_of_containsKey_eq_false [BEq α] [PartialEquivBEq α]
|
||||
{l l' : List ((a : α) × β a)} {a : α} (hl' : containsKey a l' = false) :
|
||||
getKey? a (l ++ l') = getKey? a l := by
|
||||
simp [getKey?_eq_getEntry?, getEntry?_eq_none.2 hl']
|
||||
|
||||
theorem getKey_append_of_containsKey_eq_false [BEq α] [PartialEquivBEq α]
|
||||
{l l' : List ((a : α) × β a)} {a : α} {h} (hl' : containsKey a l' = false) :
|
||||
getKey a (l ++ l') h =
|
||||
getKey a l ((containsKey_append_of_not_contains_right hl').symm.trans h) := by
|
||||
rw [← Option.some_inj, ← getKey?_eq_some_getKey, ← getKey?_eq_some_getKey,
|
||||
getKey?_append_of_containsKey_eq_false hl']
|
||||
|
||||
theorem replaceEntry_append_of_containsKey_left [BEq α] {l l' : List ((a : α) × β a)} {k : α}
|
||||
{v : β k} (h : containsKey k l) : replaceEntry k v (l ++ l') = replaceEntry k v l ++ l' := by
|
||||
induction l using assoc_induction
|
||||
|
||||
@@ -98,14 +98,14 @@ theorem exists_bucket_of_uset [BEq α] [Hashable α]
|
||||
refine ⟨?_, ?_⟩
|
||||
· apply List.containsKey_bind_eq_false
|
||||
intro j hj
|
||||
rw [← List.getElem_append (l₂ := self[i] :: l₂), getElem_congr_coll h₁.symm]
|
||||
rw [List.getElem_append_left' (l₂ := self[i] :: l₂), getElem_congr_coll h₁.symm]
|
||||
apply (h.hashes_to j _).containsKey_eq_false h₀ k
|
||||
omega
|
||||
· apply List.containsKey_bind_eq_false
|
||||
intro j hj
|
||||
rw [← List.getElem_cons_succ self[i] _ _
|
||||
(by simp only [Array.ugetElem_eq_getElem, List.length_cons]; omega)]
|
||||
rw [List.getElem_append_right'' l₁, getElem_congr_coll h₁.symm]
|
||||
rw [List.getElem_append_right' l₁, getElem_congr_coll h₁.symm]
|
||||
apply (h.hashes_to (j + 1 + l₁.length) _).containsKey_eq_false h₀ k
|
||||
omega
|
||||
|
||||
@@ -121,7 +121,7 @@ theorem exists_bucket_of_update [BEq α] [Hashable α] (m : Array (AssocList α
|
||||
|
||||
theorem exists_bucket' [BEq α] [Hashable α]
|
||||
(self : Array (AssocList α β)) (i : USize) (hi : i.toNat < self.size) :
|
||||
∃ l, Perm (self.data.bind AssocList.toList) (self[i.toNat].toList ++ l) ∧
|
||||
∃ l, Perm (self.toList.bind AssocList.toList) (self[i.toNat].toList ++ l) ∧
|
||||
(∀ [LawfulHashable α], IsHashSelf self → ∀ k,
|
||||
(mkIdx self.size (by omega) (hash k)).1.toNat = i.toNat → containsKey k l = false) := by
|
||||
obtain ⟨l, h₁, -, h₂⟩ := exists_bucket_of_uset self i hi .nil
|
||||
@@ -186,13 +186,13 @@ theorem toListModel_updateAllBuckets {m : Raw₀ α β} {f : AssocList α β →
|
||||
have := (hg (l := []) (l' := [])).length_eq
|
||||
rw [List.length_append, List.append_nil] at this
|
||||
omega
|
||||
rw [updateAllBuckets, toListModel, Array.map_data, List.bind_eq_foldl, List.foldl_map,
|
||||
rw [updateAllBuckets, toListModel, Array.map_toList, List.bind_eq_foldl, List.foldl_map,
|
||||
toListModel, List.bind_eq_foldl]
|
||||
suffices ∀ (l : List (AssocList α β)) (l' : List ((a: α) × δ a)) (l'' : List ((a : α) × β a)),
|
||||
Perm (g l'') l' →
|
||||
Perm (l.foldl (fun acc a => acc ++ (f a).toList) l')
|
||||
(g (l.foldl (fun acc a => acc ++ a.toList) l'')) by
|
||||
simpa using this m.1.buckets.data [] [] (by simp [hg₀])
|
||||
simpa using this m.1.buckets.toList [] [] (by simp [hg₀])
|
||||
rintro l l' l'' h
|
||||
induction l generalizing l' l''
|
||||
· simpa using h.symm
|
||||
@@ -262,6 +262,10 @@ def consₘ [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) (b : β a) : Raw
|
||||
def get?ₘ [BEq α] [LawfulBEq α] [Hashable α] (m : Raw₀ α β) (a : α) : Option (β a) :=
|
||||
(bucket m.1.buckets m.2 a).getCast? a
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getKey?ₘ [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) : Option α :=
|
||||
(bucket m.1.buckets m.2 a).getKey? a
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def containsₘ [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) : Bool :=
|
||||
(bucket m.1.buckets m.2 a).contains a
|
||||
@@ -278,6 +282,18 @@ def getDₘ [BEq α] [LawfulBEq α] [Hashable α] (m : Raw₀ α β) (a : α) (f
|
||||
def get!ₘ [BEq α] [LawfulBEq α] [Hashable α] (m : Raw₀ α β) (a : α) [Inhabited (β a)] : β a :=
|
||||
(m.get?ₘ a).get!
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getKeyₘ [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) (h : m.containsₘ a) : α :=
|
||||
(bucket m.1.buckets m.2 a).getKey a h
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getKeyDₘ [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) (fallback : α) : α :=
|
||||
(m.getKey?ₘ a).getD fallback
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def getKey!ₘ [BEq α] [Hashable α] [Inhabited α] (m : Raw₀ α β) (a : α) : α :=
|
||||
(m.getKey?ₘ a).get!
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
def insertₘ [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) (b : β a) : Raw₀ α β :=
|
||||
if m.containsₘ a then m.replaceₘ a b else Raw₀.expandIfNecessary (m.consₘ a b)
|
||||
@@ -348,6 +364,20 @@ theorem get!_eq_get!ₘ [BEq α] [LawfulBEq α] [Hashable α] (m : Raw₀ α β)
|
||||
get! m a = get!ₘ m a := by
|
||||
simp [get!, get!ₘ, get?ₘ, List.getValueCast!_eq_getValueCast?, bucket]
|
||||
|
||||
theorem getKey?_eq_getKey?ₘ [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) :
|
||||
getKey? m a = getKey?ₘ m a := rfl
|
||||
|
||||
theorem getKey_eq_getKeyₘ [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) (h : m.contains a) :
|
||||
getKey m a h = getKeyₘ m a h := rfl
|
||||
|
||||
theorem getKeyD_eq_getKeyDₘ [BEq α] [Hashable α] (m : Raw₀ α β) (a fallback : α) :
|
||||
getKeyD m a fallback = getKeyDₘ m a fallback := by
|
||||
simp [getKeyD, getKeyDₘ, getKey?ₘ, List.getKeyD_eq_getKey?, bucket]
|
||||
|
||||
theorem getKey!_eq_getKey!ₘ [BEq α] [Hashable α] [Inhabited α] (m : Raw₀ α β) (a : α) :
|
||||
getKey! m a = getKey!ₘ m a := by
|
||||
simp [getKey!, getKey!ₘ, getKey?ₘ, List.getKey!_eq_getKey?, bucket]
|
||||
|
||||
theorem contains_eq_containsₘ [BEq α] [Hashable α] (m : Raw₀ α β) (a : α) :
|
||||
m.contains a = m.containsₘ a := rfl
|
||||
|
||||
|
||||
@@ -135,6 +135,37 @@ theorem get!_val [BEq α] [Hashable α] [LawfulBEq α] {m : Raw₀ α β} {a :
|
||||
m.val.get! a = m.get! a := by
|
||||
simp [Raw.get!, m.2]
|
||||
|
||||
theorem getKey?_eq [BEq α] [Hashable α] {m : Raw α β} (h : m.WF) {a : α} :
|
||||
m.getKey? a = Raw₀.getKey? ⟨m, h.size_buckets_pos⟩ a := by
|
||||
simp [Raw.getKey?, h.size_buckets_pos]
|
||||
|
||||
theorem getKey?_val [BEq α] [Hashable α] {m : Raw₀ α β} {a : α} :
|
||||
m.val.getKey? a = m.getKey? a := by
|
||||
simp [Raw.getKey?, m.2]
|
||||
|
||||
theorem getKey_eq [BEq α] [Hashable α] {m : Raw α β} {a : α} {h : a ∈ m} :
|
||||
m.getKey a h = Raw₀.getKey ⟨m, by change dite .. = true at h; split at h <;> simp_all⟩ a
|
||||
(by change dite .. = true at h; split at h <;> simp_all) := rfl
|
||||
|
||||
theorem getKey_val [BEq α] [Hashable α] {m : Raw₀ α β} {a : α} {h : a ∈ m.val} :
|
||||
m.val.getKey a h = m.getKey a (contains_val (m := m) ▸ h) := rfl
|
||||
|
||||
theorem getKeyD_eq [BEq α] [Hashable α] {m : Raw α β} (h : m.WF) {a fallback : α} :
|
||||
m.getKeyD a fallback = Raw₀.getKeyD ⟨m, h.size_buckets_pos⟩ a fallback := by
|
||||
simp [Raw.getKeyD, h.size_buckets_pos]
|
||||
|
||||
theorem getKeyD_val [BEq α] [Hashable α] {m : Raw₀ α β} {a fallback : α} :
|
||||
m.val.getKeyD a fallback = m.getKeyD a fallback := by
|
||||
simp [Raw.getKeyD, m.2]
|
||||
|
||||
theorem getKey!_eq [BEq α] [Hashable α] [Inhabited α] {m : Raw α β} (h : m.WF) {a : α} :
|
||||
m.getKey! a = Raw₀.getKey! ⟨m, h.size_buckets_pos⟩ a := by
|
||||
simp [Raw.getKey!, h.size_buckets_pos]
|
||||
|
||||
theorem getKey!_val [BEq α] [Hashable α] [Inhabited α] {m : Raw₀ α β} {a : α} :
|
||||
m.val.getKey! a = m.getKey! a := by
|
||||
simp [Raw.getKey!, m.2]
|
||||
|
||||
theorem erase_eq [BEq α] [Hashable α] {m : Raw α β} (h : m.WF) {a : α} :
|
||||
m.erase a = Raw₀.erase ⟨m, h.size_buckets_pos⟩ a := by
|
||||
simp [Raw.erase, h.size_buckets_pos]
|
||||
|
||||
@@ -83,7 +83,8 @@ private def queryNames : Array Name :=
|
||||
#[``contains_eq_containsKey, ``Raw.isEmpty_eq_isEmpty, ``Raw.size_eq_length,
|
||||
``get?_eq_getValueCast?, ``Const.get?_eq_getValue?, ``get_eq_getValueCast,
|
||||
``Const.get_eq_getValue, ``get!_eq_getValueCast!, ``getD_eq_getValueCastD,
|
||||
``Const.get!_eq_getValue!, ``Const.getD_eq_getValueD]
|
||||
``Const.get!_eq_getValue!, ``Const.getD_eq_getValueD, ``getKey?_eq_getKey?,
|
||||
``getKey_eq_getKey, ``getKeyD_eq_getKeyD, ``getKey!_eq_getKey!]
|
||||
|
||||
private def modifyNames : Array Name :=
|
||||
#[``toListModel_insert, ``toListModel_erase, ``toListModel_insertIfNew]
|
||||
@@ -93,7 +94,8 @@ private def congrNames : MacroM (Array (TSyntax `term)) := do
|
||||
← `(_root_.List.Perm.length_eq), ← `(getValueCast?_of_perm _),
|
||||
← `(getValue?_of_perm _), ← `(getValue_of_perm _), ← `(getValueCast_of_perm _),
|
||||
← `(getValueCast!_of_perm _), ← `(getValueCastD_of_perm _), ← `(getValue!_of_perm _),
|
||||
← `(getValueD_of_perm _) ]
|
||||
← `(getValueD_of_perm _), ← `(getKey?_of_perm _), ← `(getKey_of_perm _), ← `(getKeyD_of_perm _),
|
||||
← `(getKey!_of_perm _)]
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
scoped syntax "simp_to_model" ("using" term)? : tactic
|
||||
@@ -535,6 +537,147 @@ theorem getD_congr [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {a b : α} {fa
|
||||
|
||||
end Const
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_empty {a : α} {c} : (empty c : Raw₀ α β).getKey? a = none := by
|
||||
simp [getKey?]
|
||||
|
||||
theorem getKey?_of_isEmpty [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {a : α} :
|
||||
m.1.isEmpty = true → m.getKey? a = none := by
|
||||
simp_to_model; empty
|
||||
|
||||
theorem getKey?_insert [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {a k : α} {v : β k} :
|
||||
(m.insert k v).getKey? a = if k == a then some k else m.getKey? a := by
|
||||
simp_to_model using List.getKey?_insertEntry
|
||||
|
||||
theorem getKey?_insert_self [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k : α} {v : β k} :
|
||||
(m.insert k v).getKey? k = some k := by
|
||||
simp_to_model using List.getKey?_insertEntry_self
|
||||
|
||||
theorem contains_eq_isSome_getKey? [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {a : α} :
|
||||
m.contains a = (m.getKey? a).isSome := by
|
||||
simp_to_model using List.containsKey_eq_isSome_getKey?
|
||||
|
||||
theorem getKey?_eq_none [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {a : α} :
|
||||
m.contains a = false → m.getKey? a = none := by
|
||||
simp_to_model using List.getKey?_eq_none
|
||||
|
||||
theorem getKey?_erase [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k a : α} :
|
||||
(m.erase k).getKey? a = if k == a then none else m.getKey? a := by
|
||||
simp_to_model using List.getKey?_eraseKey
|
||||
|
||||
theorem getKey?_erase_self [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k : α} :
|
||||
(m.erase k).getKey? k = none := by
|
||||
simp_to_model using List.getKey?_eraseKey_self
|
||||
|
||||
theorem getKey_insert [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k a : α} {v : β k} {h₁} :
|
||||
(m.insert k v).getKey a h₁ =
|
||||
if h₂ : k == a then
|
||||
k
|
||||
else
|
||||
m.getKey a (contains_of_contains_insert _ h h₁ (Bool.eq_false_iff.2 h₂)) := by
|
||||
simp_to_model using List.getKey_insertEntry
|
||||
|
||||
theorem getKey_insert_self [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k : α} {v : β k} :
|
||||
(m.insert k v).getKey k (contains_insert_self _ h) = k := by
|
||||
simp_to_model using List.getKey_insertEntry_self
|
||||
|
||||
@[simp]
|
||||
theorem getKey_erase [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k a : α} {h'} :
|
||||
(m.erase k).getKey a h' = m.getKey a (contains_of_contains_erase _ h h') := by
|
||||
simp_to_model using List.getKey_eraseKey
|
||||
|
||||
theorem getKey?_eq_some_getKey [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {a : α} {h} :
|
||||
m.getKey? a = some (m.getKey a h) := by
|
||||
simp_to_model using List.getKey?_eq_some_getKey
|
||||
|
||||
theorem getKey!_empty {a : α} [Inhabited α] {c} :
|
||||
(empty c : Raw₀ α β).getKey! a = default := by
|
||||
simp [getKey!, empty]
|
||||
|
||||
theorem getKey!_of_isEmpty [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF) {a : α} :
|
||||
m.1.isEmpty = true → m.getKey! a = default := by
|
||||
simp_to_model; empty;
|
||||
|
||||
theorem getKey!_insert [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF) {k a : α}
|
||||
{v : β k} :
|
||||
(m.insert k v).getKey! a = if k == a then k else m.getKey! a := by
|
||||
simp_to_model using List.getKey!_insertEntry
|
||||
|
||||
theorem getKey!_insert_self [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF) {a : α}
|
||||
{b : β a} : (m.insert a b).getKey! a = a := by
|
||||
simp_to_model using List.getKey!_insertEntry_self
|
||||
|
||||
theorem getKey!_eq_default [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF) {a : α} :
|
||||
m.contains a = false → m.getKey! a = default := by
|
||||
simp_to_model using List.getKey!_eq_default
|
||||
|
||||
theorem getKey!_erase [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF) {k a : α} :
|
||||
(m.erase k).getKey! a = if k == a then default else m.getKey! a := by
|
||||
simp_to_model using List.getKey!_eraseKey
|
||||
|
||||
theorem getKey!_erase_self [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF) {k : α} :
|
||||
(m.erase k).getKey! k = default := by
|
||||
simp_to_model using List.getKey!_eraseKey_self
|
||||
|
||||
theorem getKey?_eq_some_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF) {a : α} :
|
||||
m.contains a = true → m.getKey? a = some (m.getKey! a) := by
|
||||
simp_to_model using List.getKey?_eq_some_getKey!
|
||||
|
||||
theorem getKey!_eq_get!_getKey? [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF) {a : α} :
|
||||
m.getKey! a = (m.getKey? a).get! := by
|
||||
simp_to_model using List.getKey!_eq_getKey?
|
||||
|
||||
theorem getKey_eq_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF) {a : α} {h} :
|
||||
m.getKey a h = m.getKey! a := by
|
||||
simp_to_model using List.getKey_eq_getKey!
|
||||
|
||||
theorem getKeyD_empty {a : α} {fallback : α} {c} :
|
||||
(empty c : Raw₀ α β).getKeyD a fallback = fallback := by
|
||||
simp [getKeyD, empty]
|
||||
|
||||
theorem getKeyD_of_isEmpty [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {a fallback : α} :
|
||||
m.1.isEmpty = true → m.getKeyD a fallback = fallback := by
|
||||
simp_to_model; empty
|
||||
|
||||
theorem getKeyD_insert [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k a fallback : α} {v : β k} :
|
||||
(m.insert k v).getKeyD a fallback =
|
||||
if k == a then k else m.getKeyD a fallback := by
|
||||
simp_to_model using List.getKeyD_insertEntry
|
||||
|
||||
theorem getKeyD_insert_self [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {a fallback : α}
|
||||
{b : β a} :
|
||||
(m.insert a b).getKeyD a fallback = a := by
|
||||
simp_to_model using List.getKeyD_insertEntry_self
|
||||
|
||||
theorem getKeyD_eq_fallback [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {a fallback : α} :
|
||||
m.contains a = false → m.getKeyD a fallback = fallback := by
|
||||
simp_to_model using List.getKeyD_eq_fallback
|
||||
|
||||
theorem getKeyD_erase [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k a fallback : α} :
|
||||
(m.erase k).getKeyD a fallback = if k == a then fallback else m.getKeyD a fallback := by
|
||||
simp_to_model using List.getKeyD_eraseKey
|
||||
|
||||
theorem getKeyD_erase_self [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k fallback : α} :
|
||||
(m.erase k).getKeyD k fallback = fallback := by
|
||||
simp_to_model using List.getKeyD_eraseKey_self
|
||||
|
||||
theorem getKey?_eq_some_getKeyD [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {a fallback : α} :
|
||||
m.contains a = true → m.getKey? a = some (m.getKeyD a fallback) := by
|
||||
simp_to_model using List.getKey?_eq_some_getKeyD
|
||||
|
||||
theorem getKeyD_eq_getD_getKey? [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {a fallback : α} :
|
||||
m.getKeyD a fallback = (m.getKey? a).getD fallback := by
|
||||
simp_to_model using List.getKeyD_eq_getKey?
|
||||
|
||||
theorem getKey_eq_getKeyD [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {a fallback : α} {h} :
|
||||
m.getKey a h = m.getKeyD a fallback := by
|
||||
simp_to_model using List.getKey_eq_getKeyD
|
||||
|
||||
theorem getKey!_eq_getKeyD_default [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF)
|
||||
{a : α} :
|
||||
m.getKey! a = m.getKeyD a default := by
|
||||
simp_to_model using List.getKey!_eq_getKeyD_default
|
||||
|
||||
theorem isEmpty_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k : α} {v : β k} :
|
||||
(m.insertIfNew k v).1.isEmpty = false := by
|
||||
simp_to_model using List.isEmpty_insertEntryIfNew
|
||||
@@ -620,6 +763,29 @@ theorem getD_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k a :
|
||||
|
||||
end Const
|
||||
|
||||
theorem getKey?_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k a : α} {v : β k} :
|
||||
(m.insertIfNew k v).getKey? a =
|
||||
if k == a ∧ m.contains k = false then some k else m.getKey? a := by
|
||||
simp_to_model using List.getKey?_insertEntryIfNew
|
||||
|
||||
theorem getKey_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k a : α} {v : β k} {h₁} :
|
||||
(m.insertIfNew k v).getKey a h₁ =
|
||||
if h₂ : k == a ∧ m.contains k = false then k
|
||||
else m.getKey a (contains_of_contains_insertIfNew' _ h h₁ h₂) := by
|
||||
simp_to_model using List.getKey_insertEntryIfNew
|
||||
|
||||
theorem getKey!_insertIfNew [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF) {k a : α}
|
||||
{v : β k} :
|
||||
(m.insertIfNew k v).getKey! a =
|
||||
if k == a ∧ m.contains k = false then k else m.getKey! a := by
|
||||
simp_to_model using List.getKey!_insertEntryIfNew
|
||||
|
||||
theorem getKeyD_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.1.WF) {k a fallback : α}
|
||||
{v : β k} :
|
||||
(m.insertIfNew k v).getKeyD a fallback =
|
||||
if k == a ∧ m.contains k = false then k else m.getKeyD a fallback := by
|
||||
simp_to_model using List.getKeyD_insertEntryIfNew
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_fst [LawfulBEq α] {k : α} {v : β k} :
|
||||
(m.getThenInsertIfNew? k v).1 = m.get? k := by
|
||||
|
||||
@@ -38,11 +38,11 @@ theorem toListModel_mkArray_nil {c} :
|
||||
@[simp]
|
||||
theorem computeSize_eq {buckets : Array (AssocList α β)} :
|
||||
computeSize buckets = (toListModel buckets).length := by
|
||||
rw [computeSize, toListModel, List.bind_eq_foldl, Array.foldl_eq_foldl_data]
|
||||
rw [computeSize, toListModel, List.bind_eq_foldl, Array.foldl_eq_foldl_toList]
|
||||
suffices ∀ (l : List (AssocList α β)) (l' : List ((a : α) × β a)),
|
||||
l.foldl (fun d b => d + b.toList.length) l'.length =
|
||||
(l.foldl (fun acc a => acc ++ a.toList) l').length
|
||||
by simpa using this buckets.data []
|
||||
by simpa using this buckets.toList []
|
||||
intro l l'
|
||||
induction l generalizing l'
|
||||
· simp
|
||||
@@ -129,7 +129,7 @@ theorem expand.go_eq [BEq α] [Hashable α] [PartialEquivBEq α] (source : Array
|
||||
(target : {d : Array (AssocList α β) // 0 < d.size}) : expand.go 0 source target =
|
||||
(toListModel source).foldl (fun acc p => reinsertAux hash acc p.1 p.2) target := by
|
||||
suffices ∀ i, expand.go i source target =
|
||||
((source.data.drop i).bind AssocList.toList).foldl
|
||||
((source.toList.drop i).bind AssocList.toList).foldl
|
||||
(fun acc p => reinsertAux hash acc p.1 p.2) target by
|
||||
simpa using this 0
|
||||
intro i
|
||||
@@ -138,12 +138,12 @@ theorem expand.go_eq [BEq α] [Hashable α] [PartialEquivBEq α] (source : Array
|
||||
simp only [newSource, newTarget, es] at *
|
||||
rw [expand.go_pos hi]
|
||||
refine ih.trans ?_
|
||||
simp only [Array.get_eq_getElem, AssocList.foldl_eq, Array.data_set]
|
||||
simp only [Array.get_eq_getElem, AssocList.foldl_eq, Array.toList_set]
|
||||
rw [List.drop_eq_getElem_cons hi, List.bind_cons, List.foldl_append,
|
||||
List.drop_set_of_lt _ _ (by omega), Array.getElem_eq_data_getElem]
|
||||
List.drop_set_of_lt _ _ (by omega), Array.getElem_eq_toList_getElem]
|
||||
· next i source target hi =>
|
||||
rw [expand.go_neg hi, List.drop_eq_nil_of_le, bind_nil, foldl_nil]
|
||||
rwa [Array.size_eq_length_data, Nat.not_lt] at hi
|
||||
rwa [Array.size_eq_length_toList, Nat.not_lt] at hi
|
||||
|
||||
theorem isHashSelf_expand [BEq α] [Hashable α] [LawfulHashable α] [EquivBEq α]
|
||||
{buckets : {d : Array (AssocList α β) // 0 < d.size}} : IsHashSelf (expand buckets).1 := by
|
||||
@@ -233,6 +233,47 @@ theorem getD_eq_getValueCastD [BEq α] [Hashable α] [LawfulBEq α] {m : Raw₀
|
||||
m.getD a fallback = getValueCastD a (toListModel m.1.buckets) fallback := by
|
||||
rw [getD_eq_getDₘ, getDₘ_eq_getValueCastD hm]
|
||||
|
||||
theorem getKey?ₘ_eq_getKey? [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] {m : Raw₀ α β}
|
||||
(hm : Raw.WFImp m.1) {a : α} :
|
||||
m.getKey?ₘ a = List.getKey? a (toListModel m.1.buckets) :=
|
||||
apply_bucket hm AssocList.getKey?_eq List.getKey?_of_perm List.getKey?_append_of_containsKey_eq_false
|
||||
|
||||
theorem getKey?_eq_getKey? [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] {m : Raw₀ α β}
|
||||
(hm : Raw.WFImp m.1) {a : α} :
|
||||
m.getKey? a = List.getKey? a (toListModel m.1.buckets) := by
|
||||
rw [getKey?_eq_getKey?ₘ, getKey?ₘ_eq_getKey? hm]
|
||||
|
||||
theorem getKeyₘ_eq_getKey [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] {m : Raw₀ α β}
|
||||
(hm : Raw.WFImp m.1) {a : α} {h : m.contains a} :
|
||||
m.getKeyₘ a h = List.getKey a (toListModel m.1.buckets) (contains_eq_containsKey hm ▸ h) :=
|
||||
apply_bucket_with_proof hm a AssocList.getKey List.getKey AssocList.getKey_eq
|
||||
List.getKey_of_perm List.getKey_append_of_containsKey_eq_false
|
||||
|
||||
theorem getKey_eq_getKey [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] {m : Raw₀ α β}
|
||||
(hm : Raw.WFImp m.1) {a : α} {h : m.contains a} :
|
||||
m.getKey a h = List.getKey a (toListModel m.1.buckets) (contains_eq_containsKey hm ▸ h) := by
|
||||
rw [getKey_eq_getKeyₘ, getKeyₘ_eq_getKey hm]
|
||||
|
||||
theorem getKey!ₘ_eq_getKey! [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] [Inhabited α]
|
||||
{m : Raw₀ α β} (hm : Raw.WFImp m.1) {a : α} :
|
||||
m.getKey!ₘ a = List.getKey! a (toListModel m.1.buckets) := by
|
||||
rw [getKey!ₘ, getKey?ₘ_eq_getKey? hm, List.getKey!_eq_getKey?]
|
||||
|
||||
theorem getKey!_eq_getKey! [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] [Inhabited α]
|
||||
{m : Raw₀ α β} (hm : Raw.WFImp m.1) {a : α} :
|
||||
m.getKey! a = List.getKey! a (toListModel m.1.buckets) := by
|
||||
rw [getKey!_eq_getKey!ₘ, getKey!ₘ_eq_getKey! hm]
|
||||
|
||||
theorem getKeyDₘ_eq_getKeyD [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] {m : Raw₀ α β}
|
||||
(hm : Raw.WFImp m.1) {a fallback : α} :
|
||||
m.getKeyDₘ a fallback = List.getKeyD a (toListModel m.1.buckets) fallback := by
|
||||
rw [getKeyDₘ, getKey?ₘ_eq_getKey? hm, List.getKeyD_eq_getKey?]
|
||||
|
||||
theorem getKeyD_eq_getKeyD [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] {m : Raw₀ α β}
|
||||
(hm : Raw.WFImp m.1) {a fallback : α} :
|
||||
m.getKeyD a fallback = List.getKeyD a (toListModel m.1.buckets) fallback := by
|
||||
rw [getKeyD_eq_getKeyDₘ, getKeyDₘ_eq_getKeyD hm]
|
||||
|
||||
section
|
||||
|
||||
variable {β : Type v}
|
||||
|
||||
@@ -599,6 +599,189 @@ theorem getD_congr [EquivBEq α] [LawfulHashable α] {a b : α} {fallback : β}
|
||||
|
||||
end Const
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_empty {a : α} {c} : (empty c : DHashMap α β).getKey? a = none :=
|
||||
Raw₀.getKey?_empty
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_emptyc {a : α} : (∅ : DHashMap α β).getKey? a = none :=
|
||||
Raw₀.getKey?_empty
|
||||
|
||||
theorem getKey?_of_isEmpty [EquivBEq α] [LawfulHashable α] {a : α} :
|
||||
m.isEmpty = true → m.getKey? a = none :=
|
||||
Raw₀.getKey?_of_isEmpty ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey?_insert [EquivBEq α] [LawfulHashable α] {a k : α} {v : β k} :
|
||||
(m.insert k v).getKey? a = if k == a then some k else m.getKey? a :=
|
||||
Raw₀.getKey?_insert ⟨m.1, _⟩ m.2
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} :
|
||||
(m.insert k v).getKey? k = some k :=
|
||||
Raw₀.getKey?_insert_self ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem contains_eq_isSome_getKey? [EquivBEq α] [LawfulHashable α] {a : α} :
|
||||
m.contains a = (m.getKey? a).isSome :=
|
||||
Raw₀.contains_eq_isSome_getKey? ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey?_eq_none_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α} :
|
||||
m.contains a = false → m.getKey? a = none :=
|
||||
Raw₀.getKey?_eq_none ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey?_eq_none [EquivBEq α] [LawfulHashable α] {a : α} : ¬a ∈ m → m.getKey? a = none := by
|
||||
simpa [mem_iff_contains] using getKey?_eq_none_of_contains_eq_false
|
||||
|
||||
theorem getKey?_erase [EquivBEq α] [LawfulHashable α] {k a : α} :
|
||||
(m.erase k).getKey? a = if k == a then none else m.getKey? a :=
|
||||
Raw₀.getKey?_erase ⟨m.1, _⟩ m.2
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_erase_self [EquivBEq α] [LawfulHashable α] {k : α} : (m.erase k).getKey? k = none :=
|
||||
Raw₀.getKey?_erase_self ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} {h₁} :
|
||||
(m.insert k v).getKey a h₁ =
|
||||
if h₂ : k == a then
|
||||
k
|
||||
else
|
||||
m.getKey a (mem_of_mem_insert h₁ (Bool.eq_false_iff.2 h₂)) :=
|
||||
Raw₀.getKey_insert ⟨m.1, _⟩ m.2
|
||||
|
||||
@[simp]
|
||||
theorem getKey_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} :
|
||||
(m.insert k v).getKey k mem_insert_self = k :=
|
||||
Raw₀.getKey_insert_self ⟨m.1, _⟩ m.2
|
||||
|
||||
@[simp]
|
||||
theorem getKey_erase [EquivBEq α] [LawfulHashable α] {k a : α} {h'} :
|
||||
(m.erase k).getKey a h' = m.getKey a (mem_of_mem_erase h') :=
|
||||
Raw₀.getKey_erase ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey?_eq_some_getKey [EquivBEq α] [LawfulHashable α] {a : α}
|
||||
{h} :
|
||||
m.getKey? a = some (m.getKey a h) :=
|
||||
Raw₀.getKey?_eq_some_getKey ⟨m.1, _⟩ m.2
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_empty [Inhabited α] {a : α} {c} :
|
||||
(empty c : DHashMap α β).getKey! a = default :=
|
||||
Raw₀.getKey!_empty
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_emptyc [Inhabited α] {a : α} :
|
||||
(∅ : DHashMap α β).getKey! a = default :=
|
||||
getKey!_empty
|
||||
|
||||
theorem getKey!_of_isEmpty [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
m.isEmpty = true → m.getKey! a = default :=
|
||||
Raw₀.getKey!_of_isEmpty ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey!_insert [EquivBEq α] [LawfulHashable α] [Inhabited α] {k a : α} {v : β k} :
|
||||
(m.insert k v).getKey! a =
|
||||
if k == a then k else m.getKey! a :=
|
||||
Raw₀.getKey!_insert ⟨m.1, _⟩ m.2
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_insert_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} {b : β a} :
|
||||
(m.insert a b).getKey! a = a :=
|
||||
Raw₀.getKey!_insert_self ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey!_eq_default_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
|
||||
{a : α} :
|
||||
m.contains a = false → m.getKey! a = default :=
|
||||
Raw₀.getKey!_eq_default ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey!_eq_default [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
¬a ∈ m → m.getKey! a = default := by
|
||||
simpa [mem_iff_contains] using getKey!_eq_default_of_contains_eq_false
|
||||
|
||||
theorem getKey!_erase [EquivBEq α] [LawfulHashable α] [Inhabited α] {k a : α} :
|
||||
(m.erase k).getKey! a = if k == a then default else m.getKey! a :=
|
||||
Raw₀.getKey!_erase ⟨m.1, _⟩ m.2
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_erase_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} :
|
||||
(m.erase k).getKey! k = default :=
|
||||
Raw₀.getKey!_erase_self ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey?_eq_some_getKey!_of_contains [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
m.contains a = true → m.getKey? a = some (m.getKey! a) :=
|
||||
Raw₀.getKey?_eq_some_getKey! ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey?_eq_some_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
a ∈ m → m.getKey? a = some (m.getKey! a) := by
|
||||
simpa [mem_iff_contains] using getKey?_eq_some_getKey!_of_contains
|
||||
|
||||
theorem getKey!_eq_get!_getKey? [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
m.getKey! a = (m.getKey? a).get! :=
|
||||
Raw₀.getKey!_eq_get!_getKey? ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey_eq_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} {h} :
|
||||
m.getKey a h = m.getKey! a :=
|
||||
Raw₀.getKey_eq_getKey! ⟨m.1, _⟩ m.2
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_empty {a fallback : α} {c} :
|
||||
(empty c : DHashMap α β).getKeyD a fallback = fallback :=
|
||||
Raw₀.getKeyD_empty
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_emptyc {a fallback : α} :
|
||||
(∅ : DHashMap α β).getKeyD a fallback = fallback :=
|
||||
getKeyD_empty
|
||||
|
||||
theorem getKeyD_of_isEmpty [EquivBEq α] [LawfulHashable α] {a fallback : α} :
|
||||
m.isEmpty = true → m.getKeyD a fallback = fallback :=
|
||||
Raw₀.getKeyD_of_isEmpty ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKeyD_insert [EquivBEq α] [LawfulHashable α] {k a fallback : α} {v : β k} :
|
||||
(m.insert k v).getKeyD a fallback =
|
||||
if k == a then k else m.getKeyD a fallback :=
|
||||
Raw₀.getKeyD_insert ⟨m.1, _⟩ m.2
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_insert_self [EquivBEq α] [LawfulHashable α] {k fallback : α} {v : β k} :
|
||||
(m.insert k v).getKeyD k fallback = k :=
|
||||
Raw₀.getKeyD_insert_self ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKeyD_eq_fallback_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α}
|
||||
{fallback : α} :
|
||||
m.contains a = false → m.getKeyD a fallback = fallback :=
|
||||
Raw₀.getKeyD_eq_fallback ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKeyD_eq_fallback [EquivBEq α] [LawfulHashable α] {a fallback : α} :
|
||||
¬a ∈ m → m.getKeyD a fallback = fallback := by
|
||||
simpa [mem_iff_contains] using getKeyD_eq_fallback_of_contains_eq_false
|
||||
|
||||
theorem getKeyD_erase [EquivBEq α] [LawfulHashable α] {k a fallback : α} :
|
||||
(m.erase k).getKeyD a fallback = if k == a then fallback else m.getKeyD a fallback :=
|
||||
Raw₀.getKeyD_erase ⟨m.1, _⟩ m.2
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_erase_self [EquivBEq α] [LawfulHashable α] {k fallback : α} :
|
||||
(m.erase k).getKeyD k fallback = fallback :=
|
||||
Raw₀.getKeyD_erase_self ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey?_eq_some_getKeyD_of_contains [EquivBEq α] [LawfulHashable α] {a fallback : α} :
|
||||
m.contains a = true → m.getKey? a = some (m.getKeyD a fallback) :=
|
||||
Raw₀.getKey?_eq_some_getKeyD ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey?_eq_some_getKeyD [EquivBEq α] [LawfulHashable α] {a fallback : α} :
|
||||
a ∈ m → m.getKey? a = some (m.getKeyD a fallback) := by
|
||||
simpa [mem_iff_contains] using getKey?_eq_some_getKeyD_of_contains
|
||||
|
||||
theorem getKeyD_eq_getD_getKey? [EquivBEq α] [LawfulHashable α] {a fallback : α} :
|
||||
m.getKeyD a fallback = (m.getKey? a).getD fallback :=
|
||||
Raw₀.getKeyD_eq_getD_getKey? ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey_eq_getKeyD [EquivBEq α] [LawfulHashable α] {a fallback : α} {h} :
|
||||
m.getKey a h = m.getKeyD a fallback :=
|
||||
Raw₀.getKey_eq_getKeyD ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey!_eq_getKeyD_default [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
m.getKey! a = m.getKeyD a default :=
|
||||
Raw₀.getKey!_eq_getKeyD_default ⟨m.1, _⟩ m.2
|
||||
|
||||
@[simp]
|
||||
theorem isEmpty_insertIfNew [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} :
|
||||
(m.insertIfNew k v).isEmpty = false :=
|
||||
@@ -706,6 +889,29 @@ theorem getD_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {fallback
|
||||
|
||||
end Const
|
||||
|
||||
theorem getKey?_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} :
|
||||
getKey? (m.insertIfNew k v) a = if k == a ∧ ¬k ∈ m then some k else getKey? m a := by
|
||||
simp [mem_iff_contains, contains_insertIfNew]
|
||||
exact Raw₀.getKey?_insertIfNew ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β k} {h₁} :
|
||||
getKey (m.insertIfNew k v) a h₁ =
|
||||
if h₂ : k == a ∧ ¬k ∈ m then k else getKey m a (mem_of_mem_insertIfNew' h₁ h₂) := by
|
||||
simp [mem_iff_contains, contains_insertIfNew]
|
||||
exact Raw₀.getKey_insertIfNew ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKey!_insertIfNew [EquivBEq α] [LawfulHashable α] [Inhabited α] {k a : α} {v : β k} :
|
||||
getKey! (m.insertIfNew k v) a = if k == a ∧ ¬k ∈ m then k else getKey! m a := by
|
||||
simp [mem_iff_contains, contains_insertIfNew]
|
||||
exact Raw₀.getKey!_insertIfNew ⟨m.1, _⟩ m.2
|
||||
|
||||
theorem getKeyD_insertIfNew [EquivBEq α] [LawfulHashable α] {k a fallback : α} {v : β k} :
|
||||
getKeyD (m.insertIfNew k v) a fallback =
|
||||
if k == a ∧ ¬k ∈ m then k else getKeyD m a fallback := by
|
||||
simp [mem_iff_contains, contains_insertIfNew]
|
||||
exact Raw₀.getKeyD_insertIfNew ⟨m.1, _⟩ m.2
|
||||
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_fst [LawfulBEq α] {k : α} {v : β k} :
|
||||
(m.getThenInsertIfNew? k v).1 = m.get? k :=
|
||||
|
||||
@@ -237,6 +237,41 @@ returned map has a new value inserted.
|
||||
|
||||
end
|
||||
|
||||
/--
|
||||
Checks if a mapping for the given key exists and returns the key if it does, otherwise `none`.
|
||||
The result in the `some` case is guaranteed to be pointer equal to the key in the map.
|
||||
-/
|
||||
@[inline] def getKey? [BEq α] [Hashable α] (m : Raw α β) (a : α) : Option α :=
|
||||
if h : 0 < m.buckets.size then
|
||||
Raw₀.getKey? ⟨m, h⟩ a
|
||||
else none -- will never happen for well-formed inputs
|
||||
|
||||
/--
|
||||
Retrieves the key from the mapping that matches `a`. Ensures that such a mapping exists by
|
||||
requiring a proof of `a ∈ m`. The result is guaranteed to be pointer equal to the key in the map.
|
||||
-/
|
||||
@[inline] def getKey [BEq α] [Hashable α] (m : Raw α β) (a : α) (h : a ∈ m) : α :=
|
||||
Raw₀.getKey ⟨m, by change dite .. = true at h; split at h <;> simp_all⟩ a
|
||||
(by change dite .. = true at h; split at h <;> simp_all)
|
||||
|
||||
/--
|
||||
Checks if a mapping for the given key exists and returns the key if it does, otherwise `fallback`.
|
||||
If a mapping exists the result is guaranteed to be pointer equal to the key in the map.
|
||||
-/
|
||||
@[inline] def getKeyD [BEq α] [Hashable α] (m : Raw α β) (a : α) (fallback : α) : α :=
|
||||
if h : 0 < m.buckets.size then
|
||||
Raw₀.getKeyD ⟨m, h⟩ a fallback
|
||||
else fallback -- will never happen for well-formed inputs
|
||||
|
||||
/--
|
||||
Checks if a mapping for the given key exists and returns the key if it does, otherwise panics.
|
||||
If no panic occurs the result is guaranteed to be pointer equal to the key in the map.
|
||||
-/
|
||||
@[inline] def getKey! [BEq α] [Hashable α] [Inhabited α] (m : Raw α β) (a : α) : α :=
|
||||
if h : 0 < m.buckets.size then
|
||||
Raw₀.getKey! ⟨m, h⟩ a
|
||||
else default -- will never happen for well-formed inputs
|
||||
|
||||
/--
|
||||
Returns `true` if the hash map contains no mappings.
|
||||
|
||||
@@ -376,6 +411,14 @@ This is mainly useful to implement `HashSet.ofList`, so if you are considering u
|
||||
Raw α (fun _ => Unit) :=
|
||||
Const.insertManyUnit ∅ l
|
||||
|
||||
/-- Creates a hash map from an array of keys, associating the value `()` with each key.
|
||||
|
||||
This is mainly useful to implement `HashSet.ofArray`, so if you are considering using this,
|
||||
`HashSet` or `HashSet.Raw` might be a better fit for you. -/
|
||||
@[inline] def Const.unitOfArray [BEq α] [Hashable α] (l : Array α) :
|
||||
Raw α (fun _ => Unit) :=
|
||||
Const.insertManyUnit ∅ l
|
||||
|
||||
/--
|
||||
Returns the number of buckets in the internal representation of the hash map. This function may be
|
||||
useful for things like monitoring system health, but it should be considered an internal
|
||||
|
||||
@@ -54,7 +54,11 @@ private def baseNames : Array Name :=
|
||||
``contains_eq, ``contains_val,
|
||||
``get_eq, ``get_val,
|
||||
``getD_eq, ``getD_val,
|
||||
``get!_eq, ``get!_val]
|
||||
``get!_eq, ``get!_val,
|
||||
``getKey?_eq, ``getKey?_val,
|
||||
``getKey_eq, ``getKey_val,
|
||||
``getKey!_eq, ``getKey!_val,
|
||||
``getKeyD_eq, ``getKeyD_val]
|
||||
|
||||
/-- Internal implementation detail of the hash map -/
|
||||
scoped syntax "simp_to_raw" ("using" term)? : tactic
|
||||
@@ -661,6 +665,194 @@ theorem getD_congr [EquivBEq α] [LawfulHashable α] (h : m.WF) {a b : α} {fall
|
||||
|
||||
end Const
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_empty {a : α} {c} :
|
||||
(empty c : Raw α β).getKey? a = none := by
|
||||
simp_to_raw using Raw₀.getKey?_empty
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_emptyc {a : α} : (∅ : Raw α β).getKey? a = none :=
|
||||
getKey?_empty
|
||||
|
||||
theorem getKey?_of_isEmpty [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
m.isEmpty = true → m.getKey? a = none := by
|
||||
simp_to_raw using Raw₀.getKey?_of_isEmpty ⟨m, _⟩
|
||||
|
||||
theorem getKey?_insert [EquivBEq α] [LawfulHashable α] (h : m.WF) {a k : α} {v : β k} :
|
||||
(m.insert k v).getKey? a = if k == a then some k else m.getKey? a := by
|
||||
simp_to_raw using Raw₀.getKey?_insert
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_insert_self [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α} {v : β k} :
|
||||
(m.insert k v).getKey? k = some k := by
|
||||
simp_to_raw using Raw₀.getKey?_insert_self
|
||||
|
||||
theorem contains_eq_isSome_getKey? [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
m.contains a = (m.getKey? a).isSome := by
|
||||
simp_to_raw using Raw₀.contains_eq_isSome_getKey?
|
||||
|
||||
theorem getKey?_eq_none_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
m.contains a = false → m.getKey? a = none := by
|
||||
simp_to_raw using Raw₀.getKey?_eq_none
|
||||
|
||||
theorem getKey?_eq_none [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
¬a ∈ m → m.getKey? a = none := by
|
||||
simpa [mem_iff_contains] using getKey?_eq_none_of_contains_eq_false h
|
||||
|
||||
theorem getKey?_erase [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} :
|
||||
(m.erase k).getKey? a = if k == a then none else m.getKey? a := by
|
||||
simp_to_raw using Raw₀.getKey?_erase
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_erase_self [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α} :
|
||||
(m.erase k).getKey? k = none := by
|
||||
simp_to_raw using Raw₀.getKey?_erase_self
|
||||
|
||||
theorem getKey_insert [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} {v : β k} {h₁} :
|
||||
(m.insert k v).getKey a h₁ =
|
||||
if h₂ : k == a then
|
||||
k
|
||||
else
|
||||
m.getKey a (mem_of_mem_insert h h₁ (Bool.eq_false_iff.2 h₂)) := by
|
||||
simp_to_raw using Raw₀.getKey_insert ⟨m, _⟩
|
||||
|
||||
@[simp]
|
||||
theorem getKey_insert_self [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α} {v : β k} :
|
||||
(m.insert k v).getKey k (mem_insert_self h) = k := by
|
||||
simp_to_raw using Raw₀.getKey_insert_self ⟨m, _⟩
|
||||
|
||||
@[simp]
|
||||
theorem getKey_erase [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} {h'} :
|
||||
(m.erase a).getKey k h' = m.getKey k (mem_of_mem_erase h h') := by
|
||||
simp_to_raw using Raw₀.getKey_erase ⟨m, _⟩
|
||||
|
||||
theorem getKey?_eq_some_getKey [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} {h} :
|
||||
m.getKey? a = some (m.getKey a h) := by
|
||||
simp_to_raw using Raw₀.getKey?_eq_some_getKey
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_empty [Inhabited α] {a : α} {c} :
|
||||
(empty c : Raw α β).getKey! a = default := by
|
||||
simp_to_raw using Raw₀.getKey!_empty
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_emptyc [Inhabited α] {a : α} :
|
||||
(∅ : Raw α β).getKey! a = default :=
|
||||
getKey!_empty
|
||||
|
||||
theorem getKey!_of_isEmpty [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α} :
|
||||
m.isEmpty = true → m.getKey! a = default := by
|
||||
simp_to_raw using Raw₀.getKey!_of_isEmpty ⟨m, _⟩
|
||||
|
||||
theorem getKey!_insert [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {k a : α} {v : β k} :
|
||||
(m.insert k v).getKey! a = if k == a then k else m.getKey! a := by
|
||||
simp_to_raw using Raw₀.getKey!_insert
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_insert_self [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {k : α}
|
||||
{v : β k} :
|
||||
(m.insert k v).getKey! k = k := by
|
||||
simp_to_raw using Raw₀.getKey!_insert_self
|
||||
|
||||
theorem getKey!_eq_default_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
|
||||
(h : m.WF) {a : α} :
|
||||
m.contains a = false → m.getKey! a = default := by
|
||||
simp_to_raw using Raw₀.getKey!_eq_default
|
||||
|
||||
theorem getKey!_eq_default [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α}:
|
||||
¬a ∈ m → m.getKey! a = default := by
|
||||
simpa [mem_iff_contains] using getKey!_eq_default_of_contains_eq_false h
|
||||
|
||||
theorem getKey!_erase [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {k a : α} :
|
||||
(m.erase k).getKey! a = if k == a then default else m.getKey! a := by
|
||||
simp_to_raw using Raw₀.getKey!_erase
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_erase_self [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {k : α} :
|
||||
(m.erase k).getKey! k = default := by
|
||||
simp_to_raw using Raw₀.getKey!_erase_self
|
||||
|
||||
theorem getKey?_eq_some_getKey!_of_contains [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF)
|
||||
{a : α} :
|
||||
m.contains a = true → m.getKey? a = some (m.getKey! a) := by
|
||||
simp_to_raw using Raw₀.getKey?_eq_some_getKey!
|
||||
|
||||
theorem getKey?_eq_some_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α} :
|
||||
a ∈ m → m.getKey? a = some (m.getKey! a) := by
|
||||
simpa [mem_iff_contains] using getKey?_eq_some_getKey!_of_contains h
|
||||
|
||||
theorem getKey!_eq_get!_getKey? [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α} :
|
||||
m.getKey! a = (m.getKey? a).get! := by
|
||||
simp_to_raw using Raw₀.getKey!_eq_get!_getKey?
|
||||
|
||||
theorem getKey_eq_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α} {h} :
|
||||
m.getKey a h = m.getKey! a := by
|
||||
simp_to_raw using Raw₀.getKey_eq_getKey!
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_empty {a fallback : α} {c} :
|
||||
(empty c : Raw α β).getKeyD a fallback = fallback := by
|
||||
simp_to_raw using Raw₀.getKeyD_empty
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_emptyc {a fallback : α} :
|
||||
(∅ : Raw α β).getKeyD a fallback = fallback :=
|
||||
getKeyD_empty
|
||||
|
||||
theorem getKeyD_of_isEmpty [EquivBEq α] [LawfulHashable α] (h : m.WF) {a fallback : α} :
|
||||
m.isEmpty = true → m.getKeyD a fallback = fallback := by
|
||||
simp_to_raw using Raw₀.getKeyD_of_isEmpty ⟨m, _⟩
|
||||
|
||||
theorem getKeyD_insert [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a fallback : α} {v : β k} :
|
||||
(m.insert k v).getKeyD a fallback =
|
||||
if k == a then k else m.getKeyD a fallback := by
|
||||
simp_to_raw using Raw₀.getKeyD_insert
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_insert_self [EquivBEq α] [LawfulHashable α] (h : m.WF) {a fallback : α} {b : β a} :
|
||||
(m.insert a b).getKeyD a fallback = a := by
|
||||
simp_to_raw using Raw₀.getKeyD_insert_self
|
||||
|
||||
theorem getKeyD_eq_fallback_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF)
|
||||
{a fallback : α} :
|
||||
m.contains a = false → m.getKeyD a fallback = fallback := by
|
||||
simp_to_raw using Raw₀.getKeyD_eq_fallback
|
||||
|
||||
theorem getKeyD_eq_fallback [EquivBEq α] [LawfulHashable α] (h : m.WF) {a fallback : α} :
|
||||
¬a ∈ m → m.getKeyD a fallback = fallback := by
|
||||
simpa [mem_iff_contains] using getKeyD_eq_fallback_of_contains_eq_false h
|
||||
|
||||
theorem getKeyD_erase [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a fallback : α} :
|
||||
(m.erase k).getKeyD a fallback = if k == a then fallback else m.getKeyD a fallback := by
|
||||
simp_to_raw using Raw₀.getKeyD_erase
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_erase_self [EquivBEq α] [LawfulHashable α] (h : m.WF) {k fallback : α} :
|
||||
(m.erase k).getKeyD k fallback = fallback := by
|
||||
simp_to_raw using Raw₀.getKeyD_erase_self
|
||||
|
||||
theorem getKey?_eq_some_getKeyD_of_contains [EquivBEq α] [LawfulHashable α] (h : m.WF)
|
||||
{a fallback : α} :
|
||||
m.contains a = true → m.getKey? a = some (m.getKeyD a fallback) := by
|
||||
simp_to_raw using Raw₀.getKey?_eq_some_getKeyD
|
||||
|
||||
theorem getKey?_eq_some_getKeyD [EquivBEq α] [LawfulHashable α] (h : m.WF) {a fallback : α} :
|
||||
a ∈ m → m.getKey? a = some (m.getKeyD a fallback) := by
|
||||
simpa [mem_iff_contains] using getKey?_eq_some_getKeyD_of_contains h
|
||||
|
||||
theorem getKeyD_eq_getD_getKey? [EquivBEq α] [LawfulHashable α] (h : m.WF) {a fallback : α} :
|
||||
m.getKeyD a fallback = (m.getKey? a).getD fallback := by
|
||||
simp_to_raw using Raw₀.getKeyD_eq_getD_getKey?
|
||||
|
||||
theorem getKey_eq_getKeyD [EquivBEq α] [LawfulHashable α] (h : m.WF) {a fallback : α} {h} :
|
||||
m.getKey a h = m.getKeyD a fallback := by
|
||||
simp_to_raw using Raw₀.getKey_eq_getKeyD
|
||||
|
||||
theorem getKey!_eq_getKeyD_default [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF)
|
||||
{a : α} :
|
||||
m.getKey! a = m.getKeyD a default := by
|
||||
simp_to_raw using Raw₀.getKey!_eq_getKeyD_default
|
||||
|
||||
@[simp]
|
||||
theorem isEmpty_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α} {v : β k} :
|
||||
(m.insertIfNew k v).isEmpty = false := by
|
||||
@@ -774,6 +966,30 @@ theorem getD_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α}
|
||||
|
||||
end Const
|
||||
|
||||
theorem getKey?_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} {v : β k} :
|
||||
getKey? (m.insertIfNew k v) a = if k == a ∧ ¬k ∈ m then some k else getKey? m a := by
|
||||
simp only [mem_iff_contains, Bool.not_eq_true]
|
||||
simp_to_raw using Raw₀.getKey?_insertIfNew
|
||||
|
||||
theorem getKey_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} {v : β k} {h₁} :
|
||||
getKey (m.insertIfNew k v) a h₁ =
|
||||
if h₂ : k == a ∧ ¬k ∈ m then k else getKey m a (mem_of_mem_insertIfNew' h h₁ h₂) := by
|
||||
simp only [mem_iff_contains, Bool.not_eq_true]
|
||||
simp_to_raw using Raw₀.getKey_insertIfNew ⟨m, _⟩
|
||||
|
||||
theorem getKey!_insertIfNew [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {k a : α}
|
||||
{v : β k} :
|
||||
getKey! (m.insertIfNew k v) a = if k == a ∧ ¬k ∈ m then k else getKey! m a := by
|
||||
simp only [mem_iff_contains, Bool.not_eq_true]
|
||||
simp_to_raw using Raw₀.getKey!_insertIfNew
|
||||
|
||||
theorem getKeyD_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a fallback : α}
|
||||
{v : β k} :
|
||||
getKeyD (m.insertIfNew k v) a fallback =
|
||||
if k == a ∧ ¬k ∈ m then k else getKeyD m a fallback := by
|
||||
simp only [mem_iff_contains, Bool.not_eq_true]
|
||||
simp_to_raw using Raw₀.getKeyD_insertIfNew
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_fst [LawfulBEq α] (h : m.WF) {k : α} {v : β k} :
|
||||
(m.getThenInsertIfNew? k v).1 = m.get? k := by
|
||||
|
||||
@@ -160,6 +160,18 @@ instance [BEq α] [Hashable α] : GetElem? (HashMap α β) α β (fun m a => a
|
||||
getElem? m a := m.get? a
|
||||
getElem! m a := m.get! a
|
||||
|
||||
@[inline, inherit_doc DHashMap.getKey?] def getKey? (m : HashMap α β) (a : α) : Option α :=
|
||||
DHashMap.getKey? m.inner a
|
||||
|
||||
@[inline, inherit_doc DHashMap.getKey] def getKey (m : HashMap α β) (a : α) (h : a ∈ m) : α :=
|
||||
DHashMap.getKey m.inner a h
|
||||
|
||||
@[inline, inherit_doc DHashMap.getKeyD] def getKeyD (m : HashMap α β) (a : α) (fallback : α) : α :=
|
||||
DHashMap.getKeyD m.inner a fallback
|
||||
|
||||
@[inline, inherit_doc DHashMap.getKey!] def getKey! [Inhabited α] (m : HashMap α β) (a : α) : α :=
|
||||
DHashMap.getKey! m.inner a
|
||||
|
||||
@[inline, inherit_doc DHashMap.erase] def erase (m : HashMap α β) (a : α) :
|
||||
HashMap α β :=
|
||||
⟨m.inner.erase a⟩
|
||||
@@ -238,6 +250,10 @@ instance [BEq α] [Hashable α] {m : Type w → Type w} : ForIn m (HashMap α β
|
||||
HashMap α Unit :=
|
||||
⟨DHashMap.Const.unitOfList l⟩
|
||||
|
||||
@[inline, inherit_doc DHashMap.Const.unitOfArray] def unitOfArray [BEq α] [Hashable α] (l : Array α) :
|
||||
HashMap α Unit :=
|
||||
⟨DHashMap.Const.unitOfArray l⟩
|
||||
|
||||
@[inline, inherit_doc DHashMap.Internal.numBuckets] def Internal.numBuckets
|
||||
(m : HashMap α β) : Nat :=
|
||||
DHashMap.Internal.numBuckets m.inner
|
||||
|
||||
@@ -391,6 +391,178 @@ theorem getD_congr [EquivBEq α] [LawfulHashable α] {a b : α} {fallback : β}
|
||||
m.getD a fallback = m.getD b fallback :=
|
||||
DHashMap.Const.getD_congr hab
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_empty {a : α} {c} : (empty c : HashMap α β).getKey? a = none :=
|
||||
DHashMap.getKey?_empty
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_emptyc {a : α} : (∅ : HashMap α β).getKey? a = none :=
|
||||
DHashMap.getKey?_emptyc
|
||||
|
||||
theorem getKey?_of_isEmpty [EquivBEq α] [LawfulHashable α] {a : α} :
|
||||
m.isEmpty = true → m.getKey? a = none :=
|
||||
DHashMap.getKey?_of_isEmpty
|
||||
|
||||
theorem getKey?_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} :
|
||||
(m.insert k v).getKey? a = if k == a then some k else m.getKey? a :=
|
||||
DHashMap.getKey?_insert
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β} :
|
||||
(m.insert k v).getKey? k = some k :=
|
||||
DHashMap.getKey?_insert_self
|
||||
|
||||
theorem contains_eq_isSome_getKey? [EquivBEq α] [LawfulHashable α] {a : α} :
|
||||
m.contains a = (m.getKey? a).isSome :=
|
||||
DHashMap.contains_eq_isSome_getKey?
|
||||
|
||||
theorem getKey?_eq_none_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α} :
|
||||
m.contains a = false → m.getKey? a = none :=
|
||||
DHashMap.getKey?_eq_none_of_contains_eq_false
|
||||
|
||||
theorem getKey?_eq_none [EquivBEq α] [LawfulHashable α] {a : α} : ¬a ∈ m → m.getKey? a = none :=
|
||||
DHashMap.getKey?_eq_none
|
||||
|
||||
theorem getKey?_erase [EquivBEq α] [LawfulHashable α] {k a : α} :
|
||||
(m.erase k).getKey? a = if k == a then none else m.getKey? a :=
|
||||
DHashMap.getKey?_erase
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_erase_self [EquivBEq α] [LawfulHashable α] {k : α} : (m.erase k).getKey? k = none :=
|
||||
DHashMap.getKey?_erase_self
|
||||
|
||||
theorem getKey_insert [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} {h₁} :
|
||||
(m.insert k v)[a]'h₁ =
|
||||
if h₂ : k == a then v else m[a]'(mem_of_mem_insert h₁ (Bool.eq_false_iff.2 h₂)) :=
|
||||
DHashMap.Const.get_insert (h₁ := h₁)
|
||||
|
||||
@[simp]
|
||||
theorem getKey_insert_self [EquivBEq α] [LawfulHashable α] {k : α} {v : β} :
|
||||
(m.insert k v).getKey k mem_insert_self = k :=
|
||||
DHashMap.getKey_insert_self
|
||||
|
||||
@[simp]
|
||||
theorem getKey_erase [EquivBEq α] [LawfulHashable α] {k a : α} {h'} :
|
||||
(m.erase k).getKey a h' = m.getKey a (mem_of_mem_erase h') :=
|
||||
DHashMap.getKey_erase (h' := h')
|
||||
|
||||
theorem getKey?_eq_some_getKey [EquivBEq α] [LawfulHashable α] {a : α} {h' : a ∈ m} :
|
||||
m.getKey? a = some (m.getKey a h') :=
|
||||
@DHashMap.getKey?_eq_some_getKey _ _ _ _ _ _ _ _ h'
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_empty [Inhabited α] {a : α} {c} : (empty c : HashMap α β).getKey! a = default :=
|
||||
DHashMap.getKey!_empty
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_emptyc [Inhabited α] {a : α} : (∅ : HashMap α β).getKey! a = default :=
|
||||
DHashMap.getKey!_emptyc
|
||||
|
||||
theorem getKey!_of_isEmpty [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
m.isEmpty = true → m.getKey! a = default :=
|
||||
DHashMap.getKey!_of_isEmpty
|
||||
|
||||
theorem getKey!_insert [EquivBEq α] [LawfulHashable α] [Inhabited α] {k a : α} {v : β} :
|
||||
(m.insert k v).getKey! a = if k == a then k else m.getKey! a :=
|
||||
DHashMap.getKey!_insert
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_insert_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} {v : β} :
|
||||
(m.insert k v).getKey! k = k :=
|
||||
DHashMap.getKey!_insert_self
|
||||
|
||||
theorem getKey!_eq_default_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
|
||||
{a : α} : m.contains a = false → m.getKey! a = default :=
|
||||
DHashMap.getKey!_eq_default_of_contains_eq_false
|
||||
|
||||
theorem getKey!_eq_default [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
¬a ∈ m → m.getKey! a = default :=
|
||||
DHashMap.getKey!_eq_default
|
||||
|
||||
theorem getKey!_erase [EquivBEq α] [LawfulHashable α] [Inhabited α] {k a : α} :
|
||||
(m.erase k).getKey! a = if k == a then default else m.getKey! a :=
|
||||
DHashMap.getKey!_erase
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_erase_self [EquivBEq α] [LawfulHashable α] [Inhabited α] {k : α} :
|
||||
(m.erase k).getKey! k = default :=
|
||||
DHashMap.getKey!_erase_self
|
||||
|
||||
theorem getKey?_eq_some_getKey!_of_contains [EquivBEq α] [LawfulHashable α] [Inhabited α]
|
||||
{a : α} : m.contains a = true → m.getKey? a = some (m.getKey! a) :=
|
||||
DHashMap.getKey?_eq_some_getKey!_of_contains
|
||||
|
||||
theorem getKey?_eq_some_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
a ∈ m → m.getKey? a = some (m.getKey! a) :=
|
||||
DHashMap.getKey?_eq_some_getKey!
|
||||
|
||||
theorem getKey!_eq_get!_getKey? [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
m.getKey! a = (m.getKey? a).get! :=
|
||||
DHashMap.getKey!_eq_get!_getKey?
|
||||
|
||||
theorem getKey_eq_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} {h'} :
|
||||
m.getKey a h' = m.getKey! a :=
|
||||
@DHashMap.getKey_eq_getKey! _ _ _ _ _ _ _ _ _ h'
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_empty {a : α} {fallback : α} {c} :
|
||||
(empty c : HashMap α β).getKeyD a fallback = fallback :=
|
||||
DHashMap.getKeyD_empty
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_emptyc {a : α} {fallback : α} : (∅ : HashMap α β).getKeyD a fallback = fallback :=
|
||||
DHashMap.getKeyD_empty
|
||||
|
||||
theorem getKeyD_of_isEmpty [EquivBEq α] [LawfulHashable α] {a : α} {fallback : α} :
|
||||
m.isEmpty = true → m.getKeyD a fallback = fallback :=
|
||||
DHashMap.getKeyD_of_isEmpty
|
||||
|
||||
theorem getKeyD_insert [EquivBEq α] [LawfulHashable α] {k a fallback : α} {v : β} :
|
||||
(m.insert k v).getKeyD a fallback = if k == a then k else m.getKeyD a fallback :=
|
||||
DHashMap.getKeyD_insert
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_insert_self [EquivBEq α] [LawfulHashable α] {k fallback : α} {v : β} :
|
||||
(m.insert k v).getKeyD k fallback = k :=
|
||||
DHashMap.getKeyD_insert_self
|
||||
|
||||
theorem getKeyD_eq_fallback_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α}
|
||||
{fallback : α} : m.contains a = false → m.getKeyD a fallback = fallback :=
|
||||
DHashMap.getKeyD_eq_fallback_of_contains_eq_false
|
||||
|
||||
theorem getKeyD_eq_fallback [EquivBEq α] [LawfulHashable α] {a : α} {fallback : α} :
|
||||
¬a ∈ m → m.getKeyD a fallback = fallback :=
|
||||
DHashMap.getKeyD_eq_fallback
|
||||
|
||||
theorem getKeyD_erase [EquivBEq α] [LawfulHashable α] {k a : α} {fallback : α} :
|
||||
(m.erase k).getKeyD a fallback = if k == a then fallback else m.getKeyD a fallback :=
|
||||
DHashMap.getKeyD_erase
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_erase_self [EquivBEq α] [LawfulHashable α] {k : α} {fallback : α} :
|
||||
(m.erase k).getKeyD k fallback = fallback :=
|
||||
DHashMap.getKeyD_erase_self
|
||||
|
||||
theorem getKey?_eq_some_getKeyD_of_contains [EquivBEq α] [LawfulHashable α] {a : α} {fallback : α} :
|
||||
m.contains a = true → m.getKey? a = some (m.getKeyD a fallback) :=
|
||||
DHashMap.getKey?_eq_some_getKeyD_of_contains
|
||||
|
||||
theorem getKey?_eq_some_getKeyD [EquivBEq α] [LawfulHashable α] {a : α} {fallback : α} :
|
||||
a ∈ m → m.getKey? a = some (m.getKeyD a fallback) :=
|
||||
DHashMap.getKey?_eq_some_getKeyD
|
||||
|
||||
theorem getKeyD_eq_getD_getKey? [EquivBEq α] [LawfulHashable α] {a : α} {fallback : α} :
|
||||
m.getKeyD a fallback = (m.getKey? a).getD fallback :=
|
||||
DHashMap.getKeyD_eq_getD_getKey?
|
||||
|
||||
theorem getKey_eq_getKeyD [EquivBEq α] [LawfulHashable α] {a : α} {fallback : α} {h'} :
|
||||
m.getKey a h' = m.getKeyD a fallback :=
|
||||
@DHashMap.getKey_eq_getKeyD _ _ _ _ _ _ _ _ _ h'
|
||||
|
||||
theorem getKey!_eq_getKeyD_default [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
m.getKey! a = m.getKeyD a default :=
|
||||
DHashMap.getKey!_eq_getKeyD_default
|
||||
|
||||
@[simp]
|
||||
theorem isEmpty_insertIfNew [EquivBEq α] [LawfulHashable α] {k : α} {v : β} :
|
||||
(m.insertIfNew k v).isEmpty = false :=
|
||||
@@ -464,6 +636,23 @@ theorem getD_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {fallback
|
||||
if k == a ∧ ¬k ∈ m then v else m.getD a fallback :=
|
||||
DHashMap.Const.getD_insertIfNew
|
||||
|
||||
theorem getKey?_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} :
|
||||
getKey? (m.insertIfNew k v) a = if k == a ∧ ¬k ∈ m then some k else getKey? m a :=
|
||||
DHashMap.getKey?_insertIfNew
|
||||
|
||||
theorem getKey_insertIfNew [EquivBEq α] [LawfulHashable α] {k a : α} {v : β} {h₁} :
|
||||
getKey (m.insertIfNew k v) a h₁ =
|
||||
if h₂ : k == a ∧ ¬k ∈ m then k else getKey m a (mem_of_mem_insertIfNew' h₁ h₂) :=
|
||||
DHashMap.getKey_insertIfNew
|
||||
|
||||
theorem getKey!_insertIfNew [EquivBEq α] [LawfulHashable α] [Inhabited α] {k a : α} {v : β} :
|
||||
getKey! (m.insertIfNew k v) a = if k == a ∧ ¬k ∈ m then k else getKey! m a :=
|
||||
DHashMap.getKey!_insertIfNew
|
||||
|
||||
theorem getKeyD_insertIfNew [EquivBEq α] [LawfulHashable α] {k a fallback : α} {v : β} :
|
||||
getKeyD (m.insertIfNew k v) a fallback = if k == a ∧ ¬k ∈ m then k else getKeyD m a fallback :=
|
||||
DHashMap.getKeyD_insertIfNew
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_fst {k : α} {v : β} : (getThenInsertIfNew? m k v).1 = get? m k :=
|
||||
DHashMap.Const.getThenInsertIfNew?_fst
|
||||
|
||||
@@ -138,6 +138,22 @@ instance [BEq α] [Hashable α] : GetElem? (Raw α β) α β (fun m a => a ∈ m
|
||||
getElem? m a := m.get? a
|
||||
getElem! m a := m.get! a
|
||||
|
||||
@[inline, inherit_doc DHashMap.Raw.getKey?] def getKey? [BEq α] [Hashable α] (m : Raw α β) (a : α) :
|
||||
Option α :=
|
||||
DHashMap.Raw.getKey? m.inner a
|
||||
|
||||
@[inline, inherit_doc DHashMap.Raw.getKey] def getKey [BEq α] [Hashable α] (m : Raw α β) (a : α)
|
||||
(h : a ∈ m) : α :=
|
||||
DHashMap.Raw.getKey m.inner a h
|
||||
|
||||
@[inline, inherit_doc DHashMap.Raw.getKeyD] def getKeyD [BEq α] [Hashable α] (m : Raw α β) (a : α)
|
||||
(fallback : α) : α :=
|
||||
DHashMap.Raw.getKeyD m.inner a fallback
|
||||
|
||||
@[inline, inherit_doc DHashMap.Raw.getKey!] def getKey! [BEq α] [Hashable α] [Inhabited α]
|
||||
(m : Raw α β) (a : α) : α :=
|
||||
DHashMap.Raw.getKey! m.inner a
|
||||
|
||||
@[inline, inherit_doc DHashMap.Raw.erase] def erase [BEq α] [Hashable α] (m : Raw α β)
|
||||
(a : α) : Raw α β :=
|
||||
⟨m.inner.erase a⟩
|
||||
|
||||
@@ -400,6 +400,181 @@ theorem getD_congr [EquivBEq α] [LawfulHashable α] (h : m.WF) {a b : α} {fall
|
||||
(hab : a == b) : m.getD a fallback = m.getD b fallback :=
|
||||
DHashMap.Raw.Const.getD_congr h.out hab
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_empty {a : α} {c} : (empty c : Raw α β).getKey? a = none :=
|
||||
DHashMap.Raw.getKey?_empty
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_emptyc {a : α} : (∅ : Raw α β).getKey? a = none :=
|
||||
DHashMap.Raw.getKey?_emptyc
|
||||
|
||||
theorem getKey?_of_isEmpty [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
m.isEmpty = true → m.getKey? a = none :=
|
||||
DHashMap.Raw.getKey?_of_isEmpty h.out
|
||||
|
||||
theorem getKey?_insert [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} {v : β} :
|
||||
(m.insert k v).getKey? a = if k == a then some k else m.getKey? a :=
|
||||
DHashMap.Raw.getKey?_insert h.out
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_insert_self [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α} {v : β} :
|
||||
(m.insert k v).getKey? k = some k :=
|
||||
DHashMap.Raw.getKey?_insert_self h.out
|
||||
|
||||
theorem contains_eq_isSome_getKey? [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
m.contains a = (m.getKey? a).isSome :=
|
||||
DHashMap.Raw.contains_eq_isSome_getKey? h.out
|
||||
|
||||
theorem getKey?_eq_none_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
m.contains a = false → m.getKey? a = none :=
|
||||
DHashMap.Raw.getKey?_eq_none_of_contains_eq_false h.out
|
||||
|
||||
theorem getKey?_eq_none [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
¬a ∈ m → m.getKey? a = none :=
|
||||
DHashMap.Raw.getKey?_eq_none h.out
|
||||
|
||||
theorem getKey?_erase [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} :
|
||||
(m.erase k).getKey? a = if k == a then none else m.getKey? a :=
|
||||
DHashMap.Raw.getKey?_erase h.out
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_erase_self [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α} :
|
||||
(m.erase k).getKey? k = none :=
|
||||
DHashMap.Raw.getKey?_erase_self h.out
|
||||
|
||||
theorem getKey_insert [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} {v : β} {h₁} :
|
||||
(m.insert k v).getKey a h₁ =
|
||||
if h₂ : k == a then k else m.getKey a (mem_of_mem_insert h h₁ (Bool.eq_false_iff.2 h₂)) :=
|
||||
DHashMap.Raw.getKey_insert (h₁ := h₁) h.out
|
||||
|
||||
@[simp]
|
||||
theorem getKey_insert_self [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α} {v : β} :
|
||||
(m.insert k v).getKey k (mem_insert_self h) = k :=
|
||||
DHashMap.Raw.getKey_insert_self h.out
|
||||
|
||||
@[simp]
|
||||
theorem getKey_erase [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} {h'} :
|
||||
(m.erase k).getKey a h' = m.getKey a (mem_of_mem_erase h h') :=
|
||||
DHashMap.Raw.getKey_erase (h' := h') h.out
|
||||
|
||||
theorem getKey?_eq_some_getKey [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} {h' : a ∈ m} :
|
||||
m.getKey? a = some (m.getKey a h') :=
|
||||
@DHashMap.Raw.getKey?_eq_some_getKey _ _ _ _ _ _ _ h.out _ h'
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_empty [Inhabited α] {a : α} {c} : (empty c : Raw α β).getKey! a = default :=
|
||||
DHashMap.Raw.getKey!_empty
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_emptyc [Inhabited α] {a : α} : (∅ : Raw α β).getKey! a = default :=
|
||||
DHashMap.Raw.getKey!_emptyc
|
||||
|
||||
theorem getKey!_of_isEmpty [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α} :
|
||||
m.isEmpty = true → m.getKey! a = default :=
|
||||
DHashMap.Raw.getKey!_of_isEmpty h.out
|
||||
|
||||
theorem getKey!_insert [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {k a : α} {v : β} :
|
||||
(m.insert k v).getKey! a = if k == a then k else m.getKey! a :=
|
||||
DHashMap.Raw.getKey!_insert h.out
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_insert_self [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {k : α}
|
||||
{v : β} : (m.insert k v).getKey! k = k :=
|
||||
DHashMap.Raw.getKey!_insert_self h.out
|
||||
|
||||
theorem getKey!_eq_default_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
|
||||
(h : m.WF) {a : α} : m.contains a = false → m.getKey! a = default :=
|
||||
DHashMap.Raw.getKey!_eq_default_of_contains_eq_false h.out
|
||||
|
||||
theorem getKey!_eq_default [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α} :
|
||||
¬a ∈ m → m.getKey! a = default :=
|
||||
DHashMap.Raw.getKey!_eq_default h.out
|
||||
|
||||
theorem getKey!_erase [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {k a : α} :
|
||||
(m.erase k).getKey! a = if k == a then default else m.getKey! a :=
|
||||
DHashMap.Raw.getKey!_erase h.out
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_erase_self [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {k : α} :
|
||||
(m.erase k).getKey! k = default :=
|
||||
DHashMap.Raw.getKey!_erase_self h.out
|
||||
|
||||
theorem getKey?_eq_some_getKey!_of_contains [EquivBEq α] [LawfulHashable α] [Inhabited α]
|
||||
(h : m.WF) {a : α} : m.contains a = true → m.getKey? a = some (m.getKey! a) :=
|
||||
DHashMap.Raw.getKey?_eq_some_getKey!_of_contains h.out
|
||||
|
||||
theorem getKey?_eq_some_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α} :
|
||||
a ∈ m → m.getKey? a = some (m.getKey! a) :=
|
||||
DHashMap.Raw.getKey?_eq_some_getKey! h.out
|
||||
|
||||
theorem getKey!_eq_get!_getKey? [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α} :
|
||||
m.getKey! a = (m.getKey? a).get! :=
|
||||
DHashMap.Raw.getKey!_eq_get!_getKey? h.out
|
||||
|
||||
theorem getKey_eq_getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α} {h'} :
|
||||
m.getKey a h' = m.getKey! a :=
|
||||
DHashMap.Raw.getKey_eq_getKey! h.out
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_empty {a fallback : α} {c} :
|
||||
(empty c : Raw α β).getKeyD a fallback = fallback :=
|
||||
DHashMap.Raw.getKeyD_empty
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_emptyc {a fallback : α} : (∅ : Raw α β).getKeyD a fallback = fallback :=
|
||||
DHashMap.Raw.getKeyD_empty
|
||||
|
||||
theorem getKeyD_of_isEmpty [EquivBEq α] [LawfulHashable α] (h : m.WF) {a fallback : α} :
|
||||
m.isEmpty = true → m.getKeyD a fallback = fallback :=
|
||||
DHashMap.Raw.getKeyD_of_isEmpty h.out
|
||||
|
||||
theorem getKeyD_insert [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a fallback : α} {v : β} :
|
||||
(m.insert k v).getKeyD a fallback = if k == a then k else m.getKeyD a fallback :=
|
||||
DHashMap.Raw.getKeyD_insert h.out
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_insert_self [EquivBEq α] [LawfulHashable α] (h : m.WF) {k fallback : α} {v : β} :
|
||||
(m.insert k v).getKeyD k fallback = k :=
|
||||
DHashMap.Raw.getKeyD_insert_self h.out
|
||||
|
||||
theorem getKeyD_eq_fallback_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF)
|
||||
{a fallback : α} : m.contains a = false → m.getKeyD a fallback = fallback :=
|
||||
DHashMap.Raw.getKeyD_eq_fallback_of_contains_eq_false h.out
|
||||
|
||||
theorem getKeyD_eq_fallback [EquivBEq α] [LawfulHashable α] (h : m.WF) {a fallback : α} :
|
||||
¬a ∈ m → m.getKeyD a fallback = fallback :=
|
||||
DHashMap.Raw.getKeyD_eq_fallback h.out
|
||||
|
||||
theorem getKeyD_erase [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a fallback : α} :
|
||||
(m.erase k).getKeyD a fallback = if k == a then fallback else m.getKeyD a fallback :=
|
||||
DHashMap.Raw.getKeyD_erase h.out
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_erase_self [EquivBEq α] [LawfulHashable α] (h : m.WF) {k fallback : α} :
|
||||
(m.erase k).getKeyD k fallback = fallback :=
|
||||
DHashMap.Raw.getKeyD_erase_self h.out
|
||||
|
||||
theorem getKey?_eq_some_getKeyD_of_contains [EquivBEq α] [LawfulHashable α] (h : m.WF)
|
||||
{a fallback : α} : m.contains a = true → m.getKey? a = some (m.getKeyD a fallback) :=
|
||||
DHashMap.Raw.getKey?_eq_some_getKeyD_of_contains h.out
|
||||
|
||||
theorem getKey?_eq_some_getKeyD [EquivBEq α] [LawfulHashable α] (h : m.WF) {a fallback : α} :
|
||||
a ∈ m → m.getKey? a = some (m.getKeyD a fallback) :=
|
||||
DHashMap.Raw.getKey?_eq_some_getKeyD h.out
|
||||
|
||||
theorem getKeyD_eq_getD_getKey? [EquivBEq α] [LawfulHashable α] (h : m.WF) {a fallback : α} :
|
||||
m.getKeyD a fallback = (m.getKey? a).getD fallback :=
|
||||
DHashMap.Raw.getKeyD_eq_getD_getKey? h.out
|
||||
|
||||
theorem getKey_eq_getKeyD [EquivBEq α] [LawfulHashable α] (h : m.WF) {a fallback : α} {h'} :
|
||||
m.getKey a h' = m.getKeyD a fallback :=
|
||||
@DHashMap.Raw.getKey_eq_getKeyD _ _ _ _ _ _ _ h.out _ _ h'
|
||||
|
||||
theorem getKey!_eq_getKeyD_default [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF)
|
||||
{a : α} :
|
||||
m.getKey! a = m.getKeyD a default :=
|
||||
DHashMap.Raw.getKey!_eq_getKeyD_default h.out
|
||||
|
||||
@[simp]
|
||||
theorem isEmpty_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α} {v : β} :
|
||||
(m.insertIfNew k v).isEmpty = false :=
|
||||
@@ -473,6 +648,24 @@ theorem getD_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α}
|
||||
if k == a ∧ ¬k ∈ m then v else m.getD a fallback :=
|
||||
DHashMap.Raw.Const.getD_insertIfNew h.out
|
||||
|
||||
theorem getKey?_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} {v : β} :
|
||||
(m.insertIfNew k v).getKey? a = if k == a ∧ ¬k ∈ m then some k else m.getKey? a :=
|
||||
DHashMap.Raw.getKey?_insertIfNew h.out
|
||||
|
||||
theorem getKey_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} {v : β} {h₁} :
|
||||
(m.insertIfNew k v).getKey a h₁ =
|
||||
if h₂ : k == a ∧ ¬k ∈ m then k else m.getKey a (mem_of_mem_insertIfNew' h h₁ h₂) :=
|
||||
DHashMap.Raw.getKey_insertIfNew h.out
|
||||
|
||||
theorem getKey!_insertIfNew [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {k a : α} {v : β} :
|
||||
(m.insertIfNew k v).getKey! a = if k == a ∧ ¬k ∈ m then k else m.getKey! a :=
|
||||
DHashMap.Raw.getKey!_insertIfNew h.out
|
||||
|
||||
theorem getKeyD_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a fallback : α} {v : β} :
|
||||
(m.insertIfNew k v).getKeyD a fallback = if k == a ∧ ¬k ∈ m then k else m.getKeyD a fallback :=
|
||||
DHashMap.Raw.getKeyD_insertIfNew h.out
|
||||
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_fst (h : m.WF) {k : α} {v : β} :
|
||||
(getThenInsertIfNew? m k v).1 = get? m k :=
|
||||
|
||||
@@ -112,6 +112,34 @@ instance [BEq α] [Hashable α] {m : HashSet α} {a : α} : Decidable (a ∈ m)
|
||||
@[inline] def size (m : HashSet α) : Nat :=
|
||||
m.inner.size
|
||||
|
||||
/--
|
||||
Checks if given key is contained and returns the key if it is, otherwise `none`.
|
||||
The result in the `some` case is guaranteed to be pointer equal to the key in the set.
|
||||
-/
|
||||
@[inline] def get? (m : HashSet α) (a : α) : Option α :=
|
||||
m.inner.getKey? a
|
||||
|
||||
/--
|
||||
Retrieves the key from the set that matches `a`. Ensures that such a key exists by requiring a proof
|
||||
of `a ∈ m`. The result is guaranteed to be pointer equal to the key in the set.
|
||||
-/
|
||||
@[inline] def get [BEq α] [Hashable α] (m : HashSet α) (a : α) (h : a ∈ m) : α :=
|
||||
m.inner.getKey a h
|
||||
|
||||
/--
|
||||
Checks if given key is contained and returns the key if it is, otherwise `fallback`.
|
||||
If they key is contained the result is guaranteed to be pointer equal to the key in the set.
|
||||
-/
|
||||
@[inline] def getD [BEq α] [Hashable α] (m : HashSet α) (a : α) (fallback : α) : α :=
|
||||
m.inner.getKeyD a fallback
|
||||
|
||||
/--
|
||||
Checks if given key is contained and returns the key if it is, otherwise panics.
|
||||
If no panic occurs the result is guaranteed to be pointer equal to the key in the set.
|
||||
-/
|
||||
@[inline] def get! [BEq α] [Hashable α] [Inhabited α] (m : HashSet α) (a : α) : α :=
|
||||
m.inner.getKey! a
|
||||
|
||||
/--
|
||||
Returns `true` if the hash set contains no elements.
|
||||
|
||||
@@ -184,6 +212,14 @@ in the collection will be present in the returned hash set.
|
||||
@[inline] def ofList [BEq α] [Hashable α] (l : List α) : HashSet α :=
|
||||
⟨HashMap.unitOfList l⟩
|
||||
|
||||
/--
|
||||
Creates a hash set from an array of elements. Note that unlike repeatedly calling `insert`, if the
|
||||
collection contains multiple elements that are equal (with regard to `==`), then the last element
|
||||
in the collection will be present in the returned hash set.
|
||||
-/
|
||||
@[inline] def ofArray [BEq α] [Hashable α] (l : Array α) : HashSet α :=
|
||||
⟨HashMap.unitOfArray l⟩
|
||||
|
||||
/-- Computes the union of the given hash sets. -/
|
||||
@[inline] def union [BEq α] [Hashable α] (m₁ m₂ : HashSet α) : HashSet α :=
|
||||
m₂.fold (init := m₁) fun acc x => acc.insert x
|
||||
|
||||
@@ -106,6 +106,18 @@ theorem mem_of_mem_insert [EquivBEq α] [LawfulHashable α] {k a : α} :
|
||||
a ∈ m.insert k → (k == a) = false → a ∈ m :=
|
||||
HashMap.mem_of_mem_insertIfNew
|
||||
|
||||
/-- This is a restatement of `contains_insert` that is written to exactly match the proof
|
||||
obligation in the statement of `get_insert`. -/
|
||||
theorem contains_of_contains_insert' [EquivBEq α] [LawfulHashable α] {k a : α} :
|
||||
(m.insert k).contains a → ¬((k == a) ∧ m.contains k = false) → m.contains a :=
|
||||
HashMap.contains_of_contains_insertIfNew'
|
||||
|
||||
/-- This is a restatement of `mem_insert` that is written to exactly match the proof obligation
|
||||
in the statement of `get_insert`. -/
|
||||
theorem mem_of_mem_insert' [EquivBEq α] [LawfulHashable α] {k a : α} :
|
||||
a ∈ m.insert k → ¬((k == a) ∧ ¬k ∈ m) → a ∈ m :=
|
||||
DHashMap.mem_of_mem_insertIfNew'
|
||||
|
||||
@[simp]
|
||||
theorem contains_insert_self [EquivBEq α] [LawfulHashable α] {k : α} : (m.insert k).contains k :=
|
||||
HashMap.contains_insertIfNew_self
|
||||
@@ -177,6 +189,158 @@ theorem size_le_size_erase [EquivBEq α] [LawfulHashable α] {k : α} :
|
||||
m.size ≤ (m.erase k).size + 1 :=
|
||||
HashMap.size_le_size_erase
|
||||
|
||||
@[simp]
|
||||
theorem get?_empty {a : α} {c} : (empty c : HashSet α).get? a = none :=
|
||||
HashMap.getKey?_empty
|
||||
|
||||
@[simp]
|
||||
theorem get?_emptyc {a : α} : (∅ : HashSet α).get? a = none :=
|
||||
HashMap.getKey?_emptyc
|
||||
|
||||
theorem get?_of_isEmpty [EquivBEq α] [LawfulHashable α] {a : α} :
|
||||
m.isEmpty = true → m.get? a = none :=
|
||||
HashMap.getKey?_of_isEmpty
|
||||
|
||||
theorem get?_insert [EquivBEq α] [LawfulHashable α] {k a : α} :
|
||||
(m.insert k).get? a = if k == a ∧ ¬k ∈ m then some k else m.get? a :=
|
||||
HashMap.getKey?_insertIfNew
|
||||
|
||||
theorem contains_eq_isSome_get? [EquivBEq α] [LawfulHashable α] {a : α} :
|
||||
m.contains a = (m.get? a).isSome :=
|
||||
HashMap.contains_eq_isSome_getKey?
|
||||
|
||||
theorem get?_eq_none_of_contains_eq_false [EquivBEq α] [LawfulHashable α] {a : α} :
|
||||
m.contains a = false → m.get? a = none :=
|
||||
HashMap.getKey?_eq_none_of_contains_eq_false
|
||||
|
||||
theorem get?_eq_none [EquivBEq α] [LawfulHashable α] {a : α} : ¬a ∈ m → m.get? a = none :=
|
||||
HashMap.getKey?_eq_none
|
||||
|
||||
theorem get?_erase [EquivBEq α] [LawfulHashable α] {k a : α} :
|
||||
(m.erase k).get? a = if k == a then none else m.get? a :=
|
||||
HashMap.getKey?_erase
|
||||
|
||||
@[simp]
|
||||
theorem get?_erase_self [EquivBEq α] [LawfulHashable α] {k : α} : (m.erase k).get? k = none :=
|
||||
HashMap.getKey?_erase_self
|
||||
|
||||
theorem get_insert [EquivBEq α] [LawfulHashable α] {k a : α} {h₁} :
|
||||
(m.insert k).get a h₁ =
|
||||
if h₂ : k == a ∧ ¬k ∈ m then k else m.get a (mem_of_mem_insert' h₁ h₂) :=
|
||||
HashMap.getKey_insertIfNew (h₁ := h₁)
|
||||
|
||||
@[simp]
|
||||
theorem get_erase [EquivBEq α] [LawfulHashable α] {k a : α} {h'} :
|
||||
(m.erase k).get a h' = m.get a (mem_of_mem_erase h') :=
|
||||
HashMap.getKey_erase (h' := h')
|
||||
|
||||
theorem get?_eq_some_get [EquivBEq α] [LawfulHashable α] {a : α} {h' : a ∈ m} :
|
||||
m.get? a = some (m.get a h') :=
|
||||
@HashMap.getKey?_eq_some_getKey _ _ _ _ _ _ _ _ h'
|
||||
|
||||
@[simp]
|
||||
theorem get!_empty [Inhabited α] {a : α} {c} : (empty c : HashSet α).get! a = default :=
|
||||
HashMap.getKey!_empty
|
||||
|
||||
@[simp]
|
||||
theorem get!_emptyc [Inhabited α] {a : α} : (∅ : HashSet α).get! a = default :=
|
||||
HashMap.getKey!_emptyc
|
||||
|
||||
theorem get!_of_isEmpty [Inhabited α] [EquivBEq α] [LawfulHashable α] {a : α} :
|
||||
m.isEmpty = true → m.get! a = default :=
|
||||
HashMap.getKey!_of_isEmpty
|
||||
|
||||
theorem get!_insert [Inhabited α] [EquivBEq α] [LawfulHashable α] {k a : α} :
|
||||
(m.insert k).get! a = if k == a ∧ ¬k ∈ m then k else m.get! a :=
|
||||
HashMap.getKey!_insertIfNew
|
||||
|
||||
theorem get!_eq_default_of_contains_eq_false [Inhabited α] [EquivBEq α] [LawfulHashable α] {a : α} :
|
||||
m.contains a = false → m.get! a = default :=
|
||||
HashMap.getKey!_eq_default_of_contains_eq_false
|
||||
|
||||
theorem get!_eq_default [Inhabited α] [EquivBEq α] [LawfulHashable α] {a : α} :
|
||||
¬a ∈ m → m.get! a = default :=
|
||||
HashMap.getKey!_eq_default
|
||||
|
||||
theorem get!_erase [Inhabited α] [EquivBEq α] [LawfulHashable α] {k a : α} :
|
||||
(m.erase k).get! a = if k == a then default else m.get! a :=
|
||||
HashMap.getKey!_erase
|
||||
|
||||
@[simp]
|
||||
theorem get!_erase_self [Inhabited α] [EquivBEq α] [LawfulHashable α] {k : α} :
|
||||
(m.erase k).get! k = default :=
|
||||
HashMap.getKey!_erase_self
|
||||
|
||||
theorem get?_eq_some_get!_of_contains [EquivBEq α] [LawfulHashable α] [Inhabited α]
|
||||
{a : α} : m.contains a = true → m.get? a = some (m.get! a) :=
|
||||
HashMap.getKey?_eq_some_getKey!_of_contains
|
||||
|
||||
theorem get?_eq_some_get! [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
a ∈ m → m.get? a = some (m.get! a) :=
|
||||
HashMap.getKey?_eq_some_getKey!
|
||||
|
||||
theorem get!_eq_get!_get? [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
m.get! a = (m.get? a).get! :=
|
||||
HashMap.getKey!_eq_get!_getKey?
|
||||
|
||||
theorem get_eq_get! [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} {h'} :
|
||||
m.get a h' = m.get! a :=
|
||||
HashMap.getKey_eq_getKey!
|
||||
|
||||
@[simp]
|
||||
theorem getD_empty {a fallback : α} {c} : (empty c : HashSet α).getD a fallback = fallback :=
|
||||
HashMap.getKeyD_empty
|
||||
|
||||
@[simp]
|
||||
theorem getD_emptyc {a fallback : α} : (∅ : HashSet α).getD a fallback = fallback :=
|
||||
HashMap.getKeyD_emptyc
|
||||
|
||||
theorem getD_of_isEmpty [EquivBEq α] [LawfulHashable α] {a fallback : α} :
|
||||
m.isEmpty = true → m.getD a fallback = fallback :=
|
||||
HashMap.getKeyD_of_isEmpty
|
||||
|
||||
theorem getD_insert [EquivBEq α] [LawfulHashable α] {k a fallback : α} :
|
||||
(m.insert k).getD a fallback = if k == a ∧ ¬k ∈ m then k else m.getD a fallback :=
|
||||
HashMap.getKeyD_insertIfNew
|
||||
|
||||
theorem getD_eq_fallback_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
|
||||
{a fallback : α} :
|
||||
m.contains a = false → m.getD a fallback = fallback :=
|
||||
HashMap.getKeyD_eq_fallback_of_contains_eq_false
|
||||
|
||||
theorem getD_eq_fallback [EquivBEq α] [LawfulHashable α] {a fallback : α} :
|
||||
¬a ∈ m → m.getD a fallback = fallback :=
|
||||
HashMap.getKeyD_eq_fallback
|
||||
|
||||
theorem getD_erase [EquivBEq α] [LawfulHashable α] {k a fallback : α} :
|
||||
(m.erase k).getD a fallback = if k == a then fallback else m.getD a fallback :=
|
||||
HashMap.getKeyD_erase
|
||||
|
||||
@[simp]
|
||||
theorem getD_erase_self [EquivBEq α] [LawfulHashable α] {k fallback : α} :
|
||||
(m.erase k).getD k fallback = fallback :=
|
||||
HashMap.getKeyD_erase_self
|
||||
|
||||
theorem get?_eq_some_getD_of_contains [EquivBEq α] [LawfulHashable α] {a fallback : α} :
|
||||
m.contains a = true → m.get? a = some (m.getD a fallback) :=
|
||||
HashMap.getKey?_eq_some_getKeyD_of_contains
|
||||
|
||||
theorem get?_eq_some_getD [EquivBEq α] [LawfulHashable α] {a fallback : α} :
|
||||
a ∈ m → m.get? a = some (m.getD a fallback) :=
|
||||
HashMap.getKey?_eq_some_getKeyD
|
||||
|
||||
theorem getD_eq_getD_get? [EquivBEq α] [LawfulHashable α] {a fallback : α} :
|
||||
m.getD a fallback = (m.get? a).getD fallback :=
|
||||
HashMap.getKeyD_eq_getD_getKey?
|
||||
|
||||
theorem get_eq_getD [EquivBEq α] [LawfulHashable α] {a fallback : α} {h'} :
|
||||
m.get a h' = m.getD a fallback :=
|
||||
@HashMap.getKey_eq_getKeyD _ _ _ _ _ _ _ _ _ h'
|
||||
|
||||
theorem get!_eq_getD_default [EquivBEq α] [LawfulHashable α] [Inhabited α] {a : α} :
|
||||
m.get! a = m.getD a default :=
|
||||
HashMap.getKey!_eq_getKeyD_default
|
||||
|
||||
@[simp]
|
||||
theorem containsThenInsert_fst {k : α} : (m.containsThenInsert k).1 = m.contains k :=
|
||||
HashMap.containsThenInsertIfNew_fst
|
||||
|
||||
@@ -14,7 +14,7 @@ set with unbundled well-formedness invariant.
|
||||
|
||||
This version is safe to use in nested inductive types. The well-formedness predicate is
|
||||
available as `Std.Data.HashSet.Raw.WF` and we prove in this file that all operations preserve
|
||||
well-formedness. When in doubt, prefer `HashSet` over `DHashSet.Raw`.
|
||||
well-formedness. When in doubt, prefer `HashSet` over `HashSet.Raw`.
|
||||
|
||||
Lemmas about the operations on `Std.Data.HashSet.Raw` are available in the module
|
||||
`Std.Data.HashSet.RawLemmas`.
|
||||
@@ -113,6 +113,34 @@ instance [BEq α] [Hashable α] {m : Raw α} {a : α} : Decidable (a ∈ m) :=
|
||||
@[inline] def size (m : Raw α) : Nat :=
|
||||
m.inner.size
|
||||
|
||||
/--
|
||||
Checks if given key is contained and returns the key if it is, otherwise `none`.
|
||||
The result in the `some` case is guaranteed to be pointer equal to the key in the map.
|
||||
-/
|
||||
@[inline] def get? [BEq α] [Hashable α] (m : Raw α) (a : α) : Option α :=
|
||||
m.inner.getKey? a
|
||||
|
||||
/--
|
||||
Retrieves the key from the set that matches `a`. Ensures that such a key exists by requiring a proof
|
||||
of `a ∈ m`. The result is guaranteed to be pointer equal to the key in the set.
|
||||
-/
|
||||
@[inline] def get [BEq α] [Hashable α] (m : Raw α) (a : α) (h : a ∈ m) : α :=
|
||||
m.inner.getKey a h
|
||||
|
||||
/--
|
||||
Checks if given key is contained and returns the key if it is, otherwise `fallback`.
|
||||
If they key is contained the result is guaranteed to be pointer equal to the key in the set.
|
||||
-/
|
||||
@[inline] def getD [BEq α] [Hashable α] (m : Raw α) (a : α) (fallback : α) : α :=
|
||||
m.inner.getKeyD a fallback
|
||||
|
||||
/--
|
||||
Checks if given key is contained and returns the key if it is, otherwise panics.
|
||||
If no panic occurs the result is guaranteed to be pointer equal to the key in the set.
|
||||
-/
|
||||
@[inline] def get! [BEq α] [Hashable α] [Inhabited α] (m : Raw α) (a : α) : α :=
|
||||
m.inner.getKey! a
|
||||
|
||||
/--
|
||||
Returns `true` if the hash set contains no elements.
|
||||
|
||||
|
||||
@@ -122,6 +122,18 @@ theorem mem_of_mem_insert [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α
|
||||
a ∈ m.insert k → (k == a) = false → a ∈ m :=
|
||||
HashMap.Raw.mem_of_mem_insertIfNew h.out
|
||||
|
||||
/-- This is a restatement of `contains_insert` that is written to exactly match the proof
|
||||
obligation in the statement of `get_insert`. -/
|
||||
theorem contains_of_contains_insert' [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} :
|
||||
(m.insert k).contains a → ¬((k == a) ∧ m.contains k = false) → m.contains a :=
|
||||
HashMap.Raw.contains_of_contains_insertIfNew' h.out
|
||||
|
||||
/-- This is a restatement of `mem_insert` that is written to exactly match the proof obligation
|
||||
in the statement of `get_insertIfNew`. -/
|
||||
theorem mem_of_mem_insert' [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} :
|
||||
a ∈ m.insert k → ¬((k == a) ∧ ¬k ∈ m) → a ∈ m :=
|
||||
HashMap.Raw.mem_of_mem_insertIfNew' h.out
|
||||
|
||||
@[simp]
|
||||
theorem contains_insert_self [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α} :
|
||||
(m.insert k).contains k :=
|
||||
@@ -186,6 +198,162 @@ theorem size_le_size_erase [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α}
|
||||
m.size ≤ (m.erase k).size + 1 :=
|
||||
HashMap.Raw.size_le_size_erase h.out
|
||||
|
||||
@[simp]
|
||||
theorem get?_empty {a : α} {c} : (empty c : Raw α).get? a = none :=
|
||||
HashMap.Raw.getKey?_empty
|
||||
|
||||
@[simp]
|
||||
theorem get?_emptyc {a : α} : (∅ : Raw α).get? a = none :=
|
||||
HashMap.Raw.getKey?_emptyc
|
||||
|
||||
theorem get?_of_isEmpty [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
m.isEmpty = true → m.get? a = none :=
|
||||
HashMap.Raw.getKey?_of_isEmpty h.out
|
||||
|
||||
theorem get?_insert [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} :
|
||||
(m.insert k).get? a = if k == a ∧ ¬k ∈ m then some k else m.get? a :=
|
||||
HashMap.Raw.getKey?_insertIfNew h.out
|
||||
|
||||
theorem contains_eq_isSome_get? [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
m.contains a = (m.get? a).isSome :=
|
||||
HashMap.Raw.contains_eq_isSome_getKey? h.out
|
||||
|
||||
theorem get?_eq_none_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
m.contains a = false → m.get? a = none :=
|
||||
HashMap.Raw.getKey?_eq_none_of_contains_eq_false h.out
|
||||
|
||||
theorem get?_eq_none [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
¬a ∈ m → m.get? a = none :=
|
||||
HashMap.Raw.getKey?_eq_none h.out
|
||||
|
||||
theorem get?_erase [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} :
|
||||
(m.erase k).get? a = if k == a then none else m.get? a :=
|
||||
HashMap.Raw.getKey?_erase h.out
|
||||
|
||||
theorem get_insert [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} {h₁} :
|
||||
(m.insert k).get a h₁ =
|
||||
if h₂ : k == a ∧ ¬k ∈ m then k else m.get a (mem_of_mem_insert' h h₁ h₂) :=
|
||||
HashMap.Raw.getKey_insertIfNew (h₁ := h₁) h.out
|
||||
|
||||
@[simp]
|
||||
theorem get_erase [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} {h'} :
|
||||
(m.erase k).get a h' = m.get a (mem_of_mem_erase h h') :=
|
||||
HashMap.Raw.getKey_erase (h' := h') h.out
|
||||
|
||||
theorem get?_eq_some_get [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} {h' : a ∈ m} :
|
||||
m.get? a = some (m.get a h') :=
|
||||
@HashMap.Raw.getKey?_eq_some_getKey _ _ _ _ _ _ _ h.out _ h'
|
||||
|
||||
@[simp]
|
||||
theorem get?_erase_self [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α} :
|
||||
(m.erase k).get? k = none :=
|
||||
HashMap.Raw.getKey?_erase_self h.out
|
||||
|
||||
@[simp]
|
||||
theorem get!_empty [Inhabited α] {a : α} {c} : (empty c : Raw α).get! a = default :=
|
||||
HashMap.Raw.getKey!_empty
|
||||
|
||||
@[simp]
|
||||
theorem get!_emptyc [Inhabited α] {a : α} : (∅ : Raw α).get! a = default :=
|
||||
HashMap.Raw.getKey!_emptyc
|
||||
|
||||
theorem get!_of_isEmpty [Inhabited α] [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
m.isEmpty = true → m.get! a = default :=
|
||||
HashMap.Raw.getKey!_of_isEmpty h.out
|
||||
|
||||
theorem get!_insert [Inhabited α] [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} :
|
||||
(m.insert k).get! a = if k == a ∧ ¬k ∈ m then k else m.get! a :=
|
||||
HashMap.Raw.getKey!_insertIfNew h.out
|
||||
|
||||
theorem get!_eq_default_of_contains_eq_false [Inhabited α] [EquivBEq α] [LawfulHashable α]
|
||||
(h : m.WF) {a : α} :
|
||||
m.contains a = false → m.get! a = default :=
|
||||
HashMap.Raw.getKey!_eq_default_of_contains_eq_false h.out
|
||||
|
||||
theorem get!_eq_default [Inhabited α] [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} :
|
||||
¬a ∈ m → m.get! a = default :=
|
||||
HashMap.Raw.getKey!_eq_default h.out
|
||||
|
||||
theorem get!_erase [Inhabited α] [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a : α} :
|
||||
(m.erase k).get! a = if k == a then default else m.get! a :=
|
||||
HashMap.Raw.getKey!_erase h.out
|
||||
|
||||
@[simp]
|
||||
theorem get!_erase_self [Inhabited α] [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α} :
|
||||
(m.erase k).get! k = default :=
|
||||
HashMap.Raw.getKey!_erase_self h.out
|
||||
|
||||
theorem get?_eq_some_get!_of_contains [EquivBEq α] [LawfulHashable α] [Inhabited α]
|
||||
(h : m.WF) {a : α} : m.contains a = true → m.get? a = some (m.get! a) :=
|
||||
HashMap.Raw.getKey?_eq_some_getKey!_of_contains h.out
|
||||
|
||||
theorem get?_eq_some_get! [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α} :
|
||||
a ∈ m → m.get? a = some (m.get! a) :=
|
||||
HashMap.Raw.getKey?_eq_some_getKey! h.out
|
||||
|
||||
theorem get!_eq_get!_get? [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α} :
|
||||
m.get! a = (m.get? a).get! :=
|
||||
HashMap.Raw.getKey!_eq_get!_getKey? h.out
|
||||
|
||||
theorem get_eq_get! [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α} {h'} :
|
||||
m.get a h' = m.get! a :=
|
||||
HashMap.Raw.getKey_eq_getKey! h.out
|
||||
|
||||
@[simp]
|
||||
theorem getD_empty {a fallback : α} {c} : (empty c : Raw α).getD a fallback = fallback :=
|
||||
HashMap.Raw.getKeyD_empty
|
||||
|
||||
@[simp]
|
||||
theorem getD_emptyc {a fallback : α} : (∅ : Raw α).getD a fallback = fallback :=
|
||||
HashMap.Raw.getKeyD_emptyc
|
||||
|
||||
theorem getD_of_isEmpty [EquivBEq α] [LawfulHashable α] (h : m.WF) {a fallback : α} :
|
||||
m.isEmpty = true → m.getD a fallback = fallback :=
|
||||
HashMap.Raw.getKeyD_of_isEmpty h.out
|
||||
|
||||
theorem getD_insert [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a fallback : α} :
|
||||
(m.insert k).getD a fallback = if k == a ∧ ¬k ∈ m then k else m.getD a fallback :=
|
||||
HashMap.Raw.getKeyD_insertIfNew h.out
|
||||
|
||||
theorem getD_eq_fallback_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF)
|
||||
{a fallback : α} :
|
||||
m.contains a = false → m.getD a fallback = fallback :=
|
||||
HashMap.Raw.getKeyD_eq_fallback_of_contains_eq_false h.out
|
||||
|
||||
theorem getD_eq_fallback [EquivBEq α] [LawfulHashable α] (h : m.WF) {a fallback : α} :
|
||||
¬a ∈ m → m.getD a fallback = fallback :=
|
||||
HashMap.Raw.getKeyD_eq_fallback h.out
|
||||
|
||||
theorem getD_erase [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a fallback : α} :
|
||||
(m.erase k).getD a fallback = if k == a then fallback else m.getD a fallback :=
|
||||
HashMap.Raw.getKeyD_erase h.out
|
||||
|
||||
@[simp]
|
||||
theorem getD_erase_self [EquivBEq α] [LawfulHashable α] (h : m.WF) {k fallback : α} :
|
||||
(m.erase k).getD k fallback = fallback :=
|
||||
HashMap.Raw.getKeyD_erase_self h.out
|
||||
|
||||
theorem get?_eq_some_getD_of_contains [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α}
|
||||
{fallback : α} : m.contains a = true → m.get? a = some (m.getD a fallback) :=
|
||||
HashMap.Raw.getKey?_eq_some_getKeyD_of_contains h.out
|
||||
|
||||
theorem get?_eq_some_getD [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} {fallback : α} :
|
||||
a ∈ m → m.get? a = some (m.getD a fallback) :=
|
||||
HashMap.Raw.getKey?_eq_some_getKeyD h.out
|
||||
|
||||
theorem getD_eq_getD_get? [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} {fallback : α} :
|
||||
m.getD a fallback = (m.get? a).getD fallback :=
|
||||
HashMap.Raw.getKeyD_eq_getD_getKey? h.out
|
||||
|
||||
theorem get_eq_getD [EquivBEq α] [LawfulHashable α] (h : m.WF) {a : α} {fallback : α} {h'} :
|
||||
m.get a h' = m.getD a fallback :=
|
||||
@HashMap.Raw.getKey_eq_getKeyD _ _ _ _ _ _ _ h.out _ _ h'
|
||||
|
||||
theorem get!_eq_getD_default [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF)
|
||||
{a : α} :
|
||||
m.get! a = m.getD a default :=
|
||||
HashMap.Raw.getKey!_eq_getKeyD_default h.out
|
||||
|
||||
@[simp]
|
||||
theorem containsThenInsert_fst (h : m.WF) {k : α} : (m.containsThenInsert k).1 = m.contains k :=
|
||||
HashMap.Raw.containsThenInsertIfNew_fst h.out
|
||||
|
||||
@@ -277,7 +277,7 @@ theorem denote_congr (assign1 assign2 : α → Bool) (aig : AIG α) (idx : Nat)
|
||||
simp only [denote_idx_atom heq]
|
||||
apply h
|
||||
rw [mem_def, ← heq, Array.mem_def]
|
||||
apply Array.getElem_mem_data
|
||||
apply Array.getElem_mem_toList
|
||||
· intro lhs rhs linv rinv heq
|
||||
simp only [denote_idx_gate heq]
|
||||
have := aig.invariant hidx heq
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Literal
|
||||
/--
|
||||
Flip the polarity of `l`.
|
||||
-/
|
||||
def negate (l : Literal α) : Literal α := (l.1, not l.2)
|
||||
def negate (l : Literal α) : Literal α := (l.1, !l.2)
|
||||
|
||||
end Literal
|
||||
|
||||
|
||||
@@ -37,15 +37,11 @@ theorem denote_mkFullAdderOut (assign : α → Bool) (aig : AIG α) (input : Ful
|
||||
theorem denote_mkFullAdderCarry (assign : α → Bool) (aig : AIG α) (input : FullAdderInput aig) :
|
||||
⟦mkFullAdderCarry aig input, assign⟧
|
||||
=
|
||||
or
|
||||
(and
|
||||
(xor
|
||||
((xor
|
||||
⟦aig, input.lhs, assign⟧
|
||||
⟦aig, input.rhs, assign⟧)
|
||||
⟦aig, input.cin, assign⟧)
|
||||
(and
|
||||
⟦aig, input.lhs, assign⟧
|
||||
⟦aig, input.rhs, assign⟧)
|
||||
⟦aig, input.rhs, assign⟧) &&
|
||||
⟦aig, input.cin, assign⟧ ||
|
||||
⟦aig, input.lhs, assign⟧ && ⟦aig, input.rhs, assign⟧)
|
||||
:= by
|
||||
simp only [mkFullAdderCarry, Ref.cast_eq, Int.reduceNeg, denote_mkOrCached,
|
||||
LawfulOperator.denote_input_entry, denote_mkAndCached, denote_projected_entry',
|
||||
|
||||
@@ -33,7 +33,7 @@ def toString : Gate → String
|
||||
def eval : Gate → Bool → Bool → Bool
|
||||
| and => (· && ·)
|
||||
| or => (· || ·)
|
||||
| xor => _root_.xor
|
||||
| xor => Bool.xor
|
||||
| beq => (· == ·)
|
||||
| imp => (!· || ·)
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ theorem check_sound (lratProof : Array IntAction) (cnf : CNF Nat) :
|
||||
_
|
||||
(by
|
||||
intro action h
|
||||
simp only [Array.toList_eq, List.filterMap_map, List.mem_filterMap, Function.comp_apply] at h
|
||||
simp only [List.filterMap_map, List.mem_filterMap, Function.comp_apply] at h
|
||||
rcases h with ⟨WellFormedActions, _, h2⟩
|
||||
split at h2
|
||||
. contradiction
|
||||
|
||||
@@ -21,12 +21,11 @@ theorem sat_negate_iff_not_sat {p : α → Bool} {l : Literal α} : p ⊨ Litera
|
||||
simp only [Literal.negate, sat_iff]
|
||||
constructor
|
||||
· intro h pl
|
||||
rw [sat_iff, h, not.eq_def] at pl
|
||||
split at pl <;> simp_all
|
||||
rw [sat_iff, h] at pl
|
||||
simp at pl
|
||||
· intro h
|
||||
rw [sat_iff] at h
|
||||
rw [not.eq_def]
|
||||
split <;> simp_all
|
||||
cases h : p l.fst <;> simp_all
|
||||
|
||||
theorem unsat_of_limplies_complement [Entails α t] (x : t) (l : Literal α) :
|
||||
Limplies α x l → Limplies α x (Literal.negate l) → Unsatisfiable α x := by
|
||||
@@ -113,7 +112,7 @@ theorem limplies_insert [Clause α β] [Entails α σ] [Formula α β σ] {c :
|
||||
simp only [formulaEntails_def, List.all_eq_true, decide_eq_true_eq]
|
||||
intro h c' c'_in_f
|
||||
have c'_in_fc : c' ∈ toList (insert f c) := by
|
||||
simp only [insert_iff, Array.toList_eq, Array.data_toArray, List.mem_singleton]
|
||||
simp only [insert_iff, Array.toList_toArray, List.mem_singleton]
|
||||
exact Or.inr c'_in_f
|
||||
exact h c' c'_in_fc
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ Attempts to add the literal `(idx, b)` to clause `c`. Returns none if doing so w
|
||||
tautology.
|
||||
-/
|
||||
def insert (c : DefaultClause n) (l : Literal (PosFin n)) : Option (DefaultClause n) :=
|
||||
if heq1 : c.clause.contains (l.1, not l.2) then
|
||||
if heq1 : c.clause.contains (l.1, !l.2) then
|
||||
none -- Adding l would make c a tautology
|
||||
else if heq2 : c.clause.contains l then
|
||||
some c
|
||||
@@ -223,7 +223,7 @@ theorem ofArray_eq (arr : Array (Literal (PosFin n)))
|
||||
ofArray arr = some c → toList c = Array.toList arr := by
|
||||
intro h
|
||||
simp only [ofArray] at h
|
||||
rw [toList, Array.toList_eq]
|
||||
rw [toList]
|
||||
let motive (idx : Nat) (acc : Option (DefaultClause n)) : Prop :=
|
||||
∃ idx_le_arr_size : idx ≤ arr.size, ∀ c' : DefaultClause n, acc = some c' →
|
||||
∃ hsize : c'.clause.length = arr.size - idx, ∀ i : Fin c'.clause.length,
|
||||
@@ -293,13 +293,13 @@ theorem ofArray_eq (arr : Array (Literal (PosFin n)))
|
||||
next i l =>
|
||||
by_cases i_in_bounds : i < c.clause.length
|
||||
· specialize h ⟨i, i_in_bounds⟩
|
||||
have i_in_bounds' : i < arr.data.length := by
|
||||
have i_in_bounds' : i < arr.toList.length := by
|
||||
dsimp; omega
|
||||
rw [List.getElem?_eq_getElem i_in_bounds, List.getElem?_eq_getElem i_in_bounds']
|
||||
simp only [List.get_eq_getElem, Nat.zero_add] at h
|
||||
rw [← Array.getElem_eq_data_getElem]
|
||||
rw [← Array.getElem_eq_toList_getElem]
|
||||
simp [h]
|
||||
· have arr_data_length_le_i : arr.data.length ≤ i := by
|
||||
· have arr_data_length_le_i : arr.toList.length ≤ i := by
|
||||
dsimp; omega
|
||||
simp only [Nat.not_lt, ← List.getElem?_eq_none_iff] at i_in_bounds arr_data_length_le_i
|
||||
rw [i_in_bounds, arr_data_length_le_i]
|
||||
@@ -353,7 +353,7 @@ def reduce_fold_fn (assignments : Array Assignment) (acc : ReduceResult (PosFin
|
||||
else
|
||||
.reducedToEmpty
|
||||
| .neg =>
|
||||
if not l.2 then
|
||||
if !l.2 then
|
||||
.reducedToUnit l
|
||||
else
|
||||
.reducedToEmpty
|
||||
@@ -367,7 +367,7 @@ def reduce_fold_fn (assignments : Array Assignment) (acc : ReduceResult (PosFin
|
||||
else
|
||||
.reducedToUnit l'
|
||||
| .neg =>
|
||||
if not l.2 then
|
||||
if !l.2 then
|
||||
.reducedToNonunit -- Assignment fails to refute both l and l'
|
||||
else
|
||||
.reducedToUnit l'
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user