Compare commits

...

56 Commits

Author SHA1 Message Date
Leonardo de Moura
f155e80698 test: beta reduction tests for grind 2025-01-19 13:11:25 -08:00
Leonardo de Moura
fcf2fee6a4 fix: better support for beta and partial applications 2025-01-19 13:08:04 -08:00
Leonardo de Moura
a2cea4c870 feat: beta reduction during internalization 2025-01-19 12:53:14 -08:00
Leonardo de Moura
3f9d62562f feat: propagateBeta at addEqStep 2025-01-19 12:11:30 -08:00
Leonardo de Moura
f773936893 fix: ensure isEqv can be applied to terms that do not have a ENode 2025-01-19 11:27:35 -08:00
Leonardo de Moura
8b2a953a60 fix: registerParent should register even if child is not in an equivalence class 2025-01-19 11:11:53 -08:00
Leonardo de Moura
fd555a7cce feat: add foldEqc 2025-01-19 11:01:40 -08:00
Leonardo de Moura
4af0afbb03 feat: grind beta-reduction support skeleton 2025-01-19 10:53:22 -08:00
Leonardo de Moura
c300e59cc8 chore: register constant function symbols as children 2025-01-19 09:55:28 -08:00
Sebastian Ullrich
645bdea23c perf: optimize setImportedEntries (#6698)
A small boost before #6691 made `modifyState` more complex, a larger
boost after.
2025-01-19 14:27:18 +00:00
Kim Morrison
35bbb48916 feat: refactor List/Array.mapFinIdx to unbundle the Fin argument (#6697)
This PR changes the arguments of `List/Array.mapFinIdx` from `(f : Fin
as.size → α → β)` to `(f : (i : Nat) → α → (h : i < as.size) → β)`, in
line with the API design elsewhere for `List/Array`.
2025-01-19 10:30:18 +00:00
Kim Morrison
b289b660c7 chore: remove deprecations from 2024-06 (#6696)
This PR removes deprecations in the standard library from June 2024.
2025-01-19 08:46:24 +00:00
Kim Morrison
75c104ce06 feat: align List/Array/Vector.reverse lemmas (#6695)
This PR aligns `List/Array/Vector.reverse` lemmas.
2025-01-19 08:40:06 +00:00
Lean stage0 autoupdater
74bd40d34d chore: update stage0 2025-01-19 03:03:18 +00:00
Leonardo de Moura
4213862b0e chore: remove [grind_norm] attribute (#6692)
This PR removes the `[grind_norm]` attribute. The normalization theorems
used by `grind` are now fixed and cannot be modified by users. We use
normalization theorems to ensure the built-in procedures receive term
wish expected "shapes". We use it for types that have built-in support
in grind. Users could misuse this feature as a simplification rule. For
example, consider the following example:

```lean
def replicate : (n : Nat) → (a : α) → List α
  | 0,   _ => []
  | n+1, a => a :: replicate n a

-- I want `grind` to instantiate the equations theorems for me.
attribute [grind] replicate

-- I want it to use the equation theorems as simplication rules too.
attribute [grind_norm] replicate

/--
info: [grind.assert] n = 0
[grind.assert] ¬replicate n xs = []
[grind.ematch.instance] replicate.eq_1: replicate 0 xs = []
[grind.assert] True
-/
set_option trace.grind.ematch.instance true in
set_option trace.grind.assert true in
example (xs : List α) : n = 0 → replicate n xs = [] := by
  grind -- fails :(
```

In this example, `grind` starts by asserting the two propositions as
expected: `n = 0`, and `¬replicate n xs = []`. The normalizer cannot
reduce `replicate n xs` as expected.
Then, the E-matching module finds the instance `replicate 0 xs = []` for
the equation theorem `replicate.eq_1` also as expected. But, then the
normalizer kicks in and reduces the new instance to `True`. By removing
`[grind_norm]` we elimninate this kind of misuse. Users that want to
preprocess a formula before invoking `grind` should use `simp` instead.
2025-01-19 02:12:01 +00:00
Sebastian Ullrich
4d8bc22228 feat: Environment.addConstAsync (#6691)
This PR introduces the central API for making parallel changes to the
environment
2025-01-19 02:00:16 +00:00
Lean stage0 autoupdater
7ee938290b chore: update stage0 2025-01-19 01:04:01 +00:00
Leonardo de Moura
478d42105f feat: init_grind_norm elaborator (#6690)
Motivation: we will remove the `[grind_norm]` attribute.
2025-01-19 00:15:13 +00:00
Kim Morrison
5998ba545b feat: regression tests for grind adapted from lean-egg (#6688)
Adapts, with permission, unit tests from `lean-egg` written by Marcus
Rossel as regression tests for `grind`.
2025-01-18 23:46:55 +00:00
Sebastian Ullrich
8a8417f6e1 refactor: getUnfoldableConst*? (#5997)
Continuation from #5429: eliminates uses of these two functions that
care about something other than reducible defs/theorems, then restricts
the function definition to these cases to be more true to its name.
2025-01-18 23:30:40 +00:00
Lean stage0 autoupdater
26941793ff chore: update stage0 2025-01-18 23:46:01 +00:00
Leonardo de Moura
70050c3798 chore: init_grind_norm command parser (#6689) 2025-01-18 23:07:54 +00:00
Sebastian Ullrich
50a0a97b49 refactor: move registration of namespaces on kernel add into elaborator (#6214)
Kernel checking will be moved to a different thread but namespace
registration should stay on the elaboration thread
2025-01-18 23:01:29 +00:00
Lean stage0 autoupdater
5fb2e892c8 chore: update stage0 2025-01-18 19:28:20 +00:00
Sebastian Ullrich
3770808b58 feat: split Lean.Kernel.Environment from Lean.Environment (#5145)
This PR splits the environment used by the kernel from that used by the
elaborator, providing the foundation for tracking of asynchronously
elaborated declarations, which will exist as a concept only in the
latter.

Minor changes:
* kernel diagnostics are moved from an environment extension to a direct
environment as they are the only extension used directly by the kernel
* `initQuot` is moved from an environment header field to a direct
environment as it is the only header field used by the kernel; this also
makes the remaining header immutable after import
2025-01-18 18:42:57 +00:00
Andrés Goens
5e63dd292f chore: fix typo in docstring of mkMVar (#6687)
This PR fixes a very small typo in the docstring of `mkMVar` that
misspelled the function it recommends to use instead.
2025-01-18 12:28:33 +00:00
Kitamado
98e3d6f663 fix: make #check_failure's output be info (#6685)
This PR fixes the issue that `#check_failure`'s output is warning

Closes #6684
2025-01-18 07:27:44 +00:00
Leonardo de Moura
d4070d4bfb fix: grind parameter issues and configuration (#6686)
This PR fixes parameter processing, initialization, and attribute
handling issues in the `grind` tactic.
2025-01-18 03:15:59 +00:00
Leonardo de Moura
4d4c0941be feat: extensionality theorems in grind (#6682)
This PR adds support for extensionality theorems (using the `[ext]`
attribute) to the `grind` tactic. Users can disable this functionality
using `grind -ext` . Below are examples that demonstrate problems now
solvable by `grind`.

```lean
open List in
example : (replicate n a).map f = replicate n (f a) := by
  grind only [Option.map_some', Option.map_none', getElem?_map, getElem?_replicate]
```

```lean
@[ext] structure S where
  a : Nat
  b : Bool

example (x y : S) : x.a = y.a → y.b = x.b → x = y := by
  grind
```
2025-01-17 23:59:36 +00:00
Leonardo de Moura
9b629cc81f chore: update stage0
Manual update stage0 is required to get the test suite green.
2025-01-17 12:31:14 -08:00
Leonardo de Moura
f374ef154e refactor: move ext environment extension to Lean.Meta.Tactic 2025-01-17 12:31:14 -08:00
Lean stage0 autoupdater
e3fd954318 chore: update stage0 2025-01-17 04:30:58 +00:00
Cameron Zwarich
b7815b5684 feat: add lcAny constant to Prelude (#6665)
This PR adds a new lcAny constant to Prelude, which is meant for use in
LCNF to represent types whose dependency on another term has been erased
during compilation. This is in addition to the existing lcErased
constant, which represents types that are irrelevant.
2025-01-17 01:33:35 +00:00
Cameron Zwarich
7f0ae22e43 fix: don't filter out local instances in LCNF toMono pass (#6664)
This PR changes the toMono pass to longer filter out type class
instances, because they may actually be needed for later compilation.
2025-01-17 01:32:49 +00:00
Leonardo de Moura
35a4da28ac feat: add simp-like parameters to grind (#6675)
This PR adds `simp`-like parameters to `grind`, and `grind only` similar
to `simp only`.
2025-01-17 01:08:45 +00:00
Henrik Böving
60142c967c chore: remove unneeded instance (#6671)
This PR removes an `Inhabited` instance from the imported LRAT checker
code that is unneeded but also potentially triggers for each `Inhabited`
query.
2025-01-16 18:32:37 +00:00
Leonardo de Moura
17c0187252 fix: add workaround for MessageData limitations (#6669)
This PR adds a workaround for the discrepancy between Terminal/Emacs and
VS Code when displaying info trees.
2025-01-16 16:58:20 +00:00
Leonardo de Moura
e42f7d9fc3 feat: equality resolution for grind (#6663)
This PR implements a basic equality resolution procedure for the `grind`
tactic.
2025-01-16 16:33:11 +00:00
Luisa Cicolini
906aa1be4b feat: add Nat.[shiftLeft_or_distrib, shiftLeft_xor_distrib, shiftLeft_and_distrib, testBit_mul_two_pow, bitwise_mul_two_pow, shiftLeft_bitwise_distrib] (#6630)
This PR adds theorems `Nat.[shiftLeft_or_distrib`,
shiftLeft_xor_distrib`, shiftLeft_and_distrib`, `testBit_mul_two_pow`,
`bitwise_mul_two_pow`, `shiftLeft_bitwise_distrib]`, to prove
`Nat.shiftLeft_or_distrib` by emulating the proof strategy of
`shiftRight_and_distrib`.

In particular, `Nat.shiftLeft_or_distrib` is necessary to simplify the
proofs in #6476.

---------

Co-authored-by: Alex Keizer <alex@keizer.dev>
2025-01-16 10:59:00 +00:00
Kim Morrison
f01527142e feat: align List.replicate/Array.mkArray/Vector.mkVector lemmas (#6667)
This PR aligns `List.replicate`/`Array.mkArray`/`Vector.mkVector`
lemmas.
2025-01-16 09:48:01 +00:00
Kim Morrison
f4c9934171 feat: Vector.getElem_flatMap (#6661)
This PR adds array indexing lemmas for `Vector.flatMap`. (These were not
available for `List` and `Array` due to variable lengths.)
2025-01-16 06:33:54 +00:00
Kim Morrison
80ddbf45eb feat: align List/Array/Vector.flatMap (#6660)
This PR defines `Vector.flatMap`, changes the order of arguments in
`List.flatMap` for consistency, and aligns the lemmas for
`List`/`Array`/`Vector` `flatMap`.
2025-01-16 05:19:28 +00:00
Leonardo de Moura
3a6c5cf4f1 feat: canonicalizer diagnostics (#6662)
This PR improves the canonicalizer used in the `grind` tactic and the
diagnostics it produces. It also adds a new configuration option,
`canonHeartbeats`, to address (some of) the issues. Here is an example
illustrating the new diagnostics, where we intentionally create a
problem by using a very small number of heartbeats.

<img width="1173" alt="image"
src="https://github.com/user-attachments/assets/484005c8-dcaa-4164-8fbf-617864ed7350"
/>
2025-01-16 04:59:18 +00:00
Leonardo de Moura
af4a7d7e98 fix: grind term preprocessor (#6659)
This PR fixes a bug in the `grind` term preprocessor. It was abstracting
nested proofs **before** reducible constants were unfolded.

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2025-01-16 01:22:06 +00:00
Leonardo de Moura
6259b4742c feat: improve case-split heuristic used in grind (#6658)
This PR ensures that `grind` avoids case-splitting on terms congruent to
those that have already been case-split.
2025-01-16 00:17:27 +00:00
Mac Malone
0050e9369c refactor: lake: use StateRefT for BuildStore (#6290)
This PR uses `StateRefT` instead of `StateT` to equip the Lake build
monad with a build store.

As a IO reference, different threads may now contend with the build
store. However, benchmark results indicate that this does not have a
significant performance impact. On a synchronization front, the lack of
a mutex should not be a concern because the build store is a
memorization data structure and thus order is theoretically irrelevant.
2025-01-15 23:42:32 +00:00
Leonardo de Moura
64cf5e5e6a feat: improve grind search procedure (#6657)
This PR improves the `grind` search procedure, and adds the new
configuration option: `failures`.
2025-01-15 23:08:41 +00:00
Kim Morrison
127b3f9191 feat: more grind tests (#6650)
This PR adds some tests for `grind`, working on `List` lemmas.
2025-01-15 23:00:23 +00:00
Leonardo de Moura
65175dc7d4 feat: improvegrind diagnostic information (#6656)
This PR improves the diagnostic information provided in `grind` failure
states. We now include the list of issues found during the search, and
all search thresholds that have been reached. This PR also improves its
formatting.
2025-01-15 20:57:28 +00:00
Leonardo de Moura
54f06ccd64 feat: better support for partial applications in the E-matching procedure (#6654)
This PR improves the support for partial applications in the E-matching
procedure used in `grind`.
2025-01-15 18:31:34 +00:00
Leonardo de Moura
b3f8feffd3 fix: improve E-matching pattern selection heuristics (#6653)
This PR improves the E-matching pattern selection heuristics in the
`grind` tactic. They now take into account type predicates and
transformers.
2025-01-15 16:43:59 +00:00
Lukas Gerlach
6665837232 feat: verify insertMany method for adding lists to HashMaps (#6211)
This PR verifies the `insertMany` method on `HashMap`s for the special
case of inserting lists.

---------

Co-authored-by: jt0202 <johannes.tantow@gmail.com>
Co-authored-by: monsterkrampe <monsterkrampe@users.noreply.github.com>
Co-authored-by: Johannes Tantow <44068763+jt0202@users.noreply.github.com>
2025-01-15 14:57:26 +00:00
Henrik Böving
c7fd873333 feat: tag lemmas 2025-01-15 15:17:36 +01:00
Henrik Böving
a10ce9492f chore: update stage0 2025-01-15 15:17:36 +01:00
Henrik Böving
838ad281f2 feat: add the int_toBitVec simpset 2025-01-15 15:17:36 +01:00
Henrik Böving
a1ef26bd8b perf: improve bv_decide preprocessing based on Bitwuzla optimisations (#6641)
This PR implements several optimisation tricks from Bitwuzla's
preprocessing passes into the Lean equivalent in `bv_decide`. Note that
these changes are mostly geared towards large proof states as for
example seen in SMT-Lib.
2025-01-15 12:09:43 +00:00
650 changed files with 10357 additions and 2026 deletions

View File

@@ -699,12 +699,12 @@ else()
endif()
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
add_custom_target(lake_lib ALL
add_custom_target(lake_lib
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
DEPENDS leanshared
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Lake
VERBATIM)
add_custom_target(lake_shared ALL
add_custom_target(lake_shared
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
DEPENDS lake_lib
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make libLake_shared

View File

@@ -455,7 +455,7 @@ def mapM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
/-- Variant of `mapIdxM` which receives the index as a `Fin as.size`. -/
@[inline]
def mapFinIdxM {α : Type u} {β : Type v} {m : Type v Type w} [Monad m]
(as : Array α) (f : Fin as.size α m β) : m (Array β) :=
(as : Array α) (f : (i : Nat) α (h : i < as.size) m β) : m (Array β) :=
let rec @[specialize] map (i : Nat) (j : Nat) (inv : i + j = as.size) (bs : Array β) : m (Array β) := do
match i, inv with
| 0, _ => pure bs
@@ -464,12 +464,12 @@ def mapFinIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
rw [ inv, Nat.add_assoc, Nat.add_comm 1 j, Nat.add_comm]
apply Nat.le_add_right
have : i + (j + 1) = as.size := by rw [ inv, Nat.add_comm j 1, Nat.add_assoc]
map i (j+1) this (bs.push ( f j, j_lt (as.get j j_lt)))
map i (j+1) this (bs.push ( f j (as.get j j_lt) j_lt))
map as.size 0 rfl (mkEmpty as.size)
@[inline]
def mapIdxM {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : Nat α m β) (as : Array α) : m (Array β) :=
as.mapFinIdxM fun i a => f i a
as.mapFinIdxM fun i a _ => f i a
@[inline]
def findSomeM? {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m (Option β)) (as : Array α) : m (Option β) := do
@@ -588,7 +588,7 @@ def map {α : Type u} {β : Type v} (f : α → β) (as : Array α) : Array β :
/-- Variant of `mapIdx` which receives the index as a `Fin as.size`. -/
@[inline]
def mapFinIdx {α : Type u} {β : Type v} (as : Array α) (f : Fin as.size α β) : Array β :=
def mapFinIdx {α : Type u} {β : Type v} (as : Array α) (f : (i : Nat) α (h : i < as.size) β) : Array β :=
Id.run <| as.mapFinIdxM f
@[inline]

View File

@@ -93,7 +93,7 @@ theorem size_eq_one {l : Array α} : l.size = 1 ↔ ∃ a, l = #[a] := by
/-! ### push -/
theorem push_ne_empty {a : α} {xs : Array α} : xs.push a #[] := by
@[simp] theorem push_ne_empty {a : α} {xs : Array α} : xs.push a #[] := by
cases xs
simp
@@ -174,10 +174,6 @@ theorem mkArray_succ : mkArray (n + 1) a = (mkArray n a).push a := by
apply toList_inj.1
simp [List.replicate_succ']
theorem mkArray_inj : mkArray n a = mkArray m b n = m (n = 0 a = b) := by
rw [ List.replicate_inj, toList_inj]
simp
@[simp] theorem getElem_mkArray (n : Nat) (v : α) (h : i < (mkArray n v).size) :
(mkArray n v)[i] = v := by simp [ getElem_toList]
@@ -1383,8 +1379,6 @@ theorem filter_eq_push_iff {p : α → Bool} {l l' : Array α} {a : α} :
· rintro l₁, l₂, h₁, h₂, h₃, h₄
refine l₂.reverse, l₁.reverse, by simp_all
@[deprecated filter_map (since := "2024-06-15")] abbrev map_filter := @filter_map
theorem mem_of_mem_filter {a : α} {l} (h : a filter p l) : a l :=
(mem_filter.mp h).1
@@ -1560,6 +1554,11 @@ theorem filterMap_eq_push_iff {f : α → Option β} {l : Array α} {l' : Array
cases bs
simp
theorem toArray_append {xs : List α} {ys : Array α} :
xs.toArray ++ ys = (xs ++ ys.toList).toArray := by
rcases ys with ys
simp
@[simp] theorem toArray_eq_append_iff {xs : List α} {as bs : Array α} :
xs.toArray = as ++ bs xs = as.toList ++ bs.toList := by
cases as
@@ -1871,6 +1870,11 @@ theorem append_eq_map_iff {f : α → β} :
rw [ flatten_map_toArray]
simp
theorem flatten_toArray (l : List (Array α)) :
l.toArray.flatten = (l.map Array.toList).flatten.toArray := by
apply ext'
simp
@[simp] theorem size_flatten (L : Array (Array α)) : L.flatten.size = (L.map size).sum := by
cases L using array₂_induction
simp [Function.comp_def]
@@ -1886,14 +1890,14 @@ theorem mem_flatten : ∀ {L : Array (Array α)}, a ∈ L.flatten ↔ ∃ l, l
· rintro s, h₁, h₂
refine s.toList, s, h₁, rfl, h₂
@[simp] theorem flatten_eq_nil_iff {L : Array (Array α)} : L.flatten = #[] l L, l = #[] := by
@[simp] theorem flatten_eq_empty_iff {L : Array (Array α)} : L.flatten = #[] l L, l = #[] := by
induction L using array₂_induction
simp
@[simp] theorem nil_eq_flatten_iff {L : Array (Array α)} : #[] = L.flatten l L, l = #[] := by
rw [eq_comm, flatten_eq_nil_iff]
@[simp] theorem empty_eq_flatten_iff {L : Array (Array α)} : #[] = L.flatten l L, l = #[] := by
rw [eq_comm, flatten_eq_empty_iff]
theorem flatten_ne_nil_iff {xs : Array (Array α)} : xs.flatten #[] x, x xs x #[] := by
theorem flatten_ne_empty_iff {xs : Array (Array α)} : xs.flatten #[] x, x xs x #[] := by
simp
theorem exists_of_mem_flatten : a flatten L l, l L a l := mem_flatten.1
@@ -2029,8 +2033,418 @@ theorem eq_iff_flatten_eq {L L' : Array (Array α)} :
rw [List.map_inj_right]
simp +contextual
/-! ### flatMap -/
theorem flatMap_def (l : Array α) (f : α Array β) : l.flatMap f = flatten (map f l) := by
rcases l with l
simp [flatten_toArray, Function.comp_def, List.flatMap_def]
theorem flatMap_toList (l : Array α) (f : α List β) :
l.toList.flatMap f = (l.flatMap (fun a => (f a).toArray)).toList := by
rcases l with l
simp
@[simp] theorem toList_flatMap (l : Array α) (f : α Array β) :
(l.flatMap f).toList = l.toList.flatMap fun a => (f a).toList := by
rcases l with l
simp
@[simp] theorem flatMap_id (l : Array (Array α)) : l.flatMap id = l.flatten := by simp [flatMap_def]
@[simp] theorem flatMap_id' (l : Array (Array α)) : l.flatMap (fun a => a) = l.flatten := by simp [flatMap_def]
@[simp]
theorem size_flatMap (l : Array α) (f : α Array β) :
(l.flatMap f).size = sum (map (fun a => (f a).size) l) := by
rcases l with l
simp [Function.comp_def]
@[simp] theorem mem_flatMap {f : α Array β} {b} {l : Array α} : b l.flatMap f a, a l b f a := by
simp [flatMap_def, mem_flatten]
exact fun _, a, h₁, rfl, h₂ => a, h₁, h₂, fun a, h₁, h₂ => _, a, h₁, rfl, h₂
theorem exists_of_mem_flatMap {b : β} {l : Array α} {f : α Array β} :
b l.flatMap f a, a l b f a := mem_flatMap.1
theorem mem_flatMap_of_mem {b : β} {l : Array α} {f : α Array β} {a} (al : a l) (h : b f a) :
b l.flatMap f := mem_flatMap.2 a, al, h
@[simp]
theorem flatMap_eq_empty_iff {l : Array α} {f : α Array β} : l.flatMap f = #[] x l, f x = #[] := by
rw [flatMap_def, flatten_eq_empty_iff]
simp
theorem forall_mem_flatMap {p : β Prop} {l : Array α} {f : α Array β} :
( (x) (_ : x l.flatMap f), p x) (a) (_ : a l) (b) (_ : b f a), p b := by
simp only [mem_flatMap, forall_exists_index, and_imp]
constructor <;> (intros; solve_by_elim)
theorem flatMap_singleton (f : α Array β) (x : α) : #[x].flatMap f = f x := by
simp
@[simp] theorem flatMap_singleton' (l : Array α) : (l.flatMap fun x => #[x]) = l := by
rcases l with l
simp
@[simp] theorem flatMap_append (xs ys : Array α) (f : α Array β) :
(xs ++ ys).flatMap f = xs.flatMap f ++ ys.flatMap f := by
rcases xs with xs
rcases ys with ys
simp
theorem flatMap_assoc {α β} (l : Array α) (f : α Array β) (g : β Array γ) :
(l.flatMap f).flatMap g = l.flatMap fun x => (f x).flatMap g := by
rcases l with l
simp [List.flatMap_assoc, toList_flatMap]
theorem map_flatMap (f : β γ) (g : α Array β) (l : Array α) :
(l.flatMap g).map f = l.flatMap fun a => (g a).map f := by
rcases l with l
simp [List.map_flatMap]
theorem flatMap_map (f : α β) (g : β Array γ) (l : Array α) :
(map f l).flatMap g = l.flatMap (fun a => g (f a)) := by
rcases l with l
simp [List.flatMap_map]
theorem map_eq_flatMap {α β} (f : α β) (l : Array α) : map f l = l.flatMap fun x => #[f x] := by
simp only [ map_singleton]
rw [ flatMap_singleton' l, map_flatMap, flatMap_singleton']
theorem filterMap_flatMap {β γ} (l : Array α) (g : α Array β) (f : β Option γ) :
(l.flatMap g).filterMap f = l.flatMap fun a => (g a).filterMap f := by
rcases l with l
simp [List.filterMap_flatMap]
theorem filter_flatMap (l : Array α) (g : α Array β) (f : β Bool) :
(l.flatMap g).filter f = l.flatMap fun a => (g a).filter f := by
rcases l with l
simp [List.filter_flatMap]
theorem flatMap_eq_foldl (f : α Array β) (l : Array α) :
l.flatMap f = l.foldl (fun acc a => acc ++ f a) #[] := by
rcases l with l
simp only [List.flatMap_toArray, List.flatMap_eq_foldl, size_toArray, List.foldl_toArray']
suffices l', (List.foldl (fun acc a => acc ++ (f a).toList) l' l).toArray =
List.foldl (fun acc a => acc ++ f a) l'.toArray l by
simpa using this []
induction l with
| nil => simp
| cons a l ih =>
intro l'
simp [ih ((l' ++ (f a).toList)), toArray_append]
/-! ### mkArray -/
@[simp] theorem mkArray_one : mkArray 1 a = #[a] := rfl
/-- Variant of `mkArray_succ` that prepends `a` at the beginning of the array. -/
theorem mkArray_succ' : mkArray (n + 1) a = #[a] ++ mkArray n a := by
apply Array.ext'
simp [List.replicate_succ]
@[simp] theorem mem_mkArray {a b : α} {n} : b mkArray n a n 0 b = a := by
unfold mkArray
simp only [mem_toArray, List.mem_replicate]
theorem eq_of_mem_mkArray {a b : α} {n} (h : b mkArray n a) : b = a := (mem_mkArray.1 h).2
theorem forall_mem_mkArray {p : α Prop} {a : α} {n} :
( b, b mkArray n a p b) n = 0 p a := by
cases n <;> simp [mem_mkArray]
@[simp] theorem mkArray_succ_ne_empty (n : Nat) (a : α) : mkArray (n+1) a #[] := by
simp [mkArray_succ]
@[simp] theorem mkArray_eq_empty_iff {n : Nat} (a : α) : mkArray n a = #[] n = 0 := by
cases n <;> simp
@[simp] theorem getElem?_mkArray_of_lt {n : Nat} {m : Nat} (h : m < n) : (mkArray n a)[m]? = some a := by
simp [getElem?_mkArray, h]
@[simp] theorem mkArray_inj : mkArray n a = mkArray m b n = m (n = 0 a = b) := by
rw [ toList_inj]
simp
theorem eq_mkArray_of_mem {a : α} {l : Array α} (h : (b) (_ : b l), b = a) : l = mkArray l.size a := by
rw [ toList_inj]
simpa using List.eq_replicate_of_mem (by simpa using h)
theorem eq_mkArray_iff {a : α} {n} {l : Array α} :
l = mkArray n a l.size = n (b) (_ : b l), b = a := by
rw [ toList_inj]
simpa using List.eq_replicate_iff (l := l.toList)
theorem map_eq_mkArray_iff {l : Array α} {f : α β} {b : β} :
l.map f = mkArray l.size b x l, f x = b := by
simp [eq_mkArray_iff]
@[simp] theorem map_const (l : Array α) (b : β) : map (Function.const α b) l = mkArray l.size b :=
map_eq_mkArray_iff.mpr fun _ _ => rfl
@[simp] theorem map_const_fun (x : β) : map (Function.const α x) = (mkArray ·.size x) := by
funext l
simp
/-- Variant of `map_const` using a lambda rather than `Function.const`. -/
-- This can not be a `@[simp]` lemma because it would fire on every `List.map`.
theorem map_const' (l : Array α) (b : β) : map (fun _ => b) l = mkArray l.size b :=
map_const l b
@[simp] theorem set_mkArray_self : (mkArray n a).set i a h = mkArray n a := by
apply Array.ext'
simp
@[simp] theorem setIfInBounds_mkArray_self : (mkArray n a).setIfInBounds i a = mkArray n a := by
apply Array.ext'
simp
@[simp] theorem mkArray_append_mkArray : mkArray n a ++ mkArray m a = mkArray (n + m) a := by
apply Array.ext'
simp
theorem append_eq_mkArray_iff {l₁ l₂ : Array α} {a : α} :
l₁ ++ l₂ = mkArray n a
l₁.size + l₂.size = n l₁ = mkArray l₁.size a l₂ = mkArray l₂.size a := by
simp [ toList_inj, List.append_eq_replicate_iff]
theorem mkArray_eq_append_iff {l₁ l₂ : Array α} {a : α} :
mkArray n a = l₁ ++ l₂
l₁.size + l₂.size = n l₁ = mkArray l₁.size a l₂ = mkArray l₂.size a := by
rw [eq_comm, append_eq_mkArray_iff]
@[simp] theorem map_mkArray : (mkArray n a).map f = mkArray n (f a) := by
apply Array.ext'
simp
theorem filter_mkArray (w : stop = n) :
(mkArray n a).filter p 0 stop = if p a then mkArray n a else #[] := by
apply Array.ext'
simp only [w, toList_filter', toList_mkArray, List.filter_replicate]
split <;> simp_all
@[simp] theorem filter_mkArray_of_pos (w : stop = n) (h : p a) :
(mkArray n a).filter p 0 stop = mkArray n a := by
simp [filter_mkArray, h, w]
@[simp] theorem filter_mkArray_of_neg (w : stop = n) (h : ¬ p a) :
(mkArray n a).filter p 0 stop = #[] := by
simp [filter_mkArray, h, w]
theorem filterMap_mkArray {f : α Option β} (w : stop = n := by simp) :
(mkArray n a).filterMap f 0 stop = match f a with | none => #[] | .some b => mkArray n b := by
apply Array.ext'
simp only [w, size_mkArray, toList_filterMap', toList_mkArray, List.filterMap_replicate]
split <;> simp_all
-- This is not a useful `simp` lemma because `b` is unknown.
theorem filterMap_mkArray_of_some {f : α Option β} (h : f a = some b) :
(mkArray n a).filterMap f = mkArray n b := by
simp [filterMap_mkArray, h]
@[simp] theorem filterMap_mkArray_of_isSome {f : α Option β} (h : (f a).isSome) :
(mkArray n a).filterMap f = mkArray n (Option.get _ h) := by
match w : f a, h with
| some b, _ => simp [filterMap_mkArray, h, w]
@[simp] theorem filterMap_mkArray_of_none {f : α Option β} (h : f a = none) :
(mkArray n a).filterMap f = #[] := by
simp [filterMap_mkArray, h]
@[simp] theorem flatten_mkArray_empty : (mkArray n (#[] : Array α)).flatten = #[] := by
rw [ toList_inj]
simp
@[simp] theorem flatten_mkArray_singleton : (mkArray n #[a]).flatten = mkArray n a := by
rw [ toList_inj]
simp
@[simp] theorem flatten_mkArray_mkArray : (mkArray n (mkArray m a)).flatten = mkArray (n * m) a := by
rw [ toList_inj]
simp
theorem flatMap_mkArray {β} (f : α Array β) : (mkArray n a).flatMap f = (mkArray n (f a)).flatten := by
rw [ toList_inj]
simp [flatMap_toList, List.flatMap_replicate]
@[simp] theorem isEmpty_mkArray : (mkArray n a).isEmpty = decide (n = 0) := by
rw [ List.toArray_replicate, List.isEmpty_toArray]
simp
@[simp] theorem sum_mkArray_nat (n : Nat) (a : Nat) : (mkArray n a).sum = n * a := by
rw [ List.toArray_replicate, List.sum_toArray]
simp
/-! ### Preliminaries about `swap` needed for `reverse`. -/
theorem swap_def (a : Array α) (i j : Nat) (hi hj) :
a.swap i j hi hj = (a.set i a[j]).set j a[i] (by simpa using hj) := by
simp [swap]
theorem getElem?_swap (a : Array α) (i j : Nat) (hi hj) (k : Nat) : (a.swap i j hi hj)[k]? =
if j = k then some a[i] else if i = k then some a[j] else a[k]? := by
simp [swap_def, getElem?_set]
/-! ### reverse -/
@[simp] theorem size_reverse (a : Array α) : a.reverse.size = a.size := by
let rec go (as : Array α) (i j) : (reverse.loop as i j).size = as.size := by
rw [reverse.loop]
if h : i < j then
simp [(go · (i+1) j-1, ·), h]
else simp [h]
termination_by j - i
simp only [reverse]; split <;> simp [go]
@[simp] theorem toList_reverse (a : Array α) : a.reverse.toList = a.toList.reverse := by
let rec go (as : Array α) (i j hj)
(h : i + j + 1 = a.size) (h₂ : as.size = a.size)
(H : k, as.toList[k]? = if i k k j then a.toList[k]? else a.toList.reverse[k]?)
(k : Nat) : (reverse.loop as i j, hj).toList[k]? = a.toList.reverse[k]? := by
rw [reverse.loop]; dsimp only; split <;> rename_i h₁
· match j with | j+1 => ?_
simp only [Nat.add_sub_cancel]
rw [(go · (i+1) j)]
· rwa [Nat.add_right_comm i]
· simp [size_swap, h₂]
· intro k
rw [getElem?_toList, getElem?_swap]
simp only [H, getElem_toList, List.getElem?_eq_getElem, Nat.le_of_lt h₁,
getElem?_toList]
split <;> rename_i h₂
· simp only [ h₂, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, and_false]
exact (List.getElem?_reverse' (j+1) i (Eq.trans (by simp_arith) h)).symm
split <;> rename_i h₃
· simp only [ h₃, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, false_and]
exact (List.getElem?_reverse' i (j+1) (Eq.trans (by simp_arith) h)).symm
simp only [Nat.succ_le, Nat.lt_iff_le_and_ne.trans (and_iff_left h₃),
Nat.lt_succ.symm.trans (Nat.lt_iff_le_and_ne.trans (and_iff_left (Ne.symm h₂)))]
· rw [H]; split <;> rename_i h₂
· cases Nat.le_antisymm (Nat.not_lt.1 h₁) (Nat.le_trans h₂.1 h₂.2)
cases Nat.le_antisymm h₂.1 h₂.2
exact (List.getElem?_reverse' _ _ h).symm
· rfl
termination_by j - i
simp only [reverse]
split
· match a with | [] | [_] => rfl
· have := Nat.sub_add_cancel (Nat.le_of_not_le _)
refine List.ext_getElem? <| go _ _ _ _ (by simp [this]) rfl fun k => ?_
split
· rfl
· rename_i h
simp only [ show k < _ + 1 _ from Nat.lt_succ (n := a.size - 1), this, Nat.zero_le,
true_and, Nat.not_lt] at h
rw [List.getElem?_eq_none_iff.2 _, List.getElem?_eq_none_iff.2 (a.toList.length_reverse _)]
@[simp] theorem _root_.List.reverse_toArray (l : List α) : l.toArray.reverse = l.reverse.toArray := by
apply ext'
simp only [toList_reverse]
@[simp] theorem reverse_push (as : Array α) (a : α) : (as.push a).reverse = #[a] ++ as.reverse := by
cases as
simp
@[simp] theorem mem_reverse {x : α} {as : Array α} : x as.reverse x as := by
cases as
simp
@[simp] theorem getElem_reverse (as : Array α) (i : Nat) (hi : i < as.reverse.size) :
(as.reverse)[i] = as[as.size - 1 - i]'(by simp at hi; omega) := by
cases as
simp
@[simp] theorem reverse_eq_empty_iff {xs : Array α} : xs.reverse = #[] xs = #[] := by
cases xs
simp
theorem reverse_ne_empty_iff {xs : Array α} : xs.reverse #[] xs #[] :=
not_congr reverse_eq_empty_iff
/-- Variant of `getElem?_reverse` with a hypothesis giving the linear relation between the indices. -/
theorem getElem?_reverse' {l : Array α} (i j) (h : i + j + 1 = l.size) : l.reverse[i]? = l[j]? := by
rcases l with l
simp at h
simp only [List.reverse_toArray, List.getElem?_toArray]
rw [List.getElem?_reverse' (l := l) _ _ h]
@[simp]
theorem getElem?_reverse {l : Array α} {i} (h : i < l.size) :
l.reverse[i]? = l[l.size - 1 - i]? := by
cases l
simp_all
@[simp] theorem reverse_reverse (as : Array α) : as.reverse.reverse = as := by
cases as
simp
theorem reverse_eq_iff {as bs : Array α} : as.reverse = bs as = bs.reverse := by
constructor <;> (rintro rfl; simp)
@[simp] theorem reverse_inj {xs ys : Array α} : xs.reverse = ys.reverse xs = ys := by
simp [reverse_eq_iff]
@[simp] theorem reverse_eq_push_iff {xs : Array α} {ys : Array α} {a : α} :
xs.reverse = ys.push a xs = #[a] ++ ys.reverse := by
rw [reverse_eq_iff, reverse_push]
@[simp] theorem map_reverse (f : α β) (l : Array α) : l.reverse.map f = (l.map f).reverse := by
cases l <;> simp [*]
@[simp] theorem filter_reverse (p : α Bool) (l : Array α) : (l.reverse.filter p) = (l.filter p).reverse := by
cases l
simp
@[simp] theorem filterMap_reverse (f : α Option β) (l : Array α) : (l.reverse.filterMap f) = (l.filterMap f).reverse := by
cases l
simp
@[simp] theorem reverse_append (as bs : Array α) : (as ++ bs).reverse = bs.reverse ++ as.reverse := by
cases as
cases bs
simp
@[simp] theorem reverse_eq_append_iff {xs ys zs : Array α} :
xs.reverse = ys ++ zs xs = zs.reverse ++ ys.reverse := by
cases xs
cases ys
cases zs
simp
/-- Reversing a flatten is the same as reversing the order of parts and reversing all parts. -/
theorem reverse_flatten (L : Array (Array α)) :
L.flatten.reverse = (L.map reverse).reverse.flatten := by
cases L using array₂_induction
simp [flatten_toArray, List.reverse_flatten, Function.comp_def]
/-- Flattening a reverse is the same as reversing all parts and reversing the flattened result. -/
theorem flatten_reverse (L : Array (Array α)) :
L.reverse.flatten = (L.map reverse).flatten.reverse := by
cases L using array₂_induction
simp [flatten_toArray, List.flatten_reverse, Function.comp_def]
theorem reverse_flatMap {β} (l : Array α) (f : α Array β) :
(l.flatMap f).reverse = l.reverse.flatMap (reverse f) := by
cases l
simp [List.reverse_flatMap, Function.comp_def]
theorem flatMap_reverse {β} (l : Array α) (f : α Array β) :
(l.reverse.flatMap f) = (l.flatMap (reverse f)).reverse := by
cases l
simp [List.flatMap_reverse, Function.comp_def]
@[simp] theorem reverse_mkArray (n) (a : α) : reverse (mkArray n a) = mkArray n a := by
rw [ toList_inj]
simp
/-! Content below this point has not yet been aligned with `List`. -/
/-! ### sum -/
theorem sum_eq_sum_toList [Add α] [Zero α] (as : Array α) : as.toList.sum = as.sum := by
cases as
simp [Array.sum, List.sum]
-- This is a duplicate of `List.toArray_toList`.
-- It's confusing to guess which namespace this theorem should live in,
-- so we provide both.
@@ -2214,6 +2628,7 @@ theorem getElem?_push_eq (a : Array α) (x : α) : (a.push x)[a.size]? = some x
@[deprecated getElem?_size (since := "2024-10-21")] abbrev get?_size := @getElem?_size
@[deprecated getElem_set_self (since := "2025-01-17")]
theorem get_set_eq (a : Array α) (i : Nat) (v : α) (h : i < a.size) :
(a.set i v h)[i]'(by simp [h]) = v := by
simp only [set, getElem_toList, List.getElem_set_self]
@@ -2237,17 +2652,9 @@ theorem get_set (a : Array α) (i : Nat) (hi : i < a.size) (j : Nat) (hj : j < a
(h : i j) : (a.set i v)[j]'(by simp [*]) = a[j] := by
simp only [set, getElem_toList, List.getElem_set_ne h]
theorem swap_def (a : Array α) (i j : Nat) (hi hj) :
a.swap i j hi hj = (a.set i a[j]).set j a[i] (by simpa using hj) := by
simp [swap]
@[simp] theorem toList_swap (a : Array α) (i j : Nat) (hi hj) :
(a.swap i j hi hj).toList = (a.toList.set i a[j]).set j a[i] := by simp [swap_def]
theorem getElem?_swap (a : Array α) (i j : Nat) (hi hj) (k : Nat) : (a.swap i j hi hj)[k]? =
if j = k then some a[i] else if i = k then some a[j] else a[k]? := by
simp [swap_def, get?_set]
@[simp] theorem swapAt_def (a : Array α) (i : Nat) (v : α) (hi) :
a.swapAt i v hi = (a[i], a.set i v) := rfl
@@ -2301,15 +2708,6 @@ theorem size_eq_length_toList (as : Array α) : as.size = as.toList.length := rf
@[deprecated size_swapIfInBounds (since := "2024-11-24")] abbrev size_swap! := @size_swapIfInBounds
@[simp] theorem size_reverse (a : Array α) : a.reverse.size = a.size := by
let rec go (as : Array α) (i j) : (reverse.loop as i j).size = as.size := by
rw [reverse.loop]
if h : i < j then
simp [(go · (i+1) j-1, ·), h]
else simp [h]
termination_by j - i
simp only [reverse]; split <;> simp [go]
@[simp] theorem size_range {n : Nat} : (range n).size = n := by
induction n <;> simp [range]
@@ -2320,61 +2718,6 @@ theorem size_eq_length_toList (as : Array α) : as.size = as.toList.length := rf
theorem getElem_range {n : Nat} {x : Nat} (h : x < (Array.range n).size) : (Array.range n)[x] = x := by
simp [ getElem_toList]
@[simp] theorem toList_reverse (a : Array α) : a.reverse.toList = a.toList.reverse := by
let rec go (as : Array α) (i j hj)
(h : i + j + 1 = a.size) (h₂ : as.size = a.size)
(H : k, as.toList[k]? = if i k k j then a.toList[k]? else a.toList.reverse[k]?)
(k : Nat) : (reverse.loop as i j, hj).toList[k]? = a.toList.reverse[k]? := by
rw [reverse.loop]; dsimp only; split <;> rename_i h₁
· match j with | j+1 => ?_
simp only [Nat.add_sub_cancel]
rw [(go · (i+1) j)]
· rwa [Nat.add_right_comm i]
· simp [size_swap, h₂]
· intro k
rw [getElem?_toList, getElem?_swap]
simp only [H, getElem_toList, List.getElem?_eq_getElem, Nat.le_of_lt h₁,
getElem?_toList]
split <;> rename_i h₂
· simp only [ h₂, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, and_false]
exact (List.getElem?_reverse' (j+1) i (Eq.trans (by simp_arith) h)).symm
split <;> rename_i h₃
· simp only [ h₃, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, false_and]
exact (List.getElem?_reverse' i (j+1) (Eq.trans (by simp_arith) h)).symm
simp only [Nat.succ_le, Nat.lt_iff_le_and_ne.trans (and_iff_left h₃),
Nat.lt_succ.symm.trans (Nat.lt_iff_le_and_ne.trans (and_iff_left (Ne.symm h₂)))]
· rw [H]; split <;> rename_i h₂
· cases Nat.le_antisymm (Nat.not_lt.1 h₁) (Nat.le_trans h₂.1 h₂.2)
cases Nat.le_antisymm h₂.1 h₂.2
exact (List.getElem?_reverse' _ _ h).symm
· rfl
termination_by j - i
simp only [reverse]
split
· match a with | [] | [_] => rfl
· have := Nat.sub_add_cancel (Nat.le_of_not_le _)
refine List.ext_getElem? <| go _ _ _ _ (by simp [this]) rfl fun k => ?_
split
· rfl
· rename_i h
simp only [ show k < _ + 1 _ from Nat.lt_succ (n := a.size - 1), this, Nat.zero_le,
true_and, Nat.not_lt] at h
rw [List.getElem?_eq_none_iff.2 _, List.getElem?_eq_none_iff.2 (a.toList.length_reverse _)]
end Array
open Array
namespace List
@[simp] theorem reverse_toArray (l : List α) : l.toArray.reverse = l.reverse.toArray := by
apply ext'
simp only [toList_reverse]
end List
namespace Array
/-! ### foldlM and foldrM -/
theorem foldlM_append [Monad m] [LawfulMonad m] (f : β α m β) (b) (l l' : Array α) :
@@ -3070,59 +3413,6 @@ theorem foldr_map' (g : α → β) (f : ααα) (f' : β → β → β
| nil => simp
| cons xs xss ih => simp [ih]
/-! ### sum -/
theorem sum_eq_sum_toList [Add α] [Zero α] (as : Array α) : as.sum = as.toList.sum := by
cases as
simp [Array.sum, List.sum]
/-! ### mkArray -/
theorem eq_mkArray_of_mem {a : α} {l : Array α} (h : (b) (_ : b l), b = a) : l = mkArray l.size a := by
rcases l with l
have := List.eq_replicate_of_mem (by simpa using h)
rw [this]
simp
theorem eq_mkArray_iff {a : α} {n} {l : Array α} :
l = mkArray n a l.size = n (b) (_ : b l), b = a := by
rcases l with l
simp [ List.eq_replicate_iff, toArray_eq]
theorem map_eq_mkArray_iff {l : Array α} {f : α β} {b : β} :
l.map f = mkArray l.size b x l, f x = b := by
simp [eq_mkArray_iff]
@[simp] theorem mem_mkArray (a : α) (n : Nat) : b mkArray n a n 0 b = a := by
rw [mkArray, mem_toArray]
simp
@[simp] theorem map_const (l : Array α) (b : β) : map (Function.const α b) l = mkArray l.size b :=
map_eq_mkArray_iff.mpr fun _ _ => rfl
@[simp] theorem map_const_fun (x : β) : map (Function.const α x) = (mkArray ·.size x) := by
funext l
simp
/-- Variant of `map_const` using a lambda rather than `Function.const`. -/
-- This can not be a `@[simp]` lemma because it would fire on every `Array.map`.
theorem map_const' (l : Array α) (b : β) : map (fun _ => b) l = mkArray l.size b :=
map_const l b
@[simp] theorem sum_mkArray_nat (n : Nat) (a : Nat) : (mkArray n a).sum = n * a := by
simp [sum_eq_sum_toList, List.sum_replicate_nat]
/-! ### reverse -/
@[simp] theorem mem_reverse {x : α} {as : Array α} : x as.reverse x as := by
cases as
simp
@[simp] theorem getElem_reverse (as : Array α) (i : Nat) (hi : i < as.reverse.size) :
(as.reverse)[i] = as[as.size - 1 - i]'(by simp at hi; omega) := by
cases as
simp [Array.getElem_reverse]
/-! ### findSomeRevM?, findRevM?, findSomeRev?, findRev? -/
@[simp] theorem findSomeRevM?_eq_findSomeM?_reverse

View File

@@ -12,81 +12,82 @@ namespace Array
/-! ### mapFinIdx -/
-- This could also be proved from `SatisfiesM_mapIdxM` in Batteries.
theorem mapFinIdx_induction (as : Array α) (f : Fin as.size α β)
theorem mapFinIdx_induction (as : Array α) (f : (i : Nat) α (h : i < as.size) β)
(motive : Nat Prop) (h0 : motive 0)
(p : Fin as.size β Prop)
(hs : i, motive i.1 p i (f i as[i]) motive (i + 1)) :
(p : (i : Nat) β (h : i < as.size) Prop)
(hs : i h, motive i p i (f i as[i] h) h motive (i + 1)) :
motive as.size eq : (Array.mapFinIdx as f).size = as.size,
i h, p i, h ((Array.mapFinIdx as f)[i]) := by
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : i h h', p i, h bs[i]) (hm : motive j) :
i h, p i ((Array.mapFinIdx as f)[i]) h := by
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : i h h', p i bs[i] h) (hm : motive j) :
let arr : Array β := Array.mapFinIdxM.map (m := Id) as f i j h bs
motive as.size eq : arr.size = as.size, i h, p i, h arr[i] := by
motive as.size eq : arr.size = as.size, i h, p i arr[i] h := by
induction i generalizing j bs with simp [mapFinIdxM.map]
| zero =>
have := (Nat.zero_add _).symm.trans h
exact this hm, h₁ this, fun _ _ => h₂ ..
| succ i ih =>
apply @ih (bs.push (f j, by omega as[j])) (j + 1) (by omega) (by simp; omega)
apply @ih (bs.push (f j as[j] (by omega))) (j + 1) (by omega) (by simp; omega)
· intro i i_lt h'
rw [getElem_push]
split
· apply h₂
· simp only [size_push] at h'
obtain rfl : i = j := by omega
apply (hs i, by omega hm).1
· exact (hs j, by omega hm).2
apply (hs i (by omega) hm).1
· exact (hs j (by omega) hm).2
simp [mapFinIdx, mapFinIdxM]; exact go rfl nofun h0
theorem mapFinIdx_spec (as : Array α) (f : Fin as.size α β)
(p : Fin as.size β Prop) (hs : i, p i (f i as[i])) :
theorem mapFinIdx_spec (as : Array α) (f : (i : Nat) α (h : i < as.size) β)
(p : (i : Nat) β (h : i < as.size) Prop) (hs : i h, p i (f i as[i] h) h) :
eq : (Array.mapFinIdx as f).size = as.size,
i h, p i, h ((Array.mapFinIdx as f)[i]) :=
(mapFinIdx_induction _ _ (fun _ => True) trivial p fun _ _ => hs .., trivial).2
i h, p i ((Array.mapFinIdx as f)[i]) h :=
(mapFinIdx_induction _ _ (fun _ => True) trivial p fun _ _ _ => hs .., trivial).2
@[simp] theorem size_mapFinIdx (a : Array α) (f : Fin a.size α β) : (a.mapFinIdx f).size = a.size :=
(mapFinIdx_spec (p := fun _ _ => True) (hs := fun _ => trivial)).1
@[simp] theorem size_mapFinIdx (a : Array α) (f : (i : Nat) α (h : i < a.size) β) :
(a.mapFinIdx f).size = a.size :=
(mapFinIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
@[simp] theorem size_zipWithIndex (as : Array α) : as.zipWithIndex.size = as.size :=
Array.size_mapFinIdx _ _
@[simp] theorem getElem_mapFinIdx (a : Array α) (f : Fin a.size α β) (i : Nat)
@[simp] theorem getElem_mapFinIdx (a : Array α) (f : (i : Nat) α (h : i < a.size) β) (i : Nat)
(h : i < (mapFinIdx a f).size) :
(a.mapFinIdx f)[i] = f i, by simp_all (a[i]'(by simp_all)) :=
(mapFinIdx_spec _ _ (fun i b => b = f i a[i]) fun _ => rfl).2 i _
(a.mapFinIdx f)[i] = f i (a[i]'(by simp_all)) (by simp_all) :=
(mapFinIdx_spec _ _ (fun i b h => b = f i a[i] h) fun _ _ => rfl).2 i _
@[simp] theorem getElem?_mapFinIdx (a : Array α) (f : Fin a.size α β) (i : Nat) :
@[simp] theorem getElem?_mapFinIdx (a : Array α) (f : (i : Nat) α (h : i < a.size) β) (i : Nat) :
(a.mapFinIdx f)[i]? =
a[i]?.pbind fun b h => f i, (getElem?_eq_some_iff.1 h).1 b := by
a[i]?.pbind fun b h => f i b (getElem?_eq_some_iff.1 h).1 := by
simp only [getElem?_def, size_mapFinIdx, getElem_mapFinIdx]
split <;> simp_all
@[simp] theorem toList_mapFinIdx (a : Array α) (f : Fin a.size α β) :
(a.mapFinIdx f).toList = a.toList.mapFinIdx (fun i a => f i, by simp a) := by
@[simp] theorem toList_mapFinIdx (a : Array α) (f : (i : Nat) α (h : i < a.size) β) :
(a.mapFinIdx f).toList = a.toList.mapFinIdx (fun i a h => f i a (by simpa)) := by
apply List.ext_getElem <;> simp
/-! ### mapIdx -/
theorem mapIdx_induction (f : Nat α β) (as : Array α)
(motive : Nat Prop) (h0 : motive 0)
(p : Fin as.size β Prop)
(hs : i, motive i.1 p i (f i as[i]) motive (i + 1)) :
(p : (i : Nat) β (h : i < as.size) Prop)
(hs : i h, motive i p i (f i as[i]) h motive (i + 1)) :
motive as.size eq : (as.mapIdx f).size = as.size,
i h, p i, h ((as.mapIdx f)[i]) :=
mapFinIdx_induction as (fun i a => f i a) motive h0 p hs
i h, p i ((as.mapIdx f)[i]) h :=
mapFinIdx_induction as (fun i a _ => f i a) motive h0 p hs
theorem mapIdx_spec (f : Nat α β) (as : Array α)
(p : Fin as.size β Prop) (hs : i, p i (f i as[i])) :
(p : (i : Nat) β (h : i < as.size) Prop) (hs : i h, p i (f i as[i]) h) :
eq : (as.mapIdx f).size = as.size,
i h, p i, h ((as.mapIdx f)[i]) :=
(mapIdx_induction _ _ (fun _ => True) trivial p fun _ _ => hs .., trivial).2
i h, p i ((as.mapIdx f)[i]) h :=
(mapIdx_induction _ _ (fun _ => True) trivial p fun _ _ _ => hs .., trivial).2
@[simp] theorem size_mapIdx (f : Nat α β) (as : Array α) : (as.mapIdx f).size = as.size :=
(mapIdx_spec (p := fun _ _ => True) (hs := fun _ => trivial)).1
(mapIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
@[simp] theorem getElem_mapIdx (f : Nat α β) (as : Array α) (i : Nat)
(h : i < (as.mapIdx f).size) :
(as.mapIdx f)[i] = f i (as[i]'(by simp_all)) :=
(mapIdx_spec _ _ (fun i b => b = f i as[i]) fun _ => rfl).2 i (by simp_all)
(mapIdx_spec _ _ (fun i b h => b = f i as[i]) fun _ _ => rfl).2 i (by simp_all)
@[simp] theorem getElem?_mapIdx (f : Nat α β) (as : Array α) (i : Nat) :
(as.mapIdx f)[i]? =
@@ -101,7 +102,7 @@ end Array
namespace List
@[simp] theorem mapFinIdx_toArray (l : List α) (f : Fin l.length α β) :
@[simp] theorem mapFinIdx_toArray (l : List α) (f : (i : Nat) α (h : i < l.length) β) :
l.toArray.mapFinIdx f = (l.mapFinIdx f).toArray := by
ext <;> simp

View File

@@ -1294,11 +1294,6 @@ theorem allOnes_shiftLeft_or_shiftLeft {x : BitVec w} {n : Nat} :
BitVec.allOnes w <<< n ||| x <<< n = BitVec.allOnes w <<< n := by
simp [ shiftLeft_or_distrib]
@[deprecated shiftLeft_add (since := "2024-06-02")]
theorem shiftLeft_shiftLeft {w : Nat} (x : BitVec w) (n m : Nat) :
(x <<< n) <<< m = x <<< (n + m) := by
rw [shiftLeft_add]
/-! ### shiftLeft reductions from BitVec to Nat -/
@[simp]
@@ -1946,11 +1941,6 @@ theorem msb_shiftLeft {x : BitVec w} {n : Nat} :
(x <<< n).msb = x.getMsbD n := by
simp [BitVec.msb]
@[deprecated shiftRight_add (since := "2024-06-02")]
theorem shiftRight_shiftRight {w : Nat} (x : BitVec w) (n m : Nat) :
(x >>> n) >>> m = x >>> (n + m) := by
rw [shiftRight_add]
/-! ### rev -/
theorem getLsbD_rev (x : BitVec w) (i : Fin w) :

View File

@@ -70,5 +70,3 @@ theorem utf8Size_eq (c : Char) : c.utf8Size = 1 c.utf8Size = 2 c.utf8Siz
rfl
end Char
@[deprecated Char.utf8Size (since := "2024-06-04")] abbrev String.csize := Char.utf8Size

View File

@@ -258,9 +258,6 @@ theorem ext_get? : ∀ {l₁ l₂ : List α}, (∀ n, l₁.get? n = l₂.get? n)
have h0 : some a = some a' := h 0
injection h0 with aa; simp only [aa, ext_get? fun n => h (n+1)]
/-- Deprecated alias for `ext_get?`. The preferred extensionality theorem is now `ext_getElem?`. -/
@[deprecated ext_get? (since := "2024-06-07")] abbrev ext := @ext_get?
/-! ### getD -/
/--
@@ -606,11 +603,11 @@ set_option linter.missingDocs false in
to get a list of lists, and then concatenates them all together.
* `[2, 3, 2].bind range = [0, 1, 0, 1, 2, 0, 1]`
-/
@[inline] def flatMap {α : Type u} {β : Type v} (a : List α) (b : α List β) : List β := flatten (map b a)
@[inline] def flatMap {α : Type u} {β : Type v} (b : α List β) (a : List α) : List β := flatten (map b a)
@[simp] theorem flatMap_nil (f : α List β) : List.flatMap [] f = [] := by simp [flatten, List.flatMap]
@[simp] theorem flatMap_nil (f : α List β) : List.flatMap f [] = [] := by simp [flatten, List.flatMap]
@[simp] theorem flatMap_cons x xs (f : α List β) :
List.flatMap (x :: xs) f = f x ++ List.flatMap xs f := by simp [flatten, List.flatMap]
List.flatMap f (x :: xs) = f x ++ List.flatMap f xs := by simp [flatten, List.flatMap]
set_option linter.missingDocs false in
@[deprecated flatMap (since := "2024-10-16")] abbrev bind := @flatMap
@@ -619,11 +616,6 @@ set_option linter.missingDocs false in
set_option linter.missingDocs false in
@[deprecated flatMap_cons (since := "2024-10-16")] abbrev cons_flatMap := @flatMap_cons
set_option linter.missingDocs false in
@[deprecated flatMap_nil (since := "2024-06-15")] abbrev nil_bind := @flatMap_nil
set_option linter.missingDocs false in
@[deprecated flatMap_cons (since := "2024-06-15")] abbrev cons_bind := @flatMap_cons
/-! ### replicate -/
/--
@@ -713,11 +705,6 @@ def elem [BEq α] (a : α) : List α → Bool
theorem elem_cons [BEq α] {a : α} :
(b::bs).elem a = match a == b with | true => true | false => bs.elem a := rfl
/-- `notElem a l` is `!(elem a l)`. -/
@[deprecated "Use `!(elem a l)` instead."(since := "2024-06-15")]
def notElem [BEq α] (a : α) (as : List α) : Bool :=
!(as.elem a)
/-! ### contains -/
@[inherit_doc elem] abbrev contains [BEq α] (as : List α) (a : α) : Bool :=

View File

@@ -96,14 +96,14 @@ The following operations are given `@[csimp]` replacements below:
/-! ### flatMap -/
/-- Tail recursive version of `List.flatMap`. -/
@[inline] def flatMapTR (as : List α) (f : α List β) : List β := go as #[] where
@[inline] def flatMapTR (f : α List β) (as : List α) : List β := go as #[] where
/-- Auxiliary for `flatMap`: `flatMap.go f as = acc.toList ++ bind f as` -/
@[specialize] go : List α Array β List β
| [], acc => acc.toList
| x::xs, acc => go xs (acc ++ f x)
@[csimp] theorem flatMap_eq_flatMapTR : @List.flatMap = @flatMapTR := by
funext α β as f
funext α β f as
let rec go : as acc, flatMapTR.go f as acc = acc.toList ++ as.flatMap f
| [], acc => by simp [flatMapTR.go, flatMap]
| x::xs, acc => by simp [flatMapTR.go, flatMap, go xs]
@@ -112,7 +112,7 @@ The following operations are given `@[csimp]` replacements below:
/-! ### flatten -/
/-- Tail recursive version of `List.flatten`. -/
@[inline] def flattenTR (l : List (List α)) : List α := flatMapTR l id
@[inline] def flattenTR (l : List (List α)) : List α := l.flatMapTR id
@[csimp] theorem flatten_eq_flattenTR : @flatten = @flattenTR := by
funext α l; rw [ List.flatMap_id, List.flatMap_eq_flatMapTR]; rfl

View File

@@ -813,11 +813,6 @@ theorem getElem_cons_length (x : α) (xs : List α) (i : Nat) (h : i = xs.length
(x :: xs)[i]'(by simp [h]) = (x :: xs).getLast (cons_ne_nil x xs) := by
rw [getLast_eq_getElem]; cases h; rfl
@[deprecated getElem_cons_length (since := "2024-06-12")]
theorem get_cons_length (x : α) (xs : List α) (n : Nat) (h : n = xs.length) :
(x :: xs).get n, by simp [h] = (x :: xs).getLast (cons_ne_nil x xs) := by
simp [getElem_cons_length, h]
/-! ### getLast? -/
@[simp] theorem getLast?_singleton (a : α) : getLast? [a] = a := rfl
@@ -1026,21 +1021,10 @@ theorem getLast?_tail (l : List α) : (tail l).getLast? = if l.length = 1 then n
| _ :: _, 0 => by simp
| _ :: l, i+1 => by simp [getElem?_map f l i]
@[deprecated getElem?_map (since := "2024-06-12")]
theorem get?_map (f : α β) : l i, (map f l).get? i = (l.get? i).map f
| [], _ => rfl
| _ :: _, 0 => rfl
| _ :: l, i+1 => get?_map f l i
@[simp] theorem getElem_map (f : α β) {l} {i : Nat} {h : i < (map f l).length} :
(map f l)[i] = f (l[i]'(length_map l f h)) :=
Option.some.inj <| by rw [ getElem?_eq_getElem, getElem?_map, getElem?_eq_getElem]; rfl
@[deprecated getElem_map (since := "2024-06-12")]
theorem get_map (f : α β) {l i} :
get (map f l) i = f (get l i, length_map l f i.2) := by
simp
@[simp] theorem map_id_fun : map (id : α α) = id := by
funext l
induction l <;> simp_all
@@ -1286,8 +1270,6 @@ theorem filter_map (f : β → α) (l : List β) : filter p (map f l) = map f (f
| nil => rfl
| cons a l IH => by_cases h : p (f a) <;> simp [*]
@[deprecated filter_map (since := "2024-06-15")] abbrev map_filter := @filter_map
theorem map_filter_eq_foldr (f : α β) (p : α Bool) (as : List α) :
map f (filter p as) = foldr (fun a bs => bif p a then f a :: bs else bs) [] as := by
induction as with
@@ -1332,8 +1314,6 @@ theorem filter_congr {p q : α → Bool} :
· simp [pa, h.1 pa, filter_congr h.2]
· simp [pa, h.1 pa, filter_congr h.2]
@[deprecated filter_congr (since := "2024-06-20")] abbrev filter_congr' := @filter_congr
theorem head_filter_of_pos {p : α Bool} {l : List α} (w : l []) (h : p (l.head w)) :
(filter p l).head ((ne_nil_of_mem (mem_filter.2 head_mem w, h))) = l.head w := by
cases l with
@@ -1561,11 +1541,6 @@ theorem getElem?_append {l₁ l₂ : List α} {i : Nat} :
· exact getElem?_append_left h
· exact getElem?_append_right (by simpa using h)
@[deprecated getElem?_append_right (since := "2024-06-12")]
theorem get?_append_right {l₁ l₂ : List α} {i : Nat} (h : l₁.length i) :
(l₁ ++ l₂).get? i = l₂.get? (i - l₁.length) := by
simp [getElem?_append_right, h]
/-- Variant of `getElem_append_left` useful for rewriting from the small list to the big list. -/
theorem getElem_append_left' (l₂ : List α) {l₁ : List α} {i : Nat} (hi : i < l₁.length) :
l₁[i] = (l₁ ++ l₂)[i]'(by simpa using Nat.lt_add_right l₂.length hi) := by
@@ -1576,33 +1551,11 @@ theorem getElem_append_right' (l₁ : List α) {l₂ : List α} {i : Nat} (hi :
l₂[i] = (l₁ ++ l₂)[i + l₁.length]'(by simpa [Nat.add_comm] using Nat.add_lt_add_left hi _) := by
rw [getElem_append_right] <;> simp [*, le_add_left]
@[deprecated "Deprecated without replacement." (since := "2024-06-12")]
theorem get_append_right_aux {l₁ l₂ : List α} {i : Nat}
(h₁ : l₁.length i) (h₂ : i < (l₁ ++ l₂).length) : i - l₁.length < l₂.length := by
rw [length_append] at h₂
exact Nat.sub_lt_left_of_lt_add h₁ h₂
set_option linter.deprecated false in
@[deprecated getElem_append_right (since := "2024-06-12")]
theorem get_append_right' {l₁ l₂ : List α} {i : Nat} (h₁ : l₁.length i) (h₂) :
(l₁ ++ l₂).get i, h₂ = l₂.get i - l₁.length, get_append_right_aux h₁ h₂ :=
Option.some.inj <| by rw [ get?_eq_get, get?_eq_get, get?_append_right h₁]
theorem getElem_of_append {l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.length = i) :
l[i]'(eq h by simp_arith) = a := Option.some.inj <| by
rw [ getElem?_eq_getElem, eq, getElem?_append_right (h Nat.le_refl _), h]
simp
@[deprecated "Deprecated without replacement." (since := "2024-06-12")]
theorem get_of_append_proof {l : List α}
(eq : l = l₁ ++ a :: l₂) (h : l₁.length = i) : i < length l := eq h by simp_arith
set_option linter.deprecated false in
@[deprecated getElem_of_append (since := "2024-06-12")]
theorem get_of_append {l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.length = i) :
l.get i, get_of_append_proof eq h = a := Option.some.inj <| by
rw [ get?_eq_get, eq, get?_append_right (h Nat.le_refl _), h, Nat.sub_self]; rfl
@[simp 1100] theorem singleton_append : [x] ++ l = x :: l := rfl
theorem append_inj :
@@ -1653,26 +1606,6 @@ theorem getLast_concat {a : α} : ∀ (l : List α), getLast (l ++ [a]) (by simp
| a::t => by
simp [getLast_cons _, getLast_concat t]
@[deprecated getElem_append (since := "2024-06-12")]
theorem get_append {l₁ l₂ : List α} (n : Nat) (h : n < l₁.length) :
(l₁ ++ l₂).get n, length_append .. Nat.lt_add_right _ h = l₁.get n, h := by
simp [getElem_append, h]
@[deprecated getElem_append_left (since := "2024-06-12")]
theorem get_append_left (as bs : List α) (h : i < as.length) {h'} :
(as ++ bs).get i, h' = as.get i, h := by
simp [getElem_append_left, h, h']
@[deprecated getElem_append_right (since := "2024-06-12")]
theorem get_append_right (as bs : List α) (h : as.length i) {h' h''} :
(as ++ bs).get i, h' = bs.get i - as.length, h'' := by
simp [getElem_append_right, h, h', h'']
@[deprecated getElem?_append_left (since := "2024-06-12")]
theorem get?_append {l₁ l₂ : List α} {n : Nat} (hn : n < l₁.length) :
(l₁ ++ l₂).get? n = l₁.get? n := by
simp [getElem?_append_left hn]
@[simp] theorem append_eq_nil_iff : p ++ q = [] p = [] q = [] := by
cases p <;> simp
@@ -2070,14 +2003,14 @@ theorem eq_iff_flatten_eq : ∀ {L L' : List (List α)},
theorem flatMap_def (l : List α) (f : α List β) : l.flatMap f = flatten (map f l) := by rfl
@[simp] theorem flatMap_id (l : List (List α)) : List.flatMap l id = l.flatten := by simp [flatMap_def]
@[simp] theorem flatMap_id (l : List (List α)) : l.flatMap id = l.flatten := by simp [flatMap_def]
@[simp] theorem flatMap_id' (l : List (List α)) : List.flatMap l (fun a => a) = l.flatten := by simp [flatMap_def]
@[simp] theorem flatMap_id' (l : List (List α)) : l.flatMap (fun a => a) = l.flatten := by simp [flatMap_def]
@[simp]
theorem length_flatMap (l : List α) (f : α List β) :
length (l.flatMap f) = sum (map (length f) l) := by
rw [List.flatMap, length_flatten, map_map]
length (l.flatMap f) = sum (map (fun a => (f a).length) l) := by
rw [List.flatMap, length_flatten, map_map, Function.comp_def]
@[simp] theorem mem_flatMap {f : α List β} {b} {l : List α} : b l.flatMap f a, a l b f a := by
simp [flatMap_def, mem_flatten]
@@ -2090,7 +2023,7 @@ theorem mem_flatMap_of_mem {b : β} {l : List α} {f : α → List β} {a} (al :
b l.flatMap f := mem_flatMap.2 a, al, h
@[simp]
theorem flatMap_eq_nil_iff {l : List α} {f : α List β} : List.flatMap l f = [] x l, f x = [] :=
theorem flatMap_eq_nil_iff {l : List α} {f : α List β} : l.flatMap f = [] x l, f x = [] :=
flatten_eq_nil_iff.trans <| by
simp only [mem_map, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂]
@@ -2199,10 +2132,6 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
(replicate n a)[m] = a :=
eq_of_mem_replicate (getElem_mem _)
@[deprecated getElem_replicate (since := "2024-06-12")]
theorem get_replicate (a : α) {n : Nat} (m : Fin _) : (replicate n a).get m = a := by
simp
theorem getElem?_replicate : (replicate n a)[m]? = if m < n then some a else none := by
by_cases h : m < n
· rw [getElem?_eq_getElem (by simpa), getElem_replicate, if_pos h]
@@ -2274,7 +2203,7 @@ theorem map_const' (l : List α) (b : β) : map (fun _ => b) l = replicate l.len
· intro i h₁ h₂
simp [getElem_set]
@[simp] theorem append_replicate_replicate : replicate n a ++ replicate m a = replicate (n + m) a := by
@[simp] theorem replicate_append_replicate : replicate n a ++ replicate m a = replicate (n + m) a := by
rw [eq_replicate_iff]
constructor
· simp
@@ -2282,6 +2211,9 @@ theorem map_const' (l : List α) (b : β) : map (fun _ => b) l = replicate l.len
simp only [mem_append, mem_replicate, ne_eq]
rintro (-, rfl | _, rfl) <;> rfl
@[deprecated replicate_append_replicate (since := "2025-01-16")]
abbrev append_replicate_replicate := @replicate_append_replicate
theorem append_eq_replicate_iff {l₁ l₂ : List α} {a : α} :
l₁ ++ l₂ = replicate n a
l₁.length + l₂.length = n l₁ = replicate l₁.length a l₂ = replicate l₂.length a := by
@@ -2292,6 +2224,11 @@ theorem append_eq_replicate_iff {l₁ l₂ : List α} {a : α} :
@[deprecated append_eq_replicate_iff (since := "2024-09-05")] abbrev append_eq_replicate := @append_eq_replicate_iff
theorem replicate_eq_append_iff {l₁ l₂ : List α} {a : α} :
replicate n a = l₁ ++ l₂
l₁.length + l₂.length = n l₁ = replicate l₁.length a l₂ = replicate l₂.length a := by
rw [eq_comm, append_eq_replicate_iff]
@[simp] theorem map_replicate : (replicate n a).map f = replicate n (f a) := by
ext1 n
simp only [getElem?_map, getElem?_replicate]
@@ -2343,7 +2280,7 @@ theorem filterMap_replicate_of_some {f : α → Option β} (h : f a = some b) :
induction n with
| zero => simp
| succ n ih =>
simp only [replicate_succ, flatten_cons, ih, append_replicate_replicate, replicate_inj, or_true,
simp only [replicate_succ, flatten_cons, ih, replicate_append_replicate, replicate_inj, or_true,
and_true, add_one_mul, Nat.add_comm]
theorem flatMap_replicate {β} (f : α List β) : (replicate n a).flatMap f = (replicate n (f a)).flatten := by
@@ -2430,10 +2367,6 @@ theorem getElem?_reverse' : ∀ {l : List α} (i j), i + j + 1 = length l →
rw [getElem?_append_left, getElem?_reverse' _ _ this]
rw [length_reverse, this]; apply Nat.lt_add_of_pos_right (Nat.succ_pos _)
@[deprecated getElem?_reverse' (since := "2024-06-12")]
theorem get?_reverse' {l : List α} (i j) (h : i + j + 1 = length l) : get? l.reverse i = get? l j := by
simp [getElem?_reverse' _ _ h]
@[simp]
theorem getElem?_reverse {l : List α} {i} (h : i < length l) :
l.reverse[i]? = l[l.length - 1 - i]? :=
@@ -2448,11 +2381,6 @@ theorem getElem_reverse {l : List α} {i} (h : i < l.reverse.length) :
rw [ getElem?_eq_getElem, getElem?_eq_getElem]
rw [getElem?_reverse (by simpa using h)]
@[deprecated getElem?_reverse (since := "2024-06-12")]
theorem get?_reverse {l : List α} {i} (h : i < length l) :
get? l.reverse i = get? l (l.length - 1 - i) := by
simp [getElem?_reverse h]
theorem reverseAux_reverseAux_nil (as bs : List α) : reverseAux (reverseAux as bs) [] = reverseAux bs as := by
induction as generalizing bs with
| nil => rfl
@@ -2493,10 +2421,6 @@ theorem mem_of_mem_getLast? {l : List α} {a : α} (h : a ∈ getLast? l) : a
@[simp] theorem map_reverse (f : α β) (l : List α) : l.reverse.map f = (l.map f).reverse := by
induction l <;> simp [*]
@[deprecated map_reverse (since := "2024-06-20")]
theorem reverse_map (f : α β) (l : List α) : (l.map f).reverse = l.reverse.map f := by
simp
@[simp] theorem filter_reverse (p : α Bool) (l : List α) : (l.reverse.filter p) = (l.filter p).reverse := by
induction l with
| nil => simp
@@ -2960,11 +2884,6 @@ are often used for theorems about `Array.pop`.
| _::_::_, 0, _ => rfl
| _::_::_, i+1, h => getElem_dropLast _ i (Nat.add_one_lt_add_one_iff.mp h)
@[deprecated getElem_dropLast (since := "2024-06-12")]
theorem get_dropLast (xs : List α) (i : Fin xs.dropLast.length) :
xs.dropLast.get i = xs.get i, Nat.lt_of_lt_of_le i.isLt (length_dropLast .. Nat.pred_le _) := by
simp
theorem getElem?_dropLast (xs : List α) (i : Nat) :
xs.dropLast[i]? = if i < xs.length - 1 then xs[i]? else none := by
split
@@ -3502,29 +3421,6 @@ theorem mem_iff_get? {a} {l : List α} : a ∈ l ↔ ∃ n, l.get? n = some a :=
/-! ### Deprecations -/
@[deprecated getD_eq_getElem?_getD (since := "2024-06-12")]
theorem getD_eq_get? : l n (a : α), getD l n a = (get? l n).getD a := by simp
@[deprecated getElem_singleton (since := "2024-06-12")]
theorem get_singleton (a : α) (n : Fin 1) : get [a] n = a := by simp
@[deprecated getElem?_concat_length (since := "2024-06-12")]
theorem get?_concat_length (l : List α) (a : α) : (l ++ [a]).get? l.length = some a := by simp
@[deprecated getElem_set_self (since := "2024-06-12")]
theorem get_set_eq {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
(l.set i a).get i, h = a := by
simp
@[deprecated getElem_set_ne (since := "2024-06-12")]
theorem get_set_ne {l : List α} {i j : Nat} (h : i j) {a : α}
(hj : j < (l.set i a).length) :
(l.set i a).get j, hj = l.get j, by simp at hj; exact hj := by
simp [h]
@[deprecated getElem_set (since := "2024-06-12")]
theorem get_set {l : List α} {m n} {a : α} (h) :
(set l m a).get n, h = if m = n then a else l.get n, length_set .. h := by
simp [getElem_set]
@[deprecated cons_inj_right (since := "2024-06-15")] abbrev cons_inj := @cons_inj_right
@[deprecated ne_nil_of_length_eq_add_one (since := "2024-06-16")]
abbrev ne_nil_of_length_eq_succ := @ne_nil_of_length_eq_add_one
@[deprecated "Deprecated without replacement." (since := "2024-07-09")]
theorem get_cons_cons_one : (a₁ :: a₂ :: as).get (1 : Fin (as.length + 2)) = a₂ := rfl

View File

@@ -22,13 +22,13 @@ namespace List
Given a list `as = [a₀, a₁, ...]` function `f : Fin as.length → α → β`, returns the list
`[f 0 a₀, f 1 a₁, ...]`.
-/
@[inline] def mapFinIdx (as : List α) (f : Fin as.length α β) : List β := go as #[] (by simp) where
@[inline] def mapFinIdx (as : List α) (f : (i : Nat) α (h : i < as.length) β) : List β := go as #[] (by simp) where
/-- Auxiliary for `mapFinIdx`:
`mapFinIdx.go [a₀, a₁, ...] acc = acc.toList ++ [f 0 a₀, f 1 a₁, ...]` -/
@[specialize] go : (bs : List α) (acc : Array β) bs.length + acc.size = as.length List β
| [], acc, h => acc.toList
| a :: as, acc, h =>
go as (acc.push (f acc.size, by simp at h; omega a)) (by simp at h ; omega)
go as (acc.push (f acc.size a (by simp at h; omega))) (by simp at h ; omega)
/--
Given a function `f : Nat → α → β` and `as : List α`, `as = [a₀, a₁, ...]`, returns the list
@@ -44,7 +44,7 @@ Given a function `f : Nat → α → β` and `as : List α`, `as = [a₀, a₁,
/-! ### mapFinIdx -/
@[simp]
theorem mapFinIdx_nil {f : Fin 0 α β} : mapFinIdx [] f = [] :=
theorem mapFinIdx_nil {f : (i : Nat) α (h : i < 0) β} : mapFinIdx [] f = [] :=
rfl
@[simp] theorem length_mapFinIdx_go :
@@ -53,13 +53,16 @@ theorem mapFinIdx_nil {f : Fin 0 → α → β} : mapFinIdx [] f = [] :=
| nil => simpa using h
| cons _ _ ih => simp [mapFinIdx.go, ih]
@[simp] theorem length_mapFinIdx {as : List α} {f : Fin as.length α β} :
@[simp] theorem length_mapFinIdx {as : List α} {f : (i : Nat) α (h : i < as.length) β} :
(as.mapFinIdx f).length = as.length := by
simp [mapFinIdx, length_mapFinIdx_go]
theorem getElem_mapFinIdx_go {as : List α} {f : Fin as.length α β} {i : Nat} {h} {w} :
theorem getElem_mapFinIdx_go {as : List α} {f : (i : Nat) α (h : i < as.length) β} {i : Nat} {h} {w} :
(mapFinIdx.go as f bs acc h)[i] =
if w' : i < acc.size then acc[i] else f i, by simp at w; omega (bs[i - acc.size]'(by simp at w; omega)) := by
if w' : i < acc.size then
acc[i]
else
f i (bs[i - acc.size]'(by simp at w; omega)) (by simp at w; omega) := by
induction bs generalizing acc with
| nil =>
simp only [length_mapFinIdx_go, length_nil, Nat.zero_add] at w h
@@ -78,29 +81,30 @@ theorem getElem_mapFinIdx_go {as : List α} {f : Fin as.length → α → β} {i
· have h₃ : i - acc.size = (i - (acc.size + 1)) + 1 := by omega
simp [h₃]
@[simp] theorem getElem_mapFinIdx {as : List α} {f : Fin as.length α β} {i : Nat} {h} :
(as.mapFinIdx f)[i] = f i, by simp at h; omega (as[i]'(by simp at h; omega)) := by
@[simp] theorem getElem_mapFinIdx {as : List α} {f : (i : Nat) α (h : i < as.length) β} {i : Nat} {h} :
(as.mapFinIdx f)[i] = f i (as[i]'(by simp at h; omega)) (by simp at h; omega) := by
simp [mapFinIdx, getElem_mapFinIdx_go]
theorem mapFinIdx_eq_ofFn {as : List α} {f : Fin as.length α β} :
as.mapFinIdx f = List.ofFn fun i : Fin as.length => f i as[i] := by
theorem mapFinIdx_eq_ofFn {as : List α} {f : (i : Nat) α (h : i < as.length) β} :
as.mapFinIdx f = List.ofFn fun i : Fin as.length => f i as[i] i.2 := by
apply ext_getElem <;> simp
@[simp] theorem getElem?_mapFinIdx {l : List α} {f : Fin l.length α β} {i : Nat} :
(l.mapFinIdx f)[i]? = l[i]?.pbind fun x m => f i, by simp [getElem?_eq_some_iff] at m; exact m.1 x := by
@[simp] theorem getElem?_mapFinIdx {l : List α} {f : (i : Nat) α (h : i < l.length) β} {i : Nat} :
(l.mapFinIdx f)[i]? = l[i]?.pbind fun x m => f i x (by simp [getElem?_eq_some_iff] at m; exact m.1) := by
simp only [getElem?_def, length_mapFinIdx, getElem_mapFinIdx]
split <;> simp
@[simp]
theorem mapFinIdx_cons {l : List α} {a : α} {f : Fin (l.length + 1) α β} :
mapFinIdx (a :: l) f = f 0 a :: mapFinIdx l (fun i => f i.succ) := by
theorem mapFinIdx_cons {l : List α} {a : α} {f : (i : Nat) α (h : i < l.length + 1) β} :
mapFinIdx (a :: l) f = f 0 a (by omega) :: mapFinIdx l (fun i a h => f (i + 1) a (by omega)) := by
apply ext_getElem
· simp
· rintro (_|i) h₁ h₂ <;> simp
theorem mapFinIdx_append {K L : List α} {f : Fin (K ++ L).length α β} :
theorem mapFinIdx_append {K L : List α} {f : (i : Nat) α (h : i < (K ++ L).length) β} :
(K ++ L).mapFinIdx f =
K.mapFinIdx (fun i => f (i.castLE (by simp))) ++ L.mapFinIdx (fun i => f ((i.natAdd K.length).cast (by simp))) := by
K.mapFinIdx (fun i a h => f i a (by simp; omega)) ++
L.mapFinIdx (fun i a h => f (i + K.length) a (by simp; omega)) := by
apply ext_getElem
· simp
· intro i h₁ h₂
@@ -108,60 +112,57 @@ theorem mapFinIdx_append {K L : List α} {f : Fin (K ++ L).length → α → β}
simp only [getElem_mapFinIdx, length_mapFinIdx]
split <;> rename_i h
· rw [getElem_append_left]
congr
· simp only [Nat.not_lt] at h
rw [getElem_append_right h]
congr
simp
omega
@[simp] theorem mapFinIdx_concat {l : List α} {e : α} {f : Fin (l ++ [e]).length α β}:
(l ++ [e]).mapFinIdx f = l.mapFinIdx (fun i => f (i.castLE (by simp))) ++ [f l.length, by simp e] := by
@[simp] theorem mapFinIdx_concat {l : List α} {e : α} {f : (i : Nat) α (h : i < (l ++ [e]).length) β}:
(l ++ [e]).mapFinIdx f = l.mapFinIdx (fun i a h => f i a (by simp; omega)) ++ [f l.length e (by simp)] := by
simp [mapFinIdx_append]
congr
theorem mapFinIdx_singleton {a : α} {f : Fin 1 α β} :
[a].mapFinIdx f = [f 0, by simp a] := by
theorem mapFinIdx_singleton {a : α} {f : (i : Nat) α (h : i < 1) β} :
[a].mapFinIdx f = [f 0 a (by simp)] := by
simp
theorem mapFinIdx_eq_enum_map {l : List α} {f : Fin l.length α β} :
theorem mapFinIdx_eq_enum_map {l : List α} {f : (i : Nat) α (h : i < l.length) β} :
l.mapFinIdx f = l.enum.attach.map
fun i, x, m =>
f i, by rw [mk_mem_enum_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1 x := by
f i x (by rw [mk_mem_enum_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1) := by
apply ext_getElem <;> simp
@[simp]
theorem mapFinIdx_eq_nil_iff {l : List α} {f : Fin l.length α β} :
theorem mapFinIdx_eq_nil_iff {l : List α} {f : (i : Nat) α (h : i < l.length) β} :
l.mapFinIdx f = [] l = [] := by
rw [mapFinIdx_eq_enum_map, map_eq_nil_iff, attach_eq_nil_iff, enum_eq_nil_iff]
theorem mapFinIdx_ne_nil_iff {l : List α} {f : Fin l.length α β} :
theorem mapFinIdx_ne_nil_iff {l : List α} {f : (i : Nat) α (h : i < l.length) β} :
l.mapFinIdx f [] l [] := by
simp
theorem exists_of_mem_mapFinIdx {b : β} {l : List α} {f : Fin l.length α β}
(h : b l.mapFinIdx f) : (i : Fin l.length), f i l[i] = b := by
theorem exists_of_mem_mapFinIdx {b : β} {l : List α} {f : (i : Nat) α (h : i < l.length) β}
(h : b l.mapFinIdx f) : (i : Nat) (h : i < l.length), f i l[i] h = b := by
rw [mapFinIdx_eq_enum_map] at h
replace h := exists_of_mem_map h
simp only [mem_attach, true_and, Subtype.exists, Prod.exists, mk_mem_enum_iff_getElem?] at h
obtain i, b, h, rfl := h
rw [getElem?_eq_some_iff] at h
obtain h', rfl := h
exact i, h', rfl
exact i, h', rfl
@[simp] theorem mem_mapFinIdx {b : β} {l : List α} {f : Fin l.length α β} :
b l.mapFinIdx f (i : Fin l.length), f i l[i] = b := by
@[simp] theorem mem_mapFinIdx {b : β} {l : List α} {f : (i : Nat) α (h : i < l.length) β} :
b l.mapFinIdx f (i : Nat) (h : i < l.length), f i l[i] h = b := by
constructor
· intro h
exact exists_of_mem_mapFinIdx h
· rintro i, h, rfl
rw [mem_iff_getElem]
exact i, by simp
exact i, by simpa using h, by simp
theorem mapFinIdx_eq_cons_iff {l : List α} {b : β} {f : Fin l.length α β} :
theorem mapFinIdx_eq_cons_iff {l : List α} {b : β} {f : (i : Nat) α (h : i < l.length) β} :
l.mapFinIdx f = b :: l₂
(a : α) (l₁ : List α) (h : l = a :: l₁),
f 0, by simp [h] a = b l₁.mapFinIdx (fun i => f (i.succ.cast (by simp [h]))) = l₂ := by
(a : α) (l₁ : List α) (w : l = a :: l₁),
f 0 a (by simp [w]) = b l₁.mapFinIdx (fun i a h => f (i + 1) a (by simp [w]; omega)) = l₂ := by
cases l with
| nil => simp
| cons x l' =>
@@ -169,39 +170,48 @@ theorem mapFinIdx_eq_cons_iff {l : List α} {b : β} {f : Fin l.length → α
exists_and_left]
constructor
· rintro rfl, rfl
refine x, rfl, l', by simp
· rintro a, rfl, h, _, rfl, rfl, h
exact rfl, h
refine x, l', rfl, rfl, by simp
· rintro a, l', rfl, rfl, rfl, rfl
exact rfl, by simp
theorem mapFinIdx_eq_cons_iff' {l : List α} {b : β} {f : Fin l.length α β} :
theorem mapFinIdx_eq_cons_iff' {l : List α} {b : β} {f : (i : Nat) α (h : i < l.length) β} :
l.mapFinIdx f = b :: l₂
l.head?.pbind (fun x m => (f 0, by cases l <;> simp_all x)) = some b
l.tail?.attach.map (fun t, m => t.mapFinIdx fun i => f (i.succ.cast (by cases l <;> simp_all))) = some l₂ := by
l.head?.pbind (fun x m => (f 0 x (by cases l <;> simp_all))) = some b
l.tail?.attach.map (fun t, m => t.mapFinIdx fun i a h => f (i + 1) a (by cases l <;> simp_all)) = some l₂ := by
cases l <;> simp
theorem mapFinIdx_eq_iff {l : List α} {f : Fin l.length α β} :
l.mapFinIdx f = l' h : l'.length = l.length, (i : Nat) (h : i < l.length), l'[i] = f i, h l[i] := by
theorem mapFinIdx_eq_iff {l : List α} {f : (i : Nat) α (h : i < l.length) β} :
l.mapFinIdx f = l' h : l'.length = l.length, (i : Nat) (h : i < l.length), l'[i] = f i l[i] h := by
constructor
· rintro rfl
simp
· rintro h, w
apply ext_getElem <;> simp_all
theorem mapFinIdx_eq_mapFinIdx_iff {l : List α} {f g : Fin l.length α β} :
l.mapFinIdx f = l.mapFinIdx g (i : Fin l.length), f i l[i] = g i l[i] := by
theorem mapFinIdx_eq_mapFinIdx_iff {l : List α} {f g : (i : Nat) α (h : i < l.length) β} :
l.mapFinIdx f = l.mapFinIdx g (i : Nat) (h : i < l.length), f i l[i] h = g i l[i] h := by
rw [eq_comm, mapFinIdx_eq_iff]
simp [Fin.forall_iff]
@[simp] theorem mapFinIdx_mapFinIdx {l : List α} {f : Fin l.length α β} {g : Fin _ β γ} :
(l.mapFinIdx f).mapFinIdx g = l.mapFinIdx (fun i => g (i.cast (by simp)) f i) := by
@[simp] theorem mapFinIdx_mapFinIdx {l : List α}
{f : (i : Nat) α (h : i < l.length) β}
{g : (i : Nat) β (h : i < (l.mapFinIdx f).length) γ} :
(l.mapFinIdx f).mapFinIdx g = l.mapFinIdx (fun i a h => g i (f i a h) (by simpa)) := by
simp [mapFinIdx_eq_iff]
theorem mapFinIdx_eq_replicate_iff {l : List α} {f : Fin l.length α β} {b : β} :
l.mapFinIdx f = replicate l.length b (i : Fin l.length), f i l[i] = b := by
simp [eq_replicate_iff, length_mapFinIdx, mem_mapFinIdx, forall_exists_index, true_and]
theorem mapFinIdx_eq_replicate_iff {l : List α} {f : (i : Nat) α (h : i < l.length) β} {b : β} :
l.mapFinIdx f = replicate l.length b (i : Nat) (h : i < l.length), f i l[i] h = b := by
rw [eq_replicate_iff, length_mapFinIdx]
simp only [mem_mapFinIdx, forall_exists_index, true_and]
constructor
· intro w i h
exact w (f i l[i] h) i h rfl
· rintro w b i h rfl
exact w i h
@[simp] theorem mapFinIdx_reverse {l : List α} {f : Fin l.reverse.length α β} :
l.reverse.mapFinIdx f = (l.mapFinIdx (fun i => f l.length - 1 - i, by simp; omega)).reverse := by
@[simp] theorem mapFinIdx_reverse {l : List α} {f : (i : Nat) α (h : i < l.reverse.length) β} :
l.reverse.mapFinIdx f =
(l.mapFinIdx (fun i a h => f (l.length - 1 - i) a (by simp; omega))).reverse := by
simp [mapFinIdx_eq_iff]
intro i h
congr
@@ -262,13 +272,13 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {arr : Array β} {i : Nat},
rw [ getElem?_eq_getElem, getElem?_mapIdx, getElem?_eq_getElem (by simpa using h)]
simp
@[simp] theorem mapFinIdx_eq_mapIdx {l : List α} {f : Fin l.length α β} {g : Nat α β}
(h : (i : Fin l.length), f i l[i] = g i l[i]) :
@[simp] theorem mapFinIdx_eq_mapIdx {l : List α} {f : (i : Nat) α (h : i < l.length) β} {g : Nat α β}
(h : (i : Nat) (h : i < l.length), f i l[i] h = g i l[i]) :
l.mapFinIdx f = l.mapIdx g := by
simp_all [mapFinIdx_eq_iff]
theorem mapIdx_eq_mapFinIdx {l : List α} {f : Nat α β} :
l.mapIdx f = l.mapFinIdx (fun i => f i) := by
l.mapIdx f = l.mapFinIdx (fun i a _ => f i a) := by
simp [mapFinIdx_eq_mapIdx]
theorem mapIdx_eq_enum_map {l : List α} :

View File

@@ -47,41 +47,16 @@ length `> i`. Version designed to rewrite from the small list to the big list. -
L[i]'(Nat.lt_of_lt_of_le h (length_take_le' _ _)) := by
rw [length_take, Nat.lt_min] at h; rw [getElem_take' L _ h.1]
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
length `> i`. Version designed to rewrite from the big list to the small list. -/
@[deprecated getElem_take' (since := "2024-06-12")]
theorem get_take (L : List α) {i j : Nat} (hi : i < L.length) (hj : i < j) :
get L i, hi = get (L.take j) i, length_take .. Nat.lt_min.mpr hj, hi := by
simp
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
length `> i`. Version designed to rewrite from the small list to the big list. -/
@[deprecated getElem_take (since := "2024-06-12")]
theorem get_take' (L : List α) {j i} :
get (L.take j) i =
get L i.1, Nat.lt_of_lt_of_le i.2 (length_take_le' _ _) := by
simp [getElem_take]
theorem getElem?_take_eq_none {l : List α} {n m : Nat} (h : n m) :
(l.take n)[m]? = none :=
getElem?_eq_none <| Nat.le_trans (length_take_le _ _) h
@[deprecated getElem?_take_eq_none (since := "2024-06-12")]
theorem get?_take_eq_none {l : List α} {n m : Nat} (h : n m) :
(l.take n).get? m = none := by
simp [getElem?_take_eq_none h]
theorem getElem?_take {l : List α} {n m : Nat} :
(l.take n)[m]? = if m < n then l[m]? else none := by
split
· next h => exact getElem?_take_of_lt h
· next h => exact getElem?_take_eq_none (Nat.le_of_not_lt h)
@[deprecated getElem?_take (since := "2024-06-12")]
theorem get?_take_eq_if {l : List α} {n m : Nat} :
(l.take n).get? m = if m < n then l.get? m else none := by
simp [getElem?_take]
theorem head?_take {l : List α} {n : Nat} :
(l.take n).head? = if n = 0 then none else l.head? := by
simp [head?_eq_getElem?, getElem?_take]
@@ -226,13 +201,6 @@ theorem getElem_drop' (L : List α) {i j : Nat} (h : i + j < L.length) :
· simp [Nat.min_eq_left this, Nat.add_sub_cancel_left]
· simp [Nat.min_eq_left this, Nat.le_add_right]
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
dropping the first `i` elements. Version designed to rewrite from the big list to the small list. -/
@[deprecated getElem_drop' (since := "2024-06-12")]
theorem get_drop (L : List α) {i j : Nat} (h : i + j < L.length) :
get L i + j, h = get (L.drop i) j, lt_length_drop L h := by
simp [getElem_drop']
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
dropping the first `i` elements. Version designed to rewrite from the small list to the big list. -/
@[simp] theorem getElem_drop (L : List α) {i : Nat} {j : Nat} {h : j < (L.drop i).length} :
@@ -241,15 +209,6 @@ dropping the first `i` elements. Version designed to rewrite from the small list
exact Nat.add_lt_of_lt_sub (length_drop i L h)) := by
rw [getElem_drop']
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
dropping the first `i` elements. Version designed to rewrite from the small list to the big list. -/
@[deprecated getElem_drop' (since := "2024-06-12")]
theorem get_drop' (L : List α) {i j} :
get (L.drop i) j = get L i + j, by
rw [Nat.add_comm]
exact Nat.add_lt_of_lt_sub (length_drop i L j.2) := by
simp
@[simp]
theorem getElem?_drop (L : List α) (i j : Nat) : (L.drop i)[j]? = L[i + j]? := by
ext
@@ -261,10 +220,6 @@ theorem getElem?_drop (L : List α) (i j : Nat) : (L.drop i)[j]? = L[i + j]? :=
rw [Nat.add_comm] at h
apply Nat.lt_sub_of_add_lt h
@[deprecated getElem?_drop (since := "2024-06-12")]
theorem get?_drop (L : List α) (i j : Nat) : get? (L.drop i) j = get? L (i + j) := by
simp
theorem mem_take_iff_getElem {l : List α} {a : α} :
a l.take n (i : Nat) (hm : i < min n l.length), l[i] = a := by
rw [mem_iff_getElem]

View File

@@ -67,17 +67,9 @@ theorem getElem_cons_drop : ∀ (l : List α) (i : Nat) (h : i < l.length),
| _::_, 0, _ => rfl
| _::_, i+1, h => getElem_cons_drop _ i (Nat.add_one_lt_add_one_iff.mp h)
@[deprecated getElem_cons_drop (since := "2024-06-12")]
theorem get_cons_drop (l : List α) (i) : get l i :: drop (i + 1) l = drop i l := by
simp
theorem drop_eq_getElem_cons {n} {l : List α} (h : n < l.length) : drop n l = l[n] :: drop (n + 1) l :=
(getElem_cons_drop _ n h).symm
@[deprecated drop_eq_getElem_cons (since := "2024-06-12")]
theorem drop_eq_get_cons {n} {l : List α} (h) : drop n l = get l n, h :: drop (n + 1) l := by
simp [drop_eq_getElem_cons]
@[simp]
theorem getElem?_take_of_lt {l : List α} {n m : Nat} (h : m < n) : (l.take n)[m]? = l[m]? := by
induction n generalizing l m with
@@ -91,10 +83,6 @@ theorem getElem?_take_of_lt {l : List α} {n m : Nat} (h : m < n) : (l.take n)[m
· simp
· simpa using hn (Nat.lt_of_succ_lt_succ h)
@[deprecated getElem?_take_of_lt (since := "2024-06-12")]
theorem get?_take {l : List α} {n m : Nat} (h : m < n) : (l.take n).get? m = l.get? m := by
simp [getElem?_take_of_lt, h]
theorem getElem?_take_of_succ {l : List α} {n : Nat} : (l.take (n + 1))[n]? = l[n]? := by simp
@[simp] theorem drop_drop (n : Nat) : (m) (l : List α), drop n (drop m l) = drop (m + n) l
@@ -111,10 +99,6 @@ theorem take_drop : ∀ (m n : Nat) (l : List α), take n (drop m l) = drop m (t
| _, _, [] => by simp
| _+1, _, _ :: _ => by simpa [Nat.succ_add, take_succ_cons, drop_succ_cons] using take_drop ..
@[deprecated drop_drop (since := "2024-06-15")]
theorem drop_add (m n) (l : List α) : drop (m + n) l = drop n (drop m l) := by
simp [drop_drop]
@[simp]
theorem tail_drop (l : List α) (n : Nat) : (l.drop n).tail = l.drop (n + 1) := by
induction l generalizing n with

View File

@@ -76,15 +76,6 @@ theorem getElem?_zip_eq_some {l₁ : List α} {l₂ : List β} {z : α × β} {i
· rintro h₀, h₁
exact _, _, h₀, h₁, rfl
@[deprecated getElem?_zipWith (since := "2024-06-12")]
theorem get?_zipWith {f : α β γ} :
(List.zipWith f as bs).get? i = match as.get? i, bs.get? i with
| some a, some b => some (f a b) | _, _ => none := by
simp [getElem?_zipWith]
set_option linter.deprecated false in
@[deprecated getElem?_zipWith (since := "2024-06-07")] abbrev zipWith_get? := @get?_zipWith
theorem head?_zipWith {f : α β γ} :
(List.zipWith f as bs).head? = match as.head?, bs.head? with
| some a, some b => some (f a b) | _, _ => none := by
@@ -369,15 +360,6 @@ theorem getElem?_zipWithAll {f : Option α → Option β → γ} {i : Nat} :
cases i <;> simp_all
| cons b bs => cases i <;> simp_all
@[deprecated getElem?_zipWithAll (since := "2024-06-12")]
theorem get?_zipWithAll {f : Option α Option β γ} :
(zipWithAll f as bs).get? i = match as.get? i, bs.get? i with
| none, none => .none | a?, b? => some (f a? b?) := by
simp [getElem?_zipWithAll]
set_option linter.deprecated false in
@[deprecated getElem?_zipWithAll (since := "2024-06-07")] abbrev zipWithAll_get? := @get?_zipWithAll
theorem head?_zipWithAll {f : Option α Option β γ} :
(zipWithAll f as bs).head? = match as.head?, bs.head? with
| none, none => .none | a?, b? => some (f a? b?) := by

View File

@@ -788,9 +788,6 @@ theorem not_eq_zero_of_lt (h : b < a) : a ≠ 0 := by
theorem pred_lt_of_lt {n m : Nat} (h : m < n) : pred n < n :=
pred_lt (not_eq_zero_of_lt h)
set_option linter.missingDocs false in
@[deprecated pred_lt_of_lt (since := "2024-06-01")] abbrev pred_lt' := @pred_lt_of_lt
theorem sub_one_lt_of_lt {n m : Nat} (h : m < n) : n - 1 < n :=
sub_one_lt (not_eq_zero_of_lt h)
@@ -1074,9 +1071,6 @@ theorem pred_mul (n m : Nat) : pred n * m = n * m - m := by
| zero => simp
| succ n => rw [Nat.pred_succ, succ_mul, Nat.add_sub_cancel]
set_option linter.missingDocs false in
@[deprecated pred_mul (since := "2024-06-01")] abbrev mul_pred_left := @pred_mul
protected theorem sub_one_mul (n m : Nat) : (n - 1) * m = n * m - m := by
cases n with
| zero => simp
@@ -1086,9 +1080,6 @@ protected theorem sub_one_mul (n m : Nat) : (n - 1) * m = n * m - m := by
theorem mul_pred (n m : Nat) : n * pred m = n * m - n := by
rw [Nat.mul_comm, pred_mul, Nat.mul_comm]
set_option linter.missingDocs false in
@[deprecated mul_pred (since := "2024-06-01")] abbrev mul_pred_right := @mul_pred
theorem mul_sub_one (n m : Nat) : n * (m - 1) = n * m - n := by
rw [Nat.mul_comm, Nat.sub_one_mul , Nat.mul_comm]

View File

@@ -711,6 +711,32 @@ theorem mul_add_lt_is_or {b : Nat} (b_lt : b < 2^i) (a : Nat) : 2^i * a + b = 2^
rw [mod_two_eq_one_iff_testBit_zero, testBit_shiftLeft]
simp
theorem testBit_mul_two_pow (x i n : Nat) :
(x * 2 ^ n).testBit i = (decide (n i) && x.testBit (i - n)) := by
rw [ testBit_shiftLeft, shiftLeft_eq]
theorem bitwise_mul_two_pow (of_false_false : f false false = false := by rfl) :
(bitwise f x y) * 2 ^ n = bitwise f (x * 2 ^ n) (y * 2 ^ n) := by
apply Nat.eq_of_testBit_eq
simp only [testBit_mul_two_pow, testBit_bitwise of_false_false, Bool.if_false_right]
intro i
by_cases hn : n i
· simp [hn]
· simp [hn, of_false_false]
theorem shiftLeft_bitwise_distrib {a b : Nat} (of_false_false : f false false = false := by rfl) :
(bitwise f a b) <<< i = bitwise f (a <<< i) (b <<< i) := by
simp [shiftLeft_eq, bitwise_mul_two_pow of_false_false]
theorem shiftLeft_and_distrib {a b : Nat} : (a &&& b) <<< i = a <<< i &&& b <<< i :=
shiftLeft_bitwise_distrib
theorem shiftLeft_or_distrib {a b : Nat} : (a ||| b) <<< i = a <<< i ||| b <<< i :=
shiftLeft_bitwise_distrib
theorem shiftLeft_xor_distrib {a b : Nat} : (a ^^^ b) <<< i = a <<< i ^^^ b <<< i :=
shiftLeft_bitwise_distrib
@[simp] theorem decide_shiftRight_mod_two_eq_one :
decide (x >>> i % 2 = 1) = x.testBit i := by
simp only [testBit, one_and_eq_mod_two, mod_two_bne_zero]

View File

@@ -622,6 +622,14 @@ protected theorem pos_of_mul_pos_right {a b : Nat} (h : 0 < a * b) : 0 < a := by
0 < a * b 0 < a :=
Nat.pos_of_mul_pos_right, fun w => Nat.mul_pos w h
protected theorem pos_of_lt_mul_left {a b c : Nat} (h : a < b * c) : 0 < c := by
replace h : 0 < b * c := by omega
exact Nat.pos_of_mul_pos_left h
protected theorem pos_of_lt_mul_right {a b c : Nat} (h : a < b * c) : 0 < b := by
replace h : 0 < b * c := by omega
exact Nat.pos_of_mul_pos_right h
/-! ### div/mod -/
theorem mod_two_eq_zero_or_one (n : Nat) : n % 2 = 0 n % 2 = 1 :=
@@ -995,11 +1003,6 @@ theorem shiftLeft_add (m n : Nat) : ∀ k, m <<< (n + k) = (m <<< n) <<< k
| 0 => rfl
| k + 1 => by simp [ Nat.add_assoc, shiftLeft_add _ _ k, shiftLeft_succ]
@[deprecated shiftLeft_add (since := "2024-06-02")]
theorem shiftLeft_shiftLeft (m n : Nat) : k, (m <<< n) <<< k = m <<< (n + k)
| 0 => rfl
| k + 1 => by simp [ Nat.add_assoc, shiftLeft_shiftLeft _ _ k, shiftLeft_succ]
@[simp] theorem shiftLeft_shiftRight (x n : Nat) : x <<< n >>> n = x := by
rw [Nat.shiftLeft_eq, Nat.shiftRight_eq_div_pow, Nat.mul_div_cancel _ (Nat.two_pow_pos _)]

View File

@@ -13,17 +13,17 @@ macro "declare_bitwise_uint_theorems" typeName:ident bits:term:arg : command =>
`(
namespace $typeName
@[simp] protected theorem toBitVec_add {a b : $typeName} : (a + b).toBitVec = a.toBitVec + b.toBitVec := rfl
@[simp] protected theorem toBitVec_sub {a b : $typeName} : (a - b).toBitVec = a.toBitVec - b.toBitVec := rfl
@[simp] protected theorem toBitVec_mul {a b : $typeName} : (a * b).toBitVec = a.toBitVec * b.toBitVec := rfl
@[simp] protected theorem toBitVec_div {a b : $typeName} : (a / b).toBitVec = a.toBitVec / b.toBitVec := rfl
@[simp] protected theorem toBitVec_mod {a b : $typeName} : (a % b).toBitVec = a.toBitVec % b.toBitVec := rfl
@[simp] protected theorem toBitVec_not {a : $typeName} : (~~~a).toBitVec = ~~~a.toBitVec := rfl
@[simp] protected theorem toBitVec_and (a b : $typeName) : (a &&& b).toBitVec = a.toBitVec &&& b.toBitVec := rfl
@[simp] protected theorem toBitVec_or (a b : $typeName) : (a ||| b).toBitVec = a.toBitVec ||| b.toBitVec := rfl
@[simp] protected theorem toBitVec_xor (a b : $typeName) : (a ^^^ b).toBitVec = a.toBitVec ^^^ b.toBitVec := rfl
@[simp] protected theorem toBitVec_shiftLeft (a b : $typeName) : (a <<< b).toBitVec = a.toBitVec <<< (b.toBitVec % $bits) := rfl
@[simp] protected theorem toBitVec_shiftRight (a b : $typeName) : (a >>> b).toBitVec = a.toBitVec >>> (b.toBitVec % $bits) := rfl
@[simp, int_toBitVec] protected theorem toBitVec_add {a b : $typeName} : (a + b).toBitVec = a.toBitVec + b.toBitVec := rfl
@[simp, int_toBitVec] protected theorem toBitVec_sub {a b : $typeName} : (a - b).toBitVec = a.toBitVec - b.toBitVec := rfl
@[simp, int_toBitVec] protected theorem toBitVec_mul {a b : $typeName} : (a * b).toBitVec = a.toBitVec * b.toBitVec := rfl
@[simp, int_toBitVec] protected theorem toBitVec_div {a b : $typeName} : (a / b).toBitVec = a.toBitVec / b.toBitVec := rfl
@[simp, int_toBitVec] protected theorem toBitVec_mod {a b : $typeName} : (a % b).toBitVec = a.toBitVec % b.toBitVec := rfl
@[simp, int_toBitVec] protected theorem toBitVec_not {a : $typeName} : (~~~a).toBitVec = ~~~a.toBitVec := rfl
@[simp, int_toBitVec] protected theorem toBitVec_and (a b : $typeName) : (a &&& b).toBitVec = a.toBitVec &&& b.toBitVec := rfl
@[simp, int_toBitVec] protected theorem toBitVec_or (a b : $typeName) : (a ||| b).toBitVec = a.toBitVec ||| b.toBitVec := rfl
@[simp, int_toBitVec] protected theorem toBitVec_xor (a b : $typeName) : (a ^^^ b).toBitVec = a.toBitVec ^^^ b.toBitVec := rfl
@[simp, int_toBitVec] protected theorem toBitVec_shiftLeft (a b : $typeName) : (a <<< b).toBitVec = a.toBitVec <<< (b.toBitVec % $bits) := rfl
@[simp, int_toBitVec] protected theorem toBitVec_shiftRight (a b : $typeName) : (a >>> b).toBitVec = a.toBitVec >>> (b.toBitVec % $bits) := rfl
@[simp] protected theorem toNat_and (a b : $typeName) : (a &&& b).toNat = a.toNat &&& b.toNat := by simp [toNat]
@[simp] protected theorem toNat_or (a b : $typeName) : (a ||| b).toNat = a.toNat ||| b.toNat := by simp [toNat]
@@ -44,27 +44,27 @@ declare_bitwise_uint_theorems UInt32 32
declare_bitwise_uint_theorems UInt64 64
declare_bitwise_uint_theorems USize System.Platform.numBits
@[simp]
@[simp, int_toBitVec]
theorem Bool.toBitVec_toUInt8 {b : Bool} :
b.toUInt8.toBitVec = (BitVec.ofBool b).setWidth 8 := by
cases b <;> simp [toUInt8]
@[simp]
@[simp, int_toBitVec]
theorem Bool.toBitVec_toUInt16 {b : Bool} :
b.toUInt16.toBitVec = (BitVec.ofBool b).setWidth 16 := by
cases b <;> simp [toUInt16]
@[simp]
@[simp, int_toBitVec]
theorem Bool.toBitVec_toUInt32 {b : Bool} :
b.toUInt32.toBitVec = (BitVec.ofBool b).setWidth 32 := by
cases b <;> simp [toUInt32]
@[simp]
@[simp, int_toBitVec]
theorem Bool.toBitVec_toUInt64 {b : Bool} :
b.toUInt64.toBitVec = (BitVec.ofBool b).setWidth 64 := by
cases b <;> simp [toUInt64]
@[simp]
@[simp, int_toBitVec]
theorem Bool.toBitVec_toUSize {b : Bool} :
b.toUSize.toBitVec = (BitVec.ofBool b).setWidth System.Platform.numBits := by
cases b

View File

@@ -41,9 +41,9 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
theorem toNat_ofNat_of_lt {n : Nat} (h : n < size) : (ofNat n).toNat = n := by
rw [toNat, toBitVec_eq_of_lt h]
theorem le_def {a b : $typeName} : a b a.toBitVec b.toBitVec := .rfl
@[int_toBitVec] theorem le_def {a b : $typeName} : a b a.toBitVec b.toBitVec := .rfl
theorem lt_def {a b : $typeName} : a < b a.toBitVec < b.toBitVec := .rfl
@[int_toBitVec] theorem lt_def {a b : $typeName} : a < b a.toBitVec < b.toBitVec := .rfl
theorem le_iff_toNat_le {a b : $typeName} : a b a.toNat b.toNat := .rfl
@@ -74,6 +74,11 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
protected theorem toBitVec_inj {a b : $typeName} : a.toBitVec = b.toBitVec a = b :=
Iff.intro eq_of_toBitVec_eq toBitVec_eq_of_eq
open $typeName (eq_of_toBitVec_eq toBitVec_eq_of_eq) in
@[int_toBitVec]
protected theorem eq_iff_toBitVec_eq {a b : $typeName} : a = b a.toBitVec = b.toBitVec :=
Iff.intro toBitVec_eq_of_eq eq_of_toBitVec_eq
open $typeName (eq_of_toBitVec_eq) in
protected theorem eq_of_val_eq {a b : $typeName} (h : a.val = b.val) : a = b := by
rcases a with _; rcases b with _; simp_all [val]
@@ -82,10 +87,19 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
protected theorem val_inj {a b : $typeName} : a.val = b.val a = b :=
Iff.intro eq_of_val_eq (congrArg val)
open $typeName (eq_of_toBitVec_eq) in
protected theorem toBitVec_ne_of_ne {a b : $typeName} (h : a b) : a.toBitVec b.toBitVec :=
fun h' => h (eq_of_toBitVec_eq h')
open $typeName (toBitVec_eq_of_eq) in
protected theorem ne_of_toBitVec_ne {a b : $typeName} (h : a.toBitVec b.toBitVec) : a b :=
fun h' => absurd (toBitVec_eq_of_eq h') h
open $typeName (ne_of_toBitVec_ne toBitVec_ne_of_ne) in
@[int_toBitVec]
protected theorem ne_iff_toBitVec_ne {a b : $typeName} : a b a.toBitVec b.toBitVec :=
Iff.intro toBitVec_ne_of_ne ne_of_toBitVec_ne
open $typeName (ne_of_toBitVec_ne) in
protected theorem ne_of_lt {a b : $typeName} (h : a < b) : a b := by
apply ne_of_toBitVec_ne
@@ -159,7 +173,7 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
@[simp]
theorem val_ofNat (n : Nat) : val (no_index (OfNat.ofNat n)) = OfNat.ofNat n := rfl
@[simp]
@[simp, int_toBitVec]
theorem toBitVec_ofNat (n : Nat) : toBitVec (no_index (OfNat.ofNat n)) = BitVec.ofNat _ n := rfl
@[simp]
@@ -220,23 +234,3 @@ theorem UInt32.toNat_le_of_le {n : UInt32} {m : Nat} (h : m < size) : n ≤ ofNa
theorem UInt32.le_toNat_of_le {n : UInt32} {m : Nat} (h : m < size) : ofNat m n m n.toNat := by
simp [le_def, BitVec.le_def, UInt32.toNat, toBitVec_eq_of_lt h]
@[deprecated UInt8.toNat_zero (since := "2024-06-23")] protected abbrev UInt8.zero_toNat := @UInt8.toNat_zero
@[deprecated UInt8.toNat_div (since := "2024-06-23")] protected abbrev UInt8.div_toNat := @UInt8.toNat_div
@[deprecated UInt8.toNat_mod (since := "2024-06-23")] protected abbrev UInt8.mod_toNat := @UInt8.toNat_mod
@[deprecated UInt16.toNat_zero (since := "2024-06-23")] protected abbrev UInt16.zero_toNat := @UInt16.toNat_zero
@[deprecated UInt16.toNat_div (since := "2024-06-23")] protected abbrev UInt16.div_toNat := @UInt16.toNat_div
@[deprecated UInt16.toNat_mod (since := "2024-06-23")] protected abbrev UInt16.mod_toNat := @UInt16.toNat_mod
@[deprecated UInt32.toNat_zero (since := "2024-06-23")] protected abbrev UInt32.zero_toNat := @UInt32.toNat_zero
@[deprecated UInt32.toNat_div (since := "2024-06-23")] protected abbrev UInt32.div_toNat := @UInt32.toNat_div
@[deprecated UInt32.toNat_mod (since := "2024-06-23")] protected abbrev UInt32.mod_toNat := @UInt32.toNat_mod
@[deprecated UInt64.toNat_zero (since := "2024-06-23")] protected abbrev UInt64.zero_toNat := @UInt64.toNat_zero
@[deprecated UInt64.toNat_div (since := "2024-06-23")] protected abbrev UInt64.div_toNat := @UInt64.toNat_div
@[deprecated UInt64.toNat_mod (since := "2024-06-23")] protected abbrev UInt64.mod_toNat := @UInt64.toNat_mod
@[deprecated USize.toNat_zero (since := "2024-06-23")] protected abbrev USize.zero_toNat := @USize.toNat_zero
@[deprecated USize.toNat_div (since := "2024-06-23")] protected abbrev USize.div_toNat := @USize.toNat_div
@[deprecated USize.toNat_mod (since := "2024-06-23")] protected abbrev USize.mod_toNat := @USize.toNat_mod

View File

@@ -174,6 +174,9 @@ result is empty. If `stop` is greater than the size of the vector, the size is u
(v.toArray.map Vector.toArray).flatten,
by rcases v; simp_all [Function.comp_def, Array.map_const']
@[inline] def flatMap (v : Vector α n) (f : α Vector β m) : Vector β (n * m) :=
v.toArray.flatMap fun a => (f a).toArray, by simp [Array.map_const']
/-- Maps corresponding elements of two vectors of equal size using the function `f`. -/
@[inline] def zipWith (a : Vector α n) (b : Vector β n) (f : α β φ) : Vector φ n :=
Array.zipWith a.toArray b.toArray f, by simp

View File

@@ -475,7 +475,7 @@ theorem singleton_inj : #v[a] = #v[b] ↔ a = b := by
theorem mkVector_succ : mkVector (n + 1) a = (mkVector n a).push a := by
simp [mkVector, Array.mkArray_succ]
theorem mkVector_inj : mkVector n a = mkVector n b n = 0 a = b := by
@[simp] theorem mkVector_inj : mkVector n a = mkVector n b n = 0 a = b := by
simp [ toArray_inj, toArray_mkVector, Array.mkArray_inj]
/-! ## L[i] and L[i]? -/
@@ -1456,6 +1456,44 @@ theorem append_eq_map_iff {f : α → β} :
mk (L.map toArray).flatten (by simp [Function.comp_def, Array.map_const', h]) := by
simp [flatten]
@[simp] theorem getElem_flatten (l : Vector (Vector β m) n) (i : Nat) (hi : i < n * m) :
l.flatten[i] =
haveI : i / m < n := by rwa [Nat.div_lt_iff_lt_mul (Nat.pos_of_lt_mul_left hi)]
haveI : i % m < m := Nat.mod_lt _ (Nat.pos_of_lt_mul_left hi)
l[i / m][i % m] := by
rcases l with l, rfl
simp only [flatten_mk, List.map_toArray, getElem_mk, List.getElem_toArray, Array.flatten_toArray]
induction l generalizing i with
| nil => simp at hi
| cons a l ih =>
simp only [List.map_cons, List.map_map, List.flatten_cons]
by_cases h : i < m
· rw [List.getElem_append_left (by simpa)]
have h₁ : i / m = 0 := Nat.div_eq_of_lt h
have h₂ : i % m = i := Nat.mod_eq_of_lt h
simp [h₁, h₂]
· have h₁ : a.toList.length i := by simp; omega
rw [List.getElem_append_right h₁]
simp only [Array.length_toList, size_toArray]
specialize ih (i - m) (by simp_all [Nat.add_one_mul]; omega)
have h₂ : i / m = (i - m) / m + 1 := by
conv => lhs; rw [show i = i - m + m by omega]
rw [Nat.add_div_right]
exact Nat.pos_of_lt_mul_left hi
simp only [Array.length_toList, size_toArray] at h₁
have h₃ : (i - m) % m = i % m := (Nat.mod_eq_sub_mod h₁).symm
simp_all
theorem getElem?_flatten (l : Vector (Vector β m) n) (i : Nat) :
l.flatten[i]? =
if hi : i < n * m then
haveI : i / m < n := by rwa [Nat.div_lt_iff_lt_mul (Nat.pos_of_lt_mul_left hi)]
haveI : i % m < m := Nat.mod_lt _ (Nat.pos_of_lt_mul_left hi)
some l[i / m][i % m]
else
none := by
simp [getElem?_def]
@[simp] theorem flatten_singleton (l : Vector α n) : #v[l].flatten = l.cast (by simp) := by
simp [flatten]
@@ -1525,6 +1563,275 @@ theorem eq_iff_flatten_eq {L L' : Vector (Vector α n) m} :
subst this
rfl
/-! ### flatMap -/
@[simp] theorem flatMap_mk (l : Array α) (h : l.size = m) (f : α Vector β n) :
(mk l h).flatMap f =
mk (l.flatMap (fun a => (f a).toArray)) (by simp [Array.map_const', h]) := by
simp [flatMap]
@[simp] theorem flatMap_toArray (l : Vector α n) (f : α Vector β m) :
l.toArray.flatMap (fun a => (f a).toArray) = (l.flatMap f).toArray := by
rcases l with l, rfl
simp
theorem flatMap_def (l : Vector α n) (f : α Vector β m) : l.flatMap f = flatten (map f l) := by
rcases l with l, rfl
simp [Array.flatMap_def, Function.comp_def]
@[simp] theorem getElem_flatMap (l : Vector α n) (f : α Vector β m) (i : Nat) (hi : i < n * m) :
(l.flatMap f)[i] =
haveI : i / m < n := by rwa [Nat.div_lt_iff_lt_mul (Nat.pos_of_lt_mul_left hi)]
haveI : i % m < m := Nat.mod_lt _ (Nat.pos_of_lt_mul_left hi)
(f (l[i / m]))[i % m] := by
rw [flatMap_def, getElem_flatten, getElem_map]
theorem getElem?_flatMap (l : Vector α n) (f : α Vector β m) (i : Nat) :
(l.flatMap f)[i]? =
if hi : i < n * m then
haveI : i / m < n := by rwa [Nat.div_lt_iff_lt_mul (Nat.pos_of_lt_mul_left hi)]
haveI : i % m < m := Nat.mod_lt _ (Nat.pos_of_lt_mul_left hi)
some ((f (l[i / m]))[i % m])
else
none := by
simp [getElem?_def]
@[simp] theorem flatMap_id (l : Vector (Vector α m) n) : l.flatMap id = l.flatten := by simp [flatMap_def]
@[simp] theorem flatMap_id' (l : Vector (Vector α m) n) : l.flatMap (fun a => a) = l.flatten := by simp [flatMap_def]
@[simp] theorem mem_flatMap {f : α Vector β m} {b} {l : Vector α n} : b l.flatMap f a, a l b f a := by
simp [flatMap_def, mem_flatten]
exact fun _, a, h₁, rfl, h₂ => a, h₁, h₂, fun a, h₁, h₂ => _, a, h₁, rfl, h₂
theorem exists_of_mem_flatMap {b : β} {l : Vector α n} {f : α Vector β m} :
b l.flatMap f a, a l b f a := mem_flatMap.1
theorem mem_flatMap_of_mem {b : β} {l : Vector α n} {f : α Vector β m} {a} (al : a l) (h : b f a) :
b l.flatMap f := mem_flatMap.2 a, al, h
theorem forall_mem_flatMap {p : β Prop} {l : Vector α n} {f : α Vector β m} :
( (x) (_ : x l.flatMap f), p x) (a) (_ : a l) (b) (_ : b f a), p b := by
simp only [mem_flatMap, forall_exists_index, and_imp]
constructor <;> (intros; solve_by_elim)
theorem flatMap_singleton (f : α Vector β m) (x : α) : #v[x].flatMap f = (f x).cast (by simp) := by
simp [flatMap_def]
@[simp] theorem flatMap_singleton' (l : Vector α n) : (l.flatMap fun x => #v[x]) = l.cast (by simp) := by
rcases l with l, rfl
simp
@[simp] theorem flatMap_append (xs ys : Vector α n) (f : α Vector β m) :
(xs ++ ys).flatMap f = (xs.flatMap f ++ ys.flatMap f).cast (by simp [Nat.add_mul]) := by
rcases xs with xs
rcases ys with ys
simp [flatMap_def, flatten_append]
theorem flatMap_assoc {α β} (l : Vector α n) (f : α Vector β m) (g : β Vector γ k) :
(l.flatMap f).flatMap g = (l.flatMap fun x => (f x).flatMap g).cast (by simp [Nat.mul_assoc]) := by
rcases l with l, rfl
simp [Array.flatMap_assoc]
theorem map_flatMap (f : β γ) (g : α Vector β m) (l : Vector α n) :
(l.flatMap g).map f = l.flatMap fun a => (g a).map f := by
rcases l with l, rfl
simp [Array.map_flatMap]
theorem flatMap_map (f : α β) (g : β Vector γ k) (l : Vector α n) :
(map f l).flatMap g = l.flatMap (fun a => g (f a)) := by
rcases l with l, rfl
simp [Array.flatMap_map]
theorem map_eq_flatMap {α β} (f : α β) (l : Vector α n) :
map f l = (l.flatMap fun x => #v[f x]).cast (by simp) := by
rcases l with l, rfl
simp [Array.map_eq_flatMap]
/-! ### mkVector -/
@[simp] theorem mkVector_one : mkVector 1 a = #v[a] := rfl
/-- Variant of `mkVector_succ` that prepends `a` at the beginning of the vector. -/
theorem mkVector_succ' : mkVector (n + 1) a = (#v[a] ++ mkVector n a).cast (by omega) := by
rw [ toArray_inj]
simp [Array.mkArray_succ']
@[simp] theorem mem_mkVector {a b : α} {n} : b mkVector n a n 0 b = a := by
unfold mkVector
simp
theorem eq_of_mem_mkVector {a b : α} {n} (h : b mkVector n a) : b = a := (mem_mkVector.1 h).2
theorem forall_mem_mkVector {p : α Prop} {a : α} {n} :
( b, b mkVector n a p b) n = 0 p a := by
cases n <;> simp [mem_mkVector]
@[simp] theorem getElem_mkVector (a : α) (n i : Nat) (h : i < n) : (mkVector n a)[i] = a := by
simp [mkVector]
theorem getElem?_mkVector (a : α) (n i : Nat) : (mkVector n a)[i]? = if i < n then some a else none := by
simp [getElem?_def]
@[simp] theorem getElem?_mkVector_of_lt {n : Nat} {m : Nat} (h : m < n) : (mkVector n a)[m]? = some a := by
simp [getElem?_mkVector, h]
theorem eq_mkVector_of_mem {a : α} {l : Vector α n} (h : (b) (_ : b l), b = a) : l = mkVector n a := by
rw [ toArray_inj]
simpa using Array.eq_mkArray_of_mem (l := l.toArray) (by simpa using h)
theorem eq_mkVector_iff {a : α} {n} {l : Vector α n} :
l = mkVector n a (b) (_ : b l), b = a := by
rw [ toArray_inj]
simpa using Array.eq_mkArray_iff (l := l.toArray) (n := n)
theorem map_eq_mkVector_iff {l : Vector α n} {f : α β} {b : β} :
l.map f = mkVector n b x l, f x = b := by
simp [eq_mkVector_iff]
@[simp] theorem map_const (l : Vector α n) (b : β) : map (Function.const α b) l = mkVector n b :=
map_eq_mkVector_iff.mpr fun _ _ => rfl
@[simp] theorem map_const_fun (x : β) : map (n := n) (Function.const α x) = fun _ => mkVector n x := by
funext l
simp
/-- Variant of `map_const` using a lambda rather than `Function.const`. -/
-- This can not be a `@[simp]` lemma because it would fire on every `List.map`.
theorem map_const' (l : Vector α n) (b : β) : map (fun _ => b) l = mkVector n b :=
map_const l b
@[simp] theorem set_mkVector_self : (mkVector n a).set i a h = mkVector n a := by
rw [ toArray_inj]
simp
@[simp] theorem setIfInBounds_mkVector_self : (mkVector n a).setIfInBounds i a = mkVector n a := by
rw [ toArray_inj]
simp
@[simp] theorem mkVector_append_mkVector : mkVector n a ++ mkVector m a = mkVector (n + m) a := by
rw [ toArray_inj]
simp
theorem append_eq_mkVector_iff {l₁ : Vector α n} {l₂ : Vector α m} {a : α} :
l₁ ++ l₂ = mkVector (n + m) a l₁ = mkVector n a l₂ = mkVector m a := by
simp [ toArray_inj, Array.append_eq_mkArray_iff]
theorem mkVector_eq_append_iff {l₁ : Vector α n} {l₂ : Vector α m} {a : α} :
mkVector (n + m) a = l₁ ++ l₂ l₁ = mkVector n a l₂ = mkVector m a := by
rw [eq_comm, append_eq_mkVector_iff]
@[simp] theorem map_mkVector : (mkVector n a).map f = mkVector n (f a) := by
rw [ toArray_inj]
simp
@[simp] theorem flatten_mkVector_empty : (mkVector n (#v[] : Vector α 0)).flatten = #v[] := by
rw [ toArray_inj]
simp
@[simp] theorem flatten_mkVector_singleton : (mkVector n #v[a]).flatten = (mkVector n a).cast (by simp) := by
ext i h
simp [h]
@[simp] theorem flatten_mkVector_mkVector : (mkVector n (mkVector m a)).flatten = mkVector (n * m) a := by
ext i h
simp [h]
theorem flatMap_mkArray {β} (f : α Vector β m) : (mkVector n a).flatMap f = (mkVector n (f a)).flatten := by
ext i h
simp [h]
@[simp] theorem sum_mkArray_nat (n : Nat) (a : Nat) : (mkVector n a).sum = n * a := by
simp [toArray_mkVector]
/-! ### reverse -/
@[simp] theorem reverse_push (as : Vector α n) (a : α) :
(as.push a).reverse = (#v[a] ++ as.reverse).cast (by omega) := by
rcases as with as, rfl
simp [Array.reverse_push]
@[simp] theorem mem_reverse {x : α} {as : Vector α n} : x as.reverse x as := by
cases as
simp
@[simp] theorem getElem_reverse (a : Vector α n) (i : Nat) (hi : i < n) :
(a.reverse)[i] = a[n - 1 - i] := by
rcases a with a, rfl
simp
/-- Variant of `getElem?_reverse` with a hypothesis giving the linear relation between the indices. -/
theorem getElem?_reverse' {l : Vector α n} (i j) (h : i + j + 1 = n) : l.reverse[i]? = l[j]? := by
rcases l with l, rfl
simpa using Array.getElem?_reverse' i j h
@[simp]
theorem getElem?_reverse {l : Vector α n} {i} (h : i < n) :
l.reverse[i]? = l[n - 1 - i]? := by
cases l
simp_all
@[simp] theorem reverse_reverse (as : Vector α n) : as.reverse.reverse = as := by
rcases as with as, rfl
simp [Array.reverse_reverse]
theorem reverse_eq_iff {as bs : Vector α n} : as.reverse = bs as = bs.reverse := by
constructor <;> (rintro rfl; simp)
@[simp] theorem reverse_inj {xs ys : Vector α n} : xs.reverse = ys.reverse xs = ys := by
simp [reverse_eq_iff]
@[simp] theorem reverse_eq_push_iff {xs : Vector α (n + 1)} {ys : Vector α n} {a : α} :
xs.reverse = ys.push a xs = (#v[a] ++ ys.reverse).cast (by omega) := by
rcases xs with xs, h
rcases ys with ys, rfl
simp [Array.reverse_eq_push_iff]
@[simp] theorem map_reverse (f : α β) (l : Vector α n) : l.reverse.map f = (l.map f).reverse := by
rcases l with l, rfl
simp [Array.map_reverse]
@[simp] theorem reverse_append (as : Vector α n) (bs : Vector α m) :
(as ++ bs).reverse = (bs.reverse ++ as.reverse).cast (by omega) := by
rcases as with as, rfl
rcases bs with bs, rfl
simp [Array.reverse_append]
@[simp] theorem reverse_eq_append_iff {xs : Vector α (n + m)} {ys : Vector α n} {zs : Vector α m} :
xs.reverse = ys ++ zs xs = (zs.reverse ++ ys.reverse).cast (by omega) := by
cases xs
cases ys
cases zs
simp
/-- Reversing a flatten is the same as reversing the order of parts and reversing all parts. -/
theorem reverse_flatten (L : Vector (Vector α m) n) :
L.flatten.reverse = (L.map reverse).reverse.flatten := by
cases L using vector₂_induction
simp [Array.reverse_flatten]
/-- Flattening a reverse is the same as reversing all parts and reversing the flattened result. -/
theorem flatten_reverse (L : Vector (Vector α m) n) :
L.reverse.flatten = (L.map reverse).flatten.reverse := by
cases L using vector₂_induction
simp [Array.flatten_reverse]
theorem reverse_flatMap {β} (l : Vector α n) (f : α Vector β m) :
(l.flatMap f).reverse = l.reverse.flatMap (reverse f) := by
rcases l with l, rfl
simp [Array.reverse_flatMap, Function.comp_def]
theorem flatMap_reverse {β} (l : Vector α n) (f : α Vector β m) :
(l.reverse.flatMap f) = (l.flatMap (reverse f)).reverse := by
rcases l with l, rfl
simp [Array.flatMap_reverse, Function.comp_def]
@[simp] theorem reverse_mkVector (n) (a : α) : reverse (mkVector n a) = mkVector n a := by
rw [ toArray_inj]
simp
/-! Content below this point has not yet been aligned with `List` and `Array`. -/
@[simp] theorem getElem_ofFn {α n} (f : Fin n α) (i : Nat) (h : i < n) :
@@ -1656,13 +1963,6 @@ theorem swap_comm (a : Vector α n) {i j : Nat} {hi hj} :
cases a
simp
/-! ### reverse -/
@[simp] theorem getElem_reverse (a : Vector α n) (i : Nat) (hi : i < n) :
(a.reverse)[i] = a[n - 1 - i] := by
rcases a with a, rfl
simp
/-! ### Decidable quantifiers. -/
theorem forall_zero_iff {P : Vector α 0 Prop} :

View File

@@ -12,116 +12,105 @@ import Init.ByCases
namespace Lean.Grind
/-!
Normalization theorems for the `grind` tactic.
We are also going to use simproc's in the future.
-/
-- Not
attribute [grind_norm] Classical.not_not
-- Ne
attribute [grind_norm] ne_eq
-- Iff
@[grind_norm] theorem iff_eq (p q : Prop) : (p q) = (p = q) := by
theorem iff_eq (p q : Prop) : (p q) = (p = q) := by
by_cases p <;> by_cases q <;> simp [*]
-- Eq
attribute [grind_norm] eq_self heq_eq_eq
-- Prop equality
@[grind_norm] theorem eq_true_eq (p : Prop) : (p = True) = p := by simp
@[grind_norm] theorem eq_false_eq (p : Prop) : (p = False) = ¬p := by simp
@[grind_norm] theorem not_eq_prop (p q : Prop) : (¬(p = q)) = (p = ¬q) := by
theorem eq_true_eq (p : Prop) : (p = True) = p := by simp
theorem eq_false_eq (p : Prop) : (p = False) = ¬p := by simp
theorem not_eq_prop (p q : Prop) : (¬(p = q)) = (p = ¬q) := by
by_cases p <;> by_cases q <;> simp [*]
-- True
attribute [grind_norm] not_true
-- False
attribute [grind_norm] not_false_eq_true
-- Remark: we disabled the following normalization rule because we want this information when implementing splitting heuristics
-- Implication as a clause
theorem imp_eq (p q : Prop) : (p q) = (¬ p q) := by
by_cases p <;> by_cases q <;> simp [*]
@[grind_norm] theorem true_imp_eq (p : Prop) : (True p) = p := by simp
@[grind_norm] theorem false_imp_eq (p : Prop) : (False p) = True := by simp
@[grind_norm] theorem imp_true_eq (p : Prop) : (p True) = True := by simp
@[grind_norm] theorem imp_false_eq (p : Prop) : (p False) = ¬p := by simp
@[grind_norm] theorem imp_self_eq (p : Prop) : (p p) = True := by simp
theorem true_imp_eq (p : Prop) : (True p) = p := by simp
theorem false_imp_eq (p : Prop) : (False p) = True := by simp
theorem imp_true_eq (p : Prop) : (p True) = True := by simp
theorem imp_false_eq (p : Prop) : (p False) = ¬p := by simp
theorem imp_self_eq (p : Prop) : (p p) = True := by simp
-- And
@[grind_norm] theorem not_and (p q : Prop) : (¬(p q)) = (¬p ¬q) := by
theorem not_and (p q : Prop) : (¬(p q)) = (¬p ¬q) := by
by_cases p <;> by_cases q <;> simp [*]
attribute [grind_norm] and_true true_and and_false false_and and_assoc
-- Or
attribute [grind_norm] not_or
attribute [grind_norm] or_true true_or or_false false_or or_assoc
-- ite
attribute [grind_norm] ite_true ite_false
@[grind_norm] theorem not_ite {_ : Decidable p} (q r : Prop) : (¬ite p q r) = ite p (¬q) (¬r) := by
theorem not_ite {_ : Decidable p} (q r : Prop) : (¬ite p q r) = ite p (¬q) (¬r) := by
by_cases p <;> simp [*]
@[grind_norm] theorem ite_true_false {_ : Decidable p} : (ite p True False) = p := by
theorem ite_true_false {_ : Decidable p} : (ite p True False) = p := by
by_cases p <;> simp
@[grind_norm] theorem ite_false_true {_ : Decidable p} : (ite p False True) = ¬p := by
theorem ite_false_true {_ : Decidable p} : (ite p False True) = ¬p := by
by_cases p <;> simp
-- Forall
@[grind_norm] theorem not_forall (p : α Prop) : (¬ x, p x) = x, ¬p x := by simp
attribute [grind_norm] forall_and
theorem not_forall (p : α Prop) : (¬ x, p x) = x, ¬p x := by simp
-- Exists
@[grind_norm] theorem not_exists (p : α Prop) : (¬ x, p x) = x, ¬p x := by simp
attribute [grind_norm] exists_const exists_or exists_prop exists_and_left exists_and_right
theorem not_exists (p : α Prop) : (¬ x, p x) = x, ¬p x := by simp
-- Bool cond
@[grind_norm] theorem cond_eq_ite (c : Bool) (a b : α) : cond c a b = ite c a b := by
theorem cond_eq_ite (c : Bool) (a b : α) : cond c a b = ite c a b := by
cases c <;> simp [*]
-- Bool or
attribute [grind_norm]
Bool.or_false Bool.or_true Bool.false_or Bool.true_or Bool.or_eq_true Bool.or_assoc
-- Bool and
attribute [grind_norm]
Bool.and_false Bool.and_true Bool.false_and Bool.true_and Bool.and_eq_true Bool.and_assoc
-- Bool not
attribute [grind_norm]
Bool.not_not
-- beq
attribute [grind_norm] beq_iff_eq
-- bne
attribute [grind_norm] bne_iff_ne
-- Bool not eq true/false
attribute [grind_norm] Bool.not_eq_true Bool.not_eq_false
-- decide
attribute [grind_norm] decide_eq_true_eq decide_not not_decide_eq_true
-- Nat LE
attribute [grind_norm] Nat.le_zero_eq
-- Nat/Int LT
@[grind_norm] theorem Nat.lt_eq (a b : Nat) : (a < b) = (a + 1 b) := by
theorem Nat.lt_eq (a b : Nat) : (a < b) = (a + 1 b) := by
simp [Nat.lt, LT.lt]
@[grind_norm] theorem Int.lt_eq (a b : Int) : (a < b) = (a + 1 b) := by
theorem Int.lt_eq (a b : Int) : (a < b) = (a + 1 b) := by
simp [Int.lt, LT.lt]
-- GT GE
attribute [grind_norm] GT.gt GE.ge
theorem ge_eq [LE α] (a b : α) : (a b) = (b a) := rfl
theorem gt_eq [LT α] (a b : α) : (a > b) = (b < a) := rfl
-- Succ
attribute [grind_norm] Nat.succ_eq_add_one
init_grind_norm
/- Pre theorems -/
not_and not_or not_ite not_forall not_exists
|
/- Post theorems -/
Classical.not_not
ne_eq iff_eq eq_self heq_eq_eq
-- Prop equality
eq_true_eq eq_false_eq not_eq_prop
-- True
not_true
-- False
not_false_eq_true
-- Implication
true_imp_eq false_imp_eq imp_true_eq imp_false_eq imp_self_eq
-- And
and_true true_and and_false false_and and_assoc
-- Or
or_true true_or or_false false_or or_assoc
-- ite
ite_true ite_false ite_true_false ite_false_true
-- Forall
forall_and
-- Exists
exists_const exists_or exists_prop exists_and_left exists_and_right
-- Bool cond
cond_eq_ite
-- Bool or
Bool.or_false Bool.or_true Bool.false_or Bool.true_or Bool.or_eq_true Bool.or_assoc
-- Bool and
Bool.and_false Bool.and_true Bool.false_and Bool.true_and Bool.and_eq_true Bool.and_assoc
-- Bool not
Bool.not_not
-- beq
beq_iff_eq
-- bne
bne_iff_ne
-- Bool not eq true/false
Bool.not_eq_true Bool.not_eq_false
-- decide
decide_eq_true_eq decide_not not_decide_eq_true
-- Nat LE
Nat.le_zero_eq
-- Nat/Int LT
Nat.lt_eq
-- Nat.succ
Nat.succ_eq_add_one
-- Int
Int.lt_eq
-- GT GE
ge_eq gt_eq
end Lean.Grind

View File

@@ -14,7 +14,9 @@ syntax grindEqRhs := atomic("=" "_")
syntax grindBwd := ""
syntax grindFwd := ""
syntax (name := grind) "grind" (grindEqBoth <|> grindEqRhs <|> grindEq <|> grindBwd <|> grindFwd)? : attr
syntax grindThmMod := grindEqBoth <|> grindEqRhs <|> grindEq <|> grindBwd <|> grindFwd
syntax (name := grind) "grind" (grindThmMod)? : attr
end Lean.Parser.Attr
@@ -45,6 +47,12 @@ structure Config where
If `splitIndPred` is `true`, `grind` performs case-splitting on inductive predicates.
Otherwise, it performs case-splitting only on types marked with `[grind_split]` attribute. -/
splitIndPred : Bool := true
/-- By default, `grind` halts as soon as it encounters a sub-goal where no further progress can be made. -/
failures : Nat := 1
/-- Maximum number of heartbeats (in thousands) the canonicalizer can spend per definitional equality test. -/
canonHeartbeats : Nat := 1000
/-- If `ext` is `true`, `grind` uses extensionality theorems available in the environment. -/
ext : Bool := true
deriving Inhabited, BEq
end Lean.Grind
@@ -55,7 +63,13 @@ namespace Lean.Parser.Tactic
`grind` tactic and related tactics.
-/
-- TODO: parameters
syntax (name := grind) "grind" optConfig ("on_failure " term)? : tactic
syntax grindErase := "-" ident
syntax grindLemma := (Attr.grindThmMod)? ident
syntax grindParam := grindErase <|> grindLemma
syntax (name := grind)
"grind" optConfig (&" only")?
(" [" withoutPosition(grindParam,*) "]")?
("on_failure " term)? : tactic
end Lean.Parser.Tactic

View File

@@ -150,6 +150,9 @@ It can also be written as `()`.
/-- Marker for information that has been erased by the code generator. -/
unsafe axiom lcErased : Type
/-- Marker for type dependency that has been erased by the code generator. -/
unsafe axiom lcAny : Type
/--
Auxiliary unsafe constant used by the Compiler when erasing proofs from code.

View File

@@ -1648,17 +1648,6 @@ If there are several with the same priority, it is uses the "most recent one". E
-/
syntax (name := simp) "simp" (Tactic.simpPre <|> Tactic.simpPost)? patternIgnore("" <|> "<- ")? (ppSpace prio)? : attr
/--
Theorems tagged with the `grind_norm` attribute are used by the `grind` tactic normalizer/pre-processor.
-/
syntax (name := grind_norm) "grind_norm" (Tactic.simpPre <|> Tactic.simpPost)? (ppSpace prio)? : attr
/--
Simplification procedures tagged with the `grind_norm_proc` attribute are used by the `grind` tactic normalizer/pre-processor.
-/
syntax (name := grind_norm_proc) "grind_norm_proc" (Tactic.simpPre <|> Tactic.simpPost)? : attr
/-- The possible `norm_cast` kinds: `elim`, `move`, or `squash`. -/
syntax normCastLabel := &"elim" <|> &"move" <|> &"squash"

View File

@@ -14,21 +14,54 @@ register_builtin_option debug.skipKernelTC : Bool := {
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"
}
def Environment.addDecl (env : Environment) (opts : Options) (decl : Declaration)
(cancelTk? : Option IO.CancelToken := none) : Except KernelException Environment :=
/-- 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 :=
if debug.skipKernelTC.get opts then
addDeclWithoutChecking env decl
else
addDeclCore env (Core.getMaxHeartbeats opts).toUSize decl cancelTk?
private def Environment.addDeclAux (env : Environment) (opts : Options) (decl : Declaration)
(cancelTk? : Option IO.CancelToken := none) : Except Kernel.Exception Environment :=
env.addDeclCore (Core.getMaxHeartbeats opts).toUSize decl cancelTk? (!debug.skipKernelTC.get opts)
@[deprecated "use `Lean.addDecl` instead to ensure new namespaces are registered" (since := "2024-12-03")]
def Environment.addDecl (env : Environment) (opts : Options) (decl : Declaration)
(cancelTk? : Option IO.CancelToken := none) : Except Kernel.Exception Environment :=
Environment.addDeclAux env opts decl cancelTk?
private def isNamespaceName : Name Bool
| .str .anonymous _ => true
| .str p _ => isNamespaceName p
| _ => false
private def registerNamePrefixes (env : Environment) (name : Name) : Environment :=
match name with
| .str _ s =>
if s.get 0 == '_' then
-- Do not register namespaces that only contain internal declarations.
env
else
go env name
| _ => env
where go env
| .str p _ => if isNamespaceName p then go (env.registerNamespace p) p else env
| _ => env
def addDecl (decl : Declaration) : CoreM Unit := do
profileitM Exception "type checking" ( getOptions) do
withTraceNode `Kernel (fun _ => return m!"typechecking declaration") do
let mut env withTraceNode `Kernel (fun _ => return m!"typechecking declaration") do
if !( MonadLog.hasErrors) && decl.hasSorry then
logWarning "declaration uses 'sorry'"
match ( getEnv).addDecl ( getOptions) decl ( read).cancelTk? with
| .ok env => setEnv env
| .error ex => throwKernelException ex
( getEnv).addDeclAux ( getOptions) decl ( read).cancelTk? |> ofExceptKernelException
-- register namespaces for newly added constants; this used to be done by the kernel itself
-- but that is incompatible with moving it to a separate task
env := decl.getNames.foldl registerNamePrefixes env
if let .inductDecl _ _ types _ := decl then
env := types.foldl (registerNamePrefixes · <| ·.name ++ `rec) env
setEnv env
def addAndCompile (decl : Declaration) : CoreM Unit := do
addDecl decl

View File

@@ -150,18 +150,7 @@ where
def toMono : Pass where
name := `toMono
run := fun decls => do
let decls decls.filterM fun decl => do
if hasLocalInst decl.type then
/-
Declaration is a "template" for the code specialization pass.
So, we should delete it before going to next phase.
-/
decl.erase
return false
else
return true
decls.mapM (·.toMono)
run := (·.mapM (·.toMono))
phase := .base
phaseOut := .mono

View File

@@ -515,7 +515,7 @@ register_builtin_option compiler.enableNew : Bool := {
opaque compileDeclsNew (declNames : List Name) : CoreM Unit
@[extern "lean_compile_decls"]
opaque compileDeclsOld (env : Environment) (opt : @& Options) (decls : @& List Name) : Except KernelException Environment
opaque compileDeclsOld (env : Environment) (opt : @& Options) (decls : @& List Name) : Except Kernel.Exception Environment
def compileDecl (decl : Declaration) : CoreM Unit := do
let opts getOptions
@@ -526,7 +526,7 @@ def compileDecl (decl : Declaration) : CoreM Unit := do
return compileDeclsOld ( getEnv) opts decls
match res with
| Except.ok env => setEnv env
| Except.error (KernelException.other msg) =>
| Except.error (.other msg) =>
checkUnsupported decl -- Generate nicer error message for unsupported recursors and axioms
throwError msg
| Except.error ex =>
@@ -538,7 +538,7 @@ def compileDecls (decls : List Name) : CoreM Unit := do
compileDeclsNew decls
match compileDeclsOld ( getEnv) opts decls with
| Except.ok env => setEnv env
| Except.error (KernelException.other msg) =>
| Except.error (.other msg) =>
throwError msg
| Except.error ex =>
throwKernelException ex

View File

@@ -54,6 +54,10 @@ instance : EmptyCollection (NameTrie β) where
def NameTrie.find? (t : NameTrie β) (k : Name) : Option β :=
PrefixTree.find? t (toKey k)
@[inline, inherit_doc PrefixTree.findLongestPrefix?]
def NameTrie.findLongestPrefix? (t : NameTrie β) (k : Name) : Option β :=
PrefixTree.findLongestPrefix? t (toKey k)
@[inline]
def NameTrie.foldMatchingM [Monad m] (t : NameTrie β) (k : Name) (init : σ) (f : β σ m σ) : m σ :=
PrefixTree.foldMatchingM t (toKey k) init f

View File

@@ -48,6 +48,17 @@ partial def find? (t : PrefixTreeNode α β) (cmp : αα → Ordering) (k :
| some t => loop t ks
loop t k
/-- Returns the the value of the longest key in `t` that is a prefix of `k`, if any. -/
@[specialize]
partial def findLongestPrefix? (t : PrefixTreeNode α β) (cmp : α α Ordering) (k : List α) : Option β :=
let rec loop acc?
| PrefixTreeNode.Node val _, [] => val <|> acc?
| PrefixTreeNode.Node val m, k :: ks =>
match RBNode.find cmp m k with
| none => val
| some t => loop (val <|> acc?) t ks
loop none t k
@[specialize]
partial def foldMatchingM [Monad m] (t : PrefixTreeNode α β) (cmp : α α Ordering) (k : List α) (init : σ) (f : β σ m σ) : m σ :=
let rec fold : PrefixTreeNode α β σ m σ
@@ -92,6 +103,10 @@ def PrefixTree.insert (t : PrefixTree α β p) (k : List α) (v : β) : PrefixTr
def PrefixTree.find? (t : PrefixTree α β p) (k : List α) : Option β :=
t.val.find? p k
@[inline, inherit_doc PrefixTreeNode.findLongestPrefix?]
def PrefixTree.findLongestPrefix? (t : PrefixTree α β p) (k : List α) : Option β :=
t.val.findLongestPrefix? p k
@[inline]
def PrefixTree.foldMatchingM [Monad m] (t : PrefixTree α β p) (k : List α) (init : σ) (f : β σ m σ) : m σ :=
t.val.foldMatchingM p k init f

View File

@@ -193,6 +193,19 @@ def Declaration.definitionVal! : Declaration → DefinitionVal
| .defnDecl val => val
| _ => panic! "Expected a `Declaration.defnDecl`."
/--
Returns all top-level names to be defined by adding this declaration to the environment. This does
not include auxiliary definitions such as projections.
-/
def Declaration.getNames : Declaration List Name
| .axiomDecl val => [val.name]
| .defnDecl val => [val.name]
| .thmDecl val => [val.name]
| .opaqueDecl val => [val.name]
| .quotDecl => [``Quot, ``Quot.mk, ``Quot.lift, ``Quot.ind]
| .mutualDefnDecl defns => defns.map (·.name)
| .inductDecl _ _ types _ => types.map (·.name)
@[specialize] def Declaration.foldExprM {α} {m : Type Type} [Monad m] (d : Declaration) (f : α Expr m α) (a : α) : m α :=
match d with
| .quotDecl => pure a
@@ -469,6 +482,10 @@ def isInductive : ConstantInfo → Bool
| .inductInfo _ => true
| _ => false
def isDefinition : ConstantInfo Bool
| .defnInfo _ => true
| _ => false
def isTheorem : ConstantInfo Bool
| .thmInfo _ => true
| _ => false

View File

@@ -124,9 +124,7 @@ private partial def elabChoiceAux (cmds : Array Syntax) (i : Nat) : CommandElabM
n[1].forArgsM addUnivLevel
@[builtin_command_elab «init_quot»] def elabInitQuot : CommandElab := fun _ => do
match ( getEnv).addDecl ( getOptions) Declaration.quotDecl with
| Except.ok env => setEnv env
| Except.error ex => throwError (ex.toMessageData ( getOptions))
liftCoreM <| addDecl Declaration.quotDecl
@[builtin_command_elab «export»] def elabExport : CommandElab := fun stx => do
let `(export $ns ($ids*)) := stx | throwUnsupportedSyntax
@@ -294,7 +292,7 @@ def failIfSucceeds (x : CommandElabM Unit) : CommandElabM Unit := do
modify fun s => { s with messages := {} };
pure messages
let restoreMessages (prevMessages : MessageLog) : CommandElabM Unit := do
modify fun s => { s with messages := prevMessages ++ s.messages.errorsToWarnings }
modify fun s => { s with messages := prevMessages ++ s.messages.errorsToInfos }
let prevMessages resetMessages
let succeeded try
x

View File

@@ -681,7 +681,7 @@ private partial def checkResultingUniversesForFields (fieldInfos : Array StructF
throwErrorAt info.ref msg
@[extern "lean_mk_projections"]
private opaque mkProjections (env : Environment) (structName : Name) (projs : List Name) (isClass : Bool) : Except KernelException Environment
private opaque mkProjections (env : Environment) (structName : Name) (projs : List Name) (isClass : Bool) : Except Kernel.Exception Environment
private def addProjections (r : ElabHeaderResult) (fieldInfos : Array StructFieldInfo) : TermElabM Unit := do
if r.type.isProp then

View File

@@ -38,6 +38,9 @@ declare_config_elab elabBVDecideConfig Lean.Elab.Tactic.BVDecide.Frontend.BVDeci
builtin_initialize bvNormalizeExt : Meta.SimpExtension
Meta.registerSimpAttr `bv_normalize "simp theorems used by bv_normalize"
builtin_initialize intToBitVecExt : Meta.SimpExtension
Meta.registerSimpAttr `int_toBitVec "simp theorems used to convert UIntX/IntX statements into BitVec ones"
/-- Builtin `bv_normalize` simprocs. -/
builtin_initialize builtinBVNormalizeSimprocsRef : IO.Ref Meta.Simp.Simprocs IO.mkRef {}

View File

@@ -40,7 +40,7 @@ def passPipeline : PreProcessM (List Pass) := do
def bvNormalize (g : MVarId) (cfg : BVDecideConfig) : MetaM (Option MVarId) := do
withTraceNode `bv (fun _ => return "Preprocessing goal") do
(go g).run cfg
(go g).run cfg g
where
go (g : MVarId) : PreProcessM (Option MVarId) := do
let some g g.falseOrByContra | return none

View File

@@ -19,6 +19,11 @@ namespace Frontend.Normalize
open Lean.Meta
structure AndFlattenState where
hypsToDelete : Array FVarId := #[]
hypsToAdd : Array Hypothesis := #[]
cache : Std.HashSet Expr := {}
/--
Flatten out ands. That is look for hypotheses of the form `h : (x && y) = true` and replace them
with `h.left : x = true` and `h.right : y = true`. This can enable more fine grained substitutions
@@ -27,59 +32,67 @@ in embedded constraint substitution.
partial def andFlatteningPass : Pass where
name := `andFlattening
run' goal := do
let (_, { hypsToDelete, hypsToAdd, .. }) processGoal goal |>.run {}
if hypsToAdd.isEmpty then
return goal
else
let (_, goal) goal.assertHypotheses hypsToAdd
-- Given that we collected the hypotheses in the correct order above the invariant is given
let goal goal.tryClearMany hypsToDelete
return goal
where
processGoal (goal : MVarId) : StateRefT AndFlattenState MetaM Unit := do
goal.withContext do
let hyps goal.getNondepPropHyps
let mut newHyps := #[]
let mut oldHyps := #[]
for fvar in hyps do
let hyp : Hypothesis := {
userName := ( fvar.getDecl).userName
type := fvar.getType
value := mkFVar fvar
}
let sizeBefore := newHyps.size
newHyps splitAnds hyp newHyps
if newHyps.size > sizeBefore then
oldHyps := oldHyps.push fvar
if newHyps.size == 0 then
return goal
else
let (_, goal) goal.assertHypotheses newHyps
-- Given that we collected the hypotheses in the correct order above the invariant is given
let goal goal.tryClearMany oldHyps
return goal
where
splitAnds (hyp : Hypothesis) (hyps : Array Hypothesis) (first : Bool := true) :
MetaM (Array Hypothesis) := do
match trySplit hyp with
| some (left, right) =>
let hyps splitAnds left hyps false
splitAnds right hyps false
| none =>
if first then
return hyps
else
return hyps.push hyp
hyps.forM processFVar
trySplit (hyp : Hypothesis) : MetaM (Option (Hypothesis × Hypothesis)) := do
processFVar (fvar : FVarId) : StateRefT AndFlattenState MetaM Unit := do
let type fvar.getType
if ( get).cache.contains type then
modify (fun s => { s with hypsToDelete := s.hypsToDelete.push fvar })
else
let hyp := {
userName := ( fvar.getDecl).userName
type := type
value := mkFVar fvar
}
let some (lhs, rhs) trySplit hyp | return ()
modify (fun s => { s with hypsToDelete := s.hypsToDelete.push fvar })
splitAnds [lhs, rhs]
splitAnds (worklist : List Hypothesis) : StateRefT AndFlattenState MetaM Unit := do
match worklist with
| [] => return ()
| hyp :: worklist =>
match trySplit hyp with
| some (left, right) => splitAnds <| left :: right :: worklist
| none =>
modify (fun s => { s with hypsToAdd := s.hypsToAdd.push hyp })
splitAnds worklist
trySplit (hyp : Hypothesis) :
StateRefT AndFlattenState MetaM (Option (Hypothesis × Hypothesis)) := do
let typ := hyp.type
let_expr Eq α eqLhs eqRhs := typ | return none
let_expr Bool.and lhs rhs := eqLhs | return none
let_expr Bool.true := eqRhs | return none
let_expr Bool := α | return none
let mkEqTrue (lhs : Expr) : Expr :=
mkApp3 (mkConst ``Eq [1]) (mkConst ``Bool) lhs (mkConst ``Bool.true)
let leftHyp : Hypothesis := {
userName := hyp.userName,
type := mkEqTrue lhs,
value := mkApp3 (mkConst ``Std.Tactic.BVDecide.Normalize.Bool.and_left) lhs rhs hyp.value
}
let rightHyp : Hypothesis := {
userName := hyp.userName,
type := mkEqTrue rhs,
value := mkApp3 (mkConst ``Std.Tactic.BVDecide.Normalize.Bool.and_right) lhs rhs hyp.value
}
return some (leftHyp, rightHyp)
if ( get).cache.contains typ then
return none
else
modify (fun s => { s with cache := s.cache.insert typ })
let_expr Eq _ eqLhs eqRhs := typ | return none
let_expr Bool.and lhs rhs := eqLhs | return none
let_expr Bool.true := eqRhs | return none
let mkEqTrue (lhs : Expr) : Expr :=
mkApp3 (mkConst ``Eq [1]) (mkConst ``Bool) lhs (mkConst ``Bool.true)
let leftHyp : Hypothesis := {
userName := hyp.userName,
type := mkEqTrue lhs,
value := mkApp3 (mkConst ``Std.Tactic.BVDecide.Normalize.Bool.and_left) lhs rhs hyp.value
}
let rightHyp : Hypothesis := {
userName := hyp.userName,
type := mkEqTrue rhs,
value := mkApp3 (mkConst ``Std.Tactic.BVDecide.Normalize.Bool.and_right) lhs rhs hyp.value
}
return some (leftHyp, rightHyp)
end Frontend.Normalize

View File

@@ -16,14 +16,33 @@ namespace Frontend.Normalize
open Lean.Meta
abbrev PreProcessM : Type Type := ReaderT BVDecideConfig MetaM
structure PreProcessState where
/--
Contains `FVarId` that we already know are in `bv_normalize` simp normal form and thus don't
need to be processed again when we visit the next time.
-/
rewriteCache : Std.HashSet FVarId := {}
abbrev PreProcessM : Type Type := ReaderT BVDecideConfig <| StateRefT PreProcessState MetaM
namespace PreProcessM
def getConfig : PreProcessM BVDecideConfig := read
def run (cfg : BVDecideConfig) (x : PreProcessM α) : MetaM α :=
ReaderT.run x cfg
@[inline]
def checkRewritten (fvar : FVarId) : PreProcessM Bool := do
let val := ( get).rewriteCache.contains fvar
trace[Meta.Tactic.bv] m!"{mkFVar fvar} was already rewritten? {val}"
return val
@[inline]
def rewriteFinished (fvar : FVarId) : PreProcessM Unit := do
trace[Meta.Tactic.bv] m!"Adding {mkFVar fvar} to the rewritten set"
modify (fun s => { s with rewriteCache := s.rewriteCache.insert fvar })
def run (cfg : BVDecideConfig) (goal : MVarId) (x : PreProcessM α) : MetaM α := do
let hyps goal.getNondepPropHyps
ReaderT.run x cfg |>.run' { rewriteCache := Std.HashSet.empty hyps.size }
end PreProcessM

View File

@@ -33,26 +33,26 @@ def embeddedConstraintPass : Pass where
let mut duplicates : Array FVarId := #[]
for hyp in hyps do
let typ hyp.getType
let_expr Eq α lhs rhs := typ | continue
let_expr Eq _ lhs rhs := typ | continue
let_expr Bool.true := rhs | continue
let_expr Bool := α | continue
if seen.contains lhs then
-- collect and later remove duplicates on the fly
duplicates := duplicates.push hyp
else
seen := seen.insert lhs
let localDecl hyp.getDecl
let proof := localDecl.toExpr
let proof := localDecl.toExpr
relevantHyps relevantHyps.addTheorem (.fvar hyp) proof
let goal goal.tryClearMany duplicates
let cfg PreProcessM.getConfig
if relevantHyps.isEmpty then
return goal
let cfg PreProcessM.getConfig
let simpCtx Simp.mkContext
(config := { failIfUnchanged := false, maxSteps := cfg.maxSteps })
(simpTheorems := relevantHyps)
(congrTheorems := ( getSimpCongrTheorems))
let result?, _ simpGoal goal (ctx := simpCtx) (fvarIdsToSimp := goal.getNondepPropHyps)
let some (_, newGoal) := result? | return none
return newGoal

View File

@@ -35,13 +35,27 @@ def rewriteRulesPass : Pass where
(simpTheorems := #[bvThms, sevalThms])
(congrTheorems := ( getSimpCongrTheorems))
let hyps goal.getNondepPropHyps
let result?, _ simpGoal goal
(ctx := simpCtx)
(simprocs := #[bvSimprocs, sevalSimprocs])
(fvarIdsToSimp := hyps)
let some (_, newGoal) := result? | return none
return newGoal
let hyps getHyps goal
if hyps.isEmpty then
return goal
else
let result?, _ simpGoal goal
(ctx := simpCtx)
(simprocs := #[bvSimprocs, sevalSimprocs])
(fvarIdsToSimp := hyps)
let some (_, newGoal) := result? | return none
newGoal.withContext do
( newGoal.getNondepPropHyps).forM PreProcessM.rewriteFinished
return newGoal
where
getHyps (goal : MVarId) : PreProcessM (Array FVarId) := do
goal.withContext do
let mut hyps goal.getNondepPropHyps
let filter hyp := do
return !( PreProcessM.checkRewritten hyp)
hyps.filterM filter
end Frontend.Normalize
end Lean.Elab.Tactic.BVDecide

View File

@@ -5,6 +5,7 @@ Authors: Gabriel Ebner, Mario Carneiro
-/
prelude
import Init.Ext
import Lean.Meta.Tactic.Ext
import Lean.Elab.DeclarationRange
import Lean.Elab.Tactic.RCases
import Lean.Elab.Tactic.Repeat
@@ -174,65 +175,8 @@ def realizeExtIffTheorem (extName : Name) : Elab.Command.CommandElabM Name := do
### Attribute
-/
/-- Information about an extensionality theorem, stored in the environment extension. -/
structure ExtTheorem where
/-- Declaration name of the extensionality theorem. -/
declName : Name
/-- Priority of the extensionality theorem. -/
priority : Nat
/--
Key in the discrimination tree,
for the type in which the extensionality theorem holds.
-/
keys : Array DiscrTree.Key
deriving Inhabited, Repr, BEq, Hashable
/-- The state of the `ext` extension environment -/
structure ExtTheorems where
/-- The tree of `ext` extensions. -/
tree : DiscrTree ExtTheorem := {}
/-- Erased `ext`s via `attribute [-ext]`. -/
erased : PHashSet Name := {}
deriving Inhabited
/-- The environment extension to track `@[ext]` theorems. -/
builtin_initialize extExtension :
SimpleScopedEnvExtension ExtTheorem ExtTheorems
registerSimpleScopedEnvExtension {
addEntry := fun { tree, erased } thm =>
{ tree := tree.insertCore thm.keys thm, erased := erased.erase thm.declName }
initial := {}
}
/-- Gets the list of `@[ext]` theorems corresponding to the key `ty`,
ordered from high priority to low. -/
@[inline] def getExtTheorems (ty : Expr) : MetaM (Array ExtTheorem) := do
let extTheorems := extExtension.getState ( getEnv)
let arr extTheorems.tree.getMatch ty
let erasedArr := arr.filter fun thm => !extTheorems.erased.contains thm.declName
-- Using insertion sort because it is stable and the list of matches should be mostly sorted.
-- Most ext theorems have default priority.
return erasedArr.insertionSort (·.priority < ·.priority) |>.reverse
/--
Erases a name marked `ext` by adding it to the state's `erased` field and
removing it from the state's list of `Entry`s.
This is triggered by `attribute [-ext] name`.
-/
def ExtTheorems.eraseCore (d : ExtTheorems) (declName : Name) : ExtTheorems :=
{ d with erased := d.erased.insert declName }
/--
Erases a name marked as a `ext` attribute.
Check that it does in fact have the `ext` attribute by making sure it names a `ExtTheorem`
found somewhere in the state's tree, and is not erased.
-/
def ExtTheorems.erase [Monad m] [MonadError m] (d : ExtTheorems) (declName : Name) :
m ExtTheorems := do
unless d.tree.containsValueP (·.declName == declName) && !d.erased.contains declName do
throwError "'{declName}' does not have [ext] attribute"
return d.eraseCore declName
abbrev extExtension := Meta.Ext.extExtension
abbrev getExtTheorems := Meta.Ext.getExtTheorems
builtin_initialize registerBuiltinAttribute {
name := `ext

View File

@@ -34,10 +34,69 @@ def elabGrindPattern : CommandElab := fun stx => do
Grind.addEMatchTheorem declName xs.size patterns.toList
| _ => throwUnsupportedSyntax
def grind (mvarId : MVarId) (config : Grind.Config) (mainDeclName : Name) (fallback : Grind.Fallback) : MetaM Unit := do
let goals Grind.main mvarId config mainDeclName fallback
open Command Term in
@[builtin_command_elab Lean.Parser.Command.initGrindNorm]
def elabInitGrindNorm : CommandElab := fun stx =>
match stx with
| `(init_grind_norm $pre:ident* | $post*) =>
Command.liftTermElabM do
let pre pre.mapM fun id => realizeGlobalConstNoOverloadWithInfo id
let post post.mapM fun id => realizeGlobalConstNoOverloadWithInfo id
Grind.registerNormTheorems pre post
| _ => throwUnsupportedSyntax
def elabGrindParams (params : Grind.Params) (ps : TSyntaxArray ``Parser.Tactic.grindParam) : MetaM Grind.Params := do
let mut params := params
for p in ps do
match p with
| `(Parser.Tactic.grindParam| - $id:ident) =>
let declName realizeGlobalConstNoOverloadWithInfo id
if ( isInductivePredicate declName) then
throwErrorAt p "NIY"
else
params := { params with ematch := ( params.ematch.eraseDecl declName) }
| `(Parser.Tactic.grindParam| $[$mod?:grindThmMod]? $id:ident) =>
let declName realizeGlobalConstNoOverloadWithInfo id
let kind if let some mod := mod? then Grind.getTheoremKindCore mod else pure .default
if ( isInductivePredicate declName) then
throwErrorAt p "NIY"
else
let info getConstInfo declName
match info with
| .thmInfo _ =>
if kind == .eqBoth then
params := { params with extra := params.extra.push ( Grind.mkEMatchTheoremForDecl declName .eqLhs) }
params := { params with extra := params.extra.push ( Grind.mkEMatchTheoremForDecl declName .eqRhs) }
else
params := { params with extra := params.extra.push ( Grind.mkEMatchTheoremForDecl declName kind) }
| .defnInfo _ =>
if ( isReducible declName) then
throwErrorAt p "`{declName}` is a reducible definition, `grind` automatically unfolds them"
if kind != .eqLhs && kind != .default then
throwErrorAt p "invalid `grind` parameter, `{declName}` is a definition, the only acceptable (and redundant) modifier is '='"
let some thms Grind.mkEMatchEqTheoremsForDef? declName
| throwErrorAt p "failed to genereate equation theorems for `{declName}`"
params := { params with extra := params.extra ++ thms.toPArray' }
| _ =>
throwErrorAt p "invalid `grind` parameter, `{declName}` is not a theorem, definition, or inductive type"
| _ => throwError "unexpected `grind` parameter{indentD p}"
return params
def mkGrindParams (config : Grind.Config) (only : Bool) (ps : TSyntaxArray ``Parser.Tactic.grindParam) : MetaM Grind.Params := do
let params Grind.mkParams config
let ematch if only then pure {} else Grind.getEMatchTheorems
let params := { params with ematch }
elabGrindParams params ps
def grind
(mvarId : MVarId) (config : Grind.Config)
(only : Bool)
(ps : TSyntaxArray ``Parser.Tactic.grindParam)
(mainDeclName : Name) (fallback : Grind.Fallback) : MetaM Unit := do
let params mkGrindParams config only ps
let goals Grind.main mvarId params mainDeclName fallback
unless goals.isEmpty do
throwError "`grind` failed\n{← Grind.goalsToMessageData goals}"
throwError "`grind` failed\n{← Grind.goalsToMessageData goals config}"
private def elabFallback (fallback? : Option Term) : TermElabM (Grind.GoalM Unit) := do
let some fallback := fallback? | return (pure ())
@@ -56,14 +115,16 @@ private def elabFallback (fallback? : Option Term) : TermElabM (Grind.GoalM Unit
pure auxDeclName
unsafe evalConst (Grind.GoalM Unit) auxDeclName
@[builtin_tactic Lean.Parser.Tactic.grind] def evalApplyRfl : Tactic := fun stx => do
@[builtin_tactic Lean.Parser.Tactic.grind] def evalGrind : Tactic := fun stx => do
match stx with
| `(tactic| grind $config:optConfig $[on_failure $fallback?]?) =>
| `(tactic| grind $config:optConfig $[only%$only]? $[ [$params:grindParam,*] ]? $[on_failure $fallback?]?) =>
let fallback elabFallback fallback?
let only := only.isSome
let params := if let some params := params then params.getElems else #[]
logWarningAt stx "The `grind` tactic is experimental and still under development. Avoid using it in production projects"
let declName := ( Term.getDeclName?).getD `_grind
let config elabGrindConfig config
withMainContext do liftMetaFinishingTactic (grind · config declName fallback)
withMainContext do liftMetaFinishingTactic (grind · config only params declName fallback)
| _ => throwUnsupportedSyntax
end Lean.Elab.Tactic

View File

@@ -7,8 +7,10 @@ prelude
import Init.Control.StateRef
import Init.Data.Array.BinSearch
import Init.Data.Stream
import Init.System.Promise
import Lean.ImportingFlag
import Lean.Data.HashMap
import Lean.Data.NameTrie
import Lean.Data.SMap
import Lean.Declaration
import Lean.LocalContext
@@ -16,6 +18,50 @@ import Lean.Util.Path
import Lean.Util.FindExpr
import Lean.Util.Profile
import Lean.Util.InstantiateLevelParams
import Lean.PrivateName
/-!
# Note [Environment Branches]
The kernel environment type `Lean.Kernel.Environment` enforces a linear order on the addition of
declarations: `addDeclCore` takes an environment and returns a new one, assuming type checking
succeeded. On the other hand, the metaprogramming-level `Lean.Environment` wrapper must allow for
*branching* environment transformations so that multiple declarations can be elaborated
concurrently while still being able to access information about preceding declarations that have
also been branched out as soon as they are available.
The basic function to introduce such branches is `addConstAsync`, which takes an environment and
returns a structure containing two environments: one for the "main" branch that can be used in
further branching and eventually contains all the declarations of the file and one for the "async"
branch that can be used concurrently to the main branch to elaborate and add the declaration for
which the branch was introduced. Branches are "joined" back together implicitly via the kernel
environment, which as mentioned cannot be changed concurrently: when the main branch first tries to
access it, evaluation is blocked until the kernel environment on the async branch is complete.
Thus adding two declarations A and B concurrently can be visualized like this:
```text
o addConstAsync A
|\
| \
| \
o addConstAsync B
|\ \
| \ o elaborate A
| \ |
| o elaborate B
| | |
| | o addDeclCore A
| |/
| o addDeclCore B
| /
| /
|/
o .olean serialization calls Environment.toKernelEnv
```
While each edge represents a `Lean.Environment` that has its own view of the state of the module,
the kernel environment really lives only in the right-most path, with all other paths merely holding
an unfulfilled `Task` representing it and where forcing that task leads to the back-edges joining
paths back together.
-/
namespace Lean
/-- Opaque environment extension state. -/
@@ -88,11 +134,6 @@ structure EnvironmentHeader where
-/
trustLevel : UInt32 := 0
/--
`quotInit = true` if the command `init_quot` has already been executed for the environment, and
`Quot` declarations have been added to the environment.
-/
quotInit : Bool := false
/--
Name of the module being compiled.
-/
mainModule : Name := default
@@ -106,6 +147,15 @@ structure EnvironmentHeader where
moduleData : Array ModuleData := #[]
deriving Nonempty
namespace Kernel
structure Diagnostics where
/-- Number of times each declaration has been unfolded by the kernel. -/
unfoldCounter : PHashMap Name Nat := {}
/-- If `enabled = true`, kernel records declarations that have been unfolded. -/
enabled : Bool := false
deriving Inhabited
/--
An environment stores declarations provided by the user. The kernel
currently supports different kinds of declarations such as definitions, theorems,
@@ -121,10 +171,33 @@ declared by users are stored in an environment extension. Users can declare new
using meta-programming.
-/
structure Environment where
/-- The constructor of `Environment` is private to protect against modification
that bypasses the kernel. -/
/--
The constructor of `Environment` is private to protect against modification that bypasses the
kernel.
-/
private mk ::
/--
Mapping from constant name to `ConstantInfo`. It contains all constants (definitions, theorems,
axioms, etc) that have been already type checked by the kernel.
-/
constants : ConstMap
/--
`quotInit = true` if the command `init_quot` has already been executed for the environment, and
`Quot` declarations have been added to the environment. When the flag is set, the type checker can
assume that the `Quot` declarations in the environment have indeed been added by the kernel and
not by the user.
-/
quotInit : Bool := false
/--
Diagnostic information collected during kernel execution.
Remark: We store kernel diagnostic information in an environment field to simplify the interface
with the kernel implemented in C/C++. Thus, we can only track declarations in methods, such as
`addDecl`, which return a new environment. `Kernel.isDefEq` and `Kernel.whnf` do not update the
statistics. We claim this is ok since these methods are mainly used for debugging.
-/
diagnostics : Diagnostics := {}
/--
Mapping from constant name to module (index) where constant has been declared.
Recall that a Lean file has a header where previously compiled modules can be imported.
Each imported module has a unique `ModuleIdx`.
@@ -134,96 +207,23 @@ structure Environment where
the field `constants`. These auxiliary constants are invisible to the Lean kernel and elaborator.
Only the code generator uses them.
-/
const2ModIdx : Std.HashMap Name ModuleIdx
/--
Mapping from constant name to `ConstantInfo`. It contains all constants (definitions, theorems, axioms, etc)
that have been already type checked by the kernel.
-/
constants : ConstMap
const2ModIdx : Std.HashMap Name ModuleIdx
/--
Environment extensions. It also includes user-defined extensions.
-/
extensions : Array EnvExtensionState
private extensions : Array EnvExtensionState
/--
Constant names to be saved in the field `extraConstNames` at `ModuleData`.
It contains auxiliary declaration names created by the code generator which are not in `constants`.
When importing modules, we want to insert them at `const2ModIdx`.
-/
extraConstNames : NameSet
/-- The header contains additional information that is not updated often. -/
header : EnvironmentHeader := {}
deriving Nonempty
private extraConstNames : NameSet
/-- The header contains additional information that is set at import time. -/
header : EnvironmentHeader := {}
deriving Nonempty
namespace Environment
private def addAux (env : Environment) (cinfo : ConstantInfo) : Environment :=
{ env with constants := env.constants.insert cinfo.name cinfo }
/--
Save an extra constant name that is used to populate `const2ModIdx` when we import
.olean files. We use this feature to save in which module an auxiliary declaration
created by the code generator has been created.
-/
def addExtraName (env : Environment) (name : Name) : Environment :=
if env.constants.contains name then
env
else
{ env with extraConstNames := env.extraConstNames.insert name }
@[export lean_environment_find]
def find? (env : Environment) (n : Name) : Option ConstantInfo :=
/- It is safe to use `find'` because we never overwrite imported declarations. -/
env.constants.find?' n
def contains (env : Environment) (n : Name) : Bool :=
env.constants.contains n
def imports (env : Environment) : Array Import :=
env.header.imports
def allImportedModuleNames (env : Environment) : Array Name :=
env.header.moduleNames
@[export lean_environment_set_main_module]
def setMainModule (env : Environment) (m : Name) : Environment :=
{ env with header := { env.header with mainModule := m } }
@[export lean_environment_main_module]
def mainModule (env : Environment) : Name :=
env.header.mainModule
@[export lean_environment_mark_quot_init]
private def markQuotInit (env : Environment) : Environment :=
{ env with header := { env.header with quotInit := true } }
@[export lean_environment_quot_init]
private def isQuotInit (env : Environment) : Bool :=
env.header.quotInit
@[export lean_environment_trust_level]
private def getTrustLevel (env : Environment) : UInt32 :=
env.header.trustLevel
def getModuleIdxFor? (env : Environment) (declName : Name) : Option ModuleIdx :=
env.const2ModIdx[declName]?
def isConstructor (env : Environment) (declName : Name) : Bool :=
match env.find? declName with
| some (.ctorInfo _) => true
| _ => false
def isSafeDefinition (env : Environment) (declName : Name) : Bool :=
match env.find? declName with
| some (.defnInfo { safety := .safe, .. }) => true
| _ => false
def getModuleIdx? (env : Environment) (moduleName : Name) : Option ModuleIdx :=
env.header.moduleNames.findIdx? (· == moduleName)
end Environment
/-- Exceptions that can be raised by the Kernel when type checking new declarations. -/
inductive KernelException where
/-- Exceptions that can be raised by the kernel when type checking new declarations. -/
inductive Exception where
| unknownConstant (env : Environment) (name : Name)
| alreadyDeclared (env : Environment) (name : Name)
| declTypeMismatch (env : Environment) (decl : Declaration) (givenType : Expr)
@@ -244,21 +244,500 @@ inductive KernelException where
namespace Environment
/--
Type check given declaration and add it to the environment
-/
@[export lean_environment_find]
def find? (env : Environment) (n : Name) : Option ConstantInfo :=
/- It is safe to use `find'` because we never overwrite imported declarations. -/
env.constants.find?' n
@[export lean_environment_mark_quot_init]
private def markQuotInit (env : Environment) : Environment :=
{ env with quotInit := true }
@[export lean_environment_quot_init]
private def isQuotInit (env : Environment) : Bool :=
env.quotInit
/-- Type check given declaration and add it to the environment -/
@[extern "lean_add_decl"]
opaque addDeclCore (env : Environment) (maxHeartbeats : USize) (decl : @& Declaration)
(cancelTk? : @& Option IO.CancelToken) : Except KernelException Environment
(cancelTk? : @& Option IO.CancelToken) : Except Exception Environment
/--
Add declaration to kernel without type checking it.
**WARNING** This function is meant for temporarily working around kernel performance issues.
It compromises soundness because, for example, a buggy tactic may produce an invalid proof,
and the kernel will not catch it if the new option is set to true.
-/
@[extern "lean_add_decl_without_checking"]
opaque addDeclWithoutChecking (env : Environment) (decl : @& Declaration) : Except KernelException Environment
opaque addDeclWithoutChecking (env : Environment) (decl : @& Declaration) : Except Exception Environment
@[export lean_environment_add]
private def add (env : Environment) (cinfo : ConstantInfo) : Environment :=
{ env with constants := env.constants.insert cinfo.name cinfo }
@[export lean_kernel_diag_is_enabled]
def Diagnostics.isEnabled (d : Diagnostics) : Bool :=
d.enabled
/-- Enables/disables kernel diagnostics. -/
def enableDiag (env : Environment) (flag : Bool) : Environment :=
{ env with diagnostics.enabled := flag }
def isDiagnosticsEnabled (env : Environment) : Bool :=
env.diagnostics.enabled
def resetDiag (env : Environment) : Environment :=
{ env with diagnostics.unfoldCounter := {} }
@[export lean_kernel_record_unfold]
def Diagnostics.recordUnfold (d : Diagnostics) (declName : Name) : Diagnostics :=
if d.enabled then
let cNew := if let some c := d.unfoldCounter.find? declName then c + 1 else 1
{ d with unfoldCounter := d.unfoldCounter.insert declName cNew }
else
d
@[export lean_kernel_get_diag]
def getDiagnostics (env : Environment) : Diagnostics :=
env.diagnostics
@[export lean_kernel_set_diag]
def setDiagnostics (env : Environment) (diag : Diagnostics) : Environment :=
{ env with diagnostics := diag}
end Kernel.Environment
@[deprecated Kernel.Exception (since := "2024-12-12")]
abbrev KernelException := Kernel.Exception
inductive ConstantKind where
| defn | thm | «axiom» | «opaque» | quot | induct | ctor | recursor
deriving Inhabited, BEq, Repr
def ConstantKind.ofConstantInfo : ConstantInfo ConstantKind
| .defnInfo _ => .defn
| .thmInfo _ => .thm
| .axiomInfo _ => .axiom
| .opaqueInfo _ => .opaque
| .quotInfo _ => .quot
| .inductInfo _ => .induct
| .ctorInfo _ => .ctor
| .recInfo _ => .recursor
/-- `ConstantInfo` variant that allows for asynchronous filling of components via tasks. -/
structure AsyncConstantInfo where
/-- The declaration name, known immediately. -/
name : Name
/-- The kind of the constant, known immediately. -/
kind : ConstantKind
/-- The "signature" including level params and type, potentially filled asynchronously. -/
sig : Task ConstantVal
/-- The final, complete constant info, potentially filled asynchronously. -/
constInfo : Task ConstantInfo
namespace AsyncConstantInfo
def toConstantVal (c : AsyncConstantInfo) : ConstantVal :=
c.sig.get
def toConstantInfo (c : AsyncConstantInfo) : ConstantInfo :=
c.constInfo.get
def ofConstantInfo (c : ConstantInfo) : AsyncConstantInfo where
name := c.name
kind := .ofConstantInfo c
sig := .pure c.toConstantVal
constInfo := .pure c
end AsyncConstantInfo
/--
Information about the current branch of the environment representing asynchronous elaboration.
-/
structure AsyncContext where
/--
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
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 :=
ctx.declPrefix.isPrefixOf <| privateToUserName n.eraseMacroScopes
/--
Constant info and environment extension states eventually resulting from async elaboration.
-/
structure AsyncConst where
constInfo : AsyncConstantInfo
/--
Reported extension state eventually fulfilled by promise; may be missing for tasks (e.g. kernel
checking) that can eagerly guarantee they will not report any state.
-/
exts? : Option (Task (Array EnvExtensionState))
/-- Data structure holding a sequence of `AsyncConst`s optimized for efficient access. -/
structure AsyncConsts where
toArray : Array AsyncConst := #[]
/-- Map from declaration name to const for fast direct access. -/
private map : NameMap AsyncConst := {}
/-- Trie of declaration names without private name prefixes for fast longest-prefix access. -/
private normalizedTrie : NameTrie AsyncConst := {}
deriving Inhabited
def AsyncConsts.add (aconsts : AsyncConsts) (aconst : AsyncConst) : AsyncConsts :=
{ aconsts with
toArray := aconsts.toArray.push aconst
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 :=
aconsts.map.find? declName
/-- Checks whether the name of any constant in the collection is a prefix of `declName`. -/
def AsyncConsts.hasPrefix (aconsts : AsyncConsts) (declName : Name) : Bool :=
-- as macro scopes are a strict suffix,
aconsts.normalizedTrie.findLongestPrefix? (privateToUserName declName.eraseMacroScopes) |>.isSome
/--
Elaboration-specific extension of `Kernel.Environment` that adds tracking of asynchronously
elaborated declarations.
-/
structure Environment where
/-
Like with `Kernel.Environment`, this constructor is private to protect consistency of the
environment, though there are no soundness concerns in this case given that it is used purely for
elaboration.
-/
private mk ::
/--
Kernel environment not containing any asynchronously elaborated declarations. Also stores
environment extension state for the current branch of the environment.
Ignoring extension state, this is guaranteed to be some prior version of `checked` that is eagerly
available. Thus we prefer taking information from it instead of `checked` whenever possible.
-/
checkedWithoutAsync : Kernel.Environment
/--
Kernel environment task that is fulfilled when all asynchronously elaborated declarations are
finished, containing the resulting environment. Also collects the environment extension state of
all environment branches that contributed contained declarations.
-/
checked : Task Kernel.Environment := .pure checkedWithoutAsync
/--
Container of asynchronously elaborated declarations, i.e.
`checked = checkedWithoutAsync ⨃ asyncConsts`.
-/
private asyncConsts : AsyncConsts := {}
/-- Information about this asynchronous branch of the environment, if any. -/
private asyncCtx? : Option AsyncContext := none
deriving Nonempty
namespace Environment
@[export lean_elab_environment_of_kernel_env]
def ofKernelEnv (env : Kernel.Environment) : Environment :=
{ checkedWithoutAsync := env }
@[export lean_elab_environment_to_kernel_env]
def toKernelEnv (env : Environment) : Kernel.Environment :=
env.checked.get
/-- Consistently updates synchronous and asynchronous parts of the environment without blocking. -/
private def modifyCheckedAsync (env : Environment) (f : Kernel.Environment Kernel.Environment) : Environment :=
{ env with checked := env.checked.map (sync := true) f, checkedWithoutAsync := f env.checkedWithoutAsync }
/-- Sets synchronous and asynchronous parts of the environment to the given kernel environment. -/
private def setCheckedSync (env : Environment) (newChecked : Kernel.Environment) : Environment :=
{ env with checked := .pure newChecked, checkedWithoutAsync := newChecked }
@[extern "lean_elab_add_decl"]
private opaque addDeclCheck (env : Environment) (maxHeartbeats : USize) (decl : @& Declaration)
(cancelTk? : @& Option IO.CancelToken) : Except Kernel.Exception Environment
@[extern "lean_elab_add_decl_without_checking"]
private opaque addDeclWithoutChecking (env : Environment) (decl : @& Declaration) :
Except Kernel.Exception Environment
/--
Adds given declaration to the environment, type checking it unless `doCheck` is false.
This is a plumbing function for the implementation of `Lean.addDecl`, most users should use it
instead.
-/
def addDeclCore (env : Environment) (maxHeartbeats : USize) (decl : @& Declaration)
(cancelTk? : @& Option IO.CancelToken) (doCheck := true) :
Except Kernel.Exception Environment := do
if let some ctx := env.asyncCtx? then
if let some n := decl.getNames.find? (!ctx.mayContain ·) then
throw <| .other s!"cannot add declaration {n} to environment as it is restricted to the \
prefix {ctx.declPrefix}"
if doCheck then
addDeclCheck env maxHeartbeats decl cancelTk?
else
addDeclWithoutChecking env decl
@[inherit_doc Kernel.Environment.constants]
def constants (env : Environment) : ConstMap :=
env.toKernelEnv.constants
@[inherit_doc Kernel.Environment.const2ModIdx]
def const2ModIdx (env : Environment) : Std.HashMap Name ModuleIdx :=
env.toKernelEnv.const2ModIdx
-- only needed for the lakefile.lean cache
@[export lake_environment_add]
private def lakeAdd (env : Environment) (cinfo : ConstantInfo) : Environment :=
{ env with checked := .pure <| env.checked.get.add cinfo }
/--
Save an extra constant name that is used to populate `const2ModIdx` when we import
.olean files. We use this feature to save in which module an auxiliary declaration
created by the code generator has been created.
-/
def addExtraName (env : Environment) (name : Name) : Environment :=
if env.constants.contains name then
env
else
env.modifyCheckedAsync fun env => { env with extraConstNames := env.extraConstNames.insert name }
/-- Find base case: name did not match any asynchronous declaration. -/
private def findNoAsync (env : Environment) (n : Name) : Option ConstantInfo := do
if env.asyncConsts.hasPrefix n then
-- Constant generated in a different environment branch: wait for final kernel environment. Rare
-- case when only proofs are elaborated asynchronously as they are rarely inspected. Could be
-- optimized in the future by having the elaboration thread publish an (incremental?) map of
-- generated declarations before kernel checking (which must wait on all previous threads).
env.checked.get.constants.find?' n
else
-- Not in the kernel environment nor in the name prefix of environment branch: undefined by
-- `addDeclCore` invariant.
none
/--
Looks up the given declaration name in the environment, avoiding forcing any in-progress elaboration
tasks.
-/
def findAsync? (env : Environment) (n : Name) : Option AsyncConstantInfo := do
-- Check declarations already added to the kernel environment (e.g. because they were imported)
-- first as that should be the most common case. It is safe to use `find?'` because we never
-- overwrite imported declarations.
if let some c := env.checkedWithoutAsync.constants.find?' n then
some <| .ofConstantInfo c
else if let some asyncConst := env.asyncConsts.find? n then
-- Constant for which an asynchronous elaboration task was spawned
return asyncConst.constInfo
else env.findNoAsync n |>.map .ofConstantInfo
/--
Looks up the given declaration name in the environment, avoiding forcing any in-progress elaboration
tasks for declaration bodies (which are not accessible from `ConstantVal`).
-/
def findConstVal? (env : Environment) (n : Name) : Option ConstantVal := do
if let some c := env.checkedWithoutAsync.constants.find?' n then
some c.toConstantVal
else if let some asyncConst := env.asyncConsts.find? n then
return asyncConst.constInfo.toConstantVal
else env.findNoAsync n |>.map (·.toConstantVal)
/--
Looks up the given declaration name in the environment, blocking on the corresponding elaboration
task if not yet complete.
-/
def find? (env : Environment) (n : Name) : Option ConstantInfo :=
if let some c := env.checkedWithoutAsync.constants.find?' n then
some c
else if let some asyncConst := env.asyncConsts.find? n then
return asyncConst.constInfo.toConstantInfo
else
env.findNoAsync n
/-- Returns debug output about the asynchronous state of the environment. -/
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)}"
/-- Returns debug output about the synchronous state of the environment. -/
def dbgFormatCheckedSyncState (env : Environment) : BaseIO String :=
return s!"checked.get.constants.map₂: {repr <| env.checked.get.constants.map₂.toList.map (·.1)}"
/--
Result of `Lean.Environment.addConstAsync` which is necessary to complete the asynchronous addition.
-/
structure AddConstAsyncResult where
/--
Resulting "main branch" environment which contains the declaration name as an asynchronous
constant. Accessing the constant or kernel environment will block until the corresponding
`AddConstAsyncResult.commit*` function has been called.
-/
mainEnv : Environment
/--
Resulting "async branch" environment which should be used to add the desired declaration in a new
task and then call `AddConstAsyncResult.commit*` to commit results back to the main environment.
One of `commitCheckEnv` or `commitFailure` must be called eventually to prevent deadlocks on main
branch accesses.
-/
asyncEnv : Environment
private constName : Name
private kind : ConstantKind
private sigPromise : IO.Promise ConstantVal
private infoPromise : IO.Promise ConstantInfo
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
let sigPromise IO.Promise.new
let infoPromise IO.Promise.new
let extensionsPromise IO.Promise.new
let checkedEnvPromise IO.Promise.new
let asyncConst := {
constInfo := {
name := constName
kind
sig := sigPromise.result
constInfo := infoPromise.result
}
exts? := guard reportExts *> some extensionsPromise.result
}
return {
constName, kind
mainEnv := { env with
asyncConsts := env.asyncConsts.add asyncConst
checked := checkedEnvPromise.result }
asyncEnv := { env with
asyncCtx? := some { declPrefix := privateToUserName constName.eraseMacroScopes }
}
sigPromise, infoPromise, extensionsPromise, checkedEnvPromise
}
/--
Commits the signature of the constant to the main environment branch. The declaration name must
match the name originally given to `addConstAsync`. It is optional to call this function but can
help in unblocking corresponding accesses to the constant on the main branch.
-/
def AddConstAsyncResult.commitSignature (res : AddConstAsyncResult) (sig : ConstantVal) :
IO Unit := do
if sig.name != res.constName then
throw <| .userError s!"AddConstAsyncResult.commitSignature: constant has name {sig.name} but expected {res.constName}"
res.sigPromise.resolve sig
/--
Commits the full constant info to the main environment branch. If `info?` is `none`, it is taken
from the given environment. The declaration name and kind must match the original values given to
`addConstAsync`. The signature must match the previous `commitSignature` call, if any.
-/
def AddConstAsyncResult.commitConst (res : AddConstAsyncResult) (env : Environment)
(info? : Option ConstantInfo := none) :
IO Unit := do
let info match info? <|> env.find? res.constName with
| some info => pure info
| none =>
throw <| .userError s!"AddConstAsyncResult.commitConst: constant {res.constName} not found in async context"
res.commitSignature info.toConstantVal
let kind' := .ofConstantInfo info
if res.kind != kind' then
throw <| .userError s!"AddConstAsyncResult.commitConst: constant has kind {repr kind'} but expected {repr res.kind}"
let sig := res.sigPromise.result.get
if sig.levelParams != info.levelParams then
throw <| .userError s!"AddConstAsyncResult.commitConst: constant has level params {info.levelParams} but expected {sig.levelParams}"
if sig.type != info.type then
throw <| .userError s!"AddConstAsyncResult.commitConst: constant has type {info.type} but expected {sig.type}"
res.infoPromise.resolve info
res.extensionsPromise.resolve env.checkedWithoutAsync.extensions
/--
Aborts async addition, filling in missing information with default values/sorries and leaving the
kernel environment unchanged.
-/
def AddConstAsyncResult.commitFailure (res : AddConstAsyncResult) : BaseIO Unit := do
let val := if ( IO.hasFinished res.sigPromise.result) then
res.sigPromise.result.get
else {
name := res.constName
levelParams := []
type := mkApp2 (mkConst ``sorryAx [0]) (mkSort 0) (mkConst ``true)
}
res.sigPromise.resolve val
res.infoPromise.resolve <| match res.kind with
| .defn => .defnInfo { val with
value := mkApp2 (mkConst ``sorryAx [0]) val.type (mkConst ``true)
hints := .abbrev
safety := .safe
}
| .thm => .thmInfo { val with
value := mkApp2 (mkConst ``sorryAx [0]) val.type (mkConst ``true)
}
| k => panic! s!"AddConstAsyncResult.commitFailure: unsupported constant kind {repr k}"
res.extensionsPromise.resolve #[]
let _ BaseIO.mapTask (t := res.asyncEnv.checked) (sync := true) res.checkedEnvPromise.resolve
/--
Assuming `Lean.addDecl` has been run for the constant to be added on the async environment branch,
commits the full constant info from that call to the main environment, waits for the final kernel
environment resulting from the `addDecl` call, and commits it to the main branch as well, unblocking
kernel additions there. All `commitConst` preconditions apply.
-/
def AddConstAsyncResult.commitCheckEnv (res : AddConstAsyncResult) (env : Environment) :
IO Unit := do
let some _ := env.findAsync? res.constName
| throw <| .userError s!"AddConstAsyncResult.checkAndCommitEnv: constant {res.constName} not \
found in async context"
res.commitConst env
res.checkedEnvPromise.resolve env.checked.get
def contains (env : Environment) (n : Name) : Bool :=
env.findAsync? n |>.isSome
def header (env : Environment) : EnvironmentHeader :=
-- can be assumed to be in sync with `env.checked`; see `setMainModule`, the only modifier of the header
env.checkedWithoutAsync.header
def imports (env : Environment) : Array Import :=
env.header.imports
def allImportedModuleNames (env : Environment) : Array Name :=
env.header.moduleNames
def setMainModule (env : Environment) (m : Name) : Environment :=
env.modifyCheckedAsync ({ · with header.mainModule := m })
def mainModule (env : Environment) : Name :=
env.header.mainModule
def getModuleIdxFor? (env : Environment) (declName : Name) : Option ModuleIdx :=
-- async constants are always from the current module
env.checkedWithoutAsync.const2ModIdx[declName]?
def isConstructor (env : Environment) (declName : Name) : Bool :=
match env.find? declName with
| some (.ctorInfo _) => true
| _ => false
def isSafeDefinition (env : Environment) (declName : Name) : Bool :=
match env.find? declName with
| some (.defnInfo { safety := .safe, .. }) => true
| _ => false
def getModuleIdx? (env : Environment) (moduleName : Name) : Option ModuleIdx :=
env.header.moduleNames.findIdx? (· == moduleName)
end Environment
@@ -385,20 +864,22 @@ opaque EnvExtensionInterfaceImp : EnvExtensionInterface
def EnvExtension (σ : Type) : Type := EnvExtensionInterfaceImp.ext σ
private def ensureExtensionsArraySize (env : Environment) : IO Environment := do
let exts EnvExtensionInterfaceImp.ensureExtensionsSize env.extensions
return { env with extensions := exts }
let exts EnvExtensionInterfaceImp.ensureExtensionsSize env.checked.get.extensions
return env.modifyCheckedAsync ({ · with extensions := exts })
namespace EnvExtension
instance {σ} [s : Inhabited σ] : Inhabited (EnvExtension σ) := EnvExtensionInterfaceImp.inhabitedExt s
def setState {σ : Type} (ext : EnvExtension σ) (env : Environment) (s : σ) : Environment :=
{ env with extensions := EnvExtensionInterfaceImp.setState ext env.extensions s }
let checked := env.checked.get
env.setCheckedSync { checked with extensions := EnvExtensionInterfaceImp.setState ext checked.extensions s }
def modifyState {σ : Type} (ext : EnvExtension σ) (env : Environment) (f : σ σ) : Environment :=
{ env with extensions := EnvExtensionInterfaceImp.modifyState ext env.extensions f }
let checked := env.checked.get
env.setCheckedSync { checked with extensions := EnvExtensionInterfaceImp.modifyState ext checked.extensions f }
def getState {σ : Type} [Inhabited σ] (ext : EnvExtension σ) (env : Environment) : σ :=
EnvExtensionInterfaceImp.getState ext env.extensions
EnvExtensionInterfaceImp.getState ext env.checked.get.extensions
end EnvExtension
@@ -418,11 +899,13 @@ def mkEmptyEnvironment (trustLevel : UInt32 := 0) : IO Environment := do
if initializing then throw (IO.userError "environment objects cannot be created during initialization")
let exts mkInitialExtensionStates
pure {
const2ModIdx := {}
constants := {}
header := { trustLevel := trustLevel }
extraConstNames := {}
extensions := exts
checkedWithoutAsync := {
const2ModIdx := {}
constants := {}
header := { trustLevel }
extraConstNames := {}
extensions := exts
}
}
structure PersistentEnvExtensionState (α : Type) (σ : Type) where
@@ -706,11 +1189,12 @@ def mkModuleData (env : Environment) : IO ModuleData := do
let entries := pExts.map fun pExt =>
let state := pExt.getState env
(pExt.name, pExt.exportEntriesFn state)
let constNames := env.constants.foldStage2 (fun names name _ => names.push name) #[]
let constants := env.constants.foldStage2 (fun cs _ c => cs.push c) #[]
let kenv := env.toKernelEnv
let constNames := kenv.constants.foldStage2 (fun names name _ => names.push name) #[]
let constants := kenv.constants.foldStage2 (fun cs _ c => cs.push c) #[]
return {
imports := env.header.imports
extraConstNames := env.extraConstNames.toArray
extraConstNames := env.checked.get.extraConstNames.toArray
constNames, constants, entries
}
@@ -731,19 +1215,23 @@ def mkExtNameMap (startingAt : Nat) : IO (Std.HashMap Name Nat) := do
return result
private def setImportedEntries (env : Environment) (mods : Array ModuleData) (startingAt : Nat := 0) : IO Environment := do
let mut env := env
-- We work directly on the states array instead of `env` as `Environment.modifyState` introduces
-- significant overhead on such frequent calls
let mut states := env.checkedWithoutAsync.extensions
let extDescrs persistentEnvExtensionsRef.get
/- For extensions starting at `startingAt`, ensure their `importedEntries` array have size `mods.size`. -/
for extDescr in extDescrs[startingAt:] do
env := extDescr.toEnvExtension.modifyState env fun s => { s with importedEntries := mkArray mods.size #[] }
states := EnvExtensionInterfaceImp.modifyState extDescr.toEnvExtension states fun s =>
{ s with importedEntries := mkArray mods.size #[] }
/- For each module `mod`, and `mod.entries`, if the extension name is one of the extensions after `startingAt`, set `entries` -/
let extNameIdx mkExtNameMap startingAt
for h : modIdx in [:mods.size] do
let mod := mods[modIdx]
for (extName, entries) in mod.entries do
if let some entryIdx := extNameIdx[extName]? then
env := extDescrs[entryIdx]!.toEnvExtension.modifyState env fun s => { s with importedEntries := s.importedEntries.set! modIdx entries }
return env
states := EnvExtensionInterfaceImp.modifyState extDescrs[entryIdx]!.toEnvExtension states fun s =>
{ s with importedEntries := s.importedEntries.set! modIdx entries }
return env.setCheckedSync { env.checkedWithoutAsync with extensions := states }
/--
"Forward declaration" needed for updating the attribute table with user-defined attributes.
@@ -873,17 +1361,17 @@ def finalizeImport (s : ImportState) (imports : Array Import) (opts : Options) (
let constants : ConstMap := SMap.fromHashMap constantMap false
let exts mkInitialExtensionStates
let mut env : Environment := {
const2ModIdx := const2ModIdx
constants := constants
extraConstNames := {}
extensions := exts
header := {
quotInit := !imports.isEmpty -- We assume `core.lean` initializes quotient module
trustLevel := trustLevel
imports := imports
regions := s.regions
moduleNames := s.moduleNames
moduleData := s.moduleData
checkedWithoutAsync := {
const2ModIdx, constants
quotInit := !imports.isEmpty -- We assume `core.lean` initializes quotient module
extraConstNames := {}
extensions := exts
header := {
trustLevel, imports
regions := s.regions
moduleNames := s.moduleNames
moduleData := s.moduleData
}
}
}
env setImportedEntries env s.moduleData
@@ -946,54 +1434,21 @@ builtin_initialize namespacesExt : SimplePersistentEnvExtension Name NameSSet
addEntryFn := fun s n => s.insert n
}
structure Kernel.Diagnostics where
/-- Number of times each declaration has been unfolded by the kernel. -/
unfoldCounter : PHashMap Name Nat := {}
/-- If `enabled = true`, kernel records declarations that have been unfolded. -/
enabled : Bool := false
deriving Inhabited
@[inherit_doc Kernel.Environment.enableDiag]
def Kernel.enableDiag (env : Lean.Environment) (flag : Bool) : Lean.Environment :=
env.modifyCheckedAsync (·.enableDiag flag)
/--
Extension for storting diagnostic information.
def Kernel.isDiagnosticsEnabled (env : Lean.Environment) : Bool :=
env.checkedWithoutAsync.isDiagnosticsEnabled
Remark: We store kernel diagnostic information in an environment extension to simplify
the interface with the kernel implemented in C/C++. Thus, we can only track
declarations in methods, such as `addDecl`, which return a new environment.
`Kernel.isDefEq` and `Kernel.whnf` do not update the statistics. We claim
this is ok since these methods are mainly used for debugging.
-/
builtin_initialize diagExt : EnvExtension Kernel.Diagnostics
registerEnvExtension (pure {})
def Kernel.resetDiag (env : Lean.Environment) : Lean.Environment :=
env.modifyCheckedAsync (·.resetDiag)
@[export lean_kernel_diag_is_enabled]
def Kernel.Diagnostics.isEnabled (d : Diagnostics) : Bool :=
d.enabled
def Kernel.getDiagnostics (env : Lean.Environment) : Diagnostics :=
env.checked.get.diagnostics
/-- Enables/disables kernel diagnostics. -/
def Kernel.enableDiag (env : Environment) (flag : Bool) : Environment :=
diagExt.modifyState env fun s => { s with enabled := flag }
def Kernel.isDiagnosticsEnabled (env : Environment) : Bool :=
diagExt.getState env |>.enabled
def Kernel.resetDiag (env : Environment) : Environment :=
diagExt.modifyState env fun s => { s with unfoldCounter := {} }
@[export lean_kernel_record_unfold]
def Kernel.Diagnostics.recordUnfold (d : Diagnostics) (declName : Name) : Diagnostics :=
if d.enabled then
let cNew := if let some c := d.unfoldCounter.find? declName then c + 1 else 1
{ d with unfoldCounter := d.unfoldCounter.insert declName cNew }
else
d
@[export lean_kernel_get_diag]
def Kernel.getDiagnostics (env : Environment) : Diagnostics :=
diagExt.getState env
@[export lean_kernel_set_diag]
def Kernel.setDiagnostics (env : Environment) (diag : Diagnostics) : Environment :=
diagExt.setState env diag
def Kernel.setDiagnostics (env : Lean.Environment) (diag : Diagnostics) : Lean.Environment :=
env.modifyCheckedAsync (·.setDiagnostics diag)
namespace Environment
@@ -1009,27 +1464,9 @@ def isNamespace (env : Environment) (n : Name) : Bool :=
def getNamespaceSet (env : Environment) : NameSSet :=
namespacesExt.getState env
private def isNamespaceName : Name Bool
| .str .anonymous _ => true
| .str p _ => isNamespaceName p
| _ => false
private def registerNamePrefixes : Environment Name Environment
| env, .str p _ => if isNamespaceName p then registerNamePrefixes (registerNamespace env p) p else env
| env, _ => env
@[export lean_environment_add]
private def add (env : Environment) (cinfo : ConstantInfo) : Environment :=
let name := cinfo.name
let env := match name with
| .str _ s =>
if s.get 0 == '_' then
-- Do not register namespaces that only contain internal declarations.
env
else
registerNamePrefixes env name
| _ => env
env.addAux cinfo
@[export lean_elab_environment_update_base_after_kernel_add]
private def updateBaseAfterKernelAdd (env : Environment) (kernel : Kernel.Environment) : Environment :=
env.setCheckedSync kernel
@[export lean_display_stats]
def displayStats (env : Environment) : IO Unit := do
@@ -1039,7 +1476,7 @@ def displayStats (env : Environment) : IO Unit := do
IO.println ("number of memory-mapped modules: " ++ toString (env.header.regions.filter (·.isMemoryMapped) |>.size));
IO.println ("number of buckets for imported consts: " ++ toString env.constants.numBuckets);
IO.println ("trust level: " ++ toString env.header.trustLevel);
IO.println ("number of extensions: " ++ toString env.extensions.size);
IO.println ("number of extensions: " ++ toString env.checkedWithoutAsync.extensions.size);
pExtDescrs.forM fun extDescr => do
IO.println ("extension '" ++ toString extDescr.name ++ "'")
let s := extDescr.toEnvExtension.getState env
@@ -1085,27 +1522,33 @@ namespace Kernel
/--
Kernel isDefEq predicate. We use it mainly for debugging purposes.
Recall that the Kernel type checker does not support metavariables.
Recall that the kernel type checker does not support metavariables.
When implementing automation, consider using the `MetaM` methods. -/
-- We use `Lean.Environment` for ease of use; as this is a debugging function, we forgo a
-- `Kernel.Environment` base variant
@[extern "lean_kernel_is_def_eq"]
opaque isDefEq (env : Environment) (lctx : LocalContext) (a b : Expr) : Except KernelException Bool
opaque isDefEq (env : Lean.Environment) (lctx : LocalContext) (a b : Expr) : Except Kernel.Exception Bool
def isDefEqGuarded (env : Environment) (lctx : LocalContext) (a b : Expr) : Bool :=
def isDefEqGuarded (env : Lean.Environment) (lctx : LocalContext) (a b : Expr) : Bool :=
if let .ok result := isDefEq env lctx a b then result else false
/--
Kernel WHNF function. We use it mainly for debugging purposes.
Recall that the Kernel type checker does not support metavariables.
Recall that the kernel type checker does not support metavariables.
When implementing automation, consider using the `MetaM` methods. -/
-- We use `Lean.Environment` for ease of use; as this is a debugging function, we forgo a
-- `Kernel.Environment` base variant
@[extern "lean_kernel_whnf"]
opaque whnf (env : Environment) (lctx : LocalContext) (a : Expr) : Except KernelException Expr
opaque whnf (env : Lean.Environment) (lctx : LocalContext) (a : Expr) : Except Kernel.Exception Expr
/--
Kernel typecheck function. We use it mainly for debugging purposes.
Recall that the Kernel type checker does not support metavariables.
When implementing automation, consider using the `MetaM` methods. -/
-- We use `Lean.Environment` for ease of use; as this is a debugging function, we forgo a
-- `Kernel.Environment` base variant
@[extern "lean_kernel_check"]
opaque check (env : Environment) (lctx : LocalContext) (a : Expr) : Except KernelException Expr
opaque check (env : Lean.Environment) (lctx : LocalContext) (a : Expr) : Except Kernel.Exception Expr
end Kernel

View File

@@ -89,11 +89,11 @@ def ofExcept [Monad m] [MonadError m] [ToMessageData ε] (x : Except ε α) : m
/--
Throw an error exception for the given kernel exception.
-/
def throwKernelException [Monad m] [MonadError m] [MonadOptions m] (ex : KernelException) : m α := do
def throwKernelException [Monad m] [MonadError m] [MonadOptions m] (ex : Kernel.Exception) : m α := do
Lean.throwError <| ex.toMessageData ( getOptions)
/-- Lift from `Except KernelException` to `m` when `m` can throw kernel exceptions. -/
def ofExceptKernelException [Monad m] [MonadError m] [MonadOptions m] (x : Except KernelException α) : m α :=
def ofExceptKernelException [Monad m] [MonadError m] [MonadOptions m] (x : Except Kernel.Exception α) : m α :=
match x with
| .ok a => return a
| .error e => throwKernelException e

View File

@@ -639,7 +639,7 @@ def mkFVar (fvarId : FVarId) : Expr :=
/--
`.mvar mvarId` is now the preferred form.
This function is seldom used, metavariables are often created using functions such
as `mkFresheExprMVar` at `MetaM`.
as `mkFreshExprMVar` at `MetaM`.
-/
def mkMVar (mvarId : MVarId) : Expr :=
.mvar mvarId

View File

@@ -448,6 +448,9 @@ def markAllReported (log : MessageLog) : MessageLog :=
def errorsToWarnings (log : MessageLog) : MessageLog :=
{ unreported := log.unreported.map (fun m => match m.severity with | MessageSeverity.error => { m with severity := MessageSeverity.warning } | _ => m) }
def errorsToInfos (log : MessageLog) : MessageLog :=
{ unreported := log.unreported.map (fun m => match m.severity with | MessageSeverity.error => { m with severity := MessageSeverity.information } | _ => m) }
def getInfoMessages (log : MessageLog) : MessageLog :=
{ unreported := log.unreported.filter fun m => match m.severity with | MessageSeverity.information => true | _ => false }
@@ -537,12 +540,12 @@ macro_rules
def toMessageList (msgs : Array MessageData) : MessageData :=
indentD (MessageData.joinSep msgs.toList m!"\n\n")
namespace KernelException
namespace Kernel.Exception
private def mkCtx (env : Environment) (lctx : LocalContext) (opts : Options) (msg : MessageData) : MessageData :=
MessageData.withContext { env := env, mctx := {}, lctx := lctx, opts := opts } msg
MessageData.withContext { env := .ofKernelEnv env, mctx := {}, lctx := lctx, opts := opts } msg
def toMessageData (e : KernelException) (opts : Options) : MessageData :=
def toMessageData (e : Kernel.Exception) (opts : Options) : MessageData :=
match e with
| unknownConstant env constName => mkCtx env {} opts m!"(kernel) unknown constant '{constName}'"
| alreadyDeclared env constName => mkCtx env {} opts m!"(kernel) constant has already been declared '{.ofConstName constName true}'"
@@ -570,5 +573,5 @@ def toMessageData (e : KernelException) (opts : Options) : MessageData :=
| deepRecursion => "(kernel) deep recursion detected"
| interrupted => "(kernel) interrupted"
end KernelException
end Kernel.Exception
end Lean

View File

@@ -9,13 +9,13 @@ import Lean.Meta.Basic
namespace Lean
@[extern "lean_mk_cases_on"] opaque mkCasesOnImp (env : Environment) (declName : @& Name) : Except KernelException Declaration
@[extern "lean_mk_cases_on"] opaque mkCasesOnImp (env : Kernel.Environment) (declName : @& Name) : Except Kernel.Exception Declaration
open Meta
def mkCasesOn (declName : Name) : MetaM Unit := do
let name := mkCasesOnName declName
let decl ofExceptKernelException (mkCasesOnImp ( getEnv) declName)
let decl ofExceptKernelException (mkCasesOnImp ( getEnv).toKernelEnv declName)
addDecl decl
setReducibleAttribute name
modifyEnv fun env => markAuxRecursor env name

View File

@@ -10,8 +10,8 @@ import Lean.Meta.CompletionName
namespace Lean
@[extern "lean_mk_no_confusion_type"] opaque mkNoConfusionTypeCoreImp (env : Environment) (declName : @& Name) : Except KernelException Declaration
@[extern "lean_mk_no_confusion"] opaque mkNoConfusionCoreImp (env : Environment) (declName : @& Name) : Except KernelException Declaration
@[extern "lean_mk_no_confusion_type"] opaque mkNoConfusionTypeCoreImp (env : Environment) (declName : @& Name) : Except Kernel.Exception Declaration
@[extern "lean_mk_no_confusion"] opaque mkNoConfusionCoreImp (env : Environment) (declName : @& Name) : Except Kernel.Exception Declaration
open Meta

View File

@@ -72,12 +72,12 @@ def mkDiagSynthPendingFailure (failures : PHashMap Expr MessageData) : MetaM Dia
/--
We use below that this returns `m` unchanged if `s.isEmpty`
-/
def appendSection (m : MessageData) (cls : Name) (header : String) (s : DiagSummary) (resultSummary := true) : MessageData :=
def appendSection (m : Array MessageData) (cls : Name) (header : String) (s : DiagSummary) (resultSummary := true) : Array MessageData :=
if s.isEmpty then
m
else
let header := if resultSummary then s!"{header} (max: {s.max}, num: {s.data.size}):" else header
m ++ .trace { cls } header s.data
m.push <| .trace { cls } header s.data
def reportDiag : MetaM Unit := do
if ( isDiagnosticsEnabled) then
@@ -89,7 +89,7 @@ def reportDiag : MetaM Unit := do
let inst mkDiagSummaryForUsedInstances
let synthPending mkDiagSynthPendingFailure ( get).diag.synthPendingFailures
let unfoldKernel mkDiagSummary `kernel (Kernel.getDiagnostics ( getEnv)).unfoldCounter
let m := MessageData.nil
let m := #[]
let m := appendSection m `reduction "unfolded declarations" unfoldDefault
let m := appendSection m `reduction "unfolded instances" unfoldInstance
let m := appendSection m `reduction "unfolded reducible declarations" unfoldReducible
@@ -99,8 +99,8 @@ def reportDiag : MetaM Unit := do
synthPending (resultSummary := false)
let m := appendSection m `def_eq "heuristic for solving `f a =?= f b`" heu
let m := appendSection m `kernel "unfolded declarations" unfoldKernel
unless m matches .nil do
let m := m ++ "use `set_option diagnostics.threshold <num>` to control threshold for reporting counters"
logInfo m
unless m.isEmpty do
let m := m.push "use `set_option diagnostics.threshold <num>` to control threshold for reporting counters"
logInfo <| .trace { cls := `diag, collapsed := false } "Diagnostics" m
end Lean.Meta

View File

@@ -1233,10 +1233,7 @@ private def processAssignment' (mvarApp : Expr) (v : Expr) : MetaM Bool := do
private def isDeltaCandidate? (t : Expr) : MetaM (Option ConstantInfo) := do
match t.getAppFn with
| .const c _ =>
match ( getUnfoldableConst? c) with
| r@(some info) => if info.hasValue then return r else return none
| _ => return none
| .const c _ => getUnfoldableConst? c
| _ => pure none
/-- Auxiliary method for isDefEqDelta -/

View File

@@ -30,7 +30,7 @@ def canUnfold (info : ConstantInfo) : MetaM Bool := do
/--
Look up a constant name, returning the `ConstantInfo`
if it should be unfolded at the current reducibility settings,
if it is a def/theorem that should be unfolded at the current reducibility settings,
or `none` otherwise.
This is part of the implementation of `whnf`.
@@ -40,7 +40,7 @@ def getUnfoldableConst? (constName : Name) : MetaM (Option ConstantInfo) := do
match ( getEnv).find? constName with
| some (info@(.thmInfo _)) => getTheoremInfo info
| some (info@(.defnInfo _)) => if ( canUnfold info) then return info else return none
| some info => return some info
| some _ => return none
| none => throwUnknownConstant constName
/--
@@ -50,7 +50,6 @@ def getUnfoldableConstNoEx? (constName : Name) : MetaM (Option ConstantInfo) :=
match ( getEnv).find? constName with
| some (info@(.thmInfo _)) => getTheoremInfo info
| some (info@(.defnInfo _)) => if ( canUnfold info) then return info else return none
| some info => return some info
| none => return none
| _ => return none
end Meta

View File

@@ -296,7 +296,7 @@ where
m.apply recursor
applyCtors (ms : List MVarId) : MetaM $ List MVarId := do
let mss ms.toArray.mapIdxM fun _ m => do
let mss ms.toArray.mapM fun m => do
let m introNPRec m
( m.getType).withApp fun below args =>
m.withContext do

View File

@@ -41,3 +41,4 @@ import Lean.Meta.Tactic.FunInd
import Lean.Meta.Tactic.Rfl
import Lean.Meta.Tactic.Rewrites
import Lean.Meta.Tactic.Grind
import Lean.Meta.Tactic.Ext

View File

@@ -0,0 +1,76 @@
/-
Copyright (c) 2021 Gabriel Ebner. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Gabriel Ebner, Mario Carneiro
-/
prelude
import Init.Data.Array.InsertionSort
import Lean.Meta.DiscrTree
namespace Lean.Meta.Ext
/-!
### Environment extension for `ext` theorems
-/
/-- Information about an extensionality theorem, stored in the environment extension. -/
structure ExtTheorem where
/-- Declaration name of the extensionality theorem. -/
declName : Name
/-- Priority of the extensionality theorem. -/
priority : Nat
/--
Key in the discrimination tree,
for the type in which the extensionality theorem holds.
-/
keys : Array DiscrTree.Key
deriving Inhabited, Repr, BEq, Hashable
/-- The state of the `ext` extension environment -/
structure ExtTheorems where
/-- The tree of `ext` extensions. -/
tree : DiscrTree ExtTheorem := {}
/-- Erased `ext`s via `attribute [-ext]`. -/
erased : PHashSet Name := {}
deriving Inhabited
/-- The environment extension to track `@[ext]` theorems. -/
builtin_initialize extExtension :
SimpleScopedEnvExtension ExtTheorem ExtTheorems
registerSimpleScopedEnvExtension {
addEntry := fun { tree, erased } thm =>
{ tree := tree.insertCore thm.keys thm, erased := erased.erase thm.declName }
initial := {}
}
/-- Gets the list of `@[ext]` theorems corresponding to the key `ty`,
ordered from high priority to low. -/
@[inline] def getExtTheorems (ty : Expr) : MetaM (Array ExtTheorem) := do
let extTheorems := extExtension.getState ( getEnv)
let arr extTheorems.tree.getMatch ty
let erasedArr := arr.filter fun thm => !extTheorems.erased.contains thm.declName
-- Using insertion sort because it is stable and the list of matches should be mostly sorted.
-- Most ext theorems have default priority.
return erasedArr.insertionSort (·.priority < ·.priority) |>.reverse
/--
Erases a name marked `ext` by adding it to the state's `erased` field and
removing it from the state's list of `Entry`s.
This is triggered by `attribute [-ext] name`.
-/
def ExtTheorems.eraseCore (d : ExtTheorems) (declName : Name) : ExtTheorems :=
{ d with erased := d.erased.insert declName }
/--
Erases a name marked as a `ext` attribute.
Check that it does in fact have the `ext` attribute by making sure it names a `ExtTheorem`
found somewhere in the state's tree, and is not erased.
-/
def ExtTheorems.erase [Monad m] [MonadError m] (d : ExtTheorems) (declName : Name) :
m ExtTheorems := do
unless d.tree.containsValueP (·.declName == declName) && !d.erased.contains declName do
throwError "'{declName}' does not have [ext] attribute"
return d.eraseCore declName
end Lean.Meta.Ext

View File

@@ -25,6 +25,7 @@ import Lean.Meta.Tactic.Grind.EMatch
import Lean.Meta.Tactic.Grind.Main
import Lean.Meta.Tactic.Grind.CasesMatch
import Lean.Meta.Tactic.Grind.Arith
import Lean.Meta.Tactic.Grind.Ext
namespace Lean
@@ -38,6 +39,7 @@ builtin_initialize registerTraceClass `grind.ematch.pattern
builtin_initialize registerTraceClass `grind.ematch.pattern.search
builtin_initialize registerTraceClass `grind.ematch.instance
builtin_initialize registerTraceClass `grind.ematch.instance.assignment
builtin_initialize registerTraceClass `grind.eqResolution
builtin_initialize registerTraceClass `grind.issues
builtin_initialize registerTraceClass `grind.simp
builtin_initialize registerTraceClass `grind.split
@@ -51,6 +53,7 @@ builtin_initialize registerTraceClass `grind.offset.propagate
builtin_initialize registerTraceClass `grind.offset.eq
builtin_initialize registerTraceClass `grind.offset.eq.to (inherited := true)
builtin_initialize registerTraceClass `grind.offset.eq.from (inherited := true)
builtin_initialize registerTraceClass `grind.beta
/-! Trace options for `grind` developers -/
builtin_initialize registerTraceClass `grind.debug
@@ -65,4 +68,7 @@ builtin_initialize registerTraceClass `grind.debug.split
builtin_initialize registerTraceClass `grind.debug.canon
builtin_initialize registerTraceClass `grind.debug.offset
builtin_initialize registerTraceClass `grind.debug.offset.proof
builtin_initialize registerTraceClass `grind.debug.ematch.pattern
builtin_initialize registerTraceClass `grind.debug.beta
end Lean

View File

@@ -10,12 +10,6 @@ import Lean.Meta.Tactic.Simp.Simproc
namespace Lean.Meta.Grind
open Simp
builtin_initialize grindNormExt : SimpExtension
registerSimpAttr `grind_norm "simplification/normalization theorems for `grind`"
builtin_initialize grindNormSimprocExt : SimprocExtension
registerSimprocAttr `grind_norm_proc "simplification/normalization procedured for `grind`" none
builtin_initialize grindCasesExt : SimpleScopedEnvExtension Name NameSet
registerSimpleScopedEnvExtension {
initial := {}

View File

@@ -0,0 +1,77 @@
/-
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 Lean.Meta.Tactic.Grind.Types
namespace Lean.Meta.Grind
/-- Returns all lambda expressions in the equivalence class with root `root`. -/
def getEqcLambdas (root : ENode) : GoalM (Array Expr) := do
unless root.hasLambdas do return #[]
foldEqc root.self (init := #[]) fun n lams =>
if n.self.isLambda then return lams.push n.self else return lams
/--
Returns the root of the functions in the equivalence class containing `e`.
That is, if `f a` is in `root`s equivalence class, results contains the root of `f`.
-/
def getFnRoots (e : Expr) : GoalM (Array Expr) := do
foldEqc e (init := #[]) fun n fns => do
let fn := n.self.getAppFn
let fnRoot := ( getRoot? fn).getD fn
if Option.isNone <| fns.find? (isSameExpr · fnRoot) then
return fns.push fnRoot
else
return fns
/--
For each `lam` in `lams` s.t. `lam` and `f` are in the same equivalence class,
propagate `f args = lam args`.
-/
def propagateBetaEqs (lams : Array Expr) (f : Expr) (args : Array Expr) : GoalM Unit := do
if args.isEmpty then return ()
for lam in lams do
let rhs := lam.beta args
unless rhs.isLambda do
let mut gen := Nat.max ( getGeneration lam) ( getGeneration f)
let lhs := mkAppN f args
if ( hasSameType f lam) then
let mut h mkEqProof f lam
for arg in args do
gen := Nat.max gen ( getGeneration arg)
h mkCongrFun h arg
let eq mkEq lhs rhs
trace[grind.beta] "{eq}, using {lam}"
addNewFact h eq (gen+1)
private def isPropagateBetaTarget (e : Expr) : GoalM Bool := do
let .app f _ := e | return false
go f
where
go (f : Expr) : GoalM Bool := do
if let some root getRootENode? f then
return root.hasLambdas
let .app f _ := f | return false
go f
/--
Applies beta-reduction for lambdas in `f`s equivalence class.
We use this function while internalizing new applications.
-/
def propagateBetaForNewApp (e : Expr) : GoalM Unit := do
unless ( isPropagateBetaTarget e) do return ()
let mut e := e
let mut args := #[]
repeat
unless args.isEmpty do
if let some root getRootENode? e then
if root.hasLambdas then
propagateBetaEqs ( getEqcLambdas root) e args.reverse
let .app f arg := e | return ()
e := f
args := args.push arg
end Lean.Meta.Grind

View File

@@ -10,6 +10,7 @@ import Lean.Meta.FunInfo
import Lean.Util.FVarSubset
import Lean.Util.PtrSet
import Lean.Util.FVarSubset
import Lean.Meta.Tactic.Grind.Types
namespace Lean.Meta.Grind
namespace Canon
@@ -40,42 +41,37 @@ additions will still use structurally different (and definitionally different) i
Furthermore, `grind` will not be able to infer that `HEq (a + a) (b + b)` even if we add the assumptions `n = m` and `HEq a b`.
-/
structure State where
argMap : PHashMap (Expr × Nat) (List Expr) := {}
canon : PHashMap Expr Expr := {}
proofCanon : PHashMap Expr Expr := {}
deriving Inhabited
@[inline] private def get' : GoalM State :=
return ( get).canon
inductive CanonElemKind where
| /--
Type class instances are canonicalized using `TransparencyMode.instances`.
-/
instance
| /--
Types and Type formers are canonicalized using `TransparencyMode.default`.
Remark: propositions are just visited. We do not invoke `canonElemCore` for them.
-/
type
| /--
Implicit arguments that are not types, type formers, or instances, are canonicalized
using `TransparencyMode.reducible`
-/
implicit
deriving BEq
@[inline] private def modify' (f : State State) : GoalM Unit :=
modify fun s => { s with canon := f s.canon }
def CanonElemKind.explain : CanonElemKind String
| .instance => "type class instances"
| .type => "types (or type formers)"
| .implicit => "implicit arguments (which are not type class instances or types)"
/--
Helper function for `canonElemCore`. It tries `isDefEq a b` with default transparency, but using
at most `canonHeartbeats` heartbeats. It reports an issue if the threshold is reached.
Remark: `parent` is use only to report an issue
-/
private def isDefEqBounded (a b : Expr) (parent : Expr) : GoalM Bool := do
withCurrHeartbeats do
let config getConfig
tryCatchRuntimeEx
(withTheReader Core.Context (fun ctx => { ctx with maxHeartbeats := config.canonHeartbeats }) do
withDefault <| isDefEq a b)
fun ex => do
if ex.isRuntime then
let curr := ( getConfig).canonHeartbeats
reportIssue m!"failed to show that{indentExpr a}\nis definitionally equal to{indentExpr b}\nwhile canonicalizing{indentExpr parent}\nusing `{curr}*1000` heartbeats, `(canonHeartbeats := {curr})`"
return false
else
throw ex
/--
Helper function for canonicalizing `e` occurring as the `i`th argument of an `f`-application.
Thus, if diagnostics are enabled, we also re-check them using `TransparencyMode.default`. If the result is different
we report to the user.
If `useIsDefEqBounded` is `true`, we try `isDefEqBounded` before returning false
-/
def canonElemCore (f : Expr) (i : Nat) (e : Expr) (kind : CanonElemKind) : StateT State MetaM Expr := do
let s get
def canonElemCore (parent : Expr) (f : Expr) (i : Nat) (e : Expr) (useIsDefEqBounded : Bool) : GoalM Expr := do
let s get'
if let some c := s.canon.find? e then
return c
let key := (f, i)
@@ -87,20 +83,21 @@ def canonElemCore (f : Expr) (i : Nat) (e : Expr) (kind : CanonElemKind) : State
-- However, we don't revert previously canonicalized elements in the `grind` tactic.
-- Moreover, we store the canonicalizer state in the `Goal` because we case-split
-- and different locals are added in different branches.
modify fun s => { s with canon := s.canon.insert e c }
trace[grind.debug.canon] "found {e} ===> {c}"
modify' fun s => { s with canon := s.canon.insert e c }
trace[grind.debugn.canon] "found {e} ===> {c}"
return c
if kind != .type then
if ( isTracingEnabledFor `grind.issues <&&> (withDefault <| isDefEq e c)) then
-- TODO: consider storing this information in some structure that can be browsed later.
trace[grind.issues] "the following {kind.explain} are definitionally equal with `default` transparency but not with a more restrictive transparency{indentExpr e}\nand{indentExpr c}"
if useIsDefEqBounded then
if ( isDefEqBounded e c parent) then
modify' fun s => { s with canon := s.canon.insert e c }
trace[grind.debugn.canon] "found using `isDefEqBounded`: {e} ===> {c}"
return c
trace[grind.debug.canon] "({f}, {i}) ↦ {e}"
modify fun s => { s with canon := s.canon.insert e e, argMap := s.argMap.insert key (e::cs) }
modify' fun s => { s with canon := s.canon.insert e e, argMap := s.argMap.insert key (e::cs) }
return e
abbrev canonType (f : Expr) (i : Nat) (e : Expr) := withDefault <| canonElemCore f i e .type
abbrev canonInst (f : Expr) (i : Nat) (e : Expr) := withReducibleAndInstances <| canonElemCore f i e .instance
abbrev canonImplicit (f : Expr) (i : Nat) (e : Expr) := withReducible <| canonElemCore f i e .implicit
abbrev canonType (parent f : Expr) (i : Nat) (e : Expr) := withDefault <| canonElemCore parent f i e (useIsDefEqBounded := false)
abbrev canonInst (parent f : Expr) (i : Nat) (e : Expr) := withReducibleAndInstances <| canonElemCore parent f i e (useIsDefEqBounded := true)
abbrev canonImplicit (parent f : Expr) (i : Nat) (e : Expr) := withReducible <| canonElemCore parent f i e (useIsDefEqBounded := true)
/--
Return type for the `shouldCanon` function.
@@ -148,10 +145,10 @@ def shouldCanon (pinfos : Array ParamInfo) (i : Nat) (arg : Expr) : MetaM Should
else
return .visit
unsafe def canonImpl (e : Expr) : StateT State MetaM Expr := do
unsafe def canonImpl (e : Expr) : GoalM Expr := do
visit e |>.run' mkPtrMap
where
visit (e : Expr) : StateRefT (PtrMap Expr Expr) (StateT State MetaM) Expr := do
visit (e : Expr) : StateRefT (PtrMap Expr Expr) GoalM Expr := do
unless e.isApp || e.isForall do return e
-- Check whether it is cached
if let some r := ( get).find? e then
@@ -161,11 +158,11 @@ where
if f.isConstOf ``Lean.Grind.nestedProof && args.size == 2 then
let prop := args[0]!
let prop' visit prop
if let some r := ( getThe State).proofCanon.find? prop' then
if let some r := ( get').proofCanon.find? prop' then
pure r
else
let e' := if ptrEq prop prop' then e else mkAppN f (args.set! 0 prop')
modifyThe State fun s => { s with proofCanon := s.proofCanon.insert prop' e' }
modify' fun s => { s with proofCanon := s.proofCanon.insert prop' e' }
pure e'
else
let pinfos := ( getFunInfo f).paramInfo
@@ -175,9 +172,9 @@ where
let arg := args[i]
trace[grind.debug.canon] "[{repr (← shouldCanon pinfos i arg)}]: {arg} : {← inferType arg}"
let arg' match ( shouldCanon pinfos i arg) with
| .canonType => canonType f i arg
| .canonInst => canonInst f i arg
| .canonImplicit => canonImplicit f i ( visit arg)
| .canonType => canonType e f i arg
| .canonInst => canonInst e f i arg
| .canonImplicit => canonImplicit e f i ( visit arg)
| .visit => visit arg
unless ptrEq arg arg' do
args := args.set i arg'
@@ -193,11 +190,11 @@ where
modify fun s => s.insert e e'
return e'
/-- Canonicalizes nested types, type formers, and instances in `e`. -/
def canon (e : Expr) : StateT State MetaM Expr := do
trace[grind.debug.canon] "{e}"
unsafe canonImpl e
end Canon
/-- Canonicalizes nested types, type formers, and instances in `e`. -/
def canon (e : Expr) : GoalM Expr := do
trace[grind.debug.canon] "{e}"
unsafe Canon.canonImpl e
end Lean.Meta.Grind

View File

@@ -11,6 +11,7 @@ import Lean.Meta.Tactic.Grind.Inv
import Lean.Meta.Tactic.Grind.PP
import Lean.Meta.Tactic.Grind.Ctor
import Lean.Meta.Tactic.Grind.Util
import Lean.Meta.Tactic.Grind.Beta
import Lean.Meta.Tactic.Grind.Internalize
namespace Lean.Meta.Grind
@@ -40,7 +41,7 @@ Remove `root` parents from the congruence table.
This is an auxiliary function performed while merging equivalence classes.
-/
private def removeParents (root : Expr) : GoalM ParentSet := do
let parents getParentsAndReset root
let parents getParents root
for parent in parents do
-- Recall that we may have `Expr.forallE` in `parents` because of `ForallProp.lean`
if ( pure parent.isApp <&&> isCongrRoot parent) then
@@ -107,6 +108,31 @@ private def propagateOffsetEq (rhsRoot lhsRoot : ENode) : GoalM Unit := do
if let some rhsOffset := rhsRoot.offset? then
Arith.processNewOffsetEqLit rhsOffset lhsRoot.self
/--
Tries to apply beta-reductiong using the parent applications of the functions in `fns` with
the lambda expressions in `lams`.
-/
def propagateBeta (lams : Array Expr) (fns : Array Expr) : GoalM Unit := do
if lams.isEmpty then return ()
let lamRoot getRoot lams.back!
trace[grind.debug.beta] "fns: {fns}, lams: {lams}"
for fn in fns do
trace[grind.debug.beta] "fn: {fn}, parents: {(← getParents fn).toArray}"
for parent in ( getParents fn) do
let mut args := #[]
let mut curr := parent
trace[grind.debug.beta] "parent: {parent}"
repeat
trace[grind.debug.beta] "curr: {curr}"
if ( isEqv curr lamRoot) then
propagateBetaEqs lams curr args.reverse
let .app f arg := curr
| break
-- Remark: recall that we do not eagerly internalize partial applications.
internalize curr ( getGeneration parent)
args := args.push arg
curr := f
private partial def addEqStep (lhs rhs proof : Expr) (isHEq : Bool) : GoalM Unit := do
let lhsNode getENode lhs
let rhsNode getENode rhs
@@ -158,6 +184,10 @@ where
proof? := proof
flipped
}
let lams₁ getEqcLambdas lhsRoot
let lams₂ getEqcLambdas rhsRoot
let fns₁ if lams₁.isEmpty then pure #[] else getFnRoots rhsRoot.self
let fns₂ if lams₂.isEmpty then pure #[] else getFnRoots lhsRoot.self
let parents removeParents lhsRoot.self
updateRoots lhs rhsNode.root
trace_goal[grind.debug] "{← ppENodeRef lhs} new root {← ppENodeRef rhsNode.root}, {← ppENodeRef (← getRoot lhs)}"
@@ -172,6 +202,9 @@ where
hasLambdas := rhsRoot.hasLambdas || lhsRoot.hasLambdas
heqProofs := isHEq || rhsRoot.heqProofs || lhsRoot.heqProofs
}
propagateBeta lams₁ fns₁
propagateBeta lams₂ fns₂
resetParentsOf lhsRoot.self
copyParentsTo parents rhsNode.root
unless ( isInconsistent) do
updateMT rhsRoot.self

View File

@@ -20,7 +20,7 @@ private partial def propagateInjEqs (eqs : Expr) (proof : Expr) : GoalM Unit :=
| HEq _ lhs _ rhs =>
pushHEq ( shareCommon lhs) ( shareCommon rhs) proof
| _ =>
trace_goal[grind.issues] "unexpected injectivity theorem result type{indentExpr eqs}"
reportIssue m!"unexpected injectivity theorem result type{indentExpr eqs}"
return ()
/--

View File

@@ -129,6 +129,16 @@ private partial def matchArgs? (c : Choice) (p : Expr) (e : Expr) : OptionT Goal
let c matchArg? c pArg eArg
matchArgs? c p.appFn! e.appFn!
/-- Similar to `matchArgs?` but if `p` has fewer arguments than `e`, we match `p` with a prefix of `e`. -/
private partial def matchArgsPrefix? (c : Choice) (p : Expr) (e : Expr) : OptionT GoalM Choice := do
let pn := p.getAppNumArgs
let en := e.getAppNumArgs
guard (pn <= en)
if pn == en then
matchArgs? c p e
else
matchArgs? c p (e.getAppPrefix pn)
/--
Matches pattern `p` with term `e` with respect to choice `c`.
We traverse the equivalence class of `e` looking for applications compatible with `p`.
@@ -194,7 +204,7 @@ private def processContinue (c : Choice) (p : Expr) : M Unit := do
let n getENode app
if n.generation < maxGeneration
&& (n.heqProofs || n.isCongrRoot) then
if let some c matchArgs? c p app |>.run then
if let some c matchArgsPrefix? c p app |>.run then
let gen := n.generation
let c := { c with gen := Nat.max gen c.gen }
modify fun s => { s with choiceStack := c :: s.choiceStack }
@@ -240,7 +250,7 @@ private partial def instantiateTheorem (c : Choice) : M Unit := withDefault do w
assert! c.assignment.size == numParams
let (mvars, bis, _) forallMetaBoundedTelescope ( inferType proof) numParams
if mvars.size != thm.numParams then
trace_goal[grind.issues] "unexpected number of parameters at {← thm.origin.pp}"
reportIssue m!"unexpected number of parameters at {← thm.origin.pp}"
return ()
-- Apply assignment
for h : i in [:mvars.size] do
@@ -250,14 +260,14 @@ private partial def instantiateTheorem (c : Choice) : M Unit := withDefault do w
let mvarIdType mvarId.getType
let vType inferType v
unless ( isDefEq mvarIdType vType <&&> mvarId.checkedAssign v) do
trace_goal[grind.issues] "type error constructing proof for {← thm.origin.pp}\nwhen assigning metavariable {mvars[i]} with {indentExpr v}\n{← mkHasTypeButIsExpectedMsg vType mvarIdType}"
reportIssue m!"type error constructing proof for {← thm.origin.pp}\nwhen assigning metavariable {mvars[i]} with {indentExpr v}\n{← mkHasTypeButIsExpectedMsg vType mvarIdType}"
return ()
-- Synthesize instances
for mvar in mvars, bi in bis do
if bi.isInstImplicit && !( mvar.mvarId!.isAssigned) then
let type inferType mvar
unless ( synthesizeInstance mvar type) do
trace_goal[grind.issues] "failed to synthesize instance when instantiating {← thm.origin.pp}{indentExpr type}"
unless ( synthesizeInstanceAndAssign mvar type) do
reportIssue m!"failed to synthesize instance when instantiating {← thm.origin.pp}{indentExpr type}"
return ()
let proof := mkAppN proof mvars
if ( mvars.allM (·.mvarId!.isAssigned)) then
@@ -265,13 +275,9 @@ private partial def instantiateTheorem (c : Choice) : M Unit := withDefault do w
else
let mvars mvars.filterM fun mvar => return !( mvar.mvarId!.isAssigned)
if let some mvarBad mvars.findM? fun mvar => return !( isProof mvar) then
trace_goal[grind.issues] "failed to instantiate {← thm.origin.pp}, failed to instantiate non propositional argument with type{indentExpr (← inferType mvarBad)}"
reportIssue m!"failed to instantiate {← thm.origin.pp}, failed to instantiate non propositional argument with type{indentExpr (← inferType mvarBad)}"
let proof mkLambdaFVars (binderInfoForMVars := .default) mvars ( instantiateMVars proof)
addNewInstance thm.origin proof c.gen
where
synthesizeInstance (x type : Expr) : MetaM Bool := do
let .some val trySynthInstance type | return false
isDefEq x val
/-- Process choice stack until we don't have more choices to be processed. -/
private def processChoices : M Unit := do
@@ -300,7 +306,7 @@ private def main (p : Expr) (cnstrs : List Cnstr) : M Unit := do
if (n.heqProofs || n.isCongrRoot) &&
(!useMT || n.mt == gmt) then
withInitApp app do
if let some c matchArgs? { cnstrs, assignment, gen := n.generation } p app |>.run then
if let some c matchArgsPrefix? { cnstrs, assignment, gen := n.generation } p app |>.run then
modify fun s => { s with choiceStack := [c] }
processChoices
@@ -360,7 +366,4 @@ def ematchAndAssert : GrindTactic := fun goal => do
return none
assertAll goal
def ematchStar : GrindTactic :=
ematchAndAssert.iterate
end Lean.Meta.Grind

View File

@@ -269,19 +269,36 @@ private def getPatternFn? (pattern : Expr) : Option Expr :=
/--
Returns a bit-mask `mask` s.t. `mask[i]` is true if the corresponding argument is
- a type (that is not a proposition) or type former, or
- a type (that is not a proposition) or type former (which has forward dependencies) or
- a proof, or
- an instance implicit argument
When `mask[i]`, we say the corresponding argument is a "support" argument.
-/
def getPatternSupportMask (f : Expr) (numArgs : Nat) : MetaM (Array Bool) := do
let pinfos := ( getFunInfoNArgs f numArgs).paramInfo
forallBoundedTelescope ( inferType f) numArgs fun xs _ => do
xs.mapM fun x => do
xs.mapIdxM fun idx x => do
if ( isProp x) then
return false
else if ( isTypeFormer x <||> isProof x) then
else if ( isProof x) then
return true
else if ( isTypeFormer x) then
if h : idx < pinfos.size then
/-
We originally wanted to ignore types and type formers in `grind` and treat them as supporting elements.
Thus, we would always return `true`. However, we changed our heuristic because of the following example:
```
example {α} (f : α → Type) (a : α) (h : ∀ x, Nonempty (f x)) : Nonempty (f a) := by
grind
```
In this example, we are reasoning about types. Therefore, we adjusted the heuristic as follows:
a type or type former is considered a supporting element only if it has forward dependencies.
Note that this is not the case for `Nonempty`.
-/
return pinfos[idx].hasFwdDeps
else
return true
else
return ( x.fvarId!.getDecl).binderInfo matches .instImplicit
@@ -499,7 +516,9 @@ def mkEMatchEqTheoremCore (origin : Origin) (levelParams : Array Name) (proof :
| HEq _ lhs _ rhs => pure (lhs, rhs)
| _ => throwError "invalid E-matching equality theorem, conclusion must be an equality{indentExpr type}"
let pat := if useLhs then lhs else rhs
trace[grind.debug.ematch.pattern] "mkEMatchEqTheoremCore: origin: {← origin.pp}, pat: {pat}, useLhs: {useLhs}"
let pat preprocessPattern pat normalizePattern
trace[grind.debug.ematch.pattern] "mkEMatchEqTheoremCore: after preprocessing: {pat}, {← normalize pat}"
let pats := splitWhileForbidden (pat.abstract xs)
return (xs.size, pats)
mkEMatchTheoremCore origin levelParams numParams proof patterns
@@ -534,7 +553,7 @@ def getEMatchTheorems : CoreM EMatchTheorems :=
inductive TheoremKind where
| eqLhs | eqRhs | eqBoth | fwd | bwd | default
deriving Inhabited, BEq
deriving Inhabited, BEq, Repr
private def TheoremKind.toAttribute : TheoremKind String
| .eqLhs => "[grind =]"
@@ -634,9 +653,9 @@ private def collectPatterns? (proof : Expr) (xs : Array Expr) (searchPlaces : Ar
def mkEMatchTheoremWithKind? (origin : Origin) (levelParams : Array Name) (proof : Expr) (kind : TheoremKind) : MetaM (Option EMatchTheorem) := do
if kind == .eqLhs then
return ( mkEMatchEqTheoremCore origin levelParams proof (normalizePattern := false) (useLhs := true))
return ( mkEMatchEqTheoremCore origin levelParams proof (normalizePattern := true) (useLhs := true))
else if kind == .eqRhs then
return ( mkEMatchEqTheoremCore origin levelParams proof (normalizePattern := false) (useLhs := false))
return ( mkEMatchEqTheoremCore origin levelParams proof (normalizePattern := true) (useLhs := false))
let type inferType proof
forallTelescopeReducing type fun xs type => do
let searchPlaces match kind with
@@ -660,28 +679,40 @@ where
levelParams, origin
}
private def getKind (stx : Syntax) : TheoremKind :=
/-- Return theorem kind for `stx` of the form `Attr.grindThmMod` -/
def getTheoremKindCore (stx : Syntax) : CoreM TheoremKind := do
match stx with
| `(Parser.Attr.grindThmMod| =) => return .eqLhs
| `(Parser.Attr.grindThmMod| ) => return .fwd
| `(Parser.Attr.grindThmMod| ) => return .bwd
| `(Parser.Attr.grindThmMod| =_) => return .eqRhs
| `(Parser.Attr.grindThmMod| _=_) => return .eqBoth
| _ => throwError "unexpected `grind` theorem kind: `{stx}`"
/-- Return theorem kind for `stx` of the form `(Attr.grindThmMod)?` -/
def getTheoremKindFromOpt (stx : Syntax) : CoreM TheoremKind := do
if stx[1].isNone then
.default
else if stx[1][0].getKind == ``Parser.Attr.grindEq then
.eqLhs
else if stx[1][0].getKind == ``Parser.Attr.grindFwd then
.fwd
else if stx[1][0].getKind == ``Parser.Attr.grindEqRhs then
.eqRhs
else if stx[1][0].getKind == ``Parser.Attr.grindEqBoth then
.eqBoth
return .default
else
.bwd
getTheoremKindCore stx[1][0]
def mkEMatchTheoremForDecl (declName : Name) (thmKind : TheoremKind) : MetaM EMatchTheorem := do
let some thm mkEMatchTheoremWithKind? (.decl declName) #[] ( getProofFor declName) thmKind
| throwError "`@{thmKind.toAttribute} theorem {declName}` {thmKind.explainFailure}, consider using different options or the `grind_pattern` command"
return thm
def mkEMatchEqTheoremsForDef? (declName : Name) : MetaM (Option (Array EMatchTheorem)) := do
let some eqns getEqnsFor? declName | return none
eqns.mapM fun eqn => do
mkEMatchEqTheorem eqn (normalizePattern := true)
private def addGrindEqAttr (declName : Name) (attrKind : AttributeKind) (thmKind : TheoremKind) (useLhs := true) : MetaM Unit := do
if ( getConstInfo declName).isTheorem then
ematchTheoremsExt.add ( mkEMatchEqTheorem declName (normalizePattern := true) (useLhs := useLhs)) attrKind
else if let some eqns getEqnsFor? declName then
else if let some thms mkEMatchEqTheoremsForDef? declName then
unless useLhs do
throwError "`{declName}` is a definition, you must only use the left-hand side for extracting patterns"
for eqn in eqns do
ematchTheoremsExt.add ( mkEMatchEqTheorem eqn) attrKind
thms.forM (ematchTheoremsExt.add · attrKind)
else
throwError s!"`{thmKind.toAttribute}` attribute can only be applied to equational theorems or function definitions"
@@ -696,10 +727,26 @@ private def addGrindAttr (declName : Name) (attrKind : AttributeKind) (thmKind :
else if !( getConstInfo declName).isTheorem then
addGrindEqAttr declName attrKind thmKind
else
let some thm mkEMatchTheoremWithKind? (.decl declName) #[] ( getProofFor declName) thmKind
| throwError "`@{thmKind.toAttribute} theorem {declName}` {thmKind.explainFailure}, consider using different options or the `grind_pattern` command"
let thm mkEMatchTheoremForDecl declName thmKind
ematchTheoremsExt.add thm attrKind
def EMatchTheorems.eraseDecl (s : EMatchTheorems) (declName : Name) : MetaM EMatchTheorems := do
let throwErr {α} : MetaM α :=
throwError "`{declName}` is not marked with the `[grind]` attribute"
let info getConstInfo declName
if !info.isTheorem then
if let some eqns getEqnsFor? declName then
let s := ematchTheoremsExt.getState ( getEnv)
unless eqns.all fun eqn => s.contains (.decl eqn) do
throwErr
return eqns.foldl (init := s) fun s eqn => s.erase (.decl eqn)
else
throwErr
else
unless ematchTheoremsExt.getState ( getEnv) |>.contains (.decl declName) do
throwErr
return s.erase <| .decl declName
builtin_initialize
registerBuiltinAttribute {
name := `grind
@@ -722,7 +769,7 @@ builtin_initialize
`grind` will add an instance of this theorem to the local context whenever it encounters the pattern `foo (foo x)`."
applicationTime := .afterCompilation
add := fun declName stx attrKind => do
addGrindAttr declName attrKind (getKind stx) |>.run' {}
addGrindAttr declName attrKind ( getTheoremKindFromOpt stx) |>.run' {}
erase := fun declName => MetaM.run' do
/-
Remark: consider the following example
@@ -738,21 +785,9 @@ builtin_initialize
attribute [-grind] foo -- ok
```
-/
let throwErr := throwError "`{declName}` is not marked with the `[grind]` attribute"
let info getConstInfo declName
if !info.isTheorem then
if let some eqns getEqnsFor? declName then
let s := ematchTheoremsExt.getState ( getEnv)
unless eqns.all fun eqn => s.contains (.decl eqn) do
throwErr
modifyEnv fun env => ematchTheoremsExt.modifyState env fun s =>
eqns.foldl (init := s) fun s eqn => s.erase (.decl eqn)
else
throwErr
else
unless ematchTheoremsExt.getState ( getEnv) |>.contains (.decl declName) do
throwErr
modifyEnv fun env => ematchTheoremsExt.modifyState env fun s => s.erase (.decl declName)
let s := ematchTheoremsExt.getState ( getEnv)
let s s.eraseDecl declName
modifyEnv fun env => ematchTheoremsExt.modifyState env fun _ => s
}
end Lean.Meta.Grind

View File

@@ -0,0 +1,47 @@
/-
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 Lean.Meta.AppBuilder
namespace Lean.Meta.Grind
/-! A basic "equality resolution" procedure. -/
private def eqResCore (prop proof : Expr) : MetaM (Option (Expr × Expr)) := withNewMCtxDepth do
let (ms, _, type) forallMetaTelescopeReducing prop
if ms.isEmpty then return none
let mut progress := false
for m in ms do
let type inferType m
let_expr Eq _ lhs rhs type
| pure ()
if ( isDefEq lhs rhs) then
unless ( m.mvarId!.checkedAssign ( mkEqRefl lhs)) do
return none
progress := true
unless progress do
return none
if ( ms.anyM fun m => m.mvarId!.isDelayedAssigned) then
return none
let prop' instantiateMVars type
let proof' instantiateMVars (mkAppN proof ms)
let ms ms.filterM fun m => return !( m.mvarId!.isAssigned)
let prop' mkForallFVars ms prop' (binderInfoForMVars := .default)
let proof' mkLambdaFVars ms proof'
return some (prop', proof')
/--
A basic "equality resolution" procedure: Given a proposition `prop` with a proof `proof`, it attempts to resolve equality hypotheses using `isDefEq`. For example, it reduces `∀ x y, f x = f (g y y) → g x y = y` to `∀ y, g (g y y) y = y`, and `∀ (x : Nat), f x ≠ f a` to `False`.
If successful, the result is a pair `(prop', proof)`, where `prop'` is the simplified proposition,
and `proof : prop → prop'`
-/
def eqResolution (prop : Expr) : MetaM (Option (Expr × Expr)) :=
withLocalDeclD `h prop fun h => do
let some (prop', proof') eqResCore prop h
| return none
let proof' mkLambdaFVars #[h] proof'
return some (prop', proof')
end Lean.Meta.Grind

View File

@@ -0,0 +1,40 @@
/-
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 Lean.Meta.Tactic.Grind.Types
namespace Lean.Meta.Grind
/-! Extensionality theorems support. -/
def instantiateExtTheorem (thm : Ext.ExtTheorem) (e : Expr) : GoalM Unit := withNewMCtxDepth do
unless ( getGeneration e) < ( getMaxGeneration) do return ()
let c mkConstWithFreshMVarLevels thm.declName
let (mvars, bis, type) withDefault <| forallMetaTelescopeReducing ( inferType c)
unless ( isDefEq e type) do
reportIssue m!"failed to apply extensionality theorem `{thm.declName}` for {indentExpr e}\nis not definitionally equal to{indentExpr type}"
return ()
-- Instantiate type class instances
for mvar in mvars, bi in bis do
if bi.isInstImplicit && !( mvar.mvarId!.isAssigned) then
let type inferType mvar
unless ( synthesizeInstanceAndAssign mvar type) do
reportIssue m!"failed to synthesize instance when instantiating extensionality theorem `{thm.declName}` for {indentExpr e}"
return ()
-- Remark: `proof c mvars` has type `e`
let proof instantiateMVars (mkAppN c mvars)
-- `e` is equal to `False`
let eEqFalse mkEqFalseProof e
-- So, we use `Eq.mp` to build a `proof` of `False`
let proof mkEqMP eEqFalse proof
let mvars mvars.filterM fun mvar => return !( mvar.mvarId!.isAssigned)
let proof' instantiateMVars ( mkLambdaFVars mvars proof)
let prop' inferType proof'
if proof'.hasMVar || prop'.hasMVar then
reportIssue m!"failed to apply extensionality theorem `{thm.declName}` for {indentExpr e}\nresulting terms contain metavariables"
return ()
addNewFact proof' prop' (( getGeneration e) + 1)
end Lean.Meta.Grind

View File

@@ -8,6 +8,7 @@ import Init.Grind.Lemmas
import Lean.Meta.Tactic.Grind.Types
import Lean.Meta.Tactic.Grind.Internalize
import Lean.Meta.Tactic.Grind.Simp
import Lean.Meta.Tactic.Grind.EqResolution
namespace Lean.Meta.Grind
/--
@@ -77,7 +78,7 @@ private def addLocalEMatchTheorems (e : Expr) : GoalM Unit := do
if let some thm mkEMatchTheoremWithKind'? origin proof .default then
activateTheorem thm gen
if ( get).newThms.size == size then
trace[grind.issues] "failed to create E-match local theorem for{indentExpr e}"
reportIssue m!"failed to create E-match local theorem for{indentExpr e}"
def propagateForallPropDown (e : Expr) : GoalM Unit := do
let .forallE n a b bi := e | return ()
@@ -96,7 +97,13 @@ def propagateForallPropDown (e : Expr) : GoalM Unit := do
pushEqTrue a <| mkApp3 (mkConst ``Grind.eq_true_of_imp_eq_false) a b h
pushEqFalse b <| mkApp3 (mkConst ``Grind.eq_false_of_imp_eq_false) a b h
else if ( isEqTrue e) then
if b.hasLooseBVars then
addLocalEMatchTheorems e
if let some (e', h') eqResolution e then
trace[grind.eqResolution] "{e}, {e'}"
let h := mkOfEqTrueCore e ( mkEqTrueProof e)
let h' := mkApp h' h
addNewFact h' e' ( getGeneration e)
else
if b.hasLooseBVars then
addLocalEMatchTheorems e
end Lean.Meta.Grind

View File

@@ -11,6 +11,8 @@ import Lean.Meta.Match.MatcherInfo
import Lean.Meta.Match.MatchEqsExt
import Lean.Meta.Tactic.Grind.Types
import Lean.Meta.Tactic.Grind.Util
import Lean.Meta.Tactic.Grind.Canon
import Lean.Meta.Tactic.Grind.Beta
import Lean.Meta.Tactic.Grind.Arith.Internalize
namespace Lean.Meta.Grind
@@ -24,7 +26,7 @@ def addCongrTable (e : Expr) : GoalM Unit := do
let g := e'.getAppFn
unless isSameExpr f g do
unless ( hasSameType f g) do
trace_goal[grind.issues] "found congruence between{indentExpr e}\nand{indentExpr e'}\nbut functions have different types"
reportIssue m!"found congruence between{indentExpr e}\nand{indentExpr e'}\nbut functions have different types"
return ()
trace_goal[grind.debug.congr] "{e} = {e'}"
pushEqHEq e e' congrPlaceholderProof
@@ -98,13 +100,16 @@ private def pushCastHEqs (e : Expr) : GoalM Unit := do
| f@Eq.recOn α a motive b h v => pushHEq e v (mkApp6 (mkConst ``Grind.eqRecOn_heq f.constLevels!) α a motive b h v)
| _ => return ()
private def preprocessGroundPattern (e : Expr) : GoalM Expr := do
shareCommon ( canon ( normalizeLevels ( unfoldReducible e)))
mutual
/-- Internalizes the nested ground terms in the given pattern. -/
private partial def internalizePattern (pattern : Expr) (generation : Nat) : GoalM Expr := do
if pattern.isBVar || isPatternDontCare pattern then
return pattern
else if let some e := groundPattern? pattern then
let e shareCommon ( canon ( normalizeLevels ( unfoldReducible e)))
let e preprocessGroundPattern e
internalize e generation none
return mkGroundPattern e
else pattern.withApp fun f args => do
@@ -168,7 +173,7 @@ partial def internalize (e : Expr) (generation : Nat) (parent? : Option Expr :=
| .mvar ..
| .mdata ..
| .proj .. =>
trace_goal[grind.issues] "unexpected term during internalization{indentExpr e}"
reportIssue m!"unexpected kernel projection term during internalization{indentExpr e}\n`grind` uses a pre-processing step that folds them as projection applications, the pre-processor should have failed to fold this term"
mkENodeCore e (ctor := false) (interpreted := false) (generation := generation)
| .app .. =>
if ( isLitValue e) then
@@ -190,7 +195,7 @@ partial def internalize (e : Expr) (generation : Nat) (parent? : Option Expr :=
activateTheoremPatterns fName generation
else
internalize f generation e
registerParent e f
registerParent e f
for h : i in [: args.size] do
let arg := args[i]
internalize arg generation e
@@ -200,6 +205,8 @@ partial def internalize (e : Expr) (generation : Nat) (parent? : Option Expr :=
updateAppMap e
Arith.internalize e parent?
propagateUp e
propagateBetaForNewApp e
end
end Lean.Meta.Grind

View File

@@ -15,10 +15,24 @@ import Lean.Meta.Tactic.Grind.Inv
import Lean.Meta.Tactic.Grind.Intro
import Lean.Meta.Tactic.Grind.EMatch
import Lean.Meta.Tactic.Grind.Split
import Lean.Meta.Tactic.Grind.Solve
import Lean.Meta.Tactic.Grind.SimpUtil
namespace Lean.Meta.Grind
structure Params where
config : Grind.Config
ematch : EMatchTheorems := {}
extra : PArray EMatchTheorem := {}
norm : Simp.Context
normProcs : Array Simprocs
-- TODO: inductives to split
def mkParams (config : Grind.Config) : MetaM Params := do
let norm Grind.getSimpContext
let normProcs Grind.getSimprocs
return { config, norm, normProcs }
def mkMethods (fallback : Fallback) : CoreM Methods := do
let builtinPropagators builtinPropagatorsRef.get
return {
@@ -36,26 +50,29 @@ def mkMethods (fallback : Fallback) : CoreM Methods := do
prop e
}
def GrindM.run (x : GrindM α) (mainDeclName : Name) (config : Grind.Config) (fallback : Fallback) : MetaM α := do
def GrindM.run (x : GrindM α) (mainDeclName : Name) (params : Params) (fallback : Fallback) : MetaM α := do
let scState := ShareCommon.State.mk _
let (falseExpr, scState) := ShareCommon.State.shareCommon scState (mkConst ``False)
let (trueExpr, scState) := ShareCommon.State.shareCommon scState (mkConst ``True)
let (natZExpr, scState) := ShareCommon.State.shareCommon scState (mkNatLit 0)
let simprocs Grind.getSimprocs
let simp Grind.getSimpContext
let simprocs := params.normProcs
let simp := params.norm
let config := params.config
x ( mkMethods fallback).toMethodsRef { mainDeclName, config, simprocs, simp } |>.run' { scState, trueExpr, falseExpr, natZExpr }
private def mkGoal (mvarId : MVarId) : GrindM Goal := do
private def mkGoal (mvarId : MVarId) (params : Params) : GrindM Goal := do
let trueExpr getTrueExpr
let falseExpr getFalseExpr
let natZeroExpr getNatZeroExpr
let thmMap getEMatchTheorems
let thmMap := params.ematch
GoalM.run' { mvarId, thmMap } do
mkENodeCore falseExpr (interpreted := true) (ctor := false) (generation := 0)
mkENodeCore trueExpr (interpreted := true) (ctor := false) (generation := 0)
mkENodeCore natZeroExpr (interpreted := true) (ctor := false) (generation := 0)
for thm in params.extra do
activateTheorem thm 0
private def initCore (mvarId : MVarId) : GrindM (List Goal) := do
private def initCore (mvarId : MVarId) (params : Params) : GrindM (List Goal) := do
mvarId.ensureProp
-- TODO: abstract metavars
mvarId.ensureNoMVar
@@ -64,21 +81,14 @@ private def initCore (mvarId : MVarId) : GrindM (List Goal) := do
let mvarId mvarId.unfoldReducible
let mvarId mvarId.betaReduce
appendTagSuffix mvarId `grind
let goals intros ( mkGoal mvarId) (generation := 0)
let goals intros ( mkGoal mvarId params) (generation := 0)
goals.forM (·.checkInvariants (expensive := true))
return goals.filter fun goal => !goal.inconsistent
def all (goals : List Goal) (f : Goal GrindM (List Goal)) : GrindM (List Goal) := do
goals.foldlM (init := []) fun acc goal => return acc ++ ( f goal)
/-- A very simple strategy -/
private def simple (goals : List Goal) : GrindM (List Goal) := do
applyToAll (assertAll >> ematchStar >> (splitNext >> assertAll >> ematchStar).iterate) goals
def main (mvarId : MVarId) (config : Grind.Config) (mainDeclName : Name) (fallback : Fallback) : MetaM (List Goal) := do
def main (mvarId : MVarId) (params : Params) (mainDeclName : Name) (fallback : Fallback) : MetaM (List Goal) := do
let go : GrindM (List Goal) := do
let goals initCore mvarId
let goals simple goals
let goals initCore mvarId params
let goals solve goals
let goals goals.filterMapM fun goal => do
if goal.inconsistent then return none
let goal GoalM.run' goal fallback
@@ -87,6 +97,6 @@ def main (mvarId : MVarId) (config : Grind.Config) (mainDeclName : Name) (fallba
return some goal
trace[grind.debug.final] "{← ppGoals goals}"
return goals
go.run mainDeclName config fallback
go.run mainDeclName params fallback
end Lean.Meta.Grind

View File

@@ -76,10 +76,16 @@ private def ppExprArray (cls : Name) (header : String) (es : Array Expr) (clsEle
let es := es.map fun e => .trace { cls := clsElem} m!"{e}" #[]
.trace { cls } header es
private def ppEqcs (goal : Goal) : MetaM (Array MessageData) := do
private abbrev M := ReaderT Goal (StateT (Array MessageData) MetaM)
private def pushMsg (m : MessageData) : M Unit :=
modify fun s => s.push m
private def ppEqcs : M Unit := do
let mut trueEqc? : Option MessageData := none
let mut falseEqc? : Option MessageData := none
let mut otherEqcs : Array MessageData := #[]
let goal read
for eqc in goal.getEqcs do
if Option.isSome <| eqc.find? (·.isTrue) then
let eqc := eqc.filter fun e => !e.isTrue
@@ -93,44 +99,68 @@ private def ppEqcs (goal : Goal) : MetaM (Array MessageData) := do
-- We may want to add a flag to pretty print equivalence classes of nested proofs
unless ( isProof e) do
otherEqcs := otherEqcs.push <| .trace { cls := `eqc } (.group ("{" ++ (MessageData.joinSep (eqc.map toMessageData) ("," ++ Format.line)) ++ "}")) #[]
let mut result := #[]
if let some trueEqc := trueEqc? then result := result.push trueEqc
if let some falseEqc := falseEqc? then result := result.push falseEqc
if let some trueEqc := trueEqc? then pushMsg trueEqc
if let some falseEqc := falseEqc? then pushMsg falseEqc
unless otherEqcs.isEmpty do
result := result.push <| .trace { cls := `eqc } "Equivalence classes" otherEqcs
return result
pushMsg <| .trace { cls := `eqc } "Equivalence classes" otherEqcs
private def ppEMatchTheorem (thm : EMatchTheorem) : MetaM MessageData := do
let m := m!"{← thm.origin.pp}\n{← inferType thm.proof}\npatterns: {thm.patterns.map ppPattern}"
let m := m!"{← thm.origin.pp}:\n{← inferType thm.proof}\npatterns: {thm.patterns.map ppPattern}"
return .trace { cls := `thm } m #[]
private def ppActiveTheorems (goal : Goal) : MetaM MessageData := do
let m goal.thms.toArray.mapM ppEMatchTheorem
let m := m ++ ( goal.newThms.toArray.mapM ppEMatchTheorem)
if m.isEmpty then
return ""
else
return .trace { cls := `ematch } "E-matching" m
private def ppActiveTheorems : M Unit := do
let goal read
let m goal.thms.toArray.mapM fun thm => ppEMatchTheorem thm
let m := m ++ ( goal.newThms.toArray.mapM fun thm => ppEMatchTheorem thm)
unless m.isEmpty do
pushMsg <| .trace { cls := `ematch } "E-matching" m
def ppOffset (goal : Goal) : MetaM MessageData := do
private def ppOffset : M Unit := do
let goal read
let s := goal.arith.offset
let nodes := s.nodes
if nodes.isEmpty then return ""
if nodes.isEmpty then return ()
let model Arith.Offset.mkModel goal
let mut ms := #[]
for (e, val) in model do
ms := ms.push <| .trace { cls := `assign } m!"{e} := {val}" #[]
return .trace { cls := `offset } "Assignment satisfying offset contraints" ms
pushMsg <| .trace { cls := `offset } "Assignment satisfying offset contraints" ms
def goalToMessageData (goal : Goal) : MetaM MessageData := goal.mvarId.withContext do
let mut m : Array MessageData := #[.ofGoal goal.mvarId]
m := m.push <| ppExprArray `facts "Asserted facts" goal.facts.toArray `prop
m := m ++ ( ppEqcs goal)
m := m.push ( ppActiveTheorems goal)
m := m.push ( ppOffset goal)
addMessageContextFull <| MessageData.joinSep m.toList ""
private def ppIssues : M Unit := do
let issues := ( read).issues
unless issues.isEmpty do
pushMsg <| .trace { cls := `issues } "Issues" issues.reverse.toArray
def goalsToMessageData (goals : List Goal) : MetaM MessageData :=
return MessageData.joinSep ( goals.mapM goalToMessageData) m!"\n"
private def ppThresholds (c : Grind.Config) : M Unit := do
let goal read
let maxGen := goal.enodes.foldl (init := 0) fun g _ n => Nat.max g n.generation
let mut msgs := #[]
if goal.numInstances c.instances then
msgs := msgs.push <| .trace { cls := `limit } m!"maximum number of instances generated by E-matching has been reached, threshold: `(instances := {c.instances})`" #[]
if goal.numEmatch c.ematch then
msgs := msgs.push <| .trace { cls := `limit } m!"maximum number of E-matching rounds has been reached, threshold: `(ematch := {c.ematch})`" #[]
if goal.numSplits c.splits then
msgs := msgs.push <| .trace { cls := `limit } m!"maximum number of case-splits has been reached, threshold: `(splits := {c.splits})`" #[]
if maxGen c.gen then
msgs := msgs.push <| .trace { cls := `limit } m!"maximum term generation has been reached, threshold: `(gen := {c.gen})`" #[]
unless msgs.isEmpty do
pushMsg <| .trace { cls := `limits } "Thresholds reached" msgs
def goalToMessageData (goal : Goal) (config : Grind.Config) : MetaM MessageData := goal.mvarId.withContext do
let (_, m) go goal |>.run #[]
let gm := MessageData.trace { cls := `grind, collapsed := false } "Diagnostics" m
let r := m!"{.ofGoal goal.mvarId}\n{gm}"
addMessageContextFull r
where
go : M Unit := do
pushMsg <| ppExprArray `facts "Asserted facts" goal.facts.toArray `prop
ppEqcs
ppActiveTheorems
ppOffset
ppThresholds config
ppIssues
def goalsToMessageData (goals : List Goal) (config : Grind.Config) : MetaM MessageData :=
return MessageData.joinSep ( goals.mapM (goalToMessageData · config)) m!"\n"
end Lean.Meta.Grind

View File

@@ -12,4 +12,8 @@ Builtin parsers for `grind` related commands
-/
@[builtin_command_parser] def grindPattern := leading_parser
"grind_pattern " >> ident >> darrow >> sepBy1 termParser ","
@[builtin_command_parser] def initGrindNorm := leading_parser
"init_grind_norm " >> many ident >> "| " >> many ident
end Lean.Parser.Command

View File

@@ -8,6 +8,7 @@ import Init.Grind
import Lean.Meta.Tactic.Grind.Proof
import Lean.Meta.Tactic.Grind.PropagatorAttr
import Lean.Meta.Tactic.Grind.Simp
import Lean.Meta.Tactic.Grind.Ext
import Lean.Meta.Tactic.Grind.Internalize
namespace Lean.Meta.Grind
@@ -133,6 +134,19 @@ builtin_grind_propagator propagateEqDown ↓Eq := fun e => do
if ( isEqTrue e) then
let_expr Eq _ a b := e | return ()
pushEq a b <| mkOfEqTrueCore e ( mkEqTrueProof e)
else if ( isEqFalse e) then
let_expr Eq α lhs rhs := e | return ()
let thms getExtTheorems α
if !thms.isEmpty then
/-
Heuristic for lists: If `lhs` or `rhs` are contructors we do not apply extensionality theorems.
For example, we don't want to apply the extensionality theorem to things like `xs ≠ []`.
TODO: polish this hackish heuristic later.
-/
if α.isAppOf ``List && (( getRootENode lhs).ctor || ( getRootENode rhs).ctor) then
return ()
for thm in ( getExtTheorems α) do
instantiateExtTheorem thm e
/-- Propagates `EqMatch` downwards -/
builtin_grind_propagator propagateEqMatchDown Grind.EqMatch := fun e => do

View File

@@ -11,6 +11,7 @@ import Lean.Meta.Tactic.Grind.Util
import Lean.Meta.Tactic.Grind.Types
import Lean.Meta.Tactic.Grind.DoNotSimp
import Lean.Meta.Tactic.Grind.MarkNestedProofs
import Lean.Meta.Tactic.Grind.Canon
namespace Lean.Meta.Grind
/-- Simplifies the given expression using the `grind` simprocs and normalization theorems. -/
@@ -28,9 +29,9 @@ def simp (e : Expr) : GoalM Simp.Result := do
let e instantiateMVars e
let r simpCore e
let e' := r.expr
let e' unfoldReducible e'
let e' abstractNestedProofs e'
let e' markNestedProofs e'
let e' unfoldReducible e'
let e' eraseIrrelevantMData e'
let e' foldProjs e'
let e' normalizeLevels e'

View File

@@ -7,18 +7,44 @@ prelude
import Lean.Meta.Tactic.Simp.Simproc
import Lean.Meta.Tactic.Grind.Simp
import Lean.Meta.Tactic.Grind.DoNotSimp
import Lean.Meta.Tactic.Simp.BuiltinSimprocs.List
namespace Lean.Meta.Grind
builtin_initialize normExt : SimpExtension mkSimpExt
def registerNormTheorems (preDeclNames : Array Name) (postDeclNames : Array Name) : MetaM Unit := do
let thms normExt.getTheorems
unless thms.lemmaNames.isEmpty do
throwError "`grind` normalization theorems have already been initialized"
for declName in preDeclNames do
addSimpTheorem normExt declName (post := false) (inv := false) .global (eval_prio default)
for declName in postDeclNames do
addSimpTheorem normExt declName (post := true) (inv := false) .global (eval_prio default)
/-- Returns the array of simprocs used by `grind`. -/
protected def getSimprocs : MetaM (Array Simprocs) := do
let s grindNormSimprocExt.getSimprocs
let s addDoNotSimp s
return #[s, ( Simp.getSEvalSimprocs)]
let e Simp.getSEvalSimprocs
/-
We don't want to apply `List.reduceReplicate` as a normalization operation in
`grind`. Consider the following example:
```
example (ys : List α) : n = 0 → List.replicate n ys = [] := by
grind only [List.replicate]
```
The E-matching module generates the following instance for `List.replicate.eq_1`
```
List.replicate 0 [] = []
```
We don't want it to be simplified to `[] = []`.
-/
let e := e.erase ``List.reduceReplicate
let e addDoNotSimp e
return #[e]
/-- Returns the simplification context used by `grind`. -/
protected def getSimpContext : MetaM Simp.Context := do
let thms grindNormExt.getTheorems
let thms normExt.getTheorems
Simp.mkContext
(config := { arith := true })
(simpTheorems := #[thms])

View File

@@ -0,0 +1,92 @@
/-
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 Lean.Meta.Tactic.Grind.Combinators
import Lean.Meta.Tactic.Grind.Split
import Lean.Meta.Tactic.Grind.EMatch
namespace Lean.Meta.Grind
namespace Solve
structure State where
todo : List Goal
failures : List Goal := []
stop : Bool := false
private abbrev M := StateRefT State GrindM
def getNext? : M (Option Goal) := do
let goal::todo := ( get).todo | return none
modify fun s => { s with todo }
return some goal
def pushGoal (goal : Goal) : M Unit :=
modify fun s => { s with todo := goal :: s.todo }
def pushGoals (goals : List Goal) : M Unit :=
modify fun s => { s with todo := goals ++ s.todo }
def pushFailure (goal : Goal) : M Unit := do
modify fun s => { s with failures := goal :: s.failures }
if ( get).failures.length ( getConfig).failures then
modify fun s => { s with stop := true }
@[inline] def stepGuard (x : Goal M Bool) (goal : Goal) : M Bool := do
try
x goal
catch ex =>
if ex.isMaxHeartbeat || ex.isMaxRecDepth then
let goal goal.reportIssue ex.toMessageData
pushFailure goal
return true
else
throw ex
def applyTac (x : GrindTactic) (goal : Goal) : M Bool := do
let go (goal : Goal) : M Bool := do
let some goals x goal | return false
pushGoals goals
return true
stepGuard go goal
def tryAssertNext : Goal M Bool := applyTac assertNext
def tryEmatch : Goal M Bool := applyTac ematchAndAssert
def trySplit : Goal M Bool := applyTac splitNext
def maxNumFailuresReached : M Bool := do
return ( get).failures.length ( getConfig).failures
partial def main : M Unit := do
repeat do
if ( get).stop then
return ()
let some goal getNext? |
return ()
if goal.inconsistent then
continue
if ( tryAssertNext goal) then
continue
if ( tryEmatch goal) then
continue
if ( trySplit goal) then
continue
pushFailure goal
end Solve
/--
Try to solve/close the given goals, and returns the ones that could not be solved.
-/
def solve (goals : List Goal) : GrindM (List Goal) := do
let (_, s) Solve.main.run { todo := goals }
let todo s.todo.mapM fun goal => do
goal.reportIssue m!"this goal was not fully processed due to previous failures, threshold: `(failures := {(← getConfig).failures})`"
return s.failures.reverse ++ todo
end Lean.Meta.Grind

View File

@@ -74,6 +74,14 @@ private def checkIffStatus (e a b : Expr) : GoalM CaseSplitStatus := do
else
return .notReady
/-- Returns `true` is `c` is congruent to a case-split that was already performed. -/
private def isCongrToPrevSplit (c : Expr) : GoalM Bool := do
( get).resolvedSplits.foldM (init := false) fun flag { expr := c' } => do
if flag then
return true
else
return isCongruent ( get).enodes c c'
private def checkCaseSplitStatus (e : Expr) : GoalM CaseSplitStatus := do
match_expr e with
| Or a b => checkDisjunctStatus e a b
@@ -85,6 +93,8 @@ private def checkCaseSplitStatus (e : Expr) : GoalM CaseSplitStatus := do
if ( isResolvedCaseSplit e) then
trace[grind.debug.split] "split resolved: {e}"
return .resolved
if ( isCongrToPrevSplit e) then
return .resolved
if let some info := isMatcherAppCore? ( getEnv) e then
return .ready info.numAlts
let .const declName .. := e.getAppFn | unreachable!
@@ -163,6 +173,7 @@ def splitNext : GrindTactic := fun goal => do
| return none
let gen getGeneration c
let genNew := if numCases > 1 || isRec then gen+1 else gen
markCaseSplitAsResolved c
trace_goal[grind.split] "{c}, generation: {gen}"
let mvarIds if ( isMatcherApp c) then
casesMatch ( get).mvarId c

View File

@@ -13,8 +13,8 @@ import Lean.Meta.CongrTheorems
import Lean.Meta.AbstractNestedProofs
import Lean.Meta.Tactic.Simp.Types
import Lean.Meta.Tactic.Util
import Lean.Meta.Tactic.Ext
import Lean.Meta.Tactic.Grind.ENodeKey
import Lean.Meta.Tactic.Grind.Canon
import Lean.Meta.Tactic.Grind.Attr
import Lean.Meta.Tactic.Grind.Arith.Types
import Lean.Meta.Tactic.Grind.EMatchTheorem
@@ -333,6 +333,13 @@ structure NewFact where
generation : Nat
deriving Inhabited
/-- Canonicalizer state. See `Canon.lean` for additional details. -/
structure Canon.State where
argMap : PHashMap (Expr × Nat) (List Expr) := {}
canon : PHashMap Expr Expr := {}
proofCanon : PHashMap Expr Expr := {}
deriving Inhabited
structure Goal where
mvarId : MVarId
canon : Canon.State := {}
@@ -378,12 +385,19 @@ structure Goal where
splitCandidates : List Expr := []
/-- Number of splits performed to get to this goal. -/
numSplits : Nat := 0
/-- Case-splits that do not have to be performed anymore. -/
/-- Case-splits that have already been performed, or that do not have to be performed anymore. -/
resolvedSplits : PHashSet ENodeKey := {}
/-- Next local E-match theorem idx. -/
nextThmIdx : Nat := 0
/-- Asserted facts -/
facts : PArray Expr := {}
/--
Issues found during the proof search in this goal. This issues are reported to
users when `grind` fails.
-/
issues : List MessageData := []
/-- Cached extensionality theorems for types. -/
extThms : PHashMap ENodeKey (Array Ext.ExtTheorem) := {}
deriving Inhabited
def Goal.admit (goal : Goal) : MetaM Unit :=
@@ -397,13 +411,6 @@ abbrev GoalM := StateRefT Goal GrindM
@[inline] def GoalM.run' (goal : Goal) (x : GoalM Unit) : GrindM Goal :=
goal.mvarId.withContext do StateRefT'.run' (x *> get) goal
/-- Canonicalizes nested types, type formers, and instances in `e`. -/
def canon (e : Expr) : GoalM Expr := do
let canonS modifyGet fun s => (s.canon, { s with canon := {} })
let (e, canonS) Canon.canon e |>.run canonS
modify fun s => { s with canon := canonS }
return e
def updateLastTag : GoalM Unit := do
if ( isTracingEnabledFor `grind) then
let currTag ( get).mvarId.getTag
@@ -411,6 +418,20 @@ def updateLastTag : GoalM Unit := do
trace[grind] "working on goal `{currTag}`"
modifyThe Grind.State fun s => { s with lastTag := currTag }
def Goal.reportIssue (goal : Goal) (msg : MessageData) : MetaM Goal := do
let msg addMessageContext msg
let goal := { goal with issues := .trace { cls := `issue } msg #[] :: goal.issues }
/-
We also add a trace message because we may want to know when
an issue happened relative to other trace messages.
-/
trace[grind.issues] msg
return goal
def reportIssue (msg : MessageData) : GoalM Unit := do
let goal ( get).reportIssue msg
set goal
/--
Macro similar to `trace[...]`, but it includes the trace message `trace[grind] "working on <current goal>"`
if the tag has changed since the last trace message.
@@ -480,8 +501,9 @@ def getENode (e : Expr) : GoalM ENode := do
( get).getENode e
/-- Returns the generation of the given term. Is assumes it has been internalized -/
def getGeneration (e : Expr) : GoalM Nat :=
return ( getENode e).generation
def getGeneration (e : Expr) : GoalM Nat := do
let some n getENode? e | return 0
return n.generation
/-- Returns `true` if `e` is in the equivalence class of `True`. -/
def isEqTrue (e : Expr) : GoalM Bool := do
@@ -498,8 +520,8 @@ def isEqv (a b : Expr) : GoalM Bool := do
if isSameExpr a b then
return true
else
let na getENode a
let nb getENode b
let some na getENode? a | return false
let some nb getENode? b | return false
return isSameExpr na.root nb.root
/-- Returns `true` if the root of its equivalence class. -/
@@ -528,6 +550,11 @@ def getRoot (e : Expr) : GoalM Expr := do
def getRootENode (e : Expr) : GoalM ENode := do
getENode ( getRoot e)
/-- Returns the root enode in the equivalence class of `e` if it is in an equivalence class. -/
def getRootENode? (e : Expr) : GoalM (Option ENode) := do
let some n getENode? e | return none
getENode? n.root
/--
Returns the next element in the equivalence class of `e`
if `e` has been internalized in the given goal.
@@ -593,7 +620,7 @@ Records that `parent` is a parent of `child`. This function actually stores the
information in the root (aka canonical representative) of `child`.
-/
def registerParent (parent : Expr) (child : Expr) : GoalM Unit := do
let some childRoot getRoot? child | return ()
let childRoot := ( getRoot? child).getD child
let parents := if let some parents := ( get).parents.find? { expr := childRoot } then parents else {}
modify fun s => { s with parents := s.parents.insert { expr := childRoot } (parents.insert parent) }
@@ -607,12 +634,10 @@ def getParents (e : Expr) : GoalM ParentSet := do
return parents
/--
Similar to `getParents`, but also removes the entry `e ↦ parents` from the parent map.
Removes the entry `e ↦ parents` from the parent map.
-/
def getParentsAndReset (e : Expr) : GoalM ParentSet := do
let parents getParents e
def resetParentsOf (e : Expr) : GoalM Unit := do
modify fun s => { s with parents := s.parents.erase { expr := e } }
return parents
/--
Copy `parents` to the parents of `root`.
@@ -779,6 +804,18 @@ def getENodes : GoalM (Array ENode) := do
if isSameExpr n.next e then return ()
curr := n.next
/-- Folds using `f` and `init` over the equivalence class containing `e` -/
@[inline] def foldEqc (e : Expr) (init : α) (f : ENode α GoalM α) : GoalM α := do
let mut curr := e
let mut r := init
repeat
let n getENode curr
r f n r
if isSameExpr n.next e then return r
curr := n.next
unreachable!
return r
def forEachENode (f : ENode GoalM Unit) : GoalM Unit := do
let nodes getENodes
for n in nodes do
@@ -860,11 +897,33 @@ def isResolvedCaseSplit (e : Expr) : GoalM Bool :=
/--
Mark `e` as a case-split that does not need to be performed anymore.
Remark: we currently use this feature to disable `match`-case-splits
Remark: we currently use this feature to disable `match`-case-splits.
Remark: we also use this feature to record the case-splits that have already been performed.
-/
def markCaseSplitAsResolved (e : Expr) : GoalM Unit := do
unless ( isResolvedCaseSplit e) do
trace_goal[grind.split.resolved] "{e}"
modify fun s => { s with resolvedSplits := s.resolvedSplits.insert { expr := e } }
/--
Returns extensionality theorems for the given type if available.
If `Config.ext` is `false`, the result is `#[]`.
-/
def getExtTheorems (type : Expr) : GoalM (Array Ext.ExtTheorem) := do
unless ( getConfig).ext do return #[]
if let some thms := ( get).extThms.find? { expr := type } then
return thms
else
let thms Ext.getExtTheorems type
modify fun s => { s with extThms := s.extThms.insert { expr := type } thms }
return thms
/--
Helper function for instantiating a type class `type`, and
then using the result to perform `isDefEq x val`.
-/
def synthesizeInstanceAndAssign (x type : Expr) : MetaM Bool := do
let .some val trySynthInstance type | return false
isDefEq x val
end Lean.Meta.Grind

View File

@@ -52,12 +52,12 @@ def reportDiag (diag : Simp.Diagnostics) : MetaM Unit := do
let congr mkDiagSummary `simp diag.congrThmCounter
let thmsWithBadKeys mkTheoremsWithBadKeySummary diag.thmsWithBadKeys
unless used.isEmpty && tried.isEmpty && congr.isEmpty && thmsWithBadKeys.isEmpty do
let m := MessageData.nil
let m := #[]
let m := appendSection m `simp "used theorems" used
let m := appendSection m `simp "tried theorems" tried
let m := appendSection m `simp "tried congruence theorems" congr
let m := appendSection m `simp "theorems with bad keys" thmsWithBadKeys (resultSummary := false)
let m := m ++ "use `set_option diagnostics.threshold <num>` to control threshold for reporting counters"
logInfo m
let m := m.push <| "use `set_option diagnostics.threshold <num>` to control threshold for reporting counters"
logInfo <| .trace { cls := `simp, collapsed := false } "Diagnostics" m
end Lean.Meta.Simp

View File

@@ -104,7 +104,7 @@ Otherwise executes `failK`.
-- ===========================
private def getFirstCtor (d : Name) : MetaM (Option Name) := do
let some (ConstantInfo.inductInfo { ctors := ctor::_, ..}) getUnfoldableConstNoEx? d |
let some (ConstantInfo.inductInfo { ctors := ctor::_, ..}) := ( getEnv).find? d |
return none
return some ctor
@@ -258,7 +258,7 @@ private def reduceQuotRec (recVal : QuotVal) (recArgs : Array Expr) (failK : Un
let major whnf major
match major with
| Expr.app (Expr.app (Expr.app (Expr.const majorFn _) _) _) majorArg => do
let some (ConstantInfo.quotInfo { kind := QuotKind.ctor, .. }) getUnfoldableConstNoEx? majorFn | failK ()
let some (ConstantInfo.quotInfo { kind := QuotKind.ctor, .. }) := ( getEnv).find? majorFn | failK ()
let f := recArgs[argPos]!
let r := mkApp f majorArg
let recArity := majorPos + 1
@@ -321,7 +321,7 @@ mutual
| .mvar mvarId => return some mvarId
| _ => getStuckMVar? e
| .const fName _ =>
match ( getUnfoldableConstNoEx? fName) with
match ( getEnv).find? fName with
| some <| .recInfo recVal => isRecStuck? recVal e.getAppArgs
| some <| .quotInfo recVal => isQuotRecStuck? recVal e.getAppArgs
| _ =>
@@ -625,17 +625,18 @@ where
| .partialApp => pure e
| .stuck _ => pure e
| .notMatcher =>
matchConstAux f' (fun _ => return e) fun cinfo lvls =>
match cinfo with
| .recInfo rec => reduceRec rec lvls e.getAppArgs (fun _ => return e) (fun e => do recordUnfold cinfo.name; go e)
| .quotInfo rec => reduceQuotRec rec e.getAppArgs (fun _ => return e) (fun e => do recordUnfold cinfo.name; go e)
| c@(.defnInfo _) => do
if ( isAuxDef c.name) then
recordUnfold c.name
deltaBetaDefinition c lvls e.getAppRevArgs (fun _ => return e) go
else
return e
| _ => return e
let .const cname lvls := f' | return e
let some cinfo := ( getEnv).find? cname | return e
match cinfo with
| .recInfo rec => reduceRec rec lvls e.getAppArgs (fun _ => return e) (fun e => do recordUnfold cinfo.name; go e)
| .quotInfo rec => reduceQuotRec rec e.getAppArgs (fun _ => return e) (fun e => do recordUnfold cinfo.name; go e)
| c@(.defnInfo _) => do
if ( isAuxDef c.name) then
recordUnfold c.name
deltaBetaDefinition c lvls e.getAppRevArgs (fun _ => return e) go
else
return e
| _ => return e
| .proj _ i c =>
let k (c : Expr) := do
match ( projectCore? c i) with
@@ -860,7 +861,9 @@ def reduceRecMatcher? (e : Expr) : MetaM (Option Expr) := do
return none
else match ( reduceMatcher? e) with
| .reduced e => return e
| _ => matchConstAux e.getAppFn (fun _ => pure none) fun cinfo lvls => do
| _ =>
let .const cname lvls := e.getAppFn | return none
let some cinfo := ( getEnv).find? cname | return none
match cinfo with
| .recInfo «rec» => reduceRec «rec» lvls e.getAppArgs (fun _ => pure none) (fun e => do recordUnfold cinfo.name; pure (some e))
| .quotInfo «rec» => reduceQuotRec «rec» e.getAppArgs (fun _ => pure none) (fun e => do recordUnfold cinfo.name; pure (some e))

View File

@@ -5,6 +5,7 @@ Authors: Leonardo de Moura
-/
prelude
import Lean.Environment
import Lean.PrivateName
namespace Lean
@@ -16,69 +17,12 @@ def addProtected (env : Environment) (n : Name) : Environment :=
def isProtected (env : Environment) (n : Name) : Bool :=
protectedExt.isTagged env n
/-! # Private name support.
Suppose the user marks as declaration `n` as private. Then, we create
the name: `_private.<module_name>.0 ++ n`.
We say `_private.<module_name>.0` is the "private prefix"
We assume that `n` is a valid user name and does not contain
`Name.num` constructors. Thus, we can easily convert from
private internal name to the user given name.
-/
def privateHeader : Name := `_private
def mkPrivateName (env : Environment) (n : Name) : Name :=
Name.mkNum (privateHeader ++ env.mainModule) 0 ++ n
def isPrivateName : Name Bool
| n@(.str p _) => n == privateHeader || isPrivateName p
| .num p _ => isPrivateName p
| _ => false
@[export lean_is_private_name]
def isPrivateNameExport (n : Name) : Bool :=
isPrivateName n
/--
Return `true` if `n` is of the form `_private.<module_name>.0`
See comment above.
-/
def isPrivatePrefix (n : Name) : Bool :=
match n with
| .num p 0 => go p
| _ => false
where
go (n : Name) : Bool :=
n == privateHeader ||
match n with
| .str p _ => go p
| _ => false
private def privateToUserNameAux (n : Name) : Name :=
match n with
| .str p s => .str (privateToUserNameAux p) s
| .num p i => if isPrivatePrefix n then .anonymous else .num (privateToUserNameAux p) i
| _ => .anonymous
@[export lean_private_to_user_name]
def privateToUserName? (n : Name) : Option Name :=
if isPrivateName n then privateToUserNameAux n
else none
def isPrivateNameFromImportedModule (env : Environment) (n : Name) : Bool :=
match privateToUserName? n with
| some userName => mkPrivateName env userName != n
| _ => false
private def privatePrefixAux : Name Name
| .str p _ => privatePrefixAux p
| n => n
@[export lean_private_prefix]
def privatePrefix? (n : Name) : Option Name :=
if isPrivateName n then privatePrefixAux n
else none
end Lean

75
src/Lean/PrivateName.lean Normal file
View File

@@ -0,0 +1,75 @@
/-
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Init.Notation
namespace Lean
/-! # Private name support.
Suppose the user marks as declaration `n` as private. Then, we create
the name: `_private.<module_name>.0 ++ n`.
We say `_private.<module_name>.0` is the "private prefix"
We assume that `n` is a valid user name and does not contain
`Name.num` constructors. Thus, we can easily convert from
private internal name to the user given name.
-/
def privateHeader : Name := `_private
def mkPrivateNameCore (mainModule : Name) (n : Name) : Name :=
Name.mkNum (privateHeader ++ mainModule) 0 ++ n
def isPrivateName : Name Bool
| n@(.str p _) => n == privateHeader || isPrivateName p
| .num p _ => isPrivateName p
| _ => false
@[export lean_is_private_name]
def isPrivateNameExport (n : Name) : Bool :=
isPrivateName n
/--
Return `true` if `n` is of the form `_private.<module_name>.0`
See comment above.
-/
def isPrivatePrefix (n : Name) : Bool :=
match n with
| .num p 0 => go p
| _ => false
where
go (n : Name) : Bool :=
n == privateHeader ||
match n with
| .str p _ => go p
| _ => false
private def privateToUserNameAux (n : Name) : Name :=
match n with
| .str p s => .str (privateToUserNameAux p) s
| .num p i => if isPrivatePrefix n then .anonymous else .num (privateToUserNameAux p) i
| _ => .anonymous
@[export lean_private_to_user_name]
def privateToUserName? (n : Name) : Option Name :=
if isPrivateName n then privateToUserNameAux n
else none
def privateToUserName (n : Name) : Name :=
if isPrivateName n then privateToUserNameAux n
else n
private def privatePrefixAux : Name Name
| .str p _ => privatePrefixAux p
| n => n
@[export lean_private_prefix]
def privatePrefix? (n : Name) : Option Name :=
if isPrivateName n then privatePrefixAux n
else none
end Lean

View File

@@ -49,15 +49,13 @@ def isTodo (name : Name) : M Bool := do
else
return false
/-- Use the current `Environment` to throw a `KernelException`. -/
def throwKernelException (ex : KernelException) : M Unit := do
let ctx := { fileName := "", options := ({} : KVMap), fileMap := default }
let state := { env := ( get).env }
Prod.fst <$> (Lean.Core.CoreM.toIO · ctx state) do Lean.throwKernelException ex
/-- Use the current `Environment` to throw a `Kernel.Exception`. -/
def throwKernelException (ex : Kernel.Exception) : M Unit := do
throw <| .userError <| ( ex.toMessageData {} |>.toString)
/-- Add a declaration, possibly throwing a `KernelException`. -/
/-- Add a declaration, possibly throwing a `Kernel.Exception`. -/
def addDecl (d : Declaration) : M Unit := do
match ( get).env.addDecl {} d with
match ( get).env.addDeclCore 0 d (cancelTk? := none) with
| .ok env => modify fun s => { s with env := env }
| .error ex => throwKernelException ex

View File

@@ -290,24 +290,12 @@ This function ensures that the value is used linearly.
(Raw₀.Const.insertManyIfNewUnit m.1, m.2.size_buckets_pos l).1,
(Raw₀.Const.insertManyIfNewUnit m.1, m.2.size_buckets_pos l).2 _ Raw.WF.insertIfNew₀ m.2
@[inline, inherit_doc Raw.ofList] def ofList [BEq α] [Hashable α] (l : List ((a : α) × β a)) :
DHashMap α β :=
insertMany l
/-- Computes the union of the given hash maps, by traversing `m₂` and inserting its elements into `m₁`. -/
@[inline] def union [BEq α] [Hashable α] (m₁ m₂ : DHashMap α β) : DHashMap α β :=
m₂.fold (init := m₁) fun acc x => acc.insert x
instance [BEq α] [Hashable α] : Union (DHashMap α β) := union
@[inline, inherit_doc Raw.Const.ofList] def Const.ofList {β : Type v} [BEq α] [Hashable α]
(l : List (α × β)) : DHashMap α (fun _ => β) :=
Const.insertMany l
@[inline, inherit_doc Raw.Const.unitOfList] def Const.unitOfList [BEq α] [Hashable α] (l : List α) :
DHashMap α (fun _ => Unit) :=
Const.insertManyIfNewUnit l
@[inline, inherit_doc Raw.Const.unitOfArray] def Const.unitOfArray [BEq α] [Hashable α] (l : Array α) :
DHashMap α (fun _ => Unit) :=
Const.insertManyIfNewUnit l
@@ -321,4 +309,16 @@ instance [BEq α] [Hashable α] [Repr α] [(a : α) → Repr (β a)] : Repr (DHa
end Unverified
@[inline, inherit_doc Raw.ofList] def ofList [BEq α] [Hashable α] (l : List ((a : α) × β a)) :
DHashMap α β :=
insertMany l
@[inline, inherit_doc Raw.Const.ofList] def Const.ofList {β : Type v} [BEq α] [Hashable α]
(l : List (α × β)) : DHashMap α (fun _ => β) :=
Const.insertMany l
@[inline, inherit_doc Raw.Const.unitOfList] def Const.unitOfList [BEq α] [Hashable α] (l : List α) :
DHashMap α (fun _ => Unit) :=
Const.insertManyIfNewUnit l
end Std.DHashMap

View File

@@ -7,6 +7,7 @@ prelude
import Init.Data.BEq
import Init.Data.Nat.Simproc
import Init.Data.List.Perm
import Init.Data.List.Find
import Std.Data.DHashMap.Internal.List.Defs
/-!
@@ -257,6 +258,15 @@ theorem containsKey_eq_isSome_getEntry? [BEq α] {l : List ((a : α) × β a)} {
· simp [getEntry?_cons_of_false h, h, ih]
· simp [getEntry?_cons_of_true h, h]
theorem containsKey_eq_contains_map_fst [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)}
{k : α} : containsKey k l = (l.map Sigma.fst).contains k := by
induction l with
| nil => simp
| cons hd tl ih =>
rw [containsKey_cons, ih]
simp only [List.map_cons, List.contains_cons]
rw [BEq.comm]
theorem isEmpty_eq_false_of_containsKey [BEq α] {l : List ((a : α) × β a)} {a : α}
(h : containsKey a l = true) : l.isEmpty = false := by
cases l <;> simp_all
@@ -663,7 +673,7 @@ theorem isEmpty_replaceEntry [BEq α] {l : List ((a : α) × β a)} {k : α} {v
(replaceEntry k v l).isEmpty = l.isEmpty := by
induction l using assoc_induction
· simp
· simp [replaceEntry_cons, cond_eq_if]
· simp only [replaceEntry_cons, cond_eq_if, List.isEmpty_cons]
split <;> simp
theorem getEntry?_replaceEntry_of_containsKey_eq_false [BEq α] {l : List ((a : α) × β a)} {a k : α}
@@ -681,7 +691,7 @@ theorem getEntry?_replaceEntry_of_false [BEq α] [PartialEquivBEq α] {l : List
· rw [replaceEntry_cons_of_false h', getEntry?_cons, getEntry?_cons, ih]
· rw [replaceEntry_cons_of_true h']
have hk : (k' == a) = false := BEq.neq_of_beq_of_neq h' h
simp [getEntry?_cons_of_false h, getEntry?_cons_of_false hk]
simp only [getEntry?_cons_of_false h, getEntry?_cons_of_false hk]
theorem getEntry?_replaceEntry_of_true [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)}
{a k : α} {v : β k} (hl : containsKey k l = true) (h : k == a) :
@@ -874,6 +884,11 @@ theorem containsKey_of_mem [BEq α] [ReflBEq α] {l : List ((a : α) × β a)} {
theorem DistinctKeys.nil [BEq α] : DistinctKeys ([] : List ((a : α) × β a)) :=
by simp
theorem DistinctKeys.def [BEq α] {l : List ((a : α) × β a)} :
DistinctKeys l l.Pairwise (fun a b => (a.1 == b.1) = false) :=
fun h => by simpa [keys_eq_map, List.pairwise_map] using h.distinct,
fun h => by simpa [keys_eq_map, List.pairwise_map] using h
open List
theorem DistinctKeys.perm_keys [BEq α] [PartialEquivBEq α] {l l' : List ((a : α) × β a)}
@@ -909,6 +924,10 @@ theorem containsKey_eq_false_iff_forall_mem_keys [BEq α] [PartialEquivBEq α]
(containsKey a l) = false a' keys l, (a == a') = false := by
simp only [Bool.eq_false_iff, ne_eq, containsKey_iff_exists, not_exists, not_and]
theorem containsKey_eq_false_iff [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)} {a : α} :
containsKey a l = false (b : ((a : α) × β a)), b l (a == b.fst) = false := by
simp [containsKey_eq_false_iff_forall_mem_keys, keys_eq_map]
@[simp]
theorem distinctKeys_cons_iff [BEq α] [PartialEquivBEq α] {l : List ((a : α) × β a)} {k : α}
{v : β k} : DistinctKeys (k, v :: l) DistinctKeys l (containsKey k l) = false := by
@@ -963,6 +982,18 @@ theorem DistinctKeys.replaceEntry [BEq α] [PartialEquivBEq α] {l : List ((a :
refine h.1, ?_
simpa [containsKey_congr (BEq.symm hk'k)] using h.2
theorem getEntry?_of_mem [BEq α] [PartialEquivBEq α]
{l : List ((a : α) × β a)} (hl : DistinctKeys l)
{k k' : α} (hk : k == k') {v : β k} (hkv : k, v l) :
getEntry? k' l = some k, v := by
induction l using assoc_induction with
| nil => simp at hkv
| cons k₁ v₁ t ih =>
obtain |hkv := List.mem_cons.1 hkv
· rw [getEntry?_cons_of_true hk]
· rw [getEntry?_cons_of_false, ih hl.tail hkv]
exact BEq.neq_of_neq_of_beq (containsKey_eq_false_iff.1 hl.containsKey_eq_false _ hkv) hk
/-- Internal implementation detail of the hash map -/
def insertEntry [BEq α] (k : α) (v : β k) (l : List ((a : α) × β a)) : List ((a : α) × β a) :=
bif containsKey k l then replaceEntry k v l else k, v :: l
@@ -1214,6 +1245,16 @@ theorem insertEntryIfNew_of_containsKey_eq_false [BEq α] {l : List ((a : α) ×
{v : β k} (h : containsKey k l = false) : insertEntryIfNew k v l = k, v :: l := by
simp_all [insertEntryIfNew]
theorem DistinctKeys.insertEntryIfNew [BEq α] [PartialEquivBEq α] {k : α} {v : β k}
{l : List ((a : α) × β a)} (h: DistinctKeys l):
DistinctKeys (insertEntryIfNew k v l) := by
simp only [Std.DHashMap.Internal.List.insertEntryIfNew, cond_eq_if]
split
· exact h
· rw [distinctKeys_cons_iff]
rename_i h'
simp [h, h']
@[simp]
theorem isEmpty_insertEntryIfNew [BEq α] {l : List ((a : α) × β a)} {k : α} {v : β k} :
(insertEntryIfNew k v l).isEmpty = false := by
@@ -1845,6 +1886,836 @@ theorem eraseKey_append_of_containsKey_right_eq_false [BEq α] {l l' : List ((a
· rw [cond_false, cond_false, ih, List.cons_append]
· rw [cond_true, cond_true]
/-- Internal implementation detail of the hash map -/
def insertList [BEq α] (l toInsert : List ((a : α) × β a)) : List ((a : α) × β a) :=
match toInsert with
| .nil => l
| .cons k, v toInsert => insertList (insertEntry k v l) toInsert
theorem DistinctKeys.insertList [BEq α] [PartialEquivBEq α] {l₁ l₂ : List ((a : α) × β a)}
(h : DistinctKeys l₁) :
DistinctKeys (insertList l₁ l₂) := by
induction l₂ using assoc_induction generalizing l₁
· simpa [insertList]
· rename_i k v t ih
rw [insertList.eq_def]
exact ih h.insertEntry
theorem insertList_perm_of_perm_first [BEq α] [EquivBEq α] {l1 l2 toInsert : List ((a : α) × β a)}
(h : Perm l1 l2) (distinct : DistinctKeys l1) :
Perm (insertList l1 toInsert) (insertList l2 toInsert) := by
induction toInsert generalizing l1 l2 with
| nil => simp [insertList, h]
| cons hd tl ih =>
simp only [insertList]
apply ih (insertEntry_of_perm distinct h) (DistinctKeys.insertEntry distinct)
theorem insertList_cons_perm [BEq α] [EquivBEq α] {l₁ l₂ : List ((a : α) × β a)}
{p : (a : α) × β a} (hl₁ : DistinctKeys l₁) (hl₂ : DistinctKeys (p :: l₂)) :
(insertList l₁ (p :: l₂)).Perm (insertEntry p.1 p.2 (insertList l₁ l₂)) := by
induction l₂ generalizing p l₁
· simp [insertList]
· rename_i h t ih
rw [insertList]
refine (ih hl₁.insertEntry hl₂.tail).trans
((insertEntry_of_perm hl₁.insertList
(ih hl₁ (distinctKeys_of_sublist (by simp) hl₂))).trans
(List.Perm.trans ?_ (insertEntry_of_perm hl₁.insertList.insertEntry
(ih hl₁ (distinctKeys_of_sublist (by simp) hl₂)).symm)))
apply getEntry?_ext hl₁.insertList.insertEntry.insertEntry
hl₁.insertList.insertEntry.insertEntry (fun k => ?_)
simp only [getEntry?_insertEntry]
split <;> rename_i hp <;> split <;> rename_i hh <;> try rfl
rw [DistinctKeys.def] at hl₂
have := List.rel_of_pairwise_cons hl₂ (List.mem_cons_self _ _)
simp [BEq.trans hh (BEq.symm hp)] at this
theorem getEntry?_insertList [BEq α] [EquivBEq α]
{l toInsert : List ((a : α) × β a)}
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false)) (k : α) :
getEntry? k (insertList l toInsert) = (getEntry? k toInsert).or (getEntry? k l) := by
induction toInsert generalizing l with
| nil => simp [insertList]
| cons h t ih =>
rw [getEntry?_of_perm distinct_l.insertList
(insertList_cons_perm distinct_l (DistinctKeys.def.2 distinct_toInsert)),
getEntry?_insertEntry]
cases hk : h.1 == k
· simp only [Bool.false_eq_true, reduceIte]
rw [ih distinct_l distinct_toInsert.tail, getEntry?_cons_of_false hk]
· simp only [reduceIte]
rw [getEntry?_cons_of_true hk, Option.some_or]
theorem getEntry?_insertList_of_contains_eq_false [BEq α] [PartialEquivBEq α]
{l toInsert : List ((a : α) × β a)} {k : α}
(not_contains : containsKey k toInsert = false) :
getEntry? k (insertList l toInsert) = getEntry? k l := by
induction toInsert generalizing l with
| nil => simp [insertList]
| cons h t ih =>
unfold insertList
rw [containsKey_cons_eq_false] at not_contains
rw [ih not_contains.right, getEntry?_insertEntry]
simp [not_contains]
theorem getEntry?_insertList_of_contains_eq_true [BEq α] [EquivBEq α]
{l toInsert : List ((a : α) × β a)} {k : α}
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(contains : containsKey k toInsert = true) :
getEntry? k (insertList l toInsert) = getEntry? k toInsert := by
rw [getEntry?_insertList distinct_l distinct_toInsert]
rw [containsKey_eq_isSome_getEntry?] at contains
exact Option.or_of_isSome contains
theorem containsKey_insertList [BEq α] [PartialEquivBEq α] {l toInsert : List ((a : α) × β a)}
{k : α} : containsKey k (List.insertList l toInsert) =
(containsKey k l || (toInsert.map Sigma.fst).contains k) := by
induction toInsert generalizing l with
| nil => simp only [insertList, List.map_nil, List.elem_nil, Bool.or_false]
| cons hd tl ih =>
unfold insertList
rw [ih]
rw [containsKey_insertEntry]
simp only [Bool.or_eq_true, List.map_cons, List.contains_cons]
rw [BEq.comm]
conv => left; left; rw [Bool.or_comm]
rw [Bool.or_assoc]
theorem containsKey_of_containsKey_insertList [BEq α] [PartialEquivBEq α]
{l toInsert : List ((a : α) × β a)} {k : α} (h₁ : containsKey k (insertList l toInsert))
(h₂ : (toInsert.map Sigma.fst).contains k = false) : containsKey k l := by
rw [containsKey_insertList, h₂] at h₁; simp at h₁; exact h₁
theorem getValueCast?_insertList_of_contains_eq_false [BEq α] [LawfulBEq α]
{l toInsert : List ((a : α) × β a)} {k : α}
(not_contains : (toInsert.map Sigma.fst).contains k = false) :
getValueCast? k (insertList l toInsert) = getValueCast? k l := by
rw [ containsKey_eq_contains_map_fst] at not_contains
rw [getValueCast?_eq_getEntry?, getValueCast?_eq_getEntry?]
apply Option.dmap_congr
rw [getEntry?_insertList_of_contains_eq_false not_contains]
theorem getValueCast?_insertList_of_mem [BEq α] [LawfulBEq α]
{l toInsert : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k') {v : β k}
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v toInsert) :
getValueCast? k' (insertList l toInsert) =
some (cast (by congr; exact LawfulBEq.eq_of_beq k_beq) v) := by
rw [getValueCast?_eq_getEntry?]
have : getEntry? k' (insertList l toInsert) = getEntry? k' toInsert := by
apply getEntry?_insertList_of_contains_eq_true distinct_l distinct_toInsert
apply containsKey_of_beq _ k_beq
exact containsKey_of_mem mem
rw [ DistinctKeys.def] at distinct_toInsert
rw [getEntry?_of_mem distinct_toInsert k_beq mem] at this
rw [Option.dmap_congr this]
simp
theorem getValueCast_insertList_of_contains_eq_false [BEq α] [LawfulBEq α]
{l toInsert : List ((a : α) × β a)} {k : α}
(not_contains : (toInsert.map Sigma.fst).contains k = false)
{h} :
getValueCast k (insertList l toInsert) h =
getValueCast k l (containsKey_of_containsKey_insertList h not_contains) := by
rw [ Option.some_inj, getValueCast?_eq_some_getValueCast, getValueCast?_eq_some_getValueCast,
getValueCast?_insertList_of_contains_eq_false]
exact not_contains
theorem getValueCast_insertList_of_mem [BEq α] [LawfulBEq α]
{l toInsert : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k') (v : β k)
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v toInsert)
{h} :
getValueCast k' (insertList l toInsert) h =
cast (by congr; exact LawfulBEq.eq_of_beq k_beq) v := by
rw [ Option.some_inj, getValueCast?_eq_some_getValueCast,
getValueCast?_insertList_of_mem k_beq distinct_l distinct_toInsert mem]
theorem getValueCast!_insertList_of_contains_eq_false [BEq α] [LawfulBEq α]
{l toInsert : List ((a : α) × β a)} {k : α} [Inhabited (β k)]
(not_contains : (toInsert.map Sigma.fst).contains k = false) :
getValueCast! k (insertList l toInsert) = getValueCast! k l := by
rw [getValueCast!_eq_getValueCast?, getValueCast!_eq_getValueCast?,
getValueCast?_insertList_of_contains_eq_false not_contains]
theorem getValueCast!_insertList_of_mem [BEq α] [LawfulBEq α]
{l toInsert : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k') (v : β k) [Inhabited (β k')]
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v toInsert) :
getValueCast! k' (insertList l toInsert) =
cast (by congr; exact LawfulBEq.eq_of_beq k_beq) v := by
rw [getValueCast!_eq_getValueCast?,
getValueCast?_insertList_of_mem k_beq distinct_l distinct_toInsert mem, Option.get!_some]
theorem getValueCastD_insertList_of_contains_eq_false [BEq α] [LawfulBEq α]
{l toInsert : List ((a : α) × β a)} {k : α} {fallback : β k}
(not_mem : (toInsert.map Sigma.fst).contains k = false) :
getValueCastD k (insertList l toInsert) fallback = getValueCastD k l fallback := by
rw [getValueCastD_eq_getValueCast?, getValueCastD_eq_getValueCast?,
getValueCast?_insertList_of_contains_eq_false not_mem]
theorem getValueCastD_insertList_of_mem [BEq α] [LawfulBEq α]
{l toInsert : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k') {v : β k} {fallback : β k'}
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v toInsert) :
getValueCastD k' (insertList l toInsert) fallback =
cast (by congr; exact LawfulBEq.eq_of_beq k_beq) v := by
rw [getValueCastD_eq_getValueCast?,
getValueCast?_insertList_of_mem k_beq distinct_l distinct_toInsert mem, Option.getD_some]
theorem getKey?_insertList_of_contains_eq_false [BEq α] [EquivBEq α]
{l toInsert : List ((a : α) × β a)} {k : α}
(not_contains : (toInsert.map Sigma.fst).contains k = false) :
getKey? k (insertList l toInsert) = getKey? k l := by
rw [ containsKey_eq_contains_map_fst] at not_contains
rw [getKey?_eq_getEntry?, getKey?_eq_getEntry?,
getEntry?_insertList_of_contains_eq_false not_contains]
theorem getKey?_insertList_of_mem [BEq α] [EquivBEq α]
{l toInsert : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k toInsert.map Sigma.fst) :
getKey? k' (insertList l toInsert) = some k := by
rcases List.mem_map.1 mem with k, v, pair_mem, rfl
rw [getKey?_eq_getEntry?, getEntry?_insertList distinct_l distinct_toInsert,
getEntry?_of_mem (DistinctKeys.def.2 distinct_toInsert) k_beq pair_mem, Option.some_or,
Option.map_some']
theorem getKey_insertList_of_contains_eq_false [BEq α] [EquivBEq α]
{l toInsert : List ((a : α) × β a)} {k : α}
(not_contains : (toInsert.map Sigma.fst).contains k = false)
{h} :
getKey k (insertList l toInsert) h =
getKey k l (containsKey_of_containsKey_insertList h not_contains) := by
rw [ Option.some_inj, getKey?_eq_some_getKey,
getKey?_insertList_of_contains_eq_false not_contains, getKey?_eq_some_getKey]
theorem getKey_insertList_of_mem [BEq α] [EquivBEq α]
{l toInsert : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k toInsert.map Sigma.fst)
{h} :
getKey k' (insertList l toInsert) h = k := by
rw [ Option.some_inj, getKey?_eq_some_getKey,
getKey?_insertList_of_mem k_beq distinct_l distinct_toInsert mem]
theorem getKey!_insertList_of_contains_eq_false [BEq α] [EquivBEq α] [Inhabited α]
{l toInsert : List ((a : α) × β a)} {k : α}
(contains_false : (toInsert.map Sigma.fst).contains k = false) :
getKey! k (insertList l toInsert) = getKey! k l := by
rw [getKey!_eq_getKey?, getKey?_insertList_of_contains_eq_false contains_false, getKey!_eq_getKey?]
theorem getKey!_insertList_of_mem [BEq α] [EquivBEq α] [Inhabited α]
{l toInsert : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k toInsert.map Sigma.fst) :
getKey! k' (insertList l toInsert) = k := by
rw [getKey!_eq_getKey?, getKey?_insertList_of_mem k_beq distinct_l distinct_toInsert mem,
Option.get!_some]
theorem getKeyD_insertList_of_contains_eq_false [BEq α] [EquivBEq α]
{l toInsert : List ((a : α) × β a)} {k fallback : α}
(not_contains : (toInsert.map Sigma.fst).contains k = false) :
getKeyD k (insertList l toInsert) fallback = getKeyD k l fallback := by
rw [getKeyD_eq_getKey?, getKey?_insertList_of_contains_eq_false not_contains, getKeyD_eq_getKey?]
theorem getKeyD_insertList_of_mem [BEq α] [EquivBEq α]
{l toInsert : List ((a : α) × β a)}
{k k' fallback : α} (k_beq : k == k')
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k toInsert.map Sigma.fst) :
getKeyD k' (insertList l toInsert) fallback = k := by
rw [getKeyD_eq_getKey?, getKey?_insertList_of_mem k_beq distinct_l distinct_toInsert mem,
Option.getD_some]
theorem perm_insertList [BEq α] [EquivBEq α]
{l toInsert : List ((a : α) × β a)}
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(distinct_both : (a : α), containsKey a l (toInsert.map Sigma.fst).contains a = false) :
Perm (insertList l toInsert) (l ++ toInsert) := by
rw [ DistinctKeys.def] at distinct_toInsert
induction toInsert generalizing l with
| nil => simp only [insertList, List.append_nil, Perm.refl]
| cons hd tl ih =>
simp only [List.map_cons, List.contains_cons, Bool.or_eq_false_iff] at distinct_both
refine (insertList_cons_perm distinct_l distinct_toInsert).trans ?_
rw [insertEntry_of_containsKey_eq_false]
· refine (Perm.cons _ (ih distinct_l (distinct_toInsert).tail ?_)).trans List.perm_middle.symm
exact fun a ha => (distinct_both a ha).2
· simp only [containsKey_insertList, Bool.or_eq_false_iff, containsKey_eq_contains_map_fst]
refine Bool.not_eq_true _ fun h => ?_, distinct_toInsert.containsKey_eq_false
simpa using (distinct_both _ h).1
theorem length_insertList [BEq α] [EquivBEq α]
{l toInsert : List ((a : α) × β a)}
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(distinct_both : (a : α), containsKey a l (toInsert.map Sigma.fst).contains a = false) :
(insertList l toInsert).length = l.length + toInsert.length := by
simpa using (perm_insertList distinct_l distinct_toInsert distinct_both).length_eq
theorem length_le_length_insertList [BEq α]
{l toInsert : List ((a : α) × β a)} :
l.length (insertList l toInsert).length := by
induction toInsert generalizing l with
| nil => apply Nat.le_refl
| cons hd tl ih => exact Nat.le_trans length_le_length_insertEntry ih
theorem length_insertList_le [BEq α]
{l toInsert : List ((a : α) × β a)} :
(insertList l toInsert).length l.length + toInsert.length := by
induction toInsert generalizing l with
| nil => simp only [insertList, List.length_nil, Nat.add_zero, Nat.le_refl]
| cons hd tl ih =>
simp only [insertList, List.length_cons]
apply Nat.le_trans ih
rw [Nat.add_comm tl.length 1, Nat.add_assoc]
apply Nat.add_le_add length_insertEntry_le (Nat.le_refl _)
theorem isEmpty_insertList [BEq α]
{l toInsert : List ((a : α) × β a)} :
(List.insertList l toInsert).isEmpty = (l.isEmpty && toInsert.isEmpty) := by
induction toInsert generalizing l with
| nil => simp [insertList]
| cons hd tl ih =>
rw [insertList, List.isEmpty_cons, ih, isEmpty_insertEntry]
simp
section
variable {β : Type v}
/-- Internal implementation detail of the hash map -/
def Prod.toSigma (p : α × β) : ((_ : α) × β) := p.fst, p.snd
@[simp]
theorem Prod.fst_comp_toSigma :
Sigma.fst Prod.toSigma = @Prod.fst α β := by
apply funext
simp [Prod.toSigma]
/-- Internal implementation detail of the hash map -/
def insertListConst [BEq α] (l : List ((_ : α) × β)) (toInsert : List (α × β)) : List ((_ : α) × β) :=
insertList l (toInsert.map Prod.toSigma)
theorem containsKey_insertListConst [BEq α] [PartialEquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} {k : α} :
containsKey k (insertListConst l toInsert) =
(containsKey k l || (toInsert.map Prod.fst).contains k) := by
unfold insertListConst
rw [containsKey_insertList]
simp
theorem containsKey_of_containsKey_insertListConst [BEq α] [PartialEquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} {k : α}
(h₁ : containsKey k (insertListConst l toInsert))
(h₂ : (toInsert.map Prod.fst).contains k = false) : containsKey k l := by
unfold insertListConst at h₁
apply containsKey_of_containsKey_insertList h₁
simpa
theorem getKey?_insertListConst_of_contains_eq_false [BEq α] [EquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} {k : α}
(not_contains : (toInsert.map Prod.fst).contains k = false) :
getKey? k (insertListConst l toInsert) = getKey? k l := by
unfold insertListConst
apply getKey?_insertList_of_contains_eq_false
simpa
theorem getKey?_insertListConst_of_mem [BEq α] [EquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k toInsert.map Prod.fst) :
getKey? k' (insertListConst l toInsert) = some k := by
unfold insertListConst
apply getKey?_insertList_of_mem k_beq distinct_l
· simpa [List.pairwise_map]
· simp only [List.map_map, Prod.fst_comp_toSigma]
exact mem
theorem getKey_insertListConst_of_contains_eq_false [BEq α] [EquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} {k : α}
(not_contains : (toInsert.map Prod.fst).contains k = false)
{h} :
getKey k (insertListConst l toInsert) h =
getKey k l (containsKey_of_containsKey_insertListConst h not_contains) := by
rw [ Option.some_inj, getKey?_eq_some_getKey,
getKey?_insertListConst_of_contains_eq_false not_contains, getKey?_eq_some_getKey]
theorem getKey_insertListConst_of_mem [BEq α] [EquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k toInsert.map Prod.fst)
{h} :
getKey k' (insertListConst l toInsert) h = k := by
rw [ Option.some_inj, getKey?_eq_some_getKey,
getKey?_insertListConst_of_mem k_beq distinct_l distinct_toInsert mem]
theorem getKey!_insertListConst_of_contains_eq_false [BEq α] [EquivBEq α] [Inhabited α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} {k : α}
(not_contains : (toInsert.map Prod.fst).contains k = false) :
getKey! k (insertListConst l toInsert) = getKey! k l := by
rw [getKey!_eq_getKey?, getKey?_insertListConst_of_contains_eq_false not_contains,
getKey!_eq_getKey?]
theorem getKey!_insertListConst_of_mem [BEq α] [EquivBEq α] [Inhabited α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k toInsert.map Prod.fst) :
getKey! k' (insertListConst l toInsert) = k := by
rw [getKey!_eq_getKey?, getKey?_insertListConst_of_mem k_beq distinct_l distinct_toInsert mem,
Option.get!_some]
theorem getKeyD_insertListConst_of_contains_eq_false [BEq α] [EquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} {k fallback : α}
(not_contains : (toInsert.map Prod.fst).contains k = false) :
getKeyD k (insertListConst l toInsert) fallback = getKeyD k l fallback := by
rw [getKeyD_eq_getKey?, getKey?_insertListConst_of_contains_eq_false not_contains,
getKeyD_eq_getKey?]
theorem getKeyD_insertListConst_of_mem [BEq α] [EquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)}
{k k' fallback : α} (k_beq : k == k')
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k toInsert.map Prod.fst) :
getKeyD k' (insertListConst l toInsert) fallback = k := by
rw [getKeyD_eq_getKey?, getKey?_insertListConst_of_mem k_beq distinct_l distinct_toInsert mem,
Option.getD_some]
theorem length_insertListConst [BEq α] [EquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)}
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(distinct_both : (a : α), containsKey a l (toInsert.map Prod.fst).contains a = false) :
(insertListConst l toInsert).length = l.length + toInsert.length := by
unfold insertListConst
rw [length_insertList distinct_l]
· simp
· simpa [List.pairwise_map]
· simpa using distinct_both
theorem length_le_length_insertListConst [BEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} :
l.length (insertListConst l toInsert).length := by
induction toInsert generalizing l with
| nil => apply Nat.le_refl
| cons hd tl ih => exact Nat.le_trans length_le_length_insertEntry ih
theorem length_insertListConst_le [BEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} :
(insertListConst l toInsert).length l.length + toInsert.length := by
unfold insertListConst
rw [ List.length_map toInsert Prod.toSigma]
apply length_insertList_le
theorem isEmpty_insertListConst [BEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} :
(List.insertListConst l toInsert).isEmpty = (l.isEmpty && toInsert.isEmpty) := by
unfold insertListConst
rw [isEmpty_insertList, Bool.eq_iff_iff]
simp
theorem getValue?_insertListConst_of_contains_eq_false [BEq α] [PartialEquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} {k : α}
(not_contains : (toInsert.map Prod.fst).contains k = false) :
getValue? k (insertListConst l toInsert) = getValue? k l := by
unfold insertListConst
rw [getValue?_eq_getEntry?, getValue?_eq_getEntry?, getEntry?_insertList_of_contains_eq_false]
rw [containsKey_eq_contains_map_fst]
simpa
theorem getValue?_insertListConst_of_mem [BEq α] [EquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)}
{k k' : α} (k_beq : k == k') {v : β}
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v toInsert) :
getValue? k' (insertListConst l toInsert) = v := by
unfold insertListConst
rw [getValue?_eq_getEntry?]
have : getEntry? k' (insertList l (toInsert.map Prod.toSigma)) =
getEntry? k' (toInsert.map Prod.toSigma) := by
apply getEntry?_insertList_of_contains_eq_true distinct_l (by simpa [List.pairwise_map])
apply containsKey_of_beq _ k_beq
rw [containsKey_eq_contains_map_fst, List.map_map, Prod.fst_comp_toSigma,
List.contains_iff_exists_mem_beq]
exists k
rw [List.mem_map]
constructor
. exists k, v
. simp
rw [this]
rw [getEntry?_of_mem _ k_beq _]
. rfl
· simpa [DistinctKeys.def, List.pairwise_map]
. simp only [List.mem_map]
exists (k, v)
theorem getValue_insertListConst_of_contains_eq_false [BEq α] [PartialEquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} {k : α}
{not_contains : (toInsert.map Prod.fst).contains k = false}
{h} :
getValue k (insertListConst l toInsert) h =
getValue k l (containsKey_of_containsKey_insertListConst h not_contains) := by
rw [ Option.some_inj, getValue?_eq_some_getValue, getValue?_eq_some_getValue,
getValue?_insertListConst_of_contains_eq_false not_contains]
theorem getValue_insertListConst_of_mem [BEq α] [EquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)}
{k k' : α} (k_beq : k == k') {v : β}
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v toInsert)
{h} :
getValue k' (insertListConst l toInsert) h = v := by
rw [ Option.some_inj, getValue?_eq_some_getValue,
getValue?_insertListConst_of_mem k_beq distinct_l distinct_toInsert mem]
theorem getValue!_insertListConst_of_contains_eq_false [BEq α] [PartialEquivBEq α] [Inhabited β]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} {k : α}
(not_contains : (toInsert.map Prod.fst).contains k = false) :
getValue! k (insertListConst l toInsert) = getValue! k l := by
simp only [getValue!_eq_getValue?]
rw [getValue?_insertListConst_of_contains_eq_false not_contains]
theorem getValue!_insertListConst_of_mem [BEq α] [EquivBEq α] [Inhabited β]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} {k k' : α} {v: β} (k_beq : k == k')
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v toInsert):
getValue! k' (insertListConst l toInsert) = v := by
rw [getValue!_eq_getValue?,
getValue?_insertListConst_of_mem k_beq distinct_l distinct_toInsert mem, Option.get!_some]
theorem getValueD_insertListConst_of_contains_eq_false [BEq α] [PartialEquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} {k : α} {fallback : β}
(not_contains : (toInsert.map Prod.fst).contains k = false) :
getValueD k (insertListConst l toInsert) fallback = getValueD k l fallback := by
simp only [getValueD_eq_getValue?]
rw [getValue?_insertListConst_of_contains_eq_false not_contains]
theorem getValueD_insertListConst_of_mem [BEq α] [EquivBEq α]
{l : List ((_ : α) × β)} {toInsert : List (α × β)} {k k' : α} {v fallback: β} (k_beq : k == k')
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v toInsert):
getValueD k' (insertListConst l toInsert) fallback= v := by
simp only [getValueD_eq_getValue?]
rw [getValue?_insertListConst_of_mem k_beq distinct_l distinct_toInsert mem, Option.getD_some]
/-- Internal implementation detail of the hash map -/
def insertListIfNewUnit [BEq α] (l: List ((_ : α) × Unit)) (toInsert: List α) :
List ((_ : α) × Unit) :=
match toInsert with
| .nil => l
| .cons hd tl => insertListIfNewUnit (insertEntryIfNew hd () l) tl
theorem insertListIfNewUnit_perm_of_perm_first [BEq α] [EquivBEq α] {l1 l2 : List ((_ : α) × Unit)}
{toInsert : List α } (h : Perm l1 l2) (distinct : DistinctKeys l1) :
Perm (insertListIfNewUnit l1 toInsert) (insertListIfNewUnit l2 toInsert) := by
induction toInsert generalizing l1 l2 with
| nil => simp [insertListIfNewUnit, h]
| cons hd tl ih =>
simp only [insertListIfNewUnit]
apply ih
· simp only [insertEntryIfNew, cond_eq_if]
have contains_eq : containsKey hd l1 = containsKey hd l2 := containsKey_of_perm h
rw [contains_eq]
by_cases contains_hd: containsKey hd l2 = true
· simp only [contains_hd, reduceIte]
exact h
· simp only [contains_hd, Bool.false_eq_true, reduceIte, List.perm_cons]
exact h
· apply DistinctKeys.insertEntryIfNew distinct
theorem DistinctKeys.insertListIfNewUnit [BEq α] [PartialEquivBEq α] {l : List ((_ : α) × Unit)}
{toInsert : List α} (distinct: DistinctKeys l):
DistinctKeys (insertListIfNewUnit l toInsert) := by
induction toInsert generalizing l with
| nil => simp [List.insertListIfNewUnit, distinct]
| cons hd tl ih =>
simp only [List.insertListIfNewUnit]
apply ih (insertEntryIfNew distinct)
theorem getEntry?_insertListIfNewUnit [BEq α] [PartialEquivBEq α] {l : List ((_ : α) × Unit)}
{toInsert : List α} {k : α} :
getEntry? k (insertListIfNewUnit l toInsert) =
(getEntry? k l).or (getEntry? k (toInsert.map (·, ()))) := by
induction toInsert generalizing l with
| nil => simp [insertListIfNewUnit]
| cons hd tl ih =>
simp only [insertListIfNewUnit, ih, getEntry?_insertEntryIfNew, List.map_cons,
getEntry?_cons]
cases hhd : hd == k
· simp
· cases hc : containsKey hd l
· simp only [Bool.not_false, Bool.and_self, reduceIte, Option.some_or, cond_true,
Option.or_some', Option.some.injEq]
rw [getEntry?_eq_none.2, Option.getD_none]
rwa [ containsKey_congr hhd]
· simp only [Bool.not_true, Bool.and_false, Bool.false_eq_true, reduceIte, cond_true,
Option.or_some', getEntry?_eq_none]
rw [containsKey_congr hhd, containsKey_eq_isSome_getEntry?] at hc
obtain v, hv := Option.isSome_iff_exists.1 hc
simp [hv]
theorem DistinctKeys.mapUnit [BEq α]
{l : List α} (distinct: l.Pairwise (fun a b => (a == b) = false)) :
DistinctKeys (l.map (·, ())) := by
rw [DistinctKeys.def]
refine List.Pairwise.map ?_ ?_ distinct
simp
theorem getEntry?_insertListIfNewUnit_of_contains_eq_false [BEq α] [PartialEquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α } {k : α}
(not_contains : toInsert.contains k = false) :
getEntry? k (insertListIfNewUnit l toInsert) = getEntry? k l := by
induction toInsert generalizing l with
| nil => simp [insertListIfNewUnit]
| cons h t ih =>
unfold insertListIfNewUnit
simp only [List.contains_cons, Bool.or_eq_false_iff] at not_contains
rw [ih not_contains.right, getEntry?_insertEntryIfNew]
simp only [Bool.and_eq_true, Bool.not_eq_eq_eq_not, Bool.not_true, ite_eq_right_iff, and_imp]
intro h'
rw [BEq.comm, And.left not_contains] at h'
simp at h'
theorem containsKey_insertListIfNewUnit [BEq α] [PartialEquivBEq α] {l : List ((_ : α) × Unit)}
{toInsert : List α} {k : α} :
containsKey k (insertListIfNewUnit l toInsert) = (containsKey k l || toInsert.contains k) := by
induction toInsert generalizing l with
| nil => simp [insertListIfNewUnit]
| cons hd tl ih =>
simp only [insertListIfNewUnit, List.contains_cons]
rw [ih, containsKey_insertEntryIfNew]
rw [Bool.or_comm (hd == k), Bool.or_assoc, BEq.comm (a:=hd)]
theorem containsKey_of_containsKey_insertListIfNewUnit [BEq α] [PartialEquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α} {k : α}
(h₂ : toInsert.contains k = false) : containsKey k (insertListIfNewUnit l toInsert)
containsKey k l := by
intro h₁
rw [containsKey_insertListIfNewUnit, h₂] at h₁; simp at h₁; exact h₁
theorem getKey?_insertListIfNewUnit_of_contains_eq_false_of_contains_eq_false [BEq α] [EquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α} {k : α}
(h': containsKey k l = false) (h : toInsert.contains k = false) :
getKey? k (insertListIfNewUnit l toInsert) = none := by
rw [getKey?_eq_getEntry?,
getEntry?_insertListIfNewUnit_of_contains_eq_false h, Option.map_eq_none', getEntry?_eq_none]
exact h'
theorem getKey?_insertListIfNewUnit_of_contains_eq_false_of_mem [BEq α] [EquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α}
{k k' : α} (k_beq : k == k')
(mem' : containsKey k l = false)
(distinct : toInsert.Pairwise (fun a b => (a == b) = false)) (mem : k toInsert):
getKey? k' (insertListIfNewUnit l toInsert) = some k := by
simp only [getKey?_eq_getEntry?, getEntry?_insertListIfNewUnit, Option.map_eq_some',
Option.or_eq_some, getEntry?_eq_none]
exists k, ()
simp only [and_true]
right
constructor
· rw [containsKey_congr k_beq] at mem'
exact mem'
· apply getEntry?_of_mem (DistinctKeys.mapUnit distinct) k_beq
simp only [List.mem_map]
exists k
theorem getKey?_insertListIfNewUnit_of_contains [BEq α] [EquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α}
{k : α}
(h : containsKey k l = true):
getKey? k (insertListIfNewUnit l toInsert) = getKey? k l := by
rw [containsKey_eq_isSome_getEntry?] at h
simp [getKey?_eq_getEntry?, getEntry?_insertListIfNewUnit, Option.or_of_isSome h]
theorem getKey_insertListIfNewUnit_of_contains_eq_false_of_mem [BEq α] [EquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α}
{k k' : α} (k_beq : k == k')
{h} (contains_eq_false : containsKey k l = false)
(distinct : toInsert.Pairwise (fun a b => (a == b) = false))
(mem : k toInsert) :
getKey k' (insertListIfNewUnit l toInsert) h = k := by
rw [ Option.some_inj, getKey?_eq_some_getKey,
getKey?_insertListIfNewUnit_of_contains_eq_false_of_mem k_beq contains_eq_false distinct mem]
theorem getKey_insertListIfNewUnit_of_contains [BEq α] [EquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α}
{k : α}
(contains : containsKey k l = true) {h}:
getKey k (insertListIfNewUnit l toInsert) h = getKey k l contains := by
rw [ Option.some_inj, getKey?_eq_some_getKey, getKey?_eq_some_getKey,
getKey?_insertListIfNewUnit_of_contains contains]
theorem getKey!_insertListIfNewUnit_of_contains_eq_false_of_contains_eq_false [BEq α] [EquivBEq α]
[Inhabited α] {l : List ((_ : α) × Unit)} {toInsert : List α} {k : α}
(contains_eq_false : containsKey k l = false)
(contains_eq_false' : toInsert.contains k = false) :
getKey! k (insertListIfNewUnit l toInsert) = default := by
rw [getKey!_eq_getKey?, getKey?_insertListIfNewUnit_of_contains_eq_false_of_contains_eq_false
contains_eq_false contains_eq_false']
simp
theorem getKey!_insertListIfNewUnit_of_contains_eq_false_of_mem [BEq α] [EquivBEq α] [Inhabited α]
{l : List ((_ : α) × Unit)} {toInsert : List α}
{k k' : α} (k_beq : k == k')
(h : containsKey k l = false)
(distinct : toInsert.Pairwise (fun a b => (a == b) = false)) (mem : k toInsert) :
getKey! k' (insertListIfNewUnit l toInsert) = k := by
rw [getKey!_eq_getKey?,
getKey?_insertListIfNewUnit_of_contains_eq_false_of_mem k_beq h distinct mem, Option.get!_some]
theorem getKey!_insertListIfNewUnit_of_contains [BEq α] [EquivBEq α] [Inhabited α]
{l : List ((_ : α) × Unit)} {toInsert : List α}
{k : α}
(h : containsKey k l = true) :
getKey! k (insertListIfNewUnit l toInsert) = getKey! k l := by
rw [getKey!_eq_getKey?, getKey?_insertListIfNewUnit_of_contains h, getKey!_eq_getKey?]
theorem getKeyD_insertListIfNewUnit_of_contains_eq_false_of_contains_eq_false [BEq α] [EquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α} {k fallback : α}
(contains_eq_false : containsKey k l = false) (contains_eq_false' : toInsert.contains k = false) :
getKeyD k (insertListIfNewUnit l toInsert) fallback = fallback := by
rw [getKeyD_eq_getKey?, getKey?_insertListIfNewUnit_of_contains_eq_false_of_contains_eq_false
contains_eq_false contains_eq_false']
simp
theorem getKeyD_insertListIfNewUnit_of_contains_eq_false_of_mem [BEq α] [EquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α}
{k k' fallback : α} (k_beq : k == k')
(h : containsKey k l = false)
(distinct : toInsert.Pairwise (fun a b => (a == b) = false)) (mem : k toInsert) :
getKeyD k' (insertListIfNewUnit l toInsert) fallback = k := by
rw [getKeyD_eq_getKey?, getKey?_insertListIfNewUnit_of_contains_eq_false_of_mem k_beq h
distinct mem, Option.getD_some]
theorem getKeyD_insertListIfNewUnit_of_contains [BEq α] [EquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α}
{k fallback : α}
(contains : containsKey k l = true) :
getKeyD k (insertListIfNewUnit l toInsert) fallback = getKeyD k l fallback := by
rw [getKeyD_eq_getKey?,
getKey?_insertListIfNewUnit_of_contains contains, getKeyD_eq_getKey?]
theorem length_insertListIfNewUnit [BEq α] [EquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α}
(distinct_l : DistinctKeys l)
(distinct_toInsert : toInsert.Pairwise (fun a b => (a == b) = false))
(distinct_both : (a : α), containsKey a l toInsert.contains a = false) :
(insertListIfNewUnit l toInsert).length = l.length + toInsert.length := by
induction toInsert generalizing l with
| nil => simp [insertListIfNewUnit]
| cons hd tl ih =>
simp only [insertListIfNewUnit, List.length_cons]
rw [ih]
· rw [length_insertEntryIfNew]
specialize distinct_both hd
simp only [List.contains_cons, BEq.refl, Bool.true_or, and_true,
Bool.not_eq_true] at distinct_both
cases eq : containsKey hd l with
| true => simp [eq] at distinct_both
| false =>
simp only [Bool.false_eq_true, reduceIte]
rw [Nat.add_assoc, Nat.add_comm 1 _]
· apply DistinctKeys.insertEntryIfNew distinct_l
· simp only [pairwise_cons] at distinct_toInsert
apply And.right distinct_toInsert
· intro a
simp only [List.contains_cons, Bool.or_eq_true, not_and, not_or,
Bool.not_eq_true] at distinct_both
rw [containsKey_insertEntryIfNew]
simp only [Bool.or_eq_true]
intro h
cases h with
| inl h =>
simp only [pairwise_cons] at distinct_toInsert
rw [List.contains_eq_any_beq]
simp only [List.any_eq_false, Bool.not_eq_true]
intro x x_mem
rcases distinct_toInsert with left,_
specialize left x x_mem
apply BEq.neq_of_beq_of_neq
apply BEq.symm h
exact left
| inr h =>
specialize distinct_both a h
rw [Bool.or_eq_false_iff] at distinct_both
apply And.right distinct_both
theorem length_le_length_insertListIfNewUnit [BEq α] [EquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α}:
l.length (insertListIfNewUnit l toInsert).length := by
induction toInsert generalizing l with
| nil => apply Nat.le_refl
| cons hd tl ih => exact Nat.le_trans length_le_length_insertEntryIfNew ih
theorem length_insertListIfNewUnit_le [BEq α] [EquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α}:
(insertListIfNewUnit l toInsert).length l.length + toInsert.length := by
induction toInsert generalizing l with
| nil => simp only [insertListIfNewUnit, List.length_nil, Nat.add_zero, Nat.le_refl]
| cons hd tl ih =>
simp only [insertListIfNewUnit, List.length_cons]
apply Nat.le_trans ih
rw [Nat.add_comm tl.length 1, Nat.add_assoc]
apply Nat.add_le_add _ (Nat.le_refl _)
apply length_insertEntryIfNew_le
theorem isEmpty_insertListIfNewUnit [BEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α} :
(List.insertListIfNewUnit l toInsert).isEmpty = (l.isEmpty && toInsert.isEmpty) := by
induction toInsert generalizing l with
| nil => simp [insertListIfNewUnit]
| cons hd tl ih =>
rw [insertListIfNewUnit, List.isEmpty_cons, ih, isEmpty_insertEntryIfNew]
simp
theorem getValue?_list_unit [BEq α] {l : List ((_ : α) × Unit)} {k : α}:
getValue? k l = if containsKey k l = true then some () else none := by
induction l with
| nil => simp
| cons hd tl ih =>
simp only [getValue?, containsKey, Bool.or_eq_true, Bool.cond_eq_ite_iff]
by_cases hd_k: (hd.fst == k) = true
· simp [hd_k]
· simp [hd_k, ih]
theorem getValue?_insertListIfNewUnit [BEq α] [PartialEquivBEq α]
{l : List ((_ : α) × Unit)} {toInsert : List α} {k : α}:
getValue? k (insertListIfNewUnit l toInsert) =
if containsKey k l toInsert.contains k then some () else none := by
simp [containsKey_insertListIfNewUnit, getValue?_list_unit]
end
/-- Internal implementation detail of the hash map -/
def alterKey [BEq α] [LawfulBEq α] (k : α) (f : Option (β k) Option (β k))
(l : List ((a : α) × β a)) : List ((a : α) × β a) :=

View File

@@ -201,7 +201,7 @@ theorem toListModel_updateAllBuckets {m : Raw₀ α β} {f : AssocList α β →
omega
rw [updateAllBuckets, toListModel, Array.toList_map, List.flatMap_eq_foldl, List.foldl_map,
toListModel, List.flatMap_eq_foldl]
suffices (l : List (AssocList α β)) (l' : List ((a: α) × δ a)) (l'' : List ((a : α) × β a)),
suffices (l : List (AssocList α β)) (l' : List ((a : α) × δ a)) (l'' : List ((a : α) × β a)),
Perm (g l'') l'
Perm (l.foldl (fun acc a => acc ++ (f a).toList) l')
(g (l.foldl (fun acc a => acc ++ a.toList) l'')) by
@@ -378,6 +378,12 @@ def mapₘ (m : Raw₀ α β) (f : (a : α) → β a → δ a) : Raw₀ α δ :=
def filterₘ (m : Raw₀ α β) (f : (a : α) β a Bool) : Raw₀ α β :=
withComputedSize (updateAllBuckets m.1.buckets fun l => l.filter f), by simpa using m.2
/-- Internal implementation detail of the hash map -/
def insertListₘ [BEq α] [Hashable α] (m : Raw₀ α β) (l : List ((a : α) × β a)) : Raw₀ α β :=
match l with
| .nil => m
| .cons hd tl => insertListₘ (m.insert hd.1 hd.2) tl
section
variable {β : Type v}
@@ -398,6 +404,20 @@ def Const.getDₘ [BEq α] [Hashable α] (m : Raw₀ α (fun _ => β)) (a : α)
def Const.get!ₘ [BEq α] [Hashable α] [Inhabited β] (m : Raw₀ α (fun _ => β)) (a : α) : β :=
(Const.get?ₘ m a).get!
/-- Internal implementation detail of the hash map -/
def Const.insertListₘ [BEq α] [Hashable α] (m : Raw₀ α (fun _ => β)) (l: List (α × β)) :
Raw₀ α (fun _ => β) :=
match l with
| .nil => m
| .cons hd tl => insertListₘ (m.insert hd.1 hd.2) tl
/-- Internal implementation detail of the hash map -/
def Const.insertListIfNewUnitₘ [BEq α] [Hashable α] (m : Raw₀ α (fun _ => Unit)) (l: List α) :
Raw₀ α (fun _ => Unit) :=
match l with
| .nil => m
| .cons hd tl => insertListIfNewUnitₘ (m.insertIfNew hd ()) tl
end
/-! # Equivalence between model functions and real implementations -/
@@ -569,6 +589,19 @@ theorem map_eq_mapₘ (m : Raw₀ α β) (f : (a : α) → β a → δ a) :
theorem filter_eq_filterₘ (m : Raw₀ α β) (f : (a : α) β a Bool) :
m.filter f = m.filterₘ f := rfl
theorem insertMany_eq_insertListₘ [BEq α] [Hashable α](m : Raw₀ α β) (l : List ((a : α) × β a)) : insertMany m l = insertListₘ m l := by
simp only [insertMany, Id.run, Id.pure_eq, Id.bind_eq, List.forIn_yield_eq_foldl]
suffices (t : { m' // (P : Raw₀ α β Prop),
( {m'' : Raw₀ α β} {a : α} {b : β a}, P m'' P (m''.insert a b)) P m P m' }),
(List.foldl (fun m' p => m'.val.insert p.1 p.2, fun P h₁ h₂ => h₁ (m'.2 _ h₁ h₂)) t l).val =
t.val.insertListₘ l from this _
intro t
induction l generalizing m with
| nil => simp [insertListₘ]
| cons hd tl ih =>
simp only [List.foldl_cons, insertListₘ]
apply ih
section
variable {β : Type v}
@@ -599,6 +632,36 @@ theorem Const.getThenInsertIfNew?_eq_get?ₘ [BEq α] [Hashable α] (m : Raw₀
dsimp only [Array.ugetElem_eq_getElem, Array.uset]
split <;> simp_all [-getValue?_eq_none]
theorem Const.insertMany_eq_insertListₘ [BEq α] [Hashable α] (m : Raw₀ α (fun _ => β))
(l: List (α × β)):
(Const.insertMany m l).1 = Const.insertListₘ m l := by
simp only [insertMany, Id.run, Id.pure_eq, Id.bind_eq, List.forIn_yield_eq_foldl]
suffices (t : { m' // (P : Raw₀ α (fun _ => β) Prop),
( {m'' : Raw₀ α (fun _ => β)} {a : α} {b : β}, P m'' P (m''.insert a b)) P m P m' }),
(List.foldl (fun m' p => m'.val.insert p.1 p.2, fun P h₁ h₂ => h₁ (m'.2 _ h₁ h₂)) t l).val =
Const.insertListₘ t.val l from this _
intro t
induction l generalizing m with
| nil => simp [insertListₘ]
| cons hd tl ih =>
simp only [List.foldl_cons, insertListₘ]
apply ih
theorem Const.insertManyIfNewUnit_eq_insertListIfNewUnitₘ [BEq α] [Hashable α]
(m : Raw₀ α (fun _ => Unit)) (l: List α):
(Const.insertManyIfNewUnit m l).1 = Const.insertListIfNewUnitₘ m l := by
simp only [insertManyIfNewUnit, Id.run, Id.pure_eq, Id.bind_eq, List.forIn_yield_eq_foldl]
suffices (t : { m' // (P : Raw₀ α (fun _ => Unit) Prop),
( {m'' a b}, P m'' P (m''.insertIfNew a b)) P m P m'}),
(List.foldl (fun m' p => m'.val.insertIfNew p (), fun P h₁ h₂ => h₁ (m'.2 _ h₁ h₂)) t l).val =
Const.insertListIfNewUnitₘ t.val l from this _
intro t
induction l generalizing m with
| nil => simp [insertListIfNewUnitₘ]
| cons hd tl ih =>
simp only [List.foldl_cons, insertListIfNewUnitₘ]
apply ih
end
end Raw₀

View File

@@ -199,10 +199,52 @@ theorem filter_val [BEq α] [Hashable α] {m : Raw₀ α β} {f : (a : α) →
m.val.filter f = m.filter f := by
simp [Raw.filter, m.2]
theorem insertMany_eq [BEq α] [Hashable α] {m : Raw α β} (h : m.WF) {ρ : Type w} [ForIn Id ρ ((a : α) × β a)] {l : ρ} :
m.insertMany l = Raw₀.insertMany m, h.size_buckets_pos l := by
simp [Raw.insertMany, h.size_buckets_pos]
theorem insertMany_val [BEq α][Hashable α] {m : Raw₀ α β} {ρ : Type w} [ForIn Id ρ ((a : α) × β a)] {l : ρ} :
m.val.insertMany l = m.insertMany l := by
simp [Raw.insertMany, m.2]
theorem ofList_eq [BEq α] [Hashable α] {l : List ((a : α) × β a)} :
Raw.ofList l = Raw₀.insertMany Raw₀.empty l := by
simp only [Raw.ofList, Raw.insertMany, (Raw.WF.empty).size_buckets_pos , reduceDIte]
congr
section
variable {β : Type v}
theorem Const.insertMany_eq [BEq α] [Hashable α] {m : Raw α (fun _ => β)} (h : m.WF) {ρ : Type w} [ForIn Id ρ (α × β)] {l : ρ} :
Raw.Const.insertMany m l = Raw₀.Const.insertMany m, h.size_buckets_pos l := by
simp [Raw.Const.insertMany, h.size_buckets_pos]
theorem Const.insertMany_val [BEq α][Hashable α] {m : Raw₀ α (fun _ => β)} {ρ : Type w} [ForIn Id ρ (α × β)] {l : ρ} :
Raw.Const.insertMany m.val l = Raw₀.Const.insertMany m l := by
simp [Raw.Const.insertMany, m.2]
theorem Const.ofList_eq [BEq α] [Hashable α] {l : List (α × β)} :
Raw.Const.ofList l = Raw₀.Const.insertMany Raw₀.empty l := by
simp only [Raw.Const.ofList, Raw.Const.insertMany, (Raw.WF.empty).size_buckets_pos , reduceDIte]
congr
theorem Const.insertManyIfNewUnit_eq {ρ : Type w} [ForIn Id ρ α] [BEq α] [Hashable α]
{m : Raw α (fun _ => Unit)} {l : ρ} (h : m.WF):
Raw.Const.insertManyIfNewUnit m l = Raw₀.Const.insertManyIfNewUnit m, h.size_buckets_pos l := by
simp [Raw.Const.insertManyIfNewUnit, h.size_buckets_pos]
theorem Const.insertManyIfNewUnit_val {ρ : Type w} [ForIn Id ρ α] [BEq α] [Hashable α]
{m : Raw₀ α (fun _ => Unit)} {l : ρ} :
Raw.Const.insertManyIfNewUnit m.val l = Raw₀.Const.insertManyIfNewUnit m l := by
simp [Raw.Const.insertManyIfNewUnit, m.2]
theorem Const.unitOfList_eq [BEq α] [Hashable α] {l : List α} :
Raw.Const.unitOfList l = Raw₀.Const.insertManyIfNewUnit Raw₀.empty l := by
simp only [Raw.Const.unitOfList, Raw.Const.insertManyIfNewUnit, (Raw.WF.empty).size_buckets_pos ,
reduceDIte]
congr
theorem Const.get?_eq [BEq α] [Hashable α] {m : Raw α (fun _ => β)} (h : m.WF) {a : α} :
Raw.Const.get? m a = Raw₀.Const.get? m, h.size_buckets_pos a := by
simp [Raw.Const.get?, h.size_buckets_pos]

View File

@@ -70,9 +70,10 @@ variable [BEq α] [Hashable α]
/-- Internal implementation detail of the hash map -/
scoped macro "wf_trivial" : tactic => `(tactic|
repeat (first
| apply Raw₀.wfImp_insert | apply Raw₀.wfImp_insertIfNew | apply Raw₀.wfImp_erase
| apply Raw.WF.out | assumption | apply Raw₀.wfImp_empty | apply Raw.WFImp.distinct
| apply Raw.WF.empty₀))
| apply Raw₀.wfImp_insert | apply Raw₀.wfImp_insertIfNew | apply Raw₀.wfImp_insertMany
| apply Raw.Const.wfImp_insertMany| apply Raw.Const.wfImp_insertManyIfNewUnit
| apply Raw.wfImp_erase | apply Raw.WF.out | assumption | apply Raw₀.wfImp_empty
| apply Raw.WFImp.distinct | apply Raw.WF.empty₀))
/-- Internal implementation detail of the hash map -/
scoped macro "empty" : tactic => `(tactic| { intros; simp_all [List.isEmpty_iff] } )
@@ -90,7 +91,9 @@ private def queryNames : Array Name :=
``Raw.pairwise_keys_iff_pairwise_keys]
private def modifyNames : Array Name :=
#[``toListModel_insert, ``toListModel_erase, ``toListModel_insertIfNew]
#[``toListModel_insert, ``toListModel_erase, ``toListModel_insertIfNew,
``toListModel_insertMany_list, ``Const.toListModel_insertMany_list,
``Const.toListModel_insertManyIfNewUnit_list]
private def congrNames : MacroM (Array (TSyntax `term)) := do
return #[ `(_root_.List.Perm.isEmpty_eq), `(containsKey_of_perm),
@@ -820,8 +823,8 @@ theorem length_keys [EquivBEq α] [LawfulHashable α] (h : m.1.WF) :
simp_to_model using List.length_keys_eq_length
@[simp]
theorem isEmpty_keys [EquivBEq α] [LawfulHashable α] (h: m.1.WF):
m.1.keys.isEmpty = m.1.isEmpty:= by
theorem isEmpty_keys [EquivBEq α] [LawfulHashable α] (h : m.1.WF) :
m.1.keys.isEmpty = m.1.isEmpty := by
simp_to_model using List.isEmpty_keys_eq_isEmpty
@[simp]
@@ -839,6 +842,884 @@ theorem distinct_keys [EquivBEq α] [LawfulHashable α] (h : m.1.WF) :
m.1.keys.Pairwise (fun a b => (a == b) = false) := by
simp_to_model using (Raw.WF.out h).distinct.distinct
@[simp]
theorem insertMany_nil :
m.insertMany [] = m := by
simp [insertMany, Id.run]
@[simp]
theorem insertMany_list_singleton {k : α} {v : β k} :
m.insertMany [k, v] = m.insert k v := by
simp [insertMany, Id.run]
theorem insertMany_cons {l : List ((a : α) × β a)} {k : α} {v : β k} :
(m.insertMany (k, v :: l)).1 = ((m.insert k v).insertMany l).1 := by
simp only [insertMany_eq_insertListₘ]
cases l with
| nil => simp [insertListₘ]
| cons hd tl => simp [insertListₘ]
@[simp]
theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List ((a : α) × β a)} {k : α} :
(m.insertMany l).1.contains k = (m.contains k || (l.map Sigma.fst).contains k) := by
simp_to_model using List.containsKey_insertList
theorem contains_of_contains_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List ((a : α) × β a)} {k : α} :
(m.insertMany l).1.contains k (l.map Sigma.fst).contains k = false m.contains k := by
simp_to_model using List.containsKey_of_containsKey_insertList
theorem get?_insertMany_list_of_contains_eq_false [LawfulBEq α] (h : m.1.WF)
{l : List ((a : α) × β a)} {k : α}
(h' : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).1.get? k = m.get? k := by
simp_to_model using getValueCast?_insertList_of_contains_eq_false
theorem get?_insertMany_list_of_mem [LawfulBEq α] (h : m.1.WF)
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(m.insertMany l).1.get? k' = some (cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v) := by
simp_to_model using getValueCast?_insertList_of_mem
theorem get_insertMany_list_of_contains_eq_false [LawfulBEq α] (h : m.1.WF)
{l : List ((a : α) × β a)} {k : α}
(contains : (l.map Sigma.fst).contains k = false)
{h'} :
(m.insertMany l).1.get k h' =
m.get k (contains_of_contains_insertMany_list _ h h' contains) := by
simp_to_model using getValueCast_insertList_of_contains_eq_false
theorem get_insertMany_list_of_mem [LawfulBEq α] (h : m.1.WF)
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l)
{h'} :
(m.insertMany l).1.get k' h' = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by
simp_to_model using getValueCast_insertList_of_mem
theorem get!_insertMany_list_of_contains_eq_false [LawfulBEq α] (h : m.1.WF)
{l : List ((a : α) × β a)} {k : α} [Inhabited (β k)]
(h' : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).1.get! k = m.get! k := by
simp_to_model using getValueCast!_insertList_of_contains_eq_false
theorem get!_insertMany_list_of_mem [LawfulBEq α] (h : m.1.WF)
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} [Inhabited (β k')]
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(m.insertMany l).1.get! k' = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by
simp_to_model using getValueCast!_insertList_of_mem
theorem getD_insertMany_list_of_contains_eq_false [LawfulBEq α] (h : m.1.WF)
{l : List ((a : α) × β a)} {k : α} {fallback : β k}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).1.getD k fallback = m.getD k fallback := by
simp_to_model using getValueCastD_insertList_of_contains_eq_false
theorem getD_insertMany_list_of_mem [LawfulBEq α] (h : m.1.WF)
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} {fallback : β k'}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(m.insertMany l).1.getD k' fallback = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by
simp_to_model using getValueCastD_insertList_of_mem
theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List ((a : α) × β a)} {k : α}
(h' : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).1.getKey? k = m.getKey? k := by
simp_to_model using getKey?_insertList_of_contains_eq_false
theorem getKey?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(m.insertMany l).1.getKey? k' = some k := by
simp_to_model using getKey?_insertList_of_mem
theorem getKey_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List ((a : α) × β a)} {k : α}
(h₁ : (l.map Sigma.fst).contains k = false)
{h'} :
(m.insertMany l).1.getKey k h' =
m.getKey k (contains_of_contains_insertMany_list _ h h' h₁) := by
simp_to_model using getKey_insertList_of_contains_eq_false
theorem getKey_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst)
{h'} :
(m.insertMany l).1.getKey k' h' = k := by
simp_to_model using getKey_insertList_of_mem
theorem getKey!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
(h : m.1.WF) {l : List ((a : α) × β a)} {k : α}
(h' : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).1.getKey! k = m.getKey! k := by
simp_to_model using getKey!_insertList_of_contains_eq_false
theorem getKey!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF)
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(m.insertMany l).1.getKey! k' = k := by
simp_to_model using getKey!_insertList_of_mem
theorem getKeyD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List ((a : α) × β a)} {k fallback : α}
(h' : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).1.getKeyD k fallback = m.getKeyD k fallback := by
simp_to_model using getKeyD_insertList_of_contains_eq_false
theorem getKeyD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List ((a : α) × β a)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(m.insertMany l).1.getKeyD k' fallback = k := by
simp_to_model using getKeyD_insertList_of_mem
theorem size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List ((a : α) × β a)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
( (a : α), m.contains a (l.map Sigma.fst).contains a = false)
(m.insertMany l).1.1.size = m.1.size + l.length := by
simp_to_model using length_insertList
theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List ((a : α) × β a)} :
m.1.size (m.insertMany l).1.1.size := by
simp_to_model using length_le_length_insertList
theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List ((a : α) × β a)} :
(m.insertMany l).1.1.size m.1.size + l.length := by
simp_to_model using length_insertList_le
@[simp]
theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List ((a : α) × β a)} :
(m.insertMany l).1.1.isEmpty = (m.1.isEmpty && l.isEmpty) := by
simp_to_model using isEmpty_insertList
namespace Const
variable {β : Type v} (m : Raw₀ α (fun _ => β))
@[simp]
theorem insertMany_nil :
insertMany m [] = m := by
simp [insertMany, Id.run]
@[simp]
theorem insertMany_list_singleton {k : α} {v : β} :
insertMany m [k, v] = m.insert k v := by
simp [insertMany, Id.run]
theorem insertMany_cons {l : List (α × β)} {k : α} {v : β} :
(insertMany m (k, v :: l)).1 = (insertMany (m.insert k v) l).1 := by
simp only [insertMany_eq_insertListₘ]
cases l with
| nil => simp [insertListₘ]
| cons hd tl => simp [insertListₘ]
@[simp]
theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)} {k : α} :
(Const.insertMany m l).1.contains k = (m.contains k || (l.map Prod.fst).contains k) := by
simp_to_model using containsKey_insertListConst
theorem contains_of_contains_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List ( α × β )} {k : α} :
(insertMany m l).1.contains k (l.map Prod.fst).contains k = false m.contains k := by
simp_to_model using containsKey_of_containsKey_insertListConst
theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)} {k : α}
(h' : (l.map Prod.fst).contains k = false) :
(insertMany m l).1.getKey? k = m.getKey? k := by
simp_to_model using getKey?_insertListConst_of_contains_eq_false
theorem getKey?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).1.getKey? k' = some k := by
simp_to_model using getKey?_insertListConst_of_mem
theorem getKey_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)} {k : α}
(h₁ : (l.map Prod.fst).contains k = false)
{h'} :
(insertMany m l).1.getKey k h' =
m.getKey k (contains_of_contains_insertMany_list _ h h' h₁) := by
simp_to_model using getKey_insertListConst_of_contains_eq_false
theorem getKey_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst)
{h'} :
(insertMany m l).1.getKey k' h' = k := by
simp_to_model using getKey_insertListConst_of_mem
theorem getKey!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
(h : m.1.WF) {l : List (α × β)} {k : α}
(h' : (l.map Prod.fst).contains k = false) :
(insertMany m l).1.getKey! k = m.getKey! k := by
simp_to_model using getKey!_insertListConst_of_contains_eq_false
theorem getKey!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF)
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).1.getKey! k' = k := by
simp_to_model using getKey!_insertListConst_of_mem
theorem getKeyD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)} {k fallback : α}
(h' : (l.map Prod.fst).contains k = false) :
(insertMany m l).1.getKeyD k fallback = m.getKeyD k fallback := by
simp_to_model using getKeyD_insertListConst_of_contains_eq_false
theorem getKeyD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).1.getKeyD k' fallback = k := by
simp_to_model using getKeyD_insertListConst_of_mem
theorem size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
( (a : α), m.contains a (l.map Prod.fst).contains a = false)
(insertMany m l).1.1.size = m.1.size + l.length := by
simp_to_model using length_insertListConst
theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)} :
m.1.size (insertMany m l).1.1.size := by
simp_to_model using length_le_length_insertListConst
theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)} :
(insertMany m l).1.1.size m.1.size + l.length := by
simp_to_model using length_insertListConst_le
@[simp]
theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)} :
(insertMany m l).1.1.isEmpty = (m.1.isEmpty && l.isEmpty) := by
simp_to_model using isEmpty_insertListConst
theorem get?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)} {k : α}
(h' : (l.map Prod.fst).contains k = false) :
get? (insertMany m l).1 k = get? m k := by
simp_to_model using getValue?_insertListConst_of_contains_eq_false
theorem get?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
get? (insertMany m l).1 k' = v := by
simp_to_model using getValue?_insertListConst_of_mem
theorem get_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)} {k : α}
(h₁ : (l.map Prod.fst).contains k = false)
{h'} :
get (insertMany m l).1 k h' = get m k (contains_of_contains_insertMany_list _ h h' h₁) := by
simp_to_model using getValue_insertListConst_of_contains_eq_false
theorem get_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) {h'} :
get (insertMany m l).1 k' h' = v := by
simp_to_model using getValue_insertListConst_of_mem
theorem get!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited β] (h : m.1.WF) {l : List (α × β)} {k : α}
(h' : (l.map Prod.fst).contains k = false) :
get! (insertMany m l).1 k = get! m k := by
simp_to_model using getValue!_insertListConst_of_contains_eq_false
theorem get!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited β] (h : m.1.WF)
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
get! (insertMany m l).1 k' = v := by
simp_to_model using getValue!_insertListConst_of_mem
theorem getD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)} {k : α} {fallback : β}
(h' : (l.map Prod.fst).contains k = false) :
getD (insertMany m l).1 k fallback = getD m k fallback := by
simp_to_model using getValueD_insertListConst_of_contains_eq_false
theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v fallback : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
getD (insertMany m l).1 k' fallback = v := by
simp_to_model using getValueD_insertListConst_of_mem
variable (m : Raw₀ α (fun _ => Unit))
@[simp]
theorem insertManyIfNewUnit_nil :
insertManyIfNewUnit m [] = m := by
simp [insertManyIfNewUnit, Id.run]
@[simp]
theorem insertManyIfNewUnit_list_singleton {k : α} :
insertManyIfNewUnit m [k] = m.insertIfNew k () := by
simp [insertManyIfNewUnit, Id.run]
theorem insertManyIfNewUnit_cons {l : List α} {k : α} :
(insertManyIfNewUnit m (k :: l)).1 = (insertManyIfNewUnit (m.insertIfNew k ()) l).1 := by
simp only [insertManyIfNewUnit_eq_insertListIfNewUnitₘ]
cases l with
| nil => simp [insertListIfNewUnitₘ]
| cons hd tl => simp [insertListIfNewUnitₘ]
@[simp]
theorem contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List α} {k : α} :
(insertManyIfNewUnit m l).1.contains k = (m.contains k || l.contains k) := by
simp_to_model using containsKey_insertListIfNewUnit
theorem contains_of_contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List α} {k : α} (h₂ : l.contains k = false) :
(insertManyIfNewUnit m l).1.contains k m.contains k := by
simp_to_model using containsKey_of_containsKey_insertListIfNewUnit
theorem getKey?_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false
[EquivBEq α] [LawfulHashable α]
(h : m.1.WF) {l : List α} {k : α} :
m.contains k = false l.contains k = false getKey? (insertManyIfNewUnit m l).1 k = none := by
simp_to_model using getKey?_insertListIfNewUnit_of_contains_eq_false_of_contains_eq_false
theorem getKey?_insertManyIfNewUnit_list_of_contains_eq_false_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.1.WF) {l : List α} {k k' : α} (k_beq : k == k') :
m.contains k = false l.Pairwise (fun a b => (a == b) = false) k l
getKey? (insertManyIfNewUnit m l).1 k' = some k := by
simp_to_model using getKey?_insertListIfNewUnit_of_contains_eq_false_of_mem
theorem getKey?_insertManyIfNewUnit_list_of_contains [EquivBEq α] [LawfulHashable α]
(h : m.1.WF) {l : List α} {k : α} :
m.contains k getKey? (insertManyIfNewUnit m l).1 k = getKey? m k := by
simp_to_model using getKey?_insertListIfNewUnit_of_contains
theorem getKey_insertManyIfNewUnit_list_of_contains [EquivBEq α] [LawfulHashable α]
(h : m.1.WF) {l : List α} {k : α} {h'} (contains : m.contains k):
getKey (insertManyIfNewUnit m l).1 k h' = getKey m k contains := by
simp_to_model using getKey_insertListIfNewUnit_of_contains
theorem getKey_insertManyIfNewUnit_list_of_contains_eq_false_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.1.WF) {l : List α}
{k k' : α} (k_beq : k == k') {h'} :
m.contains k = false l.Pairwise (fun a b => (a == b) = false) k l
getKey (insertManyIfNewUnit m l).1 k' h' = k := by
simp_to_model using getKey_insertListIfNewUnit_of_contains_eq_false_of_mem
theorem getKey_insertManyIfNewUnit_list_mem_of_contains [EquivBEq α] [LawfulHashable α]
(h : m.1.WF) {l : List α} {k : α} (contains : m.contains k) {h'} :
getKey (insertManyIfNewUnit m l).1 k h' = getKey m k contains := by
simp_to_model using getKey_insertListIfNewUnit_of_contains
theorem getKey!_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.1.WF) {l : List α} {k : α} :
m.contains k = false l.contains k = false
getKey! (insertManyIfNewUnit m l).1 k = default := by
simp_to_model using getKey!_insertListIfNewUnit_of_contains_eq_false_of_contains_eq_false
theorem getKey!_insertManyIfNewUnit_list_of_contains_eq_false_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] (h : m.1.WF) {l : List α} {k k' : α} (k_beq : k == k') :
contains m k = false l.Pairwise (fun a b => (a == b) = false) k l
getKey! (insertManyIfNewUnit m l).1 k' = k := by
simp_to_model using getKey!_insertListIfNewUnit_of_contains_eq_false_of_mem
theorem getKey!_insertManyIfNewUnit_list_of_contains [EquivBEq α] [LawfulHashable α]
[Inhabited α] (h : m.1.WF) {l : List α} {k : α} :
m.contains k getKey! (insertManyIfNewUnit m l).1 k = getKey! m k := by
simp_to_model using getKey!_insertListIfNewUnit_of_contains
theorem getKeyD_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] (h : m.1.WF) {l : List α} {k fallback : α} :
m.contains k = false l.contains k = false getKeyD (insertManyIfNewUnit m l).1 k fallback = fallback := by
simp_to_model using getKeyD_insertListIfNewUnit_of_contains_eq_false_of_contains_eq_false
theorem getKeyD_insertManyIfNewUnit_list_of_contains_eq_false_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.1.WF) {l : List α} {k k' fallback : α} (k_beq : k == k') :
m.contains k = false l.Pairwise (fun a b => (a == b) = false) k l
getKeyD (insertManyIfNewUnit m l).1 k' fallback = k := by
simp_to_model using getKeyD_insertListIfNewUnit_of_contains_eq_false_of_mem
theorem getKeyD_insertManyIfNewUnit_list_of_contains [EquivBEq α] [LawfulHashable α]
(h : m.1.WF) {l : List α} {k fallback : α} :
m.contains k getKeyD (insertManyIfNewUnit m l).1 k fallback = getKeyD m k fallback := by
simp_to_model using getKeyD_insertListIfNewUnit_of_contains
theorem size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
( (a : α), m.contains a l.contains a = false)
(insertManyIfNewUnit m l).1.1.size = m.1.size + l.length := by
simp_to_model using length_insertListIfNewUnit
theorem size_le_size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List α} :
m.1.size (insertManyIfNewUnit m l).1.1.size := by
simp_to_model using length_le_length_insertListIfNewUnit
theorem size_insertManyIfNewUnit_list_le [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List α} :
(insertManyIfNewUnit m l).1.1.size m.1.size + l.length := by
simp_to_model using length_insertListIfNewUnit_le
@[simp]
theorem isEmpty_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List α} :
(insertManyIfNewUnit m l).1.1.isEmpty = (m.1.isEmpty && l.isEmpty) := by
simp_to_model using isEmpty_insertListIfNewUnit
theorem get?_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
{l : List α} {k : α} :
get? (insertManyIfNewUnit m l).1 k =
if m.contains k l.contains k then some () else none := by
simp_to_model using getValue?_insertListIfNewUnit
theorem get_insertManyIfNewUnit_list
{l : List α} {k : α} {h} :
get (insertManyIfNewUnit m l).1 k h = () := by
simp
theorem get!_insertManyIfNewUnit_list
{l : List α} {k : α} :
get! (insertManyIfNewUnit m l).1 k = () := by
simp
theorem getD_insertManyIfNewUnit_list
{l : List α} {k : α} {fallback : Unit} :
getD (insertManyIfNewUnit m l).1 k fallback = () := by
simp
end Const
end Raw₀
namespace Raw₀
variable [BEq α] [Hashable α]
@[simp]
theorem insertMany_empty_list_nil :
(insertMany empty ([] : List ((a : α) × (β a)))).1 = empty := by
simp
@[simp]
theorem insertMany_empty_list_singleton {k : α} {v : β k} :
(insertMany empty [k, v]).1 = empty.insert k v := by
simp
theorem insertMany_empty_list_cons {k : α} {v : β k}
{tl : List ((a : α) × (β a))} :
(insertMany empty (k, v :: tl)).1 = ((empty.insert k v).insertMany tl).1 := by
rw [insertMany_cons]
theorem contains_insertMany_empty_list [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k : α} :
(insertMany empty l).1.contains k = (l.map Sigma.fst).contains k := by
simp [contains_insertMany_list _ Raw.WF.empty₀]
theorem get?_insertMany_empty_list_of_contains_eq_false [LawfulBEq α]
{l : List ((a : α) × β a)} {k : α}
(h : (l.map Sigma.fst).contains k = false) :
(insertMany empty l).1.get? k = none := by
simp [get?_insertMany_list_of_contains_eq_false _ Raw.WF.empty₀ h]
theorem get?_insertMany_empty_list_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(insertMany empty l).1.get? k' = some (cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v) := by
rw [get?_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem get_insertMany_empty_list_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l)
{h} :
(insertMany empty l).1.get k' h = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by
rw [get_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem get!_insertMany_empty_list_of_contains_eq_false [LawfulBEq α]
{l : List ((a : α) × β a)} {k : α} [Inhabited (β k)]
(h : (l.map Sigma.fst).contains k = false) :
(insertMany empty l).1.get! k = default := by
simp only [get!_insertMany_list_of_contains_eq_false _ Raw.WF.empty₀ h]
apply get!_empty
theorem get!_insertMany_empty_list_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} [Inhabited (β k')]
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(insertMany empty l).1.get! k' = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by
rw [get!_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem getD_insertMany_empty_list_of_contains_eq_false [LawfulBEq α]
{l : List ((a : α) × β a)} {k : α} {fallback : β k}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(insertMany empty l).1.getD k fallback = fallback := by
rw [getD_insertMany_list_of_contains_eq_false _ Raw.WF.empty₀ contains_eq_false]
apply getD_empty
theorem getD_insertMany_empty_list_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} {fallback : β k'}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(insertMany empty l).1.getD k' fallback =
cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by
rw [getD_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem getKey?_insertMany_empty_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k : α}
(h : (l.map Sigma.fst).contains k = false) :
(insertMany empty l).1.getKey? k = none := by
rw [getKey?_insertMany_list_of_contains_eq_false _ Raw.WF.empty₀ h]
apply getKey?_empty
theorem getKey?_insertMany_empty_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(insertMany empty l).1.getKey? k' = some k := by
rw [getKey?_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem getKey_insertMany_empty_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst)
{h'} :
(insertMany empty l).1.getKey k' h' = k := by
rw [getKey_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem getKey!_insertMany_empty_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List ((a : α) × β a)} {k : α}
(h : (l.map Sigma.fst).contains k = false) :
(insertMany empty l).1.getKey! k = default := by
rw [getKey!_insertMany_list_of_contains_eq_false _ Raw.WF.empty₀ h]
apply getKey!_empty
theorem getKey!_insertMany_empty_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(insertMany empty l).1.getKey! k' = k := by
rw [getKey!_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem getKeyD_insertMany_empty_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k fallback : α}
(h : (l.map Sigma.fst).contains k = false) :
(insertMany empty l).1.getKeyD k fallback = fallback := by
rw [getKeyD_insertMany_list_of_contains_eq_false _ Raw.WF.empty₀ h]
apply getKeyD_empty
theorem getKeyD_insertMany_empty_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(insertMany empty l).1.getKeyD k' fallback = k := by
rw [getKeyD_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem size_insertMany_empty_list [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
(insertMany empty l).1.1.size = l.length := by
rw [size_insertMany_list _ Raw.WF.empty₀ distinct]
· simp only [size_empty, Nat.zero_add]
· simp only [contains_empty, Bool.false_eq_true, false_implies, implies_true]
theorem size_insertMany_empty_list_le [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} :
(insertMany empty l).1.1.size l.length := by
rw [ Nat.zero_add l.length]
apply (size_insertMany_list_le _ Raw.WF.empty₀)
theorem isEmpty_insertMany_empty_list [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} :
(insertMany empty l).1.1.isEmpty = l.isEmpty := by
simp [isEmpty_insertMany_list _ Raw.WF.empty₀]
namespace Const
variable {β : Type v}
@[simp]
theorem insertMany_empty_list_nil :
(insertMany empty ([] : List (α × β))).1 = empty := by
simp only [insertMany_nil]
@[simp]
theorem insertMany_empty_list_singleton {k : α} {v : β} :
(insertMany empty [k, v]).1 = empty.insert k v := by
simp only [insertMany_list_singleton]
theorem insertMany_empty_list_cons {k : α} {v : β}
{tl : List (α × β)} :
(insertMany empty (k, v :: tl)) = (insertMany (empty.insert k v) tl).1 := by
rw [insertMany_cons]
theorem contains_insertMany_empty_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} :
(insertMany (empty : Raw₀ α (fun _ => β)) l).1.contains k = (l.map Prod.fst).contains k := by
simp [contains_insertMany_list _ Raw.WF.empty₀]
theorem get?_insertMany_empty_list_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α}
(h : (l.map Prod.fst).contains k = false) :
get? (insertMany (empty : Raw₀ α (fun _ => β)) l).1 k = none := by
rw [get?_insertMany_list_of_contains_eq_false _ Raw.WF.empty₀ h]
apply get?_empty
theorem get?_insertMany_empty_list_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
get? (insertMany (empty : Raw₀ α (fun _ => β)) l) k' = some v := by
rw [get?_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem get_insertMany_empty_list_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l)
{h} :
get (insertMany (empty : Raw₀ α (fun _ => β)) l) k' h = v := by
rw [get_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem get!_insertMany_empty_list_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α} [Inhabited β]
(h : (l.map Prod.fst).contains k = false) :
get! (insertMany (empty : Raw₀ α (fun _ => β)) l) k = (default : β) := by
rw [get!_insertMany_list_of_contains_eq_false _ Raw.WF.empty₀ h]
apply get!_empty
theorem get!_insertMany_empty_list_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} [Inhabited β]
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
get! (insertMany (empty : Raw₀ α (fun _ => β)) l) k' = v := by
rw [get!_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem getD_insertMany_empty_list_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α} {fallback : β}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
getD (insertMany (empty : Raw₀ α (fun _ => β)) l) k fallback = fallback := by
rw [getD_insertMany_list_of_contains_eq_false _ Raw.WF.empty₀ contains_eq_false]
apply getD_empty
theorem getD_insertMany_empty_list_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} {fallback : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
getD (insertMany (empty : Raw₀ α (fun _ => β)) l) k' fallback = v := by
rw [getD_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem getKey?_insertMany_empty_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α}
(h : (l.map Prod.fst).contains k = false) :
(insertMany (empty : Raw₀ α (fun _ => β)) l).1.getKey? k = none := by
rw [getKey?_insertMany_list_of_contains_eq_false _ Raw.WF.empty₀ h]
apply getKey?_empty
theorem getKey?_insertMany_empty_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany (empty : Raw₀ α (fun _ => β)) l).1.getKey? k' = some k := by
rw [getKey?_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem getKey_insertMany_empty_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst)
{h'} :
(insertMany (empty : Raw₀ α (fun _ => β)) l).1.getKey k' h' = k := by
rw [getKey_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem getKey!_insertMany_empty_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List (α × β)} {k : α}
(h : (l.map Prod.fst).contains k = false) :
(insertMany (empty : Raw₀ α (fun _ => β)) l).1.getKey! k = default := by
rw [getKey!_insertMany_list_of_contains_eq_false _ Raw.WF.empty₀ h]
apply getKey!_empty
theorem getKey!_insertMany_empty_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany (empty : Raw₀ α (fun _ => β)) l).1.getKey! k' = k := by
rw [getKey!_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem getKeyD_insertMany_empty_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k fallback : α}
(h : (l.map Prod.fst).contains k = false) :
(insertMany (empty : Raw₀ α (fun _ => β)) l).1.getKeyD k fallback = fallback := by
rw [getKeyD_insertMany_list_of_contains_eq_false _ Raw.WF.empty₀ h]
apply getKeyD_empty
theorem getKeyD_insertMany_empty_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany (empty : Raw₀ α (fun _ => β)) l).1.getKeyD k' fallback = k := by
rw [getKeyD_insertMany_list_of_mem _ Raw.WF.empty₀ k_beq distinct mem]
theorem size_insertMany_empty_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
(insertMany (empty : Raw₀ α (fun _ => β)) l).1.1.size = l.length := by
rw [size_insertMany_list _ Raw.WF.empty₀ distinct]
· simp only [size_empty, Nat.zero_add]
· simp only [contains_empty, Bool.false_eq_true, false_implies, implies_true]
theorem size_insertMany_empty_list_le [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(insertMany (empty : Raw₀ α (fun _ => β)) l).1.1.size l.length := by
rw [ Nat.zero_add l.length]
apply (size_insertMany_list_le _ Raw.WF.empty₀)
theorem isEmpty_insertMany_empty_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(insertMany (empty : Raw₀ α (fun _ => β)) l).1.1.isEmpty = l.isEmpty := by
simp [isEmpty_insertMany_list _ Raw.WF.empty₀]
@[simp]
theorem insertManyIfNewUnit_empty_list_nil :
insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) ([] : List α) =
(empty : Raw₀ α (fun _ => Unit)) := by
simp
@[simp]
theorem insertManyIfNewUnit_empty_list_singleton {k : α} :
(insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) [k]).1 = empty.insertIfNew k () := by
simp
theorem insertManyIfNewUnit_empty_list_cons {hd : α} {tl : List α} :
insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) (hd :: tl) =
(insertManyIfNewUnit (empty.insertIfNew hd ()) tl).1 := by
rw [insertManyIfNewUnit_cons]
theorem contains_insertManyIfNewUnit_empty_list [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
(insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l).1.contains k = l.contains k := by
simp [contains_insertManyIfNewUnit_list _ Raw.WF.empty₀]
theorem getKey?_insertManyIfNewUnit_empty_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (h' : l.contains k = false) :
getKey? (insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l).1 k = none := by
exact getKey?_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false _ Raw.WF.empty₀
contains_empty h'
theorem getKey?_insertManyIfNewUnit_empty_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getKey? (insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l).1 k' = some k := by
exact getKey?_insertManyIfNewUnit_list_of_contains_eq_false_of_mem _ Raw.WF.empty₀ k_beq
contains_empty distinct mem
theorem getKey_insertManyIfNewUnit_empty_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) {h'} :
getKey (insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l).1 k' h' = k := by
exact getKey_insertManyIfNewUnit_list_of_contains_eq_false_of_mem _ Raw.WF.empty₀ k_beq
contains_empty distinct mem
theorem getKey!_insertManyIfNewUnit_empty_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k : α}
(h' : l.contains k = false) :
getKey! (insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l).1 k = default := by
exact getKey!_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false _ Raw.WF.empty₀
contains_empty h'
theorem getKey!_insertManyIfNewUnit_empty_list_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
getKey! (insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l).1 k' = k := by
exact getKey!_insertManyIfNewUnit_list_of_contains_eq_false_of_mem _ Raw.WF.empty₀ k_beq
contains_empty distinct mem
theorem getKeyD_insertManyIfNewUnit_empty_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k fallback : α}
(h' : l.contains k = false) :
getKeyD (insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l).1 k fallback = fallback := by
exact getKeyD_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false
_ Raw.WF.empty₀ contains_empty h'
theorem getKeyD_insertManyIfNewUnit_empty_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
getKeyD (insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l).1 k' fallback = k := by
exact getKeyD_insertManyIfNewUnit_list_of_contains_eq_false_of_mem _ Raw.WF.empty₀ k_beq
contains_empty distinct mem
theorem size_insertManyIfNewUnit_empty_list [EquivBEq α] [LawfulHashable α]
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
(insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l).1.1.size = l.length := by
simp [size_insertManyIfNewUnit_list _ Raw.WF.empty₀ distinct]
theorem size_insertManyIfNewUnit_empty_list_le [EquivBEq α] [LawfulHashable α]
{l : List α} :
(insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l).1.1.size l.length := by
apply Nat.le_trans (size_insertManyIfNewUnit_list_le _ Raw.WF.empty₀)
simp
theorem isEmpty_insertManyIfNewUnit_empty_list [EquivBEq α] [LawfulHashable α]
{l : List α} :
(insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l).1.1.isEmpty = l.isEmpty := by
rw [isEmpty_insertManyIfNewUnit_list _ Raw.WF.empty₀]
simp
theorem get?_insertManyIfNewUnit_empty_list [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
get? (insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l) k =
if l.contains k then some () else none := by
rw [get?_insertManyIfNewUnit_list _ Raw.WF.empty₀]
simp
theorem get_insertManyIfNewUnit_empty_list
{l : List α} {k : α} {h} :
get (insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l) k h = () := by
simp
theorem get!_insertManyIfNewUnit_empty_list
{l : List α} {k : α} :
get! (insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l) k = () := by
simp
theorem getD_insertManyIfNewUnit_empty_list
{l : List α} {k : α} {fallback : Unit} :
getD (insertManyIfNewUnit (empty : Raw₀ α (fun _ => Unit)) l) k fallback = () := by
simp
end Const
end Raw₀
end Std.DHashMap.Internal

View File

@@ -789,7 +789,7 @@ theorem Const.toListModel_getThenInsertIfNew? {β : Type v} [BEq α] [Hashable
exact toListModel_insertIfNewₘ h
theorem Const.wfImp_getThenInsertIfNew? {β : Type v} [BEq α] [Hashable α] [EquivBEq α]
[LawfulHashable α] {m : Raw₀ α (fun _ => β)} {a : α} {b : β} (h : Raw.WFImp m.1):
[LawfulHashable α] {m : Raw₀ α (fun _ => β)} {a : α} {b : β} (h : Raw.WFImp m.1) :
Raw.WFImp (Const.getThenInsertIfNew? m a b).2.1 := by
rw [getThenInsertIfNew?_eq_insertIfNewₘ]
exact wfImp_insertIfNewₘ h
@@ -955,6 +955,20 @@ theorem wfImp_filter [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] {m
rw [filter_eq_filterₘ]
exact wfImp_filterₘ h
/-! # `insertListₘ` -/
theorem toListModel_insertListₘ [BEq α] [Hashable α] [EquivBEq α][LawfulHashable α]
{m : Raw₀ α β} {l : List ((a : α) × β a)} (h : Raw.WFImp m.1) :
Perm (toListModel (insertListₘ m l).1.buckets)
(List.insertList (toListModel m.1.buckets) l) := by
induction l generalizing m with
| nil =>
simp [insertListₘ, List.insertList]
| cons hd tl ih =>
simp only [insertListₘ, List.insertList]
apply Perm.trans (ih (wfImp_insert h))
apply List.insertList_perm_of_perm_first (toListModel_insert h) (wfImp_insert h).distinct
end Raw₀
namespace Raw
@@ -981,16 +995,72 @@ end Raw
namespace Raw₀
/-! # `insertMany` -/
theorem wfImp_insertMany [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] {ρ : Type w}
[ForIn Id ρ ((a : α) × β a)] {m : Raw₀ α β} {l : ρ} (h : Raw.WFImp m.1) :
Raw.WFImp (m.insertMany l).1.1 :=
Raw.WF.out ((m.insertMany l).2 _ Raw.WF.insert₀ (.wf m.2 h))
theorem toListModel_insertMany_list [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α]
{m : Raw₀ α β} {l : List ((a : α) × (β a))} (h : Raw.WFImp m.1) :
Perm (toListModel (insertMany m l).1.1.buckets)
(List.insertList (toListModel m.1.buckets) l) := by
rw [insertMany_eq_insertListₘ]
apply toListModel_insertListₘ
exact h
/-! # `Const.insertListₘ` -/
theorem Const.toListModel_insertListₘ {β : Type v} [BEq α] [Hashable α] [EquivBEq α]
[LawfulHashable α] {m : Raw₀ α (fun _ => β)} {l : List (α × β)} (h : Raw.WFImp m.1) :
Perm (toListModel (Const.insertListₘ m l).1.buckets)
(insertListConst (toListModel m.1.buckets) l) := by
induction l generalizing m with
| nil => simp [Const.insertListₘ, insertListConst, insertList]
| cons hd tl ih =>
simp only [Const.insertListₘ, insertListConst]
apply Perm.trans (ih (wfImp_insert h))
unfold insertListConst
apply List.insertList_perm_of_perm_first (toListModel_insert h) (wfImp_insert h).distinct
/-! # `Const.insertMany` -/
theorem Const.toListModel_insertMany_list {β : Type v} [BEq α] [Hashable α] [EquivBEq α]
[LawfulHashable α] {m : Raw₀ α (fun _ => β)} {l : List (α × β)} (h : Raw.WFImp m.1) :
Perm (toListModel (Const.insertMany m l).1.1.buckets)
(insertListConst (toListModel m.1.buckets) l) := by
rw [Const.insertMany_eq_insertListₘ]
apply toListModel_insertListₘ h
theorem Const.wfImp_insertMany {β : Type v} [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α]
{ρ : Type w} [ForIn Id ρ (α × β)] {m : Raw₀ α (fun _ => β)}
{l : ρ} (h : Raw.WFImp m.1) : Raw.WFImp (Const.insertMany m l).1.1 :=
Raw.WF.out ((Const.insertMany m l).2 _ Raw.WF.insert₀ (.wf m.2 h))
/-! # `Const.insertListIfNewUnitₘ` -/
theorem Const.toListModel_insertListIfNewUnitₘ [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α]
{m : Raw₀ α (fun _ => Unit)} {l : List α} (h : Raw.WFImp m.1) :
Perm (toListModel (Const.insertListIfNewUnitₘ m l).1.buckets)
(List.insertListIfNewUnit (toListModel m.1.buckets) l) := by
induction l generalizing m with
| nil => simp [insertListIfNewUnitₘ, List.insertListIfNewUnit]
| cons hd tl ih =>
simp only [insertListIfNewUnitₘ, insertListIfNewUnit]
apply Perm.trans (ih (wfImp_insertIfNew h))
apply List.insertListIfNewUnit_perm_of_perm_first (toListModel_insertIfNew h)
apply (wfImp_insertIfNew h).distinct
/-! # `Const.insertManyIfNewUnit` -/
theorem Const.toListModel_insertManyIfNewUnit_list [BEq α] [Hashable α] [EquivBEq α]
[LawfulHashable α] {m : Raw₀ α (fun _ => Unit)} {l : List α} (h : Raw.WFImp m.1) :
Perm (toListModel (Const.insertManyIfNewUnit m l).1.1.buckets)
(List.insertListIfNewUnit (toListModel m.1.buckets) l) := by
rw [Const.insertManyIfNewUnit_eq_insertListIfNewUnitₘ]
apply toListModel_insertListIfNewUnitₘ h
theorem Const.wfImp_insertManyIfNewUnit [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α]
{ρ : Type w} [ForIn Id ρ α] {m : Raw₀ α (fun _ => Unit)} {l : ρ} (h : Raw.WFImp m.1) :
Raw.WFImp (Const.insertManyIfNewUnit m l).1.1 :=

View File

@@ -913,7 +913,6 @@ theorem getKeyD_insertIfNew [EquivBEq α] [LawfulHashable α] {k a fallback : α
simp [mem_iff_contains, contains_insertIfNew]
exact Raw₀.getKeyD_insertIfNew m.1, _ m.2
@[simp]
theorem getThenInsertIfNew?_fst [LawfulBEq α] {k : α} {v : β k} :
(m.getThenInsertIfNew? k v).1 = m.get? k :=
@@ -964,4 +963,907 @@ theorem distinct_keys [EquivBEq α] [LawfulHashable α] :
m.keys.Pairwise (fun a b => (a == b) = false) :=
Raw₀.distinct_keys m.1, m.2.size_buckets_pos m.2
@[simp]
theorem insertMany_nil :
m.insertMany [] = m :=
Subtype.eq (congrArg Subtype.val (Raw₀.insertMany_nil m.1, m.2.size_buckets_pos) :)
@[simp]
theorem insertMany_list_singleton {k : α} {v : β k} :
m.insertMany [k, v] = m.insert k v :=
Subtype.eq (congrArg Subtype.val (Raw₀.insertMany_list_singleton m.1, m.2.size_buckets_pos) :)
theorem insertMany_cons {l : List ((a : α) × β a)} {k : α} {v : β k} :
m.insertMany (k, v :: l) = (m.insert k v).insertMany l :=
Subtype.eq (congrArg Subtype.val (Raw₀.insertMany_cons m.1, m.2.size_buckets_pos) :)
@[simp]
theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k : α} :
(m.insertMany l).contains k = (m.contains k || (l.map Sigma.fst).contains k) :=
Raw₀.contains_insertMany_list m.1, _ m.2
@[simp]
theorem mem_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k : α} :
k m.insertMany l k m (l.map Sigma.fst).contains k := by
simp [mem_iff_contains]
theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k : α} (mem : k m.insertMany l)
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
k m :=
Raw₀.contains_of_contains_insertMany_list m.1, _ m.2 mem contains_eq_false
theorem get?_insertMany_list_of_contains_eq_false [LawfulBEq α]
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).get? k = m.get? k :=
Raw₀.get?_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem get?_insertMany_list_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(m.insertMany l).get? k' = some (cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v) :=
Raw₀.get?_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem get_insertMany_list_of_contains_eq_false [LawfulBEq α]
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false)
{h} :
(m.insertMany l).get k h =
m.get k (mem_of_mem_insertMany_list h contains_eq_false) :=
Raw₀.get_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem get_insertMany_list_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l)
{h} :
(m.insertMany l).get k' h = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v :=
Raw₀.get_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem get!_insertMany_list_of_contains_eq_false [LawfulBEq α]
{l : List ((a : α) × β a)} {k : α} [Inhabited (β k)]
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).get! k = m.get! k :=
Raw₀.get!_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem get!_insertMany_list_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} [Inhabited (β k')]
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(m.insertMany l).get! k' = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v :=
Raw₀.get!_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem getD_insertMany_list_of_contains_eq_false [LawfulBEq α]
{l : List ((a : α) × β a)} {k : α} {fallback : β k}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).getD k fallback = m.getD k fallback :=
Raw₀.getD_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem getD_insertMany_list_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} {fallback : β k'}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(m.insertMany l).getD k' fallback = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v :=
Raw₀.getD_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).getKey? k = m.getKey? k :=
Raw₀.getKey?_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem getKey?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(m.insertMany l).getKey? k' = some k :=
Raw₀.getKey?_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem getKey_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false)
{h} :
(m.insertMany l).getKey k h =
m.getKey k (mem_of_mem_insertMany_list h contains_eq_false) :=
Raw₀.getKey_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem getKey_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst)
{h} :
(m.insertMany l).getKey k' h = k :=
Raw₀.getKey_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem getKey!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).getKey! k = m.getKey! k :=
Raw₀.getKey!_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem getKey!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(m.insertMany l).getKey! k' = k :=
Raw₀.getKey!_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem getKeyD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k fallback : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).getKeyD k fallback = m.getKeyD k fallback :=
Raw₀.getKeyD_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem getKeyD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(m.insertMany l).getKeyD k' fallback = k :=
Raw₀.getKeyD_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem size_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
( (a : α), a m (l.map Sigma.fst).contains a = false)
(m.insertMany l).size = m.size + l.length :=
Raw₀.size_insertMany_list m.1, _ m.2 distinct
theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} :
m.size (m.insertMany l).size :=
Raw₀.size_le_size_insertMany_list m.1, _ m.2
theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} :
(m.insertMany l).size m.size + l.length :=
Raw₀.size_insertMany_list_le m.1, _ m.2
@[simp]
theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} :
(m.insertMany l).isEmpty = (m.isEmpty && l.isEmpty) :=
Raw₀.isEmpty_insertMany_list m.1, _ m.2
namespace Const
variable {β : Type v} {m : DHashMap α (fun _ => β)}
@[simp]
theorem insertMany_nil :
insertMany m [] = m :=
Subtype.eq (congrArg Subtype.val (Raw₀.Const.insertMany_nil m.1, m.2.size_buckets_pos) :)
@[simp]
theorem insertMany_list_singleton {k : α} {v : β} :
insertMany m [k, v] = m.insert k v :=
Subtype.eq (congrArg Subtype.val
(Raw₀.Const.insertMany_list_singleton m.1, m.2.size_buckets_pos) :)
theorem insertMany_cons {l : List (α × β)} {k : α} {v : β} :
insertMany m (k, v :: l) = insertMany (m.insert k v) l :=
Subtype.eq (congrArg Subtype.val (Raw₀.Const.insertMany_cons m.1, m.2.size_buckets_pos) :)
@[simp]
theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} :
(Const.insertMany m l).contains k = (m.contains k || (l.map Prod.fst).contains k) :=
Raw₀.Const.contains_insertMany_list m.1, _ m.2
@[simp]
theorem mem_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} :
k insertMany m l k m (l.map Prod.fst).contains k := by
simp [mem_iff_contains]
theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} (mem : k insertMany m l)
(contains_eq_false : (l.map Prod.fst).contains k = false) :
k m :=
Raw₀.Const.contains_of_contains_insertMany_list m.1, _ m.2 mem contains_eq_false
theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l).getKey? k = m.getKey? k :=
Raw₀.Const.getKey?_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem getKey?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).getKey? k' = some k :=
Raw₀.Const.getKey?_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem getKey_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false)
{h} :
(insertMany m l).getKey k h =
m.getKey k (mem_of_mem_insertMany_list h contains_eq_false) :=
Raw₀.Const.getKey_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem getKey_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst)
{h} :
(insertMany m l).getKey k' h = k :=
Raw₀.Const.getKey_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem getKey!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l).getKey! k = m.getKey! k :=
Raw₀.Const.getKey!_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem getKey!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).getKey! k' = k :=
Raw₀.Const.getKey!_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem getKeyD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k fallback : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l).getKeyD k fallback = m.getKeyD k fallback :=
Raw₀.Const.getKeyD_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem getKeyD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).getKeyD k' fallback = k :=
Raw₀.Const.getKeyD_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem size_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
( (a : α), a m (l.map Prod.fst).contains a = false)
(insertMany m l).size = m.size + l.length :=
Raw₀.Const.size_insertMany_list m.1, _ m.2 distinct
theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
m.size (insertMany m l).size :=
Raw₀.Const.size_le_size_insertMany_list m.1, _ m.2
theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(insertMany m l).size m.size + l.length :=
Raw₀.Const.size_insertMany_list_le m.1, _ m.2
@[simp]
theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(insertMany m l).isEmpty = (m.isEmpty && l.isEmpty) :=
Raw₀.Const.isEmpty_insertMany_list m.1, _ m.2
theorem get?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
get? (insertMany m l) k = get? m k :=
Raw₀.Const.get?_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem get?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
get? (insertMany m l) k' = v :=
Raw₀.Const.get?_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem get_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false)
{h} :
get (insertMany m l) k h = get m k (mem_of_mem_insertMany_list h contains_eq_false) :=
Raw₀.Const.get_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem get_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) {h} :
get (insertMany m l) k' h = v :=
Raw₀.Const.get_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem get!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited β] {l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
get! (insertMany m l) k = get! m k :=
Raw₀.Const.get!_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem get!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited β]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
get! (insertMany m l) k' = v :=
Raw₀.Const.get!_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
theorem getD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} {fallback : β}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
getD (insertMany m l) k fallback = getD m k fallback :=
Raw₀.Const.getD_insertMany_list_of_contains_eq_false m.1, _ m.2 contains_eq_false
theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v fallback : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
getD (insertMany m l) k' fallback = v :=
Raw₀.Const.getD_insertMany_list_of_mem m.1, _ m.2 k_beq distinct mem
variable {m : DHashMap α (fun _ => Unit)}
@[simp]
theorem insertManyIfNewUnit_nil :
insertManyIfNewUnit m [] = m :=
Subtype.eq (congrArg Subtype.val
(Raw₀.Const.insertManyIfNewUnit_nil m.1, m.2.size_buckets_pos) :)
@[simp]
theorem insertManyIfNewUnit_list_singleton {k : α} :
insertManyIfNewUnit m [k] = m.insertIfNew k () :=
Subtype.eq (congrArg Subtype.val
(Raw₀.Const.insertManyIfNewUnit_list_singleton m.1, m.2.size_buckets_pos) :)
theorem insertManyIfNewUnit_cons {l : List α} {k : α} :
insertManyIfNewUnit m (k :: l) = insertManyIfNewUnit (m.insertIfNew k ()) l :=
Subtype.eq (congrArg Subtype.val
(Raw₀.Const.insertManyIfNewUnit_cons m.1, m.2.size_buckets_pos) :)
@[simp]
theorem contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
(insertManyIfNewUnit m l).contains k = (m.contains k || l.contains k) :=
Raw₀.Const.contains_insertManyIfNewUnit_list m.1, _ m.2
@[simp]
theorem mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
k insertManyIfNewUnit m l k m l.contains k := by
simp [mem_iff_contains]
theorem mem_of_mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (contains_eq_false : l.contains k = false) :
k insertManyIfNewUnit m l k m :=
Raw₀.Const.contains_of_contains_insertManyIfNewUnit_list m.1, _ m.2 contains_eq_false
theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] {l : List α} {k : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
getKey? (insertManyIfNewUnit m l) k = none := by
simp only [mem_iff_contains, Bool.not_eq_true] at not_mem
exact Raw₀.Const.getKey?_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false
m.1, _ m.2 not_mem contains_eq_false
theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getKey? (insertManyIfNewUnit m l) k' = some k := by
simp only [mem_iff_contains, Bool.not_eq_true] at not_mem
exact Raw₀.Const.getKey?_insertManyIfNewUnit_list_of_contains_eq_false_of_mem m.1, _
m.2 k_beq not_mem distinct mem
theorem getKey?_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (h' : k m) :
getKey? (insertManyIfNewUnit m l) k = getKey? m k :=
Raw₀.Const.getKey?_insertManyIfNewUnit_list_of_contains m.1, _ m.2 h'
theorem getKey_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α}
{k k' : α} (k_beq : k == k')
(not_mem : ¬ k m) (distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) {h} :
getKey (insertManyIfNewUnit m l) k' h = k := by
simp only [mem_iff_contains, Bool.not_eq_true] at not_mem
exact Raw₀.Const.getKey_insertManyIfNewUnit_list_of_contains_eq_false_of_mem m.1, _ m.2 k_beq
not_mem distinct mem
theorem getKey_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (mem : k m) {h} :
getKey (insertManyIfNewUnit m l) k h = getKey m k mem :=
Raw₀.Const.getKey_insertManyIfNewUnit_list_of_contains m.1, _ m.2 _
theorem getKey!_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] [Inhabited α] {l : List α} {k : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
getKey! (insertManyIfNewUnit m l) k = default := by
simp only [mem_iff_contains, Bool.not_eq_true] at not_mem
exact Raw₀.Const.getKey!_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false
m.1, _ m.2 not_mem contains_eq_false
theorem getKey!_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k k' : α} (k_beq : k == k')
(not_mem : ¬ k m) (distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
getKey! (insertManyIfNewUnit m l) k' = k := by
simp only [mem_iff_contains, Bool.not_eq_true] at not_mem
exact Raw₀.Const.getKey!_insertManyIfNewUnit_list_of_contains_eq_false_of_mem m.1, _ m.2 k_beq
not_mem distinct mem
theorem getKey!_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k : α} (mem : k m) :
getKey! (insertManyIfNewUnit m l) k = getKey! m k :=
Raw₀.Const.getKey!_insertManyIfNewUnit_list_of_contains m.1, _ m.2 mem
theorem getKeyD_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] {l : List α} {k fallback : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
getKeyD (insertManyIfNewUnit m l) k fallback = fallback := by
simp only [mem_iff_contains, Bool.not_eq_true] at not_mem
exact Raw₀.Const.getKeyD_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false
m.1, _ m.2 not_mem contains_eq_false
theorem getKeyD_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' fallback : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getKeyD (insertManyIfNewUnit m l) k' fallback = k := by
simp only [mem_iff_contains, Bool.not_eq_true] at not_mem
exact Raw₀.Const.getKeyD_insertManyIfNewUnit_list_of_contains_eq_false_of_mem m.1, _ m.2 k_beq
not_mem distinct mem
theorem getKeyD_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k fallback : α} (mem : k m) :
getKeyD (insertManyIfNewUnit m l) k fallback = getKeyD m k fallback :=
Raw₀.Const.getKeyD_insertManyIfNewUnit_list_of_contains m.1, _ m.2 mem
theorem size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
( (a : α), a m l.contains a = false)
(insertManyIfNewUnit m l).size = m.size + l.length :=
Raw₀.Const.size_insertManyIfNewUnit_list m.1, _ m.2 distinct
theorem size_le_size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α} :
m.size (insertManyIfNewUnit m l).size :=
Raw₀.Const.size_le_size_insertManyIfNewUnit_list m.1, _ m.2
theorem size_insertManyIfNewUnit_list_le [EquivBEq α] [LawfulHashable α]
{l : List α} :
(insertManyIfNewUnit m l).size m.size + l.length :=
Raw₀.Const.size_insertManyIfNewUnit_list_le m.1, _ m.2
@[simp]
theorem isEmpty_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α} :
(insertManyIfNewUnit m l).isEmpty = (m.isEmpty && l.isEmpty) :=
Raw₀.Const.isEmpty_insertManyIfNewUnit_list m.1, _ m.2
theorem get?_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
get? (insertManyIfNewUnit m l) k =
if k m l.contains k then some () else none :=
Raw₀.Const.get?_insertManyIfNewUnit_list m.1, _ m.2
theorem get_insertManyIfNewUnit_list
{l : List α} {k : α} {h} :
get (insertManyIfNewUnit m l) k h = () :=
Raw₀.Const.get_insertManyIfNewUnit_list m.1, _
theorem get!_insertManyIfNewUnit_list
{l : List α} {k : α} :
get! (insertManyIfNewUnit m l) k = () :=
Raw₀.Const.get!_insertManyIfNewUnit_list m.1, _
theorem getD_insertManyIfNewUnit_list
{l : List α} {k : α} {fallback : Unit} :
getD (insertManyIfNewUnit m l) k fallback = () := by
simp
end Const
end DHashMap
namespace DHashMap
@[simp]
theorem ofList_nil :
ofList ([] : List ((a : α) × (β a))) = :=
Subtype.eq (congrArg Subtype.val (Raw₀.insertMany_empty_list_nil (α := α)) :)
@[simp]
theorem ofList_singleton {k : α} {v : β k} :
ofList [k, v] = (: DHashMap α β).insert k v :=
Subtype.eq (congrArg Subtype.val (Raw₀.insertMany_empty_list_singleton (α := α)) :)
theorem ofList_cons {k : α} {v : β k} {tl : List ((a : α) × (β a))} :
ofList (k, v :: tl) = (( : DHashMap α β).insert k v).insertMany tl :=
Subtype.eq (congrArg Subtype.val (Raw₀.insertMany_empty_list_cons (α := α)) :)
@[simp]
theorem contains_ofList [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k : α} :
(ofList l).contains k = (l.map Sigma.fst).contains k :=
Raw₀.contains_insertMany_empty_list
@[simp]
theorem mem_ofList [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k : α} :
k ofList l (l.map Sigma.fst).contains k := by
simp [mem_iff_contains]
theorem get?_ofList_of_contains_eq_false [LawfulBEq α]
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(ofList l).get? k = none :=
Raw₀.get?_insertMany_empty_list_of_contains_eq_false contains_eq_false
theorem get?_ofList_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(ofList l).get? k' = some (cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v) :=
Raw₀.get?_insertMany_empty_list_of_mem k_beq distinct mem
theorem get_ofList_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l)
{h} :
(ofList l).get k' h = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v :=
Raw₀.get_insertMany_empty_list_of_mem k_beq distinct mem
theorem get!_ofList_of_contains_eq_false [LawfulBEq α]
{l : List ((a : α) × β a)} {k : α} [Inhabited (β k)]
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(ofList l).get! k = default :=
Raw₀.get!_insertMany_empty_list_of_contains_eq_false contains_eq_false
theorem get!_ofList_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} [Inhabited (β k')]
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(ofList l).get! k' = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v :=
Raw₀.get!_insertMany_empty_list_of_mem k_beq distinct mem
theorem getD_ofList_of_contains_eq_false [LawfulBEq α]
{l : List ((a : α) × β a)} {k : α} {fallback : β k}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(ofList l).getD k fallback = fallback :=
Raw₀.getD_insertMany_empty_list_of_contains_eq_false contains_eq_false
theorem getD_ofList_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} {fallback : β k'}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(ofList l).getD k' fallback = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v :=
Raw₀.getD_insertMany_empty_list_of_mem k_beq distinct mem
theorem getKey?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(ofList l).getKey? k = none :=
Raw₀.getKey?_insertMany_empty_list_of_contains_eq_false contains_eq_false
theorem getKey?_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(ofList l).getKey? k' = some k :=
Raw₀.getKey?_insertMany_empty_list_of_mem k_beq distinct mem
theorem getKey_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst)
{h} :
(ofList l).getKey k' h = k :=
Raw₀.getKey_insertMany_empty_list_of_mem k_beq distinct mem
theorem getKey!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(ofList l).getKey! k = default :=
Raw₀.getKey!_insertMany_empty_list_of_contains_eq_false contains_eq_false
theorem getKey!_ofList_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(ofList l).getKey! k' = k :=
Raw₀.getKey!_insertMany_empty_list_of_mem k_beq distinct mem
theorem getKeyD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k fallback : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(ofList l).getKeyD k fallback = fallback :=
Raw₀.getKeyD_insertMany_empty_list_of_contains_eq_false contains_eq_false
theorem getKeyD_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(ofList l).getKeyD k' fallback = k :=
Raw₀.getKeyD_insertMany_empty_list_of_mem k_beq distinct mem
theorem size_ofList [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
(ofList l).size = l.length :=
Raw₀.size_insertMany_empty_list distinct
theorem size_ofList_le [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} :
(ofList l).size l.length :=
Raw₀.size_insertMany_empty_list_le
@[simp]
theorem isEmpty_ofList [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} :
(ofList l).isEmpty = l.isEmpty :=
Raw₀.isEmpty_insertMany_empty_list
namespace Const
variable {β : Type v}
@[simp]
theorem ofList_nil :
ofList ([] : List (α × β)) = :=
Subtype.eq (congrArg Subtype.val (Raw₀.Const.insertMany_empty_list_nil (α:= α)) :)
@[simp]
theorem ofList_singleton {k : α} {v : β} :
ofList [k, v] = ( : DHashMap α (fun _ => β)).insert k v :=
Subtype.eq (congrArg Subtype.val (Raw₀.Const.insertMany_empty_list_singleton (α:= α)) :)
theorem ofList_cons {k : α} {v : β} {tl : List (α × β)} :
ofList (k, v :: tl) = insertMany (( : DHashMap α (fun _ => β)).insert k v) tl :=
Subtype.eq (congrArg Subtype.val (Raw₀.Const.insertMany_empty_list_cons (α:= α)) :)
@[simp]
theorem contains_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} :
(ofList l).contains k = (l.map Prod.fst).contains k :=
Raw₀.Const.contains_insertMany_empty_list
@[simp]
theorem mem_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} :
k ofList l (l.map Prod.fst).contains k := by
simp [mem_iff_contains]
theorem get?_ofList_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
get? (ofList l) k = none :=
Raw₀.Const.get?_insertMany_empty_list_of_contains_eq_false contains_eq_false
theorem get?_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
get? (ofList l) k' = some v :=
Raw₀.Const.get?_insertMany_empty_list_of_mem k_beq distinct mem
theorem get_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l)
{h} :
get (ofList l) k' h = v :=
Raw₀.Const.get_insertMany_empty_list_of_mem k_beq distinct mem
theorem get!_ofList_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α} [Inhabited β]
(contains_eq_false : (l.map Prod.fst).contains k = false) :
get! (ofList l) k = (default : β) :=
Raw₀.Const.get!_insertMany_empty_list_of_contains_eq_false contains_eq_false
theorem get!_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} [Inhabited β]
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
get! (ofList l) k' = v :=
Raw₀.Const.get!_insertMany_empty_list_of_mem k_beq distinct mem
theorem getD_ofList_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α} {fallback : β}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
getD (ofList l) k fallback = fallback :=
Raw₀.Const.getD_insertMany_empty_list_of_contains_eq_false contains_eq_false
theorem getD_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} {fallback : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
getD (ofList l) k' fallback = v :=
Raw₀.Const.getD_insertMany_empty_list_of_mem k_beq distinct mem
theorem getKey?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l).getKey? k = none :=
Raw₀.Const.getKey?_insertMany_empty_list_of_contains_eq_false contains_eq_false
theorem getKey?_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(ofList l).getKey? k' = some k :=
Raw₀.Const.getKey?_insertMany_empty_list_of_mem k_beq distinct mem
theorem getKey_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst)
{h} :
(ofList l).getKey k' h = k :=
Raw₀.Const.getKey_insertMany_empty_list_of_mem k_beq distinct mem
theorem getKey!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l).getKey! k = default :=
Raw₀.Const.getKey!_insertMany_empty_list_of_contains_eq_false contains_eq_false
theorem getKey!_ofList_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(ofList l).getKey! k' = k :=
Raw₀.Const.getKey!_insertMany_empty_list_of_mem k_beq distinct mem
theorem getKeyD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k fallback : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l).getKeyD k fallback = fallback :=
Raw₀.Const.getKeyD_insertMany_empty_list_of_contains_eq_false contains_eq_false
theorem getKeyD_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(ofList l).getKeyD k' fallback = k :=
Raw₀.Const.getKeyD_insertMany_empty_list_of_mem k_beq distinct mem
theorem size_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
(ofList l).size = l.length :=
Raw₀.Const.size_insertMany_empty_list distinct
theorem size_ofList_le [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(ofList l).size l.length :=
Raw₀.Const.size_insertMany_empty_list_le
@[simp]
theorem isEmpty_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(ofList l).isEmpty = l.isEmpty :=
Raw₀.Const.isEmpty_insertMany_empty_list
@[simp]
theorem unitOfList_nil :
unitOfList ([] : List α) = :=
Subtype.eq (congrArg Subtype.val (Raw₀.Const.insertManyIfNewUnit_empty_list_nil (α := α)) :)
@[simp]
theorem unitOfList_singleton {k : α} :
unitOfList [k] = ( : DHashMap α (fun _ => Unit)).insertIfNew k () :=
Subtype.eq (congrArg Subtype.val (Raw₀.Const.insertManyIfNewUnit_empty_list_singleton (α := α)) :)
theorem unitOfList_cons {hd : α} {tl : List α} :
unitOfList (hd :: tl) =
insertManyIfNewUnit (( : DHashMap α (fun _ => Unit)).insertIfNew hd ()) tl :=
Subtype.eq (congrArg Subtype.val (Raw₀.Const.insertManyIfNewUnit_empty_list_cons (α := α)) :)
@[simp]
theorem contains_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
(unitOfList l).contains k = l.contains k :=
Raw₀.Const.contains_insertManyIfNewUnit_empty_list
@[simp]
theorem mem_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
k unitOfList l l.contains k := by
simp [mem_iff_contains]
theorem getKey?_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (contains_eq_false : l.contains k = false) :
getKey? (unitOfList l) k = none :=
Raw₀.Const.getKey?_insertManyIfNewUnit_empty_list_of_contains_eq_false contains_eq_false
theorem getKey?_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getKey? (unitOfList l) k' = some k :=
Raw₀.Const.getKey?_insertManyIfNewUnit_empty_list_of_mem k_beq distinct mem
theorem getKey_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) {h} :
getKey (unitOfList l) k' h = k :=
Raw₀.Const.getKey_insertManyIfNewUnit_empty_list_of_mem k_beq distinct mem
theorem getKey!_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k : α}
(contains_eq_false : l.contains k = false) :
getKey! (unitOfList l) k = default :=
Raw₀.Const.getKey!_insertManyIfNewUnit_empty_list_of_contains_eq_false contains_eq_false
theorem getKey!_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
getKey! (unitOfList l) k' = k :=
Raw₀.Const.getKey!_insertManyIfNewUnit_empty_list_of_mem k_beq distinct mem
theorem getKeyD_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k fallback : α}
(contains_eq_false : l.contains k = false) :
getKeyD (unitOfList l) k fallback = fallback :=
Raw₀.Const.getKeyD_insertManyIfNewUnit_empty_list_of_contains_eq_false contains_eq_false
theorem getKeyD_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
getKeyD (unitOfList l) k' fallback = k :=
Raw₀.Const.getKeyD_insertManyIfNewUnit_empty_list_of_mem k_beq distinct mem
theorem size_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
(unitOfList l).size = l.length :=
Raw₀.Const.size_insertManyIfNewUnit_empty_list distinct
theorem size_unitOfList_le [EquivBEq α] [LawfulHashable α]
{l : List α} :
(unitOfList l).size l.length :=
Raw₀.Const.size_insertManyIfNewUnit_empty_list_le
@[simp]
theorem isEmpty_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} :
(unitOfList l).isEmpty = l.isEmpty :=
Raw₀.Const.isEmpty_insertManyIfNewUnit_empty_list
@[simp]
theorem get?_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
get? (unitOfList l) k =
if l.contains k then some () else none :=
Raw₀.Const.get?_insertManyIfNewUnit_empty_list
@[simp]
theorem get_unitOfList
{l : List α} {k : α} {h} :
get (unitOfList l) k h = () :=
Raw₀.Const.get_insertManyIfNewUnit_empty_list
@[simp]
theorem get!_unitOfList
{l : List α} {k : α} :
get! (unitOfList l) k = () :=
Raw₀.Const.get!_insertManyIfNewUnit_empty_list
@[simp]
theorem getD_unitOfList
{l : List α} {k : α} {fallback : Unit} :
getD (unitOfList l) k fallback = () := by
simp
end Const
end Std.DHashMap

View File

@@ -94,7 +94,7 @@ Checks whether a key is present in a map, and unconditionally inserts a value fo
Equivalent to (but potentially faster than) calling `contains` followed by `insert`.
-/
@[inline] def containsThenInsert [BEq α] [Hashable α] (m : Raw α β) (a : α) (b : β a) :
Bool × Raw α β:=
Bool × Raw α β :=
if h : 0 < m.buckets.size then
let replaced, r, _ := Raw₀.containsThenInsert m, h a b
replaced, r
@@ -422,29 +422,12 @@ This is mainly useful to implement `HashSet.insertMany`, so if you are consideri
(Raw₀.Const.insertManyIfNewUnit m, h l).1
else m -- will never happen for well-formed inputs
/-- Creates a hash map from a list of mappings. If the same key appears multiple times, the last
occurrence takes precedence. -/
@[inline] def ofList [BEq α] [Hashable α] (l : List ((a : α) × β a)) : Raw α β :=
insertMany l
/-- Computes the union of the given hash maps, by traversing `m₂` and inserting its elements into `m₁`. -/
@[inline] def union [BEq α] [Hashable α] (m₁ m₂ : Raw α β) : Raw α β :=
m₂.fold (init := m₁) fun acc x => acc.insert x
instance [BEq α] [Hashable α] : Union (Raw α β) := union
@[inline, inherit_doc Raw.ofList] def Const.ofList {β : Type v} [BEq α] [Hashable α]
(l : List (α × β)) : Raw α (fun _ => β) :=
Const.insertMany l
/-- Creates a hash map from a list of keys, associating the value `()` with each key.
This is mainly useful to implement `HashSet.ofList`, so if you are considering using this,
`HashSet` or `HashSet.Raw` might be a better fit for you. -/
@[inline] def Const.unitOfList [BEq α] [Hashable α] (l : List α) :
Raw α (fun _ => Unit) :=
Const.insertManyIfNewUnit l
/-- Creates a hash map from an array of keys, associating the value `()` with each key.
This is mainly useful to implement `HashSet.ofArray`, so if you are considering using this,
@@ -470,6 +453,23 @@ end Unverified
@[inline] def keys (m : Raw α β) : List α :=
m.foldRev (fun acc k _ => k :: acc) []
/-- Creates a hash map from a list of mappings. If the same key appears multiple times, the last
occurrence takes precedence. -/
@[inline] def ofList [BEq α] [Hashable α] (l : List ((a : α) × β a)) : Raw α β :=
insertMany l
@[inline, inherit_doc Raw.ofList] def Const.ofList {β : Type v} [BEq α] [Hashable α]
(l : List (α × β)) : Raw α (fun _ => β) :=
Const.insertMany l
/-- Creates a hash map from a list of keys, associating the value `()` with each key.
This is mainly useful to implement `HashSet.ofList`, so if you are considering using this,
`HashSet` or `HashSet.Raw` might be a better fit for you. -/
@[inline] def Const.unitOfList [BEq α] [Hashable α] (l : List α) :
Raw α (fun _ => Unit) :=
Const.insertManyIfNewUnit l
section WF
/--

View File

@@ -58,7 +58,11 @@ private def baseNames : Array Name :=
``getKey?_eq, ``getKey?_val,
``getKey_eq, ``getKey_val,
``getKey!_eq, ``getKey!_val,
``getKeyD_eq, ``getKeyD_val]
``getKeyD_eq, ``getKeyD_val,
``insertMany_eq, ``insertMany_val,
``Const.insertMany_eq, ``Const.insertMany_val,
``Const.insertManyIfNewUnit_eq, ``Const.insertManyIfNewUnit_val,
``ofList_eq, ``Const.ofList_eq, ``Const.unitOfList_eq]
/-- Internal implementation detail of the hash map -/
scoped syntax "simp_to_raw" ("using" term)? : tactic
@@ -765,7 +769,7 @@ theorem getKey!_eq_default_of_contains_eq_false [EquivBEq α] [LawfulHashable α
m.contains a = false m.getKey! a = default := by
simp_to_raw using Raw₀.getKey!_eq_default
theorem getKey!_eq_default [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α}:
theorem getKey!_eq_default [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {a : α} :
¬a m m.getKey! a = default := by
simpa [mem_iff_contains] using getKey!_eq_default_of_contains_eq_false h
@@ -1028,7 +1032,7 @@ theorem length_keys [EquivBEq α] [LawfulHashable α] (h : m.WF) :
simp_to_raw using Raw₀.length_keys m, h.size_buckets_pos h
@[simp]
theorem isEmpty_keys [EquivBEq α] [LawfulHashable α] (h : m.WF):
theorem isEmpty_keys [EquivBEq α] [LawfulHashable α] (h : m.WF) :
m.keys.isEmpty = m.isEmpty := by
simp_to_raw using Raw₀.isEmpty_keys m, h.size_buckets_pos
@@ -1039,7 +1043,7 @@ theorem contains_keys [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α} :
@[simp]
theorem mem_keys [LawfulBEq α] [LawfulHashable α] (h : m.WF) {k : α} :
k m.keys k m := by
k m.keys k m := by
rw [mem_iff_contains]
simp_to_raw using Raw₀.mem_keys m, _ h
@@ -1047,6 +1051,931 @@ theorem distinct_keys [EquivBEq α] [LawfulHashable α] (h : m.WF) :
m.keys.Pairwise (fun a b => (a == b) = false) := by
simp_to_raw using Raw₀.distinct_keys m, h.size_buckets_pos h
@[simp]
theorem insertMany_nil [EquivBEq α] [LawfulHashable α] (h : m.WF) :
m.insertMany [] = m := by
simp_to_raw
rw [Raw₀.insertMany_nil]
@[simp]
theorem insertMany_list_singleton {k : α} {v : β k} [EquivBEq α] [LawfulHashable α] (h : m.WF) :
m.insertMany [k, v] = m.insert k v := by
simp_to_raw
rw [Raw₀.insertMany_list_singleton]
theorem insertMany_cons {l : List ((a : α) × β a)} {k : α} {v : β k} [EquivBEq α] [LawfulHashable α]
(h : m.WF) :
m.insertMany (k, v :: l) = (m.insert k v).insertMany l := by
simp_to_raw
rw [Raw₀.insertMany_cons]
@[simp]
theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List ((a : α) × β a)} {k : α} :
(m.insertMany l).contains k = (m.contains k || (l.map Sigma.fst).contains k) := by
simp_to_raw using Raw₀.contains_insertMany_list
@[simp]
theorem mem_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List ((a : α) × β a)} {k : α} :
k (m.insertMany l) k m (l.map Sigma.fst).contains k := by
simp [mem_iff_contains, contains_insertMany_list h]
theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List ((a : α) × β a)} {k : α} :
k (m.insertMany l) (l.map Sigma.fst).contains k = false k m := by
simp only [mem_iff_contains]
simp_to_raw using Raw₀.contains_of_contains_insertMany_list
theorem get?_insertMany_list_of_contains_eq_false [LawfulBEq α] (h : m.WF)
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).get? k = m.get? k := by
simp_to_raw using Raw₀.get?_insertMany_list_of_contains_eq_false
theorem get?_insertMany_list_of_mem [LawfulBEq α] (h : m.WF)
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(m.insertMany l).get? k' = some (cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v) := by
simp_to_raw using Raw₀.get?_insertMany_list_of_mem
theorem get_insertMany_list_of_contains_eq_false [LawfulBEq α] (h : m.WF)
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false)
{h'} :
(m.insertMany l).get k h' =
m.get k (mem_of_mem_insertMany_list h h' contains_eq_false) := by
simp_to_raw using Raw₀.get_insertMany_list_of_contains_eq_false
theorem get_insertMany_list_of_mem [LawfulBEq α] (h : m.WF)
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l)
{h'} :
(m.insertMany l).get k' h' = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by
simp_to_raw using Raw₀.get_insertMany_list_of_mem
theorem get!_insertMany_list_of_contains_eq_false [LawfulBEq α] (h : m.WF)
{l : List ((a : α) × β a)} {k : α} [Inhabited (β k)]
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).get! k = m.get! k := by
simp_to_raw using Raw₀.get!_insertMany_list_of_contains_eq_false
theorem get!_insertMany_list_of_mem [LawfulBEq α] (h : m.WF)
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} [Inhabited (β k')]
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(m.insertMany l).get! k' = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by
simp_to_raw using Raw₀.get!_insertMany_list_of_mem
theorem getD_insertMany_list_of_contains_eq_false [LawfulBEq α] (h : m.WF)
{l : List ((a : α) × β a)} {k : α} {fallback : β k}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).getD k fallback = m.getD k fallback := by
simp_to_raw using Raw₀.getD_insertMany_list_of_contains_eq_false
theorem getD_insertMany_list_of_mem [LawfulBEq α] (h : m.WF)
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} {fallback : β k'}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(m.insertMany l).getD k' fallback = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by
simp_to_raw using Raw₀.getD_insertMany_list_of_mem
theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).getKey? k = m.getKey? k := by
simp_to_raw using Raw₀.getKey?_insertMany_list_of_contains_eq_false
theorem getKey?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(m.insertMany l).getKey? k' = some k := by
simp_to_raw using Raw₀.getKey?_insertMany_list_of_mem
theorem getKey_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false)
{h'} :
(m.insertMany l).getKey k h' =
m.getKey k (mem_of_mem_insertMany_list h h' contains_eq_false) := by
simp_to_raw using Raw₀.getKey_insertMany_list_of_contains_eq_false
theorem getKey_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst)
{h'} :
(m.insertMany l).getKey k' h' = k := by
simp_to_raw using Raw₀.getKey_insertMany_list_of_mem
theorem getKey!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
(h : m.WF) {l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).getKey! k = m.getKey! k := by
simp_to_raw using Raw₀.getKey!_insertMany_list_of_contains_eq_false
theorem getKey!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF)
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(m.insertMany l).getKey! k' = k := by
simp_to_raw using Raw₀.getKey!_insertMany_list_of_mem
theorem getKeyD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List ((a : α) × β a)} {k fallback : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(m.insertMany l).getKeyD k fallback = m.getKeyD k fallback := by
simp_to_raw using Raw₀.getKeyD_insertMany_list_of_contains_eq_false
theorem getKeyD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List ((a : α) × β a)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(m.insertMany l).getKeyD k' fallback = k := by
simp_to_raw using Raw₀.getKeyD_insertMany_list_of_mem
theorem size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List ((a : α) × β a)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
( (a : α), a m (l.map Sigma.fst).contains a = false)
(m.insertMany l).size = m.size + l.length := by
simp only [mem_iff_contains]
simp_to_raw using Raw₀.size_insertMany_list
theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List ((a : α) × β a)} :
m.size (m.insertMany l).size := by
simp_to_raw using Raw₀.size_le_size_insertMany_list m, _
theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List ((a : α) × β a)} :
(m.insertMany l).size m.size + l.length := by
simp_to_raw using Raw₀.size_insertMany_list_le
@[simp]
theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List ((a : α) × β a)} :
(m.insertMany l).isEmpty = (m.isEmpty && l.isEmpty) := by
simp_to_raw using Raw₀.isEmpty_insertMany_list
namespace Const
variable {β : Type v} {m : Raw α (fun _ => β)}
@[simp]
theorem insertMany_nil (h : m.WF) :
insertMany m [] = m := by
simp_to_raw
rw [Raw₀.Const.insertMany_nil]
@[simp]
theorem insertMany_list_singleton (h : m.WF)
{k : α} {v : β} :
insertMany m [k, v] = m.insert k v := by
simp_to_raw
rw [Raw₀.Const.insertMany_list_singleton]
theorem insertMany_cons (h : m.WF) {l : List (α × β)}
{k : α} {v : β} :
insertMany m (k, v :: l) = insertMany (m.insert k v) l := by
simp_to_raw
rw [Raw₀.Const.insertMany_cons]
@[simp]
theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k : α} :
(insertMany m l).contains k = (m.contains k || (l.map Prod.fst).contains k) := by
simp_to_raw using Raw₀.Const.contains_insertMany_list
@[simp]
theorem mem_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k : α} :
k insertMany m l k m (l.map Prod.fst).contains k := by
simp [mem_iff_contains, contains_insertMany_list h]
theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k : α} :
k insertMany m l (l.map Prod.fst).contains k = false k m := by
simp only [mem_iff_contains]
simp_to_raw using Raw₀.Const.contains_of_contains_insertMany_list
theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l).getKey? k = m.getKey? k := by
simp_to_raw using Raw₀.Const.getKey?_insertMany_list_of_contains_eq_false
theorem getKey?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).getKey? k' = some k := by
simp_to_raw using Raw₀.Const.getKey?_insertMany_list_of_mem
theorem getKey_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false)
{h'} :
(insertMany m l).getKey k h' =
m.getKey k (mem_of_mem_insertMany_list h h' contains_eq_false) := by
simp_to_raw using Raw₀.Const.getKey_insertMany_list_of_contains_eq_false
theorem getKey_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst)
{h'} :
(insertMany m l).getKey k' h' = k := by
simp_to_raw using Raw₀.Const.getKey_insertMany_list_of_mem
theorem getKey!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
(h : m.WF) {l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l).getKey! k = m.getKey! k := by
simp_to_raw using Raw₀.Const.getKey!_insertMany_list_of_contains_eq_false
theorem getKey!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF)
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).getKey! k' = k := by
simp_to_raw using Raw₀.Const.getKey!_insertMany_list_of_mem
theorem getKeyD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k fallback : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l).getKeyD k fallback = m.getKeyD k fallback := by
simp_to_raw using Raw₀.Const.getKeyD_insertMany_list_of_contains_eq_false
theorem getKeyD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).getKeyD k' fallback = k := by
simp_to_raw using Raw₀.Const.getKeyD_insertMany_list_of_mem
theorem size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
( (a : α), a m (l.map Prod.fst).contains a = false)
(insertMany m l).size = m.size + l.length := by
simp [mem_iff_contains]
simp_to_raw using Raw₀.Const.size_insertMany_list
theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} :
m.size (insertMany m l).size := by
simp_to_raw using Raw₀.Const.size_le_size_insertMany_list m, _
theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} :
(insertMany m l).size m.size + l.length := by
simp_to_raw using Raw₀.Const.size_insertMany_list_le
@[simp]
theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} :
(insertMany m l).isEmpty = (m.isEmpty && l.isEmpty) := by
simp_to_raw using Raw₀.Const.isEmpty_insertMany_list
theorem get?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
get? (insertMany m l) k = get? m k := by
simp_to_raw using Raw₀.Const.get?_insertMany_list_of_contains_eq_false
theorem get?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
get? (insertMany m l) k' = v := by
simp_to_raw using Raw₀.Const.get?_insertMany_list_of_mem
theorem get_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false)
{h'} :
get (insertMany m l) k h' =
get m k (mem_of_mem_insertMany_list h h' contains_eq_false) := by
simp_to_raw using Raw₀.Const.get_insertMany_list_of_contains_eq_false
theorem get_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l){h'} :
get (insertMany m l) k' h' = v := by
simp_to_raw using Raw₀.Const.get_insertMany_list_of_mem
theorem get!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited β] (h : m.WF) {l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
get! (insertMany m l) k = get! m k := by
simp_to_raw using Raw₀.Const.get!_insertMany_list_of_contains_eq_false
theorem get!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited β] (h : m.WF)
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
get! (insertMany m l) k' = v := by
simp_to_raw using Raw₀.Const.get!_insertMany_list_of_mem
theorem getD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k : α} {fallback : β}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
getD (insertMany m l) k fallback = getD m k fallback := by
simp_to_raw using Raw₀.Const.getD_insertMany_list_of_contains_eq_false
theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v fallback : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
getD (insertMany m l) k' fallback = v := by
simp_to_raw using Raw₀.Const.getD_insertMany_list_of_mem
variable {m : Raw α (fun _ => Unit)}
@[simp]
theorem insertManyIfNewUnit_nil (h : m.WF) :
insertManyIfNewUnit m [] = m := by
simp_to_raw
rw [Raw₀.Const.insertManyIfNewUnit_nil]
@[simp]
theorem insertManyIfNewUnit_list_singleton {k : α} (h : m.WF) :
insertManyIfNewUnit m [k] = m.insertIfNew k () := by
simp_to_raw
rw [Raw₀.Const.insertManyIfNewUnit_list_singleton]
theorem insertManyIfNewUnit_cons (h : m.WF) {l : List α} {k : α} :
insertManyIfNewUnit m (k :: l) = insertManyIfNewUnit (m.insertIfNew k ()) l := by
simp_to_raw
rw [Raw₀.Const.insertManyIfNewUnit_cons]
@[simp]
theorem contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} {k : α} :
(insertManyIfNewUnit m l).contains k = (m.contains k || l.contains k) := by
simp_to_raw using Raw₀.Const.contains_insertManyIfNewUnit_list
@[simp]
theorem mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} {k : α} :
k insertManyIfNewUnit m l k m l.contains k := by
simp [mem_iff_contains, contains_insertManyIfNewUnit_list h]
theorem mem_of_mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} {k : α} (contains_eq_false : l.contains k = false) :
k insertManyIfNewUnit m l k m := by
simp only [mem_iff_contains]
simp_to_raw using Raw₀.Const.contains_of_contains_insertManyIfNewUnit_list
theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k : α} :
¬ k m l.contains k = false
getKey? (insertManyIfNewUnit m l) k = none := by
simp only [mem_iff_contains, Bool.not_eq_true]
simp_to_raw using Raw₀.Const.getKey?_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false
theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k k' : α} (k_beq : k == k') :
¬ k m l.Pairwise (fun a b => (a == b) = false) k l
getKey? (insertManyIfNewUnit m l) k' = some k := by
simp only [mem_iff_contains, Bool.not_eq_true]
simp_to_raw using Raw₀.Const.getKey?_insertManyIfNewUnit_list_of_contains_eq_false_of_mem
theorem getKey?_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k : α} :
k m getKey? (insertManyIfNewUnit m l) k = getKey? m k := by
simp only [mem_iff_contains]
simp_to_raw using Raw₀.Const.getKey?_insertManyIfNewUnit_list_of_contains
theorem getKey_insertManyIfNewUnit_list_of_mem
[EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k : α} {h'} (mem : k m) :
getKey (insertManyIfNewUnit m l) k h' = getKey m k mem := by
simp_to_raw using Raw₀.Const.getKey_insertManyIfNewUnit_list_of_contains
theorem getKey_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α}
{k k' : α} (k_beq : k == k') {h'} :
¬ k m l.Pairwise (fun a b => (a == b) = false) k l
getKey (insertManyIfNewUnit m l) k' h' = k := by
simp only [mem_iff_contains, Bool.not_eq_true]
simp_to_raw using Raw₀.Const.getKey_insertManyIfNewUnit_list_of_contains_eq_false_of_mem
theorem getKey!_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {l : List α} {k : α} :
¬ k m l.contains k = false getKey! (insertManyIfNewUnit m l) k = default := by
simp only [mem_iff_contains, Bool.not_eq_true]
simp_to_raw using
Raw₀.Const.getKey!_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false
theorem getKey!_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] (h : m.WF) {l : List α} {k k' : α} (k_beq : k == k') :
¬ k m l.Pairwise (fun a b => (a == b) = false) k l
getKey! (insertManyIfNewUnit m l) k' = k := by
simp only [mem_iff_contains, Bool.not_eq_true]
simp_to_raw using Raw₀.Const.getKey!_insertManyIfNewUnit_list_of_contains_eq_false_of_mem
theorem getKey!_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] (h : m.WF) {l : List α} {k : α} :
k m getKey! (insertManyIfNewUnit m l) k = getKey! m k := by
simp only [mem_iff_contains]
simp_to_raw using Raw₀.Const.getKey!_insertManyIfNewUnit_list_of_contains
theorem getKeyD_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k fallback : α} :
¬ k m l.contains k = false
getKeyD (insertManyIfNewUnit m l) k fallback = fallback := by
simp only [mem_iff_contains, Bool.not_eq_true]
simp_to_raw using
Raw₀.Const.getKeyD_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false
theorem getKeyD_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k k' fallback : α} (k_beq : k == k') :
¬ k m l.Pairwise (fun a b => (a == b) = false) k l
getKeyD (insertManyIfNewUnit m l) k' fallback = k := by
simp only [mem_iff_contains, Bool.not_eq_true]
simp_to_raw using Raw₀.Const.getKeyD_insertManyIfNewUnit_list_of_contains_eq_false_of_mem
theorem getKeyD_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k fallback : α} :
k m getKeyD (insertManyIfNewUnit m l) k fallback = getKeyD m k fallback := by
simp only [mem_iff_contains]
simp_to_raw using Raw₀.Const.getKeyD_insertManyIfNewUnit_list_of_contains
theorem size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
( (a : α), a m l.contains a = false)
(insertManyIfNewUnit m l).size = m.size + l.length := by
simp only [mem_iff_contains]
simp_to_raw using Raw₀.Const.size_insertManyIfNewUnit_list
theorem size_le_size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} :
m.size (insertManyIfNewUnit m l).size := by
simp_to_raw using Raw₀.Const.size_le_size_insertManyIfNewUnit_list m, _
theorem size_insertManyIfNewUnit_list_le [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} :
(insertManyIfNewUnit m l).size m.size + l.length := by
simp_to_raw using Raw₀.Const.size_insertManyIfNewUnit_list_le
@[simp]
theorem isEmpty_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} :
(insertManyIfNewUnit m l).isEmpty = (m.isEmpty && l.isEmpty) := by
simp_to_raw using Raw₀.Const.isEmpty_insertManyIfNewUnit_list
@[simp]
theorem get?_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} {k : α} :
get? (insertManyIfNewUnit m l) k =
if k m l.contains k then some () else none := by
simp only [mem_iff_contains]
simp_to_raw using Raw₀.Const.get?_insertManyIfNewUnit_list
@[simp]
theorem get_insertManyIfNewUnit_list
{l : List α} {k : α} {h} :
get (insertManyIfNewUnit m l) k h = () := by
simp
@[simp]
theorem get!_insertManyIfNewUnit_list
{l : List α} {k : α} :
get! (insertManyIfNewUnit m l) k = () := by
simp
@[simp]
theorem getD_insertManyIfNewUnit_list
{l : List α} {k : α} {fallback : Unit} :
getD (insertManyIfNewUnit m l) k fallback = () := by
simp
end Const
end Raw
namespace Raw
variable [BEq α] [Hashable α]
open Internal.Raw Internal.Raw₀
@[simp]
theorem ofList_nil :
ofList ([] : List ((a : α) × (β a))) = := by
simp_to_raw
rw [Raw₀.insertMany_empty_list_nil]
@[simp]
theorem ofList_singleton {k : α} {v : β k} :
ofList [k, v] = ( : Raw α β).insert k v := by
simp_to_raw
rw [Raw₀.insertMany_empty_list_singleton]
theorem ofList_cons [EquivBEq α] [LawfulHashable α] {k : α} {v : β k} {tl : List ((a : α) × (β a))} :
ofList (k, v :: tl) = (( : Raw α β).insert k v).insertMany tl := by
simp_to_raw
rw [Raw₀.insertMany_empty_list_cons]
@[simp]
theorem contains_ofList [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k : α} :
(ofList l).contains k = (l.map Sigma.fst).contains k := by
simp_to_raw using Raw₀.contains_insertMany_empty_list
@[simp]
theorem mem_ofList [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k : α} :
k ofList l (l.map Sigma.fst).contains k := by
simp [mem_iff_contains]
theorem get?_ofList_of_contains_eq_false [LawfulBEq α]
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(ofList l).get? k = none := by
simp_to_raw using Raw₀.get?_insertMany_empty_list_of_contains_eq_false
theorem get?_ofList_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(ofList l).get? k' = some (cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v) := by
simp_to_raw using Raw₀.get?_insertMany_empty_list_of_mem
theorem get_ofList_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l)
{h} :
(ofList l).get k' h = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by
simp_to_raw using Raw₀.get_insertMany_empty_list_of_mem
theorem get!_ofList_of_contains_eq_false [LawfulBEq α]
{l : List ((a : α) × β a)} {k : α} [Inhabited (β k)]
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(ofList l).get! k = default := by
simp_to_raw using get!_insertMany_empty_list_of_contains_eq_false
theorem get!_ofList_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} [Inhabited (β k')]
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(ofList l).get! k' = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by
simp_to_raw using Raw₀.get!_insertMany_empty_list_of_mem
theorem getD_ofList_of_contains_eq_false [LawfulBEq α]
{l : List ((a : α) × β a)} {k : α} {fallback : β k}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(ofList l).getD k fallback = fallback := by
simp_to_raw using Raw₀.getD_insertMany_empty_list_of_contains_eq_false
theorem getD_ofList_of_mem [LawfulBEq α]
{l : List ((a : α) × β a)} {k k' : α} (k_beq : k == k') {v : β k} {fallback : β k'}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(ofList l).getD k' fallback = cast (by congr; apply LawfulBEq.eq_of_beq k_beq) v := by
simp_to_raw using Raw₀.getD_insertMany_empty_list_of_mem
theorem getKey?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(ofList l).getKey? k = none := by
simp_to_raw using Raw₀.getKey?_insertMany_empty_list_of_contains_eq_false
theorem getKey?_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(ofList l).getKey? k' = some k := by
simp_to_raw using Raw₀.getKey?_insertMany_empty_list_of_mem
theorem getKey_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst)
{h'} :
(ofList l).getKey k' h' = k := by
simp_to_raw using Raw₀.getKey_insertMany_empty_list_of_mem
theorem getKey!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List ((a : α) × β a)} {k : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(ofList l).getKey! k = default := by
simp_to_raw using Raw₀.getKey!_insertMany_empty_list_of_contains_eq_false
theorem getKey!_ofList_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List ((a : α) × β a)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(ofList l).getKey! k' = k := by
simp_to_raw using Raw₀.getKey!_insertMany_empty_list_of_mem
theorem getKeyD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} {k fallback : α}
(contains_eq_false : (l.map Sigma.fst).contains k = false) :
(ofList l).getKeyD k fallback = fallback := by
simp_to_raw using Raw₀.getKeyD_insertMany_empty_list_of_contains_eq_false
theorem getKeyD_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Sigma.fst) :
(ofList l).getKeyD k' fallback = k := by
simp_to_raw using Raw₀.getKeyD_insertMany_empty_list_of_mem
theorem size_ofList [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
(ofList l).size = l.length := by
simp_to_raw using Raw₀.size_insertMany_empty_list
theorem size_ofList_le [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} :
(ofList l).size l.length := by
simp_to_raw using Raw₀.size_insertMany_empty_list_le
@[simp]
theorem isEmpty_ofList [EquivBEq α] [LawfulHashable α]
{l : List ((a : α) × β a)} :
(ofList l).isEmpty = l.isEmpty := by
simp_to_raw using Raw₀.isEmpty_insertMany_empty_list
namespace Const
variable {β : Type v}
@[simp]
theorem ofList_nil :
ofList ([] : List (α × β)) = := by
simp_to_raw
simp
@[simp]
theorem ofList_singleton {k : α} {v : β} :
ofList [k, v] = ( : Raw α (fun _ => β)).insert k v := by
simp_to_raw
simp
theorem ofList_cons {k : α} {v : β} {tl : List (α × β)} :
ofList (k, v :: tl) = insertMany (( : Raw α (fun _ => β)).insert k v) tl := by
simp_to_raw
rw [Raw₀.Const.insertMany_empty_list_cons]
@[simp]
theorem contains_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} :
(ofList l).contains k = (l.map Prod.fst).contains k := by
simp_to_raw using Raw₀.Const.contains_insertMany_empty_list
@[simp]
theorem mem_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} :
k (ofList l) (l.map Prod.fst).contains k := by
simp [mem_iff_contains]
theorem get?_ofList_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
get? (ofList l) k = none := by
simp_to_raw using Raw₀.Const.get?_insertMany_empty_list_of_contains_eq_false
theorem get?_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
get? (ofList l) k' = some v := by
simp_to_raw using Raw₀.Const.get?_insertMany_empty_list_of_mem
theorem get_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l)
{h} :
get (ofList l) k' h = v := by
simp_to_raw using Raw₀.Const.get_insertMany_empty_list_of_mem
theorem get!_ofList_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α} [Inhabited β]
(contains_eq_false : (l.map Prod.fst).contains k = false) :
get! (ofList l) k = default := by
simp_to_raw using Raw₀.Const.get!_insertMany_empty_list_of_contains_eq_false
theorem get!_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} [Inhabited β]
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
get! (ofList l) k' = v := by
simp_to_raw using Raw₀.Const.get!_insertMany_empty_list_of_mem
theorem getD_ofList_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α} {fallback : β}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
getD (ofList l) k fallback = fallback := by
simp_to_raw using Raw₀.Const.getD_insertMany_empty_list_of_contains_eq_false
theorem getD_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} {fallback : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
getD (ofList l) k' fallback = v := by
simp_to_raw using Raw₀.Const.getD_insertMany_empty_list_of_mem
theorem getKey?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l).getKey? k = none := by
simp_to_raw using Raw₀.Const.getKey?_insertMany_empty_list_of_contains_eq_false
theorem getKey?_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(ofList l).getKey? k' = some k := by
simp_to_raw using Raw₀.Const.getKey?_insertMany_empty_list_of_mem
theorem getKey_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst)
{h'} :
(ofList l).getKey k' h' = k := by
simp_to_raw using Raw₀.Const.getKey_insertMany_empty_list_of_mem
theorem getKey!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l).getKey! k = default := by
simp_to_raw using Raw₀.Const.getKey!_insertMany_empty_list_of_contains_eq_false
theorem getKey!_ofList_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(ofList l).getKey! k' = k := by
simp_to_raw using Raw₀.Const.getKey!_insertMany_empty_list_of_mem
theorem getKeyD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k fallback : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l).getKeyD k fallback = fallback := by
simp_to_raw using Raw₀.Const.getKeyD_insertMany_empty_list_of_contains_eq_false
theorem getKeyD_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(ofList l).getKeyD k' fallback = k := by
simp_to_raw using Raw₀.Const.getKeyD_insertMany_empty_list_of_mem
theorem size_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
(ofList l).size = l.length := by
simp_to_raw using Raw₀.Const.size_insertMany_empty_list
theorem size_ofList_le [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(ofList l).size l.length := by
simp_to_raw using Raw₀.Const.size_insertMany_empty_list_le
@[simp]
theorem isEmpty_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(ofList l).isEmpty = l.isEmpty := by
simp_to_raw using Raw₀.Const.isEmpty_insertMany_empty_list
@[simp]
theorem unitOfList_nil :
unitOfList ([] : List α) = := by
simp_to_raw
simp
@[simp]
theorem unitOfList_singleton {k : α} :
unitOfList [k] = ( : Raw α (fun _ => Unit)).insertIfNew k () := by
simp_to_raw
simp
theorem unitOfList_cons {hd : α} {tl : List α} :
unitOfList (hd :: tl) = insertManyIfNewUnit (( : Raw α (fun _ => Unit)).insertIfNew hd ()) tl := by
simp_to_raw
rw [Raw₀.Const.insertManyIfNewUnit_empty_list_cons]
@[simp]
theorem contains_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
(unitOfList l).contains k = l.contains k := by
simp_to_raw using Raw₀.Const.contains_insertManyIfNewUnit_empty_list
@[simp]
theorem mem_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
k unitOfList l l.contains k := by
simp [mem_iff_contains]
theorem getKey?_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (contains_eq_false : l.contains k = false) :
getKey? (unitOfList l) k = none := by
simp_to_raw using Raw₀.Const.getKey?_insertManyIfNewUnit_empty_list_of_contains_eq_false
theorem getKey?_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getKey? (unitOfList l) k' = some k := by
simp_to_raw using Raw₀.Const.getKey?_insertManyIfNewUnit_empty_list_of_mem
theorem getKey_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) {h'} :
getKey (unitOfList l) k' h' = k := by
simp_to_raw using Raw₀.Const.getKey_insertManyIfNewUnit_empty_list_of_mem
theorem getKey!_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k : α}
(contains_eq_false : l.contains k = false) :
getKey! (unitOfList l) k = default := by
simp_to_raw using Raw₀.Const.getKey!_insertManyIfNewUnit_empty_list_of_contains_eq_false
theorem getKey!_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
getKey! (unitOfList l) k' = k := by
simp_to_raw using Raw₀.Const.getKey!_insertManyIfNewUnit_empty_list_of_mem
theorem getKeyD_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k fallback : α}
(contains_eq_false : l.contains k = false) :
getKeyD (unitOfList l) k fallback = fallback := by
simp_to_raw using Raw₀.Const.getKeyD_insertManyIfNewUnit_empty_list_of_contains_eq_false
theorem getKeyD_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l ) :
getKeyD (unitOfList l) k' fallback = k := by
simp_to_raw using Raw₀.Const.getKeyD_insertManyIfNewUnit_empty_list_of_mem
theorem size_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
(unitOfList l).size = l.length := by
simp_to_raw using Raw₀.Const.size_insertManyIfNewUnit_empty_list
theorem size_unitOfList_le [EquivBEq α] [LawfulHashable α]
{l : List α} :
(unitOfList l).size l.length := by
simp_to_raw using Raw₀.Const.size_insertManyIfNewUnit_empty_list_le
@[simp]
theorem isEmpty_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} :
(unitOfList l).isEmpty = l.isEmpty := by
simp_to_raw using Raw₀.Const.isEmpty_insertManyIfNewUnit_empty_list
@[simp]
theorem get?_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
get? (unitOfList l) k =
if l.contains k then some () else none := by
simp_to_raw using Raw₀.Const.get?_insertManyIfNewUnit_empty_list
@[simp]
theorem get_unitOfList
{l : List α} {k : α} {h} :
get (unitOfList l) k h = () := by
simp
@[simp]
theorem get!_unitOfList
{l : List α} {k : α} :
get! (unitOfList l) k = () := by
simp
@[simp]
theorem getD_unitOfList
{l : List α} {k : α} {fallback : Unit} :
getD (unitOfList l) k fallback = () := by
simp
end Const
end Raw
end Std.DHashMap

View File

@@ -191,6 +191,14 @@ instance [BEq α] [Hashable α] : GetElem? (HashMap α β) α β (fun m a => a
@[inline, inherit_doc DHashMap.keys] def keys (m : HashMap α β) : List α :=
m.inner.keys
@[inline, inherit_doc DHashMap.Const.ofList] def ofList [BEq α] [Hashable α] (l : List (α × β)) :
HashMap α β :=
DHashMap.Const.ofList l
@[inline, inherit_doc DHashMap.Const.unitOfList] def unitOfList [BEq α] [Hashable α] (l : List α) :
HashMap α Unit :=
DHashMap.Const.unitOfList l
section Unverified
/-! We currently do not provide lemmas for the functions below. -/
@@ -261,20 +269,12 @@ instance [BEq α] [Hashable α] {m : Type w → Type w} : ForIn m (HashMap α β
{ρ : Type w} [ForIn Id ρ α] (m : HashMap α Unit) (l : ρ) : HashMap α Unit :=
DHashMap.Const.insertManyIfNewUnit m.inner l
@[inline, inherit_doc DHashMap.Const.ofList] def ofList [BEq α] [Hashable α] (l : List (α × β)) :
HashMap α β :=
DHashMap.Const.ofList l
/-- Computes the union of the given hash maps, by traversing `m₂` and inserting its elements into `m₁`. -/
@[inline] def union [BEq α] [Hashable α] (m₁ m₂ : HashMap α β) : HashMap α β :=
m₂.fold (init := m₁) fun acc x => acc.insert x
instance [BEq α] [Hashable α] : Union (HashMap α β) := union
@[inline, inherit_doc DHashMap.Const.unitOfList] def unitOfList [BEq α] [Hashable α] (l : List α) :
HashMap α Unit :=
DHashMap.Const.unitOfList l
@[inline, inherit_doc DHashMap.Const.unitOfArray] def unitOfArray [BEq α] [Hashable α] (l : Array α) :
HashMap α Unit :=
DHashMap.Const.unitOfArray l

View File

@@ -698,6 +698,575 @@ theorem distinct_keys [EquivBEq α] [LawfulHashable α] :
m.keys.Pairwise (fun a b => (a == b) = false) :=
DHashMap.distinct_keys
@[simp]
theorem insertMany_nil :
insertMany m [] = m :=
ext DHashMap.Const.insertMany_nil
@[simp]
theorem insertMany_list_singleton {k : α} {v : β} :
insertMany m [k, v] = m.insert k v :=
ext DHashMap.Const.insertMany_list_singleton
theorem insertMany_cons {l : List (α × β)} {k : α} {v : β} :
insertMany m (k, v :: l) = insertMany (m.insert k v) l :=
ext DHashMap.Const.insertMany_cons
@[simp]
theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} :
(insertMany m l).contains k = (m.contains k || (l.map Prod.fst).contains k) :=
DHashMap.Const.contains_insertMany_list
@[simp]
theorem mem_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} :
k insertMany m l k m (l.map Prod.fst).contains k :=
DHashMap.Const.mem_insertMany_list
theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} (mem : k insertMany m l)
(contains_eq_false : (l.map Prod.fst).contains k = false) :
k m :=
DHashMap.Const.mem_of_mem_insertMany_list mem contains_eq_false
theorem getElem?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l)[k]? = m[k]? :=
DHashMap.Const.get?_insertMany_list_of_contains_eq_false contains_eq_false
theorem getElem?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
(insertMany m l)[k']? = some v :=
DHashMap.Const.get?_insertMany_list_of_mem k_beq distinct mem
theorem getElem_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false)
{h} :
(insertMany m l)[k] = m[k]'(mem_of_mem_insertMany_list h contains_eq_false) :=
DHashMap.Const.get_insertMany_list_of_contains_eq_false contains_eq_false
theorem getElem_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) {h} :
(insertMany m l)[k'] = v :=
DHashMap.Const.get_insertMany_list_of_mem k_beq distinct mem
theorem getElem!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited β] {l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l)[k]! = m[k]! :=
DHashMap.Const.get!_insertMany_list_of_contains_eq_false contains_eq_false
theorem getElem!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited β]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
(insertMany m l)[k']! = v :=
DHashMap.Const.get!_insertMany_list_of_mem k_beq distinct mem
theorem getD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} {fallback : β}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
getD (insertMany m l) k fallback = getD m k fallback :=
DHashMap.Const.getD_insertMany_list_of_contains_eq_false contains_eq_false
theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v fallback : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
getD (insertMany m l) k' fallback = v :=
DHashMap.Const.getD_insertMany_list_of_mem k_beq distinct mem
theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l).getKey? k = m.getKey? k :=
DHashMap.Const.getKey?_insertMany_list_of_contains_eq_false contains_eq_false
theorem getKey?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).getKey? k' = some k :=
DHashMap.Const.getKey?_insertMany_list_of_mem k_beq distinct mem
theorem getKey_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false)
{h} :
(insertMany m l).getKey k h =
m.getKey k (mem_of_mem_insertMany_list h contains_eq_false) :=
DHashMap.Const.getKey_insertMany_list_of_contains_eq_false contains_eq_false
theorem getKey_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst)
{h} :
(insertMany m l).getKey k' h = k :=
DHashMap.Const.getKey_insertMany_list_of_mem k_beq distinct mem
theorem getKey!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l).getKey! k = m.getKey! k :=
DHashMap.Const.getKey!_insertMany_list_of_contains_eq_false contains_eq_false
theorem getKey!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).getKey! k' = k :=
DHashMap.Const.getKey!_insertMany_list_of_mem k_beq distinct mem
theorem getKeyD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k fallback : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l).getKeyD k fallback = m.getKeyD k fallback :=
DHashMap.Const.getKeyD_insertMany_list_of_contains_eq_false contains_eq_false
theorem getKeyD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).getKeyD k' fallback = k :=
DHashMap.Const.getKeyD_insertMany_list_of_mem k_beq distinct mem
theorem size_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
( (a : α), a m (l.map Prod.fst).contains a = false)
(insertMany m l).size = m.size + l.length :=
DHashMap.Const.size_insertMany_list distinct
theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
m.size (insertMany m l).size :=
DHashMap.Const.size_le_size_insertMany_list
theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(insertMany m l).size m.size + l.length :=
DHashMap.Const.size_insertMany_list_le
@[simp]
theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(insertMany m l).isEmpty = (m.isEmpty && l.isEmpty) :=
DHashMap.Const.isEmpty_insertMany_list
variable {m : HashMap α Unit}
@[simp]
theorem insertManyIfNewUnit_nil :
insertManyIfNewUnit m [] = m :=
ext DHashMap.Const.insertManyIfNewUnit_nil
@[simp]
theorem insertManyIfNewUnit_list_singleton {k : α} :
insertManyIfNewUnit m [k] = m.insertIfNew k () :=
ext DHashMap.Const.insertManyIfNewUnit_list_singleton
theorem insertManyIfNewUnit_cons {l : List α} {k : α} :
insertManyIfNewUnit m (k :: l) = insertManyIfNewUnit (m.insertIfNew k ()) l :=
ext DHashMap.Const.insertManyIfNewUnit_cons
@[simp]
theorem contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
(insertManyIfNewUnit m l).contains k = (m.contains k || l.contains k) :=
DHashMap.Const.contains_insertManyIfNewUnit_list
@[simp]
theorem mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
k insertManyIfNewUnit m l k m l.contains k :=
DHashMap.Const.mem_insertManyIfNewUnit_list
theorem mem_of_mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (contains_eq_false : l.contains k = false) :
k insertManyIfNewUnit m l k m :=
DHashMap.Const.mem_of_mem_insertManyIfNewUnit_list contains_eq_false
theorem getElem?_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
(insertManyIfNewUnit m l)[k]? =
if k m l.contains k then some () else none :=
DHashMap.Const.get?_insertManyIfNewUnit_list
theorem getElem_insertManyIfNewUnit_list
{l : List α} {k : α} {h} :
(insertManyIfNewUnit m l)[k] = () :=
DHashMap.Const.get_insertManyIfNewUnit_list
theorem getElem!_insertManyIfNewUnit_list
{l : List α} {k : α} :
(insertManyIfNewUnit m l)[k]! = () :=
DHashMap.Const.get!_insertManyIfNewUnit_list
theorem getD_insertManyIfNewUnit_list
{l : List α} {k : α} {fallback : Unit} :
getD (insertManyIfNewUnit m l) k fallback = () := by
simp
theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] {l : List α} {k : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
getKey? (insertManyIfNewUnit m l) k = none :=
DHashMap.Const.getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
not_mem contains_eq_false
theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' : α} (k_beq : k == k') (not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getKey? (insertManyIfNewUnit m l) k' = some k :=
DHashMap.Const.getKey?_insertManyIfNewUnit_list_of_not_mem_of_mem
k_beq not_mem distinct mem
theorem getKey?_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (mem : k m) :
getKey? (insertManyIfNewUnit m l) k = getKey? m k :=
DHashMap.Const.getKey?_insertManyIfNewUnit_list_of_mem mem
theorem getKey_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' : α} (k_beq : k == k') (not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) {h} :
getKey (insertManyIfNewUnit m l) k' h = k :=
DHashMap.Const.getKey_insertManyIfNewUnit_list_of_not_mem_of_mem
k_beq not_mem distinct mem
theorem getKey_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (mem : k m) {h} :
getKey (insertManyIfNewUnit m l) k h = getKey m k mem :=
DHashMap.Const.getKey_insertManyIfNewUnit_list_of_mem mem
theorem getKey!_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] [Inhabited α] {l : List α} {k : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
getKey! (insertManyIfNewUnit m l) k = default :=
DHashMap.Const.getKey!_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
not_mem contains_eq_false
theorem getKey!_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k k' : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getKey! (insertManyIfNewUnit m l) k' = k :=
DHashMap.Const.getKey!_insertManyIfNewUnit_list_of_not_mem_of_mem
k_beq not_mem distinct mem
theorem getKey!_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k : α} (mem : k m) :
getKey! (insertManyIfNewUnit m l) k = getKey! m k :=
DHashMap.Const.getKey!_insertManyIfNewUnit_list_of_mem mem
theorem getKeyD_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] {l : List α} {k fallback : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
getKeyD (insertManyIfNewUnit m l) k fallback = fallback :=
DHashMap.Const.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
not_mem contains_eq_false
theorem getKeyD_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' fallback : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l ) :
getKeyD (insertManyIfNewUnit m l) k' fallback = k :=
DHashMap.Const.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_mem
k_beq not_mem distinct mem
theorem getKeyD_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k fallback : α} (mem : k m) :
getKeyD (insertManyIfNewUnit m l) k fallback = getKeyD m k fallback :=
DHashMap.Const.getKeyD_insertManyIfNewUnit_list_of_mem mem
theorem size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
( (a : α), a m l.contains a = false)
(insertManyIfNewUnit m l).size = m.size + l.length :=
DHashMap.Const.size_insertManyIfNewUnit_list distinct
theorem size_le_size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α} :
m.size (insertManyIfNewUnit m l).size :=
DHashMap.Const.size_le_size_insertManyIfNewUnit_list
theorem size_insertManyIfNewUnit_list_le [EquivBEq α] [LawfulHashable α]
{l : List α} :
(insertManyIfNewUnit m l).size m.size + l.length :=
DHashMap.Const.size_insertManyIfNewUnit_list_le
@[simp]
theorem isEmpty_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
{l : List α} :
(insertManyIfNewUnit m l).isEmpty = (m.isEmpty && l.isEmpty) :=
DHashMap.Const.isEmpty_insertManyIfNewUnit_list
end
section
@[simp]
theorem ofList_nil :
ofList ([] : List (α × β)) = :=
ext DHashMap.Const.ofList_nil
@[simp]
theorem ofList_singleton {k : α} {v : β} :
ofList [k, v] = ( : HashMap α β).insert k v :=
ext DHashMap.Const.ofList_singleton
theorem ofList_cons {k : α} {v : β} {tl : List (α × β)} :
ofList (k, v :: tl) = insertMany (( : HashMap α β).insert k v) tl :=
ext DHashMap.Const.ofList_cons
@[simp]
theorem contains_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} :
(ofList l).contains k = (l.map Prod.fst).contains k :=
DHashMap.Const.contains_ofList
@[simp]
theorem mem_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} :
k ofList l (l.map Prod.fst).contains k :=
DHashMap.Const.mem_ofList
theorem getElem?_ofList_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l)[k]? = none :=
DHashMap.Const.get?_ofList_of_contains_eq_false contains_eq_false
theorem getElem?_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(ofList l)[k']? = some v :=
DHashMap.Const.get?_ofList_of_mem k_beq distinct mem
theorem getElem_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l)
{h} :
(ofList l)[k'] = v :=
DHashMap.Const.get_ofList_of_mem k_beq distinct mem
theorem getElem!_ofList_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α} [Inhabited β]
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l)[k]! = (default : β) :=
DHashMap.Const.get!_ofList_of_contains_eq_false contains_eq_false
theorem getElem!_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} [Inhabited β]
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(ofList l)[k']! = v :=
DHashMap.Const.get!_ofList_of_mem k_beq distinct mem
theorem getD_ofList_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α} {fallback : β}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
getD (ofList l) k fallback = fallback :=
DHashMap.Const.getD_ofList_of_contains_eq_false contains_eq_false
theorem getD_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} {fallback : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
getD (ofList l) k' fallback = v :=
DHashMap.Const.getD_ofList_of_mem k_beq distinct mem
theorem getKey?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l).getKey? k = none :=
DHashMap.Const.getKey?_ofList_of_contains_eq_false contains_eq_false
theorem getKey?_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(ofList l).getKey? k' = some k :=
DHashMap.Const.getKey?_ofList_of_mem k_beq distinct mem
theorem getKey_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst)
{h} :
(ofList l).getKey k' h = k :=
DHashMap.Const.getKey_ofList_of_mem k_beq distinct mem
theorem getKey!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l).getKey! k = default :=
DHashMap.Const.getKey!_ofList_of_contains_eq_false contains_eq_false
theorem getKey!_ofList_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(ofList l).getKey! k' = k :=
DHashMap.Const.getKey!_ofList_of_mem k_beq distinct mem
theorem getKeyD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k fallback : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l).getKeyD k fallback = fallback :=
DHashMap.Const.getKeyD_ofList_of_contains_eq_false contains_eq_false
theorem getKeyD_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(ofList l).getKeyD k' fallback = k :=
DHashMap.Const.getKeyD_ofList_of_mem k_beq distinct mem
theorem size_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
(ofList l).size = l.length :=
DHashMap.Const.size_ofList distinct
theorem size_ofList_le [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(ofList l).size l.length :=
DHashMap.Const.size_ofList_le
@[simp]
theorem isEmpty_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(ofList l).isEmpty = l.isEmpty :=
DHashMap.Const.isEmpty_ofList
@[simp]
theorem unitOfList_nil :
unitOfList ([] : List α) = :=
ext DHashMap.Const.unitOfList_nil
@[simp]
theorem unitOfList_singleton {k : α} :
unitOfList [k] = ( : HashMap α Unit).insertIfNew k () :=
ext DHashMap.Const.unitOfList_singleton
theorem unitOfList_cons {hd : α} {tl : List α} :
unitOfList (hd :: tl) =
insertManyIfNewUnit (( : HashMap α Unit).insertIfNew hd ()) tl :=
ext DHashMap.Const.unitOfList_cons
@[simp]
theorem contains_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
(unitOfList l).contains k = l.contains k :=
DHashMap.Const.contains_unitOfList
@[simp]
theorem mem_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
k unitOfList l l.contains k :=
DHashMap.Const.mem_unitOfList
@[simp]
theorem getElem?_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
(unitOfList l)[k]? =
if l.contains k then some () else none :=
DHashMap.Const.get?_unitOfList
@[simp]
theorem getElem_unitOfList
{l : List α} {k : α} {h} :
(unitOfList l)[k] = () :=
DHashMap.Const.get_unitOfList
@[simp]
theorem getElem!_unitOfList
{l : List α} {k : α} :
(unitOfList l)[k]! = () :=
DHashMap.Const.get!_unitOfList
@[simp]
theorem getD_unitOfList
{l : List α} {k : α} {fallback : Unit} :
getD (unitOfList l) k fallback = () := by
simp
theorem getKey?_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (contains_eq_false : l.contains k = false) :
getKey? (unitOfList l) k = none :=
DHashMap.Const.getKey?_unitOfList_of_contains_eq_false contains_eq_false
theorem getKey?_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getKey? (unitOfList l) k' = some k :=
DHashMap.Const.getKey?_unitOfList_of_mem k_beq distinct mem
theorem getKey_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) {h} :
getKey (unitOfList l) k' h = k :=
DHashMap.Const.getKey_unitOfList_of_mem k_beq distinct mem
theorem getKey!_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k : α}
(contains_eq_false : l.contains k = false) :
getKey! (unitOfList l) k = default :=
DHashMap.Const.getKey!_unitOfList_of_contains_eq_false contains_eq_false
theorem getKey!_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
getKey! (unitOfList l) k' = k :=
DHashMap.Const.getKey!_unitOfList_of_mem k_beq distinct mem
theorem getKeyD_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k fallback : α}
(contains_eq_false : l.contains k = false) :
getKeyD (unitOfList l) k fallback = fallback :=
DHashMap.Const.getKeyD_unitOfList_of_contains_eq_false contains_eq_false
theorem getKeyD_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
getKeyD (unitOfList l) k' fallback = k :=
DHashMap.Const.getKeyD_unitOfList_of_mem k_beq distinct mem
theorem size_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
(unitOfList l).size = l.length :=
DHashMap.Const.size_unitOfList distinct
theorem size_unitOfList_le [EquivBEq α] [LawfulHashable α]
{l : List α} :
(unitOfList l).size l.length :=
DHashMap.Const.size_unitOfList_le
@[simp]
theorem isEmpty_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} :
(unitOfList l).isEmpty = l.isEmpty :=
DHashMap.Const.isEmpty_unitOfList
end
end Std.HashMap

View File

@@ -173,6 +173,14 @@ instance [BEq α] [Hashable α] : GetElem? (Raw α β) α β (fun m a => a ∈ m
@[inline, inherit_doc DHashMap.Raw.keys] def keys (m : Raw α β) : List α :=
m.inner.keys
@[inline, inherit_doc DHashMap.Raw.Const.ofList] def ofList [BEq α] [Hashable α]
(l : List (α × β)) : Raw α β :=
DHashMap.Raw.Const.ofList l
@[inline, inherit_doc DHashMap.Raw.Const.unitOfList] def unitOfList [BEq α] [Hashable α]
(l : List α) : Raw α Unit :=
DHashMap.Raw.Const.unitOfList l
section Unverified
/-! We currently do not provide lemmas for the functions below. -/
@@ -233,20 +241,12 @@ m.inner.values
[Hashable α] {ρ : Type w} [ForIn Id ρ α] (m : Raw α Unit) (l : ρ) : Raw α Unit :=
DHashMap.Raw.Const.insertManyIfNewUnit m.inner l
@[inline, inherit_doc DHashMap.Raw.Const.ofList] def ofList [BEq α] [Hashable α]
(l : List (α × β)) : Raw α β :=
DHashMap.Raw.Const.ofList l
/-- Computes the union of the given hash maps, by traversing `m₂` and inserting its elements into `m₁`. -/
@[inline] def union [BEq α] [Hashable α] (m₁ m₂ : Raw α β) : Raw α β :=
m₂.fold (init := m₁) fun acc x => acc.insert x
instance [BEq α] [Hashable α] : Union (Raw α β) := union
@[inline, inherit_doc DHashMap.Raw.Const.unitOfList] def unitOfList [BEq α] [Hashable α]
(l : List α) : Raw α Unit :=
DHashMap.Raw.Const.unitOfList l
@[inline, inherit_doc DHashMap.Raw.Const.unitOfArray] def unitOfArray [BEq α] [Hashable α]
(l : Array α) : Raw α Unit :=
DHashMap.Raw.Const.unitOfArray l

View File

@@ -671,7 +671,6 @@ theorem getKeyD_insertIfNew [EquivBEq α] [LawfulHashable α] (h : m.WF) {k a fa
(m.insertIfNew k v).getKeyD a fallback = if k == a ¬k m then k else m.getKeyD a fallback :=
DHashMap.Raw.getKeyD_insertIfNew h.out
@[simp]
theorem getThenInsertIfNew?_fst (h : m.WF) {k : α} {v : β} :
(getThenInsertIfNew? m k v).1 = get? m k :=
@@ -688,7 +687,7 @@ theorem length_keys [EquivBEq α] [LawfulHashable α] (h : m.WF) :
DHashMap.Raw.length_keys h.out
@[simp]
theorem isEmpty_keys [EquivBEq α] [LawfulHashable α] (h : m.WF):
theorem isEmpty_keys [EquivBEq α] [LawfulHashable α] (h : m.WF) :
m.keys.isEmpty = m.isEmpty :=
DHashMap.Raw.isEmpty_keys h.out
@@ -699,13 +698,592 @@ theorem contains_keys [EquivBEq α] [LawfulHashable α] (h : m.WF) {k : α} :
@[simp]
theorem mem_keys [LawfulBEq α] [LawfulHashable α] (h : m.WF) {k : α} :
k m.keys k m :=
k m.keys k m :=
DHashMap.Raw.mem_keys h.out
theorem distinct_keys [EquivBEq α] [LawfulHashable α] (h : m.WF) :
m.keys.Pairwise (fun a b => (a == b) = false) :=
m.keys.Pairwise (fun a b => (a == b) = false) :=
DHashMap.Raw.distinct_keys h.out
@[simp]
theorem insertMany_nil (h : m.WF) :
insertMany m [] = m :=
ext (DHashMap.Raw.Const.insertMany_nil h.out)
@[simp]
theorem insertMany_list_singleton (h : m.WF)
{k : α} {v : β} :
insertMany m [k, v] = m.insert k v :=
ext (DHashMap.Raw.Const.insertMany_list_singleton h.out)
theorem insertMany_cons (h : m.WF) {l : List (α × β)}
{k : α} {v : β} :
insertMany m (k, v :: l) = insertMany (m.insert k v) l :=
ext (DHashMap.Raw.Const.insertMany_cons h.out)
@[simp]
theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k : α} :
(insertMany m l).contains k = (m.contains k || (l.map Prod.fst).contains k) :=
DHashMap.Raw.Const.contains_insertMany_list h.out
@[simp]
theorem mem_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k : α} :
k insertMany m l k m (l.map Prod.fst).contains k :=
DHashMap.Raw.Const.mem_insertMany_list h.out
theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List (α × β)} {k : α} :
k insertMany m l (l.map Prod.fst).contains k = false k m :=
DHashMap.Raw.Const.mem_of_mem_insertMany_list h.out
theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l).getKey? k = m.getKey? k :=
DHashMap.Raw.Const.getKey?_insertMany_list_of_contains_eq_false h.out contains_eq_false
theorem getKey?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).getKey? k' = some k :=
DHashMap.Raw.Const.getKey?_insertMany_list_of_mem h.out k_beq distinct mem
theorem getKey_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false)
{h'} :
(insertMany m l).getKey k h' =
m.getKey k (mem_of_mem_insertMany_list h h' contains_eq_false) :=
DHashMap.Raw.Const.getKey_insertMany_list_of_contains_eq_false h.out contains_eq_false
theorem getKey_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst)
{h'} :
(insertMany m l).getKey k' h' = k :=
DHashMap.Raw.Const.getKey_insertMany_list_of_mem h.out k_beq distinct mem
theorem getKey!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
(h : m.WF) {l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l).getKey! k = m.getKey! k :=
DHashMap.Raw.Const.getKey!_insertMany_list_of_contains_eq_false h.out contains_eq_false
theorem getKey!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α]
(h : m.WF) {l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).getKey! k' = k :=
DHashMap.Raw.Const.getKey!_insertMany_list_of_mem h.out k_beq distinct mem
theorem getKeyD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)} {k fallback : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l).getKeyD k fallback = m.getKeyD k fallback :=
DHashMap.Raw.Const.getKeyD_insertMany_list_of_contains_eq_false h.out contains_eq_false
theorem getKeyD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(insertMany m l).getKeyD k' fallback = k :=
DHashMap.Raw.Const.getKeyD_insertMany_list_of_mem h.out k_beq distinct mem
theorem size_insertMany_list [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
( (a : α), a m (l.map Prod.fst).contains a = false)
(insertMany m l).size = m.size + l.length :=
DHashMap.Raw.Const.size_insertMany_list h.out distinct
theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)} :
m.size (insertMany m l).size :=
DHashMap.Raw.Const.size_le_size_insertMany_list h.out
theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)} :
(insertMany m l).size m.size + l.length :=
DHashMap.Raw.Const.size_insertMany_list_le h.out
@[simp]
theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)} :
(insertMany m l).isEmpty = (m.isEmpty && l.isEmpty) :=
DHashMap.Raw.Const.isEmpty_insertMany_list h.out
theorem getElem?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l)[k]? = m[k]? :=
DHashMap.Raw.Const.get?_insertMany_list_of_contains_eq_false h.out contains_eq_false
theorem getElem?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
(insertMany m l)[k']? = v :=
DHashMap.Raw.Const.get?_insertMany_list_of_mem h.out k_beq distinct mem
theorem getElem_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false)
{h'} :
(insertMany m l)[k] =
m[k]'(mem_of_mem_insertMany_list h h' contains_eq_false) :=
DHashMap.Raw.Const.get_insertMany_list_of_contains_eq_false h.out contains_eq_false (h':= h')
theorem getElem_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) {h'} :
(insertMany m l)[k'] = v :=
DHashMap.Raw.Const.get_insertMany_list_of_mem h.out k_beq distinct mem (h' := h')
theorem getElem!_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited β] (h : m.WF) {l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(insertMany m l)[k]! = m[k]! :=
DHashMap.Raw.Const.get!_insertMany_list_of_contains_eq_false h.out contains_eq_false
theorem getElem!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited β]
(h : m.WF) {l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
(insertMany m l)[k']! = v :=
DHashMap.Raw.Const.get!_insertMany_list_of_mem h.out k_beq distinct mem
theorem getD_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)} {k : α} {fallback : β}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
getD (insertMany m l) k fallback = getD m k fallback :=
DHashMap.Raw.Const.getD_insertMany_list_of_contains_eq_false h.out contains_eq_false
theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List (α × β)} {k k' : α} (k_beq : k == k') {v fallback : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) (mem : k, v l) :
getD (insertMany m l) k' fallback = v :=
DHashMap.Raw.Const.getD_insertMany_list_of_mem h.out k_beq distinct mem
variable {m : Raw α Unit}
@[simp]
theorem insertManyIfNewUnit_nil (h : m.WF) :
insertManyIfNewUnit m [] = m :=
ext (DHashMap.Raw.Const.insertManyIfNewUnit_nil h.out)
@[simp]
theorem insertManyIfNewUnit_list_singleton (h : m.WF) {k : α} :
insertManyIfNewUnit m [k] = m.insertIfNew k () :=
ext (DHashMap.Raw.Const.insertManyIfNewUnit_list_singleton h.out)
theorem insertManyIfNewUnit_cons (h : m.WF) {l : List α} {k : α} :
insertManyIfNewUnit m (k :: l) = insertManyIfNewUnit (m.insertIfNew k ()) l :=
ext (DHashMap.Raw.Const.insertManyIfNewUnit_cons h.out)
@[simp]
theorem contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} {k : α} :
(insertManyIfNewUnit m l).contains k = (m.contains k || l.contains k) :=
DHashMap.Raw.Const.contains_insertManyIfNewUnit_list h.out
@[simp]
theorem mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} {k : α} :
k insertManyIfNewUnit m l k m l.contains k :=
DHashMap.Raw.Const.mem_insertManyIfNewUnit_list h.out
theorem mem_of_mem_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} {k : α} (contains_eq_false : l.contains k = false) :
k insertManyIfNewUnit m l k m :=
DHashMap.Raw.Const.mem_of_mem_insertManyIfNewUnit_list h.out contains_eq_false
theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k : α}
(not_mem : ¬ k m) (contains_eq_false: l.contains k = false) :
getKey? (insertManyIfNewUnit m l) k = none :=
DHashMap.Raw.Const.getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
h.out not_mem contains_eq_false
theorem getKey?_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k k' : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getKey? (insertManyIfNewUnit m l) k' = some k :=
DHashMap.Raw.Const.getKey?_insertManyIfNewUnit_list_of_not_mem_of_mem
h.out k_beq not_mem distinct mem
theorem getKey?_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k : α} (mem : k m) :
getKey? (insertManyIfNewUnit m l) k = getKey? m k :=
DHashMap.Raw.Const.getKey?_insertManyIfNewUnit_list_of_mem h.out mem
theorem getKey_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α}
{k k' : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) {h'} :
getKey (insertManyIfNewUnit m l) k' h' = k :=
DHashMap.Raw.Const.getKey_insertManyIfNewUnit_list_of_not_mem_of_mem
h.out k_beq not_mem distinct mem
theorem getKey_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k : α} (mem: k m) {h₃} :
getKey (insertManyIfNewUnit m l) k h₃ = getKey m k mem :=
DHashMap.Raw.Const.getKey_insertManyIfNewUnit_list_of_mem h.out mem
theorem getKey!_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {l : List α} {k : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
getKey! (insertManyIfNewUnit m l) k = default :=
DHashMap.Raw.Const.getKey!_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
h.out not_mem contains_eq_false
theorem getKey!_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] (h : m.WF) {l : List α} {k k' : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getKey! (insertManyIfNewUnit m l) k' = k :=
DHashMap.Raw.Const.getKey!_insertManyIfNewUnit_list_of_not_mem_of_mem
h.out k_beq not_mem distinct mem
theorem getKey!_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] (h : m.WF) {l : List α} {k : α} (mem : k m) :
getKey! (insertManyIfNewUnit m l) k = getKey! m k :=
DHashMap.Raw.Const.getKey!_insertManyIfNewUnit_list_of_mem h.out mem
theorem getKeyD_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k fallback : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
getKeyD (insertManyIfNewUnit m l) k fallback = fallback :=
DHashMap.Raw.Const.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
h.out not_mem contains_eq_false
theorem getKeyD_insertManyIfNewUnit_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k k' fallback : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getKeyD (insertManyIfNewUnit m l) k' fallback = k :=
DHashMap.Raw.Const.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_mem
h.out k_beq not_mem distinct mem
theorem getKeyD_insertManyIfNewUnit_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k fallback : α} (mem : k m) :
getKeyD (insertManyIfNewUnit m l) k fallback = getKeyD m k fallback :=
DHashMap.Raw.Const.getKeyD_insertManyIfNewUnit_list_of_mem h.out mem
theorem size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
( (a : α), a m l.contains a = false)
(insertManyIfNewUnit m l).size = m.size + l.length :=
DHashMap.Raw.Const.size_insertManyIfNewUnit_list h.out distinct
theorem size_le_size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} :
m.size (insertManyIfNewUnit m l).size :=
DHashMap.Raw.Const.size_le_size_insertManyIfNewUnit_list h.out
theorem size_insertManyIfNewUnit_list_le [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} :
(insertManyIfNewUnit m l).size m.size + l.length :=
DHashMap.Raw.Const.size_insertManyIfNewUnit_list_le h.out
@[simp]
theorem isEmpty_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} :
(insertManyIfNewUnit m l).isEmpty = (m.isEmpty && l.isEmpty) :=
DHashMap.Raw.Const.isEmpty_insertManyIfNewUnit_list h.out
@[simp]
theorem getElem?_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} {k : α} :
(insertManyIfNewUnit m l)[k]? =
if k m l.contains k then some () else none :=
DHashMap.Raw.Const.get?_insertManyIfNewUnit_list h.out
@[simp]
theorem getElem_insertManyIfNewUnit_list
{l : List α} {k : α} {h} :
(insertManyIfNewUnit m l)[k] = () :=
DHashMap.Raw.Const.get_insertManyIfNewUnit_list (h:=h)
@[simp]
theorem getElem!_insertManyIfNewUnit_list
{l : List α} {k : α} :
(insertManyIfNewUnit m l)[k]! = () :=
DHashMap.Raw.Const.get!_insertManyIfNewUnit_list
@[simp]
theorem getD_insertManyIfNewUnit_list
{l : List α} {k : α} {fallback : Unit} :
getD (insertManyIfNewUnit m l) k fallback = () := by
simp
end Raw
namespace Raw
variable [BEq α] [Hashable α]
@[simp]
theorem ofList_nil :
ofList ([] : List (α × β)) = :=
ext DHashMap.Raw.Const.ofList_nil
@[simp]
theorem ofList_singleton {k : α} {v : β} :
ofList [k, v] = ( : Raw α β).insert k v :=
ext DHashMap.Raw.Const.ofList_singleton
theorem ofList_cons {k : α} {v : β} {tl : List (α × β)} :
ofList (k, v :: tl) = insertMany (( : Raw α β).insert k v) tl :=
ext DHashMap.Raw.Const.ofList_cons
@[simp]
theorem contains_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} :
(ofList l).contains k = (l.map Prod.fst).contains k :=
DHashMap.Raw.Const.contains_ofList
@[simp]
theorem mem_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α} :
k (ofList l) (l.map Prod.fst).contains k :=
DHashMap.Raw.Const.mem_ofList
theorem getElem?_ofList_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l)[k]? = none :=
DHashMap.Raw.Const.get?_ofList_of_contains_eq_false contains_eq_false
theorem getElem?_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(ofList l)[k']? = some v :=
DHashMap.Raw.Const.get?_ofList_of_mem k_beq distinct mem
theorem getElem_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l)
{h} :
(ofList l)[k'] = v :=
DHashMap.Raw.Const.get_ofList_of_mem k_beq distinct mem (h:=h)
theorem getElem!_ofList_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α} [Inhabited β]
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l)[k]! = default :=
DHashMap.Raw.Const.get!_ofList_of_contains_eq_false contains_eq_false
theorem getElem!_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} [Inhabited β]
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
(ofList l)[k']! = v :=
DHashMap.Raw.Const.get!_ofList_of_mem k_beq distinct mem
theorem getD_ofList_of_contains_eq_false [LawfulBEq α]
{l : List (α × β)} {k : α} {fallback : β}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
getD (ofList l) k fallback = fallback :=
DHashMap.Raw.Const.getD_ofList_of_contains_eq_false contains_eq_false
theorem getD_ofList_of_mem [LawfulBEq α]
{l : List (α × β)} {k k' : α} (k_beq : k == k') {v : β} {fallback : β}
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k, v l) :
getD (ofList l) k' fallback = v :=
DHashMap.Raw.Const.getD_ofList_of_mem k_beq distinct mem
theorem getKey?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l).getKey? k = none :=
DHashMap.Raw.Const.getKey?_ofList_of_contains_eq_false contains_eq_false
theorem getKey?_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(ofList l).getKey? k' = some k :=
DHashMap.Raw.Const.getKey?_ofList_of_mem k_beq distinct mem
theorem getKey_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst)
{h'} :
(ofList l).getKey k' h' = k :=
DHashMap.Raw.Const.getKey_ofList_of_mem k_beq distinct mem
theorem getKey!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List (α × β)} {k : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l).getKey! k = default :=
DHashMap.Raw.Const.getKey!_ofList_of_contains_eq_false contains_eq_false
theorem getKey!_ofList_of_mem [EquivBEq α] [LawfulHashable α] [Inhabited α]
{l : List (α × β)}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(ofList l).getKey! k' = k :=
DHashMap.Raw.Const.getKey!_ofList_of_mem k_beq distinct mem
theorem getKeyD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} {k fallback : α}
(contains_eq_false : (l.map Prod.fst).contains k = false) :
(ofList l).getKeyD k fallback = fallback :=
DHashMap.Raw.Const.getKeyD_ofList_of_contains_eq_false contains_eq_false
theorem getKeyD_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List (α × β)}
{k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a.1 == b.1) = false))
(mem : k l.map Prod.fst) :
(ofList l).getKeyD k' fallback = k :=
DHashMap.Raw.Const.getKeyD_ofList_of_mem k_beq distinct mem
theorem size_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} (distinct : l.Pairwise (fun a b => (a.1 == b.1) = false)) :
(ofList l).size = l.length :=
DHashMap.Raw.Const.size_ofList distinct
theorem size_ofList_le [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(ofList l).size l.length :=
DHashMap.Raw.Const.size_ofList_le
@[simp]
theorem isEmpty_ofList [EquivBEq α] [LawfulHashable α]
{l : List (α × β)} :
(ofList l).isEmpty = l.isEmpty :=
DHashMap.Raw.Const.isEmpty_ofList
@[simp]
theorem unitOfList_nil :
unitOfList ([] : List α) = :=
ext DHashMap.Raw.Const.unitOfList_nil
@[simp]
theorem unitOfList_singleton {k : α} :
unitOfList [k] = ( : Raw α Unit).insertIfNew k () :=
ext DHashMap.Raw.Const.unitOfList_singleton
theorem unitOfList_cons {hd : α} {tl : List α} :
unitOfList (hd :: tl) = insertManyIfNewUnit (( : Raw α Unit).insertIfNew hd ()) tl :=
ext DHashMap.Raw.Const.unitOfList_cons
@[simp]
theorem contains_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
(unitOfList l).contains k = l.contains k :=
DHashMap.Raw.Const.contains_unitOfList
@[simp]
theorem mem_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
k unitOfList l l.contains k :=
DHashMap.Raw.Const.mem_unitOfList
theorem getKey?_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (contains_eq_false : l.contains k = false) :
getKey? (unitOfList l) k = none :=
DHashMap.Raw.Const.getKey?_unitOfList_of_contains_eq_false contains_eq_false
theorem getKey?_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getKey? (unitOfList l) k' = some k :=
DHashMap.Raw.Const.getKey?_unitOfList_of_mem k_beq distinct mem
theorem getKey_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) {h'} :
getKey (unitOfList l) k' h' = k :=
DHashMap.Raw.Const.getKey_unitOfList_of_mem k_beq distinct mem
theorem getKey!_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k : α}
(contains_eq_false : l.contains k = false) :
getKey! (unitOfList l) k = default :=
DHashMap.Raw.Const.getKey!_unitOfList_of_contains_eq_false contains_eq_false
theorem getKey!_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
getKey! (unitOfList l) k' = k :=
DHashMap.Raw.Const.getKey!_unitOfList_of_mem k_beq distinct mem
theorem getKeyD_unitOfList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k fallback : α}
(contains_eq_false : l.contains k = false) :
getKeyD (unitOfList l) k fallback = fallback :=
DHashMap.Raw.Const.getKeyD_unitOfList_of_contains_eq_false contains_eq_false
theorem getKeyD_unitOfList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
getKeyD (unitOfList l) k' fallback = k :=
DHashMap.Raw.Const.getKeyD_unitOfList_of_mem k_beq distinct mem
theorem size_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
(unitOfList l).size = l.length :=
DHashMap.Raw.Const.size_unitOfList distinct
theorem size_unitOfList_le [EquivBEq α] [LawfulHashable α]
{l : List α} :
(unitOfList l).size l.length :=
DHashMap.Raw.Const.size_unitOfList_le
@[simp]
theorem isEmpty_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} :
(unitOfList l).isEmpty = l.isEmpty :=
DHashMap.Raw.Const.isEmpty_unitOfList
@[simp]
theorem getElem?_unitOfList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
(unitOfList l)[k]? =
if l.contains k then some () else none :=
DHashMap.Raw.Const.get?_unitOfList
@[simp]
theorem getElem_unitOfList
{l : List α} {k : α} {h} :
(unitOfList l)[k] = () :=
DHashMap.Raw.Const.get_unitOfList (h:=h)
@[simp]
theorem getElem!_unitOfList
{l : List α} {k : α} :
(unitOfList l)[k]! = () :=
DHashMap.Raw.Const.get!_unitOfList
@[simp]
theorem getD_unitOfList
{l : List α} {k : α} {fallback : Unit} :
getD (unitOfList l) k fallback = () := by
simp
end Raw
end Std.HashMap

View File

@@ -162,6 +162,14 @@ for all `a`.
@[inline] def toList (m : HashSet α) : List α :=
m.inner.keys
/--
Creates a hash set from a list of elements. Note that unlike repeatedly calling `insert`, if the
collection contains multiple elements that are equal (with regard to `==`), then the last element
in the collection will be present in the returned hash set.
-/
@[inline] def ofList [BEq α] [Hashable α] (l : List α) : HashSet α :=
HashMap.unitOfList l
section Unverified
/-! We currently do not provide lemmas for the functions below. -/
@@ -233,14 +241,6 @@ appearance.
HashSet α :=
m.inner.insertManyIfNewUnit l
/--
Creates a hash set from a list of elements. Note that unlike repeatedly calling `insert`, if the
collection contains multiple elements that are equal (with regard to `==`), then the last element
in the collection will be present in the returned hash set.
-/
@[inline] def ofList [BEq α] [Hashable α] (l : List α) : HashSet α :=
HashMap.unitOfList l
/--
Creates a hash set from an array of elements. Note that unlike repeatedly calling `insert`, if the
collection contains multiple elements that are equal (with regard to `==`), then the last element

View File

@@ -361,7 +361,7 @@ theorem isEmpty_toList [EquivBEq α] [LawfulHashable α] :
HashMap.isEmpty_keys
@[simp]
theorem contains_toList [EquivBEq α] [LawfulHashable α] {k : α}:
theorem contains_toList [EquivBEq α] [LawfulHashable α] {k : α} :
m.toList.contains k = m.contains k :=
HashMap.contains_keys
@@ -373,6 +373,222 @@ theorem mem_toList [LawfulBEq α] [LawfulHashable α] {k : α} :
theorem distinct_toList [EquivBEq α] [LawfulHashable α]:
m.toList.Pairwise (fun a b => (a == b) = false) :=
HashMap.distinct_keys
@[simp]
theorem insertMany_nil :
insertMany m [] = m :=
ext HashMap.insertManyIfNewUnit_nil
@[simp]
theorem insertMany_list_singleton {k : α} :
insertMany m [k] = m.insert k :=
ext HashMap.insertManyIfNewUnit_list_singleton
theorem insertMany_cons {l : List α} {k : α} :
insertMany m (k :: l) = insertMany (m.insert k) l :=
ext HashMap.insertManyIfNewUnit_cons
@[simp]
theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
(insertMany m l).contains k = (m.contains k || l.contains k) :=
HashMap.contains_insertManyIfNewUnit_list
@[simp]
theorem mem_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
k insertMany m l k m l.contains k :=
HashMap.mem_insertManyIfNewUnit_list
theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (contains_eq_false : l.contains k = false) :
k insertMany m l k m :=
HashMap.mem_of_mem_insertManyIfNewUnit_list contains_eq_false
theorem get?_insertMany_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] {l : List α} {k : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
get? (insertMany m l) k = none :=
HashMap.getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
not_mem contains_eq_false
theorem get?_insertMany_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
get? (insertMany m l) k' = some k :=
HashMap.getKey?_insertManyIfNewUnit_list_of_not_mem_of_mem
k_beq not_mem distinct mem
theorem get?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (mem : k m) :
get? (insertMany m l) k = get? m k :=
HashMap.getKey?_insertManyIfNewUnit_list_of_mem mem
theorem get_insertMany_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α}
{k k' : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) {h} :
get (insertMany m l) k' h = k :=
HashMap.getKey_insertManyIfNewUnit_list_of_not_mem_of_mem
k_beq not_mem distinct mem
theorem get_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (mem : k m) {h} :
get (insertMany m l) k h = get m k mem :=
HashMap.getKey_insertManyIfNewUnit_list_of_mem mem
theorem get!_insertMany_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] [Inhabited α] {l : List α} {k : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
get! (insertMany m l) k = default :=
HashMap.getKey!_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
not_mem contains_eq_false
theorem get!_insertMany_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k k' : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
get! (insertMany m l) k' = k :=
HashMap.getKey!_insertManyIfNewUnit_list_of_not_mem_of_mem
k_beq not_mem distinct mem
theorem get!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k : α} (mem : k m) :
get! (insertMany m l) k = get! m k :=
HashMap.getKey!_insertManyIfNewUnit_list_of_mem mem
theorem getD_insertMany_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] {l : List α} {k fallback : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
getD (insertMany m l) k fallback = fallback :=
HashMap.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
not_mem contains_eq_false
theorem getD_insertMany_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' fallback : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getD (insertMany m l) k' fallback = k :=
HashMap.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_mem
k_beq not_mem distinct mem
theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k fallback : α} (mem : k m) :
getD (insertMany m l) k fallback = getD m k fallback :=
HashMap.getKeyD_insertManyIfNewUnit_list_of_mem mem
theorem size_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
( (a : α), a m l.contains a = false)
(insertMany m l).size = m.size + l.length :=
HashMap.size_insertManyIfNewUnit_list distinct
theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List α} :
m.size (insertMany m l).size :=
HashMap.size_le_size_insertManyIfNewUnit_list
theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α]
{l : List α} :
(insertMany m l).size m.size + l.length :=
HashMap.size_insertManyIfNewUnit_list_le
@[simp]
theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α]
{l : List α} :
(insertMany m l).isEmpty = (m.isEmpty && l.isEmpty) :=
HashMap.isEmpty_insertManyIfNewUnit_list
end
section
@[simp]
theorem ofList_nil :
ofList ([] : List α) = :=
ext HashMap.unitOfList_nil
@[simp]
theorem ofList_singleton {k : α} :
ofList [k] = ( : HashSet α).insert k :=
ext HashMap.unitOfList_singleton
theorem ofList_cons {hd : α} {tl : List α} :
ofList (hd :: tl) =
insertMany (( : HashSet α).insert hd) tl :=
ext HashMap.unitOfList_cons
@[simp]
theorem contains_ofList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
(ofList l).contains k = l.contains k :=
HashMap.contains_unitOfList
theorem get?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (contains_eq_false : l.contains k = false) :
get? (ofList l) k = none :=
HashMap.getKey?_unitOfList_of_contains_eq_false contains_eq_false
theorem get?_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
get? (ofList l) k' = some k :=
HashMap.getKey?_unitOfList_of_mem k_beq distinct mem
theorem get_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) {h} :
get (ofList l) k' h = k :=
HashMap.getKey_unitOfList_of_mem k_beq distinct mem
theorem get!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k : α}
(contains_eq_false : l.contains k = false) :
get! (ofList l) k = default :=
HashMap.getKey!_unitOfList_of_contains_eq_false contains_eq_false
theorem get!_ofList_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
get! (ofList l) k' = k :=
HashMap.getKey!_unitOfList_of_mem k_beq distinct mem
theorem getD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k fallback : α}
(contains_eq_false : l.contains k = false) :
getD (ofList l) k fallback = fallback :=
HashMap.getKeyD_unitOfList_of_contains_eq_false contains_eq_false
theorem getD_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
getD (ofList l) k' fallback = k :=
HashMap.getKeyD_unitOfList_of_mem k_beq distinct mem
theorem size_ofList [EquivBEq α] [LawfulHashable α]
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
(ofList l).size = l.length :=
HashMap.size_unitOfList distinct
theorem size_ofList_le [EquivBEq α] [LawfulHashable α]
{l : List α} :
(ofList l).size l.length :=
HashMap.size_unitOfList_le
@[simp]
theorem isEmpty_ofList [EquivBEq α] [LawfulHashable α]
{l : List α} :
(ofList l).isEmpty = l.isEmpty :=
HashMap.isEmpty_unitOfList
end
end Std.HashSet

View File

@@ -165,6 +165,14 @@ for all `a`.
@[inline] def toList (m : Raw α) : List α :=
m.inner.keys
/--
Creates a hash set from a list of elements. Note that unlike repeatedly calling `insert`, if the
collection contains multiple elements that are equal (with regard to `==`), then the last element
in the collection will be present in the returned hash set.
-/
@[inline] def ofList [BEq α] [Hashable α] (l : List α) : Raw α :=
HashMap.Raw.unitOfList l
section Unverified
/-! We currently do not provide lemmas for the functions below. -/
@@ -231,14 +239,6 @@ appearance.
Raw α :=
m.inner.insertManyIfNewUnit l
/--
Creates a hash set from a list of elements. Note that unlike repeatedly calling `insert`, if the
collection contains multiple elements that are equal (with regard to `==`), then the last element
in the collection will be present in the returned hash set.
-/
@[inline] def ofList [BEq α] [Hashable α] (l : List α) : Raw α :=
HashMap.Raw.unitOfList l
/--
Creates a hash set from an array of elements. Note that unlike repeatedly calling `insert`, if the
collection contains multiple elements that are equal (with regard to `==`), then the last element

View File

@@ -367,22 +367,22 @@ theorem containsThenInsert_snd (h : m.WF) {k : α} : (m.containsThenInsert k).2
ext (HashMap.Raw.containsThenInsertIfNew_snd h.out)
@[simp]
theorem length_toList [EquivBEq α] [LawfulHashable α] (h : m.WF):
theorem length_toList [EquivBEq α] [LawfulHashable α] (h : m.WF) :
m.toList.length = m.size :=
HashMap.Raw.length_keys h.1
@[simp]
theorem isEmpty_toList [EquivBEq α] [LawfulHashable α] (h : m.WF):
theorem isEmpty_toList [EquivBEq α] [LawfulHashable α] (h : m.WF) :
m.toList.isEmpty = m.isEmpty :=
HashMap.Raw.isEmpty_keys h.1
@[simp]
theorem contains_toList [EquivBEq α] [LawfulHashable α] {k : α} (h : m.WF):
theorem contains_toList [EquivBEq α] [LawfulHashable α] {k : α} (h : m.WF) :
m.toList.contains k = m.contains k :=
HashMap.Raw.contains_keys h.1
@[simp]
theorem mem_toList [LawfulBEq α] [LawfulHashable α] (h : m.WF) {k : α}:
theorem mem_toList [LawfulBEq α] [LawfulHashable α] (h : m.WF) {k : α} :
k m.toList k m :=
HashMap.Raw.mem_keys h.1
@@ -390,6 +390,222 @@ theorem distinct_toList [EquivBEq α] [LawfulHashable α] (h : m.WF) :
m.toList.Pairwise (fun a b => (a == b) = false) :=
HashMap.Raw.distinct_keys h.1
@[simp]
theorem insertMany_nil (h : m.WF) :
insertMany m [] = m :=
ext (HashMap.Raw.insertManyIfNewUnit_nil h.1)
@[simp]
theorem insertMany_list_singleton (h : m.WF) {k : α} :
insertMany m [k] = m.insert k :=
ext (HashMap.Raw.insertManyIfNewUnit_list_singleton h.1)
theorem insertMany_cons (h : m.WF) {l : List α} {k : α} :
insertMany m (k :: l) = insertMany (m.insert k) l :=
ext (HashMap.Raw.insertManyIfNewUnit_cons h.1)
@[simp]
theorem contains_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} {k : α} :
(insertMany m l).contains k = (m.contains k || l.contains k) :=
HashMap.Raw.contains_insertManyIfNewUnit_list h.1
@[simp]
theorem mem_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} {k : α} :
k insertMany m l k m l.contains k :=
HashMap.Raw.mem_insertManyIfNewUnit_list h.1
theorem mem_of_mem_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} {k : α} (contains_eq_false : l.contains k = false) :
k insertMany m l k m :=
HashMap.Raw.mem_of_mem_insertManyIfNewUnit_list h.1 contains_eq_false
theorem get?_insertMany_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
get? (insertMany m l) k = none :=
HashMap.Raw.getKey?_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
h.1 not_mem contains_eq_false
theorem get?_insertMany_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k k' : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
get? (insertMany m l) k' = some k :=
HashMap.Raw.getKey?_insertManyIfNewUnit_list_of_not_mem_of_mem
h.1 k_beq not_mem distinct mem
theorem get?_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k : α} (mem : k m) :
get? (insertMany m l) k = get? m k :=
HashMap.Raw.getKey?_insertManyIfNewUnit_list_of_mem h.1 mem
theorem get_insertMany_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α}
{k k' : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) {h'} :
get (insertMany m l) k' h' = k :=
HashMap.Raw.getKey_insertManyIfNewUnit_list_of_not_mem_of_mem
h.1 k_beq not_mem distinct mem
theorem get_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k : α} (mem : k m) {h₃} :
get (insertMany m l) k h₃ = get m k mem :=
HashMap.Raw.getKey_insertManyIfNewUnit_list_of_mem h.1 mem
theorem get!_insertMany_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] [Inhabited α] (h : m.WF) {l : List α} {k : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
get! (insertMany m l) k = default :=
HashMap.Raw.getKey!_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
h.1 not_mem contains_eq_false
theorem get!_insertMany_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] (h : m.WF) {l : List α} {k k' : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
get! (insertMany m l) k' = k :=
HashMap.Raw.getKey!_insertManyIfNewUnit_list_of_not_mem_of_mem
h.1 k_beq not_mem distinct mem
theorem get!_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] (h : m.WF) {l : List α} {k : α} (mem : k m) :
get! (insertMany m l) k = get! m k :=
HashMap.Raw.getKey!_insertManyIfNewUnit_list_of_mem h.1 mem
theorem getD_insertMany_list_of_not_mem_of_contains_eq_false
[EquivBEq α] [LawfulHashable α] (h : m.WF) {l : List α} {k fallback : α}
(not_mem : ¬ k m) (contains_eq_false : l.contains k = false) :
getD (insertMany m l) k fallback = fallback :=
HashMap.Raw.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_contains_eq_false
h.1 not_mem contains_eq_false
theorem getD_insertMany_list_of_not_mem_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k k' fallback : α} (k_beq : k == k')
(not_mem : ¬ k m)
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
getD (insertMany m l) k' fallback = k :=
HashMap.Raw.getKeyD_insertManyIfNewUnit_list_of_not_mem_of_mem
h.1 k_beq not_mem distinct mem
theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α]
(h : m.WF) {l : List α} {k fallback : α} (mem : k m) :
getD (insertMany m l) k fallback = getD m k fallback :=
HashMap.Raw.getKeyD_insertManyIfNewUnit_list_of_mem h.1 mem
theorem size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
( (a : α), a m l.contains a = false)
(insertMany m l).size = m.size + l.length :=
HashMap.Raw.size_insertManyIfNewUnit_list h.1 distinct
theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} :
m.size (insertMany m l).size :=
HashMap.Raw.size_le_size_insertManyIfNewUnit_list h.1
theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} :
(insertMany m l).size m.size + l.length :=
HashMap.Raw.size_insertManyIfNewUnit_list_le h.1
@[simp]
theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.WF)
{l : List α} :
(insertMany m l).isEmpty = (m.isEmpty && l.isEmpty) :=
HashMap.Raw.isEmpty_insertManyIfNewUnit_list h.1
@[simp]
theorem ofList_nil :
ofList ([] : List α) = :=
ext HashMap.Raw.unitOfList_nil
@[simp]
theorem ofList_singleton {k : α} :
ofList [k] = ( : Raw α).insert k :=
ext HashMap.Raw.unitOfList_singleton
theorem ofList_cons {hd : α} {tl : List α} :
ofList (hd :: tl) = insertMany (( : Raw α).insert hd) tl :=
ext HashMap.Raw.unitOfList_cons
@[simp]
theorem contains_ofList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
(ofList l).contains k = l.contains k :=
HashMap.Raw.contains_unitOfList
@[simp]
theorem mem_ofList [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} :
k ofList l l.contains k :=
HashMap.Raw.mem_unitOfList
theorem get?_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k : α} (contains_eq_false : l.contains k = false) :
get? (ofList l) k = none :=
HashMap.Raw.getKey?_unitOfList_of_contains_eq_false contains_eq_false
theorem get?_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false)) (mem : k l) :
get? (ofList l) k' = some k :=
HashMap.Raw.getKey?_unitOfList_of_mem k_beq distinct mem
theorem get_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α}
{k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) {h'} :
get (ofList l) k' h' = k :=
HashMap.Raw.getKey_unitOfList_of_mem k_beq distinct mem
theorem get!_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k : α}
(contains_eq_false : l.contains k = false) :
get! (ofList l) k = default :=
HashMap.Raw.getKey!_unitOfList_of_contains_eq_false contains_eq_false
theorem get!_ofList_of_mem [EquivBEq α] [LawfulHashable α]
[Inhabited α] {l : List α} {k k' : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
get! (ofList l) k' = k :=
HashMap.Raw.getKey!_unitOfList_of_mem k_beq distinct mem
theorem getD_ofList_of_contains_eq_false [EquivBEq α] [LawfulHashable α]
{l : List α} {k fallback : α}
(contains_eq_false : l.contains k = false) :
getD (ofList l) k fallback = fallback :=
HashMap.Raw.getKeyD_unitOfList_of_contains_eq_false contains_eq_false
theorem getD_ofList_of_mem [EquivBEq α] [LawfulHashable α]
{l : List α} {k k' fallback : α} (k_beq : k == k')
(distinct : l.Pairwise (fun a b => (a == b) = false))
(mem : k l) :
getD (ofList l) k' fallback = k :=
HashMap.Raw.getKeyD_unitOfList_of_mem k_beq distinct mem
theorem size_ofList [EquivBEq α] [LawfulHashable α]
{l : List α}
(distinct : l.Pairwise (fun a b => (a == b) = false)) :
(ofList l).size = l.length :=
HashMap.Raw.size_unitOfList distinct
theorem size_ofList_le [EquivBEq α] [LawfulHashable α]
{l : List α} :
(ofList l).size l.length :=
HashMap.Raw.size_unitOfList_le
@[simp]
theorem isEmpty_ofList [EquivBEq α] [LawfulHashable α]
{l : List α} :
(ofList l).isEmpty = l.isEmpty :=
HashMap.Raw.isEmpty_unitOfList
end Raw
end Std.HashSet

View File

@@ -74,9 +74,6 @@ instance [Clause α β] : Entails α β where
instance [Clause α β] (p : α Bool) (c : β) : Decidable (p c) :=
inferInstanceAs (Decidable (Clause.eval p c = true))
instance [Clause α β] : Inhabited β where
default := empty
end Clause
/--

View File

@@ -19,16 +19,9 @@ Author: Leonardo de Moura
namespace lean {
extern "C" object* lean_environment_add(object*, object*);
extern "C" object* lean_mk_empty_environment(uint32, object*);
extern "C" object* lean_environment_find(object*, object*);
extern "C" uint32 lean_environment_trust_level(object*);
extern "C" object* lean_environment_mark_quot_init(object*);
extern "C" uint8 lean_environment_quot_init(object*);
extern "C" object* lean_register_extension(object*);
extern "C" object* lean_get_extension(object*, object*);
extern "C" object* lean_set_extension(object*, object*, object*);
extern "C" object* lean_environment_set_main_module(object*, object*);
extern "C" object* lean_environment_main_module(object*);
extern "C" object* lean_kernel_record_unfold (object*, object*);
extern "C" object* lean_kernel_get_diag(object*);
extern "C" object* lean_kernel_set_diag(object*, object*);
@@ -62,14 +55,6 @@ environment scoped_diagnostics::update(environment const & env) const {
return env;
}
environment mk_empty_environment(uint32 trust_lvl) {
return get_io_result<environment>(lean_mk_empty_environment(trust_lvl, io_mk_world()));
}
environment::environment(unsigned trust_lvl):
object_ref(mk_empty_environment(trust_lvl)) {
}
diagnostics environment::get_diag() const {
return diagnostics(lean_kernel_get_diag(to_obj_arg()));
}
@@ -78,18 +63,6 @@ environment environment::set_diag(diagnostics const & diag) const {
return environment(lean_kernel_set_diag(to_obj_arg(), diag.to_obj_arg()));
}
void environment::set_main_module(name const & n) {
m_obj = lean_environment_set_main_module(m_obj, n.to_obj_arg());
}
name environment::get_main_module() const {
return name(lean_environment_main_module(to_obj_arg()));
}
unsigned environment::trust_lvl() const {
return lean_environment_trust_level(to_obj_arg());
}
bool environment::is_quot_initialized() const {
return lean_environment_quot_init(to_obj_arg()) != 0;
}
@@ -297,7 +270,7 @@ environment environment::add(declaration const & d, bool check) const {
}
/*
addDeclCore (env : Environment) (maxHeartbeats : USize) (decl : @& Declaration)
(cancelTk? : @& Option IO.CancelToken) : Except KernelException Environment
(cancelTk? : @& Option IO.CancelToken) : Except Kernel.Exception Environment
*/
extern "C" LEAN_EXPORT object * lean_add_decl(object * env, size_t max_heartbeat, object * decl,
object * opt_cancel_tk) {
@@ -321,12 +294,6 @@ void environment::for_each_constant(std::function<void(constant_info const & d)>
});
}
extern "C" obj_res lean_display_stats(obj_arg env, obj_arg w);
void environment::display_stats() const {
dec_ref(lean_display_stats(to_obj_arg(), io_mk_world()));
}
void initialize_environment() {
}

View File

@@ -24,10 +24,6 @@ Author: Leonardo de Moura
#endif
namespace lean {
class environment_extension {
public:
virtual ~environment_extension() {}
};
/* Wrapper for `Kernel.Diagnostics` */
class diagnostics : public object_ref {
@@ -41,7 +37,7 @@ public:
};
/*
Store `Kernel.Diagnostics` stored in environment extension in `m_diag` IF
Store `Kernel.Diagnostics` (to be stored in `Kernel.Environment.diagnostics`) in `m_diag` IF
- `Kernel.Diagnostics.enable = true`
- `collect = true`. This is a minor optimization.
@@ -59,6 +55,7 @@ public:
diagnostics * get() const { return m_diag; }
};
/* Wrapper for `Lean.Kernel.Environment` */
class LEAN_EXPORT environment : public object_ref {
friend class add_inductive_fn;
@@ -76,7 +73,6 @@ class LEAN_EXPORT environment : public object_ref {
environment add_quot() const;
environment add_inductive(declaration const & d) const;
public:
environment(unsigned trust_lvl = 0);
environment(environment const & other):object_ref(other) {}
environment(environment && other):object_ref(other) {}
explicit environment(b_obj_arg o, bool b):object_ref(o, b) {}
@@ -89,15 +85,8 @@ public:
diagnostics get_diag() const;
environment set_diag(diagnostics const & diag) const;
/** \brief Return the trust level of this environment. */
unsigned trust_lvl() const;
bool is_quot_initialized() const;
void set_main_module(name const & n);
name get_main_module() const;
/** \brief Return information for the constant with name \c n (if it is defined in this environment). */
optional<constant_info> find(name const & n) const;
@@ -114,8 +103,6 @@ public:
friend bool is_eqp(environment const & e1, environment const & e2) {
return e1.raw() == e2.raw();
}
void display_stats() const;
};
void check_no_metavar_no_fvar(environment const & env, name const & n, expr const & e);

View File

@@ -152,9 +152,9 @@ public:
/*
Helper function for interfacing C++ code with code written in Lean.
It executes closure `f` which produces an object_ref of type `A` and may throw
an `kernel_exception` or `exception`. Then, convert result into `Except KernelException T`
an `kernel_exception` or `exception`. Then, convert result into `Except Kernel.Exception T`
where `T` is the type of the lean objected represented by `A`.
We use the constructor `KernelException.other <msg>` to handle C++ `exception` objects which
We use the constructor `Kernel.Exception.other <msg>` to handle C++ `exception` objects which
are not `kernel_exception`.
*/
template<typename A>

View File

@@ -8,7 +8,7 @@ Author: Leonardo de Moura
#include <string>
#include "util/io.h"
#include "util/option_declarations.h"
#include "kernel/environment.h"
#include "library/elab_environment.h"
#include "kernel/local_ctx.h"
#include "kernel/trace.h"
@@ -17,7 +17,7 @@ static name_set * g_trace_classes = nullptr;
static name_map<name_set> * g_trace_aliases = nullptr;
MK_THREAD_LOCAL_GET_DEF(std::vector<name>, get_enabled_trace_classes);
MK_THREAD_LOCAL_GET_DEF(std::vector<name>, get_disabled_trace_classes);
LEAN_THREAD_PTR(environment, g_env);
LEAN_THREAD_PTR(elab_environment, g_env);
LEAN_THREAD_PTR(options, g_opts);
void register_trace_class(name const & n, name const & decl_name) {
@@ -90,7 +90,7 @@ bool is_trace_class_enabled(name const & n) {
}
void scope_trace_env::init(environment * env, options * opts) {
void scope_trace_env::init(elab_environment * env, options * opts) {
m_enable_sz = get_enabled_trace_classes().size();
m_disable_sz = get_disabled_trace_classes().size();
m_old_env = g_env;
@@ -111,12 +111,12 @@ void scope_trace_env::init(environment * env, options * opts) {
g_opts = opts;
}
scope_trace_env::scope_trace_env(environment const & env, options const & o) {
init(const_cast<environment*>(&env), const_cast<options*>(&o));
scope_trace_env::scope_trace_env(elab_environment const & env, options const & o) {
init(const_cast<elab_environment*>(&env), const_cast<options*>(&o));
}
scope_trace_env::~scope_trace_env() {
g_env = const_cast<environment*>(m_old_env);
g_env = const_cast<elab_environment*>(m_old_env);
g_opts = const_cast<options*>(m_old_opts);
get_enabled_trace_classes().resize(m_enable_sz);
get_disabled_trace_classes().resize(m_disable_sz);
@@ -169,7 +169,7 @@ def pretty (f : Format) (w : Nat := defWidth) (indent : Nat := 0) (column := 0)
*/
extern "C" object * lean_format_pretty(object * f, object * w, object * i, object * c);
std::string pp_expr(environment const & env, options const & opts, local_ctx const & lctx, expr const & e) {
std::string pp_expr(elab_environment const & env, options const & opts, local_ctx const & lctx, expr const & e) {
options o = opts;
// o = o.update(name{"pp", "proofs"}, true); --
object_ref fmt = get_io_result<object_ref>(lean_pp_expr(env.to_obj_arg(), lean_mk_metavar_ctx(lean_box(0)), lctx.to_obj_arg(), o.to_obj_arg(),
@@ -178,7 +178,7 @@ std::string pp_expr(environment const & env, options const & opts, local_ctx con
return str.to_std_string();
}
std::string pp_expr(environment const & env, options const & opts, expr const & e) {
std::string pp_expr(elab_environment const & env, options const & opts, expr const & e) {
local_ctx lctx;
return pp_expr(env, opts, lctx, e);
}

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