mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-21 04:14:07 +00:00
Compare commits
46 Commits
Array.non_
...
map_mergeS
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3591f23a15 | ||
|
|
b74f85accd | ||
|
|
46b16b6df1 | ||
|
|
445c8f2ee0 | ||
|
|
3f8e3e726d | ||
|
|
45af92fcd1 | ||
|
|
7952a7f74d | ||
|
|
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 |
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 :=
|
||||
|
||||
@@ -147,6 +147,9 @@ theorem anyM_stop_le_start [Monad m] (p : α → m Bool) (as : Array α) (start
|
||||
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
|
||||
@@ -825,7 +828,7 @@ theorem get_append_right {as bs : Array α} {h : i < (as ++ bs).size} (hle : as.
|
||||
(as ++ bs)[i] = bs[i - as.size] := by
|
||||
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' := h') (h := Nat.not_lt_of_ge hle)]
|
||||
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
|
||||
|
||||
@@ -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⟩
|
||||
@@ -173,6 +173,10 @@ instance : GetElem (BitVec w) Nat Bool fun _ i => i < w where
|
||||
theorem getElem_eq_testBit_toNat (x : BitVec w) (i : Nat) (h : i < w) :
|
||||
x[i] = x.toNat.testBit i := rfl
|
||||
|
||||
theorem getLsbD_eq_getElem {x : BitVec w} {i : Nat} (h : i < w) :
|
||||
x.getLsbD i = x[i] := by
|
||||
simp [getLsbD, getElem_eq_testBit_toNat]
|
||||
|
||||
end getElem
|
||||
|
||||
section Int
|
||||
|
||||
@@ -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.
|
||||
@@ -273,8 +273,30 @@ theorem getLsbD_ofNat (n : Nat) (x : Nat) (i : Nat) :
|
||||
private theorem lt_two_pow_of_le {x m n : Nat} (lt : x < 2 ^ m) (le : m ≤ n) : x < 2 ^ n :=
|
||||
Nat.lt_of_lt_of_le lt (Nat.pow_le_pow_of_le_right (by trivial : 0 < 2) le)
|
||||
|
||||
@[simp] theorem getElem_zero_ofNat_zero (i : Nat) (h : i < w) : (BitVec.ofNat w 0)[i] = false := by
|
||||
simp [getElem_eq_testBit_toNat]
|
||||
|
||||
@[simp] theorem getElem_zero_ofNat_one (h : 0 < w) : (BitVec.ofNat w 1)[0] = true := by
|
||||
simp [getElem_eq_testBit_toNat, h]
|
||||
|
||||
@[simp] theorem getElem?_zero_ofNat_zero : (BitVec.ofNat (w+1) 0)[0]? = some false := by
|
||||
simp [getElem?_eq_getElem]
|
||||
|
||||
@[simp] theorem getElem?_zero_ofNat_one : (BitVec.ofNat (w+1) 1)[0]? = some true := by
|
||||
simp [getElem?_eq_getElem]
|
||||
|
||||
@[simp] theorem getElem?_zero_ofBool (b : Bool) : (ofBool b)[0]? = some b := by
|
||||
simp [ofBool, cond_eq_if]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem getElem_zero_ofBool (b : Bool) : (ofBool b)[0] = b := by
|
||||
rw [getElem_eq_iff, getElem?_zero_ofBool]
|
||||
|
||||
@[simp] theorem getElem?_succ_ofBool (b : Bool) (i : Nat) : (ofBool b)[i + 1]? = none := by
|
||||
simp [ofBool]
|
||||
|
||||
@[simp]
|
||||
theorem getLsbD_ofBool (b : Bool) (i : Nat) : (BitVec.ofBool b).getLsbD i = ((i = 0) && b) := by
|
||||
theorem getLsbD_ofBool (b : Bool) (i : Nat) : (ofBool b).getLsbD i = ((i = 0) && b) := by
|
||||
rcases b with rfl | rfl
|
||||
· simp [ofBool]
|
||||
· simp only [ofBool, ofNat_eq_ofNat, cond_true, getLsbD_ofNat, Bool.and_true]
|
||||
@@ -330,6 +352,10 @@ theorem toNat_ge_of_msb_true {x : BitVec n} (p : BitVec.msb x = true) : x.toNat
|
||||
|
||||
@[simp] theorem getMsbD_cast (h : w = v) (x : BitVec w) : (cast h x).getMsbD i = x.getMsbD i := by
|
||||
subst h; simp
|
||||
|
||||
@[simp] theorem getElem_cast (h : w = v) (x : BitVec w) (p : i < v) : (cast h x)[i] = x[i] := by
|
||||
subst h; simp
|
||||
|
||||
@[simp] theorem msb_cast (h : w = v) (x : BitVec w) : (cast h x).msb = x.msb := by
|
||||
simp [BitVec.msb]
|
||||
|
||||
@@ -523,6 +549,15 @@ theorem getElem?_zeroExtend (m : Nat) (x : BitVec n) (i : Nat) :
|
||||
all_goals (first | apply getLsbD_ge | apply Eq.symm; apply getLsbD_ge)
|
||||
<;> omega
|
||||
|
||||
@[simp]
|
||||
theorem getElem_truncate (m : Nat) (x : BitVec n) (i : Nat) (hi : i < m) :
|
||||
(truncate m x)[i] = x.getLsbD i := by
|
||||
simp only [getElem_zeroExtend]
|
||||
|
||||
theorem getElem?_truncate (m : Nat) (x : BitVec n) (i : Nat) :
|
||||
(truncate m x)[i]? = if i < m then some (x.getLsbD i) else none :=
|
||||
getElem?_zeroExtend m x i
|
||||
|
||||
theorem getLsbD_truncate (m : Nat) (x : BitVec n) (i : Nat) :
|
||||
getLsbD (truncate m x) i = (decide (i < m) && getLsbD x i) :=
|
||||
getLsbD_zeroExtend m x i
|
||||
@@ -546,7 +581,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 +627,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]
|
||||
@@ -633,6 +674,9 @@ theorem extractLsb'_eq_extractLsb {w : Nat} (x : BitVec w) (start len : Nat) (h
|
||||
@[simp] theorem getLsbD_allOnes : (allOnes v).getLsbD i = decide (i < v) := by
|
||||
simp [allOnes]
|
||||
|
||||
@[simp] theorem getElem_allOnes (i : Nat) (h : i < v) : (allOnes v)[i] = true := by
|
||||
simp [getElem_eq_testBit_toNat, h]
|
||||
|
||||
@[simp] theorem ofFin_add_rev (x : Fin (2^n)) : ofFin (x + x.rev) = allOnes n := by
|
||||
ext
|
||||
simp only [Fin.rev, getLsbD_ofFin, getLsbD_allOnes, Fin.is_lt, decide_True]
|
||||
@@ -660,6 +704,9 @@ theorem extractLsb'_eq_extractLsb {w : Nat} (x : BitVec w) (start len : Nat) (h
|
||||
simp only [getMsbD]
|
||||
by_cases h : i < w <;> simp [h]
|
||||
|
||||
@[simp] theorem getElem_or {x y : BitVec w} {i : Nat} (h : i < w) : (x ||| y)[i] = (x[i] || y[i]) := by
|
||||
simp [getElem_eq_testBit_toNat]
|
||||
|
||||
@[simp] theorem msb_or {x y : BitVec w} : (x ||| y).msb = (x.msb || y.msb) := by
|
||||
simp [BitVec.msb]
|
||||
|
||||
@@ -698,6 +745,9 @@ instance : Std.Commutative (fun (x y : BitVec w) => x ||| y) := ⟨BitVec.or_com
|
||||
simp only [getMsbD]
|
||||
by_cases h : i < w <;> simp [h]
|
||||
|
||||
@[simp] theorem getElem_and {x y : BitVec w} {i : Nat} (h : i < w) : (x &&& y)[i] = (x[i] && y[i]) := by
|
||||
simp [getElem_eq_testBit_toNat]
|
||||
|
||||
@[simp] theorem msb_and {x y : BitVec w} : (x &&& y).msb = (x.msb && y.msb) := by
|
||||
simp [BitVec.msb]
|
||||
|
||||
@@ -738,6 +788,9 @@ instance : Std.Commutative (fun (x y : BitVec w) => x &&& y) := ⟨BitVec.and_co
|
||||
simp only [getMsbD]
|
||||
by_cases h : i < w <;> simp [h]
|
||||
|
||||
@[simp] theorem getElem_xor {x y : BitVec w} {i : Nat} (h : i < w) : (x ^^^ y)[i] = (xor x[i] y[i]) := by
|
||||
simp [getElem_eq_testBit_toNat]
|
||||
|
||||
@[simp] theorem msb_xor {x y : BitVec w} :
|
||||
(x ^^^ y).msb = (xor x.msb y.msb) := by
|
||||
simp [BitVec.msb]
|
||||
@@ -791,6 +844,12 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
|
||||
@[simp] theorem getLsbD_not {x : BitVec v} : (~~~x).getLsbD i = (decide (i < v) && ! x.getLsbD i) := by
|
||||
by_cases h' : i < v <;> simp_all [not_def]
|
||||
|
||||
@[simp] theorem getElem_not {x : BitVec w} {i : Nat} (h : i < w) : (~~~x)[i] = !x[i] := by
|
||||
simp only [getElem_eq_testBit_toNat, toNat_not]
|
||||
rw [← Nat.sub_add_eq, Nat.add_comm 1]
|
||||
rw [Nat.testBit_two_pow_sub_succ x.isLt]
|
||||
simp [h]
|
||||
|
||||
@[simp] theorem truncate_not {x : BitVec w} (h : k ≤ w) :
|
||||
(~~~x).truncate k = ~~~(x.truncate k) := by
|
||||
ext
|
||||
@@ -826,7 +885,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
|
||||
@@ -947,6 +1006,10 @@ theorem getLsbD_shiftLeft' {x : BitVec w₁} {y : BitVec w₂} {i : Nat} :
|
||||
getLsbD (x >>> i) j = getLsbD x (i+j) := by
|
||||
unfold getLsbD ; simp
|
||||
|
||||
@[simp] theorem getElem_ushiftRight (x : BitVec w) (i n : Nat) (h : i < w) :
|
||||
(x >>> n)[i] = x.getLsbD (n + i) := by
|
||||
simp [getElem_eq_testBit_toNat, toNat_ushiftRight, Nat.testBit_shiftRight, getLsbD]
|
||||
|
||||
theorem ushiftRight_xor_distrib (x y : BitVec w) (n : Nat) :
|
||||
(x ^^^ y) >>> n = (x >>> n) ^^^ (y >>> n) := by
|
||||
ext
|
||||
@@ -1027,7 +1090,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 +1291,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 +1322,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 +1583,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
|
||||
@@ -1667,6 +1742,14 @@ protected theorem lt_of_le_ne {x y : BitVec n} : x ≤ y → ¬ x = y → x < y
|
||||
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 -/
|
||||
|
||||
@[simp] theorem getMsbD_ofBoolListBE : (ofBoolListBE bs).getMsbD i = bs.getD i false := by
|
||||
@@ -2038,4 +2121,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 {n : Nat} [NeZero n] {i : Nat} : OfNat (Fin (no_index n)) i where
|
||||
ofNat := Fin.ofNat' i (pos_of_neZero _)
|
||||
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,14 +117,18 @@ 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 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 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 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 _ _
|
||||
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 _)
|
||||
|
||||
@[simp]
|
||||
theorem mem_attach (l : List α) : ∀ x, x ∈ l.attach
|
||||
@@ -137,7 +154,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 +176,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 +217,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 +235,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,20 +272,72 @@ 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
|
||||
| cons x xs => simp [head_attach, h]
|
||||
|
||||
@[simp] theorem tail_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).tail = xs.tail.pmap f (fun a h => H a (mem_of_mem_tail h)) := by
|
||||
cases xs <;> simp
|
||||
|
||||
@[simp] theorem tail_attachWith {P : α → Prop} {xs : List α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).tail = xs.tail.attachWith P (fun a h => H a (mem_of_mem_tail h)) := by
|
||||
cases xs <;> simp
|
||||
|
||||
@[simp] theorem tail_attach (xs : List α) :
|
||||
xs.attach.tail = xs.tail.attach.map (fun ⟨x, h⟩ => ⟨x, mem_of_mem_tail h⟩) := by
|
||||
cases xs <;> simp
|
||||
|
||||
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 +378,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 +411,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 +427,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 +452,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 +466,46 @@ 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]
|
||||
|
||||
@[simp]
|
||||
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]
|
||||
|
||||
@[simp]
|
||||
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 _ _ _
|
||||
|
||||
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'
|
||||
|
||||
@@ -115,16 +115,23 @@ theorem IsPrefix.countP_le (s : l₁ <+: l₂) : countP p l₁ ≤ countP p l₂
|
||||
theorem IsSuffix.countP_le (s : l₁ <:+ l₂) : countP p l₁ ≤ countP p l₂ := s.sublist.countP_le _
|
||||
theorem IsInfix.countP_le (s : l₁ <:+: l₂) : countP p l₁ ≤ countP p l₂ := s.sublist.countP_le _
|
||||
|
||||
-- See `Init.Data.List.Nat.Count` for `Sublist.le_countP : countP p l₂ - (l₂.length - l₁.length) ≤ countP p l₁`.
|
||||
|
||||
theorem countP_tail_le (l) : countP p l.tail ≤ countP p l :=
|
||||
(tail_sublist l).countP_le _
|
||||
|
||||
-- See `Init.Data.List.Nat.Count` for `le_countP_tail : countP p l - 1 ≤ countP p l.tail`.
|
||||
|
||||
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 : α → β) :
|
||||
@@ -207,6 +214,13 @@ theorem IsPrefix.count_le (h : l₁ <+: l₂) (a : α) : count a l₁ ≤ count
|
||||
theorem IsSuffix.count_le (h : l₁ <:+ l₂) (a : α) : count a l₁ ≤ count a l₂ := h.sublist.count_le _
|
||||
theorem IsInfix.count_le (h : l₁ <:+: l₂) (a : α) : count a l₁ ≤ count a l₂ := h.sublist.count_le _
|
||||
|
||||
-- See `Init.Data.List.Nat.Count` for `Sublist.le_count : count a l₂ - (l₂.length - l₁.length) ≤ countP a l₁`.
|
||||
|
||||
theorem count_tail_le (a : α) (l) : count a l.tail ≤ count a l :=
|
||||
(tail_sublist l).count_le _
|
||||
|
||||
-- See `Init.Data.List.Nat.Count` for `le_count_tail : count a l - 1 ≤ count a l.tail`.
|
||||
|
||||
theorem count_le_count_cons (a b : α) (l : List α) : count a l ≤ count a (b :: l) :=
|
||||
(sublist_cons_self _ _).count_le _
|
||||
|
||||
|
||||
@@ -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 _
|
||||
@@ -991,6 +1045,11 @@ theorem head?_eq_getElem? : ∀ l : List α, head? l = l[0]?
|
||||
| [] => rfl
|
||||
| a :: l => by simp
|
||||
|
||||
theorem head_eq_getElem (l : List α) (h : l ≠ []) : head l h = l[0]'(length_pos.mpr h) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
| cons _ _ => simp
|
||||
|
||||
theorem head_eq_iff_head?_eq_some {xs : List α} (h) : xs.head h = a ↔ xs.head? = some a := by
|
||||
cases xs with
|
||||
| nil => simp at h
|
||||
@@ -1018,6 +1077,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 +1107,58 @@ 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
|
||||
|
||||
theorem ne_nil_of_tail_ne_nil {l : List α} : l.tail ≠ [] → l ≠ [] := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp] theorem getElem_tail (l : List α) (i : Nat) (h : i < l.tail.length) :
|
||||
(tail l)[i] = l[i + 1]'(add_lt_of_lt_sub (by simpa using h)) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
| cons _ l => simp
|
||||
|
||||
@[simp] theorem getElem?_tail (l : List α) (i : Nat) :
|
||||
(tail l)[i]? = l[i + 1]? := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp] theorem set_tail (l : List α) (i : Nat) (a : α) :
|
||||
l.tail.set i a = (l.set (i + 1) a).tail := by
|
||||
cases l <;> simp
|
||||
|
||||
theorem one_lt_length_of_tail_ne_nil {l : List α} (h : l.tail ≠ []) : 1 < l.length := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
| cons _ l =>
|
||||
simp only [tail_cons, ne_eq] at h
|
||||
exact Nat.lt_add_of_pos_left (length_pos.mpr h)
|
||||
|
||||
@[simp] theorem head_tail (l : List α) (h : l.tail ≠ []) :
|
||||
(tail l).head h = l[1]'(one_lt_length_of_tail_ne_nil h) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
| cons _ l => simp [head_eq_getElem]
|
||||
|
||||
@[simp] theorem head?_tail (l : List α) : (tail l).head? = l[1]? := by
|
||||
simp [head?_eq_getElem?]
|
||||
|
||||
@[simp] theorem getLast_tail (l : List α) (h : l.tail ≠ []) :
|
||||
(tail l).getLast h = l.getLast (ne_nil_of_tail_ne_nil h) := by
|
||||
simp only [getLast_eq_getElem, length_tail, getElem_tail]
|
||||
congr
|
||||
match l with
|
||||
| _ :: _ :: l => simp
|
||||
|
||||
theorem getLast?_tail (l : List α) : (tail l).getLast? = if l.length = 1 then none else l.getLast? := by
|
||||
match l with
|
||||
| [] => simp
|
||||
| [a] => simp
|
||||
| _ :: _ :: l =>
|
||||
simp only [tail_cons, length_cons, getLast?_cons_cons]
|
||||
rw [if_neg]
|
||||
rintro ⟨⟩
|
||||
|
||||
/-! ## Basic operations -/
|
||||
|
||||
/-! ### map -/
|
||||
@@ -1496,10 +1611,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 +1641,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 +1658,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 +1750,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 +2429,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
|
||||
@@ -2743,6 +2901,12 @@ theorem dropLast_append_cons : dropLast (l₁ ++ b :: l₂) = l₁ ++ dropLast (
|
||||
dropLast (a :: replicate n a) = replicate n a := by
|
||||
rw [← replicate_succ, dropLast_replicate, Nat.add_sub_cancel]
|
||||
|
||||
@[simp] theorem tail_reverse (l : List α) : l.reverse.tail = l.dropLast.reverse := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro i h₁ h₂
|
||||
simp [Nat.add_comm i, Nat.sub_add_eq]
|
||||
|
||||
/-!
|
||||
### splitAt
|
||||
|
||||
|
||||
@@ -18,6 +18,26 @@ open Nat
|
||||
|
||||
namespace List
|
||||
|
||||
/-! ### dropLast -/
|
||||
|
||||
theorem tail_dropLast (l : List α) : tail (dropLast l) = dropLast (tail l) := by
|
||||
ext1
|
||||
simp only [getElem?_tail, getElem?_dropLast, length_tail]
|
||||
split <;> split
|
||||
· rfl
|
||||
· omega
|
||||
· omega
|
||||
· rfl
|
||||
|
||||
@[simp] theorem dropLast_reverse (l : List α) : l.reverse.dropLast = l.tail.reverse := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro i h₁ h₂
|
||||
simp only [getElem_dropLast, getElem_reverse, length_tail, getElem_tail]
|
||||
congr
|
||||
simp only [length_dropLast, length_reverse, length_tail] at h₁ h₂
|
||||
omega
|
||||
|
||||
/-! ### filter -/
|
||||
|
||||
theorem length_filter_lt_length_iff_exists {l} :
|
||||
|
||||
@@ -28,4 +28,59 @@ theorem count_set [BEq α] (a b : α) (l : List α) (i : Nat) (h : i < l.length)
|
||||
(l.set i a).count b = l.count b - (if l[i] == b then 1 else 0) + (if a == b then 1 else 0) := by
|
||||
simp [count_eq_countP, countP_set, h]
|
||||
|
||||
/--
|
||||
The number of elements satisfying a predicate in a sublist is at least the number of elements satisfying the predicate in the list,
|
||||
minus the difference in the lengths.
|
||||
-/
|
||||
theorem Sublist.le_countP (s : l₁ <+ l₂) (p) : countP p l₂ - (l₂.length - l₁.length) ≤ countP p l₁ := by
|
||||
match s with
|
||||
| .slnil => simp
|
||||
| .cons a s =>
|
||||
rename_i l
|
||||
simp only [countP_cons, length_cons]
|
||||
have := s.le_countP p
|
||||
have := s.length_le
|
||||
split <;> omega
|
||||
| .cons₂ a s =>
|
||||
rename_i l₁ l₂
|
||||
simp only [countP_cons, length_cons]
|
||||
have := s.le_countP p
|
||||
have := s.length_le
|
||||
split <;> omega
|
||||
|
||||
theorem IsPrefix.le_countP (s : l₁ <+: l₂) : countP p l₂ - (l₂.length - l₁.length) ≤ countP p l₁ :=
|
||||
s.sublist.le_countP _
|
||||
|
||||
theorem IsSuffix.le_countP (s : l₁ <:+ l₂) : countP p l₂ - (l₂.length - l₁.length) ≤ countP p l₁ :=
|
||||
s.sublist.le_countP _
|
||||
|
||||
theorem IsInfix.le_countP (s : l₁ <:+: l₂) : countP p l₂ - (l₂.length - l₁.length) ≤ countP p l₁ :=
|
||||
s.sublist.le_countP _
|
||||
|
||||
/--
|
||||
The number of elements satisfying a predicate in the tail of a list is
|
||||
at least one less than the number of elements satisfying the predicate in the list.
|
||||
-/
|
||||
theorem le_countP_tail (l) : countP p l - 1 ≤ countP p l.tail := by
|
||||
have := (tail_sublist l).le_countP p
|
||||
simp only [length_tail] at this
|
||||
omega
|
||||
|
||||
variable [BEq α]
|
||||
|
||||
theorem Sublist.le_count (s : l₁ <+ l₂) (a : α) : count a l₂ - (l₂.length - l₁.length) ≤ count a l₁ :=
|
||||
s.le_countP _
|
||||
|
||||
theorem IsPrefix.le_count (s : l₁ <+: l₂) (a : α) : count a l₂ - (l₂.length - l₁.length) ≤ count a l₁ :=
|
||||
s.sublist.le_count _
|
||||
|
||||
theorem IsSuffix.le_count (s : l₁ <:+ l₂) (a : α) : count a l₂ - (l₂.length - l₁.length) ≤ count a l₁ :=
|
||||
s.sublist.le_count _
|
||||
|
||||
theorem IsInfix.le_count (s : l₁ <:+: l₂) (a : α) : count a l₂ - (l₂.length - l₁.length) ≤ count a l₁ :=
|
||||
s.sublist.le_count _
|
||||
|
||||
theorem le_count_tail (a : α) (l) : count a l - 1 ≤ count a l.tail :=
|
||||
le_countP_tail _
|
||||
|
||||
end List
|
||||
|
||||
@@ -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']
|
||||
@@ -258,6 +258,9 @@ theorem nodup_iota (n : Nat) : Nodup (iota n) :=
|
||||
| zero => simp at h
|
||||
| succ n => simp
|
||||
|
||||
@[simp] theorem tail_iota (n : Nat) : (iota n).tail = iota (n - 1) := by
|
||||
cases n <;> simp
|
||||
|
||||
@[simp] theorem reverse_iota : reverse (iota n) = range' 1 n := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
@@ -448,6 +451,9 @@ theorem getElem_enum (l : List α) (i : Nat) (h : i < l.enum.length) :
|
||||
l.enum.getLast? = l.getLast?.map fun a => (l.length - 1, a) := by
|
||||
simp [getLast?_eq_getElem?]
|
||||
|
||||
@[simp] theorem tail_enum (l : List α) : (enum l).tail = enumFrom 1 l.tail := by
|
||||
simp [enum]
|
||||
|
||||
theorem mk_mem_enum_iff_getElem? {i : Nat} {x : α} {l : List α} : (i, x) ∈ enum l ↔ l[i]? = x := by
|
||||
simp [enum, mk_mem_enumFrom_iff_le_and_getElem?_sub]
|
||||
|
||||
|
||||
@@ -36,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. -/
|
||||
@@ -60,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 :=
|
||||
@@ -110,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
|
||||
@@ -196,7 +196,7 @@ theorem dropLast_take {n : Nat} {l : List α} (h : n < l.length) :
|
||||
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
|
||||
|
||||
@@ -219,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. -/
|
||||
@@ -267,9 +268,9 @@ theorem mem_take_iff_getElem {l : List α} {a : α} :
|
||||
constructor
|
||||
· rintro ⟨i, hm, rfl⟩
|
||||
simp at hm
|
||||
refine ⟨i, by omega, by rw [getElem_take']⟩
|
||||
refine ⟨i, by omega, by rw [getElem_take]⟩
|
||||
· rintro ⟨i, hm, rfl⟩
|
||||
refine ⟨i, by simpa, by rw [getElem_take']⟩
|
||||
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
|
||||
@@ -478,7 +479,7 @@ theorem false_of_mem_take_findIdx {xs : List α} {p : α → Bool} (h : x ∈ xs
|
||||
· simp only [take_succ_cons, findIdx?_cons]
|
||||
split
|
||||
· simp
|
||||
· simp [ih, Option.guard_comp]
|
||||
· 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
|
||||
|
||||
@@ -35,11 +35,16 @@ theorem range'_succ (s n step) : range' s (n + 1) step = s :: range' (s + step)
|
||||
theorem range'_ne_nil (s : Nat) {n : Nat} : range' s n ≠ [] ↔ n ≠ 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[simp] theorem range'_zero : range' s 0 = [] := by
|
||||
@[simp] theorem range'_zero : range' s 0 step = [] := by
|
||||
simp
|
||||
|
||||
@[simp] theorem range'_one {s step : Nat} : range' s 1 step = [s] := rfl
|
||||
|
||||
@[simp] theorem tail_range' (n : Nat) : (range' s n step).tail = range' (s + step) (n - 1) step := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n => simp [range'_succ]
|
||||
|
||||
@[simp] theorem range'_inj : range' s n = range' s' n' ↔ n = n' ∧ (n = 0 ∨ s = s') := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -153,6 +158,9 @@ theorem range'_eq_map_range (s n : Nat) : range' s n = map (s + ·) (range n) :=
|
||||
theorem range_ne_nil {n : Nat} : range n ≠ [] ↔ n ≠ 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[simp] theorem tail_range (n : Nat) : (range n).tail = range' 1 (n - 1) := by
|
||||
rw [range_eq_range', tail_range']
|
||||
|
||||
@[simp]
|
||||
theorem range_sublist {m n : Nat} : range m <+ range n ↔ m ≤ n := by
|
||||
simp only [range_eq_range', range'_sublist_right]
|
||||
@@ -219,6 +227,12 @@ theorem getElem_enumFrom (l : List α) (n) (i : Nat) (h : i < (l.enumFrom n).len
|
||||
simp only [getElem?_enumFrom, getElem?_eq_getElem h]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem tail_enumFrom (l : List α) (n : Nat) : (enumFrom n l).tail = enumFrom (n + 1) l.tail := by
|
||||
induction l generalizing n with
|
||||
| nil => simp
|
||||
| cons _ l ih => simp [ih, enumFrom_cons]
|
||||
|
||||
theorem map_fst_add_enumFrom_eq_enumFrom (l : List α) (n k : Nat) :
|
||||
map (Prod.map (· + n) id) (enumFrom k l) = enumFrom (n + k) l :=
|
||||
ext_getElem? fun i ↦ by simp [(· ∘ ·), Nat.add_comm, Nat.add_left_comm]; rfl
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
Authors: Kim Morrison, Eric Wieser, François G. Dorais
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Perm
|
||||
@@ -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]
|
||||
@@ -128,26 +125,34 @@ 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))
|
||||
| [], ys, _ => by simp [merge]
|
||||
| xs, [], _ => by simp [merge]
|
||||
| (i, x) :: xs, (j, y) :: ys, h => by
|
||||
simp only [merge, enumLE, map_cons]
|
||||
split <;> rename_i w
|
||||
· rw [if_pos (by simp [h _ _ (mem_cons_self ..) (mem_cons_self ..)])]
|
||||
simp only [map_cons, cons.injEq, true_and]
|
||||
rw [merge_stable, map_cons]
|
||||
exact fun x' y' mx my => h x' y' (mem_cons_of_mem (i, x) mx) my
|
||||
· simp only [↓reduceIte, map_cons, cons.injEq, true_and, reduceCtorEq]
|
||||
rw [merge_stable, map_cons]
|
||||
exact fun x' y' mx my => h x' y' mx (mem_cons_of_mem (j, y) my)
|
||||
theorem cons_merge_cons (s : α → α → Bool) (a b l r) :
|
||||
merge (a::l) (b::r) s = if s a b then a :: merge l (b::r) s else b :: merge (a::l) r s := by
|
||||
simp only [merge]
|
||||
|
||||
@[simp] theorem cons_merge_cons_pos (s : α → α → Bool) (l r) (h : s a b) :
|
||||
merge (a::l) (b::r) s = a :: merge l (b::r) s := by
|
||||
rw [cons_merge_cons, if_pos h]
|
||||
|
||||
@[simp] theorem cons_merge_cons_neg (s : α → α → Bool) (l r) (h : ¬ s a b) :
|
||||
merge (a::l) (b::r) s = b :: merge (a::l) r s := by
|
||||
rw [cons_merge_cons, if_neg h]
|
||||
|
||||
@[simp] theorem length_merge (s : α → α → Bool) (l r) :
|
||||
(merge l r s).length = l.length + r.length := by
|
||||
match l, r with
|
||||
| [], r => simp
|
||||
| l, [] => simp
|
||||
| a::l, b::r =>
|
||||
rw [cons_merge_cons]
|
||||
split
|
||||
· simp_arith [length_merge s l (b::r)]
|
||||
· simp_arith [length_merge s (a::l) r]
|
||||
|
||||
/--
|
||||
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 +166,30 @@ 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]
|
||||
|
||||
theorem mem_merge_left (s : α → α → Bool) (h : x ∈ l) : x ∈ merge l r s :=
|
||||
mem_merge.2 <| .inl h
|
||||
|
||||
theorem mem_merge_right (s : α → α → Bool) (h : x ∈ r) : x ∈ merge l r s :=
|
||||
mem_merge.2 <| .inr h
|
||||
|
||||
theorem merge_stable : ∀ (xs ys) (_ : ∀ x y, x ∈ xs → y ∈ ys → x.1 ≤ y.1),
|
||||
(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
|
||||
simp only [merge, enumLE, map_cons]
|
||||
split <;> rename_i w
|
||||
· rw [if_pos (by simp [h _ _ (mem_cons_self ..) (mem_cons_self ..)])]
|
||||
simp only [map_cons, cons.injEq, true_and]
|
||||
rw [merge_stable, map_cons]
|
||||
exact fun x' y' mx my => h x' y' (mem_cons_of_mem (i, x) mx) my
|
||||
· simp only [↓reduceIte, map_cons, cons.injEq, true_and, reduceCtorEq]
|
||||
rw [merge_stable, map_cons]
|
||||
exact fun x' y' mx my => h x' y' mx (mem_cons_of_mem (j, y) my)
|
||||
|
||||
-- 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 +197,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 +224,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 +235,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 +251,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 +279,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 +296,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 +322,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 +348,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 +407,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 +437,44 @@ 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
|
||||
|
||||
theorem map_merge {f : α → β} {r : α → α → Bool} {s : β → β → Bool} {l l' : List α}
|
||||
(hl : ∀ a ∈ l, ∀ b ∈ l', r a b = s (f a) (f b)) :
|
||||
(l.merge l' r).map f = (l.map f).merge (l'.map f) s := by
|
||||
match l, l' with
|
||||
| [], x' => simp
|
||||
| x, [] => simp
|
||||
| x :: xs, x' :: xs' =>
|
||||
simp only [List.forall_mem_cons] at hl
|
||||
simp only [forall_and] at hl
|
||||
simp only [List.map, List.cons_merge_cons]
|
||||
rw [← hl.1.1]
|
||||
split
|
||||
· rw [List.map, map_merge, List.map]
|
||||
simp only [List.forall_mem_cons, forall_and]
|
||||
exact ⟨hl.2.1, hl.2.2⟩
|
||||
· rw [List.map, map_merge, List.map]
|
||||
simp only [List.forall_mem_cons]
|
||||
exact ⟨hl.1.2, hl.2.2⟩
|
||||
|
||||
theorem map_mergeSort {r : α → α → Bool} {s : β → β → Bool} {f : α → β} {l : List α}
|
||||
(hl : ∀ a ∈ l, ∀ b ∈ l, r a b = s (f a) (f b)) :
|
||||
(l.mergeSort r).map f = (l.map f).mergeSort s :=
|
||||
match l with
|
||||
| [] => by simp
|
||||
| [x] => by simp
|
||||
| a :: b :: l => by
|
||||
simp only [mergeSort, splitInTwo_fst, splitInTwo_snd, map_cons]
|
||||
rw [map_merge (fun a am b bm => hl a (mem_of_mem_take (by simpa using am))
|
||||
b (mem_of_mem_drop (by simpa using bm)))]
|
||||
rw [map_mergeSort (s := s) (fun a am b bm => hl a (mem_of_mem_take (by simpa using am))
|
||||
b (mem_of_mem_take (by simpa using bm)))]
|
||||
rw [map_mergeSort (s := s) (fun a am b bm => hl a (mem_of_mem_drop (by simpa using am))
|
||||
b (mem_of_mem_drop (by simpa using bm)))]
|
||||
rw [map_take, map_drop]
|
||||
simp
|
||||
termination_by length l
|
||||
|
||||
@@ -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`.
|
||||
|
||||
|
||||
@@ -31,6 +31,10 @@ theorem zip_map_left (f : α → γ) (l₁ : List α) (l₂ : List β) :
|
||||
theorem zip_map_right (f : β → γ) (l₁ : List α) (l₂ : List β) :
|
||||
zip l₁ (l₂.map f) = (zip l₁ l₂).map (Prod.map id f) := by rw [← zip_map, map_id]
|
||||
|
||||
@[simp] theorem tail_zip (l₁ : List α) (l₂ : List β) :
|
||||
(zip l₁ l₂).tail = zip l₁.tail l₂.tail := by
|
||||
cases l₁ <;> cases l₂ <;> simp
|
||||
|
||||
theorem zip_append :
|
||||
∀ {l₁ r₁ : List α} {l₂ r₂ : List β} (_h : length l₁ = length l₂),
|
||||
zip (l₁ ++ r₁) (l₂ ++ r₂) = zip l₁ l₂ ++ zip r₁ r₂
|
||||
@@ -229,6 +233,7 @@ theorem drop_zipWith : (zipWith f l l').drop n = zipWith f (l.drop n) (l'.drop n
|
||||
|
||||
@[deprecated drop_zipWith (since := "2024-07-26")] abbrev zipWith_distrib_drop := @drop_zipWith
|
||||
|
||||
@[simp]
|
||||
theorem tail_zipWith : (zipWith f l l').tail = zipWith f l.tail l'.tail := by
|
||||
rw [← drop_one]; simp [drop_zipWith]
|
||||
|
||||
@@ -284,12 +289,16 @@ theorem head?_zipWithAll {f : Option α → Option β → γ} :
|
||||
| none, none => .none | a?, b? => some (f a? b?) := by
|
||||
simp [head?_eq_getElem?, getElem?_zipWithAll]
|
||||
|
||||
theorem head_zipWithAll {f : Option α → Option β → γ} (h) :
|
||||
@[simp] theorem head_zipWithAll {f : Option α → Option β → γ} (h) :
|
||||
(zipWithAll f as bs).head h = f as.head? bs.head? := by
|
||||
apply Option.some.inj
|
||||
rw [← head?_eq_head, head?_zipWithAll]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem tail_zipWithAll {f : Option α → Option β → γ} :
|
||||
(zipWithAll f as bs).tail = zipWithAll f as.tail bs.tail := by
|
||||
cases as <;> cases bs <;> simp
|
||||
|
||||
theorem zipWithAll_map {μ} (f : Option γ → Option δ → μ) (g : α → γ) (h : β → δ) (l₁ : List α) (l₂ : List β) :
|
||||
zipWithAll f (l₁.map g) (l₂.map h) = zipWithAll (fun a b => f (g <$> a) (h <$> b)) l₁ l₂ := by
|
||||
induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all
|
||||
@@ -358,6 +367,12 @@ theorem zip_of_prod {l : List α} {l' : List β} {lp : List (α × β)} (hl : lp
|
||||
(hr : lp.map Prod.snd = l') : lp = l.zip l' := by
|
||||
rw [← hl, ← hr, ← zip_unzip lp, ← unzip_fst, ← unzip_snd, zip_unzip, zip_unzip]
|
||||
|
||||
@[simp] theorem tail_zip_fst {l : List (α × β)} : l.unzip.1.tail = l.tail.unzip.1 := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp] theorem tail_zip_snd {l : List (α × β)} : l.unzip.2.tail = l.tail.unzip.2 := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp] theorem unzip_replicate {n : Nat} {a : α} {b : β} :
|
||||
unzip (replicate n (a, b)) = (replicate n a, replicate n b) := by
|
||||
ext1 <;> simp
|
||||
|
||||
@@ -514,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
|
||||
|
||||
@@ -718,7 +722,7 @@ protected theorem zero_ne_one : 0 ≠ (1 : Nat) :=
|
||||
|
||||
theorem succ_ne_zero (n : Nat) : succ n ≠ 0 := by simp
|
||||
|
||||
instance {n : Nat} : NeZero (succ n) := ⟨succ_ne_zero n⟩
|
||||
instance instNeZeroSucc {n : Nat} : NeZero (n + 1) := ⟨succ_ne_zero n⟩
|
||||
|
||||
/-! # mul + order -/
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,7 +248,7 @@ 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
|
||||
|
||||
@[simp] theorem bind_map {f : α → β} {g : β → Option γ} {x : Option α} :
|
||||
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 α} :
|
||||
@@ -411,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 -/
|
||||
@@ -432,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace InitParamMap
|
||||
def initBorrow (ps : Array Param) : Array Param :=
|
||||
ps.map fun p => { p with borrow := p.ty.isObj }
|
||||
|
||||
/-- We do perform borrow inference for constants marked as `export`.
|
||||
/-- We do not perform borrow inference for constants marked as `export`.
|
||||
Reason: we current write wrappers in C++ for using exported functions.
|
||||
These wrappers use smart pointers such as `object_ref`.
|
||||
When writing a new wrapper we need to know whether an argument is a borrow
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -199,9 +199,8 @@ Performs a possibly type-changing transformation to a `MatcherApp`.
|
||||
If `useSplitter` is true, the matcher is replaced with the splitter.
|
||||
NB: Not all operations on `MatcherApp` can handle one `matcherName` is a splitter.
|
||||
|
||||
The array `addEqualities`, if provided, indicates for which of the discriminants an equality
|
||||
connecting the discriminant to the parameters of the alternative (like in `match h : x with …`)
|
||||
should be added (if it is isn't already there).
|
||||
If `addEqualities` is true, then equalities connecting the discriminant to the parameters of the
|
||||
alternative (like in `match h : x with …`) are be added, if not already there.
|
||||
|
||||
This function works even if the the type of alternatives do *not* fit the inferred type. This
|
||||
allows you to post-process the `MatcherApp` with `MatcherApp.inferMatchType`, which will
|
||||
@@ -212,20 +211,13 @@ def transform
|
||||
[AddMessageContext n] [MonadOptions n]
|
||||
(matcherApp : MatcherApp)
|
||||
(useSplitter := false)
|
||||
(addEqualities : Array Bool := mkArray matcherApp.discrs.size false)
|
||||
(addEqualities : Bool := false)
|
||||
(onParams : Expr → n Expr := pure)
|
||||
(onMotive : Array Expr → Expr → n Expr := fun _ e => pure e)
|
||||
(onAlt : Expr → Expr → n Expr := fun _ e => pure e)
|
||||
(onRemaining : Array Expr → n (Array Expr) := pure) :
|
||||
n MatcherApp := do
|
||||
|
||||
if addEqualities.size != matcherApp.discrs.size then
|
||||
throwError "MatcherApp.transform: addEqualities has wrong size"
|
||||
|
||||
-- Do not add equalities when the matcher already does so
|
||||
let addEqualities := Array.zipWith addEqualities matcherApp.discrInfos fun b di =>
|
||||
if di.hName?.isSome then false else b
|
||||
|
||||
-- We also handle CasesOn applications here, and need to treat them specially in a
|
||||
-- few places.
|
||||
-- TODO: Expand MatcherApp with the necessary fields to make this more uniform
|
||||
@@ -241,17 +233,26 @@ def transform
|
||||
let params' ← matcherApp.params.mapM onParams
|
||||
let discrs' ← matcherApp.discrs.mapM onParams
|
||||
|
||||
|
||||
let (motive', uElim) ← lambdaTelescope matcherApp.motive fun motiveArgs motiveBody => do
|
||||
let (motive', uElim, addHEqualities) ← lambdaTelescope matcherApp.motive fun motiveArgs motiveBody => do
|
||||
unless motiveArgs.size == matcherApp.discrs.size do
|
||||
throwError "unexpected matcher application, motive must be lambda expression with #{matcherApp.discrs.size} arguments"
|
||||
let mut motiveBody' ← onMotive motiveArgs motiveBody
|
||||
|
||||
-- Prepend (x = e) → to the motive when an equality is requested
|
||||
for arg in motiveArgs, discr in discrs', b in addEqualities do if b then
|
||||
motiveBody' ← liftMetaM <| mkArrow (← mkEq discr arg) motiveBody'
|
||||
-- Prepend `(x = e) →` or `(HEq x e) → ` to the motive when an equality is requested
|
||||
-- and not already present, and remember whether we added an Eq or a HEq
|
||||
let mut addHEqualities : Array (Option Bool) := #[]
|
||||
for arg in motiveArgs, discr in discrs', di in matcherApp.discrInfos do
|
||||
if addEqualities && di.hName?.isNone then
|
||||
if ← isProof arg then
|
||||
addHEqualities := addHEqualities.push none
|
||||
else
|
||||
let heq ← mkEqHEq discr arg
|
||||
motiveBody' ← liftMetaM <| mkArrow heq motiveBody'
|
||||
addHEqualities := addHEqualities.push heq.isHEq
|
||||
else
|
||||
addHEqualities := addHEqualities.push none
|
||||
|
||||
return (← mkLambdaFVars motiveArgs motiveBody', ← getLevel motiveBody')
|
||||
return (← mkLambdaFVars motiveArgs motiveBody', ← getLevel motiveBody', addHEqualities)
|
||||
|
||||
let matcherLevels ← match matcherApp.uElimPos? with
|
||||
| none => pure matcherApp.matcherLevels
|
||||
@@ -261,15 +262,14 @@ def transform
|
||||
-- (and count them along the way)
|
||||
let mut remaining' := #[]
|
||||
let mut extraEqualities : Nat := 0
|
||||
for discr in discrs'.reverse, b in addEqualities.reverse do if b then
|
||||
remaining' := remaining'.push (← mkEqRefl discr)
|
||||
extraEqualities := extraEqualities + 1
|
||||
for discr in discrs'.reverse, b in addHEqualities.reverse do
|
||||
match b with
|
||||
| none => pure ()
|
||||
| some is_heq =>
|
||||
remaining' := remaining'.push (← (if is_heq then mkHEqRefl else mkEqRefl) discr)
|
||||
extraEqualities := extraEqualities + 1
|
||||
|
||||
if useSplitter && !isCasesOn then
|
||||
-- We replace the matcher with the splitter
|
||||
let matchEqns ← Match.getEquationsFor matcherApp.matcherName
|
||||
let splitter := matchEqns.splitterName
|
||||
|
||||
let aux1 := mkAppN (mkConst matcherApp.matcherName matcherLevels.toList) params'
|
||||
let aux1 := mkApp aux1 motive'
|
||||
let aux1 := mkAppN aux1 discrs'
|
||||
@@ -278,6 +278,10 @@ def transform
|
||||
check aux1
|
||||
let origAltTypes ← inferArgumentTypesN matcherApp.alts.size aux1
|
||||
|
||||
-- We replace the matcher with the splitter
|
||||
let matchEqns ← Match.getEquationsFor matcherApp.matcherName
|
||||
let splitter := matchEqns.splitterName
|
||||
|
||||
let aux2 := mkAppN (mkConst splitter matcherLevels.toList) params'
|
||||
let aux2 := mkApp aux2 motive'
|
||||
let aux2 := mkAppN aux2 discrs'
|
||||
|
||||
@@ -8,7 +8,6 @@ prelude
|
||||
import Lean.Meta.Basic
|
||||
import Lean.Meta.Match.MatcherApp.Transform
|
||||
import Lean.Meta.Check
|
||||
import Lean.Meta.Tactic.Cleanup
|
||||
import Lean.Meta.Tactic.Subst
|
||||
import Lean.Meta.Injective -- for elimOptParam
|
||||
import Lean.Meta.ArgsPacker
|
||||
@@ -402,19 +401,51 @@ def assertIHs (vals : Array Expr) (mvarid : MVarId) : MetaM MVarId := do
|
||||
mvarid ← mvarid.assert (.mkSimple s!"ih{i+1}") (← inferType v) v
|
||||
return mvarid
|
||||
|
||||
|
||||
/--
|
||||
Substitutes equations, but makes sure to only substitute variables introduced after the motives
|
||||
(given by the index) as the motive could depend on anything before, and `substVar` would happily
|
||||
drop equations about these fixed parameters.
|
||||
Goal cleanup:
|
||||
Substitutes equations (with `substVar`) to remove superfluous varialbes, and clears unused
|
||||
let bindings.
|
||||
|
||||
Substitutes from the outside in so that the inner-bound variable name wins, but does a first pass
|
||||
looking only at variables with names with macro scope, so that preferably they disappear.
|
||||
|
||||
Careful to only touch the context after the motives (given by the index) as the motive could depend
|
||||
on anything before, and `substVar` would happily drop equations about these fixed parameters.
|
||||
-/
|
||||
def substVarAfter (mvarId : MVarId) (index : Nat) : MetaM MVarId := do
|
||||
mvarId.withContext do
|
||||
let mut mvarId := mvarId
|
||||
for localDecl in (← getLCtx) do
|
||||
if localDecl.index > index then
|
||||
mvarId ← trySubstVar mvarId localDecl.fvarId
|
||||
return mvarId
|
||||
partial def cleanupAfter (mvarId : MVarId) (index : Nat) : MetaM MVarId := do
|
||||
let mvarId ← go mvarId index true
|
||||
let mvarId ← go mvarId index false
|
||||
return mvarId
|
||||
where
|
||||
go (mvarId : MVarId) (index : Nat) (firstPass : Bool) : MetaM MVarId := do
|
||||
if let some mvarId ← cleanupAfter? mvarId index firstPass then
|
||||
go mvarId index firstPass
|
||||
else
|
||||
return mvarId
|
||||
|
||||
allHeqToEq (mvarId : MVarId) (index : Nat) : MetaM MVarId :=
|
||||
mvarId.withContext do
|
||||
let mut mvarId := mvarId
|
||||
for localDecl in (← getLCtx) do
|
||||
if localDecl.index > index then
|
||||
let (_, mvarId') ← heqToEq mvarId localDecl.fvarId
|
||||
mvarId := mvarId'
|
||||
return mvarId
|
||||
|
||||
cleanupAfter? (mvarId : MVarId) (index : Nat) (firstPass : Bool) : MetaM (Option MVarId) := do
|
||||
mvarId.withContext do
|
||||
for localDecl in (← getLCtx) do
|
||||
if localDecl.index > index && (!firstPass || localDecl.userName.hasMacroScopes) then
|
||||
if localDecl.isLet then
|
||||
if let some mvarId' ← observing? <| mvarId.clear localDecl.fvarId then
|
||||
return some mvarId'
|
||||
if let some mvarId' ← substVar? mvarId localDecl.fvarId then
|
||||
-- After substituting, some HEq might turn into Eqs, and we want to be able to substitute
|
||||
-- them as well
|
||||
let mvarId' ← allHeqToEq mvarId' index
|
||||
return some mvarId'
|
||||
return none
|
||||
|
||||
|
||||
/--
|
||||
Second helper monad collecting the cases as mvars
|
||||
@@ -429,7 +460,7 @@ def M2.branch {α} (act : M2 α) : M2 α :=
|
||||
|
||||
|
||||
/-- Base case of `buildInductionBody`: Construct a case for the final induction hypthesis. -/
|
||||
def buildInductionCase (oldIH newIH : FVarId) (isRecCall : Expr → Option Expr) (toClear toPreserve : Array FVarId)
|
||||
def buildInductionCase (oldIH newIH : FVarId) (isRecCall : Expr → Option Expr) (toClear : Array FVarId)
|
||||
(goal : Expr) (e : Expr) : M2 Expr := do
|
||||
let _e' ← foldAndCollect oldIH newIH isRecCall e
|
||||
let IHs : Array Expr ← M.ask
|
||||
@@ -438,9 +469,9 @@ 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)
|
||||
modify (·.push mvarId)
|
||||
let mvar ← instantiateMVars mvar
|
||||
pure mvar
|
||||
@@ -455,7 +486,7 @@ Like `mkLambdaFVars (usedOnly := true)`, but
|
||||
The result `r` can be applied with `r.beta (maskArray mask args)`.
|
||||
|
||||
We use this when generating the functional induction principle to refine the goal through a `match`,
|
||||
here `xs` are the discriminans of the `match`.
|
||||
here `xs` are the discriminants of the `match`.
|
||||
We do not expect non-trivial discriminants to appear in the goal (and if they do, the user will
|
||||
get a helpful equality into the context).
|
||||
-/
|
||||
@@ -485,7 +516,7 @@ Builds an expression of type `goal` by replicating the expression `e` into its t
|
||||
where it calls `buildInductionCase`. Collects the cases of the final induction hypothesis
|
||||
as `MVars` as it goes.
|
||||
-/
|
||||
partial def buildInductionBody (toClear toPreserve : Array FVarId) (goal : Expr)
|
||||
partial def buildInductionBody (toClear : Array FVarId) (goal : Expr)
|
||||
(oldIH newIH : FVarId) (isRecCall : Expr → Option Expr) (e : Expr) : M2 Expr := do
|
||||
|
||||
-- if-then-else cause case split:
|
||||
@@ -494,10 +525,10 @@ partial def buildInductionBody (toClear toPreserve : Array FVarId) (goal : Expr)
|
||||
let c' ← foldAndCollect oldIH newIH isRecCall c
|
||||
let h' ← foldAndCollect oldIH newIH isRecCall h
|
||||
let t' ← withLocalDecl `h .default c' fun h => M2.branch do
|
||||
let t' ← buildInductionBody toClear (toPreserve.push h.fvarId!) goal oldIH newIH isRecCall t
|
||||
let t' ← buildInductionBody toClear goal oldIH newIH isRecCall t
|
||||
mkLambdaFVars #[h] t'
|
||||
let f' ← withLocalDecl `h .default (mkNot c') fun h => M2.branch do
|
||||
let f' ← buildInductionBody toClear (toPreserve.push h.fvarId!) goal oldIH newIH isRecCall f
|
||||
let f' ← buildInductionBody toClear goal oldIH newIH isRecCall f
|
||||
mkLambdaFVars #[h] f'
|
||||
let u ← getLevel goal
|
||||
return mkApp5 (mkConst ``dite [u]) goal c' h' t' f'
|
||||
@@ -506,11 +537,11 @@ partial def buildInductionBody (toClear toPreserve : Array FVarId) (goal : Expr)
|
||||
let h' ← foldAndCollect oldIH newIH isRecCall h
|
||||
let t' ← withLocalDecl `h .default c' fun h => M2.branch do
|
||||
let t ← instantiateLambda t #[h]
|
||||
let t' ← buildInductionBody toClear (toPreserve.push h.fvarId!) goal oldIH newIH isRecCall t
|
||||
let t' ← buildInductionBody toClear goal oldIH newIH isRecCall t
|
||||
mkLambdaFVars #[h] t'
|
||||
let f' ← withLocalDecl `h .default (mkNot c') fun h => M2.branch do
|
||||
let f ← instantiateLambda f #[h]
|
||||
let f' ← buildInductionBody toClear (toPreserve.push h.fvarId!) goal oldIH newIH isRecCall f
|
||||
let f' ← buildInductionBody toClear goal oldIH newIH isRecCall f
|
||||
mkLambdaFVars #[h] f'
|
||||
let u ← getLevel goal
|
||||
return mkApp5 (mkConst ``dite [u]) goal c' h' t' f'
|
||||
@@ -521,8 +552,8 @@ partial def buildInductionBody (toClear toPreserve : Array FVarId) (goal : Expr)
|
||||
match_expr goal with
|
||||
| And goal₁ goal₂ => match_expr e with
|
||||
| PProd.mk _α _β e₁ e₂ =>
|
||||
let e₁' ← buildInductionBody toClear toPreserve goal₁ oldIH newIH isRecCall e₁
|
||||
let e₂' ← buildInductionBody toClear toPreserve goal₂ oldIH newIH isRecCall e₂
|
||||
let e₁' ← buildInductionBody toClear goal₁ oldIH newIH isRecCall e₁
|
||||
let e₂' ← buildInductionBody toClear goal₂ oldIH newIH isRecCall e₂
|
||||
return mkApp4 (.const ``And.intro []) goal₁ goal₂ e₁' e₂'
|
||||
| _ =>
|
||||
throwError "Goal is PProd, but expression is:{indentExpr e}"
|
||||
@@ -541,14 +572,14 @@ partial def buildInductionBody (toClear toPreserve : Array FVarId) (goal : Expr)
|
||||
-- so we need to replace that IH
|
||||
if matcherApp.remaining.size == 1 && matcherApp.remaining[0]!.isFVarOf oldIH then
|
||||
let matcherApp' ← matcherApp.transform (useSplitter := true)
|
||||
(addEqualities := mask.map not)
|
||||
(addEqualities := true)
|
||||
(onParams := (foldAndCollect oldIH newIH isRecCall ·))
|
||||
(onMotive := fun xs _body => pure (absMotiveBody.beta (maskArray mask xs)))
|
||||
(onAlt := fun expAltType alt => M2.branch do
|
||||
removeLamda alt fun oldIH' alt => do
|
||||
forallBoundedTelescope expAltType (some 1) fun newIH' goal' => do
|
||||
let #[newIH'] := newIH' | unreachable!
|
||||
let alt' ← buildInductionBody (toClear.push newIH'.fvarId!) toPreserve goal' oldIH' newIH'.fvarId! isRecCall alt
|
||||
let alt' ← buildInductionBody (toClear.push newIH'.fvarId!) goal' oldIH' newIH'.fvarId! isRecCall alt
|
||||
mkLambdaFVars #[newIH'] alt')
|
||||
(onRemaining := fun _ => pure #[.fvar newIH])
|
||||
return matcherApp'.toExpr
|
||||
@@ -560,32 +591,34 @@ partial def buildInductionBody (toClear toPreserve : Array FVarId) (goal : Expr)
|
||||
let (mask, absMotiveBody) ← mkLambdaFVarsMasked matcherApp.discrs goal
|
||||
|
||||
let matcherApp' ← matcherApp.transform (useSplitter := true)
|
||||
(addEqualities := mask.map not)
|
||||
(addEqualities := true)
|
||||
(onParams := (foldAndCollect oldIH newIH isRecCall ·))
|
||||
(onMotive := fun xs _body => pure (absMotiveBody.beta (maskArray mask xs)))
|
||||
(onAlt := fun expAltType alt => M2.branch do
|
||||
buildInductionBody toClear toPreserve expAltType oldIH newIH isRecCall alt)
|
||||
buildInductionBody toClear expAltType oldIH newIH isRecCall alt)
|
||||
return matcherApp'.toExpr
|
||||
|
||||
if let .letE n t v b _ := e then
|
||||
let t' ← foldAndCollect oldIH newIH isRecCall t
|
||||
let v' ← foldAndCollect oldIH newIH isRecCall v
|
||||
return ← withLetDecl n t' v' fun x => M2.branch do
|
||||
let b' ← buildInductionBody toClear toPreserve goal oldIH newIH isRecCall (b.instantiate1 x)
|
||||
let b' ← buildInductionBody toClear goal oldIH newIH isRecCall (b.instantiate1 x)
|
||||
mkLetFVars #[x] b'
|
||||
|
||||
if let some (n, t, v, b) := e.letFun? then
|
||||
let t' ← foldAndCollect oldIH newIH isRecCall t
|
||||
let v' ← foldAndCollect oldIH newIH isRecCall v
|
||||
return ← withLocalDecl n .default t' fun x => M2.branch do
|
||||
let b' ← buildInductionBody toClear toPreserve goal oldIH newIH isRecCall (b.instantiate1 x)
|
||||
let b' ← buildInductionBody toClear goal oldIH newIH isRecCall (b.instantiate1 x)
|
||||
mkLetFun x v' b'
|
||||
|
||||
liftM <| buildInductionCase oldIH newIH isRecCall toClear toPreserve goal e
|
||||
liftM <| buildInductionCase oldIH newIH isRecCall toClear goal e
|
||||
|
||||
/--
|
||||
Given an expression `e` with metavariables
|
||||
* collects all these meta-variables,
|
||||
Given an expression `e` with metavariables `mvars`
|
||||
* performs more cleanup:
|
||||
* removes unused let-expressions after index `index`
|
||||
* tries to substitute variables after index `index`
|
||||
* lifts them to the current context by reverting all local declarations after index `index`
|
||||
* introducing a local variable for each of the meta variable
|
||||
* assigning that local variable to the mvar
|
||||
@@ -603,7 +636,7 @@ do not handle delayed assignemnts correctly.
|
||||
def abstractIndependentMVars (mvars : Array MVarId) (index : Nat) (e : Expr) : MetaM Expr := do
|
||||
trace[Meta.FunInd] "abstractIndependentMVars, to revert after {index}, original mvars: {mvars}"
|
||||
let mvars ← mvars.mapM fun mvar => do
|
||||
let mvar ← substVarAfter mvar index
|
||||
let mvar ← cleanupAfter mvar index
|
||||
mvar.withContext do
|
||||
let fvarIds := (← getLCtx).foldl (init := #[]) (start := index+1) fun fvarIds decl => fvarIds.push decl.fvarId
|
||||
let (_, mvar) ← mvar.revert fvarIds
|
||||
@@ -660,7 +693,7 @@ def deriveUnaryInduction (name : Name) : MetaM Name := do
|
||||
let body ← instantiateLambda body targets
|
||||
removeLamda body fun oldIH body => do
|
||||
let body ← instantiateLambda body extraParams
|
||||
let body' ← buildInductionBody #[genIH.fvarId!] #[] goal oldIH genIH.fvarId! isRecCall body
|
||||
let body' ← buildInductionBody #[genIH.fvarId!] goal oldIH genIH.fvarId! isRecCall body
|
||||
if body'.containsFVar oldIH then
|
||||
throwError m!"Did not fully eliminate {mkFVar oldIH} from induction principle body:{indentExpr body}"
|
||||
mkLambdaFVars (targets.push genIH) (← mkLambdaFVars extraParams body')
|
||||
@@ -970,7 +1003,7 @@ def deriveInductionStructural (names : Array Name) (numFixed : Nat) : MetaM Unit
|
||||
removeLamda body fun oldIH body => do
|
||||
trace[Meta.FunInd] "replacing {Expr.fvar oldIH} with {genIH}"
|
||||
let body ← instantiateLambda body extraParams
|
||||
let body' ← buildInductionBody #[genIH.fvarId!] #[] goal oldIH genIH.fvarId! isRecCall body
|
||||
let body' ← buildInductionBody #[genIH.fvarId!] goal oldIH genIH.fvarId! isRecCall body
|
||||
if body'.containsFVar oldIH then
|
||||
throwError m!"Did not fully eliminate {mkFVar oldIH} from induction principle body:{indentExpr body}"
|
||||
mkLambdaFVars (targets.push genIH) (← mkLambdaFVars extraParams body')
|
||||
|
||||
@@ -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"
|
||||
@@ -450,6 +451,15 @@ def withAnonymousAntiquot := leading_parser
|
||||
@[builtin_term_parser] def «trailing_parser» := leading_parser:leadPrec
|
||||
"trailing_parser" >> optExprPrecedence >> optExprPrecedence >> ppSpace >> termParser
|
||||
|
||||
/--
|
||||
Indicates that an argument to a function marked `@[extern]` is borrowed.
|
||||
|
||||
Being borrowed only affects the ABI and runtime behavior of the function when compiled or interpreted. From the perspective of Lean's type system, this annotation has no effect. It similarly has no effect on functions not marked `@[extern]`.
|
||||
|
||||
When a function argument is borrowed, the function does not consume the value. This means that the function will not decrement the value's reference count or deallocate it, and the caller is responsible for doing so.
|
||||
|
||||
Please see https://lean-lang.org/lean4/doc/dev/ffi.html#borrowing for a complete description.
|
||||
-/
|
||||
@[builtin_term_parser] def borrowed := leading_parser
|
||||
"@& " >> termParser leadPrec
|
||||
/-- A literal of type `Name`. -/
|
||||
@@ -497,7 +507,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 +566,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 +580,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 +617,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 +636,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 +650,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]
|
||||
@@ -752,7 +763,7 @@ We use them to implement `macro_rules` and `elab_rules`
|
||||
def namedArgument := leading_parser (withAnonymousAntiquot := false)
|
||||
atomic ("(" >> ident >> " := ") >> withoutPosition termParser >> ")"
|
||||
def ellipsis := leading_parser (withAnonymousAntiquot := false)
|
||||
".." >> notFollowedBy "." "`.` immediately after `..`"
|
||||
".." >> notFollowedBy (checkNoWsBefore >> ".") "`.` immediately after `..`"
|
||||
def argument :=
|
||||
checkWsBefore "expected space" >>
|
||||
checkColGt "expected to be indented" >>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -666,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)
|
||||
@@ -675,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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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⟩
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 => (!· || ·)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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'
|
||||
|
||||
@@ -219,7 +219,7 @@ def performRupAdd {n : Nat} (f : DefaultFormula n) (c : DefaultClause n) (rupHin
|
||||
let (f, derivedLits, derivedEmpty, encounteredError) := performRupCheck f rupHints
|
||||
if encounteredError then
|
||||
(f, false)
|
||||
else if not derivedEmpty then
|
||||
else if !derivedEmpty then
|
||||
(f, false)
|
||||
else -- derivedEmpty is true and encounteredError is false
|
||||
let ⟨clauses, rupUnits, ratUnits, assignments⟩ := f
|
||||
@@ -284,7 +284,7 @@ def performRatCheck {n : Nat} (f : DefaultFormula n) (negPivot : Literal (PosFin
|
||||
-- assignments should now be the same as it was before the performRupCheck call
|
||||
let f := clearRatUnits ⟨clauses, rupUnits, ratUnits, assignments⟩
|
||||
-- f should now be the same as it was before insertRatUnits
|
||||
if encounteredError || not derivedEmpty then (f, false)
|
||||
if encounteredError || !derivedEmpty then (f, false)
|
||||
else (f, true)
|
||||
| none => (⟨clauses, rupUnits, ratUnits, assignments⟩, false)
|
||||
|
||||
@@ -309,7 +309,7 @@ def performRatAdd {n : Nat} (f : DefaultFormula n) (c : DefaultClause n)
|
||||
if allChecksPassed then performRatCheck f (Literal.negate pivot) ratHint
|
||||
else (f, false)
|
||||
let (f, allChecksPassed) := ratHints.foldl fold_fn (f, true)
|
||||
if not allChecksPassed then (f, false)
|
||||
if !allChecksPassed then (f, false)
|
||||
else
|
||||
match f with
|
||||
| ⟨clauses, rupUnits, ratUnits, assignments⟩ =>
|
||||
|
||||
@@ -507,8 +507,8 @@ theorem deleteOne_preserves_strongAssignmentsInvariant {n : Nat} (f : DefaultFor
|
||||
Fin.eta, Array.get_eq_getElem, Array.getElem_eq_toList_getElem, decidableGetElem?] at heq
|
||||
rw [hidx, hl] at heq
|
||||
simp only [unit, Option.some.injEq, DefaultClause.mk.injEq, List.cons.injEq, and_true] at heq
|
||||
simp only [← heq, not] at l_ne_b
|
||||
split at l_ne_b <;> simp at l_ne_b
|
||||
simp only [← heq] at l_ne_b
|
||||
simp at l_ne_b
|
||||
· next id_ne_idx => simp [id_ne_idx]
|
||||
· exact hf
|
||||
· exact Or.inr hf
|
||||
|
||||
@@ -57,8 +57,8 @@ theorem entails_of_irrelevant_assignment {n : Nat} {p : (PosFin n) → Bool} {c
|
||||
· simp [Clause.toList, delete_iff, negl_ne_v, v_in_c_del_l]
|
||||
· split
|
||||
· next heq =>
|
||||
simp only [heq, Literal.negate, not, ne_eq, Prod.mk.injEq, true_and] at negl_ne_v
|
||||
split at negl_ne_v <;> simp_all
|
||||
simp only [heq, Literal.negate, ne_eq, Prod.mk.injEq, true_and] at negl_ne_v
|
||||
simp_all
|
||||
· next hne =>
|
||||
exact pv
|
||||
· exists v
|
||||
@@ -67,8 +67,8 @@ theorem entails_of_irrelevant_assignment {n : Nat} {p : (PosFin n) → Bool} {c
|
||||
· simp [Clause.toList, delete_iff, negl_ne_v, v_in_c_del_l]
|
||||
· split
|
||||
· next heq =>
|
||||
simp only [heq, Literal.negate, not, ne_eq, Prod.mk.injEq, true_and] at negl_ne_v
|
||||
split at negl_ne_v <;> simp_all
|
||||
simp only [heq, Literal.negate, ne_eq, Prod.mk.injEq, true_and] at negl_ne_v
|
||||
simp_all
|
||||
· next hne =>
|
||||
exact pv
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ theorem or_congr (lhs rhs lhs' rhs' : Bool) (h1 : lhs' = lhs) (h2 : rhs' = rhs)
|
||||
simp[*]
|
||||
|
||||
theorem xor_congr (lhs rhs lhs' rhs' : Bool) (h1 : lhs' = lhs) (h2 : rhs' = rhs) :
|
||||
(xor lhs' rhs') = (xor lhs rhs) := by
|
||||
(Bool.xor lhs' rhs') = (xor lhs rhs) := by
|
||||
simp[*]
|
||||
|
||||
theorem beq_congr (lhs rhs lhs' rhs' : Bool) (h1 : lhs' = lhs) (h2 : rhs' = rhs) :
|
||||
|
||||
BIN
stage0/stdlib/Init/Control/Basic.c
generated
BIN
stage0/stdlib/Init/Control/Basic.c
generated
Binary file not shown.
BIN
stage0/stdlib/Init/Control/Lawful/Basic.c
generated
BIN
stage0/stdlib/Init/Control/Lawful/Basic.c
generated
Binary file not shown.
BIN
stage0/stdlib/Init/Core.c
generated
BIN
stage0/stdlib/Init/Core.c
generated
Binary file not shown.
BIN
stage0/stdlib/Init/Data/Array/Basic.c
generated
BIN
stage0/stdlib/Init/Data/Array/Basic.c
generated
Binary file not shown.
BIN
stage0/stdlib/Init/Data/BitVec/Basic.c
generated
BIN
stage0/stdlib/Init/Data/BitVec/Basic.c
generated
Binary file not shown.
BIN
stage0/stdlib/Init/Data/Bool.c
generated
BIN
stage0/stdlib/Init/Data/Bool.c
generated
Binary file not shown.
BIN
stage0/stdlib/Init/Data/Int/DivMod.c
generated
BIN
stage0/stdlib/Init/Data/Int/DivMod.c
generated
Binary file not shown.
BIN
stage0/stdlib/Init/Data/Int/DivModLemmas.c
generated
BIN
stage0/stdlib/Init/Data/Int/DivModLemmas.c
generated
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user