Compare commits

..

30 Commits

Author SHA1 Message Date
Sebastian Ullrich
26611b153b chore: temporarily disable Elab.async in the server 2025-02-27 09:14:09 +01:00
Kim Morrison
727c696d9f chore: add @[simp] to List.getElem_append_left|right (#7216)
Helps with confluence.
2025-02-27 03:01:33 +00:00
Mac Malone
cf2b7f4c1b feat: lake: builtin inits, elabs, & macros for DSL (#7171)
This PR changes the Lake DSL to use builtin elaborators, macros, and
initializers.

This works out of the box for the Lake executable and is supported in
interactive contexts through the Lake plugin.
2025-02-27 02:34:14 +00:00
Leonardo de Moura
cd4383b6f3 feat: refine inequalites using disequalities in cutsat (#7252)
This PR implements inequality refinement using disequalities. It
minimizes the number of case splits cutsat will have to perform.
2025-02-27 01:33:58 +00:00
Cameron Zwarich
0d9859370a fix: make extern decls evaluate as ⊤ instead of ⊥ in LCNF.elimDeadBranches (#6928)
This PR makes extern decls evaluate as ⊤ rather than the default value
of ⊥ in the LCNF elimDeadBranches analysis.
2025-02-27 01:24:47 +00:00
Cameron Zwarich
c292ae2e0e fix: don't create reduced arity LCNF decls with no params (#7086)
This PR makes the arity reduction pass in the new code generator match
the old one when it comes to the behavior of decls with no used
parameters. This is important, because otherwise we might create a
top-level decl with no params that contains unreachable code, which
would get evaluated unconditionally during initialization. This actually
happens when initializing Init.Core built with the new code generator.
2025-02-27 01:23:34 +00:00
Kim Morrison
3113847806 chore: reenable Vector variable name linters (#7251) 2025-02-26 23:59:28 +00:00
Kim Morrison
d275455674 chore: alignment of a List/Array/Vector.reverse lemma (#7250)
Minor lemma alignment missed earlier.
2025-02-26 23:59:06 +00:00
Kim Morrison
a4d10742d3 feat: align List/Array/Vector.any/all theorems (#7249)
This PR completes alignment of theorems about
`List/Array/Vector.any/all`.
2025-02-26 23:53:53 +00:00
Leonardo de Moura
777fba495a feat: cutsat implied equalities (#7248)
This PR implements simple equality propagation in cutsat `p <= 0 -> -p
<= 0 -> p = 0`
2025-02-26 22:52:37 +00:00
Sebastian Ullrich
2e66341f69 feat: Environment.realizeConst (#7076)
This PR introduces the central parallelism API for ensuring that helper
declarations can be generated lazily without duplicating work or
creating conflicts across threads.
2025-02-26 19:32:21 +00:00
Mac Malone
2e44585ce9 fix: set CP_UTF8 on Windows (#7213)
This PR adds `SetConsoleOutputCP(CP_UTF8)` during runtime initialization
to properly display Unicode on the Windows console. This effects both
the Lean executable itself and user executables (including Lake).

Closes #4291.
2025-02-26 18:36:32 +00:00
Leonardo de Moura
e2f0e14b04 feat: disequalities in cutsat (#7244)
This PR adds support for disequalities in the cutsat procedure used in
`grind`.
2025-02-26 17:26:59 +00:00
Henrik Böving
e801dc96ca chore: cleanup non terminal simps in LRAT (#7243)
This PR cleans up non terminal simps in the LRAT checking module.
2025-02-26 15:02:57 +00:00
Henrik Böving
56a3ac1814 feat: bv_decide structure projections and if (#7242)
This PR makes sure bv_decide can work with projections applied to `ite`
and `cond` in its structures pass.
2025-02-26 14:47:44 +00:00
Paul Reichert
6c62f720c8 feat: tree map lemmas for getThenInsertIfNew? (#7229)
This PR provides lemmas for the tree map function `getThenInsertIfNew?`.

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-26 10:29:51 +00:00
Eric Wieser
a57efd0a88 fix: free memory from lib_uv requests (#7151)
This PR fixes a memory leak in `IO.FS.createTempFile`
2025-02-26 07:52:34 +00:00
Paul Reichert
7e2d6e2254 feat: tree map lemmas for the getKey variants and insertIfNew functions (#7221)
This PR provides lemmas about the tree map functions `getKey?`,
`getKey`, `getKey!`, `getKeyD` and `insertIfNew` and their interaction
with other functions for which lemmas already exist.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-26 07:36:28 +00:00
Kim Morrison
4603e1a6ad feat: add Array/Vector.replace (#7235)
This PR adds `Array.replace` and `Vector.replace`, proves the
correspondences with `List.replace`, and reproduces the basic API. In
order to do so, it fills in some gaps in the `List.findX` APIs.
2025-02-26 06:03:45 +00:00
Mac Malone
550d2918b8 feat: Lake plugin w/ USE_LAKE (#7233)
This PR uses the Lake plugin when Lake is built with Lake via
`USE_LAKE`.
2025-02-26 04:05:15 +00:00
Leonardo de Moura
eb5ad2c03a feat: disequality propagation from grind core module to cutsat (#7234)
This PR implements dIsequality propagation from `grind` core module to
cutsat.
2025-02-26 03:34:39 +00:00
Leonardo de Moura
769fe4ebf6 feat: add Grind.mkDiseqProof? (#7231)
This PR implements functions for constructing disequality proofs in
`grind`.
2025-02-25 23:40:07 +00:00
Joachim Breitner
8130fdc474 feat: induction tactic to err on extra targets (#7224)
This PR make `induction … using` and `cases … using` complain if more
targets were given than expected by that eliminator.
2025-02-25 20:53:16 +00:00
Markus Himmel
41bba59868 feat: UIntX conversion lemmas (part 2/2) (#7210)
This PR adds the remaining lemmas about iterated conversions between
finite types starting with something of type `UIntX`.

In the near future, we will add similar lemmas when starting with
something of type `IntX`, `Nat`, `Int`, `BitVec` or `Fin`.
2025-02-25 18:52:17 +00:00
Eric Wieser
115f06c32a fix: missing indents in Try this message (#7191)
This PR fixes the indentation of "Try this" suggestions in widget-less
multiline messages, as they appear in `#guard_msgs` outputs.
2025-02-25 16:55:50 +00:00
Sebastian Ullrich
1e1e17cb35 fix: be consistent in not reporting newlines between trace nodes to info view (#7143)
This PR makes the server consistently not report newlines between trace
nodes to the info view, enabling it to render them on dedicates lines
without extraneous spacing between them in all circumstances.

The info view code will separately need to be adjusted to this new
behavior, until then this change will make adjacent trace node leafs
consistently be rendered *on the same line* if there is sufficient
space. The cmdline should be unaffected in any case.
2025-02-25 16:16:35 +00:00
Paul Reichert
831e8d768b feat: tree map lemmas for get, get! and getD (#7207)
This PR provides lemmas for the tree map functions `get`, `get!` and
`getD` in relation to the other operations for which lemmas already
exist.

Internally, the `simp_to_model` tactic was provided two new simp lemmas
to eliminate some common complications that require `rw`'ing before
using `simp_to_model`. However, it is still necessary to sometimes
`revert` some hypotheses.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-25 15:26:50 +00:00
jrr6
b4b878b2d0 fix: prevent exact? and apply? from suggesting invalid tactics (#7192)
This PR prevents `exact?` and `apply?` from suggesting tactics that
correspond to correct proofs but do not elaborate, and it allows these
tactics to suggest `expose_names` when needed.

These tactics now indicate that a non-compiling term was generated but
do not suggest that that term be inserted. `exact?` also no longer
suggests that the user try `apply?` if no partial suggestions were
found.

This addresses part of #5407 but does not achieve the exact expected
behavior therein (due to #6122).
2025-02-25 15:24:09 +00:00
Paul Reichert
2377f35426 fix: replace the compare_self simp lemma with a less generic one (#7222)
This PR removes the `simp` attribute from `ReflCmp.compare_self` because
it matches arbitrary function applications. Instead, a new `simp` lemma
`ReflOrd.compare_self` is introduced, which only matches applications of
`compare`.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-25 10:08:23 +00:00
Lean stage0 autoupdater
c7f706baeb chore: update stage0 2025-02-25 08:57:53 +00:00
265 changed files with 6421 additions and 717 deletions

View File

@@ -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

View File

@@ -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 }}

View File

@@ -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 -/

View File

@@ -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

View File

@@ -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 }}

View File

@@ -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

View File

@@ -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

View File

@@ -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 = ? :=

View File

@@ -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} :

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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]

View File

@@ -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

View File

@@ -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 :=

View File

@@ -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)

View File

@@ -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 :=

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 }

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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))

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 ()

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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`.

View File

@@ -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
}

View File

@@ -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 =>

View 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

View File

@@ -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
/-

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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}"

View File

@@ -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

View File

@@ -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 : β) : β :=

View File

@@ -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 _]

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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
/-!

View File

@@ -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

View File

@@ -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 : β) : β :=

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 :=

View File

@@ -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 :=

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -10,7 +10,7 @@ open Lean
namespace Lake
initialize
builtin_initialize
registerBuiltinAttribute {
ref := by exact decl_name%
name := `test_runner

View File

@@ -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"

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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]?)

View File

@@ -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)

View File

@@ -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?

View File

@@ -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}"]

View File

@@ -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,

View File

@@ -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;
}
}

View File

@@ -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));
}

View File

@@ -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;

Binary file not shown.

BIN
stage0/src/kernel/expr.h generated

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More