Compare commits

..

4 Commits

Author SHA1 Message Date
Kim Morrison
55444c67f9 chore: deprecate Array.get
fix test
2025-02-19 08:47:58 +11:00
Kim Morrison
fe19b1889e chore: use as[i] instead of as.get i 2025-02-18 23:19:24 +11:00
Kim Morrison
ce441a2b78 chore: update stage0 2025-02-18 23:19:23 +11:00
Kim Morrison
513374c0db chore: add Array.getInternal, also @[extern] 2025-02-18 23:16:00 +11:00
825 changed files with 10214 additions and 17102 deletions

View File

@@ -764,12 +764,11 @@ Structures and Records
The ``structure`` command in Lean is used to define an inductive data type with a single constructor and to define its projections at the same time. The syntax is as follows:
```
structure Foo (a : α) : Sort u extends Bar, Baz :=
structure Foo (a : α) extends Bar, Baz : Sort u :=
constructor :: (field₁ : β₁) ... (fieldₙ : βₙ)
```
Here ``(a : α)`` is a telescope, that is, the parameters to the inductive definition. The name ``constructor`` followed by the double colon is optional; if it is not present, the name ``mk`` is used by default. The keyword ``extends`` followed by a list of previously defined structures is also optional; if it is present, an instance of each of these structures is included among the fields to ``Foo``, and the types ``βᵢ`` can refer to their fields as well. The output type, ``Sort u``, can be omitted, in which case Lean infers to smallest non-``Prop`` sort possible (unless all the fields are ``Prop``, in which case it infers ``Prop``).
Finally, ``(field₁ : β₁) ... (fieldₙ : βₙ)`` is a telescope relative to ``(a : α)`` and the fields in ``bar`` and ``baz``.
Here ``(a : α)`` is a telescope, that is, the parameters to the inductive definition. The name ``constructor`` followed by the double colon is optional; if it is not present, the name ``mk`` is used by default. The keyword ``extends`` followed by a list of previously defined structures is also optional; if it is present, an instance of each of these structures is included among the fields to ``Foo``, and the types ``βᵢ`` can refer to their fields as well. The output type, ``Sort u``, can be omitted, in which case Lean infers to smallest non-``Prop`` sort possible. Finally, ``(field₁ : β₁) ... (fieldₙ : βₙ)`` is a telescope relative to ``(a : α)`` and the fields in ``bar`` and ``baz``.
The declaration above is syntactic sugar for an inductive type declaration, and so results in the addition of the following constants to the environment:

View File

@@ -239,22 +239,3 @@ If an acronym is typically spelled using mixed case, this mixed spelling may be
Simp sets centered around a conversion function should be called `source_to_target`. For example, a simp set for the `BitVec.toNat` function, which goes from `BitVec` to
`Nat`, should be called `bitvec_to_nat`.
## Variable names
We make the following recommendations for variable names, but without insisting on them:
* Simple hypotheses should be named `h`, `h'`, or using a numerical sequence `h₁`, `h₂`, etc.
* Another common name for a simple hypothesis is `w` (for "witness").
* `List`s should be named `l`, `l'`, `l₁`, etc, or `as`, `bs`, etc.
(Use of `as`, `bs` is encouraged when the lists are of different types, e.g. `as : List α` and `bs : List β`.)
`xs`, `ys`, `zs` are allowed, but it is better if these are reserved for `Array` and `Vector`.
A list of lists may be named `L`.
* `Array`s should be named `xs`, `ys`, `zs`, although `as`, `bs` are encouraged when the arrays are of different types, e.g. `as : Array α` and `bs : Array β`.
An array of arrays may be named `xss`.
* `Vector`s should be named `xs`, `ys`, `zs`, although `as`, `bs` are encouraged when the vectors are of different types, e.g. `as : Vector α n` and `bs : Vector β n`.
A vector of vectors may be named `xss`.
* A common exception for `List` / `Array` / `Vector` is to use `acc` for an accumulator in a recursive function.
* `i`, `j`, `k` are preferred for numerical indices.
Descriptive names such as `start`, `stop`, `lo`, and `hi` are encouraged when they increase readability.
* `n`, `m` are preferred for sizes, e.g. in `Vector α n` or `xs.size = n`.
* `w` is preferred for the width of a `BitVec`.

View File

@@ -144,12 +144,11 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
# do not import the world from windows.h using appropriately named flag
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D WIN32_LEAN_AND_MEAN")
# DLLs must go next to executables on Windows
set(CMAKE_RELATIVE_LIBRARY_OUTPUT_DIRECTORY "bin")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
else()
set(CMAKE_RELATIVE_LIBRARY_OUTPUT_DIRECTORY "lib/lean")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/lean")
endif()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_RELATIVE_LIBRARY_OUTPUT_DIRECTORY}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/lean")
# OSX default thread stack size is very small. Moreover, in Debug mode, each new stack frame consumes a lot of extra memory.

View File

@@ -78,7 +78,7 @@ Error recovery and state can interact subtly. For example, the implementation of
-/
-- NB: List instance is in mathlib. Once upstreamed, add
-- * `List`, where `failure` is the empty list and `<|>` concatenates.
class Alternative (f : Type u Type v) : Type (max (u+1) v) extends Applicative f where
class Alternative (f : Type u Type v) extends Applicative f : Type (max (u+1) v) where
/--
Produces an empty collection or recoverable failure. The `<|>` operator collects values or recovers
from failures. See `Alternative` for more details.

View File

@@ -47,7 +47,7 @@ pure f <*> pure x = pure (f x)
u <*> pure y = pure (· y) <*> u
```
-/
class LawfulApplicative (f : Type u Type v) [Applicative f] : Prop extends LawfulFunctor f where
class LawfulApplicative (f : Type u Type v) [Applicative f] extends LawfulFunctor f : Prop where
seqLeft_eq (x : f α) (y : f β) : x <* y = const β <$> x <*> y
seqRight_eq (x : f α) (y : f β) : x *> y = const α id <$> x <*> y
pure_seq (g : α β) (x : f α) : pure g <*> x = g <$> x
@@ -77,7 +77,7 @@ x >>= f >>= g = x >>= (fun x => f x >>= g)
`LawfulMonad.mk'` is an alternative constructor containing useful defaults for many fields.
-/
class LawfulMonad (m : Type u Type v) [Monad m] : Prop extends LawfulApplicative m where
class LawfulMonad (m : Type u Type v) [Monad m] extends LawfulApplicative m : Prop where
bind_pure_comp (f : α β) (x : m α) : x >>= (fun a => pure (f a)) = f <$> x
bind_map {α β : Type u} (f : m (α β)) (x : m α) : f >>= (. <$> x) = f <*> x
pure_bind (x : α) (f : α m β) : pure x >>= f = f x

View File

@@ -2020,7 +2020,7 @@ free variables. The frontend automatically declares a fresh auxiliary constant `
Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base.
This is extra 30k lines of code. More importantly, you will probably not be able to check your development using
external type checkers that do not implement this feature.
external type checkers (e.g., Trepplein) that do not implement this feature.
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
So, you are mainly losing the capability of type checking your development using external checkers.
@@ -2055,7 +2055,7 @@ decidability instance can be evaluated to `true` using the lean compiler / inter
Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base.
This is extra 30k lines of code. More importantly, you will probably not be able to check your development using
external type checkers that do not implement this feature.
external type checkers (e.g., Trepplein) that do not implement this feature.
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
So, you are mainly losing the capability of type checking your development using external checkers.
-/
@@ -2066,7 +2066,7 @@ The axiom `ofReduceNat` is used to perform proofs by reflection. See `reduceBool
Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base.
This is extra 30k lines of code. More importantly, you will probably not be able to check your development using
external type checkers that do not implement this feature.
external type checkers (e.g., Trepplein) that do not implement this feature.
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
So, you are mainly losing the capability of type checking your development using external checkers.
-/
@@ -2125,7 +2125,7 @@ class LeftIdentity (op : α → β → β) (o : outParam α) : Prop
`LawfulLeftIdentify op o` indicates `o` is a verified left identity of
`op`.
-/
class LawfulLeftIdentity (op : α β β) (o : outParam α) : Prop extends LeftIdentity op o where
class LawfulLeftIdentity (op : α β β) (o : outParam α) extends LeftIdentity op o : Prop where
/-- Left identity `o` is an identity. -/
left_id : a, op o a = a
@@ -2141,7 +2141,7 @@ class RightIdentity (op : α → β → α) (o : outParam β) : Prop
`LawfulRightIdentify op o` indicates `o` is a verified right identity of
`op`.
-/
class LawfulRightIdentity (op : α β α) (o : outParam β) : Prop extends RightIdentity op o where
class LawfulRightIdentity (op : α β α) (o : outParam β) extends RightIdentity op o : Prop where
/-- Right identity `o` is an identity. -/
right_id : a, op a o = a
@@ -2151,13 +2151,13 @@ class LawfulRightIdentity (op : α → β → α) (o : outParam β) : Prop exten
This class does not require a proof that `o` is an identity, and is used
primarily for inferring the identity using class resolution.
-/
class Identity (op : α α α) (o : outParam α) : Prop extends LeftIdentity op o, RightIdentity op o
class Identity (op : α α α) (o : outParam α) extends LeftIdentity op o, RightIdentity op o : Prop
/--
`LawfulIdentity op o` indicates `o` is a verified left and right
identity of `op`.
-/
class LawfulIdentity (op : α α α) (o : outParam α) : Prop extends Identity op o, LawfulLeftIdentity op o, LawfulRightIdentity op o
class LawfulIdentity (op : α α α) (o : outParam α) extends Identity op o, LawfulLeftIdentity op o, LawfulRightIdentity op o : Prop
/--
`LawfulCommIdentity` can simplify defining instances of `LawfulIdentity`
@@ -2168,7 +2168,7 @@ This class is intended for simplifying defining instances of
`LawfulIdentity` and functions needed commutative operations with
identity should just add a `LawfulIdentity` constraint.
-/
class LawfulCommIdentity (op : α α α) (o : outParam α) [hc : Commutative op] : Prop extends LawfulIdentity op o where
class LawfulCommIdentity (op : α α α) (o : outParam α) [hc : Commutative op] extends LawfulIdentity op o : Prop where
left_id a := Eq.trans (hc.comm o a) (right_id a)
right_id a := Eq.trans (hc.comm a o) (left_id a)

View File

@@ -9,9 +9,6 @@ import Init.Data.Array.Lemmas
import Init.Data.Array.Count
import Init.Data.List.Attach
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/--
@@ -22,8 +19,8 @@ to apply `f`.
We replace this at runtime with a more efficient version via the `csimp` lemma `pmap_eq_pmapImpl`.
-/
def pmap {P : α Prop} (f : a, P a β) (xs : Array α) (H : a xs, P a) : Array β :=
(xs.toList.pmap f (fun a m => H a (mem_def.mpr m))).toArray
def pmap {P : α Prop} (f : a, P a β) (l : Array α) (H : a l, P a) : Array β :=
(l.toList.pmap f (fun a m => H a (mem_def.mpr m))).toArray
/--
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
@@ -54,25 +51,25 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
l.toArray.pmap f H = (l.pmap f (by simpa using H)).toArray := by
simp [pmap]
@[simp] theorem toList_attachWith {xs : Array α} {P : α Prop} {H : x xs, P x} :
(xs.attachWith P H).toList = xs.toList.attachWith P (by simpa [mem_toList] using H) := by
@[simp] theorem toList_attachWith {l : Array α} {P : α Prop} {H : x l, P x} :
(l.attachWith P H).toList = l.toList.attachWith P (by simpa [mem_toList] using H) := by
simp [attachWith]
@[simp] theorem toList_attach {xs : Array α} :
xs.attach.toList = xs.toList.attachWith (· xs) (by simp [mem_toList]) := by
@[simp] theorem toList_attach {α : Type _} {l : Array α} :
l.attach.toList = l.toList.attachWith (· l) (by simp [mem_toList]) := by
simp [attach]
@[simp] theorem toList_pmap {xs : Array α} {P : α Prop} {f : a, P a β} {H : a xs, P a} :
(xs.pmap f H).toList = xs.toList.pmap f (fun a m => H a (mem_def.mpr m)) := by
@[simp] theorem toList_pmap {l : Array α} {P : α Prop} {f : a, P a β} {H : a l, P a} :
(l.pmap f H).toList = l.toList.pmap f (fun a m => H a (mem_def.mpr m)) := by
simp [pmap]
/-- Implementation of `pmap` using the zero-copy version of `attach`. -/
@[inline] private def pmapImpl {P : α Prop} (f : a, P a β) (xs : Array α) (H : a xs, P a) :
Array β := (xs.attachWith _ H).map fun x, h' => f x h'
@[inline] private def pmapImpl {P : α Prop} (f : a, P a β) (l : Array α) (H : a l, P a) :
Array β := (l.attachWith _ H).map fun x, h' => f x h'
@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by
funext α β p f xs H
cases xs
funext α β p f L h'
cases L
simp only [pmap, pmapImpl, List.attachWith_toArray, List.map_toArray, mk.injEq, List.map_attachWith_eq_pmap]
apply List.pmap_congr_left
intro a m h₁ h₂
@@ -80,9 +77,9 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
@[simp] theorem pmap_empty {P : α Prop} (f : a, P a β) : pmap f #[] (by simp) = #[] := rfl
@[simp] theorem pmap_push {P : α Prop} (f : a, P a β) (a : α) (xs : Array α) (h : b xs.push a, P b) :
pmap f (xs.push a) h =
(pmap f xs (fun a m => by simp at h; exact h a (.inl m))).push (f a (h a (by simp))) := by
@[simp] theorem pmap_push {P : α Prop} (f : a, P a β) (a : α) (l : Array α) (h : b l.push a, P b) :
pmap f (l.push a) h =
(pmap f l (fun a m => by simp at h; exact h a (.inl m))).push (f a (h a (by simp))) := by
simp [pmap]
@[simp] theorem attach_empty : (#[] : Array α).attach = #[] := rfl
@@ -97,158 +94,158 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
simp
@[simp]
theorem pmap_eq_map (p : α Prop) (f : α β) (xs : Array α) (H) :
@pmap _ _ p (fun a _ => f a) xs H = map f xs := by
cases xs; simp
theorem pmap_eq_map (p : α Prop) (f : α β) (l : Array α) (H) :
@pmap _ _ p (fun a _ => f a) l H = map f l := by
cases l; simp
theorem pmap_congr_left {p q : α Prop} {f : a, p a β} {g : a, q a β} (xs : Array α) {H₁ H₂}
(h : a xs, (h₁ h₂), f a h₁ = g a h₂) : pmap f xs H₁ = pmap g xs H₂ := by
cases xs
theorem pmap_congr_left {p q : α Prop} {f : a, p a β} {g : a, q a β} (l : Array α) {H₁ H₂}
(h : a l, (h₁ h₂), f a h₁ = g a h₂) : pmap f l H₁ = pmap g l H₂ := by
cases l
simp only [mem_toArray] at h
simp only [List.pmap_toArray, mk.injEq]
rw [List.pmap_congr_left _ h]
theorem map_pmap {p : α Prop} (g : β γ) (f : a, p a β) (xs H) :
map g (pmap f xs H) = pmap (fun a h => g (f a h)) xs H := by
cases xs
theorem map_pmap {p : α Prop} (g : β γ) (f : a, p a β) (l H) :
map g (pmap f l H) = pmap (fun a h => g (f a h)) l H := by
cases l
simp [List.map_pmap]
theorem pmap_map {p : β Prop} (g : b, p b γ) (f : α β) (xs H) :
pmap g (map f xs) H = pmap (fun a h => g (f a) h) xs fun _ h => H _ (mem_map_of_mem _ h) := by
cases xs
theorem pmap_map {p : β Prop} (g : b, p b γ) (f : α β) (l H) :
pmap g (map f l) H = pmap (fun a h => g (f a) h) l fun _ h => H _ (mem_map_of_mem _ h) := by
cases l
simp [List.pmap_map]
theorem attach_congr {xs ys : Array α} (h : xs = ys) :
xs.attach = ys.attach.map (fun x => x.1, h x.2) := by
theorem attach_congr {l₁ l₂ : Array α} (h : l₁ = l₂) :
l₁.attach = l₂.attach.map (fun x => x.1, h x.2) := by
subst h
simp
theorem attachWith_congr {xs ys : Array α} (w : xs = ys) {P : α Prop} {H : x xs, P x} :
xs.attachWith P H = ys.attachWith P fun _ h => H _ (w h) := by
theorem attachWith_congr {l₁ l₂ : Array α} (w : l₁ = l₂) {P : α Prop} {H : x l₁, P x} :
l₁.attachWith P H = l₂.attachWith P fun _ h => H _ (w h) := by
subst w
simp
@[simp] theorem attach_push {a : α} {xs : Array α} :
(xs.push a).attach =
(xs.attach.map (fun x, h => x, mem_push_of_mem a h)).push a, by simp := by
cases xs
@[simp] theorem attach_push {a : α} {l : Array α} :
(l.push a).attach =
(l.attach.map (fun x, h => x, mem_push_of_mem a h)).push a, by simp := by
cases l
rw [attach_congr (List.push_toArray _ _)]
simp [Function.comp_def]
@[simp] theorem attachWith_push {a : α} {xs : Array α} {P : α Prop} {H : x xs.push a, P x} :
(xs.push a).attachWith P H =
(xs.attachWith P (fun x h => by simp at H; exact H x (.inl h))).push a, H a (by simp) := by
cases xs
@[simp] theorem attachWith_push {a : α} {l : Array α} {P : α Prop} {H : x l.push a, P x} :
(l.push a).attachWith P H =
(l.attachWith P (fun x h => by simp at H; exact H x (.inl h))).push a, H a (by simp) := by
cases l
simp [attachWith_congr (List.push_toArray _ _)]
theorem pmap_eq_map_attach {p : α Prop} (f : a, p a β) (xs H) :
pmap f xs H = xs.attach.map fun x => f x.1 (H _ x.2) := by
cases xs
theorem pmap_eq_map_attach {p : α Prop} (f : a, p a β) (l H) :
pmap f l H = l.attach.map fun x => f x.1 (H _ x.2) := by
cases l
simp [List.pmap_eq_map_attach]
@[simp]
theorem pmap_eq_attachWith {p q : α Prop} (f : a, p a q a) (xs H) :
pmap (fun a h => a, f a h) xs H = xs.attachWith q (fun x h => f x (H x h)) := by
cases xs
theorem pmap_eq_attachWith {p q : α Prop} (f : a, p a q a) (l H) :
pmap (fun a h => a, f a h) l H = l.attachWith q (fun x h => f x (H x h)) := by
cases l
simp [List.pmap_eq_attachWith]
theorem attach_map_val (xs : Array α) (f : α β) :
(xs.attach.map fun (i : {i // i xs}) => f i) = xs.map f := by
cases xs
theorem attach_map_val (l : Array α) (f : α β) :
(l.attach.map fun (i : {i // i l}) => f i) = l.map f := by
cases l
simp
@[deprecated attach_map_val (since := "2025-02-17")]
abbrev attach_map_coe := @attach_map_val
theorem attach_map_subtype_val (xs : Array α) : xs.attach.map Subtype.val = xs := by
cases xs; simp
theorem attach_map_subtype_val (l : Array α) : l.attach.map Subtype.val = l := by
cases l; simp
theorem attachWith_map_val {p : α Prop} (f : α β) (xs : Array α) (H : a xs, p a) :
((xs.attachWith p H).map fun (i : { i // p i}) => f i) = xs.map f := by
cases xs; simp
theorem attachWith_map_val {p : α Prop} (f : α β) (l : Array α) (H : a l, p a) :
((l.attachWith p H).map fun (i : { i // p i}) => f i) = l.map f := by
cases l; simp
@[deprecated attachWith_map_val (since := "2025-02-17")]
abbrev attachWith_map_coe := @attachWith_map_val
theorem attachWith_map_subtype_val {p : α Prop} (xs : Array α) (H : a xs, p a) :
(xs.attachWith p H).map Subtype.val = xs := by
cases xs; simp
theorem attachWith_map_subtype_val {p : α Prop} (l : Array α) (H : a l, p a) :
(l.attachWith p H).map Subtype.val = l := by
cases l; simp
@[simp]
theorem mem_attach (xs : Array α) : x, x xs.attach
theorem mem_attach (l : Array α) : x, x l.attach
| a, h => by
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
rcases this with _, _, m, rfl
exact m
@[simp]
theorem mem_attachWith (xs : Array α) {q : α Prop} (H) (x : {x // q x}) :
x xs.attachWith q H x.1 xs := by
cases xs
theorem mem_attachWith (l : Array α) {q : α Prop} (H) (x : {x // q x}) :
x l.attachWith q H x.1 l := by
cases l
simp
@[simp]
theorem mem_pmap {p : α Prop} {f : a, p a β} {xs H b} :
b pmap f xs H (a : _) (h : a xs), f a (H a h) = b := by
theorem mem_pmap {p : α Prop} {f : a, p a β} {l H b} :
b pmap f l H (a : _) (h : a l), f a (H a h) = b := by
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
theorem mem_pmap_of_mem {p : α Prop} {f : a, p a β} {xs H} {a} (h : a xs) :
f a (H a h) pmap f xs H := by
theorem mem_pmap_of_mem {p : α Prop} {f : a, p a β} {l H} {a} (h : a l) :
f a (H a h) pmap f l H := by
rw [mem_pmap]
exact a, h, rfl
@[simp]
theorem size_pmap {p : α Prop} {f : a, p a β} {xs H} : (pmap f xs H).size = xs.size := by
cases xs; simp
theorem size_pmap {p : α Prop} {f : a, p a β} {l H} : (pmap f l H).size = l.size := by
cases l; simp
@[simp]
theorem size_attach {xs : Array α} : xs.attach.size = xs.size := by
cases xs; simp
theorem size_attach {L : Array α} : L.attach.size = L.size := by
cases L; simp
@[simp]
theorem size_attachWith {p : α Prop} {xs : Array α} {H} : (xs.attachWith p H).size = xs.size := by
cases xs; simp
theorem size_attachWith {p : α Prop} {l : Array α} {H} : (l.attachWith p H).size = l.size := by
cases l; simp
@[simp]
theorem pmap_eq_empty_iff {p : α Prop} {f : a, p a β} {xs H} : pmap f xs H = #[] xs = #[] := by
cases xs; simp
theorem pmap_eq_empty_iff {p : α Prop} {f : a, p a β} {l H} : pmap f l H = #[] l = #[] := by
cases l; simp
theorem pmap_ne_empty_iff {P : α Prop} (f : (a : α) P a β) {xs : Array α}
(H : (a : α), a xs P a) : xs.pmap f H #[] xs #[] := by
cases xs; simp
theorem pmap_eq_self {xs : Array α} {p : α Prop} {hp : (a : α), a xs p a}
{f : (a : α) p a α} : xs.pmap f hp = xs a (h : a xs), f a (hp a h) = a := by
cases xs; simp [List.pmap_eq_self]
theorem pmap_eq_self {l : Array α} {p : α Prop} {hp : (a : α), a l p a}
{f : (a : α) p a α} : l.pmap f hp = l a (h : a l), f a (hp a h) = a := by
cases l; simp [List.pmap_eq_self]
@[simp]
theorem attach_eq_empty_iff {xs : Array α} : xs.attach = #[] xs = #[] := by
cases xs; simp
theorem attach_eq_empty_iff {l : Array α} : l.attach = #[] l = #[] := by
cases l; simp
theorem attach_ne_empty_iff {xs : Array α} : xs.attach #[] xs #[] := by
cases xs; simp
theorem attach_ne_empty_iff {l : Array α} : l.attach #[] l #[] := by
cases l; simp
@[simp]
theorem attachWith_eq_empty_iff {xs : Array α} {P : α Prop} {H : a xs, P a} :
xs.attachWith P H = #[] xs = #[] := by
cases xs; simp
theorem attachWith_eq_empty_iff {l : Array α} {P : α Prop} {H : a l, P a} :
l.attachWith P H = #[] l = #[] := by
cases l; simp
theorem attachWith_ne_empty_iff {xs : Array α} {P : α Prop} {H : a xs, P a} :
xs.attachWith P H #[] xs #[] := by
cases xs; simp
theorem attachWith_ne_empty_iff {l : Array α} {P : α Prop} {H : a l, P a} :
l.attachWith P H #[] l #[] := by
cases l; simp
@[simp]
theorem getElem?_pmap {p : α Prop} (f : a, p a β) {xs : Array α} (h : a xs, p a) (i : Nat) :
(pmap f xs h)[i]? = Option.pmap f xs[i]? fun x H => h x (mem_of_getElem? H) := by
cases xs; simp
theorem getElem?_pmap {p : α Prop} (f : a, p a β) {l : Array α} (h : a l, p a) (i : Nat) :
(pmap f l h)[i]? = Option.pmap f l[i]? fun x H => h x (mem_of_getElem? H) := by
cases l; simp
@[simp]
theorem getElem_pmap {p : α Prop} (f : a, p a β) {xs : Array α} (h : a xs, p a) {i : Nat}
(hi : i < (pmap f xs h).size) :
(pmap f xs h)[i] =
f (xs[i]'(@size_pmap _ _ p f xs h hi))
(h _ (getElem_mem (@size_pmap _ _ p f xs h hi))) := by
cases xs; simp
theorem getElem_pmap {p : α Prop} (f : a, p a β) {l : Array α} (h : a l, p a) {i : Nat}
(hi : i < (pmap f l h).size) :
(pmap f l h)[i] =
f (l[i]'(@size_pmap _ _ p f l h hi))
(h _ (getElem_mem (@size_pmap _ _ p f l h hi))) := by
cases l; simp
@[simp]
theorem getElem?_attachWith {xs : Array α} {i : Nat} {P : α Prop} {H : a xs, P a} :
@@ -271,40 +268,40 @@ theorem getElem_attach {xs : Array α} {i : Nat} (h : i < xs.attach.size) :
xs.attach[i] = xs[i]'(by simpa using h), getElem_mem (by simpa using h) :=
getElem_attachWith h
@[simp] theorem pmap_attach (xs : Array α) {p : {x // x xs} Prop} (f : a, p a β) (H) :
pmap f xs.attach H =
xs.pmap (P := fun a => h : a xs, p a, h)
@[simp] theorem pmap_attach (l : Array α) {p : {x // x l} Prop} (f : a, p a β) (H) :
pmap f l.attach H =
l.pmap (P := fun a => h : a l, p a, h)
(fun a h => f a, h.1 h.2) (fun a h => h, H a, h (by simp)) := by
ext <;> simp
@[simp] theorem pmap_attachWith (xs : Array α) {p : {x // q x} Prop} (f : a, p a β) (H₁ H₂) :
pmap f (xs.attachWith q H₁) H₂ =
xs.pmap (P := fun a => h : q a, p a, h)
@[simp] theorem pmap_attachWith (l : Array α) {p : {x // q x} Prop} (f : a, p a β) (H₁ H₂) :
pmap f (l.attachWith q H₁) H₂ =
l.pmap (P := fun a => h : q a, p a, h)
(fun a h => f a, h.1 h.2) (fun a h => H₁ _ h, H₂ a, H₁ _ h (by simpa)) := by
ext <;> simp
theorem foldl_pmap (xs : Array α) {P : α Prop} (f : (a : α) P a β)
(H : (a : α), a xs P a) (g : γ β γ) (x : γ) :
(xs.pmap f H).foldl g x = xs.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
theorem foldl_pmap (l : Array α) {P : α Prop} (f : (a : α) P a β)
(H : (a : α), a l P a) (g : γ β γ) (x : γ) :
(l.pmap f H).foldl g x = l.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
rw [pmap_eq_map_attach, foldl_map]
theorem foldr_pmap (xs : Array α) {P : α Prop} (f : (a : α) P a β)
(H : (a : α), a xs P a) (g : β γ γ) (x : γ) :
(xs.pmap f H).foldr g x = xs.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
theorem foldr_pmap (l : Array α) {P : α Prop} (f : (a : α) P a β)
(H : (a : α), a l P a) (g : β γ γ) (x : γ) :
(l.pmap f H).foldr g x = l.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
rw [pmap_eq_map_attach, foldr_map]
@[simp] theorem foldl_attachWith
(xs : Array α) {q : α Prop} (H : a, a xs q a) {f : β { x // q x} β} {b} (w : stop = xs.size) :
(xs.attachWith q H).foldl f b 0 stop = xs.attach.foldl (fun b a, h => f b a, H _ h) b := by
(l : Array α) {q : α Prop} (H : a, a l q a) {f : β { x // q x} β} {b} (w : stop = l.size) :
(l.attachWith q H).foldl f b 0 stop = l.attach.foldl (fun b a, h => f b a, H _ h) b := by
subst w
rcases xs with xs
rcases l with l
simp [List.foldl_attachWith, List.foldl_map]
@[simp] theorem foldr_attachWith
(xs : Array α) {q : α Prop} (H : a, a xs q a) {f : { x // q x} β β} {b} (w : start = xs.size) :
(xs.attachWith q H).foldr f b start 0 = xs.attach.foldr (fun a acc => f a.1, H _ a.2 acc) b := by
(l : Array α) {q : α Prop} (H : a, a l q a) {f : { x // q x} β β} {b} (w : start = l.size) :
(l.attachWith q H).foldr f b start 0 = l.attach.foldr (fun a acc => f a.1, H _ a.2 acc) b := by
subst w
rcases xs with xs
rcases l with l
simp [List.foldr_attachWith, List.foldr_map]
/--
@@ -317,9 +314,9 @@ Unfortunately this can't be applied by `simp` because of the higher order unific
and even when rewriting we need to specify the function explicitly.
See however `foldl_subtype` below.
-/
theorem foldl_attach (xs : Array α) (f : β α β) (b : β) :
xs.attach.foldl (fun acc t => f acc t.1) b = xs.foldl f b := by
rcases xs with xs
theorem foldl_attach (l : Array α) (f : β α β) (b : β) :
l.attach.foldl (fun acc t => f acc t.1) b = l.foldl f b := by
rcases l with l
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
List.length_pmap, List.foldl_toArray', mem_toArray, List.foldl_subtype]
congr
@@ -336,101 +333,101 @@ Unfortunately this can't be applied by `simp` because of the higher order unific
and even when rewriting we need to specify the function explicitly.
See however `foldr_subtype` below.
-/
theorem foldr_attach (xs : Array α) (f : α β β) (b : β) :
xs.attach.foldr (fun t acc => f t.1 acc) b = xs.foldr f b := by
rcases xs with xs
theorem foldr_attach (l : Array α) (f : α β β) (b : β) :
l.attach.foldr (fun t acc => f t.1 acc) b = l.foldr f b := by
rcases l with l
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
List.length_pmap, List.foldr_toArray', mem_toArray, List.foldr_subtype]
congr
ext
simpa using fun a => List.mem_of_getElem? a
theorem attach_map {xs : Array α} (f : α β) :
(xs.map f).attach = xs.attach.map (fun x, h => f x, mem_map_of_mem f h) := by
cases xs
theorem attach_map {l : Array α} (f : α β) :
(l.map f).attach = l.attach.map (fun x, h => f x, mem_map_of_mem f h) := by
cases l
ext <;> simp
theorem attachWith_map {xs : Array α} (f : α β) {P : β Prop} {H : (b : β), b xs.map f P b} :
(xs.map f).attachWith P H = (xs.attachWith (P f) (fun _ h => H _ (mem_map_of_mem f h))).map
theorem attachWith_map {l : Array α} (f : α β) {P : β Prop} {H : (b : β), b l.map f P b} :
(l.map f).attachWith P H = (l.attachWith (P f) (fun _ h => H _ (mem_map_of_mem f h))).map
fun x, h => f x, h := by
cases xs
cases l
simp [List.attachWith_map]
@[simp] theorem map_attachWith {xs : Array α} {P : α Prop} {H : (a : α), a xs P a}
@[simp] theorem map_attachWith {l : Array α} {P : α Prop} {H : (a : α), a l P a}
(f : { x // P x } β) :
(xs.attachWith P H).map f = xs.attach.map fun x, h => f x, H _ h := by
cases xs <;> simp_all
(l.attachWith P H).map f = l.attach.map fun x, h => f x, H _ h := by
cases l <;> simp_all
theorem map_attachWith_eq_pmap {xs : Array α} {P : α Prop} {H : (a : α), a xs P a}
theorem map_attachWith_eq_pmap {l : Array α} {P : α Prop} {H : (a : α), a l P a}
(f : { x // P x } β) :
(xs.attachWith P H).map f =
xs.pmap (fun a (h : a xs P a) => f a, H _ h.1) (fun a h => h, H a h) := by
cases xs
(l.attachWith P H).map f =
l.pmap (fun a (h : a l P a) => f a, H _ h.1) (fun a h => h, H a h) := by
cases l
ext <;> simp
/-- See also `pmap_eq_map_attach` for writing `pmap` in terms of `map` and `attach`. -/
theorem map_attach_eq_pmap {xs : Array α} (f : { x // x xs } β) :
xs.attach.map f = xs.pmap (fun a h => f a, h) (fun _ => id) := by
cases xs
theorem map_attach_eq_pmap {l : Array α} (f : { x // x l } β) :
l.attach.map f = l.pmap (fun a h => f a, h) (fun _ => id) := by
cases l
ext <;> simp
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
abbrev map_attach := @map_attach_eq_pmap
theorem attach_filterMap {xs : Array α} {f : α Option β} :
(xs.filterMap f).attach = xs.attach.filterMap
theorem attach_filterMap {l : Array α} {f : α Option β} :
(l.filterMap f).attach = l.attach.filterMap
fun x, h => (f x).pbind (fun b m => some b, mem_filterMap.mpr x, h, m) := by
cases xs
cases l
rw [attach_congr (List.filterMap_toArray f _)]
simp [List.attach_filterMap, List.map_filterMap, Function.comp_def]
theorem attach_filter {xs : Array α} (p : α Bool) :
(xs.filter p).attach = xs.attach.filterMap
theorem attach_filter {l : Array α} (p : α Bool) :
(l.filter p).attach = l.attach.filterMap
fun x => if w : p x.1 then some x.1, mem_filter.mpr x.2, w else none := by
cases xs
cases l
rw [attach_congr (List.filter_toArray p _)]
simp [List.attach_filter, List.map_filterMap, Function.comp_def]
-- We are still missing here `attachWith_filterMap` and `attachWith_filter`.
@[simp]
theorem filterMap_attachWith {q : α Prop} {xs : Array α} {f : {x // q x} Option β} (H)
(w : stop = (xs.attachWith q H).size) :
(xs.attachWith q H).filterMap f 0 stop = xs.attach.filterMap (fun x, h => f x, H _ h) := by
theorem filterMap_attachWith {q : α Prop} {l : Array α} {f : {x // q x} Option β} (H)
(w : stop = (l.attachWith q H).size) :
(l.attachWith q H).filterMap f 0 stop = l.attach.filterMap (fun x, h => f x, H _ h) := by
subst w
cases xs
cases l
simp [Function.comp_def]
@[simp]
theorem filter_attachWith {q : α Prop} {xs : Array α} {p : {x // q x} Bool} (H)
(w : stop = (xs.attachWith q H).size) :
(xs.attachWith q H).filter p 0 stop =
(xs.attach.filter (fun x, h => p x, H _ h)).map (fun x, h => x, H _ h) := by
theorem filter_attachWith {q : α Prop} {l : Array α} {p : {x // q x} Bool} (H)
(w : stop = (l.attachWith q H).size) :
(l.attachWith q H).filter p 0 stop =
(l.attach.filter (fun x, h => p x, H _ h)).map (fun x, h => x, H _ h) := by
subst w
cases xs
cases l
simp [Function.comp_def, List.filter_map]
theorem pmap_pmap {p : α Prop} {q : β Prop} (g : a, p a β) (f : b, q b γ) (xs H₁ H₂) :
pmap f (pmap g xs H₁) H₂ =
pmap (α := { x // x xs }) (fun a h => f (g a h) (H₂ (g a h) (mem_pmap_of_mem a.2))) xs.attach
theorem pmap_pmap {p : α Prop} {q : β Prop} (g : a, p a β) (f : b, q b γ) (l H₁ H₂) :
pmap f (pmap g l H₁) H₂ =
pmap (α := { x // x l }) (fun a h => f (g a h) (H₂ (g a h) (mem_pmap_of_mem a.2))) l.attach
(fun a _ => H₁ a a.2) := by
cases xs
cases l
simp [List.pmap_pmap, List.pmap_map]
@[simp] theorem pmap_append {p : ι Prop} (f : a : ι, p a α) (xs ys : Array ι)
(h : a xs ++ ys, p a) :
(xs ++ ys).pmap f h =
(xs.pmap f fun a ha => h a (mem_append_left ys ha)) ++
ys.pmap f fun a ha => h a (mem_append_right xs ha) := by
cases xs
cases ys
@[simp] theorem pmap_append {p : ι Prop} (f : a : ι, p a α) (l₁ l₂ : Array ι)
(h : a l₁ ++ l₂, p a) :
(l₁ ++ l₂).pmap f h =
(l₁.pmap f fun a ha => h a (mem_append_left l₂ ha)) ++
l₂.pmap f fun a ha => h a (mem_append_right l₁ ha) := by
cases l₁
cases l₂
simp
theorem pmap_append' {p : α Prop} (f : a : α, p a β) (xs ys : Array α)
(h₁ : a xs, p a) (h₂ : a ys, p a) :
((xs ++ ys).pmap f fun a ha => (mem_append.1 ha).elim (h₁ a) (h₂ a)) =
xs.pmap f h₁ ++ ys.pmap f h₂ :=
pmap_append f xs ys _
theorem pmap_append' {p : α Prop} (f : a : α, p a β) (l₁ l₂ : Array α)
(h₁ : a l₁, p a) (h₂ : a l₂, p a) :
((l₁ ++ l₂).pmap f fun a ha => (mem_append.1 ha).elim (h₁ a) (h₂ a)) =
l₁.pmap f h₁ ++ l₂.pmap f h₂ :=
pmap_append f l₁ l₂ _
@[simp] theorem attach_append (xs ys : Array α) :
(xs ++ ys).attach = xs.attach.map (fun x, h => x, mem_append_left ys h) ++
@@ -499,35 +496,35 @@ theorem back?_attach {xs : Array α} :
simp
@[simp]
theorem countP_attach (xs : Array α) (p : α Bool) :
xs.attach.countP (fun a : {x // x xs} => p a) = xs.countP p := by
cases xs
theorem countP_attach (l : Array α) (p : α Bool) :
l.attach.countP (fun a : {x // x l} => p a) = l.countP p := by
cases l
simp [Function.comp_def]
@[simp]
theorem countP_attachWith {p : α Prop} (xs : Array α) (H : a xs, p a) (q : α Bool) :
(xs.attachWith p H).countP (fun a : {x // p x} => q a) = xs.countP q := by
cases xs
theorem countP_attachWith {p : α Prop} (l : Array α) (H : a l, p a) (q : α Bool) :
(l.attachWith p H).countP (fun a : {x // p x} => q a) = l.countP q := by
cases l
simp
@[simp]
theorem count_attach [DecidableEq α] (xs : Array α) (a : {x // x xs}) :
xs.attach.count a = xs.count a := by
rcases xs with xs
theorem count_attach [DecidableEq α] (l : Array α) (a : {x // x l}) :
l.attach.count a = l.count a := by
rcases l with l
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.count_toArray]
rw [List.map_attach_eq_pmap, List.count_eq_countP]
simp only [Subtype.beq_iff]
rw [List.countP_pmap, List.countP_attach (p := (fun x => x == a.1)), List.count]
@[simp]
theorem count_attachWith [DecidableEq α] {p : α Prop} (xs : Array α) (H : a xs, p a) (a : {x // p x}) :
(xs.attachWith p H).count a = xs.count a := by
cases xs
theorem count_attachWith [DecidableEq α] {p : α Prop} (l : Array α) (H : a l, p a) (a : {x // p x}) :
(l.attachWith p H).count a = l.count a := by
cases l
simp
@[simp] theorem countP_pmap {p : α Prop} (g : a, p a β) (f : β Bool) (xs : Array α) (H₁) :
(xs.pmap g H₁).countP f =
xs.attach.countP (fun a, m => f (g a (H₁ a m))) := by
@[simp] theorem countP_pmap {p : α Prop} (g : a, p a β) (f : β Bool) (l : Array α) (H₁) :
(l.pmap g H₁).countP f =
l.attach.countP (fun a, m => f (g a (H₁ a m))) := by
simp [pmap_eq_map_attach, countP_map, Function.comp_def]
/-! ## unattach
@@ -548,43 +545,43 @@ and is ideally subsequently simplified away by `unattach_attach`.
If not, usually the right approach is `simp [Array.unattach, -Array.map_subtype]` to unfold.
-/
def unattach {α : Type _} {p : α Prop} (xs : Array { x // p x }) : Array α := xs.map (·.val)
def unattach {α : Type _} {p : α Prop} (l : Array { x // p x }) : Array α := l.map (·.val)
@[simp] theorem unattach_nil {p : α Prop} : (#[] : Array { x // p x }).unattach = #[] := rfl
@[simp] theorem unattach_push {p : α Prop} {a : { x // p x }} {xs : Array { x // p x }} :
(xs.push a).unattach = xs.unattach.push a.1 := by
@[simp] theorem unattach_push {p : α Prop} {a : { x // p x }} {l : Array { x // p x }} :
(l.push a).unattach = l.unattach.push a.1 := by
simp only [unattach, Array.map_push]
@[simp] theorem size_unattach {p : α Prop} {xs : Array { x // p x }} :
xs.unattach.size = xs.size := by
@[simp] theorem size_unattach {p : α Prop} {l : Array { x // p x }} :
l.unattach.size = l.size := by
unfold unattach
simp
@[simp] theorem _root_.List.unattach_toArray {p : α Prop} {xs : List { x // p x }} :
xs.toArray.unattach = xs.unattach.toArray := by
@[simp] theorem _root_.List.unattach_toArray {p : α Prop} {l : List { x // p x }} :
l.toArray.unattach = l.unattach.toArray := by
simp only [unattach, List.map_toArray, List.unattach]
@[simp] theorem toList_unattach {p : α Prop} {xs : Array { x // p x }} :
xs.unattach.toList = xs.toList.unattach := by
@[simp] theorem toList_unattach {p : α Prop} {l : Array { x // p x }} :
l.unattach.toList = l.toList.unattach := by
simp only [unattach, toList_map, List.unattach]
@[simp] theorem unattach_attach {xs : Array α} : xs.attach.unattach = xs := by
cases xs
@[simp] theorem unattach_attach {l : Array α} : l.attach.unattach = l := by
cases l
simp only [List.attach_toArray, List.unattach_toArray, List.unattach_attachWith]
@[simp] theorem unattach_attachWith {p : α Prop} {xs : Array α}
{H : a xs, p a} :
(xs.attachWith p H).unattach = xs := by
cases xs
@[simp] theorem unattach_attachWith {p : α Prop} {l : Array α}
{H : a l, p a} :
(l.attachWith p H).unattach = l := by
cases l
simp
@[simp] theorem getElem?_unattach {p : α Prop} {xs : Array { x // p x }} (i : Nat) :
xs.unattach[i]? = xs[i]?.map Subtype.val := by
@[simp] theorem getElem?_unattach {p : α Prop} {l : Array { x // p x }} (i : Nat) :
l.unattach[i]? = l[i]?.map Subtype.val := by
simp [unattach]
@[simp] theorem getElem_unattach
{p : α Prop} {xs : Array { x // p x }} (i : Nat) (h : i < xs.unattach.size) :
xs.unattach[i] = (xs[i]'(by simpa using h)).1 := by
{p : α Prop} {l : Array { x // p x }} (i : Nat) (h : i < l.unattach.size) :
l.unattach[i] = (l[i]'(by simpa using h)).1 := by
simp [unattach]
/-! ### Recognizing higher order functions using a function that only depends on the value. -/
@@ -593,20 +590,20 @@ def unattach {α : Type _} {p : α → Prop} (xs : Array { x // p x }) : Array
This lemma identifies folds over arrays of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
theorem foldl_subtype {p : α Prop} {xs : Array { x // p x }}
theorem foldl_subtype {p : α Prop} {l : Array { x // p x }}
{f : β { x // p x } β} {g : β α β} {x : β}
(hf : b x h, f b x, h = g b x) :
xs.foldl f x = xs.unattach.foldl g x := by
cases xs
l.foldl f x = l.unattach.foldl g x := by
cases l
simp only [List.foldl_toArray', List.unattach_toArray]
rw [List.foldl_subtype] -- Why can't simp do this?
simp [hf]
/-- Variant of `foldl_subtype` with side condition to check `stop = l.size`. -/
@[simp] theorem foldl_subtype' {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem foldl_subtype' {p : α Prop} {l : Array { x // p x }}
{f : β { x // p x } β} {g : β α β} {x : β}
(hf : b x h, f b x, h = g b x) (h : stop = xs.size) :
xs.foldl f x 0 stop = xs.unattach.foldl g x := by
(hf : b x h, f b x, h = g b x) (h : stop = l.size) :
l.foldl f x 0 stop = l.unattach.foldl g x := by
subst h
rwa [foldl_subtype]
@@ -614,20 +611,20 @@ theorem foldl_subtype {p : α → Prop} {xs : Array { x // p x }}
This lemma identifies folds over arrays of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
theorem foldr_subtype {p : α Prop} {xs : Array { x // p x }}
theorem foldr_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } β β} {g : α β β} {x : β}
(hf : x h b, f x, h b = g x b) :
xs.foldr f x = xs.unattach.foldr g x := by
cases xs
l.foldr f x = l.unattach.foldr g x := by
cases l
simp only [List.foldr_toArray', List.unattach_toArray]
rw [List.foldr_subtype]
simp [hf]
/-- Variant of `foldr_subtype` with side condition to check `stop = l.size`. -/
@[simp] theorem foldr_subtype' {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem foldr_subtype' {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } β β} {g : α β β} {x : β}
(hf : x h b, f x, h b = g x b) (h : start = xs.size) :
xs.foldr f x start 0 = xs.unattach.foldr g x := by
(hf : x h b, f x, h b = g x b) (h : start = l.size) :
l.foldr f x start 0 = l.unattach.foldr g x := by
subst h
rwa [foldr_subtype]
@@ -635,70 +632,70 @@ theorem foldr_subtype {p : α → Prop} {xs : Array { x // p x }}
This lemma identifies maps over arrays of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
@[simp] theorem map_subtype {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem map_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } β} {g : α β} (hf : x h, f x, h = g x) :
xs.map f = xs.unattach.map g := by
cases xs
l.map f = l.unattach.map g := by
cases l
simp only [List.map_toArray, List.unattach_toArray]
rw [List.map_subtype]
simp [hf]
@[simp] theorem filterMap_subtype {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem filterMap_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Option β} {g : α Option β} (hf : x h, f x, h = g x) :
xs.filterMap f = xs.unattach.filterMap g := by
cases xs
l.filterMap f = l.unattach.filterMap g := by
cases l
simp only [List.size_toArray, List.filterMap_toArray', List.unattach_toArray, List.length_unattach,
mk.injEq]
rw [List.filterMap_subtype]
simp [hf]
@[simp] theorem flatMap_subtype {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem flatMap_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Array β} {g : α Array β} (hf : x h, f x, h = g x) :
(xs.flatMap f) = xs.unattach.flatMap g := by
cases xs
(l.flatMap f) = l.unattach.flatMap g := by
cases l
simp only [List.size_toArray, List.flatMap_toArray, List.unattach_toArray, List.length_unattach,
mk.injEq]
rw [List.flatMap_subtype]
simp [hf]
@[simp] theorem findSome?_subtype {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem findSome?_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Option β} {g : α Option β} (hf : x h, f x, h = g x) :
xs.findSome? f = xs.unattach.findSome? g := by
cases xs
l.findSome? f = l.unattach.findSome? g := by
cases l
simp
rw [List.findSome?_subtype hf]
@[simp] theorem find?_subtype {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem find?_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
(xs.find? f).map Subtype.val = xs.unattach.find? g := by
cases xs
(l.find? f).map Subtype.val = l.unattach.find? g := by
cases l
simp
rw [List.find?_subtype hf]
/-! ### Simp lemmas pushing `unattach` inwards. -/
@[simp] theorem unattach_filter {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem unattach_filter {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
(xs.filter f).unattach = xs.unattach.filter g := by
cases xs
(l.filter f).unattach = l.unattach.filter g := by
cases l
simp [hf]
@[simp] theorem unattach_reverse {p : α Prop} {xs : Array { x // p x }} :
xs.reverse.unattach = xs.unattach.reverse := by
cases xs
@[simp] theorem unattach_reverse {p : α Prop} {l : Array { x // p x }} :
l.reverse.unattach = l.unattach.reverse := by
cases l
simp
@[simp] theorem unattach_append {p : α Prop} {xs xs : Array { x // p x }} :
(xs ++ xs).unattach = xs.unattach ++ xs.unattach := by
cases xs
cases xs
@[simp] theorem unattach_append {p : α Prop} {l l : Array { x // p x }} :
(l ++ l).unattach = l.unattach ++ l.unattach := by
cases l
cases l
simp
@[simp] theorem unattach_flatten {p : α Prop} {xs : Array (Array { x // p x })} :
xs.flatten.unattach = (xs.map unattach).flatten := by
@[simp] theorem unattach_flatten {p : α Prop} {l : Array (Array { x // p x })} :
l.flatten.unattach = (l.map unattach).flatten := by
unfold unattach
cases xs using array₂_induction
cases l using array₂_induction
simp only [flatten_toArray, List.map_map, Function.comp_def, List.map_id_fun', id_eq,
List.map_toArray, List.map_flatten, map_subtype, map_id_fun', List.unattach_toArray, mk.injEq]
simp only [List.unattach]

View File

@@ -14,9 +14,6 @@ import Init.GetElem
import Init.Data.List.ToArrayImpl
import Init.Data.Array.Set
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
universe u v w
/-! ### Array literal syntax -/
@@ -38,28 +35,28 @@ namespace Array
/-! ### Preliminary theorems -/
@[simp] theorem size_set (xs : Array α) (i : Nat) (v : α) (h : i < xs.size) :
(set xs i v h).size = xs.size :=
@[simp] theorem size_set (a : Array α) (i : Nat) (v : α) (h : i < a.size) :
(set a i v h).size = a.size :=
List.length_set ..
@[simp] theorem size_push (xs : Array α) (v : α) : (push xs v).size = xs.size + 1 :=
@[simp] theorem size_push (a : Array α) (v : α) : (push a v).size = a.size + 1 :=
List.length_concat ..
theorem ext (xs ys : Array α)
(h₁ : xs.size = ys.size)
(h₂ : (i : Nat) (hi₁ : i < xs.size) (hi₂ : i < ys.size) xs[i] = ys[i])
: xs = ys := by
let rec extAux (as bs : List α)
(h₁ : as.length = bs.length)
(h₂ : (i : Nat) (hi₁ : i < as.length) (hi₂ : i < bs.length) as[i] = bs[i])
: as = bs := by
induction as generalizing bs with
theorem ext (a b : Array α)
(h₁ : a.size = b.size)
(h₂ : (i : Nat) (hi₁ : i < a.size) (hi₂ : i < b.size) a[i] = b[i])
: a = b := by
let rec extAux (a b : List α)
(h₁ : a.length = b.length)
(h₂ : (i : Nat) (hi₁ : i < a.length) (hi₂ : i < b.length) a[i] = b[i])
: a = b := by
induction a generalizing b with
| nil =>
cases bs with
cases b with
| nil => rfl
| cons b bs => rw [List.length_cons] at h₁; injection h₁
| cons a as ih =>
cases bs with
cases b with
| nil => rw [List.length_cons] at h₁; injection h₁
| cons b bs =>
have hz₁ : 0 < (a::as).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
@@ -74,23 +71,23 @@ theorem ext (xs ys : Array α)
apply this
have tailEq : as = bs := ih bs h₁' h₂'
rw [headEq, tailEq]
cases xs; cases ys
cases a; cases b
apply congrArg
apply extAux
assumption
assumption
theorem ext' {xs ys : Array α} (h : xs.toList = ys.toList) : xs = ys := by
cases xs; cases ys; simp at h; rw [h]
theorem ext' {as bs : Array α} (h : as.toList = bs.toList) : as = bs := by
cases as; cases bs; simp at h; rw [h]
@[simp] theorem toArrayAux_eq (as : List α) (acc : Array α) : (as.toArrayAux acc).toList = acc.toList ++ as := by
induction as generalizing acc <;> simp [*, List.toArrayAux, Array.push, List.append_assoc, List.concat_eq_append]
@[simp] theorem toArray_toList (xs : Array α) : xs.toList.toArray = xs := rfl
@[simp] theorem toArray_toList (a : Array α) : a.toList.toArray = a := rfl
@[simp] theorem getElem_toList {xs : Array α} {i : Nat} (h : i < xs.size) : xs.toList[i] = xs[i] := rfl
@[simp] theorem getElem_toList {a : Array α} {i : Nat} (h : i < a.size) : a.toList[i] = a[i] := rfl
@[simp] theorem getElem?_toList {xs : Array α} {i : Nat} : xs.toList[i]? = xs[i]? := by
@[simp] theorem getElem?_toList {a : Array α} {i : Nat} : a.toList[i]? = a[i]? := by
simp [getElem?_def]
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
@@ -108,7 +105,7 @@ theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
@[simp] theorem mem_toArray {a : α} {l : List α} : a l.toArray a l := by
simp [mem_def]
@[simp] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] xs := by
@[simp] theorem getElem_mem {l : Array α} {i : Nat} (h : i < l.size) : l[i] l := by
rw [Array.mem_def, getElem_toList]
apply List.getElem_mem
@@ -130,14 +127,14 @@ abbrev _root_.Array.toList_toArray := @List.toList_toArray
@[deprecated size_toArray (since := "2025-02-17")]
abbrev _root_.Array.size_toArray := @List.size_toArray
@[simp] theorem getElem_toArray {xs : List α} {i : Nat} (h : i < xs.toArray.size) :
xs.toArray[i] = xs[i]'(by simpa using h) := rfl
@[simp] theorem getElem_toArray {a : List α} {i : Nat} (h : i < a.toArray.size) :
a.toArray[i] = a[i]'(by simpa using h) := rfl
@[simp] theorem getElem?_toArray {xs : List α} {i : Nat} : xs.toArray[i]? = xs[i]? := by
@[simp] theorem getElem?_toArray {a : List α} {i : Nat} : a.toArray[i]? = a[i]? := by
simp [getElem?_def]
@[simp] theorem getElem!_toArray [Inhabited α] {xs : List α} {i : Nat} :
xs.toArray[i]! = xs[i]! := by
@[simp] theorem getElem!_toArray [Inhabited α] {a : List α} {i : Nat} :
a.toArray[i]! = a[i]! := by
simp [getElem!_def]
end List
@@ -168,15 +165,15 @@ def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
`Fin` values are represented as tag pointers in the Lean runtime. Thus,
`fset` may be slightly slower than `uset`. -/
@[extern "lean_array_uset"]
def uset (xs : Array α) (i : USize) (v : α) (h : i.toNat < xs.size) : Array α :=
xs.set i.toNat v h
def uset (a : Array α) (i : USize) (v : α) (h : i.toNat < a.size) : Array α :=
a.set i.toNat v h
@[extern "lean_array_pop"]
def pop (xs : Array α) : Array α where
toList := xs.toList.dropLast
def pop (a : Array α) : Array α where
toList := a.toList.dropLast
@[simp] theorem size_pop (xs : Array α) : xs.pop.size = xs.size - 1 := by
match xs with
@[simp] theorem size_pop (a : Array α) : a.pop.size = a.size - 1 := by
match a with
| [] => rfl
| a::as => simp [pop, Nat.succ_sub_succ_eq_sub, size]
@@ -191,15 +188,15 @@ This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[extern "lean_array_fswap"]
def swap (xs : Array α) (i j : @& Nat) (hi : i < xs.size := by get_elem_tactic) (hj : j < xs.size := by get_elem_tactic) : Array α :=
let v₁ := xs[i]
let v₂ := xs[j]
let xs' := xs.set i v₂
xs'.set j v₁ (Nat.lt_of_lt_of_eq hj (size_set xs i v₂ _).symm)
def swap (a : Array α) (i j : @& Nat) (hi : i < a.size := by get_elem_tactic) (hj : j < a.size := by get_elem_tactic) : Array α :=
let v₁ := a[i]
let v₂ := a[j]
let a' := a.set i v₂
a'.set j v₁ (Nat.lt_of_lt_of_eq hj (size_set a i v₂ _).symm)
@[simp] theorem size_swap (xs : Array α) (i j : Nat) {hi hj} : (xs.swap i j hi hj).size = xs.size := by
show ((xs.set i xs[j]).set j xs[i]
(Nat.lt_of_lt_of_eq hj (size_set xs i xs[j] _).symm)).size = xs.size
@[simp] theorem size_swap (a : Array α) (i j : Nat) {hi hj} : (a.swap i j hi hj).size = a.size := by
show ((a.set i a[j]).set j a[i]
(Nat.lt_of_lt_of_eq hj (size_set a i a[j] _).symm)).size = a.size
rw [size_set, size_set]
/--
@@ -209,11 +206,11 @@ This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[extern "lean_array_swap"]
def swapIfInBounds (xs : Array α) (i j : @& Nat) : Array α :=
if h₁ : i < xs.size then
if h₂ : j < xs.size then swap xs i j
else xs
else xs
def swapIfInBounds (a : Array α) (i j : @& Nat) : Array α :=
if h₁ : i < a.size then
if h₂ : j < a.size then swap a i j
else a
else a
@[deprecated swapIfInBounds (since := "2024-11-24")] abbrev swap! := @swapIfInBounds
@@ -228,24 +225,24 @@ instance : EmptyCollection (Array α) := ⟨Array.empty⟩
instance : Inhabited (Array α) where
default := Array.empty
def isEmpty (xs : Array α) : Bool :=
xs.size = 0
def isEmpty (a : Array α) : Bool :=
a.size = 0
@[specialize]
def isEqvAux (xs ys : Array α) (hsz : xs.size = ys.size) (p : α α Bool) :
(i : Nat) (_ : i xs.size), Bool
def isEqvAux (a b : Array α) (hsz : a.size = b.size) (p : α α Bool) :
(i : Nat) (_ : i a.size), Bool
| 0, _ => true
| i+1, h =>
p xs[i] (ys[i]'(hsz h)) && isEqvAux xs ys hsz p i (Nat.le_trans (Nat.le_add_right i 1) h)
p a[i] (b[i]'(hsz h)) && isEqvAux a b hsz p i (Nat.le_trans (Nat.le_add_right i 1) h)
@[inline] def isEqv (xs ys : Array α) (p : α α Bool) : Bool :=
if h : xs.size = ys.size then
isEqvAux xs ys h p xs.size (Nat.le_refl xs.size)
@[inline] def isEqv (a b : Array α) (p : α α Bool) : Bool :=
if h : a.size = b.size then
isEqvAux a b h p a.size (Nat.le_refl a.size)
else
false
instance [BEq α] : BEq (Array α) :=
fun xs ys => isEqv xs ys BEq.beq
fun a b => isEqv a b BEq.beq
/--
`ofFn f` with `f : Fin n → α` returns the list whose ith element is `f i`.
@@ -275,8 +272,8 @@ Return the last element of an array, or panic if the array is empty.
See `back` for the version that requires a proof the array is non-empty,
or `back?` for the version that returns an option.
-/
def back! [Inhabited α] (xs : Array α) : α :=
xs[xs.size - 1]!
def back! [Inhabited α] (a : Array α) : α :=
a[a.size - 1]!
/--
Return the last element of an array, given a proof that the array is not empty.
@@ -284,8 +281,8 @@ Return the last element of an array, given a proof that the array is not empty.
See `back!` for the version that panics if the array is empty,
or `back?` for the version that returns an option.
-/
def back (xs : Array α) (h : 0 < xs.size := by get_elem_tactic) : α :=
xs[xs.size - 1]'(Nat.sub_one_lt_of_lt h)
def back (a : Array α) (h : 0 < a.size := by get_elem_tactic) : α :=
a[a.size - 1]'(Nat.sub_one_lt_of_lt h)
/--
Return the last element of an array, or `none` if the array is empty.
@@ -293,73 +290,72 @@ Return the last element of an array, or `none` if the array is empty.
See `back!` for the version that panics if the array is empty,
or `back` for the version that requires a proof the array is non-empty.
-/
def back? (xs : Array α) : Option α :=
xs[xs.size - 1]?
def back? (a : Array α) : Option α :=
a[a.size - 1]?
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12")]
def get? (xs : Array α) (i : Nat) : Option α :=
if h : i < xs.size then some xs[i] else none
def get? (a : Array α) (i : Nat) : Option α :=
if h : i < a.size then some a[i] else none
@[inline] def swapAt (xs : Array α) (i : Nat) (v : α) (hi : i < xs.size := by get_elem_tactic) : α × Array α :=
let e := xs[i]
let xs' := xs.set i v
(e, xs')
@[inline] def swapAt (a : Array α) (i : Nat) (v : α) (hi : i < a.size := by get_elem_tactic) : α × Array α :=
let e := a[i]
let a := a.set i v
(e, a)
@[inline]
def swapAt! (xs : Array α) (i : Nat) (v : α) : α × Array α :=
if h : i < xs.size then
swapAt xs i v
def swapAt! (a : Array α) (i : Nat) (v : α) : α × Array α :=
if h : i < a.size then
swapAt a i v
else
have : Inhabited (α × Array α) := (v, xs)
have : Inhabited (α × Array α) := (v, a)
panic! ("index " ++ toString i ++ " out of bounds")
/-- `shrink a n` returns the first `n` elements of `a`, implemented by repeatedly popping the last element. -/
def shrink (xs : Array α) (n : Nat) : Array α :=
def shrink (a : Array α) (n : Nat) : Array α :=
let rec loop
| 0, xs => xs
| n+1, xs => loop n xs.pop
loop (xs.size - n) xs
| 0, a => a
| n+1, a => loop n a.pop
loop (a.size - n) a
/-- `take a n` returns the first `n` elements of `a`, implemented by copying the first `n` elements. -/
abbrev take (xs : Array α) (i : Nat) : Array α := extract xs 0 i
abbrev take (a : Array α) (n : Nat) : Array α := extract a 0 n
@[simp] theorem take_eq_extract (xs : Array α) (i : Nat) : xs.take i = xs.extract 0 i := rfl
@[simp] theorem take_eq_extract (a : Array α) (n : Nat) : a.take n = a.extract 0 n := rfl
/-- `drop a n` removes the first `n` elements of `a`, implemented by copying the remaining elements. -/
abbrev drop (xs : Array α) (i : Nat) : Array α := extract xs i xs.size
abbrev drop (a : Array α) (n : Nat) : Array α := extract a n a.size
@[simp] theorem drop_eq_extract (xs : Array α) (i : Nat) : xs.drop i = xs.extract i xs.size := rfl
@[simp] theorem drop_eq_extract (a : Array α) (n : Nat) : a.drop n = a.extract n a.size := rfl
@[inline]
unsafe def modifyMUnsafe [Monad m] (xs : Array α) (i : Nat) (f : α m α) : m (Array α) := do
if h : i < xs.size then
let v := xs[i]
unsafe def modifyMUnsafe [Monad m] (a : Array α) (i : Nat) (f : α m α) : m (Array α) := do
if h : i < a.size then
let v := a[i]
-- Replace a[i] by `box(0)`. This ensures that `v` remains unshared if possible.
-- Note: we assume that arrays have a uniform representation irrespective
-- of the element type, and that it is valid to store `box(0)` in any array.
let xs' := xs.set i (unsafeCast ())
let a' := a.set i (unsafeCast ())
let v f v
pure <| xs'.set i v (Nat.lt_of_lt_of_eq h (size_set xs ..).symm)
pure <| a'.set i v (Nat.lt_of_lt_of_eq h (size_set a ..).symm)
else
pure xs
pure a
@[implemented_by modifyMUnsafe]
def modifyM [Monad m] (xs : Array α) (i : Nat) (f : α m α) : m (Array α) := do
if h : i < xs.size then
let v := xs[i]
def modifyM [Monad m] (a : Array α) (i : Nat) (f : α m α) : m (Array α) := do
if h : i < a.size then
let v := a[i]
let v f v
pure <| xs.set i v
pure <| a.set i v
else
pure xs
pure a
@[inline]
def modify (xs : Array α) (i : Nat) (f : α α) : Array α :=
Id.run <| modifyM xs i f
def modify (a : Array α) (i : Nat) (f : α α) : Array α :=
Id.run <| modifyM a i f
set_option linter.indexVariables false in -- Changing `idx` causes bootstrapping issues, haven't investigated.
@[inline]
def modifyOp (xs : Array α) (idx : Nat) (f : α α) : Array α :=
xs.modify idx f
def modifyOp (self : Array α) (idx : Nat) (f : α α) : Array α :=
self.modify idx f
/--
We claim this unsafe implementation is correct because an array cannot have more than `usizeSz` elements in our runtime.
@@ -478,17 +474,17 @@ def foldrM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
@[inline]
unsafe def mapMUnsafe {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m β) (as : Array α) : m (Array β) :=
let sz := as.usize
let rec @[specialize] map (i : USize) (bs : Array NonScalar) : m (Array PNonScalar.{v}) := do
let rec @[specialize] map (i : USize) (r : Array NonScalar) : m (Array PNonScalar.{v}) := do
if i < sz then
let v := bs.uget i lcProof
-- Replace bs[i] by `box(0)`. This ensures that `v` remains unshared if possible.
let v := r.uget i lcProof
-- Replace r[i] by `box(0)`. This ensures that `v` remains unshared if possible.
-- Note: we assume that arrays have a uniform representation irrespective
-- of the element type, and that it is valid to store `box(0)` in any array.
let bs' := bs.uset i default lcProof
let r := r.uset i default lcProof
let vNew f (unsafeCast v)
map (i+1) (bs'.uset i (unsafeCast vNew) lcProof)
map (i+1) (r.uset i (unsafeCast vNew) lcProof)
else
pure (unsafeCast bs)
pure (unsafeCast r)
unsafeCast <| map 0 (unsafeCast as)
/-- Reference implementation for `mapM` -/
@@ -497,11 +493,11 @@ def mapM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
-- Note: we cannot use `foldlM` here for the reference implementation because this calls
-- `bind` and `pure` too many times. (We are not assuming `m` is a `LawfulMonad`)
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
map (i : Nat) (bs : Array β) : m (Array β) := do
map (i : Nat) (r : Array β) : m (Array β) := do
if hlt : i < as.size then
map (i+1) (bs.push ( f as[i]))
map (i+1) (r.push ( f as[i]))
else
pure bs
pure r
decreasing_by simp_wf; decreasing_trivial_pre_omega
map 0 (mkEmpty as.size)
@@ -682,8 +678,8 @@ def mapIdx {α : Type u} {β : Type v} (f : Nat → α → β) (as : Array α) :
Id.run <| as.mapIdxM f
/-- Turns `#[a, b]` into `#[(a, 0), (b, 1)]`. -/
def zipIdx (xs : Array α) (start := 0) : Array (α × Nat) :=
xs.mapIdx fun i a => (a, start + i)
def zipIdx (arr : Array α) (start := 0) : Array (α × Nat) :=
arr.mapIdx fun i a => (a, start + i)
@[deprecated zipIdx (since := "2025-01-21")] abbrev zipWithIndex := @zipIdx
@@ -700,8 +696,8 @@ def findSome? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α)
Id.run <| as.findSomeM? f
@[inline]
def findSome! {α : Type u} {β : Type v} [Inhabited β] (f : α Option β) (xs : Array α) : β :=
match xs.findSome? f with
def findSome! {α : Type u} {β : Type v} [Inhabited β] (f : α Option β) (a : Array α) : β :=
match a.findSome? f with
| some b => b
| none => panic! "failed to find element"
@@ -755,18 +751,18 @@ theorem findIdx?_eq_map_findFinIdx?_val {xs : Array α} {p : α → Bool} :
def findIdx (p : α Bool) (as : Array α) : Nat := (as.findIdx? p).getD as.size
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def idxOfAux [BEq α] (xs : Array α) (v : α) (i : Nat) : Option (Fin xs.size) :=
if h : i < xs.size then
if xs[i] == v then some i, h
else idxOfAux xs v (i+1)
def idxOfAux [BEq α] (a : Array α) (v : α) (i : Nat) : Option (Fin a.size) :=
if h : i < a.size then
if a[i] == v then some i, h
else idxOfAux a v (i+1)
else none
decreasing_by simp_wf; decreasing_trivial_pre_omega
@[deprecated idxOfAux (since := "2025-01-29")]
abbrev indexOfAux := @idxOfAux
def finIdxOf? [BEq α] (xs : Array α) (v : α) : Option (Fin xs.size) :=
idxOfAux xs v 0
def finIdxOf? [BEq α] (a : Array α) (v : α) : Option (Fin a.size) :=
idxOfAux a v 0
@[deprecated "`Array.indexOf?` has been deprecated, use `idxOf?` or `finIdxOf?` instead." (since := "2025-01-29")]
abbrev indexOf? := @finIdxOf?
@@ -774,12 +770,12 @@ abbrev indexOf? := @finIdxOf?
/-- Returns the index of the first element equal to `a`, or the length of the array otherwise. -/
def idxOf [BEq α] (a : α) : Array α Nat := findIdx (· == a)
def idxOf? [BEq α] (xs : Array α) (v : α) : Option Nat :=
(xs.finIdxOf? v).map (·.val)
def idxOf? [BEq α] (a : Array α) (v : α) : Option Nat :=
(a.finIdxOf? v).map (·.val)
@[deprecated idxOf? (since := "2024-11-20")]
def getIdx? [BEq α] (xs : Array α) (v : α) : Option Nat :=
xs.findIdx? fun a => a == v
def getIdx? [BEq α] (a : Array α) (v : α) : Option Nat :=
a.findIdx? fun a => a == v
@[inline]
def any (as : Array α) (p : α Bool) (start := 0) (stop := as.size) : Bool :=
@@ -814,12 +810,12 @@ def toListAppend (as : Array α) (l : List α) : List α :=
as.foldr List.cons l
protected def append (as : Array α) (bs : Array α) : Array α :=
bs.foldl (init := as) fun xs v => xs.push v
bs.foldl (init := as) fun r v => r.push v
instance : Append (Array α) := Array.append
protected def appendList (as : Array α) (bs : List α) : Array α :=
bs.foldl (init := as) fun xs v => xs.push v
bs.foldl (init := as) fun r v => r.push v
instance : HAppend (Array α) (List α) (Array α) := Array.appendList
@@ -839,8 +835,8 @@ def flatMap (f : α → Array β) (as : Array α) : Array β :=
`flatten #[#[a₁, a₂, ⋯], #[b₁, b₂, ⋯], ⋯]` = `#[a₁, a₂, ⋯, b₁, b₂, ⋯]`
-/
@[inline] def flatten (xss : Array (Array α)) : Array α :=
xss.foldl (init := empty) fun acc xs => acc ++ xs
@[inline] def flatten (as : Array (Array α)) : Array α :=
as.foldl (init := empty) fun r a => r ++ a
def reverse (as : Array α) : Array α :=
if h : as.size 1 then
@@ -862,18 +858,18 @@ where
@[inline]
def filter (p : α Bool) (as : Array α) (start := 0) (stop := as.size) : Array α :=
as.foldl (init := #[]) (start := start) (stop := stop) fun acc a =>
if p a then acc.push a else acc
as.foldl (init := #[]) (start := start) (stop := stop) fun r a =>
if p a then r.push a else r
@[inline]
def filterM {α : Type} [Monad m] (p : α m Bool) (as : Array α) (start := 0) (stop := as.size) : m (Array α) :=
as.foldlM (init := #[]) (start := start) (stop := stop) fun acc a => do
if ( p a) then return acc.push a else return acc
as.foldlM (init := #[]) (start := start) (stop := stop) fun r a => do
if ( p a) then return r.push a else return r
@[inline]
def filterRevM {α : Type} [Monad m] (p : α m Bool) (as : Array α) (start := as.size) (stop := 0) : m (Array α) :=
reverse <$> as.foldrM (init := #[]) (start := start) (stop := stop) fun a acc => do
if ( p a) then return acc.push a else return acc
reverse <$> as.foldrM (init := #[]) (start := start) (stop := stop) fun a r => do
if ( p a) then return r.push a else return r
@[specialize]
def filterMapM [Monad m] (f : α m (Option β)) (as : Array α) (start := 0) (stop := as.size) : m (Array β) :=
@@ -923,15 +919,15 @@ decreasing_by simp_wf; decreasing_trivial_pre_omega
def takeWhile (p : α Bool) (as : Array α) : Array α :=
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
go (i : Nat) (acc : Array α) : Array α :=
go (i : Nat) (r : Array α) : Array α :=
if h : i < as.size then
let a := as[i]
if p a then
go (i+1) (acc.push a)
go (i+1) (r.push a)
else
acc
r
else
acc
r
decreasing_by simp_wf; decreasing_trivial_pre_omega
go 0 #[]
@@ -942,22 +938,22 @@ using a `Nat` index and a tactic-provided bound.
This function takes worst case O(n) time because
it has to backshift all elements at positions greater than `i`.-/
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def eraseIdx (xs : Array α) (i : Nat) (h : i < xs.size := by get_elem_tactic) : Array α :=
if h' : i + 1 < xs.size then
let xs' := xs.swap (i + 1) i
xs'.eraseIdx (i + 1) (by simp [xs', h'])
def eraseIdx (a : Array α) (i : Nat) (h : i < a.size := by get_elem_tactic) : Array α :=
if h' : i + 1 < a.size then
let a' := a.swap (i + 1) i
a'.eraseIdx (i + 1) (by simp [a', h'])
else
xs.pop
termination_by xs.size - i
a.pop
termination_by a.size - i
decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
-- This is required in `Lean.Data.PersistentHashMap`.
@[simp] theorem size_eraseIdx (xs : Array α) (i : Nat) (h) : (xs.eraseIdx i h).size = xs.size - 1 := by
induction xs, i, h using Array.eraseIdx.induct with
| @case1 xs i h h' xs' ih =>
@[simp] theorem size_eraseIdx (a : Array α) (i : Nat) (h) : (a.eraseIdx i h).size = a.size - 1 := by
induction a, i, h using Array.eraseIdx.induct with
| @case1 a i h h' a' ih =>
unfold eraseIdx
simp +zetaDelta [h', xs', ih]
| case2 xs i h h' =>
simp +zetaDelta [h', a', ih]
| case2 a i h h' =>
unfold eraseIdx
simp [h']
@@ -965,15 +961,15 @@ decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
This function takes worst case O(n) time because
it has to backshift all elements at positions greater than `i`.-/
def eraseIdxIfInBounds (xs : Array α) (i : Nat) : Array α :=
if h : i < xs.size then xs.eraseIdx i h else xs
def eraseIdxIfInBounds (a : Array α) (i : Nat) : Array α :=
if h : i < a.size then a.eraseIdx i h else a
/-- Remove the element at a given index from an array, or panic if the index is out of bounds.
This function takes worst case O(n) time because
it has to backshift all elements at positions greater than `i`. -/
def eraseIdx! (xs : Array α) (i : Nat) : Array α :=
if h : i < xs.size then xs.eraseIdx i h else panic! "invalid index"
def eraseIdx! (a : Array α) (i : Nat) : Array α :=
if h : i < a.size then a.eraseIdx i h else panic! "invalid index"
/-- Remove a specified element from an array, or do nothing if it is not present.
@@ -1090,11 +1086,6 @@ def split (as : Array α) (p : α → Bool) : Array α × Array α :=
as.foldl (init := (#[], #[])) fun (as, bs) a =>
if p a then (as.push a, bs) else (as, bs.push a)
def replace [BEq α] (xs : Array α) (a b : α) : Array α :=
match xs.finIdxOf? a with
| none => xs
| some i => xs.set i b
/-! ### Lexicographic ordering -/
instance instLT [LT α] : LT (Array α) := fun as bs => as.toList < bs.toList
@@ -1107,20 +1098,6 @@ instance instLE [LT α] : LE (Array α) := ⟨fun as bs => as.toList ≤ bs.toLi
We do not currently intend to provide verification theorems for these functions.
-/
/-! ### leftpad and rightpad -/
/--
Pads `l : Array α` on the left with repeated occurrences of `a : α` until it is of size `n`.
If `l` is initially larger than `n`, just return `l`.
-/
def leftpad (n : Nat) (a : α) (xs : Array α) : Array α := mkArray (n - xs.size) a ++ xs
/--
Pads `l : Array α` on the right with repeated occurrences of `a : α` until it is of size `n`.
If `l` is initially larger than `n`, just return `l`.
-/
def rightpad (n : Nat) (a : α) (xs : Array α) : Array α := xs ++ mkArray (n - xs.size) a
/- ### reduceOption -/
/-- Drop `none`s from a Array, and replace each remaining `some a` with `a`. -/
@@ -1135,9 +1112,9 @@ def rightpad (n : Nat) (a : α) (xs : Array α) : Array α := xs ++ mkArray (n -
-/
def eraseReps {α} [BEq α] (as : Array α) : Array α :=
if h : 0 < as.size then
let last, acc := as.foldl (init := (as[0], #[])) fun last, acc a =>
if a == last then last, acc else a, acc.push last
acc.push last
let last, r := as.foldl (init := (as[0], #[])) fun last, r a =>
if a == last then last, r else a, r.push last
r.push last
else
#[]
@@ -1163,24 +1140,24 @@ def allDiff [BEq α] (as : Array α) : Bool :=
/-! ### getEvenElems -/
@[inline] def getEvenElems (as : Array α) : Array α :=
(·.2) <| as.foldl (init := (true, Array.empty)) fun (even, acc) a =>
(·.2) <| as.foldl (init := (true, Array.empty)) fun (even, r) a =>
if even then
(false, acc.push a)
(false, r.push a)
else
(true, acc)
(true, r)
/-! ### Repr and ToString -/
instance {α : Type u} [Repr α] : Repr (Array α) where
reprPrec xs _ :=
reprPrec a _ :=
let _ : Std.ToFormat α := repr
if xs.size == 0 then
if a.size == 0 then
"#[]"
else
Std.Format.bracketFill "#[" (Std.Format.joinSep (toList xs) ("," ++ Std.Format.line)) "]"
Std.Format.bracketFill "#[" (Std.Format.joinSep (toList a) ("," ++ Std.Format.line)) "]"
instance [ToString α] : ToString (Array α) where
toString xs := "#" ++ toString xs.toList
toString a := "#" ++ toString a.toList
end Array

View File

@@ -8,9 +8,6 @@ import Init.Data.Array.Basic
import Init.Data.Nat.Linear
import Init.NotationExtra
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
theorem Array.of_push_eq_push {as bs : Array α} (h : as.push a = bs.push b) : as = bs a = b := by
simp only [push, mk.injEq] at h
have h₁, h₂ := List.of_concat_eq_concat h

View File

@@ -5,13 +5,9 @@ Authors: Leonardo de Moura
-/
prelude
import Init.Data.Array.Basic
import Init.Data.Int.DivMod.Lemmas
import Init.Omega
universe u v
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- We do not use `linter.indexVariables` here as it is helpful to name the index variables as `lo`, `mid`, and `hi`.
namespace Array
@[specialize] def binSearchAux {α : Type u} {β : Type v} (lt : α α Bool) (found : Option α β) (as : Array α) (k : α) :

View File

@@ -13,9 +13,6 @@ import Init.Data.List.TakeDrop
This file contains some theorems about `Array` and `List` needed for `Init.Data.List.Impl`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/--
@@ -42,122 +39,122 @@ def get! {α : Type u} [Inhabited α] (a : @& Array α) (i : @& Nat) : α :=
Array.getD a i default
theorem foldlM_toList.aux [Monad m]
(f : β α m β) (xs : Array α) (i j) (H : xs.size i + j) (b) :
foldlM.loop f xs xs.size (Nat.le_refl _) i j b = (xs.toList.drop j).foldlM f b := by
(f : β α m β) (arr : Array α) (i j) (H : arr.size i + j) (b) :
foldlM.loop f arr arr.size (Nat.le_refl _) i j b = (arr.toList.drop j).foldlM f b := by
unfold foldlM.loop
split; split
· cases Nat.not_le_of_gt _ (Nat.zero_add _ H)
· rename_i i; rw [Nat.succ_add] at H
simp [foldlM_toList.aux f xs i (j+1) H]
simp [foldlM_toList.aux f arr i (j+1) H]
rw (occs := [2]) [ List.getElem_cons_drop_succ_eq_drop _]
rfl
· rw [List.drop_of_length_le (Nat.ge_of_not_lt _)]; rfl
@[simp] theorem foldlM_toList [Monad m]
(f : β α m β) (init : β) (xs : Array α) :
xs.toList.foldlM f init = xs.foldlM f init := by
(f : β α m β) (init : β) (arr : Array α) :
arr.toList.foldlM f init = arr.foldlM f init := by
simp [foldlM, foldlM_toList.aux]
@[simp] theorem foldl_toList (f : β α β) (init : β) (xs : Array α) :
xs.toList.foldl f init = xs.foldl f init :=
@[simp] theorem foldl_toList (f : β α β) (init : β) (arr : Array α) :
arr.toList.foldl f init = arr.foldl f init :=
List.foldl_eq_foldlM .. foldlM_toList ..
theorem foldrM_eq_reverse_foldlM_toList.aux [Monad m]
(f : α β m β) (xs : Array α) (init : β) (i h) :
(xs.toList.take i).reverse.foldlM (fun x y => f y x) init = foldrM.fold f xs 0 i h init := by
(f : α β m β) (arr : Array α) (init : β) (i h) :
(arr.toList.take i).reverse.foldlM (fun x y => f y x) init = foldrM.fold f arr 0 i h init := by
unfold foldrM.fold
match i with
| 0 => simp [List.foldlM, List.take]
| i+1 => rw [ List.take_concat_get _ _ h]; simp [ (aux f xs · i)]
| i+1 => rw [ List.take_concat_get _ _ h]; simp [ (aux f arr · i)]
theorem foldrM_eq_reverse_foldlM_toList [Monad m] (f : α β m β) (init : β) (xs : Array α) :
xs.foldrM f init = xs.toList.reverse.foldlM (fun x y => f y x) init := by
have : xs = #[] 0 < xs.size :=
match xs with | [] => .inl rfl | a::l => .inr (Nat.zero_lt_succ _)
match xs, this with | _, .inl rfl => rfl | xs, .inr h => ?_
theorem foldrM_eq_reverse_foldlM_toList [Monad m] (f : α β m β) (init : β) (arr : Array α) :
arr.foldrM f init = arr.toList.reverse.foldlM (fun x y => f y x) init := by
have : arr = #[] 0 < arr.size :=
match arr with | [] => .inl rfl | a::l => .inr (Nat.zero_lt_succ _)
match arr, this with | _, .inl rfl => rfl | arr, .inr h => ?_
simp [foldrM, h, foldrM_eq_reverse_foldlM_toList.aux, List.take_length]
@[simp] theorem foldrM_toList [Monad m]
(f : α β m β) (init : β) (xs : Array α) :
xs.toList.foldrM f init = xs.foldrM f init := by
(f : α β m β) (init : β) (arr : Array α) :
arr.toList.foldrM f init = arr.foldrM f init := by
rw [foldrM_eq_reverse_foldlM_toList, List.foldlM_reverse]
@[simp] theorem foldr_toList (f : α β β) (init : β) (xs : Array α) :
xs.toList.foldr f init = xs.foldr f init :=
@[simp] theorem foldr_toList (f : α β β) (init : β) (arr : Array α) :
arr.toList.foldr f init = arr.foldr f init :=
List.foldr_eq_foldrM .. foldrM_toList ..
@[simp] theorem push_toList (xs : Array α) (a : α) : (xs.push a).toList = xs.toList ++ [a] := by
@[simp] theorem push_toList (arr : Array α) (a : α) : (arr.push a).toList = arr.toList ++ [a] := by
simp [push, List.concat_eq_append]
@[simp] theorem toListAppend_eq (xs : Array α) (l : List α) : xs.toListAppend l = xs.toList ++ l := by
@[simp] theorem toListAppend_eq (arr : Array α) (l) : arr.toListAppend l = arr.toList ++ l := by
simp [toListAppend, foldr_toList]
@[simp] theorem toListImpl_eq (xs : Array α) : xs.toListImpl = xs.toList := by
@[simp] theorem toListImpl_eq (arr : Array α) : arr.toListImpl = arr.toList := by
simp [toListImpl, foldr_toList]
@[simp] theorem toList_pop (xs : Array α) : xs.pop.toList = xs.toList.dropLast := rfl
@[simp] theorem toList_pop (a : Array α) : a.pop.toList = a.toList.dropLast := rfl
@[deprecated toList_pop (since := "2025-02-17")]
abbrev pop_toList := @Array.toList_pop
@[simp] theorem append_eq_append (xs ys : Array α) : xs.append ys = xs ++ ys := rfl
@[simp] theorem append_eq_append (arr arr' : Array α) : arr.append arr' = arr ++ arr' := rfl
@[simp] theorem toList_append (xs ys : Array α) :
(xs ++ ys).toList = xs.toList ++ ys.toList := by
@[simp] theorem toList_append (arr arr' : Array α) :
(arr ++ arr').toList = arr.toList ++ arr'.toList := by
rw [ append_eq_append]; unfold Array.append
rw [ foldl_toList]
induction ys.toList generalizing xs <;> simp [*]
induction arr'.toList generalizing arr <;> simp [*]
@[simp] theorem toList_empty : (#[] : Array α).toList = [] := rfl
@[simp] theorem append_empty (xs : Array α) : xs ++ #[] = xs := by
@[simp] theorem append_empty (as : Array α) : as ++ #[] = as := by
apply ext'; simp only [toList_append, toList_empty, List.append_nil]
@[deprecated append_empty (since := "2025-01-13")]
abbrev append_nil := @append_empty
@[simp] theorem empty_append (xs : Array α) : #[] ++ xs = xs := by
@[simp] theorem empty_append (as : Array α) : #[] ++ as = as := by
apply ext'; simp only [toList_append, toList_empty, List.nil_append]
@[deprecated empty_append (since := "2025-01-13")]
abbrev nil_append := @empty_append
@[simp] theorem append_assoc (xs ys zs : Array α) : xs ++ ys ++ zs = xs ++ (ys ++ zs) := by
@[simp] theorem append_assoc (as bs cs : Array α) : as ++ bs ++ cs = as ++ (bs ++ cs) := by
apply ext'; simp only [toList_append, List.append_assoc]
@[simp] theorem appendList_eq_append
(xs : Array α) (l : List α) : xs.appendList l = xs ++ l := rfl
(arr : Array α) (l : List α) : arr.appendList l = arr ++ l := rfl
@[simp] theorem toList_appendList (xs : Array α) (l : List α) :
(xs ++ l).toList = xs.toList ++ l := by
@[simp] theorem toList_appendList (arr : Array α) (l : List α) :
(arr ++ l).toList = arr.toList ++ l := by
rw [ appendList_eq_append]; unfold Array.appendList
induction l generalizing xs <;> simp [*]
induction l generalizing arr <;> simp [*]
@[deprecated toList_appendList (since := "2024-12-11")]
abbrev appendList_toList := @toList_appendList
@[deprecated "Use the reverse direction of `foldrM_toList`." (since := "2024-11-13")]
theorem foldrM_eq_foldrM_toList [Monad m]
(f : α β m β) (init : β) (xs : Array α) :
xs.foldrM f init = xs.toList.foldrM f init := by
(f : α β m β) (init : β) (arr : Array α) :
arr.foldrM f init = arr.toList.foldrM f init := by
simp
@[deprecated "Use the reverse direction of `foldlM_toList`." (since := "2024-11-13")]
theorem foldlM_eq_foldlM_toList [Monad m]
(f : β α m β) (init : β) (xs : Array α) :
xs.foldlM f init = xs.toList.foldlM f init:= by
(f : β α m β) (init : β) (arr : Array α) :
arr.foldlM f init = arr.toList.foldlM f init:= by
simp
@[deprecated "Use the reverse direction of `foldr_toList`." (since := "2024-11-13")]
theorem foldr_eq_foldr_toList
(f : α β β) (init : β) (xs : Array α) :
xs.foldr f init = xs.toList.foldr f init := by
(f : α β β) (init : β) (arr : Array α) :
arr.foldr f init = arr.toList.foldr f init := by
simp
@[deprecated "Use the reverse direction of `foldl_toList`." (since := "2024-11-13")]
theorem foldl_eq_foldl_toList
(f : β α β) (init : β) (xs : Array α) :
xs.foldl f init = xs.toList.foldl f init:= by
(f : β α β) (init : β) (arr : Array α) :
arr.foldl f init = arr.toList.foldl f init:= by
simp
@[deprecated foldlM_toList (since := "2024-09-09")]

View File

@@ -11,9 +11,6 @@ import Init.Data.List.Nat.Count
# Lemmas about `Array.countP` and `Array.count`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
@@ -25,120 +22,120 @@ variable (p q : α → Bool)
@[simp] theorem countP_empty : countP p #[] = 0 := rfl
@[simp] theorem countP_push_of_pos (xs) (pa : p a) : countP p (xs.push a) = countP p xs + 1 := by
rcases xs with xs
@[simp] theorem countP_push_of_pos (l) (pa : p a) : countP p (l.push a) = countP p l + 1 := by
rcases l with l
simp_all
@[simp] theorem countP_push_of_neg (xs) (pa : ¬p a) : countP p (xs.push a) = countP p xs := by
rcases xs with xs
@[simp] theorem countP_push_of_neg (l) (pa : ¬p a) : countP p (l.push a) = countP p l := by
rcases l with l
simp_all
theorem countP_push (a : α) (xs) : countP p (xs.push a) = countP p xs + if p a then 1 else 0 := by
rcases xs with xs
theorem countP_push (a : α) (l) : countP p (l.push a) = countP p l + if p a then 1 else 0 := by
rcases l with l
simp_all
@[simp] theorem countP_singleton (a : α) : countP p #[a] = if p a then 1 else 0 := by
simp [countP_push]
theorem size_eq_countP_add_countP (xs) : xs.size = countP p xs + countP (fun a => ¬p a) xs := by
rcases xs with xs
theorem size_eq_countP_add_countP (l) : l.size = countP p l + countP (fun a => ¬p a) l := by
cases l
simp [List.length_eq_countP_add_countP (p := p)]
theorem countP_eq_size_filter (xs) : countP p xs = (filter p xs).size := by
rcases xs with xs
theorem countP_eq_size_filter (l) : countP p l = (filter p l).size := by
cases l
simp [List.countP_eq_length_filter]
theorem countP_eq_size_filter' : countP p = size filter p := by
funext xs
funext l
apply countP_eq_size_filter
theorem countP_le_size : countP p xs xs.size := by
theorem countP_le_size : countP p l l.size := by
simp only [countP_eq_size_filter]
apply size_filter_le
@[simp] theorem countP_append (xs ys) : countP p (xs ++ ys) = countP p xs + countP p ys := by
rcases xs with xs
rcases ys with ys
@[simp] theorem countP_append (l₁ l₂) : countP p (l₁ ++ l₂) = countP p l₁ + countP p l₂ := by
cases l₁
cases l₂
simp
@[simp] theorem countP_pos_iff {p} : 0 < countP p xs a xs, p a := by
rcases xs with xs
@[simp] theorem countP_pos_iff {p} : 0 < countP p l a l, p a := by
cases l
simp
@[simp] theorem one_le_countP_iff {p} : 1 countP p xs a xs, p a :=
@[simp] theorem one_le_countP_iff {p} : 1 countP p l a l, p a :=
countP_pos_iff
@[simp] theorem countP_eq_zero {p} : countP p xs = 0 a xs, ¬p a := by
rcases xs with xs
@[simp] theorem countP_eq_zero {p} : countP p l = 0 a l, ¬p a := by
cases l
simp
@[simp] theorem countP_eq_size {p} : countP p xs = xs.size a xs, p a := by
rcases xs with xs
@[simp] theorem countP_eq_size {p} : countP p l = l.size a l, p a := by
cases l
simp
theorem countP_mkArray (p : α Bool) (a : α) (n : Nat) :
countP p (mkArray n a) = if p a then n else 0 := by
simp [ List.toArray_replicate, List.countP_replicate]
theorem boole_getElem_le_countP (p : α Bool) (xs : Array α) (i : Nat) (h : i < xs.size) :
(if p xs[i] then 1 else 0) xs.countP p := by
rcases xs with xs
theorem boole_getElem_le_countP (p : α Bool) (l : Array α) (i : Nat) (h : i < l.size) :
(if p l[i] then 1 else 0) l.countP p := by
cases l
simp [List.boole_getElem_le_countP]
theorem countP_set (p : α Bool) (xs : Array α) (i : Nat) (a : α) (h : i < xs.size) :
(xs.set i a).countP p = xs.countP p - (if p xs[i] then 1 else 0) + (if p a then 1 else 0) := by
rcases xs with xs
theorem countP_set (p : α Bool) (l : Array α) (i : Nat) (a : α) (h : i < l.size) :
(l.set i a).countP p = l.countP p - (if p l[i] then 1 else 0) + (if p a then 1 else 0) := by
cases l
simp [List.countP_set, h]
theorem countP_filter (xs : Array α) :
countP p (filter q xs) = countP (fun a => p a && q a) xs := by
rcases xs with xs
theorem countP_filter (l : Array α) :
countP p (filter q l) = countP (fun a => p a && q a) l := by
cases l
simp [List.countP_filter]
@[simp] theorem countP_true : (countP fun (_ : α) => true) = size := by
funext xs
funext l
simp
@[simp] theorem countP_false : (countP fun (_ : α) => false) = Function.const _ 0 := by
funext xs
funext l
simp
@[simp] theorem countP_map (p : β Bool) (f : α β) (xs : Array α) :
countP p (map f xs) = countP (p f) xs := by
rcases xs with xs
@[simp] theorem countP_map (p : β Bool) (f : α β) (l : Array α) :
countP p (map f l) = countP (p f) l := by
cases l
simp
theorem size_filterMap_eq_countP (f : α Option β) (xs : Array α) :
(filterMap f xs).size = countP (fun a => (f a).isSome) xs := by
rcases xs with xs
theorem size_filterMap_eq_countP (f : α Option β) (l : Array α) :
(filterMap f l).size = countP (fun a => (f a).isSome) l := by
cases l
simp [List.length_filterMap_eq_countP]
theorem countP_filterMap (p : β Bool) (f : α Option β) (xs : Array α) :
countP p (filterMap f xs) = countP (fun a => ((f a).map p).getD false) xs := by
rcases xs with xs
theorem countP_filterMap (p : β Bool) (f : α Option β) (l : Array α) :
countP p (filterMap f l) = countP (fun a => ((f a).map p).getD false) l := by
cases l
simp [List.countP_filterMap]
@[simp] theorem countP_flatten (xss : Array (Array α)) :
countP p xss.flatten = (xss.map (countP p)).sum := by
cases xss using array₂_induction
@[simp] theorem countP_flatten (l : Array (Array α)) :
countP p l.flatten = (l.map (countP p)).sum := by
cases l using array₂_induction
simp [List.countP_flatten, Function.comp_def]
theorem countP_flatMap (p : β Bool) (xs : Array α) (f : α Array β) :
countP p (xs.flatMap f) = sum (map (countP p f) xs) := by
rcases xs with xs
theorem countP_flatMap (p : β Bool) (l : Array α) (f : α Array β) :
countP p (l.flatMap f) = sum (map (countP p f) l) := by
cases l
simp [List.countP_flatMap, Function.comp_def]
@[simp] theorem countP_reverse (xs : Array α) : countP p xs.reverse = countP p xs := by
rcases xs with xs
@[simp] theorem countP_reverse (l : Array α) : countP p l.reverse = countP p l := by
cases l
simp [List.countP_reverse]
variable {p q}
theorem countP_mono_left (h : x xs, p x q x) : countP p xs countP q xs := by
rcases xs with xs
theorem countP_mono_left (h : x l, p x q x) : countP p l countP q l := by
cases l
simpa using List.countP_mono_left (by simpa using h)
theorem countP_congr (h : x xs, p x q x) : countP p xs = countP q xs :=
theorem countP_congr (h : x l, p x q x) : countP p l = countP q l :=
Nat.le_antisymm
(countP_mono_left fun x hx => (h x hx).1)
(countP_mono_left fun x hx => (h x hx).2)
@@ -152,71 +149,71 @@ variable [BEq α]
@[simp] theorem count_empty (a : α) : count a #[] = 0 := rfl
theorem count_push (a b : α) (xs : Array α) :
count a (xs.push b) = count a xs + if b == a then 1 else 0 := by
theorem count_push (a b : α) (l : Array α) :
count a (l.push b) = count a l + if b == a then 1 else 0 := by
simp [count, countP_push]
theorem count_eq_countP (a : α) (xs : Array α) : count a xs = countP (· == a) xs := rfl
theorem count_eq_countP (a : α) (l : Array α) : count a l = countP (· == a) l := rfl
theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
funext xs
funext l
apply count_eq_countP
theorem count_le_size (a : α) (xs : Array α) : count a xs xs.size := countP_le_size _
theorem count_le_size (a : α) (l : Array α) : count a l l.size := countP_le_size _
theorem count_le_count_push (a b : α) (xs : Array α) : count a xs count a (xs.push b) := by
theorem count_le_count_push (a b : α) (l : Array α) : count a l count a (l.push b) := by
simp [count_push]
theorem count_singleton (a b : α) : count a #[b] = if b == a then 1 else 0 := by
simp [count_eq_countP]
@[simp] theorem count_append (a : α) : xs ys, count a (xs ++ ys) = count a xs + count a ys :=
@[simp] theorem count_append (a : α) : l₁ l₂, count a (l₁ ++ l₂) = count a l₁ + count a l₂ :=
countP_append _
@[simp] theorem count_flatten (a : α) (xss : Array (Array α)) :
count a xss.flatten = (xss.map (count a)).sum := by
cases xss using array₂_induction
@[simp] theorem count_flatten (a : α) (l : Array (Array α)) :
count a l.flatten = (l.map (count a)).sum := by
cases l using array₂_induction
simp [List.count_flatten, Function.comp_def]
@[simp] theorem count_reverse (a : α) (xs : Array α) : count a xs.reverse = count a xs := by
rcases xs with xs
@[simp] theorem count_reverse (a : α) (l : Array α) : count a l.reverse = count a l := by
cases l
simp
theorem boole_getElem_le_count (a : α) (xs : Array α) (i : Nat) (h : i < xs.size) :
(if xs[i] == a then 1 else 0) xs.count a := by
theorem boole_getElem_le_count (a : α) (l : Array α) (i : Nat) (h : i < l.size) :
(if l[i] == a then 1 else 0) l.count a := by
rw [count_eq_countP]
apply boole_getElem_le_countP (· == a)
theorem count_set (a b : α) (xs : Array α) (i : Nat) (h : i < xs.size) :
(xs.set i a).count b = xs.count b - (if xs[i] == b then 1 else 0) + (if a == b then 1 else 0) := by
theorem count_set (a b : α) (l : Array α) (i : Nat) (h : i < l.size) :
(l.set i a).count b = l.count b - (if l[i] == b then 1 else 0) + (if a == b then 1 else 0) := by
simp [count_eq_countP, countP_set, h]
variable [LawfulBEq α]
@[simp] theorem count_push_self (a : α) (xs : Array α) : count a (xs.push a) = count a xs + 1 := by
@[simp] theorem count_push_self (a : α) (l : Array α) : count a (l.push a) = count a l + 1 := by
simp [count_push]
@[simp] theorem count_push_of_ne (h : b a) (xs : Array α) : count a (xs.push b) = count a xs := by
@[simp] theorem count_push_of_ne (h : b a) (l : Array α) : count a (l.push b) = count a l := by
simp_all [count_push, h]
theorem count_singleton_self (a : α) : count a #[a] = 1 := by simp
@[simp]
theorem count_pos_iff {a : α} {xs : Array α} : 0 < count a xs a xs := by
theorem count_pos_iff {a : α} {l : Array α} : 0 < count a l a l := by
simp only [count, countP_pos_iff, beq_iff_eq, exists_eq_right]
@[simp] theorem one_le_count_iff {a : α} {xs : Array α} : 1 count a xs a xs :=
@[simp] theorem one_le_count_iff {a : α} {l : Array α} : 1 count a l a l :=
count_pos_iff
theorem count_eq_zero_of_not_mem {a : α} {xs : Array α} (h : a xs) : count a xs = 0 :=
theorem count_eq_zero_of_not_mem {a : α} {l : Array α} (h : a l) : count a l = 0 :=
Decidable.byContradiction fun h' => h <| count_pos_iff.1 (Nat.pos_of_ne_zero h')
theorem not_mem_of_count_eq_zero {a : α} {xs : Array α} (h : count a xs = 0) : a xs :=
theorem not_mem_of_count_eq_zero {a : α} {l : Array α} (h : count a l = 0) : a l :=
fun h' => Nat.ne_of_lt (count_pos_iff.2 h') h.symm
theorem count_eq_zero {xs : Array α} : count a xs = 0 a xs :=
theorem count_eq_zero {l : Array α} : count a l = 0 a l :=
not_mem_of_count_eq_zero, count_eq_zero_of_not_mem
theorem count_eq_size {xs : Array α} : count a xs = xs.size b xs, a = b := by
theorem count_eq_size {l : Array α} : count a l = l.size b l, a = b := by
rw [count, countP_eq_size]
refine fun h b hb => Eq.symm ?_, fun h b hb => ?_
· simpa using h b hb
@@ -228,37 +225,36 @@ theorem count_eq_size {xs : Array α} : count a xs = xs.size ↔ ∀ b ∈ xs, a
theorem count_mkArray (a b : α) (n : Nat) : count a (mkArray n b) = if b == a then n else 0 := by
simp [ List.toArray_replicate, List.count_replicate]
theorem filter_beq (xs : Array α) (a : α) : xs.filter (· == a) = mkArray (count a xs) a := by
rcases xs with xs
theorem filter_beq (l : Array α) (a : α) : l.filter (· == a) = mkArray (count a l) a := by
cases l
simp [List.filter_beq]
theorem filter_eq {α} [DecidableEq α] (xs : Array α) (a : α) : xs.filter (· = a) = mkArray (count a xs) a :=
filter_beq xs a
theorem filter_eq {α} [DecidableEq α] (l : Array α) (a : α) : l.filter (· = a) = mkArray (count a l) a :=
filter_beq l a
theorem mkArray_count_eq_of_count_eq_size {xs : Array α} (h : count a xs = xs.size) :
mkArray (count a xs) a = xs := by
rcases xs with xs
theorem mkArray_count_eq_of_count_eq_size {l : Array α} (h : count a l = l.size) :
mkArray (count a l) a = l := by
cases l
rw [ toList_inj]
simp [List.replicate_count_eq_of_count_eq_length (by simpa using h)]
@[simp] theorem count_filter {xs : Array α} (h : p a) : count a (filter p xs) = count a xs := by
rcases xs with xs
@[simp] theorem count_filter {l : Array α} (h : p a) : count a (filter p l) = count a l := by
cases l
simp [List.count_filter, h]
theorem count_le_count_map [DecidableEq β] (xs : Array α) (f : α β) (x : α) :
count x xs count (f x) (map f xs) := by
rcases xs with xs
theorem count_le_count_map [DecidableEq β] (l : Array α) (f : α β) (x : α) :
count x l count (f x) (map f l) := by
cases l
simp [List.count_le_count_map, countP_map]
theorem count_filterMap {α} [BEq β] (b : β) (f : α Option β) (xs : Array α) :
count b (filterMap f xs) = countP (fun a => f a == some b) xs := by
rcases xs with xs
theorem count_filterMap {α} [BEq β] (b : β) (f : α Option β) (l : Array α) :
count b (filterMap f l) = countP (fun a => f a == some b) l := by
cases l
simp [List.count_filterMap, countP_filterMap]
theorem count_flatMap {α} [BEq β] (xs : Array α) (f : α Array β) (x : β) :
count x (xs.flatMap f) = sum (map (count x f) xs) := by
rcases xs with xs
simp [List.count_flatMap, countP_flatMap, Function.comp_def]
theorem count_flatMap {α} [BEq β] (l : Array α) (f : α Array β) (x : β) :
count x (l.flatMap f) = sum (map (count x f) l) := by
simp [count_eq_countP, countP_flatMap, Function.comp_def]
-- FIXME these theorems can be restored once `List.erase` and `Array.erase` have been related.

View File

@@ -9,9 +9,6 @@ import Init.Data.BEq
import Init.Data.List.Nat.BEq
import Init.ByCases
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
private theorem rel_of_isEqvAux
@@ -87,9 +84,9 @@ theorem isEqv_self [DecidableEq α] (xs : Array α) : Array.isEqv xs xs (· = ·
simp [isEqv, isEqvAux_self]
instance [DecidableEq α] : DecidableEq (Array α) :=
fun xs ys =>
match h:isEqv xs ys (fun a b => a = b) with
| true => isTrue (eq_of_isEqv xs ys h)
fun a b =>
match h:isEqv a b (fun a b => a = b) with
| true => isTrue (eq_of_isEqv a b h)
| false => isFalse fun h' => by subst h'; rw [isEqv_self] at h; contradiction
theorem beq_eq_decide [BEq α] (xs ys : Array α) :

View File

@@ -12,9 +12,6 @@ import Init.Data.List.Nat.Basic
# Lemmas about `Array.eraseP`, `Array.erase`, and `Array.eraseIdx`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
@@ -23,11 +20,11 @@ open Nat
@[simp] theorem eraseP_empty : #[].eraseP p = #[] := rfl
theorem eraseP_of_forall_mem_not {xs : Array α} (h : a, a xs ¬p a) : xs.eraseP p = xs := by
rcases xs with xs
theorem eraseP_of_forall_mem_not {l : Array α} (h : a, a l ¬p a) : l.eraseP p = l := by
cases l
simp_all [List.eraseP_of_forall_not]
theorem eraseP_of_forall_getElem_not {xs : Array α} (h : i, (h : i < xs.size) ¬p xs[i]) : xs.eraseP p = xs :=
theorem eraseP_of_forall_getElem_not {l : Array α} (h : i, (h : i < l.size) ¬p l[i]) : l.eraseP p = l :=
eraseP_of_forall_mem_not fun a m => by
rw [mem_iff_getElem] at m
obtain i, w, rfl := m
@@ -40,86 +37,86 @@ theorem eraseP_of_forall_getElem_not {xs : Array α} (h : ∀ i, (h : i < xs.siz
theorem eraseP_ne_empty_iff {xs : Array α} {p : α Bool} : xs.eraseP p #[] xs #[] x, p x xs #[x] := by
simp
theorem exists_of_eraseP {xs : Array α} {a} (hm : a xs) (hp : p a) :
a ys zs, ( b ys, ¬p b) p a xs = ys.push a ++ zs xs.eraseP p = ys ++ zs := by
rcases xs with xs
theorem exists_of_eraseP {l : Array α} {a} (hm : a l) (hp : p a) :
a l₁ l₂, ( b l₁, ¬p b) p a l = l₁.push a ++ l₂ l.eraseP p = l₁ ++ l₂ := by
rcases l with l
obtain a, l₁, l₂, h₁, h₂, rfl, h₃ := List.exists_of_eraseP (by simpa using hm) (hp)
refine a, l₁, l₂, by simpa using h₁, h₂, by simp, by simpa using h₃
theorem exists_or_eq_self_of_eraseP (p) (xs : Array α) :
xs.eraseP p = xs
a ys zs, ( b ys, ¬p b) p a xs = ys.push a ++ zs xs.eraseP p = ys ++ zs :=
if h : a xs, p a then
theorem exists_or_eq_self_of_eraseP (p) (l : Array α) :
l.eraseP p = l
a l₁ l₂, ( b l₁, ¬p b) p a l = l₁.push a ++ l₂ l.eraseP p = l₁ ++ l₂ :=
if h : a l, p a then
let _, ha, pa := h
.inr (exists_of_eraseP ha pa)
else
.inl (eraseP_of_forall_mem_not (h ·, ·, ·))
@[simp] theorem size_eraseP_of_mem {xs : Array α} (al : a xs) (pa : p a) :
(xs.eraseP p).size = xs.size - 1 := by
let _, ys, zs, _, _, e₁, e₂ := exists_of_eraseP al pa
@[simp] theorem size_eraseP_of_mem {l : Array α} (al : a l) (pa : p a) :
(l.eraseP p).size = l.size - 1 := by
let _, l₁, l₂, _, _, e₁, e₂ := exists_of_eraseP al pa
rw [e₂]; simp [size_append, e₁]; omega
theorem size_eraseP {xs : Array α} : (xs.eraseP p).size = if xs.any p then xs.size - 1 else xs.size := by
theorem size_eraseP {l : Array α} : (l.eraseP p).size = if l.any p then l.size - 1 else l.size := by
split <;> rename_i h
· simp only [any_eq_true] at h
obtain i, h, w := h
simp [size_eraseP_of_mem (xs := xs) (by simp) w]
simp [size_eraseP_of_mem (l := l) (by simp) w]
· simp only [any_eq_true] at h
rw [eraseP_of_forall_getElem_not]
simp_all
theorem size_eraseP_le (xs : Array α) : (xs.eraseP p).size xs.size := by
rcases xs with xs
simpa using List.length_eraseP_le xs
theorem size_eraseP_le (l : Array α) : (l.eraseP p).size l.size := by
rcases l with l
simpa using List.length_eraseP_le l
theorem le_size_eraseP (xs : Array α) : xs.size - 1 (xs.eraseP p).size := by
rcases xs with xs
simpa using List.le_length_eraseP xs
theorem le_size_eraseP (l : Array α) : l.size - 1 (l.eraseP p).size := by
rcases l with l
simpa using List.le_length_eraseP l
theorem mem_of_mem_eraseP {xs : Array α} : a xs.eraseP p a xs := by
rcases xs with xs
theorem mem_of_mem_eraseP {l : Array α} : a l.eraseP p a l := by
rcases l with l
simpa using List.mem_of_mem_eraseP
@[simp] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a xs.eraseP p a xs := by
rcases xs with xs
@[simp] theorem mem_eraseP_of_neg {l : Array α} (pa : ¬p a) : a l.eraseP p a l := by
rcases l with l
simpa using List.mem_eraseP_of_neg pa
@[simp] theorem eraseP_eq_self_iff {xs : Array α} : xs.eraseP p = xs a xs, ¬ p a := by
rcases xs with xs
@[simp] theorem eraseP_eq_self_iff {p} {l : Array α} : l.eraseP p = l a l, ¬ p a := by
rcases l with l
simp
theorem eraseP_map (f : β α) (xs : Array β) : (xs.map f).eraseP p = (xs.eraseP (p f)).map f := by
rcases xs with xs
simpa using List.eraseP_map f xs
theorem eraseP_map (f : β α) (l : Array β) : (map f l).eraseP p = map f (l.eraseP (p f)) := by
rcases l with l
simpa using List.eraseP_map f l
theorem eraseP_filterMap (f : α Option β) (xs : Array α) :
(filterMap f xs).eraseP p = filterMap f (xs.eraseP (fun x => match f x with | some y => p y | none => false)) := by
rcases xs with xs
simpa using List.eraseP_filterMap f xs
theorem eraseP_filterMap (f : α Option β) (l : Array α) :
(filterMap f l).eraseP p = filterMap f (l.eraseP (fun x => match f x with | some y => p y | none => false)) := by
rcases l with l
simpa using List.eraseP_filterMap f l
theorem eraseP_filter (f : α Bool) (xs : Array α) :
(filter f xs).eraseP p = filter f (xs.eraseP (fun x => p x && f x)) := by
rcases xs with xs
simpa using List.eraseP_filter f xs
theorem eraseP_filter (f : α Bool) (l : Array α) :
(filter f l).eraseP p = filter f (l.eraseP (fun x => p x && f x)) := by
rcases l with l
simpa using List.eraseP_filter f l
theorem eraseP_append_left {a : α} (pa : p a) {xs : Array α} {ys : Array α} (h : a xs) :
(xs ++ ys).eraseP p = xs.eraseP p ++ ys := by
rcases xs with xs
rcases ys with ys
simpa using List.eraseP_append_left pa ys (by simpa using h)
theorem eraseP_append_left {a : α} (pa : p a) {l₁ : Array α} l₂ (h : a l₁) :
(l₁ ++ l₂).eraseP p = l₁.eraseP p ++ l₂ := by
rcases l₁ with l₁
rcases l₂ with l₂
simpa using List.eraseP_append_left pa l₂ (by simpa using h)
theorem eraseP_append_right {xs : Array α} ys (h : b xs, ¬p b) :
(xs ++ ys).eraseP p = xs ++ ys.eraseP p := by
rcases xs with xs
rcases ys with ys
simpa using List.eraseP_append_right ys (by simpa using h)
theorem eraseP_append_right {l₁ : Array α} l₂ (h : b l₁, ¬p b) :
(l₁ ++ l₂).eraseP p = l₁ ++ l₂.eraseP p := by
rcases l₁ with l₁
rcases l₂ with l₂
simpa using List.eraseP_append_right l₂ (by simpa using h)
theorem eraseP_append {xs : Array α} {ys : Array α} :
(xs ++ ys).eraseP p = if xs.any p then xs.eraseP p ++ ys else xs ++ ys.eraseP p := by
rcases xs with xs
rcases ys with ys
simp only [List.append_toArray, List.eraseP_toArray, List.eraseP_append, List.any_toArray]
theorem eraseP_append (l₁ l₂ : Array α) :
(l₁ ++ l₂).eraseP p = if l₁.any p then l₁.eraseP p ++ l₂ else l₁ ++ l₂.eraseP p := by
rcases l₁ with l₁
rcases l₂ with l₂
simp only [List.append_toArray, List.eraseP_toArray, List.eraseP_append l₁ l₂, List.any_toArray']
split <;> simp
theorem eraseP_mkArray (n : Nat) (a : α) (p : α Bool) :
@@ -137,24 +134,24 @@ theorem eraseP_mkArray (n : Nat) (a : α) (p : α → Bool) :
simp only [ List.toArray_replicate, List.eraseP_toArray]
simp [h]
theorem eraseP_eq_iff {p} {xs : Array α} :
xs.eraseP p = ys
(( a xs, ¬ p a) xs = ys)
a as bs, ( b as, ¬ p b) p a xs = as.push a ++ bs ys = as ++ bs := by
rcases xs with l
rcases ys with ys
theorem eraseP_eq_iff {p} {l : Array α} :
l.eraseP p = l'
(( a l, ¬ p a) l = l')
a l₁ l₂, ( b l₁, ¬ p b) p a l = l₁.push a ++ l₂ l' = l₁ ++ l₂ := by
rcases l with l
rcases l' with l'
simp [List.eraseP_eq_iff]
constructor
· rintro (h | a, l₁, h₁, h₂, l, rfl, rfl)
· rintro (h | a, l₁, h₁, h₂, x, rfl, rfl)
· exact Or.inl h
· exact Or.inr a, l₁, by simpa using h₁, h₂, l, by simp
· rintro (h | a, l₁, h₁, h₂, l, rfl, rfl)
· exact Or.inr a, l₁, by simpa using h₁, h₂, x, by simp
· rintro (h | a, l₁, h₁, h₂, x, rfl, rfl)
· exact Or.inl h
· exact Or.inr a, l₁, by simpa using h₁, h₂, l, by simp
· exact Or.inr a, l₁, by simpa using h₁, h₂, x, by simp
theorem eraseP_comm {xs : Array α} (h : a xs, ¬ p a ¬ q a) :
(xs.eraseP p).eraseP q = (xs.eraseP q).eraseP p := by
rcases xs with xs
theorem eraseP_comm {l : Array α} (h : a l, ¬ p a ¬ q a) :
(l.eraseP p).eraseP q = (l.eraseP q).eraseP p := by
rcases l with l
simpa using List.eraseP_comm (by simpa using h)
/-! ### erase -/
@@ -162,16 +159,16 @@ theorem eraseP_comm {xs : Array α} (h : ∀ a ∈ xs, ¬ p a ¬ q a) :
section erase
variable [BEq α]
theorem erase_of_not_mem [LawfulBEq α] {a : α} {xs : Array α} (h : a xs) : xs.erase a = xs := by
rcases xs with xs
theorem erase_of_not_mem [LawfulBEq α] {a : α} {l : Array α} (h : a l) : l.erase a = l := by
rcases l with l
simp [List.erase_of_not_mem (by simpa using h)]
theorem erase_eq_eraseP' (a : α) (xs : Array α) : xs.erase a = xs.eraseP (· == a) := by
rcases xs with xs
theorem erase_eq_eraseP' (a : α) (l : Array α) : l.erase a = l.eraseP (· == a) := by
rcases l with l
simp [List.erase_eq_eraseP']
theorem erase_eq_eraseP [LawfulBEq α] (a : α) (xs : Array α) : xs.erase a = xs.eraseP (a == ·) := by
rcases xs with xs
theorem erase_eq_eraseP [LawfulBEq α] (a : α) (l : Array α) : l.erase a = l.eraseP (a == ·) := by
rcases l with l
simp [List.erase_eq_eraseP]
@[simp] theorem erase_eq_empty_iff [LawfulBEq α] {xs : Array α} {a : α} :
@@ -184,62 +181,62 @@ theorem erase_ne_empty_iff [LawfulBEq α] {xs : Array α} {a : α} :
rcases xs with xs
simp [List.erase_ne_nil_iff]
theorem exists_erase_eq [LawfulBEq α] {a : α} {xs : Array α} (h : a xs) :
ys zs, a ys xs = ys.push a ++ zs xs.erase a = ys ++ zs := by
let _, ys, zs, h₁, e, h₂, h₃ := exists_of_eraseP h (beq_self_eq_true _)
rw [erase_eq_eraseP]; exact ys, zs, fun h => h₁ _ h (beq_self_eq_true _), eq_of_beq e h₂, h₃
theorem exists_erase_eq [LawfulBEq α] {a : α} {l : Array α} (h : a l) :
l₁ l₂, a l₁ l = l₁.push a ++ l₂ l.erase a = l₁ ++ l₂ := by
let _, l₁, l₂, h₁, e, h₂, h₃ := exists_of_eraseP h (beq_self_eq_true _)
rw [erase_eq_eraseP]; exact l₁, l₂, fun h => h₁ _ h (beq_self_eq_true _), eq_of_beq e h₂, h₃
@[simp] theorem size_erase_of_mem [LawfulBEq α] {a : α} {xs : Array α} (h : a xs) :
(xs.erase a).size = xs.size - 1 := by
@[simp] theorem size_erase_of_mem [LawfulBEq α] {a : α} {l : Array α} (h : a l) :
(l.erase a).size = l.size - 1 := by
rw [erase_eq_eraseP]; exact size_eraseP_of_mem h (beq_self_eq_true a)
theorem size_erase [LawfulBEq α] (a : α) (xs : Array α) :
(xs.erase a).size = if a xs then xs.size - 1 else xs.size := by
theorem size_erase [LawfulBEq α] (a : α) (l : Array α) :
(l.erase a).size = if a l then l.size - 1 else l.size := by
rw [erase_eq_eraseP, size_eraseP]
congr
simp [mem_iff_getElem, eq_comm (a := a)]
theorem size_erase_le (a : α) (xs : Array α) : (xs.erase a).size xs.size := by
rcases xs with xs
simpa using List.length_erase_le a xs
theorem size_erase_le (a : α) (l : Array α) : (l.erase a).size l.size := by
rcases l with l
simpa using List.length_erase_le a l
theorem le_size_erase [LawfulBEq α] (a : α) (xs : Array α) : xs.size - 1 (xs.erase a).size := by
rcases xs with xs
simpa using List.le_length_erase a xs
theorem le_size_erase [LawfulBEq α] (a : α) (l : Array α) : l.size - 1 (l.erase a).size := by
rcases l with l
simpa using List.le_length_erase a l
theorem mem_of_mem_erase {a b : α} {xs : Array α} (h : a xs.erase b) : a xs := by
rcases xs with xs
theorem mem_of_mem_erase {a b : α} {l : Array α} (h : a l.erase b) : a l := by
rcases l with l
simpa using List.mem_of_mem_erase (by simpa using h)
@[simp] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a b) :
a xs.erase b a xs :=
erase_eq_eraseP b xs mem_eraseP_of_neg (mt eq_of_beq ab.symm)
@[simp] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : Array α} (ab : a b) :
a l.erase b a l :=
erase_eq_eraseP b l mem_eraseP_of_neg (mt eq_of_beq ab.symm)
@[simp] theorem erase_eq_self_iff [LawfulBEq α] {xs : Array α} : xs.erase a = xs a xs := by
@[simp] theorem erase_eq_self_iff [LawfulBEq α] {l : Array α} : l.erase a = l a l := by
rw [erase_eq_eraseP', eraseP_eq_self_iff]
simp [forall_mem_ne']
theorem erase_filter [LawfulBEq α] (f : α Bool) (xs : Array α) :
(filter f xs).erase a = filter f (xs.erase a) := by
rcases xs with xs
simpa using List.erase_filter f xs
theorem erase_filter [LawfulBEq α] (f : α Bool) (l : Array α) :
(filter f l).erase a = filter f (l.erase a) := by
rcases l with l
simpa using List.erase_filter f l
theorem erase_append_left [LawfulBEq α] {xs : Array α} (ys) (h : a xs) :
(xs ++ ys).erase a = xs.erase a ++ ys := by
rcases xs with xs
rcases ys with ys
simpa using List.erase_append_left ys (by simpa using h)
theorem erase_append_left [LawfulBEq α] {l₁ : Array α} (l₂) (h : a l₁) :
(l₁ ++ l₂).erase a = l₁.erase a ++ l₂ := by
rcases l₁ with l₁
rcases l₂ with l₂
simpa using List.erase_append_left l₂ (by simpa using h)
theorem erase_append_right [LawfulBEq α] {a : α} {xs : Array α} (ys : Array α) (h : a xs) :
(xs ++ ys).erase a = (xs ++ ys.erase a) := by
rcases xs with xs
rcases ys with ys
simpa using List.erase_append_right ys (by simpa using h)
theorem erase_append_right [LawfulBEq α] {a : α} {l₁ : Array α} (l₂ : Array α) (h : a l₁) :
(l₁ ++ l₂).erase a = (l₁ ++ l₂.erase a) := by
rcases l₁ with l₁
rcases l₂ with l₂
simpa using List.erase_append_right l₂ (by simpa using h)
theorem erase_append [LawfulBEq α] {a : α} {xs ys : Array α} :
(xs ++ ys).erase a = if a xs then xs.erase a ++ ys else xs ++ ys.erase a := by
rcases xs with xs
rcases ys with ys
theorem erase_append [LawfulBEq α] {a : α} {l₁ l₂ : Array α} :
(l₁ ++ l₂).erase a = if a l₁ then l₁.erase a ++ l₂ else l₁ ++ l₂.erase a := by
rcases l₁ with l₁
rcases l₂ with l₂
simp only [List.append_toArray, List.erase_toArray, List.erase_append, mem_toArray]
split <;> simp
@@ -249,24 +246,24 @@ theorem erase_mkArray [LawfulBEq α] (n : Nat) (a b : α) :
simp only [List.erase_replicate, beq_iff_eq, List.toArray_replicate]
split <;> simp
theorem erase_comm [LawfulBEq α] (a b : α) (xs : Array α) :
(xs.erase a).erase b = (xs.erase b).erase a := by
rcases xs with xs
simpa using List.erase_comm a b xs
theorem erase_comm [LawfulBEq α] (a b : α) (l : Array α) :
(l.erase a).erase b = (l.erase b).erase a := by
rcases l with l
simpa using List.erase_comm a b l
theorem erase_eq_iff [LawfulBEq α] {a : α} {xs : Array α} :
xs.erase a = ys
(a xs xs = ys)
as bs, a as xs = as.push a ++ bs ys = as ++ bs := by
theorem erase_eq_iff [LawfulBEq α] {a : α} {l : Array α} :
l.erase a = l'
(a l l = l')
l₁ l₂, a l₁ l = l₁.push a ++ l₂ l' = l₁ ++ l₂ := by
rw [erase_eq_eraseP', eraseP_eq_iff]
simp only [beq_iff_eq, forall_mem_ne', exists_and_left]
constructor
· rintro (h, rfl | a', as, h, rfl, bs, rfl, rfl)
· rintro (h, rfl | a', l', h, rfl, x, rfl, rfl)
· left; simp_all
· right; refine as, h, bs, by simp
· rintro (h, rfl | as, h, bs, rfl, rfl)
· right; refine l', h, x, by simp
· rintro (h, rfl | l₁, h, x, rfl, rfl)
· left; simp_all
· right; refine a, as, h, rfl, bs, by simp
· right; refine a, l₁, h, rfl, x, by simp
@[simp] theorem erase_mkArray_self [LawfulBEq α] {a : α} :
(mkArray n a).erase a = mkArray (n - 1) a := by
@@ -282,8 +279,8 @@ end erase
/-! ### eraseIdx -/
theorem eraseIdx_eq_take_drop_succ (xs : Array α) (i : Nat) (h) : xs.eraseIdx i = xs.take i ++ xs.drop (i + 1) := by
rcases xs with xs
theorem eraseIdx_eq_take_drop_succ (l : Array α) (i : Nat) (h) : l.eraseIdx i = l.take i ++ l.drop (i + 1) := by
rcases l with l
simp only [List.size_toArray] at h
simp only [List.eraseIdx_toArray, List.eraseIdx_eq_take_drop_succ, take_eq_extract,
List.extract_toArray, List.extract_eq_drop_take, Nat.sub_zero, List.drop_zero, drop_eq_extract,
@@ -291,61 +288,61 @@ theorem eraseIdx_eq_take_drop_succ (xs : Array α) (i : Nat) (h) : xs.eraseIdx i
rw [List.take_of_length_le]
simp
theorem getElem?_eraseIdx (xs : Array α) (i : Nat) (h : i < xs.size) (j : Nat) :
(xs.eraseIdx i)[j]? = if j < i then xs[j]? else xs[j + 1]? := by
rcases xs with xs
theorem getElem?_eraseIdx (l : Array α) (i : Nat) (h : i < l.size) (j : Nat) :
(l.eraseIdx i)[j]? = if j < i then l[j]? else l[j + 1]? := by
rcases l with l
simp [List.getElem?_eraseIdx]
theorem getElem?_eraseIdx_of_lt (xs : Array α) (i : Nat) (h : i < xs.size) (j : Nat) (h' : j < i) :
(xs.eraseIdx i)[j]? = xs[j]? := by
theorem getElem?_eraseIdx_of_lt (l : Array α) (i : Nat) (h : i < l.size) (j : Nat) (h' : j < i) :
(l.eraseIdx i)[j]? = l[j]? := by
rw [getElem?_eraseIdx]
simp [h']
theorem getElem?_eraseIdx_of_ge (xs : Array α) (i : Nat) (h : i < xs.size) (j : Nat) (h' : i j) :
(xs.eraseIdx i)[j]? = xs[j + 1]? := by
theorem getElem?_eraseIdx_of_ge (l : Array α) (i : Nat) (h : i < l.size) (j : Nat) (h' : i j) :
(l.eraseIdx i)[j]? = l[j + 1]? := by
rw [getElem?_eraseIdx]
simp only [dite_eq_ite, ite_eq_right_iff]
intro h'
omega
theorem getElem_eraseIdx (xs : Array α) (i : Nat) (h : i < xs.size) (j : Nat) (h' : j < (xs.eraseIdx i).size) :
(xs.eraseIdx i)[j] = if h'' : j < i then
xs[j]
theorem getElem_eraseIdx (l : Array α) (i : Nat) (h : i < l.size) (j : Nat) (h' : j < (l.eraseIdx i).size) :
(l.eraseIdx i)[j] = if h'' : j < i then
l[j]
else
xs[j + 1]'(by rw [size_eraseIdx] at h'; omega) := by
l[j + 1]'(by rw [size_eraseIdx] at h'; omega) := by
apply Option.some.inj
rw [ getElem?_eq_getElem, getElem?_eraseIdx]
split <;> simp
@[simp] theorem eraseIdx_eq_empty_iff {xs : Array α} {i : Nat} {h} : xs.eraseIdx i = #[] xs.size = 1 i = 0 := by
rcases xs with xs
@[simp] theorem eraseIdx_eq_empty_iff {l : Array α} {i : Nat} {h} : eraseIdx l i = #[] l.size = 1 i = 0 := by
rcases l with l
simp only [List.eraseIdx_toArray, mk.injEq, List.eraseIdx_eq_nil_iff, List.size_toArray,
or_iff_right_iff_imp]
rintro rfl
simp_all
theorem eraseIdx_ne_empty_iff {xs : Array α} {i : Nat} {h} : xs.eraseIdx i #[] 2 xs.size := by
rcases xs with _ | a, (_ | b, l)
theorem eraseIdx_ne_empty_iff {l : Array α} {i : Nat} {h} : eraseIdx l i #[] 2 l.size := by
rcases l with _ | a, (_ | b, l)
· simp
· simp at h
simp [h]
· simp
theorem mem_of_mem_eraseIdx {xs : Array α} {i : Nat} {h} {a : α} (h : a xs.eraseIdx i) : a xs := by
rcases xs with xs
theorem mem_of_mem_eraseIdx {l : Array α} {i : Nat} {h} {a : α} (h : a l.eraseIdx i) : a l := by
rcases l with l
simpa using List.mem_of_mem_eraseIdx (by simpa using h)
theorem eraseIdx_append_of_lt_size {xs : Array α} {k : Nat} (hk : k < xs.size) (ys : Array α) (h) :
eraseIdx (xs ++ ys) k = eraseIdx xs k ++ ys := by
rcases xs with l
rcases ys with l'
theorem eraseIdx_append_of_lt_size {l : Array α} {k : Nat} (hk : k < l.size) (l' : Array α) (h) :
eraseIdx (l ++ l') k = eraseIdx l k ++ l' := by
rcases l with l
rcases l' with l'
simp at hk
simp [List.eraseIdx_append_of_lt_length, *]
theorem eraseIdx_append_of_length_le {xs : Array α} {k : Nat} (hk : xs.size k) (ys : Array α) (h) :
eraseIdx (xs ++ ys) k = xs ++ eraseIdx ys (k - xs.size) (by simp at h; omega) := by
rcases xs with l
rcases ys with l'
theorem eraseIdx_append_of_length_le {l : Array α} {k : Nat} (hk : l.size k) (l' : Array α) (h) :
eraseIdx (l ++ l') k = l ++ eraseIdx l' (k - l.size) (by simp at h; omega) := by
rcases l with l
rcases l' with l'
simp at hk
simp [List.eraseIdx_append_of_length_le, *]
@@ -355,49 +352,49 @@ theorem eraseIdx_mkArray {n : Nat} {a : α} {k : Nat} {h} :
simp only [ List.toArray_replicate, List.eraseIdx_toArray]
simp [List.eraseIdx_replicate, h]
theorem mem_eraseIdx_iff_getElem {x : α} {xs : Array α} {k} {h} : x xs.eraseIdx k h i w, i k xs[i]'w = x := by
rcases xs with xs
theorem mem_eraseIdx_iff_getElem {x : α} {l} {k} {h} : x eraseIdx l k h i w, i k l[i]'w = x := by
rcases l with l
simp [List.mem_eraseIdx_iff_getElem, *]
theorem mem_eraseIdx_iff_getElem? {x : α} {xs : Array α} {k} {h} : x xs.eraseIdx k h i k, xs[i]? = some x := by
rcases xs with xs
theorem mem_eraseIdx_iff_getElem? {x : α} {l} {k} {h} : x eraseIdx l k h i k, l[i]? = some x := by
rcases l with l
simp [List.mem_eraseIdx_iff_getElem?, *]
theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α] (xs : Array α) (a : α) (i : Nat) (w : xs.idxOf a = i) (h : i < xs.size) :
xs.erase a = xs.eraseIdx i := by
rcases xs with xs
theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α] (l : Array α) (a : α) (i : Nat) (w : l.idxOf a = i) (h : i < l.size) :
l.erase a = l.eraseIdx i := by
rcases l with l
simp at w
simp [List.erase_eq_eraseIdx_of_idxOf, *]
theorem getElem_eraseIdx_of_lt (xs : Array α) (i : Nat) (w : i < xs.size) (j : Nat) (h : j < (xs.eraseIdx i).size) (h' : j < i) :
(xs.eraseIdx i)[j] = xs[j] := by
rcases xs with xs
theorem getElem_eraseIdx_of_lt (l : Array α) (i : Nat) (w : i < l.size) (j : Nat) (h : j < (l.eraseIdx i).size) (h' : j < i) :
(l.eraseIdx i)[j] = l[j] := by
rcases l with l
simp [List.getElem_eraseIdx_of_lt, *]
theorem getElem_eraseIdx_of_ge (xs : Array α) (i : Nat) (w : i < xs.size) (j : Nat) (h : j < (xs.eraseIdx i).size) (h' : i j) :
(xs.eraseIdx i)[j] = xs[j + 1]'(by simp at h; omega) := by
rcases xs with xs
theorem getElem_eraseIdx_of_ge (l : Array α) (i : Nat) (w : i < l.size) (j : Nat) (h : j < (l.eraseIdx i).size) (h' : i j) :
(l.eraseIdx i)[j] = l[j + 1]'(by simp at h; omega) := by
rcases l with l
simp [List.getElem_eraseIdx_of_ge, *]
theorem eraseIdx_set_eq {xs : Array α} {i : Nat} {a : α} {h : i < xs.size} :
(xs.set i a).eraseIdx i (by simp; omega) = xs.eraseIdx i := by
rcases xs with xs
theorem eraseIdx_set_eq {l : Array α} {i : Nat} {a : α} {h : i < l.size} :
(l.set i a).eraseIdx i (by simp; omega) = l.eraseIdx i := by
rcases l with l
simp [List.eraseIdx_set_eq, *]
theorem eraseIdx_set_lt {xs : Array α} {i : Nat} {w : i < xs.size} {j : Nat} {a : α} (h : j < i) :
(xs.set i a).eraseIdx j (by simp; omega) = (xs.eraseIdx j).set (i - 1) a (by simp; omega) := by
rcases xs with xs
theorem eraseIdx_set_lt {l : Array α} {i : Nat} {w : i < l.size} {j : Nat} {a : α} (h : j < i) :
(l.set i a).eraseIdx j (by simp; omega) = (l.eraseIdx j).set (i - 1) a (by simp; omega) := by
rcases l with l
simp [List.eraseIdx_set_lt, *]
theorem eraseIdx_set_gt {xs : Array α} {i : Nat} {j : Nat} {a : α} (h : i < j) {w : j < xs.size} :
(xs.set i a).eraseIdx j (by simp; omega) = (xs.eraseIdx j).set i a (by simp; omega) := by
rcases xs with xs
theorem eraseIdx_set_gt {l : Array α} {i : Nat} {j : Nat} {a : α} (h : i < j) {w : j < l.size} :
(l.set i a).eraseIdx j (by simp; omega) = (l.eraseIdx j).set i a (by simp; omega) := by
rcases l with l
simp [List.eraseIdx_set_gt, *]
@[simp] theorem set_getElem_succ_eraseIdx_succ
{xs : Array α} {i : Nat} (h : i + 1 < xs.size) :
(xs.eraseIdx (i + 1)).set i xs[i + 1] (by simp; omega) = xs.eraseIdx i := by
rcases xs with xs
{l : Array α} {i : Nat} (h : i + 1 < l.size) :
(l.eraseIdx (i + 1)).set i l[i + 1] (by simp; omega) = l.eraseIdx i := by
rcases l with l
simp [List.set_getElem_succ_eraseIdx_succ, *]
end Array

View File

@@ -13,9 +13,6 @@ import Init.Data.List.Nat.TakeDrop
This file follows the contents of `Init.Data.List.TakeDrop` and `Init.Data.List.Nat.TakeDrop`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Nat
namespace Array
@@ -357,10 +354,10 @@ theorem takeWhile_append {xs ys : Array α} :
simp only [List.append_toArray, List.takeWhile_toArray, List.takeWhile_append, List.size_toArray]
split <;> rfl
@[simp] theorem takeWhile_append_of_pos {p : α Bool} {xs ys : Array α} (h : a xs, p a) :
(xs ++ ys).takeWhile p = xs ++ ys.takeWhile p := by
rcases xs with xs
rcases ys with ys
@[simp] theorem takeWhile_append_of_pos {p : α Bool} {l₁ l₂ : Array α} (h : a l₁, p a) :
(l₁ ++ l₂).takeWhile p = l₁ ++ l₂.takeWhile p := by
rcases l₁ with l₁
rcases l₂ with l₂
simp at h
simp [List.takeWhile_append_of_pos h]
@@ -377,10 +374,10 @@ theorem popWhile_append {xs ys : Array α} :
· rfl
· simp
@[simp] theorem popWhile_append_of_pos {p : α Bool} {xs ys : Array α} (h : a ys, p a) :
(xs ++ ys).popWhile p = xs.popWhile p := by
rcases xs with xs
rcases ys with ys
@[simp] theorem popWhile_append_of_pos {p : α Bool} {l₁ l₂ : Array α} (h : a l₂, p a) :
(l₁ ++ l₂).popWhile p = l₁.popWhile p := by
rcases l₁ with l₁
rcases l₂ with l₂
simp at h
simp only [List.append_toArray, List.popWhile_toArray, List.reverse_append, mk.injEq,
List.reverse_inj]

View File

@@ -7,9 +7,6 @@ prelude
import Init.Data.List.FinRange
import Init.Data.Array.OfFn
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/-- `finRange n` is the array of all elements of `Fin n` in order. -/

View File

@@ -13,79 +13,77 @@ import Init.Data.Array.Range
# Lemmas about `Array.findSome?`, `Array.find?, `Array.findIdx`, `Array.findIdx?`, `Array.idxOf`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
/-! ### findSome? -/
@[simp] theorem findSomeRev?_push_of_isSome (xs : Array α) (h : (f a).isSome) : (xs.push a).findSomeRev? f = f a := by
cases xs; simp_all
@[simp] theorem findSomeRev?_push_of_isSome (l : Array α) (h : (f a).isSome) : (l.push a).findSomeRev? f = f a := by
cases l; simp_all
@[simp] theorem findSomeRev?_push_of_isNone (xs : Array α) (h : (f a).isNone) : (xs.push a).findSomeRev? f = xs.findSomeRev? f := by
cases xs; simp_all
@[simp] theorem findSomeRev?_push_of_isNone (l : Array α) (h : (f a).isNone) : (l.push a).findSomeRev? f = l.findSomeRev? f := by
cases l; simp_all
theorem exists_of_findSome?_eq_some {f : α Option β} {xs : Array α} (w : xs.findSome? f = some b) :
a, a xs f a = b := by
cases xs; simp_all [List.exists_of_findSome?_eq_some]
theorem exists_of_findSome?_eq_some {f : α Option β} {l : Array α} (w : l.findSome? f = some b) :
a, a l f a = b := by
cases l; simp_all [List.exists_of_findSome?_eq_some]
@[simp] theorem findSome?_eq_none_iff : findSome? p xs = none x xs, p x = none := by
cases xs; simp
@[simp] theorem findSome?_eq_none_iff : findSome? p l = none x l, p x = none := by
cases l; simp
@[simp] theorem findSome?_isSome_iff {f : α Option β} {xs : Array α} :
(xs.findSome? f).isSome x, x xs (f x).isSome := by
cases xs; simp
@[simp] theorem findSome?_isSome_iff {f : α Option β} {l : Array α} :
(l.findSome? f).isSome x, x l (f x).isSome := by
cases l; simp
theorem findSome?_eq_some_iff {f : α Option β} {xs : Array α} {b : β} :
xs.findSome? f = some b (ys : Array α) (a : α) (zs : Array α), xs = ys.push a ++ zs f a = some b x ys, f x = none := by
cases xs
theorem findSome?_eq_some_iff {f : α Option β} {l : Array α} {b : β} :
l.findSome? f = some b (l₁ : Array α) (a : α) (l₂ : Array α), l = l₁.push a ++ l₂ f a = some b x l₁, f x = none := by
cases l
simp only [List.findSome?_toArray, List.findSome?_eq_some_iff]
constructor
· rintro l₁, a, l₂, rfl, h₁, h₂
exact l₁.toArray, a, l₂.toArray, by simp_all
· rintro xs, a, ys, h₀, h₁, h₂
exact xs.toList, a, ys.toList, by simpa using congrArg toList h₀, h₁, by simpa
· rintro l₁, a, l₂, h₀, h₁, h₂
exact l₁.toList, a, l₂.toList, by simpa using congrArg toList h₀, h₁, by simpa
@[simp] theorem findSome?_guard (xs : Array α) : findSome? (Option.guard fun x => p x) xs = find? p xs := by
cases xs; simp
@[simp] theorem findSome?_guard (l : Array α) : findSome? (Option.guard fun x => p x) l = find? p l := by
cases l; simp
theorem find?_eq_findSome?_guard (xs : Array α) : find? p xs = findSome? (Option.guard fun x => p x) xs :=
(findSome?_guard xs).symm
theorem find?_eq_findSome?_guard (l : Array α) : find? p l = findSome? (Option.guard fun x => p x) l :=
(findSome?_guard l).symm
@[simp] theorem getElem?_zero_filterMap (f : α Option β) (xs : Array α) : (xs.filterMap f)[0]? = xs.findSome? f := by
cases xs; simp [ List.head?_eq_getElem?]
@[simp] theorem getElem?_zero_filterMap (f : α Option β) (l : Array α) : (l.filterMap f)[0]? = l.findSome? f := by
cases l; simp [ List.head?_eq_getElem?]
@[simp] theorem getElem_zero_filterMap (f : α Option β) (xs : Array α) (h) :
(xs.filterMap f)[0] = (xs.findSome? f).get (by cases xs; simpa [List.length_filterMap_eq_countP] using h) := by
cases xs; simp [ List.head_eq_getElem, getElem?_zero_filterMap]
@[simp] theorem getElem_zero_filterMap (f : α Option β) (l : Array α) (h) :
(l.filterMap f)[0] = (l.findSome? f).get (by cases l; simpa [List.length_filterMap_eq_countP] using h) := by
cases l; simp [ List.head_eq_getElem, getElem?_zero_filterMap]
@[simp] theorem back?_filterMap (f : α Option β) (xs : Array α) : (xs.filterMap f).back? = xs.findSomeRev? f := by
cases xs; simp
@[simp] theorem back?_filterMap (f : α Option β) (l : Array α) : (l.filterMap f).back? = l.findSomeRev? f := by
cases l; simp
@[simp] theorem back!_filterMap [Inhabited β] (f : α Option β) (xs : Array α) :
(xs.filterMap f).back! = (xs.findSomeRev? f).getD default := by
cases xs; simp
@[simp] theorem back!_filterMap [Inhabited β] (f : α Option β) (l : Array α) :
(l.filterMap f).back! = (l.findSomeRev? f).getD default := by
cases l; simp
@[simp] theorem map_findSome? (f : α Option β) (g : β γ) (xs : Array α) :
(xs.findSome? f).map g = xs.findSome? (Option.map g f) := by
cases xs; simp
@[simp] theorem map_findSome? (f : α Option β) (g : β γ) (l : Array α) :
(l.findSome? f).map g = l.findSome? (Option.map g f) := by
cases l; simp
theorem findSome?_map (f : β γ) (xs : Array β) : findSome? p (xs.map f) = xs.findSome? (p f) := by
cases xs; simp [List.findSome?_map]
theorem findSome?_map (f : β γ) (l : Array β) : findSome? p (l.map f) = l.findSome? (p f) := by
cases l; simp [List.findSome?_map]
theorem findSome?_append {xs ys : Array α} : (xs ++ ys).findSome? f = (xs.findSome? f).or (ys.findSome? f) := by
cases xs; cases ys; simp [List.findSome?_append]
theorem findSome?_append {l₁ l₂ : Array α} : (l₁ ++ l₂).findSome? f = (l₁.findSome? f).or (l₂.findSome? f) := by
cases l₁; cases l₂; simp [List.findSome?_append]
theorem getElem?_zero_flatten (xss : Array (Array α)) :
(flatten xss)[0]? = xss.findSome? fun xs => xs[0]? := by
cases xss using array₂_induction
theorem getElem?_zero_flatten (L : Array (Array α)) :
(flatten L)[0]? = L.findSome? fun l => l[0]? := by
cases L using array₂_induction
simp [ List.head?_eq_getElem?, List.head?_flatten, List.findSome?_map, Function.comp_def]
theorem getElem_zero_flatten.proof {xss : Array (Array α)} (h : 0 < xss.flatten.size) :
(xss.findSome? fun xs => xs[0]?).isSome := by
cases xss using array₂_induction
theorem getElem_zero_flatten.proof {L : Array (Array α)} (h : 0 < L.flatten.size) :
(L.findSome? fun l => l[0]?).isSome := by
cases L using array₂_induction
simp only [List.findSome?_toArray, List.findSome?_map, Function.comp_def, List.getElem?_toArray,
List.findSome?_isSome_iff, isSome_getElem?]
simp only [flatten_toArray_map_toArray, List.size_toArray, List.length_flatten,
@@ -93,12 +91,17 @@ theorem getElem_zero_flatten.proof {xss : Array (Array α)} (h : 0 < xss.flatten
obtain _, xs, m, rfl, h := h
exact xs, m, by simpa using h
theorem getElem_zero_flatten {xss : Array (Array α)} (h) :
(flatten xss)[0] = (xss.findSome? fun xs => xs[0]?).get (getElem_zero_flatten.proof h) := by
have t := getElem?_zero_flatten xss
theorem getElem_zero_flatten {L : Array (Array α)} (h) :
(flatten L)[0] = (L.findSome? fun l => l[0]?).get (getElem_zero_flatten.proof h) := by
have t := getElem?_zero_flatten L
simp [getElem?_eq_getElem, h] at t
simp [ t]
theorem back?_flatten {L : Array (Array α)} :
(flatten L).back? = (L.findSomeRev? fun l => l.back?) := by
cases L using array₂_induction
simp [List.getLast?_flatten, List.map_reverse, List.findSome?_map, Function.comp_def]
theorem findSome?_mkArray : findSome? f (mkArray n a) = if n = 0 then none else f a := by
simp [ List.toArray_replicate, List.findSome?_replicate]
@@ -121,16 +124,16 @@ theorem findSome?_mkArray : findSome? f (mkArray n a) = if n = 0 then none else
#[a].find? p = if p a then some a else none := by
simp [singleton_eq_toArray_singleton]
@[simp] theorem findRev?_push_of_pos (xs : Array α) (h : p a) :
findRev? p (xs.push a) = some a := by
cases xs; simp [h]
@[simp] theorem findRev?_push_of_pos (l : Array α) (h : p a) :
findRev? p (l.push a) = some a := by
cases l; simp [h]
@[simp] theorem findRev?_cons_of_neg (xs : Array α) (h : ¬p a) :
findRev? p (xs.push a) = findRev? p xs := by
cases xs; simp [h]
@[simp] theorem findRev?_cons_of_neg (l : Array α) (h : ¬p a) :
findRev? p (l.push a) = findRev? p l := by
cases l; simp [h]
@[simp] theorem find?_eq_none : find? p xs = none x xs, ¬ p x := by
cases xs; simp
@[simp] theorem find?_eq_none : find? p l = none x l, ¬ p x := by
cases l; simp
theorem find?_eq_some_iff_append {xs : Array α} :
xs.find? p = some b p b (as bs : Array α), xs = as.push b ++ bs a as, !p a := by
@@ -139,10 +142,10 @@ theorem find?_eq_some_iff_append {xs : Array α} :
Bool.not_true, exists_and_right, and_congr_right_iff]
intro w
constructor
· rintro as, xs, rfl, h
exact as.toArray, xs.toArray, by simp , by simpa using h
· rintro as, l, h', h
exact as.toList, l, by simpa using congrArg Array.toList h',
· rintro as, x, rfl, h
exact as.toArray, x.toArray, by simp , by simpa using h
· rintro as, x, h', h
exact as.toList, x.toList, by simpa using congrArg Array.toList h',
by simpa using h
@[simp]
@@ -171,22 +174,22 @@ theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
(xs.filter p).find? q = xs.find? (fun a => p a q a) := by
cases xs; simp
@[simp] theorem getElem?_zero_filter (p : α Bool) (xs : Array α) :
(xs.filter p)[0]? = xs.find? p := by
cases xs; simp [ List.head?_eq_getElem?]
@[simp] theorem getElem?_zero_filter (p : α Bool) (l : Array α) :
(l.filter p)[0]? = l.find? p := by
cases l; simp [ List.head?_eq_getElem?]
@[simp] theorem getElem_zero_filter (p : α Bool) (xs : Array α) (h) :
(xs.filter p)[0] =
(xs.find? p).get (by cases xs; simpa [ List.countP_eq_length_filter] using h) := by
cases xs
@[simp] theorem getElem_zero_filter (p : α Bool) (l : Array α) (h) :
(l.filter p)[0] =
(l.find? p).get (by cases l; simpa [ List.countP_eq_length_filter] using h) := by
cases l
simp [List.getElem_zero_eq_head]
@[simp] theorem back?_filter (p : α Bool) (xs : Array α) : (xs.filter p).back? = xs.findRev? p := by
cases xs; simp
@[simp] theorem back?_filter (p : α Bool) (l : Array α) : (l.filter p).back? = l.findRev? p := by
cases l; simp
@[simp] theorem back!_filter [Inhabited α] (p : α Bool) (xs : Array α) :
(xs.filter p).back! = (xs.findRev? p).get! := by
cases xs; simp [Option.get!_eq_getD]
@[simp] theorem back!_filter [Inhabited α] (p : α Bool) (l : Array α) :
(l.filter p).back! = (l.findRev? p).get! := by
cases l; simp [Option.get!_eq_getD]
@[simp] theorem find?_filterMap (xs : Array α) (f : α Option β) (p : β Bool) :
(xs.filterMap f).find? p = (xs.find? (fun a => (f a).any p)).bind f := by
@@ -196,19 +199,19 @@ theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
find? p (xs.map f) = (xs.find? (p f)).map f := by
cases xs; simp
@[simp] theorem find?_append {xs ys : Array α} :
(xs ++ ys).find? p = (xs.find? p).or (ys.find? p) := by
cases xs
cases ys
@[simp] theorem find?_append {l₁ l₂ : Array α} :
(l₁ ++ l₂).find? p = (l₁.find? p).or (l₂.find? p) := by
cases l₁
cases l₂
simp
@[simp] theorem find?_flatten (xss : Array (Array α)) (p : α Bool) :
xss.flatten.find? p = xss.findSome? (·.find? p) := by
cases xss using array₂_induction
@[simp] theorem find?_flatten (xs : Array (Array α)) (p : α Bool) :
xs.flatten.find? p = xs.findSome? (·.find? p) := by
cases xs using array₂_induction
simp [List.findSome?_map, Function.comp_def]
theorem find?_flatten_eq_none_iff {xss : Array (Array α)} {p : α Bool} :
xss.flatten.find? p = none ys xss, x ys, !p x := by
theorem find?_flatten_eq_none_iff {xs : Array (Array α)} {p : α Bool} :
xs.flatten.find? p = none ys xs, x ys, !p x := by
simp
@[deprecated find?_flatten_eq_none_iff (since := "2025-02-03")]
@@ -219,12 +222,12 @@ If `find? p` returns `some a` from `xs.flatten`, then `p a` holds, and
some array in `xs` contains `a`, and no earlier element of that array satisfies `p`.
Moreover, no earlier array in `xs` has an element satisfying `p`.
-/
theorem find?_flatten_eq_some_iff {xss : Array (Array α)} {p : α Bool} {a : α} :
xss.flatten.find? p = some a
theorem find?_flatten_eq_some_iff {xs : Array (Array α)} {p : α Bool} {a : α} :
xs.flatten.find? p = some a
p a (as : Array (Array α)) (ys zs : Array α) (bs : Array (Array α)),
xss = as.push (ys.push a ++ zs) ++ bs
( ws as, x ws, !p x) ( x ys, !p x) := by
cases xss using array₂_induction
xs = as.push (ys.push a ++ zs) ++ bs
( a as, x a, !p x) ( x ys, !p x) := by
cases xs using array₂_induction
simp only [flatten_toArray_map_toArray, List.find?_toArray, List.find?_flatten_eq_some_iff]
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, and_congr_right_iff]
intro w
@@ -299,6 +302,24 @@ theorem find?_eq_some_iff_getElem {xs : Array α} {p : α → Bool} {b : α} :
rcases xs with xs
simp [List.find?_eq_some_iff_getElem]
/-! ### findFinIdx? -/
@[simp] theorem findFinIdx?_empty {p : α Bool} : findFinIdx? p #[] = none := rfl
-- We can't mark this as a `@[congr]` lemma since the head of the RHS is not `findFinIdx?`.
theorem findFinIdx?_congr {p : α Bool} {l₁ : Array α} {l₂ : Array α} (w : l₁ = l₂) :
findFinIdx? p l₁ = (findFinIdx? p l₂).map (fun i => i.cast (by simp [w])) := by
subst w
simp
@[simp] theorem findFinIdx?_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findFinIdx? f = (l.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
cases l
simp only [List.findFinIdx?_toArray, hf, List.findFinIdx?_subtype]
rw [findFinIdx?_congr List.unattach_toArray]
simp [Function.comp_def]
/-! ### findIdx -/
theorem findIdx_of_getElem?_eq_some {xs : Array α} (w : xs[xs.findIdx p]? = some y) : p y := by
@@ -374,21 +395,21 @@ theorem findIdx_eq {p : α → Bool} {xs : Array α} {i : Nat} (h : i < xs.size)
simp at h3
simp_all [not_of_lt_findIdx h3]
theorem findIdx_append (p : α Bool) (xs ys : Array α) :
(xs ++ ys).findIdx p =
if xs.findIdx p < xs.size then xs.findIdx p else ys.findIdx p + xs.size := by
rcases xs with xs
rcases ys with ys
theorem findIdx_append (p : α Bool) (l₁ l₂ : Array α) :
(l₁ ++ l₂).findIdx p =
if l₁.findIdx p < l₁.size then l₁.findIdx p else l₂.findIdx p + l₁.size := by
rcases l₁ with l₁
rcases l₂ with l₂
simp [List.findIdx_append]
theorem findIdx_le_findIdx {xs : Array α} {p q : α Bool} (h : x xs, p x q x) : xs.findIdx q xs.findIdx p := by
rcases xs with xs
theorem findIdx_le_findIdx {l : Array α} {p q : α Bool} (h : x l, p x q x) : l.findIdx q l.findIdx p := by
rcases l with l
simp_all [List.findIdx_le_findIdx]
@[simp] theorem findIdx_subtype {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem findIdx_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
xs.findIdx f = xs.unattach.findIdx g := by
cases xs
l.findIdx f = l.unattach.findIdx g := by
cases l
simp [hf]
theorem false_of_mem_extract_findIdx {xs : Array α} {p : α Bool} (h : x xs.extract 0 (xs.findIdx p)) :
@@ -462,8 +483,8 @@ theorem of_findIdx?_eq_none {xs : Array α} {p : α → Bool} (w : xs.findIdx? p
rcases xs with xs
simpa using List.of_findIdx?_eq_none (by simpa using w)
@[simp] theorem findIdx?_map (f : β α) (xs : Array β) : findIdx? p (xs.map f) = xs.findIdx? (p f) := by
rcases xs with xs
@[simp] theorem findIdx?_map (f : β α) (l : Array β) : findIdx? p (l.map f) = l.findIdx? (p f) := by
rcases l with l
simp [List.findIdx?_map]
@[simp] theorem findIdx?_append :
@@ -473,12 +494,12 @@ theorem of_findIdx?_eq_none {xs : Array α} {p : α → Bool} (w : xs.findIdx? p
rcases ys with ys
simp [List.findIdx?_append]
theorem findIdx?_flatten {xss : Array (Array α)} {p : α Bool} :
xss.flatten.findIdx? p =
(xss.findIdx? (·.any p)).map
fun i => ((xss.take i).map Array.size).sum +
(xss[i]?.map fun xs => xs.findIdx p).getD 0 := by
cases xss using array₂_induction
theorem findIdx?_flatten {l : Array (Array α)} {p : α Bool} :
l.flatten.findIdx? p =
(l.findIdx? (·.any p)).map
fun i => ((l.take i).map Array.size).sum +
(l[i]?.map fun xs => xs.findIdx p).getD 0 := by
cases l using array₂_induction
simp [List.findIdx?_flatten, Function.comp_def]
@[simp] theorem findIdx?_mkArray :
@@ -513,10 +534,10 @@ theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : Array α} {p q : α → Bo
rcases xs with xs
simp [List.findIdx?_eq_some_le_of_findIdx?_eq_some (by simpa using w) (by simpa using h)]
@[simp] theorem findIdx?_subtype {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem findIdx?_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
xs.findIdx? f = xs.unattach.findIdx? g := by
cases xs
l.findIdx? f = l.unattach.findIdx? g := by
cases l
simp [hf]
@[simp] theorem findIdx?_take {xs : Array α} {i : Nat} {p : α Bool} :
@@ -524,55 +545,14 @@ theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : Array α} {p q : α → Bo
cases xs
simp
/-! ### findFinIdx? -/
@[simp] theorem findFinIdx?_empty {p : α Bool} : findFinIdx? p #[] = none := rfl
-- We can't mark this as a `@[congr]` lemma since the head of the RHS is not `findFinIdx?`.
theorem findFinIdx?_congr {p : α Bool} {xs ys : Array α} (w : xs = ys) :
findFinIdx? p xs = (findFinIdx? p ys).map (fun i => i.cast (by simp [w])) := by
subst w
simp
theorem findFinIdx?_eq_pmap_findIdx? {xs : Array α} {p : α Bool} :
xs.findFinIdx? p =
(xs.findIdx? p).pmap
(fun i m => by simp [findIdx?_eq_some_iff_getElem] at m; exact i, m.choose)
(fun i h => h) := by
simp [findIdx?_eq_map_findFinIdx?_val, Option.pmap_map]
@[simp] theorem findFinIdx?_eq_none_iff {xs : Array α} {p : α Bool} :
xs.findFinIdx? p = none x, x xs ¬ p x := by
simp [findFinIdx?_eq_pmap_findIdx?]
@[simp]
theorem findFinIdx?_eq_some_iff {xs : Array α} {p : α Bool} {i : Fin xs.size} :
xs.findFinIdx? p = some i
p xs[i] j (hji : j < i), ¬p (xs[j]'(Nat.lt_trans hji i.2)) := by
simp only [findFinIdx?_eq_pmap_findIdx?, Option.pmap_eq_some_iff, findIdx?_eq_some_iff_getElem,
Bool.not_eq_true, Option.mem_def, exists_and_left, and_exists_self, Fin.getElem_fin]
constructor
· rintro a, h, w₁, w₂, rfl
exact w₁, fun j hji => by simpa using w₂ j hji
· rintro h, w
exact i, i.2, h, fun j hji => w j, by omega hji, rfl
@[simp] theorem findFinIdx?_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
xs.findFinIdx? f = (xs.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
cases xs
simp only [List.findFinIdx?_toArray, hf, List.findFinIdx?_subtype]
rw [findFinIdx?_congr List.unattach_toArray]
simp [Function.comp_def]
/-! ### idxOf
The verification API for `idxOf` is still incomplete.
The lemmas below should be made consistent with those for `findIdx` (and proved using them).
-/
theorem idxOf_append [BEq α] [LawfulBEq α] {xs ys : Array α} {a : α} :
(xs ++ ys).idxOf a = if a xs then xs.idxOf a else ys.idxOf a + xs.size := by
theorem idxOf_append [BEq α] [LawfulBEq α] {l₁ l₂ : Array α} {a : α} :
(l₁ ++ l₂).idxOf a = if a l₁ then l₁.idxOf a else l₂.idxOf a + l₁.size := by
rw [idxOf, findIdx_append]
split <;> rename_i h
· rw [if_pos]
@@ -580,12 +560,12 @@ theorem idxOf_append [BEq α] [LawfulBEq α] {xs ys : Array α} {a : α} :
· rw [if_neg]
simpa using h
theorem idxOf_eq_size [BEq α] [LawfulBEq α] {xs : Array α} (h : a xs) : xs.idxOf a = xs.size := by
rcases xs with xs
theorem idxOf_eq_size [BEq α] [LawfulBEq α] {l : Array α} (h : a l) : l.idxOf a = l.size := by
rcases l with l
simp [List.idxOf_eq_length (by simpa using h)]
theorem idxOf_lt_length [BEq α] [LawfulBEq α] {xs : Array α} (h : a xs) : xs.idxOf a < xs.size := by
rcases xs with xs
theorem idxOf_lt_length [BEq α] [LawfulBEq α] {l : Array α} (h : a l) : l.idxOf a < l.size := by
rcases l with l
simp [List.idxOf_lt_length (by simpa using h)]
@@ -597,31 +577,15 @@ The lemmas below should be made consistent with those for `findIdx?` (and proved
@[simp] theorem idxOf?_empty [BEq α] : (#[] : Array α).idxOf? a = none := rfl
@[simp] theorem idxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
xs.idxOf? a = none a xs := by
rcases xs with xs
@[simp] theorem idxOf?_eq_none_iff [BEq α] [LawfulBEq α] {l : Array α} {a : α} :
l.idxOf? a = none a l := by
rcases l with l
simp [List.idxOf?_eq_none_iff]
/-! ### finIdxOf?
The verification API for `finIdxOf?` is still incomplete.
The lemmas below should be made consistent with those for `findFinIdx?` (and proved using them).
-/
/-! ### finIdxOf? -/
theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : Array α} {a : α} :
xs.idxOf? a = (xs.finIdxOf? a).map (·.val) := by
simp [idxOf?, finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
@[simp] theorem finIdxOf?_empty [BEq α] : (#[] : Array α).finIdxOf? a = none := rfl
@[simp] theorem finIdxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
xs.finIdxOf? a = none a xs := by
rcases xs with xs
simp [List.finIdxOf?_eq_none_iff]
@[simp] theorem finIdxOf?_eq_some_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} {i : Fin xs.size} :
xs.finIdxOf? a = some i xs[i] = a j (_ : j < i), ¬xs[j] = a := by
rcases xs with xs
simp [List.finIdxOf?_eq_some_iff]
end Array

View File

@@ -7,43 +7,40 @@ Authors: Leonardo de Moura
prelude
import Init.Data.Array.Basic
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/-! ### getLit -/
-- auxiliary declaration used in the equation compiler when pattern matching array literals.
abbrev getLit {α : Type u} {n : Nat} (xs : Array α) (i : Nat) (h₁ : xs.size = n) (h₂ : i < n) : α :=
abbrev getLit {α : Type u} {n : Nat} (a : Array α) (i : Nat) (h₁ : a.size = n) (h₂ : i < n) : α :=
have := h₁.symm h₂
xs[i]
a[i]
theorem extLit {n : Nat}
(xs ys : Array α)
(hsz₁ : xs.size = n) (hsz₂ : ys.size = n)
(h : (i : Nat) (hi : i < n) xs.getLit i hsz₁ hi = ys.getLit i hsz₂ hi) : xs = ys :=
Array.ext xs ys (hsz₁.trans hsz₂.symm) fun i hi₁ _ => h i (hsz₁ hi₁)
(a b : Array α)
(hsz₁ : a.size = n) (hsz₂ : b.size = n)
(h : (i : Nat) (hi : i < n) a.getLit i hsz₁ hi = b.getLit i hsz₂ hi) : a = b :=
Array.ext a b (hsz₁.trans hsz₂.symm) fun i hi₁ _ => h i (hsz₁ hi₁)
def toListLitAux (xs : Array α) (n : Nat) (hsz : xs.size = n) : (i : Nat), i xs.size List α List α
def toListLitAux (a : Array α) (n : Nat) (hsz : a.size = n) : (i : Nat), i a.size List α List α
| 0, _, acc => acc
| (i+1), hi, acc => toListLitAux xs n hsz i (Nat.le_of_succ_le hi) (xs.getLit i hsz (Nat.lt_of_lt_of_eq (Nat.lt_of_lt_of_le (Nat.lt_succ_self i) hi) hsz) :: acc)
| (i+1), hi, acc => toListLitAux a n hsz i (Nat.le_of_succ_le hi) (a.getLit i hsz (Nat.lt_of_lt_of_eq (Nat.lt_of_lt_of_le (Nat.lt_succ_self i) hi) hsz) :: acc)
def toArrayLit (xs : Array α) (n : Nat) (hsz : xs.size = n) : Array α :=
List.toArray <| toListLitAux xs n hsz n (hsz Nat.le_refl _) []
def toArrayLit (a : Array α) (n : Nat) (hsz : a.size = n) : Array α :=
List.toArray <| toListLitAux a n hsz n (hsz Nat.le_refl _) []
theorem toArrayLit_eq (xs : Array α) (n : Nat) (hsz : xs.size = n) : xs = toArrayLit xs n hsz := by
theorem toArrayLit_eq (as : Array α) (n : Nat) (hsz : as.size = n) : as = toArrayLit as n hsz := by
apply ext'
simp [toArrayLit, List.toList_toArray]
have hle : n xs.size := hsz Nat.le_refl _
have hge : xs.size n := hsz Nat.le_refl _
have hle : n as.size := hsz Nat.le_refl _
have hge : as.size n := hsz Nat.le_refl _
have := go n hle
rw [List.drop_eq_nil_of_le hge] at this
rw [this]
where
getLit_eq (xs : Array α) (i : Nat) (h₁ : xs.size = n) (h₂ : i < n) : xs.getLit i h₁ h₂ = getElem xs.toList i ((id (α := xs.toList.length = n) h₁) h₂) :=
getLit_eq (as : Array α) (i : Nat) (h₁ : as.size = n) (h₂ : i < n) : as.getLit i h₁ h₂ = getElem as.toList i ((id (α := as.toList.length = n) h₁) h₂) :=
rfl
go (i : Nat) (hi : i xs.size) : toListLitAux xs n hsz i hi (xs.toList.drop i) = xs.toList := by
go (i : Nat) (hi : i as.size) : toListLitAux as n hsz i hi (as.toList.drop i) = as.toList := by
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.getElem_cons_drop_succ_eq_drop, *]
end Array

View File

@@ -13,9 +13,6 @@ import Init.Data.List.Nat.InsertIdx
Proves various lemmas about `Array.insertIdx`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Function
open Nat
@@ -30,23 +27,23 @@ section InsertIdx
variable {a : α}
@[simp] theorem toList_insertIdx (xs : Array α) (i x) (h) :
(xs.insertIdx i x h).toList = xs.toList.insertIdx i x := by
rcases xs with xs
@[simp] theorem toList_insertIdx (a : Array α) (i x) (h) :
(a.insertIdx i x h).toList = a.toList.insertIdx i x := by
rcases a with a
simp
@[simp]
theorem insertIdx_zero (xs : Array α) (x : α) : xs.insertIdx 0 x = #[x] ++ xs := by
rcases xs with xs
theorem insertIdx_zero (s : Array α) (x : α) : s.insertIdx 0 x = #[x] ++ s := by
cases s
simp
@[simp] theorem size_insertIdx {xs : Array α} (h : i xs.size) : (xs.insertIdx i a).size = xs.size + 1 := by
rcases xs with xs
@[simp] theorem size_insertIdx {as : Array α} (h : n as.size) : (as.insertIdx n a).size = as.size + 1 := by
cases as
simp [List.length_insertIdx, h]
theorem eraseIdx_insertIdx (i : Nat) (xs : Array α) (h : i xs.size) :
(xs.insertIdx i a).eraseIdx i (by simp; omega) = xs := by
rcases xs with xs
theorem eraseIdx_insertIdx (i : Nat) (l : Array α) (h : i l.size) :
(l.insertIdx i a).eraseIdx i (by simp; omega) = l := by
cases l
simp_all
theorem insertIdx_eraseIdx_of_ge {as : Array α}
@@ -63,68 +60,68 @@ theorem insertIdx_eraseIdx_of_le {as : Array α}
cases as
simpa using List.insertIdx_eraseIdx_of_le _ _ _ (by simpa) (by simpa)
theorem insertIdx_comm (a b : α) (i j : Nat) (xs : Array α) (_ : i j) (_ : j xs.size) :
(xs.insertIdx i a).insertIdx (j + 1) b (by simpa) =
(xs.insertIdx j b).insertIdx i a (by simp; omega) := by
rcases xs with xs
theorem insertIdx_comm (a b : α) (i j : Nat) (l : Array α) (_ : i j) (_ : j l.size) :
(l.insertIdx i a).insertIdx (j + 1) b (by simpa) =
(l.insertIdx j b).insertIdx i a (by simp; omega) := by
cases l
simpa using List.insertIdx_comm a b i j _ (by simpa) (by simpa)
theorem mem_insertIdx {xs : Array α} {h : i xs.size} : a xs.insertIdx i b h a = b a xs := by
rcases xs with xs
theorem mem_insertIdx {l : Array α} {h : i l.size} : a l.insertIdx i b h a = b a l := by
cases l
simpa using List.mem_insertIdx (by simpa)
@[simp]
theorem insertIdx_size_self (xs : Array α) (x : α) : xs.insertIdx xs.size x = xs.push x := by
rcases xs with xs
theorem insertIdx_size_self (l : Array α) (x : α) : l.insertIdx l.size x = l.push x := by
cases l
simp
theorem getElem_insertIdx {xs : Array α} {x : α} {i k : Nat} (w : i xs.size) (h : k < (xs.insertIdx i x).size) :
(xs.insertIdx i x)[k] =
theorem getElem_insertIdx {as : Array α} {x : α} {i k : Nat} (w : i as.size) (h : k < (as.insertIdx i x).size) :
(as.insertIdx i x)[k] =
if h₁ : k < i then
xs[k]'(by simp [size_insertIdx] at h; omega)
as[k]'(by simp [size_insertIdx] at h; omega)
else
if h₂ : k = i then
x
else
xs[k-1]'(by simp [size_insertIdx] at h; omega) := by
cases xs
as[k-1]'(by simp [size_insertIdx] at h; omega) := by
cases as
simp [List.getElem_insertIdx, w]
theorem getElem_insertIdx_of_lt {xs : Array α} {x : α} {i k : Nat} (w : i xs.size) (h : k < i) :
(xs.insertIdx i x)[k]'(by simp; omega) = xs[k] := by
theorem getElem_insertIdx_of_lt {as : Array α} {x : α} {i k : Nat} (w : i as.size) (h : k < i) :
(as.insertIdx i x)[k]'(by simp; omega) = as[k] := by
simp [getElem_insertIdx, w, h]
theorem getElem_insertIdx_self {xs : Array α} {x : α} {i : Nat} (w : i xs.size) :
(xs.insertIdx i x)[i]'(by simp; omega) = x := by
theorem getElem_insertIdx_self {as : Array α} {x : α} {i : Nat} (w : i as.size) :
(as.insertIdx i x)[i]'(by simp; omega) = x := by
simp [getElem_insertIdx, w]
theorem getElem_insertIdx_of_gt {xs : Array α} {x : α} {i k : Nat} (w : k xs.size) (h : k > i) :
(xs.insertIdx i x)[k]'(by simp; omega) = xs[k - 1]'(by omega) := by
theorem getElem_insertIdx_of_gt {as : Array α} {x : α} {i k : Nat} (w : k as.size) (h : k > i) :
(as.insertIdx i x)[k]'(by simp; omega) = as[k - 1]'(by omega) := by
simp [getElem_insertIdx, w, h]
rw [dif_neg (by omega), dif_neg (by omega)]
theorem getElem?_insertIdx {xs : Array α} {x : α} {i k : Nat} (h : i xs.size) :
(xs.insertIdx i x)[k]? =
theorem getElem?_insertIdx {l : Array α} {x : α} {i k : Nat} (h : i l.size) :
(l.insertIdx i x)[k]? =
if k < i then
xs[k]?
l[k]?
else
if k = i then
if k xs.size then some x else none
if k l.size then some x else none
else
xs[k-1]? := by
cases xs
l[k-1]? := by
cases l
simp [List.getElem?_insertIdx, h]
theorem getElem?_insertIdx_of_lt {xs : Array α} {x : α} {i k : Nat} (w : i xs.size) (h : k < i) :
(xs.insertIdx i x)[k]? = xs[k]? := by
theorem getElem?_insertIdx_of_lt {l : Array α} {x : α} {i k : Nat} (w : i l.size) (h : k < i) :
(l.insertIdx i x)[k]? = l[k]? := by
rw [getElem?_insertIdx, if_pos h]
theorem getElem?_insertIdx_self {xs : Array α} {x : α} {i : Nat} (w : i xs.size) :
(xs.insertIdx i x)[i]? = some x := by
theorem getElem?_insertIdx_self {l : Array α} {x : α} {i : Nat} (w : i l.size) :
(l.insertIdx i x)[i]? = some x := by
rw [getElem?_insertIdx, if_neg (by omega), if_pos rfl, if_pos w]
theorem getElem?_insertIdx_of_ge {xs : Array α} {x : α} {i k : Nat} (w : i < k) (h : k xs.size) :
(xs.insertIdx i x)[k]? = xs[k - 1]? := by
theorem getElem?_insertIdx_of_ge {l : Array α} {x : α} {i k : Nat} (w : i < k) (h : k l.size) :
(l.insertIdx i x)[k]? = l[k - 1]? := by
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
end InsertIdx

View File

@@ -6,26 +6,23 @@ Authors: Leonardo de Moura
prelude
import Init.Data.Array.Basic
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
@[inline] def Array.insertionSort (xs : Array α) (lt : α α Bool := by exact (· < ·)) : Array α :=
traverse xs 0 xs.size
@[inline] def Array.insertionSort (a : Array α) (lt : α α Bool := by exact (· < ·)) : Array α :=
traverse a 0 a.size
where
@[specialize] traverse (xs : Array α) (i : Nat) (fuel : Nat) : Array α :=
@[specialize] traverse (a : Array α) (i : Nat) (fuel : Nat) : Array α :=
match fuel with
| 0 => xs
| 0 => a
| fuel+1 =>
if h : i < xs.size then
traverse (swapLoop xs i h) (i+1) fuel
if h : i < a.size then
traverse (swapLoop a i h) (i+1) fuel
else
xs
@[specialize] swapLoop (xs : Array α) (j : Nat) (h : j < xs.size) : Array α :=
a
@[specialize] swapLoop (a : Array α) (j : Nat) (h : j < a.size) : Array α :=
match (generalizing := false) he:j with -- using `generalizing` because we don't want to refine the type of `h`
| 0 => xs
| 0 => a
| j'+1 =>
have h' : j' < xs.size := by subst j; exact Nat.lt_trans (Nat.lt_succ_self _) h
if lt xs[j] xs[j'] then
swapLoop (xs.swap j j') j' (by rw [size_swap]; assumption; done)
have h' : j' < a.size := by subst j; exact Nat.lt_trans (Nat.lt_succ_self _) h
if lt a[j] a[j'] then
swapLoop (a.swap j j') j' (by rw [size_swap]; assumption; done)
else
xs
a

File diff suppressed because it is too large Load Diff

View File

@@ -8,8 +8,8 @@ import Init.Data.Array.Basic
import Init.Data.Nat.Lemmas
import Init.Data.Range
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array

View File

@@ -7,9 +7,6 @@ prelude
import Init.Data.Array.Lemmas
import Init.Data.List.Lex
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/-! ### Lexicographic ordering -/
@@ -17,15 +14,15 @@ namespace Array
@[simp] theorem _root_.List.lt_toArray [LT α] (l₁ l₂ : List α) : l₁.toArray < l₂.toArray l₁ < l₂ := Iff.rfl
@[simp] theorem _root_.List.le_toArray [LT α] (l₁ l₂ : List α) : l₁.toArray l₂.toArray l₁ l₂ := Iff.rfl
@[simp] theorem lt_toList [LT α] (xs ys : Array α) : xs.toList < ys.toList xs < ys := Iff.rfl
@[simp] theorem le_toList [LT α] (xs ys : Array α) : xs.toList ys.toList xs ys := Iff.rfl
@[simp] theorem lt_toList [LT α] (l₁ l₂ : Array α) : l₁.toList < l₂.toList l₁ < l₂ := Iff.rfl
@[simp] theorem le_toList [LT α] (l₁ l₂ : Array α) : l₁.toList l₂.toList l₁ l₂ := Iff.rfl
protected theorem not_lt_iff_ge [LT α] (l₁ l₂ : List α) : ¬ l₁ < l₂ l₂ l₁ := Iff.rfl
protected theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] (l₁ l₂ : List α) :
¬ l₁ l₂ l₂ < l₁ :=
Decidable.not_not
@[simp] theorem lex_empty [BEq α] {lt : α α Bool} (xs : Array α) : xs.lex #[] lt = false := by
@[simp] theorem lex_empty [BEq α] {lt : α α Bool} (l : Array α) : l.lex #[] lt = false := by
simp [lex, Id.run]
@[simp] theorem singleton_lex_singleton [BEq α] {lt : α α Bool} : #[a].lex #[b] lt = lt a b := by
@@ -55,35 +52,35 @@ private theorem cons_lex_cons [BEq α] {lt : αα → Bool} {a b : α} {xs
| cons y l₂ =>
rw [List.toArray_cons, List.toArray_cons y, cons_lex_cons, List.lex, ih]
@[simp] theorem lex_toList [BEq α] (lt : α α Bool) (xs ys : Array α) :
xs.toList.lex ys.toList lt = xs.lex ys lt := by
cases xs <;> cases ys <;> simp
@[simp] theorem lex_toList [BEq α] (lt : α α Bool) (l₁ l₂ : Array α) :
l₁.toList.lex l₂.toList lt = l₁.lex l₂ lt := by
cases l₁ <;> cases l₂ <;> simp
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α α Prop)] (xs : Array α) : ¬ xs < xs :=
List.lt_irrefl xs.toList
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α α Prop)] (l : Array α) : ¬ l < l :=
List.lt_irrefl l.toList
instance ltIrrefl [LT α] [Std.Irrefl (· < · : α α Prop)] : Std.Irrefl (α := Array α) (· < ·) where
irrefl := Array.lt_irrefl
@[simp] theorem not_lt_empty [LT α] (xs : Array α) : ¬ xs < #[] := List.not_lt_nil xs.toList
@[simp] theorem empty_le [LT α] (xs : Array α) : #[] xs := List.nil_le xs.toList
@[simp] theorem not_lt_empty [LT α] (l : Array α) : ¬ l < #[] := List.not_lt_nil l.toList
@[simp] theorem empty_le [LT α] (l : Array α) : #[] l := List.nil_le l.toList
@[simp] theorem le_empty [LT α] (xs : Array α) : xs #[] xs = #[] := by
cases xs
@[simp] theorem le_empty [LT α] (l : Array α) : l #[] l = #[] := by
cases l
simp
@[simp] theorem empty_lt_push [LT α] (xs : Array α) (a : α) : #[] < xs.push a := by
rcases xs with (_ | x, xs) <;> simp
@[simp] theorem empty_lt_push [LT α] (l : Array α) (a : α) : #[] < l.push a := by
rcases l with (_ | x, l) <;> simp
protected theorem le_refl [LT α] [i₀ : Std.Irrefl (· < · : α α Prop)] (xs : Array α) : xs xs :=
List.le_refl xs.toList
protected theorem le_refl [LT α] [i₀ : Std.Irrefl (· < · : α α Prop)] (l : Array α) : l l :=
List.le_refl l.toList
instance [LT α] [Std.Irrefl (· < · : α α Prop)] : Std.Refl (· · : Array α Array α Prop) where
refl := Array.le_refl
protected theorem lt_trans [LT α]
[i₁ : Trans (· < · : α α Prop) (· < ·) (· < ·)]
{xs ys zs : Array α} (h₁ : xs < ys) (h₂ : ys < zs) : xs < zs :=
{l₁ l₂ l₃ : Array α} (h₁ : l₁ < l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
List.lt_trans h₁ h₂
instance [LT α] [Trans (· < · : α α Prop) (· < ·) (· < ·)] :
@@ -95,7 +92,7 @@ protected theorem lt_of_le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
[i₃ : Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{xs ys zs : Array α} (h₁ : xs ys) (h₂ : ys < zs) : xs < zs :=
{l₁ l₂ l₃ : Array α} (h₁ : l₁ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
List.lt_of_le_of_lt h₁ h₂
protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
@@ -103,7 +100,7 @@ protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{xs ys zs : Array α} (h₁ : xs ys) (h₂ : ys zs) : xs zs :=
{l₁ l₂ l₃ : Array α} (h₁ : l₁ l₂) (h₂ : l₂ l₃) : l₁ l₃ :=
fun h₃ => h₁ (Array.lt_of_le_of_lt h₂ h₃)
instance [DecidableEq α] [LT α] [DecidableLT α]
@@ -116,7 +113,7 @@ instance [DecidableEq α] [LT α] [DecidableLT α]
protected theorem lt_asymm [LT α]
[i : Std.Asymm (· < · : α α Prop)]
{xs ys : Array α} (h : xs < ys) : ¬ ys < xs := List.lt_asymm h
{l₁ l₂ : Array α} (h : l₁ < l₂) : ¬ l₂ < l₁ := List.lt_asymm h
instance [DecidableEq α] [LT α] [DecidableLT α]
[Std.Asymm (· < · : α α Prop)] :
@@ -124,26 +121,26 @@ instance [DecidableEq α] [LT α] [DecidableLT α]
asymm _ _ := Array.lt_asymm
protected theorem le_total [DecidableEq α] [LT α] [DecidableLT α]
[i : Std.Total (¬ · < · : α α Prop)] (xs ys : Array α) : xs ys ys xs :=
List.le_total xs.toList ys.toList
[i : Std.Total (¬ · < · : α α Prop)] (l₁ l₂ : Array α) : l₁ l₂ l₂ l₁ :=
List.le_total _ _
@[simp] protected theorem not_lt [LT α]
{xs ys : Array α} : ¬ xs < ys ys xs := Iff.rfl
{l₁ l₂ : Array α} : ¬ l₁ < l₂ l₂ l₁ := Iff.rfl
@[simp] protected theorem not_le [DecidableEq α] [LT α] [DecidableLT α]
{xs ys : Array α} : ¬ ys xs xs < ys := Decidable.not_not
{l₁ l₂ : Array α} : ¬ l₂ l₁ l₁ < l₂ := Decidable.not_not
protected theorem le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
[i : Std.Total (¬ · < · : α α Prop)]
{xs ys : Array α} (h : xs < ys) : xs ys :=
{l₁ l₂ : Array α} (h : l₁ < l₂) : l₁ l₂ :=
List.le_of_lt h
protected theorem le_iff_lt_or_eq [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Std.Total (¬ · < · : α α Prop)]
{xs ys : Array α} : xs ys xs < ys xs = ys := by
simpa using List.le_iff_lt_or_eq (l₁ := xs.toList) (l₂ := ys.toList)
{l₁ l₂ : Array α} : l₁ l₂ l₁ < l₂ l₁ = l₂ := by
simpa using List.le_iff_lt_or_eq (l₁ := l₁.toList) (l₂ := l₂.toList)
instance [DecidableEq α] [LT α] [DecidableLT α]
[Std.Total (¬ · < · : α α Prop)] :
@@ -151,22 +148,22 @@ instance [DecidableEq α] [LT α] [DecidableLT α]
total := Array.le_total
@[simp] theorem lex_eq_true_iff_lt [DecidableEq α] [LT α] [DecidableLT α]
{xs ys : Array α} : lex xs ys = true xs < ys := by
cases xs
cases ys
{l₁ l₂ : Array α} : lex l₁ l₂ = true l₁ < l₂ := by
cases l₁
cases l₂
simp
@[simp] theorem lex_eq_false_iff_ge [DecidableEq α] [LT α] [DecidableLT α]
{xs ys : Array α} : lex xs ys = false ys xs := by
cases xs
cases ys
{l₁ l₂ : Array α} : lex l₁ l₂ = false l₂ l₁ := by
cases l₁
cases l₂
simp [List.not_lt_iff_ge]
instance [DecidableEq α] [LT α] [DecidableLT α] : DecidableLT (Array α) :=
fun xs ys => decidable_of_iff (lex xs ys = true) lex_eq_true_iff_lt
fun l₁ l₂ => decidable_of_iff (lex l₁ l₂ = true) lex_eq_true_iff_lt
instance [DecidableEq α] [LT α] [DecidableLT α] : DecidableLE (Array α) :=
fun xs ys => decidable_of_iff (lex ys xs = false) lex_eq_false_iff_ge
fun l₁ l₂ => decidable_of_iff (lex l₂ l₁ = false) lex_eq_false_iff_ge
/--
`l₁` is lexicographically less than `l₂` if either
@@ -214,58 +211,58 @@ theorem lex_eq_false_iff_exists [BEq α] [PartialEquivBEq α] (lt : αα
cases l₂
simp_all [List.lex_eq_false_iff_exists]
protected theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {xs ys : Array α} :
xs < ys
(xs = ys.take xs.size xs.size < ys.size)
( (i : Nat) (h₁ : i < xs.size) (h₂ : i < ys.size),
protected theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {l₁ l₂ : Array α} :
l₁ < l₂
(l₁ = l₂.take l₁.size l₁.size < l₂.size)
( (i : Nat) (h₁ : i < l₁.size) (h₂ : i < l₂.size),
( j, (hj : j < i)
xs[j]'(Nat.lt_trans hj h₁) = ys[j]'(Nat.lt_trans hj h₂)) xs[i] < ys[i]) := by
cases xs
cases ys
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) l₁[i] < l₂[i]) := by
cases l₁
cases l₂
simp [List.lt_iff_exists]
protected theorem le_iff_exists [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)] {xs ys : Array α} :
xs ys
(xs = ys.take xs.size)
( (i : Nat) (h₁ : i < xs.size) (h₂ : i < ys.size),
[Std.Antisymm (¬ · < · : α α Prop)] {l₁ l₂ : Array α} :
l₁ l₂
(l₁ = l₂.take l₁.size)
( (i : Nat) (h₁ : i < l₁.size) (h₂ : i < l₂.size),
( j, (hj : j < i)
xs[j]'(Nat.lt_trans hj h₁) = ys[j]'(Nat.lt_trans hj h₂)) xs[i] < ys[i]) := by
cases xs
cases ys
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) l₁[i] < l₂[i]) := by
cases l₁
cases l₂
simp [List.le_iff_exists]
theorem append_left_lt [LT α] {xs ys zs : Array α} (h : ys < zs) :
xs ++ ys < xs ++ zs := by
cases xs
cases ys
cases zs
theorem append_left_lt [LT α] {l₁ l₂ l₃ : Array α} (h : l₂ < l₃) :
l₁ ++ l₂ < l₁ ++ l₃ := by
cases l₁
cases l₂
cases l₃
simpa using List.append_left_lt h
theorem append_left_le [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
{xs ys zs : Array α} (h : ys zs) :
xs ++ ys xs ++ zs := by
cases xs
cases ys
cases zs
{l₁ l₂ l₃ : Array α} (h : l₂ l₃) :
l₁ ++ l₂ l₁ ++ l₃ := by
cases l₁
cases l₂
cases l₃
simpa using List.append_left_le h
theorem le_append_left [LT α] [Std.Irrefl (· < · : α α Prop)]
{xs ys : Array α} : xs xs ++ ys := by
cases xs
cases ys
{l₁ l₂ : Array α} : l₁ l₁ ++ l₂ := by
cases l₁
cases l₂
simpa using List.le_append_left
protected theorem map_lt [LT α] [LT β]
{xs ys : Array α} {f : α β} (w : x y, x < y f x < f y) (h : xs < ys) :
map f xs < map f ys := by
cases xs
cases ys
{l₁ l₂ : Array α} {f : α β} (w : x y, x < y f x < f y) (h : l₁ < l₂) :
map f l₁ < map f l₂ := by
cases l₁
cases l₂
simpa using List.map_lt w h
protected theorem map_le [DecidableEq α] [LT α] [DecidableLT α] [DecidableEq β] [LT β] [DecidableLT β]
@@ -275,10 +272,10 @@ protected theorem map_le [DecidableEq α] [LT α] [DecidableLT α] [DecidableEq
[Std.Irrefl (· < · : β β Prop)]
[Std.Asymm (· < · : β β Prop)]
[Std.Antisymm (¬ · < · : β β Prop)]
{xs ys : Array α} {f : α β} (w : x y, x < y f x < f y) (h : xs ys) :
map f xs map f ys := by
cases xs
cases ys
{l₁ l₂ : Array α} {f : α β} (w : x y, x < y f x < f y) (h : l₁ l₂) :
map f l₁ map f l₂ := by
cases l₁
cases l₂
simpa using List.map_le w h
end Array

View File

@@ -8,29 +8,26 @@ import Init.Data.Array.Lemmas
import Init.Data.Array.Attach
import Init.Data.List.MapIdx
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/-! ### mapFinIdx -/
-- This could also be proved from `SatisfiesM_mapIdxM` in Batteries.
theorem mapFinIdx_induction (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β)
theorem mapFinIdx_induction (as : Array α) (f : (i : Nat) α (h : i < as.size) β)
(motive : Nat Prop) (h0 : motive 0)
(p : (i : Nat) β (h : i < xs.size) Prop)
(hs : i h, motive i p i (f i xs[i] h) h motive (i + 1)) :
motive xs.size eq : (Array.mapFinIdx xs f).size = xs.size,
i h, p i ((Array.mapFinIdx xs f)[i]) h := by
(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 ((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 as : Array β := Array.mapFinIdxM.map (m := Id) xs f i j h bs
motive xs.size eq : as.size = xs.size, i h, p i as[i] h := by
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 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 xs[j] (by omega))) (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
@@ -41,67 +38,67 @@ theorem mapFinIdx_induction (xs : Array α) (f : (i : Nat) → α → (h : i < x
· exact (hs j (by omega) hm).2
simp [mapFinIdx, mapFinIdxM]; exact go rfl nofun h0
theorem mapFinIdx_spec (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β)
(p : (i : Nat) β (h : i < xs.size) Prop) (hs : i h, p i (f i xs[i] h) h) :
eq : (Array.mapFinIdx xs f).size = xs.size,
i h, p i ((Array.mapFinIdx xs f)[i]) h :=
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 ((Array.mapFinIdx as f)[i]) h :=
(mapFinIdx_induction _ _ (fun _ => True) trivial p fun _ _ _ => hs .., trivial).2
@[simp] theorem size_mapFinIdx (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β) :
(xs.mapFinIdx f).size = xs.size :=
@[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_zipIdx (xs : Array α) (k : Nat) : (xs.zipIdx k).size = xs.size :=
@[simp] theorem size_zipIdx (as : Array α) (k : Nat) : (as.zipIdx k).size = as.size :=
Array.size_mapFinIdx _ _
@[deprecated size_zipIdx (since := "2025-01-21")] abbrev size_zipWithIndex := @size_zipIdx
@[simp] theorem getElem_mapFinIdx (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β) (i : Nat)
(h : i < (xs.mapFinIdx f).size) :
(xs.mapFinIdx f)[i] = f i (xs[i]'(by simp_all)) (by simp_all) :=
(mapFinIdx_spec _ _ (fun i b h => b = f i xs[i] h) fun _ _ => rfl).2 i _
@[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 (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 (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β) (i : Nat) :
(xs.mapFinIdx f)[i]? =
xs[i]?.pbind fun b h => f i b (getElem?_eq_some_iff.1 h).1 := by
@[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 b (getElem?_eq_some_iff.1 h).1 := by
simp only [getElem?_def, size_mapFinIdx, getElem_mapFinIdx]
split <;> simp_all
@[simp] theorem toList_mapFinIdx (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β) :
(xs.mapFinIdx f).toList = xs.toList.mapFinIdx (fun i a h => f i a (by simpa)) := 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 α β) (xs : Array α)
theorem mapIdx_induction (f : Nat α β) (as : Array α)
(motive : Nat Prop) (h0 : motive 0)
(p : (i : Nat) β (h : i < xs.size) Prop)
(hs : i h, motive i p i (f i xs[i]) h motive (i + 1)) :
motive xs.size eq : (xs.mapIdx f).size = xs.size,
i h, p i ((xs.mapIdx f)[i]) h :=
mapFinIdx_induction xs (fun i a _ => f i a) motive h0 p hs
(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 ((as.mapIdx f)[i]) h :=
mapFinIdx_induction as (fun i a _ => f i a) motive h0 p hs
theorem mapIdx_spec (f : Nat α β) (xs : Array α)
(p : (i : Nat) β (h : i < xs.size) Prop) (hs : i h, p i (f i xs[i]) h) :
eq : (xs.mapIdx f).size = xs.size,
i h, p i ((xs.mapIdx f)[i]) h :=
theorem mapIdx_spec (f : Nat α β) (as : Array α)
(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 ((as.mapIdx f)[i]) h :=
(mapIdx_induction _ _ (fun _ => True) trivial p fun _ _ _ => hs .., trivial).2
@[simp] theorem size_mapIdx (f : Nat α β) (xs : Array α) : (xs.mapIdx f).size = xs.size :=
@[simp] theorem size_mapIdx (f : Nat α β) (as : Array α) : (as.mapIdx f).size = as.size :=
(mapIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
@[simp] theorem getElem_mapIdx (f : Nat α β) (xs : Array α) (i : Nat)
(h : i < (xs.mapIdx f).size) :
(xs.mapIdx f)[i] = f i (xs[i]'(by simp_all)) :=
(mapIdx_spec _ _ (fun i b h => b = f i xs[i]) fun _ _ => rfl).2 i (by simp_all)
@[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 h => b = f i as[i]) fun _ _ => rfl).2 i (by simp_all)
@[simp] theorem getElem?_mapIdx (f : Nat α β) (xs : Array α) (i : Nat) :
(xs.mapIdx f)[i]? =
xs[i]?.map (f i) := by
@[simp] theorem getElem?_mapIdx (f : Nat α β) (as : Array α) (i : Nat) :
(as.mapIdx f)[i]? =
as[i]?.map (f i) := by
simp [getElem?_def, size_mapIdx, getElem_mapIdx]
@[simp] theorem toList_mapIdx (f : Nat α β) (xs : Array α) :
(xs.mapIdx f).toList = xs.toList.mapIdx (fun i a => f i a) := by
@[simp] theorem toList_mapIdx (f : Nat α β) (as : Array α) :
(as.mapIdx f).toList = as.toList.mapIdx (fun i a => f i a) := by
apply List.ext_getElem <;> simp
end Array
@@ -122,8 +119,8 @@ namespace Array
/-! ### zipIdx -/
@[simp] theorem getElem_zipIdx (xs : Array α) (k : Nat) (i : Nat) (h : i < (xs.zipIdx k).size) :
(xs.zipIdx k)[i] = (xs[i]'(by simp_all), k + i) := by
@[simp] theorem getElem_zipIdx (a : Array α) (k : Nat) (i : Nat) (h : i < (a.zipIdx k).size) :
(a.zipIdx k)[i] = (a[i]'(by simp_all), k + i) := by
simp [zipIdx]
@[deprecated getElem_zipIdx (since := "2025-01-21")]
@@ -136,35 +133,35 @@ abbrev getElem_zipWithIndex := @getElem_zipIdx
@[deprecated zipIdx_toArray (since := "2025-01-21")]
abbrev zipWithIndex_toArray := @zipIdx_toArray
@[simp] theorem toList_zipIdx (xs : Array α) (k : Nat) :
(xs.zipIdx k).toList = xs.toList.zipIdx k := by
rcases xs with xs
@[simp] theorem toList_zipIdx (a : Array α) (k : Nat) :
(a.zipIdx k).toList = a.toList.zipIdx k := by
rcases a with a
simp
@[deprecated toList_zipIdx (since := "2025-01-21")]
abbrev toList_zipWithIndex := @toList_zipIdx
theorem mk_mem_zipIdx_iff_le_and_getElem?_sub {k i : Nat} {x : α} {xs : Array α} :
(x, i) xs.zipIdx k k i xs[i - k]? = some x := by
rcases xs with xs
theorem mk_mem_zipIdx_iff_le_and_getElem?_sub {k i : Nat} {x : α} {l : Array α} :
(x, i) zipIdx l k k i l[i - k]? = some x := by
rcases l with l
simp [List.mk_mem_zipIdx_iff_le_and_getElem?_sub]
/-- Variant of `mk_mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
to avoid the inequality and the subtraction. -/
theorem mk_mem_zipIdx_iff_getElem? {x : α} {i : Nat} {xs : Array α} :
(x, i) xs.zipIdx xs[i]? = x := by
theorem mk_mem_zipIdx_iff_getElem? {x : α} {i : Nat} {l : Array α} :
(x, i) l.zipIdx l[i]? = x := by
rw [mk_mem_zipIdx_iff_le_and_getElem?_sub]
simp
theorem mem_zipIdx_iff_le_and_getElem?_sub {x : α × Nat} {xs : Array α} {k : Nat} :
x xs.zipIdx k k x.2 xs[x.2 - k]? = some x.1 := by
theorem mem_zipIdx_iff_le_and_getElem?_sub {x : α × Nat} {l : Array α} {k : Nat} :
x zipIdx l k k x.2 l[x.2 - k]? = some x.1 := by
cases x
simp [mk_mem_zipIdx_iff_le_and_getElem?_sub]
/-- Variant of `mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
to avoid the inequality and the subtraction. -/
theorem mem_zipIdx_iff_getElem? {x : α × Nat} {xs : Array α} :
x xs.zipIdx xs[x.2]? = some x.1 := by
theorem mem_zipIdx_iff_getElem? {x : α × Nat} {l : Array α} :
x l.zipIdx l[x.2]? = some x.1 := by
rw [mk_mem_zipIdx_iff_getElem?]
@[deprecated mk_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
@@ -185,31 +182,31 @@ abbrev mem_zipWithIndex_iff_getElem? := @mem_zipIdx_iff_getElem?
theorem mapFinIdx_empty {f : (i : Nat) α (h : i < 0) β} : mapFinIdx #[] f = #[] :=
rfl
theorem mapFinIdx_eq_ofFn {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = Array.ofFn fun i : Fin xs.size => f i xs[i] i.2 := by
cases xs
theorem mapFinIdx_eq_ofFn {as : Array α} {f : (i : Nat) α (h : i < as.size) β} :
as.mapFinIdx f = Array.ofFn fun i : Fin as.size => f i as[i] i.2 := by
cases as
simp [List.mapFinIdx_eq_ofFn]
theorem mapFinIdx_append {xs ys : Array α} {f : (i : Nat) α (h : i < (xs ++ ys).size) β} :
(xs ++ ys).mapFinIdx f =
xs.mapFinIdx (fun i a h => f i a (by simp; omega)) ++
ys.mapFinIdx (fun i a h => f (i + xs.size) a (by simp; omega)) := by
cases xs
cases ys
theorem mapFinIdx_append {K L : Array α} {f : (i : Nat) α (h : i < (K ++ L).size) β} :
(K ++ L).mapFinIdx f =
K.mapFinIdx (fun i a h => f i a (by simp; omega)) ++
L.mapFinIdx (fun i a h => f (i + K.size) a (by simp; omega)) := by
cases K
cases L
simp [List.mapFinIdx_append]
@[simp]
theorem mapFinIdx_push {xs : Array α} {a : α} {f : (i : Nat) α (h : i < (xs.push a).size) β} :
mapFinIdx (xs.push a) f =
(mapFinIdx xs (fun i a h => f i a (by simp; omega))).push (f xs.size a (by simp)) := by
theorem mapFinIdx_push {l : Array α} {a : α} {f : (i : Nat) α (h : i < (l.push a).size) β} :
mapFinIdx (l.push a) f =
(mapFinIdx l (fun i a h => f i a (by simp; omega))).push (f l.size a (by simp)) := by
simp [ append_singleton, mapFinIdx_append]
theorem mapFinIdx_singleton {a : α} {f : (i : Nat) α (h : i < 1) β} :
#[a].mapFinIdx f = #[f 0 a (by simp)] := by
simp
theorem mapFinIdx_eq_zipIdx_map {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = xs.zipIdx.attach.map
theorem mapFinIdx_eq_zipIdx_map {l : Array α} {f : (i : Nat) α (h : i < l.size) β} :
l.mapFinIdx f = l.zipIdx.attach.map
fun x, i, m =>
f i x (by simp [mk_mem_zipIdx_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1) := by
ext <;> simp
@@ -218,44 +215,44 @@ theorem mapFinIdx_eq_zipIdx_map {xs : Array α} {f : (i : Nat) → α → (h : i
abbrev mapFinIdx_eq_zipWithIndex_map := @mapFinIdx_eq_zipIdx_map
@[simp]
theorem mapFinIdx_eq_empty_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = #[] xs = #[] := by
cases xs
theorem mapFinIdx_eq_empty_iff {l : Array α} {f : (i : Nat) α (h : i < l.size) β} :
l.mapFinIdx f = #[] l = #[] := by
cases l
simp
theorem mapFinIdx_ne_empty_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f #[] xs #[] := by
theorem mapFinIdx_ne_empty_iff {l : Array α} {f : (i : Nat) α (h : i < l.size) β} :
l.mapFinIdx f #[] l #[] := by
simp
theorem exists_of_mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β}
(h : b xs.mapFinIdx f) : (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
rcases xs with xs
theorem exists_of_mem_mapFinIdx {b : β} {l : Array α} {f : (i : Nat) α (h : i < l.size) β}
(h : b l.mapFinIdx f) : (i : Nat) (h : i < l.size), f i l[i] h = b := by
rcases l with l
exact List.exists_of_mem_mapFinIdx (by simpa using h)
@[simp] theorem mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
b xs.mapFinIdx f (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
rcases xs with xs
@[simp] theorem mem_mapFinIdx {b : β} {l : Array α} {f : (i : Nat) α (h : i < l.size) β} :
b l.mapFinIdx f (i : Nat) (h : i < l.size), f i l[i] h = b := by
rcases l with l
simp
theorem mapFinIdx_eq_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {ys : Array β} :
xs.mapFinIdx f = ys h : ys.size = xs.size, (i : Nat) (h : i < xs.size), ys[i] = f i xs[i] h := by
rcases xs with xs
rcases ys with ys
theorem mapFinIdx_eq_iff {l : Array α} {f : (i : Nat) α (h : i < l.size) β} :
l.mapFinIdx f = l' h : l'.size = l.size, (i : Nat) (h : i < l.size), l'[i] = f i l[i] h := by
rcases l with l
rcases l' with l'
simpa using List.mapFinIdx_eq_iff
@[simp] theorem mapFinIdx_eq_singleton_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {b : β} :
xs.mapFinIdx f = #[b] (a : α) (w : xs = #[a]), f 0 a (by simp [w]) = b := by
rcases xs with xs
@[simp] theorem mapFinIdx_eq_singleton_iff {l : Array α} {f : (i : Nat) α (h : i < l.size) β} {b : β} :
l.mapFinIdx f = #[b] (a : α) (w : l = #[a]), f 0 a (by simp [w]) = b := by
rcases l with l
simp
theorem mapFinIdx_eq_append_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {ys zs : Array β} :
xs.mapFinIdx f = ys ++ zs
(ys' : Array α) (zs' : Array α) (w : xs = ys' ++ zs'),
ys'.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = ys
zs'.mapFinIdx (fun i a h => f (i + ys'.size) a (by simp [w]; omega)) = zs := by
rcases xs with l
rcases ys with l₁
rcases zs with l₂
theorem mapFinIdx_eq_append_iff {l : Array α} {f : (i : Nat) α (h : i < l.size) β} {l₁ l₂ : Array β} :
l.mapFinIdx f = l₁ ++ l₂
(l₁' : Array α) (l₂' : Array α) (w : l = l₁' ++ l₂'),
l₁'.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = l₁
l₂'.mapFinIdx (fun i a h => f (i + l₁'.size) a (by simp [w]; omega)) = l₂ := by
rcases l with l
rcases l₁ with l₁
rcases l₂ with l₂
simp only [List.mapFinIdx_toArray, List.append_toArray, mk.injEq, List.mapFinIdx_eq_append_iff,
toArray_eq_append_iff]
constructor
@@ -267,39 +264,39 @@ theorem mapFinIdx_eq_append_iff {xs : Array α} {f : (i : Nat) → α → (h : i
obtain rfl := h₂
refine l₁, l₂, by simp_all
theorem mapFinIdx_eq_push_iff {xs : Array α} {b : β} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = ys.push b
(zs : Array α) (a : α) (w : xs = zs.push a),
zs.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = ys b = f (xs.size - 1) a (by simp [w]) := by
theorem mapFinIdx_eq_push_iff {l : Array α} {b : β} {f : (i : Nat) α (h : i < l.size) β} :
l.mapFinIdx f = l₂.push b
(l₁ : Array α) (a : α) (w : l = l₁.push a),
l₁.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = l₂ b = f (l.size - 1) a (by simp [w]) := by
rw [push_eq_append, mapFinIdx_eq_append_iff]
constructor
· rintro ys', zs', rfl, rfl, h₂
· rintro l₁, l₂, rfl, rfl, h₂
simp only [mapFinIdx_eq_singleton_iff, Nat.zero_add] at h₂
obtain a, rfl, rfl := h₂
exact ys', a, by simp
· rintro zs, a, rfl, rfl, rfl
exact zs, #[a], by simp
exact l₁, a, by simp
· rintro l₁, a, rfl, rfl, rfl
exact l₁, #[a], by simp
theorem mapFinIdx_eq_mapFinIdx_iff {xs : Array α} {f g : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = xs.mapFinIdx g (i : Nat) (h : i < xs.size), f i xs[i] h = g i xs[i] h := by
theorem mapFinIdx_eq_mapFinIdx_iff {l : Array α} {f g : (i : Nat) α (h : i < l.size) β} :
l.mapFinIdx f = l.mapFinIdx g (i : Nat) (h : i < l.size), f i l[i] h = g i l[i] h := by
rw [eq_comm, mapFinIdx_eq_iff]
simp
@[simp] theorem mapFinIdx_mapFinIdx {xs : Array α}
{f : (i : Nat) α (h : i < xs.size) β}
{g : (i : Nat) β (h : i < (xs.mapFinIdx f).size) γ} :
(xs.mapFinIdx f).mapFinIdx g = xs.mapFinIdx (fun i a h => g i (f i a h) (by simpa using h)) := by
@[simp] theorem mapFinIdx_mapFinIdx {l : Array α}
{f : (i : Nat) α (h : i < l.size) β}
{g : (i : Nat) β (h : i < (l.mapFinIdx f).size) γ} :
(l.mapFinIdx f).mapFinIdx g = l.mapFinIdx (fun i a h => g i (f i a h) (by simpa using h)) := by
simp [mapFinIdx_eq_iff]
theorem mapFinIdx_eq_mkArray_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {b : β} :
xs.mapFinIdx f = mkArray xs.size b (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
rcases xs with l
theorem mapFinIdx_eq_mkArray_iff {l : Array α} {f : (i : Nat) α (h : i < l.size) β} {b : β} :
l.mapFinIdx f = mkArray l.size b (i : Nat) (h : i < l.size), f i l[i] h = b := by
rcases l with l
rw [ toList_inj]
simp [List.mapFinIdx_eq_replicate_iff]
@[simp] theorem mapFinIdx_reverse {xs : Array α} {f : (i : Nat) α (h : i < xs.reverse.size) β} :
xs.reverse.mapFinIdx f = (xs.mapFinIdx (fun i a h => f (xs.size - 1 - i) a (by simp; omega))).reverse := by
rcases xs with l
@[simp] theorem mapFinIdx_reverse {l : Array α} {f : (i : Nat) α (h : i < l.reverse.size) β} :
l.reverse.mapFinIdx f = (l.mapFinIdx (fun i a h => f (l.size - 1 - i) a (by simp; omega))).reverse := by
rcases l with l
simp [List.mapFinIdx_reverse]
/-! ### mapIdx -/
@@ -308,52 +305,52 @@ theorem mapFinIdx_eq_mkArray_iff {xs : Array α} {f : (i : Nat) → α → (h :
theorem mapIdx_empty {f : Nat α β} : mapIdx f #[] = #[] :=
rfl
@[simp] theorem mapFinIdx_eq_mapIdx {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {g : Nat α β}
(h : (i : Nat) (h : i < xs.size), f i xs[i] h = g i xs[i]) :
xs.mapFinIdx f = xs.mapIdx g := by
@[simp] theorem mapFinIdx_eq_mapIdx {l : Array α} {f : (i : Nat) α (h : i < l.size) β} {g : Nat α β}
(h : (i : Nat) (h : i < l.size), 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 {xs : Array α} {f : Nat α β} :
xs.mapIdx f = xs.mapFinIdx (fun i a _ => f i a) := by
theorem mapIdx_eq_mapFinIdx {l : Array α} {f : Nat α β} :
l.mapIdx f = l.mapFinIdx (fun i a _ => f i a) := by
simp [mapFinIdx_eq_mapIdx]
theorem mapIdx_eq_zipIdx_map {xs : Array α} {f : Nat α β} :
xs.mapIdx f = xs.zipIdx.map fun a, i => f i a := by
theorem mapIdx_eq_zipIdx_map {l : Array α} {f : Nat α β} :
l.mapIdx f = l.zipIdx.map fun a, i => f i a := by
ext <;> simp
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-21")]
abbrev mapIdx_eq_zipWithIndex_map := @mapIdx_eq_zipIdx_map
theorem mapIdx_append {xs ys : Array α} :
(xs ++ ys).mapIdx f = xs.mapIdx f ++ ys.mapIdx (fun i => f (i + xs.size)) := by
rcases xs with xs
rcases ys with ys
theorem mapIdx_append {K L : Array α} :
(K ++ L).mapIdx f = K.mapIdx f ++ L.mapIdx fun i => f (i + K.size) := by
rcases K with K
rcases L with L
simp [List.mapIdx_append]
@[simp]
theorem mapIdx_push {xs : Array α} {a : α} :
mapIdx f (xs.push a) = (mapIdx f xs).push (f xs.size a) := by
theorem mapIdx_push {l : Array α} {a : α} :
mapIdx f (l.push a) = (mapIdx f l).push (f l.size a) := by
simp [ append_singleton, mapIdx_append]
theorem mapIdx_singleton {a : α} : mapIdx f #[a] = #[f 0 a] := by
simp
@[simp]
theorem mapIdx_eq_empty_iff {xs : Array α} : mapIdx f xs = #[] xs = #[] := by
rcases xs with xs
theorem mapIdx_eq_empty_iff {l : Array α} : mapIdx f l = #[] l = #[] := by
rcases l with l
simp
theorem mapIdx_ne_empty_iff {xs : Array α} :
mapIdx f xs #[] xs #[] := by
theorem mapIdx_ne_empty_iff {l : Array α} :
mapIdx f l #[] l #[] := by
simp
theorem exists_of_mem_mapIdx {b : β} {xs : Array α}
(h : b mapIdx f xs) : (i : Nat) (h : i < xs.size), f i xs[i] = b := by
theorem exists_of_mem_mapIdx {b : β} {l : Array α}
(h : b mapIdx f l) : (i : Nat) (h : i < l.size), f i l[i] = b := by
rw [mapIdx_eq_mapFinIdx] at h
simpa [Fin.exists_iff] using exists_of_mem_mapFinIdx h
@[simp] theorem mem_mapIdx {b : β} {xs : Array α} :
b mapIdx f xs (i : Nat) (h : i < xs.size), f i xs[i] = b := by
@[simp] theorem mem_mapIdx {b : β} {l : Array α} :
b mapIdx f l (i : Nat) (h : i < l.size), f i l[i] = b := by
constructor
· intro h
exact exists_of_mem_mapIdx h
@@ -361,30 +358,30 @@ theorem exists_of_mem_mapIdx {b : β} {xs : Array α}
rw [mem_iff_getElem]
exact i, by simpa using h, by simp
theorem mapIdx_eq_push_iff {xs : Array α} {b : β} :
mapIdx f xs = ys.push b
(a : α) (zs : Array α), xs = zs.push a mapIdx f zs = ys f zs.size a = b := by
theorem mapIdx_eq_push_iff {l : Array α} {b : β} :
mapIdx f l = l₂.push b
(a : α) (l₁ : Array α), l = l₁.push a mapIdx f l₁ = l₂ f l₁.size a = b := by
rw [mapIdx_eq_mapFinIdx, mapFinIdx_eq_push_iff]
simp only [mapFinIdx_eq_mapIdx, exists_and_left, exists_prop]
constructor
· rintro zs, rfl, a, rfl, rfl
exact a, zs, by simp
· rintro a, zs, rfl, rfl, rfl
exact zs, rfl, a, by simp
· rintro l₁, rfl, a, rfl, rfl
exact a, l₁, by simp
· rintro a, l₁, rfl, rfl, rfl
exact l₁, rfl, a, by simp
@[simp] theorem mapIdx_eq_singleton_iff {xs : Array α} {f : Nat α β} {b : β} :
mapIdx f xs = #[b] (a : α), xs = #[a] f 0 a = b := by
rcases xs with xs
@[simp] theorem mapIdx_eq_singleton_iff {l : Array α} {f : Nat α β} {b : β} :
mapIdx f l = #[b] (a : α), l = #[a] f 0 a = b := by
rcases l with l
simp [List.mapIdx_eq_singleton_iff]
theorem mapIdx_eq_append_iff {xs : Array α} {f : Nat α β} {ys zs : Array β} :
mapIdx f xs = ys ++ zs
(xs' : Array α) (zs' : Array α), xs = xs' ++ zs'
xs'.mapIdx f = ys
zs'.mapIdx (fun i => f (i + xs'.size)) = zs := by
rcases xs with xs
rcases ys with ys
rcases zs with zs
theorem mapIdx_eq_append_iff {l : Array α} {f : Nat α β} {l₁ l₂ : Array β} :
mapIdx f l = l₁ ++ l₂
(l₁' : Array α) (l₂' : Array α), l = l₁' ++ l₂'
l₁'.mapIdx f = l₁
l₂'.mapIdx (fun i => f (i + l₁'.size)) = l₂ := by
rcases l with l
rcases l₁ with l₁
rcases l₂ with l₂
simp only [List.mapIdx_toArray, List.append_toArray, mk.injEq, List.mapIdx_eq_append_iff,
toArray_eq_append_iff]
constructor
@@ -396,49 +393,49 @@ theorem mapIdx_eq_append_iff {xs : Array α} {f : Nat → α → β} {ys zs : Ar
obtain rfl := h₂
exact l₁, l₂, by simp
theorem mapIdx_eq_iff {xs : Array α} : mapIdx f xs = ys i : Nat, ys[i]? = xs[i]?.map (f i) := by
rcases xs with xs
rcases ys with ys
theorem mapIdx_eq_iff {l : Array α} : mapIdx f l = l' i : Nat, l'[i]? = l[i]?.map (f i) := by
rcases l with l
rcases l' with l'
simp [List.mapIdx_eq_iff]
theorem mapIdx_eq_mapIdx_iff {xs : Array α} :
mapIdx f xs = mapIdx g xs i : Nat, (h : i < xs.size) f i xs[i] = g i xs[i] := by
rcases xs with xs
theorem mapIdx_eq_mapIdx_iff {l : Array α} :
mapIdx f l = mapIdx g l i : Nat, (h : i < l.size) f i l[i] = g i l[i] := by
rcases l with l
simp [List.mapIdx_eq_mapIdx_iff]
@[simp] theorem mapIdx_set {xs : Array α} {i : Nat} {h : i < xs.size} {a : α} :
(xs.set i a).mapIdx f = (xs.mapIdx f).set i (f i a) (by simpa) := by
rcases xs with xs
@[simp] theorem mapIdx_set {l : Array α} {i : Nat} {h : i < l.size} {a : α} :
(l.set i a).mapIdx f = (l.mapIdx f).set i (f i a) (by simpa) := by
rcases l with l
simp [List.mapIdx_set]
@[simp] theorem mapIdx_setIfInBounds {xs : Array α} {i : Nat} {a : α} :
(xs.setIfInBounds i a).mapIdx f = (xs.mapIdx f).setIfInBounds i (f i a) := by
rcases xs with xs
@[simp] theorem mapIdx_setIfInBounds {l : Array α} {i : Nat} {a : α} :
(l.setIfInBounds i a).mapIdx f = (l.mapIdx f).setIfInBounds i (f i a) := by
rcases l with l
simp [List.mapIdx_set]
@[simp] theorem back?_mapIdx {xs : Array α} {f : Nat α β} :
(mapIdx f xs).back? = (xs.back?).map (f (xs.size - 1)) := by
rcases xs with xs
@[simp] theorem back?_mapIdx {l : Array α} {f : Nat α β} :
(mapIdx f l).back? = (l.back?).map (f (l.size - 1)) := by
rcases l with l
simp [List.getLast?_mapIdx]
@[simp] theorem back_mapIdx {xs : Array α} {f : Nat α β} (h) :
(xs.mapIdx f).back h = f (xs.size - 1) (xs.back (by simpa using h)) := by
rcases xs with xs
@[simp] theorem back_mapIdx {l : Array α} {f : Nat α β} (h) :
(l.mapIdx f).back h = f (l.size - 1) (l.back (by simpa using h)) := by
rcases l with l
simp [List.getLast_mapIdx]
@[simp] theorem mapIdx_mapIdx {xs : Array α} {f : Nat α β} {g : Nat β γ} :
(xs.mapIdx f).mapIdx g = xs.mapIdx (fun i => g i f i) := by
@[simp] theorem mapIdx_mapIdx {l : Array α} {f : Nat α β} {g : Nat β γ} :
(l.mapIdx f).mapIdx g = l.mapIdx (fun i => g i f i) := by
simp [mapIdx_eq_iff]
theorem mapIdx_eq_mkArray_iff {xs : Array α} {f : Nat α β} {b : β} :
mapIdx f xs = mkArray xs.size b (i : Nat) (h : i < xs.size), f i xs[i] = b := by
rcases xs with xs
theorem mapIdx_eq_mkArray_iff {l : Array α} {f : Nat α β} {b : β} :
mapIdx f l = mkArray l.size b (i : Nat) (h : i < l.size), f i l[i] = b := by
rcases l with l
rw [ toList_inj]
simp [List.mapIdx_eq_replicate_iff]
@[simp] theorem mapIdx_reverse {xs : Array α} {f : Nat α β} :
xs.reverse.mapIdx f = (mapIdx (fun i => f (xs.size - 1 - i)) xs).reverse := by
rcases xs with xs
@[simp] theorem mapIdx_reverse {l : Array α} {f : Nat α β} :
l.reverse.mapIdx f = (mapIdx (fun i => f (l.size - 1 - i)) l).reverse := by
rcases l with l
simp [List.mapIdx_reverse]
end Array
@@ -483,15 +480,15 @@ end List
namespace Array
theorem toList_mapFinIdxM [Monad m] [LawfulMonad m] (xs : Array α)
(f : (i : Nat) α (h : i < xs.size) m β) :
toList <$> xs.mapFinIdxM f = xs.toList.mapFinIdxM f := by
theorem toList_mapFinIdxM [Monad m] [LawfulMonad m] (l : Array α)
(f : (i : Nat) α (h : i < l.size) m β) :
toList <$> l.mapFinIdxM f = l.toList.mapFinIdxM f := by
rw [List.mapFinIdxM_toArray]
simp only [Functor.map_map, id_map']
theorem toList_mapIdxM [Monad m] [LawfulMonad m] (xs : Array α)
theorem toList_mapIdxM [Monad m] [LawfulMonad m] (l : Array α)
(f : Nat α m β) :
toList <$> xs.mapIdxM f = xs.toList.mapIdxM f := by
toList <$> l.mapIdxM f = l.toList.mapIdxM f := by
rw [List.mapIdxM_toArray]
simp only [Functor.map_map, id_map']

View File

@@ -8,9 +8,6 @@ import Init.Data.Array.Basic
import Init.Data.Nat.Linear
import Init.Data.List.BasicAux
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
theorem sizeOf_lt_of_mem [SizeOf α] {as : Array α} (h : a as) : sizeOf a < sizeOf as := by

View File

@@ -12,9 +12,6 @@ import Init.Data.List.Monadic
# Lemmas about `Array.forIn'` and `Array.forIn`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
@@ -23,90 +20,90 @@ open Nat
/-! ### mapM -/
@[simp] theorem mapM_append [Monad m] [LawfulMonad m] (f : α m β) {xs ys : Array α} :
(xs ++ ys).mapM f = (return ( xs.mapM f) ++ ( ys.mapM f)) := by
rcases xs with xs
rcases ys with ys
@[simp] theorem mapM_append [Monad m] [LawfulMonad m] (f : α m β) {l₁ l₂ : Array α} :
(l₁ ++ l₂).mapM f = (return ( l₁.mapM f) ++ ( l₂.mapM f)) := by
rcases l₁ with l₁
rcases l₂ with l₂
simp
theorem mapM_eq_foldlM_push [Monad m] [LawfulMonad m] (f : α m β) (xs : Array α) :
mapM f xs = xs.foldlM (fun acc a => return (acc.push ( f a))) #[] := by
rcases xs with xs
theorem mapM_eq_foldlM_push [Monad m] [LawfulMonad m] (f : α m β) (l : Array α) :
mapM f l = l.foldlM (fun acc a => return (acc.push ( f a))) #[] := by
rcases l with l
simp only [List.mapM_toArray, bind_pure_comp, List.size_toArray, List.foldlM_toArray']
rw [List.mapM_eq_reverse_foldlM_cons]
simp only [bind_pure_comp, Functor.map_map]
suffices (l), (fun l' => l'.reverse.toArray) <$> List.foldlM (fun acc a => (fun a => a :: acc) <$> f a) l xs =
List.foldlM (fun acc a => acc.push <$> f a) l.reverse.toArray xs by
suffices (k), (fun a => a.reverse.toArray) <$> List.foldlM (fun acc a => (fun a => a :: acc) <$> f a) k l =
List.foldlM (fun acc a => acc.push <$> f a) k.reverse.toArray l by
exact this []
intro l
induction xs generalizing l with
intro k
induction l generalizing k with
| nil => simp
| cons a as ih =>
simp [ih, List.foldlM_cons]
/-! ### foldlM and foldrM -/
theorem foldlM_map [Monad m] (f : β₁ β₂) (g : α β₂ m α) (xs : Array β₁) (init : α) (w : stop = xs.size) :
(xs.map f).foldlM g init 0 stop = xs.foldlM (fun x y => g x (f y)) init 0 stop := by
theorem foldlM_map [Monad m] (f : β₁ β₂) (g : α β₂ m α) (l : Array β₁) (init : α) (w : stop = l.size) :
(l.map f).foldlM g init 0 stop = l.foldlM (fun x y => g x (f y)) init 0 stop := by
subst w
cases xs
cases l
simp [List.foldlM_map]
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ β₂) (g : β₂ α m α) (xs : Array β₁)
(init : α) (w : start = xs.size) :
(xs.map f).foldrM g init start 0 = xs.foldrM (fun x y => g (f x) y) init start 0 := by
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ β₂) (g : β₂ α m α) (l : Array β₁)
(init : α) (w : start = l.size) :
(l.map f).foldrM g init start 0 = l.foldrM (fun x y => g (f x) y) init start 0 := by
subst w
cases xs
cases l
simp [List.foldrM_map]
theorem foldlM_filterMap [Monad m] [LawfulMonad m] (f : α Option β) (g : γ β m γ)
(xs : Array α) (init : γ) (w : stop = (xs.filterMap f).size) :
(xs.filterMap f).foldlM g init 0 stop =
xs.foldlM (fun x y => match f y with | some b => g x b | none => pure x) init := by
(l : Array α) (init : γ) (w : stop = (l.filterMap f).size) :
(l.filterMap f).foldlM g init 0 stop =
l.foldlM (fun x y => match f y with | some b => g x b | none => pure x) init := by
subst w
cases xs
cases l
simp [List.foldlM_filterMap]
rfl
theorem foldrM_filterMap [Monad m] [LawfulMonad m] (f : α Option β) (g : β γ m γ)
(xs : Array α) (init : γ) (w : start = (xs.filterMap f).size) :
(xs.filterMap f).foldrM g init start 0 =
xs.foldrM (fun x y => match f x with | some b => g b y | none => pure y) init := by
(l : Array α) (init : γ) (w : start = (l.filterMap f).size) :
(l.filterMap f).foldrM g init start 0 =
l.foldrM (fun x y => match f x with | some b => g b y | none => pure y) init := by
subst w
cases xs
cases l
simp [List.foldrM_filterMap]
rfl
theorem foldlM_filter [Monad m] [LawfulMonad m] (p : α Bool) (g : β α m β)
(xs : Array α) (init : β) (w : stop = (xs.filter p).size) :
(xs.filter p).foldlM g init 0 stop =
xs.foldlM (fun x y => if p y then g x y else pure x) init := by
(l : Array α) (init : β) (w : stop = (l.filter p).size) :
(l.filter p).foldlM g init 0 stop =
l.foldlM (fun x y => if p y then g x y else pure x) init := by
subst w
cases xs
cases l
simp [List.foldlM_filter]
theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α Bool) (g : α β m β)
(xs : Array α) (init : β) (w : start = (xs.filter p).size) :
(xs.filter p).foldrM g init start 0 =
xs.foldrM (fun x y => if p x then g x y else pure y) init := by
(l : Array α) (init : β) (w : start = (l.filter p).size) :
(l.filter p).foldrM g init start 0 =
l.foldrM (fun x y => if p x then g x y else pure y) init := by
subst w
cases xs
cases l
simp [List.foldrM_filter]
@[simp] theorem foldlM_attachWith [Monad m]
(xs : Array α) {q : α Prop} (H : a, a xs q a) {f : β { x // q x} m β} {b} (w : stop = xs.size):
(xs.attachWith q H).foldlM f b 0 stop =
xs.attach.foldlM (fun b a, h => f b a, H _ h) b := by
(l : Array α) {q : α Prop} (H : a, a l q a) {f : β { x // q x} m β} {b} (w : stop = l.size):
(l.attachWith q H).foldlM f b 0 stop =
l.attach.foldlM (fun b a, h => f b a, H _ h) b := by
subst w
rcases xs with xs
rcases l with l
simp [List.foldlM_map]
@[simp] theorem foldrM_attachWith [Monad m] [LawfulMonad m]
(xs : Array α) {q : α Prop} (H : a, a xs q a) {f : { x // q x} β m β} {b} (w : start = xs.size):
(xs.attachWith q H).foldrM f b start 0 =
xs.attach.foldrM (fun a acc => f a.1, H _ a.2 acc) b := by
(l : Array α) {q : α Prop} (H : a, a l q a) {f : { x // q x} β m β} {b} (w : start = l.size):
(l.attachWith q H).foldrM f b start 0 =
l.attach.foldrM (fun a acc => f a.1, H _ a.2 acc) b := by
subst w
rcases xs with xs
rcases l with l
simp [List.foldrM_map]
/-! ### forM -/
@@ -117,15 +114,15 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β
cases as <;> cases bs
simp_all
@[simp] theorem forM_append [Monad m] [LawfulMonad m] (xs ys : Array α) (f : α m PUnit) :
forM (xs ++ ys) f = (do forM xs f; forM ys f) := by
rcases xs with xs
rcases ys with ys
@[simp] theorem forM_append [Monad m] [LawfulMonad m] (l₁ l₂ : Array α) (f : α m PUnit) :
forM (l₁ ++ l₂) f = (do forM l₁ f; forM l₂ f) := by
rcases l₁ with l₁
rcases l₂ with l₂
simp
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (xs : Array α) (g : α β) (f : β m PUnit) :
forM (xs.map g) f = forM xs (fun a => f (g a)) := by
rcases xs with xs
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (l : Array α) (g : α β) (f : β m PUnit) :
forM (l.map g) f = forM l (fun a => f (g a)) := by
cases l
simp
/-! ### forIn' -/
@@ -145,41 +142,41 @@ We can express a for loop over an array as a fold,
in which whenever we reach `.done b` we keep that value through the rest of the fold.
-/
theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
(xs : Array α) (f : (a : α) a xs β m (ForInStep β)) (init : β) :
forIn' xs init f = ForInStep.value <$>
xs.attach.foldlM (fun b a, m => match b with
(l : Array α) (f : (a : α) a l β m (ForInStep β)) (init : β) :
forIn' l init f = ForInStep.value <$>
l.attach.foldlM (fun b a, m => match b with
| .yield b => f a m b
| .done b => pure (.done b)) (ForInStep.yield init) := by
rcases xs with xs
cases l
simp [List.forIn'_eq_foldlM, List.foldlM_map]
congr
/-- We can express a for loop over an array which always yields as a fold. -/
@[simp] theorem forIn'_yield_eq_foldlM [Monad m] [LawfulMonad m]
(xs : Array α) (f : (a : α) a xs β m γ) (g : (a : α) a xs β γ β) (init : β) :
forIn' xs init (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
xs.attach.foldlM (fun b a, m => g a m b <$> f a m b) init := by
rcases xs with xs
(l : Array α) (f : (a : α) a l β m γ) (g : (a : α) a l β γ β) (init : β) :
forIn' l init (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
l.attach.foldlM (fun b a, m => g a m b <$> f a m b) init := by
cases l
simp [List.foldlM_map]
theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
(xs : Array α) (f : (a : α) a xs β β) (init : β) :
forIn' xs init (fun a m b => pure (.yield (f a m b))) =
pure (f := m) (xs.attach.foldl (fun b a, h => f a h b) init) := by
rcases xs with xs
(l : Array α) (f : (a : α) a l β β) (init : β) :
forIn' l init (fun a m b => pure (.yield (f a m b))) =
pure (f := m) (l.attach.foldl (fun b a, h => f a h b) init) := by
cases l
simp [List.forIn'_pure_yield_eq_foldl, List.foldl_map]
@[simp] theorem forIn'_yield_eq_foldl
(xs : Array α) (f : (a : α) a xs β β) (init : β) :
forIn' (m := Id) xs init (fun a m b => .yield (f a m b)) =
xs.attach.foldl (fun b a, h => f a h b) init := by
rcases xs with xs
(l : Array α) (f : (a : α) a l β β) (init : β) :
forIn' (m := Id) l init (fun a m b => .yield (f a m b)) =
l.attach.foldl (fun b a, h => f a h b) init := by
cases l
simp [List.foldl_map]
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
(xs : Array α) (g : α β) (f : (b : β) b xs.map g γ m (ForInStep γ)) :
forIn' (xs.map g) init f = forIn' xs init fun a h y => f (g a) (mem_map_of_mem g h) y := by
rcases xs with xs
(l : Array α) (g : α β) (f : (b : β) b l.map g γ m (ForInStep γ)) :
forIn' (l.map g) init f = forIn' l init fun a h y => f (g a) (mem_map_of_mem g h) y := by
cases l
simp
/--
@@ -187,41 +184,41 @@ We can express a for loop over an array as a fold,
in which whenever we reach `.done b` we keep that value through the rest of the fold.
-/
theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
(f : α β m (ForInStep β)) (init : β) (xs : Array α) :
forIn xs init f = ForInStep.value <$>
xs.foldlM (fun b a => match b with
(f : α β m (ForInStep β)) (init : β) (l : Array α) :
forIn l init f = ForInStep.value <$>
l.foldlM (fun b a => match b with
| .yield b => f a b
| .done b => pure (.done b)) (ForInStep.yield init) := by
rcases xs with xs
cases l
simp only [List.forIn_toArray, List.forIn_eq_foldlM, List.size_toArray, List.foldlM_toArray']
congr
/-- We can express a for loop over an array which always yields as a fold. -/
@[simp] theorem forIn_yield_eq_foldlM [Monad m] [LawfulMonad m]
(xs : Array α) (f : α β m γ) (g : α β γ β) (init : β) :
forIn xs init (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
xs.foldlM (fun b a => g a b <$> f a b) init := by
rcases xs with xs
(l : Array α) (f : α β m γ) (g : α β γ β) (init : β) :
forIn l init (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
l.foldlM (fun b a => g a b <$> f a b) init := by
cases l
simp [List.foldlM_map]
theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
(xs : Array α) (f : α β β) (init : β) :
forIn xs init (fun a b => pure (.yield (f a b))) =
pure (f := m) (xs.foldl (fun b a => f a b) init) := by
rcases xs with xs
(l : Array α) (f : α β β) (init : β) :
forIn l init (fun a b => pure (.yield (f a b))) =
pure (f := m) (l.foldl (fun b a => f a b) init) := by
cases l
simp [List.forIn_pure_yield_eq_foldl, List.foldl_map]
@[simp] theorem forIn_yield_eq_foldl
(xs : Array α) (f : α β β) (init : β) :
forIn (m := Id) xs init (fun a b => .yield (f a b)) =
xs.foldl (fun b a => f a b) init := by
rcases xs with xs
(l : Array α) (f : α β β) (init : β) :
forIn (m := Id) l init (fun a b => .yield (f a b)) =
l.foldl (fun b a => f a b) init := by
cases l
simp [List.foldl_map]
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
(xs : Array α) (g : α β) (f : β γ m (ForInStep γ)) :
forIn (xs.map g) init f = forIn xs init fun a y => f (g a) y := by
rcases xs with xs
(l : Array α) (g : α β) (f : β γ m (ForInStep γ)) :
forIn (l.map g) init f = forIn l init fun a y => f (g a) y := by
cases l
simp
end Array
@@ -287,7 +284,7 @@ theorem filterMapM_toArray [Monad m] [LawfulMonad m] (l : List α) (f : α → m
| nil => simp only [foldlM_nil, flatMapM.loop, map_pure]
| cons x xs ih =>
simp only [foldlM_cons, bind_map_left, flatMapM.loop, _root_.map_bind]
congr; funext xs
congr; funext a
conv => lhs; rw [Array.toArray_append, flatten_concat, reverse_cons]
exact ih _
@@ -319,23 +316,23 @@ namespace Array
subst w
simp [flatMapM, h]
theorem toList_filterM [Monad m] [LawfulMonad m] (xs : Array α) (p : α m Bool) :
toList <$> xs.filterM p = xs.toList.filterM p := by
theorem toList_filterM [Monad m] [LawfulMonad m] (a : Array α) (p : α m Bool) :
toList <$> a.filterM p = a.toList.filterM p := by
rw [List.filterM_toArray]
simp only [Functor.map_map, id_map']
theorem toList_filterRevM [Monad m] [LawfulMonad m] (xs : Array α) (p : α m Bool) :
toList <$> xs.filterRevM p = xs.toList.filterRevM p := by
theorem toList_filterRevM [Monad m] [LawfulMonad m] (a : Array α) (p : α m Bool) :
toList <$> a.filterRevM p = a.toList.filterRevM p := by
rw [List.filterRevM_toArray]
simp only [Functor.map_map, id_map']
theorem toList_filterMapM [Monad m] [LawfulMonad m] (xs : Array α) (f : α m (Option β)) :
toList <$> xs.filterMapM f = xs.toList.filterMapM f := by
theorem toList_filterMapM [Monad m] [LawfulMonad m] (a : Array α) (f : α m (Option β)) :
toList <$> a.filterMapM f = a.toList.filterMapM f := by
rw [List.filterMapM_toArray]
simp only [Functor.map_map, id_map']
theorem toList_flatMapM [Monad m] [LawfulMonad m] (xs : Array α) (f : α m (Array β)) :
toList <$> xs.flatMapM f = xs.toList.flatMapM (fun a => toList <$> f a) := by
theorem toList_flatMapM [Monad m] [LawfulMonad m] (a : Array α) (f : α m (Array β)) :
toList <$> a.flatMapM f = a.toList.flatMapM (fun a => toList <$> f a) := by
rw [List.flatMapM_toArray]
simp only [Functor.map_map, id_map']
@@ -345,12 +342,12 @@ theorem toList_flatMapM [Monad m] [LawfulMonad m] (xs : Array α) (f : α → m
This lemma identifies monadic folds over lists of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
@[simp] theorem foldlM_subtype [Monad m] {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem foldlM_subtype [Monad m] {p : α Prop} {l : Array { x // p x }}
{f : β { x // p x } m β} {g : β α m β} {x : β}
(hf : b x h, f b x, h = g b x) (w : stop = xs.size) :
xs.foldlM f x 0 stop = xs.unattach.foldlM g x 0 stop := by
(hf : b x h, f b x, h = g b x) (w : stop = l.size) :
l.foldlM f x 0 stop = l.unattach.foldlM g x 0 stop := by
subst w
rcases xs with l
rcases l with l
simp
rw [List.foldlM_subtype hf]
@@ -368,12 +365,12 @@ and simplifies these to the function directly taking the value.
This lemma identifies monadic folds over lists of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
@[simp] theorem foldrM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem foldrM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } β m β} {g : α β m β} {x : β}
(hf : x h b, f x, h b = g x b) (w : start = xs.size) :
xs.foldrM f x start 0 = xs.unattach.foldrM g x start 0:= by
(hf : x h b, f x, h b = g x b) (w : start = l.size) :
l.foldrM f x start 0 = l.unattach.foldrM g x start 0:= by
subst w
rcases xs with xs
rcases l with l
simp
rw [List.foldrM_subtype hf]
@@ -392,10 +389,10 @@ and simplifies these to the function directly taking the value.
This lemma identifies monadic maps over lists of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
@[simp] theorem mapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem mapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } m β} {g : α m β} (hf : x h, f x, h = g x) :
xs.mapM f = xs.unattach.mapM g := by
rcases xs with xs
l.mapM f = l.unattach.mapM g := by
rcases l with l
simp
rw [List.mapM_subtype hf]
@@ -408,11 +405,11 @@ and simplifies these to the function directly taking the value.
binderNameHint x f <| binderNameHint h () <| f (wfParam x) := by
simp [wfParam]
@[simp] theorem filterMapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } m (Option β)} {g : α m (Option β)} (hf : x h, f x, h = g x) (w : stop = xs.size) :
xs.filterMapM f 0 stop = xs.unattach.filterMapM g := by
@[simp] theorem filterMapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } m (Option β)} {g : α m (Option β)} (hf : x h, f x, h = g x) (w : stop = l.size) :
l.filterMapM f 0 stop = l.unattach.filterMapM g := by
subst w
rcases xs with xs
rcases l with l
simp
rw [List.filterMapM_subtype hf]
@@ -428,14 +425,15 @@ and simplifies these to the function directly taking the value.
binderNameHint x f <| binderNameHint h () <| f (wfParam x) := by
simp [wfParam]
@[simp] theorem flatMapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {xs : Array { x // p x }}
@[simp] theorem flatMapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } m (Array β)} {g : α m (Array β)} (hf : x h, f x, h = g x) :
(xs.flatMapM f) = xs.unattach.flatMapM g := by
rcases xs with xs
(l.flatMapM f) = l.unattach.flatMapM g := by
rcases l with l
simp
rw [List.flatMapM_subtype]
simp [hf]
@[wf_preprocess] theorem flatMapM_wfParam [Monad m] [LawfulMonad m]
(xs : Array α) (f : α m (Array β)) :
(wfParam xs).flatMapM f = xs.attach.unattach.flatMapM f := by

View File

@@ -11,9 +11,6 @@ import Init.Data.List.OfFn
# Theorems about `Array.ofFn`
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
@[simp]

View File

@@ -7,9 +7,6 @@ prelude
import Init.Data.List.Nat.Perm
import Init.Data.Array.Lemmas
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open List
@@ -30,38 +27,38 @@ theorem perm_iff_toList_perm {as bs : Array α} : as ~ bs ↔ as.toList ~ bs.toL
@[simp] theorem perm_toArray (as bs : List α) : as.toArray ~ bs.toArray as ~ bs := by
simp [perm_iff_toList_perm]
@[simp, refl] protected theorem Perm.refl (xs : Array α) : xs ~ xs := by
cases xs
@[simp, refl] protected theorem Perm.refl (l : Array α) : l ~ l := by
cases l
simp
protected theorem Perm.rfl {xs : List α} : xs ~ xs := .refl _
protected theorem Perm.rfl {l : List α} : l ~ l := .refl _
theorem Perm.of_eq {xs ys : Array α} (h : xs = ys) : xs ~ ys := h .rfl
theorem Perm.of_eq {l₁ l₂ : Array α} (h : l₁ = l₂) : l₁ ~ l₂ := h .rfl
protected theorem Perm.symm {xs ys : Array α} (h : xs ~ ys) : ys ~ xs := by
cases xs; cases ys
protected theorem Perm.symm {l₁ l₂ : Array α} (h : l₁ ~ l₂) : l₂ ~ l₁ := by
cases l₁; cases l₂
simp only [perm_toArray] at h
simpa using h.symm
protected theorem Perm.trans {xs ys zs : Array α} (h₁ : xs ~ ys) (h₂ : ys ~ zs) : xs ~ zs := by
cases xs; cases ys; cases zs
protected theorem Perm.trans {l₁ l₂ l₃ : Array α} (h₁ : l₁ ~ l₂) (h₂ : l₂ ~ l₃) : l₁ ~ l₃ := by
cases l₁; cases l₂; cases l₃
simp only [perm_toArray] at h₁ h₂
simpa using h₁.trans h₂
instance : Trans (Perm (α := α)) (Perm (α := α)) (Perm (α := α)) where
trans h₁ h₂ := Perm.trans h₁ h₂
theorem perm_comm {xs ys : Array α} : xs ~ ys ys ~ xs := Perm.symm, Perm.symm
theorem perm_comm {l₁ l₂ : Array α} : l₁ ~ l₂ l₂ ~ l₁ := Perm.symm, Perm.symm
theorem Perm.push (x y : α) {xs ys : Array α} (p : xs ~ ys) :
(xs.push x).push y ~ (ys.push y).push x := by
cases xs; cases ys
theorem Perm.push (x y : α) {l₁ l₂ : Array α} (p : l₁ ~ l₂) :
(l₁.push x).push y ~ (l₂.push y).push x := by
cases l₁; cases l₂
simp only [perm_toArray] at p
simp only [push_toArray, List.append_assoc, singleton_append, perm_toArray]
exact p.append (Perm.swap' _ _ Perm.nil)
theorem swap_perm {xs : Array α} {i j : Nat} (h₁ : i < xs.size) (h₂ : j < xs.size) :
xs.swap i j ~ xs := by
theorem swap_perm {as : Array α} {i j : Nat} (h₁ : i < as.size) (h₂ : j < as.size) :
as.swap i j ~ as := by
simp only [swap, perm_iff_toList_perm, toList_set]
apply set_set_perm

View File

@@ -7,9 +7,6 @@ prelude
import Init.Data.Vector.Basic
import Init.Data.Ord
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- We do not enable `linter.indexVariables` because it is helpful to name index variables `lo`, `mid`, `hi`, etc.
namespace Array
private def qpartition {n} (as : Vector α n) (lt : α α Bool) (lo hi : Nat)

View File

@@ -15,9 +15,6 @@ import Init.Data.List.Nat.Range
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
@@ -31,7 +28,7 @@ theorem range'_succ (s n step) : range' s (n + 1) step = #[s] ++ range' (s + ste
simp [List.range'_succ]
@[simp] theorem range'_eq_empty_iff : range' s n step = #[] n = 0 := by
rw [ size_eq_zero_iff, size_range']
rw [ size_eq_zero, size_range']
theorem range'_ne_empty_iff (s : Nat) {n step : Nat} : range' s n step #[] n 0 := by
cases n <;> simp
@@ -136,7 +133,7 @@ theorem range'_eq_map_range (s n : Nat) : range' s n = map (s + ·) (range n) :=
rw [range_eq_range', map_add_range']; rfl
@[simp] theorem range_eq_empty_iff {n : Nat} : range n = #[] n = 0 := by
rw [ size_eq_zero_iff, size_range]
rw [ size_eq_zero, size_range]
theorem range_ne_empty_iff {n : Nat} : range n #[] n 0 := by
cases n <;> simp
@@ -149,9 +146,9 @@ theorem range_succ (n : Nat) : range (succ n) = range n ++ #[n] := by
dite_eq_ite]
split <;> omega
theorem range_add (n m : Nat) : range (n + m) = range n ++ (range m).map (n + ·) := by
theorem range_add (a b : Nat) : range (a + b) = range a ++ (range b).map (a + ·) := by
rw [ range'_eq_map_range]
simpa [range_eq_range', Nat.add_comm] using (range'_append_1 0 n m).symm
simpa [range_eq_range', Nat.add_comm] using (range'_append_1 0 a b).symm
theorem reverse_range' (s n : Nat) : reverse (range' s n) = map (s + n - 1 - ·) (range n) := by
simp [ toList_inj, List.reverse_range']
@@ -164,7 +161,7 @@ theorem not_mem_range_self {n : Nat} : n ∉ range n := by simp
theorem self_mem_range_succ (n : Nat) : n range (n + 1) := by simp
@[simp] theorem take_range (i n : Nat) : take (range n) i = range (min i n) := by
@[simp] theorem take_range (m n : Nat) : take (range n) m = range (min m n) := by
ext <;> simp
@[simp] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat Bool} :
@@ -182,48 +179,48 @@ theorem erase_range : (range n).erase i = range (min n i) ++ range' (i + 1) (n -
/-! ### zipIdx -/
@[simp]
theorem zipIdx_eq_empty_iff {xs : Array α} {i : Nat} : xs.zipIdx i = #[] xs = #[] := by
cases xs
theorem zipIdx_eq_empty_iff {l : Array α} {n : Nat} : l.zipIdx n = #[] l = #[] := by
cases l
simp
@[simp]
theorem getElem?_zipIdx (xs : Array α) (i j) : (zipIdx xs i)[j]? = xs[j]?.map fun a => (a, i + j) := by
theorem getElem?_zipIdx (l : Array α) (n m) : (zipIdx l n)[m]? = l[m]?.map fun a => (a, n + m) := by
simp [getElem?_def]
theorem map_snd_add_zipIdx_eq_zipIdx (xs : Array α) (n k : Nat) :
map (Prod.map id (· + n)) (zipIdx xs k) = zipIdx xs (n + k) :=
theorem map_snd_add_zipIdx_eq_zipIdx (l : Array α) (n k : Nat) :
map (Prod.map id (· + n)) (zipIdx l k) = zipIdx l (n + k) :=
ext_getElem? fun i by simp [(· ·), Nat.add_comm, Nat.add_left_comm]; rfl
@[simp]
theorem zipIdx_map_snd (i) (xs : Array α) : map Prod.snd (zipIdx xs i) = range' i xs.size := by
cases xs
theorem zipIdx_map_snd (n) (l : Array α) : map Prod.snd (zipIdx l n) = range' n l.size := by
cases l
simp
@[simp]
theorem zipIdx_map_fst (i) (xs : Array α) : map Prod.fst (zipIdx xs i) = xs := by
cases xs
theorem zipIdx_map_fst (n) (l : Array α) : map Prod.fst (zipIdx l n) = l := by
cases l
simp
theorem zipIdx_eq_zip_range' (xs : Array α) {i : Nat} : xs.zipIdx i = xs.zip (range' i xs.size) := by
theorem zipIdx_eq_zip_range' (l : Array α) {n : Nat} : l.zipIdx n = l.zip (range' n l.size) := by
simp [zip_of_prod (zipIdx_map_fst _ _) (zipIdx_map_snd _ _)]
@[simp]
theorem unzip_zipIdx_eq_prod (xs : Array α) {i : Nat} :
(xs.zipIdx i).unzip = (xs, range' i xs.size) := by
theorem unzip_zipIdx_eq_prod (l : Array α) {n : Nat} :
(l.zipIdx n).unzip = (l, range' n l.size) := by
simp only [zipIdx_eq_zip_range', unzip_zip, size_range']
/-- Replace `zipIdx` with a starting index `n+1` with `zipIdx` starting from `n`,
followed by a `map` increasing the indices by one. -/
theorem zipIdx_succ (xs : Array α) (i : Nat) :
xs.zipIdx (i + 1) = (xs.zipIdx i).map (fun a, j => (a, j + 1)) := by
cases xs
theorem zipIdx_succ (l : Array α) (n : Nat) :
l.zipIdx (n + 1) = (l.zipIdx n).map (fun a, i => (a, i + 1)) := by
cases l
simp [List.zipIdx_succ]
/-- Replace `zipIdx` with a starting index with `zipIdx` starting from 0,
followed by a `map` increasing the indices. -/
theorem zipIdx_eq_map_add (xs : Array α) (i : Nat) :
xs.zipIdx i = (xs.zipIdx 0).map (fun a, j => (a, i + j)) := by
cases xs
theorem zipIdx_eq_map_add (l : Array α) (n : Nat) :
l.zipIdx n = l.zipIdx.map (fun a, i => (a, n + i)) := by
cases l
simp only [zipIdx_toArray, List.map_toArray, mk.injEq]
rw [List.zipIdx_eq_map_add]
@@ -231,33 +228,33 @@ theorem zipIdx_eq_map_add (xs : Array α) (i : Nat) :
theorem zipIdx_singleton (x : α) (k : Nat) : zipIdx #[x] k = #[(x, k)] :=
rfl
theorem mk_add_mem_zipIdx_iff_getElem? {k i : Nat} {x : α} {xs : Array α} :
(x, k + i) zipIdx xs k xs[i]? = some x := by
theorem mk_add_mem_zipIdx_iff_getElem? {k i : Nat} {x : α} {l : Array α} :
(x, k + i) zipIdx l k l[i]? = some x := by
simp [mem_iff_getElem?, and_left_comm]
theorem le_snd_of_mem_zipIdx {x : α × Nat} {k : Nat} {xs : Array α} (h : x zipIdx xs k) :
theorem le_snd_of_mem_zipIdx {x : α × Nat} {k : Nat} {l : Array α} (h : x zipIdx l k) :
k x.2 :=
(mk_mem_zipIdx_iff_le_and_getElem?_sub.1 h).1
theorem snd_lt_add_of_mem_zipIdx {x : α × Nat} {k : Nat} {xs : Array α} (h : x zipIdx xs k) :
x.2 < k + xs.size := by
theorem snd_lt_add_of_mem_zipIdx {x : α × Nat} {l : Array α} {k : Nat} (h : x zipIdx l k) :
x.2 < k + l.size := by
rcases mem_iff_getElem.1 h with i, h', rfl
simpa using h'
theorem snd_lt_of_mem_zipIdx {x : α × Nat} {k : Nat} {xs : Array α} (h : x zipIdx xs k) : x.2 < xs.size + k := by
theorem snd_lt_of_mem_zipIdx {x : α × Nat} {l : Array α} {k : Nat} (h : x l.zipIdx k) : x.2 < l.size + k := by
simpa [Nat.add_comm] using snd_lt_add_of_mem_zipIdx h
theorem map_zipIdx (f : α β) (xs : Array α) (k : Nat) :
map (Prod.map f id) (zipIdx xs k) = zipIdx (xs.map f) k := by
cases xs
theorem map_zipIdx (f : α β) (l : Array α) (k : Nat) :
map (Prod.map f id) (zipIdx l k) = zipIdx (l.map f) k := by
cases l
simp [List.map_zipIdx]
theorem fst_mem_of_mem_zipIdx {x : α × Nat} {xs : Array α} {k : Nat} (h : x zipIdx xs k) : x.1 xs :=
zipIdx_map_fst k xs mem_map_of_mem _ h
theorem fst_mem_of_mem_zipIdx {x : α × Nat} {l : Array α} {k : Nat} (h : x zipIdx l k) : x.1 l :=
zipIdx_map_fst k l mem_map_of_mem _ h
theorem fst_eq_of_mem_zipIdx {x : α × Nat} {xs : Array α} {k : Nat} (h : x zipIdx xs k) :
x.1 = xs[x.2 - k]'(by have := le_snd_of_mem_zipIdx h; have := snd_lt_add_of_mem_zipIdx h; omega) := by
cases xs
theorem fst_eq_of_mem_zipIdx {x : α × Nat} {l : Array α} {k : Nat} (h : x zipIdx l k) :
x.1 = l[x.2 - k]'(by have := le_snd_of_mem_zipIdx h; have := snd_lt_add_of_mem_zipIdx h; omega) := by
cases l
exact List.fst_eq_of_mem_zipIdx (by simpa using h)
theorem mem_zipIdx {x : α} {i : Nat} {xs : Array α} {k : Nat} (h : (x, i) xs.zipIdx k) :
@@ -270,9 +267,9 @@ theorem mem_zipIdx' {x : α} {i : Nat} {xs : Array α} (h : (x, i) ∈ xs.zipIdx
i < xs.size x = xs[i]'(by have := le_snd_of_mem_zipIdx h; have := snd_lt_add_of_mem_zipIdx h; omega) :=
by simpa using snd_lt_add_of_mem_zipIdx h, fst_eq_of_mem_zipIdx h
theorem zipIdx_map (xs : Array α) (k : Nat) (f : α β) :
zipIdx (xs.map f) k = (zipIdx xs k).map (Prod.map f id) := by
cases xs
theorem zipIdx_map (l : Array α) (k : Nat) (f : α β) :
zipIdx (l.map f) k = (zipIdx l k).map (Prod.map f id) := by
cases l
simp [List.zipIdx_map]
theorem zipIdx_append (xs ys : Array α) (k : Nat) :
@@ -281,12 +278,12 @@ theorem zipIdx_append (xs ys : Array α) (k : Nat) :
cases ys
simp [List.zipIdx_append]
theorem zipIdx_eq_append_iff {xs : Array α} {k : Nat} :
zipIdx xs k = ys ++ zs
ys' zs', xs = ys' ++ zs' ys = zipIdx ys' k zs = zipIdx zs' (k + ys'.size) := by
rcases xs with xs
rcases ys with ys
rcases zs with zs
theorem zipIdx_eq_append_iff {l : Array α} {k : Nat} :
zipIdx l k = l₁ ++ l₂
l₁' l₂', l = l₁' ++ l₂' l₁ = zipIdx l₁' k l₂ = zipIdx l₂' (k + l₁'.size) := by
rcases l with l
rcases l₁ with l₁
rcases l₂ with l₂
simp only [zipIdx_toArray, List.append_toArray, mk.injEq, List.zipIdx_eq_append_iff,
toArray_eq_append_iff]
constructor

View File

@@ -6,9 +6,6 @@ Authors: Leonardo de Moura, Mario Carneiro
prelude
import Init.Tactics
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
/--
Set an element in an array, using a proof that the index is in bounds.
@@ -18,9 +15,9 @@ This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[extern "lean_array_fset"]
def Array.set (xs : Array α) (i : @& Nat) (v : α) (h : i < xs.size := by get_elem_tactic) :
def Array.set (a : Array α) (i : @& Nat) (v : α) (h : i < a.size := by get_elem_tactic) :
Array α where
toList := xs.toList.set i v
toList := a.toList.set i v
/--
Set an element in an array, or do nothing if the index is out of bounds.
@@ -28,8 +25,8 @@ Set an element in an array, or do nothing if the index is out of bounds.
This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[inline] def Array.setIfInBounds (xs : Array α) (i : Nat) (v : α) : Array α :=
dite (LT.lt i xs.size) (fun h => xs.set i v h) (fun _ => xs)
@[inline] def Array.setIfInBounds (a : Array α) (i : Nat) (v : α) : Array α :=
dite (LT.lt i a.size) (fun h => a.set i v h) (fun _ => a)
@[deprecated Array.setIfInBounds (since := "2024-11-24")] abbrev Array.setD := @Array.setIfInBounds
@@ -40,5 +37,5 @@ This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[extern "lean_array_set"]
def Array.set! (xs : Array α) (i : @& Nat) (v : α) : Array α :=
Array.setIfInBounds xs i v
def Array.set! (a : Array α) (i : @& Nat) (v : α) : Array α :=
Array.setIfInBounds a i v

View File

@@ -6,8 +6,6 @@ Authors: Leonardo de Moura
prelude
import Init.Data.Array.Basic
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
universe u v w
structure Subarray (α : Type u) where

View File

@@ -15,9 +15,6 @@ automation. Placing them in another module breaks an import cycle, because `omeg
array library.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Subarray
/--
Splits a subarray into two parts.

View File

@@ -12,9 +12,6 @@ These lemmas are used in the internals of HashMap.
They should find a new home and/or be reformulated.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
theorem exists_of_set {i : Nat} {a' : α} {l : List α} (h : i < l.length) :
@@ -26,9 +23,9 @@ end List
namespace Array
theorem exists_of_uset (xs : Array α) (i d h) :
l₁ l₂, xs.toList = l₁ ++ xs[i] :: l₂ List.length l₁ = i.toNat
(xs.uset i d h).toList = l₁ ++ d :: l₂ := by
theorem exists_of_uset (self : Array α) (i d h) :
l₁ l₂, self.toList = l₁ ++ self[i] :: l₂ List.length l₁ = i.toNat
(self.uset i d h).toList = l₁ ++ d :: l₂ := by
simpa only [ugetElem_eq_getElem, getElem_toList, uset, toList_set] using
List.exists_of_set _

View File

@@ -11,9 +11,6 @@ import Init.Data.List.Zip
# Lemmas about `Array.zip`, `Array.zipWith`, `Array.zipWithAll`, and `Array.unzip`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
@@ -22,20 +19,20 @@ open Nat
/-! ### zipWith -/
theorem zipWith_comm (f : α β γ) (as : Array α) (bs : Array β) :
zipWith f as bs = zipWith (fun b a => f a b) bs as := by
cases as
cases bs
theorem zipWith_comm (f : α β γ) (la : Array α) (lb : Array β) :
zipWith f la lb = zipWith (fun b a => f a b) lb la := by
cases la
cases lb
simpa using List.zipWith_comm _ _ _
theorem zipWith_comm_of_comm (f : α α β) (comm : x y : α, f x y = f y x) (xs ys : Array α) :
zipWith f xs ys = zipWith f ys xs := by
theorem zipWith_comm_of_comm (f : α α β) (comm : x y : α, f x y = f y x) (l l' : Array α) :
zipWith f l l' = zipWith f l' l := by
rw [zipWith_comm]
simp only [comm]
@[simp]
theorem zipWith_self (f : α α δ) (xs : Array α) : zipWith f xs xs = xs.map fun a => f a a := by
cases xs
theorem zipWith_self (f : α α δ) (l : Array α) : zipWith f l l = l.map fun a => f a a := by
cases l
simp
/--
@@ -57,15 +54,15 @@ theorem getElem?_zipWith' {f : α → β → γ} {i : Nat} :
cases l₂
simp [List.getElem?_zipWith']
theorem getElem?_zipWith_eq_some {f : α β γ} {as : Array α} {bs : Array β} {z : γ} {i : Nat} :
(zipWith f as bs)[i]? = some z
x y, as[i]? = some x bs[i]? = some y f x y = z := by
cases as
cases bs
theorem getElem?_zipWith_eq_some {f : α β γ} {l₁ : Array α} {l₂ : Array β} {z : γ} {i : Nat} :
(zipWith f l₁ l₂)[i]? = some z
x y, l₁[i]? = some x l₂[i]? = some y f x y = z := by
cases l₁
cases l₂
simp [List.getElem?_zipWith_eq_some]
theorem getElem?_zip_eq_some {as : Array α} {bs : Array β} {z : α × β} {i : Nat} :
(zip as bs)[i]? = some z as[i]? = some z.1 bs[i]? = some z.2 := by
theorem getElem?_zip_eq_some {l₁ : Array α} {l₂ : Array β} {z : α × β} {i : Nat} :
(zip l₁ l₂)[i]? = some z l₁[i]? = some z.1 l₂[i]? = some z.2 := by
cases z
rw [zip, getElem?_zipWith_eq_some]; constructor
· rintro x, y, h₀, h₁, h₂
@@ -74,210 +71,210 @@ theorem getElem?_zip_eq_some {as : Array α} {bs : Array β} {z : α × β} {i :
exact _, _, h₀, h₁, rfl
@[simp]
theorem zipWith_map {μ} (f : γ δ μ) (g : α γ) (h : β δ) (as : Array α) (bs : Array β) :
zipWith f (as.map g) (bs.map h) = zipWith (fun a b => f (g a) (h b)) as bs := by
cases as
cases bs
theorem zipWith_map {μ} (f : γ δ μ) (g : α γ) (h : β δ) (l₁ : Array α) (l₂ : Array β) :
zipWith f (l₁.map g) (l₂.map h) = zipWith (fun a b => f (g a) (h b)) l₁ l₂ := by
cases l₁
cases l₂
simp [List.zipWith_map]
theorem zipWith_map_left (as : Array α) (bs : Array β) (f : α α') (g : α' β γ) :
zipWith g (as.map f) bs = zipWith (fun a b => g (f a) b) as bs := by
cases as
cases bs
theorem zipWith_map_left (l₁ : Array α) (l₂ : Array β) (f : α α') (g : α' β γ) :
zipWith g (l₁.map f) l₂ = zipWith (fun a b => g (f a) b) l₁ l₂ := by
cases l₁
cases l₂
simp [List.zipWith_map_left]
theorem zipWith_map_right (as : Array α) (bs : Array β) (f : β β') (g : α β' γ) :
zipWith g as (bs.map f) = zipWith (fun a b => g a (f b)) as bs := by
cases as
cases bs
theorem zipWith_map_right (l₁ : Array α) (l₂ : Array β) (f : β β') (g : α β' γ) :
zipWith g l₁ (l₂.map f) = zipWith (fun a b => g a (f b)) l₁ l₂ := by
cases l₁
cases l₂
simp [List.zipWith_map_right]
theorem zipWith_foldr_eq_zip_foldr {f : α β γ} (i : δ):
(zipWith f as bs).foldr g i = (zip as bs).foldr (fun p r => g (f p.1 p.2) r) i := by
cases as
cases bs
(zipWith f l₁ l₂).foldr g i = (zip l₁ l₂).foldr (fun p r => g (f p.1 p.2) r) i := by
cases l₁
cases l₂
simp [List.zipWith_foldr_eq_zip_foldr]
theorem zipWith_foldl_eq_zip_foldl {f : α β γ} (i : δ):
(zipWith f as bs).foldl g i = (zip as bs).foldl (fun r p => g r (f p.1 p.2)) i := by
cases as
cases bs
(zipWith f l₁ l₂).foldl g i = (zip l₁ l₂).foldl (fun r p => g r (f p.1 p.2)) i := by
cases l₁
cases l₂
simp [List.zipWith_foldl_eq_zip_foldl]
@[simp]
theorem zipWith_eq_empty_iff {f : α β γ} {as : Array α} {bs : Array β} : zipWith f as bs = #[] as = #[] bs = #[] := by
cases as <;> cases bs <;> simp
theorem zipWith_eq_empty_iff {f : α β γ} {l l'} : zipWith f l l' = #[] l = #[] l' = #[] := by
cases l <;> cases l' <;> simp
theorem map_zipWith {δ : Type _} (f : α β) (g : γ δ α) (cs : Array γ) (ds : Array δ) :
map f (zipWith g cs ds) = zipWith (fun x y => f (g x y)) cs ds := by
cases cs
cases ds
theorem map_zipWith {δ : Type _} (f : α β) (g : γ δ α) (l : Array γ) (l' : Array δ) :
map f (zipWith g l l') = zipWith (fun x y => f (g x y)) l l' := by
cases l
cases l'
simp [List.map_zipWith]
theorem take_zipWith : (zipWith f as bs).take i = zipWith f (as.take i) (bs.take i) := by
cases as
cases bs
theorem take_zipWith : (zipWith f l l').take n = zipWith f (l.take n) (l'.take n) := by
cases l
cases l'
simp [List.take_zipWith]
theorem extract_zipWith : (zipWith f as bs).extract i j = zipWith f (as.extract i j) (bs.extract i j) := by
cases as
cases bs
theorem extract_zipWith : (zipWith f l l').extract m n = zipWith f (l.extract m n) (l'.extract m n) := by
cases l
cases l'
simp [List.drop_zipWith, List.take_zipWith]
theorem zipWith_append (f : α β γ) (as as' : Array α) (bs bs' : Array β)
(h : as.size = bs.size) :
zipWith f (as ++ as') (bs ++ bs') = zipWith f as bs ++ zipWith f as' bs' := by
cases as
cases bs
cases as'
cases bs'
theorem zipWith_append (f : α β γ) (l la : Array α) (l' lb : Array β)
(h : l.size = l'.size) :
zipWith f (l ++ la) (l' ++ lb) = zipWith f l l' ++ zipWith f la lb := by
cases l
cases l'
cases la
cases lb
simp at h
simp [List.zipWith_append, h]
theorem zipWith_eq_append_iff {f : α β γ} {as : Array α} {bs : Array β} :
zipWith f as bs = xs ++ ys
as₁ as₂ bs₁ bs₂, as₁.size = bs₁.size as = as₁ ++ as₂ bs = bs₁ ++ bs₂ xs = zipWith f as₁ bs₁ ys = zipWith f as₂ bs₂ := by
cases as
cases bs
cases xs
cases ys
theorem zipWith_eq_append_iff {f : α β γ} {l₁ : Array α} {l₂ : Array β} :
zipWith f l₁ l₂ = l₁' ++ l₂'
w x y z, w.size = y.size l₁ = w ++ x l₂ = y ++ z l₁' = zipWith f w y l₂' = zipWith f x z := by
cases l₁
cases l₂
cases l₁'
cases l₂'
simp only [List.zipWith_toArray, List.append_toArray, mk.injEq, List.zipWith_eq_append_iff,
toArray_eq_append_iff]
constructor
· rintro ws, xs, ys, zs, h, rfl, rfl, rfl, rfl
exact ws.toArray, xs.toArray, ys.toArray, zs.toArray, by simp [h]
· rintro ws, xs, ys, zs, h, rfl, rfl, h₁, h₂
exact ws, xs, ys, zs, by simp_all
· rintro w, x, y, z, h, rfl, rfl, rfl, rfl
exact w.toArray, x.toArray, y.toArray, z.toArray, by simp [h]
· rintro w, x, y, z, h, rfl, rfl, h₁, h₂
exact w, x, y, z, by simp_all
@[simp] theorem zipWith_mkArray {a : α} {b : β} {m n : Nat} :
zipWith f (mkArray m a) (mkArray n b) = mkArray (min m n) (f a b) := by
simp [ List.toArray_replicate]
theorem map_uncurry_zip_eq_zipWith (f : α β γ) (as : Array α) (bs : Array β) :
map (Function.uncurry f) (as.zip bs) = zipWith f as bs := by
cases as
cases bs
theorem map_uncurry_zip_eq_zipWith (f : α β γ) (l : Array α) (l' : Array β) :
map (Function.uncurry f) (l.zip l') = zipWith f l l' := by
cases l
cases l'
simp [List.map_uncurry_zip_eq_zipWith]
theorem map_zip_eq_zipWith (f : α × β γ) (as : Array α) (bs : Array β) :
map f (as.zip bs) = zipWith (Function.curry f) as bs := by
cases as
cases bs
theorem map_zip_eq_zipWith (f : α × β γ) (l : Array α) (l' : Array β) :
map f (l.zip l') = zipWith (Function.curry f) l l' := by
cases l
cases l'
simp [List.map_zip_eq_zipWith]
theorem lt_size_left_of_zipWith {f : α β γ} {i : Nat} {as : Array α} {bs : Array β}
(h : i < (zipWith f as bs).size) : i < as.size := by rw [size_zipWith] at h; omega
theorem lt_size_left_of_zipWith {f : α β γ} {i : Nat} {l : Array α} {l' : Array β}
(h : i < (zipWith f l l').size) : i < l.size := by rw [size_zipWith] at h; omega
theorem lt_size_right_of_zipWith {f : α β γ} {i : Nat} {as : Array α} {bs : Array β}
(h : i < (zipWith f as bs).size) : i < bs.size := by rw [size_zipWith] at h; omega
theorem lt_size_right_of_zipWith {f : α β γ} {i : Nat} {l : Array α} {l' : Array β}
(h : i < (zipWith f l l').size) : i < l'.size := by rw [size_zipWith] at h; omega
theorem zipWith_eq_zipWith_take_min (as : Array α) (bs : Array β) :
zipWith f as bs = zipWith f (as.take (min as.size bs.size)) (bs.take (min as.size bs.size)) := by
cases as
cases bs
theorem zipWith_eq_zipWith_take_min (l₁ : Array α) (l₂ : Array β) :
zipWith f l₁ l₂ = zipWith f (l₁.take (min l₁.size l₂.size)) (l₂.take (min l₁.size l₂.size)) := by
cases l₁
cases l₂
simp
rw [List.zipWith_eq_zipWith_take_min]
theorem reverse_zipWith (h : as.size = bs.size) :
(zipWith f as bs).reverse = zipWith f as.reverse bs.reverse := by
cases as
cases bs
theorem reverse_zipWith (h : l.size = l'.size) :
(zipWith f l l').reverse = zipWith f l.reverse l'.reverse := by
cases l
cases l'
simp [List.reverse_zipWith (by simpa using h)]
/-! ### zip -/
theorem lt_size_left_of_zip {i : Nat} {as : Array α} {bs : Array β} (h : i < (zip as bs).size) :
i < as.size :=
theorem lt_size_left_of_zip {i : Nat} {l : Array α} {l' : Array β} (h : i < (zip l l').size) :
i < l.size :=
lt_size_left_of_zipWith h
theorem lt_size_right_of_zip {i : Nat} {as : Array α} {bs : Array β} (h : i < (zip as bs).size) :
i < bs.size :=
theorem lt_size_right_of_zip {i : Nat} {l : Array α} {l' : Array β} (h : i < (zip l l').size) :
i < l'.size :=
lt_size_right_of_zipWith h
@[simp]
theorem getElem_zip {as : Array α} {bs : Array β} {i : Nat} {h : i < (zip as bs).size} :
(zip as bs)[i] =
(as[i]'(lt_size_left_of_zip h), bs[i]'(lt_size_right_of_zip h)) :=
theorem getElem_zip {l : Array α} {l' : Array β} {i : Nat} {h : i < (zip l l').size} :
(zip l l')[i] =
(l[i]'(lt_size_left_of_zip h), l'[i]'(lt_size_right_of_zip h)) :=
getElem_zipWith (hi := by simpa using h)
theorem zip_eq_zipWith (as : Array α) (bs : Array β) : zip as bs = zipWith Prod.mk as bs := by
cases as
cases bs
theorem zip_eq_zipWith (l₁ : Array α) (l₂ : Array β) : zip l₁ l₂ = zipWith Prod.mk l₁ l₂ := by
cases l₁
cases l₂
simp [List.zip_eq_zipWith]
theorem zip_map (f : α γ) (g : β δ) (as : Array α) (bs : Array β) :
zip (as.map f) (bs.map g) = (zip as bs).map (Prod.map f g) := by
cases as
cases bs
theorem zip_map (f : α γ) (g : β δ) (l₁ : Array α) (l₂ : Array β) :
zip (l₁.map f) (l₂.map g) = (zip l₁ l₂).map (Prod.map f g) := by
cases l₁
cases l₂
simp [List.zip_map]
theorem zip_map_left (f : α γ) (as : Array α) (bs : Array β) :
zip (as.map f) bs = (zip as bs).map (Prod.map f id) := by rw [ zip_map, map_id]
theorem zip_map_left (f : α γ) (l₁ : Array α) (l₂ : Array β) :
zip (l₁.map f) l₂ = (zip l₁ l₂).map (Prod.map f id) := by rw [ zip_map, map_id]
theorem zip_map_right (f : β γ) (as : Array α) (bs : Array β) :
zip as (bs.map f) = (zip as bs).map (Prod.map id f) := by rw [ zip_map, map_id]
theorem zip_map_right (f : β γ) (l₁ : Array α) (l₂ : Array β) :
zip l₁ (l₂.map f) = (zip l₁ l₂).map (Prod.map id f) := by rw [ zip_map, map_id]
theorem zip_append {as bs : Array α} {cs ds : Array β} (_h : as.size = cs.size) :
zip (as ++ bs) (cs ++ ds) = zip as cs ++ zip bs ds := by
cases as
cases cs
cases bs
cases ds
theorem zip_append {l₁ r₁ : Array α} {l₂ r₂ : Array β} (_h : l₁.size = l₂.size) :
zip (l₁ ++ r₁) (l₂ ++ r₂) = zip l₁ l₂ ++ zip r₁ r₂ := by
cases l₁
cases l₂
cases r₁
cases r₂
simp_all [List.zip_append]
theorem zip_map' (f : α β) (g : α γ) (xs : Array α) :
zip (xs.map f) (xs.map g) = xs.map fun a => (f a, g a) := by
cases xs
theorem zip_map' (f : α β) (g : α γ) (l : Array α) :
zip (l.map f) (l.map g) = l.map fun a => (f a, g a) := by
cases l
simp [List.zip_map']
theorem of_mem_zip {a b} {as : Array α} {bs : Array β} : (a, b) zip as bs a as b bs := by
cases as
cases bs
theorem of_mem_zip {a b} {l₁ : Array α} {l₂ : Array β} : (a, b) zip l₁ l₂ a l₁ b l₂ := by
cases l₁
cases l₂
simpa using List.of_mem_zip
theorem map_fst_zip (as : Array α) (bs : Array β) (h : as.size bs.size) :
map Prod.fst (zip as bs) = as := by
cases as
cases bs
theorem map_fst_zip (l₁ : Array α) (l₂ : Array β) (h : l₁.size l₂.size) :
map Prod.fst (zip l₁ l₂) = l₁ := by
cases l₁
cases l₂
simp_all [List.map_fst_zip]
theorem map_snd_zip (as : Array α) (bs : Array β) (h : bs.size as.size) :
map Prod.snd (zip as bs) = bs := by
cases as
cases bs
theorem map_snd_zip (l₁ : Array α) (l₂ : Array β) (h : l₂.size l₁.size) :
map Prod.snd (zip l₁ l₂) = l₂ := by
cases l₁
cases l₂
simp_all [List.map_snd_zip]
theorem map_prod_left_eq_zip {xs : Array α} (f : α β) :
(xs.map fun x => (x, f x)) = xs.zip (xs.map f) := by
theorem map_prod_left_eq_zip {l : Array α} (f : α β) :
(l.map fun x => (x, f x)) = l.zip (l.map f) := by
rw [ zip_map']
congr
simp
theorem map_prod_right_eq_zip {xs : Array α} (f : α β) :
(xs.map fun x => (f x, x)) = (xs.map f).zip xs := by
theorem map_prod_right_eq_zip {l : Array α} (f : α β) :
(l.map fun x => (f x, x)) = (l.map f).zip l := by
rw [ zip_map']
congr
simp
@[simp] theorem zip_eq_empty_iff {as : Array α} {bs : Array β} :
zip as bs = #[] as = #[] bs = #[] := by
cases as
cases bs
@[simp] theorem zip_eq_empty_iff {l₁ : Array α} {l₂ : Array β} :
zip l₁ l₂ = #[] l₁ = #[] l₂ = #[] := by
cases l₁
cases l₂
simp [List.zip_eq_nil_iff]
theorem zip_eq_append_iff {as : Array α} {bs : Array β} :
zip as bs = xs ++ ys
as₁ as₂ bs₁ bs₂, as₁.size = bs₁.size as = as₁ ++ as₂ bs = bs₁ ++ bs₂ xs = zip as₁ bs₁ ys = zip as₂ bs₂ := by
theorem zip_eq_append_iff {l₁ : Array α} {l₂ : Array β} :
zip l₁ l₂ = l₁' ++ l₂'
w x y z, w.size = y.size l₁ = w ++ x l₂ = y ++ z l₁' = zip w y l₂' = zip x z := by
simp [zip_eq_zipWith, zipWith_eq_append_iff]
@[simp] theorem zip_mkArray {a : α} {b : β} {m n : Nat} :
zip (mkArray m a) (mkArray n b) = mkArray (min m n) (a, b) := by
simp [ List.toArray_replicate]
theorem zip_eq_zip_take_min (as : Array α) (bs : Array β) :
zip as bs = zip (as.take (min as.size bs.size)) (bs.take (min as.size bs.size)) := by
cases as
cases bs
theorem zip_eq_zip_take_min (l₁ : Array α) (l₂ : Array β) :
zip l₁ l₂ = zip (l₁.take (min l₁.size l₂.size)) (l₂.take (min l₁.size l₂.size)) := by
cases l₁
cases l₂
simp only [List.zip_toArray, List.size_toArray, List.take_toArray, mk.injEq]
rw [List.zip_eq_zip_take_min]
@@ -292,30 +289,31 @@ theorem getElem?_zipWithAll {f : Option α → Option β → γ} {i : Nat} :
simp [List.getElem?_zipWithAll]
rfl
theorem zipWithAll_map {μ} (f : Option γ Option δ μ) (g : α γ) (h : β δ) (as : Array α) (bs : Array β) :
zipWithAll f (as.map g) (bs.map h) = zipWithAll (fun a b => f (g <$> a) (h <$> b)) as bs := by
cases as
cases bs
theorem zipWithAll_map {μ} (f : Option γ Option δ μ) (g : α γ) (h : β δ) (l₁ : Array α) (l₂ : Array β) :
zipWithAll f (l₁.map g) (l₂.map h) = zipWithAll (fun a b => f (g <$> a) (h <$> b)) l₁ l₂ := by
cases l₁
cases l₂
simp [List.zipWithAll_map]
theorem zipWithAll_map_left (as : Array α) (bs : Array β) (f : α α') (g : Option α' Option β γ) :
zipWithAll g (as.map f) bs = zipWithAll (fun a b => g (f <$> a) b) as bs := by
cases as
cases bs
theorem zipWithAll_map_left (l₁ : Array α) (l₂ : Array β) (f : α α') (g : Option α' Option β γ) :
zipWithAll g (l₁.map f) l₂ = zipWithAll (fun a b => g (f <$> a) b) l₁ l₂ := by
cases l₁
cases l₂
simp [List.zipWithAll_map_left]
theorem zipWithAll_map_right (as : Array α) (bs : Array β) (f : β β') (g : Option α Option β' γ) :
zipWithAll g as (bs.map f) = zipWithAll (fun a b => g a (f <$> b)) as bs := by
cases as
cases bs
theorem zipWithAll_map_right (l₁ : Array α) (l₂ : Array β) (f : β β') (g : Option α Option β' γ) :
zipWithAll g l₁ (l₂.map f) = zipWithAll (fun a b => g a (f <$> b)) l₁ l₂ := by
cases l₁
cases l₂
simp [List.zipWithAll_map_right]
theorem map_zipWithAll {δ : Type _} (f : α β) (g : Option γ Option δ α) (cs : Array γ) (ds : Array δ) :
map f (zipWithAll g cs ds) = zipWithAll (fun x y => f (g x y)) cs ds := by
cases cs
cases ds
theorem map_zipWithAll {δ : Type _} (f : α β) (g : Option γ Option δ α) (l : Array γ) (l' : Array δ) :
map f (zipWithAll g l l') = zipWithAll (fun x y => f (g x y)) l l' := by
cases l
cases l'
simp [List.map_zipWithAll]
@[simp] theorem zipWithAll_replicate {a : α} {b : β} {n : Nat} :
zipWithAll f (mkArray n a) (mkArray n b) = mkArray n (f a b) := by
simp [ List.toArray_replicate]
@@ -328,37 +326,37 @@ theorem map_zipWithAll {δ : Type _} (f : α → β) (g : Option γ → Option
@[simp] theorem unzip_snd : (unzip l).snd = l.map Prod.snd := by
induction l <;> simp_all
theorem unzip_eq_map (xs : Array (α × β)) : unzip xs = (xs.map Prod.fst, xs.map Prod.snd) := by
cases xs
theorem unzip_eq_map (l : Array (α × β)) : unzip l = (l.map Prod.fst, l.map Prod.snd) := by
cases l
simp [List.unzip_eq_map]
theorem zip_unzip (xs : Array (α × β)) : zip (unzip xs).1 (unzip xs).2 = xs := by
cases xs
theorem zip_unzip (l : Array (α × β)) : zip (unzip l).1 (unzip l).2 = l := by
cases l
simp only [List.unzip_toArray, Prod.map_fst, Prod.map_snd, List.zip_toArray, List.zip_unzip]
theorem unzip_zip_left {as : Array α} {bs : Array β} (h : as.size bs.size) :
(unzip (zip as bs)).1 = as := by
cases as
cases bs
theorem unzip_zip_left {l₁ : Array α} {l₂ : Array β} (h : l₁.size l₂.size) :
(unzip (zip l₁ l₂)).1 = l₁ := by
cases l₁
cases l₂
simp_all only [List.size_toArray, List.zip_toArray, List.unzip_toArray, Prod.map_fst,
List.unzip_zip_left]
theorem unzip_zip_right {as : Array α} {bs : Array β} (h : bs.size as.size) :
(unzip (zip as bs)).2 = bs := by
cases as
cases bs
theorem unzip_zip_right {l₁ : Array α} {l₂ : Array β} (h : l₂.size l₁.size) :
(unzip (zip l₁ l₂)).2 = l₂ := by
cases l₁
cases l₂
simp_all only [List.size_toArray, List.zip_toArray, List.unzip_toArray, Prod.map_snd,
List.unzip_zip_right]
theorem unzip_zip {as : Array α} {bs : Array β} (h : as.size = bs.size) :
unzip (zip as bs) = (as, bs) := by
cases as
cases bs
theorem unzip_zip {l₁ : Array α} {l₂ : Array β} (h : l₁.size = l₂.size) :
unzip (zip l₁ l₂) = (l₁, l₂) := by
cases l₁
cases l₂
simp_all only [List.size_toArray, List.zip_toArray, List.unzip_toArray, List.unzip_zip, Prod.map_apply]
theorem zip_of_prod {as : Array α} {bs : Array β} {xs : Array (α × β)} (hl : xs.map Prod.fst = as)
(hr : xs.map Prod.snd = bs) : xs = as.zip bs := by
rw [ hl, hr, zip_unzip xs, unzip_fst, unzip_snd, zip_unzip, zip_unzip]
theorem zip_of_prod {l : Array α} {l' : Array β} {lp : Array (α × β)} (hl : lp.map Prod.fst = l)
(hr : lp.map Prod.snd = l') : lp = l.zip l' := by
rw [ hl, hr, zip_unzip lp, unzip_fst, unzip_snd, zip_unzip, zip_unzip]
@[simp] theorem unzip_mkArray {n : Nat} {a : α} {b : β} :
unzip (mkArray n (a, b)) = (mkArray n a, mkArray n b) := by

View File

@@ -25,7 +25,7 @@ class ReflBEq (α) [BEq α] : Prop where
refl : (a : α) == a
/-- `EquivBEq` says that the `BEq` implementation is an equivalence relation. -/
class EquivBEq (α) [BEq α] : Prop extends PartialEquivBEq α, ReflBEq α
class EquivBEq (α) [BEq α] extends PartialEquivBEq α, ReflBEq α : Prop
@[simp]
theorem BEq.refl [BEq α] [ReflBEq α] {a : α} : a == a :=

View File

@@ -907,7 +907,7 @@ The input to the shift subtractor is a legal input to `divrem`, and we also need
input bit to perform shift subtraction on, and thus we need `0 < wn`.
-/
structure DivModState.Poised {w : Nat} (args : DivModArgs w) (qr : DivModState w)
extends DivModState.Lawful args qr where
extends DivModState.Lawful args qr : Type where
/-- Only perform a round of shift-subtract if we have dividend bits. -/
hwn_lt : 0 < qr.wn
@@ -1034,10 +1034,11 @@ theorem divRec_succ (m : Nat) (args : DivModArgs w) (qr : DivModState w) :
theorem lawful_divRec {args : DivModArgs w} {qr : DivModState w}
(h : DivModState.Lawful args qr) :
DivModState.Lawful args (divRec qr.wn args qr) := by
induction hm : qr.wn generalizing qr with
| zero =>
generalize hm : qr.wn = m
induction m generalizing qr
case zero =>
exact h
| succ wn' ih =>
case succ wn' ih =>
simp only [divRec_succ]
apply ih
· apply lawful_divSubtractShift
@@ -1051,10 +1052,11 @@ theorem lawful_divRec {args : DivModArgs w} {qr : DivModState w}
@[simp]
theorem wn_divRec (args : DivModArgs w) (qr : DivModState w) :
(divRec qr.wn args qr).wn = 0 := by
induction hm : qr.wn generalizing qr with
| zero =>
generalize hm : qr.wn = m
induction m generalizing qr
case zero =>
assumption
| succ wn' ih =>
case succ wn' ih =>
apply ih
simp only [divSubtractShift, hm]
split <;> rfl

View File

@@ -1517,8 +1517,8 @@ theorem zero_shiftLeft (n : Nat) : 0#w <<< n = 0#w := by
all_goals { simp_all <;> omega }
@[simp] theorem getElem_shiftLeft {x : BitVec m} {n : Nat} (h : i < m) :
(x <<< n)[i] = (!decide (i < n) && x[i - n]) := by
rw [getElem_eq_testBit_toNat, getElem_eq_testBit_toNat]
(x <<< n)[i] = (!decide (i < n) && getLsbD x (i - n)) := by
rw [ testBit_toNat, getElem_eq_testBit_toNat]
simp only [toNat_shiftLeft, Nat.testBit_mod_two_pow, Nat.testBit_shiftLeft, ge_iff_le]
-- This step could be a case bashing tactic.
cases h₁ : decide (i < m) <;> cases h₂ : decide (n i) <;> cases h₃ : decide (i < n)
@@ -1568,8 +1568,8 @@ theorem shiftLeftZeroExtend_eq {x : BitVec w} :
· omega
@[simp] theorem getElem_shiftLeftZeroExtend {x : BitVec m} {n : Nat} (h : i < m + n) :
(shiftLeftZeroExtend x n)[i] = if h' : i < n then false else x[i - n] := by
rw [shiftLeftZeroExtend_eq]
(shiftLeftZeroExtend x n)[i] = ((! decide (i < n)) && getLsbD x (i - n)) := by
rw [shiftLeftZeroExtend_eq, getLsbD]
simp only [getElem_eq_testBit_toNat, getLsbD_shiftLeft, getLsbD_setWidth]
cases h₁ : decide (i < n) <;> cases h₂ : decide (i - n < m + n)
<;> simp_all [h]
@@ -1598,8 +1598,8 @@ theorem shiftLeftZeroExtend_eq {x : BitVec w} :
theorem shiftLeft_add {w : Nat} (x : BitVec w) (n m : Nat) :
x <<< (n + m) = (x <<< n) <<< m := by
ext i
simp only [getElem_shiftLeft]
rw [show x[i - (n + m)] = x[i - m - n] by congr 1; omega]
simp only [getElem_shiftLeft, Fin.is_lt, decide_true, Bool.true_and]
rw [show i - (n + m) = (i - m - n) by omega]
cases h₂ : decide (i < m) <;>
cases h₃ : decide (i - m < w) <;>
cases h₄ : decide (i - m < n) <;>
@@ -1632,7 +1632,7 @@ theorem getLsbD_shiftLeft' {x : BitVec w₁} {y : BitVec w₂} {i : Nat} :
simp [shiftLeft_eq', getLsbD_shiftLeft]
theorem getElem_shiftLeft' {x : BitVec w₁} {y : BitVec w₂} {i : Nat} (h : i < w₁) :
(x <<< y)[i] = (!decide (i < y.toNat) && x[i - y.toNat]) := by
(x <<< y)[i] = (!decide (i < y.toNat) && x.getLsbD (i - y.toNat)) := by
simp
@[simp] theorem shiftLeft_eq_zero {x : BitVec w} {n : Nat} (hn : w n) : x <<< n = 0#w := by
@@ -1844,10 +1844,13 @@ theorem getLsbD_sshiftRight (x : BitVec w) (s i : Nat) :
omega
theorem getElem_sshiftRight {x : BitVec w} {s i : Nat} (h : i < w) :
(x.sshiftRight s)[i] = (if h : s + i < w then x[s + i] else x.msb) := by
rw [ getLsbD_eq_getElem, getLsbD_sshiftRight]
simp only [show ¬(w i) by omega, decide_false, Bool.not_false, Bool.true_and]
by_cases h' : s + i < w <;> simp [h']
(x.sshiftRight s)[i] = (if s + i < w then x.getLsbD (s + i) else x.msb) := by
rcases hmsb : x.msb with rfl | rfl
· simp only [sshiftRight_eq_of_msb_false hmsb, getElem_ushiftRight, Bool.if_false_right,
Bool.iff_and_self, decide_eq_true_eq]
intros hlsb
apply BitVec.lt_of_getLsbD hlsb
· simp [sshiftRight_eq_of_msb_true hmsb]
theorem sshiftRight_xor_distrib (x y : BitVec w) (n : Nat) :
(x ^^^ y).sshiftRight n = (x.sshiftRight n) ^^^ (y.sshiftRight n) := by
@@ -1954,8 +1957,9 @@ theorem getLsbD_sshiftRight' {x y : BitVec w} {i : Nat} :
-- This should not be a `@[simp]` lemma as the left hand side is not in simp normal form.
theorem getElem_sshiftRight' {x y : BitVec w} {i : Nat} (h : i < w) :
(x.sshiftRight' y)[i] = (if h : y.toNat + i < w then x[y.toNat + i] else x.msb) := by
simp [show ¬ w i by omega, getElem_sshiftRight]
(x.sshiftRight' y)[i] =
(!decide (w i) && if y.toNat + i < w then x.getLsbD (y.toNat + i) else x.msb) := by
simp only [ getLsbD_eq_getElem, BitVec.sshiftRight', BitVec.getLsbD_sshiftRight]
theorem getMsbD_sshiftRight' {x y: BitVec w} {i : Nat} :
(x.sshiftRight y.toNat).getMsbD i =
@@ -2026,8 +2030,9 @@ theorem getMsbD_signExtend {x : BitVec w} {v i : Nat} :
by_cases h : i < v <;> by_cases h' : v - w i <;> simp [h, h'] <;> omega
theorem getElem_signExtend {x : BitVec w} {v i : Nat} (h : i < v) :
(x.signExtend v)[i] = if h : i < w then x[i] else x.msb := by
simp [getLsbD_eq_getElem, getLsbD_signExtend, h]
(x.signExtend v)[i] = if i < w then x.getLsbD i else x.msb := by
rw [getLsbD_eq_getElem, getLsbD_signExtend]
simp [h]
theorem msb_signExtend {x : BitVec w} :
(x.signExtend v).msb = (decide (0 < v) && if w v then x.getMsbD (w - v) else x.msb) := by
@@ -2039,7 +2044,9 @@ theorem msb_signExtend {x : BitVec w} :
theorem signExtend_eq_setWidth_of_lt (x : BitVec w) {v : Nat} (hv : v w):
x.signExtend v = x.setWidth v := by
ext i h
simp [getElem_signExtend, show i < w by omega]
simp only [getElem_signExtend, h, decide_true, Bool.true_and, getElem_setWidth,
ite_eq_left_iff, Nat.not_lt]
omega
/-- Sign extending to the same bitwidth is a no op. -/
theorem signExtend_eq (x : BitVec w) : x.signExtend w = x := by
@@ -2094,7 +2101,6 @@ theorem toInt_signExtend_of_lt {x : BitVec w} (hv : w < v):
have : (x.signExtend v).msb = x.msb := by
rw [msb_eq_getLsbD_last, getLsbD_eq_getElem (Nat.sub_one_lt_of_lt hv)]
simp [getElem_signExtend, Nat.le_sub_one_of_lt hv]
omega
have H : 2^w 2^v := Nat.pow_le_pow_right (by omega) (by omega)
simp only [this, toNat_setWidth, Int.natCast_add, Int.ofNat_emod, Int.natCast_mul]
by_cases h : x.msb
@@ -2276,11 +2282,11 @@ theorem ushiftRight_eq_extractLsb'_of_lt {x : BitVec w} {n : Nat} (hn : n < w) :
theorem shiftLeft_eq_concat_of_lt {x : BitVec w} {n : Nat} (hn : n < w) :
x <<< n = (x.extractLsb' 0 (w - n) ++ 0#n).cast (by omega) := by
ext i hi
simp only [getElem_shiftLeft, getElem_cast, getElem_append, getElem_zero, getElem_extractLsb',
simp only [getElem_shiftLeft, getElem_cast, getElem_append, getLsbD_zero, getLsbD_extractLsb',
Nat.zero_add, Bool.if_false_left]
by_cases hi' : i < n
· simp [hi']
· simp [hi', show i - n < w by omega]
· simp [hi']
/-! ### rev -/
@@ -2330,7 +2336,7 @@ theorem getLsbD_cons (b : Bool) {n} (x : BitVec n) (i : Nat) :
simp [p1, p2, Nat.testBit_bool_to_nat]
theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
(cons b x)[i] = if h : i = n then b else x[i] := by
(cons b x)[i] = if i = n then b else getLsbD x i := by
simp only [getElem_eq_testBit_toNat, toNat_cons, Nat.testBit_or, getLsbD]
rw [Nat.testBit_shiftLeft]
rcases Nat.lt_trichotomy i n with i_lt_n | i_eq_n | n_lt_i
@@ -2438,7 +2444,7 @@ theorem getLsbD_concat (x : BitVec w) (b : Bool) (i : Nat) :
· simp [Nat.div_eq_of_lt b.toNat_lt, Nat.testBit_add_one]
theorem getElem_concat (x : BitVec w) (b : Bool) (i : Nat) (h : i < w + 1) :
(concat x b)[i] = if h : i = 0 then b else x[i - 1] := by
(concat x b)[i] = if i = 0 then b else x.getLsbD (i - 1) := by
simp only [concat, getElem_eq_testBit_toNat, getLsbD, toNat_append,
toNat_ofBool, Nat.testBit_or, Nat.shiftLeft_eq]
cases i
@@ -2478,7 +2484,10 @@ theorem msb_concat {w : Nat} {b : Bool} {x : BitVec w} :
simp only [BitVec.msb, getMsbD_eq_getLsbD, Nat.zero_lt_succ, decide_true, Nat.add_one_sub_one,
Nat.sub_zero, Bool.true_and]
by_cases h₀ : 0 < w
· simp [getElem_concat, h₀, show ¬ w = 0 by omega, show w - 1 < w by omega]
· simp only [Nat.lt_add_one, getLsbD_eq_getElem, getElem_concat, h₀, reduceIte, decide_true,
Bool.true_and, ite_eq_right_iff]
intro
omega
· simp [h₀, show w = 0 by omega]
@[simp] theorem toInt_concat (x : BitVec w) (b : Bool) :
@@ -4208,10 +4217,6 @@ theorem toInt_abs_eq_natAbs_of_ne_intMin {x : BitVec w} (hx : x ≠ intMin w) :
x.abs.toInt = x.toInt.natAbs := by
simp [toInt_abs_eq_natAbs, hx]
theorem toFin_abs {x : BitVec w} :
x.abs.toFin = if x.msb then Fin.ofNat' (2 ^ w) (2 ^ w - x.toNat) else x.toFin := by
by_cases h : x.msb <;> simp [BitVec.abs, h]
/-! ### Reverse -/
theorem getLsbD_reverse {i : Nat} {x : BitVec w} :

View File

@@ -7,6 +7,7 @@ prelude
import Init.Data.Int.Basic
import Init.Data.Int.Bitwise
import Init.Data.Int.DivMod
import Init.Data.Int.DivModLemmas
import Init.Data.Int.Gcd
import Init.Data.Int.Lemmas
import Init.Data.Int.LemmasAux

View File

@@ -6,7 +6,6 @@ Authors: Siddharth Bhat, Jeremy Avigad
prelude
import Init.Data.Nat.Bitwise.Lemmas
import Init.Data.Int.Bitwise
import Init.Data.Int.DivMod.Lemmas
namespace Int

View File

@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Int.DivMod.Lemmas
import Init.Data.Int.DivModLemmas
import Init.Data.Int.Gcd
/-!
@@ -99,7 +99,7 @@ def resolve_left' (a c d p x : Int) (h₁ : p ≤ a * x) : Nat := (add_of_le h
/-- `resolve_left` is nonnegative when `p ≤ a * x`. -/
theorem le_zero_resolve_left (a c d p x : Int) (h₁ : p a * x) :
0 resolve_left a c d p x := by
simp [h₁]
simpa [h₁] using Int.ofNat_nonneg _
/-- `resolve_left` is bounded above by `lcm a (a * d / gcd (a * d) c)`. -/
theorem resolve_left_lt_lcm (a c d p x : Int) (a_pos : 0 < a) (d_pos : 0 < d) (h₁ : p a * x) :

View File

@@ -1,9 +1,328 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Copyright (c) 2016 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
Authors: Jeremy Avigad, Mario Carneiro
-/
prelude
import Init.Data.Int.DivMod.Basic
import Init.Data.Int.DivMod.Bootstrap
import Init.Data.Int.DivMod.Lemmas
import Init.Data.Int.Basic
open Nat
namespace Int
/-! ## Quotient and remainder
There are three main conventions for integer division,
referred here as the E, F, T rounding conventions.
All three pairs satisfy the identity `x % y + (x / y) * y = x` unconditionally,
and satisfy `x / 0 = 0` and `x % 0 = x`.
### Historical notes
In early versions of Lean, the typeclasses provided by `/` and `%`
were defined in terms of `tdiv` and `tmod`, and these were named simply as `div` and `mod`.
However we decided it was better to use `ediv` and `emod`,
as they are consistent with the conventions used in SMTLib, and Mathlib,
and often mathematical reasoning is easier with these conventions.
At that time, we did not rename `div` and `mod` to `tdiv` and `tmod` (along with all their lemma).
In September 2024, we decided to do this rename (with deprecations in place),
and later we intend to rename `ediv` and `emod` to `div` and `mod`, as nearly all users will only
ever need to use these functions and their associated lemmas.
In December 2024, we removed `tdiv` and `tmod`, but have not yet renamed `ediv` and `emod`.
-/
/-! ### T-rounding division -/
/--
`tdiv` uses the [*"T-rounding"*][t-rounding]
(**T**runcation-rounding) convention, meaning that it rounds toward
zero. Also note that division by zero is defined to equal zero.
The relation between integer division and modulo is found in
`Int.tmod_add_tdiv` which states that
`tmod a b + b * (tdiv a b) = a`, unconditionally.
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862
[theo tmod_add_tdiv]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.tmod_add_tdiv#doc
Examples:
```
#eval (7 : Int).tdiv (0 : Int) -- 0
#eval (0 : Int).tdiv (7 : Int) -- 0
#eval (12 : Int).tdiv (6 : Int) -- 2
#eval (12 : Int).tdiv (-6 : Int) -- -2
#eval (-12 : Int).tdiv (6 : Int) -- -2
#eval (-12 : Int).tdiv (-6 : Int) -- 2
#eval (12 : Int).tdiv (7 : Int) -- 1
#eval (12 : Int).tdiv (-7 : Int) -- -1
#eval (-12 : Int).tdiv (7 : Int) -- -1
#eval (-12 : Int).tdiv (-7 : Int) -- 1
```
Implemented by efficient native code.
-/
@[extern "lean_int_div"]
def tdiv : (@& Int) (@& Int) Int
| ofNat m, ofNat n => ofNat (m / n)
| ofNat m, -[n +1] => -ofNat (m / succ n)
| -[m +1], ofNat n => -ofNat (succ m / n)
| -[m +1], -[n +1] => ofNat (succ m / succ n)
/-- Integer modulo. This function uses the
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention
to pair with `Int.tdiv`, meaning that `tmod a b + b * (tdiv a b) = a`
unconditionally (see [`Int.tmod_add_tdiv`][theo tmod_add_tdiv]). In
particular, `a % 0 = a`.
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862
[theo tmod_add_tdiv]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.tmod_add_tdiv#doc
Examples:
```
#eval (7 : Int).tmod (0 : Int) -- 7
#eval (0 : Int).tmod (7 : Int) -- 0
#eval (12 : Int).tmod (6 : Int) -- 0
#eval (12 : Int).tmod (-6 : Int) -- 0
#eval (-12 : Int).tmod (6 : Int) -- 0
#eval (-12 : Int).tmod (-6 : Int) -- 0
#eval (12 : Int).tmod (7 : Int) -- 5
#eval (12 : Int).tmod (-7 : Int) -- 5
#eval (-12 : Int).tmod (7 : Int) -- -5
#eval (-12 : Int).tmod (-7 : Int) -- -5
```
Implemented by efficient native code. -/
@[extern "lean_int_mod"]
def tmod : (@& Int) (@& Int) Int
| ofNat m, ofNat n => ofNat (m % n)
| ofNat m, -[n +1] => ofNat (m % succ n)
| -[m +1], ofNat n => -ofNat (succ m % n)
| -[m +1], -[n +1] => -ofNat (succ m % succ n)
/-! ### F-rounding division
This pair satisfies `fdiv x y = floor (x / y)`.
-/
/--
Integer division. This version of division uses the F-rounding convention
(flooring division), in which `Int.fdiv x y` satisfies `fdiv x y = floor (x / y)`
and `Int.fmod` is the unique function satisfying `fmod x y + (fdiv x y) * y = x`.
Examples:
```
#eval (7 : Int).fdiv (0 : Int) -- 0
#eval (0 : Int).fdiv (7 : Int) -- 0
#eval (12 : Int).fdiv (6 : Int) -- 2
#eval (12 : Int).fdiv (-6 : Int) -- -2
#eval (-12 : Int).fdiv (6 : Int) -- -2
#eval (-12 : Int).fdiv (-6 : Int) -- 2
#eval (12 : Int).fdiv (7 : Int) -- 1
#eval (12 : Int).fdiv (-7 : Int) -- -2
#eval (-12 : Int).fdiv (7 : Int) -- -2
#eval (-12 : Int).fdiv (-7 : Int) -- 1
```
-/
def fdiv : Int Int Int
| 0, _ => 0
| ofNat m, ofNat n => ofNat (m / n)
| ofNat (succ m), -[n+1] => -[m / succ n +1]
| -[_+1], 0 => 0
| -[m+1], ofNat (succ n) => -[m / succ n +1]
| -[m+1], -[n+1] => ofNat (succ m / succ n)
/--
Integer modulus. This version of `Int.mod` uses the F-rounding convention
(flooring division), in which `Int.fdiv x y` satisfies `fdiv x y = floor (x / y)`
and `Int.fmod` is the unique function satisfying `fmod x y + (fdiv x y) * y = x`.
Examples:
```
#eval (7 : Int).fmod (0 : Int) -- 7
#eval (0 : Int).fmod (7 : Int) -- 0
#eval (12 : Int).fmod (6 : Int) -- 0
#eval (12 : Int).fmod (-6 : Int) -- 0
#eval (-12 : Int).fmod (6 : Int) -- 0
#eval (-12 : Int).fmod (-6 : Int) -- 0
#eval (12 : Int).fmod (7 : Int) -- 5
#eval (12 : Int).fmod (-7 : Int) -- -2
#eval (-12 : Int).fmod (7 : Int) -- 2
#eval (-12 : Int).fmod (-7 : Int) -- -5
```
-/
def fmod : Int Int Int
| 0, _ => 0
| ofNat m, ofNat n => ofNat (m % n)
| ofNat (succ m), -[n+1] => subNatNat (m % succ n) n
| -[m+1], ofNat n => subNatNat n (succ (m % n))
| -[m+1], -[n+1] => -ofNat (succ m % succ n)
/-! ### E-rounding division
This pair satisfies `0 ≤ mod x y < natAbs y` for `y ≠ 0`.
-/
/--
Integer division. This version of `Int.div` uses the E-rounding convention
(euclidean division), in which `Int.emod x y` satisfies `0 ≤ mod x y < natAbs y` for `y ≠ 0`
and `Int.ediv` is the unique function satisfying `emod x y + (ediv x y) * y = x`.
This is the function powering the `/` notation on integers.
Examples:
```
#eval (7 : Int) / (0 : Int) -- 0
#eval (0 : Int) / (7 : Int) -- 0
#eval (12 : Int) / (6 : Int) -- 2
#eval (12 : Int) / (-6 : Int) -- -2
#eval (-12 : Int) / (6 : Int) -- -2
#eval (-12 : Int) / (-6 : Int) -- 2
#eval (12 : Int) / (7 : Int) -- 1
#eval (12 : Int) / (-7 : Int) -- -1
#eval (-12 : Int) / (7 : Int) -- -2
#eval (-12 : Int) / (-7 : Int) -- 2
```
Implemented by efficient native code.
-/
@[extern "lean_int_ediv"]
def ediv : (@& Int) (@& Int) Int
| ofNat m, ofNat n => ofNat (m / n)
| ofNat m, -[n+1] => -ofNat (m / succ n)
| -[_+1], 0 => 0
| -[m+1], ofNat (succ n) => -[m / succ n +1]
| -[m+1], -[n+1] => ofNat (succ (m / succ n))
/--
Integer modulus. This version of `Int.mod` uses the E-rounding convention
(euclidean division), in which `Int.emod x y` satisfies `0 ≤ emod x y < natAbs y` for `y ≠ 0`
and `Int.ediv` is the unique function satisfying `emod x y + (ediv x y) * y = x`.
This is the function powering the `%` notation on integers.
Examples:
```
#eval (7 : Int) % (0 : Int) -- 7
#eval (0 : Int) % (7 : Int) -- 0
#eval (12 : Int) % (6 : Int) -- 0
#eval (12 : Int) % (-6 : Int) -- 0
#eval (-12 : Int) % (6 : Int) -- 0
#eval (-12 : Int) % (-6 : Int) -- 0
#eval (12 : Int) % (7 : Int) -- 5
#eval (12 : Int) % (-7 : Int) -- 5
#eval (-12 : Int) % (7 : Int) -- 2
#eval (-12 : Int) % (-7 : Int) -- 2
```
Implemented by efficient native code.
-/
@[extern "lean_int_emod"]
def emod : (@& Int) (@& Int) Int
| ofNat m, n => ofNat (m % natAbs n)
| -[m+1], n => subNatNat (natAbs n) (succ (m % natAbs n))
/--
The Div and Mod syntax uses ediv and emod for compatibility with SMTLIb and mathematical
reasoning tends to be easier.
-/
instance : Div Int where
div := Int.ediv
instance : Mod Int where
mod := Int.emod
@[simp, norm_cast] theorem ofNat_ediv (m n : Nat) : ((m / n) : Int) = m / n := rfl
theorem ofNat_tdiv (m n : Nat) : (m / n) = tdiv m n := rfl
theorem ofNat_fdiv : m n : Nat, (m / n) = fdiv m n
| 0, _ => by simp [fdiv]
| succ _, _ => rfl
/-!
# `bmod` ("balanced" mod)
Balanced mod (and balanced div) are a division and modulus pair such
that `b * (Int.bdiv a b) + Int.bmod a b = a` and `-b/2 ≤ Int.bmod a b <
b/2` for all `a : Int` and `b > 0`.
This is used in Omega as well as signed bitvectors.
-/
/--
Balanced modulus. This version of Integer modulus uses the
balanced rounding convention, which guarantees that
`-m/2 ≤ bmod x m < m/2` for `m ≠ 0` and `bmod x m` is congruent
to `x` modulo `m`.
If `m = 0`, then `bmod x m = x`.
Examples:
```
#eval (7 : Int).bdiv 0 -- 0
#eval (0 : Int).bdiv 7 -- 0
#eval (12 : Int).bdiv 6 -- 2
#eval (12 : Int).bdiv 7 -- 2
#eval (12 : Int).bdiv 8 -- 2
#eval (12 : Int).bdiv 9 -- 1
#eval (-12 : Int).bdiv 6 -- -2
#eval (-12 : Int).bdiv 7 -- -2
#eval (-12 : Int).bdiv 8 -- -1
#eval (-12 : Int).bdiv 9 -- -1
```
-/
def bmod (x : Int) (m : Nat) : Int :=
let r := x % m
if r < (m + 1) / 2 then
r
else
r - m
/--
Balanced division. This returns the unique integer so that
`b * (Int.bdiv a b) + Int.bmod a b = a`.
Examples:
```
#eval (7 : Int).bmod 0 -- 7
#eval (0 : Int).bmod 7 -- 0
#eval (12 : Int).bmod 6 -- 0
#eval (12 : Int).bmod 7 -- -2
#eval (12 : Int).bmod 8 -- -4
#eval (12 : Int).bmod 9 -- 3
#eval (-12 : Int).bmod 6 -- 0
#eval (-12 : Int).bmod 7 -- 2
#eval (-12 : Int).bmod 8 -- -4
#eval (-12 : Int).bmod 9 -- -3
```
-/
def bdiv (x : Int) (m : Nat) : Int :=
if m = 0 then
0
else
let q := x / m
let r := x % m
if r < (m + 1) / 2 then
q
else
q + 1
end Int

View File

@@ -1,336 +0,0 @@
/-
Copyright (c) 2016 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Mario Carneiro
-/
prelude
import Init.Data.Int.Basic
open Nat
namespace Int
/-! ## Quotient and remainder
There are three main conventions for integer division,
referred here as the E, F, T rounding conventions.
All three pairs satisfy the identity `x % y + (x / y) * y = x` unconditionally,
and satisfy `x / 0 = 0` and `x % 0 = x`.
### Historical notes
In early versions of Lean, the typeclasses provided by `/` and `%`
were defined in terms of `tdiv` and `tmod`, and these were named simply as `div` and `mod`.
However we decided it was better to use `ediv` and `emod`,
as they are consistent with the conventions used in SMTLib, and Mathlib,
and often mathematical reasoning is easier with these conventions.
At that time, we did not rename `div` and `mod` to `tdiv` and `tmod` (along with all their lemma).
In September 2024, we decided to do this rename (with deprecations in place),
and later we intend to rename `ediv` and `emod` to `div` and `mod`, as nearly all users will only
ever need to use these functions and their associated lemmas.
In December 2024, we removed `tdiv` and `tmod`, but have not yet renamed `ediv` and `emod`.
-/
/-! ### E-rounding division
This pair satisfies `0 ≤ mod x y < natAbs y` for `y ≠ 0`.
-/
/--
Integer division. This version of `Int.div` uses the E-rounding convention
(euclidean division), in which `Int.emod x y` satisfies `0 ≤ mod x y < natAbs y` for `y ≠ 0`
and `Int.ediv` is the unique function satisfying `emod x y + (ediv x y) * y = x`.
This is the function powering the `/` notation on integers.
Examples:
```
#eval (7 : Int) / (0 : Int) -- 0
#eval (0 : Int) / (7 : Int) -- 0
#eval (12 : Int) / (6 : Int) -- 2
#eval (12 : Int) / (-6 : Int) -- -2
#eval (-12 : Int) / (6 : Int) -- -2
#eval (-12 : Int) / (-6 : Int) -- 2
#eval (12 : Int) / (7 : Int) -- 1
#eval (12 : Int) / (-7 : Int) -- -1
#eval (-12 : Int) / (7 : Int) -- -2
#eval (-12 : Int) / (-7 : Int) -- 2
```
Implemented by efficient native code.
-/
@[extern "lean_int_ediv"]
def ediv : (@& Int) (@& Int) Int
| ofNat m, ofNat n => ofNat (m / n)
| ofNat m, -[n+1] => -ofNat (m / succ n)
| -[_+1], 0 => 0
| -[m+1], ofNat (succ n) => -[m / succ n +1]
| -[m+1], -[n+1] => ofNat (succ (m / succ n))
/--
Integer modulus. This version of `Int.mod` uses the E-rounding convention
(euclidean division), in which `Int.emod x y` satisfies `0 ≤ emod x y < natAbs y` for `y ≠ 0`
and `Int.ediv` is the unique function satisfying `emod x y + (ediv x y) * y = x`.
This is the function powering the `%` notation on integers.
Examples:
```
#eval (7 : Int) % (0 : Int) -- 7
#eval (0 : Int) % (7 : Int) -- 0
#eval (12 : Int) % (6 : Int) -- 0
#eval (12 : Int) % (-6 : Int) -- 0
#eval (-12 : Int) % (6 : Int) -- 0
#eval (-12 : Int) % (-6 : Int) -- 0
#eval (12 : Int) % (7 : Int) -- 5
#eval (12 : Int) % (-7 : Int) -- 5
#eval (-12 : Int) % (7 : Int) -- 2
#eval (-12 : Int) % (-7 : Int) -- 2
```
Implemented by efficient native code.
-/
@[extern "lean_int_emod"]
def emod : (@& Int) (@& Int) Int
| ofNat m, n => ofNat (m % natAbs n)
| -[m+1], n => subNatNat (natAbs n) (succ (m % natAbs n))
/--
The Div and Mod syntax uses ediv and emod for compatibility with SMTLIb and mathematical
reasoning tends to be easier.
-/
instance : Div Int where
div := Int.ediv
instance : Mod Int where
mod := Int.emod
@[simp, norm_cast] theorem ofNat_ediv (m n : Nat) : ((m / n) : Int) = m / n := rfl
theorem ofNat_ediv_ofNat {a b : Nat} : (a / b : Int) = (a / b : Nat) := rfl
@[norm_cast]
theorem negSucc_ediv_ofNat_succ {a b : Nat} : ((-[a+1]) / (b+1) : Int) = -[a / succ b +1] := rfl
theorem negSucc_ediv_negSucc {a b : Nat} : ((-[a+1]) / (-[b+1]) : Int) = ((a / (b + 1)) + 1 : Nat) := rfl
theorem ofNat_ediv_negSucc {a b : Nat} : (ofNat a / (-[b+1])) = -(a / (b + 1) : Nat) := rfl
theorem negSucc_emod_ofNat {a b : Nat} : -[a+1] % (b : Int) = subNatNat b (succ (a % b)) := rfl
theorem negSucc_emod_negSucc {a b : Nat} : -[a+1] % -[b+1] = subNatNat (b + 1) (succ (a % (b + 1))) := rfl
/-! ### T-rounding division -/
/--
`tdiv` uses the [*"T-rounding"*][t-rounding]
(**T**runcation-rounding) convention, meaning that it rounds toward
zero. Also note that division by zero is defined to equal zero.
The relation between integer division and modulo is found in
`Int.tmod_add_tdiv` which states that
`tmod a b + b * (tdiv a b) = a`, unconditionally.
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862
[theo tmod_add_tdiv]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.tmod_add_tdiv#doc
Examples:
```
#eval (7 : Int).tdiv (0 : Int) -- 0
#eval (0 : Int).tdiv (7 : Int) -- 0
#eval (12 : Int).tdiv (6 : Int) -- 2
#eval (12 : Int).tdiv (-6 : Int) -- -2
#eval (-12 : Int).tdiv (6 : Int) -- -2
#eval (-12 : Int).tdiv (-6 : Int) -- 2
#eval (12 : Int).tdiv (7 : Int) -- 1
#eval (12 : Int).tdiv (-7 : Int) -- -1
#eval (-12 : Int).tdiv (7 : Int) -- -1
#eval (-12 : Int).tdiv (-7 : Int) -- 1
```
Implemented by efficient native code.
-/
@[extern "lean_int_div"]
def tdiv : (@& Int) (@& Int) Int
| ofNat m, ofNat n => ofNat (m / n)
| ofNat m, -[n +1] => -ofNat (m / succ n)
| -[m +1], ofNat n => -ofNat (succ m / n)
| -[m +1], -[n +1] => ofNat (succ m / succ n)
/-- Integer modulo. This function uses the
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention
to pair with `Int.tdiv`, meaning that `tmod a b + b * (tdiv a b) = a`
unconditionally (see [`Int.tmod_add_tdiv`][theo tmod_add_tdiv]). In
particular, `a % 0 = a`.
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862
[theo tmod_add_tdiv]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.tmod_add_tdiv#doc
Examples:
```
#eval (7 : Int).tmod (0 : Int) -- 7
#eval (0 : Int).tmod (7 : Int) -- 0
#eval (12 : Int).tmod (6 : Int) -- 0
#eval (12 : Int).tmod (-6 : Int) -- 0
#eval (-12 : Int).tmod (6 : Int) -- 0
#eval (-12 : Int).tmod (-6 : Int) -- 0
#eval (12 : Int).tmod (7 : Int) -- 5
#eval (12 : Int).tmod (-7 : Int) -- 5
#eval (-12 : Int).tmod (7 : Int) -- -5
#eval (-12 : Int).tmod (-7 : Int) -- -5
```
Implemented by efficient native code. -/
@[extern "lean_int_mod"]
def tmod : (@& Int) (@& Int) Int
| ofNat m, ofNat n => ofNat (m % n)
| ofNat m, -[n +1] => ofNat (m % succ n)
| -[m +1], ofNat n => -ofNat (succ m % n)
| -[m +1], -[n +1] => -ofNat (succ m % succ n)
theorem ofNat_tdiv (m n : Nat) : (m / n) = tdiv m n := rfl
/-! ### F-rounding division
This pair satisfies `fdiv x y = floor (x / y)`.
-/
/--
Integer division. This version of division uses the F-rounding convention
(flooring division), in which `Int.fdiv x y` satisfies `fdiv x y = floor (x / y)`
and `Int.fmod` is the unique function satisfying `fmod x y + (fdiv x y) * y = x`.
Examples:
```
#eval (7 : Int).fdiv (0 : Int) -- 0
#eval (0 : Int).fdiv (7 : Int) -- 0
#eval (12 : Int).fdiv (6 : Int) -- 2
#eval (12 : Int).fdiv (-6 : Int) -- -2
#eval (-12 : Int).fdiv (6 : Int) -- -2
#eval (-12 : Int).fdiv (-6 : Int) -- 2
#eval (12 : Int).fdiv (7 : Int) -- 1
#eval (12 : Int).fdiv (-7 : Int) -- -2
#eval (-12 : Int).fdiv (7 : Int) -- -2
#eval (-12 : Int).fdiv (-7 : Int) -- 1
```
-/
def fdiv : Int Int Int
| 0, _ => 0
| ofNat m, ofNat n => ofNat (m / n)
| ofNat (succ m), -[n+1] => -[m / succ n +1]
| -[_+1], 0 => 0
| -[m+1], ofNat (succ n) => -[m / succ n +1]
| -[m+1], -[n+1] => ofNat (succ m / succ n)
/--
Integer modulus. This version of `Int.mod` uses the F-rounding convention
(flooring division), in which `Int.fdiv x y` satisfies `fdiv x y = floor (x / y)`
and `Int.fmod` is the unique function satisfying `fmod x y + (fdiv x y) * y = x`.
Examples:
```
#eval (7 : Int).fmod (0 : Int) -- 7
#eval (0 : Int).fmod (7 : Int) -- 0
#eval (12 : Int).fmod (6 : Int) -- 0
#eval (12 : Int).fmod (-6 : Int) -- 0
#eval (-12 : Int).fmod (6 : Int) -- 0
#eval (-12 : Int).fmod (-6 : Int) -- 0
#eval (12 : Int).fmod (7 : Int) -- 5
#eval (12 : Int).fmod (-7 : Int) -- -2
#eval (-12 : Int).fmod (7 : Int) -- 2
#eval (-12 : Int).fmod (-7 : Int) -- -5
```
-/
def fmod : Int Int Int
| 0, _ => 0
| ofNat m, ofNat n => ofNat (m % n)
| ofNat (succ m), -[n+1] => subNatNat (m % succ n) n
| -[m+1], ofNat n => subNatNat n (succ (m % n))
| -[m+1], -[n+1] => -ofNat (succ m % succ n)
theorem ofNat_fdiv : m n : Nat, (m / n) = fdiv m n
| 0, _ => by simp [fdiv]
| succ _, _ => rfl
/-!
# `bmod` ("balanced" mod)
Balanced mod (and balanced div) are a division and modulus pair such
that `b * (Int.bdiv a b) + Int.bmod a b = a` and
`-b/2 ≤ Int.bmod a b < b/2` for all `a : Int` and `b > 0`.
This is used in Omega as well as signed bitvectors.
-/
/--
Balanced modulus. This version of Integer modulus uses the
balanced rounding convention, which guarantees that
`-m/2 ≤ bmod x m < m/2` for `m ≠ 0` and `bmod x m` is congruent
to `x` modulo `m`.
If `m = 0`, then `bmod x m = x`.
Examples:
```
#eval (7 : Int).bdiv 0 -- 0
#eval (0 : Int).bdiv 7 -- 0
#eval (12 : Int).bdiv 6 -- 2
#eval (12 : Int).bdiv 7 -- 2
#eval (12 : Int).bdiv 8 -- 2
#eval (12 : Int).bdiv 9 -- 1
#eval (-12 : Int).bdiv 6 -- -2
#eval (-12 : Int).bdiv 7 -- -2
#eval (-12 : Int).bdiv 8 -- -1
#eval (-12 : Int).bdiv 9 -- -1
```
-/
def bmod (x : Int) (m : Nat) : Int :=
let r := x % m
if r < (m + 1) / 2 then
r
else
r - m
/--
Balanced division. This returns the unique integer so that
`b * (Int.bdiv a b) + Int.bmod a b = a`.
Examples:
```
#eval (7 : Int).bmod 0 -- 7
#eval (0 : Int).bmod 7 -- 0
#eval (12 : Int).bmod 6 -- 0
#eval (12 : Int).bmod 7 -- -2
#eval (12 : Int).bmod 8 -- -4
#eval (12 : Int).bmod 9 -- 3
#eval (-12 : Int).bmod 6 -- 0
#eval (-12 : Int).bmod 7 -- 2
#eval (-12 : Int).bmod 8 -- -4
#eval (-12 : Int).bmod 9 -- -3
```
-/
def bdiv (x : Int) (m : Nat) : Int :=
if m = 0 then
0
else
let q := x / m
let r := x % m
if r < (m + 1) / 2 then
q
else
q + 1
end Int

View File

@@ -1,322 +0,0 @@
/-
Copyright (c) 2016 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Mario Carneiro
-/
prelude
import Init.Data.Int.DivMod.Basic
import Init.Data.Int.Order
import Init.Data.Nat.Dvd
import Init.RCases
/-!
# Lemmas about integer division needed to bootstrap `omega`.
-/
open Nat (succ)
namespace Int
-- /-! ### dvd -/
protected theorem dvd_def (a b : Int) : (a b) = Exists (fun c => b = a * c) := rfl
@[simp] protected theorem dvd_zero (n : Int) : n 0 := 0, (Int.mul_zero _).symm
@[simp] protected theorem dvd_refl (n : Int) : n n := 1, (Int.mul_one _).symm
@[simp] protected theorem one_dvd (n : Int) : 1 n := n, (Int.one_mul n).symm
protected theorem dvd_trans : {a b c : Int}, a b b c a c
| _, _, _, d, rfl, e, rfl => Exists.intro (d * e) (by rw [Int.mul_assoc])
@[norm_cast] theorem ofNat_dvd {m n : Nat} : (m : Int) n m n := by
refine fun a, ae => ?_, fun k, e => k, by rw [e, Int.ofNat_mul]
match Int.le_total a 0 with
| .inl h =>
have := ae.symm Int.mul_nonpos_of_nonneg_of_nonpos (ofNat_zero_le _) h
rw [Nat.le_antisymm (ofNat_le.1 this) (Nat.zero_le _)]
apply Nat.dvd_zero
| .inr h => match a, eq_ofNat_of_zero_le h with
| _, k, rfl => exact k, Int.ofNat.inj ae
@[simp] protected theorem zero_dvd {n : Int} : 0 n n = 0 :=
Iff.intro (fun k, e => by rw [e, Int.zero_mul])
(fun h => h.symm Int.dvd_refl _)
protected theorem dvd_mul_right (a b : Int) : a a * b := _, rfl
protected theorem dvd_mul_left (a b : Int) : b a * b := _, Int.mul_comm ..
@[simp] protected theorem neg_dvd {a b : Int} : -a b a b := by
constructor <;> exact fun k, e =>
-k, by simp [e, Int.neg_mul, Int.mul_neg, Int.neg_neg]
protected theorem dvd_neg {a b : Int} : a -b a b := by
constructor <;> exact fun k, e =>
-k, by simp [ e, Int.neg_mul, Int.mul_neg, Int.neg_neg]
@[simp] theorem natAbs_dvd_natAbs {a b : Int} : natAbs a natAbs b a b := by
refine fun k, hk => ?_, fun k, hk => natAbs k, hk.symm natAbs_mul a k
rw [ natAbs_ofNat k, natAbs_mul, natAbs_eq_natAbs_iff] at hk
cases hk <;> subst b
· apply Int.dvd_mul_right
· rw [ Int.mul_neg]; apply Int.dvd_mul_right
theorem ofNat_dvd_left {n : Nat} {z : Int} : (n : Int) z n z.natAbs := by
rw [ natAbs_dvd_natAbs, natAbs_ofNat]
/-! ### *div zero -/
@[simp] theorem zero_ediv : b : Int, 0 / b = 0
| ofNat _ => show ofNat _ = _ by simp
| -[_+1] => show -ofNat _ = _ by simp
@[simp] protected theorem ediv_zero : a : Int, a / 0 = 0
| ofNat _ => show ofNat _ = _ by simp
| -[_+1] => rfl
/-! ### mod zero -/
@[simp] theorem zero_emod (b : Int) : 0 % b = 0 := rfl
@[simp] theorem emod_zero : a : Int, a % 0 = a
| ofNat _ => congrArg ofNat <| Nat.mod_zero _
| -[_+1] => congrArg negSucc <| Nat.mod_zero _
/-! ### ofNat mod -/
@[simp, norm_cast] theorem ofNat_emod (m n : Nat) : ((m % n) : Int) = m % n := rfl
/-! ### mod definitions -/
theorem emod_add_ediv : a b : Int, a % b + b * (a / b) = a
| ofNat _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..
| ofNat m, -[n+1] => by
show (m % succ n + -(succ n) * -(m / succ n) : Int) = m
rw [Int.neg_mul_neg]; exact congrArg ofNat <| Nat.mod_add_div ..
| -[_+1], 0 => by rw [emod_zero]; rfl
| -[m+1], succ n => aux m n.succ
| -[m+1], -[n+1] => aux m n.succ
where
aux (m n : Nat) : n - (m % n + 1) - (n * (m / n) + n) = -[m+1] := by
rw [ ofNat_emod, ofNat_ediv, Int.sub_sub, negSucc_eq, Int.sub_sub n,
Int.neg_neg (_-_), Int.neg_sub, Int.sub_sub_self, Int.add_right_comm]
exact congrArg (fun x => -(ofNat x + 1)) (Nat.mod_add_div ..)
theorem emod_add_ediv' (a b : Int) : a % b + a / b * b = a := by
rw [Int.mul_comm]; exact emod_add_ediv ..
theorem ediv_add_emod (a b : Int) : b * (a / b) + a % b = a := by
rw [Int.add_comm]; exact emod_add_ediv ..
theorem emod_def (a b : Int) : a % b = a - b * (a / b) := by
rw [ Int.add_sub_cancel (a % b), emod_add_ediv]
/-! ### `/` ediv -/
@[simp] protected theorem ediv_neg : a b : Int, a / (-b) = -(a / b)
| ofNat m, 0 => show ofNat (m / 0) = -(m / 0) by rw [Nat.div_zero]; rfl
| ofNat _, -[_+1] => (Int.neg_neg _).symm
| ofNat _, succ _ | -[_+1], 0 | -[_+1], succ _ | -[_+1], -[_+1] => rfl
protected theorem div_def (a b : Int) : a / b = Int.ediv a b := rfl
theorem add_mul_ediv_right (a b : Int) {c : Int} (H : c 0) : (a + b * c) / c = a / c + b :=
suffices {{a b c : Int}}, 0 < c (a + b * c).ediv c = a.ediv c + b from
match Int.lt_trichotomy c 0 with
| Or.inl hlt => by
rw [ Int.neg_inj, Int.ediv_neg, Int.neg_add, Int.ediv_neg, Int.neg_mul_neg]
exact this (Int.neg_pos_of_neg hlt)
| Or.inr (Or.inl HEq) => absurd HEq H
| Or.inr (Or.inr hgt) => this hgt
suffices {k n : Nat} {a : Int}, (a + n * k.succ).ediv k.succ = a.ediv k.succ + n from
fun a b c H => match c, eq_succ_of_zero_lt H, b with
| _, _, rfl, ofNat _ => this
| _, k, rfl, -[n+1] => show (a - n.succ * k.succ).ediv k.succ = a.ediv k.succ - n.succ by
rw [ Int.add_sub_cancel (ediv ..), this, Int.sub_add_cancel]
fun {k n} => @fun
| ofNat _ => congrArg ofNat <| Nat.add_mul_div_right _ _ k.succ_pos
| -[m+1] => by
show ((n * k.succ : Nat) - m.succ : Int).ediv k.succ = n - (m / k.succ + 1 : Nat)
by_cases h : m < n * k.succ
· rw [ Int.ofNat_sub h, Int.ofNat_sub ((Nat.div_lt_iff_lt_mul k.succ_pos).2 h)]
apply congrArg ofNat
rw [Nat.mul_comm, Nat.mul_sub_div]; rwa [Nat.mul_comm]
· have h := Nat.not_lt.1 h
have H {a b : Nat} (h : a b) : (a : Int) + -((b : Int) + 1) = -[b - a +1] := by
rw [negSucc_eq, Int.ofNat_sub h]
simp only [Int.sub_eq_add_neg, Int.neg_add, Int.neg_neg, Int.add_left_comm, Int.add_assoc]
show ediv ((n * succ k) + -((m : Int) + 1)) (succ k) = n + -((m / succ k) + 1 : Int)
rw [H h, H ((Nat.le_div_iff_mul_le k.succ_pos).2 h)]
apply congrArg negSucc
rw [Nat.mul_comm, Nat.sub_mul_div]; rwa [Nat.mul_comm]
theorem add_ediv_of_dvd_right {a b c : Int} (H : c b) : (a + b) / c = a / c + b / c :=
if h : c = 0 then by simp [h] else by
let k, hk := H
rw [hk, Int.mul_comm c k, Int.add_mul_ediv_right _ _ h,
Int.zero_add (k * c), Int.add_mul_ediv_right _ _ h, Int.zero_ediv, Int.zero_add]
theorem add_ediv_of_dvd_left {a b c : Int} (H : c a) : (a + b) / c = a / c + b / c := by
rw [Int.add_comm, Int.add_ediv_of_dvd_right H, Int.add_comm]
@[simp] theorem mul_ediv_cancel (a : Int) {b : Int} (H : b 0) : (a * b) / b = a := by
have := Int.add_mul_ediv_right 0 a H
rwa [Int.zero_add, Int.zero_ediv, Int.zero_add] at this
@[simp] theorem mul_ediv_cancel_left (b : Int) (H : a 0) : (a * b) / a = b :=
Int.mul_comm .. Int.mul_ediv_cancel _ H
theorem div_nonneg_iff_of_pos {a b : Int} (h : 0 < b) : a / b 0 a 0 := by
rw [Int.div_def]
match b, h with
| Int.ofNat (b+1), _ =>
rcases a with a <;> simp [Int.ediv]
norm_cast
simp
/-! ### emod -/
theorem emod_nonneg : (a : Int) {b : Int}, b 0 0 a % b
| ofNat _, _, _ => ofNat_zero_le _
| -[_+1], _, H => Int.sub_nonneg_of_le <| ofNat_le.2 <| Nat.mod_lt _ (natAbs_pos.2 H)
theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < b :=
match a, b, eq_succ_of_zero_lt H with
| ofNat _, _, _, rfl => ofNat_lt.2 (Nat.mod_lt _ (Nat.succ_pos _))
| -[_+1], _, _, rfl => Int.sub_lt_self _ (ofNat_lt.2 <| Nat.succ_pos _)
theorem mul_ediv_self_le {x k : Int} (h : k 0) : k * (x / k) x :=
calc k * (x / k)
_ k * (x / k) + x % k := Int.le_add_of_nonneg_right (emod_nonneg x h)
_ = x := ediv_add_emod _ _
theorem lt_mul_ediv_self_add {x k : Int} (h : 0 < k) : x < k * (x / k) + k :=
calc x
_ = k * (x / k) + x % k := (ediv_add_emod _ _).symm
_ < k * (x / k) + k := Int.add_lt_add_left (emod_lt_of_pos x h) _
@[simp] theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
if cz : c = 0 then by
rw [cz, Int.mul_zero, Int.add_zero]
else by
rw [Int.emod_def, Int.emod_def, Int.add_mul_ediv_right _ _ cz, Int.add_comm _ b,
Int.mul_add, Int.mul_comm, Int.sub_sub, Int.add_sub_cancel]
@[simp] theorem add_mul_emod_self_left (a b c : Int) : (a + b * c) % b = a % b := by
rw [Int.mul_comm, Int.add_mul_emod_self]
@[simp] theorem emod_add_emod (m n k : Int) : (m % n + k) % n = (m + k) % n := by
have := (add_mul_emod_self_left (m % n + k) n (m / n)).symm
rwa [Int.add_right_comm, emod_add_ediv] at this
@[simp] theorem add_emod_emod (m n k : Int) : (m + n % k) % k = (m + n) % k := by
rw [Int.add_comm, emod_add_emod, Int.add_comm]
theorem add_emod (a b n : Int) : (a + b) % n = (a % n + b % n) % n := by
rw [add_emod_emod, emod_add_emod]
theorem add_emod_eq_add_emod_right {m n k : Int} (i : Int)
(H : m % n = k % n) : (m + i) % n = (k + i) % n := by
rw [ emod_add_emod, emod_add_emod k, H]
theorem emod_add_cancel_right {m n k : Int} (i) : (m + i) % n = (k + i) % n m % n = k % n :=
fun H => by
have := add_emod_eq_add_emod_right (-i) H
rwa [Int.add_neg_cancel_right, Int.add_neg_cancel_right] at this,
add_emod_eq_add_emod_right _
@[simp] theorem mul_emod_left (a b : Int) : (a * b) % b = 0 := by
rw [ Int.zero_add (a * b), Int.add_mul_emod_self, Int.zero_emod]
@[simp] theorem mul_emod_right (a b : Int) : (a * b) % a = 0 := by
rw [Int.mul_comm, mul_emod_left]
theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
conv => lhs; rw [
emod_add_ediv a n, emod_add_ediv' b n, Int.add_mul, Int.mul_add, Int.mul_add,
Int.mul_assoc, Int.mul_assoc, Int.mul_add n _ _, add_mul_emod_self_left,
Int.mul_assoc, add_mul_emod_self]
@[simp] theorem emod_self {a : Int} : a % a = 0 := by
have := mul_emod_left 1 a; rwa [Int.one_mul] at this
@[simp] theorem emod_emod_of_dvd (n : Int) {m k : Int}
(h : m k) : (n % k) % m = n % m := by
conv => rhs; rw [ emod_add_ediv n k]
match k, h with
| _, t, rfl => rw [Int.mul_assoc, add_mul_emod_self_left]
@[simp] theorem emod_emod (a b : Int) : (a % b) % b = a % b := by
conv => rhs; rw [ emod_add_ediv a b, add_mul_emod_self_left]
theorem sub_emod (a b n : Int) : (a - b) % n = (a % n - b % n) % n := by
apply (emod_add_cancel_right b).mp
rw [Int.sub_add_cancel, Int.add_emod_emod, Int.sub_add_cancel, emod_emod]
/-! ### properties of `/` and `%` -/
theorem mul_ediv_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : b * (a / b) = a := by
have := emod_add_ediv a b; rwa [H, Int.zero_add] at this
theorem ediv_mul_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : a / b * b = a := by
rw [Int.mul_comm, mul_ediv_cancel_of_emod_eq_zero H]
theorem dvd_of_emod_eq_zero {a b : Int} (H : b % a = 0) : a b :=
b / a, (mul_ediv_cancel_of_emod_eq_zero H).symm
theorem emod_eq_zero_of_dvd : {a b : Int}, a b b % a = 0
| _, _, _, rfl => mul_emod_right ..
theorem dvd_iff_emod_eq_zero {a b : Int} : a b b % a = 0 :=
emod_eq_zero_of_dvd, dvd_of_emod_eq_zero
protected theorem mul_ediv_assoc (a : Int) : {b c : Int}, c b (a * b) / c = a * (b / c)
| _, c, d, rfl =>
if cz : c = 0 then by simp [cz, Int.mul_zero] else by
rw [Int.mul_left_comm, Int.mul_ediv_cancel_left _ cz, Int.mul_ediv_cancel_left _ cz]
protected theorem mul_ediv_assoc' (b : Int) {a c : Int}
(h : c a) : (a * b) / c = a / c * b := by
rw [Int.mul_comm, Int.mul_ediv_assoc _ h, Int.mul_comm]
theorem neg_ediv_of_dvd : {a b : Int}, b a (-a) / b = -(a / b)
| _, b, c, rfl => by
by_cases bz : b = 0
· simp [bz]
· rw [Int.neg_mul_eq_mul_neg, Int.mul_ediv_cancel_left _ bz, Int.mul_ediv_cancel_left _ bz]
theorem sub_ediv_of_dvd (a : Int) {b c : Int}
(hcb : c b) : (a - b) / c = a / c - b / c := by
rw [Int.sub_eq_add_neg, Int.sub_eq_add_neg, Int.add_ediv_of_dvd_right (Int.dvd_neg.2 hcb)]
congr; exact Int.neg_ediv_of_dvd hcb
protected theorem ediv_mul_cancel {a b : Int} (H : b a) : a / b * b = a :=
ediv_mul_cancel_of_emod_eq_zero (emod_eq_zero_of_dvd H)
protected theorem mul_ediv_cancel' {a b : Int} (H : a b) : a * (b / a) = b := by
rw [Int.mul_comm, Int.ediv_mul_cancel H]
theorem emod_pos_of_not_dvd {a b : Int} (h : ¬ a b) : a = 0 0 < b % a := by
rw [dvd_iff_emod_eq_zero] at h
by_cases w : a = 0
· simp_all
· exact Or.inr (Int.lt_iff_le_and_ne.mpr emod_nonneg b w, Ne.symm h)
/-! ### bmod -/
@[simp] theorem bmod_emod : bmod x m % m = x % m := by
dsimp [bmod]
split <;> simp [Int.sub_emod]
theorem bmod_def (x : Int) (m : Nat) : bmod x m =
if (x % m) < (m + 1) / 2 then
x % m
else
(x % m) - m :=
rfl
end Int

View File

@@ -5,16 +5,13 @@ Authors: Jeremy Avigad, Mario Carneiro
-/
prelude
import Init.Data.Int.DivMod.Bootstrap
import Init.Data.Nat.Lemmas
import Init.Data.Nat.Div.Lemmas
import Init.Data.Int.DivMod
import Init.Data.Int.Order
import Init.Data.Int.Lemmas
import Init.Data.Nat.Dvd
import Init.RCases
/-!
# Further lemmas about integer division, now that `omega` is available.
# Lemmas about integer division needed to bootstrap `omega`.
-/
open Nat (succ)
@@ -23,11 +20,58 @@ namespace Int
/-! ### dvd -/
protected theorem dvd_def (a b : Int) : (a b) = Exists (fun c => b = a * c) := rfl
@[simp] protected theorem dvd_zero (n : Int) : n 0 := 0, (Int.mul_zero _).symm
@[simp] protected theorem dvd_refl (n : Int) : n n := 1, (Int.mul_one _).symm
@[simp] protected theorem one_dvd (n : Int) : 1 n := n, (Int.one_mul n).symm
protected theorem dvd_trans : {a b c : Int}, a b b c a c
| _, _, _, d, rfl, e, rfl => Exists.intro (d * e) (by rw [Int.mul_assoc])
@[norm_cast] theorem ofNat_dvd {m n : Nat} : (m : Int) n m n := by
refine fun a, ae => ?_, fun k, e => k, by rw [e, Int.ofNat_mul]
match Int.le_total a 0 with
| .inl h =>
have := ae.symm Int.mul_nonpos_of_nonneg_of_nonpos (ofNat_zero_le _) h
rw [Nat.le_antisymm (ofNat_le.1 this) (Nat.zero_le _)]
apply Nat.dvd_zero
| .inr h => match a, eq_ofNat_of_zero_le h with
| _, k, rfl => exact k, Int.ofNat.inj ae
theorem dvd_antisymm {a b : Int} (H1 : 0 a) (H2 : 0 b) : a b b a a = b := by
rw [ natAbs_of_nonneg H1, natAbs_of_nonneg H2]
rw [ofNat_dvd, ofNat_dvd, ofNat_inj]
apply Nat.dvd_antisymm
@[simp] protected theorem zero_dvd {n : Int} : 0 n n = 0 :=
Iff.intro (fun k, e => by rw [e, Int.zero_mul])
(fun h => h.symm Int.dvd_refl _)
protected theorem dvd_mul_right (a b : Int) : a a * b := _, rfl
protected theorem dvd_mul_left (a b : Int) : b a * b := _, Int.mul_comm ..
@[simp] protected theorem neg_dvd {a b : Int} : -a b a b := by
constructor <;> exact fun k, e =>
-k, by simp [e, Int.neg_mul, Int.mul_neg, Int.neg_neg]
protected theorem dvd_neg {a b : Int} : a -b a b := by
constructor <;> exact fun k, e =>
-k, by simp [ e, Int.neg_mul, Int.mul_neg, Int.neg_neg]
@[simp] theorem natAbs_dvd_natAbs {a b : Int} : natAbs a natAbs b a b := by
refine fun k, hk => ?_, fun k, hk => natAbs k, hk.symm natAbs_mul a k
rw [ natAbs_ofNat k, natAbs_mul, natAbs_eq_natAbs_iff] at hk
cases hk <;> subst b
· apply Int.dvd_mul_right
· rw [ Int.mul_neg]; apply Int.dvd_mul_right
theorem ofNat_dvd_left {n : Nat} {z : Int} : (n : Int) z n z.natAbs := by
rw [ natAbs_dvd_natAbs, natAbs_ofNat]
protected theorem dvd_add : {a b c : Int}, a b a c a b + c
| _, _, _, d, rfl, e, rfl => d + e, by rw [Int.mul_add]
@@ -73,14 +117,6 @@ theorem dvd_natAbs_self {a : Int} : a (a.natAbs : Int) := by
theorem ofNat_dvd_right {n : Nat} {z : Int} : z (n : Int) z.natAbs n := by
rw [ natAbs_dvd_natAbs, natAbs_ofNat]
@[simp] theorem negSucc_dvd {a : Nat} {b : Int} : -[a+1] b ((a + 1 : Nat) : Int) b := by
rw [ natAbs_dvd]
norm_cast
@[simp] theorem dvd_negSucc {a : Int} {b : Nat} : a -[b+1] a ((b + 1 : Nat) : Int) := by
rw [ dvd_natAbs]
norm_cast
theorem eq_one_of_dvd_one {a : Int} (H : 0 a) (H' : a 1) : a = 1 :=
match a, eq_ofNat_of_zero_le H, H' with
| _, _, rfl, H' => congrArg ofNat <| Nat.eq_one_of_dvd_one <| ofNat_dvd.1 H'
@@ -91,11 +127,16 @@ theorem eq_one_of_mul_eq_one_right {a b : Int} (H : 0 ≤ a) (H' : a * b = 1) :
theorem eq_one_of_mul_eq_one_left {a b : Int} (H : 0 b) (H' : a * b = 1) : b = 1 :=
eq_one_of_mul_eq_one_right (b := a) H <| by rw [Int.mul_comm, H']
instance decidableDvd : DecidableRel (α := Int) (· ·) := fun _ _ =>
decidable_of_decidable_of_iff (dvd_iff_emod_eq_zero ..).symm
/-! ### *div zero -/
@[simp] theorem zero_ediv : b : Int, 0 / b = 0
| ofNat _ => show ofNat _ = _ by simp
| -[_+1] => show -ofNat _ = _ by simp
@[simp] protected theorem ediv_zero : a : Int, a / 0 = 0
| ofNat _ => show ofNat _ = _ by simp
| -[_+1] => rfl
@[simp] protected theorem zero_tdiv : b : Int, tdiv 0 b = 0
| ofNat _ => show ofNat _ = _ by simp
| -[_+1] => show -ofNat _ = _ by simp
@@ -113,129 +154,28 @@ unseal Nat.div in
| succ _ => rfl
| -[_+1] => rfl
/-! ### preliminaries for div equivalences -/
theorem negSucc_emod_ofNat_succ_eq_zero_iff {a b : Nat} :
-[a+1] % (b + 1 : Int) = 0 (a + 1) % (b + 1) = 0 := by
rw [ natCast_one, natCast_add]
change Int.emod _ _ = 0 _
rw [emod, natAbs_ofNat]
simp only [Nat.succ_eq_add_one, subNat_eq_zero_iff, Nat.add_right_cancel_iff]
rw [eq_comm]
apply Nat.succ_mod_succ_eq_zero_iff.symm
theorem negSucc_emod_negSucc_eq_zero_iff {a b : Nat} :
-[a+1] % -[b+1] = 0 (a + 1) % (b + 1) = 0 := by
change Int.emod _ _ = 0 _
rw [emod, natAbs_negSucc]
simp only [Nat.succ_eq_add_one, subNat_eq_zero_iff, Nat.add_right_cancel_iff]
rw [eq_comm]
apply Nat.succ_mod_succ_eq_zero_iff.symm
/-! ### div equivalences -/
theorem tdiv_eq_ediv_of_nonneg : {a b : Int}, 0 a a.tdiv b = a / b
| 0, _, _
| _, 0, _ => by simp
| succ _, succ _, _ => rfl
| succ _, -[_+1], _ => rfl
theorem tdiv_eq_ediv : {a b : Int}, 0 a 0 b a.tdiv b = a / b
| 0, _, _, _ | _, 0, _, _ => by simp
| succ _, succ _, _, _ => rfl
theorem tdiv_eq_ediv {a b : Int} :
a.tdiv b = a / b + if 0 a b a then 0 else sign b := by
simp only [dvd_iff_emod_eq_zero]
match a, b with
| ofNat a, ofNat b => simp [tdiv_eq_ediv_of_nonneg]
| ofNat a, -[b+1] => simp [tdiv_eq_ediv_of_nonneg]
| -[a+1], 0 => simp
| -[a+1], ofNat (succ b) =>
simp only [tdiv, Nat.succ_eq_add_one, ofNat_eq_coe, natCast_add, Nat.cast_ofNat_Int,
negSucc_not_nonneg, sign_of_add_one]
simp only [negSucc_emod_ofNat_succ_eq_zero_iff]
norm_cast
simp only [subNat_eq_zero_iff, Nat.succ_eq_add_one, sign_negSucc, Int.sub_neg, false_or]
split <;> rename_i h
· rw [Int.add_zero, neg_ofNat_eq_negSucc_iff]
exact Nat.succ_div_of_mod_eq_zero h
· rw [neg_ofNat_eq_negSucc_add_one_iff]
exact Nat.succ_div_of_mod_ne_zero h
| -[a+1], -[b+1] =>
simp only [tdiv, ofNat_eq_coe, negSucc_not_nonneg, false_or, sign_negSucc]
norm_cast
simp only [negSucc_ediv_negSucc]
rw [natCast_add, natCast_one]
simp only [negSucc_emod_negSucc_eq_zero_iff]
split <;> rename_i h
· norm_cast
exact Nat.succ_div_of_mod_eq_zero h
· rw [ Int.sub_eq_add_neg, Int.add_sub_cancel]
norm_cast
exact Nat.succ_div_of_mod_ne_zero h
theorem ediv_eq_tdiv {a b : Int} :
a / b = a.tdiv b - if 0 a b a then 0 else sign b := by
simp [tdiv_eq_ediv]
theorem fdiv_eq_ediv_of_nonneg : (a : Int) {b : Int}, 0 b fdiv a b = a / b
theorem fdiv_eq_ediv : (a : Int) {b : Int}, 0 b fdiv a b = a / b
| 0, _, _ | -[_+1], 0, _ => by simp
| succ _, ofNat _, _ | -[_+1], succ _, _ => rfl
theorem fdiv_eq_ediv {a b : Int} :
a.fdiv b = a / b - if 0 b b a then 0 else 1 := by
match a, b with
| ofNat a, ofNat b => simp [fdiv_eq_ediv_of_nonneg]
| -[a+1], ofNat b => simp [fdiv_eq_ediv_of_nonneg]
| 0, -[b+1] => simp
| ofNat (a + 1), -[b+1] =>
simp only [fdiv, ofNat_ediv_negSucc, negSucc_not_nonneg, negSucc_dvd, false_or]
simp only [ofNat_eq_coe, ofNat_dvd]
norm_cast
rw [Nat.succ_div, negSucc_eq]
split <;> rename_i h
· simp
· simp [Int.neg_add]
norm_cast
| -[a+1], -[b+1] =>
simp only [fdiv, ofNat_eq_coe, negSucc_ediv_negSucc, negSucc_not_nonneg, dvd_negSucc, negSucc_dvd,
false_or]
norm_cast
rw [natCast_add, natCast_one, Nat.succ_div]
split <;> simp
theorem ediv_eq_fdiv {a b : Int} :
a / b = a.fdiv b + if 0 b b a then 0 else 1 := by
simp [fdiv_eq_ediv]
theorem fdiv_eq_tdiv_of_nonneg {a b : Int} (Ha : 0 a) (Hb : 0 b) : fdiv a b = tdiv a b :=
tdiv_eq_ediv_of_nonneg Ha fdiv_eq_ediv_of_nonneg _ Hb
theorem fdiv_eq_tdiv {a b : Int} :
a.fdiv b = a.tdiv b -
if b a then 0
else
if 0 a then
if 0 b then 0
else 1
else
if 0 b then b.sign
else 1 + b.sign := by
rw [fdiv_eq_ediv, tdiv_eq_ediv]
by_cases h : b a <;> simp [h] <;> omega
theorem tdiv_eq_fdiv {a b : Int} :
a.tdiv b = a.fdiv b +
if b a then 0
else
if 0 a then
if 0 b then 0
else 1
else
if 0 b then b.sign
else 1 + b.sign := by
rw [fdiv_eq_tdiv]
omega
theorem fdiv_eq_tdiv {a b : Int} (Ha : 0 a) (Hb : 0 b) : fdiv a b = tdiv a b :=
tdiv_eq_ediv Ha Hb fdiv_eq_ediv _ Hb
/-! ### mod zero -/
@[simp] theorem zero_emod (b : Int) : 0 % b = 0 := rfl
@[simp] theorem emod_zero : a : Int, a % 0 = a
| ofNat _ => congrArg ofNat <| Nat.mod_zero _
| -[_+1] => congrArg negSucc <| Nat.mod_zero _
@[simp] theorem zero_tmod (b : Int) : tmod 0 b = 0 := by cases b <;> simp [tmod]
@[simp] theorem tmod_zero : a : Int, tmod a 0 = a
@@ -249,11 +189,39 @@ theorem tdiv_eq_fdiv {a b : Int} :
| succ _ => congrArg ofNat <| Nat.mod_zero _
| -[_+1] => congrArg negSucc <| Nat.mod_zero _
/-! ### ofNat mod -/
@[simp, norm_cast] theorem ofNat_emod (m n : Nat) : ((m % n) : Int) = m % n := rfl
/-! ### mod definitions -/
theorem emod_add_ediv : a b : Int, a % b + b * (a / b) = a
| ofNat _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..
| ofNat m, -[n+1] => by
show (m % succ n + -(succ n) * -(m / succ n) : Int) = m
rw [Int.neg_mul_neg]; exact congrArg ofNat <| Nat.mod_add_div ..
| -[_+1], 0 => by rw [emod_zero]; rfl
| -[m+1], succ n => aux m n.succ
| -[m+1], -[n+1] => aux m n.succ
where
aux (m n : Nat) : n - (m % n + 1) - (n * (m / n) + n) = -[m+1] := by
rw [ ofNat_emod, ofNat_ediv, Int.sub_sub, negSucc_eq, Int.sub_sub n,
Int.neg_neg (_-_), Int.neg_sub, Int.sub_sub_self, Int.add_right_comm]
exact congrArg (fun x => -(ofNat x + 1)) (Nat.mod_add_div ..)
theorem emod_add_ediv' (a b : Int) : a % b + a / b * b = a := by
rw [Int.mul_comm]; exact emod_add_ediv ..
theorem ediv_add_emod (a b : Int) : b * (a / b) + a % b = a := by
rw [Int.add_comm]; exact emod_add_ediv ..
theorem ediv_add_emod' (a b : Int) : a / b * b + a % b = a := by
rw [Int.mul_comm]; exact ediv_add_emod ..
theorem emod_def (a b : Int) : a % b = a - b * (a / b) := by
rw [ Int.add_sub_cancel (a % b), emod_add_ediv]
theorem tmod_add_tdiv : a b : Int, tmod a b + b * (a.tdiv b) = a
| ofNat _, ofNat _ => congrArg ofNat (Nat.mod_add_div ..)
| ofNat m, -[n+1] => by
@@ -308,70 +276,28 @@ theorem fmod_def (a b : Int) : a.fmod b = a - b * a.fdiv b := by
/-! ### mod equivalences -/
theorem fmod_eq_emod_of_nonneg (a : Int) {b : Int} (hb : 0 b) : fmod a b = a % b := by
simp [fmod_def, emod_def, fdiv_eq_ediv_of_nonneg _ hb]
theorem fmod_eq_emod (a : Int) {b : Int} (hb : 0 b) : fmod a b = a % b := by
simp [fmod_def, emod_def, fdiv_eq_ediv _ hb]
theorem fmod_eq_emod {a b : Int} :
fmod a b = a % b + if 0 b b a then 0 else b := by
simp [fmod_def, emod_def, fdiv_eq_ediv]
split <;> simp [Int.mul_sub]
omega
theorem tmod_eq_emod {a b : Int} (ha : 0 a) (hb : 0 b) : tmod a b = a % b := by
simp [emod_def, tmod_def, tdiv_eq_ediv ha hb]
theorem emod_eq_fmod {a b : Int} :
a % b = fmod a b - if 0 b b a then 0 else b := by
simp [fmod_eq_emod]
theorem tmod_eq_emod_of_nonneg {a b : Int} (ha : 0 a) : tmod a b = a % b := by
simp [emod_def, tmod_def, tdiv_eq_ediv_of_nonneg ha]
theorem tmod_eq_emod {a b : Int} :
tmod a b = a % b - if 0 a b a then 0 else b.natAbs := by
rw [tmod_def, tdiv_eq_ediv]
simp only [dvd_iff_emod_eq_zero]
split
· simp [emod_def]
· rw [Int.mul_add, Int.sub_sub, emod_def]
simp
theorem emod_eq_tmod {a b : Int} :
a % b = tmod a b + if 0 a b a then 0 else b.natAbs := by
simp [tmod_eq_emod]
theorem fmod_eq_tmod_of_nonneg {a b : Int} (ha : 0 a) (hb : 0 b) : fmod a b = tmod a b :=
tmod_eq_emod_of_nonneg ha fmod_eq_emod_of_nonneg _ hb
theorem fmod_eq_tmod {a b : Int} :
fmod a b = tmod a b +
if b a then 0
else
if 0 a then
if 0 b then 0
else b
else
if 0 b then b.natAbs
else 2 * b.toNat := by
simp [fmod_eq_emod, tmod_eq_emod]
by_cases h : b a <;> simp [h]
split <;> split <;> omega
theorem tmod_eq_fmod {a b : Int} :
tmod a b = fmod a b -
if b a then 0
else
if 0 a then
if 0 b then 0
else b
else
if 0 b then b.natAbs
else 2 * b.toNat := by
simp [fmod_eq_tmod]
theorem fmod_eq_tmod {a b : Int} (Ha : 0 a) (Hb : 0 b) : fmod a b = tmod a b :=
tmod_eq_emod Ha Hb fmod_eq_emod _ Hb
/-! ### `/` ediv -/
@[simp] protected theorem ediv_neg : a b : Int, a / (-b) = -(a / b)
| ofNat m, 0 => show ofNat (m / 0) = -(m / 0) by rw [Nat.div_zero]; rfl
| ofNat _, -[_+1] => (Int.neg_neg _).symm
| ofNat _, succ _ | -[_+1], 0 | -[_+1], succ _ | -[_+1], -[_+1] => rfl
theorem ediv_neg' {a b : Int} (Ha : a < 0) (Hb : 0 < b) : a / b < 0 :=
match a, b, eq_negSucc_of_lt_zero Ha, eq_succ_of_zero_lt Hb with
| _, _, _, rfl, _, rfl => negSucc_lt_zero _
protected theorem div_def (a b : Int) : a / b = Int.ediv a b := rfl
theorem negSucc_ediv (m : Nat) {b : Int} (H : 0 < b) : -[m+1] / b = -(ediv m b + 1) :=
match b, eq_succ_of_zero_lt H with
| _, _, rfl => rfl
@@ -399,6 +325,60 @@ theorem ediv_nonneg_of_nonpos_of_nonpos {a b : Int} (Ha : a ≤ 0) (Hb : b ≤ 0
theorem ediv_nonpos {a b : Int} (Ha : 0 a) (Hb : b 0) : a / b 0 :=
Int.nonpos_of_neg_nonneg <| Int.ediv_neg .. Int.ediv_nonneg Ha (Int.neg_nonneg_of_nonpos Hb)
theorem add_mul_ediv_right (a b : Int) {c : Int} (H : c 0) : (a + b * c) / c = a / c + b :=
suffices {{a b c : Int}}, 0 < c (a + b * c).ediv c = a.ediv c + b from
match Int.lt_trichotomy c 0 with
| Or.inl hlt => by
rw [ Int.neg_inj, Int.ediv_neg, Int.neg_add, Int.ediv_neg, Int.neg_mul_neg]
exact this (Int.neg_pos_of_neg hlt)
| Or.inr (Or.inl HEq) => absurd HEq H
| Or.inr (Or.inr hgt) => this hgt
suffices {k n : Nat} {a : Int}, (a + n * k.succ).ediv k.succ = a.ediv k.succ + n from
fun a b c H => match c, eq_succ_of_zero_lt H, b with
| _, _, rfl, ofNat _ => this
| _, k, rfl, -[n+1] => show (a - n.succ * k.succ).ediv k.succ = a.ediv k.succ - n.succ by
rw [ Int.add_sub_cancel (ediv ..), this, Int.sub_add_cancel]
fun {k n} => @fun
| ofNat _ => congrArg ofNat <| Nat.add_mul_div_right _ _ k.succ_pos
| -[m+1] => by
show ((n * k.succ : Nat) - m.succ : Int).ediv k.succ = n - (m / k.succ + 1 : Nat)
by_cases h : m < n * k.succ
· rw [ Int.ofNat_sub h, Int.ofNat_sub ((Nat.div_lt_iff_lt_mul k.succ_pos).2 h)]
apply congrArg ofNat
rw [Nat.mul_comm, Nat.mul_sub_div]; rwa [Nat.mul_comm]
· have h := Nat.not_lt.1 h
have H {a b : Nat} (h : a b) : (a : Int) + -((b : Int) + 1) = -[b - a +1] := by
rw [negSucc_eq, Int.ofNat_sub h]
simp only [Int.sub_eq_add_neg, Int.neg_add, Int.neg_neg, Int.add_left_comm, Int.add_assoc]
show ediv ((n * succ k) + -((m : Int) + 1)) (succ k) = n + -((m / succ k) + 1 : Int)
rw [H h, H ((Nat.le_div_iff_mul_le k.succ_pos).2 h)]
apply congrArg negSucc
rw [Nat.mul_comm, Nat.sub_mul_div]; rwa [Nat.mul_comm]
theorem add_ediv_of_dvd_right {a b c : Int} (H : c b) : (a + b) / c = a / c + b / c :=
if h : c = 0 then by simp [h] else by
let k, hk := H
rw [hk, Int.mul_comm c k, Int.add_mul_ediv_right _ _ h,
Int.zero_add (k * c), Int.add_mul_ediv_right _ _ h, Int.zero_ediv, Int.zero_add]
theorem add_ediv_of_dvd_left {a b c : Int} (H : c a) : (a + b) / c = a / c + b / c := by
rw [Int.add_comm, Int.add_ediv_of_dvd_right H, Int.add_comm]
@[simp] theorem mul_ediv_cancel (a : Int) {b : Int} (H : b 0) : (a * b) / b = a := by
have := Int.add_mul_ediv_right 0 a H
rwa [Int.zero_add, Int.zero_ediv, Int.zero_add] at this
@[simp] theorem mul_ediv_cancel_left (b : Int) (H : a 0) : (a * b) / a = b :=
Int.mul_comm .. Int.mul_ediv_cancel _ H
theorem div_nonneg_iff_of_pos {a b : Int} (h : 0 < b) : a / b 0 a 0 := by
rw [Int.div_def]
match b, h with
| Int.ofNat (b+1), _ =>
rcases a with a <;> simp [Int.ediv]
exact decide_eq_decide.mp rfl
theorem ediv_eq_zero_of_lt {a b : Int} (H1 : 0 a) (H2 : a < b) : a / b = 0 :=
match a, b, eq_ofNat_of_zero_le H1, eq_succ_of_zero_lt (Int.lt_of_le_of_lt H1 H2) with
| _, _, _, rfl, _, rfl => congrArg Nat.cast <| Nat.div_eq_of_lt <| ofNat_lt.1 H2
@@ -460,6 +440,35 @@ theorem emod_negSucc (m : Nat) (n : Int) :
theorem ofNat_mod_ofNat (m n : Nat) : (m % n : Int) = (m % n) := rfl
theorem emod_nonneg : (a : Int) {b : Int}, b 0 0 a % b
| ofNat _, _, _ => ofNat_zero_le _
| -[_+1], _, H => Int.sub_nonneg_of_le <| ofNat_le.2 <| Nat.mod_lt _ (natAbs_pos.2 H)
theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < b :=
match a, b, eq_succ_of_zero_lt H with
| ofNat _, _, _, rfl => ofNat_lt.2 (Nat.mod_lt _ (Nat.succ_pos _))
| -[_+1], _, _, rfl => Int.sub_lt_self _ (ofNat_lt.2 <| Nat.succ_pos _)
theorem mul_ediv_self_le {x k : Int} (h : k 0) : k * (x / k) x :=
calc k * (x / k)
_ k * (x / k) + x % k := Int.le_add_of_nonneg_right (emod_nonneg x h)
_ = x := ediv_add_emod _ _
theorem lt_mul_ediv_self_add {x k : Int} (h : 0 < k) : x < k * (x / k) + k :=
calc x
_ = k * (x / k) + x % k := (ediv_add_emod _ _).symm
_ < k * (x / k) + k := Int.add_lt_add_left (emod_lt_of_pos x h) _
@[simp] theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
if cz : c = 0 then by
rw [cz, Int.mul_zero, Int.add_zero]
else by
rw [Int.emod_def, Int.emod_def, Int.add_mul_ediv_right _ _ cz, Int.add_comm _ b,
Int.mul_add, Int.mul_comm, Int.sub_sub, Int.add_sub_cancel]
@[simp] theorem add_mul_emod_self_left (a b c : Int) : (a + b * c) % b = a % b := by
rw [Int.mul_comm, Int.add_mul_emod_self]
@[simp] theorem add_neg_mul_emod_self {a b c : Int} : (a + -(b * c)) % c = a % c := by
rw [Int.neg_mul_eq_neg_mul, add_mul_emod_self]
@@ -478,9 +487,53 @@ theorem neg_emod {a b : Int} : -a % b = (b - a) % b := by
@[simp] theorem emod_neg (a b : Int) : a % -b = a % b := by
rw [emod_def, emod_def, Int.ediv_neg, Int.neg_mul_neg]
@[simp] theorem emod_add_emod (m n k : Int) : (m % n + k) % n = (m + k) % n := by
have := (add_mul_emod_self_left (m % n + k) n (m / n)).symm
rwa [Int.add_right_comm, emod_add_ediv] at this
@[simp] theorem add_emod_emod (m n k : Int) : (m + n % k) % k = (m + n) % k := by
rw [Int.add_comm, emod_add_emod, Int.add_comm]
theorem add_emod (a b n : Int) : (a + b) % n = (a % n + b % n) % n := by
rw [add_emod_emod, emod_add_emod]
theorem add_emod_eq_add_emod_right {m n k : Int} (i : Int)
(H : m % n = k % n) : (m + i) % n = (k + i) % n := by
rw [ emod_add_emod, emod_add_emod k, H]
theorem emod_add_cancel_right {m n k : Int} (i) : (m + i) % n = (k + i) % n m % n = k % n :=
fun H => by
have := add_emod_eq_add_emod_right (-i) H
rwa [Int.add_neg_cancel_right, Int.add_neg_cancel_right] at this,
add_emod_eq_add_emod_right _
@[simp] theorem mul_emod_left (a b : Int) : (a * b) % b = 0 := by
rw [ Int.zero_add (a * b), Int.add_mul_emod_self, Int.zero_emod]
@[simp] theorem mul_emod_right (a b : Int) : (a * b) % a = 0 := by
rw [Int.mul_comm, mul_emod_left]
theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
conv => lhs; rw [
emod_add_ediv a n, emod_add_ediv' b n, Int.add_mul, Int.mul_add, Int.mul_add,
Int.mul_assoc, Int.mul_assoc, Int.mul_add n _ _, add_mul_emod_self_left,
Int.mul_assoc, add_mul_emod_self]
@[simp] theorem emod_self {a : Int} : a % a = 0 := by
have := mul_emod_left 1 a; rwa [Int.one_mul] at this
@[simp] theorem neg_emod_self (a : Int) : -a % a = 0 := by
rw [neg_emod, Int.sub_self, zero_emod]
@[simp] theorem emod_emod_of_dvd (n : Int) {m k : Int}
(h : m k) : (n % k) % m = n % m := by
conv => rhs; rw [ emod_add_ediv n k]
match k, h with
| _, t, rfl => rw [Int.mul_assoc, add_mul_emod_self_left]
@[simp] theorem emod_emod (a b : Int) : (a % b) % b = a % b := by
conv => rhs; rw [ emod_add_ediv a b, add_mul_emod_self_left]
@[simp] theorem emod_sub_emod (m n k : Int) : (m % n - k) % n = (m - k) % n :=
Int.emod_add_emod m n (-k)
@@ -488,6 +541,10 @@ theorem neg_emod {a b : Int} : -a % b = (b - a) % b := by
apply (emod_add_cancel_right (n % k)).mp
rw [Int.sub_add_cancel, Int.add_emod_emod, Int.sub_add_cancel]
theorem sub_emod (a b n : Int) : (a - b) % n = (a % n - b % n) % n := by
apply (emod_add_cancel_right b).mp
rw [Int.sub_add_cancel, Int.add_emod_emod, Int.sub_add_cancel, emod_emod]
theorem emod_eq_of_lt {a b : Int} (H1 : 0 a) (H2 : a < b) : a % b = a :=
have b0 := Int.le_trans H1 (Int.le_of_lt H2)
match a, b, eq_ofNat_of_zero_le H1, eq_ofNat_of_zero_le b0 with
@@ -498,6 +555,12 @@ theorem emod_eq_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a % b = a :=
/-! ### properties of `/` and `%` -/
theorem mul_ediv_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : b * (a / b) = a := by
have := emod_add_ediv a b; rwa [H, Int.zero_add] at this
theorem ediv_mul_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : a / b * b = a := by
rw [Int.mul_comm, mul_ediv_cancel_of_emod_eq_zero H]
theorem emod_two_eq (x : Int) : x % 2 = 0 x % 2 = 1 := by
have h₁ : 0 x % 2 := Int.emod_nonneg x (by decide)
have h₂ : x % 2 < 2 := Int.emod_lt_of_pos x (by decide)
@@ -551,10 +614,19 @@ theorem ediv_le_self {a : Int} (b : Int) (Ha : 0 ≤ a) : a / b ≤ a := by
have := Int.le_trans le_natAbs (ofNat_le.2 <| natAbs_div_le_natAbs a b)
rwa [natAbs_of_nonneg Ha] at this
theorem dvd_of_emod_eq_zero {a b : Int} (H : b % a = 0) : a b :=
b / a, (mul_ediv_cancel_of_emod_eq_zero H).symm
theorem dvd_emod_sub_self {x : Int} {m : Nat} : (m : Int) x % m - x := by
apply dvd_of_emod_eq_zero
simp [sub_emod]
theorem emod_eq_zero_of_dvd : {a b : Int}, a b b % a = 0
| _, _, _, rfl => mul_emod_right ..
theorem dvd_iff_emod_eq_zero {a b : Int} : a b b % a = 0 :=
emod_eq_zero_of_dvd, dvd_of_emod_eq_zero
@[simp] theorem neg_mul_emod_left (a b : Int) : -(a * b) % b = 0 := by
rw [ dvd_iff_emod_eq_zero, Int.dvd_neg]
exact Int.dvd_mul_left a b
@@ -563,12 +635,41 @@ theorem dvd_emod_sub_self {x : Int} {m : Nat} : (m : Int) x % m - x := by
rw [ dvd_iff_emod_eq_zero, Int.dvd_neg]
exact Int.dvd_mul_right a b
instance decidableDvd : DecidableRel (α := Int) (· ·) := fun _ _ =>
decidable_of_decidable_of_iff (dvd_iff_emod_eq_zero ..).symm
theorem emod_pos_of_not_dvd {a b : Int} (h : ¬ a b) : a = 0 0 < b % a := by
rw [dvd_iff_emod_eq_zero] at h
by_cases w : a = 0
· simp_all
· exact Or.inr (Int.lt_iff_le_and_ne.mpr emod_nonneg b w, Ne.symm h)
protected theorem mul_ediv_assoc (a : Int) : {b c : Int}, c b (a * b) / c = a * (b / c)
| _, c, d, rfl =>
if cz : c = 0 then by simp [cz, Int.mul_zero] else by
rw [Int.mul_left_comm, Int.mul_ediv_cancel_left _ cz, Int.mul_ediv_cancel_left _ cz]
protected theorem mul_ediv_assoc' (b : Int) {a c : Int}
(h : c a) : (a * b) / c = a / c * b := by
rw [Int.mul_comm, Int.mul_ediv_assoc _ h, Int.mul_comm]
theorem neg_ediv_of_dvd : {a b : Int}, b a (-a) / b = -(a / b)
| _, b, c, rfl => by
by_cases bz : b = 0
· simp [bz]
· rw [Int.neg_mul_eq_mul_neg, Int.mul_ediv_cancel_left _ bz, Int.mul_ediv_cancel_left _ bz]
@[simp] theorem neg_mul_ediv_cancel (a b : Int) (h : b 0) : -(a * b) / b = -a := by
rw [neg_ediv_of_dvd (Int.dvd_mul_left a b), mul_ediv_cancel _ h]
@[simp] theorem neg_mul_ediv_cancel_left (a b : Int) (h : a 0) : -(a * b) / a = -b := by
rw [neg_ediv_of_dvd (Int.dvd_mul_right a b), mul_ediv_cancel_left _ h]
theorem sub_ediv_of_dvd (a : Int) {b c : Int}
(hcb : c b) : (a - b) / c = a / c - b / c := by
rw [Int.sub_eq_add_neg, Int.sub_eq_add_neg, Int.add_ediv_of_dvd_right (Int.dvd_neg.2 hcb)]
congr; exact Int.neg_ediv_of_dvd hcb
@[simp] theorem ediv_one : a : Int, a / 1 = a
| (_:Nat) => congrArg Nat.cast (Nat.div_one _)
| -[_+1] => congrArg negSucc (Nat.div_one _)
@@ -602,6 +703,12 @@ theorem dvd_sub_of_emod_eq {a b c : Int} (h : a % b = c) : b a - c := by
rw [Int.emod_emod, emod_sub_cancel_right c, Int.sub_self, zero_emod] at hx
exact dvd_of_emod_eq_zero hx
protected theorem ediv_mul_cancel {a b : Int} (H : b a) : a / b * b = a :=
ediv_mul_cancel_of_emod_eq_zero (emod_eq_zero_of_dvd H)
protected theorem mul_ediv_cancel' {a b : Int} (H : a b) : a * (b / a) = b := by
rw [Int.mul_comm, Int.ediv_mul_cancel H]
protected theorem eq_mul_of_ediv_eq_right {a b c : Int}
(H1 : b a) (H2 : a / b = c) : a = b * c := by rw [ H2, Int.mul_ediv_cancel' H1]
@@ -811,7 +918,7 @@ theorem ofNat_tmod (m n : Nat) : (↑(m % n) : Int) = tmod m n := rfl
simp [tmod_def, Int.tdiv_one, Int.one_mul, Int.sub_self]
theorem tmod_eq_of_lt {a b : Int} (H1 : 0 a) (H2 : a < b) : tmod a b = a := by
rw [tmod_eq_emod_of_nonneg H1, emod_eq_of_lt H1 H2]
rw [tmod_eq_emod H1 (Int.le_trans H1 (Int.le_of_lt H2)), emod_eq_of_lt H1 H2]
theorem tmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : tmod a b < b :=
match a, b, eq_succ_of_zero_lt H with
@@ -920,7 +1027,7 @@ theorem fdiv_neg' : ∀ {a b : Int}, a < 0 → 0 < b → a.fdiv b < 0
@[simp] theorem mul_fdiv_cancel (a : Int) {b : Int} (H : b 0) : fdiv (a * b) b = a :=
if b0 : 0 b then by
rw [fdiv_eq_ediv_of_nonneg _ b0, mul_ediv_cancel _ H]
rw [fdiv_eq_ediv _ b0, mul_ediv_cancel _ H]
else
match a, b, Int.not_le.1 b0 with
| 0, _, _ => by simp [Int.zero_mul]
@@ -936,7 +1043,7 @@ theorem fdiv_neg' : ∀ {a b : Int}, a < 0 → 0 < b → a.fdiv b < 0
have := Int.mul_fdiv_cancel 1 H; rwa [Int.one_mul] at this
theorem lt_fdiv_add_one_mul_self (a : Int) {b : Int} (H : 0 < b) : a < (a.fdiv b + 1) * b :=
Int.fdiv_eq_ediv_of_nonneg _ (Int.le_of_lt H) lt_ediv_add_one_mul_self a H
Int.fdiv_eq_ediv _ (Int.le_of_lt H) lt_ediv_add_one_mul_self a H
/-! ### fmod -/
@@ -947,16 +1054,16 @@ theorem ofNat_fmod (m n : Nat) : ↑(m % n) = fmod m n := by
simp [fmod_def, Int.one_mul, Int.sub_self]
theorem fmod_eq_of_lt {a b : Int} (H1 : 0 a) (H2 : a < b) : a.fmod b = a := by
rw [fmod_eq_emod_of_nonneg _ (Int.le_trans H1 (Int.le_of_lt H2)), emod_eq_of_lt H1 H2]
rw [fmod_eq_emod _ (Int.le_trans H1 (Int.le_of_lt H2)), emod_eq_of_lt H1 H2]
theorem fmod_nonneg {a b : Int} (ha : 0 a) (hb : 0 b) : 0 a.fmod b :=
fmod_eq_tmod_of_nonneg ha hb tmod_nonneg _ ha
fmod_eq_tmod ha hb tmod_nonneg _ ha
theorem fmod_nonneg' (a : Int) {b : Int} (hb : 0 < b) : 0 a.fmod b :=
fmod_eq_emod_of_nonneg _ (Int.le_of_lt hb) emod_nonneg _ (Int.ne_of_lt hb).symm
fmod_eq_emod _ (Int.le_of_lt hb) emod_nonneg _ (Int.ne_of_lt hb).symm
theorem fmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a.fmod b < b :=
fmod_eq_emod_of_nonneg _ (Int.le_of_lt H) emod_lt_of_pos a H
fmod_eq_emod _ (Int.le_of_lt H) emod_lt_of_pos a H
@[simp] theorem mul_fmod_left (a b : Int) : (a * b).fmod b = 0 :=
if h : b = 0 then by simp [h, Int.mul_zero] else by
@@ -983,10 +1090,21 @@ theorem fdiv_eq_ediv_of_dvd : ∀ {a b : Int}, b a → a.fdiv b = a / b
/-! ### bmod -/
@[simp] theorem bmod_emod : bmod x m % m = x % m := by
dsimp [bmod]
split <;> simp [Int.sub_emod]
@[simp]
theorem emod_bmod_congr (x : Int) (n : Nat) : Int.bmod (x%n) n = Int.bmod x n := by
simp [bmod, Int.emod_emod]
theorem bmod_def (x : Int) (m : Nat) : bmod x m =
if (x % m) < (m + 1) / 2 then
x % m
else
(x % m) - m :=
rfl
theorem bdiv_add_bmod (x : Int) (m : Nat) : m * bdiv x m + bmod x m = x := by
unfold bdiv bmod
split

View File

@@ -7,7 +7,7 @@ prelude
import Init.Data.Int.Basic
import Init.Data.Nat.Gcd
import Init.Data.Nat.Lcm
import Init.Data.Int.DivMod.Lemmas
import Init.Data.Int.DivModLemmas
/-!
Definition and lemmas for gcd and lcm over Int

View File

@@ -129,17 +129,6 @@ theorem subNatNat_of_le {m n : Nat} (h : n ≤ m) : subNatNat m n = ↑(m - n) :
theorem subNatNat_of_lt {m n : Nat} (h : m < n) : subNatNat m n = -[pred (n - m) +1] :=
subNatNat_of_sub_eq_succ <| (Nat.succ_pred_eq_of_pos (Nat.sub_pos_of_lt h)).symm
@[simp] theorem subNat_eq_zero_iff {a b : Nat} : subNatNat a b = 0 a = b := by
cases Nat.lt_or_ge a b with
| inl h =>
rw [subNatNat_of_lt h]
simpa using ne_of_lt h
| inr h =>
rw [subNatNat_of_le h]
norm_cast
rw [Nat.sub_eq_iff_eq_add' h]
simp
/- # Additive group properties -/
/- addition -/
@@ -341,20 +330,6 @@ theorem toNat_of_nonpos : ∀ {z : Int}, z ≤ 0 → z.toNat = 0
| 0, _ => rfl
| -[_+1], _ => rfl
@[simp] theorem neg_ofNat_eq_negSucc_iff {a b : Nat} : - (a : Int) = -[b+1] a = b + 1 := by
rw [Int.neg_eq_comm]
rw [Int.neg_negSucc]
norm_cast
simp [eq_comm]
@[simp] theorem neg_ofNat_eq_negSucc_add_one_iff {a b : Nat} : - (a : Int) = -[b+1] + 1 a = b := by
cases b with
| zero => simp; norm_cast
| succ b =>
rw [Int.neg_eq_comm, Int.negSucc_sub_one, Int.sub_add_cancel, Int.neg_negSucc]
norm_cast
simp [eq_comm]
/- ## add/sub injectivity -/
protected theorem add_left_inj {i j : Int} (k : Int) : (i + k = j + k) i = j := by

View File

@@ -5,7 +5,6 @@ Authors: Kim Morrison
-/
prelude
import Init.Data.Int.Order
import Init.Data.Int.DivMod.Lemmas
import Init.Omega

View File

@@ -8,7 +8,7 @@ import Init.ByCases
import Init.Data.Prod
import Init.Data.Int.Lemmas
import Init.Data.Int.LemmasAux
import Init.Data.Int.DivMod.Bootstrap
import Init.Data.Int.DivModLemmas
import Init.Data.Int.Gcd
import Init.Data.RArray
import Init.Data.AC
@@ -147,9 +147,28 @@ where
| .neg a => go (-coeff) a
/-- Converts the given expression into a polynomial, and then normalizes it. -/
def Expr.norm (e : Expr) : Poly :=
def Expr.toPoly (e : Expr) : Poly :=
e.toPoly'.norm
/-- Relational contraints: equality and inequality. -/
inductive RelCnstr where
| /-- `p = 0` constraint. -/
eq (p : Poly)
| /-- `p ≤ 0` contraint. -/
le (p : Poly)
deriving BEq
def RelCnstr.denote (ctx : Context) : RelCnstr Prop
| .eq p => p.denote ctx = 0
| .le p => p.denote ctx 0
def RelCnstr.denote' (ctx : Context) : RelCnstr Prop
| .eq p => p.denote' ctx = 0
| .le p => p.denote' ctx 0
theorem RelCnstr.denote'_eq_denote (ctx : Context) (c : RelCnstr) : c.denote' ctx = c.denote ctx := by
cases c <;> simp [denote, denote', Poly.denote'_eq_denote]
/--
Returns the ceiling of the division `a / b`. That is, the result is equivalent to `⌈a / b⌉`.
Examples:
@@ -259,6 +278,79 @@ def Poly.mul (p : Poly) (k : Int) : Poly :=
induction p <;> simp [mul, denote, *]
rw [Int.mul_assoc, Int.mul_add]
/-- Normalizes the polynomial of the given relational constraint. -/
def RelCnstr.norm : RelCnstr RelCnstr
| .eq p => .eq p.norm
| .le p => .le p.norm
/-- Returns `true` if `k` divides all coefficients and constant of the given relational constraint. -/
def RelCnstr.divAll (k : Int) : RelCnstr Bool
| .eq p | .le p => p.divAll k
/-- Returns `true` if `k` divides all coefficients of the given relational constraint. -/
def RelCnstr.divCoeffs (k : Int) : RelCnstr Bool
| .eq p | .le p => p.divCoeffs k
/-- Returns `true` if the given relational constraint is an inequality constraint of the form `p ≤ 0`. -/
def RelCnstr.isLe : RelCnstr Bool
| .eq _ => false
| .le _ => true
/--
Divides all coefficients and constants in the linear polynomial of the given constraint by `k`.
We rounds up the constant using `cdiv`.
-/
def RelCnstr.div (k : Int) : RelCnstr RelCnstr
| .eq p => .eq <| p.div k
| .le p => .le <| p.div k
/--
Multiplies all coefficients and constants in the linear polynomial of the given constraint by `k`.
-/
def RelCnstr.mul (k : Int) : RelCnstr RelCnstr
| .eq p => .eq <| p.mul k
| .le p => .le <| p.mul k
@[simp] theorem RelCnstr.denote_mul (ctx : Context) (c : RelCnstr) (k : Int) (h : k > 0) : (c.mul k).denote ctx = c.denote ctx := by
cases c <;> simp [mul, denote]
next =>
constructor
· intro h₁; cases (Int.mul_eq_zero.mp h₁)
next hz => simp [hz] at h
next => assumption
· intro h'; simp [*]
next =>
constructor
· intro h₁
conv at h₁ => rhs; rw [ Int.mul_zero k]
exact Int.le_of_mul_le_mul_left h₁ h
· intro h₂
have := Int.mul_le_mul_of_nonneg_left h₂ (Int.le_of_lt h)
simp at this; assumption
/-- Raw relational constraint. They are later converted into `RelCnstr`. -/
inductive RawRelCnstr where
| eq (p₁ p₂ : Expr)
| le (p₁ p₂ : Expr)
deriving Inhabited, BEq
/-- Returns `true` if the given relational constraint is an inequality constraint of the form `e₁ ≤ e₂`. -/
def RawRelCnstr.isLe : RawRelCnstr Bool
| .eq .. => false
| .le .. => true
def RawRelCnstr.denote (ctx : Context) : RawRelCnstr Prop
| .eq e₁ e₂ => e₁.denote ctx = e₂.denote ctx
| .le e₁ e₂ => e₁.denote ctx e₂.denote ctx
def RawRelCnstr.norm : RawRelCnstr RelCnstr
| .eq e₁ e₂ => .eq (e₁.sub e₂).toPoly.norm
| .le e₁ e₂ => .le (e₁.sub e₂).toPoly.norm
/-- A certificate for normalizing the coefficients of a raw relational constraint. -/
def divBy (c : RawRelCnstr) (c' : RelCnstr) (k : Int) : Bool :=
k > 0 && c.norm == c'.mul k
attribute [local simp] Int.add_comm Int.add_assoc Int.add_left_comm Int.add_mul Int.mul_add
attribute [local simp] Poly.insert Poly.denote Poly.norm Poly.addConst
@@ -269,9 +361,13 @@ attribute [local simp] Poly.denote_addConst
theorem Poly.denote_insert (ctx : Context) (k : Int) (v : Var) (p : Poly) :
(p.insert k v).denote ctx = p.denote ctx + k * v.denote ctx := by
fun_induction p.insert k v <;>
simp only [insert, cond_true, cond_false, reduceIte, *] <;>
simp_all [ Int.add_mul]
induction p <;> simp [*]
next k' v' p' ih =>
by_cases h₁ : Nat.blt v' v <;> simp [*]
by_cases h₂ : Nat.beq v v' <;> simp [*]
by_cases h₃ : k + k' = 0 <;> simp [*, Nat.eq_of_beq_eq_true h₂]
rw [ Int.add_mul]
simp [*]
attribute [local simp] Poly.denote_insert
@@ -286,21 +382,26 @@ theorem Poly.denote_append (ctx : Context) (p₁ p₂ : Poly) : (p₁.append p
attribute [local simp] Poly.denote_append
theorem Poly.denote_combine' (ctx : Context) (fuel : Nat) (p₁ p₂ : Poly) : (p₁.combine' fuel p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
fun_induction p₁.combine' fuel p₂ <;>
simp +zetaDelta only [combine', cond_true, cond_false, *] <;>
simp_all +zetaDelta [denote, Int.add_mul]
induction fuel generalizing p₁ p₂ <;> simp [combine']
next ih =>
split <;> simp [*]
next a₁ x₁ p₁ a₂ x₂ p₂ =>
by_cases h₁ : Nat.beq x₁ x₂ <;> simp [*]
· simp at h₁; simp [h₁]
by_cases h₂ : a₁ + a₂ == 0 <;> simp [*]
· simp at h₂
rw [ Int.add_mul, h₂]; simp
· by_cases h₃ : Nat.blt x₂ x₁ <;> simp [*]
theorem Poly.denote_combine (ctx : Context) (p₁ p₂ : Poly) : (p₁.combine p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
simp [combine, denote_combine']
attribute [local simp] Poly.denote_combine
theorem sub_fold (a b : Int) : a.sub b = a - b := rfl
theorem neg_fold (a : Int) : a.neg = -a := rfl
attribute [local simp] sub_fold neg_fold
attribute [local simp] Poly.div Poly.divAll
attribute [local simp] Poly.div Poly.divAll RelCnstr.denote
theorem Poly.denote_div_eq_of_divAll (ctx : Context) (p : Poly) (k : Int) : p.divAll k (p.div k).denote ctx * k = p.denote ctx := by
induction p with
@@ -324,40 +425,43 @@ theorem Poly.denote_div_eq_of_divCoeffs (ctx : Context) (p : Poly) (k : Int) : p
rw [ ih h₂]
rw [Int.mul_right_comm, h₁, Int.add_assoc]
attribute [local simp] Expr.denote
attribute [local simp] RawRelCnstr.denote RawRelCnstr.norm Expr.denote
theorem Expr.denote_toPoly'_go (ctx : Context) (e : Expr) :
(toPoly'.go k e p).denote ctx = k * e.denote ctx + p.denote ctx := by
induction k, e using Expr.toPoly'.go.induct generalizing p with
| case1 k k' h =>
simp only [toPoly'.go, h, cond_true]
simp [eq_of_beq h]
| case2 k k' h =>
simp only [toPoly'.go, h, cond_false]
simp [Var.denote]
| case3 k i => simp [toPoly'.go]
| case4 k a b iha ihb => simp [toPoly'.go, iha, ihb]
| case5 k a b iha ihb =>
| case1 k k' =>
simp only [toPoly'.go]
by_cases h : k' == 0
· simp [h, eq_of_beq h]
· simp [h, Var.denote]
| case2 k i => simp [toPoly'.go]
| case3 k a b iha ihb => simp [toPoly'.go, iha, ihb]
| case4 k a b iha ihb =>
simp [toPoly'.go, iha, ihb, Int.mul_sub]
rw [Int.sub_eq_add_neg, Int.neg_mul, Int.add_assoc]
| case6 k k' a h
| case8 k a k' h =>
simp only [toPoly'.go, h, cond_false]
simp [eq_of_beq h]
| case7 k a k' h ih =>
simp only [toPoly'.go, h, cond_false]
simpa [denote, Int.mul_assoc] using ih
| case9 k a h h ih =>
simp only [toPoly'.go, h, cond_false]
simp only [mul_def, denote]
rw [Int.mul_comm (denote _ _) _]
simpa [Int.mul_assoc] using ih
| case10 k a ih => simp [toPoly'.go, ih]
| case5 k k' a ih
| case6 k a k' ih =>
simp only [toPoly'.go]
by_cases h : k' == 0
· simp [h, eq_of_beq h]
· simp [h, cond_false, Int.mul_assoc]
simp at ih
rw [ih]
rw [Int.mul_assoc, Int.mul_comm k']
| case7 k a ih => simp [toPoly'.go, ih]
theorem Expr.denote_norm (ctx : Context) (e : Expr) : e.norm.denote ctx = e.denote ctx := by
simp [norm, toPoly', Expr.denote_toPoly'_go]
theorem Expr.denote_toPoly (ctx : Context) (e : Expr) : e.toPoly.denote ctx = e.denote ctx := by
simp [toPoly, toPoly', Expr.denote_toPoly'_go]
attribute [local simp] Expr.denote_norm
attribute [local simp] Expr.denote_toPoly RelCnstr.denote
theorem RawRelCnstr.denote_norm (ctx : Context) (c : RawRelCnstr) : c.norm.denote ctx = c.denote ctx := by
cases c <;> simp
· rw [Int.sub_eq_zero]
· constructor
· exact Int.le_of_sub_nonpos
· exact Int.sub_nonpos_of_le
instance : LawfulBEq Poly where
eq_of_beq {a} := by
@@ -370,83 +474,54 @@ instance : LawfulBEq Poly where
induction a <;> simp! [BEq.beq]
assumption
attribute [local simp] Poly.denote'_eq_denote
instance : LawfulBEq RelCnstr where
eq_of_beq {a b} := by
cases a <;> cases b <;> rename_i p₁ p₂ <;> simp_all! [BEq.beq]
· show (p₁ == p₂) = true _
simp
· show (p₁ == p₂) = true _
simp
rfl {a} := by
cases a <;> rename_i p <;> show (p == p) = true
<;> simp
theorem Expr.eq_of_norm_eq (ctx : Context) (e : Expr) (p : Poly) (h : e.norm == p) : e.denote ctx = p.denote' ctx := by
theorem Expr.eq_of_toPoly_eq (ctx : Context) (e e' : Expr) (h : e.toPoly == e'.toPoly) : e.denote ctx = e'.denote ctx := by
have h := congrArg (Poly.denote ctx) (eq_of_beq h)
simp [Poly.norm] at h
simp [*]
assumption
def norm_eq_cert (lhs rhs : Expr) (p : Poly) : Bool :=
p == (lhs.sub rhs).norm
theorem RawRelCnstr.eq_of_norm_eq (ctx : Context) (c : RawRelCnstr) (c' : RelCnstr) (h : c.norm == c') : c.denote ctx = c'.denote' ctx := by
have h := congrArg (RelCnstr.denote ctx) (eq_of_beq h)
rw [denote_norm] at h
rw [RelCnstr.denote'_eq_denote, h]
theorem norm_eq (ctx : Context) (lhs rhs : Expr) (p : Poly) (h : norm_eq_cert lhs rhs p) : (lhs.denote ctx = rhs.denote ctx) = (p.denote' ctx = 0) := by
simp [norm_eq_cert] at h; subst p
simp
rw [Int.sub_eq_zero]
theorem RawRelCnstr.eq_of_norm_eq_var (ctx : Context) (x y : Var) (c : RawRelCnstr) (h : c.norm == .eq (.add 1 x (.add (-1) y (.num 0))))
: c.denote ctx = (x.denote ctx = y.denote ctx) := by
have h := congrArg (RelCnstr.denote ctx) (eq_of_beq h)
rw [denote_norm] at h
rw [h]; simp
rw [ Int.sub_eq_add_neg, Int.sub_eq_zero]
theorem norm_le (ctx : Context) (lhs rhs : Expr) (p : Poly) (h : norm_eq_cert lhs rhs p) : (lhs.denote ctx rhs.denote ctx) = (p.denote' ctx 0) := by
simp [norm_eq_cert] at h; subst p
simp
constructor
· exact Int.sub_nonpos_of_le
· exact Int.le_of_sub_nonpos
theorem RawRelCnstr.eq_of_norm_eq_const (ctx : Context) (x : Var) (k : Int) (c : RawRelCnstr) (h : c.norm == .eq (.add 1 x (.num (-k))))
: c.denote ctx = (x.denote ctx = k) := by
have h := congrArg (RelCnstr.denote ctx) (eq_of_beq h)
rw [denote_norm] at h
rw [h]; simp
rw [Int.add_comm, Int.sub_eq_add_neg, Int.sub_eq_zero]
def norm_eq_var_cert (lhs rhs : Expr) (x y : Var) : Bool :=
(lhs.sub rhs).norm == .add 1 x (.add (-1) y (.num 0))
attribute [local simp] RelCnstr.divAll RelCnstr.div RelCnstr.mul
theorem norm_eq_var (ctx : Context) (lhs rhs : Expr) (x y : Var) (h : norm_eq_var_cert lhs rhs x y)
: (lhs.denote ctx = rhs.denote ctx) = (x.denote ctx = y.denote ctx) := by
simp [norm_eq_var_cert] at h
replace h := congrArg (Poly.denote ctx) h
simp at h
rw [Int.sub_eq_zero, h, @Int.sub_eq_zero (Var.denote ctx x), Int.sub_eq_add_neg]
theorem RawRelCnstr.eq_of_norm_eq_mul (ctx : Context) (c : RawRelCnstr) (c' : RelCnstr) (k : Int) (hz : k > 0) (h : c.norm = c'.mul k) : c.denote ctx = c'.denote ctx := by
replace h := congrArg (RelCnstr.denote ctx) h
simp only [RawRelCnstr.denote_norm, RelCnstr.denote_mul, *] at h
assumption
def norm_eq_var_const_cert (lhs rhs : Expr) (x : Var) (k : Int) : Bool :=
(lhs.sub rhs).norm == .add 1 x (.num (-k))
theorem norm_eq_var_const (ctx : Context) (lhs rhs : Expr) (x : Var) (k : Int) (h : norm_eq_var_const_cert lhs rhs x k)
: (lhs.denote ctx = rhs.denote ctx) = (x.denote ctx = k) := by
simp [norm_eq_var_const_cert] at h
replace h := congrArg (Poly.denote ctx) h
simp at h
rw [Int.sub_eq_zero, h, Int.add_comm, Int.sub_eq_add_neg, Int.sub_eq_zero]
private theorem mul_eq_zero_iff (a k : Int) (h₁ : k > 0) : k * a = 0 a = 0 := by
conv => lhs; rw [ Int.mul_zero k]
apply Int.mul_eq_mul_left_iff
exact Int.ne_of_gt h₁
theorem norm_eq_coeff' (ctx : Context) (p p' : Poly) (k : Int) : p = p'.mul k k > 0 (p.denote ctx = 0 p'.denote ctx = 0) := by
intro; subst p; intro h; simp [mul_eq_zero_iff, *]
def norm_eq_coeff_cert (lhs rhs : Expr) (p : Poly) (k : Int) : Bool :=
(lhs.sub rhs).norm == p.mul k && k > 0
theorem norm_eq_coeff (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int)
: norm_eq_coeff_cert lhs rhs p k (lhs.denote ctx = rhs.denote ctx) = (p.denote' ctx = 0) := by
simp [norm_eq_coeff_cert]
rw [norm_eq ctx lhs rhs (lhs.sub rhs).norm BEq.refl, Poly.denote'_eq_denote]
apply norm_eq_coeff'
private theorem mul_le_zero_iff (a k : Int) (h₁ : k > 0) : k * a 0 a 0 := by
constructor
· intro h
rw [ Int.mul_zero k] at h
exact Int.le_of_mul_le_mul_left h h₁
· intro h
replace h := Int.mul_le_mul_of_nonneg_left h (Int.le_of_lt h₁)
simp at h; assumption
private theorem norm_le_coeff' (ctx : Context) (p p' : Poly) (k : Int) : p = p'.mul k k > 0 (p.denote ctx 0 p'.denote ctx 0) := by
simp [norm_eq_coeff_cert]
intro; subst p; intro h; simp [mul_le_zero_iff, *]
theorem norm_le_coeff (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int)
: norm_eq_coeff_cert lhs rhs p k (lhs.denote ctx rhs.denote ctx) = (p.denote' ctx 0) := by
simp [norm_eq_coeff_cert]
rw [norm_le ctx lhs rhs (lhs.sub rhs).norm BEq.refl, Poly.denote'_eq_denote]
apply norm_le_coeff'
theorem RawRelCnstr.eq_of_divBy (ctx : Context) (c : RawRelCnstr) (c' : RelCnstr) (k : Int) : divBy c c' k c.denote ctx = c'.denote' ctx := by
intro h
simp only [RelCnstr.denote'_eq_denote]
simp only [divBy, Bool.and_eq_true, bne_iff_ne, ne_eq, beq_iff_eq, decide_eq_true_eq] at h
have h₁, h₂ := h
exact eq_of_norm_eq_mul ctx c c' k h h₂
private theorem mul_add_cmod_le_iff {a k b : Int} (h : k > 0) : a*k + cmod b k 0 a 0 := by
constructor
@@ -472,93 +547,57 @@ private theorem mul_add_cmod_le_iff {a k b : Int} (h : k > 0) : a*k + cmod b k
simp at this
assumption
private theorem eq_of_norm_eq_of_divCoeffs {ctx : Context} {p p₂ : Poly} {k : Int}
: k > 0 p₁.divCoeffs k p = p₁.div k (p.denote ctx 0 p₂.denote ctx 0) := by
intro h₀ h₁ h₂
theorem RawRelCnstr.eq_of_norm_eq_of_divCoeffs (ctx : Context) (c : RawRelCnstr) (c₂ : RelCnstr) (c₃ : RelCnstr) (k : Int)
: k > 0 c₂.divCoeffs k c.isLe c₁.norm = c₂ c₃ = c₂.div k c.denote ctx = c₃.denote ctx := by
intro h₀ h₁ h₂ h₃ h₄
have hz : k 0 := Int.ne_of_gt h₀
replace h₁ := Poly.denote_div_eq_of_divCoeffs ctx p₁ k h
replace h₂ := congrArg (Poly.denote ctx) h₂
simp at h₂
rw [h₂, h₁]; clear h₁ h₂
apply mul_add_cmod_le_iff
cases c₂ <;> simp [RelCnstr.isLe] at h
clear h₂
next p =>
simp [RelCnstr.divCoeffs] at h₁
replace h₁ := Poly.denote_div_eq_of_divCoeffs ctx p k h₁
replace h₃ := congrArg (RelCnstr.denote ctx) h₃
simp only [RelCnstr.denote.eq_2, h₁] at h₃
replace h₄ := congrArg (RelCnstr.denote ctx) h₄
simp only [RelCnstr.denote.eq_2, RelCnstr.div] at h₄
rw [denote_norm] at h₃
rw [h₃, h₄]
apply propext
apply mul_add_cmod_le_iff
exact h₀
/-- Certificate for normalizing the coefficients of inequality constraint with bound tightening. -/
def divByLe (c : RawRelCnstr) (c' : RelCnstr) (k : Int) : Bool :=
k > 0 && c.isLe && c.norm.divCoeffs k && c' == c.norm.div k
theorem RawRelCnstr.eq_of_divByLe (ctx : Context) (c : RawRelCnstr) (c' : RelCnstr) (k : Int) : divByLe c c' k c.denote ctx = c'.denote' ctx := by
intro h
simp only [RelCnstr.denote'_eq_denote]
simp only [divByLe, Bool.and_eq_true, bne_iff_ne, ne_eq, beq_iff_eq, decide_eq_true_eq] at h
have h₀, h₁, h₂, h₃ := h
have hle : c.norm.isLe := by
cases c <;> simp [RawRelCnstr.isLe] at h₁
simp [RelCnstr.isLe]
apply eq_of_norm_eq_of_divCoeffs ctx c c.norm c' k h₀ h₂ hle rfl h₃
def RelCnstr.isUnsat : RelCnstr Bool
| .eq (.num k) => k != 0
| .eq _ => false
| .le (.num k) => k > 0
| .le _ => false
theorem RelCnstr.eq_false_of_isUnsat (ctx : Context) (c : RelCnstr) : c.isUnsat c.denote ctx = False := by
unfold isUnsat <;> split <;> simp <;> try contradiction
apply Int.not_le_of_gt
theorem RawRelCnstr.eq_false_of_isUnsat (ctx : Context) (c : RawRelCnstr) (h : c.norm.isUnsat) : c.denote ctx = False := by
have := RelCnstr.eq_false_of_isUnsat ctx c.norm h
rw [RawRelCnstr.denote_norm] at this
assumption
def norm_le_coeff_tight_cert (lhs rhs : Expr) (p : Poly) (k : Int) : Bool :=
let p' := lhs.sub rhs |>.norm
k > 0 && (p'.divCoeffs k && p == p'.div k)
theorem norm_le_coeff_tight (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int)
: norm_le_coeff_tight_cert lhs rhs p k (lhs.denote ctx rhs.denote ctx) = (p.denote' ctx 0) := by
simp [norm_le_coeff_tight_cert]
rw [norm_le ctx lhs rhs (lhs.sub rhs).norm BEq.refl, Poly.denote'_eq_denote]
apply eq_of_norm_eq_of_divCoeffs
def Poly.isUnsatEq (p : Poly) : Bool :=
match p with
| .num k => k != 0
| _ => false
def Poly.isValidEq (p : Poly) : Bool :=
match p with
| .num k => k == 0
| _ => false
theorem eq_eq_false (ctx : Context) (lhs rhs : Expr) : (lhs.sub rhs).norm.isUnsatEq (lhs.denote ctx = rhs.denote ctx) = False := by
simp [Poly.isUnsatEq] <;> split <;> simp
next p k h =>
intro h'
replace h := congrArg (Poly.denote ctx) h
simp at h
rw [ Int.sub_eq_zero, h]
assumption
theorem eq_eq_true (ctx : Context) (lhs rhs : Expr) : (lhs.sub rhs).norm.isValidEq (lhs.denote ctx = rhs.denote ctx) = True := by
simp [Poly.isValidEq] <;> split <;> simp
next p k h =>
intro h'
replace h := congrArg (Poly.denote ctx) h
simp at h
rw [ Int.sub_eq_zero, h]
assumption
def Poly.isUnsatLe (p : Poly) : Bool :=
match p with
| .num k => k > 0
| _ => false
def Poly.isValidLe (p : Poly) : Bool :=
match p with
| .num k => k 0
| _ => false
theorem le_eq_false (ctx : Context) (lhs rhs : Expr) : (lhs.sub rhs).norm.isUnsatLe (lhs.denote ctx rhs.denote ctx) = False := by
simp [Poly.isUnsatLe] <;> split <;> simp
next p k h =>
intro h'
replace h := congrArg (Poly.denote ctx) h
simp at h
replace h := congrArg (Expr.denote ctx rhs + ·) h
simp at h
rw [Int.add_comm, Int.sub_add_cancel] at h
rw [h]; clear h
intro h
conv at h => rhs; rw [ Int.zero_add (Expr.denote ctx rhs)]
rw [Int.add_le_add_iff_right] at h
replace h := Int.lt_of_lt_of_le h' h
contradiction
theorem le_eq_true (ctx : Context) (lhs rhs : Expr) : (lhs.sub rhs).norm.isValidLe (lhs.denote ctx rhs.denote ctx) = True := by
simp [Poly.isValidLe] <;> split <;> simp
next p k h =>
intro h'
replace h := congrArg (Poly.denote ctx) h
simp at h
replace h := congrArg (Expr.denote ctx rhs + ·) h
simp at h
rw [Int.add_comm, Int.sub_add_cancel] at h
rw [h]; clear h; simp
conv => rhs; rw [ Int.zero_add (Expr.denote ctx rhs)]
rw [Int.add_le_add_iff_right]; assumption
def RelCnstr.isUnsatCoeff (k : Int) : RelCnstr Bool
| .eq p => p.divCoeffs k && k > 0 && cmod p.getConst k < 0
| .le _ => false
private theorem contra {a b k : Int} (h₀ : 0 < k) (h₁ : -k < b) (h₂ : b < 0) (h₃ : a*k + b = 0) : False := by
have : b = -a*k := by
@@ -575,7 +614,7 @@ private theorem contra {a b k : Int} (h₀ : 0 < k) (h₁ : -k < b) (h₂ : b <
have : (1 : Int) < 1 := Int.lt_of_le_of_lt h₂ h₁
contradiction
private theorem poly_eq_zero_eq_false (ctx : Context) {p : Poly} {k : Int} : p.divCoeffs k k > 0 cmod p.getConst k < 0 (p.denote ctx = 0) = False := by
private theorem RelCnstr.eq_false (ctx : Context) (p : Poly) (k : Int) : p.divCoeffs k k > 0 cmod p.getConst k < 0 (RelCnstr.eq p).denote ctx = False := by
simp
intro h₁ h₂ h₃ h
have hnz : k 0 := by intro h; rw [h] at h₂; contradiction
@@ -585,17 +624,30 @@ private theorem poly_eq_zero_eq_false (ctx : Context) {p : Poly} {k : Int} : p.d
have high := h₃
exact contra h₂ low high this
def unsatEqDivCoeffCert (lhs rhs : Expr) (k : Int) : Bool :=
let p := (lhs.sub rhs).norm
p.divCoeffs k && k > 0 && cmod p.getConst k < 0
theorem RawRelCnstr.eq_false_of_isUnsat_coeff (ctx : Context) (c : RawRelCnstr) (k : Int) : c.norm.isUnsatCoeff k c.denote ctx = False := by
intro h
cases c <;> simp [norm, RelCnstr.isUnsatCoeff] at h
next e₁ e₂ =>
have h₁, h₂, h₃ := h
have := RelCnstr.eq_false ctx _ _ h₁ h₂ h₃
simp at this
simp
intro he
simp [he] at this
theorem eq_eq_false_of_divCoeff (ctx : Context) (lhs rhs : Expr) (k : Int) : unsatEqDivCoeffCert lhs rhs k (lhs.denote ctx = rhs.denote ctx) = False := by
simp [unsatEqDivCoeffCert]
intro h₁ h₂ h₃
have h := poly_eq_zero_eq_false ctx h₁ h₂ h₃; clear h₁ h₂ h₃
simp at h
intro h'
simp [h'] at h
def RelCnstr.isValid : RelCnstr Bool
| .eq (.num k) => k == 0
| .eq _ => false
| .le (.num k) => k 0
| .le _ => false
theorem RelCnstr.eq_true_of_isValid (ctx : Context) (c : RelCnstr) : c.isValid c.denote ctx = True := by
unfold isValid <;> split <;> simp
theorem RawRelCnstr.eq_true_of_isValid (ctx : Context) (c : RawRelCnstr) (h : c.norm.isValid) : c.denote ctx = True := by
have := RelCnstr.eq_true_of_isValid ctx c.norm h
rw [RawRelCnstr.denote_norm] at this
assumption
private def gcd (a b : Int) : Int :=
Int.ofNat <| Int.gcd a b
@@ -621,24 +673,40 @@ theorem Poly.gcd_dvd_const {ctx : Context} {p : Poly} {k : Int} (h : k p.den
rw [Int.add_comm] at h
exact ih (gcd_dvd_step h)
def Poly.isUnsatDvd (k : Int) (p : Poly) : Bool :=
p.getConst % p.gcdCoeffs k != 0
/-- Divibility constraint of the form `k p`. -/
structure DvdCnstr where
k : Int
p : Poly
def DvdCnstr.denote (ctx : Context) (c : DvdCnstr) : Prop :=
c.k c.p.denote ctx
def DvdCnstr.denote' (ctx : Context) (c : DvdCnstr) : Prop :=
c.k c.p.denote' ctx
theorem DvdCnstr.denote'_eq_denote (ctx : Context) (c : DvdCnstr) : c.denote' ctx = c.denote ctx := by
simp [denote', denote, Poly.denote'_eq_denote]
def DvdCnstr.isUnsat (c : DvdCnstr) : Bool :=
c.p.getConst % c.p.gcdCoeffs c.k != 0
def DvdCnstr.isEqv (c₁ c₂ : DvdCnstr) (k : Int) : Bool :=
k != 0 && c₁.k == k*c₂.k && c₁.p == c₂.p.mul k
def DvdCnstr.div (k' : Int) : DvdCnstr DvdCnstr
| { k, p } => { k := k / k', p := p.div k' }
private theorem not_dvd_of_not_mod_zero {a b : Int} (h : ¬ b % a = 0) : ¬ a b := by
intro h; have := Int.emod_eq_zero_of_dvd h; contradiction
private theorem dvd_eq_false' (ctx : Context) (k : Int) (p : Poly) : p.isUnsatDvd k (k p.denote' ctx) = False := by
simp [Poly.isUnsatDvd]
def DvdCnstr.eq_false_of_isUnsat (ctx : Context) (c : DvdCnstr) : c.isUnsat c.denote ctx = False := by
rcases c with a, p
simp [isUnsat, denote]
intro h₁ h₂
have := Poly.gcd_dvd_const h₂
have := not_dvd_of_not_mod_zero h₁
contradiction
theorem dvd_unsat (ctx : Context) (k : Int) (p : Poly) : p.isUnsatDvd k k p.denote' ctx False := by
intro h₁
rw [dvd_eq_false' ctx _ _ h₁]
intro; contradiction
@[local simp] private theorem mul_dvd_mul_eq {a b c : Int} (hnz : a 0) : a * b a * c b c := by
constructor
· intro h
@@ -651,61 +719,43 @@ theorem dvd_unsat (ctx : Context) (k : Int) (p : Poly) : p.isUnsatDvd k → k
exists k
rw [h, Int.mul_assoc]
theorem norm_dvd (ctx : Context) (k : Int) (e : Expr) (p : Poly) : e.norm == p (k e.denote ctx) = (k p.denote' ctx) := by
simp; intro h; simp [ h]
theorem dvd_eq_false (ctx : Context) (k : Int) (e : Expr) (h : e.norm.isUnsatDvd k) : (k e.denote ctx) = False := by
rw [norm_dvd ctx k e e.norm BEq.refl]
apply dvd_eq_false' ctx k e.norm h
def dvd_coeff_cert (k₁ : Int) (p₁ : Poly) (k₂ : Int) (p₂ : Poly) (k : Int) : Bool :=
k != 0 && (k₁ == k*k₂ && p₁ == p₂.mul k)
def norm_dvd_gcd_cert (k₁ : Int) (e₁ : Expr) (k₂ : Int) (p₂ : Poly) (k : Int) : Bool :=
dvd_coeff_cert k₁ e₁.norm k₂ p₂ k
theorem norm_dvd_gcd (ctx : Context) (k₁ : Int) (e₁ : Expr) (k₂ : Int) (p₂ : Poly) (g : Int)
: norm_dvd_gcd_cert k₁ e₁ k₂ p₂ g (k₁ e₁.denote ctx) = (k₂ p₂.denote' ctx) := by
simp [norm_dvd_gcd_cert, dvd_coeff_cert]
intro h₁ h₂ h₃
@[local simp] theorem DvdCnstr.eq_of_isEqv (ctx : Context) (c₁ c₂ : DvdCnstr) (k : Int) (h : isEqv c₁ c₂ k) : c₁.denote ctx = c₂.denote ctx := by
rcases c₁ with a₁, e₁
rcases c₂ with a₂, e₂
simp [isEqv] at h
rcases h with h₁, h₂, h₃
replace h₃ := congrArg (Poly.denote ctx) h₃
simp at h₃
simp [*]
simp [denote, *]
theorem dvd_coeff (ctx : Context) (k₁ : Int) (p₁ : Poly) (k₂ : Int) (p₂ : Poly) (g : Int)
: dvd_coeff_cert k₁ p₁ k₂ p₂ g k₁ p₁.denote' ctx k₂ p₂.denote' ctx := by
simp [dvd_coeff_cert]
intro h₁ h₂ h₃
replace h₃ := congrArg (Poly.denote ctx) h₃
simp at h₃
simp [*]
/-- Raw divisibility constraint of the form `k e`. -/
structure RawDvdCnstr where
k : Int
e : Expr
deriving BEq
private theorem dvd_gcd_of_dvd (d a x p : Int) (h : d a * x + p) : gcd d a p := by
rcases h with k, h
simp [Int.Linear.gcd]
replace h := congrArg (· - a*x) h
simp at h
rcases @Int.gcd_dvd_left d a with k₁, h₁
rcases @Int.gcd_dvd_right d a with k₂, h₂
conv at h => enter [2, 1]; rw [h₁]
conv at h => enter [2, 2]; rw [h₂]
rw [Int.mul_assoc, Int.mul_assoc, Int.mul_sub] at h
exists k₁ * k - k₂ * x
def RawDvdCnstr.denote (ctx : Context) (c : RawDvdCnstr) : Prop :=
c.k c.e.denote ctx
def dvd_elim_cert (k₁ : Int) (p₁ : Poly) (k₂ : Int) (p₂ : Poly) : Bool :=
match p with
| .add a _ p => k₂ == gcd k₁ a && p₂ == p
| _ => false
def RawDvdCnstr.norm (c : RawDvdCnstr) : DvdCnstr :=
{ k := c.k, p := c.e.toPoly }
theorem dvd_elim (ctx : Context) (k₁ : Int) (p₁ : Poly) (k₂ : Int) (p₂ : Poly)
: dvd_elim_cert k₁ p₁ k₂ p₂ k₁ p₁.denote' ctx k₂ p₂.denote' ctx := by
rcases p₁ <;> simp [dvd_elim_cert]
next a _ p =>
intro _ _; subst k₂ p₂
rw [Int.add_comm]
apply dvd_gcd_of_dvd
@[simp] theorem RawDvdCnstr.denote_norm_eq (ctx : Context) (c : RawDvdCnstr) : c.denote ctx = c.norm.denote ctx := by
simp [norm, denote, DvdCnstr.denote]
private theorem dvd_solve_combine' {x : Int} {d₁ a₁ p₁ : Int} {d₂ a₂ p₂ : Int} {α β d : Int}
def RawDvdCnstr.isEqv (c : RawDvdCnstr) (c' : DvdCnstr) (k : Int) : Bool :=
c.norm.isEqv c' k
def RawDvdCnstr.isUnsat (c : RawDvdCnstr) : Bool :=
c.norm.isUnsat
theorem RawDvdCnstr.eq_of_isEqv (ctx : Context) (c : RawDvdCnstr) (c' : DvdCnstr) (k : Int) (h : isEqv c c' k) : c.denote ctx = c'.denote' ctx := by
simp [DvdCnstr.eq_of_isEqv ctx c.norm c' k h, DvdCnstr.denote'_eq_denote]
theorem RawDvdCnstr.eq_false_of_isUnsat (ctx : Context) (c : RawDvdCnstr) (h : c.isUnsat) : c.denote ctx = False := by
simp [DvdCnstr.eq_false_of_isUnsat ctx c.norm h]
theorem solveCombine {x : Int} {d₁ a₁ p₁ : Int} {d₂ a₂ p₂ : Int} {α β d : Int}
(h : α*a₁*d₂ + β*a₂*d₁ = d)
(h₁ : d₁ a₁*x + p₁)
(h₂ : d₂ a₂*x + p₂)
@@ -732,7 +782,7 @@ private theorem dvd_solve_combine' {x : Int} {d₁ a₁ p₁ : Int} {d₂ a₂ p
rw [h, ac]
assumption
private theorem dvd_solve_elim' {x : Int} {d₁ a₁ p₁ : Int} {d₂ a₂ p₂ : Int} {d : Int}
theorem solveElim {x : Int} {d₁ a₁ p₁ : Int} {d₂ a₂ p₂ : Int} {d : Int}
(h : d = Int.gcd (a₁*d₂) (a₂*d₁))
(h₁ : d₁ a₁*x + p₁)
(h₂ : d₂ a₂*x + p₂)
@@ -754,257 +804,61 @@ private theorem dvd_solve_elim' {x : Int} {d₁ a₁ p₁ : Int} {d₂ a₂ p₂
rw [h₃, h₄, Int.mul_assoc, Int.mul_assoc, Int.mul_sub] at this
exact k₄ * k₁ - k₃ * k₂, this
def dvd_solve_combine_cert (d : Int) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d : Int) (p : Poly) (g α β : Int) : Bool :=
match p, p with
| .add a₁ x₁ p₁, .add a₂ x₂ p₂ =>
def isSolveCombine (c c₂ c : DvdCnstr) (d α β : Int) : Bool :=
match c, c with
| { k := d₁, p := .add a₁ x₁ p₁ }, { k := d₂, p := .add a₂ x₂ p₂ } =>
x₁ == x₂ &&
(g == α*a₁*d₂ + β*a₂*d₁ &&
(d == d₁*d₂ &&
p == .add g x₁ (p₁.mul (α*d₂) |>.combine (p₂.mul (β*d₁)))))
(d == α*a₁*d₂ + β*a₂*d₁ &&
(c.k == d₁*d₂ &&
c.p == .add d x₁ (p₁.mul (α*d₂) |>.combine (p₂.mul (β*d₁)))))
| _, _ => false
theorem dvd_solve_combine (ctx : Context) (d : Int) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d : Int) (p : Poly) (g α β : Int)
: dvd_solve_combine_cert d₁ p d p₂ d p g α β d₁ p.denote' ctx d₂ p.denote' ctx d p.denote' ctx := by
simp [dvd_solve_combine_cert]
split <;> simp
next a₁ x₁ p₁ a₂ x₂ p₂ =>
intro _ hg hd hp; subst x₁ p
simp [Poly.denote'_add]
theorem DvdCnstr.solve_combine (ctx : Context) (c c₂ c : DvdCnstr) (d α β : Int)
: isSolveCombine c c c d α β c.denote' ctx c.denote' ctx c.denote' ctx := by
simp [isSolveCombine]
split <;> simp <;> cases c <;> simp [denote', Poly.denote_combine, Poly.denote'_add]
next d₁ a₁ x₁ p₁ d₂ a₂ x₂ p₂ k p =>
intro _ hd _ hp; subst x₁ k p
simp [Poly.denote'_add, Poly.denote, Poly.denote_combine]
intro h₁ h₂
rw [Int.add_comm] at h₁ h₂
rw [Int.add_comm _ (g * x₂.denote ctx), Int.add_left_comm, Int.add_assoc, hd]
exact dvd_solve_combine' hg.symm h₁ h₂
rw [Int.add_comm _ (d * x₂.denote ctx), Int.add_left_comm, Int.add_assoc]
exact solveCombine hd.symm h₁ h₂
def dvd_solve_elim_cert (d : Int) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d : Int) (p : Poly) : Bool :=
match p, p with
| .add a₁ x₁ p₁, .add a₂ x₂ p₂ =>
def isSolveElim (c c₂ c : DvdCnstr) (d : Int) : Bool :=
match c, c with
| { k := d₁, p := .add a₁ x₁ p₁ }, { k := d₂, p := .add a₂ x₂ p₂ } =>
x₁ == x₂ &&
(d == Int.gcd (a₁*d₂) (a₂*d₁) &&
p == (p₁.mul a₂ |>.combine (p₂.mul (- a₁))))
(c.k == d &&
c.p == (p₁.mul a₂ |>.combine (p₂.mul (- a₁)))))
| _, _ => false
theorem dvd_solve_elim (ctx : Context) (d : Int) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d : Int) (p : Poly)
: dvd_solve_elim_cert d p₁ d p₂ d p d₁ p.denote' ctx d₂ p.denote' ctx d p.denote' ctx := by
simp [dvd_solve_elim_cert]
split <;> simp
next a₁ x₁ p₁ a₂ x₂ p₂ =>
intro _ hd _; subst x₁ p; simp
theorem DvdCnstr.solve_elim (ctx : Context) (c c₂ c : DvdCnstr) (d : Int)
: isSolveElim c c c d c.denote' ctx c.denote' ctx c.denote' ctx := by
simp [isSolveElim]
split <;> simp <;> cases c <;> simp [denote', Poly.denote_combine, Poly.denote'_add]
next d₁ a₁ x₁ p₁ d₂ a₂ x₂ p₂ k p =>
intro _ hd _ hp; subst x₁ k p
simp [Poly.denote'_eq_denote, Poly.denote_combine]
intro h₁ h₂
rw [Int.add_comm] at h₁ h₂
rw [ Int.sub_eq_add_neg]
exact dvd_solve_elim' hd h₁ h₂
exact solveElim hd h₁ h₂
theorem dvd_norm (ctx : Context) (d : Int) (p p : Poly) : p₁.norm == p₂ d p₁.denote' ctx d p₂.denote' ctx := by
simp
intro; subst p₂
intro h₁
simp [Poly.denote_norm ctx p₁, h₁]
def isNorm (c c : DvdCnstr) : Bool :=
c₁.k == c₂.k && c₁.p.norm == c₂.p
theorem le_norm (ctx : Context) (p p : Poly) (h : p₁.norm == p₂) : p₁.denote' ctx 0 p₂.denote' ctx 0 := by
simp at h
replace h := congrArg (Poly.denote ctx) h
simp at h
simp [*]
theorem DvdCnstr.of_isNorm (ctx : Context) (c c : DvdCnstr)
: isNorm c₁ c₂ c₁.denote' ctx c₂.denote' ctx := by
cases c₁ <;> cases c₂ <;> simp [isNorm, denote', Poly.denote'_eq_denote]
next k₁ p₁ k₂ p₂ =>
intro; subst k₁; intro; subst p₂
intro h₁
simp [Poly.denote_norm ctx p₁, h₁]
def le_coeff_cert (p p : Poly) (k : Int) : Bool :=
k > 0 && (p₁.divCoeffs k && p == p₁.div k)
theorem le_coeff (ctx : Context) (p₁ p₂ : Poly) (k : Int) : le_coeff_cert p₁ p₂ k p₁.denote' ctx 0 p₂.denote' ctx 0 := by
simp [le_coeff_cert]
intro h₁ h₂ h₃
exact eq_of_norm_eq_of_divCoeffs h₁ h₂ h₃ |>.mp
def le_neg_cert (p₁ p₂ : Poly) : Bool :=
p₂ == (p₁.mul (-1) |>.addConst 1)
theorem le_neg (ctx : Context) (p₁ p₂ : Poly) : le_neg_cert p₁ p₂ ¬ p₁.denote' ctx 0 p₂.denote' ctx 0 := by
simp [le_neg_cert]
intro; subst p₂; simp; intro h
replace h : _ + 1 -0 := Int.neg_lt_neg <| Int.lt_of_not_ge h
simp at h
exact h
def Poly.leadCoeff (p : Poly) : Int :=
match p with
| .add a _ _ => a
| _ => 1
def le_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
let a₁ := p₁.leadCoeff.natAbs
let a₂ := p₂.leadCoeff.natAbs
p₃ == (p₁.mul a₂ |>.combine (p₂.mul a₁))
theorem le_combine (ctx : Context) (p₁ p₂ p₃ : Poly)
: le_combine_cert p₁ p₂ p₃ p₁.denote' ctx 0 p₂.denote' ctx 0 p₃.denote' ctx 0 := by
simp [le_combine_cert]
intro; subst p₃
intro h₁ h₂; simp
rw [ Int.add_zero 0]
apply Int.add_le_add
· rw [ Int.zero_mul (Poly.denote ctx p₂)]; apply Int.mul_le_mul_of_nonpos_right <;> simp [*]
· rw [ Int.zero_mul (Poly.denote ctx p₁)]; apply Int.mul_le_mul_of_nonpos_right <;> simp [*]
theorem le_unsat (ctx : Context) (p : Poly) : p.isUnsatLe p.denote' ctx 0 False := by
simp [Poly.isUnsatLe]; split <;> simp
intro h₁ h₂
have := Int.lt_of_le_of_lt h₂ h₁
simp at this
theorem eq_norm (ctx : Context) (p₁ p₂ : Poly) (h : p₁.norm == p₂) : p₁.denote' ctx = 0 p₂.denote' ctx = 0 := by
simp at h
replace h := congrArg (Poly.denote ctx) h
simp at h
simp [*]
def eq_coeff_cert (p p' : Poly) (k : Int) : Bool :=
p == p'.mul k && k > 0
theorem eq_coeff (ctx : Context) (p p' : Poly) (k : Int) : eq_coeff_cert p p' k p.denote' ctx = 0 p'.denote' ctx = 0 := by
simp [eq_coeff_cert]
intro _ _; simp [mul_eq_zero_iff, *]
theorem eq_unsat (ctx : Context) (p : Poly) : p.isUnsatEq p.denote' ctx = 0 False := by
simp [Poly.isUnsatEq] <;> split <;> simp
def eq_unsat_coeff_cert (p : Poly) (k : Int) : Bool :=
p.divCoeffs k && k > 0 && cmod p.getConst k < 0
theorem eq_unsat_coeff (ctx : Context) (p : Poly) (k : Int) : eq_unsat_coeff_cert p k p.denote' ctx = 0 False := by
simp [eq_unsat_coeff_cert]
intro h₁ h₂ h₃
have h := poly_eq_zero_eq_false ctx h₁ h₂ h₃; clear h₁ h₂ h₃
simp [h]
def Poly.coeff (p : Poly) (x : Var) : Int :=
match p with
| .add a y p => bif x == y then a else coeff p x
| .num _ => 0
private theorem eq_add_coeff_insert (ctx : Context) (p : Poly) (x : Var) : p.denote ctx = (p.coeff x) * (x.denote ctx) + (p.insert (-p.coeff x) x).denote ctx := by
simp; rw [ Int.add_assoc, Int.add_neg_cancel_right]
private theorem dvd_of_eq' {a x p : Int} : a*x + p = 0 a p := by
intro h
replace h := Int.neg_eq_of_add_eq_zero h
rw [Int.mul_comm, Int.neg_mul, Eq.comm, Int.mul_comm] at h
exact -x, h
private def abs (x : Int) : Int :=
Int.ofNat x.natAbs
private theorem abs_dvd {a p : Int} (h : a p) : abs a p := by
cases a <;> simp [abs]
· simp at h; assumption
· simp [Int.negSucc_eq] at h; assumption
def dvd_of_eq_cert (x : Var) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) : Bool :=
let a := p₁.coeff x
d₂ == abs a && p₂ == p₁.insert (-a) x
theorem dvd_of_eq (ctx : Context) (x : Var) (p₁ : Poly) (d₂ : Int) (p₂ : Poly)
: dvd_of_eq_cert x p₁ d₂ p₂ p₁.denote' ctx = 0 d₂ p₂.denote' ctx := by
simp [dvd_of_eq_cert]
intro h₁ h₂
have h := eq_add_coeff_insert ctx p₁ x
rw [ h₂] at h
rw [h, h₁]
intro h₃
apply abs_dvd
apply dvd_of_eq' h₃
private theorem eq_dvd_subst' {a x p d b q : Int} : a*x + p = 0 d b*x + q a*d a*q - b*p := by
intro h₁ z, h₂
have h : a*q - b*p = a*(b*x + q) - b*(a*x+p) := by
conv => rhs; rw [Int.sub_eq_add_neg]; rhs; rw [Int.mul_add, Int.neg_add]
rw [Int.mul_add, Int.add_assoc, Int.mul_left_comm a b x]
rw [Int.add_comm (b*(a*x)), Int.add_neg_cancel_right, Int.sub_eq_add_neg]
rw [h₁, h₂] at h
simp at h
rw [ Int.mul_assoc] at h
exact z, h
def eq_dvd_subst_cert (x : Var) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d₃ : Int) (p₃ : Poly) : Bool :=
let a := p₁.coeff x
let b := p₂.coeff x
let p := p₁.insert (-a) x
let q := p₂.insert (-b) x
d₃ == abs (a * d₂) &&
p₃ == (q.mul a |>.combine (p.mul (-b)))
theorem eq_dvd_subst (ctx : Context) (x : Var) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d₃ : Int) (p₃ : Poly)
: eq_dvd_subst_cert x p₁ d₂ p₂ d₃ p₃ p₁.denote' ctx = 0 d₂ p₂.denote' ctx d₃ p₃.denote' ctx := by
simp [eq_dvd_subst_cert]
have eq₁ := eq_add_coeff_insert ctx p₁ x
have eq₂ := eq_add_coeff_insert ctx p₂ x
revert eq₁ eq₂
generalize p₁.coeff x = a
generalize p₂.coeff x = b
generalize p₁.insert (-a) x = p
generalize p₂.insert (-b) x = q
intro eq₁; simp [eq₁]; clear eq₁
intro eq₂; simp [eq₂]; clear eq₂
intro; subst d₃
intro; subst p₃
intro h₁ h₂
rw [Int.add_comm] at h₁ h₂
have := eq_dvd_subst' h₁ h₂
rw [Int.sub_eq_add_neg, Int.add_comm] at this
apply abs_dvd
simp [this]
def eq_eq_subst_cert (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
let a := p₁.coeff x
let b := p₂.coeff x
p₃ == (p₁.mul b |>.combine (p₂.mul (-a)))
theorem eq_eq_subst (ctx : Context) (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
: eq_eq_subst_cert x p₁ p₂ p₃ p₁.denote' ctx = 0 p₂.denote' ctx = 0 p₃.denote' ctx = 0 := by
simp [eq_eq_subst_cert]
intro; subst p₃
intro h₁ h₂
simp [*]
def eq_le_subst_nonneg_cert (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
let a := p₁.coeff x
let b := p₂.coeff x
a 0 && p₃ == (p₂.mul a |>.combine (p₁.mul (-b)))
theorem eq_le_subst_nonneg (ctx : Context) (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
: eq_le_subst_nonneg_cert x p₁ p₂ p₃ p₁.denote' ctx = 0 p₂.denote' ctx 0 p₃.denote' ctx 0 := by
simp [eq_le_subst_nonneg_cert]
intro h
intro; subst p₃
intro h₁ h₂
replace h₂ := Int.mul_le_mul_of_nonneg_left h₂ h
simp at h₂
simp [*]
def eq_le_subst_nonpos_cert (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
let a := p₁.coeff x
let b := p₂.coeff x
a 0 && p₃ == (p₁.mul b |>.combine (p₂.mul (-a)))
theorem eq_le_subst_nonpos (ctx : Context) (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
: eq_le_subst_nonpos_cert x p₁ p₂ p₃ p₁.denote' ctx = 0 p₂.denote' ctx 0 p₃.denote' ctx 0 := by
simp [eq_le_subst_nonpos_cert]
intro h
intro; subst p₃
intro h₁ h₂
simp [*]
replace h₂ := Int.mul_le_mul_of_nonpos_left h₂ h; simp at h₂; clear h
rw [ Int.neg_zero]
apply Int.neg_le_neg
rw [Int.mul_comm]
assumption
def eq_of_core_cert (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
p₃ == p₁.combine (p₂.mul (-1))
theorem eq_of_core (ctx : Context) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
: eq_of_core_cert p₁ p₂ p₃ p₁.denote' ctx = p₂.denote' ctx p₃.denote' ctx = 0 := by
simp [eq_of_core_cert]
intro; subst p₃; simp
intro h; rw [h, Int.sub_eq_add_neg, Int.sub_self]
theorem DvdCnstr.of_isEqv (ctx : Context) (c c : DvdCnstr) (k : Int) (h : isEqv c₁ c₂ k) : c₁.denote' ctx c₂.denote' ctx := by
simp [DvdCnstr.denote'_eq_denote, DvdCnstr.eq_of_isEqv ctx c₁ c k h]
end Int.Linear

View File

@@ -56,7 +56,7 @@ protected theorem le_total (a b : Int) : a ≤ b b ≤ a :=
let k, (hk : m + k = n) := Nat.le.dest h
le.intro k (by rw [ hk]; rfl)
@[simp] theorem ofNat_zero_le (n : Nat) : 0 (n : Int) := ofNat_le.2 n.zero_le
theorem ofNat_zero_le (n : Nat) : 0 (n : Int) := ofNat_le.2 n.zero_le
theorem eq_ofNat_of_zero_le {a : Int} (h : 0 a) : n : Nat, a = n := by
have t := le.dest_sub h; rwa [Int.sub_zero] at t
@@ -1011,16 +1011,11 @@ theorem sign_eq_neg_one_iff_neg {a : Int} : sign a = -1 ↔ a < 0 :=
exact Int.le_add_one (ofNat_nonneg _)
| .negSucc _ => simp +decide [sign]
@[simp] theorem mul_sign_self : i : Int, i * sign i = natAbs i
theorem mul_sign : i : Int, i * sign i = natAbs i
| succ _ => Int.mul_one _
| 0 => Int.mul_zero _
| -[_+1] => Int.mul_neg_one _
@[deprecated mul_sign_self (since := "2025-02-24")] abbrev mul_sign := @mul_sign_self
@[simp] theorem sign_mul_self : sign i * i = natAbs i := by
rw [Int.mul_comm, mul_sign_self]
/- ## natAbs -/
theorem natAbs_ne_zero {a : Int} : a.natAbs 0 a 0 := not_congr Int.natAbs_eq_zero

View File

@@ -8,8 +8,8 @@ import Init.Data.List.Count
import Init.Data.Subtype
import Init.BinderNameHint
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -190,7 +190,7 @@ theorem length_attachWith {p : α → Prop} {l H} : length (l.attachWith p H) =
@[simp]
theorem pmap_eq_nil_iff {p : α Prop} {f : a, p a β} {l H} : pmap f l H = [] l = [] := by
rw [ length_eq_zero_iff, length_pmap, length_eq_zero_iff]
rw [ length_eq_zero, length_pmap, length_eq_zero]
theorem pmap_ne_nil_iff {P : α Prop} (f : (a : α) P a β) {xs : List α}
(H : (a : α), a xs P a) : xs.pmap f H [] xs [] := by

View File

@@ -58,8 +58,8 @@ Further operations are defined in `Init.Data.List.BasicAux`
-/
set_option linter.missingDocs true -- keep it documented
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Decidable List

View File

@@ -6,8 +6,8 @@ Author: Leonardo de Moura
prelude
import Init.Data.Nat.Linear
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
universe u

View File

@@ -9,8 +9,8 @@ import Init.Control.Id
import Init.Control.Lawful
import Init.Data.List.Basic
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
universe u v w u₁ u₂

View File

@@ -10,8 +10,8 @@ import Init.Data.List.Sublist
# Lemmas about `List.countP` and `List.count`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -87,7 +87,7 @@ theorem countP_le_length : countP p l ≤ l.length := by
countP_pos_iff
@[simp] theorem countP_eq_zero {p} : countP p l = 0 a l, ¬p a := by
simp only [countP_eq_length_filter, length_eq_zero_iff, filter_eq_nil_iff]
simp only [countP_eq_length_filter, length_eq_zero, filter_eq_nil_iff]
@[simp] theorem countP_eq_length {p} : countP p l = l.length a l, p a := by
rw [countP_eq_length_filter, filter_length_eq_length]

View File

@@ -12,8 +12,8 @@ import Init.Data.List.Find
# Lemmas about `List.eraseP`, `List.erase`, and `List.eraseIdx`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -137,7 +137,7 @@ theorem mem_of_mem_eraseP {l : List α} : a ∈ l.eraseP p → a ∈ l := (erase
@[simp] theorem eraseP_eq_self_iff {p} {l : List α} : l.eraseP p = l a l, ¬ p a := by
rw [ Sublist.length_eq (eraseP_sublist l), length_eraseP]
split <;> rename_i h
· simp only [any_eq_true, length_eq_zero_iff] at h
· simp only [any_eq_true, length_eq_zero] at h
constructor
· intro; simp_all [Nat.sub_one_eq_self]
· intro; obtain x, m, h := h; simp_all

View File

@@ -6,8 +6,8 @@ Authors: François G. Dorais
prelude
import Init.Data.List.OfFn
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -15,8 +15,8 @@ Lemmas about `List.findSome?`, `List.find?`, `List.findIdx`, `List.findIdx?`, `L
and `List.lookup`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -514,6 +514,47 @@ private theorem findIdx?_go_eq {p : α → Bool} {xs : List α} {i : Nat} :
(x :: xs).findIdx? p = if p x then some 0 else (xs.findIdx? p).map fun i => i + 1 := by
simp [findIdx?, findIdx?_go_eq]
/-! ### findFinIdx? -/
@[simp] theorem findFinIdx?_nil {p : α Bool} : findFinIdx? p [] = none := rfl
theorem findIdx?_go_eq_map_findFinIdx?_go_val {xs : List α} {p : α Bool} {i : Nat} {h} :
List.findIdx?.go p xs i =
(List.findFinIdx?.go p l xs i h).map (·.val) := by
unfold findIdx?.go
unfold findFinIdx?.go
split
· simp_all
· simp only
split
· simp
· rw [findIdx?_go_eq_map_findFinIdx?_go_val]
theorem findIdx?_eq_map_findFinIdx?_val {xs : List α} {p : α Bool} :
xs.findIdx? p = (xs.findFinIdx? p).map (·.val) := by
simp [findIdx?, findFinIdx?]
rw [findIdx?_go_eq_map_findFinIdx?_go_val]
@[simp] theorem findFinIdx?_cons {p : α Bool} {x : α} {xs : List α} :
findFinIdx? p (x :: xs) = if p x then some 0 else (findFinIdx? p xs).map Fin.succ := by
rw [ Option.map_inj_right (f := Fin.val) (fun a b => Fin.eq_of_val_eq)]
rw [ findIdx?_eq_map_findFinIdx?_val]
rw [findIdx?_cons]
split
· simp
· rw [findIdx?_eq_map_findFinIdx?_val]
simp [Function.comp_def]
@[simp] theorem findFinIdx?_subtype {p : α Prop} {l : List { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findFinIdx? f = (l.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
unfold unattach
induction l with
| nil => simp
| cons a l ih =>
simp [hf, findFinIdx?_cons]
split <;> simp [ih, Function.comp_def]
/-! ### findIdx -/
theorem findIdx_cons (p : α Bool) (b : α) (l : List α) :
@@ -935,71 +976,6 @@ theorem findIdx_eq_getD_findIdx? {xs : List α} {p : α → Bool} :
simp [hf, findIdx?_cons]
split <;> simp [ih, Function.comp_def]
/-! ### findFinIdx? -/
@[simp] theorem findFinIdx?_nil {p : α Bool} : findFinIdx? p [] = none := rfl
theorem findIdx?_go_eq_map_findFinIdx?_go_val {xs : List α} {p : α Bool} {i : Nat} {h} :
List.findIdx?.go p xs i =
(List.findFinIdx?.go p l xs i h).map (·.val) := by
unfold findIdx?.go
unfold findFinIdx?.go
split
· simp_all
· simp only
split
· simp
· rw [findIdx?_go_eq_map_findFinIdx?_go_val]
theorem findIdx?_eq_map_findFinIdx?_val {xs : List α} {p : α Bool} :
xs.findIdx? p = (xs.findFinIdx? p).map (·.val) := by
simp [findIdx?, findFinIdx?]
rw [findIdx?_go_eq_map_findFinIdx?_go_val]
theorem findFinIdx?_eq_pmap_findIdx? {xs : List α} {p : α Bool} :
xs.findFinIdx? p =
(xs.findIdx? p).pmap
(fun i m => by simp [findIdx?_eq_some_iff_getElem] at m; exact i, m.choose)
(fun i h => h) := by
simp [findIdx?_eq_map_findFinIdx?_val, Option.pmap_map]
@[simp] theorem findFinIdx?_cons {p : α Bool} {x : α} {xs : List α} :
findFinIdx? p (x :: xs) = if p x then some 0 else (findFinIdx? p xs).map Fin.succ := by
rw [ Option.map_inj_right (f := Fin.val) (fun a b => Fin.eq_of_val_eq)]
rw [ findIdx?_eq_map_findFinIdx?_val]
rw [findIdx?_cons]
split
· simp
· rw [findIdx?_eq_map_findFinIdx?_val]
simp [Function.comp_def]
@[simp] theorem findFinIdx?_eq_none_iff {l : List α} {p : α Bool} :
l.findFinIdx? p = none x l, ¬ p x := by
simp [findFinIdx?_eq_pmap_findIdx?]
@[simp]
theorem findFinIdx?_eq_some_iff {xs : List α} {p : α Bool} {i : Fin xs.length} :
xs.findFinIdx? p = some i
p xs[i] j (hji : j < i), ¬p (xs[j]'(Nat.lt_trans hji i.2)) := by
simp only [findFinIdx?_eq_pmap_findIdx?, Option.pmap_eq_some_iff, findIdx?_eq_some_iff_getElem,
Bool.not_eq_true, Option.mem_def, exists_and_left, and_exists_self, Fin.getElem_fin]
constructor
· rintro a, h, w₁, w₂, rfl
exact w₁, fun j hji => by simpa using w₂ j hji
· rintro h, w
exact i, i.2, h, fun j hji => w j, by omega hji, rfl
@[simp] theorem findFinIdx?_subtype {p : α Prop} {l : List { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findFinIdx? f = (l.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
unfold unattach
induction l with
| nil => simp
| cons a l ih =>
simp [hf, findFinIdx?_cons]
split <;> simp [ih, Function.comp_def]
/-! ### idxOf
The verification API for `idxOf` is still incomplete.
@@ -1059,36 +1035,6 @@ theorem idxOf_lt_length [BEq α] [LawfulBEq α] {l : List α} (h : a ∈ l) : l.
@[deprecated idxOf_lt_length (since := "2025-01-29")]
abbrev indexOf_lt_length := @idxOf_lt_length
/-! ### finIdxOf?
The verification API for `finIdxOf?` is still incomplete.
The lemmas below should be made consistent with those for `findFinIdx?` (and proved using them).
-/
theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : List α} {a : α} :
xs.idxOf? a = (xs.finIdxOf? a).map (·.val) := by
simp [idxOf?, finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
@[simp] theorem finIdxOf?_nil [BEq α] : ([] : List α).finIdxOf? a = none := rfl
@[simp] theorem finIdxOf?_cons [BEq α] (a : α) (xs : List α) :
(a :: xs).finIdxOf? b =
if a == b then some 0, by simp else (xs.finIdxOf? b).map (·.succ) := by
simp [finIdxOf?]
@[simp] theorem finIdxOf?_eq_none_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} :
l.finIdxOf? a = none a l := by
simp only [finIdxOf?, findFinIdx?_eq_none_iff, beq_iff_eq]
constructor
· intro w m
exact w a m rfl
· rintro h a m rfl
exact h m
@[simp] theorem finIdxOf?_eq_some_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} {i : Fin l.length} :
l.finIdxOf? a = some i l[i] = a j (_ : j < i), ¬l[j] = a := by
simp only [finIdxOf?, findFinIdx?_eq_some_iff, beq_iff_eq]
/-! ### idxOf?
The verification API for `idxOf?` is still incomplete.
@@ -1114,6 +1060,12 @@ theorem idxOf?_cons [BEq α] (a : α) (xs : List α) (b : α) :
@[deprecated idxOf?_eq_none_iff (since := "2025-01-29")]
abbrev indexOf?_eq_none_iff := @idxOf?_eq_none_iff
/-! ### finIdxOf? -/
theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : List α} {a : α} :
xs.idxOf? a = (xs.finIdxOf? a).map (·.val) := by
simp [idxOf?, finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
/-! ### lookup -/
section lookup

View File

@@ -16,8 +16,8 @@ If you import `Init.Data.List.Basic` but do not import this file,
then at runtime you will get non-tail recursive versions of the following definitions.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -210,7 +210,7 @@ def modifyTR (f : αα) (n : Nat) (l : List α) : List α := go l n #[] whe
| a :: l, 0, acc => acc.toListAppend (f a :: l)
| a :: l, n+1, acc => go l n (acc.push a)
theorem modifyTR_go_eq : l i, modifyTR.go f l i acc = acc.toList ++ modify f i l
theorem modifyTR_go_eq : l n, modifyTR.go f l n acc = acc.toList ++ modify f n l
| [], n => by cases n <;> simp [modifyTR.go, modify]
| a :: l, 0 => by simp [modifyTR.go, modify]
| a :: l, n+1 => by simp [modifyTR.go, modify, modifyTR_go_eq l]

View File

@@ -74,8 +74,8 @@ Also
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -96,15 +96,9 @@ theorem ne_nil_of_length_eq_add_one (_ : length l = n + 1) : l ≠ [] := fun _ =
theorem ne_nil_of_length_pos (_ : 0 < length l) : l [] := fun _ => nomatch l
@[simp] theorem length_eq_zero_iff : length l = 0 l = [] :=
@[simp] theorem length_eq_zero : length l = 0 l = [] :=
eq_nil_of_length_eq_zero, fun h => h rfl
@[deprecated length_eq_zero_iff (since := "2025-02-24")]
abbrev length_eq_zero := @length_eq_zero_iff
theorem eq_nil_iff_length_eq_zero : l = [] length l = 0 :=
length_eq_zero_iff.symm
theorem length_pos_of_mem {a : α} : {l : List α}, a l 0 < length l
| _::_, _ => Nat.zero_lt_succ _
@@ -129,21 +123,12 @@ theorem exists_cons_of_length_eq_add_one :
{l : List α}, l.length = n + 1 h t, l = h :: t
| _::_, _ => _, _, rfl
theorem length_pos_iff {l : List α} : 0 < length l l [] :=
Nat.pos_iff_ne_zero.trans (not_congr length_eq_zero_iff)
theorem length_pos {l : List α} : 0 < length l l [] :=
Nat.pos_iff_ne_zero.trans (not_congr length_eq_zero)
@[deprecated length_pos_iff (since := "2025-02-24")]
abbrev length_pos := @length_pos_iff
theorem ne_nil_iff_length_pos {l : List α} : l [] 0 < length l :=
length_pos_iff.symm
theorem length_eq_one_iff {l : List α} : length l = 1 a, l = [a] :=
theorem length_eq_one {l : List α} : length l = 1 a, l = [a] :=
fun h => match l, h with | [_], _ => _, rfl, fun _, h => by simp [h]
@[deprecated length_eq_one_iff (since := "2025-02-24")]
abbrev length_eq_one := @length_eq_one_iff
/-! ### cons -/
theorem cons_ne_nil (a : α) (l : List α) : a :: l [] := nofun
@@ -299,7 +284,7 @@ such a rewrite, with `rw [getElem_of_eq h]`.
theorem getElem_of_eq {l l' : List α} (h : l = l') {i : Nat} (w : i < l.length) :
l[i] = l'[i]'(h w) := by cases h; rfl
theorem getElem_zero {l : List α} (h : 0 < l.length) : l[0] = l.head (length_pos_iff.mp h) :=
theorem getElem_zero {l : List α} (h : 0 < l.length) : l[0] = l.head (length_pos.mp h) :=
match l, h with
| _ :: _, _ => rfl
@@ -390,7 +375,7 @@ theorem eq_append_cons_of_mem {a : α} {xs : List α} (h : a ∈ xs) :
theorem mem_cons_of_mem (y : α) {a : α} {l : List α} : a l a y :: l := .tail _
theorem exists_mem_of_ne_nil (l : List α) (h : l []) : x, x l :=
exists_mem_of_length_pos (length_pos_iff.2 h)
exists_mem_of_length_pos (length_pos.2 h)
theorem eq_nil_iff_forall_not_mem {l : List α} : l = [] a, a l := by
cases l <;> simp [-not_or]
@@ -548,7 +533,7 @@ theorem isEmpty_eq_false_iff_exists_mem {xs : List α} :
cases xs <;> simp
theorem isEmpty_iff_length_eq_zero {l : List α} : l.isEmpty l.length = 0 := by
rw [isEmpty_iff, length_eq_zero_iff]
rw [isEmpty_iff, length_eq_zero]
/-! ### any / all -/
@@ -925,13 +910,13 @@ theorem head?_eq_getElem? : ∀ l : List α, head? l = l[0]?
| [] => rfl
| a :: l => by simp
theorem head_eq_getElem (l : List α) (h : l []) : head l h = l[0]'(length_pos_iff.mpr h) := by
theorem head_eq_getElem (l : List α) (h : l []) : head l h = l[0]'(length_pos.mpr h) := by
cases l with
| nil => simp at h
| cons _ _ => simp
theorem getElem_zero_eq_head (l : List α) (h : 0 < l.length) :
l[0] = head l (by simpa [length_pos_iff] using h) := by
l[0] = head l (by simpa [length_pos] using h) := by
cases l with
| nil => simp at h
| cons _ _ => simp
@@ -1018,7 +1003,7 @@ theorem one_lt_length_of_tail_ne_nil {l : List α} (h : l.tail ≠ []) : 1 < l.l
| nil => simp at h
| cons _ l =>
simp only [tail_cons, ne_eq] at h
exact Nat.lt_add_of_pos_left (length_pos_iff.mpr h)
exact Nat.lt_add_of_pos_left (length_pos.mpr h)
@[simp] theorem head_tail (l : List α) (h : l.tail []) :
(tail l).head h = l[1]'(one_lt_length_of_tail_ne_nil h) := by
@@ -2898,7 +2883,7 @@ theorem getLast?_replicate (a : α) (n : Nat) : (replicate n a).getLast? = if n
-- We unfold `leftpad` and `rightpad` for verification purposes.
attribute [simp] leftpad rightpad
-- `length_leftpad` and `length_rightpad` are in `Init.Data.List.Nat.Basic`.
-- `length_leftpad` is in `Init.Data.List.Nat.Basic`.
theorem leftpad_prefix (n : Nat) (a : α) (l : List α) :
replicate (n - length l) a <+: leftpad n a l := by
@@ -3086,12 +3071,8 @@ variable [BEq α]
@[simp] theorem replace_cons_self [LawfulBEq α] {a : α} : (a::as).replace a b = b::as := by
simp [replace_cons]
@[simp] theorem replace_of_not_mem [LawfulBEq α] {l : List α} (h : a l) : l.replace a b = l := by
induction l with
| nil => rfl
| cons x xs ih =>
simp only [replace_cons]
split <;> simp_all
@[simp] theorem replace_of_not_mem {l : List α} (h : !l.elem a) : l.replace a b = l := by
induction l <;> simp_all [replace_cons]
@[simp] theorem length_replace {l : List α} : (l.replace a b).length = l.length := by
induction l with
@@ -3174,7 +3155,7 @@ theorem replace_take {l : List α} {i : Nat} :
(replicate n a).replace a b = b :: replicate (n - 1) a := by
cases n <;> simp_all [replicate_succ, replace_cons]
@[simp] theorem replace_replicate_ne [LawfulBEq α] {a b c : α} (h : !b == a) :
@[simp] theorem replace_replicate_ne {a b c : α} (h : !b == a) :
(replicate n a).replace b c = replicate n a := by
rw [replace_of_not_mem]
simp_all
@@ -3436,7 +3417,7 @@ theorem get_cons_succ {as : List α} {h : i + 1 < (a :: as).length} :
theorem get_cons_succ' {as : List α} {i : Fin as.length} :
(a :: as).get i.succ = as.get i := rfl
theorem get_mk_zero : {l : List α} (h : 0 < l.length), l.get 0, h = l.head (length_pos_iff.mp h)
theorem get_mk_zero : {l : List α} (h : 0 < l.length), l.get 0, h = l.head (length_pos.mp h)
| _::_, _ => rfl
set_option linter.deprecated false in

View File

@@ -7,8 +7,8 @@ prelude
import Init.Data.List.Lemmas
import Init.Data.List.Nat.TakeDrop
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -11,8 +11,8 @@ import Init.Data.List.OfFn
import Init.Data.Fin.Lemmas
import Init.Data.Option.Attach
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -10,8 +10,8 @@ import Init.Data.List.Lemmas
# Lemmas about `List.min?` and `List.max?.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -11,8 +11,8 @@ import Init.Data.List.Attach
# Lemmas about `List.mapM` and `List.forM`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -321,21 +321,24 @@ theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
forIn' l init (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
l.attach.foldlM (fun b a, m => g a m b <$> f a m b) init := by
simp only [forIn'_eq_foldlM]
induction l.attach generalizing init <;> simp_all
generalize l.attach = l'
induction l' generalizing init <;> simp_all
theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
(l : List α) (f : (a : α) a l β β) (init : β) :
forIn' l init (fun a m b => pure (.yield (f a m b))) =
pure (f := m) (l.attach.foldl (fun b a, h => f a h b) init) := by
simp only [forIn'_eq_foldlM]
induction l.attach generalizing init <;> simp_all
generalize l.attach = l'
induction l' generalizing init <;> simp_all
@[simp] theorem forIn'_yield_eq_foldl
(l : List α) (f : (a : α) a l β β) (init : β) :
forIn' (m := Id) l init (fun a m b => .yield (f a m b)) =
l.attach.foldl (fun b a, h => f a h b) init := by
simp only [forIn'_eq_foldlM]
induction l.attach generalizing init <;> simp_all
generalize l.attach = l'
induction l' generalizing init <;> simp_all
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
(l : List α) (g : α β) (f : (b : β) b l.map g γ m (ForInStep γ)) :

View File

@@ -7,8 +7,8 @@ prelude
import Init.Data.Nat.Lemmas
import Init.Data.List.Basic
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -15,8 +15,8 @@ import Init.Data.Nat.Lemmas
In particular, `omega` is available here.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Nat
@@ -44,42 +44,10 @@ theorem tail_dropLast (l : List α) : tail (dropLast l) = dropLast (tail l) := b
/-! ### filter -/
@[simp]
theorem length_filter_pos_iff {l : List α} {p : α Bool} :
0 < (filter p l).length x l, p x := by
simpa [length_eq_countP_add_countP p l, countP_eq_length_filter] using
countP_pos_iff (p := p)
@[simp]
theorem length_filter_lt_length_iff_exists {l} :
(filter p l).length < l.length x l, ¬p x := by
simp [length_eq_countP_add_countP p l, countP_eq_length_filter]
/-! ### filterMap -/
@[simp]
theorem length_filterMap_pos_iff {xs : List α} {f : α Option β} :
0 < (filterMap f xs).length (x : α) (_ : x xs) (b : β), f x = some b := by
induction xs with
| nil => simp
| cons x xs ih =>
simp only [filterMap, mem_cons, exists_prop, exists_eq_or_imp]
split
· simp_all [ih]
· simp_all
@[simp]
theorem length_filterMap_lt_length_iff_exists {xs : List α} {f : α Option β} :
(filterMap f xs).length < xs.length (x : α) (_ : x xs), f x = none := by
induction xs with
| nil => simp
| cons x xs ih =>
simp only [filterMap, mem_cons, exists_prop, exists_eq_or_imp]
split
· simp_all only [exists_prop, length_cons, true_or, iff_true]
have := length_filterMap_le f xs
omega
· simp_all
length (filter p l) < length l x l, ¬p x := by
simpa [length_eq_countP_add_countP p l, countP_eq_length_filter] using
countP_pos_iff (p := fun x => ¬p x)
/-! ### reverse -/
@@ -95,18 +63,10 @@ theorem getElem_eq_getElem_reverse {l : List α} {i} (h : i < l.length) :
to the larger of `n` and `l.length` -/
-- We don't mark this as a `@[simp]` lemma since we allow `simp` to unfold `leftpad`,
-- so the left hand side simplifies directly to `n - l.length + l.length`.
theorem length_leftpad (n : Nat) (a : α) (l : List α) :
theorem leftpad_length (n : Nat) (a : α) (l : List α) :
(leftpad n a l).length = max n l.length := by
simp only [leftpad, length_append, length_replicate, Nat.sub_add_eq_max]
@[deprecated length_leftpad (since := "2025-02-24")]
abbrev leftpad_length := @length_leftpad
theorem length_rightpad (n : Nat) (a : α) (l : List α) :
(rightpad n a l).length = max n l.length := by
simp [rightpad]
omega
/-! ### eraseIdx -/
theorem mem_eraseIdx_iff_getElem {x : α} :

View File

@@ -7,8 +7,8 @@ prelude
import Init.Data.List.Count
import Init.Data.Nat.Lemmas
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -7,8 +7,8 @@ prelude
import Init.Data.List.Nat.TakeDrop
import Init.Data.List.Erase
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -7,8 +7,8 @@ prelude
import Init.Data.List.Nat.Range
import Init.Data.List.Find
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -12,8 +12,8 @@ import Init.Data.List.Nat.Modify
Proves various lemmas about `List.insertIdx`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Function Nat

View File

@@ -8,8 +8,8 @@ prelude
import Init.Data.List.Nat.TakeDrop
import Init.Data.List.Nat.Erase
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -140,19 +140,19 @@ theorem modifyTailIdx_modifyTailIdx_self {f g : List α → List α} (n : Nat) (
/-! ### modify -/
@[simp] theorem modify_nil (f : α α) (i) : [].modify f i = [] := by cases i <;> rfl
@[simp] theorem modify_nil (f : α α) (n) : [].modify f n = [] := by cases n <;> rfl
@[simp] theorem modify_zero_cons (f : α α) (a : α) (l : List α) :
(a :: l).modify f 0 = f a :: l := rfl
@[simp] theorem modify_succ_cons (f : α α) (a : α) (l : List α) (i) :
(a :: l).modify f (i + 1) = a :: l.modify f i := by rfl
@[simp] theorem modify_succ_cons (f : α α) (a : α) (l : List α) (n) :
(a :: l).modify f (n + 1) = a :: l.modify f n := by rfl
theorem modifyHead_eq_modify_zero (f : α α) (l : List α) :
l.modifyHead f = l.modify f 0 := by cases l <;> simp
@[simp] theorem modify_eq_nil_iff {f : α α} {i} {l : List α} :
l.modify f i = [] l = [] := by cases l <;> cases i <;> simp
@[simp] theorem modify_eq_nil_iff {f : α α} {n} {l : List α} :
l.modify f n = [] l = [] := by cases l <;> cases n <;> simp
theorem getElem?_modify (f : α α) :
i (l : List α) j, (modify f i l)[j]? = (fun a => if i = j then f a else a) <$> l[j]?
@@ -189,8 +189,8 @@ theorem getElem_modify (f : αα) (i) (l : List α) (j) (h : j < (modify f
@[simp] theorem getElem_modify_ne (f : α α) {i j} (l : List α) (h : i j) (h') :
(modify f i l)[j] = l[j]'(by simpa using h') := by simp [getElem_modify, h]
theorem modify_eq_self {f : α α} {i} {l : List α} (h : l.length i) :
l.modify f i = l := by
theorem modify_eq_self {f : α α} {n} {l : List α} (h : l.length n) :
l.modify f n = l := by
apply ext_getElem
· simp
· intro m h₁ h₂
@@ -198,16 +198,16 @@ theorem modify_eq_self {f : αα} {i} {l : List α} (h : l.length ≤ i) :
intro h
omega
theorem modify_modify_eq (f g : α α) (i) (l : List α) :
(modify f i l).modify g i = modify (g f) i l := by
theorem modify_modify_eq (f g : α α) (n) (l : List α) :
(modify f n l).modify g n = modify (g f) n l := by
apply ext_getElem
· simp
· intro m h₁ h₂
simp only [getElem_modify, Function.comp_apply]
split <;> simp
theorem modify_modify_ne (f g : α α) {i j} (l : List α) (h : i j) :
(modify f i l).modify g j = (l.modify g j).modify f i := by
theorem modify_modify_ne (f g : α α) {m n} (l : List α) (h : m n) :
(modify f m l).modify g n = (l.modify g n).modify f m := by
apply ext_getElem
· simp
· intro m' h₁ h₂
@@ -234,13 +234,13 @@ theorem modify_eq_take_cons_drop {f : αα} {i} {l : List α} (h : i < l.le
modify f i l = take i l ++ f l[i] :: drop (i + 1) l := by
rw [modify_eq_take_drop, drop_eq_getElem_cons h]; rfl
theorem exists_of_modify (f : α α) {i} {l : List α} (h : i < l.length) :
l₁ a l₂, l = l₁ ++ a :: l₂ l₁.length = i modify f i l = l₁ ++ f a :: l₂ :=
theorem exists_of_modify (f : α α) {n} {l : List α} (h : n < l.length) :
l₁ a l₂, l = l₁ ++ a :: l₂ l₁.length = n modify f n l = l₁ ++ f a :: l₂ :=
match exists_of_modifyTailIdx _ (Nat.le_of_lt h) with
| _, _::_, eq, hl, H => _, _, _, eq, hl, H
| _, [], eq, hl, _ => nomatch Nat.ne_of_gt h (eq append_nil _ hl)
@[simp] theorem modify_id (i) (l : List α) : l.modify id i = l := by
@[simp] theorem modify_id (n) (l : List α) : l.modify id n = l := by
simp [modify]
theorem take_modify (f : α α) (i j) (l : List α) :

View File

@@ -12,8 +12,8 @@ import Init.Data.List.Pairwise
# Lemmas about `List.Pairwise`
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -7,8 +7,8 @@ prelude
import Init.Data.List.Nat.TakeDrop
import Init.Data.List.Perm
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -14,8 +14,8 @@ import Init.Data.List.Erase
# Lemmas about `List.range` and `List.enum`
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -16,8 +16,8 @@ These are in a separate file from most of the lemmas about `List.IsSuffix`
as they required importing more lemmas about natural numbers, and use `omega`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -156,7 +156,7 @@ theorem append_sublist_of_sublist_left {xs ys zs : List α} (h : zs <+ xs) :
have hl' := h'.length_le
simp only [length_append] at hl'
have : ys.length = 0 := by omega
simp_all only [Nat.add_zero, length_eq_zero_iff, true_and, append_nil]
simp_all only [Nat.add_zero, length_eq_zero, true_and, append_nil]
exact Sublist.eq_of_length_le h' hl
· rintro rfl, rfl
simp
@@ -169,7 +169,7 @@ theorem append_sublist_of_sublist_right {xs ys zs : List α} (h : zs <+ ys) :
have hl' := h'.length_le
simp only [length_append] at hl'
have : xs.length = 0 := by omega
simp_all only [Nat.zero_add, length_eq_zero_iff, true_and, append_nil]
simp_all only [Nat.zero_add, length_eq_zero, true_and, append_nil]
exact Sublist.eq_of_length_le h' hl
· rintro rfl, rfl
simp

View File

@@ -16,8 +16,8 @@ These are in a separate file from most of the list lemmas
as they required importing more lemmas about natural numbers, and use `omega`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -115,12 +115,12 @@ theorem take_set_of_le (a : α) {i j : Nat} (l : List α) (h : j ≤ i) :
@[deprecated take_set_of_le (since := "2025-02-04")]
abbrev take_set_of_lt := @take_set_of_le
@[simp] theorem take_replicate (a : α) : i n : Nat, take i (replicate n a) = replicate (min i n) a
@[simp] theorem take_replicate (a : α) : i j : Nat, take i (replicate j a) = replicate (min i j) a
| n, 0 => by simp [Nat.min_zero]
| 0, m => by simp [Nat.zero_min]
| succ n, succ m => by simp [replicate_succ, succ_min_succ, take_replicate]
@[simp] theorem drop_replicate (a : α) : i n : Nat, drop i (replicate n a) = replicate (n - i) a
@[simp] theorem drop_replicate (a : α) : i j : Nat, drop i (replicate j a) = replicate (j - i) a
| n, 0 => by simp
| 0, m => by simp
| succ n, succ m => by simp [replicate_succ, succ_sub_succ, drop_replicate]

View File

@@ -11,8 +11,8 @@ import Init.Data.Nat.Div.Basic
-/
set_option linter.missingDocs true -- keep it documented
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Decidable List

View File

@@ -11,8 +11,8 @@ import Init.Data.Fin.Fold
# Theorems about `List.ofFn`
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -11,8 +11,8 @@ import Init.Data.List.Attach
# Lemmas about `List.Pairwise` and `List.Nodup`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -18,8 +18,8 @@ another.
The notation `~` is used for permutation equivalence.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Nat

View File

@@ -14,8 +14,8 @@ Most of the results are deferred to `Data.Init.List.Nat.Range`, where more resul
natural arithmetic are available.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -33,7 +33,7 @@ theorem range'_succ (s n step) : range' s (n + 1) step = s :: range' (s + step)
| _ + 1 => congrArg succ (length_range' _ _ _)
@[simp] theorem range'_eq_nil_iff : range' s n step = [] n = 0 := by
rw [ length_eq_zero_iff, length_range']
rw [ length_eq_zero, length_range']
@[deprecated range'_eq_nil_iff (since := "2025-01-29")] abbrev range'_eq_nil := @range'_eq_nil_iff
@@ -74,7 +74,7 @@ theorem mem_range' : ∀{n}, m ∈ range' s n step ↔ ∃ i < n, m = s + step *
rw [exists_comm]; simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm]
theorem getElem?_range' (s step) :
{i n : Nat}, i < n (range' s n step)[i]? = some (s + step * i)
{i j : Nat}, i < j (range' s j step)[i]? = some (s + step * i)
| 0, n + 1, _ => by simp [range'_succ]
| m + 1, n + 1, h => by
simp only [range'_succ, getElem?_cons_succ]
@@ -147,10 +147,10 @@ theorem range_loop_range' : ∀ s n : Nat, range.loop s (range' s n) = range' 0
theorem range_eq_range' (n : Nat) : range n = range' 0 n :=
(range_loop_range' n 0).trans <| by rw [Nat.zero_add]
theorem getElem?_range {i n : Nat} (h : i < n) : (range n)[i]? = some i := by
theorem getElem?_range {i j : Nat} (h : i < j) : (range j)[i]? = some i := by
simp [range_eq_range', getElem?_range' _ _ h]
@[simp] theorem getElem_range {n : Nat} (j) (h : j < (range n).length) : (range n)[j] = j := by
@[simp] theorem getElem_range {i : Nat} (j) (h : j < (range i).length) : (range i)[j] = j := by
simp [range_eq_range']
theorem range_succ_eq_map (n : Nat) : range (n + 1) = 0 :: map succ (range n) := by
@@ -164,7 +164,7 @@ theorem range'_eq_map_range (s n : Nat) : range' s n = map (s + ·) (range n) :=
simp only [range_eq_range', length_range']
@[simp] theorem range_eq_nil {n : Nat} : range n = [] n = 0 := by
rw [ length_eq_zero_iff, length_range]
rw [ length_eq_zero, length_range]
theorem range_ne_nil {n : Nat} : range n [] n 0 := by
cases n <;> simp
@@ -183,9 +183,9 @@ theorem range_subset {m n : Nat} : range m ⊆ range n ↔ m ≤ n := by
theorem range_succ (n : Nat) : range (succ n) = range n ++ [n] := by
simp only [range_eq_range', range'_1_concat, Nat.zero_add]
theorem range_add (n m : Nat) : range (n + m) = range n ++ (range m).map (n + ·) := by
theorem range_add (a b : Nat) : range (a + b) = range a ++ (range b).map (a + ·) := by
rw [ range'_eq_map_range]
simpa [range_eq_range', Nat.add_comm] using (range'_append_1 0 n m).symm
simpa [range_eq_range', Nat.add_comm] using (range'_append_1 0 a b).symm
theorem head?_range (n : Nat) : (range n).head? = if n = 0 then none else some 0 := by
induction n with

View File

@@ -14,8 +14,8 @@ These definitions are intended for verification purposes,
and are replaced at runtime by efficient versions in `Init.Data.List.Sort.Impl`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -31,8 +31,8 @@ as long as such improvements are carefully validated by benchmarking,
they can be done without changing the theory, as long as a `@[csimp]` lemma is provided.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open List

View File

@@ -21,8 +21,8 @@ import Init.Data.Bool
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -11,8 +11,8 @@ import Init.Data.List.TakeDrop
# Lemmas about `List.Subset`, `List.Sublist`, `List.IsPrefix`, `List.IsSuffix`, and `List.IsInfix`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -150,8 +150,8 @@ theorem Sublist.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ <+ l₂) (h₂ : l
| slnil => exact h₁
| cons _ _ IH => exact (IH h₁).cons _
| @cons₂ l₂ _ a _ IH =>
generalize e : a :: l₂ = l₂' at h₁
match h₁ with
generalize e : a :: l₂ = l₂'
match e h₁ with
| .slnil => apply nil_sublist
| .cons a' h₁' => cases e; apply (IH h₁').cons
| .cons₂ a' h₁' => cases e; apply (IH h₁').cons₂

View File

@@ -10,8 +10,8 @@ import Init.Data.List.Lemmas
# Lemmas about `List.take` and `List.drop`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -45,7 +45,7 @@ theorem drop_one : ∀ l : List α, drop 1 l = tail l
_ = succ (length l) - succ i := (Nat.succ_sub_succ_eq_sub (length l) i).symm
theorem drop_of_length_le {l : List α} (h : l.length i) : drop i l = [] :=
length_eq_zero_iff.1 (length_drop .. Nat.sub_eq_zero_of_le h)
length_eq_zero.1 (length_drop .. Nat.sub_eq_zero_of_le h)
theorem length_lt_of_drop_ne_nil {l : List α} {i} (h : drop i l []) : i < l.length :=
gt_of_not_le (mt drop_of_length_le h)

View File

@@ -15,8 +15,8 @@ import Init.Data.Array.Lex.Basic
We prefer to pull `List.toArray` outwards past `Array` operations.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
@@ -44,16 +44,6 @@ theorem toArray_inj {as bs : List α} (h : as.toArray = bs.toArray) : as = bs :=
| nil => simp at h
| cons b bs => simpa using h
theorem toArray_eq_iff {as : List α} {bs : Array α} : as.toArray = bs as = bs.toList := by
cases bs
simp
-- We can't make this a `@[simp]` lemma because `#[] = [].toArray` at reducible transparency,
-- so this would loop with `toList_eq_nil_iff`
theorem eq_toArray_iff {as : Array α} {bs : List α} : as = bs.toArray as.toList = bs := by
cases as
simp
@[simp] theorem size_toArrayAux {as : List α} {xs : Array α} :
(as.toArrayAux xs).size = xs.size + as.length := by
simp [size]
@@ -87,21 +77,6 @@ theorem toArray_cons (a : α) (l : List α) : (a :: l).toArray = #[a] ++ l.toArr
l.toArray.back = l.getLast (by simp at h; exact ne_nil_of_length_pos h) := by
simp [back, List.getLast_eq_getElem]
@[simp] theorem _root_.Array.getLast!_toList [Inhabited α] (xs : Array α) :
xs.toList.getLast! = xs.back! := by
rcases xs with xs
simp
@[simp] theorem _root_.Array.getLast?_toList (xs : Array α) :
xs.toList.getLast? = xs.back? := by
rcases xs with xs
simp
@[simp] theorem _root_.Array.getLast_toList (xs : Array α) (h) :
xs.toList.getLast h = xs.back (by simpa [ne_nil_iff_length_pos] using h) := by
rcases xs with xs
simp
@[simp] theorem set_toArray (l : List α) (i : Nat) (a : α) (h : i < l.length) :
(l.toArray.set i a) = (l.set i a).toArray := rfl
@@ -539,8 +514,8 @@ private theorem popWhile_toArray_aux (p : α → Bool) (l : List α) :
@[simp] theorem toArray_replicate (n : Nat) (v : α) : (List.replicate n v).toArray = mkArray n v := rfl
theorem _root_.Array.mkArray_eq_toArray_replicate : mkArray n v = (List.replicate n v).toArray := by
simp
@[deprecated toArray_replicate (since := "2024-12-13")]
abbrev _root_.Array.mkArray_eq_toArray_replicate := @toArray_replicate
@[simp] theorem flatMap_empty {β} (f : α Array β) : (#[] : Array α).flatMap f = #[] := rfl
@@ -658,46 +633,4 @@ private theorem insertIdx_loop_toArray (i : Nat) (l : List α) (j : Nat) (hj : j
· simp only [size_toArray, Nat.not_le] at h'
rw [List.insertIdx_of_length_lt (h := h')]
@[simp]
theorem replace_toArray [BEq α] [LawfulBEq α] (l : List α) (a b : α) :
l.toArray.replace a b = (l.replace a b).toArray := by
rw [Array.replace]
split <;> rename_i i h
· simp only [finIdxOf?_toArray, finIdxOf?_eq_none_iff] at h
rw [replace_of_not_mem]
simpa
· simp_all only [finIdxOf?_toArray, finIdxOf?_eq_some_iff, Fin.getElem_fin, set_toArray,
mk.injEq]
apply List.ext_getElem
· simp
· intro j h₁ h₂
rw [List.getElem_replace, List.getElem_set]
by_cases h₃ : j < i
· rw [if_neg (by omega), if_neg]
simp only [length_set] at h₁ h₃
simpa using h.2 j, by omega h₃
· by_cases h₃ : j = i
· rw [if_pos (by omega), if_pos, if_neg]
· simp only [mem_take_iff_getElem, not_exists]
intro k hk
simpa using h.2 k, by omega (by show k < i.1; omega)
· subst h₃
simpa using h.1
· rw [if_neg (by omega)]
split
· rw [if_pos]
· simp_all
· simp only [mem_take_iff_getElem]
simp only [length_set] at h₁
exact i, by omega, h.1
· rfl
@[simp] theorem leftpad_toArray (n : Nat) (a : α) (l : List α) :
Array.leftpad n a l.toArray = (leftpad n a l).toArray := by
simp [leftpad, Array.leftpad, toArray_replicate]
@[simp] theorem rightpad_toArray (n : Nat) (a : α) (l : List α) :
Array.rightpad n a l.toArray = (rightpad n a l).toArray := by
simp [rightpad, Array.rightpad, toArray_replicate]
end List

View File

@@ -6,8 +6,8 @@ Authors: Henrik Böving
prelude
import Init.Data.List.Basic
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
/--
Auxiliary definition for `List.toArray`.

View File

@@ -11,8 +11,8 @@ import Init.Data.Function
# Lemmas about `List.zip`, `List.zipWith`, `List.zipWithAll`, and `List.unzip`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -186,7 +186,7 @@ theorem zipWith_eq_cons_iff {f : α → β → γ} {l₁ : List α} {l₂ : List
theorem zipWith_eq_append_iff {f : α β γ} {l₁ : List α} {l₂ : List β} :
zipWith f l₁ l₂ = l₁' ++ l₂'
ws xs ys zs, ws.length = ys.length l₁ = ws ++ xs l₂ = ys ++ zs l₁' = zipWith f ws ys l₂' = zipWith f xs zs := by
w x y z, w.length = y.length l₁ = w ++ x l₂ = y ++ z l₁' = zipWith f w y l₂' = zipWith f x z := by
induction l₁ generalizing l₂ l₁' with
| nil =>
simp
@@ -347,7 +347,7 @@ theorem zip_eq_cons_iff {l₁ : List α} {l₂ : List β} :
theorem zip_eq_append_iff {l₁ : List α} {l₂ : List β} :
zip l₁ l₂ = l₁' ++ l₂'
ws xs ys zs, ws.length = ys.length l₁ = ws ++ xs l₂ = ys ++ zs l₁' = zip ws ys l₂' = zip xs zs := by
w x y z, w.length = y.length l₁ = w ++ x l₂ = y ++ z l₁' = zip w y l₂' = zip x z := by
simp [zip_eq_zipWith, zipWith_eq_append_iff]
/-- See also `List.zip_replicate` in `Init.Data.List.TakeDrop` for a generalization with different lengths. -/

View File

@@ -6,7 +6,6 @@ Authors: Kim Morrison
prelude
import Init.Omega
import Init.Data.Nat.Lemmas
import Init.Data.Nat.Simproc
/-!
# Further lemmas about `Nat.div` and `Nat.mod`, with the convenience of having `omega` available.
@@ -63,53 +62,4 @@ theorem div_add_le_right {z : Nat} (h : 0 < z) (x y : Nat) :
x / (y + z) x / z :=
div_le_div_left (Nat.le_add_left z y) h
theorem succ_div_of_dvd {a b : Nat} (h : b a + 1) :
(a + 1) / b = a / b + 1 := by
replace h := mod_eq_zero_of_dvd h
cases b with
| zero => simp at h
| succ b =>
by_cases h' : b a
· rw [Nat.div_eq]
simp only [zero_lt_succ, Nat.add_le_add_iff_right, h', and_self, reduceIte,
Nat.reduceSubDiff, Nat.add_right_cancel_iff]
obtain _|k, h := Nat.dvd_of_mod_eq_zero h
· simp at h
· simp only [Nat.mul_add, Nat.add_mul, Nat.one_mul, Nat.mul_one, Nat.add_assoc,
Nat.add_right_cancel_iff] at h
subst h
rw [Nat.add_sub_cancel, Nat.add_one_mul, mul_div_right _ (zero_lt_succ _), Nat.add_comm,
Nat.add_mul_div_left _ _ (zero_lt_succ _), Nat.self_eq_add_left, div_eq_of_lt le.refl]
· simp only [Nat.not_le] at h'
replace h' : a + 1 < b + 1 := Nat.add_lt_add_right h' 1
rw [Nat.mod_eq_of_lt h'] at h
simp at h
theorem succ_div_of_mod_eq_zero {a b : Nat} (h : (a + 1) % b = 0) :
(a + 1) / b = a / b + 1 := by
rw [succ_div_of_dvd (by rwa [dvd_iff_mod_eq_zero])]
theorem succ_div_of_not_dvd {a b : Nat} (h : ¬ b a + 1) :
(a + 1) / b = a / b := by
replace h := mt dvd_of_mod_eq_zero h
cases b with
| zero => simp
| succ b =>
rw [eq_comm, Nat.div_eq_iff (by simp)]
constructor
· rw [Nat.div_mul_self_eq_mod_sub_self]
have : (a + 1) % (b + 1) < b + 1 := Nat.mod_lt _ (by simp)
omega
· rw [Nat.div_mul_self_eq_mod_sub_self]
omega
theorem succ_div_of_mod_ne_zero {a b : Nat} (h : (a + 1) % b 0) :
(a + 1) / b = a / b := by
rw [succ_div_of_not_dvd (by rwa [dvd_iff_mod_eq_zero])]
theorem succ_div {a b : Nat} : (a + 1) / b = a / b + if b a + 1 then 1 else 0 := by
split <;> rename_i h
· simp [succ_div_of_dvd h]
· simp [succ_div_of_not_dvd h]
end Nat

View File

@@ -1016,39 +1016,6 @@ theorem mul_add_mod (m x y : Nat) : (m * x + y) % m = y % m := by
· exact (m % 0).div_zero
· case succ n => exact Nat.div_eq_of_lt (m.mod_lt n.succ_pos)
theorem mod_eq_iff {a b c : Nat} :
a % b = c (b = 0 a = c) (c < b Exists fun k => a = b * k + c) :=
fun h =>
if w : b = 0 then
.inl w, by simpa [w] using h
else
.inr by subst h; exact Nat.mod_lt a (zero_lt_of_ne_zero w),
a / b, by subst h; exact (div_add_mod a b).symm,
by
rintro (rfl, rfl | w, h, rfl)
· simp_all
· rw [mul_add_mod, mod_eq_of_lt w]
theorem succ_mod_succ_eq_zero_iff {a b : Nat} :
(a + 1) % (b + 1) = 0 a % (b + 1) = b := by
symm
rw [mod_eq_iff, mod_eq_iff]
simp only [add_one_ne_zero, false_and, Nat.lt_add_one, true_and, false_or, and_self, zero_lt_succ,
Nat.add_zero]
constructor
· rintro k, rfl
refine k + 1, ?_
simp [Nat.add_mul, Nat.mul_add, Nat.add_assoc]
· rintro k, h
cases k with
| zero => simp at h
| succ k =>
refine k, ?_
simp only [Nat.mul_add, Nat.add_mul, Nat.one_mul, Nat.mul_one, Nat.add_assoc,
Nat.add_right_cancel_iff] at h
subst h
simp [Nat.add_mul]
/-! ### Decidability of predicates -/
instance decidableBallLT :

View File

@@ -431,22 +431,19 @@ attribute [local simp] Poly.denote_le_cancel_eq
theorem Expr.denote_toPoly_go (ctx : Context) (e : Expr) :
(toPoly.go k e p).denote ctx = k * e.denote ctx + p.denote ctx := by
induction k, e using Expr.toPoly.go.induct generalizing p with
| case1 k k' h =>
simp [toPoly.go, eq_of_beq h]
| case2 k k' h =>
simp [toPoly.go, h, Var.denote]
| case3 k i => simp [toPoly.go]
| case4 k a b iha ihb => simp [toPoly.go, iha, ihb]
| case5 k k' a h => simp [toPoly.go, h, eq_of_beq h]
| case6 k a k' h ih =>
| case1 k k' =>
simp only [toPoly.go]
by_cases h : k' == 0
· simp [h, eq_of_beq h]
· simp [h, Var.denote]
| case2 k i => simp [toPoly.go]
| case3 k a b iha ihb => simp [toPoly.go, iha, ihb]
| case4 k k' a ih
| case5 k a k' ih =>
simp only [toPoly.go, denote, mul_eq]
simp [h, cond_false, ih, Nat.mul_assoc]
| case7 k a k' h =>
simp only [toPoly.go, denote, mul_eq]
simp [h, eq_of_beq h]
| case8 k a k' h ih =>
simp only [toPoly.go, denote, mul_eq]
simp [h, cond_false, ih, Nat.mul_assoc]
by_cases h : k' == 0
· simp [h, eq_of_beq h]
· simp [h, cond_false, ih, Nat.mul_assoc]
theorem Expr.denote_toPoly (ctx : Context) (e : Expr) : e.toPoly.denote ctx = e.denote ctx := by
simp [toPoly, Expr.denote_toPoly_go]

View File

@@ -40,20 +40,3 @@ theorem neZero_iff {n : R} : NeZero n ↔ n ≠ 0 :=
instance {p : Prop} [Decidable p] {n m : Nat} [NeZero n] [NeZero m] :
NeZero (if p then n else m) := by
split <;> infer_instance
instance {n m : Nat} [h : NeZero n] : NeZero (n + m) where
out :=
match n, h, m with
| _ + 1, _, 0
| _ + 1, _, _ + 1 => fun h => nomatch h
instance {n m : Nat} [h : NeZero m] : NeZero (n + m) where
out :=
match m, h, n with
| _ + 1, _, 0 => fun h => nomatch h
| _ + 1, _, _ + 1 => fun h => nomatch h
instance {n m : Nat} [hn : NeZero n] [hm : NeZero m] : NeZero (n * m) where
out :=
match n, hn, m, hm with
| _ + 1, _, _ + 1, _ => fun h => nomatch h

View File

@@ -654,11 +654,6 @@ theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (o H)
Option.map g (pmap f o H) = pmap (fun a h => g (f a h)) o H := by
cases o <;> simp
theorem pmap_map (o : Option α) (f : α β) {p : β Prop} (g : b, p b γ) (H) :
pmap g (o.map f) H =
pmap (fun a h => g (f a) h) o (fun a m => H (f a) (mem_map_of_mem f m)) := by
cases o <;> simp
/-! ### pelim -/
@[simp] theorem pelim_none : pelim none b f = b := rfl

View File

@@ -7,7 +7,6 @@ prelude
import Init.Data.SInt.Basic
import Init.Data.SInt.Float
import Init.Data.SInt.Float32
import Init.Data.SInt.Lemmas
/-!
This module contains the definitions and basic theory about signed fixed width integer types.

View File

@@ -154,10 +154,6 @@ def Int8.shiftLeft (a b : Int8) : Int8 := ⟨⟨a.toBitVec <<< (b.toBitVec.smod
def Int8.shiftRight (a b : Int8) : Int8 := BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 8)
@[extern "lean_int8_complement"]
def Int8.complement (a : Int8) : Int8 := ~~~a.toBitVec
/-- Computes the absolute value of the signed integer. This function is equivalent to
`if a < 0 then -a else a`, so in particular `Int8.minValue` will be mapped to `Int8.minValue`. -/
@[extern "lean_int8_abs"]
def Int8.abs (a : Int8) : Int8 := a.toBitVec.abs
@[extern "lean_int8_dec_eq"]
def Int8.decEq (a b : Int8) : Decidable (a = b) :=
@@ -294,10 +290,6 @@ def Int16.shiftLeft (a b : Int16) : Int16 := ⟨⟨a.toBitVec <<< (b.toBitVec.sm
def Int16.shiftRight (a b : Int16) : Int16 := BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 16)
@[extern "lean_int16_complement"]
def Int16.complement (a : Int16) : Int16 := ~~~a.toBitVec
/-- Computes the absolute value of the signed integer. This function is equivalent to
`if a < 0 then -a else a`, so in particular `Int16.minValue` will be mapped to `Int16.minValue`. -/
@[extern "lean_int16_abs"]
def Int16.abs (a : Int16) : Int16 := a.toBitVec.abs
@[extern "lean_int16_dec_eq"]
def Int16.decEq (a b : Int16) : Decidable (a = b) :=
@@ -438,10 +430,6 @@ def Int32.shiftLeft (a b : Int32) : Int32 := ⟨⟨a.toBitVec <<< (b.toBitVec.sm
def Int32.shiftRight (a b : Int32) : Int32 := BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 32)
@[extern "lean_int32_complement"]
def Int32.complement (a : Int32) : Int32 := ~~~a.toBitVec
/-- Computes the absolute value of the signed integer. This function is equivalent to
`if a < 0 then -a else a`, so in particular `Int32.minValue` will be mapped to `Int32.minValue`. -/
@[extern "lean_int32_abs"]
def Int32.abs (a : Int32) : Int32 := a.toBitVec.abs
@[extern "lean_int32_dec_eq"]
def Int32.decEq (a b : Int32) : Decidable (a = b) :=
@@ -586,10 +574,6 @@ def Int64.shiftLeft (a b : Int64) : Int64 := ⟨⟨a.toBitVec <<< (b.toBitVec.sm
def Int64.shiftRight (a b : Int64) : Int64 := BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 64)
@[extern "lean_int64_complement"]
def Int64.complement (a : Int64) : Int64 := ~~~a.toBitVec
/-- Computes the absolute value of the signed integer. This function is equivalent to
`if a < 0 then -a else a`, so in particular `Int64.minValue` will be mapped to `Int64.minValue`. -/
@[extern "lean_int64_abs"]
def Int64.abs (a : Int64) : Int64 := a.toBitVec.abs
@[extern "lean_int64_dec_eq"]
def Int64.decEq (a b : Int64) : Decidable (a = b) :=
@@ -706,8 +690,9 @@ instance : Neg ISize where
/-- The maximum value an `ISize` may attain, that is, `2^(System.Platform.numBits - 1) - 1`. -/
abbrev ISize.maxValue : ISize := .ofInt (2 ^ (System.Platform.numBits - 1) - 1)
-- 9223372036854775807
/-- The minimum value an `ISize` may attain, that is, `-2^(System.Platform.numBits - 1)`. -/
abbrev ISize.minValue : ISize := .ofInt (-2 ^ (System.Platform.numBits - 1))
abbrev ISize.minValue : ISize := .ofInt (2 ^ (System.Platform.numBits - 1))
/-- Constructs an `ISize` from an `Int` which is known to be in bounds. -/
@[inline]
@@ -745,10 +730,6 @@ def ISize.shiftLeft (a b : ISize) : ISize := ⟨⟨a.toBitVec <<< (b.toBitVec.sm
def ISize.shiftRight (a b : ISize) : ISize := BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod System.Platform.numBits)
@[extern "lean_isize_complement"]
def ISize.complement (a : ISize) : ISize := ~~~a.toBitVec
/-- Computes the absolute value of the signed integer. This function is equivalent to
`if a < 0 then -a else a`, so in particular `ISize.minValue` will be mapped to `ISize.minValue`. -/
@[extern "lean_isize_abs"]
def ISize.abs (a : ISize) : ISize := a.toBitVec.abs
@[extern "lean_isize_dec_eq"]
def ISize.decEq (a b : ISize) : Decidable (a = b) :=

View File

@@ -1,13 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Markus Himmel
-/
prelude
import Init.Data.SInt.Basic
@[simp] theorem UInt8.toBitVec_toInt8 (x : UInt8) : x.toInt8.toBitVec = x.toBitVec := rfl
@[simp] theorem UInt16.toBitVec_toInt16 (x : UInt16) : x.toInt16.toBitVec = x.toBitVec := rfl
@[simp] theorem UInt32.toBitVec_toInt32 (x : UInt32) : x.toInt32.toBitVec = x.toBitVec := rfl
@[simp] theorem UInt64.toBitVec_toInt64 (x : UInt64) : x.toInt64.toBitVec = x.toBitVec := rfl
@[simp] theorem USize.toBitVec_toISize (x : USize) : x.toISize.toBitVec = x.toBitVec := rfl

View File

@@ -295,16 +295,11 @@ def USize.mk (bitVec : BitVec System.Platform.numBits) : USize :=
def USize.ofNatCore (n : Nat) (h : n < USize.size) : USize :=
USize.ofNatLT n h
@[simp] theorem USize.le_size : 2 ^ 32 USize.size := by cases USize.size_eq <;> simp_all
@[simp] theorem USize.size_le : USize.size 2 ^ 64 := by cases USize.size_eq <;> simp_all
theorem usize_size_le : USize.size 18446744073709551616 := by
cases usize_size_eq <;> next h => rw [h]; decide
@[deprecated USize.size_le (since := "2025-02-24")]
theorem usize_size_le : USize.size 18446744073709551616 :=
USize.size_le
@[deprecated USize.le_size (since := "2025-02-24")]
theorem le_usize_size : 4294967296 USize.size :=
USize.le_size
theorem le_usize_size : 4294967296 USize.size := by
cases usize_size_eq <;> next h => rw [h]; decide
@[extern "lean_usize_mul"]
def USize.mul (a b : USize) : USize := a.toBitVec * b.toBitVec
@@ -331,7 +326,7 @@ This function is overridden with a native implementation.
-/
@[extern "lean_usize_of_nat"]
def USize.ofNat32 (n : @& Nat) (h : n < 4294967296) : USize :=
USize.ofNatLT n (Nat.lt_of_lt_of_le h USize.le_size)
USize.ofNatLT n (Nat.lt_of_lt_of_le h le_usize_size)
@[extern "lean_uint8_to_usize"]
def UInt8.toUSize (a : UInt8) : USize :=
USize.ofNat32 a.toBitVec.toNat (Nat.lt_trans a.toBitVec.isLt (by decide))
@@ -356,7 +351,7 @@ This function is overridden with a native implementation.
-/
@[extern "lean_usize_to_uint64"]
def USize.toUInt64 (a : USize) : UInt64 :=
UInt64.ofNatLT a.toBitVec.toNat (Nat.lt_of_lt_of_le a.toBitVec.isLt USize.size_le)
UInt64.ofNatLT a.toBitVec.toNat (Nat.lt_of_lt_of_le a.toBitVec.isLt usize_size_le)
instance : Mul USize := USize.mul
instance : Mod USize := USize.mod

View File

@@ -138,16 +138,8 @@ def UInt32.toUInt64 (a : UInt32) : UInt64 := ⟨⟨a.toNat, Nat.lt_trans a.toBit
instance UInt64.instOfNat : OfNat UInt64 n := UInt64.ofNat n
@[deprecated USize.size_eq (since := "2025-02-24")]
theorem usize_size_eq : USize.size = 4294967296 USize.size = 18446744073709551616 :=
USize.size_eq
@[deprecated USize.size_pos (since := "2025-02-24")]
theorem usize_size_pos : 0 < USize.size :=
USize.size_pos
@[deprecated USize.size_pos (since := "2024-11-24")] theorem usize_size_gt_zero : USize.size > 0 :=
USize.size_pos
@[deprecated usize_size_pos (since := "2024-11-24")] theorem usize_size_gt_zero : USize.size > 0 :=
usize_size_pos
/-- Converts a `USize` into the corresponding `Fin USize.size`. -/
def USize.toFin (x : USize) : Fin USize.size := x.toBitVec.toFin
@@ -163,7 +155,7 @@ def USize.ofNatTruncate (n : Nat) : USize :=
if h : n < USize.size then
USize.ofNatLT n h
else
USize.ofNatLT (USize.size - 1) (Nat.pred_lt (Nat.ne_zero_of_lt USize.size_pos))
USize.ofNatLT (USize.size - 1) (Nat.pred_lt (Nat.ne_zero_of_lt usize_size_pos))
abbrev Nat.toUSize := USize.ofNat
@[extern "lean_usize_to_nat"]
def USize.toNat (n : USize) : Nat := n.toBitVec.toNat

View File

@@ -25,11 +25,11 @@ namespace $typeName
@[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, -toNat_toBitVec]
@[simp] protected theorem toNat_or (a b : $typeName) : (a ||| b).toNat = a.toNat ||| b.toNat := by simp [toNat, -toNat_toBitVec]
@[simp] protected theorem toNat_xor (a b : $typeName) : (a ^^^ b).toNat = a.toNat ^^^ b.toNat := by simp [toNat, -toNat_toBitVec]
@[simp] protected theorem toNat_shiftLeft (a b : $typeName) : (a <<< b).toNat = a.toNat <<< (b.toNat % $bits) % 2 ^ $bits := by simp [toNat, -toNat_toBitVec]
@[simp] protected theorem toNat_shiftRight (a b : $typeName) : (a >>> b).toNat = a.toNat >>> (b.toNat % $bits) := by simp [toNat, -toNat_toBitVec]
@[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]
@[simp] protected theorem toNat_xor (a b : $typeName) : (a ^^^ b).toNat = a.toNat ^^^ b.toNat := by simp [toNat]
@[simp] protected theorem toNat_shiftLeft (a b : $typeName) : (a <<< b).toNat = a.toNat <<< (b.toNat % $bits) % 2 ^ $bits := by simp [toNat]
@[simp] protected theorem toNat_shiftRight (a b : $typeName) : (a >>> b).toNat = a.toNat >>> (b.toNat % $bits) := by simp [toNat]
open $typeName (toNat_and) in
@[deprecated toNat_and (since := "2024-11-28")]
@@ -37,6 +37,7 @@ protected theorem and_toNat (a b : $typeName) : (a &&& b).toNat = a.toNat &&& b.
end $typeName
)
declare_bitwise_uint_theorems UInt8 8
declare_bitwise_uint_theorems UInt16 16
declare_bitwise_uint_theorems UInt32 32

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