mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-20 03:44:10 +00:00
Compare commits
30 Commits
array_repl
...
disable-as
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26611b153b | ||
|
|
727c696d9f | ||
|
|
cf2b7f4c1b | ||
|
|
cd4383b6f3 | ||
|
|
0d9859370a | ||
|
|
c292ae2e0e | ||
|
|
3113847806 | ||
|
|
d275455674 | ||
|
|
a4d10742d3 | ||
|
|
777fba495a | ||
|
|
2e66341f69 | ||
|
|
2e44585ce9 | ||
|
|
e2f0e14b04 | ||
|
|
e801dc96ca | ||
|
|
56a3ac1814 | ||
|
|
6c62f720c8 | ||
|
|
a57efd0a88 | ||
|
|
7e2d6e2254 | ||
|
|
4603e1a6ad | ||
|
|
550d2918b8 | ||
|
|
eb5ad2c03a | ||
|
|
769fe4ebf6 | ||
|
|
8130fdc474 | ||
|
|
41bba59868 | ||
|
|
115f06c32a | ||
|
|
1e1e17cb35 | ||
|
|
831e8d768b | ||
|
|
b4b878b2d0 | ||
|
|
2377f35426 | ||
|
|
c7f706baeb |
@@ -25,7 +25,10 @@ cp llvm/lib/clang/*/include/{std*,__std*,limits}.h stage1/include/clang
|
||||
echo '
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-seterrormode
|
||||
#define SEM_FAILCRITICALERRORS 0x0001
|
||||
__declspec(dllimport) __stdcall unsigned int SetErrorMode(unsigned int uMode);' > stage1/include/clang/windows.h
|
||||
__declspec(dllimport) __stdcall unsigned int SetErrorMode(unsigned int uMode);
|
||||
// https://docs.microsoft.com/en-us/windows/console/setconsoleoutputcp
|
||||
#define CP_UTF8 65001
|
||||
__declspec(dllimport) __stdcall int SetConsoleOutputCP(unsigned int wCodePageID);' > stage1/include/clang/windows.h
|
||||
# COFF dependencies
|
||||
cp /clang64/lib/{crtbegin,crtend,crt2,dllcrt2}.o stage1/lib/
|
||||
# runtime
|
||||
|
||||
@@ -555,6 +555,10 @@ def unattach {α : Type _} {p : α → Prop} (xs : Array { x // p x }) : Array
|
||||
(xs.push a).unattach = xs.unattach.push a.1 := by
|
||||
simp only [unattach, Array.map_push]
|
||||
|
||||
@[simp] theorem mem_unattach {p : α → Prop} {xs : Array { x // p x }} {a} :
|
||||
a ∈ xs.unattach ↔ ∃ h : p a, ⟨a, h⟩ ∈ xs := by
|
||||
simp only [unattach, mem_map, Subtype.exists, exists_and_right, exists_eq_right]
|
||||
|
||||
@[simp] theorem size_unattach {p : α → Prop} {xs : Array { x // p x }} :
|
||||
xs.unattach.size = xs.size := by
|
||||
unfold unattach
|
||||
@@ -676,6 +680,20 @@ and simplifies these to the function directly taking the value.
|
||||
simp
|
||||
rw [List.find?_subtype hf]
|
||||
|
||||
@[simp] theorem all_subtype {p : α → Prop} {xs : Array { x // p x }} {f : { x // p x } → Bool} {g : α → Bool}
|
||||
(hf : ∀ x h, f ⟨x, h⟩ = g x) (w : stop = xs.size) :
|
||||
xs.all f 0 stop = xs.unattach.all g := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [hf]
|
||||
|
||||
@[simp] theorem any_subtype {p : α → Prop} {xs : Array { x // p x }} {f : { x // p x } → Bool} {g : α → Bool}
|
||||
(hf : ∀ x h, f ⟨x, h⟩ = g x) (w : stop = xs.size) :
|
||||
xs.any f 0 stop = xs.unattach.any g := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [hf]
|
||||
|
||||
/-! ### Simp lemmas pushing `unattach` inwards. -/
|
||||
|
||||
@[simp] theorem unattach_filter {p : α → Prop} {xs : Array { x // p x }}
|
||||
|
||||
@@ -1689,6 +1689,7 @@ theorem getElem_append {xs ys : Array α} (h : i < (xs ++ ys).size) :
|
||||
cases xs; cases ys
|
||||
simp [List.getElem_append]
|
||||
|
||||
@[simp]
|
||||
theorem getElem_append_left {xs ys : Array α} {h : i < (xs ++ ys).size} (hlt : i < xs.size) :
|
||||
(xs ++ ys)[i] = xs[i] := by
|
||||
simp only [← getElem_toList]
|
||||
@@ -1696,6 +1697,7 @@ theorem getElem_append_left {xs ys : Array α} {h : i < (xs ++ ys).size} (hlt :
|
||||
conv => rhs; rw [← List.getElem_append_left (bs := ys.toList) (h' := h')]
|
||||
apply List.get_of_eq; rw [toList_append]
|
||||
|
||||
@[simp]
|
||||
theorem getElem_append_right {xs ys : Array α} {h : i < (xs ++ ys).size} (hle : xs.size ≤ i) :
|
||||
(xs ++ ys)[i] = ys[i - xs.size]'(Nat.sub_lt_left_of_lt_add hle (size_append .. ▸ h)) := by
|
||||
simp only [← getElem_toList]
|
||||
@@ -2435,6 +2437,12 @@ theorem getElem?_swap (xs : Array α) (i j : Nat) (hi hj) (k : Nat) : (xs.swap i
|
||||
cases xs
|
||||
simp
|
||||
|
||||
theorem getElem_eq_getElem_reverse {xs : Array α} {i} (h : i < xs.size) :
|
||||
xs[i] = xs.reverse[xs.size - 1 - i]'(by simpa using Nat.sub_one_sub_lt_of_lt h) := by
|
||||
rw [getElem_reverse]
|
||||
congr
|
||||
omega
|
||||
|
||||
@[simp] theorem reverse_eq_empty_iff {xs : Array α} : xs.reverse = #[] ↔ xs = #[] := by
|
||||
cases xs
|
||||
simp
|
||||
@@ -3496,6 +3504,239 @@ theorem replace_extract {xs : Array α} {i : Nat} :
|
||||
|
||||
end replace
|
||||
|
||||
/-! ## Logic -/
|
||||
|
||||
/-! ### any / all -/
|
||||
|
||||
theorem not_any_eq_all_not (xs : Array α) (p : α → Bool) : (!xs.any p) = xs.all fun a => !p a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.not_any_eq_all_not]
|
||||
|
||||
theorem not_all_eq_any_not (xs : Array α) (p : α → Bool) : (!xs.all p) = xs.any fun a => !p a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.not_all_eq_any_not]
|
||||
|
||||
theorem and_any_distrib_left (xs : Array α) (p : α → Bool) (q : Bool) :
|
||||
(q && xs.any p) = xs.any fun a => q && p a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.and_any_distrib_left]
|
||||
|
||||
theorem and_any_distrib_right (xs : Array α) (p : α → Bool) (q : Bool) :
|
||||
(xs.any p && q) = xs.any fun a => p a && q := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.and_any_distrib_right]
|
||||
|
||||
theorem or_all_distrib_left (xs : Array α) (p : α → Bool) (q : Bool) :
|
||||
(q || xs.all p) = xs.all fun a => q || p a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.or_all_distrib_left]
|
||||
|
||||
theorem or_all_distrib_right (xs : Array α) (p : α → Bool) (q : Bool) :
|
||||
(xs.all p || q) = xs.all fun a => p a || q := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.or_all_distrib_right]
|
||||
|
||||
theorem any_eq_not_all_not (xs : Array α) (p : α → Bool) : xs.any p = !xs.all (!p .) := by
|
||||
simp only [not_all_eq_any_not, Bool.not_not]
|
||||
|
||||
/-- Variant of `any_map` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem any_map' {xs : Array α} {p : β → Bool} (w : stop = xs.size):
|
||||
(xs.map f).any p 0 stop = xs.any (p ∘ f) := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
rw [List.map_toArray]
|
||||
simp [List.any_map]
|
||||
|
||||
/-- Variant of `all_map` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem all_map' {xs : Array α} {p : β → Bool} (w : stop = xs.size):
|
||||
(xs.map f).all p 0 stop = xs.all (p ∘ f) := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
rw [List.map_toArray]
|
||||
simp [List.all_map]
|
||||
|
||||
theorem any_map {xs : Array α} {p : β → Bool} : (xs.map f).any p = xs.any (p ∘ f) := by
|
||||
simp
|
||||
|
||||
theorem all_map {xs : Array α} {p : β → Bool} : (xs.map f).all p = xs.all (p ∘ f) := by
|
||||
simp
|
||||
|
||||
/-- Variant of `any_filter` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem any_filter' {xs : Array α} {p q : α → Bool} (w : stop = (xs.filter p).size) :
|
||||
(xs.filter p).any q 0 stop = xs.any fun a => p a && q a := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
rw [List.filter_toArray]
|
||||
simp [List.any_filter]
|
||||
|
||||
/-- Variant of `all_filter` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem all_filter' {xs : Array α} {p q : α → Bool} (w : stop = (xs.filter p).size) :
|
||||
(xs.filter p).all q 0 stop = xs.all fun a => p a → q a := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
rw [List.filter_toArray]
|
||||
simp [List.all_filter]
|
||||
|
||||
theorem any_filter {xs : Array α} {p q : α → Bool} :
|
||||
(xs.filter p).any q 0 = xs.any fun a => p a && q a := by
|
||||
simp
|
||||
|
||||
theorem all_filter {xs : Array α} {p q : α → Bool} :
|
||||
(xs.filter p).all q 0 = xs.all fun a => p a → q a := by
|
||||
simp
|
||||
|
||||
/-- Variant of `any_filterMap` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem any_filterMap' {xs : Array α} {f : α → Option β} {p : β → Bool} (w : stop = (xs.filterMap f).size) :
|
||||
(xs.filterMap f).any p 0 stop = xs.any fun a => match f a with | some b => p b | none => false := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
rw [List.filterMap_toArray]
|
||||
simp [List.any_filterMap]
|
||||
rfl
|
||||
|
||||
/-- Variant of `all_filterMap` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem all_filterMap' {xs : Array α} {f : α → Option β} {p : β → Bool} (w : stop = (xs.filterMap f).size) :
|
||||
(xs.filterMap f).all p 0 stop = xs.all fun a => match f a with | some b => p b | none => true := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
rw [List.filterMap_toArray]
|
||||
simp [List.all_filterMap]
|
||||
rfl
|
||||
|
||||
theorem any_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
|
||||
(xs.filterMap f).any p 0 = xs.any fun a => match f a with | some b => p b | none => false := by
|
||||
simp
|
||||
|
||||
theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
|
||||
(xs.filterMap f).all p 0 = xs.all fun a => match f a with | some b => p b | none => true := by
|
||||
simp
|
||||
|
||||
/-- Variant of `any_append` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem any_append' {xs ys : Array α} (w : stop = (xs ++ ys).size) :
|
||||
(xs ++ ys).any f 0 stop = (xs.any f || ys.any f) := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
rw [List.append_toArray]
|
||||
simp [List.any_append]
|
||||
|
||||
/-- Variant of `all_append` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem all_append' {xs ys : Array α} (w : stop = (xs ++ ys).size) :
|
||||
(xs ++ ys).all f 0 stop = (xs.all f && ys.all f) := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
rw [List.append_toArray]
|
||||
simp [List.all_append]
|
||||
|
||||
theorem any_append {xs ys : Array α} :
|
||||
(xs ++ ys).any f 0 = (xs.any f || ys.any f) := by
|
||||
simp
|
||||
|
||||
theorem all_append {xs ys : Array α} :
|
||||
(xs ++ ys).all f 0 = (xs.all f && ys.all f) := by
|
||||
simp
|
||||
|
||||
@[congr] theorem anyM_congr [Monad m]
|
||||
{xs ys : Array α} (w : xs = ys) {p q : α → m Bool} (h : ∀ a, p a = q a) (wstart : start₁ = start₂) (wstop : stop₁ = stop₂) :
|
||||
xs.anyM p start₁ stop₁ = ys.anyM q start₂ stop₂ := by
|
||||
have : p = q := by funext a; apply h
|
||||
subst this
|
||||
subst w
|
||||
subst wstart
|
||||
subst wstop
|
||||
rfl
|
||||
|
||||
@[congr] theorem any_congr
|
||||
{xs ys : Array α} (w : xs = ys) {p q : α → Bool} (h : ∀ a, p a = q a) (wstart : start₁ = start₂) (wstop : stop₁ = stop₂) :
|
||||
xs.any p start₁ stop₁ = ys.any q start₂ stop₂ := by
|
||||
unfold any
|
||||
apply anyM_congr w h wstart wstop
|
||||
|
||||
@[congr] theorem allM_congr [Monad m]
|
||||
{xs ys : Array α} (w : xs = ys) {p q : α → m Bool} (h : ∀ a, p a = q a) (wstart : start₁ = start₂) (wstop : stop₁ = stop₂) :
|
||||
xs.allM p start₁ stop₁ = ys.allM q start₂ stop₂ := by
|
||||
have : p = q := by funext a; apply h
|
||||
subst this
|
||||
subst w
|
||||
subst wstart
|
||||
subst wstop
|
||||
rfl
|
||||
|
||||
@[congr] theorem all_congr
|
||||
{xs ys : Array α} (w : xs = ys) {p q : α → Bool} (h : ∀ a, p a = q a) (wstart : start₁ = start₂) (wstop : stop₁ = stop₂) :
|
||||
xs.all p start₁ stop₁ = ys.all q start₂ stop₂ := by
|
||||
unfold all
|
||||
apply allM_congr w h wstart wstop
|
||||
|
||||
@[simp] theorem any_flatten' {xss : Array (Array α)} (w : stop = xss.flatten.size) : xss.flatten.any f 0 stop = xss.any (any · f) := by
|
||||
subst w
|
||||
cases xss using array₂_induction
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[simp] theorem all_flatten' {xss : Array (Array α)} (w : stop = xss.flatten.size) : xss.flatten.all f 0 stop = xss.all (all · f) := by
|
||||
subst w
|
||||
cases xss using array₂_induction
|
||||
simp [Function.comp_def]
|
||||
|
||||
theorem any_flatten {xss : Array (Array α)} : xss.flatten.any f = xss.any (any · f) := by
|
||||
simp
|
||||
|
||||
theorem all_flatten {xss : Array (Array α)} : xss.flatten.all f = xss.all (all · f) := by
|
||||
simp
|
||||
|
||||
/-- Variant of `any_flatMap` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem any_flatMap' {xs : Array α} {f : α → Array β} {p : β → Bool} (w : stop = (xs.flatMap f).size) :
|
||||
(xs.flatMap f).any p 0 stop = xs.any fun a => (f a).any p := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
rw [List.flatMap_toArray]
|
||||
simp [List.any_flatMap]
|
||||
|
||||
/-- Variant of `all_flatMap` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem all_flatMap' {xs : Array α} {f : α → Array β} {p : β → Bool} (w : stop = (xs.flatMap f).size) :
|
||||
(xs.flatMap f).all p 0 stop = xs.all fun a => (f a).all p := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
rw [List.flatMap_toArray]
|
||||
simp [List.all_flatMap]
|
||||
|
||||
theorem any_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
(xs.flatMap f).any p 0 = xs.any fun a => (f a).any p := by
|
||||
simp
|
||||
|
||||
theorem all_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
(xs.flatMap f).all p 0 = xs.all fun a => (f a).all p := by
|
||||
simp
|
||||
|
||||
/-- Variant of `any_reverse` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem any_reverse' {xs : Array α} (w : stop = xs.size) : xs.reverse.any f 0 stop = xs.any f := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
rw [List.reverse_toArray]
|
||||
simp [List.any_reverse]
|
||||
|
||||
/-- Variant of `all_reverse` with a side condition for the `stop` argument. -/
|
||||
@[simp] theorem all_reverse' {xs : Array α} (w : stop = xs.size) : xs.reverse.all f 0 stop = xs.all f := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
rw [List.reverse_toArray]
|
||||
simp [List.all_reverse]
|
||||
|
||||
theorem any_reverse {xs : Array α} : xs.reverse.any f 0 = xs.any f := by
|
||||
simp
|
||||
|
||||
theorem all_reverse {xs : Array α} : xs.reverse.all f 0 = xs.all f := by
|
||||
simp
|
||||
|
||||
@[simp] theorem any_mkArray {n : Nat} {a : α} :
|
||||
(mkArray n a).any f = if n = 0 then false else f a := by
|
||||
induction n <;> simp_all [mkArray_succ']
|
||||
|
||||
@[simp] theorem all_mkArray {n : Nat} {a : α} :
|
||||
(mkArray n a).all f = if n = 0 then true else f a := by
|
||||
induction n <;> simp_all +contextual [mkArray_succ']
|
||||
|
||||
/-! Content below this point has not yet been aligned with `List`. -/
|
||||
|
||||
/-! ### sum -/
|
||||
|
||||
@@ -1006,6 +1006,68 @@ theorem eq_of_core (ctx : Context) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
|
||||
intro; subst p₃; simp
|
||||
intro h; rw [h, ←Int.sub_eq_add_neg, Int.sub_self]
|
||||
|
||||
def Poly.isUnsatDiseq (p : Poly) : Bool :=
|
||||
match p with
|
||||
| .num 0 => true
|
||||
| _ => false
|
||||
|
||||
theorem diseq_norm (ctx : Context) (p₁ p₂ : Poly) (h : p₁.norm == p₂) : p₁.denote' ctx ≠ 0 → p₂.denote' ctx ≠ 0 := by
|
||||
simp at h
|
||||
replace h := congrArg (Poly.denote ctx) h
|
||||
simp at h
|
||||
simp [*]
|
||||
|
||||
theorem diseq_coeff (ctx : Context) (p p' : Poly) (k : Int) : eq_coeff_cert p p' k → p.denote' ctx ≠ 0 → p'.denote' ctx ≠ 0 := by
|
||||
simp [eq_coeff_cert]
|
||||
intro _ _; simp [mul_eq_zero_iff, *]
|
||||
|
||||
theorem diseq_unsat (ctx : Context) (p : Poly) : p.isUnsatDiseq → p.denote' ctx ≠ 0 → False := by
|
||||
simp [Poly.isUnsatDiseq] <;> split <;> simp
|
||||
|
||||
def diseq_eq_subst_cert (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
|
||||
let a := p₁.coeff x
|
||||
let b := p₂.coeff x
|
||||
a != 0 && p₃ == (p₁.mul b |>.combine (p₂.mul (-a)))
|
||||
|
||||
theorem eq_diseq_subst (ctx : Context) (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
|
||||
: diseq_eq_subst_cert x p₁ p₂ p₃ → p₁.denote' ctx = 0 → p₂.denote' ctx ≠ 0 → p₃.denote' ctx ≠ 0 := by
|
||||
simp [diseq_eq_subst_cert]
|
||||
intros _ _; subst p₃
|
||||
intro h₁ h₂
|
||||
simp [*]
|
||||
|
||||
theorem diseq_of_core (ctx : Context) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
|
||||
: eq_of_core_cert p₁ p₂ p₃ → p₁.denote' ctx ≠ p₂.denote' ctx → p₃.denote' ctx ≠ 0 := by
|
||||
simp [eq_of_core_cert]
|
||||
intro; subst p₃; simp
|
||||
intro h; rw [← Int.sub_eq_zero] at h
|
||||
rw [←Int.sub_eq_add_neg]; assumption
|
||||
|
||||
def eq_of_le_ge_cert (p₁ p₂ : Poly) : Bool :=
|
||||
p₂ == p₁.mul (-1)
|
||||
|
||||
theorem eq_of_le_ge (ctx : Context) (p₁ : Poly) (p₂ : Poly)
|
||||
: eq_of_le_ge_cert p₁ p₂ → p₁.denote' ctx ≤ 0 → p₂.denote' ctx ≤ 0 → p₁.denote' ctx = 0 := by
|
||||
simp [eq_of_le_ge_cert]
|
||||
intro; subst p₂; simp
|
||||
intro h₁ h₂
|
||||
replace h₂ := Int.neg_le_of_neg_le h₂; simp at h₂
|
||||
simp [Int.eq_iff_le_and_ge, *]
|
||||
|
||||
def le_of_le_diseq_cert (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
|
||||
-- Remark: we can generate two different certificates in the future, and avoid the `||` in the certificate.
|
||||
(p₂ == p₁ || p₂ == p₁.mul (-1)) &&
|
||||
p₃ == p₁.addConst 1
|
||||
|
||||
theorem le_of_le_diseq (ctx : Context) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
|
||||
: le_of_le_diseq_cert p₁ p₂ p₃ → p₁.denote' ctx ≤ 0 → p₂.denote' ctx ≠ 0 → p₃.denote' ctx ≤ 0 := by
|
||||
simp [le_of_le_diseq_cert]
|
||||
have (a : Int) : a ≤ 0 → ¬ a = 0 → 1 + a ≤ 0 := by
|
||||
intro h₁ h₂; cases (Int.lt_or_gt_of_ne h₂)
|
||||
next => apply Int.le_of_lt_add_one; rw [Int.add_comm, Int.add_lt_add_iff_right]; assumption
|
||||
next h => have := Int.lt_of_le_of_lt h₁ h; simp at this
|
||||
intro h; cases h <;> intro <;> subst p₂ p₃ <;> simp <;> apply this
|
||||
|
||||
end Int.Linear
|
||||
|
||||
theorem Int.not_le_eq (a b : Int) : (¬a ≤ b) = (b + 1 ≤ a) := by
|
||||
|
||||
@@ -662,6 +662,10 @@ def unattach {α : Type _} {p : α → Prop} (l : List { x // p x }) : List α :
|
||||
@[simp] theorem unattach_cons {p : α → Prop} {a : { x // p x }} {l : List { x // p x }} :
|
||||
(a :: l).unattach = a.val :: l.unattach := rfl
|
||||
|
||||
@[simp] theorem mem_unattach {p : α → Prop} {l : List { x // p x }} {a} :
|
||||
a ∈ l.unattach ↔ ∃ h : p a, ⟨a, h⟩ ∈ l := by
|
||||
simp only [unattach, mem_map, Subtype.exists, exists_and_right, exists_eq_right]
|
||||
|
||||
@[simp] theorem length_unattach {p : α → Prop} {l : List { x // p x }} :
|
||||
l.unattach.length = l.length := by
|
||||
unfold unattach
|
||||
@@ -766,6 +770,16 @@ and simplifies these to the function directly taking the value.
|
||||
simp [hf, find?_cons]
|
||||
split <;> simp [ih]
|
||||
|
||||
@[simp] theorem all_subtype {p : α → Prop} {l : List { x // p x }} {f : { x // p x } → Bool} {g : α → Bool}
|
||||
(hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
l.all f = l.unattach.all g := by
|
||||
simp [all_eq, hf]
|
||||
|
||||
@[simp] theorem any_subtype {p : α → Prop} {l : List { x // p x }} {f : { x // p x } → Bool} {g : α → Bool}
|
||||
(hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
l.any f = l.unattach.any g := by
|
||||
simp [any_eq, hf]
|
||||
|
||||
/-! ### Simp lemmas pushing `unattach` inwards. -/
|
||||
|
||||
@[simp] theorem unattach_filter {p : α → Prop} {l : List { x // p x }}
|
||||
|
||||
@@ -212,6 +212,7 @@ def mapMono (as : List α) (f : α → α) : List α :=
|
||||
|
||||
/-! ## Additional lemmas required for bootstrapping `Array`. -/
|
||||
|
||||
@[simp]
|
||||
theorem getElem_append_left {as bs : List α} (h : i < as.length) {h' : i < (as ++ bs).length} :
|
||||
(as ++ bs)[i] = as[i] := by
|
||||
induction as generalizing i with
|
||||
@@ -221,6 +222,7 @@ theorem getElem_append_left {as bs : List α} (h : i < as.length) {h' : i < (as
|
||||
| zero => rfl
|
||||
| succ i => apply ih
|
||||
|
||||
@[simp]
|
||||
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
|
||||
|
||||
@@ -11,3 +11,15 @@ import Init.Data.SInt.Basic
|
||||
@[simp] theorem UInt32.toBitVec_toInt32 (x : UInt32) : x.toInt32.toBitVec = x.toBitVec := rfl
|
||||
@[simp] theorem UInt64.toBitVec_toInt64 (x : UInt64) : x.toInt64.toBitVec = x.toBitVec := rfl
|
||||
@[simp] theorem USize.toBitVec_toISize (x : USize) : x.toISize.toBitVec = x.toBitVec := rfl
|
||||
|
||||
@[simp] theorem Int8.ofBitVec_uInt8ToBitVec (x : UInt8) : Int8.ofBitVec x.toBitVec = x.toInt8 := rfl
|
||||
@[simp] theorem Int16.ofBitVec_uInt16ToBitVec (x : UInt16) : Int16.ofBitVec x.toBitVec = x.toInt16 := rfl
|
||||
@[simp] theorem Int32.ofBitVec_uInt32ToBitVec (x : UInt32) : Int32.ofBitVec x.toBitVec = x.toInt32 := rfl
|
||||
@[simp] theorem Int64.ofBitVec_uInt64ToBitVec (x : UInt64) : Int64.ofBitVec x.toBitVec = x.toInt64 := rfl
|
||||
@[simp] theorem ISize.ofBitVec_uSize8ToBitVec (x : USize) : ISize.ofBitVec x.toBitVec = x.toISize := rfl
|
||||
|
||||
@[simp] theorem UInt8.toUInt8_toInt8 (x : UInt8) : x.toInt8.toUInt8 = x := rfl
|
||||
@[simp] theorem UInt16.toUInt16_toInt16 (x : UInt16) : x.toInt16.toUInt16 = x := rfl
|
||||
@[simp] theorem UInt32.toUInt32_toInt32 (x : UInt32) : x.toInt32.toUInt32 = x := rfl
|
||||
@[simp] theorem UInt64.toUInt64_toInt64 (x : UInt64) : x.toInt64.toUInt64 = x := rfl
|
||||
@[simp] theorem USize.toUSize_toISize (x : USize) : x.toISize.toUSize = x := rfl
|
||||
|
||||
@@ -295,6 +295,51 @@ theorem UInt16.toNat_lt_usizeSize (n : UInt16) : n.toNat < USize.size :=
|
||||
theorem UInt32.toNat_lt_usizeSize (n : UInt32) : n.toNat < USize.size :=
|
||||
Nat.lt_of_lt_of_le n.toNat_lt (by cases USize.size_eq <;> simp_all)
|
||||
|
||||
theorem UInt8.size_dvd_usizeSize : UInt8.size ∣ USize.size := by cases USize.size_eq <;> simp_all +decide
|
||||
theorem UInt16.size_dvd_usizeSize : UInt16.size ∣ USize.size := by cases USize.size_eq <;> simp_all +decide
|
||||
theorem UInt32.size_dvd_usizeSize : UInt32.size ∣ USize.size := by cases USize.size_eq <;> simp_all +decide
|
||||
theorem USize.size_dvd_uInt64Size : USize.size ∣ UInt64.size := by cases USize.size_eq <;> simp_all +decide
|
||||
|
||||
@[simp] theorem mod_usizeSize_uInt8Size (n : Nat) : n % USize.size % UInt8.size = n % UInt8.size :=
|
||||
Nat.mod_mod_of_dvd _ UInt8.size_dvd_usizeSize
|
||||
@[simp] theorem mod_usizeSize_uInt16Size (n : Nat) : n % USize.size % UInt16.size = n % UInt16.size :=
|
||||
Nat.mod_mod_of_dvd _ UInt16.size_dvd_usizeSize
|
||||
@[simp] theorem mod_usizeSize_uInt32Size (n : Nat) : n % USize.size % UInt32.size = n % UInt32.size :=
|
||||
Nat.mod_mod_of_dvd _ UInt32.size_dvd_usizeSize
|
||||
@[simp] theorem mod_uInt64Size_uSizeSize (n : Nat) : n % UInt64.size % USize.size = n % USize.size :=
|
||||
Nat.mod_mod_of_dvd _ USize.size_dvd_uInt64Size
|
||||
|
||||
@[simp] theorem UInt8.toNat_mod_size (n : UInt8) : n.toNat % UInt8.size = n.toNat := Nat.mod_eq_of_lt n.toNat_lt
|
||||
@[simp] theorem UInt8.toNat_mod_uInt16Size (n : UInt8) : n.toNat % UInt16.size = n.toNat := Nat.mod_eq_of_lt (Nat.lt_trans n.toNat_lt (by decide))
|
||||
@[simp] theorem UInt8.toNat_mod_uInt32Size (n : UInt8) : n.toNat % UInt32.size = n.toNat := Nat.mod_eq_of_lt (Nat.lt_trans n.toNat_lt (by decide))
|
||||
@[simp] theorem UInt8.toNat_mod_uInt64Size (n : UInt8) : n.toNat % UInt64.size = n.toNat := Nat.mod_eq_of_lt (Nat.lt_trans n.toNat_lt (by decide))
|
||||
@[simp] theorem UInt8.toNat_mod_uSizeSize (n : UInt8) : n.toNat % USize.size = n.toNat := Nat.mod_eq_of_lt n.toNat_lt_usizeSize
|
||||
|
||||
@[simp] theorem UInt16.toNat_mod_size (n : UInt16) : n.toNat % UInt16.size = n.toNat := Nat.mod_eq_of_lt n.toNat_lt
|
||||
@[simp] theorem UInt16.toNat_mod_uInt32Size (n : UInt16) : n.toNat % UInt32.size = n.toNat := Nat.mod_eq_of_lt (Nat.lt_trans n.toNat_lt (by decide))
|
||||
@[simp] theorem UInt16.toNat_mod_uInt64Size (n : UInt16) : n.toNat % UInt64.size = n.toNat := Nat.mod_eq_of_lt (Nat.lt_trans n.toNat_lt (by decide))
|
||||
@[simp] theorem UInt16.toNat_mod_uSizeSize (n : UInt16) : n.toNat % USize.size = n.toNat := Nat.mod_eq_of_lt n.toNat_lt_usizeSize
|
||||
|
||||
@[simp] theorem UInt32.toNat_mod_size (n : UInt32) : n.toNat % UInt32.size = n.toNat := Nat.mod_eq_of_lt n.toNat_lt
|
||||
@[simp] theorem UInt32.toNat_mod_uInt64Size (n : UInt32) : n.toNat % UInt64.size = n.toNat := Nat.mod_eq_of_lt (Nat.lt_trans n.toNat_lt (by decide))
|
||||
@[simp] theorem UInt32.toNat_mod_uSizeSize (n : UInt32) : n.toNat % USize.size = n.toNat := Nat.mod_eq_of_lt n.toNat_lt_usizeSize
|
||||
|
||||
@[simp] theorem UInt64.toNat_mod_size (n : UInt64) : n.toNat % UInt64.size = n.toNat := Nat.mod_eq_of_lt n.toNat_lt
|
||||
|
||||
@[simp] theorem USize.toNat_mod_size (n : USize) : n.toNat % USize.size = n.toNat := Nat.mod_eq_of_lt n.toNat_lt_size
|
||||
@[simp] theorem USize.toNat_mod_uInt64Size (n : USize) : n.toNat % UInt64.size = n.toNat := Nat.mod_eq_of_lt n.toNat_lt
|
||||
|
||||
@[simp] theorem UInt8.toUInt16_mod_256 (n : UInt8) : n.toUInt16 % 256 = n.toUInt16 := UInt16.toNat.inj (by simp)
|
||||
@[simp] theorem UInt8.toUInt32_mod_256 (n : UInt8) : n.toUInt32 % 256 = n.toUInt32 := UInt32.toNat.inj (by simp)
|
||||
@[simp] theorem UInt8.toUInt64_mod_256 (n : UInt8) : n.toUInt64 % 256 = n.toUInt64 := UInt64.toNat.inj (by simp)
|
||||
@[simp] theorem UInt8.toUSize_mod_256 (n : UInt8) : n.toUSize % 256 = n.toUSize := USize.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt16.toUInt32_mod_65536 (n : UInt16) : n.toUInt32 % 65536 = n.toUInt32 := UInt32.toNat.inj (by simp)
|
||||
@[simp] theorem UInt16.toUInt64_mod_65536 (n : UInt16) : n.toUInt64 % 65536 = n.toUInt64 := UInt64.toNat.inj (by simp)
|
||||
@[simp] theorem UInt16.toUSize_mod_65536 (n : UInt16) : n.toUSize % 65536 = n.toUSize := USize.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt32.toUInt64_mod_4294967296 (n : UInt32) : n.toUInt64 % 4294967296 = n.toUInt64 := UInt64.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem Fin.mk_uInt8ToNat (n : UInt8) : Fin.mk n.toNat n.toFin.isLt = n.toFin := rfl
|
||||
@[simp] theorem Fin.mk_uInt16ToNat (n : UInt16) : Fin.mk n.toNat n.toFin.isLt = n.toFin := rfl
|
||||
@[simp] theorem Fin.mk_uInt32ToNat (n : UInt32) : Fin.mk n.toNat n.toFin.isLt = n.toFin := rfl
|
||||
@@ -349,14 +394,14 @@ theorem UInt32.toNat_lt_usizeSize (n : UInt32) : n.toNat < USize.size :=
|
||||
@[simp] theorem UInt16.toBitVec_toUInt64 (n : UInt16) : n.toUInt64.toBitVec = n.toBitVec.setWidth 64 := rfl
|
||||
@[simp] theorem UInt32.toBitVec_toUInt64 (n : UInt32) : n.toUInt64.toBitVec = n.toBitVec.setWidth 64 := rfl
|
||||
@[simp] theorem USize.toBitVec_toUInt64 (n : USize) : n.toUInt64.toBitVec = n.toBitVec.setWidth 64 :=
|
||||
BitVec.eq_of_toNat_eq (by simp [Nat.mod_eq_of_lt (USize.toNat_lt _)])
|
||||
BitVec.eq_of_toNat_eq (by simp)
|
||||
|
||||
@[simp] theorem UInt8.toBitVec_toUSize (n : UInt8) : n.toUSize.toBitVec = n.toBitVec.setWidth System.Platform.numBits :=
|
||||
BitVec.eq_of_toNat_eq (by simp [Nat.mod_eq_of_lt n.toNat_lt_usizeSize])
|
||||
BitVec.eq_of_toNat_eq (by simp)
|
||||
@[simp] theorem UInt16.toBitVec_toUSize (n : UInt16) : n.toUSize.toBitVec = n.toBitVec.setWidth System.Platform.numBits :=
|
||||
BitVec.eq_of_toNat_eq (by simp [Nat.mod_eq_of_lt n.toNat_lt_usizeSize])
|
||||
BitVec.eq_of_toNat_eq (by simp)
|
||||
@[simp] theorem UInt32.toBitVec_toUSize (n : UInt32) : n.toUSize.toBitVec = n.toBitVec.setWidth System.Platform.numBits :=
|
||||
BitVec.eq_of_toNat_eq (by simp [Nat.mod_eq_of_lt n.toNat_lt_usizeSize])
|
||||
BitVec.eq_of_toNat_eq (by simp)
|
||||
@[simp] theorem UInt64.toBitVec_toUSize (n : UInt64) : n.toUSize.toBitVec = n.toBitVec.setWidth System.Platform.numBits :=
|
||||
BitVec.eq_of_toNat_eq (by simp)
|
||||
|
||||
@@ -420,3 +465,321 @@ theorem USize.ofNatLT_uInt64ToNat (n : UInt64) (h) : USize.ofNatLT n.toNat h = n
|
||||
@[simp] theorem USize.ofFin_uint8ToFin (n : UInt8) : USize.ofFin (n.toFin.castLE UInt8.size_le_usizeSize) = n.toUSize := rfl
|
||||
@[simp] theorem USize.ofFin_uint16ToFin (n : UInt16) : USize.ofFin (n.toFin.castLE UInt16.size_le_usizeSize) = n.toUSize := rfl
|
||||
@[simp] theorem USize.ofFin_uint32ToFin (n : UInt32) : USize.ofFin (n.toFin.castLE UInt32.size_le_usizeSize) = n.toUSize := rfl
|
||||
|
||||
@[simp] theorem Nat.toUInt8_eq {n : Nat} : n.toUInt8 = UInt8.ofNat n := rfl
|
||||
@[simp] theorem Nat.toUInt16_eq {n : Nat} : n.toUInt16 = UInt16.ofNat n := rfl
|
||||
@[simp] theorem Nat.toUInt32_eq {n : Nat} : n.toUInt32 = UInt32.ofNat n := rfl
|
||||
@[simp] theorem Nat.toUInt64_eq {n : Nat} : n.toUInt64 = UInt64.ofNat n := rfl
|
||||
@[simp] theorem Nat.toUSize_eq {n : Nat} : n.toUSize = USize.ofNat n := rfl
|
||||
|
||||
@[simp] theorem UInt8.ofBitVec_uInt16ToBitVec (n : UInt16) :
|
||||
UInt8.ofBitVec (n.toBitVec.setWidth 8) = n.toUInt8 := rfl
|
||||
@[simp] theorem UInt8.ofBitVec_uInt32ToBitVec (n : UInt32) :
|
||||
UInt8.ofBitVec (n.toBitVec.setWidth 8) = n.toUInt8 := rfl
|
||||
@[simp] theorem UInt8.ofBitVec_uInt64ToBitVec (n : UInt64) :
|
||||
UInt8.ofBitVec (n.toBitVec.setWidth 8) = n.toUInt8 := rfl
|
||||
@[simp] theorem UInt8.ofBitVec_uSizeToBitVec (n : USize) :
|
||||
UInt8.ofBitVec (n.toBitVec.setWidth 8) = n.toUInt8 := UInt8.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt16.ofBitVec_uInt8ToBitVec (n : UInt8) :
|
||||
UInt16.ofBitVec (n.toBitVec.setWidth 16) = n.toUInt16 := rfl
|
||||
@[simp] theorem UInt16.ofBitVec_uInt32ToBitVec (n : UInt32) :
|
||||
UInt16.ofBitVec (n.toBitVec.setWidth 16) = n.toUInt16 := rfl
|
||||
@[simp] theorem UInt16.ofBitVec_uInt64ToBitVec (n : UInt64) :
|
||||
UInt16.ofBitVec (n.toBitVec.setWidth 16) = n.toUInt16 := rfl
|
||||
@[simp] theorem UInt16.ofBitVec_uSizeToBitVec (n : USize) :
|
||||
UInt16.ofBitVec (n.toBitVec.setWidth 16) = n.toUInt16 := UInt16.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt32.ofBitVec_uInt8ToBitVec (n : UInt8) :
|
||||
UInt32.ofBitVec (n.toBitVec.setWidth 32) = n.toUInt32 := rfl
|
||||
@[simp] theorem UInt32.ofBitVec_uInt16ToBitVec (n : UInt16) :
|
||||
UInt32.ofBitVec (n.toBitVec.setWidth 32) = n.toUInt32 := rfl
|
||||
@[simp] theorem UInt32.ofBitVec_uInt64ToBitVec (n : UInt64) :
|
||||
UInt32.ofBitVec (n.toBitVec.setWidth 32) = n.toUInt32 := rfl
|
||||
@[simp] theorem UInt32.ofBitVec_uSizeToBitVec (n : USize) :
|
||||
UInt32.ofBitVec (n.toBitVec.setWidth 32) = n.toUInt32 := UInt32.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt64.ofBitVec_uInt8ToBitVec (n : UInt8) :
|
||||
UInt64.ofBitVec (n.toBitVec.setWidth 64) = n.toUInt64 := rfl
|
||||
@[simp] theorem UInt64.ofBitVec_uInt16ToBitVec (n : UInt16) :
|
||||
UInt64.ofBitVec (n.toBitVec.setWidth 64) = n.toUInt64 := rfl
|
||||
@[simp] theorem UInt64.ofBitVec_uInt32ToBitVec (n : UInt32) :
|
||||
UInt64.ofBitVec (n.toBitVec.setWidth 64) = n.toUInt64 := rfl
|
||||
@[simp] theorem UInt64.ofBitVec_uSizeToBitVec (n : USize) :
|
||||
UInt64.ofBitVec (n.toBitVec.setWidth 64) = n.toUInt64 :=
|
||||
UInt64.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem USize.ofBitVec_uInt8ToBitVec (n : UInt8) :
|
||||
USize.ofBitVec (n.toBitVec.setWidth System.Platform.numBits) = n.toUSize :=
|
||||
USize.toNat.inj (by simp)
|
||||
@[simp] theorem USize.ofBitVec_uInt16ToBitVec (n : UInt16) :
|
||||
USize.ofBitVec (n.toBitVec.setWidth System.Platform.numBits) = n.toUSize :=
|
||||
USize.toNat.inj (by simp)
|
||||
@[simp] theorem USize.ofBitVec_uInt32ToBitVec (n : UInt32) :
|
||||
USize.ofBitVec (n.toBitVec.setWidth System.Platform.numBits) = n.toUSize :=
|
||||
USize.toNat.inj (by simp)
|
||||
@[simp] theorem USize.ofBitVec_uInt64ToBitVec (n : UInt64) :
|
||||
USize.ofBitVec (n.toBitVec.setWidth System.Platform.numBits) = n.toUSize :=
|
||||
USize.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt8.ofNat_uInt16ToNat (n : UInt16) : UInt8.ofNat n.toNat = n.toUInt8 := rfl
|
||||
@[simp] theorem UInt8.ofNat_uInt32ToNat (n : UInt32) : UInt8.ofNat n.toNat = n.toUInt8 := rfl
|
||||
@[simp] theorem UInt8.ofNat_uInt64ToNat (n : UInt64) : UInt8.ofNat n.toNat = n.toUInt8 := rfl
|
||||
@[simp] theorem UInt8.ofNat_uSizeToNat (n : USize) : UInt8.ofNat n.toNat = n.toUInt8 := rfl
|
||||
|
||||
@[simp] theorem UInt16.ofNat_uInt8ToNat (n : UInt8) : UInt16.ofNat n.toNat = n.toUInt16 :=
|
||||
UInt16.toNat.inj (by simp)
|
||||
@[simp] theorem UInt16.ofNat_uInt32ToNat (n : UInt32) : UInt16.ofNat n.toNat = n.toUInt16 := rfl
|
||||
@[simp] theorem UInt16.ofNat_uInt64ToNat (n : UInt64) : UInt16.ofNat n.toNat = n.toUInt16 := rfl
|
||||
@[simp] theorem UInt16.ofNat_uSizeToNat (n : USize) : UInt16.ofNat n.toNat = n.toUInt16 := rfl
|
||||
|
||||
@[simp] theorem UInt32.ofNat_uInt8ToNat (n : UInt8) : UInt32.ofNat n.toNat = n.toUInt32 :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
@[simp] theorem UInt32.ofNat_uInt16ToNat (n : UInt16) : UInt32.ofNat n.toNat = n.toUInt32 :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
@[simp] theorem UInt32.ofNat_uInt64ToNat (n : UInt64) : UInt32.ofNat n.toNat = n.toUInt32 := rfl
|
||||
@[simp] theorem UInt32.ofNat_uSizeToNat (n : USize) : UInt32.ofNat n.toNat = n.toUInt32 := rfl
|
||||
|
||||
@[simp] theorem UInt64.ofNat_uInt8ToNat (n : UInt8) : UInt64.ofNat n.toNat = n.toUInt64 :=
|
||||
UInt64.toNat.inj (by simp)
|
||||
@[simp] theorem UInt64.ofNat_uInt16ToNat (n : UInt16) : UInt64.ofNat n.toNat = n.toUInt64 :=
|
||||
UInt64.toNat.inj (by simp)
|
||||
@[simp] theorem UInt64.ofNat_uInt32ToNat (n : UInt32) : UInt64.ofNat n.toNat = n.toUInt64 :=
|
||||
UInt64.toNat.inj (by simp)
|
||||
@[simp] theorem UInt64.ofNat_uSizeToNat (n : USize) : UInt64.ofNat n.toNat = n.toUInt64 :=
|
||||
UInt64.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem USize.ofNat_uInt8ToNat (n : UInt8) : USize.ofNat n.toNat = n.toUSize :=
|
||||
USize.toNat.inj (by simp)
|
||||
@[simp] theorem USize.ofNat_uInt16ToNat (n : UInt16) : USize.ofNat n.toNat = n.toUSize :=
|
||||
USize.toNat.inj (by simp)
|
||||
@[simp] theorem USize.ofNat_uInt32ToNat (n : UInt32) : USize.ofNat n.toNat = n.toUSize :=
|
||||
USize.toNat.inj (by simp)
|
||||
@[simp] theorem USize.ofNat_uInt64ToNat (n : UInt64) : USize.ofNat n.toNat = n.toUSize :=
|
||||
USize.toNat.inj (by simp)
|
||||
|
||||
theorem UInt8.ofNatLT_eq_ofNat (n : Nat) {h} : UInt8.ofNatLT n h = UInt8.ofNat n :=
|
||||
UInt8.toNat.inj (by simp [Nat.mod_eq_of_lt h])
|
||||
theorem UInt16.ofNatLT_eq_ofNat (n : Nat) {h} : UInt16.ofNatLT n h = UInt16.ofNat n :=
|
||||
UInt16.toNat.inj (by simp [Nat.mod_eq_of_lt h])
|
||||
theorem UInt32.ofNatLT_eq_ofNat (n : Nat) {h} : UInt32.ofNatLT n h = UInt32.ofNat n :=
|
||||
UInt32.toNat.inj (by simp [Nat.mod_eq_of_lt h])
|
||||
theorem UInt64.ofNatLT_eq_ofNat (n : Nat) {h} : UInt64.ofNatLT n h = UInt64.ofNat n :=
|
||||
UInt64.toNat.inj (by simp [Nat.mod_eq_of_lt h])
|
||||
theorem USize.ofNatLT_eq_ofNat (n : Nat) {h} : USize.ofNatLT n h = USize.ofNat n :=
|
||||
USize.toNat.inj (by simp [Nat.mod_eq_of_lt h])
|
||||
|
||||
theorem UInt8.ofNatTruncate_eq_ofNat (n : Nat) (hn : n < UInt8.size) :
|
||||
UInt8.ofNatTruncate n = UInt8.ofNat n := by
|
||||
simp [ofNatTruncate, hn, UInt8.ofNatLT_eq_ofNat]
|
||||
theorem UInt16.ofNatTruncate_eq_ofNat (n : Nat) (hn : n < UInt16.size) :
|
||||
UInt16.ofNatTruncate n = UInt16.ofNat n := by
|
||||
simp [ofNatTruncate, hn, UInt16.ofNatLT_eq_ofNat]
|
||||
theorem UInt32.ofNatTruncate_eq_ofNat (n : Nat) (hn : n < UInt32.size) :
|
||||
UInt32.ofNatTruncate n = UInt32.ofNat n := by
|
||||
simp [ofNatTruncate, hn, UInt32.ofNatLT_eq_ofNat]
|
||||
theorem UInt64.ofNatTruncate_eq_ofNat (n : Nat) (hn : n < UInt64.size) :
|
||||
UInt64.ofNatTruncate n = UInt64.ofNat n := by
|
||||
simp [ofNatTruncate, hn, UInt64.ofNatLT_eq_ofNat]
|
||||
theorem USize.ofNatTruncate_eq_ofNat (n : Nat) (hn : n < USize.size) :
|
||||
USize.ofNatTruncate n = USize.ofNat n := by
|
||||
simp [ofNatTruncate, hn, USize.ofNatLT_eq_ofNat]
|
||||
|
||||
@[simp] theorem UInt8.ofNatTruncate_toNat (n : UInt8) : UInt8.ofNatTruncate n.toNat = n := by
|
||||
rw [UInt8.ofNatTruncate_eq_ofNat] <;> simp [n.toNat_lt]
|
||||
|
||||
@[simp] theorem UInt16.ofNatTruncate_uInt8ToNat (n : UInt8) : UInt16.ofNatTruncate n.toNat = n.toUInt16 := by
|
||||
rw [UInt16.ofNatTruncate_eq_ofNat, ofNat_uInt8ToNat]
|
||||
exact Nat.lt_trans (n.toNat_lt) (by decide)
|
||||
@[simp] theorem UInt16.ofNatTruncate_toNat (n : UInt16) : UInt16.ofNatTruncate n.toNat = n := by
|
||||
rw [UInt16.ofNatTruncate_eq_ofNat] <;> simp [n.toNat_lt]
|
||||
|
||||
@[simp] theorem UInt32.ofNatTruncate_uInt8ToNat (n : UInt8) : UInt32.ofNatTruncate n.toNat = n.toUInt32 := by
|
||||
rw [UInt32.ofNatTruncate_eq_ofNat, ofNat_uInt8ToNat]
|
||||
exact Nat.lt_trans (n.toNat_lt) (by decide)
|
||||
@[simp] theorem UInt32.ofNatTruncate_uInt16ToNat (n : UInt16) : UInt32.ofNatTruncate n.toNat = n.toUInt32 := by
|
||||
rw [UInt32.ofNatTruncate_eq_ofNat, ofNat_uInt16ToNat]
|
||||
exact Nat.lt_trans (n.toNat_lt) (by decide)
|
||||
@[simp] theorem UInt32.ofNatTruncate_toNat (n : UInt32) : UInt32.ofNatTruncate n.toNat = n := by
|
||||
rw [UInt32.ofNatTruncate_eq_ofNat] <;> simp [n.toNat_lt]
|
||||
|
||||
@[simp] theorem UInt64.ofNatTruncate_uInt8ToNat (n : UInt8) : UInt64.ofNatTruncate n.toNat = n.toUInt64 := by
|
||||
rw [UInt64.ofNatTruncate_eq_ofNat, ofNat_uInt8ToNat]
|
||||
exact Nat.lt_trans (n.toNat_lt) (by decide)
|
||||
@[simp] theorem UInt64.ofNatTruncate_uInt16ToNat (n : UInt16) : UInt64.ofNatTruncate n.toNat = n.toUInt64 := by
|
||||
rw [UInt64.ofNatTruncate_eq_ofNat, ofNat_uInt16ToNat]
|
||||
exact Nat.lt_trans (n.toNat_lt) (by decide)
|
||||
@[simp] theorem UInt64.ofNatTruncate_uInt32ToNat (n : UInt32) : UInt64.ofNatTruncate n.toNat = n.toUInt64 := by
|
||||
rw [UInt64.ofNatTruncate_eq_ofNat, ofNat_uInt32ToNat]
|
||||
exact Nat.lt_trans (n.toNat_lt) (by decide)
|
||||
@[simp] theorem UInt64.ofNatTruncate_toNat (n : UInt64) : UInt64.ofNatTruncate n.toNat = n := by
|
||||
rw [UInt64.ofNatTruncate_eq_ofNat] <;> simp [n.toNat_lt]
|
||||
@[simp] theorem UInt64.ofNatTruncate_uSizeToNat (n : USize) : UInt64.ofNatTruncate n.toNat = n.toUInt64 := by
|
||||
rw [UInt64.ofNatTruncate_eq_ofNat, ofNat_uSizeToNat]
|
||||
exact n.toNat_lt
|
||||
|
||||
@[simp] theorem USize.ofNatTruncate_uInt8ToNat (n : UInt8) : USize.ofNatTruncate n.toNat = n.toUSize := by
|
||||
rw [USize.ofNatTruncate_eq_ofNat, ofNat_uInt8ToNat]
|
||||
exact n.toNat_lt_usizeSize
|
||||
@[simp] theorem USize.ofNatTruncate_uInt16ToNat (n : UInt16) : USize.ofNatTruncate n.toNat = n.toUSize := by
|
||||
rw [USize.ofNatTruncate_eq_ofNat, ofNat_uInt16ToNat]
|
||||
exact n.toNat_lt_usizeSize
|
||||
@[simp] theorem USize.ofNatTruncate_uInt32ToNat (n : UInt32) : USize.ofNatTruncate n.toNat = n.toUSize := by
|
||||
rw [USize.ofNatTruncate_eq_ofNat, ofNat_uInt32ToNat]
|
||||
exact n.toNat_lt_usizeSize
|
||||
@[simp] theorem USize.ofNatTruncate_toNat (n : USize) : USize.ofNatTruncate n.toNat = n := by
|
||||
rw [USize.ofNatTruncate_eq_ofNat] <;> simp [n.toNat_lt_size]
|
||||
|
||||
@[simp] theorem UInt8.toUInt8_toUInt16 (n : UInt8) : n.toUInt16.toUInt8 = n :=
|
||||
UInt8.toNat.inj (by simp)
|
||||
@[simp] theorem UInt8.toUInt8_toUInt32 (n : UInt8) : n.toUInt32.toUInt8 = n :=
|
||||
UInt8.toNat.inj (by simp)
|
||||
@[simp] theorem UInt8.toUInt8_toUInt64 (n : UInt8) : n.toUInt64.toUInt8 = n :=
|
||||
UInt8.toNat.inj (by simp)
|
||||
@[simp] theorem UInt8.toUInt8_toUSize (n : UInt8) : n.toUSize.toUInt8 = n :=
|
||||
UInt8.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt8.toUInt16_toUInt32 (n : UInt8) : n.toUInt32.toUInt16 = n.toUInt16 :=
|
||||
UInt16.toNat.inj (by simp)
|
||||
@[simp] theorem UInt8.toUInt16_toUInt64 (n : UInt8) : n.toUInt64.toUInt16 = n.toUInt16 :=
|
||||
UInt16.toNat.inj (by simp)
|
||||
@[simp] theorem UInt8.toUInt16_toUSize (n : UInt8) : n.toUSize.toUInt16 = n.toUInt16 :=
|
||||
UInt16.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt8.toUInt32_toUInt16 (n : UInt8) : n.toUInt16.toUInt32 = n.toUInt32 := rfl
|
||||
@[simp] theorem UInt8.toUInt32_toUInt64 (n : UInt8) : n.toUInt64.toUInt32 = n.toUInt32 :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
@[simp] theorem UInt8.toUInt32_toUSize (n : UInt8) : n.toUSize.toUInt32 = n.toUInt32 :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt8.toUInt64_toUInt16 (n : UInt8) : n.toUInt16.toUInt64 = n.toUInt64 := rfl
|
||||
@[simp] theorem UInt8.toUInt64_toUInt32 (n : UInt8) : n.toUInt32.toUInt64 = n.toUInt64 := rfl
|
||||
@[simp] theorem UInt8.toUInt64_toUSize (n : UInt8) : n.toUSize.toUInt64 = n.toUInt64 := rfl
|
||||
|
||||
@[simp] theorem UInt8.toUSize_toUInt16 (n : UInt8) : n.toUInt16.toUSize = n.toUSize := rfl
|
||||
@[simp] theorem UInt8.toUSize_toUInt32 (n : UInt8) : n.toUInt32.toUSize = n.toUSize := rfl
|
||||
@[simp] theorem UInt8.toUSize_toUInt64 (n : UInt8) : n.toUInt64.toUSize = n.toUSize :=
|
||||
USize.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt16.toUInt8_toUInt32 (n : UInt16) : n.toUInt32.toUInt8 = n.toUInt8 := rfl
|
||||
@[simp] theorem UInt16.toUInt8_toUInt64 (n : UInt16) : n.toUInt64.toUInt8 = n.toUInt8 := rfl
|
||||
@[simp] theorem UInt16.toUInt8_toUSize (n : UInt16) : n.toUSize.toUInt8 = n.toUInt8 := rfl
|
||||
|
||||
@[simp] theorem UInt16.toUInt16_toUInt8 (n : UInt16) : n.toUInt8.toUInt16 = n % 256 := rfl
|
||||
@[simp] theorem UInt16.toUInt16_toUInt32 (n : UInt16) : n.toUInt32.toUInt16 = n :=
|
||||
UInt16.toNat.inj (by simp)
|
||||
@[simp] theorem UInt16.toUInt16_toUInt64 (n : UInt16) : n.toUInt64.toUInt16 = n :=
|
||||
UInt16.toNat.inj (by simp)
|
||||
@[simp] theorem UInt16.toUInt16_toUSize (n : UInt16) : n.toUSize.toUInt16 = n :=
|
||||
UInt16.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt16.toUInt32_toUInt8 (n : UInt16) : n.toUInt8.toUInt32 = n.toUInt32 % 256 := rfl
|
||||
@[simp] theorem UInt16.toUInt32_toUInt64 (n : UInt16) : n.toUInt64.toUInt32 = n.toUInt32 :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
@[simp] theorem UInt16.toUInt32_toUSize (n : UInt16) : n.toUSize.toUInt32 = n.toUInt32 :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt16.toUInt64_toUInt8 (n : UInt16) : n.toUInt8.toUInt64 = n.toUInt64 % 256 := rfl
|
||||
@[simp] theorem UInt16.toUInt64_toUInt32 (n : UInt16) : n.toUInt32.toUInt64 = n.toUInt64 := rfl
|
||||
@[simp] theorem UInt16.toUInt64_toUSize (n : UInt16) : n.toUSize.toUInt64 = n.toUInt64 := rfl
|
||||
|
||||
@[simp] theorem UInt16.toUSize_toUInt8 (n : UInt16) : n.toUInt8.toUSize = n.toUSize % 256 :=
|
||||
USize.toNat.inj (by simp)
|
||||
@[simp] theorem UInt16.toUSize_toUInt32 (n : UInt16) : n.toUInt32.toUSize = n.toUSize :=
|
||||
USize.toNat.inj (by simp)
|
||||
@[simp] theorem UInt16.toUSize_toUInt64 (n : UInt16) : n.toUInt64.toUSize = n.toUSize :=
|
||||
USize.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt32.toUInt8_toUInt16 (n : UInt32) : n.toUInt16.toUInt8 = n.toUInt8 :=
|
||||
UInt8.toNat.inj (by simp)
|
||||
@[simp] theorem UInt32.toUInt8_toUInt64 (n : UInt32) : n.toUInt64.toUInt8 = n.toUInt8 := rfl
|
||||
@[simp] theorem UInt32.toUInt8_toUSize (n : UInt32) : n.toUSize.toUInt8 = n.toUInt8 := rfl
|
||||
|
||||
@[simp] theorem UInt32.toUInt16_toUInt8 (n : UInt32) : n.toUInt8.toUInt16 = n.toUInt16 % 256 :=
|
||||
UInt16.toNat.inj (by simp)
|
||||
@[simp] theorem UInt32.toUInt16_toUInt64 (n : UInt32) : n.toUInt64.toUInt16 = n.toUInt16 := rfl
|
||||
@[simp] theorem UInt32.toUInt16_toUSize (n : UInt32) : n.toUSize.toUInt16 = n.toUInt16 := rfl
|
||||
|
||||
@[simp] theorem UInt32.toUInt32_toUInt8 (n : UInt32) : n.toUInt8.toUInt32 = n % 256 := rfl
|
||||
@[simp] theorem UInt32.toUInt32_toUInt16 (n : UInt32) : n.toUInt16.toUInt32 = n % 65536 := rfl
|
||||
@[simp] theorem UInt32.toUInt32_toUInt64 (n : UInt32) : n.toUInt64.toUInt32 = n :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
@[simp] theorem UInt32.toUInt32_toUSize (n : UInt32) : n.toUSize.toUInt32 = n :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt32.toUInt64_toUInt8 (n : UInt32) : n.toUInt8.toUInt64 = n.toUInt64 % 256 := rfl
|
||||
@[simp] theorem UInt32.toUInt64_toUInt16 (n : UInt32) : n.toUInt16.toUInt64 = n.toUInt64 % 65536 := rfl
|
||||
@[simp] theorem UInt32.toUInt64_toUSize (n : UInt32) : n.toUSize.toUInt64 = n.toUInt64 := rfl
|
||||
|
||||
@[simp] theorem UInt32.toUSize_toUInt8 (n : UInt32) : n.toUInt8.toUSize = n.toUSize % 256 :=
|
||||
USize.toNat.inj (by simp)
|
||||
@[simp] theorem UInt32.toUSize_toUInt16 (n : UInt32) : n.toUInt16.toUSize = n.toUSize % 65536 :=
|
||||
USize.toNat.inj (by simp)
|
||||
@[simp] theorem UInt32.toUSize_toUInt64 (n : UInt32) : n.toUInt64.toUSize = n.toUSize :=
|
||||
USize.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt64.toUInt8_toUInt16 (n : UInt64) : n.toUInt16.toUInt8 = n.toUInt8 :=
|
||||
UInt8.toNat.inj (by simp)
|
||||
@[simp] theorem UInt64.toUInt8_toUInt32 (n : UInt64) : n.toUInt32.toUInt8 = n.toUInt8 :=
|
||||
UInt8.toNat.inj (by simp)
|
||||
@[simp] theorem UInt64.toUInt8_toUSize (n : UInt64) : n.toUSize.toUInt8 = n.toUInt8 :=
|
||||
UInt8.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt64.toUInt16_toUInt8 (n : UInt64) : n.toUInt8.toUInt16 = n.toUInt16 % 256 :=
|
||||
UInt16.toNat.inj (by simp)
|
||||
@[simp] theorem UInt64.toUInt16_toUInt32 (n : UInt64) : n.toUInt32.toUInt16 = n.toUInt16 :=
|
||||
UInt16.toNat.inj (by simp)
|
||||
@[simp] theorem UInt64.toUInt16_toUSize (n : UInt64) : n.toUSize.toUInt16 = n.toUInt16 :=
|
||||
UInt16.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt64.toUInt32_toUInt8 (n : UInt64) : n.toUInt8.toUInt32 = n.toUInt32 % 256 :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
@[simp] theorem UInt64.toUInt32_toUInt16 (n : UInt64) : n.toUInt16.toUInt32 = n.toUInt32 % 65536 :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
@[simp] theorem UInt64.toUInt32_toUSize (n : UInt64) : n.toUSize.toUInt32 = n.toUInt32 :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem UInt64.toUInt64_toUInt8 (n : UInt64) : n.toUInt8.toUInt64 = n % 256 := rfl
|
||||
@[simp] theorem UInt64.toUInt64_toUInt16 (n : UInt64) : n.toUInt16.toUInt64 = n % 65536 := rfl
|
||||
@[simp] theorem UInt64.toUInt64_toUInt32 (n : UInt64) : n.toUInt32.toUInt64 = n % 4294967296 := rfl
|
||||
|
||||
@[simp] theorem UInt64.toUSize_toUInt8 (n : UInt64) : n.toUInt8.toUSize = n.toUSize % 256 :=
|
||||
USize.toNat.inj (by simp)
|
||||
@[simp] theorem UInt64.toUSize_toUInt16 (n : UInt64) : n.toUInt16.toUSize = n.toUSize % 65536 :=
|
||||
USize.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem USize.toUInt8_toUInt16 (n : USize) : n.toUInt16.toUInt8 = n.toUInt8 :=
|
||||
UInt8.toNat.inj (by simp)
|
||||
@[simp] theorem USize.toUInt8_toUInt32 (n : USize) : n.toUInt32.toUInt8 = n.toUInt8 :=
|
||||
UInt8.toNat.inj (by simp)
|
||||
@[simp] theorem USize.toUInt8_toUInt64 (n : USize) : n.toUInt64.toUInt8 = n.toUInt8 := rfl
|
||||
|
||||
@[simp] theorem USize.toUInt16_toUInt8 (n : USize) : n.toUInt8.toUInt16 = n.toUInt16 % 256 :=
|
||||
UInt16.toNat.inj (by simp)
|
||||
@[simp] theorem USize.toUInt16_toUInt32 (n : USize) : n.toUInt32.toUInt16 = n.toUInt16 :=
|
||||
UInt16.toNat.inj (by simp)
|
||||
@[simp] theorem USize.toUInt16_toUInt64 (n : USize) : n.toUInt64.toUInt16 = n.toUInt16 := rfl
|
||||
|
||||
@[simp] theorem USize.toUInt64_toUInt8 (n : USize) : n.toUInt8.toUInt64 = n.toUInt64 % 256 := rfl
|
||||
@[simp] theorem USize.toUInt64_toUInt16 (n : USize) : n.toUInt16.toUInt64 = n.toUInt64 % 65536 := rfl
|
||||
|
||||
@[simp] theorem USize.toUInt32_toUInt8 (n : USize) : n.toUInt8.toUInt32 = n.toUInt32 % 256 :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
@[simp] theorem USize.toUInt32_toUInt16 (n : USize) : n.toUInt16.toUInt32 = n.toUInt32 % 65536 :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
@[simp] theorem USize.toUInt32_toUInt64 (n : USize) : n.toUInt64.toUInt32 = n.toUInt32 :=
|
||||
UInt32.toNat.inj (by simp)
|
||||
|
||||
@[simp] theorem USize.toUSize_toUInt8 (n : USize) : n.toUInt8.toUSize = n % 256 :=
|
||||
USize.toNat.inj (by simp)
|
||||
@[simp] theorem USize.toUSize_toUInt16 (n : USize) : n.toUInt16.toUSize = n % 65536 :=
|
||||
USize.toNat.inj (by simp)
|
||||
@[simp] theorem USize.toUSize_toUInt64 (n : USize) : n.toUInt64.toUSize = n :=
|
||||
USize.toNat.inj (by simp)
|
||||
|
||||
-- Note: we are currently missing the following four results for which there does not seem to
|
||||
-- be a good candidate for the RHS:
|
||||
-- @[simp] theorem UInt64.toUInt64_toUSize (n : UInt64) : n.toUSize.toUInt64 = ? :=
|
||||
-- @[simp] theorem UInt64.toUSize_toUInt32 (n : UInt64) : n.toUInt32.toUSize = ? :=
|
||||
-- @[simp] theorem USize.toUInt64_toUInt32 (n : USize) : n.toUInt32.toUInt64 = ? :=
|
||||
-- @[simp] theorem USize.toUSize_toUInt32 (n : USize) : n.toInt32.toUSize = ? :=
|
||||
|
||||
@@ -7,8 +7,8 @@ prelude
|
||||
import Init.Data.Vector.Lemmas
|
||||
import Init.Data.Array.Attach
|
||||
|
||||
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
namespace Vector
|
||||
|
||||
@@ -473,6 +473,10 @@ def unattach {α : Type _} {p : α → Prop} (xs : Vector { x // p x } n) : Vect
|
||||
(xs.push a).unattach = xs.unattach.push a.1 := by
|
||||
simp only [unattach, Vector.map_push]
|
||||
|
||||
@[simp] theorem mem_unattach {p : α → Prop} {xs : Vector { x // p x } n} {a} :
|
||||
a ∈ xs.unattach ↔ ∃ h : p a, ⟨a, h⟩ ∈ xs := by
|
||||
simp only [unattach, mem_map, Subtype.exists, exists_and_right, exists_eq_right]
|
||||
|
||||
@[simp] theorem unattach_mk {p : α → Prop} {xs : Array { x // p x }} {h : xs.size = n} :
|
||||
(mk xs h).unattach = mk xs.unattach (by simpa using h) := by
|
||||
simp [unattach]
|
||||
@@ -552,6 +556,18 @@ and simplifies these to the function directly taking the value.
|
||||
simp
|
||||
rw [Array.find?_subtype hf]
|
||||
|
||||
@[simp] theorem all_subtype {p : α → Prop} {xs : Vector { x // p x } n} {f : { x // p x } → Bool} {g : α → Bool}
|
||||
(hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
xs.all f = xs.unattach.all g := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [hf]
|
||||
|
||||
@[simp] theorem any_subtype {p : α → Prop} {xs : Vector { x // p x } n} {f : { x // p x } → Bool} {g : α → Bool}
|
||||
(hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
xs.any f = xs.unattach.any g := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [hf]
|
||||
|
||||
/-! ### Simp lemmas pushing `unattach` inwards. -/
|
||||
|
||||
@[simp] theorem unattach_reverse {p : α → Prop} {xs : Vector { x // p x } n} :
|
||||
|
||||
@@ -17,8 +17,8 @@ import Init.Data.Stream
|
||||
`Vector α n` is a thin wrapper around `Array α` for arrays of fixed size `n`.
|
||||
-/
|
||||
|
||||
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
/-- `Vector α n` is an `Array α` with size `n`. -/
|
||||
structure Vector (α : Type u) (n : Nat) extends Array α where
|
||||
|
||||
@@ -15,8 +15,8 @@ import Init.Data.Array.Find
|
||||
We are still missing results about `idxOf?`, `findIdx`, and `findIdx?`.
|
||||
-/
|
||||
|
||||
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
namespace Vector
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ import Init.Data.Array.Find
|
||||
Lemmas about `Vector α n`
|
||||
-/
|
||||
|
||||
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
namespace Array
|
||||
|
||||
@@ -1592,9 +1592,11 @@ theorem getElem_append (xs : Vector α n) (ys : Vector α m) (i : Nat) (hi : i <
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp [Array.getElem_append, hi]
|
||||
|
||||
@[simp]
|
||||
theorem getElem_append_left {xs : Vector α n} {ys : Vector α m} {i : Nat} (hi : i < n) :
|
||||
(xs ++ ys)[i] = xs[i] := by simp [getElem_append, hi]
|
||||
|
||||
@[simp]
|
||||
theorem getElem_append_right {xs : Vector α n} {ys : Vector α m} {i : Nat} (h : i < n + m) (hi : n ≤ i) :
|
||||
(xs ++ ys)[i] = ys[i - n] := by
|
||||
rw [getElem_append, dif_neg (by omega)]
|
||||
@@ -2068,6 +2070,12 @@ theorem flatMap_mkArray {β} (f : α → Vector β m) : (mkVector n a).flatMap f
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
theorem getElem_eq_getElem_reverse {xs : Vector α n} {i} (h : i < n) :
|
||||
xs[i] = xs.reverse[n - 1 - i] := by
|
||||
rw [getElem_reverse]
|
||||
congr
|
||||
omega
|
||||
|
||||
/-- Variant of `getElem?_reverse` with a hypothesis giving the linear relation between the indices. -/
|
||||
theorem getElem?_reverse' {xs : Vector α n} (i j) (h : i + j + 1 = n) : xs.reverse[i]? = xs[j]? := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -2585,6 +2593,161 @@ theorem replace_extract {xs : Vector α n} {i : Nat} :
|
||||
|
||||
end replace
|
||||
|
||||
/-! ## Logic -/
|
||||
|
||||
/-! ### any / all -/
|
||||
|
||||
theorem not_any_eq_all_not (xs : Vector α n) (p : α → Bool) : (!xs.any p) = xs.all fun a => !p a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.not_any_eq_all_not]
|
||||
|
||||
theorem not_all_eq_any_not (xs : Vector α n) (p : α → Bool) : (!xs.all p) = xs.any fun a => !p a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.not_all_eq_any_not]
|
||||
|
||||
theorem and_any_distrib_left (xs : Vector α n) (p : α → Bool) (q : Bool) :
|
||||
(q && xs.any p) = xs.any fun a => q && p a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.and_any_distrib_left]
|
||||
|
||||
theorem and_any_distrib_right (xs : Vector α n) (p : α → Bool) (q : Bool) :
|
||||
(xs.any p && q) = xs.any fun a => p a && q := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.and_any_distrib_right]
|
||||
|
||||
theorem or_all_distrib_left (xs : Vector α n) (p : α → Bool) (q : Bool) :
|
||||
(q || xs.all p) = xs.all fun a => q || p a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.or_all_distrib_left]
|
||||
|
||||
theorem or_all_distrib_right (xs : Vector α n) (p : α → Bool) (q : Bool) :
|
||||
(xs.all p || q) = xs.all fun a => p a || q := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.or_all_distrib_right]
|
||||
|
||||
theorem any_eq_not_all_not (xs : Vector α n) (p : α → Bool) : xs.any p = !xs.all (!p .) := by
|
||||
simp only [not_all_eq_any_not, Bool.not_not]
|
||||
|
||||
@[simp] theorem any_map {xs : Vector α n} {p : β → Bool} : (xs.map f).any p = xs.any (p ∘ f) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem all_map {xs : Vector α n} {p : β → Bool} : (xs.map f).all p = xs.all (p ∘ f) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem any_filter {xs : Vector α n} {p q : α → Bool} :
|
||||
(xs.filter p).any q = xs.any fun a => p a && q a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem all_filter {xs : Vector α n} {p q : α → Bool} :
|
||||
(xs.filter p).all q = xs.all fun a => p a → q a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem any_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool} :
|
||||
(xs.filterMap f).any p = xs.any fun a => match f a with | some b => p b | none => false := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
rfl
|
||||
|
||||
@[simp] theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool} :
|
||||
(xs.filterMap f).all p = xs.all fun a => match f a with | some b => p b | none => true := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
rfl
|
||||
|
||||
@[simp] theorem any_append {xs : Vector α n} {ys : Vector α m} :
|
||||
(xs ++ ys).any f = (xs.any f || ys.any f) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem all_append {xs : Vector α n} {ys : Vector α m} :
|
||||
(xs ++ ys).all f = (xs.all f && ys.all f) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp
|
||||
|
||||
@[congr] theorem anyM_congr [Monad m]
|
||||
{xs ys : Vector α n} (w : xs = ys) {p q : α → m Bool} (h : ∀ a, p a = q a) :
|
||||
xs.anyM p = ys.anyM q := by
|
||||
have : p = q := by funext a; apply h
|
||||
subst this
|
||||
subst w
|
||||
rfl
|
||||
|
||||
@[congr] theorem any_congr
|
||||
{xs ys : Vector α n} (w : xs = ys) {p q : α → Bool} (h : ∀ a, p a = q a) :
|
||||
xs.any p = ys.any q := by
|
||||
unfold any
|
||||
apply anyM_congr w h
|
||||
|
||||
@[congr] theorem allM_congr [Monad m]
|
||||
{xs ys : Vector α n} (w : xs = ys) {p q : α → m Bool} (h : ∀ a, p a = q a) :
|
||||
xs.allM p = ys.allM q := by
|
||||
have : p = q := by funext a; apply h
|
||||
subst this
|
||||
subst w
|
||||
rfl
|
||||
|
||||
@[congr] theorem all_congr
|
||||
{xs ys : Vector α n} (w : xs = ys) {p q : α → Bool} (h : ∀ a, p a = q a) :
|
||||
xs.all p = ys.all q := by
|
||||
unfold all
|
||||
apply allM_congr w h
|
||||
|
||||
@[simp] theorem any_flatten {xss : Vector (Vector α n) m} : xss.flatten.any f = xss.any (any · f) := by
|
||||
cases xss using vector₂_induction
|
||||
simp
|
||||
|
||||
@[simp] theorem all_flatten {xss : Vector (Vector α n) m} : xss.flatten.all f = xss.all (all · f) := by
|
||||
cases xss using vector₂_induction
|
||||
simp
|
||||
|
||||
@[simp] theorem any_flatMap {xs : Vector α n} {f : α → Vector β m} {p : β → Bool} :
|
||||
(xs.flatMap f).any p = xs.any fun a => (f a).any p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [flatMap_mk, any_mk, Array.size_flatMap, size_toArray, Array.any_flatMap']
|
||||
congr
|
||||
funext
|
||||
congr
|
||||
simp [Vector.size_toArray]
|
||||
|
||||
@[simp] theorem all_flatMap {xs : Vector α n} {f : α → Vector β m} {p : β → Bool} :
|
||||
(xs.flatMap f).all p = xs.all fun a => (f a).all p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [flatMap_mk, all_mk, Array.size_flatMap, size_toArray, Array.all_flatMap']
|
||||
congr
|
||||
funext
|
||||
congr
|
||||
simp [Vector.size_toArray]
|
||||
|
||||
@[simp] theorem any_reverse {xs : Vector α n} : xs.reverse.any f = xs.any f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem all_reverse {xs : Vector α n} : xs.reverse.all f = xs.all f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem any_cast {xs : Vector α n} : (xs.cast h).any f = xs.any f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem all_cast {xs : Vector α n} : (xs.cast h).all f = xs.all f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem any_mkVector {n : Nat} {a : α} :
|
||||
(mkVector n a).any f = if n = 0 then false else f a := by
|
||||
induction n <;> simp_all [mkVector_succ']
|
||||
|
||||
@[simp] theorem all_mkVector {n : Nat} {a : α} :
|
||||
(mkVector n a).all f = if n = 0 then true else f a := by
|
||||
induction n <;> simp_all +contextual [mkVector_succ']
|
||||
|
||||
/-! Content below this point has not yet been aligned with `List` and `Array`. -/
|
||||
|
||||
set_option linter.indexVariables false in
|
||||
|
||||
@@ -69,6 +69,11 @@ theorem eq_eq_of_eq_true_right {a b : Prop} (h : b = True) : (a = b) = a := by s
|
||||
theorem eq_congr {α : Sort u} {a₁ b₁ a₂ b₂ : α} (h₁ : a₁ = a₂) (h₂ : b₁ = b₂) : (a₁ = b₁) = (a₂ = b₂) := by simp [*]
|
||||
theorem eq_congr' {α : Sort u} {a₁ b₁ a₂ b₂ : α} (h₁ : a₁ = b₂) (h₂ : b₁ = a₂) : (a₁ = b₁) = (a₂ = b₂) := by rw [h₁, h₂, Eq.comm (a := a₂)]
|
||||
|
||||
/-! Ne -/
|
||||
|
||||
theorem ne_of_ne_of_eq_left {α : Sort u} {a b c : α} (h₁ : a = b) (h₂ : b ≠ c) : a ≠ c := by simp [*]
|
||||
theorem ne_of_ne_of_eq_right {α : Sort u} {a b c : α} (h₁ : a = c) (h₂ : b ≠ c) : b ≠ a := by simp [*]
|
||||
|
||||
/-! Bool.and -/
|
||||
|
||||
theorem Bool.and_eq_of_eq_true_left {a b : Bool} (h : a = true) : (a && b) = b := by simp [h]
|
||||
|
||||
@@ -57,6 +57,11 @@ def EIO.catchExceptions (act : EIO ε α) (h : ε → BaseIO α) : BaseIO α :=
|
||||
| EStateM.Result.ok a s => EStateM.Result.ok a s
|
||||
| EStateM.Result.error ex s => h ex s
|
||||
|
||||
def EIO.ofExcept (e : Except ε α) : EIO ε α :=
|
||||
match e with
|
||||
| Except.ok a => pure a
|
||||
| Except.error e => throw e
|
||||
|
||||
open IO (Error) in
|
||||
abbrev IO : Type → Type := EIO Error
|
||||
|
||||
|
||||
@@ -48,7 +48,9 @@ inductive IO.Error where
|
||||
|
||||
| unexpectedEof
|
||||
| userError (msg : String)
|
||||
deriving Inhabited
|
||||
|
||||
instance : Inhabited IO.Error where
|
||||
default := .userError "(`Inhabited.default` for `IO.Error`)"
|
||||
|
||||
@[export lean_mk_io_user_error]
|
||||
def IO.userError (s : String) : IO.Error :=
|
||||
|
||||
@@ -73,5 +73,5 @@ def Promise.result := @Promise.result!
|
||||
/--
|
||||
Like `Promise.result`, but resolves to `dflt` if the promise is dropped without ever being resolved.
|
||||
-/
|
||||
def Promise.resultD (promise : Promise α) (dflt : α): Task α :=
|
||||
@[macro_inline] def Promise.resultD (promise : Promise α) (dflt : α) : Task α :=
|
||||
promise.result?.map (sync := true) (·.getD dflt)
|
||||
|
||||
@@ -8,12 +8,6 @@ import Lean.CoreM
|
||||
|
||||
namespace Lean
|
||||
|
||||
register_builtin_option debug.skipKernelTC : Bool := {
|
||||
defValue := false
|
||||
group := "debug"
|
||||
descr := "skip kernel type checker. WARNING: setting this option to true may compromise soundness because your proofs will not be checked by the Lean kernel"
|
||||
}
|
||||
|
||||
/-- Adds given declaration to the environment, respecting `debug.skipKernelTC`. -/
|
||||
def Kernel.Environment.addDecl (env : Environment) (opts : Options) (decl : Declaration)
|
||||
(cancelTk? : Option IO.CancelToken := none) : Except Exception Environment :=
|
||||
|
||||
@@ -155,6 +155,7 @@ def emitMainFn : M Unit := do
|
||||
int main(int argc, char ** argv) {
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
lean_object* in; lean_object* res;";
|
||||
if usesLeanAPI then
|
||||
|
||||
@@ -514,7 +514,9 @@ def inferStep : InterpM Bool := do
|
||||
let currentVal ← getFunVal idx
|
||||
withReader (fun ctx => { ctx with currFnIdx := idx }) do
|
||||
decl.params.forM fun p => updateVarAssignment p.fvarId .top
|
||||
decl.value.forCodeM interpCode
|
||||
match decl.value with
|
||||
| .code code .. => interpCode code
|
||||
| .extern .. => updateCurrFnSummary .top
|
||||
let newVal ← getFunVal idx
|
||||
if currentVal != newVal then
|
||||
return true
|
||||
|
||||
@@ -149,8 +149,10 @@ def Decl.reduceArity (decl : Decl) : CompilerM (Array Decl) := do
|
||||
match decl.value with
|
||||
| .code code =>
|
||||
let used ← collectUsedParams decl
|
||||
if used.size == decl.params.size then
|
||||
return #[decl] -- Declarations uses all parameters
|
||||
if used.size == decl.params.size || used.size == 0 then
|
||||
-- Do nothing if all params were used, or if no params were used. In the latter case,
|
||||
-- this would promote the decl to a constant, which could execute unreachable code.
|
||||
return #[decl]
|
||||
else
|
||||
trace[Compiler.reduceArity] "{decl.name}, used params: {used.toList.map mkFVar}"
|
||||
let mask := decl.params.map fun param => used.contains param.fvarId
|
||||
|
||||
@@ -194,7 +194,7 @@ protected def withFreshMacroScope (x : CoreM α) : CoreM α := do
|
||||
|
||||
instance : MonadQuotation CoreM where
|
||||
getCurrMacroScope := return (← read).currMacroScope
|
||||
getMainModule := return (← get).env.mainModule
|
||||
getMainModule := return (← getEnv).mainModule
|
||||
withFreshMacroScope := Core.withFreshMacroScope
|
||||
|
||||
instance : Elab.MonadInfoTree CoreM where
|
||||
@@ -413,6 +413,26 @@ register_builtin_option stderrAsMessages : Bool := {
|
||||
descr := "(server) capture output to the Lean stderr channel (such as from `dbg_trace`) during elaboration of a command as a diagnostic message"
|
||||
}
|
||||
|
||||
/--
|
||||
Creates snapshot reporting given `withIsolatedStreams` output and diagnostics and traces from the
|
||||
given state.
|
||||
-/
|
||||
def mkSnapshot (output : String) (ctx : Context) (st : State)
|
||||
(desc : String := by exact decl_name%.toString) : BaseIO Language.SnapshotTree := do
|
||||
let mut msgs := st.messages
|
||||
if !output.isEmpty then
|
||||
msgs := msgs.add {
|
||||
fileName := ctx.fileName
|
||||
severity := MessageSeverity.information
|
||||
pos := ctx.fileMap.toPosition <| ctx.ref.getPos?.getD 0
|
||||
data := output
|
||||
}
|
||||
return .mk {
|
||||
desc
|
||||
diagnostics := (← Language.Snapshot.Diagnostics.ofMessageLog msgs)
|
||||
traces := st.traceState
|
||||
} st.snapshotTasks
|
||||
|
||||
open Language in
|
||||
/--
|
||||
Wraps the given action for use in `BaseIO.asTask` etc., discarding its final state except for
|
||||
@@ -443,20 +463,7 @@ def wrapAsyncAsSnapshot (act : Unit → CoreM Unit) (cancelTk? : Option IO.Cance
|
||||
let ctx ← readThe Core.Context
|
||||
return do
|
||||
match (← t.toBaseIO) with
|
||||
| .ok (output, st) =>
|
||||
let mut msgs := st.messages
|
||||
if !output.isEmpty then
|
||||
msgs := msgs.add {
|
||||
fileName := ctx.fileName
|
||||
severity := MessageSeverity.information
|
||||
pos := ctx.fileMap.toPosition <| ctx.ref.getPos?.getD 0
|
||||
data := output
|
||||
}
|
||||
return .mk {
|
||||
desc
|
||||
diagnostics := (← Language.Snapshot.Diagnostics.ofMessageLog msgs)
|
||||
traces := st.traceState
|
||||
} st.snapshotTasks
|
||||
| .ok (output, st) => mkSnapshot output ctx st desc
|
||||
-- interrupt or abort exception as `try catch` above should have caught any others
|
||||
| .error _ => default
|
||||
|
||||
@@ -646,6 +653,11 @@ def logMessageKind (kind : Name) : CoreM Bool := do
|
||||
modify fun s => { s with messages.loggedKinds := s.messages.loggedKinds.insert kind }
|
||||
return true
|
||||
|
||||
@[inherit_doc Environment.enableRealizationsForConst]
|
||||
def enableRealizationsForConst (n : Name) : CoreM Unit := do
|
||||
let env ← (← getEnv).enableRealizationsForConst (← getOptions) n
|
||||
setEnv env
|
||||
|
||||
builtin_initialize
|
||||
registerTraceClass `Elab.async
|
||||
registerTraceClass `Elab.block
|
||||
|
||||
@@ -931,6 +931,7 @@ private def mkInductiveDecl (vars : Array Expr) (elabs : Array InductiveElabStep
|
||||
for ctor in view.ctors do
|
||||
if (ctor.declId.getPos? (canonicalOnly := true)).isSome then
|
||||
Term.addTermInfo' ctor.declId (← mkConstWithLevelParams ctor.declName) (isBinder := true)
|
||||
enableRealizationsForConst ctor.declName
|
||||
return res
|
||||
|
||||
private def mkAuxConstructions (declNames : Array Name) : TermElabM Unit := do
|
||||
|
||||
@@ -161,6 +161,7 @@ private def addNonRecAux (preDef : PreDefinition) (compile : Bool) (all : List N
|
||||
if compile && shouldGenCodeFor preDef then
|
||||
compileDecl decl
|
||||
if applyAttrAfterCompilation then
|
||||
enableRealizationsForConst preDef.declName
|
||||
generateEagerEqns preDef.declName
|
||||
applyAttributesOf #[preDef] AttributeApplicationTime.afterCompilation
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ Assign final attributes to the definitions. Assumes the EqnInfos to be already p
|
||||
def addPreDefAttributes (preDefs : Array PreDefinition) : TermElabM Unit := do
|
||||
for preDef in preDefs do
|
||||
markAsRecursive preDef.declName
|
||||
enableRealizationsForConst preDef.declName
|
||||
generateEagerEqns preDef.declName
|
||||
applyAttributesOf #[preDef] AttributeApplicationTime.afterCompilation
|
||||
-- Unless the user asks for something else, mark the definition as irreducible
|
||||
|
||||
@@ -20,18 +20,23 @@ Simple, coarse-grained equation theorem for nonrecursive definitions.
|
||||
-/
|
||||
private def mkSimpleEqThm (declName : Name) (suffix := Name.mkSimple unfoldThmSuffix) : MetaM (Option Name) := do
|
||||
if let some (.defnInfo info) := (← getEnv).find? declName then
|
||||
let name := declName ++ suffix
|
||||
-- determinism: `name` and `info` are dependent only on `declName`, not any later env
|
||||
-- modifications
|
||||
realizeConst declName name (doRealize name info)
|
||||
return some name
|
||||
else
|
||||
return none
|
||||
where
|
||||
doRealize name info :=
|
||||
lambdaTelescope (cleanupAnnotations := true) info.value fun xs body => do
|
||||
let lhs := mkAppN (mkConst info.name <| info.levelParams.map mkLevelParam) xs
|
||||
let type ← mkForallFVars xs (← mkEq lhs body)
|
||||
let value ← mkLambdaFVars xs (← mkEqRefl lhs)
|
||||
let name := declName ++ suffix
|
||||
addDecl <| Declaration.thmDecl {
|
||||
addDecl <| .thmDecl {
|
||||
name, type, value
|
||||
levelParams := info.levelParams
|
||||
}
|
||||
return some name
|
||||
else
|
||||
return none
|
||||
|
||||
def getEqnsFor? (declName : Name) : MetaM (Option (Array Name)) := do
|
||||
if (← isRecursiveDefinition declName) then
|
||||
|
||||
@@ -193,6 +193,10 @@ def structuralRecursion (preDefs : Array PreDefinition) (termMeasure?s : Array (
|
||||
registerEqnsInfo preDef (preDefs.map (·.declName)) recArgPos numFixed
|
||||
addSmartUnfoldingDef preDef recArgPos
|
||||
markAsRecursive preDef.declName
|
||||
for preDef in preDefs do
|
||||
-- must happen in separate loop so realizations can see eqnInfos of all other preDefs
|
||||
enableRealizationsForConst preDef.declName
|
||||
-- must happen after `enableRealizationsForConst`
|
||||
generateEagerEqns preDef.declName
|
||||
applyAttributesOf preDefsNonRec AttributeApplicationTime.afterCompilation
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ def wfRecursion (preDefs : Array PreDefinition) (termMeasure?s : Array (Option T
|
||||
unless (← isProp preDef.type) do
|
||||
WF.mkUnfoldEq preDef preDefNonRec.declName wfPreprocessProof
|
||||
Mutual.addPreDefAttributes preDefs
|
||||
enableRealizationsForConst preDefNonRec.declName
|
||||
|
||||
builtin_initialize registerTraceClass `Elab.definition.wf
|
||||
|
||||
|
||||
@@ -100,4 +100,7 @@ def mkUnfoldEq (preDef : PreDefinition) (unaryPreDefName : Name) (wfPreprocessPr
|
||||
}
|
||||
trace[Elab.definition.wf] "mkUnfoldEq defined {.ofConstName name}"
|
||||
|
||||
builtin_initialize
|
||||
registerTraceClass `Elab.definition.wf.eqns
|
||||
|
||||
end Lean.Elab.WF
|
||||
|
||||
@@ -839,6 +839,9 @@ private def addProjections (r : ElabHeaderResult) (fieldInfos : Array StructFiel
|
||||
for fieldInfo in fieldInfos do
|
||||
if fieldInfo.isSubobject then
|
||||
addDeclarationRangesFromSyntax fieldInfo.declName r.view.ref fieldInfo.ref
|
||||
for n in projNames do
|
||||
-- projections may generate equation theorems
|
||||
enableRealizationsForConst n
|
||||
|
||||
private def registerStructure (structName : Name) (infos : Array StructFieldInfo) : TermElabM Unit := do
|
||||
let fields ← infos.filterMapM fun info => do
|
||||
|
||||
@@ -274,11 +274,11 @@ partial def enumsPass : Pass where
|
||||
|
||||
let simprocs ← Simp.SimprocsArray.add #[] ``enumsPassPost true
|
||||
let ⟨result?, _⟩ ←
|
||||
simpGoal
|
||||
goal
|
||||
(ctx := simpCtx)
|
||||
(simprocs := simprocs)
|
||||
(fvarIdsToSimp := ← getPropHyps)
|
||||
simpGoal
|
||||
goal
|
||||
(ctx := simpCtx)
|
||||
(simprocs := simprocs)
|
||||
(fvarIdsToSimp := ← getPropHyps)
|
||||
let some (_, newGoal) := result? | return none
|
||||
postprocess newGoal |>.run' {}
|
||||
where
|
||||
|
||||
@@ -18,8 +18,9 @@ it is a non recursive structure and at least one of the following conditions hol
|
||||
- it contains something of type `BitVec`/`UIntX`/`Bool`
|
||||
- it is parametrized by an interesting type
|
||||
- it contains another interesting type
|
||||
Afterwards we also apply relevant `injEq` theorems to support at least equality for these types out
|
||||
of the box.
|
||||
Afterwards we also:
|
||||
- apply relevant `injEq` theorems to support at least equality for these types out of the box.
|
||||
- push projections of relevant types inside of `ite` and `cond`.
|
||||
-/
|
||||
|
||||
namespace Lean.Elab.Tactic.BVDecide
|
||||
@@ -27,6 +28,33 @@ namespace Frontend.Normalize
|
||||
|
||||
open Lean.Meta
|
||||
|
||||
|
||||
def applyIteSimproc : Simp.Simproc := fun e => e.withApp fun proj args => do
|
||||
if h : args.size ≠ 0 then
|
||||
let_expr ite α c instDec t e := args.back | return .continue
|
||||
let params := args.pop
|
||||
let projApp := mkAppN proj params
|
||||
let newT := mkApp projApp t
|
||||
let newE := mkApp projApp e
|
||||
let newIf ← mkAppOptM ``ite #[none, c, instDec, newT, newE]
|
||||
let proof ← mkAppOptM ``apply_ite #[α, none, projApp, c, instDec, t, e]
|
||||
return .visit { expr := newIf, proof? := some proof }
|
||||
else
|
||||
return .continue
|
||||
|
||||
def applyCondSimproc : Simp.Simproc := fun e => e.withApp fun proj args => do
|
||||
if h : args.size ≠ 0 then
|
||||
let_expr cond α c t e := args.back | return .continue
|
||||
let params := args.pop
|
||||
let projApp := mkAppN proj params
|
||||
let newT := mkApp projApp t
|
||||
let newE := mkApp projApp e
|
||||
let newCond ← mkAppOptM ``cond #[none, c, newT, newE]
|
||||
let proof ← mkAppOptM ``Bool.apply_cond #[α, none, projApp, c, t, e]
|
||||
return .visit { expr := newCond, proof? := some proof }
|
||||
else
|
||||
return .continue
|
||||
|
||||
partial def structuresPass : Pass where
|
||||
name := `structures
|
||||
run' goal := do
|
||||
@@ -43,7 +71,9 @@ partial def structuresPass : Pass where
|
||||
| _ => throwError "structures preprocessor generated more than 1 goal"
|
||||
where
|
||||
postprocess (goal : MVarId) (interesting : Std.HashSet Name) : PreProcessM (Option MVarId) := do
|
||||
let env ← getEnv
|
||||
goal.withContext do
|
||||
let mut simprocs : Simprocs := {}
|
||||
let mut relevantLemmas : SimpTheoremsArray := #[]
|
||||
relevantLemmas ← relevantLemmas.addTheorem (.decl ``ne_eq) (← mkConstWithLevelParams ``ne_eq)
|
||||
for const in interesting do
|
||||
@@ -54,14 +84,43 @@ where
|
||||
trace[Meta.Tactic.bv] m!"Using injEq lemma: {lemmaName}"
|
||||
let statement ← mkConstWithLevelParams lemmaName
|
||||
relevantLemmas ← relevantLemmas.addTheorem (.decl lemmaName) statement
|
||||
let fields := (getStructureInfo env const).fieldNames.size
|
||||
let numParams := constInfo.numParams
|
||||
for proj in [0:fields] do
|
||||
-- We use the simprocs with pre such that we push in projections eagerly in order to
|
||||
-- potentially not have to simplify complex structure expressions that we only project one
|
||||
-- element out of.
|
||||
let path := mkDiscrPathFor const numParams proj ``ite 5
|
||||
simprocs := simprocs.addCore path ``applyIteSimproc false (.inl applyIteSimproc)
|
||||
let path := mkDiscrPathFor const numParams proj ``cond 4
|
||||
simprocs := simprocs.addCore path ``applyCondSimproc false (.inl applyCondSimproc)
|
||||
let cfg ← PreProcessM.getConfig
|
||||
let simpCtx ← Simp.mkContext
|
||||
(config := { failIfUnchanged := false, maxSteps := cfg.maxSteps })
|
||||
(simpTheorems := relevantLemmas)
|
||||
(congrTheorems := ← getSimpCongrTheorems)
|
||||
let ⟨result?, _⟩ ← simpGoal goal (ctx := simpCtx) (fvarIdsToSimp := ← getPropHyps)
|
||||
let ⟨result?, _⟩ ←
|
||||
simpGoal
|
||||
goal
|
||||
(ctx := simpCtx)
|
||||
(simprocs := #[simprocs])
|
||||
(fvarIdsToSimp := ← getPropHyps)
|
||||
let some (_, newGoal) := result? | return none
|
||||
return newGoal
|
||||
|
||||
/--
|
||||
For `Prod.fst` and `ite` this function creates the path: `Prod.fst (ite (Prod _ _) _ _ _ _)`.
|
||||
This path can be used to match on applications of structure projections onto control flow primitives.
|
||||
-/
|
||||
mkDiscrPathFor (struct : Name) (structParams : Nat) (projIdx : Nat) (controlFlow : Name)
|
||||
(controlFlowParams : Nat) : Array DiscrTree.Key := Id.run do
|
||||
let stars := structParams + controlFlowParams - 1
|
||||
let mut path : Array DiscrTree.Key := Array.mkEmpty (3 + stars)
|
||||
path := path.push <| .proj struct projIdx 0
|
||||
path := path.push <| .const controlFlow controlFlowParams
|
||||
path := path.push <| .const struct structParams
|
||||
path := Nat.fold (init := path) stars (fun _ _ acc => acc.push .star)
|
||||
return path
|
||||
|
||||
end Frontend.Normalize
|
||||
end Lean.Elab.Tactic.BVDecide
|
||||
|
||||
@@ -173,6 +173,10 @@ partial def mkElimApp (elimInfo : ElimInfo) (targets : Array Expr) (tag : Name)
|
||||
addNewArg arg
|
||||
loop
|
||||
| _ =>
|
||||
let s ← get
|
||||
let ctx ← read
|
||||
unless s.targetPos = ctx.targets.size do
|
||||
throwError "unexpected number of targets for '{elimInfo.elimExpr}'"
|
||||
pure ()
|
||||
let (_, s) ← (loop).run { elimInfo := elimInfo, targets := targets }
|
||||
|>.run { f := elimInfo.elimExpr, fType := elimInfo.elimType, motive := none }
|
||||
|
||||
@@ -24,28 +24,70 @@ Implementation of the `exact?` tactic.
|
||||
def exact? (ref : Syntax) (required : Option (Array (TSyntax `term))) (requireClose : Bool) :
|
||||
TacticM Unit := do
|
||||
let mvar ← getMainGoal
|
||||
let initialState ← saveState
|
||||
let (_, goal) ← (← getMainGoal).intros
|
||||
goal.withContext do
|
||||
let required := (← (required.getD #[]).mapM getFVarId).toList.map .fvar
|
||||
let tactic := fun exfalso =>
|
||||
solveByElim required (exfalso := exfalso) (maxDepth := 6)
|
||||
solveByElim required (exfalso := exfalso) (maxDepth := 6)
|
||||
let allowFailure := fun g => do
|
||||
let g ← g.withContext (instantiateMVars (.mvar g))
|
||||
return required.all fun e => e.occurs g
|
||||
match ← librarySearch goal tactic allowFailure with
|
||||
match (← librarySearch goal tactic allowFailure) with
|
||||
-- Found goal that closed problem
|
||||
| none =>
|
||||
addExactSuggestion ref (← instantiateMVars (mkMVar mvar)).headBeta
|
||||
addSuggestionIfValid ref mvar initialState
|
||||
-- Found suggestions
|
||||
| some suggestions =>
|
||||
if requireClose then throwError
|
||||
"`exact?` could not close the goal. Try `apply?` to see partial suggestions."
|
||||
if requireClose then
|
||||
let hint := if suggestions.isEmpty then "" else " Try `apply?` to see partial suggestions."
|
||||
throwError "`exact?` could not close the goal.{hint}"
|
||||
reportOutOfHeartbeats `apply? ref
|
||||
for (_, suggestionMCtx) in suggestions do
|
||||
withMCtx suggestionMCtx do
|
||||
addExactSuggestion ref (← instantiateMVars (mkMVar mvar)).headBeta (addSubgoalsMsg := true)
|
||||
addSuggestionIfValid ref mvar initialState (addSubgoalsMsg := true) (errorOnInvalid := false)
|
||||
if suggestions.isEmpty then logError "apply? didn't find any relevant lemmas"
|
||||
admitGoal goal
|
||||
where
|
||||
/--
|
||||
Executes `tac` in `savedState` (then restores the current state). Used to ensure that a suggested
|
||||
tactic is valid.
|
||||
|
||||
Remark: we don't merely elaborate the proof term's syntax because it may successfully round-trip
|
||||
(d)elaboration but still produce an invalid tactic (see the example in #5407).
|
||||
-/
|
||||
evalTacticWithState (savedState : Tactic.SavedState) (tac : TSyntax `tactic) : TacticM Unit := do
|
||||
let currState ← saveState
|
||||
savedState.restore
|
||||
try
|
||||
Term.withoutErrToSorry <| withoutRecover <| evalTactic tac
|
||||
finally
|
||||
currState.restore
|
||||
|
||||
/--
|
||||
Suggests using the value of `goal` as a proof term if the corresponding tactic is valid at
|
||||
`origGoal`, or else informs the user that a proof exists but is not syntactically valid.
|
||||
-/
|
||||
addSuggestionIfValid (ref : Syntax) (goal : MVarId) (initialState : Tactic.SavedState)
|
||||
(addSubgoalsMsg := false) (errorOnInvalid := true) : TacticM Unit := do
|
||||
let proofExpr := (← instantiateMVars (mkMVar goal)).headBeta
|
||||
let proofMVars ← getMVars proofExpr
|
||||
let hasMVars := !proofMVars.isEmpty
|
||||
let suggestion ← mkExactSuggestionSyntax proofExpr (useRefine := hasMVars) (exposeNames := false)
|
||||
let mut exposeNames := false
|
||||
try evalTacticWithState initialState suggestion
|
||||
catch _ =>
|
||||
exposeNames := true
|
||||
let suggestion' ← mkExactSuggestionSyntax proofExpr (useRefine := hasMVars) (exposeNames := true)
|
||||
try evalTacticWithState initialState suggestion'
|
||||
catch _ =>
|
||||
let suggestionStr ← SuggestionText.prettyExtra suggestion
|
||||
-- Pretty-print the version without `expose_names` so variable names match the Infoview
|
||||
let msg := m!"found a {if hasMVars then "partial " else ""}proof, \
|
||||
but the corresponding tactic failed:{indentD suggestionStr}"
|
||||
if errorOnInvalid then throwError msg else logInfo msg
|
||||
return
|
||||
addExactSuggestion ref proofExpr (addSubgoalsMsg := addSubgoalsMsg) (exposeNames := exposeNames)
|
||||
|
||||
@[builtin_tactic Lean.Parser.Tactic.exact?]
|
||||
def evalExact : Tactic := fun stx => do
|
||||
@@ -69,7 +111,7 @@ def elabExact?Term : TermElab := fun stx expectedType? => do
|
||||
introdGoal.withContext do
|
||||
if let some suggestions ← librarySearch introdGoal then
|
||||
if suggestions.isEmpty then logError "`exact?%` didn't find any relevant lemmas"
|
||||
else logError "`exact?%` could not close the goal. Try `by apply` to see partial suggestions."
|
||||
else logError "`exact?%` could not close the goal. Try `by apply?` to see partial suggestions."
|
||||
mkLabeledSorry expectedType (synthetic := true) (unique := true)
|
||||
else
|
||||
addTermSuggestion stx (← instantiateMVars goal).headBeta
|
||||
|
||||
@@ -48,14 +48,6 @@ private def isExprAccessible (e : Expr) : MetaM Bool := do
|
||||
let (_, s) ← e.collectFVars |>.run {}
|
||||
s.fvarIds.allM isAccessible
|
||||
|
||||
/-- Creates a temporary local context where all names are exposed, and executes `k`-/
|
||||
private def withExposedNames (k : MetaM α) : MetaM α := do
|
||||
withNewMCtxDepth do
|
||||
-- Create a helper goal to apply
|
||||
let mvarId := (← mkFreshExprMVar (mkConst ``True)).mvarId!
|
||||
let mvarId ← mvarId.exposeNames
|
||||
mvarId.withContext do k
|
||||
|
||||
/-- Executes `tac` in the saved state. This function is used to validate a tactic before suggesting it. -/
|
||||
def checkTactic (savedState : SavedState) (tac : TSyntax `tactic) : TacticM Unit := do
|
||||
let currState ← saveState
|
||||
|
||||
@@ -18,8 +18,10 @@ import Lean.Util.Path
|
||||
import Lean.Util.FindExpr
|
||||
import Lean.Util.Profile
|
||||
import Lean.Util.InstantiateLevelParams
|
||||
import Lean.Util.FoldConsts
|
||||
import Lean.PrivateName
|
||||
import Lean.LoadDynlib
|
||||
import Init.Dynamic
|
||||
|
||||
/-!
|
||||
# Note [Environment Branches]
|
||||
@@ -65,6 +67,12 @@ paths back together.
|
||||
-/
|
||||
|
||||
namespace Lean
|
||||
register_builtin_option debug.skipKernelTC : Bool := {
|
||||
defValue := false
|
||||
group := "debug"
|
||||
descr := "skip kernel type checker. WARNING: setting this option to true may compromise soundness because your proofs will not be checked by the Lean kernel"
|
||||
}
|
||||
|
||||
/-- Opaque environment extension state. -/
|
||||
opaque EnvExtensionStateSpec : (α : Type) × Inhabited α := ⟨Unit, ⟨()⟩⟩
|
||||
def EnvExtensionState : Type := EnvExtensionStateSpec.fst
|
||||
@@ -252,6 +260,28 @@ inductive Exception where
|
||||
| excessiveMemory
|
||||
| deepRecursion
|
||||
| interrupted
|
||||
deriving Nonempty
|
||||
|
||||
/-- Basic `Exception` formatting without `MessageData` dependency. -/
|
||||
private def Exception.toRawString : Kernel.Exception → String
|
||||
| unknownConstant _ constName => s!"(kernel) unknown constant '{constName}'"
|
||||
| alreadyDeclared _ constName => s!"(kernel) constant has already been declared '{constName}'"
|
||||
| declTypeMismatch _ _ _ => s!"(kernel) declaration type mismatch"
|
||||
| declHasMVars _ constName _ => s!"(kernel) declaration has metavariables '{constName}'"
|
||||
| declHasFVars _ constName _ => s!"(kernel) declaration has free variables '{constName}'"
|
||||
| funExpected _ _ e => s!"(kernel) function expected: {e}"
|
||||
| typeExpected _ _ e => s!"(kernel) type expected: {e}"
|
||||
| letTypeMismatch _ _ n _ _ => s!"(kernel) let-declaration type mismatch '{n}'"
|
||||
| exprTypeMismatch _ _ e _ => s!"(kernel) type mismatch at {e}"
|
||||
| appTypeMismatch _ _ e fnType argType =>
|
||||
s!"application type mismatch: {e}\nargument has type {argType}\nbut function has type {fnType}"
|
||||
| invalidProj _ _ e => s!"(kernel) invalid projection {e}"
|
||||
| thmTypeIsNotProp _ constName type => s!"(kernel) type of theorem '{constName}' is not a proposition: {type}"
|
||||
| other msg => s!"(kernel) {msg}"
|
||||
| deterministicTimeout => "(kernel) deterministic timeout"
|
||||
| excessiveMemory => "(kernel) excessive memory consumption detected"
|
||||
| deepRecursion => "(kernel) deep recursion detected"
|
||||
| interrupted => "(kernel) interrupted"
|
||||
|
||||
namespace Environment
|
||||
|
||||
@@ -346,6 +376,7 @@ structure AsyncConstantInfo where
|
||||
sig : Task ConstantVal
|
||||
/-- The final, complete constant info, potentially filled asynchronously. -/
|
||||
constInfo : Task ConstantInfo
|
||||
deriving Inhabited
|
||||
|
||||
namespace AsyncConstantInfo
|
||||
|
||||
@@ -365,21 +396,25 @@ end AsyncConstantInfo
|
||||
|
||||
/--
|
||||
Information about the current branch of the environment representing asynchronous elaboration.
|
||||
|
||||
Use `Environment.enterAsync` instead of `mkRaw`.
|
||||
-/
|
||||
structure AsyncContext where
|
||||
private structure AsyncContext where mkRaw ::
|
||||
/--
|
||||
Name of the declaration asynchronous elaboration was started for. All constants added to this
|
||||
environment branch must have the name as a prefix, after erasing macro scopes and private name
|
||||
prefixes.
|
||||
-/
|
||||
declPrefix : Name
|
||||
/-- Whether we are in `realizeConst`, used to restrict env ext modifications. -/
|
||||
realizing : Bool
|
||||
deriving Nonempty
|
||||
|
||||
/--
|
||||
Checks whether a declaration named `n` may be added to the environment in the given context. See
|
||||
also `AsyncContext.declPrefix`.
|
||||
-/
|
||||
def AsyncContext.mayContain (ctx : AsyncContext) (n : Name) : Bool :=
|
||||
private def AsyncContext.mayContain (ctx : AsyncContext) (n : Name) : Bool :=
|
||||
ctx.declPrefix.isPrefixOf <| privateToUserName n.eraseMacroScopes
|
||||
|
||||
/--
|
||||
@@ -394,29 +429,47 @@ structure AsyncConst where
|
||||
exts? : Option (Task (Array EnvExtensionState))
|
||||
|
||||
/-- Data structure holding a sequence of `AsyncConst`s optimized for efficient access. -/
|
||||
structure AsyncConsts where
|
||||
toArray : Array AsyncConst := #[]
|
||||
private structure AsyncConsts where
|
||||
size : Nat
|
||||
revList : List AsyncConst
|
||||
/-- Map from declaration name to const for fast direct access. -/
|
||||
private map : NameMap AsyncConst := {}
|
||||
map : NameMap AsyncConst
|
||||
/-- Trie of declaration names without private name prefixes for fast longest-prefix access. -/
|
||||
private normalizedTrie : NameTrie AsyncConst := {}
|
||||
normalizedTrie : NameTrie AsyncConst
|
||||
deriving Inhabited
|
||||
|
||||
def AsyncConsts.add (aconsts : AsyncConsts) (aconst : AsyncConst) : AsyncConsts :=
|
||||
private def AsyncConsts.add (aconsts : AsyncConsts) (aconst : AsyncConst) : AsyncConsts :=
|
||||
{ aconsts with
|
||||
toArray := aconsts.toArray.push aconst
|
||||
size := aconsts.size + 1
|
||||
revList := aconst :: aconsts.revList
|
||||
map := aconsts.map.insert aconst.constInfo.name aconst
|
||||
normalizedTrie := aconsts.normalizedTrie.insert (privateToUserName aconst.constInfo.name) aconst
|
||||
}
|
||||
|
||||
def AsyncConsts.find? (aconsts : AsyncConsts) (declName : Name) : Option AsyncConst :=
|
||||
private def AsyncConsts.find? (aconsts : AsyncConsts) (declName : Name) : Option AsyncConst :=
|
||||
aconsts.map.find? declName
|
||||
|
||||
/-- Finds the constant in the collection that is a prefix of `declName`, if any. -/
|
||||
def AsyncConsts.findPrefix? (aconsts : AsyncConsts) (declName : Name) : Option AsyncConst :=
|
||||
private def AsyncConsts.findPrefix? (aconsts : AsyncConsts) (declName : Name) : Option AsyncConst :=
|
||||
-- as macro scopes are a strict suffix,
|
||||
aconsts.normalizedTrie.findLongestPrefix? (privateToUserName declName.eraseMacroScopes)
|
||||
|
||||
/-- Context for `realizeConst` established by `enableRealizationsForConst`. -/
|
||||
private structure RealizationContext where
|
||||
/--
|
||||
Saved `Environment`, untyped to avoid cyclic reference. Import environment for imported constants.
|
||||
-/
|
||||
env : NonScalar
|
||||
/-- Saved options. Empty for imported constants. -/
|
||||
opts : Options
|
||||
/--
|
||||
`realizeConst _ c ..` adds a mapping from `c` to a task of the realization results: the newly
|
||||
added constants (incl. extension data in `AsyncConst.exts?`), a function for replaying the
|
||||
changes onto a derived kernel environment, and auxiliary data (always `SnapshotTree` in builtin
|
||||
uses, but untyped to avoid cyclic module references).
|
||||
-/
|
||||
constsRef : IO.Ref (NameMap (Task (List AsyncConst × (Kernel.Environment → Kernel.Environment) × Dynamic)))
|
||||
|
||||
/--
|
||||
Elaboration-specific extension of `Kernel.Environment` that adds tracking of asynchronously
|
||||
elaborated declarations.
|
||||
@@ -443,19 +496,32 @@ structure Environment where
|
||||
-/
|
||||
checked : Task Kernel.Environment := .pure checkedWithoutAsync
|
||||
/--
|
||||
Container of asynchronously elaborated declarations, i.e.
|
||||
`checked = checkedWithoutAsync ⨃ asyncConsts`.
|
||||
Container of asynchronously elaborated declarations. For consistency, `updateBaseAfterKernelAdd`
|
||||
makes sure this contains constants added even synchronously, i.e. this is a superset of
|
||||
`checkedWithoutAsync` except for imported constants.
|
||||
-/
|
||||
private asyncConsts : AsyncConsts := {}
|
||||
private asyncConsts : AsyncConsts := default
|
||||
/-- Information about this asynchronous branch of the environment, if any. -/
|
||||
private asyncCtx? : Option AsyncContext := none
|
||||
/--
|
||||
Realized constants belonging to imported declarations. `none` only from `Environment.ofKernelEnv`,
|
||||
which should never leak into general elaboration.
|
||||
-/
|
||||
private realizedImportedConsts? : Option RealizationContext
|
||||
/--
|
||||
Realized constants belonging to local declarations. This is a map from local declarations, which
|
||||
need to be registered synchronously using `enableRealizationsForConst`, to their realization
|
||||
context incl. a ref of realized constants.
|
||||
-/
|
||||
private realizedLocalConsts : NameMap RealizationContext := {}
|
||||
deriving Nonempty
|
||||
|
||||
namespace Environment
|
||||
|
||||
-- used only when the kernel calls into the interpreter, and in `Lean.Kernel.Exception.mkCtx`
|
||||
@[export lean_elab_environment_of_kernel_env]
|
||||
def ofKernelEnv (env : Kernel.Environment) : Environment :=
|
||||
{ checkedWithoutAsync := env }
|
||||
{ checkedWithoutAsync := env, realizedImportedConsts? := none }
|
||||
|
||||
@[export lean_elab_environment_to_kernel_env]
|
||||
def toKernelEnv (env : Environment) : Kernel.Environment :=
|
||||
@@ -469,6 +535,10 @@ private def modifyCheckedAsync (env : Environment) (f : Kernel.Environment → K
|
||||
private def setCheckedSync (env : Environment) (newChecked : Kernel.Environment) : Environment :=
|
||||
{ env with checked := .pure newChecked, checkedWithoutAsync := newChecked }
|
||||
|
||||
/-- True while inside `realizeConst`'s `realize`. -/
|
||||
def isRealizing (env : Environment) : Bool :=
|
||||
env.asyncCtx?.any (·.realizing)
|
||||
|
||||
/--
|
||||
Checks whether the given declaration name may potentially added, or have been added, to the current
|
||||
environment branch, which is the case either if this is the main branch or if the declaration name
|
||||
@@ -574,6 +644,30 @@ def findConstVal? (env : Environment) (n : Name) : Option ConstantVal := do
|
||||
return asyncConst.constInfo.toConstantVal
|
||||
else env.findNoAsync n |>.map (·.toConstantVal)
|
||||
|
||||
/--
|
||||
Allows `realizeConst` calls for the given declaration in all derived environment branches.
|
||||
Realizations will run using the given environment and options to ensure deterministic results. Note
|
||||
that while we check that the function isn't called too *early*, i.e. before the declaration is
|
||||
actually added to the environment, we cannot automatically check that it isn't called too *late*,
|
||||
i.e. before all environment extensions that may be relevant to realizations have been set. We do
|
||||
check that we are not calling it from a different branch than `c` was added on, which would be
|
||||
definitely too late.
|
||||
-/
|
||||
def enableRealizationsForConst (env : Environment) (opts : Options) (c : Name) :
|
||||
BaseIO Environment := do
|
||||
if env.findAsync? c |>.isNone then
|
||||
panic! s!"Environment.enableRealizationsForConst: declaration {c} not found in environment"
|
||||
if let some asyncCtx := env.asyncCtx? then
|
||||
if !asyncCtx.mayContain c then
|
||||
panic! s!"Environment.enableRealizationsForConst: {c} is outside current context {asyncCtx.declPrefix}"
|
||||
if env.realizedLocalConsts.contains c then
|
||||
return env
|
||||
return { env with realizedLocalConsts := env.realizedLocalConsts.insert c {
|
||||
-- safety: `RealizationContext` is private
|
||||
env := unsafe unsafeCast env
|
||||
opts
|
||||
constsRef := (← IO.mkRef {}) } }
|
||||
|
||||
/--
|
||||
Looks up the given declaration name in the environment, blocking on the corresponding elaboration
|
||||
task if not yet complete.
|
||||
@@ -590,9 +684,14 @@ def find? (env : Environment) (n : Name) : Option ConstantInfo :=
|
||||
def dbgFormatAsyncState (env : Environment) : BaseIO String :=
|
||||
return s!"\
|
||||
asyncCtx.declPrefix: {repr <| env.asyncCtx?.map (·.declPrefix)}\
|
||||
\nasyncConsts: {repr <| env.asyncConsts.toArray.map (·.constInfo.name)}\
|
||||
\ncheckedWithoutAsync.constants.map₂: {repr <|
|
||||
env.checkedWithoutAsync.constants.map₂.toList.map (·.1)}"
|
||||
\nasyncConsts: {repr <| env.asyncConsts.revList.reverse.map (·.constInfo.name)}\
|
||||
\nrealizedLocalConsts: {repr (← env.realizedLocalConsts.toList.mapM fun (n, ctx) => do
|
||||
let consts := (← ctx.constsRef.get).toList
|
||||
return (n, consts.map (·.1)))}
|
||||
\nrealizedImportedConsts?: {repr <| (← env.realizedImportedConsts?.mapM fun ctx => do
|
||||
return (← ctx.constsRef.get).toList.map fun (n, m?) =>
|
||||
(n, m?.get.1.map (fun c : AsyncConst => c.constInfo.name.toString) |> toString))}
|
||||
\ncheckedWithoutAsync.constants.map₂: {repr <| env.checkedWithoutAsync.constants.map₂.toList.map (·.1)}"
|
||||
|
||||
/-- Returns debug output about the synchronous state of the environment. -/
|
||||
def dbgFormatCheckedSyncState (env : Environment) : BaseIO String :=
|
||||
@@ -614,6 +713,13 @@ structure PromiseCheckedResult where
|
||||
asyncEnv : Environment
|
||||
private checkedEnvPromise : IO.Promise Kernel.Environment
|
||||
|
||||
/-- Creates an async context for the given declaration name, normalizing it for use as a prefix. -/
|
||||
private def enterAsync (declName : Name) (realizing := false) (env : Environment) : Environment :=
|
||||
{ env with asyncCtx? := some {
|
||||
declPrefix := privateToUserName declName.eraseMacroScopes
|
||||
-- `realizing` is sticky
|
||||
realizing := realizing || env.asyncCtx?.any (·.realizing) } }
|
||||
|
||||
/--
|
||||
Starts an asynchronous modification of the kernel environment. The environment is split into a
|
||||
"main" branch that will block on access to the kernel environment until
|
||||
@@ -626,10 +732,8 @@ def promiseChecked (env : Environment) : BaseIO PromiseCheckedResult := do
|
||||
checked := checkedEnvPromise.result?.bind (sync := true) fun
|
||||
| some kenv => .pure kenv
|
||||
| none => env.checked }
|
||||
asyncEnv := { env with
|
||||
-- Do not allow adding new constants
|
||||
asyncCtx? := some { declPrefix := `__reserved__Environment_promiseChecked }
|
||||
}
|
||||
-- Do not allow adding new constants
|
||||
asyncEnv := env.enterAsync `__reserved__Environment_promiseChecked
|
||||
checkedEnvPromise
|
||||
}
|
||||
|
||||
@@ -664,28 +768,14 @@ structure AddConstAsyncResult where
|
||||
private extensionsPromise : IO.Promise (Array EnvExtensionState)
|
||||
private checkedEnvPromise : IO.Promise Kernel.Environment
|
||||
|
||||
/--
|
||||
Starts the asynchronous addition of a constant to the environment. The environment is split into a
|
||||
"main" branch that holds a reference to the constant to be added but will block on access until the
|
||||
corresponding information has been added on the "async" environment branch and committed there; see
|
||||
the respective fields of `AddConstAsyncResult` as well as the [Environment Branches] note for more
|
||||
information.
|
||||
-/
|
||||
def addConstAsync (env : Environment) (constName : Name) (kind : ConstantKind) (reportExts := true) :
|
||||
IO AddConstAsyncResult := do
|
||||
assert! env.asyncMayContain constName
|
||||
let sigPromise ← IO.Promise.new
|
||||
let infoPromise ← IO.Promise.new
|
||||
let extensionsPromise ← IO.Promise.new
|
||||
let checkedEnvPromise ← IO.Promise.new
|
||||
|
||||
-- fallback info in case promises are dropped unfulfilled
|
||||
let fallbackVal := {
|
||||
/-- Creates fallback info to be used in case promises are dropped unfulfilled. -/
|
||||
private def mkFallbackConstInfo (constName : Name) (kind : ConstantKind) : ConstantInfo :=
|
||||
let fallbackVal : ConstantVal := {
|
||||
name := constName
|
||||
levelParams := []
|
||||
type := mkApp2 (mkConst ``sorryAx [0]) (mkSort 0) (mkConst ``true)
|
||||
type := mkApp2 (mkConst ``sorryAx [1]) (mkSort 0) (mkConst ``true)
|
||||
}
|
||||
let fallbackInfo := match kind with
|
||||
match kind with
|
||||
| .defn => .defnInfo { fallbackVal with
|
||||
value := mkApp2 (mkConst ``sorryAx [0]) fallbackVal.type (mkConst ``true)
|
||||
hints := .abbrev
|
||||
@@ -697,16 +787,38 @@ def addConstAsync (env : Environment) (constName : Name) (kind : ConstantKind) (
|
||||
| .axiom => .axiomInfo { fallbackVal with
|
||||
isUnsafe := false
|
||||
}
|
||||
| k => panic! s!"AddConstAsyncResult.addConstAsync: unsupported constant kind {repr k}"
|
||||
| k => panic! s!"Environment.mkFallbackConstInfo: unsupported constant kind {repr k}"
|
||||
|
||||
/--
|
||||
Starts the asynchronous addition of a constant to the environment. The environment is split into a
|
||||
"main" branch that holds a reference to the constant to be added but will block on access until the
|
||||
corresponding information has been added on the "async" environment branch and committed there; see
|
||||
the respective fields of `AddConstAsyncResult` as well as the [Environment Branches] note for more
|
||||
information.
|
||||
-/
|
||||
def addConstAsync (env : Environment) (constName : Name) (kind : ConstantKind) (reportExts := true)
|
||||
(checkMayContain := true) :
|
||||
IO AddConstAsyncResult := do
|
||||
if checkMayContain then
|
||||
if let some ctx := env.asyncCtx? then
|
||||
if !ctx.mayContain constName then
|
||||
throw <| .userError s!"cannot add declaration {constName} to environment as it is \
|
||||
restricted to the prefix {ctx.declPrefix}"
|
||||
let sigPromise ← IO.Promise.new
|
||||
let infoPromise ← IO.Promise.new
|
||||
let extensionsPromise ← IO.Promise.new
|
||||
let checkedEnvPromise ← IO.Promise.new
|
||||
|
||||
let fallbackConstInfo := mkFallbackConstInfo constName kind
|
||||
|
||||
let asyncConst := {
|
||||
constInfo := {
|
||||
name := constName
|
||||
kind
|
||||
sig := sigPromise.resultD fallbackVal
|
||||
constInfo := infoPromise.resultD fallbackInfo
|
||||
sig := sigPromise.resultD fallbackConstInfo.toConstantVal
|
||||
constInfo := infoPromise.resultD fallbackConstInfo
|
||||
}
|
||||
exts? := guard reportExts *> some (extensionsPromise.resultD #[])
|
||||
exts? := guard reportExts *> some (extensionsPromise.resultD env.toKernelEnv.extensions)
|
||||
}
|
||||
return {
|
||||
constName, kind
|
||||
@@ -715,9 +827,7 @@ def addConstAsync (env : Environment) (constName : Name) (kind : ConstantKind) (
|
||||
checked := checkedEnvPromise.result?.bind (sync := true) fun
|
||||
| some kenv => .pure kenv
|
||||
| none => env.checked }
|
||||
asyncEnv := { env with
|
||||
asyncCtx? := some { declPrefix := privateToUserName constName.eraseMacroScopes }
|
||||
}
|
||||
asyncEnv := env.enterAsync constName
|
||||
sigPromise, infoPromise, extensionsPromise, checkedEnvPromise
|
||||
}
|
||||
|
||||
@@ -880,6 +990,9 @@ inductive EnvExtension.AsyncMode where
|
||||
| async
|
||||
deriving Inhabited
|
||||
|
||||
abbrev ReplayFn (σ : Type) :=
|
||||
(oldState : σ) → (newState : σ) → (newConsts : List Name) → σ → σ
|
||||
|
||||
/--
|
||||
Environment extension, can only be generated by `registerEnvExtension` that allocates a unique index
|
||||
for this extension into each environment's extension state's array.
|
||||
@@ -888,6 +1001,13 @@ structure EnvExtension (σ : Type) where private mk ::
|
||||
idx : Nat
|
||||
mkInitial : IO σ
|
||||
asyncMode : EnvExtension.AsyncMode
|
||||
/--
|
||||
Optional function that, given state before and after realization and newly added constants,
|
||||
replays this change onto a state from another (derived) environment. This function is used only
|
||||
when making changes to an extension inside a `realizeConst` call, in which case it must be
|
||||
present.
|
||||
-/
|
||||
replay? : Option (ReplayFn σ)
|
||||
deriving Inhabited
|
||||
|
||||
namespace EnvExtension
|
||||
@@ -949,19 +1069,24 @@ from different environment branches are reconciled.
|
||||
Note that in modes `sync` and `async`, `f` will be called twice, on the local and on the `checked`
|
||||
state.
|
||||
-/
|
||||
def modifyState {σ : Type} (ext : EnvExtension σ) (env : Environment) (f : σ → σ) : Environment :=
|
||||
def modifyState {σ : Type} (ext : EnvExtension σ) (env : Environment) (f : σ → σ) : Environment := Id.run do
|
||||
-- safety: `ext`'s constructor is private, so we can assume the entry at `ext.idx` is of type `σ`
|
||||
match ext.asyncMode with
|
||||
| .mainOnly =>
|
||||
if let some asyncCtx := env.asyncCtx? then
|
||||
let _ : Inhabited Environment := ⟨env⟩
|
||||
panic! s!"Environment.modifyState: environment extension is marked as `mainOnly` but used in \
|
||||
async context '{asyncCtx.declPrefix}'"
|
||||
else
|
||||
{ env with checkedWithoutAsync.extensions := unsafe ext.modifyStateImpl env.checkedWithoutAsync.extensions f }
|
||||
{if asyncCtx.realizing then "realization" else "async"} context '{asyncCtx.declPrefix}'"
|
||||
return { env with checkedWithoutAsync.extensions := unsafe ext.modifyStateImpl env.checkedWithoutAsync.extensions f }
|
||||
| .local =>
|
||||
{ env with checkedWithoutAsync.extensions := unsafe ext.modifyStateImpl env.checkedWithoutAsync.extensions f }
|
||||
if let some asyncCtx := env.asyncCtx?.filter (·.realizing) then
|
||||
panic! s!"Environment.modifyState: environment extension is marked as `local` but used in \
|
||||
realization context '{asyncCtx.declPrefix}'"
|
||||
return { env with checkedWithoutAsync.extensions := unsafe ext.modifyStateImpl env.checkedWithoutAsync.extensions f }
|
||||
| _ =>
|
||||
if ext.replay?.isNone then
|
||||
if let some asyncCtx := env.asyncCtx?.filter (·.realizing) then
|
||||
panic! s!"Environment.modifyState: environment extension must set `replay?` field to be \
|
||||
used in realization context '{asyncCtx.declPrefix}'"
|
||||
env.modifyCheckedAsync fun env =>
|
||||
{ env with extensions := unsafe ext.modifyStateImpl env.extensions f }
|
||||
|
||||
@@ -992,6 +1117,24 @@ recommended and should be considered only for important optimizations.
|
||||
opaque getState {σ : Type} [Inhabited σ] (ext : EnvExtension σ) (env : Environment)
|
||||
(asyncMode := ext.asyncMode) : σ
|
||||
|
||||
-- `unsafe` fails to infer `Nonempty` here
|
||||
private unsafe def findStateAsyncUnsafe {σ : Type} [Inhabited σ]
|
||||
(ext : EnvExtension σ) (env : Environment) (declPrefix : Name) : σ :=
|
||||
-- safety: `ext`'s constructor is private, so we can assume the entry at `ext.idx` is of type `σ`
|
||||
if let some { exts? := some exts, .. } := env.asyncConsts.findPrefix? declPrefix then
|
||||
ext.getStateImpl exts.get
|
||||
else
|
||||
ext.getStateImpl env.checkedWithoutAsync.extensions
|
||||
|
||||
/--
|
||||
Returns the final extension state on the environment branch corresponding to the passed declaration
|
||||
name, if any, or otherwise the state on the current branch. In other words, at most one environment
|
||||
branch will be blocked on.
|
||||
-/
|
||||
@[implemented_by findStateAsyncUnsafe]
|
||||
opaque findStateAsync {σ : Type} [Inhabited σ] (ext : EnvExtension σ)
|
||||
(env : Environment) (declPrefix : Name) : σ
|
||||
|
||||
end EnvExtension
|
||||
|
||||
/-- Environment extensions can only be registered during initialization.
|
||||
@@ -1002,12 +1145,13 @@ end EnvExtension
|
||||
Note that by default, extension state is *not* stored in .olean files and will not propagate across `import`s.
|
||||
For that, you need to register a persistent environment extension. -/
|
||||
def registerEnvExtension {σ : Type} (mkInitial : IO σ)
|
||||
(replay? : Option (ReplayFn σ) := none)
|
||||
(asyncMode : EnvExtension.AsyncMode := .mainOnly) : IO (EnvExtension σ) := do
|
||||
unless (← initializing) do
|
||||
throw (IO.userError "failed to register environment, extensions can only be registered during initialization")
|
||||
let exts ← EnvExtension.envExtensionsRef.get
|
||||
let idx := exts.size
|
||||
let ext : EnvExtension σ := { idx, mkInitial, asyncMode }
|
||||
let ext : EnvExtension σ := { idx, mkInitial, asyncMode, replay? }
|
||||
-- safety: `EnvExtensionState` is opaque, so we can upcast to it
|
||||
EnvExtension.envExtensionsRef.modify fun exts => exts.push (unsafe unsafeCast ext)
|
||||
pure ext
|
||||
@@ -1019,7 +1163,7 @@ def mkEmptyEnvironment (trustLevel : UInt32 := 0) : IO Environment := do
|
||||
let initializing ← IO.initializing
|
||||
if initializing then throw (IO.userError "environment objects cannot be created during initialization")
|
||||
let exts ← mkInitialExtensionStates
|
||||
pure {
|
||||
return {
|
||||
checkedWithoutAsync := {
|
||||
const2ModIdx := {}
|
||||
constants := {}
|
||||
@@ -1027,6 +1171,7 @@ def mkEmptyEnvironment (trustLevel : UInt32 := 0) : IO Environment := do
|
||||
extraConstNames := {}
|
||||
extensions := exts
|
||||
}
|
||||
realizedImportedConsts? := none
|
||||
}
|
||||
|
||||
structure PersistentEnvExtensionState (α : Type) (σ : Type) where
|
||||
@@ -1117,8 +1262,9 @@ def addEntry {α β σ : Type} (ext : PersistentEnvExtension α β σ) (env : En
|
||||
{ s with state := state }
|
||||
|
||||
/-- Get the current state of the given extension in the given environment. -/
|
||||
def getState {α β σ : Type} [Inhabited σ] (ext : PersistentEnvExtension α β σ) (env : Environment) : σ :=
|
||||
(ext.toEnvExtension.getState env).state
|
||||
def getState {α β σ : Type} [Inhabited σ] (ext : PersistentEnvExtension α β σ) (env : Environment)
|
||||
(asyncMode := ext.toEnvExtension.asyncMode) : σ :=
|
||||
(ext.toEnvExtension.getState (asyncMode := asyncMode) env).state
|
||||
|
||||
/-- Set the current state of the given extension in the given environment. -/
|
||||
def setState {α β σ : Type} (ext : PersistentEnvExtension α β σ) (env : Environment) (s : σ) : Environment :=
|
||||
@@ -1128,23 +1274,11 @@ def setState {α β σ : Type} (ext : PersistentEnvExtension α β σ) (env : En
|
||||
def modifyState {α β σ : Type} (ext : PersistentEnvExtension α β σ) (env : Environment) (f : σ → σ) : Environment :=
|
||||
ext.toEnvExtension.modifyState env fun ps => { ps with state := f (ps.state) }
|
||||
|
||||
-- `unsafe` fails to infer `Nonempty` here
|
||||
private unsafe def findStateAsyncUnsafe {α β σ : Type} [Inhabited σ]
|
||||
(ext : PersistentEnvExtension α β σ) (env : Environment) (declPrefix : Name) : σ :=
|
||||
-- safety: `ext`'s constructor is private, so we can assume the entry at `ext.idx` is of type `σ`
|
||||
if let some { exts? := some exts, .. } := env.asyncConsts.findPrefix? declPrefix then
|
||||
ext.toEnvExtension.getStateImpl exts.get |>.state
|
||||
else
|
||||
ext.toEnvExtension.getStateImpl env.checkedWithoutAsync.extensions |>.state
|
||||
@[inherit_doc EnvExtension.findStateAsync]
|
||||
def findStateAsync {α β σ : Type} [Inhabited σ] (ext : PersistentEnvExtension α β σ)
|
||||
(env : Environment) (declPrefix : Name) : σ :=
|
||||
ext.toEnvExtension.findStateAsync env declPrefix |>.state
|
||||
|
||||
/--
|
||||
Returns the final extension state on the environment branch corresponding to the passed declaration
|
||||
name, if any, or otherwise the state on the current branch. In other words, at most one environment
|
||||
branch will be blocked on.
|
||||
-/
|
||||
@[implemented_by findStateAsyncUnsafe]
|
||||
opaque findStateAsync {α β σ : Type} [Inhabited σ] (ext : PersistentEnvExtension α β σ)
|
||||
(env : Environment) (declPrefix : Name) : σ
|
||||
|
||||
end PersistentEnvExtension
|
||||
|
||||
@@ -1158,11 +1292,14 @@ structure PersistentEnvExtensionDescr (α β σ : Type) where
|
||||
exportEntriesFn : σ → Array α
|
||||
statsFn : σ → Format := fun _ => Format.nil
|
||||
asyncMode : EnvExtension.AsyncMode := .mainOnly
|
||||
replay? : Option (ReplayFn σ) := none
|
||||
|
||||
unsafe def registerPersistentEnvExtensionUnsafe {α β σ : Type} [Inhabited σ] (descr : PersistentEnvExtensionDescr α β σ) : IO (PersistentEnvExtension α β σ) := do
|
||||
let pExts ← persistentEnvExtensionsRef.get
|
||||
if pExts.any (fun ext => ext.name == descr.name) then throw (IO.userError s!"invalid environment extension, '{descr.name}' has already been used")
|
||||
let ext ← registerEnvExtension (asyncMode := descr.asyncMode) do
|
||||
let replay? := descr.replay?.map fun replay =>
|
||||
fun oldState newState newConsts s => { s with state := replay oldState.state newState.state newConsts s.state }
|
||||
let ext ← registerEnvExtension (asyncMode := descr.asyncMode) (replay? := replay?) do
|
||||
let initial ← descr.mkInitial
|
||||
let s : PersistentEnvExtensionState α σ := {
|
||||
importedEntries := #[],
|
||||
@@ -1206,6 +1343,9 @@ def registerSimplePersistentEnvExtension {α σ : Type} [Inhabited σ] (descr :
|
||||
exportEntriesFn := fun s => descr.toArrayFn s.1.reverse,
|
||||
statsFn := fun s => format "number of local entries: " ++ format s.1.length
|
||||
asyncMode := descr.asyncMode
|
||||
replay? := some fun oldState newState _ (entries, s) =>
|
||||
let newEntries := newState.1.drop oldState.1.length
|
||||
(newEntries ++ entries, newEntries.foldl descr.addEntryFn s)
|
||||
}
|
||||
|
||||
namespace SimplePersistentEnvExtension
|
||||
@@ -1219,8 +1359,9 @@ def getEntries {α σ : Type} [Inhabited σ] (ext : SimplePersistentEnvExtension
|
||||
(PersistentEnvExtension.getState ext env).1
|
||||
|
||||
/-- Get the current state of the given `SimplePersistentEnvExtension`. -/
|
||||
def getState {α σ : Type} [Inhabited σ] (ext : SimplePersistentEnvExtension α σ) (env : Environment) : σ :=
|
||||
(PersistentEnvExtension.getState ext env).2
|
||||
def getState {α σ : Type} [Inhabited σ] (ext : SimplePersistentEnvExtension α σ) (env : Environment)
|
||||
(asyncMode := ext.toEnvExtension.asyncMode) : σ :=
|
||||
(PersistentEnvExtension.getState (asyncMode := asyncMode) ext env).2
|
||||
|
||||
/-- Set the current state of the given `SimplePersistentEnvExtension`. This change is *not* persisted across files. -/
|
||||
def setState {α σ : Type} (ext : SimplePersistentEnvExtension α σ) (env : Environment) (s : σ) : Environment :=
|
||||
@@ -1230,6 +1371,11 @@ def setState {α σ : Type} (ext : SimplePersistentEnvExtension α σ) (env : En
|
||||
def modifyState {α σ : Type} (ext : SimplePersistentEnvExtension α σ) (env : Environment) (f : σ → σ) : Environment :=
|
||||
PersistentEnvExtension.modifyState ext env (fun ⟨entries, s⟩ => (entries, f s))
|
||||
|
||||
@[inherit_doc PersistentEnvExtension.findStateAsync]
|
||||
def findStateAsync {α σ : Type} [Inhabited σ] (ext : SimplePersistentEnvExtension α σ)
|
||||
(env : Environment) (declPrefix : Name) : σ :=
|
||||
PersistentEnvExtension.findStateAsync ext env declPrefix |>.2
|
||||
|
||||
end SimplePersistentEnvExtension
|
||||
|
||||
/-- Environment extension for tagging declarations.
|
||||
@@ -1329,8 +1475,12 @@ unsafe def Environment.freeRegions (env : Environment) : IO Unit :=
|
||||
|
||||
def mkModuleData (env : Environment) : IO ModuleData := do
|
||||
let pExts ← persistentEnvExtensionsRef.get
|
||||
let entries := pExts.map fun pExt =>
|
||||
let state := pExt.getState env
|
||||
let entries := pExts.map fun pExt => Id.run do
|
||||
-- get state from `checked` at the end if `async`; it would otherwise panic
|
||||
let mut asyncMode := pExt.toEnvExtension.asyncMode
|
||||
if asyncMode matches .async then
|
||||
asyncMode := .sync
|
||||
let state := pExt.getState (asyncMode := asyncMode) env
|
||||
(pExt.name, pExt.exportEntriesFn state)
|
||||
let kenv := env.toKernelEnv
|
||||
let constNames := kenv.constants.foldStage2 (fun names name _ => names.push name) #[]
|
||||
@@ -1403,7 +1553,9 @@ where
|
||||
let pExtDescrs ← persistentEnvExtensionsRef.get
|
||||
if h : i < pExtDescrs.size then
|
||||
let extDescr := pExtDescrs[i]
|
||||
let s := extDescr.toEnvExtension.getState env
|
||||
-- `local` as `async` does not allow for `getState` but it's all safe here as there is only
|
||||
-- one branch so far.
|
||||
let s := extDescr.toEnvExtension.getState (asyncMode := .local) env
|
||||
let prevSize := (← persistentEnvExtensionsRef.get).size
|
||||
let prevAttrSize ← getNumBuiltinAttributes
|
||||
let newState ← extDescr.addImportedFn s.importedEntries { env := env, opts := opts }
|
||||
@@ -1522,6 +1674,7 @@ def finalizeImport (s : ImportState) (imports : Array Import) (opts : Options) (
|
||||
moduleData := s.moduleData
|
||||
}
|
||||
}
|
||||
realizedImportedConsts? := none
|
||||
}
|
||||
env ← setImportedEntries env s.moduleData
|
||||
if leakEnv then
|
||||
@@ -1539,6 +1692,14 @@ def finalizeImport (s : ImportState) (imports : Array Import) (opts : Options) (
|
||||
Safety: There are no concurrent accesses to `env` at this point. -/
|
||||
env ← unsafe Runtime.markPersistent env
|
||||
env ← finalizePersistentExtensions env s.moduleData opts
|
||||
env := { env with
|
||||
realizedImportedConsts? := some {
|
||||
-- safety: `RealizationContext` is private
|
||||
env := unsafe unsafeCast env
|
||||
opts
|
||||
constsRef := (← IO.mkRef {})
|
||||
}
|
||||
}
|
||||
if leakEnv then
|
||||
/- Ensure the final environment including environment extension states is
|
||||
marked persistent as documented.
|
||||
@@ -1583,6 +1744,9 @@ builtin_initialize namespacesExt : SimplePersistentEnvExtension Name NameSSet
|
||||
let map := mkStateFromImportedEntries (fun map name => map.insert name ()) map as
|
||||
SMap.fromHashMap map |>.switch
|
||||
addEntryFn := fun s n => s.insert n
|
||||
-- Namespaces from local helper constants can be disregarded in other environment branches. We
|
||||
-- do *not* want `getNamespaceSet` to have to wait on all prior branches.
|
||||
asyncMode := .local
|
||||
}
|
||||
|
||||
@[inherit_doc Kernel.Environment.enableDiag]
|
||||
@@ -1616,8 +1780,18 @@ def getNamespaceSet (env : Environment) : NameSSet :=
|
||||
namespacesExt.getState env
|
||||
|
||||
@[export lean_elab_environment_update_base_after_kernel_add]
|
||||
private def updateBaseAfterKernelAdd (env : Environment) (kernel : Kernel.Environment) : Environment :=
|
||||
{ env with checked := .pure kernel, checkedWithoutAsync := { kernel with extensions := env.checkedWithoutAsync.extensions } }
|
||||
private def updateBaseAfterKernelAdd (env : Environment) (kernel : Kernel.Environment) (decl : Declaration) : Environment :=
|
||||
{ env with
|
||||
checked := .pure kernel
|
||||
checkedWithoutAsync := { kernel with extensions := env.checkedWithoutAsync.extensions }
|
||||
-- make constants available in `asyncConsts` as well; see its docstring
|
||||
asyncConsts := decl.getNames.foldl (init := env.asyncConsts) fun asyncConsts n =>
|
||||
if asyncConsts.find? n |>.isNone then
|
||||
asyncConsts.add {
|
||||
constInfo := .ofConstantInfo (kernel.find? n |>.get!)
|
||||
exts? := none
|
||||
}
|
||||
else asyncConsts }
|
||||
|
||||
@[export lean_display_stats]
|
||||
def displayStats (env : Environment) : IO Unit := do
|
||||
@@ -1666,6 +1840,101 @@ def hasUnsafe (env : Environment) (e : Expr) : Bool :=
|
||||
| _ => false;
|
||||
c?.isSome
|
||||
|
||||
/-- Plumbing function for `Lean.Meta.realizeConst`; see documentation there. -/
|
||||
def realizeConst (env : Environment) (forConst : Name) (constName : Name)
|
||||
(realize : Environment → Options → BaseIO (Environment × Dynamic)) :
|
||||
IO (Environment × Dynamic) := do
|
||||
let mut env := env
|
||||
-- find `RealizationContext` for `forConst` in `realizedImportedConsts?` or `realizedLocalConsts`
|
||||
let ctx ← if env.checkedWithoutAsync.const2ModIdx.contains forConst then
|
||||
env.realizedImportedConsts?.getDM <|
|
||||
throw <| .userError s!"Environment.realizeConst: `realizedImportedConsts` is empty"
|
||||
else
|
||||
match env.realizedLocalConsts.find? forConst with
|
||||
| some ctx => pure ctx
|
||||
| none =>
|
||||
throw <| .userError s!"trying to realize {constName} but `enableRealizationsForConst` must be called for '{forConst}' first"
|
||||
let prom ← IO.Promise.new
|
||||
-- ensure `prom` is not left unresolved from stray exceptions
|
||||
BaseIO.toIO do
|
||||
-- atomically check whether we are the first branch to realize `constName`
|
||||
let existingConsts? ← ctx.constsRef.modifyGet fun m => match m.find? constName with
|
||||
| some prom' => (some prom', m)
|
||||
| none => (none, m.insert constName prom.result!)
|
||||
let (consts, replay, dyn) ← if let some existingConsts := existingConsts? then
|
||||
pure existingConsts.get
|
||||
else
|
||||
-- safety: `RealizationContext` is private
|
||||
let realizeEnv : Environment := unsafe unsafeCast ctx.env
|
||||
let realizeEnv := { realizeEnv with
|
||||
-- allow realizations to recursively realize other constants for `forConst`. Do note that
|
||||
-- this allows for recursive realization of `constName` itself, which will deadlock.
|
||||
realizedLocalConsts := realizeEnv.realizedLocalConsts.insert forConst ctx
|
||||
}
|
||||
-- ensure realized constants are nested below `forConst` and that environment extension
|
||||
-- modifications know they are in an async context
|
||||
let realizeEnv := realizeEnv.enterAsync (realizing := true) forConst
|
||||
-- skip kernel in `realize`, we'll re-typecheck anyway
|
||||
let realizeOpts := debug.skipKernelTC.set ctx.opts true
|
||||
let (realizeEnv', dyn) ← realize realizeEnv realizeOpts
|
||||
-- We could check that `c` was indeed added here but in practice `realize` has already
|
||||
-- reported an error so we don't.
|
||||
|
||||
-- find new constants incl. nested realizations, add current extension state, and compute
|
||||
-- closure
|
||||
let consts := realizeEnv'.asyncConsts.revList.take (realizeEnv'.asyncConsts.size - realizeEnv.asyncConsts.size)
|
||||
let consts := consts.map fun c =>
|
||||
if c.exts?.isNone then
|
||||
{ c with exts? := some <| .pure realizeEnv'.checkedWithoutAsync.extensions }
|
||||
else c
|
||||
let exts ← EnvExtension.envExtensionsRef.get
|
||||
let replay := (maybeAddToKernelEnv realizeEnv realizeEnv' consts · exts)
|
||||
prom.resolve (consts, replay, dyn)
|
||||
pure (consts, replay, dyn)
|
||||
return ({ env with
|
||||
asyncConsts := consts.foldl (·.add) env.asyncConsts
|
||||
checked := env.checked.map replay
|
||||
}, dyn)
|
||||
where
|
||||
-- Adds `consts` if they haven't already been added by a previous branch. Note that this
|
||||
-- conditional is deterministic because of the linearizing effect of `env.checked`.
|
||||
maybeAddToKernelEnv (oldEnv newEnv : Environment) (consts : List AsyncConst)
|
||||
(kenv : Kernel.Environment)
|
||||
(exts : Array (EnvExtension EnvExtensionState)) : Kernel.Environment := Id.run do
|
||||
let mut kenv := kenv
|
||||
for c in consts do
|
||||
if kenv.find? c.constInfo.name |>.isSome then
|
||||
continue
|
||||
let info := c.constInfo.toConstantInfo
|
||||
if info.isUnsafe then
|
||||
-- Checking unsafe declarations is not necessary for consistency, and it is necessary to
|
||||
-- avoid checking them in the case of the old code generator, which adds ill-typed constants
|
||||
-- to the kernel environment. We can delete this branch after removing the old code
|
||||
-- generator.
|
||||
kenv := kenv.add info
|
||||
continue
|
||||
let decl := match info with
|
||||
| .thmInfo thm => .thmDecl thm
|
||||
| .defnInfo defn => .defnDecl defn
|
||||
| _ => panic! s!"Environment.realizeConst: {c.constInfo.name} must be definition/theorem"
|
||||
-- realized kernel additions cannot be interrupted - which would be bad anyway as they can be
|
||||
-- reused between snapshots
|
||||
match kenv.addDeclCore 0 decl none with
|
||||
| .ok kenv' => kenv := kenv'
|
||||
| .error e =>
|
||||
let _ : Inhabited Kernel.Environment := ⟨kenv⟩
|
||||
panic! s!"Environment.realizeConst: failed to add {c.constInfo.name} to environment\n{e.toRawString}"
|
||||
for ext in exts do
|
||||
if let some replay := ext.replay? then
|
||||
kenv := { kenv with
|
||||
-- safety: like in `modifyState`, but that one takes an elab env instead of a kernel env
|
||||
extensions := unsafe (ext.modifyStateImpl kenv.extensions <|
|
||||
replay
|
||||
(ext.getStateImpl oldEnv.toKernelEnv.extensions)
|
||||
(ext.getStateImpl newEnv.toKernelEnv.extensions)
|
||||
(consts.map (·.constInfo.name))) }
|
||||
return kenv
|
||||
|
||||
end Environment
|
||||
|
||||
namespace Kernel
|
||||
@@ -1721,4 +1990,13 @@ def mkDefinitionValInferrringUnsafe [Monad m] [MonadEnv m] (name : Name) (levelP
|
||||
let safety := if env.hasUnsafe type || env.hasUnsafe value then DefinitionSafety.unsafe else DefinitionSafety.safe
|
||||
return { name, levelParams, type, value, hints, safety }
|
||||
|
||||
def getMaxHeight (env : Environment) (e : Expr) : UInt32 :=
|
||||
e.foldConsts 0 fun constName max =>
|
||||
match env.find? constName with
|
||||
| ConstantInfo.defnInfo val =>
|
||||
match val.hints with
|
||||
| ReducibilityHints.regular h => if h > max then h else max
|
||||
| _ => max
|
||||
| _ => max
|
||||
|
||||
end Lean
|
||||
|
||||
@@ -184,7 +184,7 @@ structure SnapshotTree where
|
||||
element : Snapshot
|
||||
/-- The asynchronously available children of the snapshot tree node. -/
|
||||
children : Array (SnapshotTask SnapshotTree)
|
||||
deriving Inhabited
|
||||
deriving Inhabited, TypeName
|
||||
|
||||
/--
|
||||
Helper class for projecting a heterogeneous hierarchy of snapshot classes to a homogeneous
|
||||
|
||||
@@ -241,6 +241,11 @@ partial def formatAux : NamingContext → Option MessageDataContext → MessageD
|
||||
| nCtx, ctx, compose d₁ d₂ => return (← formatAux nCtx ctx d₁) ++ (← formatAux nCtx ctx d₂)
|
||||
| nCtx, ctx, group d => Format.group <$> formatAux nCtx ctx d
|
||||
| nCtx, ctx, trace data header children => do
|
||||
let childFmts ← children.mapM (formatAux nCtx ctx)
|
||||
if data.cls.isAnonymous then
|
||||
-- Sequence of top-level traces collected by `addTraceAsMessages`, do not indent.
|
||||
return .joinSep childFmts.toList "\n"
|
||||
|
||||
let mut msg := f!"[{data.cls}]"
|
||||
if data.startTime != 0 then
|
||||
msg := f!"{msg} [{data.stopTime - data.startTime}]"
|
||||
@@ -250,7 +255,6 @@ partial def formatAux : NamingContext → Option MessageDataContext → MessageD
|
||||
if maxNum > 0 && children.size > maxNum then
|
||||
children := children.take maxNum |>.push <|
|
||||
ofFormat f!"{children.size - maxNum} more entries... (increase `maxTraceChildren` to see more)"
|
||||
let childFmts ← children.mapM (formatAux nCtx ctx)
|
||||
return .nest 2 (.joinSep (msg::childFmts.toList) "\n")
|
||||
| nCtx, ctx?, ofLazy pp _ => do
|
||||
let dyn ← pp (ctx?.map (mkPPContext nCtx))
|
||||
|
||||
@@ -2203,10 +2203,84 @@ def instantiateMVarsIfMVarApp (e : Expr) : MetaM Expr := do
|
||||
else
|
||||
return e
|
||||
|
||||
private partial def setAllDiagRanges (snap : Language.SnapshotTree) (pos endPos : Position) :
|
||||
BaseIO Language.SnapshotTree := do
|
||||
let msgLog := snap.element.diagnostics.msgLog
|
||||
let msgLog := { msgLog with unreported := msgLog.unreported.map fun diag =>
|
||||
{ diag with pos, endPos } }
|
||||
return {
|
||||
element.diagnostics := (← Language.Snapshot.Diagnostics.ofMessageLog msgLog)
|
||||
children := (← snap.children.mapM fun task => return { task with
|
||||
stx? := none
|
||||
task := (← BaseIO.mapTask (t := task.task) (setAllDiagRanges · pos endPos)) })
|
||||
}
|
||||
|
||||
/--
|
||||
Makes the helper constant `constName` that is derived from `forConst` available in the environment.
|
||||
`enableRealizationsForConst forConst` must have been called first on this environment branch. If
|
||||
this is the first environment branch requesting `constName` to be realized (atomically), `realize`
|
||||
is called with the environment and options at the time of calling `enableRealizationsForConst` if
|
||||
`forConst` is from the current module and the state just after importing otherwise, thus helping
|
||||
achieve deterministic results despite the non-deterministic choice of which thread is tasked with
|
||||
realization. In other words, the state after calling `realizeConst` is *as if* `realize` had been
|
||||
called immediately after `enableRealizationsForConst forConst`, though the effects of this call are
|
||||
visible only after calling `realizeConst`. See below for more details on the replayed effects.
|
||||
|
||||
`realizeConst` cannot check what other data is captured in the `realize` closure,
|
||||
so it is best practice to extract it into a separate function and pay close attention to the passed
|
||||
arguments, if any. `realize` must return with `constName` added to the environment,
|
||||
at which point all callers of `realizeConst` with this `constName` will be unblocked
|
||||
and have access to an updated version of their own environment containing any new constants
|
||||
`realize` added, including recursively realized constants. Traces, diagnostics, and raw std stream
|
||||
output are reported at all callers via `Core.logSnapshotTask` (so that the location of generated
|
||||
diagnostics is deterministic). Note that, as `realize` is run using the options at declaration time
|
||||
of `forConst`, trace options must be set prior to that (or, for imported constants, on the cmdline)
|
||||
in order to be active. The environment extension state at the end of `realize` is available to each
|
||||
caller via `EnvExtension.findStateAsync` for `constName`. If `realize` throws an exception or fails
|
||||
to add `constName` to the environment, an appropriate diagnostic is reported to all callers but no
|
||||
constants are added to the environment.
|
||||
-/
|
||||
def realizeConst (forConst : Name) (constName : Name) (realize : MetaM Unit) :
|
||||
MetaM Unit := withTraceNode `Meta.realizeConst (fun _ => return constName) do
|
||||
let env ← getEnv
|
||||
let coreCtx ← readThe Core.Context
|
||||
-- these fields should be invariant throughout the file
|
||||
let coreCtx := { fileName := coreCtx.fileName, fileMap := coreCtx.fileMap }
|
||||
let (env, dyn) ← env.realizeConst forConst constName (realizeAndReport coreCtx)
|
||||
if let some snap := dyn.get? Language.SnapshotTree then
|
||||
let mut snap := snap
|
||||
-- localize diagnostics
|
||||
if let some range := (← getRef).getRange? then
|
||||
let fileMap ← getFileMap
|
||||
snap ← setAllDiagRanges snap (fileMap.toPosition range.start) (fileMap.toPosition range.stop)
|
||||
Core.logSnapshotTask <| .finished (stx? := none) snap
|
||||
setEnv env
|
||||
where
|
||||
-- similar to `wrapAsyncAsSnapshot` but not sufficiently so to share code
|
||||
realizeAndReport (coreCtx : Core.Context) env opts := do
|
||||
let coreCtx := { coreCtx with options := opts }
|
||||
let act :=
|
||||
IO.FS.withIsolatedStreams (isolateStderr := Core.stderrAsMessages.get opts) do
|
||||
-- catch all exceptions
|
||||
let _ : MonadExceptOf _ MetaM := MonadAlwaysExcept.except
|
||||
try
|
||||
realize
|
||||
if !(← getEnv).contains constName then
|
||||
throwError "Lean.Meta.realizeConst: {constName} was not added to the environment"
|
||||
catch e : Exception =>
|
||||
logError e.toMessageData
|
||||
finally
|
||||
addTraceAsMessages
|
||||
let res? ← act |>.run' |>.run coreCtx { env } |>.toBaseIO
|
||||
match res? with
|
||||
| .ok ((output, ()), st) => pure (st.env, .mk (← Core.mkSnapshot output coreCtx st))
|
||||
| .error _e => unreachable!; pure (env, .mk ({ diagnostics := .empty : Language.SnapshotLeaf}))
|
||||
|
||||
end Meta
|
||||
|
||||
builtin_initialize
|
||||
registerTraceClass `Meta.isLevelDefEq.postponed
|
||||
registerTraceClass `Meta.realizeConst
|
||||
|
||||
export Meta (MetaM)
|
||||
|
||||
|
||||
@@ -784,6 +784,7 @@ def mkMatcherAuxDefinition (name : Name) (type : Expr) (value : Expr) : MetaM (E
|
||||
modifyEnv fun env => matcherExt.modifyState env fun s => s.insert (result.value, compile) name
|
||||
addMatcherInfo name mi
|
||||
setInlineAttribute name
|
||||
enableRealizationsForConst name
|
||||
if compile then
|
||||
compileDecl decl
|
||||
return (mkMatcherConst name, some addMatcher)
|
||||
|
||||
@@ -120,6 +120,8 @@ where
|
||||
else
|
||||
collect (b.instantiate1 (← mkFreshExprMVar d)) (argIdx+1) targetIdx implicits targets'
|
||||
| _ =>
|
||||
unless targetIdx = targets.size do
|
||||
throwError "extra targets for '{elimInfo.elimExpr}'"
|
||||
return (implicits, targets')
|
||||
|
||||
structure CustomEliminator where
|
||||
|
||||
@@ -7,15 +7,13 @@ prelude
|
||||
import Lean.Meta.Tactic.Util
|
||||
|
||||
namespace Lean.Meta
|
||||
/--
|
||||
Creates a new goal whose local context has been "exposed" so that every local declaration has a clear, accessible name.
|
||||
If no local declarations require renaming, the original goal is returned unchanged.
|
||||
-/
|
||||
def _root_.Lean.MVarId.exposeNames (mvarId : MVarId) : MetaM MVarId := mvarId.withContext do
|
||||
mvarId.checkNotAssigned `expose_names
|
||||
|
||||
/-- Returns a copy of the local context in which all declarations have clear, accessible names. -/
|
||||
private def getLCtxWithExposedNames : MetaM LocalContext := do
|
||||
let mut map : Std.HashMap Name FVarId := {}
|
||||
let mut toRename := #[]
|
||||
for localDecl in (← getLCtx) do
|
||||
let mut lctx ← getLCtx
|
||||
for localDecl in lctx do
|
||||
let userName := localDecl.userName
|
||||
if userName.hasMacroScopes then
|
||||
toRename := toRename.push localDecl.fvarId
|
||||
@@ -25,9 +23,8 @@ def _root_.Lean.MVarId.exposeNames (mvarId : MVarId) : MetaM MVarId := mvarId.wi
|
||||
toRename := toRename.push fvarId
|
||||
map := map.insert userName localDecl.fvarId
|
||||
if toRename.isEmpty then
|
||||
return mvarId
|
||||
return lctx
|
||||
let mut next : Std.HashMap Name Nat := {}
|
||||
let mut lctx ← getLCtx
|
||||
-- Remark: Shadowed variables may be inserted later.
|
||||
toRename := toRename.qsort fun fvarId₁ fvarId₂ =>
|
||||
(lctx.get! fvarId₁).index < (lctx.get! fvarId₂).index
|
||||
@@ -49,8 +46,21 @@ def _root_.Lean.MVarId.exposeNames (mvarId : MVarId) : MetaM MVarId := mvarId.wi
|
||||
next := next.insert baseName i
|
||||
map := map.insert userName fvarId
|
||||
lctx := lctx.modifyLocalDecl fvarId (·.setUserName userName)
|
||||
return lctx
|
||||
|
||||
/--
|
||||
Creates a new goal whose local context has been "exposed" so that every local declaration has a clear, accessible name.
|
||||
If no local declarations require renaming, the original goal is returned unchanged.
|
||||
-/
|
||||
def _root_.Lean.MVarId.exposeNames (mvarId : MVarId) : MetaM MVarId := mvarId.withContext do
|
||||
mvarId.checkNotAssigned `expose_names
|
||||
let lctx ← getLCtxWithExposedNames
|
||||
let mvarNew ← mkFreshExprMVarAt lctx (← getLocalInstances) (← mvarId.getType) .syntheticOpaque (← mvarId.getTag)
|
||||
mvarId.assign mvarNew
|
||||
return mvarNew.mvarId!
|
||||
|
||||
/-- Creates a temporary local context where all names are exposed, and executes `k` -/
|
||||
def withExposedNames (k : MetaM α) : MetaM α := do
|
||||
withNewMCtxDepth <| withLCtx (← getLCtxWithExposedNames) (← getLocalInstances) k
|
||||
|
||||
end Lean.Meta
|
||||
|
||||
@@ -28,6 +28,7 @@ import Lean.Meta.Tactic.Grind.Arith
|
||||
import Lean.Meta.Tactic.Grind.Ext
|
||||
import Lean.Meta.Tactic.Grind.MatchCond
|
||||
import Lean.Meta.Tactic.Grind.MatchDiscrOnly
|
||||
import Lean.Meta.Tactic.Grind.Diseq
|
||||
|
||||
namespace Lean
|
||||
|
||||
|
||||
@@ -43,4 +43,10 @@ builtin_initialize registerTraceClass `grind.cutsat.le.upper (inherited := true)
|
||||
builtin_initialize registerTraceClass `grind.cutsat.assign
|
||||
builtin_initialize registerTraceClass `grind.cutsat.conflict
|
||||
|
||||
builtin_initialize registerTraceClass `grind.cutsat.diseq
|
||||
builtin_initialize registerTraceClass `grind.cutsat.diseq.trivial (inherited := true)
|
||||
|
||||
builtin_initialize registerTraceClass `grind.debug.cutsat.eq
|
||||
builtin_initialize registerTraceClass `grind.debug.cutsat.diseq
|
||||
|
||||
end Lean
|
||||
|
||||
@@ -59,7 +59,7 @@ partial def DvdCnstr.assert (c : DvdCnstr) : GoalM Unit := withIncRecDepth do
|
||||
let .add a₁ x p₁ := c.p | c.throwUnexpected
|
||||
if (← c.satisfied) == .false then
|
||||
resetAssignmentFrom x
|
||||
if let some c' := (← get').dvdCnstrs[x]! then
|
||||
if let some c' := (← get').dvds[x]! then
|
||||
trace[grind.cutsat.dvd.solve] "{← c.pp}, {← c'.pp}"
|
||||
let d₂ := c'.d
|
||||
let .add a₂ _ p₂ := c'.p | c'.throwUnexpected
|
||||
@@ -76,7 +76,7 @@ partial def DvdCnstr.assert (c : DvdCnstr) : GoalM Unit := withIncRecDepth do
|
||||
let β_d₁_p₂ := p₂.mul (β*d₁)
|
||||
let combine ← mkDvdCnstr (d₁*d₂) (.add d x (α_d₂_p₁.combine β_d₁_p₂)) (.solveCombine c c')
|
||||
trace[grind.cutsat.dvd.solve.combine] "{← combine.pp}"
|
||||
modify' fun s => { s with dvdCnstrs := s.dvdCnstrs.set x none}
|
||||
modify' fun s => { s with dvds := s.dvds.set x none}
|
||||
combine.assert
|
||||
let a₂_p₁ := p₁.mul a₂
|
||||
let a₁_p₂ := p₂.mul (-a₁)
|
||||
@@ -86,7 +86,7 @@ partial def DvdCnstr.assert (c : DvdCnstr) : GoalM Unit := withIncRecDepth do
|
||||
else
|
||||
trace[grind.cutsat.dvd.update] "{← c.pp}"
|
||||
c.p.updateOccs
|
||||
modify' fun s => { s with dvdCnstrs := s.dvdCnstrs.set x (some c) }
|
||||
modify' fun s => { s with dvds := s.dvds.set x (some c) }
|
||||
|
||||
builtin_grind_propagator propagateDvd ↓Dvd.dvd := fun e => do
|
||||
let_expr Dvd.dvd _ inst a b ← e | return ()
|
||||
|
||||
@@ -4,14 +4,18 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Lean.Meta.Tactic.Grind.Diseq
|
||||
import Lean.Meta.Tactic.Grind.Arith.Cutsat.Var
|
||||
import Lean.Meta.Tactic.Grind.Arith.Cutsat.DvdCnstr
|
||||
import Lean.Meta.Tactic.Grind.Arith.Cutsat.LeCnstr
|
||||
|
||||
namespace Lean.Meta.Grind.Arith.Cutsat
|
||||
|
||||
def mkEqCnstr (p : Poly) (h : EqCnstrProof) : GoalM EqCnstr := do
|
||||
return { p, h, id := (← mkCnstrId) }
|
||||
private def _root_.Int.Linear.Poly.substVar (p : Poly) : GoalM (Option (Var × EqCnstr × Poly)) := do
|
||||
let some (a, x, c) ← p.findVarToSubst | return none
|
||||
let b := c.p.coeff x
|
||||
let p := p.mul (-b) |>.combine (c.p.mul a)
|
||||
return some (x, c, p)
|
||||
|
||||
def EqCnstr.norm (c : EqCnstr) : GoalM EqCnstr := do
|
||||
let c ← if c.p.isSorted then
|
||||
@@ -19,6 +23,75 @@ def EqCnstr.norm (c : EqCnstr) : GoalM EqCnstr := do
|
||||
else
|
||||
mkEqCnstr c.p.norm (.norm c)
|
||||
|
||||
def mkDiseqCnstr (p : Poly) (h : DiseqCnstrProof) : GoalM DiseqCnstr := do
|
||||
return { p, h, id := (← mkCnstrId) }
|
||||
|
||||
def DiseqCnstr.norm (c : DiseqCnstr) : GoalM DiseqCnstr := do
|
||||
let c ← if c.p.isSorted then
|
||||
pure c
|
||||
else
|
||||
mkDiseqCnstr c.p.norm (.norm c)
|
||||
|
||||
/--
|
||||
Given an equation `c₁` containing the monomial `a*x`, and a disequality constraint `c₂`
|
||||
containing the monomial `b*x`, eliminate `x` by applying substitution.
|
||||
-/
|
||||
def DiseqCnstr.applyEq (a : Int) (x : Var) (c₁ : EqCnstr) (b : Int) (c₂ : DiseqCnstr) : GoalM DiseqCnstr := do
|
||||
let p := c₁.p
|
||||
let q := c₂.p
|
||||
let p := p.mul b |>.combine (q.mul (-a))
|
||||
trace[grind.cutsat.subst] "{← getVar x}, {← c₁.pp}, {← c₂.pp}"
|
||||
mkDiseqCnstr p (.subst x c₁ c₂)
|
||||
|
||||
partial def DiseqCnstr.applySubsts (c : DiseqCnstr) : GoalM DiseqCnstr := withIncRecDepth do
|
||||
let some (x, c₁, p) ← c.p.substVar | return c
|
||||
trace[grind.cutsat.subst] "{← getVar x}, {← c.pp}, {← c₁.pp}"
|
||||
let c ← mkDiseqCnstr p (.subst x c₁ c)
|
||||
applySubsts c
|
||||
|
||||
/--
|
||||
Given a disequality `c`, tries to find an inequality to be refined using
|
||||
`p ≤ 0 → p ≠ 0 → p + 1 ≤ 0`
|
||||
-/
|
||||
private def DiseqCnstr.findLe (c : DiseqCnstr) : GoalM Bool := do
|
||||
let .add _ x _ := c.p | c.throwUnexpected
|
||||
let s ← get'
|
||||
let go (atLower : Bool) : GoalM Bool := do
|
||||
let cs' := if atLower then s.lowers[x]! else s.uppers[x]!
|
||||
for c' in cs' do
|
||||
if c.p == c'.p || c.p.isNegEq c'.p then
|
||||
c'.erase
|
||||
let le ← mkLeCnstr (c'.p.addConst 1) (.ofLeDiseq c' c)
|
||||
le.assert
|
||||
return true
|
||||
return false
|
||||
go true <||> go false
|
||||
|
||||
def DiseqCnstr.assert (c : DiseqCnstr) : GoalM Unit := do
|
||||
if (← inconsistent) then return ()
|
||||
trace[grind.cutsat.assert] "{← c.pp}"
|
||||
let c ← c.norm
|
||||
let c ← c.applySubsts
|
||||
if c.p.isUnsatDiseq then
|
||||
setInconsistent (.diseq c)
|
||||
return ()
|
||||
if c.isTrivial then
|
||||
trace[grind.cutsat.diseq.trivial] "{← c.pp}"
|
||||
return ()
|
||||
let k := c.p.gcdCoeffs c.p.getConst
|
||||
let c ← if k == 1 then
|
||||
pure c
|
||||
else
|
||||
mkDiseqCnstr (c.p.div k) (.divCoeffs c)
|
||||
if (← c.findLe) then
|
||||
return ()
|
||||
let .add _ x _ := c.p | c.throwUnexpected
|
||||
c.p.updateOccs
|
||||
trace[grind.cutsat.diseq] "{← c.pp}"
|
||||
modify' fun s => { s with diseqs := s.diseqs.modify x (·.push c) }
|
||||
if (← c.satisfied) == .false then
|
||||
resetAssignmentFrom x
|
||||
|
||||
/--
|
||||
Selects the variable in the given linear polynomial whose coefficient has the smallest absolute value.
|
||||
-/
|
||||
@@ -39,18 +112,16 @@ where
|
||||
go k x p
|
||||
|
||||
partial def EqCnstr.applySubsts (c : EqCnstr) : GoalM EqCnstr := withIncRecDepth do
|
||||
let some (a, x, c₁) ← c.p.findVarToSubst | return c
|
||||
let some (x, c₁, p) ← c.p.substVar | return c
|
||||
trace[grind.cutsat.subst] "{← getVar x}, {← c.pp}, {← c₁.pp}"
|
||||
let b := c₁.p.coeff x
|
||||
let p := c.p.mul (-b) |>.combine (c₁.p.mul a)
|
||||
let c ← mkEqCnstr p (.subst x c₁ c)
|
||||
applySubsts c
|
||||
|
||||
private def updateDvdCnstr (a : Int) (x : Var) (c : EqCnstr) (y : Var) : GoalM Unit := do
|
||||
let some c' := (← get').dvdCnstrs[y]! | return ()
|
||||
let some c' := (← get').dvds[y]! | return ()
|
||||
let b := c'.p.coeff x
|
||||
if b == 0 then return ()
|
||||
modify' fun s => { s with dvdCnstrs := s.dvdCnstrs.set y none }
|
||||
modify' fun s => { s with dvds := s.dvds.set y none }
|
||||
let c' ← c'.applyEq a x c b
|
||||
c'.assert
|
||||
|
||||
@@ -93,10 +164,31 @@ private def updateUppers (a : Int) (x : Var) (c : EqCnstr) (y : Var) : GoalM Uni
|
||||
modify' fun s => { s with uppers := s.uppers.set y uppers' }
|
||||
updateLeCnstrs a x c todo
|
||||
|
||||
private def splitDiseqs (x : Var) (cs : PArray DiseqCnstr) : GoalM (PArray DiseqCnstr × Array (Int × DiseqCnstr)) := do
|
||||
let mut cs' := {}
|
||||
let mut todo := #[]
|
||||
for c in cs do
|
||||
let b := c.p.coeff x
|
||||
if b == 0 then
|
||||
cs' := cs'.push c
|
||||
else
|
||||
todo := todo.push (b, c)
|
||||
return (cs', todo)
|
||||
|
||||
private def updateDiseqs (a : Int) (x : Var) (c : EqCnstr) (y : Var) : GoalM Unit := do
|
||||
if (← inconsistent) then return ()
|
||||
let (diseqs', todo) ← splitDiseqs x (← get').diseqs[y]!
|
||||
modify' fun s => { s with diseqs := s.diseqs.set y diseqs' }
|
||||
for (b, c₂) in todo do
|
||||
let c₂ ← c₂.applyEq a x c b
|
||||
c₂.assert
|
||||
if (← inconsistent) then return ()
|
||||
|
||||
private def updateOccsAt (k : Int) (x : Var) (c : EqCnstr) (y : Var) : GoalM Unit := do
|
||||
updateDvdCnstr k x c y
|
||||
updateLowers k x c y
|
||||
updateUppers k x c y
|
||||
updateDiseqs k x c y
|
||||
|
||||
private def updateOccs (k : Int) (x : Var) (c : EqCnstr) : GoalM Unit := do
|
||||
let ys := (← get').occurs[x]!
|
||||
@@ -105,7 +197,8 @@ private def updateOccs (k : Int) (x : Var) (c : EqCnstr) : GoalM Unit := do
|
||||
for y in ys do
|
||||
updateOccsAt k x c y
|
||||
|
||||
def EqCnstr.assert (c : EqCnstr) : GoalM Unit := do
|
||||
@[export lean_grind_cutsat_assert_eq]
|
||||
def EqCnstr.assertImpl (c : EqCnstr) : GoalM Unit := do
|
||||
if (← inconsistent) then return ()
|
||||
trace[grind.cutsat.assert] "{← c.pp}"
|
||||
let c ← c.norm
|
||||
@@ -151,14 +244,16 @@ private def exprAsPoly (a : Expr) : GoalM Poly := do
|
||||
|
||||
@[export lean_process_cutsat_eq]
|
||||
def processNewEqImpl (a b : Expr) : GoalM Unit := do
|
||||
trace[grind.debug.cutsat.eq] "{a} = {b}"
|
||||
let p₁ ← exprAsPoly a
|
||||
let p₂ ← exprAsPoly b
|
||||
let p := p₁.combine (p₂.mul (-1))
|
||||
let c ← mkEqCnstr p (.core p₁ p₂ (← mkEqProof a b))
|
||||
c.assert
|
||||
|
||||
@[export lean_process_new_cutsat_lit]
|
||||
@[export lean_process_cutsat_eq_lit]
|
||||
def processNewEqLitImpl (a ke : Expr) : GoalM Unit := do
|
||||
trace[grind.debug.cutsat.eq] "{a} = {ke}"
|
||||
let some k ← getIntValue? ke | return ()
|
||||
let p₁ ← exprAsPoly a
|
||||
let h ← mkEqProof a ke
|
||||
@@ -170,6 +265,20 @@ def processNewEqLitImpl (a ke : Expr) : GoalM Unit := do
|
||||
mkEqCnstr p (.core p₁ p₂ h)
|
||||
c.assert
|
||||
|
||||
@[export lean_process_cutsat_diseq]
|
||||
def processNewDiseqImpl (a b : Expr) : GoalM Unit := do
|
||||
trace[grind.debug.cutsat.diseq] "{a} ≠ {b}"
|
||||
let p₁ ← exprAsPoly a
|
||||
let some h ← mkDiseqProof? a b
|
||||
| throwError "internal `grind` error, failed to build disequality proof for{indentExpr a}\nand{indentExpr b}"
|
||||
let c ← if let some 0 ← getIntValue? b then
|
||||
mkDiseqCnstr p₁ (.expr h)
|
||||
else
|
||||
let p₂ ← exprAsPoly b
|
||||
let p := p₁.combine (p₂.mul (-1))
|
||||
mkDiseqCnstr p (.core p₁ p₂ h)
|
||||
c.assert
|
||||
|
||||
/-- Different kinds of terms internalized by this module. -/
|
||||
private inductive SupportedTermKind where
|
||||
| add | mul | num
|
||||
|
||||
@@ -59,11 +59,11 @@ def checkUppers : GoalM Unit := do
|
||||
assert! s.uppers.size == s.vars.size
|
||||
checkLeCnstrs s.uppers (isLower := false)
|
||||
|
||||
def checkDvdCnstrs : GoalM Unit := do
|
||||
def checkDvds : GoalM Unit := do
|
||||
let s ← get'
|
||||
assert! s.vars.size == s.dvdCnstrs.size
|
||||
assert! s.vars.size == s.dvds.size
|
||||
let mut x := 0
|
||||
for c? in s.dvdCnstrs do
|
||||
for c? in s.dvds do
|
||||
if let some c := c? then
|
||||
c.p.checkCnstrOf x
|
||||
assert! c.d > 1
|
||||
@@ -97,12 +97,23 @@ def checkElimStack : GoalM Unit := do
|
||||
for x in (← get').elimStack do
|
||||
assert! (← eliminated x)
|
||||
|
||||
def checkDiseqCnstrs : GoalM Unit := do
|
||||
let s ← get'
|
||||
assert! s.vars.size == s.diseqs.size
|
||||
let mut x := 0
|
||||
for cs in s.diseqs do
|
||||
for c in cs do
|
||||
c.p.checkCnstrOf x
|
||||
x := x + 1
|
||||
return ()
|
||||
|
||||
def checkInvariants : GoalM Unit := do
|
||||
checkVars
|
||||
checkDvdCnstrs
|
||||
checkDvds
|
||||
checkLowers
|
||||
checkUppers
|
||||
checkElimEqs
|
||||
checkElimStack
|
||||
checkDiseqCnstrs
|
||||
|
||||
end Lean.Meta.Grind.Arith.Cutsat
|
||||
|
||||
@@ -45,6 +45,57 @@ partial def LeCnstr.applySubsts (c : LeCnstr) : GoalM LeCnstr := withIncRecDepth
|
||||
let c ← c.applyEq a x c₁ b
|
||||
applySubsts c
|
||||
|
||||
def _root_.Int.Linear.Poly.isNegEq (p₁ p₂ : Poly) : Bool :=
|
||||
match p₁, p₂ with
|
||||
| .num k₁, .num k₂ => k₁ == -k₂
|
||||
| .add a₁ x p₁, .add a₂ y p₂ => a₁ == -a₂ && x == y && isNegEq p₁ p₂
|
||||
| _, _ => false
|
||||
|
||||
def LeCnstr.erase (c : LeCnstr) : GoalM Unit := do
|
||||
let .add a x _ := c.p | c.throwUnexpected
|
||||
if a < 0 then
|
||||
modify' fun s => { s with lowers := s.lowers.modify x fun cs' => cs'.filter fun c' => c'.p != c.p }
|
||||
else
|
||||
modify' fun s => { s with uppers := s.uppers.modify x fun cs' => cs'.filter fun c' => c'.p != c.p }
|
||||
|
||||
/--
|
||||
Given a lower (upper) bound constraint `c`, tries to find
|
||||
an imply equality by searching a upper (lower) bound constraint `c'` such that
|
||||
`c.p == -c'.p`
|
||||
-/
|
||||
private def findEq (c : LeCnstr) : GoalM Bool := do
|
||||
let .add a x _ := c.p | c.throwUnexpected
|
||||
let s ← get'
|
||||
let cs' := if a < 0 then s.uppers[x]! else s.lowers[x]!
|
||||
for c' in cs' do
|
||||
if c.p.isNegEq c'.p then
|
||||
c'.erase
|
||||
let eq ← mkEqCnstr c.p (.ofLeGe c c')
|
||||
eq.assert
|
||||
return true
|
||||
return false
|
||||
|
||||
/--
|
||||
Applies `p ≤ 0 → p ≠ 0 → p + 1 ≤ 0`
|
||||
-/
|
||||
private def refineWithDiseq (c : LeCnstr) : GoalM LeCnstr := do
|
||||
let .add _ x _ := c.p | c.throwUnexpected
|
||||
let mut c := c
|
||||
repeat
|
||||
let some c' ← refineWithDiseqStep? x c | return c
|
||||
c := c'
|
||||
return c
|
||||
where
|
||||
refineWithDiseqStep? (x : Var) (c : LeCnstr) : GoalM (Option LeCnstr) := do
|
||||
let s ← get'
|
||||
let cs' := s.diseqs[x]!
|
||||
for c' in cs' do
|
||||
if c.p == c'.p || c.p.isNegEq c'.p then
|
||||
-- Remove `c'`
|
||||
modify' fun s => { s with diseqs := s.diseqs.modify x fun cs' => cs'.filter fun c => c.p != c'.p }
|
||||
return some (← mkLeCnstr (c.p.addConst 1) (.ofLeDiseq c c'))
|
||||
return none
|
||||
|
||||
def LeCnstr.assert (c : LeCnstr) : GoalM Unit := do
|
||||
if (← inconsistent) then return ()
|
||||
let c ← c.norm
|
||||
@@ -56,6 +107,9 @@ def LeCnstr.assert (c : LeCnstr) : GoalM Unit := do
|
||||
trace[grind.cutsat.le.trivial] "{← c.pp}"
|
||||
return ()
|
||||
let .add a x _ := c.p | c.throwUnexpected
|
||||
if (← findEq c) then
|
||||
return ()
|
||||
let c ← refineWithDiseq c
|
||||
if a < 0 then
|
||||
trace[grind.cutsat.le.lower] "{← c.pp}"
|
||||
c.p.updateOccs
|
||||
|
||||
@@ -14,6 +14,26 @@ private def DvdCnstr.get_d_a (c : DvdCnstr) : GoalM (Int × Int) := do
|
||||
return (d, a)
|
||||
|
||||
mutual
|
||||
partial def EqCnstr.toExprProof (c' : EqCnstr) : ProofM Expr := c'.caching do
|
||||
match c'.h with
|
||||
| .expr h =>
|
||||
return h
|
||||
| .core p₁ p₂ h =>
|
||||
return mkApp6 (mkConst ``Int.Linear.eq_of_core) (← getContext) (toExpr p₁) (toExpr p₂) (toExpr c'.p) reflBoolTrue h
|
||||
| .norm c =>
|
||||
return mkApp5 (mkConst ``Int.Linear.eq_norm) (← getContext) (toExpr c.p) (toExpr c'.p) reflBoolTrue (← c.toExprProof)
|
||||
| .divCoeffs c =>
|
||||
let k := c.p.gcdCoeffs c.p.getConst
|
||||
return mkApp6 (mkConst ``Int.Linear.eq_coeff) (← getContext) (toExpr c.p) (toExpr c'.p) (toExpr k) reflBoolTrue (← c.toExprProof)
|
||||
| .subst x c₁ c₂ =>
|
||||
return mkApp8 (mkConst ``Int.Linear.eq_eq_subst)
|
||||
(← getContext) (toExpr x) (toExpr c₁.p) (toExpr c₂.p) (toExpr c'.p)
|
||||
reflBoolTrue (← c₁.toExprProof) (← c₂.toExprProof)
|
||||
| .ofLeGe c₁ c₂ =>
|
||||
return mkApp6 (mkConst ``Int.Linear.eq_of_le_ge)
|
||||
(← getContext) (toExpr c₁.p) (toExpr c₂.p)
|
||||
reflBoolTrue (← c₁.toExprProof) (← c₂.toExprProof)
|
||||
|
||||
partial def DvdCnstr.toExprProof (c' : DvdCnstr) : ProofM Expr := c'.caching do
|
||||
match c'.h with
|
||||
| .expr h =>
|
||||
@@ -72,20 +92,24 @@ partial def LeCnstr.toExprProof (c' : LeCnstr) : ProofM Expr := c'.caching do
|
||||
(← getContext) (toExpr x) (toExpr c₁.p) (toExpr c₂.p) (toExpr c'.p)
|
||||
reflBoolTrue
|
||||
(← c₁.toExprProof) (← c₂.toExprProof)
|
||||
| .ofLeDiseq c₁ c₂ =>
|
||||
return mkApp7 (mkConst ``Int.Linear.le_of_le_diseq)
|
||||
(← getContext) (toExpr c₁.p) (toExpr c₂.p) (toExpr c'.p)
|
||||
reflBoolTrue (← c₁.toExprProof) (← c₂.toExprProof)
|
||||
|
||||
partial def EqCnstr.toExprProof (c' : EqCnstr) : ProofM Expr := c'.caching do
|
||||
partial def DiseqCnstr.toExprProof (c' : DiseqCnstr) : ProofM Expr := c'.caching do
|
||||
match c'.h with
|
||||
| .expr h =>
|
||||
return h
|
||||
| .core p₁ p₂ h =>
|
||||
return mkApp6 (mkConst ``Int.Linear.eq_of_core) (← getContext) (toExpr p₁) (toExpr p₂) (toExpr c'.p) reflBoolTrue h
|
||||
return mkApp6 (mkConst ``Int.Linear.diseq_of_core) (← getContext) (toExpr p₁) (toExpr p₂) (toExpr c'.p) reflBoolTrue h
|
||||
| .norm c =>
|
||||
return mkApp5 (mkConst ``Int.Linear.eq_norm) (← getContext) (toExpr c.p) (toExpr c'.p) reflBoolTrue (← c.toExprProof)
|
||||
return mkApp5 (mkConst ``Int.Linear.diseq_norm) (← getContext) (toExpr c.p) (toExpr c'.p) reflBoolTrue (← c.toExprProof)
|
||||
| .divCoeffs c =>
|
||||
let k := c.p.gcdCoeffs c.p.getConst
|
||||
return mkApp6 (mkConst ``Int.Linear.eq_coeff) (← getContext) (toExpr c.p) (toExpr c'.p) (toExpr k) reflBoolTrue (← c.toExprProof)
|
||||
return mkApp6 (mkConst ``Int.Linear.diseq_coeff) (← getContext) (toExpr c.p) (toExpr c'.p) (toExpr k) reflBoolTrue (← c.toExprProof)
|
||||
| .subst x c₁ c₂ =>
|
||||
return mkApp8 (mkConst ``Int.Linear.eq_eq_subst)
|
||||
return mkApp8 (mkConst ``Int.Linear.eq_diseq_subst)
|
||||
(← getContext) (toExpr x) (toExpr c₁.p) (toExpr c₂.p) (toExpr c'.p)
|
||||
reflBoolTrue (← c₁.toExprProof) (← c₂.toExprProof)
|
||||
|
||||
@@ -107,6 +131,9 @@ def setInconsistent (h : UnsatProof) : GoalM Unit := do
|
||||
else
|
||||
let k := c.p.gcdCoeffs'
|
||||
return mkApp5 (mkConst ``Int.Linear.eq_unsat_coeff) (← getContext) (toExpr c.p) (toExpr (Int.ofNat k)) reflBoolTrue (← c.toExprProof)
|
||||
| .diseq c =>
|
||||
trace[grind.cutsat.diseq.unsat] "{← c.pp}"
|
||||
return mkApp4 (mkConst ``Int.Linear.diseq_unsat) (← getContext) (toExpr c.p) reflBoolTrue (← c.toExprProof)
|
||||
closeGoal hf
|
||||
|
||||
end Lean.Meta.Grind.Arith.Cutsat
|
||||
|
||||
@@ -60,6 +60,13 @@ def DvdCnstr.getSolutions? (c : DvdCnstr) : GoalM (Option (Int × Int)) := do
|
||||
-- `x = k*d + -b*a'` for any k
|
||||
return some (d, -b*a')
|
||||
|
||||
private partial def skipAssignment (x : Var) : GoalM Unit := do
|
||||
if x < (← get').assignment.size then
|
||||
throwError "`grind` internal error, variable is already assigned"
|
||||
modify' fun s => { s with assignment := s.assignment.push 0 }
|
||||
if x > (← get').assignment.size then
|
||||
skipAssignment x
|
||||
|
||||
private partial def setAssignment (x : Var) (v : Int) : GoalM Unit := do
|
||||
if x == (← get').assignment.size then
|
||||
trace[grind.cutsat.assign] "{quoteIfNotAtom (← getVar x)} := {v}"
|
||||
@@ -90,9 +97,12 @@ def resolveDvdConflict (c : DvdCnstr) : GoalM Unit := do
|
||||
(← mkDvdCnstr (a.gcd d) p (.elim c)).assert
|
||||
|
||||
def decideVar (x : Var) : GoalM Unit := do
|
||||
if (← eliminated x) then
|
||||
skipAssignment x
|
||||
return ()
|
||||
let lower? ← getBestLower? x
|
||||
let upper? ← getBestUpper? x
|
||||
let dvd? := (← get').dvdCnstrs[x]!
|
||||
let dvd? := (← get').dvds[x]!
|
||||
match lower?, upper?, dvd? with
|
||||
| none, none, none =>
|
||||
setAssignment x 0
|
||||
|
||||
@@ -19,6 +19,20 @@ fields until the compiler provides support for avoiding the performance overhead
|
||||
-/
|
||||
|
||||
mutual
|
||||
/-- A equality constraint and its justification/proof. -/
|
||||
structure EqCnstr where
|
||||
p : Poly
|
||||
h : EqCnstrProof
|
||||
id : Nat
|
||||
|
||||
inductive EqCnstrProof where
|
||||
| expr (h : Expr)
|
||||
| core (p₁ p₂ : Poly) (h : Expr)
|
||||
| norm (c : EqCnstr)
|
||||
| divCoeffs (c : EqCnstr)
|
||||
| subst (x : Var) (c₁ : EqCnstr) (c₂ : EqCnstr)
|
||||
| ofLeGe (c₁ : LeCnstr) (c₂ : LeCnstr)
|
||||
|
||||
/-- A divisibility constraint and its justification/proof. -/
|
||||
structure DvdCnstr where
|
||||
d : Int
|
||||
@@ -37,6 +51,7 @@ inductive DvdCnstrProof where
|
||||
| ofEq (x : Var) (c : EqCnstr)
|
||||
| subst (x : Var) (c₁ : EqCnstr) (c₂ : DvdCnstr)
|
||||
|
||||
/-- An inequality constraint and its justification/proof. -/
|
||||
structure LeCnstr where
|
||||
p : Poly
|
||||
h : LeCnstrProof
|
||||
@@ -49,19 +64,22 @@ inductive LeCnstrProof where
|
||||
| divCoeffs (c : LeCnstr)
|
||||
| combine (c₁ c₂ : LeCnstr)
|
||||
| subst (x : Var) (c₁ : EqCnstr) (c₂ : LeCnstr)
|
||||
| ofLeDiseq (c₁ : LeCnstr) (c₂ : DiseqCnstr)
|
||||
-- TODO: missing constructors
|
||||
|
||||
structure EqCnstr where
|
||||
/-- A disequality constraint and its justification/proof. -/
|
||||
structure DiseqCnstr where
|
||||
p : Poly
|
||||
h : EqCnstrProof
|
||||
h : DiseqCnstrProof
|
||||
id : Nat
|
||||
|
||||
inductive EqCnstrProof where
|
||||
inductive DiseqCnstrProof where
|
||||
| expr (h : Expr)
|
||||
| core (p₁ p₂ : Poly) (h : Expr)
|
||||
| norm (c : EqCnstr)
|
||||
| divCoeffs (c : EqCnstr)
|
||||
| subst (x : Var) (c₁ : EqCnstr) (c₂ : EqCnstr)
|
||||
| norm (c : DiseqCnstr)
|
||||
| divCoeffs (c : DiseqCnstr)
|
||||
| subst (x : Var) (c₁ : EqCnstr) (c₂ : DiseqCnstr)
|
||||
|
||||
end
|
||||
|
||||
/--
|
||||
@@ -72,6 +90,7 @@ inductive UnsatProof where
|
||||
| dvd (c : DvdCnstr)
|
||||
| le (c : LeCnstr)
|
||||
| eq (c : EqCnstr)
|
||||
| diseq (c : DiseqCnstr)
|
||||
|
||||
abbrev VarSet := RBTree Var compare
|
||||
|
||||
@@ -84,18 +103,23 @@ structure State where
|
||||
/--
|
||||
Mapping from variables to divisibility constraints. Recall that we keep the divisibility constraint in solved form.
|
||||
Thus, we have at most one divisibility per variable. -/
|
||||
dvdCnstrs : PArray (Option DvdCnstr) := {}
|
||||
dvds : PArray (Option DvdCnstr) := {}
|
||||
/--
|
||||
Mapping from variables to their "lower" bounds. We say a relational constraint `c` is a lower bound for a variable `x`
|
||||
if `x` is the maximal variable in `c`, `c.isLe`, and `x` coefficient in `c` is negative.
|
||||
if `x` is the maximal variable in `c`, and `x` coefficient in `c` is negative.
|
||||
-/
|
||||
lowers : PArray (PArray LeCnstr) := {}
|
||||
/--
|
||||
Mapping from variables to their "upper" bounds. We say a relational constraint `c` is a upper bound for a variable `x`
|
||||
if `x` is the maximal variable in `c`, `c.isLe`, and `x` coefficient in `c` is positive.
|
||||
if `x` is the maximal variable in `c`, and `x` coefficient in `c` is positive.
|
||||
-/
|
||||
uppers : PArray (PArray LeCnstr) := {}
|
||||
/--
|
||||
Mapping from variables to their disequalities. We say a disequality constraint `c` is a disequality for a variable `x`
|
||||
if `x` is the maximal variable in `c`.
|
||||
-/
|
||||
diseqs : PArray (PArray DiseqCnstr) := {}
|
||||
/--
|
||||
Mapping from variable to equation constraint used to eliminate it. `solved` variables should not occur in
|
||||
`dvdCnstrs`, `lowers`, or `uppers`.
|
||||
-/
|
||||
@@ -123,7 +147,6 @@ structure State where
|
||||
/-
|
||||
TODO: support for storing
|
||||
- Disjuctions: they come from conflict resolution, and disequalities.
|
||||
- Disequalities.
|
||||
- Linear integer terms appearing in the main module, and model-based equality propagation.
|
||||
-/
|
||||
deriving Inhabited
|
||||
|
||||
@@ -65,6 +65,12 @@ def mkCnstrId : GoalM Nat := do
|
||||
modify' fun s => { s with nextCnstrId := id + 1 }
|
||||
return id
|
||||
|
||||
def mkEqCnstr (p : Poly) (h : EqCnstrProof) : GoalM EqCnstr := do
|
||||
return { p, h, id := (← mkCnstrId) }
|
||||
|
||||
@[extern "lean_grind_cutsat_assert_eq"] -- forward definition
|
||||
opaque EqCnstr.assert (c : EqCnstr) : GoalM Unit
|
||||
|
||||
private partial def shrink (a : PArray Int) (sz : Nat) : PArray Int :=
|
||||
if a.size > sz then
|
||||
shrink a.pop sz
|
||||
@@ -106,6 +112,20 @@ def DvdCnstr.denoteExpr (c : DvdCnstr) : GoalM Expr := do
|
||||
def DvdCnstr.throwUnexpected (c : DvdCnstr) : GoalM α := do
|
||||
throwError "`grind` internal error, unexpected{indentD (← c.pp)} "
|
||||
|
||||
def DiseqCnstr.isTrivial (c : DiseqCnstr) : Bool :=
|
||||
match c.p with
|
||||
| .num k => k != 0
|
||||
| _ => c.p.getConst % c.p.gcdCoeffs' != 0
|
||||
|
||||
def DiseqCnstr.pp (c : DiseqCnstr) : GoalM MessageData := do
|
||||
return m!"{← c.p.pp} ≠ 0"
|
||||
|
||||
def DiseqCnstr.throwUnexpected (c : DiseqCnstr) : GoalM α := do
|
||||
throwError "`grind` internal error, unexpected{indentD (← c.pp)}"
|
||||
|
||||
def DiseqCnstr.denoteExpr (c : DiseqCnstr) : GoalM Expr := do
|
||||
return mkNot (mkIntEq (← c.p.denoteExpr') (mkIntLit 0))
|
||||
|
||||
def LeCnstr.isTrivial (c : LeCnstr) : Bool :=
|
||||
match c.p with
|
||||
| .num k => k ≤ 0
|
||||
@@ -185,6 +205,7 @@ abbrev caching (id : Nat) (k : ProofM Expr) : ProofM Expr := do
|
||||
abbrev DvdCnstr.caching (c : DvdCnstr) (k : ProofM Expr) : ProofM Expr := Cutsat.caching c.id k
|
||||
abbrev LeCnstr.caching (c : LeCnstr) (k : ProofM Expr) : ProofM Expr := Cutsat.caching c.id k
|
||||
abbrev EqCnstr.caching (c : EqCnstr) (k : ProofM Expr) : ProofM Expr := Cutsat.caching c.id k
|
||||
abbrev DiseqCnstr.caching (c : DiseqCnstr) (k : ProofM Expr) : ProofM Expr := Cutsat.caching c.id k
|
||||
|
||||
abbrev withProofContext (x : ProofM Expr) : GoalM Expr := do
|
||||
withLetDecl `ctx (mkApp (mkConst ``RArray) (mkConst ``Int)) (← toContextExpr) fun ctx => do
|
||||
@@ -231,6 +252,14 @@ Returns `.true` if `c` is satisfied by the current partial model,
|
||||
def LeCnstr.satisfied (c : LeCnstr) : GoalM LBool := do
|
||||
c.p.satisfiedLe
|
||||
|
||||
/--
|
||||
Returns `.true` if `c` is satisfied by the current partial model,
|
||||
`.undef` if `c` contains unassigned variables, and `.false` otherwise.
|
||||
-/
|
||||
def DiseqCnstr.satisfied (c : DiseqCnstr) : GoalM LBool := do
|
||||
let some v ← c.p.eval? | return .undef
|
||||
return v != 0 |>.toLBool
|
||||
|
||||
/--
|
||||
Given a polynomial `p`, returns `some (x, k, c)` if `p` contains the monomial `k*x`,
|
||||
and `x` has been eliminated using the equality `c`.
|
||||
|
||||
@@ -18,9 +18,10 @@ def mkVar (expr : Expr) : GoalM Var := do
|
||||
modify' fun s => { s with
|
||||
vars := s.vars.push expr
|
||||
varMap := s.varMap.insert { expr } var
|
||||
dvdCnstrs := s.dvdCnstrs.push none
|
||||
dvds := s.dvds.push none
|
||||
lowers := s.lowers.push {}
|
||||
uppers := s.uppers.push {}
|
||||
diseqs := s.diseqs.push {}
|
||||
occurs := s.occurs.push {}
|
||||
elimEqs := s.elimEqs.push none
|
||||
}
|
||||
|
||||
@@ -112,22 +112,31 @@ private def propagateOffsetEq (rhsRoot lhsRoot : ENode) : GoalM Unit := do
|
||||
/--
|
||||
Helper function for combining `ENode.cutsat?` fields and propagating equalities
|
||||
to the offset constraint module.
|
||||
It returns a set of parents that should be traversed for disequality propagation.
|
||||
-/
|
||||
private def propagateCutsatEq (rhsRoot lhsRoot : ENode) : GoalM Unit := do
|
||||
private def propagateCutsatEq (rhsRoot lhsRoot : ENode) : GoalM ParentSet := do
|
||||
match lhsRoot.cutsat? with
|
||||
| some lhsCutsat =>
|
||||
if let some rhsCutsat := rhsRoot.cutsat? then
|
||||
Arith.Cutsat.processNewEq lhsCutsat rhsCutsat
|
||||
return {}
|
||||
else if isIntNum rhsRoot.self then
|
||||
Arith.Cutsat.processNewEqLit lhsCutsat rhsRoot.self
|
||||
return {}
|
||||
else
|
||||
-- We have to retrieve the node because other fields have been updated
|
||||
let rhsRoot ← getENode rhsRoot.self
|
||||
setENode rhsRoot.self { rhsRoot with cutsat? := lhsCutsat }
|
||||
getParents rhsRoot.self
|
||||
| none =>
|
||||
if isIntNum lhsRoot.self then
|
||||
if let some rhsCutsat := rhsRoot.cutsat? then
|
||||
Arith.Cutsat.processNewEqLit rhsCutsat lhsRoot.self
|
||||
if isIntNum lhsRoot.self then
|
||||
Arith.Cutsat.processNewEqLit rhsCutsat lhsRoot.self
|
||||
return {}
|
||||
else
|
||||
getParents lhsRoot.self
|
||||
else
|
||||
return {}
|
||||
|
||||
/--
|
||||
Tries to apply beta-reductiong using the parent applications of the functions in `fns` with
|
||||
@@ -225,15 +234,16 @@ where
|
||||
}
|
||||
propagateBeta lams₁ fns₁
|
||||
propagateBeta lams₂ fns₂
|
||||
propagateOffsetEq rhsRoot lhsRoot
|
||||
let parentsToPropagateDiseqs ← propagateCutsatEq rhsRoot lhsRoot
|
||||
resetParentsOf lhsRoot.self
|
||||
copyParentsTo parents rhsNode.root
|
||||
unless (← isInconsistent) do
|
||||
updateMT rhsRoot.self
|
||||
propagateOffsetEq rhsRoot lhsRoot
|
||||
propagateCutsatEq rhsRoot lhsRoot
|
||||
unless (← isInconsistent) do
|
||||
for parent in parents do
|
||||
propagateUp parent
|
||||
propagateCutsatDiseqs parentsToPropagateDiseqs
|
||||
|
||||
updateRoots (lhs : Expr) (rootNew : Expr) : GoalM Unit := do
|
||||
traverseEqc lhs fun n =>
|
||||
|
||||
81
src/Lean/Meta/Tactic/Grind/Diseq.lean
Normal file
81
src/Lean/Meta/Tactic/Grind/Diseq.lean
Normal file
@@ -0,0 +1,81 @@
|
||||
/-
|
||||
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Grind.Lemmas
|
||||
import Lean.Meta.Tactic.Grind.Types
|
||||
|
||||
namespace Lean.Meta.Grind
|
||||
|
||||
/--
|
||||
Returns `some (c = d)` if
|
||||
- `c = d` and `False` are in the same equivalence class, and
|
||||
- `a` (`b`) and `c` are in the same equivalence class, and
|
||||
- `b` (`a`) and `d` are in the same equivalence class.
|
||||
Otherwise return `none`.
|
||||
|
||||
Remark `a` and `b` are assumed to have the same type.
|
||||
-/
|
||||
private def getDiseqFor? (a b : Expr) : GoalM (Option Expr) := do
|
||||
/-
|
||||
In Z3, we use the congruence table to find equalities more efficiently,
|
||||
but this optimization would be more complicated here because equalities have
|
||||
the type as an implicit argument, and `grind`s congruence table assumes it is
|
||||
hash-consed and canonicalized. So, we use the "slower" approach of visiting
|
||||
parents.
|
||||
-/
|
||||
let aRoot ← getRoot a
|
||||
let bRoot ← getRoot b
|
||||
let aParents ← getParents aRoot
|
||||
let bParents ← getParents bRoot
|
||||
if aParents.size ≤ bParents.size then
|
||||
go aParents
|
||||
else
|
||||
go bParents
|
||||
where
|
||||
go (parents : ParentSet) : GoalM (Option Expr) := do
|
||||
for parent in parents do
|
||||
let_expr Eq α c d := parent | continue
|
||||
if (← isEqFalse parent) then
|
||||
-- Remark: we expect `hasType` test to seldom fail, but it can happen because of
|
||||
-- heterogeneous equalities
|
||||
if (← isEqv a c <&&> isEqv b d <&&> hasType a α) then
|
||||
return some parent
|
||||
if (← isEqv a d <&&> isEqv b c <&&> hasType a α) then
|
||||
return some parent
|
||||
return none
|
||||
|
||||
/--
|
||||
Returns `true` if `a` and `b` are known to be disequal.
|
||||
See `getDiseqFor?`
|
||||
-/
|
||||
def isDiseq (a b : Expr) : GoalM Bool := do
|
||||
return (← getDiseqFor? a b).isSome
|
||||
|
||||
/--
|
||||
Returns a proof for `true` if `a` and `b` are known to be disequal.
|
||||
See `getDiseqFor?`
|
||||
-/
|
||||
def mkDiseqProof? (a b : Expr) : GoalM (Option Expr) := do
|
||||
let some eq ← getDiseqFor? a b | return none
|
||||
let_expr f@Eq α c d := eq | unreachable!
|
||||
let u := f.constLevels!
|
||||
let h ← mkOfEqFalse (← mkEqFalseProof eq)
|
||||
let (c, d, h) ← if (← isEqv a c <&&> isEqv b d) then
|
||||
pure (c, d, h)
|
||||
else
|
||||
pure (d, c, mkApp4 (mkConst ``Ne.symm u) α c d h)
|
||||
-- We have `a = c` and `b = d`
|
||||
let h ← if isSameExpr a c then
|
||||
pure h
|
||||
else
|
||||
pure <| mkApp6 (mkConst ``Grind.ne_of_ne_of_eq_left u) α a c d (← mkEqProof a c) h
|
||||
-- `h : a ≠ d
|
||||
if isSameExpr b d then
|
||||
return h
|
||||
else
|
||||
return mkApp6 (mkConst ``Grind.ne_of_ne_of_eq_right u) α b a d (← mkEqProof b d) h
|
||||
|
||||
end Lean.Meta.Grind
|
||||
@@ -146,6 +146,7 @@ builtin_grind_propagator propagateEqDown ↓Eq := fun e => do
|
||||
pushEq a b <| mkOfEqTrueCore e (← mkEqTrueProof e)
|
||||
else if (← isEqFalse e) then
|
||||
let_expr Eq α lhs rhs := e | return ()
|
||||
propagateCutsatDiseq lhs rhs
|
||||
let thms ← getExtTheorems α
|
||||
if !thms.isEmpty then
|
||||
/-
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Leonardo de Moura
|
||||
prelude
|
||||
import Init.Grind.Tactics
|
||||
import Init.Data.Queue
|
||||
import Std.Data.TreeSet
|
||||
import Lean.Util.ShareCommon
|
||||
import Lean.HeadIndex
|
||||
import Lean.Meta.Basic
|
||||
@@ -396,7 +397,7 @@ instance : BEq (CongrKey enodes) where
|
||||
abbrev CongrTable (enodes : ENodeMap) := PHashSet (CongrKey enodes)
|
||||
|
||||
-- Remark: we cannot use pointer addresses here because we have to traverse the tree.
|
||||
abbrev ParentSet := RBTree Expr Expr.quickComp
|
||||
abbrev ParentSet := Std.TreeSet Expr Expr.quickComp
|
||||
abbrev ParentMap := PHashMap ENodeKey ParentSet
|
||||
|
||||
/--
|
||||
@@ -865,9 +866,16 @@ opaque Arith.Cutsat.processNewEq (a b : Expr) : GoalM Unit
|
||||
Notifies the cutsat module that `a = k` where
|
||||
`a` is term that has been internalized by this module, and `k` is a numeral.
|
||||
-/
|
||||
@[extern "lean_process_new_cutsat_lit"] -- forward definition
|
||||
@[extern "lean_process_cutsat_eq_lit"] -- forward definition
|
||||
opaque Arith.Cutsat.processNewEqLit (a k : Expr) : GoalM Unit
|
||||
|
||||
/--
|
||||
Notifies the cutsat module that `a ≠ b` where
|
||||
`a` and `b` are terms that have been internalized by this module.
|
||||
-/
|
||||
@[extern "lean_process_cutsat_diseq"] -- forward definition
|
||||
opaque Arith.Cutsat.processNewDiseq (a b : Expr) : GoalM Unit
|
||||
|
||||
/-- Returns `true` if `e` is a nonegative numeral and has type `Int`. -/
|
||||
def isNonnegIntNum (e : Expr) : Bool := Id.run do
|
||||
let_expr OfNat.ofNat _ _ inst := e | false
|
||||
@@ -882,6 +890,47 @@ def isIntNum (e : Expr) : Bool :=
|
||||
isNonnegIntNum e
|
||||
| _ => isNonnegIntNum e
|
||||
|
||||
/--
|
||||
Returns `true` if type of `t` is definitionally equal to `α`
|
||||
-/
|
||||
def hasType (t α : Expr) : MetaM Bool :=
|
||||
withDefault do isDefEq (← inferType t) α
|
||||
|
||||
/--
|
||||
For each equality `b = c` in `parents`, executes `k b c` IF
|
||||
- `b = c` is equal to `False`, and
|
||||
-/
|
||||
@[inline] def forEachDiseq (parents : ParentSet) (k : (lhs : Expr) → (rhs : Expr) → GoalM Unit) : GoalM Unit := do
|
||||
for parent in parents do
|
||||
let_expr Eq _ b c := parent | continue
|
||||
if (← isEqFalse parent) then
|
||||
k b c
|
||||
|
||||
/--
|
||||
Given `lhs` and `rhs` that are known to be disequal, checks whether
|
||||
`lhs` and `rhs` have cutsat terms `e₁` and `e₂` attached to them,
|
||||
and invokes process `Arith.Cutsat.processNewDiseq e₁ e₂`
|
||||
-/
|
||||
def propagateCutsatDiseq (lhs rhs : Expr) : GoalM Unit := do
|
||||
let some lhs ← get? lhs | return ()
|
||||
let some rhs ← get? rhs | return ()
|
||||
-- Recall that core can take care of disequalities of the form `1≠2`.
|
||||
unless isIntNum lhs && isIntNum rhs do
|
||||
Arith.Cutsat.processNewDiseq lhs rhs
|
||||
where
|
||||
get? (a : Expr) : GoalM (Option Expr) := do
|
||||
let root ← getRootENode a
|
||||
if isIntNum root.self then
|
||||
return some root.self
|
||||
return root.cutsat?
|
||||
|
||||
/--
|
||||
Traverses disequalities in `parents`, and propagate the ones relevant to the
|
||||
cutsat module.
|
||||
-/
|
||||
def propagateCutsatDiseqs (parents : ParentSet) : GoalM Unit := do
|
||||
forEachDiseq parents propagateCutsatDiseq
|
||||
|
||||
/--
|
||||
Marks `e` as a term of interest to the cutsat module.
|
||||
If the root of `e`s equivalence class has already a term of interest,
|
||||
@@ -895,6 +944,7 @@ def markAsCutsatTerm (e : Expr) : GoalM Unit := do
|
||||
Arith.Cutsat.processNewEqLit e root.self
|
||||
else
|
||||
setENode root.self { root with cutsat? := some e }
|
||||
propagateCutsatDiseqs (← getParents root.self)
|
||||
|
||||
/-- Returns `true` is `e` is the root of its congruence class. -/
|
||||
def isCongrRoot (e : Expr) : GoalM Bool := do
|
||||
|
||||
@@ -8,6 +8,7 @@ import Lean.Server.CodeActions
|
||||
import Lean.Widget.UserWidget
|
||||
import Lean.Data.Json.Elab
|
||||
import Lean.Data.Lsp.Utf16
|
||||
import Lean.Meta.Tactic.ExposeNames
|
||||
|
||||
/-!
|
||||
# "Try this" support
|
||||
@@ -426,17 +427,27 @@ def addSuggestions (ref : Syntax) (suggestions : Array Suggestion)
|
||||
(codeActionPrefix? : Option String := none) : MetaM Unit := do
|
||||
if suggestions.isEmpty then throwErrorAt ref "no suggestions available"
|
||||
let msgs := suggestions.map toMessageData
|
||||
let msgs := msgs.foldl (init := MessageData.nil) (fun msg m => msg ++ m!"\n• " ++ m)
|
||||
let msgs := msgs.foldl (init := MessageData.nil) (fun msg m => msg ++ m!"\n• " ++ .nest 2 m)
|
||||
logInfoAt ref m!"{header}{msgs}"
|
||||
addSuggestionCore ref suggestions header (isInline := false) origSpan? style? codeActionPrefix?
|
||||
|
||||
private def addExactSuggestionCore (addSubgoalsMsg : Bool) (e : Expr) : MetaM Suggestion :=
|
||||
/--
|
||||
Returns the syntax for an `exact` or `refine` (as indicated by `useRefine`) tactic corresponding to
|
||||
`e`. If `exposeNames` is `true`, prepends the tactic with `expose_names.`
|
||||
-/
|
||||
def mkExactSuggestionSyntax (e : Expr) (useRefine : Bool) (exposeNames : Bool) : MetaM (TSyntax `tactic) :=
|
||||
withOptions (pp.mvars.set · false) do
|
||||
let exprStx ← (if exposeNames then withExposedNames else id) <| delabToRefinableSyntax e
|
||||
let tac ← if useRefine then `(tactic| refine $exprStx) else `(tactic| exact $exprStx)
|
||||
let tacSeq ← if exposeNames then `(tactic| (expose_names; $tac)) else pure tac
|
||||
return tacSeq
|
||||
|
||||
private def addExactSuggestionCore (addSubgoalsMsg : Bool) (exposeNames : Bool) (e : Expr) :
|
||||
MetaM Suggestion :=
|
||||
withOptions (pp.mvars.set · false) do
|
||||
let stx ← delabToRefinableSyntax e
|
||||
let mvars ← getMVars e
|
||||
let suggestion ← if mvars.isEmpty then `(tactic| exact $stx) else `(tactic| refine $stx)
|
||||
let pp ← ppExpr e
|
||||
let messageData? := if mvars.isEmpty then m!"exact {pp}" else m!"refine {pp}"
|
||||
let mut suggestion ← mkExactSuggestionSyntax e (useRefine := !mvars.isEmpty) exposeNames
|
||||
let messageData? ← SuggestionText.prettyExtra suggestion
|
||||
let postInfo? ← if !addSubgoalsMsg || mvars.isEmpty then pure none else
|
||||
let mut str := "\nRemaining subgoals:"
|
||||
for g in mvars do
|
||||
@@ -457,11 +468,12 @@ The parameters are:
|
||||
`Remaining subgoals:`
|
||||
* `codeActionPrefix?`: an optional string to be used as the prefix of the replacement text if the
|
||||
suggestion does not have a custom `toCodeActionTitle?`. If not provided, `"Try this: "` is used.
|
||||
* `exposeNames`: if true (default false), will insert `expose_names` prior to the generated tactic
|
||||
-/
|
||||
def addExactSuggestion (ref : Syntax) (e : Expr)
|
||||
(origSpan? : Option Syntax := none) (addSubgoalsMsg := false)
|
||||
(codeActionPrefix? : Option String := none): MetaM Unit := do
|
||||
addSuggestion ref (← addExactSuggestionCore addSubgoalsMsg e)
|
||||
(codeActionPrefix? : Option String := none) (exposeNames := false) : MetaM Unit := do
|
||||
addSuggestion ref (← addExactSuggestionCore addSubgoalsMsg exposeNames e)
|
||||
(origSpan? := origSpan?) (codeActionPrefix? := codeActionPrefix?)
|
||||
|
||||
/-- Add `exact e` or `refine e` suggestions.
|
||||
@@ -479,8 +491,8 @@ The parameters are:
|
||||
-/
|
||||
def addExactSuggestions (ref : Syntax) (es : Array Expr)
|
||||
(origSpan? : Option Syntax := none) (addSubgoalsMsg := false)
|
||||
(codeActionPrefix? : Option String := none) : MetaM Unit := do
|
||||
let suggestions ← es.mapM <| addExactSuggestionCore addSubgoalsMsg
|
||||
(codeActionPrefix? : Option String := none) (exposeNames := false) : MetaM Unit := do
|
||||
let suggestions ← es.mapM <| addExactSuggestionCore addSubgoalsMsg exposeNames
|
||||
addSuggestions ref suggestions (origSpan? := origSpan?) (codeActionPrefix? := codeActionPrefix?)
|
||||
|
||||
/-- Add a term suggestion.
|
||||
|
||||
@@ -390,7 +390,8 @@ def setupImports (meta : DocumentMeta) (cmdlineOpts : Options) (chanOut : Std.Ch
|
||||
let opts := cmdlineOpts.mergeBy (fun _ _ fileOpt => fileOpt) fileSetupResult.fileOptions
|
||||
|
||||
-- default to async elaboration; see also `Elab.async` docs
|
||||
let opts := Elab.async.setIfNotSet opts true
|
||||
-- (temporarily disabled pending #7241)
|
||||
--let opts := Elab.async.setIfNotSet opts true
|
||||
|
||||
return .ok {
|
||||
mainModuleName
|
||||
|
||||
@@ -5,7 +5,8 @@ Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Lean.Expr
|
||||
import Lean.Environment
|
||||
import Lean.Util.PtrSet
|
||||
import Lean.Declaration
|
||||
|
||||
namespace Lean
|
||||
namespace Expr
|
||||
@@ -70,14 +71,4 @@ def getUsedConstantsAsSet (c : ConstantInfo) : NameSet :=
|
||||
| _ => {}
|
||||
|
||||
end ConstantInfo
|
||||
|
||||
def getMaxHeight (env : Environment) (e : Expr) : UInt32 :=
|
||||
e.foldConsts 0 fun constName max =>
|
||||
match env.find? constName with
|
||||
| ConstantInfo.defnInfo val =>
|
||||
match val.hints with
|
||||
| ReducibilityHints.regular h => if h > max then h else max
|
||||
| _ => max
|
||||
| _ => max
|
||||
|
||||
end Lean
|
||||
|
||||
@@ -380,7 +380,9 @@ def addTraceAsMessages [Monad m] [MonadRef m] [MonadLog m] [MonadTrace m] : m Un
|
||||
pos2traces := pos2traces.insert (pos, endPos) <| pos2traces.getD (pos, endPos) #[] |>.push traceElem.msg
|
||||
let traces' := pos2traces.toArray.qsort fun ((a, _), _) ((b, _), _) => a < b
|
||||
for ((pos, endPos), traceMsg) in traces' do
|
||||
let data := .tagged `trace <| .joinSep traceMsg.toList "\n"
|
||||
-- cmdline and info view differ in how they insert newlines in between trace nodes so we just
|
||||
-- put them in a synthetic root node for now and let the rendering functions handle this case
|
||||
let data := .tagged `trace <| .trace { cls := .anonymous } .nil traceMsg
|
||||
logMessage <| Elab.mkMessageCore (← getFileName) (← getFileMap) data .information pos endPos
|
||||
|
||||
end Lean
|
||||
|
||||
@@ -149,6 +149,12 @@ where
|
||||
| ctx, compose d₁ d₂ => do let d₁ ← go nCtx ctx d₁; let d₂ ← go nCtx ctx d₂; pure $ d₁ ++ d₂
|
||||
| ctx, group d => Format.group <$> go nCtx ctx d
|
||||
| ctx, .trace data header children => do
|
||||
if data.cls.isAnonymous then
|
||||
-- Sequence of top-level traces collected by `addTraceAsMessages`, do not indent.
|
||||
-- As with nested sibling nodes, we do not separate them with newlines but rely on the client
|
||||
-- to never put trace nodes on the same line.
|
||||
return .join (← children.mapM (go nCtx ctx)).toList
|
||||
|
||||
let mut header := (← go nCtx ctx header).nest 4
|
||||
if data.startTime != 0 then
|
||||
header := f!"[{data.stopTime - data.startTime}] {header}"
|
||||
|
||||
@@ -28,12 +28,14 @@ class ReflCmp {α : Type u} (cmp : α → α → Ordering) : Prop where
|
||||
/-- Comparison is reflexive. -/
|
||||
compare_self {a : α} : cmp a a = .eq
|
||||
|
||||
export ReflCmp (compare_self)
|
||||
|
||||
/-- A typeclasses for ordered types for which `compare a a = .eq` for all `a`. -/
|
||||
abbrev ReflOrd (α : Type u) [Ord α] := ReflCmp (compare : α → α → Ordering)
|
||||
|
||||
attribute [simp] compare_self
|
||||
@[simp]
|
||||
theorem ReflOrd.compare_self {α : Type u} [Ord α] [ReflOrd α] {a : α} : compare a a = .eq :=
|
||||
ReflCmp.compare_self
|
||||
|
||||
export ReflOrd (compare_self)
|
||||
|
||||
end Refl
|
||||
|
||||
@@ -266,7 +268,7 @@ variable {α : Type u} {cmp : α → α → Ordering} [LawfulEqCmp cmp]
|
||||
|
||||
@[simp]
|
||||
theorem compare_eq_iff_eq {a b : α} : cmp a b = .eq ↔ a = b :=
|
||||
⟨LawfulEqCmp.eq_of_compare, by rintro rfl; simp⟩
|
||||
⟨LawfulEqCmp.eq_of_compare, by rintro rfl; exact ReflCmp.compare_self⟩
|
||||
|
||||
@[simp]
|
||||
theorem compare_beq_iff_eq {a b : α} : cmp a b == .eq ↔ a = b :=
|
||||
@@ -293,7 +295,7 @@ theorem beq_eq [Ord α] {a b : α} : (a == b) = (compare a b == .eq) :=
|
||||
theorem equivBEq_of_transOrd [Ord α] [TransOrd α] : EquivBEq α where
|
||||
symm {a b} h := by simp_all [OrientedCmp.eq_comm]
|
||||
trans h₁ h₂ := by simp_all only [beq_eq, beq_iff_eq]; exact TransCmp.eq_trans h₁ h₂
|
||||
refl := by simp
|
||||
refl := by simp only [beq_eq, beq_iff_eq]; exact compare_self
|
||||
|
||||
theorem lawfulBEq_of_lawfulEqOrd [Ord α] [LawfulEqOrd α] : LawfulBEq α where
|
||||
eq_of_beq hbeq := by simp_all
|
||||
|
||||
@@ -629,12 +629,12 @@ variable {β : Type v}
|
||||
def getThenInsertIfNew? (t : DTreeMap α β cmp) (a : α) (b : β) :
|
||||
Option β × DTreeMap α β cmp :=
|
||||
letI : Ord α := ⟨cmp⟩
|
||||
let p := Impl.Const.getThenInsertIfNew? a b t.inner t.wf.balanced
|
||||
let p := Impl.Const.getThenInsertIfNew? t.inner a b t.wf.balanced
|
||||
(p.1, ⟨p.2, t.wf.constGetThenInsertIfNew?⟩)
|
||||
|
||||
@[inline, inherit_doc DTreeMap.get?]
|
||||
def get? (t : DTreeMap α β cmp) (a : α) : Option β :=
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.get? a t.inner
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.get? t.inner a
|
||||
|
||||
@[inline, inherit_doc get?, deprecated get? (since := "2025-02-12")]
|
||||
def find? (t : DTreeMap α β cmp) (a : α) : Option β :=
|
||||
@@ -642,11 +642,11 @@ def find? (t : DTreeMap α β cmp) (a : α) : Option β :=
|
||||
|
||||
@[inline, inherit_doc DTreeMap.get]
|
||||
def get (t : DTreeMap α β cmp) (a : α) (h : a ∈ t) : β :=
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.get a t.inner h
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.get t.inner a h
|
||||
|
||||
@[inline, inherit_doc DTreeMap.get!]
|
||||
def get! (t : DTreeMap α β cmp) (a : α) [Inhabited β] : β :=
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.get! a t.inner
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.get! t.inner a
|
||||
|
||||
@[inline, inherit_doc get!, deprecated get! (since := "2025-02-12")]
|
||||
def find! (t : DTreeMap α β cmp) (a : α) [Inhabited β] : β :=
|
||||
@@ -654,7 +654,7 @@ def find! (t : DTreeMap α β cmp) (a : α) [Inhabited β] : β :=
|
||||
|
||||
@[inline, inherit_doc DTreeMap.getD]
|
||||
def getD (t : DTreeMap α β cmp) (a : α) (fallback : β) : β :=
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.getD a t.inner fallback
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.getD t.inner a fallback
|
||||
|
||||
@[inline, inherit_doc getD, deprecated getD (since := "2025-02-12")]
|
||||
def findD (t : DTreeMap α β cmp) (a : α) (fallback : β) : β :=
|
||||
|
||||
@@ -763,13 +763,13 @@ theorem balance_eq_inner [Ord α] {sz k v} {l r : Impl α β}
|
||||
balance k v l r hl.left hl.right h = inner sz k v l r := by
|
||||
rw [balance_eq_balance!, balance!_eq_balanceₘ hl.left hl.right h, balanceₘ]
|
||||
have hl' := balanced_inner_iff.mp hl
|
||||
cases k, v, l, r, hl.left, hl.right, h using balanceₘ.fun_cases <;> tree_tac
|
||||
fun_cases balanceₘ k v l r <;> tree_tac
|
||||
|
||||
theorem balance!_desc {k : α} {v : β k} {l r : Impl α β} (hlb : l.Balanced) (hrb : r.Balanced)
|
||||
(hlr : BalanceLErasePrecond l.size r.size ∨ BalanceLErasePrecond r.size l.size) :
|
||||
(balance! k v l r).size = l.size + 1 + r.size ∧ (balance! k v l r).Balanced := by
|
||||
rw [balance!_eq_balanceₘ hlb hrb hlr, balanceₘ]
|
||||
cases k, v, l, r, hlb, hrb, hlr using balanceₘ.fun_cases
|
||||
fun_cases balanceₘ k v l r
|
||||
· rw [if_pos ‹_›, bin, balanced_inner_iff]
|
||||
exact ⟨rfl, hlb, hrb, Or.inl ‹_›, rfl⟩
|
||||
· rw [if_neg ‹_›, dif_pos ‹_›]
|
||||
|
||||
@@ -43,7 +43,7 @@ def ofEq [Ord α] {k : α → Ordering} (k' : α) (v' : β k') (hcmp : ∀ [Orie
|
||||
|
||||
/-- Create a cell with a matching key. Internal implementation detail of the tree map -/
|
||||
def of [Ord α] (k : α) (v : β k) : Cell α β (compare k) :=
|
||||
.ofEq k v (by intro; simp)
|
||||
.ofEq k v compare_self
|
||||
|
||||
@[simp]
|
||||
theorem ofEq_inner [Ord α] {k : α → Ordering} {k' : α} {v' : β k'} {h} :
|
||||
@@ -97,6 +97,16 @@ theorem get?_empty [Ord α] [OrientedOrd α] [LawfulEqOrd α] {k : α} :
|
||||
(Cell.empty : Cell α β (compare k)).get? = none :=
|
||||
rfl
|
||||
|
||||
/-- Internal implementation detail of the tree map -/
|
||||
def getKey? [Ord α] {k : α} (c : Cell α β (compare k)) : Option α :=
|
||||
match c.inner with
|
||||
| none => none
|
||||
| some p => some p.1
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_empty [Ord α] {k : α} : (Cell.empty : Cell α β (compare k)).getKey? = none :=
|
||||
rfl
|
||||
|
||||
/-- Internal implementation detail of the tree map -/
|
||||
def alter [Ord α] [OrientedOrd α] [LawfulEqOrd α] {k : α}
|
||||
(f : Option (β k) → Option (β k)) (c : Cell α β (compare k)) :
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -202,16 +202,66 @@ def updateCell [Ord α] (k : α) (f : Cell α β (compare k) → Cell α β (com
|
||||
Model implementation of the `contains` function.
|
||||
Internal implementation detail of the tree map
|
||||
-/
|
||||
def containsₘ [Ord α] (k : α) (l : Impl α β) : Bool :=
|
||||
def containsₘ [Ord α] (l : Impl α β) (k : α) : Bool :=
|
||||
applyCell k l fun c _ => c.contains
|
||||
|
||||
/--
|
||||
Model implementation of the `get?` function.
|
||||
Internal implementation detail of the tree map
|
||||
-/
|
||||
def get?ₘ [Ord α] [OrientedOrd α] [LawfulEqOrd α] (k : α) (l : Impl α β) : Option (β k) :=
|
||||
def get?ₘ [Ord α] [OrientedOrd α] [LawfulEqOrd α] (l : Impl α β) (k : α) : Option (β k) :=
|
||||
applyCell k l fun c _ => c.get?
|
||||
|
||||
/--
|
||||
Model implementation of the `get` function.
|
||||
Internal implementation detail of the tree map
|
||||
-/
|
||||
def getₘ [Ord α] [OrientedOrd α] [LawfulEqOrd α] (l : Impl α β) (k : α) (h : (get?ₘ l k).isSome) :
|
||||
β k :=
|
||||
get?ₘ l k |>.get h
|
||||
|
||||
/--
|
||||
Model implementation of the `get!` function.
|
||||
Internal implementation detail of the tree map
|
||||
-/
|
||||
def get!ₘ [Ord α] [OrientedOrd α] [LawfulEqOrd α] (l : Impl α β) (k : α) [Inhabited (β k)] : β k :=
|
||||
get?ₘ l k |>.get!
|
||||
|
||||
/--
|
||||
Model implementation of the `getD` function.
|
||||
Internal implementation detail of the tree map
|
||||
-/
|
||||
def getDₘ [Ord α] [OrientedOrd α] [LawfulEqOrd α] (k : α) (l : Impl α β) (fallback : β k) : β k :=
|
||||
get?ₘ l k |>.getD fallback
|
||||
|
||||
/--
|
||||
Model implementation of the `getKey?` function.
|
||||
Internal implementation detail of the tree map
|
||||
-/
|
||||
def getKey?ₘ [Ord α] (l : Impl α β) (k : α) : Option α :=
|
||||
applyCell k l fun c _ => c.getKey?
|
||||
|
||||
/--
|
||||
Model implementation of the `getKey` function.
|
||||
Internal implementation detail of the tree map
|
||||
-/
|
||||
def getKeyₘ [Ord α] (l : Impl α β) (k : α) (h : (getKey?ₘ l k).isSome) : α :=
|
||||
getKey?ₘ l k |>.get h
|
||||
|
||||
/--
|
||||
Model implementation of the `getKey!` function.
|
||||
Internal implementation detail of the tree map
|
||||
-/
|
||||
def getKey!ₘ [Ord α] (l : Impl α β) (k : α) [Inhabited α] : α :=
|
||||
getKey?ₘ l k |>.get!
|
||||
|
||||
/--
|
||||
Model implementation of the `getKeyD` function.
|
||||
Internal implementation detail of the tree map
|
||||
-/
|
||||
def getKeyDₘ [Ord α] (k : α) (l : Impl α β) (fallback : α) : α :=
|
||||
getKey?ₘ l k |>.getD fallback
|
||||
|
||||
/--
|
||||
Model implementation of the `insert` function.
|
||||
Internal implementation detail of the tree map
|
||||
@@ -251,9 +301,31 @@ variable {β : Type v}
|
||||
Model implementation of the `get?` function.
|
||||
Internal implementation detail of the tree map
|
||||
-/
|
||||
def get?ₘ [Ord α] (k : α) (l : Impl α (fun _ => β)) : Option β :=
|
||||
def get?ₘ [Ord α] (l : Impl α (fun _ => β)) (k : α) : Option β :=
|
||||
applyCell k l fun c _ => Cell.Const.get? c
|
||||
|
||||
/--
|
||||
Model implementation of the `get` function.
|
||||
Internal implementation detail of the tree map
|
||||
-/
|
||||
def getₘ [Ord α] (l : Impl α (fun _ => β)) (k : α) (h : (get?ₘ l k).isSome) :
|
||||
β :=
|
||||
get?ₘ l k |>.get h
|
||||
|
||||
/--
|
||||
Model implementation of the `get!` function.
|
||||
Internal implementation detail of the tree map
|
||||
-/
|
||||
def get!ₘ [Ord α] (l : Impl α (fun _ => β)) (k : α) [Inhabited β] : β :=
|
||||
get?ₘ l k |>.get!
|
||||
|
||||
/--
|
||||
Model implementation of the `getD` function.
|
||||
Internal implementation detail of the tree map
|
||||
-/
|
||||
def getDₘ [Ord α] (l : Impl α (fun _ => β)) (k : α) (fallback : β) : β :=
|
||||
get?ₘ l k |>.getD fallback
|
||||
|
||||
/--
|
||||
Model implementation of the `alter` function.
|
||||
Internal implementation detail of the tree map
|
||||
@@ -301,6 +373,75 @@ theorem get?_eq_get?ₘ [Ord α] [OrientedOrd α] [LawfulEqOrd α] (k : α) (l :
|
||||
all_goals simp_all [Cell.get?, Cell.ofEq]
|
||||
· simp [get?, applyCell]
|
||||
|
||||
theorem get_eq_get? [Ord α] [OrientedOrd α] [LawfulEqOrd α] (k : α) (l : Impl α β) {h} :
|
||||
l.get k h = l.get? k := by
|
||||
induction l
|
||||
· simp only [applyCell, get, get?]
|
||||
split <;> rename_i ihl ihr hcmp <;> simp_all
|
||||
· contradiction
|
||||
|
||||
theorem get_eq_getₘ [Ord α] [OrientedOrd α] [LawfulEqOrd α] (k : α) (l : Impl α β) {h} (h') :
|
||||
l.get k h = l.getₘ k h' := by
|
||||
apply Option.some.inj
|
||||
simp [get_eq_get?, get?_eq_get?ₘ, getₘ]
|
||||
|
||||
theorem get!_eq_get!ₘ [Ord α] [OrientedOrd α] [LawfulEqOrd α] (k : α) [Inhabited (β k)] (l : Impl α β) :
|
||||
l.get! k = l.get!ₘ k := by
|
||||
simp only [get!ₘ, get?ₘ]
|
||||
induction l
|
||||
· simp only [applyCell, get!]
|
||||
split <;> rename_i hcmp₁ <;> split <;> rename_i hcmp₂ <;> try (simp [hcmp₁] at hcmp₂; done)
|
||||
all_goals simp_all [Cell.get?, Cell.ofEq]
|
||||
· simp only [get!, applyCell, Cell.get?_empty, Option.get!_none]; rfl
|
||||
|
||||
theorem getD_eq_getDₘ [Ord α] [OrientedOrd α] [LawfulEqOrd α] (k : α) (l : Impl α β)
|
||||
(fallback : β k) : l.getD k fallback = l.getDₘ k fallback := by
|
||||
simp only [getDₘ, get?ₘ]
|
||||
induction l
|
||||
· simp only [applyCell, getD]
|
||||
split <;> rename_i hcmp₁ <;> split <;> rename_i hcmp₂ <;> try (simp [hcmp₁] at hcmp₂; done)
|
||||
all_goals simp_all [Cell.get?, Cell.ofEq]
|
||||
· simp only [getD, applyCell, Cell.get?_empty, Option.getD_none]
|
||||
|
||||
theorem getKey?_eq_getKey?ₘ [Ord α] (k : α) (l : Impl α β) :
|
||||
l.getKey? k = l.getKey?ₘ k := by
|
||||
simp only [getKey?ₘ]
|
||||
induction l
|
||||
· simp only [applyCell, getKey?]
|
||||
split <;> rename_i hcmp₁ <;> split <;> rename_i hcmp₂ <;> try (simp [hcmp₁] at hcmp₂; done)
|
||||
all_goals simp_all [Cell.getKey?, Cell.ofEq]
|
||||
· simp [getKey?, applyCell]
|
||||
|
||||
theorem getKey_eq_getKey? [Ord α] (k : α) (l : Impl α β) {h} :
|
||||
l.getKey k h = l.getKey? k := by
|
||||
induction l
|
||||
· simp only [applyCell, getKey, getKey?]
|
||||
split <;> rename_i ihl ihr hcmp <;> simp_all
|
||||
· contradiction
|
||||
|
||||
theorem getKey_eq_getKeyₘ [Ord α] (k : α) (l : Impl α β) {h} (h') :
|
||||
l.getKey k h = l.getKeyₘ k h' := by
|
||||
apply Option.some.inj
|
||||
simp [getKey_eq_getKey?, getKey?_eq_getKey?ₘ, getKeyₘ]
|
||||
|
||||
theorem getKey!_eq_getKey!ₘ [Ord α] (k : α) [Inhabited α] (l : Impl α β) :
|
||||
l.getKey! k = l.getKey!ₘ k := by
|
||||
simp only [getKey!ₘ, getKey?ₘ]
|
||||
induction l
|
||||
· simp only [applyCell, getKey!]
|
||||
split <;> rename_i hcmp₁ <;> split <;> rename_i hcmp₂ <;> try (simp [hcmp₁] at hcmp₂; done)
|
||||
all_goals simp_all [Cell.getKey?, Cell.ofEq]
|
||||
· simp only [getKey!, applyCell, Cell.getKey?_empty, Option.get!_none]; rfl
|
||||
|
||||
theorem getKeyD_eq_getKeyDₘ [Ord α] (k : α) (l : Impl α β)
|
||||
(fallback : α) : l.getKeyD k fallback = l.getKeyDₘ k fallback := by
|
||||
simp only [getKeyDₘ, getKey?ₘ]
|
||||
induction l
|
||||
· simp only [applyCell, getKeyD]
|
||||
split <;> rename_i hcmp₁ <;> split <;> rename_i hcmp₂ <;> try (simp [hcmp₁] at hcmp₂; done)
|
||||
all_goals simp_all [Cell.getKey?, Cell.ofEq]
|
||||
· simp only [getKeyD, applyCell, Cell.getKey?_empty, Option.getD_none]
|
||||
|
||||
theorem balanceL_eq_balance {k : α} {v : β k} {l r : Impl α β} {hlb hrb hlr} :
|
||||
balanceL k v l r hlb hrb hlr = balance k v l r hlb hrb (Or.inl hlr.erase) := by
|
||||
rw [balanceL_eq_balanceLErase, balanceLErase_eq_balanceL!,
|
||||
@@ -469,7 +610,7 @@ namespace Const
|
||||
variable {β : Type v}
|
||||
|
||||
theorem get?_eq_get?ₘ [Ord α] (k : α) (l : Impl α (fun _ => β)) :
|
||||
Const.get? k l = Const.get?ₘ k l := by
|
||||
Const.get? l k = Const.get?ₘ l k := by
|
||||
simp only [Const.get?ₘ]
|
||||
induction l
|
||||
· simp only [applyCell, Const.get?]
|
||||
@@ -477,6 +618,36 @@ theorem get?_eq_get?ₘ [Ord α] (k : α) (l : Impl α (fun _ => β)) :
|
||||
all_goals simp_all [Cell.Const.get?, Cell.ofEq]
|
||||
· simp [Const.get?, applyCell]
|
||||
|
||||
theorem get_eq_get? [Ord α] (k : α) (l : Impl α (fun _ => β)) {h} :
|
||||
get l k h = get? l k := by
|
||||
induction l
|
||||
· simp only [applyCell, get, get?]
|
||||
split <;> rename_i ihl ihr hcmp <;> simp_all
|
||||
· contradiction
|
||||
|
||||
theorem get_eq_getₘ [Ord α] (k : α) (l : Impl α (fun _ => β)) {h} (h') :
|
||||
get l k h = getₘ l k h' := by
|
||||
apply Option.some.inj
|
||||
simp [get_eq_get?, get?_eq_get?ₘ, getₘ]
|
||||
|
||||
theorem get!_eq_get!ₘ [Ord α] (k : α) [Inhabited β] (l : Impl α (fun _ => β)) :
|
||||
get! l k = get!ₘ l k := by
|
||||
simp only [get!ₘ, get?ₘ]
|
||||
induction l
|
||||
· simp only [applyCell, get!]
|
||||
split <;> rename_i hcmp₁ <;> split <;> rename_i hcmp₂ <;> try (simp [hcmp₁] at hcmp₂; done)
|
||||
all_goals simp_all [Cell.Const.get?, Cell.ofEq]
|
||||
· simp only [get!, applyCell, Option.get!_none]; rfl
|
||||
|
||||
theorem getD_eq_getDₘ [Ord α] (k : α) (l : Impl α (fun _ => β))
|
||||
(fallback : β) : getD l k fallback = getDₘ l k fallback := by
|
||||
simp only [getDₘ, get?ₘ]
|
||||
induction l
|
||||
· simp only [applyCell, getD]
|
||||
split <;> rename_i hcmp₁ <;> split <;> rename_i hcmp₂ <;> try (simp [hcmp₁] at hcmp₂; done)
|
||||
all_goals simp_all [Cell.Const.get?, Cell.ofEq]
|
||||
· simp only [getD, applyCell, Cell.Const.get?_empty, Option.getD_none]
|
||||
|
||||
end Const
|
||||
|
||||
end Impl
|
||||
|
||||
@@ -401,7 +401,7 @@ def containsThenInsertIfNew! [Ord α] (k : α) (v : β k) (t : Impl α β) :
|
||||
|
||||
/-- Implementation detail of the tree map -/
|
||||
@[inline]
|
||||
def getThenInsertIfNew? [Ord α] [LawfulEqOrd α] (k : α) (v : β k) (t : Impl α β) (ht : t.Balanced) :
|
||||
def getThenInsertIfNew? [Ord α] [LawfulEqOrd α] (t : Impl α β) (k : α) (v : β k) (ht : t.Balanced) :
|
||||
Option (β k) × Impl α β :=
|
||||
match t.get? k with
|
||||
| none => (none, t.insertIfNew k v ht |>.impl)
|
||||
@@ -412,7 +412,7 @@ Slower version of `getThenInsertIfNew?` which can be used in the absence of bala
|
||||
information but still assumes the preconditions of `getThenInsertIfNew?`, otherwise might panic.
|
||||
-/
|
||||
@[inline]
|
||||
def getThenInsertIfNew?! [Ord α] [LawfulEqOrd α] (k : α) (v : β k) (t : Impl α β) :
|
||||
def getThenInsertIfNew?! [Ord α] [LawfulEqOrd α] (t : Impl α β) (k : α) (v : β k) :
|
||||
Option (β k) × Impl α β :=
|
||||
match t.get? k with
|
||||
| none => (none, t.insertIfNew! k v)
|
||||
@@ -604,9 +604,9 @@ variable {β : Type v}
|
||||
|
||||
/-- Implementation detail of the tree map -/
|
||||
@[inline]
|
||||
def getThenInsertIfNew? [Ord α] (k : α) (v : β) (t : Impl α (fun _ => β))
|
||||
def getThenInsertIfNew? [Ord α] (t : Impl α (fun _ => β)) (k : α) (v : β)
|
||||
(ht : t.Balanced) : Option β × Impl α (fun _ => β) :=
|
||||
match get? k t with
|
||||
match get? t k with
|
||||
| none => (none, t.insertIfNew k v ht |>.impl)
|
||||
| some b => (some b, t)
|
||||
|
||||
@@ -615,9 +615,9 @@ Slower version of `getThenInsertIfNew?` which can be used in the absence of bala
|
||||
information but still assumes the preconditions of `getThenInsertIfNew?`, otherwise might panic.
|
||||
-/
|
||||
@[inline]
|
||||
def getThenInsertIfNew?! [Ord α] (k : α) (v : β) (t : Impl α (fun _ => β))
|
||||
def getThenInsertIfNew?! [Ord α] (t : Impl α (fun _ => β)) (k : α) (v : β)
|
||||
: Option β × Impl α (fun _ => β) :=
|
||||
match get? k t with
|
||||
match get? t k with
|
||||
| none => (none, t.insertIfNew! k v)
|
||||
| some b => (some b, t)
|
||||
|
||||
|
||||
@@ -62,122 +62,122 @@ def isEmpty (t : Impl α β) : Bool :=
|
||||
| .inner _ _ _ _ _ => false
|
||||
|
||||
/-- Returns the value for the key `k`, or `none` if such a key does not exist. -/
|
||||
def get? [Ord α] [LawfulEqOrd α] (k : α) (t : Impl α β) : Option (β k) :=
|
||||
def get? [Ord α] [LawfulEqOrd α] (t : Impl α β) (k : α) : Option (β k) :=
|
||||
match t with
|
||||
| .leaf => none
|
||||
| .inner _ k' v' l r =>
|
||||
match h : compare k k' with
|
||||
| .lt => get? k l
|
||||
| .gt => get? k r
|
||||
| .lt => get? l k
|
||||
| .gt => get? r k
|
||||
| .eq => some (cast (congrArg β (compare_eq_iff_eq.mp h).symm) v')
|
||||
|
||||
/-- Returns the value for the key `k`. -/
|
||||
def get [Ord α] [LawfulEqOrd α] (k : α) (t : Impl α β) (hlk : t.contains k = true) : β k :=
|
||||
def get [Ord α] [LawfulEqOrd α] (t : Impl α β) (k : α) (hlk : t.contains k = true) : β k :=
|
||||
match t with
|
||||
| .inner _ k' v' l r =>
|
||||
match h : compare k k' with
|
||||
| .lt => get k l (by simpa [contains, h] using hlk)
|
||||
| .gt => get k r (by simpa [contains, h] using hlk)
|
||||
| .lt => get l k (by simpa [contains, h] using hlk)
|
||||
| .gt => get r k (by simpa [contains, h] using hlk)
|
||||
| .eq => cast (congrArg β (compare_eq_iff_eq.mp h).symm) v'
|
||||
|
||||
/-- Returns the value for the key `k`, or panics if such a key does not exist. -/
|
||||
def get! [Ord α] [LawfulEqOrd α] (k : α) (t : Impl α β) [Inhabited (β k)] : β k :=
|
||||
def get! [Ord α] [LawfulEqOrd α] (t : Impl α β) (k : α) [Inhabited (β k)] : β k :=
|
||||
match t with
|
||||
| .leaf => panic! "Key is not present in map"
|
||||
| .inner _ k' v' l r =>
|
||||
match h : compare k k' with
|
||||
| .lt => get! k l
|
||||
| .gt => get! k r
|
||||
| .lt => get! l k
|
||||
| .gt => get! r k
|
||||
| .eq => cast (congrArg β (compare_eq_iff_eq.mp h).symm) v'
|
||||
|
||||
/-- Returns the value for the key `k`, or `fallback` if such a key does not exist. -/
|
||||
def getD [Ord α] [LawfulEqOrd α] (k : α) (t : Impl α β) (fallback : β k) : β k :=
|
||||
def getD [Ord α] [LawfulEqOrd α] (t : Impl α β) (k : α) (fallback : β k) : β k :=
|
||||
match t with
|
||||
| .leaf => fallback
|
||||
| .inner _ k' v' l r =>
|
||||
match h : compare k k' with
|
||||
| .lt => getD k l fallback
|
||||
| .gt => getD k r fallback
|
||||
| .lt => getD l k fallback
|
||||
| .gt => getD r k fallback
|
||||
| .eq => cast (congrArg β (compare_eq_iff_eq.mp h).symm) v'
|
||||
|
||||
/-- Implementation detail of the tree map -/
|
||||
def getKey? [Ord α] (k : α) (t : Impl α β) : Option α :=
|
||||
def getKey? [Ord α] (t : Impl α β) (k : α) : Option α :=
|
||||
match t with
|
||||
| .leaf => none
|
||||
| .inner _ k' _ l r =>
|
||||
match compare k k' with
|
||||
| .lt => getKey? k l
|
||||
| .gt => getKey? k r
|
||||
| .lt => getKey? l k
|
||||
| .gt => getKey? r k
|
||||
| .eq => some k'
|
||||
|
||||
/-- Implementation detail of the tree map -/
|
||||
def getKey [Ord α] (k : α) (t : Impl α β) (hlk : t.contains k = true) : α :=
|
||||
def getKey [Ord α] (t : Impl α β) (k : α) (hlk : t.contains k = true) : α :=
|
||||
match t with
|
||||
| .inner _ k' _ l r =>
|
||||
match h : compare k k' with
|
||||
| .lt => getKey k l (by simpa [contains, h] using hlk)
|
||||
| .gt => getKey k r (by simpa [contains, h] using hlk)
|
||||
| .lt => getKey l k (by simpa [contains, h] using hlk)
|
||||
| .gt => getKey r k (by simpa [contains, h] using hlk)
|
||||
| .eq => k'
|
||||
|
||||
/-- Implementation detail of the tree map -/
|
||||
def getKey! [Ord α] (k : α) (t : Impl α β) [Inhabited α] : α :=
|
||||
def getKey! [Ord α] (t : Impl α β) (k : α) [Inhabited α] : α :=
|
||||
match t with
|
||||
| .leaf => panic! "Key is not present in map"
|
||||
| .inner _ k' _ l r =>
|
||||
match compare k k' with
|
||||
| .lt => getKey! k l
|
||||
| .gt => getKey! k r
|
||||
| .lt => getKey! l k
|
||||
| .gt => getKey! r k
|
||||
| .eq => k'
|
||||
|
||||
/-- Implementation detail of the tree map -/
|
||||
def getKeyD [Ord α] (k : α) (t : Impl α β) (fallback : α) : α :=
|
||||
def getKeyD [Ord α] (t : Impl α β) (k : α) (fallback : α) : α :=
|
||||
match t with
|
||||
| .leaf => fallback
|
||||
| .inner _ k' _ l r =>
|
||||
match compare k k' with
|
||||
| .lt => getKeyD k l fallback
|
||||
| .gt => getKeyD k r fallback
|
||||
| .lt => getKeyD l k fallback
|
||||
| .gt => getKeyD r k fallback
|
||||
| .eq => k'
|
||||
|
||||
namespace Const
|
||||
|
||||
/-- Returns the value for the key `k`, or `none` if such a key does not exist. -/
|
||||
def get? [Ord α] (k : α) (t : Impl α δ) : Option δ :=
|
||||
def get? [Ord α] (t : Impl α δ) (k : α) : Option δ :=
|
||||
match t with
|
||||
| .leaf => none
|
||||
| .inner _ k' v' l r =>
|
||||
match compare k k' with
|
||||
| .lt => get? k l
|
||||
| .gt => get? k r
|
||||
| .lt => get? l k
|
||||
| .gt => get? r k
|
||||
| .eq => some v'
|
||||
|
||||
/-- Returns the value for the key `k`. -/
|
||||
def get [Ord α] (k : α) (t : Impl α δ) (hlk : t.contains k = true) : δ :=
|
||||
def get [Ord α] (t : Impl α δ) (k : α) (hlk : t.contains k = true) : δ :=
|
||||
match t with
|
||||
| .inner _ k' v' l r =>
|
||||
match h : compare k k' with
|
||||
| .lt => get k l (by simpa [contains, h] using hlk)
|
||||
| .gt => get k r (by simpa [contains, h] using hlk)
|
||||
| .lt => get l k (by simpa [contains, h] using hlk)
|
||||
| .gt => get r k (by simpa [contains, h] using hlk)
|
||||
| .eq => v'
|
||||
|
||||
/-- Returns the value for the key `k`, or panics if such a key does not exist. -/
|
||||
def get! [Ord α] (k : α) (t : Impl α δ) [Inhabited δ] : δ :=
|
||||
def get! [Ord α] (t : Impl α δ) (k : α) [Inhabited δ] : δ :=
|
||||
match t with
|
||||
| .leaf => panic! "Key is not present in map"
|
||||
| .inner _ k' v' l r =>
|
||||
match compare k k' with
|
||||
| .lt => get! k l
|
||||
| .gt => get! k r
|
||||
| .lt => get! l k
|
||||
| .gt => get! r k
|
||||
| .eq => v'
|
||||
|
||||
/-- Returns the value for the key `k`, or `fallback` if such a key does not exist. -/
|
||||
def getD [Ord α] (k : α) (t : Impl α δ) (fallback : δ) : δ :=
|
||||
def getD [Ord α] (t : Impl α δ) (k : α) (fallback : δ) : δ :=
|
||||
match t with
|
||||
| .leaf => fallback
|
||||
| .inner _ k' v' l r =>
|
||||
match compare k k' with
|
||||
| .lt => getD k l fallback
|
||||
| .gt => getD k r fallback
|
||||
| .lt => getD l k fallback
|
||||
| .gt => getD r k fallback
|
||||
| .eq => v'
|
||||
|
||||
end Const
|
||||
|
||||
@@ -97,7 +97,7 @@ section Const
|
||||
variable {β : Type v}
|
||||
|
||||
theorem WF.constGetThenInsertIfNew? [Ord α] {t : Impl α β} {k v} {h : t.WF} :
|
||||
(Impl.Const.getThenInsertIfNew? k v t h.balanced).2.WF := by
|
||||
(Impl.Const.getThenInsertIfNew? t k v h.balanced).2.WF := by
|
||||
simp only [Impl.Const.getThenInsertIfNew?]
|
||||
split
|
||||
· exact h.insertIfNew
|
||||
|
||||
@@ -546,7 +546,7 @@ theorem contains_eq_containsKey [Ord α] [TransOrd α] {k : α} {l : Impl α β}
|
||||
rw [contains_eq_containsₘ, containsₘ_eq_containsKey hlo]
|
||||
|
||||
/-!
|
||||
''' `get?`
|
||||
### `get?`
|
||||
-/
|
||||
|
||||
theorem get?ₘ_eq_getValueCast? [Ord α] [TransOrd α] [LawfulEqOrd α] {k : α} {t : Impl α β}
|
||||
@@ -564,16 +564,127 @@ theorem get?_eq_getValueCast? [Ord α] [TransOrd α] [LawfulEqOrd α] {k : α} {
|
||||
(hto : t.Ordered) : t.get? k = getValueCast? k t.toListModel := by
|
||||
rw [get?_eq_get?ₘ, get?ₘ_eq_getValueCast? hto]
|
||||
|
||||
/-!
|
||||
### `get`
|
||||
-/
|
||||
|
||||
theorem contains_eq_isSome_get?ₘ [Ord α] [TransOrd α] [LawfulEqOrd α] {k : α} {t : Impl α β}
|
||||
(hto : t.Ordered) : contains k t = (t.get?ₘ k).isSome := by
|
||||
rw [get?ₘ_eq_getValueCast? hto, contains_eq_containsKey hto, containsKey_eq_isSome_getValueCast?]
|
||||
|
||||
theorem getₘ_eq_getValueCast [Ord α] [TransOrd α] [LawfulEqOrd α] {k : α} {t : Impl α β} (h) {h'}
|
||||
(hto : t.Ordered) : t.getₘ k h' = getValueCast k t.toListModel h := by
|
||||
simp only [getₘ]
|
||||
revert h'
|
||||
rw [get?ₘ_eq_getValueCast? hto]
|
||||
simp [getValueCast?_eq_some_getValueCast ‹_›]
|
||||
|
||||
theorem get_eq_getValueCast [Ord α] [TransOrd α] [LawfulEqOrd α] {k : α} {t : Impl α β} {h}
|
||||
(hto : t.Ordered): t.get k h = getValueCast k t.toListModel (contains_eq_containsKey hto ▸ h) := by
|
||||
rw [get_eq_getₘ, getₘ_eq_getValueCast _ hto]
|
||||
exact contains_eq_isSome_get?ₘ hto ▸ h
|
||||
|
||||
/-!
|
||||
### `get!`
|
||||
-/
|
||||
|
||||
theorem get!ₘ_eq_getValueCast! [Ord α] [TransOrd α] [LawfulEqOrd α] {k : α} [Inhabited (β k)]
|
||||
{t : Impl α β} (hto : t.Ordered) : t.get!ₘ k = getValueCast! k t.toListModel := by
|
||||
simp [get!ₘ, get?ₘ_eq_getValueCast? hto, getValueCast!_eq_getValueCast?]
|
||||
|
||||
theorem get!_eq_getValueCast! [Ord α] [TransOrd α] [LawfulEqOrd α] {k : α} [Inhabited (β k)]
|
||||
{t : Impl α β} (hto : t.Ordered) : t.get! k = getValueCast! k t.toListModel := by
|
||||
rw [get!_eq_get!ₘ, get!ₘ_eq_getValueCast! hto]
|
||||
|
||||
/-!
|
||||
### `getD`
|
||||
-/
|
||||
|
||||
theorem getDₘ_eq_getValueCastD [Ord α] [TransOrd α] [LawfulEqOrd α] {k : α}
|
||||
{t : Impl α β} {fallback : β k} (hto : t.Ordered) :
|
||||
t.getDₘ k fallback = getValueCastD k t.toListModel fallback := by
|
||||
simp [getDₘ, get?ₘ_eq_getValueCast? hto, getValueCastD_eq_getValueCast?]
|
||||
|
||||
theorem getD_eq_getValueCastD [Ord α] [TransOrd α] [LawfulEqOrd α] {k : α}
|
||||
{t : Impl α β} {fallback : β k} (hto : t.Ordered) :
|
||||
t.getD k fallback = getValueCastD k t.toListModel fallback := by
|
||||
rw [getD_eq_getDₘ, getDₘ_eq_getValueCastD hto]
|
||||
|
||||
/-!
|
||||
### `getKey?`
|
||||
-/
|
||||
|
||||
theorem getKey?ₘ_eq_getKey? [Ord α] [TransOrd α] {k : α} {t : Impl α β}
|
||||
(hto : t.Ordered) : t.getKey?ₘ k = List.getKey? k t.toListModel := by
|
||||
rw [getKey?ₘ, applyCell_eq_apply_toListModel hto (fun l _ => List.getKey? k l)]
|
||||
· rintro ⟨(_|p), hp⟩ -
|
||||
· simp [Cell.getKey?]
|
||||
· simp only [Cell.getKey?, Option.toList_some, List.getKey?, beq_eq,
|
||||
compare_eq_iff_eq, Option.some_eq_dite_none_right, exists_prop, and_true]
|
||||
simp [OrientedCmp.eq_symm (hp p rfl)]
|
||||
· exact fun l₁ l₂ h => List.getKey?_of_perm
|
||||
· exact fun l₁ l₂ h => List.getKey?_append_of_containsKey_eq_false
|
||||
|
||||
theorem getKey?_eq_getKey? [Ord α] [TransOrd α] {k : α} {t : Impl α β}
|
||||
(hto : t.Ordered) : t.getKey? k = List.getKey? k t.toListModel := by
|
||||
rw [getKey?_eq_getKey?ₘ, getKey?ₘ_eq_getKey? hto]
|
||||
|
||||
/-!
|
||||
### `getKey`
|
||||
-/
|
||||
|
||||
theorem contains_eq_isSome_getKey?ₘ [Ord α] [TransOrd α] {k : α} {t : Impl α β}
|
||||
(hto : t.Ordered) : contains k t = (t.getKey?ₘ k).isSome := by
|
||||
rw [getKey?ₘ_eq_getKey? hto, contains_eq_containsKey hto, containsKey_eq_isSome_getKey?]
|
||||
|
||||
theorem getKeyₘ_eq_getKey [Ord α] [TransOrd α] {k : α} {t : Impl α β} (h) {h'}
|
||||
(hto : t.Ordered) : t.getKeyₘ k h' = List.getKey k t.toListModel h := by
|
||||
simp only [getKeyₘ]
|
||||
revert h'
|
||||
rw [getKey?ₘ_eq_getKey? hto]
|
||||
simp [getKey?_eq_some_getKey ‹_›]
|
||||
|
||||
theorem getKey_eq_getKey [Ord α] [TransOrd α] {k : α} {t : Impl α β} {h}
|
||||
(hto : t.Ordered): t.getKey k h = List.getKey k t.toListModel (contains_eq_containsKey hto ▸ h) := by
|
||||
rw [getKey_eq_getKeyₘ, getKeyₘ_eq_getKey _ hto]
|
||||
exact contains_eq_isSome_getKey?ₘ hto ▸ h
|
||||
|
||||
/-!
|
||||
### `getKey!`
|
||||
-/
|
||||
|
||||
theorem getKey!ₘ_eq_getKey! [Ord α] [TransOrd α] {k : α} [Inhabited α]
|
||||
{t : Impl α β} (hto : t.Ordered) : t.getKey!ₘ k = List.getKey! k t.toListModel := by
|
||||
simp [getKey!ₘ, getKey?ₘ_eq_getKey? hto, getKey!_eq_getKey?]
|
||||
|
||||
theorem getKey!_eq_getKey! [Ord α] [TransOrd α] {k : α} [Inhabited α]
|
||||
{t : Impl α β} (hto : t.Ordered) : t.getKey! k = List.getKey! k t.toListModel := by
|
||||
rw [getKey!_eq_getKey!ₘ, getKey!ₘ_eq_getKey! hto]
|
||||
|
||||
/-!
|
||||
### `getKeyD`
|
||||
-/
|
||||
|
||||
theorem getKeyDₘ_eq_getKeyD [Ord α] [TransOrd α] {k : α}
|
||||
{t : Impl α β} {fallback : α} (hto : t.Ordered) :
|
||||
t.getKeyDₘ k fallback = List.getKeyD k t.toListModel fallback := by
|
||||
simp [getKeyDₘ, getKey?ₘ_eq_getKey? hto, getKeyD_eq_getKey?]
|
||||
|
||||
theorem getKeyD_eq_getKeyD [Ord α] [TransOrd α] {k : α}
|
||||
{t : Impl α β} {fallback : α} (hto : t.Ordered) :
|
||||
t.getKeyD k fallback = List.getKeyD k t.toListModel fallback := by
|
||||
rw [getKeyD_eq_getKeyDₘ, getKeyDₘ_eq_getKeyD hto]
|
||||
|
||||
namespace Const
|
||||
|
||||
variable {β : Type v}
|
||||
|
||||
/-!
|
||||
''' `get?`
|
||||
### `get?`
|
||||
-/
|
||||
|
||||
theorem get?ₘ_eq_getValue? [Ord α] [TransOrd α] {k : α} {t : Impl α (fun _ => β)} (hto : t.Ordered) :
|
||||
get?ₘ k t = getValue? k t.toListModel := by
|
||||
get?ₘ t k = getValue? k t.toListModel := by
|
||||
rw [get?ₘ, applyCell_eq_apply_toListModel hto (fun l _ => getValue? k l)]
|
||||
· rintro ⟨(_|p), hp⟩ -
|
||||
· simp [Cell.Const.get?]
|
||||
@@ -584,9 +695,55 @@ theorem get?ₘ_eq_getValue? [Ord α] [TransOrd α] {k : α} {t : Impl α (fun _
|
||||
· exact fun l₁ l₂ h => getValue?_append_of_containsKey_eq_false
|
||||
|
||||
theorem get?_eq_getValue? [Ord α] [TransOrd α] {k : α} {t : Impl α (fun _ => β)} (hto : t.Ordered) :
|
||||
get? k t = getValue? k t.toListModel := by
|
||||
get? t k = getValue? k t.toListModel := by
|
||||
rw [get?_eq_get?ₘ, get?ₘ_eq_getValue? hto]
|
||||
|
||||
/-!
|
||||
### `get`
|
||||
-/
|
||||
|
||||
theorem contains_eq_isSome_get?ₘ [Ord α] [TransOrd α] {k : α} {t : Impl α β}
|
||||
(hto : t.Ordered) : contains k t = (get?ₘ t k).isSome := by
|
||||
rw [get?ₘ_eq_getValue? hto, contains_eq_containsKey hto, containsKey_eq_isSome_getValue?]
|
||||
|
||||
theorem getₘ_eq_getValue [Ord α] [TransOrd α] {k : α} {t : Impl α β} (h) {h'}
|
||||
(hto : t.Ordered) : getₘ t k h' = getValue k t.toListModel h := by
|
||||
simp only [getₘ]
|
||||
revert h'
|
||||
rw [get?ₘ_eq_getValue? hto]
|
||||
simp [getValue?_eq_some_getValue ‹_›]
|
||||
|
||||
theorem get_eq_getValue [Ord α] [TransOrd α] {k : α} {t : Impl α β} {h}
|
||||
(hto : t.Ordered): get t k h = getValue k t.toListModel (contains_eq_containsKey hto ▸ h) := by
|
||||
rw [get_eq_getₘ, getₘ_eq_getValue _ hto]
|
||||
exact contains_eq_isSome_get?ₘ hto ▸ h
|
||||
|
||||
/-!
|
||||
### `get!`
|
||||
-/
|
||||
|
||||
theorem get!ₘ_eq_getValue! [Ord α] [TransOrd α] {k : α} [Inhabited β]
|
||||
{t : Impl α β} (hto : t.Ordered) : get!ₘ t k = getValue! k t.toListModel := by
|
||||
simp [get!ₘ, get?ₘ_eq_getValue? hto, getValue!_eq_getValue?]
|
||||
|
||||
theorem get!_eq_getValue! [Ord α] [TransOrd α] {k : α} [Inhabited β]
|
||||
{t : Impl α β} (hto : t.Ordered) : get! t k = getValue! k t.toListModel := by
|
||||
rw [get!_eq_get!ₘ, get!ₘ_eq_getValue! hto]
|
||||
|
||||
/-!
|
||||
### `getD`
|
||||
-/
|
||||
|
||||
theorem getDₘ_eq_getValueD [Ord α] [TransOrd α] {k : α}
|
||||
{t : Impl α β} {fallback : β} (hto : t.Ordered) :
|
||||
getDₘ t k fallback = getValueD k t.toListModel fallback := by
|
||||
simp [getDₘ, get?ₘ_eq_getValue? hto, getValueD_eq_getValue?]
|
||||
|
||||
theorem getD_eq_getValueD [Ord α] [TransOrd α] {k : α}
|
||||
{t : Impl α β} {fallback : β} (hto : t.Ordered) :
|
||||
getD t k fallback = getValueD k t.toListModel fallback := by
|
||||
rw [getD_eq_getDₘ, getDₘ_eq_getValueD hto]
|
||||
|
||||
end Const
|
||||
|
||||
/-!
|
||||
|
||||
@@ -48,11 +48,6 @@ theorem contains_congr [TransCmp cmp] {k k' : α} (hab : cmp k k' = .eq) :
|
||||
theorem mem_congr [TransCmp cmp] {k k' : α} (hab : cmp k k' = .eq) : k ∈ t ↔ k' ∈ t :=
|
||||
Impl.mem_congr t.wf hab
|
||||
|
||||
@[simp]
|
||||
theorem isEmpty_insertIfNew [TransCmp cmp] {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).isEmpty = false :=
|
||||
Impl.isEmpty_insertIfNew t.wf
|
||||
|
||||
@[simp]
|
||||
theorem contains_emptyc {k : α} : (∅ : DTreeMap α β cmp).contains k = false :=
|
||||
Impl.contains_empty
|
||||
@@ -142,7 +137,7 @@ theorem size_insert_le [TransCmp cmp] {k : α} {v : β k} :
|
||||
|
||||
@[simp]
|
||||
theorem erase_emptyc {k : α} :
|
||||
(∅ : DTreeMap α β cmp).erase k = empty :=
|
||||
(∅ : DTreeMap α β cmp).erase k = ∅ :=
|
||||
ext <| Impl.erase_empty (instOrd := ⟨cmp⟩) (k := k)
|
||||
|
||||
@[simp]
|
||||
@@ -200,44 +195,6 @@ theorem containsThenInsertIfNew_snd [TransCmp cmp] {k : α} {v : β k} :
|
||||
(t.containsThenInsertIfNew k v).2 = t.insertIfNew k v :=
|
||||
ext <| Impl.containsThenInsertIfNew_snd t.wf
|
||||
|
||||
@[simp]
|
||||
theorem contains_insertIfNew [TransCmp cmp] {k a : α} {v : β k} :
|
||||
(t.insertIfNew k v).contains a = (cmp k a == .eq || t.contains a) :=
|
||||
Impl.contains_insertIfNew t.wf
|
||||
|
||||
@[simp]
|
||||
theorem mem_insertIfNew [TransCmp cmp] {k a : α} {v : β k} :
|
||||
a ∈ t.insertIfNew k v ↔ cmp k a = .eq ∨ a ∈ t :=
|
||||
Impl.mem_insertIfNew t.wf
|
||||
|
||||
theorem contains_insertIfNew_self [TransCmp cmp] {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).contains k :=
|
||||
Impl.contains_insertIfNew_self t.wf
|
||||
|
||||
theorem mem_insertIfNew_self [TransCmp cmp] {k : α} {v : β k} :
|
||||
k ∈ t.insertIfNew k v :=
|
||||
Impl.mem_insertIfNew_self t.wf
|
||||
|
||||
theorem contains_of_contains_insertIfNew [TransCmp cmp] {k a : α} {v : β k} :
|
||||
(t.insertIfNew k v).contains a → cmp k a ≠ .eq → t.contains a :=
|
||||
Impl.contains_of_contains_insertIfNew t.wf
|
||||
|
||||
theorem mem_of_mem_insertIfNew [TransCmp cmp] {k a : α} {v : β k} :
|
||||
a ∈ t.insertIfNew k v → cmp k a ≠ .eq → a ∈ t :=
|
||||
Impl.contains_of_contains_insertIfNew t.wf
|
||||
|
||||
theorem size_insertIfNew [TransCmp cmp] {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).size = if k ∈ t then t.size else t.size + 1 :=
|
||||
Impl.size_insertIfNew t.wf
|
||||
|
||||
theorem size_le_size_insertIfNew [TransCmp cmp] {k : α} {v : β k} :
|
||||
t.size ≤ (t.insertIfNew k v).size :=
|
||||
Impl.size_le_size_insertIfNew t.wf
|
||||
|
||||
theorem size_insertIfNew_le [TransCmp cmp] {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).size ≤ t.size + 1 :=
|
||||
Impl.size_insertIfNew_le t.wf
|
||||
|
||||
@[simp]
|
||||
theorem get?_emptyc [TransCmp cmp] [LawfulEqCmp cmp] {a : α} :
|
||||
(∅ : DTreeMap α β cmp).get? a = none :=
|
||||
@@ -339,4 +296,630 @@ theorem get?_congr [TransCmp cmp] {a b : α} (hab : cmp a b = .eq) :
|
||||
|
||||
end Const
|
||||
|
||||
theorem get_insert [TransCmp cmp] [LawfulEqCmp cmp] {k a : α} {v : β k} {h₁} :
|
||||
(t.insert k v).get a h₁ =
|
||||
if h₂ : cmp k a = .eq then
|
||||
cast (congrArg β (compare_eq_iff_eq.mp h₂)) v
|
||||
else
|
||||
t.get a (mem_of_mem_insert h₁ h₂) :=
|
||||
Impl.get_insert t.wf
|
||||
|
||||
@[simp]
|
||||
theorem get_insert_self [TransCmp cmp] [LawfulEqCmp cmp] {k : α} {v : β k} :
|
||||
(t.insert k v).get k mem_insert_self = v :=
|
||||
Impl.get_insert_self t.wf
|
||||
|
||||
@[simp]
|
||||
theorem get_erase [TransCmp cmp] [LawfulEqCmp cmp] {k a : α} {h'} :
|
||||
(t.erase k).get a h' = t.get a (mem_of_mem_erase h') :=
|
||||
Impl.get_erase t.wf
|
||||
|
||||
theorem get?_eq_some_get [TransCmp cmp] [LawfulEqCmp cmp] {a : α} {h'} :
|
||||
t.get? a = some (t.get a h') :=
|
||||
Impl.get?_eq_some_get t.wf
|
||||
|
||||
namespace Const
|
||||
|
||||
variable {β : Type v} {t : DTreeMap α β cmp}
|
||||
|
||||
theorem get_insert [TransCmp cmp] {k a : α} {v : β} {h₁} :
|
||||
get (t.insert k v) a h₁ =
|
||||
if h₂ : cmp k a = .eq then v
|
||||
else get t a (mem_of_mem_insert h₁ h₂) :=
|
||||
Impl.Const.get_insert t.wf
|
||||
|
||||
@[simp]
|
||||
theorem get_insert_self [TransCmp cmp] {k : α} {v : β} :
|
||||
get (t.insert k v) k mem_insert_self = v :=
|
||||
Impl.Const.get_insert_self t.wf
|
||||
|
||||
@[simp]
|
||||
theorem get_erase [TransCmp cmp] {k a : α} {h'} :
|
||||
get (t.erase k) a h' = get t a (mem_of_mem_erase h') :=
|
||||
Impl.Const.get_erase t.wf
|
||||
|
||||
theorem get?_eq_some_get [TransCmp cmp] {a : α} {h} :
|
||||
get? t a = some (get t a h) :=
|
||||
Impl.Const.get?_eq_some_get t.wf
|
||||
|
||||
theorem get_eq_get [TransCmp cmp] [LawfulEqCmp cmp] {a : α} {h} : get t a h = t.get a h :=
|
||||
Impl.Const.get_eq_get t.wf
|
||||
|
||||
theorem get_congr [TransCmp cmp] {a b : α} (hab : cmp a b = .eq) {h'} :
|
||||
get t a h' = get t b ((mem_congr hab).mp h') :=
|
||||
Impl.Const.get_congr t.wf hab
|
||||
|
||||
end Const
|
||||
|
||||
@[simp]
|
||||
theorem get!_emptyc [TransCmp cmp] [LawfulEqCmp cmp] {a : α} [Inhabited (β a)] :
|
||||
get! (∅ : DTreeMap α β cmp) a = default :=
|
||||
Impl.get!_empty
|
||||
|
||||
theorem get!_of_isEmpty [TransCmp cmp] [LawfulEqCmp cmp] {a : α} [Inhabited (β a)] :
|
||||
t.isEmpty = true → t.get! a = default :=
|
||||
Impl.get!_of_isEmpty t.wf
|
||||
|
||||
theorem get!_insert [TransCmp cmp] [LawfulEqCmp cmp] {k a : α} [Inhabited (β a)] {v : β k} :
|
||||
(t.insert k v).get! a =
|
||||
if h : cmp k a = .eq then cast (congrArg β (compare_eq_iff_eq.mp h)) v else t.get! a :=
|
||||
Impl.get!_insert t.wf
|
||||
|
||||
@[simp]
|
||||
theorem get!_insert_self [TransCmp cmp] [LawfulEqCmp cmp] {a : α} [Inhabited (β a)] {b : β a} :
|
||||
(t.insert a b).get! a = b :=
|
||||
Impl.get!_insert_self t.wf
|
||||
|
||||
theorem get!_eq_default_of_contains_eq_false [TransCmp cmp] [LawfulEqCmp cmp] {a : α}
|
||||
[Inhabited (β a)] : t.contains a = false → t.get! a = default :=
|
||||
Impl.get!_eq_default_of_contains_eq_false t.wf
|
||||
|
||||
theorem get!_eq_default [TransCmp cmp] [LawfulEqCmp cmp] {a : α} [Inhabited (β a)] :
|
||||
¬ a ∈ t → t.get! a = default :=
|
||||
Impl.get!_eq_default t.wf
|
||||
|
||||
theorem get!_erase [TransCmp cmp] [LawfulEqCmp cmp] {k a : α} [Inhabited (β a)] :
|
||||
(t.erase k).get! a = if cmp k a = .eq then default else t.get! a :=
|
||||
Impl.get!_erase t.wf
|
||||
|
||||
@[simp]
|
||||
theorem get!_erase_self [TransCmp cmp] [LawfulEqCmp cmp] {k : α} [Inhabited (β k)] :
|
||||
(t.erase k).get! k = default :=
|
||||
Impl.get!_erase_self t.wf
|
||||
|
||||
theorem get?_eq_some_get!_of_contains [TransCmp cmp] [LawfulEqCmp cmp] {a : α} [Inhabited (β a)] :
|
||||
t.contains a = true → t.get? a = some (t.get! a) :=
|
||||
Impl.get?_eq_some_get!_of_contains t.wf
|
||||
|
||||
theorem get?_eq_some_get! [TransCmp cmp] [LawfulEqCmp cmp] {a : α} [Inhabited (β a)] :
|
||||
a ∈ t → t.get? a = some (t.get! a) :=
|
||||
Impl.get?_eq_some_get! t.wf
|
||||
|
||||
theorem get!_eq_get!_get? [TransCmp cmp] [LawfulEqCmp cmp] {a : α} [Inhabited (β a)] :
|
||||
t.get! a = (t.get? a).get! :=
|
||||
Impl.get!_eq_get!_get? t.wf
|
||||
|
||||
theorem get_eq_get! [TransCmp cmp] [LawfulEqCmp cmp] {a : α} [Inhabited (β a)] {h} :
|
||||
t.get a h = t.get! a :=
|
||||
Impl.get_eq_get! t.wf
|
||||
|
||||
namespace Const
|
||||
|
||||
variable {β : Type v} {t : DTreeMap α β cmp}
|
||||
|
||||
@[simp]
|
||||
theorem get!_emptyc [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
get! (∅ : DTreeMap α β cmp) a = default :=
|
||||
Impl.Const.get!_empty
|
||||
|
||||
theorem get!_of_isEmpty [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
t.isEmpty = true → get! t a = default :=
|
||||
Impl.Const.get!_of_isEmpty t.wf
|
||||
|
||||
theorem get!_insert [TransCmp cmp] [Inhabited β] {k a : α} {v : β} :
|
||||
get! (t.insert k v) a = if cmp k a = .eq then v else get! t a :=
|
||||
Impl.Const.get!_insert t.wf
|
||||
|
||||
@[simp]
|
||||
theorem get!_insert_self [TransCmp cmp] [Inhabited β] {k : α} {v : β} : get! (t.insert k v) k = v :=
|
||||
Impl.Const.get!_insert_self t.wf
|
||||
|
||||
theorem get!_eq_default_of_contains_eq_false [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
t.contains a = false → get! t a = default :=
|
||||
Impl.Const.get!_eq_default_of_contains_eq_false t.wf
|
||||
|
||||
theorem get!_eq_default [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
¬ a ∈ t → get! t a = default :=
|
||||
Impl.Const.get!_eq_default t.wf
|
||||
|
||||
theorem get!_erase [TransCmp cmp] [Inhabited β] {k a : α} :
|
||||
get! (t.erase k) a = if cmp k a = .eq then default else get! t a :=
|
||||
Impl.Const.get!_erase t.wf
|
||||
|
||||
@[simp]
|
||||
theorem get!_erase_self [TransCmp cmp] [Inhabited β] {k : α} :
|
||||
get! (t.erase k) k = default :=
|
||||
Impl.Const.get!_erase_self t.wf
|
||||
|
||||
theorem get?_eq_some_get!_of_contains [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
t.contains a = true → get? t a = some (get! t a) :=
|
||||
Impl.Const.get?_eq_some_get! t.wf
|
||||
|
||||
theorem get?_eq_some_get! [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
a ∈ t → get? t a = some (get! t a) :=
|
||||
Impl.Const.get?_eq_some_get! t.wf
|
||||
|
||||
theorem get!_eq_get!_get? [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
get! t a = (get? t a).get! :=
|
||||
Impl.Const.get!_eq_get!_get? t.wf
|
||||
|
||||
theorem get_eq_get! [TransCmp cmp] [Inhabited β] {a : α} {h} :
|
||||
get t a h = get! t a :=
|
||||
Impl.Const.get_eq_get! t.wf
|
||||
|
||||
theorem get!_eq_get! [TransCmp cmp] [LawfulEqCmp cmp] [Inhabited β] {a : α} :
|
||||
get! t a = t.get! a :=
|
||||
Impl.Const.get!_eq_get! t.wf
|
||||
|
||||
theorem get!_congr [TransCmp cmp] [Inhabited β] {a b : α} (hab : cmp a b = .eq) :
|
||||
get! t a = get! t b :=
|
||||
Impl.Const.get!_congr t.wf hab
|
||||
|
||||
end Const
|
||||
|
||||
@[simp]
|
||||
theorem getD_emptyc [TransCmp cmp] [LawfulEqCmp cmp] {a : α} {fallback : β a} :
|
||||
(∅ : DTreeMap α β cmp).getD a fallback = fallback :=
|
||||
Impl.getD_empty
|
||||
|
||||
theorem getD_of_isEmpty [TransCmp cmp] [LawfulEqCmp cmp] {a : α} {fallback : β a} :
|
||||
t.isEmpty = true → t.getD a fallback = fallback :=
|
||||
Impl.getD_of_isEmpty t.wf
|
||||
|
||||
theorem getD_insert [TransCmp cmp] [LawfulEqCmp cmp] {k a : α} {fallback : β a} {v : β k} :
|
||||
(t.insert k v).getD a fallback =
|
||||
if h : cmp k a = .eq then
|
||||
cast (congrArg β (compare_eq_iff_eq.mp h)) v
|
||||
else t.getD a fallback :=
|
||||
Impl.getD_insert t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getD_insert_self [TransCmp cmp] [LawfulEqCmp cmp] {a : α} {fallback b : β a} :
|
||||
(t.insert a b).getD a fallback = b :=
|
||||
Impl.getD_insert_self t.wf
|
||||
|
||||
theorem getD_eq_fallback_of_contains_eq_false [TransCmp cmp] [LawfulEqCmp cmp] {a : α}
|
||||
{fallback : β a} : t.contains a = false → t.getD a fallback = fallback :=
|
||||
Impl.getD_eq_fallback_of_contains_eq_false t.wf
|
||||
|
||||
theorem getD_eq_fallback [TransCmp cmp] [LawfulEqCmp cmp] {a : α} {fallback : β a} :
|
||||
¬ a ∈ t → t.getD a fallback = fallback :=
|
||||
Impl.getD_eq_fallback t.wf
|
||||
|
||||
theorem getD_erase [TransCmp cmp] [LawfulEqCmp cmp] {k a : α} {fallback : β a} :
|
||||
(t.erase k).getD a fallback = if cmp k a = .eq then fallback else t.getD a fallback :=
|
||||
Impl.getD_erase t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getD_erase_self [TransCmp cmp] [LawfulEqCmp cmp] {k : α} {fallback : β k} :
|
||||
(t.erase k).getD k fallback = fallback :=
|
||||
Impl.getD_erase_self t.wf
|
||||
|
||||
theorem get?_eq_some_getD_of_contains [TransCmp cmp] [LawfulEqCmp cmp] {a : α} {fallback : β a} :
|
||||
t.contains a = true → t.get? a = some (t.getD a fallback) :=
|
||||
Impl.get?_eq_some_getD_of_contains t.wf
|
||||
|
||||
theorem get?_eq_some_getD [TransCmp cmp] [LawfulEqCmp cmp] {a : α} {fallback : β a} :
|
||||
a ∈ t → t.get? a = some (t.getD a fallback) :=
|
||||
Impl.get?_eq_some_getD t.wf
|
||||
|
||||
theorem getD_eq_getD_get? [TransCmp cmp] [LawfulEqCmp cmp] {a : α} {fallback : β a} :
|
||||
t.getD a fallback = (t.get? a).getD fallback :=
|
||||
Impl.getD_eq_getD_get? t.wf
|
||||
|
||||
theorem get_eq_getD [TransCmp cmp] [LawfulEqCmp cmp] {a : α} {fallback : β a} {h} :
|
||||
t.get a h = t.getD a fallback :=
|
||||
Impl.get_eq_getD t.wf
|
||||
|
||||
theorem get!_eq_getD_default [TransCmp cmp] [LawfulEqCmp cmp] {a : α} [Inhabited (β a)] :
|
||||
t.get! a = t.getD a default :=
|
||||
Impl.get!_eq_getD_default t.wf
|
||||
|
||||
namespace Const
|
||||
|
||||
variable {β : Type v} {t : DTreeMap α β cmp}
|
||||
|
||||
@[simp]
|
||||
theorem getD_emptyc [TransCmp cmp] {a : α} {fallback : β} :
|
||||
getD (∅ : DTreeMap α β cmp) a fallback = fallback :=
|
||||
Impl.Const.getD_empty
|
||||
|
||||
theorem getD_of_isEmpty [TransCmp cmp] {a : α} {fallback : β} :
|
||||
t.isEmpty = true → getD t a fallback = fallback :=
|
||||
Impl.Const.getD_of_isEmpty t.wf
|
||||
|
||||
theorem getD_insert [TransCmp cmp] {k a : α} {fallback v : β} :
|
||||
getD (t.insert k v) a fallback = if cmp k a = .eq then v else getD t a fallback :=
|
||||
Impl.Const.getD_insert t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getD_insert_self [TransCmp cmp] {k : α} {fallback v : β} :
|
||||
getD (t.insert k v) k fallback = v :=
|
||||
Impl.Const.getD_insert_self t.wf
|
||||
|
||||
theorem getD_eq_fallback_of_contains_eq_false [TransCmp cmp] {a : α} {fallback : β} :
|
||||
t.contains a = false → getD t a fallback = fallback :=
|
||||
Impl.Const.getD_eq_fallback_of_contains_eq_false t.wf
|
||||
|
||||
theorem getD_eq_fallback [TransCmp cmp] {a : α} {fallback : β} :
|
||||
¬ a ∈ t → getD t a fallback = fallback :=
|
||||
Impl.Const.getD_eq_fallback t.wf
|
||||
|
||||
theorem getD_erase [TransCmp cmp] {k a : α} {fallback : β} :
|
||||
getD (t.erase k) a fallback = if cmp k a = .eq then
|
||||
fallback
|
||||
else
|
||||
getD t a fallback :=
|
||||
Impl.Const.getD_erase t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getD_erase_self [TransCmp cmp] {k : α} {fallback : β} :
|
||||
getD (t.erase k) k fallback = fallback :=
|
||||
Impl.Const.getD_erase_self t.wf
|
||||
|
||||
theorem get?_eq_some_getD_of_contains [TransCmp cmp] {a : α} {fallback : β} :
|
||||
t.contains a = true → get? t a = some (getD t a fallback) :=
|
||||
Impl.Const.get?_eq_some_getD_of_contains t.wf
|
||||
|
||||
theorem get?_eq_some_getD [TransCmp cmp] {a : α} {fallback : β} :
|
||||
a ∈ t → get? t a = some (getD t a fallback) :=
|
||||
Impl.Const.get?_eq_some_getD t.wf
|
||||
|
||||
theorem getD_eq_getD_get? [TransCmp cmp] {a : α} {fallback : β} :
|
||||
getD t a fallback = (get? t a).getD fallback :=
|
||||
Impl.Const.getD_eq_getD_get? t.wf
|
||||
|
||||
theorem get_eq_getD [TransCmp cmp] {a : α} {fallback : β} {h} :
|
||||
get t a h = getD t a fallback :=
|
||||
Impl.Const.get_eq_getD t.wf
|
||||
|
||||
theorem get!_eq_getD_default [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
get! t a = getD t a default :=
|
||||
Impl.Const.get!_eq_getD_default t.wf
|
||||
|
||||
theorem getD_eq_getD [TransCmp cmp] [LawfulEqCmp cmp] {a : α} {fallback : β} :
|
||||
getD t a fallback = t.getD a fallback :=
|
||||
Impl.Const.getD_eq_getD t.wf
|
||||
|
||||
theorem getD_congr [TransCmp cmp] {a b : α} {fallback : β} (hab : cmp a b = .eq) :
|
||||
getD t a fallback = getD t b fallback :=
|
||||
Impl.Const.getD_congr t.wf hab
|
||||
|
||||
end Const
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_emptyc {a : α} : (∅ : DTreeMap α β cmp).getKey? a = none :=
|
||||
Impl.getKey?_empty
|
||||
|
||||
theorem getKey?_of_isEmpty [TransCmp cmp] {a : α} :
|
||||
t.isEmpty = true → t.getKey? a = none :=
|
||||
Impl.getKey?_of_isEmpty t.wf
|
||||
|
||||
theorem getKey?_insert [TransCmp cmp] {a k : α} {v : β k} :
|
||||
(t.insert k v).getKey? a = if cmp k a = .eq then some k else t.getKey? a :=
|
||||
Impl.getKey?_insert t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_insert_self [TransCmp cmp] {k : α} {v : β k} :
|
||||
(t.insert k v).getKey? k = some k :=
|
||||
Impl.getKey?_insert_self t.wf
|
||||
|
||||
theorem contains_eq_isSome_getKey? [TransCmp cmp] {a : α} :
|
||||
t.contains a = (t.getKey? a).isSome :=
|
||||
Impl.contains_eq_isSome_getKey? t.wf
|
||||
|
||||
theorem mem_iff_isSome_getKey? [TransCmp cmp] {a : α} :
|
||||
a ∈ t ↔ (t.getKey? a).isSome :=
|
||||
Impl.mem_iff_isSome_getKey? t.wf
|
||||
|
||||
theorem getKey?_eq_none_of_contains_eq_false [TransCmp cmp] {a : α} :
|
||||
t.contains a = false → t.getKey? a = none :=
|
||||
Impl.getKey?_eq_none_of_contains_eq_false t.wf
|
||||
|
||||
theorem getKey?_eq_none [TransCmp cmp] {a : α} :
|
||||
¬ a ∈ t → t.getKey? a = none :=
|
||||
Impl.getKey?_eq_none t.wf
|
||||
|
||||
theorem getKey?_erase [TransCmp cmp] {k a : α} :
|
||||
(t.erase k).getKey? a = if cmp k a = .eq then none else t.getKey? a :=
|
||||
Impl.getKey?_erase t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_erase_self [TransCmp cmp] {k : α} :
|
||||
(t.erase k).getKey? k = none :=
|
||||
Impl.getKey?_erase_self t.wf
|
||||
|
||||
theorem getKey_insert [TransCmp cmp] {k a : α} {v : β k} {h₁} :
|
||||
(t.insert k v).getKey a h₁ =
|
||||
if h₂ : cmp k a = .eq then
|
||||
k
|
||||
else
|
||||
t.getKey a (mem_of_mem_insert h₁ h₂) :=
|
||||
Impl.getKey_insert t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getKey_insert_self [TransCmp cmp] {k : α} {v : β k} :
|
||||
(t.insert k v).getKey k mem_insert_self = k :=
|
||||
Impl.getKey_insert_self t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getKey_erase [TransCmp cmp] {k a : α} {h'} :
|
||||
(t.erase k).getKey a h' = t.getKey a (mem_of_mem_erase h') :=
|
||||
Impl.getKey_erase t.wf
|
||||
|
||||
theorem getKey?_eq_some_getKey [TransCmp cmp] {a : α} {h'} :
|
||||
t.getKey? a = some (t.getKey a h') :=
|
||||
Impl.getKey?_eq_some_getKey t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_emptyc {a : α} [Inhabited α] :
|
||||
(∅ : DTreeMap α β cmp).getKey! a = default :=
|
||||
Impl.getKey!_empty
|
||||
|
||||
theorem getKey!_of_isEmpty [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.isEmpty = true → t.getKey! a = default :=
|
||||
Impl.getKey!_of_isEmpty t.wf
|
||||
|
||||
theorem getKey!_insert [TransCmp cmp] [Inhabited α] {k a : α}
|
||||
{v : β k} : (t.insert k v).getKey! a = if cmp k a = .eq then k else t.getKey! a :=
|
||||
Impl.getKey!_insert t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_insert_self [TransCmp cmp] [Inhabited α] {a : α}
|
||||
{b : β a} : (t.insert a b).getKey! a = a :=
|
||||
Impl.getKey!_insert_self t.wf
|
||||
|
||||
theorem getKey!_eq_default_of_contains_eq_false [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.contains a = false → t.getKey! a = default :=
|
||||
Impl.getKey!_eq_default_of_contains_eq_false t.wf
|
||||
|
||||
theorem getKey!_eq_default [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
¬ a ∈ t → t.getKey! a = default :=
|
||||
Impl.getKey!_eq_default t.wf
|
||||
|
||||
theorem getKey!_erase [TransCmp cmp] [Inhabited α] {k a : α} :
|
||||
(t.erase k).getKey! a = if cmp k a = .eq then default else t.getKey! a :=
|
||||
Impl.getKey!_erase t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_erase_self [TransCmp cmp] [Inhabited α] {k : α} :
|
||||
(t.erase k).getKey! k = default :=
|
||||
Impl.getKey!_erase_self t.wf
|
||||
|
||||
theorem getKey?_eq_some_getKey!_of_contains [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.contains a = true → t.getKey? a = some (t.getKey! a) :=
|
||||
Impl.getKey?_eq_some_getKey!_of_contains t.wf
|
||||
|
||||
theorem getKey?_eq_some_getKey! [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
a ∈ t → t.getKey? a = some (t.getKey! a) :=
|
||||
Impl.getKey?_eq_some_getKey! t.wf
|
||||
|
||||
theorem getKey!_eq_get!_getKey? [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.getKey! a = (t.getKey? a).get! :=
|
||||
Impl.getKey!_eq_get!_getKey? t.wf
|
||||
|
||||
theorem getKey_eq_getKey! [TransCmp cmp] [Inhabited α] {a : α} {h} :
|
||||
t.getKey a h = t.getKey! a :=
|
||||
Impl.getKey_eq_getKey! t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_emptyc {a : α} {fallback : α} :
|
||||
(∅ : DTreeMap α β cmp).getKeyD a fallback = fallback :=
|
||||
Impl.getKeyD_empty
|
||||
|
||||
theorem getKeyD_of_isEmpty [TransCmp cmp] {a fallback : α} :
|
||||
t.isEmpty = true → t.getKeyD a fallback = fallback :=
|
||||
Impl.getKeyD_of_isEmpty t.wf
|
||||
|
||||
theorem getKeyD_insert [TransCmp cmp] {k a fallback : α} {v : β k} :
|
||||
(t.insert k v).getKeyD a fallback =
|
||||
if cmp k a = .eq then k else t.getKeyD a fallback :=
|
||||
Impl.getKeyD_insert t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_insert_self [TransCmp cmp] {a fallback : α} {b : β a} :
|
||||
(t.insert a b).getKeyD a fallback = a :=
|
||||
Impl.getKeyD_insert_self t.wf
|
||||
|
||||
theorem getKeyD_eq_fallback_of_contains_eq_false [TransCmp cmp] {a fallback : α} :
|
||||
t.contains a = false → t.getKeyD a fallback = fallback :=
|
||||
Impl.getKeyD_eq_fallback_of_contains_eq_false t.wf
|
||||
|
||||
theorem getKeyD_eq_fallback [TransCmp cmp] {a fallback : α} :
|
||||
¬ a ∈ t → t.getKeyD a fallback = fallback :=
|
||||
Impl.getKeyD_eq_fallback t.wf
|
||||
|
||||
theorem getKeyD_erase [TransCmp cmp] {k a fallback : α} :
|
||||
(t.erase k).getKeyD a fallback =
|
||||
if cmp k a = .eq then fallback else t.getKeyD a fallback :=
|
||||
Impl.getKeyD_erase t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_erase_self [TransCmp cmp] {k fallback : α} :
|
||||
(t.erase k).getKeyD k fallback = fallback :=
|
||||
Impl.getKeyD_erase_self t.wf
|
||||
|
||||
theorem getKey?_eq_some_getKeyD_of_contains [TransCmp cmp] {a fallback : α} :
|
||||
t.contains a = true → t.getKey? a = some (t.getKeyD a fallback) :=
|
||||
Impl.getKey?_eq_some_getKeyD_of_contains t.wf
|
||||
|
||||
theorem getKey?_eq_some_getKeyD [TransCmp cmp] {a fallback : α} :
|
||||
a ∈ t → t.getKey? a = some (t.getKeyD a fallback) :=
|
||||
Impl.getKey?_eq_some_getKeyD t.wf
|
||||
|
||||
theorem getKeyD_eq_getD_getKey? [TransCmp cmp] {a fallback : α} :
|
||||
t.getKeyD a fallback = (t.getKey? a).getD fallback :=
|
||||
Impl.getKeyD_eq_getD_getKey? t.wf
|
||||
|
||||
theorem getKey_eq_getKeyD [TransCmp cmp] {a fallback : α} {h} :
|
||||
t.getKey a h = t.getKeyD a fallback :=
|
||||
Impl.getKey_eq_getKeyD t.wf
|
||||
|
||||
theorem getKey!_eq_getKeyD_default [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.getKey! a = t.getKeyD a default :=
|
||||
Impl.getKey!_eq_getKeyD_default t.wf
|
||||
|
||||
@[simp]
|
||||
theorem isEmpty_insertIfNew [TransCmp cmp] {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).isEmpty = false :=
|
||||
Impl.isEmpty_insertIfNew t.wf
|
||||
|
||||
@[simp]
|
||||
theorem contains_insertIfNew [TransCmp cmp] {k a : α} {v : β k} :
|
||||
(t.insertIfNew k v).contains a = (cmp k a == .eq || t.contains a) :=
|
||||
Impl.contains_insertIfNew t.wf
|
||||
|
||||
@[simp]
|
||||
theorem mem_insertIfNew [TransCmp cmp] {k a : α} {v : β k} :
|
||||
a ∈ t.insertIfNew k v ↔ cmp k a = .eq ∨ a ∈ t :=
|
||||
Impl.mem_insertIfNew t.wf
|
||||
|
||||
theorem contains_insertIfNew_self [TransCmp cmp] {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).contains k :=
|
||||
Impl.contains_insertIfNew_self t.wf
|
||||
|
||||
theorem mem_insertIfNew_self [TransCmp cmp] {k : α} {v : β k} :
|
||||
k ∈ t.insertIfNew k v :=
|
||||
Impl.mem_insertIfNew_self t.wf
|
||||
|
||||
theorem contains_of_contains_insertIfNew [TransCmp cmp] {k a : α} {v : β k} :
|
||||
(t.insertIfNew k v).contains a → cmp k a ≠ .eq → t.contains a :=
|
||||
Impl.contains_of_contains_insertIfNew t.wf
|
||||
|
||||
theorem mem_of_mem_insertIfNew [TransCmp cmp] {k a : α} {v : β k} :
|
||||
a ∈ t.insertIfNew k v → cmp k a ≠ .eq → a ∈ t :=
|
||||
Impl.contains_of_contains_insertIfNew t.wf
|
||||
|
||||
/-- This is a restatement of `mem_of_mem_insertIfNew` that is written to exactly match the
|
||||
proof obligation in the statement of `get_insertIfNew`. -/
|
||||
theorem mem_of_mem_insertIfNew' [TransCmp cmp] {k a : α} {v : β k} :
|
||||
a ∈ (t.insertIfNew k v) → ¬ (cmp k a = .eq ∧ ¬ k ∈ t) → a ∈ t :=
|
||||
Impl.mem_of_mem_insertIfNew' t.wf
|
||||
|
||||
theorem size_insertIfNew [TransCmp cmp] {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).size = if k ∈ t then t.size else t.size + 1 :=
|
||||
Impl.size_insertIfNew t.wf
|
||||
|
||||
theorem size_le_size_insertIfNew [TransCmp cmp] {k : α} {v : β k} :
|
||||
t.size ≤ (t.insertIfNew k v).size :=
|
||||
Impl.size_le_size_insertIfNew t.wf
|
||||
|
||||
theorem size_insertIfNew_le [TransCmp cmp] {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).size ≤ t.size + 1 :=
|
||||
Impl.size_insertIfNew_le t.wf
|
||||
|
||||
theorem get?_insertIfNew [TransCmp cmp] [LawfulEqCmp cmp] {k a : α} {v : β k} :
|
||||
(t.insertIfNew k v).get? a =
|
||||
if h : cmp k a = .eq ∧ ¬ k ∈ t then
|
||||
some (cast (congrArg β (compare_eq_iff_eq.mp h.1)) v)
|
||||
else
|
||||
t.get? a :=
|
||||
Impl.get?_insertIfNew t.wf
|
||||
|
||||
theorem get_insertIfNew [TransCmp cmp] [LawfulEqCmp cmp] {k a : α} {v : β k} {h₁} :
|
||||
(t.insertIfNew k v).get a h₁ =
|
||||
if h₂ : cmp k a = .eq ∧ ¬ k ∈ t then
|
||||
cast (congrArg β (compare_eq_iff_eq.mp h₂.1)) v
|
||||
else
|
||||
t.get a (mem_of_mem_insertIfNew' h₁ h₂) :=
|
||||
Impl.get_insertIfNew t.wf
|
||||
|
||||
theorem get!_insertIfNew [TransCmp cmp] [LawfulEqCmp cmp] {k a : α} [Inhabited (β a)] {v : β k} :
|
||||
(t.insertIfNew k v).get! a =
|
||||
if h : cmp k a = .eq ∧ ¬ k ∈ t then
|
||||
cast (congrArg β (compare_eq_iff_eq.mp h.1)) v
|
||||
else
|
||||
t.get! a :=
|
||||
Impl.get!_insertIfNew t.wf
|
||||
|
||||
theorem getD_insertIfNew [TransCmp cmp] [LawfulEqCmp cmp] {k a : α} {fallback : β a} {v : β k} :
|
||||
(t.insertIfNew k v).getD a fallback =
|
||||
if h : cmp k a = .eq ∧ ¬ k ∈ t then
|
||||
cast (congrArg β (compare_eq_iff_eq.mp h.1)) v
|
||||
else
|
||||
t.getD a fallback :=
|
||||
Impl.getD_insertIfNew t.wf
|
||||
|
||||
namespace Const
|
||||
|
||||
variable {β : Type v} {t : DTreeMap α β cmp}
|
||||
|
||||
theorem get?_insertIfNew [TransCmp cmp] {k a : α} {v : β} :
|
||||
get? (t.insertIfNew k v) a =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then some v else get? t a :=
|
||||
Impl.Const.get?_insertIfNew t.wf
|
||||
|
||||
theorem get_insertIfNew [TransCmp cmp] {k a : α} {v : β} {h₁} :
|
||||
get (t.insertIfNew k v) a h₁ =
|
||||
if h₂ : cmp k a = .eq ∧ ¬ k ∈ t then v else get t a (mem_of_mem_insertIfNew' h₁ h₂) :=
|
||||
Impl.Const.get_insertIfNew t.wf
|
||||
|
||||
theorem get!_insertIfNew [TransCmp cmp] [Inhabited β] {k a : α} {v : β} :
|
||||
get! (t.insertIfNew k v) a = if cmp k a = .eq ∧ ¬ k ∈ t then v else get! t a :=
|
||||
Impl.Const.get!_insertIfNew t.wf
|
||||
|
||||
theorem getD_insertIfNew [TransCmp cmp] {k a : α} {fallback v : β} :
|
||||
getD (t.insertIfNew k v) a fallback =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then v else getD t a fallback :=
|
||||
Impl.Const.getD_insertIfNew t.wf
|
||||
|
||||
end Const
|
||||
|
||||
theorem getKey?_insertIfNew [TransCmp cmp] {k a : α} {v : β k} :
|
||||
(t.insertIfNew k v).getKey? a =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then some k else t.getKey? a :=
|
||||
Impl.getKey?_insertIfNew t.wf
|
||||
|
||||
theorem getKey_insertIfNew [TransCmp cmp] {k a : α} {v : β k} {h₁} :
|
||||
(t.insertIfNew k v).getKey a h₁ =
|
||||
if h₂ : cmp k a = .eq ∧ ¬ k ∈ t then k
|
||||
else t.getKey a (mem_of_mem_insertIfNew' h₁ h₂) :=
|
||||
Impl.getKey_insertIfNew t.wf
|
||||
|
||||
theorem getKey!_insertIfNew [TransCmp cmp] [Inhabited α] {k a : α} {v : β k} :
|
||||
(t.insertIfNew k v).getKey! a =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then k else t.getKey! a :=
|
||||
Impl.getKey!_insertIfNew t.wf
|
||||
|
||||
theorem getKeyD_insertIfNew [TransCmp cmp] {k a fallback : α} {v : β k} :
|
||||
(t.insertIfNew k v).getKeyD a fallback =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then k else t.getKeyD a fallback :=
|
||||
Impl.getKeyD_insertIfNew t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_fst [TransCmp cmp] [LawfulEqCmp cmp] {k : α} {v : β k} :
|
||||
(t.getThenInsertIfNew? k v).1 = t.get? k :=
|
||||
Impl.getThenInsertIfNew?_fst t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_snd [TransCmp cmp] [LawfulEqCmp cmp] {k : α} {v : β k} :
|
||||
(t.getThenInsertIfNew? k v).2 = t.insertIfNew k v :=
|
||||
ext <| Impl.getThenInsertIfNew?_snd t.wf
|
||||
|
||||
namespace Const
|
||||
|
||||
variable {β : Type v} {t : DTreeMap α β cmp}
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_fst [TransCmp cmp] {k : α} {v : β} :
|
||||
(getThenInsertIfNew? t k v).1 = get? t k :=
|
||||
Impl.Const.getThenInsertIfNew?_fst t.wf
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_snd [TransCmp cmp] {k : α} {v : β} :
|
||||
(getThenInsertIfNew? t k v).2 = t.insertIfNew k v :=
|
||||
ext <| Impl.Const.getThenInsertIfNew?_snd t.wf
|
||||
|
||||
end Const
|
||||
|
||||
end Std.DTreeMap
|
||||
|
||||
@@ -406,12 +406,12 @@ variable {β : Type v}
|
||||
@[inline, inherit_doc DTreeMap.Const.getThenInsertIfNew?]
|
||||
def getThenInsertIfNew? (t : Raw α β cmp) (a : α) (b : β) : Option β × Raw α β cmp :=
|
||||
letI : Ord α := ⟨cmp⟩
|
||||
let p := Impl.Const.getThenInsertIfNew?! a b t.inner
|
||||
let p := Impl.Const.getThenInsertIfNew?! t.inner a b
|
||||
(p.1, ⟨p.2⟩)
|
||||
|
||||
@[inline, inherit_doc DTreeMap.Const.get?]
|
||||
def get? (t : Raw α β cmp) (a : α) : Option β :=
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.get? a t.inner
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.get? t.inner a
|
||||
|
||||
@[inline, inherit_doc get?, deprecated get? (since := "2025-02-12")]
|
||||
def find? (t : Raw α β cmp) (a : α) : Option β :=
|
||||
@@ -419,11 +419,11 @@ def find? (t : Raw α β cmp) (a : α) : Option β :=
|
||||
|
||||
@[inline, inherit_doc DTreeMap.Const.get]
|
||||
def get (t : Raw α β cmp) (a : α) (h : a ∈ t) : β :=
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.get a t.inner h
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.get t.inner a h
|
||||
|
||||
@[inline, inherit_doc DTreeMap.Const.get!]
|
||||
def get! (t : Raw α β cmp) (a : α) [Inhabited β] : β :=
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.get! a t.inner
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.get! t.inner a
|
||||
|
||||
@[inline, inherit_doc get!, deprecated get! (since := "2025-02-12")]
|
||||
def find! (t : Raw α β cmp) (a : α) [Inhabited β] : β :=
|
||||
@@ -431,7 +431,7 @@ def find! (t : Raw α β cmp) (a : α) [Inhabited β] : β :=
|
||||
|
||||
@[inline, inherit_doc DTreeMap.Const.getD]
|
||||
def getD (t : Raw α β cmp) (a : α) (fallback : β) : β :=
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.getD a t.inner fallback
|
||||
letI : Ord α := ⟨cmp⟩; Impl.Const.getD t.inner a fallback
|
||||
|
||||
@[inline, inherit_doc getD, deprecated getD (since := "2025-02-12")]
|
||||
def findD (t : Raw α β cmp) (a : α) (fallback : β) : β :=
|
||||
|
||||
@@ -48,11 +48,6 @@ theorem contains_congr [TransCmp cmp] (h : t.WF) {k k' : α} (hab : cmp k k' = .
|
||||
theorem mem_congr [TransCmp cmp] (h : t.WF) {k k' : α} (hab : cmp k k' = .eq) : k ∈ t ↔ k' ∈ t :=
|
||||
Impl.mem_congr h hab
|
||||
|
||||
@[simp]
|
||||
theorem isEmpty_insertIfNew [TransCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).isEmpty = false :=
|
||||
Impl.isEmpty_insertIfNew! h
|
||||
|
||||
@[simp]
|
||||
theorem contains_emptyc {k : α} : (∅ : Raw α β cmp).contains k = false :=
|
||||
Impl.contains_empty
|
||||
@@ -142,7 +137,7 @@ theorem size_insert_le [TransCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
|
||||
@[simp]
|
||||
theorem erase_emptyc {k : α} :
|
||||
(∅ : Raw α β cmp).erase k = empty :=
|
||||
(∅ : Raw α β cmp).erase k = ∅ :=
|
||||
ext <| Impl.erase!_empty (instOrd := ⟨cmp⟩) (k := k)
|
||||
|
||||
@[simp]
|
||||
@@ -200,44 +195,6 @@ theorem containsThenInsertIfNew_snd [TransCmp cmp] (h : t.WF) {k : α} {v : β k
|
||||
(t.containsThenInsertIfNew k v).2 = t.insertIfNew k v :=
|
||||
ext <| Impl.containsThenInsertIfNew!_snd h
|
||||
|
||||
@[simp]
|
||||
theorem contains_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β k} :
|
||||
(t.insertIfNew k v).contains a = (cmp k a == .eq || t.contains a) :=
|
||||
Impl.contains_insertIfNew! h
|
||||
|
||||
@[simp]
|
||||
theorem mem_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β k} :
|
||||
a ∈ t.insertIfNew k v ↔ cmp k a = .eq ∨ a ∈ t :=
|
||||
Impl.mem_insertIfNew! h
|
||||
|
||||
theorem contains_insertIfNew_self [TransCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).contains k :=
|
||||
Impl.contains_insertIfNew!_self h
|
||||
|
||||
theorem mem_insertIfNew_self [TransCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
k ∈ t.insertIfNew k v :=
|
||||
Impl.mem_insertIfNew!_self h
|
||||
|
||||
theorem contains_of_contains_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β k} :
|
||||
(t.insertIfNew k v).contains a → cmp k a ≠ .eq → t.contains a :=
|
||||
Impl.contains_of_contains_insertIfNew! h
|
||||
|
||||
theorem mem_of_mem_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β k} :
|
||||
a ∈ t.insertIfNew k v → cmp k a ≠ .eq → a ∈ t :=
|
||||
Impl.contains_of_contains_insertIfNew! h
|
||||
|
||||
theorem size_insertIfNew [TransCmp cmp] {k : α} (h : t.WF) {v : β k} :
|
||||
(t.insertIfNew k v).size = if k ∈ t then t.size else t.size + 1 :=
|
||||
Impl.size_insertIfNew! h
|
||||
|
||||
theorem size_le_size_insertIfNew [TransCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
t.size ≤ (t.insertIfNew k v).size :=
|
||||
Impl.size_le_size_insertIfNew! h
|
||||
|
||||
theorem size_insertIfNew_le [TransCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).size ≤ t.size + 1 :=
|
||||
Impl.size_insertIfNew!_le h
|
||||
|
||||
@[simp]
|
||||
theorem get?_emptyc [TransCmp cmp] [LawfulEqCmp cmp] {a : α} :
|
||||
(∅ : DTreeMap α β cmp).get? a = none :=
|
||||
@@ -339,4 +296,637 @@ theorem get?_congr [TransCmp cmp] (h : t.WF) {a b : α} (hab : cmp a b = .eq) :
|
||||
|
||||
end Const
|
||||
|
||||
theorem get_insert [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k a : α} {v : β k} {h₁} :
|
||||
(t.insert k v).get a h₁ =
|
||||
if h₂ : cmp k a = .eq then
|
||||
cast (congrArg β (compare_eq_iff_eq.mp h₂)) v
|
||||
else
|
||||
t.get a (mem_of_mem_insert h h₁ h₂) :=
|
||||
Impl.get_insert! h
|
||||
|
||||
@[simp]
|
||||
theorem get_insert_self [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
(t.insert k v).get k (mem_insert_self h) = v :=
|
||||
Impl.get_insert!_self h
|
||||
|
||||
@[simp]
|
||||
theorem get_erase [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k a : α} {h'} :
|
||||
(t.erase k).get a h' = t.get a (mem_of_mem_erase h h') :=
|
||||
Impl.get_erase! h
|
||||
|
||||
theorem get?_eq_some_get [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} {h'} :
|
||||
t.get? a = some (t.get a h') :=
|
||||
Impl.get?_eq_some_get h
|
||||
|
||||
namespace Const
|
||||
|
||||
variable {β : Type v} {t : Raw α β cmp}
|
||||
|
||||
theorem get_insert [TransCmp cmp] (h : t.WF) {k a : α} {v : β} {h₁} :
|
||||
get (t.insert k v) a h₁ =
|
||||
if h₂ : cmp k a = .eq then v
|
||||
else get t a (mem_of_mem_insert h h₁ h₂) :=
|
||||
Impl.Const.get_insert! h
|
||||
|
||||
@[simp]
|
||||
theorem get_insert_self [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
get (t.insert k v) k (mem_insert_self h) = v :=
|
||||
Impl.Const.get_insert!_self h
|
||||
|
||||
@[simp]
|
||||
theorem get_erase [TransCmp cmp] (h : t.WF) {k a : α} {h'} :
|
||||
get (t.erase k) a h' = get t a (mem_of_mem_erase h h') :=
|
||||
Impl.Const.get_erase! h
|
||||
|
||||
theorem get?_eq_some_get [TransCmp cmp] (h : t.WF) {a : α} {h'} :
|
||||
get? t a = some (get t a h') :=
|
||||
Impl.Const.get?_eq_some_get h
|
||||
|
||||
theorem get_eq_get [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} {h'} :
|
||||
get t a h' = t.get a h' :=
|
||||
Impl.Const.get_eq_get h
|
||||
|
||||
theorem get_congr [TransCmp cmp] (h : t.WF) {a b : α} (hab : cmp a b = .eq) {h'} :
|
||||
get t a h' = get t b ((mem_congr h hab).mp h') :=
|
||||
Impl.Const.get_congr h hab
|
||||
|
||||
end Const
|
||||
|
||||
@[simp]
|
||||
theorem get!_emptyc [TransCmp cmp] [LawfulEqCmp cmp] {a : α} [Inhabited (β a)] :
|
||||
get! (∅ : Raw α β cmp) a = default :=
|
||||
Impl.get!_empty
|
||||
|
||||
theorem get!_of_isEmpty [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} [Inhabited (β a)] :
|
||||
t.isEmpty = true → t.get! a = default :=
|
||||
Impl.get!_of_isEmpty h
|
||||
|
||||
theorem get!_insert [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k a : α} [Inhabited (β a)]
|
||||
{v : β k} : (t.insert k v).get! a =
|
||||
if h : cmp k a = .eq then cast (congrArg β (compare_eq_iff_eq.mp h)) v else t.get! a :=
|
||||
Impl.get!_insert! h
|
||||
|
||||
@[simp]
|
||||
theorem get!_insert_self [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} [Inhabited (β a)]
|
||||
{b : β a} : (t.insert a b).get! a = b :=
|
||||
Impl.get!_insert!_self h
|
||||
|
||||
theorem get!_eq_default_of_contains_eq_false [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α}
|
||||
[Inhabited (β a)] : t.contains a = false → t.get! a = default :=
|
||||
Impl.get!_eq_default_of_contains_eq_false h
|
||||
|
||||
theorem get!_eq_default [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} [Inhabited (β a)] :
|
||||
¬ a ∈ t → t.get! a = default :=
|
||||
Impl.get!_eq_default h
|
||||
|
||||
theorem get!_erase [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k a : α} [Inhabited (β a)] :
|
||||
(t.erase k).get! a = if cmp k a = .eq then default else t.get! a :=
|
||||
Impl.get!_erase! h
|
||||
|
||||
@[simp]
|
||||
theorem get!_erase_self [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k : α} [Inhabited (β k)] :
|
||||
(t.erase k).get! k = default :=
|
||||
Impl.get!_erase!_self h
|
||||
|
||||
theorem get?_eq_some_get!_of_contains [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α}
|
||||
[Inhabited (β a)] : t.contains a = true → t.get? a = some (t.get! a) :=
|
||||
Impl.get?_eq_some_get!_of_contains h
|
||||
|
||||
theorem get?_eq_some_get! [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} [Inhabited (β a)] :
|
||||
a ∈ t → t.get? a = some (t.get! a) :=
|
||||
Impl.get?_eq_some_get! h
|
||||
|
||||
theorem get!_eq_get!_get? [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} [Inhabited (β a)] :
|
||||
t.get! a = (t.get? a).get! :=
|
||||
Impl.get!_eq_get!_get? h
|
||||
|
||||
theorem get_eq_get! [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} [Inhabited (β a)] {h'} :
|
||||
t.get a h' = t.get! a :=
|
||||
Impl.get_eq_get! h
|
||||
|
||||
namespace Const
|
||||
|
||||
variable {β : Type v} {t : Raw α β cmp}
|
||||
|
||||
@[simp]
|
||||
theorem get!_emptyc [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
get! (∅ : Raw α β cmp) a = default :=
|
||||
Impl.Const.get!_empty
|
||||
|
||||
theorem get!_of_isEmpty [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
t.isEmpty = true → get! t a = default :=
|
||||
Impl.Const.get!_of_isEmpty h
|
||||
|
||||
theorem get!_insert [TransCmp cmp] [Inhabited β] (h : t.WF) {k a : α} {v : β} :
|
||||
get! (t.insert k v) a = if cmp k a = .eq then v else get! t a :=
|
||||
Impl.Const.get!_insert! h
|
||||
|
||||
@[simp]
|
||||
theorem get!_insert_self [TransCmp cmp] [Inhabited β] (h : t.WF) {k : α} {v : β} :
|
||||
get! (t.insert k v) k = v :=
|
||||
Impl.Const.get!_insert!_self h
|
||||
|
||||
theorem get!_eq_default_of_contains_eq_false [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
t.contains a = false → get! t a = default :=
|
||||
Impl.Const.get!_eq_default_of_contains_eq_false h
|
||||
|
||||
theorem get!_eq_default [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
¬ a ∈ t → get! t a = default :=
|
||||
Impl.Const.get!_eq_default h
|
||||
|
||||
theorem get!_erase [TransCmp cmp] [Inhabited β] (h : t.WF) {k a : α} :
|
||||
get! (t.erase k) a = if cmp k a = .eq then default else get! t a :=
|
||||
Impl.Const.get!_erase! h
|
||||
|
||||
@[simp]
|
||||
theorem get!_erase_self [TransCmp cmp] [Inhabited β] (h : t.WF) {k : α} :
|
||||
get! (t.erase k) k = default :=
|
||||
Impl.Const.get!_erase!_self h
|
||||
|
||||
theorem get?_eq_some_get!_of_contains [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
t.contains a = true → get? t a = some (get! t a) :=
|
||||
Impl.Const.get?_eq_some_get! h
|
||||
|
||||
theorem get?_eq_some_get! [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
a ∈ t → get? t a = some (get! t a) :=
|
||||
Impl.Const.get?_eq_some_get! h
|
||||
|
||||
theorem get!_eq_get!_get? [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
get! t a = (get? t a).get! :=
|
||||
Impl.Const.get!_eq_get!_get? h
|
||||
|
||||
theorem get_eq_get! [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} {h'} :
|
||||
get t a h' = get! t a :=
|
||||
Impl.Const.get_eq_get! h
|
||||
|
||||
theorem get!_eq_get! [TransCmp cmp] [LawfulEqCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
get! t a = t.get! a :=
|
||||
Impl.Const.get!_eq_get! h
|
||||
|
||||
theorem get!_congr [TransCmp cmp] [Inhabited β] (h : t.WF) {a b : α} (hab : cmp a b = .eq) :
|
||||
get! t a = get! t b :=
|
||||
Impl.Const.get!_congr h hab
|
||||
|
||||
end Const
|
||||
|
||||
@[simp]
|
||||
theorem getD_emptyc [TransCmp cmp] [LawfulEqCmp cmp] {a : α} {fallback : β a} :
|
||||
(∅ : DTreeMap α β cmp).getD a fallback = fallback :=
|
||||
Impl.getD_empty
|
||||
|
||||
theorem getD_of_isEmpty [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} {fallback : β a} :
|
||||
t.isEmpty = true → t.getD a fallback = fallback :=
|
||||
Impl.getD_of_isEmpty h
|
||||
|
||||
theorem getD_insert [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k a : α} {fallback : β a} {v : β k} :
|
||||
(t.insert k v).getD a fallback =
|
||||
if h : cmp k a = .eq then
|
||||
cast (congrArg β (compare_eq_iff_eq.mp h)) v
|
||||
else t.getD a fallback :=
|
||||
Impl.getD_insert! h
|
||||
|
||||
@[simp]
|
||||
theorem getD_insert_self [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} {fallback b : β a} :
|
||||
(t.insert a b).getD a fallback = b :=
|
||||
Impl.getD_insert!_self h
|
||||
|
||||
theorem getD_eq_fallback_of_contains_eq_false [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} {fallback : β a} :
|
||||
t.contains a = false → t.getD a fallback = fallback :=
|
||||
Impl.getD_eq_fallback_of_contains_eq_false h
|
||||
|
||||
theorem getD_eq_fallback [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} {fallback : β a} :
|
||||
¬ a ∈ t → t.getD a fallback = fallback :=
|
||||
Impl.getD_eq_fallback h
|
||||
|
||||
theorem getD_erase [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k a : α} {fallback : β a} :
|
||||
(t.erase k).getD a fallback = if cmp k a = .eq then fallback else t.getD a fallback :=
|
||||
Impl.getD_erase! h
|
||||
|
||||
@[simp]
|
||||
theorem getD_erase_self [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k : α} {fallback : β k} :
|
||||
(t.erase k).getD k fallback = fallback :=
|
||||
Impl.getD_erase!_self h
|
||||
|
||||
theorem get?_eq_some_getD_of_contains [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α}
|
||||
{fallback : β a} : t.contains a = true → t.get? a = some (t.getD a fallback) :=
|
||||
Impl.get?_eq_some_getD_of_contains h
|
||||
|
||||
theorem get?_eq_some_getD [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} {fallback : β a} :
|
||||
a ∈ t → t.get? a = some (t.getD a fallback) :=
|
||||
Impl.get?_eq_some_getD h
|
||||
|
||||
theorem getD_eq_getD_get? [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} {fallback : β a} :
|
||||
t.getD a fallback = (t.get? a).getD fallback :=
|
||||
Impl.getD_eq_getD_get? h
|
||||
|
||||
theorem get_eq_getD [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} {fallback : β a} {h'} :
|
||||
t.get a h' = t.getD a fallback :=
|
||||
Impl.get_eq_getD h
|
||||
|
||||
theorem get!_eq_getD_default [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} [Inhabited (β a)] :
|
||||
t.get! a = t.getD a default :=
|
||||
Impl.get!_eq_getD_default h
|
||||
|
||||
namespace Const
|
||||
|
||||
variable {β : Type v} {t : Raw α β cmp}
|
||||
|
||||
@[simp]
|
||||
theorem getD_emptyc [TransCmp cmp] {a : α} {fallback : β} :
|
||||
getD (∅ : Raw α β cmp) a fallback = fallback :=
|
||||
Impl.Const.getD_empty
|
||||
|
||||
theorem getD_of_isEmpty [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} :
|
||||
t.isEmpty = true → getD t a fallback = fallback :=
|
||||
Impl.Const.getD_of_isEmpty h
|
||||
|
||||
theorem getD_insert [TransCmp cmp] (h : t.WF) {k a : α} {fallback v : β} :
|
||||
getD (t.insert k v) a fallback = if cmp k a = .eq then v else getD t a fallback :=
|
||||
Impl.Const.getD_insert! h
|
||||
|
||||
@[simp]
|
||||
theorem getD_insert_self [TransCmp cmp] (h : t.WF) {k : α} {fallback v : β} :
|
||||
getD (t.insert k v) k fallback = v :=
|
||||
Impl.Const.getD_insert!_self h
|
||||
|
||||
theorem getD_eq_fallback_of_contains_eq_false [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} :
|
||||
t.contains a = false → getD t a fallback = fallback :=
|
||||
Impl.Const.getD_eq_fallback_of_contains_eq_false h
|
||||
|
||||
theorem getD_eq_fallback [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} :
|
||||
¬ a ∈ t → getD t a fallback = fallback :=
|
||||
Impl.Const.getD_eq_fallback h
|
||||
|
||||
theorem getD_erase [TransCmp cmp] (h : t.WF) {k a : α} {fallback : β} :
|
||||
getD (t.erase k) a fallback = if cmp k a = .eq then
|
||||
fallback
|
||||
else
|
||||
getD t a fallback :=
|
||||
Impl.Const.getD_erase! h
|
||||
|
||||
@[simp]
|
||||
theorem getD_erase_self [TransCmp cmp] (h : t.WF) {k : α} {fallback : β} :
|
||||
getD (t.erase k) k fallback = fallback :=
|
||||
Impl.Const.getD_erase!_self h
|
||||
|
||||
theorem get?_eq_some_getD_of_contains [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} :
|
||||
t.contains a = true → get? t a = some (getD t a fallback) :=
|
||||
Impl.Const.get?_eq_some_getD_of_contains h
|
||||
|
||||
theorem get?_eq_some_getD [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} :
|
||||
a ∈ t → get? t a = some (getD t a fallback) :=
|
||||
Impl.Const.get?_eq_some_getD h
|
||||
|
||||
theorem getD_eq_getD_get? [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} :
|
||||
getD t a fallback = (get? t a).getD fallback :=
|
||||
Impl.Const.getD_eq_getD_get? h
|
||||
|
||||
theorem get_eq_getD [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} {h'} :
|
||||
get t a h' = getD t a fallback :=
|
||||
Impl.Const.get_eq_getD h
|
||||
|
||||
theorem get!_eq_getD_default [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
get! t a = getD t a default :=
|
||||
Impl.Const.get!_eq_getD_default h
|
||||
|
||||
theorem getD_eq_getD [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {a : α} {fallback : β} :
|
||||
getD t a fallback = t.getD a fallback :=
|
||||
Impl.Const.getD_eq_getD h
|
||||
|
||||
theorem getD_congr [TransCmp cmp] (h : t.WF) {a b : α} {fallback : β} (hab : cmp a b = .eq) :
|
||||
getD t a fallback = getD t b fallback :=
|
||||
Impl.Const.getD_congr h hab
|
||||
|
||||
end Const
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_emptyc {a : α} : (∅ : DTreeMap α β cmp).getKey? a = none :=
|
||||
Impl.getKey?_empty
|
||||
|
||||
theorem getKey?_of_isEmpty [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
t.isEmpty = true → t.getKey? a = none :=
|
||||
Impl.getKey?_of_isEmpty h
|
||||
|
||||
theorem getKey?_insert [TransCmp cmp] (h : t.WF) {a k : α} {v : β k} :
|
||||
(t.insert k v).getKey? a = if cmp k a = .eq then some k else t.getKey? a :=
|
||||
Impl.getKey?_insert! h
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_insert_self [TransCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
(t.insert k v).getKey? k = some k :=
|
||||
Impl.getKey?_insert!_self h
|
||||
|
||||
theorem contains_eq_isSome_getKey? [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
t.contains a = (t.getKey? a).isSome :=
|
||||
Impl.contains_eq_isSome_getKey? h
|
||||
|
||||
theorem mem_iff_isSome_getKey? [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
a ∈ t ↔ (t.getKey? a).isSome :=
|
||||
Impl.mem_iff_isSome_getKey? h
|
||||
|
||||
theorem getKey?_eq_none_of_contains_eq_false [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
t.contains a = false → t.getKey? a = none :=
|
||||
Impl.getKey?_eq_none_of_contains_eq_false h
|
||||
|
||||
theorem getKey?_eq_none [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
¬ a ∈ t → t.getKey? a = none :=
|
||||
Impl.getKey?_eq_none h
|
||||
|
||||
theorem getKey?_erase [TransCmp cmp] (h : t.WF) {k a : α} :
|
||||
(t.erase k).getKey? a = if cmp k a = .eq then none else t.getKey? a :=
|
||||
Impl.getKey?_erase! h
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_erase_self [TransCmp cmp] (h : t.WF) {k : α} :
|
||||
(t.erase k).getKey? k = none :=
|
||||
Impl.getKey?_erase!_self h
|
||||
|
||||
theorem getKey_insert [TransCmp cmp] (h : t.WF) {k a : α} {v : β k} {h₁} :
|
||||
(t.insert k v).getKey a h₁ =
|
||||
if h₂ : cmp k a = .eq then
|
||||
k
|
||||
else
|
||||
t.getKey a (mem_of_mem_insert h h₁ h₂) :=
|
||||
Impl.getKey_insert! h
|
||||
|
||||
@[simp]
|
||||
theorem getKey_insert_self [TransCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
(t.insert k v).getKey k (mem_insert_self h) = k :=
|
||||
Impl.getKey_insert!_self h
|
||||
|
||||
@[simp]
|
||||
theorem getKey_erase [TransCmp cmp] (h : t.WF) {k a : α} {h'} :
|
||||
(t.erase k).getKey a h' = t.getKey a (mem_of_mem_erase h h') :=
|
||||
Impl.getKey_erase! h
|
||||
|
||||
theorem getKey?_eq_some_getKey [TransCmp cmp] (h : t.WF) {a : α} {h'} :
|
||||
t.getKey? a = some (t.getKey a h') :=
|
||||
Impl.getKey?_eq_some_getKey h
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_emptyc {a : α} [Inhabited α] :
|
||||
(∅ : DTreeMap α β cmp).getKey! a = default :=
|
||||
Impl.getKey!_empty
|
||||
|
||||
theorem getKey!_of_isEmpty [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.isEmpty = true → t.getKey! a = default :=
|
||||
Impl.getKey!_of_isEmpty h
|
||||
|
||||
theorem getKey!_insert [TransCmp cmp] [Inhabited α] (h : t.WF) {k a : α} {v : β k} :
|
||||
(t.insert k v).getKey! a = if cmp k a = .eq then k else t.getKey! a :=
|
||||
Impl.getKey!_insert! h
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_insert_self [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} {b : β a} :
|
||||
(t.insert a b).getKey! a = a :=
|
||||
Impl.getKey!_insert!_self h
|
||||
|
||||
theorem getKey!_eq_default_of_contains_eq_false [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.contains a = false → t.getKey! a = default :=
|
||||
Impl.getKey!_eq_default_of_contains_eq_false h
|
||||
|
||||
theorem getKey!_eq_default [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
¬ a ∈ t → t.getKey! a = default :=
|
||||
Impl.getKey!_eq_default h
|
||||
|
||||
theorem getKey!_erase [TransCmp cmp] [Inhabited α] (h : t.WF) {k a : α} :
|
||||
(t.erase k).getKey! a = if cmp k a = .eq then default else t.getKey! a :=
|
||||
Impl.getKey!_erase! h
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_erase_self [TransCmp cmp] [Inhabited α] (h : t.WF) {k : α} :
|
||||
(t.erase k).getKey! k = default :=
|
||||
Impl.getKey!_erase!_self h
|
||||
|
||||
theorem getKey?_eq_some_getKey!_of_contains [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.contains a = true → t.getKey? a = some (t.getKey! a) :=
|
||||
Impl.getKey?_eq_some_getKey!_of_contains h
|
||||
|
||||
theorem getKey?_eq_some_getKey! [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
a ∈ t → t.getKey? a = some (t.getKey! a) :=
|
||||
Impl.getKey?_eq_some_getKey! h
|
||||
|
||||
theorem getKey!_eq_get!_getKey? [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.getKey! a = (t.getKey? a).get! :=
|
||||
Impl.getKey!_eq_get!_getKey? h
|
||||
|
||||
theorem getKey_eq_getKey! [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} {h'} :
|
||||
t.getKey a h' = t.getKey! a :=
|
||||
Impl.getKey_eq_getKey! h
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_emptyc {a : α} {fallback : α} :
|
||||
(∅ : DTreeMap α β cmp).getKeyD a fallback = fallback :=
|
||||
Impl.getKeyD_empty
|
||||
|
||||
theorem getKeyD_of_isEmpty [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
t.isEmpty = true → t.getKeyD a fallback = fallback :=
|
||||
Impl.getKeyD_of_isEmpty h
|
||||
|
||||
theorem getKeyD_insert [TransCmp cmp] (h : t.WF) {k a fallback : α} {v : β k} :
|
||||
(t.insert k v).getKeyD a fallback = if cmp k a = .eq then k else t.getKeyD a fallback :=
|
||||
Impl.getKeyD_insert! h
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_insert_self [TransCmp cmp] (h : t.WF) {a fallback : α} {b : β a} :
|
||||
(t.insert a b).getKeyD a fallback = a :=
|
||||
Impl.getKeyD_insert!_self h
|
||||
|
||||
theorem getKeyD_eq_fallback_of_contains_eq_false [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
t.contains a = false → t.getKeyD a fallback = fallback :=
|
||||
Impl.getKeyD_eq_fallback_of_contains_eq_false h
|
||||
|
||||
theorem getKeyD_eq_fallback [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
¬ a ∈ t → t.getKeyD a fallback = fallback :=
|
||||
Impl.getKeyD_eq_fallback h
|
||||
|
||||
theorem getKeyD_erase [TransCmp cmp] (h : t.WF) {k a fallback : α} :
|
||||
(t.erase k).getKeyD a fallback =
|
||||
if cmp k a = .eq then fallback else t.getKeyD a fallback :=
|
||||
Impl.getKeyD_erase! h
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_erase_self [TransCmp cmp] (h : t.WF) {k fallback : α} :
|
||||
(t.erase k).getKeyD k fallback = fallback :=
|
||||
Impl.getKeyD_erase!_self h
|
||||
|
||||
theorem getKey?_eq_some_getKeyD_of_contains [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
t.contains a = true → t.getKey? a = some (t.getKeyD a fallback) :=
|
||||
Impl.getKey?_eq_some_getKeyD_of_contains h
|
||||
|
||||
theorem getKey?_eq_some_getKeyD [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
a ∈ t → t.getKey? a = some (t.getKeyD a fallback) :=
|
||||
Impl.getKey?_eq_some_getKeyD h
|
||||
|
||||
theorem getKeyD_eq_getD_getKey? [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
t.getKeyD a fallback = (t.getKey? a).getD fallback :=
|
||||
Impl.getKeyD_eq_getD_getKey? h
|
||||
|
||||
theorem getKey_eq_getKeyD [TransCmp cmp] (h : t.WF) {a fallback : α} {h'} :
|
||||
t.getKey a h' = t.getKeyD a fallback :=
|
||||
Impl.getKey_eq_getKeyD h
|
||||
|
||||
theorem getKey!_eq_getKeyD_default [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.getKey! a = t.getKeyD a default :=
|
||||
Impl.getKey!_eq_getKeyD_default h
|
||||
|
||||
@[simp]
|
||||
theorem isEmpty_insertIfNew [TransCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).isEmpty = false :=
|
||||
Impl.isEmpty_insertIfNew! h
|
||||
|
||||
@[simp]
|
||||
theorem contains_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β k} :
|
||||
(t.insertIfNew k v).contains a = (cmp k a == .eq || t.contains a) :=
|
||||
Impl.contains_insertIfNew! h
|
||||
|
||||
@[simp]
|
||||
theorem mem_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β k} :
|
||||
a ∈ t.insertIfNew k v ↔ cmp k a = .eq ∨ a ∈ t :=
|
||||
Impl.mem_insertIfNew! h
|
||||
|
||||
theorem contains_insertIfNew_self [TransCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).contains k :=
|
||||
Impl.contains_insertIfNew!_self h
|
||||
|
||||
theorem mem_insertIfNew_self [TransCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
k ∈ t.insertIfNew k v :=
|
||||
Impl.mem_insertIfNew!_self h
|
||||
|
||||
theorem contains_of_contains_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β k} :
|
||||
(t.insertIfNew k v).contains a → cmp k a ≠ .eq → t.contains a :=
|
||||
Impl.contains_of_contains_insertIfNew! h
|
||||
|
||||
theorem mem_of_mem_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β k} :
|
||||
a ∈ t.insertIfNew k v → cmp k a ≠ .eq → a ∈ t :=
|
||||
Impl.contains_of_contains_insertIfNew! h
|
||||
|
||||
/-- This is a restatement of `mem_of_mem_insertIfNew` that is written to exactly match the
|
||||
proof obligation in the statement of `get_insertIfNew`. -/
|
||||
theorem mem_of_mem_insertIfNew' [TransCmp cmp] (h : t.WF) {k a : α} {v : β k} :
|
||||
a ∈ t.insertIfNew k v → ¬ (cmp k a = .eq ∧ ¬ k ∈ t) → a ∈ t :=
|
||||
Impl.mem_of_mem_insertIfNew!' h
|
||||
|
||||
theorem size_insertIfNew [TransCmp cmp] {k : α} (h : t.WF) {v : β k} :
|
||||
(t.insertIfNew k v).size = if k ∈ t then t.size else t.size + 1 :=
|
||||
Impl.size_insertIfNew! h
|
||||
|
||||
theorem size_le_size_insertIfNew [TransCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
t.size ≤ (t.insertIfNew k v).size :=
|
||||
Impl.size_le_size_insertIfNew! h
|
||||
|
||||
theorem size_insertIfNew_le [TransCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
(t.insertIfNew k v).size ≤ t.size + 1 :=
|
||||
Impl.size_insertIfNew!_le h
|
||||
|
||||
theorem get?_insertIfNew [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k a : α} {v : β k} :
|
||||
(t.insertIfNew k v).get? a =
|
||||
if h : cmp k a = .eq ∧ ¬ k ∈ t then
|
||||
some (cast (congrArg β (compare_eq_iff_eq.mp h.1)) v)
|
||||
else
|
||||
t.get? a :=
|
||||
Impl.get?_insertIfNew! h
|
||||
|
||||
theorem get_insertIfNew [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k a : α} {v : β k} {h₁} :
|
||||
(t.insertIfNew k v).get a h₁ =
|
||||
if h₂ : cmp k a = .eq ∧ ¬ k ∈ t then
|
||||
cast (congrArg β (compare_eq_iff_eq.mp h₂.1)) v
|
||||
else
|
||||
t.get a (mem_of_mem_insertIfNew' h h₁ h₂) :=
|
||||
Impl.get_insertIfNew! h
|
||||
|
||||
theorem get!_insertIfNew [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k a : α} [Inhabited (β a)] {v : β k} :
|
||||
(t.insertIfNew k v).get! a =
|
||||
if h : cmp k a = .eq ∧ ¬ k ∈ t then
|
||||
cast (congrArg β (compare_eq_iff_eq.mp h.1)) v
|
||||
else
|
||||
t.get! a :=
|
||||
Impl.get!_insertIfNew! h
|
||||
|
||||
theorem getD_insertIfNew [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k a : α} {fallback : β a} {v : β k} :
|
||||
(t.insertIfNew k v).getD a fallback =
|
||||
if h : cmp k a = .eq ∧ ¬ k ∈ t then
|
||||
cast (congrArg β (compare_eq_iff_eq.mp h.1)) v
|
||||
else
|
||||
t.getD a fallback :=
|
||||
Impl.getD_insertIfNew! h
|
||||
|
||||
namespace Const
|
||||
|
||||
variable {β : Type v} {t : Raw α β cmp}
|
||||
|
||||
theorem get?_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} :
|
||||
get? (t.insertIfNew k v) a =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then some v else get? t a :=
|
||||
Impl.Const.get?_insertIfNew! h
|
||||
|
||||
theorem get_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} {h₁} :
|
||||
get (t.insertIfNew k v) a h₁ =
|
||||
if h₂ : cmp k a = .eq ∧ ¬ k ∈ t then
|
||||
v
|
||||
else
|
||||
get t a (mem_of_mem_insertIfNew' h h₁ h₂) :=
|
||||
Impl.Const.get_insertIfNew! h
|
||||
|
||||
theorem get!_insertIfNew [TransCmp cmp] [Inhabited β] (h : t.WF) {k a : α} {v : β} :
|
||||
get! (t.insertIfNew k v) a =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then v else get! t a :=
|
||||
Impl.Const.get!_insertIfNew! h
|
||||
|
||||
theorem getD_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {fallback v : β} :
|
||||
getD (t.insertIfNew k v) a fallback =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then v else getD t a fallback :=
|
||||
Impl.Const.getD_insertIfNew! h
|
||||
|
||||
end Const
|
||||
|
||||
theorem getKey?_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β k} :
|
||||
(t.insertIfNew k v).getKey? a =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then some k else t.getKey? a :=
|
||||
Impl.getKey?_insertIfNew! h
|
||||
|
||||
theorem getKey_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β k} {h₁} :
|
||||
(t.insertIfNew k v).getKey a h₁ =
|
||||
if h₂ : cmp k a = .eq ∧ ¬ k ∈ t then k
|
||||
else t.getKey a (mem_of_mem_insertIfNew' h h₁ h₂) :=
|
||||
Impl.getKey_insertIfNew! h
|
||||
|
||||
theorem getKey!_insertIfNew [TransCmp cmp] [Inhabited α] (h : t.WF) {k a : α}
|
||||
{v : β k} :
|
||||
(t.insertIfNew k v).getKey! a =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then k else t.getKey! a :=
|
||||
Impl.getKey!_insertIfNew! h
|
||||
|
||||
theorem getKeyD_insertIfNew [TransCmp cmp] (h : t.WF) {k a fallback : α}
|
||||
{v : β k} :
|
||||
(t.insertIfNew k v).getKeyD a fallback =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then k else t.getKeyD a fallback :=
|
||||
Impl.getKeyD_insertIfNew! h
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_fst [TransCmp cmp] [LawfulEqCmp cmp] (_ : t.WF) {k : α} {v : β k} :
|
||||
(t.getThenInsertIfNew? k v).1 = t.get? k :=
|
||||
Impl.getThenInsertIfNew?!_fst
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_snd [TransCmp cmp] [LawfulEqCmp cmp] (h : t.WF) {k : α} {v : β k} :
|
||||
(t.getThenInsertIfNew? k v).2 = t.insertIfNew k v :=
|
||||
ext <| Impl.getThenInsertIfNew?!_snd h
|
||||
|
||||
namespace Const
|
||||
|
||||
variable {β : Type v} {t : Raw α β cmp}
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_fst [TransCmp cmp] (_ : t.WF) {k : α} {v : β} :
|
||||
(getThenInsertIfNew? t k v).1 = get? t k :=
|
||||
Impl.Const.getThenInsertIfNew?!_fst
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_snd [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
(getThenInsertIfNew? t k v).2 = t.insertIfNew k v :=
|
||||
ext <| Impl.Const.getThenInsertIfNew?!_snd h
|
||||
|
||||
end Const
|
||||
|
||||
end Std.DTreeMap.Raw
|
||||
|
||||
@@ -45,11 +45,6 @@ theorem contains_congr [TransCmp cmp] {k k' : α} (hab : cmp k k' = .eq) :
|
||||
theorem mem_congr [TransCmp cmp] {k k' : α} (hab : cmp k k' = .eq) : k ∈ t ↔ k' ∈ t :=
|
||||
DTreeMap.mem_congr hab
|
||||
|
||||
@[simp]
|
||||
theorem isEmpty_insertIfNew [TransCmp cmp] {k : α} {v : β} :
|
||||
(t.insertIfNew k v).isEmpty = false :=
|
||||
DTreeMap.isEmpty_insertIfNew
|
||||
|
||||
@[simp]
|
||||
theorem contains_emptyc {k : α} : (∅ : TreeMap α β cmp).contains k = false :=
|
||||
DTreeMap.contains_emptyc
|
||||
@@ -139,7 +134,7 @@ theorem size_insert_le [TransCmp cmp] {k : α} {v : β} :
|
||||
|
||||
@[simp]
|
||||
theorem erase_emptyc {k : α} :
|
||||
(∅ : TreeMap α β cmp).erase k = empty :=
|
||||
(∅ : TreeMap α β cmp).erase k = ∅ :=
|
||||
ext <| DTreeMap.erase_emptyc
|
||||
|
||||
@[simp]
|
||||
@@ -197,46 +192,6 @@ theorem containsThenInsertIfNew_snd [TransCmp cmp] {k : α} {v : β} :
|
||||
(t.containsThenInsertIfNew k v).2 = t.insertIfNew k v :=
|
||||
ext <| DTreeMap.containsThenInsertIfNew_snd
|
||||
|
||||
@[simp]
|
||||
theorem contains_insertIfNew [TransCmp cmp] {k a : α} {v : β} :
|
||||
(t.insertIfNew k v).contains a = (cmp k a == .eq || t.contains a) :=
|
||||
DTreeMap.contains_insertIfNew
|
||||
|
||||
@[simp]
|
||||
theorem mem_insertIfNew [TransCmp cmp] {k a : α} {v : β} :
|
||||
a ∈ t.insertIfNew k v ↔ cmp k a = .eq ∨ a ∈ t :=
|
||||
DTreeMap.mem_insertIfNew
|
||||
|
||||
@[simp]
|
||||
theorem contains_insertIfNew_self [TransCmp cmp] {k : α} {v : β} :
|
||||
(t.insertIfNew k v).contains k :=
|
||||
DTreeMap.contains_insertIfNew_self
|
||||
|
||||
@[simp]
|
||||
theorem mem_insertIfNew_self [TransCmp cmp] {k : α} {v : β} :
|
||||
k ∈ t.insertIfNew k v :=
|
||||
DTreeMap.mem_insertIfNew_self
|
||||
|
||||
theorem contains_of_contains_insertIfNew [TransCmp cmp] {k a : α} {v : β} :
|
||||
(t.insertIfNew k v).contains a → cmp k a ≠ .eq → t.contains a :=
|
||||
DTreeMap.contains_of_contains_insertIfNew
|
||||
|
||||
theorem mem_of_mem_insertIfNew [TransCmp cmp] {k a : α} {v : β} :
|
||||
a ∈ t.insertIfNew k v → cmp k a ≠ .eq → a ∈ t :=
|
||||
DTreeMap.contains_of_contains_insertIfNew
|
||||
|
||||
theorem size_insertIfNew [TransCmp cmp] {k : α} {v : β} :
|
||||
(t.insertIfNew k v).size = if k ∈ t then t.size else t.size + 1 :=
|
||||
DTreeMap.size_insertIfNew
|
||||
|
||||
theorem size_le_size_insertIfNew [TransCmp cmp] {k : α} {v : β} :
|
||||
t.size ≤ (t.insertIfNew k v).size :=
|
||||
DTreeMap.size_le_size_insertIfNew
|
||||
|
||||
theorem size_insertIfNew_le [TransCmp cmp] {k : α} {v : β} :
|
||||
(t.insertIfNew k v).size ≤ t.size + 1 :=
|
||||
DTreeMap.size_insertIfNew_le
|
||||
|
||||
@[simp] theorem get_eq_getElem {a : α} {h} : get t a h = t[a]'h := rfl
|
||||
@[simp] theorem get?_eq_getElem? {a : α} : get? t a = t[a]? := rfl
|
||||
@[simp] theorem get!_eq_getElem! [Inhabited β] {a : α} : get! t a = t[a]! := rfl
|
||||
@@ -288,4 +243,416 @@ theorem getElem?_congr [TransCmp cmp] {a b : α} (hab : cmp a b = .eq) :
|
||||
t[a]? = t[b]? :=
|
||||
DTreeMap.Const.get?_congr hab
|
||||
|
||||
theorem getElem_insert [TransCmp cmp] {k a : α} {v : β} {h₁} :
|
||||
(t.insert k v)[a]'h₁ =
|
||||
if h₂ : cmp k a = .eq then v
|
||||
else get t a (mem_of_mem_insert h₁ h₂) :=
|
||||
DTreeMap.Const.get_insert
|
||||
|
||||
@[simp]
|
||||
theorem getElem_insert_self [TransCmp cmp] {k : α} {v : β} :
|
||||
(t.insert k v)[k]'mem_insert_self = v :=
|
||||
DTreeMap.Const.get_insert_self
|
||||
|
||||
@[simp]
|
||||
theorem getElem_erase [TransCmp cmp] {k a : α} {h'} :
|
||||
(t.erase k)[a]'h' = t[a]'(mem_of_mem_erase h') :=
|
||||
DTreeMap.Const.get_erase
|
||||
|
||||
theorem getElem?_eq_some_getElem [TransCmp cmp] {a : α} {h} :
|
||||
t[a]? = some (t[a]'h) :=
|
||||
DTreeMap.Const.get?_eq_some_get
|
||||
|
||||
theorem getElem_congr [TransCmp cmp] {a b : α} (hab : cmp a b = .eq) {h'} :
|
||||
t[a]'h' = t[b]'((mem_congr hab).mp h') :=
|
||||
DTreeMap.Const.get_congr hab
|
||||
|
||||
@[simp]
|
||||
theorem getElem!_emptyc [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
(∅ : TreeMap α β cmp)[a]! = default :=
|
||||
DTreeMap.Const.get!_emptyc (cmp := cmp) (a := a)
|
||||
|
||||
theorem getElem!_of_isEmpty [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
t.isEmpty = true → t[a]! = default :=
|
||||
DTreeMap.Const.get!_of_isEmpty
|
||||
|
||||
theorem getElem!_insert [TransCmp cmp] [Inhabited β] {k a : α} {v : β} :
|
||||
(t.insert k v)[a]! = if cmp k a = .eq then v else t[a]! :=
|
||||
DTreeMap.Const.get!_insert
|
||||
|
||||
@[simp]
|
||||
theorem getElem!_insert_self [TransCmp cmp] [Inhabited β] {k : α}
|
||||
{v : β} : (t.insert k v)[k]! = v :=
|
||||
DTreeMap.Const.get!_insert_self
|
||||
|
||||
theorem getElem!_eq_default_of_contains_eq_false [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
t.contains a = false → t[a]! = default :=
|
||||
DTreeMap.Const.get!_eq_default_of_contains_eq_false
|
||||
|
||||
theorem getElem!_eq_default [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
¬ a ∈ t → t[a]! = default :=
|
||||
DTreeMap.Const.get!_eq_default
|
||||
|
||||
theorem getElem!_erase [TransCmp cmp] [Inhabited β] {k a : α} :
|
||||
(t.erase k)[a]! = if cmp k a = .eq then default else t[a]! :=
|
||||
DTreeMap.Const.get!_erase
|
||||
|
||||
@[simp]
|
||||
theorem getElem!_erase_self [TransCmp cmp] [Inhabited β] {k : α} :
|
||||
(t.erase k)[k]! = default :=
|
||||
DTreeMap.Const.get!_erase_self
|
||||
|
||||
theorem getElem?_eq_some_getElem!_of_contains [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
t.contains a = true → t[a]? = some t[a]! :=
|
||||
DTreeMap.Const.get?_eq_some_get!
|
||||
|
||||
theorem getElem?_eq_some_getElem! [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
a ∈ t → t[a]? = some t[a]! :=
|
||||
DTreeMap.Const.get?_eq_some_get!
|
||||
|
||||
theorem getElem!_eq_getElem!_getElem? [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
t[a]! = t[a]?.get! :=
|
||||
DTreeMap.Const.get!_eq_get!_get?
|
||||
|
||||
theorem getElem_eq_getElem! [TransCmp cmp] [Inhabited β] {a : α} {h} :
|
||||
t[a]'h = t[a]! :=
|
||||
DTreeMap.Const.get_eq_get!
|
||||
|
||||
theorem getElem!_congr [TransCmp cmp] [Inhabited β] {a b : α}
|
||||
(hab : cmp a b = .eq) : t[a]! = t[b]! :=
|
||||
DTreeMap.Const.get!_congr hab
|
||||
|
||||
@[simp]
|
||||
theorem getD_emptyc [TransCmp cmp] {a : α} {fallback : β} :
|
||||
getD (∅ : TreeMap α β cmp) a fallback = fallback :=
|
||||
DTreeMap.Const.getD_emptyc
|
||||
|
||||
theorem getD_of_isEmpty [TransCmp cmp] {a : α} {fallback : β} :
|
||||
t.isEmpty = true → getD t a fallback = fallback :=
|
||||
DTreeMap.Const.getD_of_isEmpty
|
||||
|
||||
theorem getD_insert [TransCmp cmp] {k a : α} {fallback v : β} :
|
||||
getD (t.insert k v) a fallback = if cmp k a = .eq then v else getD t a fallback :=
|
||||
DTreeMap.Const.getD_insert
|
||||
|
||||
@[simp]
|
||||
theorem getD_insert_self [TransCmp cmp] {k : α} {fallback v : β} :
|
||||
getD (t.insert k v) k fallback = v :=
|
||||
DTreeMap.Const.getD_insert_self
|
||||
|
||||
theorem getD_eq_fallback_of_contains_eq_false [TransCmp cmp] {a : α} {fallback : β} :
|
||||
t.contains a = false → getD t a fallback = fallback :=
|
||||
DTreeMap.Const.getD_eq_fallback_of_contains_eq_false
|
||||
|
||||
theorem getD_eq_fallback [TransCmp cmp] {a : α} {fallback : β} :
|
||||
¬ a ∈ t → getD t a fallback = fallback :=
|
||||
DTreeMap.Const.getD_eq_fallback
|
||||
|
||||
theorem getD_erase [TransCmp cmp] {k a : α} {fallback : β} :
|
||||
getD (t.erase k) a fallback = if cmp k a = .eq then
|
||||
fallback
|
||||
else
|
||||
getD t a fallback :=
|
||||
DTreeMap.Const.getD_erase
|
||||
|
||||
@[simp]
|
||||
theorem getD_erase_self [TransCmp cmp] {k : α} {fallback : β} :
|
||||
getD (t.erase k) k fallback = fallback :=
|
||||
DTreeMap.Const.getD_erase_self
|
||||
|
||||
theorem getElem?_eq_some_getD_of_contains [TransCmp cmp] {a : α} {fallback : β} :
|
||||
t.contains a = true → get? t a = some (getD t a fallback) :=
|
||||
DTreeMap.Const.get?_eq_some_getD_of_contains
|
||||
|
||||
theorem getElem?_eq_some_getD [TransCmp cmp] {a : α} {fallback : β} :
|
||||
a ∈ t → t[a]? = some (getD t a fallback) :=
|
||||
DTreeMap.Const.get?_eq_some_getD
|
||||
|
||||
theorem getD_eq_getD_getElem? [TransCmp cmp] {a : α} {fallback : β} :
|
||||
getD t a fallback = t[a]?.getD fallback :=
|
||||
DTreeMap.Const.getD_eq_getD_get?
|
||||
|
||||
theorem getElem_eq_getD [TransCmp cmp] {a : α} {fallback : β} {h} :
|
||||
t[a]'h = getD t a fallback :=
|
||||
DTreeMap.Const.get_eq_getD
|
||||
|
||||
theorem getElem!_eq_getD_default [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
t[a]! = getD t a default :=
|
||||
DTreeMap.Const.get!_eq_getD_default
|
||||
|
||||
theorem getD_congr [TransCmp cmp] {a b : α} {fallback : β}
|
||||
(hab : cmp a b = .eq) : getD t a fallback = getD t b fallback :=
|
||||
DTreeMap.Const.getD_congr hab
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_emptyc {a : α} : (∅ : TreeMap α β cmp).getKey? a = none :=
|
||||
DTreeMap.getKey?_emptyc
|
||||
|
||||
theorem getKey?_of_isEmpty [TransCmp cmp] {a : α} :
|
||||
t.isEmpty = true → t.getKey? a = none :=
|
||||
DTreeMap.getKey?_of_isEmpty
|
||||
|
||||
theorem getKey?_insert [TransCmp cmp] {a k : α} {v : β} :
|
||||
(t.insert k v).getKey? a = if cmp k a = .eq then some k else t.getKey? a :=
|
||||
DTreeMap.getKey?_insert
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_insert_self [TransCmp cmp] {k : α} {v : β} :
|
||||
(t.insert k v).getKey? k = some k :=
|
||||
DTreeMap.getKey?_insert_self
|
||||
|
||||
theorem contains_eq_isSome_getKey? [TransCmp cmp] {a : α} :
|
||||
t.contains a = (t.getKey? a).isSome :=
|
||||
DTreeMap.contains_eq_isSome_getKey?
|
||||
|
||||
theorem mem_iff_isSome_getKey? [TransCmp cmp] {a : α} :
|
||||
a ∈ t ↔ (t.getKey? a).isSome :=
|
||||
DTreeMap.mem_iff_isSome_getKey?
|
||||
|
||||
theorem getKey?_eq_none_of_contains_eq_false [TransCmp cmp] {a : α} :
|
||||
t.contains a = false → t.getKey? a = none :=
|
||||
DTreeMap.getKey?_eq_none_of_contains_eq_false
|
||||
|
||||
theorem getKey?_eq_none [TransCmp cmp] {a : α} :
|
||||
¬ a ∈ t → t.getKey? a = none :=
|
||||
DTreeMap.getKey?_eq_none
|
||||
|
||||
theorem getKey?_erase [TransCmp cmp] {k a : α} :
|
||||
(t.erase k).getKey? a = if cmp k a = .eq then none else t.getKey? a :=
|
||||
DTreeMap.getKey?_erase
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_erase_self [TransCmp cmp] {k : α} :
|
||||
(t.erase k).getKey? k = none :=
|
||||
DTreeMap.getKey?_erase_self
|
||||
|
||||
theorem getKey_insert [TransCmp cmp] {k a : α} {v : β} {h₁} :
|
||||
(t.insert k v).getKey a h₁ =
|
||||
if h₂ : cmp k a = .eq then k else t.getKey a (mem_of_mem_insert h₁ h₂) :=
|
||||
DTreeMap.getKey_insert
|
||||
|
||||
@[simp]
|
||||
theorem getKey_insert_self [TransCmp cmp] {k : α} {v : β} :
|
||||
(t.insert k v).getKey k mem_insert_self = k :=
|
||||
DTreeMap.getKey_insert_self
|
||||
|
||||
@[simp]
|
||||
theorem getKey_erase [TransCmp cmp] {k a : α} {h'} :
|
||||
(t.erase k).getKey a h' = t.getKey a (mem_of_mem_erase h') :=
|
||||
DTreeMap.getKey_erase
|
||||
|
||||
theorem getKey?_eq_some_getKey [TransCmp cmp] {a : α} {h'} :
|
||||
t.getKey? a = some (t.getKey a h') :=
|
||||
DTreeMap.getKey?_eq_some_getKey
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_emptyc {a : α} [Inhabited α] :
|
||||
(∅ : TreeMap α β cmp).getKey! a = default :=
|
||||
DTreeMap.getKey!_emptyc
|
||||
|
||||
theorem getKey!_of_isEmpty [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.isEmpty = true → t.getKey! a = default :=
|
||||
DTreeMap.getKey!_of_isEmpty
|
||||
|
||||
theorem getKey!_insert [TransCmp cmp] [Inhabited α] {k a : α}
|
||||
{v : β} : (t.insert k v).getKey! a = if cmp k a = .eq then k else t.getKey! a :=
|
||||
DTreeMap.getKey!_insert
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_insert_self [TransCmp cmp] [Inhabited α] {a : α}
|
||||
{b : β} : (t.insert a b).getKey! a = a :=
|
||||
DTreeMap.getKey!_insert_self
|
||||
|
||||
theorem getKey!_eq_default_of_contains_eq_false [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.contains a = false → t.getKey! a = default :=
|
||||
DTreeMap.getKey!_eq_default_of_contains_eq_false
|
||||
|
||||
theorem getKey!_eq_default [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
¬ a ∈ t → t.getKey! a = default :=
|
||||
DTreeMap.getKey!_eq_default
|
||||
|
||||
theorem getKey!_erase [TransCmp cmp] [Inhabited α] {k a : α} :
|
||||
(t.erase k).getKey! a = if cmp k a = .eq then default else t.getKey! a :=
|
||||
DTreeMap.getKey!_erase
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_erase_self [TransCmp cmp] [Inhabited α] {k : α} :
|
||||
(t.erase k).getKey! k = default :=
|
||||
DTreeMap.getKey!_erase_self
|
||||
|
||||
theorem getKey?_eq_some_getKey!_of_contains [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.contains a = true → t.getKey? a = some (t.getKey! a) :=
|
||||
DTreeMap.getKey?_eq_some_getKey!_of_contains
|
||||
|
||||
theorem getKey?_eq_some_getKey! [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
a ∈ t → t.getKey? a = some (t.getKey! a) :=
|
||||
DTreeMap.getKey?_eq_some_getKey!
|
||||
|
||||
theorem getKey!_eq_get!_getKey? [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.getKey! a = (t.getKey? a).get! :=
|
||||
DTreeMap.getKey!_eq_get!_getKey?
|
||||
|
||||
theorem getKey_eq_getKey! [TransCmp cmp] [Inhabited α] {a : α} {h} :
|
||||
t.getKey a h = t.getKey! a :=
|
||||
DTreeMap.getKey_eq_getKey!
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_emptyc {a : α} {fallback : α} :
|
||||
(∅ : TreeMap α β cmp).getKeyD a fallback = fallback :=
|
||||
DTreeMap.getKeyD_emptyc
|
||||
|
||||
theorem getKeyD_of_isEmpty [TransCmp cmp] {a fallback : α} :
|
||||
t.isEmpty = true → t.getKeyD a fallback = fallback :=
|
||||
DTreeMap.getKeyD_of_isEmpty
|
||||
|
||||
theorem getKeyD_insert [TransCmp cmp] {k a fallback : α} {v : β} :
|
||||
(t.insert k v).getKeyD a fallback = if cmp k a = .eq then k else t.getKeyD a fallback :=
|
||||
DTreeMap.getKeyD_insert
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_insert_self [TransCmp cmp] {a fallback : α} {b : β} :
|
||||
(t.insert a b).getKeyD a fallback = a :=
|
||||
DTreeMap.getKeyD_insert_self
|
||||
|
||||
theorem getKeyD_eq_fallback_of_contains_eq_false [TransCmp cmp] {a fallback : α} :
|
||||
t.contains a = false → t.getKeyD a fallback = fallback :=
|
||||
DTreeMap.getKeyD_eq_fallback_of_contains_eq_false
|
||||
|
||||
theorem getKeyD_eq_fallback [TransCmp cmp] {a fallback : α} :
|
||||
¬ a ∈ t → t.getKeyD a fallback = fallback :=
|
||||
DTreeMap.getKeyD_eq_fallback
|
||||
|
||||
theorem getKeyD_erase [TransCmp cmp] {k a fallback : α} :
|
||||
(t.erase k).getKeyD a fallback =
|
||||
if cmp k a = .eq then fallback else t.getKeyD a fallback :=
|
||||
DTreeMap.getKeyD_erase
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_erase_self [TransCmp cmp] {k fallback : α} :
|
||||
(t.erase k).getKeyD k fallback = fallback :=
|
||||
DTreeMap.getKeyD_erase_self
|
||||
|
||||
theorem getKey?_eq_some_getKeyD_of_contains [TransCmp cmp] {a fallback : α} :
|
||||
t.contains a = true → t.getKey? a = some (t.getKeyD a fallback) :=
|
||||
DTreeMap.getKey?_eq_some_getKeyD_of_contains
|
||||
|
||||
theorem getKey?_eq_some_getKeyD [TransCmp cmp] {a fallback : α} :
|
||||
a ∈ t → t.getKey? a = some (t.getKeyD a fallback) :=
|
||||
DTreeMap.getKey?_eq_some_getKeyD
|
||||
|
||||
theorem getKeyD_eq_getD_getKey? [TransCmp cmp] {a fallback : α} :
|
||||
t.getKeyD a fallback = (t.getKey? a).getD fallback :=
|
||||
DTreeMap.getKeyD_eq_getD_getKey?
|
||||
|
||||
theorem getKey_eq_getKeyD [TransCmp cmp] {a fallback : α} {h} :
|
||||
t.getKey a h = t.getKeyD a fallback :=
|
||||
DTreeMap.getKey_eq_getKeyD
|
||||
|
||||
theorem getKey!_eq_getKeyD_default [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.getKey! a = t.getKeyD a default :=
|
||||
DTreeMap.getKey!_eq_getKeyD_default
|
||||
|
||||
@[simp]
|
||||
theorem isEmpty_insertIfNew [TransCmp cmp] {k : α} {v : β} :
|
||||
(t.insertIfNew k v).isEmpty = false :=
|
||||
DTreeMap.isEmpty_insertIfNew
|
||||
|
||||
@[simp]
|
||||
theorem contains_insertIfNew [TransCmp cmp] {k a : α} {v : β} :
|
||||
(t.insertIfNew k v).contains a = (cmp k a == .eq || t.contains a) :=
|
||||
DTreeMap.contains_insertIfNew
|
||||
|
||||
@[simp]
|
||||
theorem mem_insertIfNew [TransCmp cmp] {k a : α} {v : β} :
|
||||
a ∈ t.insertIfNew k v ↔ cmp k a = .eq ∨ a ∈ t :=
|
||||
DTreeMap.mem_insertIfNew
|
||||
|
||||
@[simp]
|
||||
theorem contains_insertIfNew_self [TransCmp cmp] {k : α} {v : β} :
|
||||
(t.insertIfNew k v).contains k :=
|
||||
DTreeMap.contains_insertIfNew_self
|
||||
|
||||
@[simp]
|
||||
theorem mem_insertIfNew_self [TransCmp cmp] {k : α} {v : β} :
|
||||
k ∈ t.insertIfNew k v :=
|
||||
DTreeMap.mem_insertIfNew_self
|
||||
|
||||
theorem contains_of_contains_insertIfNew [TransCmp cmp] {k a : α} {v : β} :
|
||||
(t.insertIfNew k v).contains a → cmp k a ≠ .eq → t.contains a :=
|
||||
DTreeMap.contains_of_contains_insertIfNew
|
||||
|
||||
theorem mem_of_mem_insertIfNew [TransCmp cmp] {k a : α} {v : β} :
|
||||
a ∈ t.insertIfNew k v → cmp k a ≠ .eq → a ∈ t :=
|
||||
DTreeMap.contains_of_contains_insertIfNew
|
||||
|
||||
/-- This is a restatement of `mem_of_mem_insertIfNew` that is written to exactly match the
|
||||
proof obligation in the statement of `get_insertIfNew`. -/
|
||||
theorem mem_of_mem_insertIfNew' [TransCmp cmp] {k a : α} {v : β} :
|
||||
a ∈ (t.insertIfNew k v) → ¬ (cmp k a = .eq ∧ ¬ k ∈ t) → a ∈ t :=
|
||||
DTreeMap.mem_of_mem_insertIfNew'
|
||||
|
||||
theorem size_insertIfNew [TransCmp cmp] {k : α} {v : β} :
|
||||
(t.insertIfNew k v).size = if k ∈ t then t.size else t.size + 1 :=
|
||||
DTreeMap.size_insertIfNew
|
||||
|
||||
theorem size_le_size_insertIfNew [TransCmp cmp] {k : α} {v : β} :
|
||||
t.size ≤ (t.insertIfNew k v).size :=
|
||||
DTreeMap.size_le_size_insertIfNew
|
||||
|
||||
theorem size_insertIfNew_le [TransCmp cmp] {k : α} {v : β} :
|
||||
(t.insertIfNew k v).size ≤ t.size + 1 :=
|
||||
DTreeMap.size_insertIfNew_le
|
||||
|
||||
theorem getElem?_insertIfNew [TransCmp cmp] {k a : α} {v : β} :
|
||||
(t.insertIfNew k v)[a]? =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then some v else t[a]? :=
|
||||
DTreeMap.Const.get?_insertIfNew
|
||||
|
||||
theorem getElem_insertIfNew [TransCmp cmp] {k a : α} {v : β} {h₁} :
|
||||
(t.insertIfNew k v)[a]'h₁ =
|
||||
if h₂ : cmp k a = .eq ∧ ¬ k ∈ t then v else t[a]'(mem_of_mem_insertIfNew' h₁ h₂) :=
|
||||
DTreeMap.Const.get_insertIfNew
|
||||
|
||||
theorem getElem!_insertIfNew [TransCmp cmp] [Inhabited β] {k a : α} {v : β} :
|
||||
(t.insertIfNew k v)[a]! = if cmp k a = .eq ∧ ¬ k ∈ t then v else t[a]! :=
|
||||
DTreeMap.Const.get!_insertIfNew
|
||||
|
||||
theorem getD_insertIfNew [TransCmp cmp] {k a : α} {fallback v : β} :
|
||||
getD (t.insertIfNew k v) a fallback =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then v else getD t a fallback :=
|
||||
DTreeMap.Const.getD_insertIfNew
|
||||
|
||||
theorem getKey?_insertIfNew [TransCmp cmp] {k a : α} {v : β} :
|
||||
(t.insertIfNew k v).getKey? a =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then some k else t.getKey? a :=
|
||||
DTreeMap.getKey?_insertIfNew
|
||||
|
||||
theorem getKey_insertIfNew [TransCmp cmp] {k a : α} {v : β} {h₁} :
|
||||
(t.insertIfNew k v).getKey a h₁ =
|
||||
if h₂ : cmp k a = .eq ∧ ¬ k ∈ t then k
|
||||
else t.getKey a (mem_of_mem_insertIfNew' h₁ h₂) :=
|
||||
DTreeMap.getKey_insertIfNew
|
||||
|
||||
theorem getKey!_insertIfNew [TransCmp cmp] [Inhabited α] {k a : α}
|
||||
{v : β} :
|
||||
(t.insertIfNew k v).getKey! a =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then k else t.getKey! a :=
|
||||
DTreeMap.getKey!_insertIfNew
|
||||
|
||||
theorem getKeyD_insertIfNew [TransCmp cmp] {k a fallback : α}
|
||||
{v : β} :
|
||||
(t.insertIfNew k v).getKeyD a fallback =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then k else t.getKeyD a fallback :=
|
||||
DTreeMap.getKeyD_insertIfNew
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_fst [TransCmp cmp] {k : α} {v : β} :
|
||||
(getThenInsertIfNew? t k v).1 = get? t k :=
|
||||
DTreeMap.Const.getThenInsertIfNew?_fst
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_snd [TransCmp cmp] {k : α} {v : β} :
|
||||
(getThenInsertIfNew? t k v).2 = t.insertIfNew k v :=
|
||||
ext <| DTreeMap.Const.getThenInsertIfNew?_snd
|
||||
|
||||
end Std.TreeMap
|
||||
|
||||
@@ -45,11 +45,6 @@ theorem contains_congr [TransCmp cmp] (h : t.WF) {k k' : α} (hab : cmp k k' = .
|
||||
theorem mem_congr [TransCmp cmp] (h : t.WF) {k k' : α} (hab : cmp k k' = .eq) : k ∈ t ↔ k' ∈ t :=
|
||||
DTreeMap.Raw.mem_congr h hab
|
||||
|
||||
@[simp]
|
||||
theorem isEmpty_insertIfNew [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
(t.insertIfNew k v).isEmpty = false :=
|
||||
DTreeMap.Raw.isEmpty_insertIfNew h
|
||||
|
||||
@[simp]
|
||||
theorem contains_emptyc {k : α} : (∅ : Raw α β cmp).contains k = false :=
|
||||
DTreeMap.Raw.contains_emptyc
|
||||
@@ -139,7 +134,7 @@ theorem size_insert_le [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
|
||||
@[simp]
|
||||
theorem erase_emptyc {k : α} :
|
||||
(empty : Raw α β cmp).erase k = empty :=
|
||||
(∅ : Raw α β cmp).erase k = ∅ :=
|
||||
ext <| DTreeMap.Raw.erase_emptyc
|
||||
|
||||
@[simp]
|
||||
@@ -197,44 +192,6 @@ theorem containsThenInsertIfNew_snd [TransCmp cmp] (h : t.WF) {k : α} {v : β}
|
||||
(t.containsThenInsertIfNew k v).2 = t.insertIfNew k v :=
|
||||
ext <| DTreeMap.Raw.containsThenInsertIfNew_snd h
|
||||
|
||||
@[simp]
|
||||
theorem contains_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} :
|
||||
(t.insertIfNew k v).contains a = (cmp k a == .eq || t.contains a) :=
|
||||
DTreeMap.Raw.contains_insertIfNew h
|
||||
|
||||
@[simp]
|
||||
theorem mem_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} :
|
||||
a ∈ t.insertIfNew k v ↔ cmp k a = .eq ∨ a ∈ t :=
|
||||
DTreeMap.Raw.mem_insertIfNew h
|
||||
|
||||
theorem contains_insertIfNew_self [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
(t.insertIfNew k v).contains k :=
|
||||
DTreeMap.Raw.contains_insertIfNew_self h
|
||||
|
||||
theorem mem_insertIfNew_self [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
k ∈ t.insertIfNew k v :=
|
||||
DTreeMap.Raw.mem_insertIfNew_self h
|
||||
|
||||
theorem contains_of_contains_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} :
|
||||
(t.insertIfNew k v).contains a → cmp k a ≠ .eq → t.contains a :=
|
||||
DTreeMap.Raw.contains_of_contains_insertIfNew h
|
||||
|
||||
theorem mem_of_mem_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} :
|
||||
a ∈ t.insertIfNew k v → cmp k a ≠ .eq → a ∈ t :=
|
||||
DTreeMap.Raw.contains_of_contains_insertIfNew h
|
||||
|
||||
theorem size_insertIfNew [TransCmp cmp] {k : α} (h : t.WF) {v : β} :
|
||||
(t.insertIfNew k v).size = if k ∈ t then t.size else t.size + 1 :=
|
||||
DTreeMap.Raw.size_insertIfNew h
|
||||
|
||||
theorem size_le_size_insertIfNew [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
t.size ≤ (t.insertIfNew k v).size :=
|
||||
DTreeMap.Raw.size_le_size_insertIfNew h
|
||||
|
||||
theorem size_insertIfNew_le [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
(t.insertIfNew k v).size ≤ t.size + 1 :=
|
||||
DTreeMap.Raw.size_insertIfNew_le h
|
||||
|
||||
@[simp] theorem get_eq_getElem {a : α} {h} : get t a h = t[a]'h := rfl
|
||||
@[simp] theorem get?_eq_getElem? {a : α} : get? t a = t[a]? := rfl
|
||||
@[simp] theorem get!_eq_getElem! [Inhabited β] {a : α} : get! t a = t[a]! := rfl
|
||||
@@ -286,4 +243,422 @@ theorem getElem?_congr [TransCmp cmp] (h : t.WF) {a b : α} (hab : cmp a b = .eq
|
||||
t[a]? = t[b]? :=
|
||||
DTreeMap.Raw.Const.get?_congr h hab
|
||||
|
||||
theorem getElem_insert [TransCmp cmp] (h : t.WF) {k a : α} {v : β} {h₁} :
|
||||
(t.insert k v)[a]'h₁ =
|
||||
if h₂ : cmp k a = .eq then v
|
||||
else t[a]'(mem_of_mem_insert h h₁ h₂) :=
|
||||
DTreeMap.Raw.Const.get_insert h
|
||||
|
||||
@[simp]
|
||||
theorem getElem_insert_self [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
(t.insert k v)[k]'(mem_insert_self h) = v :=
|
||||
DTreeMap.Raw.Const.get_insert_self h
|
||||
|
||||
@[simp]
|
||||
theorem getElem_erase [TransCmp cmp] (h : t.WF) {k a : α} {h'} :
|
||||
(t.erase k)[a]'h' = t[a]'(mem_of_mem_erase h h') :=
|
||||
DTreeMap.Raw.Const.get_erase h
|
||||
|
||||
theorem getElem?_eq_some_getElem [TransCmp cmp] (h : t.WF) {a : α} {h'} :
|
||||
t[a]? = some (t[a]'h') :=
|
||||
DTreeMap.Raw.Const.get?_eq_some_get h
|
||||
|
||||
theorem getElem_congr [TransCmp cmp] (h : t.WF) {a b : α} (hab : cmp a b = .eq) {h'} :
|
||||
t[a]'h' = t[b]'((mem_congr h hab).mp h') :=
|
||||
DTreeMap.Raw.Const.get_congr h hab
|
||||
|
||||
@[simp]
|
||||
theorem getElem!_emptyc [TransCmp cmp] [Inhabited β] {a : α} :
|
||||
(∅ : Raw α β cmp)[a]! = default :=
|
||||
DTreeMap.Raw.Const.get!_emptyc (cmp := cmp) (a := a)
|
||||
|
||||
theorem getElem!_of_isEmpty [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
t.isEmpty = true → t[a]! = default :=
|
||||
DTreeMap.Raw.Const.get!_of_isEmpty h
|
||||
|
||||
theorem getElem!_insert [TransCmp cmp] [Inhabited β] (h : t.WF) {k a : α} {v : β} :
|
||||
(t.insert k v)[a]! = if cmp k a = .eq then v else t[a]! :=
|
||||
DTreeMap.Raw.Const.get!_insert h
|
||||
|
||||
@[simp]
|
||||
theorem getElem!_insert_self [TransCmp cmp] [Inhabited β] (h : t.WF) {k : α}
|
||||
{v : β} : (t.insert k v)[k]! = v :=
|
||||
DTreeMap.Raw.Const.get!_insert_self h
|
||||
|
||||
theorem getElem!_eq_default_of_contains_eq_false [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
t.contains a = false → t[a]! = default :=
|
||||
DTreeMap.Raw.Const.get!_eq_default_of_contains_eq_false h
|
||||
|
||||
theorem getElem!_eq_default [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
¬ a ∈ t → t[a]! = default :=
|
||||
DTreeMap.Raw.Const.get!_eq_default h
|
||||
|
||||
theorem getElem!_erase [TransCmp cmp] [Inhabited β] (h : t.WF) {k a : α} :
|
||||
(t.erase k)[a]! = if cmp k a = .eq then default else t[a]! :=
|
||||
DTreeMap.Raw.Const.get!_erase h
|
||||
|
||||
@[simp]
|
||||
theorem getElem!_erase_self [TransCmp cmp] [Inhabited β] (h : t.WF) {k : α} :
|
||||
(t.erase k)[k]! = default :=
|
||||
DTreeMap.Raw.Const.get!_erase_self h
|
||||
|
||||
theorem getElem?_eq_some_getElem!_of_contains [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
t.contains a = true → t[a]? = some t[a]! :=
|
||||
DTreeMap.Raw.Const.get?_eq_some_get! h
|
||||
|
||||
theorem getElem?_eq_some_getElem! [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
a ∈ t → t[a]? = some t[a]! :=
|
||||
DTreeMap.Raw.Const.get?_eq_some_get! h
|
||||
|
||||
theorem getElem!_eq_getElem!_getElem? [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
t[a]! = t[a]?.get! :=
|
||||
DTreeMap.Raw.Const.get!_eq_get!_get? h
|
||||
|
||||
theorem getElem_eq_getElem! [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} {h'} :
|
||||
t[a]'h' = t[a]! :=
|
||||
DTreeMap.Raw.Const.get_eq_get! h
|
||||
|
||||
theorem getElem!_congr [TransCmp cmp] [Inhabited β] (h : t.WF) {a b : α}
|
||||
(hab : cmp a b = .eq) : t[a]! = t[b]! :=
|
||||
DTreeMap.Raw.Const.get!_congr h hab
|
||||
|
||||
@[simp]
|
||||
theorem getD_emptyc [TransCmp cmp] {a : α} {fallback : β} :
|
||||
getD (∅ : Raw α β cmp) a fallback = fallback :=
|
||||
DTreeMap.Raw.Const.getD_emptyc
|
||||
|
||||
theorem getD_of_isEmpty [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} :
|
||||
t.isEmpty = true → getD t a fallback = fallback :=
|
||||
DTreeMap.Raw.Const.getD_of_isEmpty h
|
||||
|
||||
theorem getD_insert [TransCmp cmp] (h : t.WF) {k a : α} {fallback v : β} :
|
||||
getD (t.insert k v) a fallback = if cmp k a = .eq then v else getD t a fallback :=
|
||||
DTreeMap.Raw.Const.getD_insert h
|
||||
|
||||
@[simp]
|
||||
theorem getD_insert_self [TransCmp cmp] (h : t.WF) {k : α} {fallback v : β} :
|
||||
getD (t.insert k v) k fallback = v :=
|
||||
DTreeMap.Raw.Const.getD_insert_self h
|
||||
|
||||
theorem getD_eq_fallback_of_contains_eq_false [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} :
|
||||
t.contains a = false → getD t a fallback = fallback :=
|
||||
DTreeMap.Raw.Const.getD_eq_fallback_of_contains_eq_false h
|
||||
|
||||
theorem getD_eq_fallback [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} :
|
||||
¬ a ∈ t → getD t a fallback = fallback :=
|
||||
DTreeMap.Raw.Const.getD_eq_fallback h
|
||||
|
||||
theorem getD_erase [TransCmp cmp] (h : t.WF) {k a : α} {fallback : β} :
|
||||
getD (t.erase k) a fallback = if cmp k a = .eq then
|
||||
fallback
|
||||
else
|
||||
getD t a fallback :=
|
||||
DTreeMap.Raw.Const.getD_erase h
|
||||
|
||||
@[simp]
|
||||
theorem getD_erase_self [TransCmp cmp] (h : t.WF) {k : α} {fallback : β} :
|
||||
getD (t.erase k) k fallback = fallback :=
|
||||
DTreeMap.Raw.Const.getD_erase_self h
|
||||
|
||||
theorem getElem?_eq_some_getD_of_contains [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} :
|
||||
t.contains a = true → get? t a = some (getD t a fallback) :=
|
||||
DTreeMap.Raw.Const.get?_eq_some_getD_of_contains h
|
||||
|
||||
theorem getElem?_eq_some_getD [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} :
|
||||
a ∈ t → t[a]? = some (getD t a fallback) :=
|
||||
DTreeMap.Raw.Const.get?_eq_some_getD h
|
||||
|
||||
theorem getD_eq_getD_getElem? [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} :
|
||||
getD t a fallback = t[a]?.getD fallback :=
|
||||
DTreeMap.Raw.Const.getD_eq_getD_get? h
|
||||
|
||||
theorem getElem_eq_getD [TransCmp cmp] (h : t.WF) {a : α} {fallback : β} {h'} :
|
||||
t[a]'h' = getD t a fallback :=
|
||||
DTreeMap.Raw.Const.get_eq_getD h
|
||||
|
||||
theorem getElem!_eq_getD_default [TransCmp cmp] [Inhabited β] (h : t.WF) {a : α} :
|
||||
t[a]! = getD t a default :=
|
||||
DTreeMap.Raw.Const.get!_eq_getD_default h
|
||||
|
||||
theorem getD_congr [TransCmp cmp] (h : t.WF) {a b : α} {fallback : β}
|
||||
(hab : cmp a b = .eq) : getD t a fallback = getD t b fallback :=
|
||||
DTreeMap.Raw.Const.getD_congr h hab
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_emptyc {a : α} : (∅ : Raw α β cmp).getKey? a = none :=
|
||||
DTreeMap.Raw.getKey?_emptyc
|
||||
|
||||
theorem getKey?_of_isEmpty [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
t.isEmpty = true → t.getKey? a = none :=
|
||||
DTreeMap.Raw.getKey?_of_isEmpty h
|
||||
|
||||
theorem getKey?_insert [TransCmp cmp] (h : t.WF) {a k : α} {v : β} :
|
||||
(t.insert k v).getKey? a = if cmp k a = .eq then some k else t.getKey? a :=
|
||||
DTreeMap.Raw.getKey?_insert h
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_insert_self [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
(t.insert k v).getKey? k = some k :=
|
||||
DTreeMap.Raw.getKey?_insert_self h
|
||||
|
||||
theorem contains_eq_isSome_getKey? [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
t.contains a = (t.getKey? a).isSome :=
|
||||
DTreeMap.Raw.contains_eq_isSome_getKey? h
|
||||
|
||||
theorem mem_iff_isSome_getKey? [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
a ∈ t ↔ (t.getKey? a).isSome :=
|
||||
DTreeMap.Raw.mem_iff_isSome_getKey? h
|
||||
|
||||
theorem getKey?_eq_none_of_contains_eq_false [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
t.contains a = false → t.getKey? a = none :=
|
||||
DTreeMap.Raw.getKey?_eq_none_of_contains_eq_false h
|
||||
|
||||
theorem getKey?_eq_none [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
¬ a ∈ t → t.getKey? a = none :=
|
||||
DTreeMap.Raw.getKey?_eq_none h
|
||||
|
||||
theorem getKey?_erase [TransCmp cmp] (h : t.WF) {k a : α} :
|
||||
(t.erase k).getKey? a = if cmp k a = .eq then none else t.getKey? a :=
|
||||
DTreeMap.Raw.getKey?_erase h
|
||||
|
||||
@[simp]
|
||||
theorem getKey?_erase_self [TransCmp cmp] (h : t.WF) {k : α} :
|
||||
(t.erase k).getKey? k = none :=
|
||||
DTreeMap.Raw.getKey?_erase_self h
|
||||
|
||||
theorem getKey_insert [TransCmp cmp] (h : t.WF) {k a : α} {v : β} {h₁} :
|
||||
(t.insert k v).getKey a h₁ =
|
||||
if h₂ : cmp k a = .eq then k else t.getKey a (mem_of_mem_insert h h₁ h₂) :=
|
||||
DTreeMap.Raw.getKey_insert h
|
||||
|
||||
@[simp]
|
||||
theorem getKey_insert_self [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
(t.insert k v).getKey k (mem_insert_self h) = k :=
|
||||
DTreeMap.Raw.getKey_insert_self h
|
||||
|
||||
@[simp]
|
||||
theorem getKey_erase [TransCmp cmp] (h : t.WF) {k a : α} {h'} :
|
||||
(t.erase k).getKey a h' = t.getKey a (mem_of_mem_erase h h') :=
|
||||
DTreeMap.Raw.getKey_erase h
|
||||
|
||||
theorem getKey?_eq_some_getKey [TransCmp cmp] (h : t.WF) {a : α} {h'} :
|
||||
t.getKey? a = some (t.getKey a h') :=
|
||||
DTreeMap.Raw.getKey?_eq_some_getKey h
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_emptyc {a : α} [Inhabited α] :
|
||||
(∅ : Raw α β cmp).getKey! a = default :=
|
||||
DTreeMap.Raw.getKey!_emptyc
|
||||
|
||||
theorem getKey!_of_isEmpty [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.isEmpty = true → t.getKey! a = default :=
|
||||
DTreeMap.Raw.getKey!_of_isEmpty h
|
||||
|
||||
theorem getKey!_insert [TransCmp cmp] [Inhabited α] (h : t.WF) {k a : α}
|
||||
{v : β} : (t.insert k v).getKey! a = if cmp k a = .eq then k else t.getKey! a :=
|
||||
DTreeMap.Raw.getKey!_insert h
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_insert_self [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α}
|
||||
{b : β} : (t.insert a b).getKey! a = a :=
|
||||
DTreeMap.Raw.getKey!_insert_self h
|
||||
|
||||
theorem getKey!_eq_default_of_contains_eq_false [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.contains a = false → t.getKey! a = default :=
|
||||
DTreeMap.Raw.getKey!_eq_default_of_contains_eq_false h
|
||||
|
||||
theorem getKey!_eq_default [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
¬ a ∈ t → t.getKey! a = default :=
|
||||
DTreeMap.Raw.getKey!_eq_default h
|
||||
|
||||
theorem getKey!_erase [TransCmp cmp] [Inhabited α] (h : t.WF) {k a : α} :
|
||||
(t.erase k).getKey! a = if cmp k a = .eq then default else t.getKey! a :=
|
||||
DTreeMap.Raw.getKey!_erase h
|
||||
|
||||
@[simp]
|
||||
theorem getKey!_erase_self [TransCmp cmp] [Inhabited α] (h : t.WF) {k : α} :
|
||||
(t.erase k).getKey! k = default :=
|
||||
DTreeMap.Raw.getKey!_erase_self h
|
||||
|
||||
theorem getKey?_eq_some_getKey!_of_contains [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.contains a = true → t.getKey? a = some (t.getKey! a) :=
|
||||
DTreeMap.Raw.getKey?_eq_some_getKey!_of_contains h
|
||||
|
||||
theorem getKey?_eq_some_getKey! [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
a ∈ t → t.getKey? a = some (t.getKey! a) :=
|
||||
DTreeMap.Raw.getKey?_eq_some_getKey! h
|
||||
|
||||
theorem getKey!_eq_get!_getKey? [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.getKey! a = (t.getKey? a).get! :=
|
||||
DTreeMap.Raw.getKey!_eq_get!_getKey? h
|
||||
|
||||
theorem getKey_eq_getKey! [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} {h'} :
|
||||
t.getKey a h' = t.getKey! a :=
|
||||
DTreeMap.Raw.getKey_eq_getKey! h
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_emptyc {a : α} {fallback : α} :
|
||||
(∅ : Raw α β cmp).getKeyD a fallback = fallback :=
|
||||
DTreeMap.Raw.getKeyD_emptyc
|
||||
|
||||
theorem getKeyD_of_isEmpty [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
t.isEmpty = true → t.getKeyD a fallback = fallback :=
|
||||
DTreeMap.Raw.getKeyD_of_isEmpty h
|
||||
|
||||
theorem getKeyD_insert [TransCmp cmp] (h : t.WF) {k a fallback : α} {v : β} :
|
||||
(t.insert k v).getKeyD a fallback =
|
||||
if cmp k a = .eq then k else t.getKeyD a fallback :=
|
||||
DTreeMap.Raw.getKeyD_insert h
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_insert_self [TransCmp cmp] (h : t.WF) {a fallback : α} {b : β} :
|
||||
(t.insert a b).getKeyD a fallback = a :=
|
||||
DTreeMap.Raw.getKeyD_insert_self h
|
||||
|
||||
theorem getKeyD_eq_fallback_of_contains_eq_false [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
t.contains a = false → t.getKeyD a fallback = fallback :=
|
||||
DTreeMap.Raw.getKeyD_eq_fallback_of_contains_eq_false h
|
||||
|
||||
theorem getKeyD_eq_fallback [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
¬ a ∈ t → t.getKeyD a fallback = fallback :=
|
||||
DTreeMap.Raw.getKeyD_eq_fallback h
|
||||
|
||||
theorem getKeyD_erase [TransCmp cmp] (h : t.WF) {k a fallback : α} :
|
||||
(t.erase k).getKeyD a fallback =
|
||||
if cmp k a = .eq then fallback else t.getKeyD a fallback :=
|
||||
DTreeMap.Raw.getKeyD_erase h
|
||||
|
||||
@[simp]
|
||||
theorem getKeyD_erase_self [TransCmp cmp] (h : t.WF) {k fallback : α} :
|
||||
(t.erase k).getKeyD k fallback = fallback :=
|
||||
DTreeMap.Raw.getKeyD_erase_self h
|
||||
|
||||
theorem getKey?_eq_some_getKeyD_of_contains [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
t.contains a = true → t.getKey? a = some (t.getKeyD a fallback) :=
|
||||
DTreeMap.Raw.getKey?_eq_some_getKeyD_of_contains h
|
||||
|
||||
theorem getKey?_eq_some_getKeyD [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
a ∈ t → t.getKey? a = some (t.getKeyD a fallback) :=
|
||||
DTreeMap.Raw.getKey?_eq_some_getKeyD h
|
||||
|
||||
theorem getKeyD_eq_getD_getKey? [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
t.getKeyD a fallback = (t.getKey? a).getD fallback :=
|
||||
DTreeMap.Raw.getKeyD_eq_getD_getKey? h
|
||||
|
||||
theorem getKey_eq_getKeyD [TransCmp cmp] (h : t.WF) {a fallback : α} {h'} :
|
||||
t.getKey a h' = t.getKeyD a fallback :=
|
||||
DTreeMap.Raw.getKey_eq_getKeyD h
|
||||
|
||||
theorem getKey!_eq_getKeyD_default [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.getKey! a = t.getKeyD a default :=
|
||||
DTreeMap.Raw.getKey!_eq_getKeyD_default h
|
||||
|
||||
@[simp]
|
||||
theorem isEmpty_insertIfNew [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
(t.insertIfNew k v).isEmpty = false :=
|
||||
DTreeMap.Raw.isEmpty_insertIfNew h
|
||||
|
||||
@[simp]
|
||||
theorem contains_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} :
|
||||
(t.insertIfNew k v).contains a = (cmp k a == .eq || t.contains a) :=
|
||||
DTreeMap.Raw.contains_insertIfNew h
|
||||
|
||||
@[simp]
|
||||
theorem mem_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} :
|
||||
a ∈ t.insertIfNew k v ↔ cmp k a = .eq ∨ a ∈ t :=
|
||||
DTreeMap.Raw.mem_insertIfNew h
|
||||
|
||||
theorem contains_insertIfNew_self [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
(t.insertIfNew k v).contains k :=
|
||||
DTreeMap.Raw.contains_insertIfNew_self h
|
||||
|
||||
theorem mem_insertIfNew_self [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
k ∈ t.insertIfNew k v :=
|
||||
DTreeMap.Raw.mem_insertIfNew_self h
|
||||
|
||||
theorem contains_of_contains_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} :
|
||||
(t.insertIfNew k v).contains a → cmp k a ≠ .eq → t.contains a :=
|
||||
DTreeMap.Raw.contains_of_contains_insertIfNew h
|
||||
|
||||
theorem mem_of_mem_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} :
|
||||
a ∈ t.insertIfNew k v → cmp k a ≠ .eq → a ∈ t :=
|
||||
DTreeMap.Raw.contains_of_contains_insertIfNew h
|
||||
|
||||
/-- This is a restatement of `mem_of_mem_insertIfNew` that is written to exactly match the
|
||||
proof obligation in the statement of `get_insertIfNew`. -/
|
||||
theorem mem_of_mem_insertIfNew' [TransCmp cmp] (h : t.WF) {k a : α}
|
||||
{v : β} :
|
||||
a ∈ (t.insertIfNew k v) → ¬ (cmp k a = .eq ∧ ¬ k ∈ t) → a ∈ t :=
|
||||
DTreeMap.Raw.mem_of_mem_insertIfNew' h
|
||||
|
||||
theorem size_insertIfNew [TransCmp cmp] {k : α} (h : t.WF) {v : β} :
|
||||
(t.insertIfNew k v).size = if k ∈ t then t.size else t.size + 1 :=
|
||||
DTreeMap.Raw.size_insertIfNew h
|
||||
|
||||
theorem size_le_size_insertIfNew [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
t.size ≤ (t.insertIfNew k v).size :=
|
||||
DTreeMap.Raw.size_le_size_insertIfNew h
|
||||
|
||||
theorem size_insertIfNew_le [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
(t.insertIfNew k v).size ≤ t.size + 1 :=
|
||||
DTreeMap.Raw.size_insertIfNew_le h
|
||||
|
||||
theorem getElem?_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} :
|
||||
(t.insertIfNew k v)[a]? =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then
|
||||
some v
|
||||
else
|
||||
t[a]? :=
|
||||
DTreeMap.Raw.Const.get?_insertIfNew h
|
||||
|
||||
theorem getElem_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} {h₁} :
|
||||
(t.insertIfNew k v)[a]'h₁ =
|
||||
if h₂ : cmp k a = .eq ∧ ¬ k ∈ t then
|
||||
v
|
||||
else
|
||||
t[a]'(mem_of_mem_insertIfNew' h h₁ h₂) :=
|
||||
DTreeMap.Raw.Const.get_insertIfNew h
|
||||
|
||||
theorem getElem!_insertIfNew [TransCmp cmp] [Inhabited β] (h : t.WF) {k a : α} {v : β} :
|
||||
(t.insertIfNew k v)[a]! = if cmp k a = .eq ∧ ¬ k ∈ t then v else t[a]! :=
|
||||
DTreeMap.Raw.Const.get!_insertIfNew h
|
||||
|
||||
theorem getD_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {fallback v : β} :
|
||||
getD (t.insertIfNew k v) a fallback =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then v else getD t a fallback :=
|
||||
DTreeMap.Raw.Const.getD_insertIfNew h
|
||||
|
||||
theorem getKey?_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} :
|
||||
(t.insertIfNew k v).getKey? a =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then some k else t.getKey? a :=
|
||||
DTreeMap.Raw.getKey?_insertIfNew h
|
||||
|
||||
theorem getKey_insertIfNew [TransCmp cmp] (h : t.WF) {k a : α} {v : β} {h₁} :
|
||||
(t.insertIfNew k v).getKey a h₁ =
|
||||
if h₂ : cmp k a = .eq ∧ ¬ k ∈ t then k
|
||||
else t.getKey a (mem_of_mem_insertIfNew' h h₁ h₂) :=
|
||||
DTreeMap.Raw.getKey_insertIfNew h
|
||||
|
||||
theorem getKey!_insertIfNew [TransCmp cmp] [Inhabited α] (h : t.WF) {k a : α}
|
||||
{v : β} :
|
||||
(t.insertIfNew k v).getKey! a =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then k else t.getKey! a :=
|
||||
DTreeMap.Raw.getKey!_insertIfNew h
|
||||
|
||||
theorem getKeyD_insertIfNew [TransCmp cmp] (h : t.WF) {k a fallback : α}
|
||||
{v : β} :
|
||||
(t.insertIfNew k v).getKeyD a fallback =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then k else t.getKeyD a fallback :=
|
||||
DTreeMap.Raw.getKeyD_insertIfNew h
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_fst [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
(getThenInsertIfNew? t k v).1 = get? t k :=
|
||||
DTreeMap.Raw.Const.getThenInsertIfNew?_fst h
|
||||
|
||||
@[simp]
|
||||
theorem getThenInsertIfNew?_snd [TransCmp cmp] (h : t.WF) {k : α} {v : β} :
|
||||
(getThenInsertIfNew? t k v).2 = t.insertIfNew k v :=
|
||||
ext <| DTreeMap.Raw.Const.getThenInsertIfNew?_snd h
|
||||
|
||||
end Std.TreeMap.Raw
|
||||
|
||||
@@ -112,6 +112,12 @@ theorem mem_of_mem_insert [TransCmp cmp] {k a : α} :
|
||||
a ∈ t.insert k → cmp k a ≠ .eq → a ∈ t :=
|
||||
TreeMap.mem_of_mem_insertIfNew
|
||||
|
||||
/-- This is a restatement of `mem_of_mem_insert` that is written to exactly match the
|
||||
proof obligation in the statement of `get_insert`. -/
|
||||
theorem mem_of_mem_insert' [TransCmp cmp] {k a : α} :
|
||||
a ∈ t.insert k → ¬ (cmp k a = .eq ∧ ¬ k ∈ t) → a ∈ t :=
|
||||
TreeMap.mem_of_mem_insertIfNew'
|
||||
|
||||
@[simp]
|
||||
theorem size_emptyc : (∅ : TreeSet α cmp).size = 0 :=
|
||||
TreeMap.size_emptyc
|
||||
@@ -134,7 +140,7 @@ theorem size_insert_le [TransCmp cmp] {k : α} :
|
||||
|
||||
@[simp]
|
||||
theorem erase_emptyc {k : α} :
|
||||
(empty : TreeSet α cmp).erase k = empty :=
|
||||
(∅ : TreeSet α cmp).erase k = ∅ :=
|
||||
ext <| TreeMap.erase_emptyc
|
||||
|
||||
@[simp]
|
||||
@@ -172,6 +178,152 @@ theorem size_le_size_erase [TransCmp cmp] {k : α} :
|
||||
t.size ≤ (t.erase k).size + 1 :=
|
||||
TreeMap.size_le_size_erase
|
||||
|
||||
@[simp]
|
||||
theorem get?_emptyc {a : α} : (∅ : TreeSet α cmp).get? a = none :=
|
||||
TreeMap.getKey?_emptyc
|
||||
|
||||
theorem get?_of_isEmpty [TransCmp cmp] {a : α} :
|
||||
t.isEmpty = true → t.get? a = none :=
|
||||
TreeMap.getKey?_of_isEmpty
|
||||
|
||||
theorem get?_insert [TransCmp cmp] {k a : α} :
|
||||
(t.insert k).get? a = if cmp k a = .eq ∧ ¬k ∈ t then some k else t.get? a :=
|
||||
TreeMap.getKey?_insertIfNew
|
||||
|
||||
theorem contains_eq_isSome_get? [TransCmp cmp] {a : α} :
|
||||
t.contains a = (t.get? a).isSome :=
|
||||
TreeMap.contains_eq_isSome_getKey?
|
||||
|
||||
theorem get?_eq_none_of_contains_eq_false [TransCmp cmp] {a : α} :
|
||||
t.contains a = false → t.get? a = none :=
|
||||
TreeMap.getKey?_eq_none_of_contains_eq_false
|
||||
|
||||
theorem get?_eq_none [TransCmp cmp] {a : α} :
|
||||
¬ a ∈ t → t.get? a = none :=
|
||||
TreeMap.getKey?_eq_none
|
||||
|
||||
theorem get?_erase [TransCmp cmp] {k a : α} :
|
||||
(t.erase k).get? a = if cmp k a = .eq then none else t.get? a :=
|
||||
TreeMap.getKey?_erase
|
||||
|
||||
@[simp]
|
||||
theorem get?_erase_self [TransCmp cmp] {k : α} :
|
||||
(t.erase k).get? k = none :=
|
||||
TreeMap.getKey?_erase_self
|
||||
|
||||
theorem get_insert [TransCmp cmp] {k a : α} {h₁} :
|
||||
(t.insert k).get a h₁ =
|
||||
if h₂ : cmp k a = .eq ∧ ¬ k ∈ t then k
|
||||
else t.get a (mem_of_mem_insert' h₁ h₂) :=
|
||||
TreeMap.getKey_insertIfNew
|
||||
|
||||
@[simp]
|
||||
theorem get_erase [TransCmp cmp] {k a : α} {h'} :
|
||||
(t.erase k).get a h' = t.get a (mem_of_mem_erase h') :=
|
||||
TreeMap.getKey_erase
|
||||
|
||||
theorem get?_eq_some_get [TransCmp cmp] {a : α} {h'} :
|
||||
t.get? a = some (t.get a h') :=
|
||||
TreeMap.getKey?_eq_some_getKey
|
||||
|
||||
@[simp]
|
||||
theorem get!_emptyc {a : α} [Inhabited α] :
|
||||
(∅ : TreeSet α cmp).get! a = default :=
|
||||
TreeMap.getKey!_emptyc
|
||||
|
||||
theorem get!_of_isEmpty [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.isEmpty = true → t.get! a = default :=
|
||||
TreeMap.getKey!_of_isEmpty
|
||||
|
||||
theorem get!_insert [TransCmp cmp] [Inhabited α] {k a : α} :
|
||||
(t.insert k).get! a = if cmp k a = .eq ∧ ¬ k ∈ t then k else t.get! a :=
|
||||
TreeMap.getKey!_insertIfNew
|
||||
|
||||
theorem get!_eq_default_of_contains_eq_false [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.contains a = false → t.get! a = default :=
|
||||
TreeMap.getKey!_eq_default_of_contains_eq_false
|
||||
|
||||
theorem get!_eq_default [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
¬ a ∈ t → t.get! a = default :=
|
||||
TreeMap.getKey!_eq_default
|
||||
|
||||
theorem get!_erase [TransCmp cmp] [Inhabited α] {k a : α} :
|
||||
(t.erase k).get! a = if cmp k a = .eq then default else t.get! a :=
|
||||
TreeMap.getKey!_erase
|
||||
|
||||
@[simp]
|
||||
theorem get!_erase_self [TransCmp cmp] [Inhabited α] {k : α} :
|
||||
(t.erase k).get! k = default :=
|
||||
TreeMap.getKey!_erase_self
|
||||
|
||||
theorem get?_eq_some_get!_of_contains [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.contains a = true → t.get? a = some (t.get! a) :=
|
||||
TreeMap.getKey?_eq_some_getKey!_of_contains
|
||||
|
||||
theorem get?_eq_some_get! [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
a ∈ t → t.get? a = some (t.get! a) :=
|
||||
TreeMap.getKey?_eq_some_getKey!
|
||||
|
||||
theorem get!_eq_get!_get? [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.get! a = (t.get? a).get! :=
|
||||
TreeMap.getKey!_eq_get!_getKey?
|
||||
|
||||
theorem get_eq_get! [TransCmp cmp] [Inhabited α] {a : α} {h} :
|
||||
t.get a h = t.get! a :=
|
||||
TreeMap.getKey_eq_getKey!
|
||||
|
||||
@[simp]
|
||||
theorem getD_emptyc {a : α} {fallback : α} :
|
||||
(∅ : TreeSet α cmp).getD a fallback = fallback :=
|
||||
TreeMap.getKeyD_emptyc
|
||||
|
||||
theorem getD_of_isEmpty [TransCmp cmp] {a fallback : α} :
|
||||
t.isEmpty = true → t.getD a fallback = fallback :=
|
||||
TreeMap.getKeyD_of_isEmpty
|
||||
|
||||
theorem getD_insert [TransCmp cmp] {k a fallback : α} :
|
||||
(t.insert k).getD a fallback =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then k else t.getD a fallback :=
|
||||
TreeMap.getKeyD_insertIfNew
|
||||
|
||||
theorem getD_eq_fallback_of_contains_eq_false [TransCmp cmp] {a fallback : α} :
|
||||
t.contains a = false → t.getD a fallback = fallback :=
|
||||
TreeMap.getKeyD_eq_fallback_of_contains_eq_false
|
||||
|
||||
theorem getD_eq_fallback [TransCmp cmp] {a fallback : α} :
|
||||
¬ a ∈ t → t.getD a fallback = fallback :=
|
||||
TreeMap.getKeyD_eq_fallback
|
||||
|
||||
theorem getD_erase [TransCmp cmp] {k a fallback : α} :
|
||||
(t.erase k).getD a fallback =
|
||||
if cmp k a = .eq then fallback else t.getD a fallback :=
|
||||
TreeMap.getKeyD_erase
|
||||
|
||||
@[simp]
|
||||
theorem getD_erase_self [TransCmp cmp] {k fallback : α} :
|
||||
(t.erase k).getD k fallback = fallback :=
|
||||
TreeMap.getKeyD_erase_self
|
||||
|
||||
theorem get?_eq_some_getD_of_contains [TransCmp cmp] {a fallback : α} :
|
||||
t.contains a = true → t.get? a = some (t.getD a fallback) :=
|
||||
TreeMap.getKey?_eq_some_getKeyD_of_contains
|
||||
|
||||
theorem get?_eq_some_getD [TransCmp cmp] {a fallback : α} :
|
||||
a ∈ t → t.get? a = some (t.getD a fallback) :=
|
||||
TreeMap.getKey?_eq_some_getKeyD
|
||||
|
||||
theorem getD_eq_getD_get? [TransCmp cmp] {a fallback : α} :
|
||||
t.getD a fallback = (t.get? a).getD fallback :=
|
||||
TreeMap.getKeyD_eq_getD_getKey?
|
||||
|
||||
theorem get_eq_getD [TransCmp cmp] {a fallback : α} {h} :
|
||||
t.get a h = t.getD a fallback :=
|
||||
TreeMap.getKey_eq_getKeyD
|
||||
|
||||
theorem get!_eq_getD_default [TransCmp cmp] [Inhabited α] {a : α} :
|
||||
t.get! a = t.getD a default :=
|
||||
TreeMap.getKey!_eq_getKeyD_default
|
||||
|
||||
@[simp]
|
||||
theorem containsThenInsert_fst [TransCmp cmp] {k : α} :
|
||||
(t.containsThenInsert k).1 = t.contains k :=
|
||||
|
||||
@@ -112,6 +112,12 @@ theorem mem_of_mem_insert [TransCmp cmp] (h : t.WF) {k a : α} :
|
||||
a ∈ t.insert k → cmp k a ≠ .eq → a ∈ t :=
|
||||
TreeMap.Raw.mem_of_mem_insertIfNew h
|
||||
|
||||
/-- This is a restatement of `mem_of_mem_insert` that is written to exactly match the
|
||||
proof obligation in the statement of `get_insert`. -/
|
||||
theorem mem_of_mem_insert' [TransCmp cmp] (h : t.WF) {k a : α} :
|
||||
a ∈ t.insert k → ¬ (cmp k a = .eq ∧ ¬ k ∈ t) → a ∈ t :=
|
||||
TreeMap.Raw.mem_of_mem_insertIfNew' h
|
||||
|
||||
@[simp]
|
||||
theorem size_emptyc : (∅ : Raw α cmp).size = 0 :=
|
||||
TreeMap.Raw.size_emptyc
|
||||
@@ -134,7 +140,7 @@ theorem size_insert_le [TransCmp cmp] (h : t.WF) {k : α} :
|
||||
|
||||
@[simp]
|
||||
theorem erase_emptyc {k : α} :
|
||||
(empty : Raw α cmp).erase k = empty :=
|
||||
(∅ : Raw α cmp).erase k = ∅ :=
|
||||
ext <| TreeMap.Raw.erase_emptyc
|
||||
|
||||
@[simp]
|
||||
@@ -172,6 +178,152 @@ theorem size_le_size_erase [TransCmp cmp] (h : t.WF) {k : α} :
|
||||
t.size ≤ (t.erase k).size + 1 :=
|
||||
TreeMap.Raw.size_le_size_erase h
|
||||
|
||||
@[simp]
|
||||
theorem get?_emptyc {a : α} : (∅ : TreeSet α cmp).get? a = none :=
|
||||
TreeMap.Raw.getKey?_emptyc
|
||||
|
||||
theorem get?_of_isEmpty [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
t.isEmpty = true → t.get? a = none :=
|
||||
TreeMap.Raw.getKey?_of_isEmpty h
|
||||
|
||||
theorem get?_insert [TransCmp cmp] (h : t.WF) {k a : α} :
|
||||
(t.insert k).get? a = if cmp k a = .eq ∧ ¬k ∈ t then some k else t.get? a :=
|
||||
TreeMap.Raw.getKey?_insertIfNew h
|
||||
|
||||
theorem contains_eq_isSome_get? [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
t.contains a = (t.get? a).isSome :=
|
||||
TreeMap.Raw.contains_eq_isSome_getKey? h
|
||||
|
||||
theorem get?_eq_none_of_contains_eq_false [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
t.contains a = false → t.get? a = none :=
|
||||
TreeMap.Raw.getKey?_eq_none_of_contains_eq_false h
|
||||
|
||||
theorem get?_eq_none [TransCmp cmp] (h : t.WF) {a : α} :
|
||||
¬ a ∈ t → t.get? a = none :=
|
||||
TreeMap.Raw.getKey?_eq_none h
|
||||
|
||||
theorem get?_erase [TransCmp cmp] (h : t.WF) {k a : α} :
|
||||
(t.erase k).get? a = if cmp k a = .eq then none else t.get? a :=
|
||||
TreeMap.Raw.getKey?_erase h
|
||||
|
||||
@[simp]
|
||||
theorem get?_erase_self [TransCmp cmp] (h : t.WF) {k : α} :
|
||||
(t.erase k).get? k = none :=
|
||||
TreeMap.Raw.getKey?_erase_self h
|
||||
|
||||
theorem get_insert [TransCmp cmp] (h : t.WF) {k a : α} {h₁} :
|
||||
(t.insert k).get a h₁ =
|
||||
if h₂ : cmp k a = .eq ∧ ¬ k ∈ t then k
|
||||
else t.get a (mem_of_mem_insert' h h₁ h₂) :=
|
||||
TreeMap.Raw.getKey_insertIfNew h
|
||||
|
||||
@[simp]
|
||||
theorem get_erase [TransCmp cmp] (h : t.WF) {k a : α} {h'} :
|
||||
(t.erase k).get a h' = t.get a (mem_of_mem_erase h h') :=
|
||||
TreeMap.Raw.getKey_erase h
|
||||
|
||||
theorem get?_eq_some_get [TransCmp cmp] (h : t.WF) {a : α} {h'} :
|
||||
t.get? a = some (t.get a h') :=
|
||||
TreeMap.Raw.getKey?_eq_some_getKey h
|
||||
|
||||
@[simp]
|
||||
theorem get!_emptyc {a : α} [Inhabited α] :
|
||||
(∅ : TreeSet α cmp).get! a = default :=
|
||||
TreeMap.Raw.getKey!_emptyc
|
||||
|
||||
theorem get!_of_isEmpty [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.isEmpty = true → t.get! a = default :=
|
||||
TreeMap.Raw.getKey!_of_isEmpty h
|
||||
|
||||
theorem get!_insert [TransCmp cmp] [Inhabited α] (h : t.WF) {k a : α} :
|
||||
(t.insert k).get! a = if cmp k a = .eq ∧ ¬ k ∈ t then k else t.get! a :=
|
||||
TreeMap.Raw.getKey!_insertIfNew h
|
||||
|
||||
theorem get!_eq_default_of_contains_eq_false [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.contains a = false → t.get! a = default :=
|
||||
TreeMap.Raw.getKey!_eq_default_of_contains_eq_false h
|
||||
|
||||
theorem get!_eq_default [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
¬ a ∈ t → t.get! a = default :=
|
||||
TreeMap.Raw.getKey!_eq_default h
|
||||
|
||||
theorem get!_erase [TransCmp cmp] [Inhabited α] (h : t.WF) {k a : α} :
|
||||
(t.erase k).get! a = if cmp k a = .eq then default else t.get! a :=
|
||||
TreeMap.Raw.getKey!_erase h
|
||||
|
||||
@[simp]
|
||||
theorem get!_erase_self [TransCmp cmp] [Inhabited α] (h : t.WF) {k : α} :
|
||||
(t.erase k).get! k = default :=
|
||||
TreeMap.Raw.getKey!_erase_self h
|
||||
|
||||
theorem get?_eq_some_get!_of_contains [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.contains a = true → t.get? a = some (t.get! a) :=
|
||||
TreeMap.Raw.getKey?_eq_some_getKey!_of_contains h
|
||||
|
||||
theorem get?_eq_some_get! [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
a ∈ t → t.get? a = some (t.get! a) :=
|
||||
TreeMap.Raw.getKey?_eq_some_getKey! h
|
||||
|
||||
theorem get!_eq_get!_get? [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.get! a = (t.get? a).get! :=
|
||||
TreeMap.Raw.getKey!_eq_get!_getKey? h
|
||||
|
||||
theorem get_eq_get! [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} {h'} :
|
||||
t.get a h' = t.get! a :=
|
||||
TreeMap.Raw.getKey_eq_getKey! h
|
||||
|
||||
@[simp]
|
||||
theorem getD_emptyc {a : α} {fallback : α} :
|
||||
(∅ : TreeSet α cmp).getD a fallback = fallback :=
|
||||
TreeMap.Raw.getKeyD_emptyc
|
||||
|
||||
theorem getD_of_isEmpty [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
t.isEmpty = true → t.getD a fallback = fallback :=
|
||||
TreeMap.Raw.getKeyD_of_isEmpty h
|
||||
|
||||
theorem getD_insert [TransCmp cmp] (h : t.WF) {k a fallback : α} :
|
||||
(t.insert k).getD a fallback =
|
||||
if cmp k a = .eq ∧ ¬ k ∈ t then k else t.getD a fallback :=
|
||||
TreeMap.Raw.getKeyD_insertIfNew h
|
||||
|
||||
theorem getD_eq_fallback_of_contains_eq_false [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
t.contains a = false → t.getD a fallback = fallback :=
|
||||
TreeMap.Raw.getKeyD_eq_fallback_of_contains_eq_false h
|
||||
|
||||
theorem getD_eq_fallback [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
¬ a ∈ t → t.getD a fallback = fallback :=
|
||||
TreeMap.Raw.getKeyD_eq_fallback h
|
||||
|
||||
theorem getD_erase [TransCmp cmp] (h : t.WF) {k a fallback : α} :
|
||||
(t.erase k).getD a fallback =
|
||||
if cmp k a = .eq then fallback else t.getD a fallback :=
|
||||
TreeMap.Raw.getKeyD_erase h
|
||||
|
||||
@[simp]
|
||||
theorem getD_erase_self [TransCmp cmp] (h : t.WF) {k fallback : α} :
|
||||
(t.erase k).getD k fallback = fallback :=
|
||||
TreeMap.Raw.getKeyD_erase_self h
|
||||
|
||||
theorem get?_eq_some_getD_of_contains [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
t.contains a = true → t.get? a = some (t.getD a fallback) :=
|
||||
TreeMap.Raw.getKey?_eq_some_getKeyD_of_contains h
|
||||
|
||||
theorem get?_eq_some_getD [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
a ∈ t → t.get? a = some (t.getD a fallback) :=
|
||||
TreeMap.Raw.getKey?_eq_some_getKeyD h
|
||||
|
||||
theorem getD_eq_getD_get? [TransCmp cmp] (h : t.WF) {a fallback : α} :
|
||||
t.getD a fallback = (t.get? a).getD fallback :=
|
||||
TreeMap.Raw.getKeyD_eq_getD_getKey? h
|
||||
|
||||
theorem get_eq_getD [TransCmp cmp] (h : t.WF) {a fallback : α} {h'} :
|
||||
t.get a h' = t.getD a fallback :=
|
||||
TreeMap.Raw.getKey_eq_getKeyD h
|
||||
|
||||
theorem get!_eq_getD_default [TransCmp cmp] [Inhabited α] (h : t.WF) {a : α} :
|
||||
t.get! a = t.getD a default :=
|
||||
TreeMap.Raw.getKey!_eq_getKeyD_default h
|
||||
|
||||
@[simp]
|
||||
theorem containsThenInsert_fst [TransCmp cmp] (h : t.WF) {k : α} :
|
||||
(t.containsThenInsert k).1 = t.contains k :=
|
||||
|
||||
@@ -32,17 +32,13 @@ theorem mem_of_necessary_assignment {n : Nat} {p : (PosFin n) → Bool} {c : Def
|
||||
simp only [Entails.eval, Bool.not_eq_false] at h
|
||||
split at h
|
||||
· next heq => simp [Literal.negate, ← heq, h, v_in_c]
|
||||
· next hne =>
|
||||
exfalso
|
||||
simp [(· ⊨ ·), h] at pv
|
||||
· next hne => simp [(· ⊨ ·), h] at pv
|
||||
· specialize p'_not_entails_c v
|
||||
have h := p'_not_entails_c.2 v_in_c
|
||||
simp only [(· ⊨ ·), Bool.not_eq_false] at h
|
||||
split at h
|
||||
· next heq => simp [Literal.negate, ← heq, h, v_in_c]
|
||||
· next hne =>
|
||||
exfalso
|
||||
simp [(· ⊨ ·), h] at pv
|
||||
· next hne => simp [(· ⊨ ·), h] at pv
|
||||
|
||||
theorem entails_of_irrelevant_assignment {n : Nat} {p : (PosFin n) → Bool} {c : DefaultClause n}
|
||||
{l : Literal (PosFin n)} (p_entails_cl : p ⊨ c.delete (Literal.negate l)) :
|
||||
@@ -199,7 +195,8 @@ theorem sat_of_confirmRupHint_of_insertRat_fold {n : Nat} (f : DefaultFormula n)
|
||||
intro fc confirmRupHint_fold_res confirmRupHint_success
|
||||
let motive := ConfirmRupHintFoldEntailsMotive fc.1
|
||||
have h_base : motive 0 (fc.fst.assignments, [], false, false) := by
|
||||
simp [ConfirmRupHintFoldEntailsMotive, size_assignments_insertRatUnits, hf.2.1, fc, motive]
|
||||
simp only [ConfirmRupHintFoldEntailsMotive, size_assignments_insertRatUnits, hf.2.1,
|
||||
Bool.false_eq_true, false_implies, and_true, true_and, motive, fc]
|
||||
have fc_satisfies_AssignmentsInvariant : AssignmentsInvariant fc.1 :=
|
||||
assignmentsInvariant_insertRatUnits f hf (negate c)
|
||||
exact limplies_of_assignmentsInvariant fc.1 fc_satisfies_AssignmentsInvariant
|
||||
|
||||
@@ -177,7 +177,7 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
let mostRecentUnitIdx : Fin (insertUnit (units, assignments, foundContradiction) l).1.size :=
|
||||
⟨units.size, units_size_lt_updatedUnits_size⟩
|
||||
have j_lt_updatedUnits_size : j.1 < (insertUnit (units, assignments, foundContradiction) l).1.size := by
|
||||
simp [insertUnit, h5, ite_false, Array.size_push]
|
||||
simp only [insertUnit, h5, Bool.false_eq_true, ↓reduceIte, Array.size_push]
|
||||
exact Nat.lt_trans j.2 (Nat.lt_succ_self units.size)
|
||||
match hb : b, hl : l.2 with
|
||||
| true, true =>
|
||||
@@ -225,7 +225,7 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
exact k_ne_l rfl
|
||||
| false, true =>
|
||||
refine ⟨mostRecentUnitIdx, ⟨j.1, j_lt_updatedUnits_size⟩, i_gt_zero, ?_⟩
|
||||
simp [insertUnit, h5, ite_false, Array.getElem_push_eq, ne_eq]
|
||||
simp only [insertUnit, h5, Bool.false_eq_true, ↓reduceIte, mostRecentUnitIdx]
|
||||
constructor
|
||||
· simp +zetaDelta [i_eq_l, ← hl]
|
||||
rfl
|
||||
@@ -259,7 +259,6 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
rcases Nat.lt_or_eq_of_le <| Nat.le_of_lt_succ k_property with k_lt_units_size | k_eq_units_size
|
||||
· exact h k_lt_units_size
|
||||
· simp only [← k_eq_units_size, not_true, mostRecentUnitIdx] at k_ne_l
|
||||
exact k_ne_l rfl
|
||||
| false, false =>
|
||||
exfalso
|
||||
have assignments_i_rw : assignments[i.1]! = assignments[i.1] := by
|
||||
|
||||
@@ -42,11 +42,11 @@ theorem contradiction_of_insertUnit_success {n : Nat} (assignments : Array Assig
|
||||
apply Exists.intro i
|
||||
by_cases l.1.1 = i.1
|
||||
· next l_eq_i =>
|
||||
simp [l_eq_i, Array.getElem_modify_self, h]
|
||||
simp only [Bool.false_eq_true, ↓reduceIte, l_eq_i, Array.getElem_modify_self, h,
|
||||
insertUnit_res]
|
||||
exact add_both_eq_both l.2
|
||||
· next l_ne_i =>
|
||||
simp [Array.getElem_modify_of_ne l_ne_i]
|
||||
exact h
|
||||
simpa [Array.getElem_modify_of_ne l_ne_i] using h
|
||||
· apply Exists.intro l.1
|
||||
simp only [insertUnit, hl, ite_false, Array.getElem_modify_self, reduceCtorEq]
|
||||
simp only [getElem!_def, l_in_bounds, Array.getElem?_eq_getElem,
|
||||
@@ -60,8 +60,9 @@ theorem contradiction_of_insertUnit_success {n : Nat} (assignments : Array Assig
|
||||
· next l_eq_false =>
|
||||
simp only [Bool.not_eq_true] at l_eq_false
|
||||
simp only [l_eq_false]
|
||||
simp [hasAssignment, l_eq_false, hasNegAssignment, getElem!_def, l_in_bounds,
|
||||
Array.getElem?_eq_getElem] at hl
|
||||
simp only [hasAssignment, l_eq_false, Bool.false_eq_true, ↓reduceIte, hasNegAssignment,
|
||||
getElem!_def, l_in_bounds, Array.getElem?_eq_getElem, Bool.not_eq_true,
|
||||
insertUnit_res] at hl
|
||||
split at hl <;> simp_all +decide
|
||||
|
||||
theorem contradiction_of_insertUnit_fold_success {n : Nat} (assignments : Array Assignment) (assignments_size : assignments.size = n)
|
||||
@@ -350,7 +351,10 @@ theorem assignmentsInvariant_insertRupUnits_of_assignmentsInvariant {n : Nat} (f
|
||||
rcases hp2 with ⟨i2, hp2⟩
|
||||
simp only [Fin.getElem_fin] at h1
|
||||
simp only [Fin.getElem_fin] at h2
|
||||
simp [h1, Clause.toList, unit_eq, List.mem_singleton, h2] at hp1 hp2
|
||||
simp only [Clause.toList, h1, unit_eq, List.mem_cons, Prod.mk.injEq, Bool.false_eq_true,
|
||||
and_false, List.not_mem_nil, or_self, Bool.decide_eq_false, Bool.not_eq_eq_eq_not,
|
||||
Bool.not_true, false_and, and_true, or_false, false_or, h2, Bool.true_eq_false, j2_unit,
|
||||
j1_unit] at hp1 hp2
|
||||
simp only [hp2.1, ← hp1.1, decide_eq_true_eq, true_and] at hp2
|
||||
simp [hp1.2] at hp2
|
||||
|
||||
@@ -693,8 +697,7 @@ theorem confirmRupHint_preserves_motive {n : Nat} (f : DefaultFormula n) (rupHin
|
||||
simp only [Bool.true_eq_false, decide_false, Bool.false_eq_true, ↓reduceIte,
|
||||
hasNeg_addPos]
|
||||
exact pacc
|
||||
· exfalso -- hb, pi, l_eq_i, and plb are incompatible
|
||||
simp only [Bool.not_eq_true] at hb
|
||||
· simp only [Bool.not_eq_true] at hb
|
||||
simp [(· ⊨ ·), hb, Subtype.ext l_eq_i, pi] at plb
|
||||
· simp only [Bool.not_eq_true] at pi
|
||||
simp only [pi, decide_true]
|
||||
@@ -726,7 +729,8 @@ theorem sat_of_confirmRupHint_insertRup_fold {n : Nat} (f : DefaultFormula n)
|
||||
intro fc confirmRupHint_fold_res confirmRupHint_success
|
||||
let motive := ConfirmRupHintFoldEntailsMotive fc.1
|
||||
have h_base : motive 0 (fc.fst.assignments, [], false, false) := by
|
||||
simp [ConfirmRupHintFoldEntailsMotive, size_assignments_insertRupUnits, f_readyForRupAdd.2.1, motive, fc]
|
||||
simp only [ConfirmRupHintFoldEntailsMotive, size_assignments_insertRupUnits,
|
||||
f_readyForRupAdd.2.1, Bool.false_eq_true, false_implies, and_true, true_and, motive, fc]
|
||||
have fc_satisfies_AssignmentsInvariant :=
|
||||
assignmentsInvariant_insertRupUnits_of_assignmentsInvariant f f_readyForRupAdd (negate c)
|
||||
exact limplies_of_assignmentsInvariant fc.1 fc_satisfies_AssignmentsInvariant
|
||||
|
||||
@@ -13,8 +13,6 @@ This module contains the `Prop` simplifying part of the `bv_normalize` simp set.
|
||||
namespace Std.Tactic.BVDecide
|
||||
namespace Frontend.Normalize
|
||||
|
||||
attribute [bv_normalize] dite_true
|
||||
attribute [bv_normalize] dite_false
|
||||
attribute [bv_normalize] and_true
|
||||
attribute [bv_normalize] true_and
|
||||
attribute [bv_normalize] and_false
|
||||
|
||||
@@ -10,7 +10,7 @@ open Lean
|
||||
|
||||
namespace Lake
|
||||
|
||||
initialize
|
||||
builtin_initialize
|
||||
registerBuiltinAttribute {
|
||||
ref := by exact decl_name%
|
||||
name := `test_runner
|
||||
|
||||
@@ -9,37 +9,37 @@ import Lake.Util.OrderedTagAttribute
|
||||
open Lean
|
||||
namespace Lake
|
||||
|
||||
initialize packageAttr : OrderedTagAttribute ←
|
||||
builtin_initialize packageAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `package "mark a definition as a Lake package configuration"
|
||||
|
||||
initialize packageDepAttr : OrderedTagAttribute ←
|
||||
builtin_initialize packageDepAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `package_dep "mark a definition as a Lake package dependency"
|
||||
|
||||
initialize postUpdateAttr : OrderedTagAttribute ←
|
||||
builtin_initialize postUpdateAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `post_update "mark a definition as a Lake package post-update hook"
|
||||
|
||||
initialize scriptAttr : OrderedTagAttribute ←
|
||||
builtin_initialize scriptAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `script "mark a definition as a Lake script"
|
||||
|
||||
initialize defaultScriptAttr : OrderedTagAttribute ←
|
||||
builtin_initialize defaultScriptAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `default_script "mark a Lake script as the package's default"
|
||||
fun name => do
|
||||
unless (← getEnv <&> (scriptAttr.hasTag · name)) do
|
||||
throwError "attribute `default_script` can only be used on a `script`"
|
||||
|
||||
initialize leanLibAttr : OrderedTagAttribute ←
|
||||
builtin_initialize leanLibAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `lean_lib "mark a definition as a Lake Lean library target configuration"
|
||||
|
||||
initialize leanExeAttr : OrderedTagAttribute ←
|
||||
builtin_initialize leanExeAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `lean_exe "mark a definition as a Lake Lean executable target configuration"
|
||||
|
||||
initialize externLibAttr : OrderedTagAttribute ←
|
||||
builtin_initialize externLibAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `extern_lib "mark a definition as a Lake external library target"
|
||||
|
||||
initialize targetAttr : OrderedTagAttribute ←
|
||||
builtin_initialize targetAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `target "mark a definition as a custom Lake target"
|
||||
|
||||
initialize defaultTargetAttr : OrderedTagAttribute ←
|
||||
builtin_initialize defaultTargetAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `default_target "mark a Lake target as the package's default"
|
||||
fun name => do
|
||||
let valid ← getEnv <&> fun env =>
|
||||
@@ -50,7 +50,7 @@ initialize defaultTargetAttr : OrderedTagAttribute ←
|
||||
unless valid do
|
||||
throwError "attribute `default_target` can only be used on a target (e.g., `lean_lib`, `lean_exe`)"
|
||||
|
||||
initialize testDriverAttr : OrderedTagAttribute ←
|
||||
builtin_initialize testDriverAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `test_driver "mark a Lake script, executable, or library as package's test driver"
|
||||
fun name => do
|
||||
let valid ← getEnv <&> fun env =>
|
||||
@@ -60,7 +60,7 @@ initialize testDriverAttr : OrderedTagAttribute ←
|
||||
unless valid do
|
||||
throwError "attribute `test_driver` can only be used on a `script`, `lean_exe`, or `lean_lib`"
|
||||
|
||||
initialize lintDriverAttr : OrderedTagAttribute ←
|
||||
builtin_initialize lintDriverAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `lint_driver "mark a Lake script or executable as package's linter"
|
||||
fun name => do
|
||||
let valid ← getEnv <&> fun env =>
|
||||
@@ -69,11 +69,11 @@ initialize lintDriverAttr : OrderedTagAttribute ←
|
||||
unless valid do
|
||||
throwError "attribute `lint_driver` can only be used on a `script` or `lean_exe`"
|
||||
|
||||
initialize moduleFacetAttr : OrderedTagAttribute ←
|
||||
builtin_initialize moduleFacetAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `module_facet "mark a definition as a Lake module facet"
|
||||
|
||||
initialize packageFacetAttr : OrderedTagAttribute ←
|
||||
builtin_initialize packageFacetAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `package_facet "mark a definition as a Lake package facet"
|
||||
|
||||
initialize libraryFacetAttr : OrderedTagAttribute ←
|
||||
builtin_initialize libraryFacetAttr : OrderedTagAttribute ←
|
||||
registerOrderedTagAttribute `library_facet "mark a definition as a Lake library facet"
|
||||
|
||||
@@ -28,7 +28,7 @@ during the Lakefile's elaboration.
|
||||
-/
|
||||
scoped syntax (name := dirConst) "__dir__" : term
|
||||
|
||||
@[term_elab dirConst]
|
||||
@[builtin_term_elab dirConst]
|
||||
def elabDirConst : TermElab := fun stx expectedType? => do
|
||||
let exp :=
|
||||
if let some dir := dirExt.getState (← getEnv) then
|
||||
@@ -48,7 +48,7 @@ or via the `with` clause in a `require` statement.
|
||||
-/
|
||||
scoped syntax (name := getConfig) "get_config? " ident :term
|
||||
|
||||
@[term_elab getConfig]
|
||||
@[builtin_term_elab getConfig]
|
||||
def elabGetConfig : TermElab := fun stx expectedType? => do
|
||||
tryPostponeIfNoneOrMVar expectedType?
|
||||
match stx with
|
||||
|
||||
@@ -10,8 +10,8 @@ open Lean
|
||||
|
||||
namespace Lake
|
||||
|
||||
initialize dirExt : EnvExtension (Option System.FilePath) ←
|
||||
builtin_initialize dirExt : EnvExtension (Option System.FilePath) ←
|
||||
registerEnvExtension (pure none)
|
||||
|
||||
initialize optsExt : EnvExtension (Option (NameMap String)) ←
|
||||
builtin_initialize optsExt : EnvExtension (Option (NameMap String)) ←
|
||||
registerEnvExtension (pure none)
|
||||
|
||||
@@ -57,7 +57,10 @@ extern_lib linuxOnlyLib := ...
|
||||
scoped syntax (name := metaIf)
|
||||
"meta " "if " term " then " cmdDo (" else " cmdDo)? : command
|
||||
|
||||
elab_rules : command | `(meta if $c then $t $[else $e?]?) => do
|
||||
@[builtin_command_elab metaIf]
|
||||
def elabMetaIf : CommandElab := fun stx => do
|
||||
let `(meta if $c then $t $[else $e?]?) := stx
|
||||
| throwErrorAt stx "ill-formed meta if command"
|
||||
if (← withRef c <| runTermElabM fun _ => evalTerm Bool (toTypeExpr Bool) c .unsafe) then
|
||||
let cmd := mkNullNode (expandCmdDo t)
|
||||
withMacroExpansion (← getRef) cmd <| elabCommand cmd
|
||||
@@ -77,7 +80,7 @@ and produces an expression corresponding to the result via `ToExpr α`.
|
||||
-/
|
||||
scoped syntax:lead (name := runIO) "run_io " doSeq : term
|
||||
|
||||
@[term_elab runIO]
|
||||
@[builtin_term_elab runIO]
|
||||
def elabRunIO : TermElab := fun stx expectedType? =>
|
||||
match stx with
|
||||
| `(run_io%$tk $t) => withRef t do
|
||||
|
||||
@@ -8,8 +8,9 @@ import Lake.Config.Package
|
||||
import Lake.DSL.Attributes
|
||||
import Lake.DSL.DeclUtil
|
||||
|
||||
open Lean Parser Elab Command
|
||||
|
||||
namespace Lake.DSL
|
||||
open Lean Parser Command
|
||||
|
||||
/-! # Package Declarations
|
||||
DSL definitions for packages and hooks.
|
||||
@@ -30,9 +31,14 @@ package «pkg-name» where /- config opts -/
|
||||
There can only be one `package` declaration per Lake configuration file.
|
||||
The defined package configuration will be available for reference as `_package`.
|
||||
-/
|
||||
scoped elab (name := packageDecl)
|
||||
doc?:optional(docComment) attrs?:optional(Term.attributes)
|
||||
kw:"package " sig:structDeclSig : command => withRef kw do
|
||||
scoped syntax (name := packageDecl)
|
||||
(docComment)? (Term.attributes)? "package " structDeclSig : command
|
||||
|
||||
@[builtin_command_elab packageDecl]
|
||||
def elabPackageDecl : CommandElab := fun stx => do
|
||||
let `(packageDecl|$(doc?)? $(attrs?)? package%$kw $sig) := stx
|
||||
| throwErrorAt stx "ill-formed package declaration"
|
||||
withRef kw do
|
||||
let attr ← `(Term.attrInstance| «package»)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
elabConfigDecl ``PackageConfig sig doc? attrs packageDeclName
|
||||
@@ -42,7 +48,6 @@ abbrev PackageDecl := TSyntax ``packageDecl
|
||||
instance : Coe PackageDecl Command where
|
||||
coe x := ⟨x.raw⟩
|
||||
|
||||
|
||||
/--
|
||||
Declare a post-`lake update` hook for the package.
|
||||
Runs the monadic action is after a successful `lake update` execution
|
||||
@@ -69,13 +74,16 @@ scoped syntax (name := postUpdateDecl)
|
||||
optional(docComment) optional(Term.attributes)
|
||||
"post_update " (ppSpace simpleBinder)? (declValSimple <|> declValDo) : command
|
||||
|
||||
macro_rules
|
||||
| `($[$doc?]? $[$attrs?]? post_update%$kw $[$pkg?]? do $seq $[$wds?:whereDecls]?) =>
|
||||
`($[$doc?]? $[$attrs?]? post_update%$kw $[$pkg?]? := do $seq $[$wds?:whereDecls]?)
|
||||
| `($[$doc?]? $[$attrs?]? post_update%$kw $[$pkg?]? := $defn $[$wds?:whereDecls]?) => withRef kw do
|
||||
let pkg ← expandOptSimpleBinder pkg?
|
||||
let pkgName := mkIdentFrom pkg `_package.name
|
||||
let attr ← `(Term.attrInstance| «post_update»)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
`($[$doc?]? @[$attrs,*] def postUpdateHook : PostUpdateHookDecl :=
|
||||
{pkg := $pkgName, fn := fun $pkg => $defn} $[$wds?:whereDecls]?)
|
||||
@[builtin_macro postUpdateDecl]
|
||||
def expandPostUpdateDecl : Macro := fun stx => do
|
||||
match stx with
|
||||
| `($[$doc?]? $[$attrs?]? post_update%$kw $[$pkg?]? do $seq $[$wds?:whereDecls]?) =>
|
||||
`($[$doc?]? $[$attrs?]? post_update%$kw $[$pkg?]? := do $seq $[$wds?:whereDecls]?)
|
||||
| `($[$doc?]? $[$attrs?]? post_update%$kw $[$pkg?]? := $defn $[$wds?:whereDecls]?) => withRef kw do
|
||||
let pkg ← expandOptSimpleBinder pkg?
|
||||
let pkgName := mkIdentFrom pkg `_package.name
|
||||
let attr ← `(Term.attrInstance| «post_update»)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
`($[$doc?]? @[$attrs,*] def postUpdateHook : PostUpdateHookDecl :=
|
||||
{pkg := $pkgName, fn := fun $pkg => $defn} $[$wds?:whereDecls]?)
|
||||
| stx => Macro.throwErrorAt stx "ill-formed post_update declaration"
|
||||
|
||||
@@ -140,9 +140,14 @@ The `with` clause specifies a `NameMap String` of Lake options
|
||||
used to configure the dependency. This is equivalent to passing `-K`
|
||||
options to the dependency on the command line.
|
||||
-/
|
||||
scoped macro (name := requireDecl)
|
||||
doc?:(docComment)? kw:"require " spec:depSpec : command => withRef kw do
|
||||
expandDepSpec spec doc?
|
||||
scoped syntax (name := requireDecl)
|
||||
(docComment)? "require " depSpec : command
|
||||
|
||||
@[builtin_macro requireDecl]
|
||||
def expandRequireDecl : Macro := fun stx => do
|
||||
let `(requireDecl|$(doc?)? require%$kw $spec) := stx
|
||||
| Macro.throwErrorAt stx "ill-formed require declaration"
|
||||
withRef kw do expandDepSpec spec doc?
|
||||
|
||||
@[inherit_doc requireDecl] abbrev RequireDecl := TSyntax ``requireDecl
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ script «script-name» (args) do
|
||||
scoped syntax (name := scriptDecl)
|
||||
(docComment)? optional(Term.attributes) "script " scriptDeclSpec : command
|
||||
|
||||
@[macro scriptDecl]
|
||||
@[builtin_macro scriptDecl]
|
||||
def expandScriptDecl : Macro
|
||||
| `($[$doc?]? $[$attrs?]? script%$kw $name $[$args?]? do $seq $[$wds?:whereDecls]?) => do
|
||||
`($[$doc?]? $[$attrs?]? script%$kw $name $[$args?]? := do $seq $[$wds?:whereDecls]?)
|
||||
|
||||
@@ -11,9 +11,10 @@ import Lake.Build.Index
|
||||
Macros for declaring Lake targets and facets.
|
||||
-/
|
||||
|
||||
namespace Lake.DSL
|
||||
open Lean Parser Command
|
||||
open System (FilePath)
|
||||
open Lean Parser Elab Command
|
||||
|
||||
namespace Lake.DSL
|
||||
|
||||
syntax buildDeclSig :=
|
||||
identOrStr (ppSpace simpleBinder)? Term.typeSpec declValSimple
|
||||
@@ -40,22 +41,26 @@ module_facet «facet-name» (mod : Module) : α :=
|
||||
|
||||
The `mod` parameter (and its type specifier) is optional.
|
||||
-/
|
||||
scoped macro (name := moduleFacetDecl)
|
||||
doc?:optional(docComment) attrs?:optional(Term.attributes)
|
||||
kw:"module_facet " sig:buildDeclSig : command => withRef kw do
|
||||
match sig with
|
||||
| `(buildDeclSig| $nameStx $[$mod?]? : $ty := $defn $[$wds?:whereDecls]?) =>
|
||||
let attr ← withRef kw `(Term.attrInstance| module_facet)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
let id := expandIdentOrStrAsIdent nameStx
|
||||
let facet := Name.quoteFrom id id.getId
|
||||
let declId := mkIdentFrom id <| id.getId.modifyBase (.str · "_modFacet")
|
||||
let mod ← expandOptSimpleBinder mod?
|
||||
`(module_data $id : $ty
|
||||
$[$doc?:docComment]? @[$attrs,*] abbrev $declId :=
|
||||
Lake.DSL.mkModuleFacetDecl $ty $facet (fun $mod => $defn)
|
||||
$[$wds?:whereDecls]?)
|
||||
| stx => Macro.throwErrorAt stx "ill-formed module facet declaration"
|
||||
scoped syntax (name := moduleFacetDecl)
|
||||
(docComment)? (Term.attributes)? "module_facet " buildDeclSig : command
|
||||
|
||||
@[builtin_macro moduleFacetDecl]
|
||||
def expandModuleFacetDecl : Macro := fun stx => do
|
||||
let `(moduleFacetDecl|$(doc?)? $(attrs?)? module_facet%$kw $sig) := stx
|
||||
| Macro.throwErrorAt stx "ill-formed module facet declaration"
|
||||
let `(buildDeclSig| $nameStx $[$mod?]? : $ty := $defn $[$wds?:whereDecls]?) := sig
|
||||
| Macro.throwErrorAt sig "ill-formed module facet declaration"
|
||||
withRef kw do
|
||||
let attr ← `(Term.attrInstance| «module_facet»)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
let id := expandIdentOrStrAsIdent nameStx
|
||||
let facet := Name.quoteFrom id id.getId
|
||||
let declId := mkIdentFrom id <| id.getId.modifyBase (.str · "_modFacet")
|
||||
let mod ← expandOptSimpleBinder mod?
|
||||
`(module_data $id : $ty
|
||||
$[$doc?:docComment]? @[$attrs,*] abbrev $declId :=
|
||||
Lake.DSL.mkModuleFacetDecl $ty $facet (fun $mod => $defn)
|
||||
$[$wds?:whereDecls]?)
|
||||
|
||||
abbrev mkPackageFacetDecl
|
||||
(α) (facet : Name)
|
||||
@@ -75,22 +80,26 @@ package_facet «facet-name» (pkg : Package) : α :=
|
||||
|
||||
The `pkg` parameter (and its type specifier) is optional.
|
||||
-/
|
||||
scoped macro (name := packageFacetDecl)
|
||||
doc?:optional(docComment) attrs?:optional(Term.attributes)
|
||||
kw:"package_facet " sig:buildDeclSig : command => withRef kw do
|
||||
match sig with
|
||||
| `(buildDeclSig| $nameStx $[$pkg?]? : $ty := $defn $[$wds?:whereDecls]?) =>
|
||||
let attr ← withRef kw `(Term.attrInstance| package_facet)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
let id := expandIdentOrStrAsIdent nameStx
|
||||
let facet := Name.quoteFrom id id.getId
|
||||
let declId := mkIdentFrom id <| id.getId.modifyBase (.str · "_pkgFacet")
|
||||
let pkg ← expandOptSimpleBinder pkg?
|
||||
`(package_data $id : $ty
|
||||
$[$doc?]? @[$attrs,*] abbrev $declId :=
|
||||
Lake.DSL.mkPackageFacetDecl $ty $facet (fun $pkg => $defn)
|
||||
$[$wds?:whereDecls]?)
|
||||
| stx => Macro.throwErrorAt stx "ill-formed package facet declaration"
|
||||
scoped syntax (name := packageFacetDecl)
|
||||
(docComment)? (Term.attributes)? "package_facet " buildDeclSig : command
|
||||
|
||||
@[builtin_macro packageFacetDecl]
|
||||
def expandPackageFacetDecl : Macro := fun stx => do
|
||||
let `(packageFacetDecl|$(doc?)? $(attrs?)? package_facet%$kw $sig) := stx
|
||||
| Macro.throwErrorAt stx "ill-formed package facet declaration"
|
||||
let `(buildDeclSig| $nameStx $[$pkg?]? : $ty := $defn $[$wds?:whereDecls]?) := sig
|
||||
| Macro.throwErrorAt sig "ill-formed package facet signature"
|
||||
withRef kw do
|
||||
let attr ← `(Term.attrInstance| «package_facet»)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
let id := expandIdentOrStrAsIdent nameStx
|
||||
let facet := Name.quoteFrom id id.getId
|
||||
let declId := mkIdentFrom id <| id.getId.modifyBase (.str · "_pkgFacet")
|
||||
let pkg ← expandOptSimpleBinder pkg?
|
||||
`(package_data $id : $ty
|
||||
$[$doc?]? @[$attrs,*] abbrev $declId :=
|
||||
Lake.DSL.mkPackageFacetDecl $ty $facet (fun $pkg => $defn)
|
||||
$[$wds?:whereDecls]?)
|
||||
|
||||
abbrev mkLibraryFacetDecl
|
||||
(α) (facet : Name)
|
||||
@@ -110,22 +119,27 @@ library_facet «facet-name» (lib : LeanLib) : α :=
|
||||
|
||||
The `lib` parameter (and its type specifier) is optional.
|
||||
-/
|
||||
scoped macro (name := libraryFacetDecl)
|
||||
doc?:optional(docComment) attrs?:optional(Term.attributes)
|
||||
kw:"library_facet " sig:buildDeclSig : command => withRef kw do
|
||||
match sig with
|
||||
| `(buildDeclSig| $nameStx $[$lib?]? : $ty := $defn $[$wds?:whereDecls]?) =>
|
||||
let attr ← withRef kw `(Term.attrInstance| library_facet)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
let id := expandIdentOrStrAsIdent nameStx
|
||||
let facet := Name.quoteFrom id id.getId
|
||||
let declId := mkIdentFrom id <| id.getId.modifyBase (.str · "_libFacet")
|
||||
let lib ← expandOptSimpleBinder lib?
|
||||
`(library_data $id : $ty
|
||||
$[$doc?]? @[$attrs,*] abbrev $declId : LibraryFacetDecl :=
|
||||
Lake.DSL.mkLibraryFacetDecl $ty $facet (fun $lib => $defn)
|
||||
$[$wds?:whereDecls]?)
|
||||
| stx => Macro.throwErrorAt stx "ill-formed library facet declaration"
|
||||
scoped syntax (name := libraryFacetDecl)
|
||||
(docComment)? (Term.attributes)? "library_facet " buildDeclSig : command
|
||||
|
||||
@[builtin_macro libraryFacetDecl]
|
||||
def expandLibraryFacetDecl : Macro := fun stx => do
|
||||
let `(libraryFacetDecl|$(doc?)? $(attrs?)? library_facet%$kw $sig) := stx
|
||||
| Macro.throwErrorAt stx "ill-formed library facet declaration"
|
||||
let `(buildDeclSig| $nameStx $[$lib?]? : $ty := $defn $[$wds?:whereDecls]?) := sig
|
||||
| Macro.throwErrorAt sig "ill-formed library facet signature"
|
||||
withRef kw do
|
||||
let attr ← `(Term.attrInstance| «library_facet»)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
let id := expandIdentOrStrAsIdent nameStx
|
||||
let facet := Name.quoteFrom id id.getId
|
||||
let declId := mkIdentFrom id <| id.getId.modifyBase (.str · "_libFacet")
|
||||
let lib ← expandOptSimpleBinder lib?
|
||||
`(library_data $id : $ty
|
||||
$[$doc?]? @[$attrs,*] abbrev $declId : LibraryFacetDecl :=
|
||||
Lake.DSL.mkLibraryFacetDecl $ty $facet (fun $lib => $defn)
|
||||
$[$wds?:whereDecls]?)
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
/-! ## Custom Target Declaration -/
|
||||
@@ -151,22 +165,25 @@ The `pkg` parameter (and its type specifier) is optional.
|
||||
It is of type `NPackage _package.name` to provably demonstrate the package
|
||||
provided is the package in which the target is defined.
|
||||
-/
|
||||
scoped macro (name := targetDecl)
|
||||
doc?:optional(docComment) attrs?:optional(Term.attributes)
|
||||
kw:"target " sig:buildDeclSig : command => do
|
||||
match sig with
|
||||
| `(buildDeclSig| $id:ident $[$pkg?]? : $ty := $defn $[$wds?:whereDecls]?) =>
|
||||
let attr ← withRef kw `(Term.attrInstance| target)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
let name := Name.quoteFrom id id.getId
|
||||
let pkgName := mkIdentFrom id `_package.name
|
||||
let pkg ← expandOptSimpleBinder pkg?
|
||||
`(family_def $id : CustomData ($pkgName, $name) := $ty
|
||||
$[$doc?]? @[$attrs,*] abbrev $id :=
|
||||
Lake.DSL.mkTargetDecl $ty $pkgName $name (fun $pkg => $defn)
|
||||
$[$wds?:whereDecls]?)
|
||||
| stx => Macro.throwErrorAt stx "ill-formed target declaration"
|
||||
scoped syntax (name := targetDecl)
|
||||
(docComment)? (Term.attributes)? "target " buildDeclSig : command
|
||||
|
||||
@[builtin_macro targetDecl]
|
||||
def expandTargetDecl : Macro := fun stx => do
|
||||
let `(targetDecl|$(doc?)? $(attrs?)? target%$kw $sig) := stx
|
||||
| Macro.throwErrorAt stx "ill-formed target declaration"
|
||||
let `(buildDeclSig|$id:ident $[$pkg?]? : $ty := $defn $[$wds?:whereDecls]?) := sig
|
||||
| Macro.throwErrorAt sig "ill-formed target signature"
|
||||
withRef kw do
|
||||
let attr ← `(Term.attrInstance| «target»)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
let name := Name.quoteFrom id id.getId
|
||||
let pkgName := mkIdentFrom id `_package.name
|
||||
let pkg ← expandOptSimpleBinder pkg?
|
||||
`(family_def $id : CustomData ($pkgName, $name) := $ty
|
||||
$[$doc?]? @[$attrs,*] abbrev $id :=
|
||||
Lake.DSL.mkTargetDecl $ty $pkgName $name (fun $pkg => $defn)
|
||||
$[$wds?:whereDecls]?)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
/-! ## Lean Library & Executable Target Declarations -/
|
||||
@@ -183,10 +200,15 @@ lean_lib «target-name» { /- config opts -/ }
|
||||
lean_lib «target-name» where /- config opts -/
|
||||
```
|
||||
-/
|
||||
scoped elab (name := leanLibDecl)
|
||||
doc?:optional(docComment) attrs?:optional(Term.attributes)
|
||||
kw:"lean_lib " sig:structDeclSig : command => withRef kw do
|
||||
let attr ← `(Term.attrInstance| lean_lib)
|
||||
scoped syntax (name := leanLibDecl)
|
||||
(docComment)? (Term.attributes)? "lean_lib " structDeclSig : command
|
||||
|
||||
@[builtin_command_elab leanLibDecl]
|
||||
def elabLeanLibDecl : CommandElab := fun stx => do
|
||||
let `(leanLibDecl|$(doc?)? $(attrs?)? lean_lib%$kw $sig) := stx
|
||||
| throwErrorAt stx "ill-formed lean_lib declaration"
|
||||
withRef kw do
|
||||
let attr ← `(Term.attrInstance| «lean_lib»)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
elabConfigDecl ``LeanLibConfig sig doc? attrs
|
||||
|
||||
@@ -206,10 +228,15 @@ lean_exe «target-name» { /- config opts -/ }
|
||||
lean_exe «target-name» where /- config opts -/
|
||||
```
|
||||
-/
|
||||
scoped elab (name := leanExeDecl)
|
||||
doc?:optional(docComment) attrs?:optional(Term.attributes)
|
||||
kw:"lean_exe " sig:structDeclSig : command => withRef kw do
|
||||
let attr ← `(Term.attrInstance| lean_exe)
|
||||
scoped syntax (name := leanExeDecl)
|
||||
(docComment)? (Term.attributes)? "lean_exe " structDeclSig : command
|
||||
|
||||
@[builtin_command_elab leanExeDecl]
|
||||
def elabLeanExeDecl : CommandElab := fun stx => do
|
||||
let `(leanExeDecl|$(doc?)? $(attrs?)? lean_exe%$kw $sig) := stx
|
||||
| throwErrorAt stx "ill-formed lean_exe declaration"
|
||||
withRef kw do
|
||||
let attr ← `(Term.attrInstance| «lean_exe»)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
elabConfigDecl ``LeanExeConfig sig doc? attrs
|
||||
|
||||
@@ -244,18 +271,22 @@ provided is the package in which the target is defined.
|
||||
|
||||
The term should build the external library's **static** library.
|
||||
-/
|
||||
scoped macro (name := externLibDecl)
|
||||
doc?:optional(docComment) attrs?:optional(Term.attributes)
|
||||
kw:"extern_lib " spec:externLibDeclSpec : command => withRef kw do
|
||||
match spec with
|
||||
| `(externLibDeclSpec| $nameStx $[$pkg?]? := $defn $[$wds?:whereDecls]?) =>
|
||||
let attr ← `(Term.attrInstance| extern_lib)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
let id := expandIdentOrStrAsIdent nameStx
|
||||
let pkgName := mkIdentFrom id `_package.name
|
||||
let targetId := mkIdentFrom id <| id.getId.modifyBase (· ++ `static)
|
||||
let name := Name.quoteFrom id id.getId
|
||||
`(target $targetId:ident $[$pkg?]? : FilePath := $defn $[$wds?:whereDecls]?
|
||||
$[$doc?:docComment]? @[$attrs,*] def $id : ExternLibDecl :=
|
||||
Lake.DSL.mkExternLibDecl $pkgName $name)
|
||||
| stx => Macro.throwErrorAt stx "ill-formed external library declaration"
|
||||
scoped syntax (name := externLibDecl)
|
||||
(docComment)? (Term.attributes)? "extern_lib " externLibDeclSpec : command
|
||||
|
||||
@[builtin_macro externLibDecl]
|
||||
def expandExternLibDecl : Macro := fun stx => do
|
||||
let `(externLibDecl|$(doc?)? $(attrs?)? extern_lib%$kw $spec) := stx
|
||||
| Macro.throwErrorAt stx "ill-formed external library declaration"
|
||||
let `(externLibDeclSpec| $nameStx $[$pkg?]? := $defn $[$wds?:whereDecls]?) := spec
|
||||
| Macro.throwErrorAt spec "ill-formed external library signature"
|
||||
withRef kw do
|
||||
let attr ← `(Term.attrInstance| «extern_lib»)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
let id := expandIdentOrStrAsIdent nameStx
|
||||
let pkgName := mkIdentFrom id `_package.name
|
||||
let targetId := mkIdentFrom id <| id.getId.modifyBase (· ++ `static)
|
||||
let name := Name.quoteFrom id id.getId
|
||||
`(target $targetId:ident $[$pkg?]? : FilePath := $defn $[$wds?:whereDecls]?
|
||||
$[$doc?:docComment]? @[$attrs,*] def $id : ExternLibDecl :=
|
||||
Lake.DSL.mkExternLibDecl $pkgName $name)
|
||||
|
||||
@@ -250,7 +250,8 @@ private def toResultExpr [ToExpr α] (x : Except String α) : Except String Expr
|
||||
/-- A Lake version literal. -/
|
||||
scoped syntax:max (name := verLit) "v!" noWs interpolatedStr(term) : term
|
||||
|
||||
@[term_elab verLit] def elabVerLit : TermElab := fun stx expectedType? => do
|
||||
@[builtin_term_elab verLit]
|
||||
def elabVerLit : TermElab := fun stx expectedType? => do
|
||||
let `(v!$v) := stx | throwUnsupportedSyntax
|
||||
tryPostponeIfNoneOrMVar expectedType?
|
||||
let some expectedType := expectedType?
|
||||
|
||||
@@ -44,3 +44,4 @@ globs = [
|
||||
[[lean_lib]]
|
||||
name = "Lake"
|
||||
srcDir = "lake"
|
||||
moreLeanArgs = ["--plugin=${PREV_STAGE}/${CMAKE_RELATIVE_LIBRARY_OUTPUT_DIRECTORY}/libLake_shared${CMAKE_SHARED_LIBRARY_SUFFIX}"]
|
||||
|
||||
@@ -11,17 +11,18 @@ Authors: Leonardo de Moura, Sebastian Ullrich
|
||||
#include "library/compiler/ir_interpreter.h"
|
||||
|
||||
namespace lean {
|
||||
/* updateBaseAfterKernelAdd (env : Environment) (base : Kernel.Environment) : Environment
|
||||
/* updateBaseAfterKernelAdd (env : Environment) (base : Kernel.Environment) (decl : Declaration) : Environment
|
||||
|
||||
Updates an elab environment with a given kernel environment.
|
||||
|
||||
NOTE: Ideally this language switching would not be necessary and we could do all this in Lean
|
||||
only but the old code generator and `mk_projections` still need a C++ `elab_environment::add`. */
|
||||
extern "C" obj_res lean_elab_environment_update_base_after_kernel_add(obj_arg env, obj_arg kenv);
|
||||
only but the old code generator and `mk_projections` still need a C++ `elab_environment::add`
|
||||
that throws C++ exceptions. */
|
||||
extern "C" obj_res lean_elab_environment_update_base_after_kernel_add(obj_arg env, obj_arg kenv, obj_arg decl);
|
||||
|
||||
elab_environment elab_environment::add(declaration const & d, bool check) const {
|
||||
environment kenv = to_kernel_env().add(d, check);
|
||||
return elab_environment(lean_elab_environment_update_base_after_kernel_add(this->to_obj_arg(), kenv.to_obj_arg()));
|
||||
return elab_environment(lean_elab_environment_update_base_after_kernel_add(this->to_obj_arg(), kenv.to_obj_arg(), d.to_obj_arg()));
|
||||
}
|
||||
|
||||
extern "C" LEAN_EXPORT object * lean_elab_add_decl(object * env, size_t max_heartbeat, object * decl,
|
||||
|
||||
@@ -1149,6 +1149,7 @@ extern "C" LEAN_EXPORT obj_res lean_io_create_tempfile(lean_object * /* w */) {
|
||||
} else {
|
||||
FILE* handle = fdopen(req.result, "r+");
|
||||
object_ref pair = mk_cnstr(0, io_wrap_handle(handle), mk_string(req.path));
|
||||
uv_fs_req_cleanup(&req);
|
||||
return lean_io_result_mk_ok(pair.steal());
|
||||
}
|
||||
}
|
||||
@@ -1191,7 +1192,9 @@ extern "C" LEAN_EXPORT obj_res lean_io_create_tempdir(lean_object * /* w */) {
|
||||
// If mkdtemp throws an error we cannot rely on path to contain a proper file name.
|
||||
return io_result_mk_error(decode_uv_error(ret, nullptr));
|
||||
} else {
|
||||
return lean_io_result_mk_ok(mk_string(req.path));
|
||||
obj_res res = lean_io_result_mk_ok(mk_string(req.path));
|
||||
uv_fs_req_cleanup(&req);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,8 +102,8 @@ extern "C" LEAN_EXPORT void lean_set_panic_messages(bool flag) {
|
||||
g_panic_messages = flag;
|
||||
}
|
||||
|
||||
static void panic_eprintln(char const * line) {
|
||||
if (g_exit_on_panic || should_abort_on_panic()) {
|
||||
static void panic_eprintln(char const * line, bool force_stderr) {
|
||||
if (force_stderr || g_exit_on_panic || should_abort_on_panic()) {
|
||||
// If we are about to kill the process, we should skip the Lean stderr buffer
|
||||
std::cerr << line << "\n";
|
||||
} else {
|
||||
@@ -111,37 +111,33 @@ static void panic_eprintln(char const * line) {
|
||||
}
|
||||
}
|
||||
|
||||
static void print_backtrace() {
|
||||
static void print_backtrace(bool force_stderr) {
|
||||
#if LEAN_SUPPORTS_BACKTRACE
|
||||
void * bt_buf[100];
|
||||
int nptrs = backtrace(bt_buf, sizeof(bt_buf) / sizeof(void *));
|
||||
if (char ** symbols = backtrace_symbols(bt_buf, nptrs)) {
|
||||
for (int i = 0; i < nptrs; i++) {
|
||||
panic_eprintln(symbols[i]);
|
||||
panic_eprintln(symbols[i], force_stderr);
|
||||
}
|
||||
// According to `man backtrace`, each `symbols[i]` should NOT be freed
|
||||
free(symbols);
|
||||
if (nptrs == sizeof(bt_buf)) {
|
||||
panic_eprintln("...");
|
||||
panic_eprintln("...", force_stderr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
panic_eprintln("(stack trace unavailable)");
|
||||
panic_eprintln("(stack trace unavailable)", force_stderr);
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" LEAN_EXPORT void lean_panic(char const * msg, bool force_stderr = false) {
|
||||
if (g_panic_messages) {
|
||||
if (force_stderr) {
|
||||
std::cerr << msg << "\n";
|
||||
} else {
|
||||
panic_eprintln(msg);
|
||||
}
|
||||
panic_eprintln(msg, force_stderr);
|
||||
#if LEAN_SUPPORTS_BACKTRACE
|
||||
char * bt_env = getenv("LEAN_BACKTRACE");
|
||||
if (!bt_env || strcmp(bt_env, "0") != 0) {
|
||||
panic_eprintln("backtrace:");
|
||||
print_backtrace();
|
||||
panic_eprintln("backtrace:", force_stderr);
|
||||
print_backtrace(force_stderr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -2558,7 +2554,7 @@ extern "C" LEAN_EXPORT object * lean_dbg_trace_if_shared(obj_arg s, obj_arg a) {
|
||||
}
|
||||
|
||||
extern "C" LEAN_EXPORT object * lean_dbg_stack_trace(obj_arg fn) {
|
||||
print_backtrace();
|
||||
print_backtrace(/* force_stderr */ false);
|
||||
return lean_apply_1(fn, lean_box(0));
|
||||
}
|
||||
|
||||
|
||||
@@ -474,6 +474,9 @@ extern "C" LEAN_EXPORT int lean_main(int argc, char ** argv) {
|
||||
#elif defined(LEAN_WINDOWS)
|
||||
// "best practice" according to https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-seterrormode
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
// properly formats Unicode characters on the Windows console
|
||||
// see https://github.com/leanprover/lean4/issues/4291
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
auto init_start = std::chrono::steady_clock::now();
|
||||
lean::initializer init;
|
||||
|
||||
BIN
stage0/src/CMakeLists.txt
generated
BIN
stage0/src/CMakeLists.txt
generated
Binary file not shown.
BIN
stage0/src/kernel/expr.h
generated
BIN
stage0/src/kernel/expr.h
generated
Binary file not shown.
BIN
stage0/src/kernel/for_each_fn.cpp
generated
BIN
stage0/src/kernel/for_each_fn.cpp
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