Compare commits

..

11 Commits

Author SHA1 Message Date
Kim Morrison
f1d1b28d12 Merge remote-tracking branch 'origin/master' into back_get 2025-02-17 12:12:48 +11:00
Kim Morrison
37e851d82e cleanup 2025-02-17 12:08:14 +11:00
Kim Morrison
5699f29ba1 fix tests 2025-02-14 14:48:36 +11:00
Kim Morrison
bd98715f0c fix tests 2025-02-14 14:13:14 +11:00
Kim Morrison
24feb34190 . 2025-02-13 10:58:20 +11:00
Kim Morrison
45a3bb6af1 . 2025-02-13 10:58:19 +11:00
Kim Morrison
d4cf3ec0ff . 2025-02-13 10:58:19 +11:00
Kim Morrison
6501af8a16 . 2025-02-13 10:58:19 +11:00
Kim Morrison
a9891d7173 . 2025-02-13 10:58:19 +11:00
Kim Morrison
5ce7ce1605 deprecating List.get? too 2025-02-13 10:58:19 +11:00
Kim Morrison
1151636139 chore: deprecate Array.get?, add Array.back 2025-02-13 10:58:19 +11:00
1043 changed files with 11174 additions and 24021 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

@@ -122,8 +122,6 @@ example : Vector Nat :=
Every file should start with a copyright header, imports (in the standard library, this always includes a `prelude` declaration) and a module documentation string. There should not be a blank line between the copyright header and the imports. There should be a blank line between the imports and the module documentation string.
If you explicitly declare universe variables, do so at the top of the file, after the module documentation.
Correct:
```lean
/-
@@ -139,8 +137,6 @@ import Init.Data.List.Find
/-!
**# Lemmas about `List.eraseP` and `List.erase`.**
-/
universe u u'
```
Syntax that is not supposed to be user-facing must be scoped. New public syntax must always be discussed explicitly in an RFC.
@@ -289,15 +285,6 @@ structure Iterator where
deriving Inhabited
```
## Notation and Unicode
We generally prefer to use notation as available. We usually prefer the Unicode versions of notations over non-Unicode alternatives.
There are some rules and exceptions regarding specific notations which are listed below:
* Sigma types: use `(a : α) × β a` instead of `Σ a, β a` or `Sigma β`.
* Function arrows: use `fun a => f x` instead of `fun x ↦ f x` or `λ x => f x` or any other variant.
## Language constructs
### Pattern matching, induction etc.
@@ -417,35 +404,6 @@ instance [Inhabited α] : Inhabited (Descr α β σ) where
}
```
### Declaring structures
When defining structure types, do not parenthesize structure fields.
When declaring a structure type with a custom constructor name, put the custom name on its own line, indented like the
structure fields, and add a documentation comment.
Correct:
```lean
/--
A bitvector of the specified width.
This is represented as the underlying `Nat` number in both the runtime
and the kernel, inheriting all the special support for `Nat`.
-/
structure BitVec (w : Nat) where
/--
Constructs a `BitVec w` from a number less than `2^w`.
O(1), because we use `Fin` as the internal representation of a bitvector.
-/
ofFin ::
/--
Interprets a bitvector as a number less than `2^w`.
O(1), because we use `Fin` as the internal representation of a bitvector.
-/
toFin : Fin (2 ^ w)
```
## Tactic proofs
Tactic proofs are the most common thing to break during any kind of upgrade, so it is important to write them in a way that minimizes the likelihood of proofs breaking and that makes it easy to debug breakages if they do occur.

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

@@ -27,4 +27,3 @@ import Init.Data.Array.Range
import Init.Data.Array.Erase
import Init.Data.Array.Zip
import Init.Data.Array.InsertIdx
import Init.Data.Array.Extract

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,159 @@ 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_coe (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_val (l : Array α) (f : α β) : (l.attach.map fun i => f i.val) = l.map f :=
attach_map_coe _ _
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_coe {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_val {p : α Prop} (f : α β) (l : Array α) (H : a l, p a) :
((l.attachWith p H).map fun i => f i.val) = l.map f :=
attachWith_map_coe _ _ _
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 +269,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,10 +315,10 @@ 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
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
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, size_toArray,
List.length_pmap, List.foldl_toArray', mem_toArray, List.foldl_subtype]
congr
ext
@@ -336,101 +334,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
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
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, 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 +497,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 +546,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 +591,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 +612,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 +633,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
simp only [List.size_toArray, List.filterMap_toArray', List.unattach_toArray, List.length_unattach,
l.filterMap f = l.unattach.filterMap g := by
cases l
simp only [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
simp only [List.size_toArray, List.flatMap_toArray, List.unattach_toArray, List.length_unattach,
(l.flatMap f) = l.unattach.flatMap g := by
cases l
simp only [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,24 +71,26 @@ 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
-- This does not need to be a simp lemma, as already after the `whnfR` the right hand side is `as`.
theorem toList_toArray (as : List α) : as.toArray.toList = as := rfl
@[simp] theorem getElem_toList {xs : Array α} {i : Nat} (h : i < xs.size) : xs.toList[i] = xs[i] := rfl
@[simp] theorem size_toArray (as : List α) : as.toArray.size = as.length := by simp [size]
@[simp] theorem getElem?_toList {xs : Array α} {i : Nat} : xs.toList[i]? = xs[i]? := by
simp [getElem?_def]
@[simp] theorem getElem_toList {a : Array α} {i : Nat} (h : i < a.size) : a.toList[i] = a[i] := rfl
@[simp] theorem getElem?_toList {a : Array α} {i : Nat} : a.toList[i]? = a[i]? := rfl
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
-- NB: This is defined as a structure rather than a plain def so that a lemma
@@ -108,7 +107,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
@@ -116,35 +115,22 @@ end Array
namespace List
@[deprecated Array.toArray_toList (since := "2025-02-17")]
abbrev toArray_toList := @Array.toArray_toList
@[simp] theorem toArray_toList (a : Array α) : a.toList.toArray = a := rfl
-- This does not need to be a simp lemma, as already after the `whnfR` the right hand side is `as`.
theorem toList_toArray (as : List α) : as.toArray.toList = as := rfl
@[simp] theorem getElem_toArray {a : List α} {i : Nat} (h : i < a.toArray.size) :
a.toArray[i] = a[i]'(by simpa using h) := rfl
@[deprecated toList_toArray (since := "2025-02-17")]
abbrev _root_.Array.toList_toArray := @List.toList_toArray
@[simp] theorem getElem?_toArray {a : List α} {i : Nat} : a.toArray[i]? = a[i]? := rfl
@[simp] theorem size_toArray (as : List α) : as.toArray.size = as.length := by simp [Array.size]
@[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 {xs : List α} {i : Nat} : xs.toArray[i]? = xs[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
namespace Array
@[deprecated toList_toArray (since := "2024-09-09")] abbrev data_toArray := @List.toList_toArray
@[deprecated toList_toArray (since := "2024-09-09")] abbrev data_toArray := @toList_toArray
@[deprecated Array.toList (since := "2024-09-10")] abbrev Array.data := @Array.toList
@@ -168,15 +154,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 +177,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 +195,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 +214,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 +261,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 +270,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 +279,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 +463,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 +482,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 +667,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 +685,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 +740,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 +759,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 +799,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 +824,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 +847,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 β) :=
@@ -917,21 +902,17 @@ def popWhile (p : α → Bool) (as : Array α) : Array α :=
as
decreasing_by simp_wf; decreasing_trivial_pre_omega
@[simp] theorem popWhile_empty (p : α Bool) :
popWhile p #[] = #[] := by
simp [popWhile]
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 +923,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 +946,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 +1071,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 +1083,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 +1097,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 +1125,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,151 +13,122 @@ 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
/--
Use the indexing notation `a[i]` instead.
Access an element from an array without needing a runtime bounds checks,
using a `Nat` index and a proof that it is in bounds.
This function does not use `get_elem_tactic` to automatically find the proof that
the index is in bounds. This is because the tactic itself needs to look up values in
arrays.
-/
@[deprecated "Use indexing notation `as[i]` instead" (since := "2025-02-17")]
def get {α : Type u} (a : @& Array α) (i : @& Nat) (h : LT.lt i a.size) : α :=
a.toList.get i, h
/--
Use the indexing notation `a[i]!` instead.
Access an element from an array, or panic if the index is out of bounds.
-/
@[deprecated "Use indexing notation `as[i]!` instead" (since := "2025-02-17")]
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 pop_toList (arr : Array α) : arr.pop.toList = arr.toList.dropLast := rfl
@[deprecated toList_pop (since := "2025-02-17")]
abbrev pop_toList := @Array.toList_pop
@[simp] theorem append_eq_append (arr arr' : Array α) : arr.append arr' = arr ++ arr' := rfl
@[simp] theorem append_eq_append (xs ys : Array α) : xs.append ys = xs ++ ys := 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")]
@@ -182,7 +153,7 @@ abbrev push_data := @push_toList
abbrev toList_eq := @toListImpl_eq
@[deprecated pop_toList (since := "2024-09-09")]
abbrev pop_data := @toList_pop
abbrev pop_data := @pop_toList
@[deprecated toList_append (since := "2024-09-09")]
abbrev append_data := @toList_append

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,70 +279,70 @@ 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
simp only [List.size_toArray] at h
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 [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,
List.size_toArray, List.append_toArray, mk.injEq, List.append_cancel_left_eq]
size_toArray, List.append_toArray, mk.injEq, List.append_cancel_left_eq]
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 only [List.eraseIdx_toArray, mk.injEq, List.eraseIdx_eq_nil_iff, List.size_toArray,
@[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, 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

@@ -1,430 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Array.Lemmas
import Init.Data.List.Nat.TakeDrop
/-!
# Lemmas about `Array.extract`
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
/-! ### extract -/
@[simp] theorem extract_of_size_lt {as : Array α} {i j : Nat} (h : as.size < j) :
as.extract i j = as.extract i as.size := by
ext l h₁ h₂
· simp
omega
· simp only [size_extract] at h₁ h₂
simp [h]
theorem size_extract_le {as : Array α} {i j : Nat} :
(as.extract i j).size j - i := by
simp
omega
theorem size_extract_le' {as : Array α} {i j : Nat} :
(as.extract i j).size as.size - i := by
simp
omega
theorem size_extract_of_le {as : Array α} {i j : Nat} (h : j as.size) :
(as.extract i j).size = j - i := by
simp
omega
@[simp]
theorem extract_push {as : Array α} {b : α} {start stop : Nat} (h : stop as.size) :
(as.push b).extract start stop = as.extract start stop := by
ext i h₁ h₂
· simp
omega
· simp only [size_extract, size_push] at h₁ h₂
simp only [getElem_extract, getElem_push]
rw [dif_pos (by omega)]
@[simp]
theorem extract_eq_pop {as : Array α} {stop : Nat} (h : stop = as.size - 1) :
as.extract 0 stop = as.pop := by
ext i h₁ h₂
· simp
omega
· simp only [size_extract, size_pop] at h₁ h₂
simp [getElem_extract, getElem_pop]
@[simp]
theorem extract_append_extract {as : Array α} {i j k : Nat} :
as.extract i j ++ as.extract j k = as.extract (min i j) (max j k) := by
ext l h₁ h₂
· simp
omega
· simp only [size_append, size_extract] at h₁ h₂
simp only [getElem_append, size_extract, getElem_extract]
split <;>
· congr 1
omega
@[simp]
theorem extract_eq_empty_iff {as : Array α} :
as.extract i j = #[] min j as.size i := by
constructor
· intro h
replace h := congrArg Array.size h
simp at h
omega
· intro h
exact eq_empty_of_size_eq_zero (by simp; omega)
theorem extract_eq_empty_of_le {as : Array α} (h : min j as.size i) :
as.extract i j = #[] :=
extract_eq_empty_iff.2 h
theorem lt_of_extract_ne_empty {as : Array α} (h : as.extract i j #[]) :
i < min j as.size :=
gt_of_not_le (mt extract_eq_empty_of_le h)
@[simp]
theorem extract_eq_self_iff {as : Array α} :
as.extract i j = as as.size = 0 i = 0 as.size j := by
constructor
· intro h
replace h := congrArg Array.size h
simp at h
omega
· intro h
ext l h₁ h₂
· simp
omega
· simp only [size_extract] at h₁
simp only [getElem_extract]
congr 1
omega
theorem extract_eq_self_of_le {as : Array α} (h : as.size j) :
as.extract 0 j = as :=
extract_eq_self_iff.2 (.inr rfl, h)
theorem le_of_extract_eq_self {as : Array α} (h : as.extract i j = as) :
as.size j := by
replace h := congrArg Array.size h
simp at h
omega
@[simp]
theorem extract_size_left {as : Array α} :
as.extract as.size j = #[] := by
simp
omega
@[simp]
theorem push_extract_getElem {as : Array α} {i j : Nat} (h : j < as.size) :
(as.extract i j).push as[j] = as.extract (min i j) (j + 1) := by
ext l h₁ h₂
· simp
omega
· simp only [size_push, size_extract] at h₁ h₂
simp only [getElem_push, size_extract, getElem_extract]
split <;>
· congr
omega
theorem extract_succ_right {as : Array α} {i j : Nat} (w : i < j + 1) (h : j < as.size) :
as.extract i (j + 1) = (as.extract i j).push as[j] := by
ext l h₁ h₂
· simp
omega
· simp only [size_extract, push_extract_getElem] at h₁ h₂
simp only [getElem_extract, push_extract_getElem]
congr
omega
theorem extract_sub_one {as : Array α} {i j : Nat} (h : j < as.size) :
as.extract i (j - 1) = (as.extract i j).pop := by
ext l h₁ h₂
· simp
omega
· simp only [size_extract, size_pop] at h₁ h₂
simp only [getElem_extract, getElem_pop]
@[simp]
theorem getElem?_extract_of_lt {as : Array α} {i j k : Nat} (h : k < min j as.size - i) :
(as.extract i j)[k]? = some (as[i + k]'(by omega)) := by
simp [getElem?_extract, h]
theorem getElem?_extract_of_succ {as : Array α} {j : Nat} :
(as.extract 0 (j + 1))[j]? = as[j]? := by
simp [getElem?_extract]
omega
@[simp] theorem extract_extract {as : Array α} {i j k l : Nat} :
(as.extract i j).extract k l = as.extract (i + k) (min (i + l) j) := by
ext m h₁ h₂
· simp
omega
· simp only [size_extract] at h₁ h₂
simp [Nat.add_assoc]
theorem extract_eq_empty_of_eq_empty {as : Array α} {i j : Nat} (h : as = #[]) :
as.extract i j = #[] := by
simp [h]
theorem ne_empty_of_extract_ne_empty {as : Array α} {i j : Nat} (h : as.extract i j #[]) :
as #[] :=
mt extract_eq_empty_of_eq_empty h
theorem extract_set {as : Array α} {i j k : Nat} (h : k < as.size) {a : α} :
(as.set k a).extract i j =
if _ : k < i then
as.extract i j
else if _ : k < min j as.size then
(as.extract i j).set (k - i) a (by simp; omega)
else as.extract i j := by
split
· ext l h₁ h₂
· simp
· simp at h₁ h₂
simp [getElem_set]
omega
· split
· ext l h₁ h₂
· simp
· simp only [getElem_extract, getElem_set]
split
· rw [if_pos]; omega
· rw [if_neg]; omega
· ext l h₁ h₂
· simp
· simp at h₁ h₂
simp [getElem_set]
omega
theorem set_extract {as : Array α} {i j k : Nat} (h : k < (as.extract i j).size) {a : α} :
(as.extract i j).set k a = (as.set (i + k) a (by simp at h; omega)).extract i j := by
ext l h₁ h₂
· simp
· simp_all [getElem_set]
@[simp]
theorem extract_append {as bs : Array α} {i j : Nat} :
(as ++ bs).extract i j = as.extract i j ++ bs.extract (i - as.size) (j - as.size) := by
ext l h₁ h₂
· simp
omega
· simp only [size_extract, size_append] at h₁ h₂
simp only [getElem_extract, getElem_append, size_extract]
split
· split
· rfl
· omega
· split
· omega
· congr 1
omega
theorem extract_append_left {as bs : Array α} :
(as ++ bs).extract 0 as.size = as.extract 0 as.size := by
simp
@[simp] theorem extract_append_right {as bs : Array α} :
(as ++ bs).extract as.size (as.size + i) = bs.extract 0 i := by
simp only [extract_append, extract_size_left, Nat.sub_self, empty_append]
congr 1
omega
@[simp] theorem map_extract {as : Array α} {i j : Nat} :
(as.extract i j).map f = (as.map f).extract i j := by
ext l h₁ h₂
· simp
· simp only [size_map, size_extract] at h₁ h₂
simp only [getElem_map, getElem_extract]
@[simp] theorem extract_mkArray {a : α} {n i j : Nat} :
(mkArray n a).extract i j = mkArray (min j n - i) a := by
ext l h₁ h₂
· simp
· simp only [size_extract, size_mkArray] at h₁ h₂
simp only [getElem_extract, getElem_mkArray]
theorem extract_eq_extract_right {as : Array α} {i j j' : Nat} :
as.extract i j = as.extract i j' min (j - i) (as.size - i) = min (j' - i) (as.size - i) := by
rcases as with as
simp
theorem extract_eq_extract_left {as : Array α} {i i' j : Nat} :
as.extract i j = as.extract i' j min j as.size - i = min j as.size - i' := by
constructor
· intro h
replace h := congrArg Array.size h
simpa using h
· intro h
ext l h₁ h₂
· simpa
· simp only [size_extract] at h₁ h₂
simp only [getElem_extract]
congr 1
omega
theorem extract_add_left {as : Array α} {i j k : Nat} :
as.extract (i + j) k = (as.extract i k).extract j (k - i) := by
simp [extract_eq_extract_right]
omega
theorem mem_extract_iff_getElem {as : Array α} {a : α} {i j : Nat} :
a as.extract i j (k : Nat) (hm : k < min j as.size - i), as[i + k] = a := by
rcases as with as
simp [List.mem_take_iff_getElem]
constructor <;>
· rintro k, h, rfl
exact k, by omega, rfl
theorem set_eq_push_extract_append_extract {as : Array α} {i : Nat} (h : i < as.size) {a : α} :
as.set i a = (as.extract 0 i).push a ++ (as.extract (i + 1) as.size) := by
rcases as with as
simp at h
simp [List.set_eq_take_append_cons_drop, h, List.take_of_length_le]
theorem extract_reverse {as : Array α} {i j : Nat} :
as.reverse.extract i j = (as.extract (as.size - j) (as.size - i)).reverse := by
ext l h₁ h₂
· simp
omega
· simp only [size_extract, size_reverse] at h₁ h₂
simp only [getElem_extract, getElem_reverse, size_extract]
congr 1
omega
theorem reverse_extract {as : Array α} {i j : Nat} :
(as.extract i j).reverse = as.reverse.extract (as.size - j) (as.size - i) := by
rw [extract_reverse]
simp
by_cases h : j as.size
· have : as.size - (as.size - j) = j := by omega
simp [this, extract_eq_extract_left]
omega
· have : as.size - (as.size - j) = as.size := by omega
simp only [Nat.not_le] at h
simp [h, this, extract_eq_extract_left]
omega
/-! ### takeWhile -/
theorem takeWhile_map (f : α β) (p : β Bool) (as : Array α) :
(as.map f).takeWhile p = (as.takeWhile (p f)).map f := by
rcases as with as
simp [List.takeWhile_map]
theorem popWhile_map (f : α β) (p : β Bool) (as : Array α) :
(as.map f).popWhile p = (as.popWhile (p f)).map f := by
rcases as with as
simp [List.dropWhile_map, List.map_reverse]
theorem takeWhile_filterMap (f : α Option β) (p : β Bool) (as : Array α) :
(as.filterMap f).takeWhile p = (as.takeWhile fun a => (f a).all p).filterMap f := by
rcases as with as
simp [List.takeWhile_filterMap]
theorem popWhile_filterMap (f : α Option β) (p : β Bool) (as : Array α) :
(as.filterMap f).popWhile p = (as.popWhile fun a => (f a).all p).filterMap f := by
rcases as with as
simp [List.dropWhile_filterMap, List.filterMap_reverse]
theorem takeWhile_filter (p q : α Bool) (as : Array α) :
(as.filter p).takeWhile q = (as.takeWhile fun a => !p a || q a).filter p := by
rcases as with as
simp [List.takeWhile_filter]
theorem popWhile_filter (p q : α Bool) (as : Array α) :
(as.filter p).popWhile q = (as.popWhile fun a => !p a || q a).filter p := by
rcases as with as
simp [List.dropWhile_filter, List.filter_reverse]
theorem takeWhile_append {xs ys : Array α} :
(xs ++ ys).takeWhile p =
if (xs.takeWhile p).size = xs.size then xs ++ ys.takeWhile p else xs.takeWhile p := by
rcases xs with xs
rcases ys with ys
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 at h
simp [List.takeWhile_append_of_pos h]
theorem popWhile_append {xs ys : Array α} :
(xs ++ ys).popWhile p =
if (ys.popWhile p).isEmpty then xs.popWhile p else xs ++ ys.popWhile p := by
rcases xs with xs
rcases ys with ys
simp only [List.append_toArray, List.popWhile_toArray, List.reverse_append, List.dropWhile_append,
List.isEmpty_iff, List.isEmpty_toArray, List.isEmpty_reverse]
-- Why do these not fire with `simp`?
rw [List.popWhile_toArray, List.isEmpty_toArray, List.isEmpty_reverse]
split
· 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 at h
simp only [List.append_toArray, List.popWhile_toArray, List.reverse_append, mk.injEq,
List.reverse_inj]
rw [List.dropWhile_append_of_pos]
simpa
@[simp] theorem takeWhile_mkArray_eq_filter (p : α Bool) :
(mkArray n a).takeWhile p = (mkArray n a).filter p := by
simp [ List.toArray_replicate]
theorem takeWhile_mkArray (p : α Bool) :
(mkArray n a).takeWhile p = if p a then mkArray n a else #[] := by
simp [takeWhile_mkArray_eq_filter, filter_mkArray]
@[simp] theorem popWhile_mkArray_eq_filter_not (p : α Bool) :
(mkArray n a).popWhile p = (mkArray n a).filter (fun a => !p a) := by
simp [ List.toArray_replicate, List.filter_reverse]
theorem popWhile_mkArray (p : α Bool) :
(mkArray n a).popWhile p = if p a then #[] else mkArray n a := by
simp only [popWhile_mkArray_eq_filter_not, size_mkArray, filter_mkArray, Bool.not_eq_eq_eq_not,
Bool.not_true]
split <;> simp_all
theorem extract_takeWhile {as : Array α} {i : Nat} :
(as.takeWhile p).extract 0 i = (as.extract 0 i).takeWhile p := by
rcases as with as
simp [List.take_takeWhile]
@[simp] theorem all_takeWhile {as : Array α} :
(as.takeWhile p).all p = true := by
rcases as with as
rw [List.takeWhile_toArray] -- Not sure why this doesn't fire with `simp`.
simp
@[simp] theorem any_popWhile {as : Array α} :
(as.popWhile p).any (fun a => !p a) = !as.all p := by
rcases as with as
rw [List.popWhile_toArray] -- Not sure why this doesn't fire with `simp`.
simp
theorem takeWhile_eq_extract_findIdx_not {xs : Array α} {p : α Bool} :
takeWhile p xs = xs.extract 0 (xs.findIdx (fun a => !p a)) := by
rcases xs with xs
simp [List.takeWhile_eq_take_findIdx_not]
end Array

View File

@@ -5,46 +5,10 @@ Authors: François G. Dorais
-/
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. -/
protected def finRange (n : Nat) : Array (Fin n) := ofFn fun i => i
@[simp] theorem size_finRange (n) : (Array.finRange n).size = n := by
simp [Array.finRange]
@[simp] theorem getElem_finRange (i : Nat) (h : i < (Array.finRange n).size) :
(Array.finRange n)[i] = Fin.cast (size_finRange n) i, h := by
simp [Array.finRange]
@[simp] theorem finRange_zero : Array.finRange 0 = #[] := by simp [Array.finRange]
theorem finRange_succ (n) : Array.finRange (n+1) = #[0] ++ (Array.finRange n).map Fin.succ := by
ext
· simp [Nat.add_comm]
· simp [getElem_append]
split <;>
· simp; omega
theorem finRange_succ_last (n) :
Array.finRange (n+1) = (Array.finRange n).map Fin.castSucc ++ #[Fin.last n] := by
ext
· simp
· simp [getElem_push]
split
· simp
· simp_all
omega
theorem finRange_reverse (n) : (Array.finRange n).reverse = (Array.finRange n).map Fin.rev := by
ext i h
· simp
· simp
omega
end Array

View File

@@ -13,92 +13,95 @@ 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,
simp only [flatten_toArray_map_toArray, size_toArray, List.length_flatten,
Nat.sum_pos_iff_exists_pos, List.mem_map] at h
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,38 +395,23 @@ 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)) :
p x = false := by
rcases xs with xs
exact List.false_of_mem_take_findIdx (by simpa using h)
@[simp] theorem findIdx_extract {xs : Array α} {i : Nat} {p : α Bool} :
(xs.extract 0 i).findIdx p = min i (xs.findIdx p) := by
cases xs
simp
@[simp] theorem min_findIdx_findIdx {xs : Array α} {p q : α Bool} :
min (xs.findIdx p) (xs.findIdx q) = xs.findIdx (fun a => p a || q a) := by
cases xs
simp
/-! ### findIdx? -/
@[simp] theorem findIdx?_empty : (#[] : Array α).findIdx? p = none := rfl
@@ -462,8 +468,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 +479,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,66 +519,20 @@ 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} :
(xs.take i).findIdx? p = (xs.findIdx? p).bind (Option.guard (fun j => j < i)) := by
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 +540,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 +557,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 _
simp [toArrayLit, toList_toArray]
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
@@ -36,7 +33,7 @@ private theorem cons_lex_cons [BEq α] {lt : αα → Bool} {a b : α} {xs
(#[a] ++ xs).lex (#[b] ++ ys) lt =
(lt a b || a == b && xs.lex ys lt) := by
simp only [lex, Id.run]
simp only [Std.Range.forIn'_eq_forIn'_range', size_append, List.size_toArray, List.length_singleton,
simp only [Std.Range.forIn'_eq_forIn'_range', size_append, size_toArray, List.length_singleton,
Nat.add_comm 1]
simp [Nat.add_min_add_right, List.range'_succ, getElem_append_left, List.range'_succ_left,
getElem_append_right]
@@ -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,84 +358,84 @@ 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
· rintro l₁, l₂, rfl, rfl, rfl
exact l₁.toArray, l₂.toArray, by simp
· rintro l₁, l₂, rfl, h₁, h₂
simp only [List.mapIdx_toArray, mk.injEq, List.size_toArray] at h₁ h₂
simp only [List.mapIdx_toArray, mk.injEq, size_toArray] at h₁ h₂
obtain rfl := h₁
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,16 +8,13 @@ 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
cases as with | _ as =>
exact Nat.lt_trans (List.sizeOf_lt_of_mem h.val) (by simp +arith)
theorem sizeOf_get [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) : sizeOf as[i] < sizeOf as := by
theorem sizeOf_get [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) : sizeOf (as.get i h) < sizeOf as := by
cases as with | _ as =>
simpa using Nat.lt_trans (List.sizeOf_get _ i, h) (by simp +arith)

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
simp only [List.mapM_toArray, bind_pure_comp, List.size_toArray, List.foldlM_toArray']
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, 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
simp only [List.forIn_toArray, List.forIn_eq_foldlM, List.size_toArray, List.foldlM_toArray']
cases l
simp only [List.forIn_toArray, List.forIn_eq_foldlM, 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
@@ -127,7 +124,7 @@ theorem range_succ_eq_map (n : Nat) : range (n + 1) = #[0] ++ map succ (range n)
ext i h₁ h₂
· simp
omega
· simp only [getElem_range, getElem_append, List.size_toArray, List.length_cons, List.length_nil,
· simp only [getElem_range, getElem_append, size_toArray, List.length_cons, List.length_nil,
Nat.zero_add, lt_one_iff, List.getElem_toArray, List.getElem_singleton, getElem_map,
succ_eq_add_one, dite_eq_ite]
split <;> omega
@@ -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,19 +278,19 @@ 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
· rintro l₁', l₂', rfl, rfl, rfl
exact l₁', l₂', by simp
· rintro l₁', l₂', rfl, h
simp only [zipIdx_toArray, mk.injEq, List.size_toArray] at h
simp only [zipIdx_toArray, mk.injEq, size_toArray] at h
obtain rfl, rfl := h
exact l₁', l₂', by simp

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

@@ -7,28 +7,11 @@ prelude
import Init.Data.Array.Lemmas
import Init.Data.List.Nat.TakeDrop
/-!
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) :
l₁ l₂, l = l₁ ++ l[i] :: l₂ l₁.length = i l.set i a' = l₁ ++ a' :: l₂ := by
refine l.take i, l.drop (i + 1), by simp, length_take_of_le (Nat.le_of_lt h), ?_
simp [set_eq_take_append_cons_drop, h]
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,211 +71,211 @@ 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
simp only [List.zip_toArray, List.size_toArray, List.take_toArray, mk.injEq]
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, 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
simp_all only [List.size_toArray, List.zip_toArray, List.unzip_toArray, Prod.map_fst,
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 [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
simp_all only [List.size_toArray, List.zip_toArray, List.unzip_toArray, Prod.map_snd,
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 [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
simp_all only [List.size_toArray, List.zip_toArray, List.unzip_toArray, List.unzip_zip, Prod.map_apply]
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 [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

@@ -395,7 +395,7 @@ and is a computational noop.
def setWidth' {n w : Nat} (le : n w) (x : BitVec n) : BitVec w :=
x.toNat#'(by
apply Nat.lt_of_lt_of_le x.isLt
exact Nat.pow_le_pow_right (by trivial) le)
exact Nat.pow_le_pow_of_le_right (by trivial) le)
@[deprecated setWidth' (since := "2024-09-18"), inherit_doc setWidth'] abbrev zeroExtend' := @setWidth'

View File

@@ -144,7 +144,7 @@ private theorem testBit_limit {x i : Nat} (x_lt_succ : x < 2^(i+1)) :
exfalso
apply Nat.lt_irrefl
calc x < 2^(i+1) := x_lt_succ
_ 2 ^ j := Nat.pow_le_pow_right Nat.zero_lt_two x_lt
_ 2 ^ j := Nat.pow_le_pow_of_le_right Nat.zero_lt_two x_lt
_ x := testBit_implies_ge jp
private theorem mod_two_pow_succ (x i : Nat) :
@@ -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

@@ -29,7 +29,7 @@ namespace BitVec
let x, x_lt := x
simp only [getLsbD_ofFin]
apply Nat.testBit_lt_two_pow
have p : 2^w 2^i := Nat.pow_le_pow_right (by omega) ge
have p : 2^w 2^i := Nat.pow_le_pow_of_le_right (by omega) ge
omega
@[simp] theorem getMsbD_ge (x : BitVec w) (i : Nat) (ge : w i) : getMsbD x i = false := by
@@ -52,16 +52,12 @@ theorem lt_of_getMsbD {x : BitVec w} {i : Nat} : getMsbD x i = true → i < w :=
@[simp] theorem getElem?_eq_getElem {l : BitVec w} {n} (h : n < w) : l[n]? = some l[n] := by
simp only [getElem?_def, h, reduceDIte]
theorem getElem?_eq_some_iff {l : BitVec w} : l[n]? = some a h : n < w, l[n] = a := by
theorem getElem?_eq_some {l : BitVec w} : l[n]? = some a h : n < w, l[n] = a := by
simp only [getElem?_def]
split
· simp_all
· simp; omega
set_option linter.missingDocs false in
@[deprecated getElem?_eq_some_iff (since := "2025-02-17")]
abbrev getElem?_eq_some := @getElem?_eq_some_iff
@[simp] theorem getElem?_eq_none_iff {l : BitVec w} : l[n]? = none w n := by
simp only [getElem?_def]
split
@@ -83,7 +79,7 @@ theorem getElem?_eq (l : BitVec w) (i : Nat) :
simp [h]
theorem getElem_eq_iff {l : BitVec w} {n : Nat} {h : n < w} : l[n] = x l[n]? = some x := by
simp only [getElem?_eq_some_iff]
simp only [getElem?_eq_some]
exact fun w => h, w, fun h => h.2
theorem getElem_eq_getElem? (l : BitVec w) (i : Nat) (h : i < w) :
@@ -378,7 +374,7 @@ theorem getLsbD_ofNat (n : Nat) (x : Nat) (i : Nat) :
Int.sub_eq_add_neg]
private theorem lt_two_pow_of_le {x m n : Nat} (lt : x < 2 ^ m) (le : m n) : x < 2 ^ n :=
Nat.lt_of_lt_of_le lt (Nat.pow_le_pow_right (by trivial : 0 < 2) le)
Nat.lt_of_lt_of_le lt (Nat.pow_le_pow_of_le_right (by trivial : 0 < 2) le)
theorem getElem_zero_ofNat_zero (i : Nat) (h : i < w) : (BitVec.ofNat w 0)[i] = false := by
simp
@@ -876,85 +872,6 @@ protected theorem extractLsb_ofNat (x n : Nat) (hi lo : Nat) :
(extractLsb' start len x).getLsbD i = (i < len && x.getLsbD (start+i)) := by
simp [getLsbD, Nat.lt_succ]
/--
Get the most significant bit after `extractLsb'`. With `extractLsb'`, we extract
a `BitVec len` `x'` with length `len` from `BitVec w` `x`, starting from the
element at position `start`. The function `getMsb` extracts a bit counting from
the most significant bit. Assuming certain conditions,
`(@extractLsbD' w x start len).getMsbD i` is equal to
`@getMsbD w x (w - (start + len - i))`.
Example (w := 10, start := 3, len := 4):
|---| = w - (start + len) = 3
|start + len| = 7
|start| = 3
| len | = 4
let x = 9 8 7 6 5 4 3 2 1 0
let x' = x.extractLsb' 3 4 = 6 5 4 3
| |
| x'.getMsbD 1 =
x.getMsbD (i := w - (start + len - i) = 10 - (3 + 4 - 1) = 4)
|
x'.getMsbD 0 =
x.getMsbD (i := w - (start + len - i) = 10 - (3 + 4 - 0) = 3)
# Condition 1: `i < len`
The index `i` must be within the range of `len`.
# Condition 2: `start + len - i ≤ w`
If `start + len` is larger than `w`, the high bits at `i` with `w ≤ i` are filled with 0,
meaning that `getMsbD[i] = false` for these `i`.
If `i` is large enough, `getMsbD[i]` is again within the bounds `x`.
The precise condition is:
`start + len - i ≤ w`
Example (w := 10, start := 7, len := 5):
|= w - (start + len) = 0
| start + len | = 12
| start | = 7
| len | = 5
let x = 9 8 7 6 5 4 3 2 1 0
let x' = x.extractLsb' 7 5 = _ _ 9 8 7
| |
| x'.getMsbD (i := 2) =
| x.getMsbD (i := w - (start + len - i) = 10 - (7 + 5 - 2)) =
| x.getMsbD 0
| ✅ start + len - i ≤ w
| 7 + 5 - 2 = 10 ≤ 10
|
x'.getMsbD (i := 0) =
x.getMsbD (i := w - (start + len - i) = 10 - (7 + 5 - 0)) =
x.getMsbD (i := w - (start + len - i) = x.getMsbD (i := -2) -- in Nat becomes 0
❌ start + len - i ≤ w
7 + 5 - 0 ≤ w
-/
@[simp] theorem getMsbD_extractLsb' {start len : Nat} {x : BitVec w} {i : Nat} :
(extractLsb' start len x).getMsbD i =
(decide (i < len) &&
(decide (start + len - i w) &&
x.getMsbD (w - (start + len - i)))) := by
rw [getMsbD_eq_getLsbD, getLsbD_extractLsb', getLsbD_eq_getMsbD]
simp only [bool_to_prop]
constructor
· rintro h₁, h₂, h₃, h₄
simp [show w - (start + len - i) = w - 1 - (start + (len - 1 - i)) by omega, h₄]
omega
· rintro h₁, h₂, h₃
simp [show w - 1 - (start + (len - 1 - i)) = w - (start + len - i) by omega, h₃]
omega
@[simp] theorem msb_extractLsb' {start len : Nat} {x : BitVec w} :
(extractLsb' start len x).msb =
(decide (0 < len) &&
(decide (start + len w) &&
x.getMsbD (w - (start + len)))) := by
simp [BitVec.msb, getMsbD_extractLsb']
@[simp] theorem getElem_extract {hi lo : Nat} {x : BitVec n} {i : Nat} (h : i < hi - lo + 1) :
(extractLsb hi lo x)[i] = getLsbD x (lo+i) := by
simp [getElem_eq_testBit_toNat, getLsbD, h]
@@ -963,34 +880,6 @@ let x' = x.extractLsb' 7 5 = _ _ 9 8 7
getLsbD (extractLsb hi lo x) i = (i (hi-lo) && getLsbD x (lo+i)) := by
simp [getLsbD, Nat.lt_succ]
@[simp] theorem getLsbD_extractLsb {hi lo : Nat} {x : BitVec n} {i : Nat} :
(extractLsb hi lo x).getLsbD i = (decide (i < hi - lo + 1) && x.getLsbD (lo + i)) := by
rw [extractLsb, getLsbD_extractLsb']
@[simp] theorem getMsbD_extractLsb {hi lo : Nat} {x : BitVec w} {i : Nat} :
(extractLsb hi lo x).getMsbD i =
(decide (i < hi - lo + 1) &&
(decide (max hi lo - i < w) &&
x.getMsbD (w - 1 - (max hi lo - i)))) := by
rw [getMsbD_eq_getLsbD, getLsbD_extractLsb, getLsbD_eq_getMsbD]
simp only [bool_to_prop]
constructor
· rintro h₁, h₂, h₃, h₄
have p : w - 1 - (lo + (hi - lo + 1 - 1 - i)) = w - 1 - (max hi lo - i) := by omega
rw [p] at h₄
simp [h₄]
omega
· rintro h₁, h₂, h₃
have p : w - 1 - (lo + (hi - lo + 1 - 1 - i)) = w - 1 - (max hi lo - i) := by omega
rw [ p] at h₃
rw [h₃]
simp
omega
@[simp] theorem msb_extractLsb {hi lo : Nat} {x : BitVec w} :
(extractLsb hi lo x).msb = (decide (max hi lo < w) && x.getMsbD (w - 1 - max hi lo)) := by
simp [BitVec.msb]
theorem extractLsb'_eq_extractLsb {w : Nat} (x : BitVec w) (start len : Nat) (h : len > 0) :
x.extractLsb' start len = (x.extractLsb (len - 1 + start) start).cast (by omega) := by
apply eq_of_toNat_eq
@@ -1348,7 +1237,7 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
simp only [Bool.false_bne, Bool.false_and]
rw [Nat.testBit_lt_two_pow]
calc BitVec.toNat x < 2 ^ v := isLt _
_ 2 ^ i := Nat.pow_le_pow_right Nat.zero_lt_two w
_ 2 ^ i := Nat.pow_le_pow_of_le_right Nat.zero_lt_two w
· simp
@[simp] theorem toInt_not {x : BitVec w} :
@@ -1517,8 +1406,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 +1457,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 +1487,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 +1521,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 +1733,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 +1846,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 +1919,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 +1933,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
@@ -2079,9 +1975,9 @@ If the msb is true, then we add a value of `(2^v - 2^w)`, which arises from the
theorem toNat_signExtend (x : BitVec w) {v : Nat} :
(x.signExtend v).toNat = (x.setWidth v).toNat + if x.msb then 2^v - 2^w else 0 := by
by_cases h : v w
· have : 2^v 2^w := Nat.pow_le_pow_right Nat.two_pos h
· have : 2^v 2^w := Nat.pow_le_pow_of_le_right Nat.two_pos h
simp [signExtend_eq_setWidth_of_lt x h, toNat_setWidth, Nat.sub_eq_zero_of_le this]
· have : 2^w 2^v := Nat.pow_le_pow_right Nat.two_pos (by omega)
· have : 2^w 2^v := Nat.pow_le_pow_of_le_right Nat.two_pos (by omega)
rw [toNat_signExtend_of_le x (by omega), toNat_setWidth, Nat.mod_eq_of_lt (by omega)]
/-
@@ -2094,8 +1990,7 @@ 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)
have H : 2^w 2^v := Nat.pow_le_pow_of_le_right (by omega) (by omega)
simp only [this, toNat_setWidth, Int.natCast_add, Int.ofNat_emod, Int.natCast_mul]
by_cases h : x.msb
<;> norm_cast
@@ -2276,11 +2171,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 +2225,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 +2333,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 +2373,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 +4106,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

@@ -581,10 +581,14 @@ protected theorem decide_coe (b : Bool) [Decidable (b = true)] : decide (b = tru
cases dp with | _ p => simp [p]
@[bool_to_prop]
theorem and_eq_decide (p q : Bool) : (p && q) = decide (p q) := by simp
theorem and_eq_decide (p q : Prop) [dpq : Decidable (p q)] [dp : Decidable p] [dq : Decidable q] :
(p && q) = decide (p q) := by
cases dp with | _ p => simp [p]
@[bool_to_prop]
theorem or_eq_decide (p q : Bool) : (p || q) = decide (p q) := by simp
theorem or_eq_decide (p q : Prop) [dpq : Decidable (p q)] [dp : Decidable p] [dq : Decidable q] :
(p || q) = decide (p q) := by
cases dp with | _ p => simp [p]
@[bool_to_prop]
theorem decide_beq_decide (p q : Prop) [dpq : Decidable (p q)] [dp : Decidable p] [dq : Decidable q] :

View File

@@ -134,22 +134,7 @@ Returns an undefined value if `x` is not finite.
instance : ToString Float where
toString := Float.toString
/-- Obtains the `Float` whose value is the same as the given `UInt8`. -/
@[extern "lean_uint8_to_float"] opaque UInt8.toFloat (n : UInt8) : Float
/-- Obtains the `Float` whose value is the same as the given `UInt16`. -/
@[extern "lean_uint16_to_float"] opaque UInt16.toFloat (n : UInt16) : Float
/-- Obtains the `Float` whose value is the same as the given `UInt32`. -/
@[extern "lean_uint32_to_float"] opaque UInt32.toFloat (n : UInt32) : Float
/-- Obtains a `Float` whose value is near the given `UInt64`. It will be exactly the value of the
given `UInt64` if such a `Float` exists. If no such `Float` exists, the returned value will either
be the smallest `Float` this is larger than the given value, or the largest `Float` this is smaller
than the given value. -/
@[extern "lean_uint64_to_float"] opaque UInt64.toFloat (n : UInt64) : Float
/-- Obtains a `Float` whose value is near the given `USize`. It will be exactly the value of the
given `USize` if such a `Float` exists. If no such `Float` exists, the returned value will either
be the smallest `Float` this is larger than the given value, or the largest `Float` this is smaller
than the given value. -/
@[extern "lean_usize_to_float"] opaque USize.toFloat (n : USize) : Float
instance : Inhabited Float where
default := UInt64.toFloat 0

View File

@@ -127,25 +127,7 @@ Returns an undefined value if `x` is not finite.
instance : ToString Float32 where
toString := Float32.toString
/-- Obtains the `Float32` whose value is the same as the given `UInt8`. -/
@[extern "lean_uint8_to_float32"] opaque UInt8.toFloat32 (n : UInt8) : Float32
/-- Obtains the `Float32` whose value is the same as the given `UInt16`. -/
@[extern "lean_uint16_to_float32"] opaque UInt16.toFloat32 (n : UInt16) : Float32
/-- Obtains a `Float32` whose value is near the given `UInt32`. It will be exactly the value of the
given `UInt32` if such a `Float32` exists. If no such `Float32` exists, the returned value will either
be the smallest `Float32` this is larger than the given value, or the largest `Float32` this is smaller
than the given value. -/
@[extern "lean_uint32_to_float32"] opaque UInt32.toFloat32 (n : UInt32) : Float32
/-- Obtains a `Float32` whose value is near the given `UInt64`. It will be exactly the value of the
given `UInt64` if such a `Float32` exists. If no such `Float32` exists, the returned value will either
be the smallest `Float32` this is larger than the given value, or the largest `Float32` this is smaller
than the given value. -/
@[extern "lean_uint64_to_float32"] opaque UInt64.toFloat32 (n : UInt64) : Float32
/-- Obtains a `Float32` whose value is near the given `USize`. It will be exactly the value of the
given `USize` if such a `Float32` exists. If no such `Float32` exists, the returned value will either
be the smallest `Float32` this is larger than the given value, or the largest `Float32` this is smaller
than the given value. -/
@[extern "lean_usize_to_float32"] opaque USize.toFloat32 (n : USize) : Float32
instance : Inhabited Float32 where
default := UInt64.toFloat32 0

View File

@@ -47,7 +47,7 @@ def uget : (a : @& FloatArray) → (i : USize) → i.toNat < a.size → Float
@[extern "lean_float_array_fget"]
def get : (ds : @& FloatArray) (i : @& Nat) (h : i < ds.size := by get_elem_tactic) Float
| ds, i, h => ds[i]
| ds, i, h => ds.get i h
@[extern "lean_float_array_get"]
def get! : (@& FloatArray) (@& Nat) Float

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
@@ -14,3 +15,4 @@ import Init.Data.Int.Order
import Init.Data.Int.Pow
import Init.Data.Int.Cooper
import Init.Data.Int.Linear
import Init.Data.Int.Cutsat

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

@@ -0,0 +1,68 @@
/-
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Init.Data.AC
import Init.Data.Int.Gcd
namespace Int.Linear
/-!
Helper theorems for solving divisibility constraints.
The two theorems are used to justify the `Div-Solve` rule
in the section "Strong Conflict Resolution" in the paper
"Cutting to the Chase: Solving Linear Integer Arithmetic".
-/
theorem dvd_solve_1 {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₂)
: d₁*d₂ d*x + α*d₂*p₁ + β*d₁*p₂ := by
rcases h₁ with k₁, h₁
replace h₁ : α*a₁*d₂*x + α*d₂*p₁ = d₁*d₂*(α*k₁) := by
have ac₁ : d₁*d₂*(α*k₁) = α*d₂*(d₁*k₁) := by ac_rfl
have ac₂ : α * a₁ * d₂ * x = α * d₂ * (a₁ * x) := by ac_rfl
rw [ac₁, h₁, Int.mul_add, ac₂]
rcases h₂ with k₂, h₂
replace h₂ : β*a₂*d₁*x + β*d₁*p₂ = d₁*d₂*(β*k₂) := by
have ac₁ : d₁*d₂*(β*k₂) = β*d₁*(d₂*k₂) := by ac_rfl
have ac₂ : β * a₂ * d₁ * x = β * d₁ * (a₂ * x) := by ac_rfl
rw [ac₁, h₂, Int.mul_add, ac₂]
replace h₁ : d₁*d₂ α*a₁*d₂*x + α*d₂*p₁ := α*k₁, h₁
replace h₂ : d₁*d₂ β*a₂*d₁*x + β*d₁*p₂ := β*k₂, h₂
have h' := Int.dvd_add h₁ h₂; clear h₁ h₂ k₁ k₂
replace h : d*x = α*a₁*d₂*x + β*a₂*d₁*x := by
rw [h, Int.add_mul]
have ac :
α * a₁ * d₂ * x + α * d₂ * p₁ + (β * a₂ * d₁ * x + β * d₁ * p₂)
=
α * a₁ * d₂ * x + β * a₂ * d₁ * x + α * d₂ * p₁ + β * d₁ * p₂ := by ac_rfl
rw [h, ac]
assumption
theorem dvd_solve_2 {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₂)
: d a₂*p₁ - a₁*p₂ := by
rcases h₁ with k₁, h₁
rcases h₂ with k₂, h₂
have h₃ : d a₁*d₂ := by
rw [h]; apply Int.gcd_dvd_left
have h₄ : d a₂*d₁ := by
rw [h]; apply Int.gcd_dvd_right
rcases h₃ with k₃, h₃
rcases h₄ with k₄, h₄
have : a₂*p₁ - a₁*p₂ = a₂*d₁*k₁ - a₁*d₂*k₂ := by
have ac₁ : a₂*d₁*k₁ = a₂*(d₁*k₁) := by ac_rfl
have ac₂ : a₁*d₂*k₂ = a₁*(d₂*k₂) := by ac_rfl
have ac₃ : a₁*(a₂*x) = a₂*(a₁*x) := by ac_rfl
rw [ac₁, ac₂, h₁, h₂, Int.mul_add, Int.mul_add, ac₃, Int.sub_sub, Int.add_comm, Int.add_sub_assoc]
simp
rw [h₃, h₄, Int.mul_assoc, Int.mul_assoc, Int.mul_sub] at this
exact k₄ * k₁ - k₃ * k₂, this
end Int.Linear

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

File diff suppressed because it is too large Load Diff

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

@@ -17,14 +17,24 @@ protected theorem pow_succ (b : Int) (e : Nat) : b ^ (e+1) = (b ^ e) * b := rfl
protected theorem pow_succ' (b : Int) (e : Nat) : b ^ (e+1) = b * (b ^ e) := by
rw [Int.mul_comm, Int.pow_succ]
@[deprecated Nat.pow_le_pow_left (since := "2025-02-17")]
abbrev pow_le_pow_of_le_left := @Nat.pow_le_pow_left
theorem pow_le_pow_of_le_left {n m : Nat} (h : n m) : (i : Nat), n^i m^i
| 0 => Nat.le_refl _
| i + 1 => Nat.mul_le_mul (pow_le_pow_of_le_left h i) h
@[deprecated Nat.pow_le_pow_right (since := "2025-02-17")]
abbrev pow_le_pow_of_le_right := @Nat.pow_le_pow_right
theorem pow_le_pow_of_le_right {n : Nat} (hx : n > 0) {i : Nat} : {j}, i j n^i n^j
| 0, h =>
have : i = 0 := Nat.eq_zero_of_le_zero h
this.symm Nat.le_refl _
| j + 1, h =>
match Nat.le_or_eq_of_le_succ h with
| Or.inl h => show n^i n^j * n from
have : n^i * 1 n^j * n := Nat.mul_le_mul (pow_le_pow_of_le_right hx h) hx
Nat.mul_one (n^i) this
| Or.inr h =>
h.symm Nat.le_refl _
@[deprecated Nat.pow_pos (since := "2025-02-17")]
abbrev pos_pow_of_pos := @Nat.pow_pos
theorem pos_pow_of_pos {n : Nat} (m : Nat) (h : 0 < n) : 0 < n^m :=
pow_le_pow_of_le_right h (Nat.zero_le _)
@[norm_cast]
theorem natCast_pow (b n : Nat) : ((b^n : Nat) : Int) = (b : Int) ^ n := by

View File

@@ -8,9 +8,6 @@ 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.
namespace List
/-- `O(n)`. Partial map. If `f : Π a, P a → β` is a partial function defined on
@@ -43,12 +40,12 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
List β := (l.attachWith _ H).map fun x, h' => f x h'
@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by
funext α β p f l h'
let rec go : l' (hL' : x, x l' p x),
pmap f l' hL' = map (fun x, hx => f x hx) (pmap Subtype.mk l' hL')
funext α β p f L h'
let rec go : L' (hL' : x, x L' p x),
pmap f L' hL' = map (fun x, hx => f x hx) (pmap Subtype.mk L' hL')
| nil, hL' => rfl
| cons _ l', hL' => congrArg _ <| go l' fun _ hx => hL' (.tail _ hx)
exact go l h'
| cons _ L', hL' => congrArg _ <| go L' fun _ hx => hL' (.tail _ hx)
exact go L h'
@[simp] theorem pmap_nil {P : α Prop} (f : a, P a β) : pmap f [] (by simp) = [] := rfl
@@ -123,26 +120,27 @@ theorem pmap_eq_attachWith {p q : α → Prop} (f : ∀ a, p a → q a) (l H) :
| cons a l ih =>
simp [pmap, attachWith, ih]
theorem attach_map_val (l : List α) (f : α β) :
theorem attach_map_coe (l : List α) (f : α β) :
(l.attach.map fun (i : {i // i l}) => f i) = l.map f := by
rw [attach, attachWith, map_pmap]; exact pmap_eq_map _ _ _ _
@[deprecated attach_map_val (since := "2025-02-17")]
abbrev attach_map_coe := @attach_map_val
theorem attach_map_val (l : List α) (f : α β) : (l.attach.map fun i => f i.val) = l.map f :=
attach_map_coe _ _
theorem attach_map_subtype_val (l : List α) : l.attach.map Subtype.val = l :=
(attach_map_val _ _).trans (List.map_id _)
(attach_map_coe _ _).trans (List.map_id _)
theorem attachWith_map_val {p : α Prop} (f : α β) (l : List α) (H : a l, p a) :
theorem attachWith_map_coe {p : α Prop} (f : α β) (l : List α) (H : a l, p a) :
((l.attachWith p H).map fun (i : { i // p i}) => f i) = l.map f := by
rw [attachWith, map_pmap]; exact pmap_eq_map _ _ _ _
@[deprecated attachWith_map_val (since := "2025-02-17")]
abbrev attachWith_map_coe := @attachWith_map_val
theorem attachWith_map_val {p : α Prop} (f : α β) (l : List α) (H : a l, p a) :
((l.attachWith p H).map fun i => f i.val) = l.map f :=
attachWith_map_coe _ _ _
theorem attachWith_map_subtype_val {p : α Prop} (l : List α) (H : a l, p a) :
(l.attachWith p H).map Subtype.val = l :=
(attachWith_map_val _ _ _).trans (List.map_id _)
(attachWith_map_coe _ _ _).trans (List.map_id _)
@[simp]
theorem mem_attach (l : List α) : x, x l.attach
@@ -181,7 +179,7 @@ theorem length_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H} : (pmap f l
· simp only [*, pmap, length]
@[simp]
theorem length_attach {l : List α} : l.attach.length = l.length :=
theorem length_attach {L : List α} : L.attach.length = L.length :=
length_pmap
@[simp]
@@ -190,7 +188,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
@@ -225,15 +223,21 @@ theorem attachWith_ne_nil_iff {l : List α} {P : α → Prop} {H : ∀ a ∈ l,
@[deprecated attach_ne_nil_iff (since := "2024-09-06")] abbrev attach_ne_nil := @attach_ne_nil_iff
@[simp]
theorem getElem?_pmap {p : α Prop} (f : a, p a β) {l : List α} (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
induction l generalizing i with
theorem getElem?_pmap {p : α Prop} (f : a, p a β) {l : List α} (h : a l, p a) (n : Nat) :
(pmap f l h)[n]? = Option.pmap f l[n]? fun x H => h x (mem_of_getElem? H) := by
induction l generalizing n with
| nil => simp
| cons hd tl hl =>
rcases i with i
rcases n with n
· simp only [Option.pmap]
split <;> simp_all
· simp only [pmap, getElem?_cons_succ, hl, Option.pmap]
· simp only [hl, pmap, Option.pmap, getElem?_cons_succ]
split <;> rename_i h₁ _ <;> split <;> rename_i h₂ _
· simp_all
· simp at h₂
simp_all
· simp_all
· simp_all
set_option linter.deprecated false in
@[deprecated List.getElem?_pmap (since := "2025-02-12")]
@@ -243,17 +247,17 @@ theorem get?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h :
simp [getElem?_pmap, h]
@[simp]
theorem getElem_pmap {p : α Prop} (f : a, p a β) {l : List α} (h : a l, p a) {i : Nat}
(hn : i < (pmap f l h).length) :
(pmap f l h)[i] =
f (l[i]'(@length_pmap _ _ p f l h hn))
theorem getElem_pmap {p : α Prop} (f : a, p a β) {l : List α} (h : a l, p a) {n : Nat}
(hn : n < (pmap f l h).length) :
(pmap f l h)[n] =
f (l[n]'(@length_pmap _ _ p f l h hn))
(h _ (getElem_mem (@length_pmap _ _ p f l h hn))) := by
induction l generalizing i with
induction l generalizing n with
| nil =>
simp only [length, pmap] at hn
exact absurd hn (Nat.not_lt_of_le i.zero_le)
exact absurd hn (Nat.not_lt_of_le n.zero_le)
| cons hd tl hl =>
cases i
cases n
· simp
· simp [hl]

View File

@@ -58,8 +58,6 @@ 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.
open Decidable List
@@ -206,7 +204,7 @@ instance decidableLT [DecidableEq α] [LT α] [DecidableLT α] (l₁ l₂ : List
abbrev hasDecidableLt := @decidableLT
/-- The lexicographic order on lists. -/
@[reducible] protected def le [LT α] (as bs : List α) : Prop := ¬ bs < as
@[reducible] protected def le [LT α] (a b : List α) : Prop := ¬ b < a
instance instLE [LT α] : LE (List α) := List.le
@@ -357,15 +355,14 @@ def tail? : List α → Option (List α)
/-! ### tailD -/
set_option linter.listVariables false in
/--
Drops the first element of the list.
If the list is empty, this function returns `fallback`.
Also see `head?` and `head!`.
-/
def tailD (l fallback : List α) : List α :=
match l with
def tailD (list fallback : List α) : List α :=
match list with
| [] => fallback
| _ :: tl => tl
@@ -557,10 +554,10 @@ theorem reverseAux_eq_append (as bs : List α) : reverseAux as bs = reverseAux a
-/
def flatten : List (List α) List α
| [] => []
| l :: L => l ++ flatten L
| a :: as => a ++ flatten as
@[simp] theorem flatten_nil : List.flatten ([] : List (List α)) = [] := rfl
@[simp] theorem flatten_cons : (l :: L).flatten = l ++ L.flatten := rfl
@[simp] theorem flatten_cons : (l :: ls).flatten = l ++ ls.flatten := rfl
@[deprecated flatten (since := "2024-10-14"), inherit_doc flatten] abbrev join := @flatten
@@ -579,7 +576,7 @@ set_option linter.missingDocs false in
to get a list of lists, and then concatenates them all together.
* `[2, 3, 2].bind range = [0, 1, 0, 1, 2, 0, 1]`
-/
@[inline] def flatMap {α : Type u} {β : Type v} (b : α List β) (as : List α) : List β := flatten (map b as)
@[inline] def flatMap {α : Type u} {β : Type v} (b : α List β) (a : List α) : List β := flatten (map b a)
@[simp] theorem flatMap_nil (f : α List β) : List.flatMap f [] = [] := by simp [flatten, List.flatMap]
@[simp] theorem flatMap_cons x xs (f : α List β) :
@@ -784,14 +781,14 @@ def take : Nat → List α → List α
* `drop 6 [a, b, c, d, e] = []`
-/
def drop : Nat List α List α
| 0, as => as
| 0, a => a
| _+1, [] => []
| n+1, _::as => drop n as
@[simp] theorem drop_nil : ([] : List α).drop i = [] := by
cases i <;> rfl
@[simp] theorem drop_zero (l : List α) : l.drop 0 = l := rfl
@[simp] theorem drop_succ_cons : (a :: l).drop (i + 1) = l.drop i := rfl
@[simp] theorem drop_succ_cons : (a :: l).drop (n + 1) = l.drop n := rfl
theorem drop_eq_nil_of_le {as : List α} {i : Nat} (h : as.length i) : as.drop i = [] := by
match as, i with
@@ -1025,15 +1022,15 @@ def splitAt (n : Nat) (l : List α) : List α × List α := go l n [] where
* `rotateLeft [1, 2, 3, 4, 5] 5 = [1, 2, 3, 4, 5]`
* `rotateLeft [1, 2, 3, 4, 5] = [2, 3, 4, 5, 1]`
-/
def rotateLeft (xs : List α) (i : Nat := 1) : List α :=
def rotateLeft (xs : List α) (n : Nat := 1) : List α :=
let len := xs.length
if len 1 then
xs
else
let i := i % len
let ys := xs.take i
let zs := xs.drop i
zs ++ ys
let n := n % len
let b := xs.take n
let e := xs.drop n
e ++ b
@[simp] theorem rotateLeft_nil : ([] : List α).rotateLeft n = [] := rfl
@@ -1046,15 +1043,15 @@ def rotateLeft (xs : List α) (i : Nat := 1) : List α :=
* `rotateRight [1, 2, 3, 4, 5] 5 = [1, 2, 3, 4, 5]`
* `rotateRight [1, 2, 3, 4, 5] = [5, 1, 2, 3, 4]`
-/
def rotateRight (xs : List α) (i : Nat := 1) : List α :=
def rotateRight (xs : List α) (n : Nat := 1) : List α :=
let len := xs.length
if len 1 then
xs
else
let i := len - i % len
let ys := xs.take i
let zs := xs.drop i
zs ++ ys
let n := len - n % len
let b := xs.take n
let e := xs.drop n
e ++ b
@[simp] theorem rotateRight_nil : ([] : List α).rotateRight n = [] := rfl
@@ -1169,8 +1166,8 @@ def modify (f : αα) : Nat → List α → List α :=
insertIdx 2 1 [1, 2, 3, 4] = [1, 2, 1, 3, 4]
```
-/
def insertIdx (i : Nat) (a : α) : List α List α :=
modifyTailIdx (cons a) i
def insertIdx (n : Nat) (a : α) : List α List α :=
modifyTailIdx (cons a) n
/-! ### erase -/
@@ -1343,13 +1340,13 @@ and returns the first `β` value corresponding to an `α` value in the list equa
-/
def lookup [BEq α] : α List (α × β) Option β
| _, [] => none
| a, (k,b)::as => match a == k with
| a, (k,b)::es => match a == k with
| true => some b
| false => lookup a as
| false => lookup a es
@[simp] theorem lookup_nil [BEq α] : ([] : List (α × β)).lookup a = none := rfl
theorem lookup_cons [BEq α] {k : α} :
((k,b)::as).lookup a = match a == k with | true => some b | false => as.lookup a :=
((k,b)::es).lookup a = match a == k with | true => some b | false => es.lookup a :=
rfl
/-! ## Permutations -/
@@ -1495,11 +1492,11 @@ def zipWithAll (f : Option α → Option β → γ) : List α → List β → Li
-/
def unzip : List (α × β) List α × List β
| [] => ([], [])
| (a, b) :: t => match unzip t with | (as, bs) => (a::as, b::bs)
| (a, b) :: t => match unzip t with | (al, bl) => (a::al, b::bl)
@[simp] theorem unzip_nil : ([] : List (α × β)).unzip = ([], []) := rfl
@[simp] theorem unzip_cons {h : α × β} :
(h :: t).unzip = match unzip t with | (as, bs) => (h.1::as, h.2::bs) := rfl
(h :: t).unzip = match unzip t with | (al, bl) => (h.1::al, h.2::bl) := rfl
/-! ## Ranges and enumeration -/
@@ -1534,8 +1531,8 @@ def range (n : Nat) : List Nat :=
loop n []
where
loop : Nat List Nat List Nat
| 0, acc => acc
| n+1, acc => loop n (n::acc)
| 0, ns => ns
| n+1, ns => loop n (n::ns)
@[simp] theorem range_zero : range 0 = [] := rfl
@@ -1666,7 +1663,6 @@ def intersperse (sep : α) : List α → List α
/-! ### intercalate -/
set_option linter.listVariables false in
/--
`O(|xs|)`. `intercalate sep xs` alternates `sep` and the elements of `xs`:
* `intercalate sep [] = []`
@@ -1703,10 +1699,10 @@ def eraseReps {α} [BEq α] : List α → List α
| a::as => loop a as []
where
loop {α} [BEq α] : α List α List α List α
| a, [], acc => (a::acc).reverse
| a, a'::as, acc => match a == a' with
| true => loop a as acc
| false => loop a' as (a::acc)
| a, [], rs => (a::rs).reverse
| a, a'::as, rs => match a == a' with
| true => loop a as rs
| false => loop a' as (a::rs)
/-! ### span -/
@@ -1722,10 +1718,10 @@ and the second part is everything else.
loop as []
where
@[specialize] loop : List α List α List α × List α
| [], acc => (acc.reverse, [])
| a::as, acc => match p a with
| true => loop as (a::acc)
| false => (acc.reverse, a::as)
| [], rs => (rs.reverse, [])
| a::as, rs => match p a with
| true => loop as (a::rs)
| false => (rs.reverse, a::as)
/-! ### splitBy -/
@@ -1741,18 +1737,18 @@ such that adjacent elements are related by `R`.
| a::as => loop as a [] []
where
/--
The arguments of `splitBy.loop l b g gs` represent the following:
The arguments of `splitBy.loop l ag g gs` represent the following:
- `l : List α` are the elements which we still need to split.
- `b : α` is the previous element for which a comparison was performed.
- `r : List α` is the group currently being assembled, in **reverse order**.
- `acc : List (List α)` is all of the groups that have been completed, in **reverse order**.
- `ag : α` is the previous element for which a comparison was performed.
- `g : List α` is the group currently being assembled, in **reverse order**.
- `gs : List (List α)` is all of the groups that have been completed, in **reverse order**.
-/
@[specialize] loop : List α α List α List (List α) List (List α)
| a::as, b, r, acc => match R b a with
| true => loop as a (b::r) acc
| false => loop as a [] ((b::r).reverse::acc)
| [], ag, r, acc => ((ag::r).reverse::acc).reverse
| a::as, ag, g, gs => match R ag a with
| true => loop as a (ag::g) gs
| false => loop as a [] ((ag::g).reverse::gs)
| [], ag, g, gs => ((ag::g).reverse::gs).reverse
@[deprecated splitBy (since := "2024-10-30"), inherit_doc splitBy] abbrev groupBy := @splitBy
@@ -1818,10 +1814,10 @@ theorem mapTR_loop_eq (f : α → β) (as : List α) (bs : List β) :
loop as []
where
@[specialize] loop : List α List α List α
| [], acc => acc.reverse
| a::as, acc => match p a with
| true => loop as (a::acc)
| false => loop as acc
| [], rs => rs.reverse
| a::as, rs => match p a with
| true => loop as (a::rs)
| false => loop as rs
theorem filterTR_loop_eq (p : α Bool) (as bs : List α) :
filterTR.loop p as bs = bs.reverse ++ filter p as := by
@@ -1877,7 +1873,7 @@ theorem replicateTR_loop_eq : ∀ n, replicateTR.loop a n acc = replicate n a ++
/-- Tail recursive version of `List.unzip`. -/
def unzipTR (l : List (α × β)) : List α × List β :=
l.foldr (fun (a, b) (as, bs) => (a::as, b::bs)) ([], [])
l.foldr (fun (a, b) (al, bl) => (a::al, b::bl)) ([], [])
@[csimp] theorem unzip_eq_unzipTR : @unzip = @unzipTR := by
apply funext; intro α; apply funext; intro β; apply funext; intro l

View File

@@ -6,9 +6,6 @@ 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.
universe u
namespace List
@@ -51,6 +48,19 @@ theorem ext_get? : ∀ {l₁ l₂ : List α}, (∀ n, l₁.get? n = l₂.get? n)
have h0 : some a = some a' := h 0
injection h0 with aa; simp only [aa, ext_get? fun n => h (n+1)]
/-! ### getD -/
/--
Returns the `i`-th element in the list (zero-based).
If the index is out of bounds (`i ≥ as.length`), this function returns `fallback`.
See also `get?` and `get!`.
-/
def getD (as : List α) (i : Nat) (fallback : α) : α :=
as[i]?.getD fallback
@[simp] theorem getD_nil : getD [] n d = d := rfl
/-! ### get! -/
/--
@@ -76,19 +86,6 @@ set_option linter.deprecated false in
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12")]
theorem get!_cons_zero [Inhabited α] (l : List α) (a : α) : (a::l).get! 0 = a := rfl
/-! ### getD -/
/--
Returns the `i`-th element in the list (zero-based).
If the index is out of bounds (`i ≥ as.length`), this function returns `fallback`.
See also `get?` and `get!`.
-/
def getD (as : List α) (i : Nat) (fallback : α) : α :=
as[i]?.getD fallback
@[simp] theorem getD_nil : getD [] n d = d := rfl
/-! ### getLast! -/
/--

View File

@@ -9,9 +9,6 @@ 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.
namespace List
universe u v w u₁ u₂

View File

@@ -10,9 +10,6 @@ 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.
namespace List
open Nat
@@ -27,10 +24,10 @@ variable (p q : α → Bool)
protected theorem countP_go_eq_add (l) : countP.go p l n = n + countP.go p l 0 := by
induction l generalizing n with
| nil => rfl
| cons hd _ ih =>
| cons head tail ih =>
unfold countP.go
rw [ih (n := n + 1), ih (n := n), ih (n := 1)]
if h : p hd then simp [h, Nat.add_assoc] else simp [h]
if h : p head then simp [h, Nat.add_assoc] else simp [h]
@[simp] theorem countP_cons_of_pos (l) (pa : p a) : countP p (a :: l) = countP p l + 1 := by
have : countP.go p (a :: l) 0 = countP.go p l 1 := show cond .. = _ by rw [pa]; rfl
@@ -49,8 +46,8 @@ theorem countP_cons (a : α) (l) : countP p (a :: l) = countP p l + if p a then
theorem length_eq_countP_add_countP (l) : length l = countP p l + countP (fun a => ¬p a) l := by
induction l with
| nil => rfl
| cons hd _ ih =>
if h : p hd then
| cons x h ih =>
if h : p x then
rw [countP_cons_of_pos _ _ h, countP_cons_of_neg _ _ _, length, ih]
· rw [Nat.add_assoc, Nat.add_comm _ 1, Nat.add_assoc]
· simp [h]
@@ -87,7 +84,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]
@@ -213,7 +210,7 @@ theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
theorem count_tail : (l : List α) (a : α) (h : l []),
l.tail.count a = l.count a - if l.head h == a then 1 else 0
| _ :: _, a, _ => by simp [count_cons]
| head :: tail, a, _ => by simp [count_cons]
theorem count_le_length (a : α) (l : List α) : count a l l.length := countP_le_length _

View File

@@ -12,9 +12,6 @@ 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.
namespace List
open Nat
@@ -137,7 +134,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
@@ -440,10 +437,10 @@ theorem erase_eq_iff [LawfulBEq α] {a : α} {l : List α} :
rw [erase_eq_eraseP', eraseP_eq_iff]
simp only [beq_iff_eq, forall_mem_ne', exists_and_left]
constructor
· rintro (h, rfl | a', l', h, rfl, xs, rfl, rfl)
· rintro (h, rfl | a', l', h, rfl, x, rfl, rfl)
· left; simp_all
· right; refine l', h, xs, by simp
· rintro (h, rfl | l₁, h, xs, rfl, rfl)
· right; refine l', h, x, by simp
· rintro (h, rfl | l₁, h, x, rfl, rfl)
· left; simp_all
· right; refine a, l₁, h, by simp

View File

@@ -6,9 +6,6 @@ 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.
namespace List
/-- `finRange n` lists all elements of `Fin n` in order -/

View File

@@ -15,10 +15,6 @@ 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.
namespace List
open Nat
@@ -121,7 +117,7 @@ theorem find?_eq_findSome?_guard (l : List α) : find? p l = findSome? (Option.g
@[simp] theorem getLast_filterMap (f : α Option β) (l : List α) (h) :
(l.filterMap f).getLast h = (l.reverse.findSome? f).get (by simp_all [Option.isSome_iff_ne_none]) := by
simp [getLast_eq_iff_getLast?_eq_some]
simp [getLast_eq_iff_getLast_eq_some]
@[simp] theorem map_findSome? (f : α Option β) (g : β γ) (l : List α) :
(l.findSome? f).map g = l.findSome? (Option.map g f) := by
@@ -148,7 +144,7 @@ theorem head_flatten {L : List (List α)} (h : ∃ l, l ∈ L ∧ l ≠ []) :
theorem getLast_flatten {L : List (List α)} (h : l, l L l []) :
(flatten L).getLast (by simpa using h) =
(L.reverse.findSome? fun l => l.getLast?).get (by simpa using h) := by
simp [getLast_eq_iff_getLast?_eq_some, getLast?_flatten]
simp [getLast_eq_iff_getLast_eq_some, getLast?_flatten]
theorem findSome?_replicate : findSome? f (replicate n a) = if n = 0 then none else f a := by
cases n with
@@ -313,7 +309,7 @@ theorem get_find?_mem (xs : List α) (p : α → Bool) (h) : (xs.find? p).get h
@[simp] theorem getLast_filter (p : α Bool) (l : List α) (h) :
(l.filter p).getLast h = (l.reverse.find? p).get (by simp_all [Option.isSome_iff_ne_none]) := by
simp [getLast_eq_iff_getLast?_eq_some]
simp [getLast_eq_iff_getLast_eq_some]
@[simp] theorem find?_filterMap (xs : List α) (f : α Option β) (p : β Bool) :
(xs.filterMap f).find? p = (xs.find? (fun a => (f a).any p)).bind f := by
@@ -339,11 +335,11 @@ theorem get_find?_mem (xs : List α) (p : α → Bool) (h) : (xs.find? p).get h
simp only [cons_append, find?]
by_cases h : p x <;> simp [h, ih]
@[simp] theorem find?_flatten (xss : List (List α)) (p : α Bool) :
xss.flatten.find? p = xss.findSome? (·.find? p) := by
induction xss with
@[simp] theorem find?_flatten (xs : List (List α)) (p : α Bool) :
xs.flatten.find? p = xs.findSome? (·.find? p) := by
induction xs with
| nil => simp
| cons _ _ ih =>
| cons x xs ih =>
simp only [flatten_cons, find?_append, findSome?_cons, ih]
split <;> simp [*]
@@ -362,7 +358,7 @@ Moreover, no earlier list in `xs` has an element satisfying `p`.
theorem find?_flatten_eq_some_iff {xs : List (List α)} {p : α Bool} {a : α} :
xs.flatten.find? p = some a
p a as ys zs bs, xs = as ++ (ys ++ a :: zs) :: bs
( l as, x l, !p x) ( x ys, !p x) := by
( a as, x a, !p x) ( x ys, !p x) := by
rw [find?_eq_some_iff_append]
constructor
· rintro h, ys, zs, h₁, h₂
@@ -374,8 +370,8 @@ theorem find?_flatten_eq_some_iff {xs : List (List α)} {p : α → Bool} {a :
obtain bs, cs, ds, rfl, h₁, rfl := h₁
refine as ++ bs, [], cs, ds, by simp, ?_
simp
rintro l (ma | mb) x m
· simpa using h₂ x (by simpa using l, ma, m)
rintro a (ma | mb) x m
· simpa using h₂ x (by simpa using a, ma, m)
· specialize h₁ _ mb
simp_all
· simp [h₁]
@@ -514,6 +510,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 <;> rename_i a xs
· 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 α) :
@@ -526,10 +563,10 @@ where
List.findIdx.go p l (n + 1) = (findIdx.go p l n) + 1 := by
cases l with
| nil => unfold findIdx.go; exact Nat.succ_eq_add_one n
| cons hd tl =>
| cons head tail =>
unfold findIdx.go
cases p hd <;> simp only [cond_false, cond_true]
exact findIdx_go_succ p tl (n + 1)
cases p head <;> simp only [cond_false, cond_true]
exact findIdx_go_succ p tail (n + 1)
theorem findIdx_of_getElem?_eq_some {xs : List α} (w : xs[xs.findIdx p]? = some y) : p y := by
induction xs with
@@ -935,71 +972,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 +1031,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 +1056,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,9 +16,6 @@ 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.
namespace List
/-! ## Basic `List` operations.
@@ -60,8 +57,8 @@ The following operations are given `@[csimp]` replacements below:
@[csimp] theorem set_eq_setTR : @set = @setTR := by
funext α l n a; simp [setTR]
let rec go (acc) : xs i, l = acc.toList ++ xs
setTR.go l a xs i acc = acc.toList ++ xs.set i a
let rec go (acc) : xs n, l = acc.toList ++ xs
setTR.go l a xs n acc = acc.toList ++ xs.set n a
| [], _ => fun h => by simp [setTR.go, set, h]
| x::xs, 0 => by simp [setTR.go, set]
| x::xs, n+1 => fun h => by simp only [setTR.go, set]; rw [go _ xs] <;> simp [h]
@@ -94,7 +91,7 @@ The following operations are given `@[csimp]` replacements below:
@[specialize] def foldrTR (f : α β β) (init : β) (l : List α) : β := l.toArray.foldr f init
@[csimp] theorem foldr_eq_foldrTR : @foldr = @foldrTR := by
funext α β f init l; simp only [foldrTR, Array.foldr_toList]
funext α β f init l; simp [foldrTR, Array.foldr_toList, -Array.size_toArray]
/-! ### flatMap -/
@@ -134,13 +131,13 @@ The following operations are given `@[csimp]` replacements below:
| a::as, n+1, acc => go as n (acc.push a)
@[csimp] theorem take_eq_takeTR : @take = @takeTR := by
funext α i l; simp [takeTR]
suffices xs acc, l = acc.toList ++ xs takeTR.go l xs i acc = acc.toList ++ xs.take i from
funext α n l; simp [takeTR]
suffices xs acc, l = acc.toList ++ xs takeTR.go l xs n acc = acc.toList ++ xs.take n from
(this l #[] (by simp)).symm
intro xs; induction xs generalizing i with intro acc
| nil => cases i <;> simp [take, takeTR.go]
intro xs; induction xs generalizing n with intro acc
| nil => cases n <;> simp [take, takeTR.go]
| cons x xs IH =>
cases i with simp only [take, takeTR.go]
cases n with simp only [take, takeTR.go]
| zero => simp
| succ n => intro h; rw [IH] <;> simp_all
@@ -210,7 +207,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]
@@ -228,7 +225,7 @@ theorem modifyTR_go_eq : ∀ l i, modifyTR.go f l i acc = acc.toList ++ modify f
| _, [], acc => acc.toList
| n+1, a :: l, acc => go n l (acc.push a)
theorem insertIdxTR_go_eq : i l, insertIdxTR.go a i l acc = acc.toList ++ insertIdx i a l
theorem insertIdxTR_go_eq : n l, insertIdxTR.go a n l acc = acc.toList ++ insertIdx n a l
| 0, l | _+1, [] => by simp [insertIdxTR.go, insertIdx]
| n+1, a :: l => by simp [insertIdxTR.go, insertIdx, insertIdxTR_go_eq n l]
@@ -287,15 +284,15 @@ theorem insertIdxTR_go_eq : ∀ i l, insertIdxTR.go a i l acc = acc.toList ++ in
| a::as, n+1, acc => go as n (acc.push a)
@[csimp] theorem eraseIdx_eq_eraseIdxTR : @eraseIdx = @eraseIdxTR := by
funext α l i; simp [eraseIdxTR]
suffices xs acc, l = acc.toList ++ xs eraseIdxTR.go l xs i acc = acc.toList ++ xs.eraseIdx i from
funext α l n; simp [eraseIdxTR]
suffices xs acc, l = acc.toList ++ xs eraseIdxTR.go l xs n acc = acc.toList ++ xs.eraseIdx n from
(this l #[] (by simp)).symm
intro xs; induction xs generalizing i with intro acc h
intro xs; induction xs generalizing n with intro acc h
| nil => simp [eraseIdx, eraseIdxTR.go, h]
| cons x xs IH =>
match i with
match n with
| 0 => simp [eraseIdx, eraseIdxTR.go]
| i+1 =>
| n+1 =>
simp only [eraseIdxTR.go, eraseIdx]
rw [IH]; simp; simp; exact h
@@ -323,13 +320,13 @@ theorem insertIdxTR_go_eq : ∀ i l, insertIdxTR.go a i l acc = acc.toList ++ in
/-- Tail recursive version of `List.zipIdx`. -/
def zipIdxTR (l : List α) (n : Nat := 0) : List (α × Nat) :=
let as := l.toArray
(as.foldr (fun a (n, acc) => (n-1, (a, n-1) :: acc)) (n + as.size, [])).2
let arr := l.toArray
(arr.foldr (fun a (n, acc) => (n-1, (a, n-1) :: acc)) (n + arr.size, [])).2
@[csimp] theorem zipIdx_eq_zipIdxTR : @zipIdx = @zipIdxTR := by
funext α l n; simp only [zipIdxTR, size_toArray]
funext α l n; simp [zipIdxTR, -Array.size_toArray]
let f := fun (a : α) (n, acc) => (n-1, (a, n-1) :: acc)
let rec go : l i, l.foldr f (i + l.length, []) = (i, zipIdx l i)
let rec go : l n, l.foldr f (n + l.length, []) = (n, zipIdx l n)
| [], n => rfl
| a::as, n => by
rw [ show _ + as.length = n + (a::as).length from Nat.succ_add .., foldr, go as]
@@ -342,13 +339,13 @@ def zipIdxTR (l : List α) (n : Nat := 0) : List (α × Nat) :=
/-- Tail recursive version of `List.enumFrom`. -/
@[deprecated zipIdxTR (since := "2025-01-21")]
def enumFromTR (n : Nat) (l : List α) : List (Nat × α) :=
let as := l.toArray
(as.foldr (fun a (n, acc) => (n-1, (n-1, a) :: acc)) (n + as.size, [])).2
let arr := l.toArray
(arr.foldr (fun a (n, acc) => (n-1, (n-1, a) :: acc)) (n + arr.size, [])).2
set_option linter.deprecated false in
@[deprecated zipIdx_eq_zipIdxTR (since := "2025-01-21"), csimp]
theorem enumFrom_eq_enumFromTR : @enumFrom = @enumFromTR := by
funext α n l; simp only [enumFromTR, size_toArray]
funext α n l; simp [enumFromTR, -Array.size_toArray]
let f := fun (a : α) (n, acc) => (n-1, (n-1, a) :: acc)
let rec go : l n, l.foldr f (n + l.length, []) = (n, enumFrom n l)
| [], n => rfl
@@ -362,7 +359,6 @@ theorem enumFrom_eq_enumFromTR : @enumFrom = @enumFromTR := by
/-! ### intercalate -/
set_option linter.listVariables false in
/-- Tail recursive version of `List.intercalate`. -/
def intercalateTR (sep : List α) : List (List α) List α
| [] => []
@@ -375,7 +371,6 @@ where
| x, [], acc => acc.toListAppend x
| x, y::xs, acc => go sep y xs (acc ++ x ++ sep)
set_option linter.listVariables false in
@[csimp] theorem intercalate_eq_intercalateTR : @intercalate = @intercalateTR := by
funext α sep l; simp [intercalate, intercalateTR]
match l with

View File

@@ -73,10 +73,6 @@ Also
* `Init.Data.List.Monadic` for addiation 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.
namespace List
open Nat
@@ -96,15 +92,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 +119,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
@@ -165,10 +146,10 @@ theorem cons_inj_right (a : α) {l l' : List α} : a :: l = a :: l' ↔ l = l' :
theorem cons_eq_cons {a b : α} {l l' : List α} : a :: l = b :: l' a = b l = l' :=
List.cons.injEq .. .rfl
theorem exists_cons_of_ne_nil : {l : List α}, l [] b l', l = b :: l'
theorem exists_cons_of_ne_nil : {l : List α}, l [] b L, l = b :: L
| c :: l', _ => c, l', rfl
theorem ne_nil_iff_exists_cons {l : List α} : l [] b l', l = b :: l' :=
theorem ne_nil_iff_exists_cons {l : List α} : l [] b L, l = b :: L :=
exists_cons_of_ne_nil, fun _, _, eq => eq.symm cons_ne_nil _ _
theorem singleton_inj {α : Type _} {a b : α} : [a] = [b] a = b := by
@@ -239,13 +220,28 @@ theorem getElem_cons {l : List α} (w : i < (a :: l).length) :
if h : i = 0 then a else l[i-1]'(match i, h with | i+1, _ => succ_lt_succ_iff.mp w) := by
cases i <;> simp
theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := rfl
theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := by
simp [getElem?]
@[simp] theorem getElem?_cons_succ {l : List α} : (a::l)[i+1]? = l[i]? := rfl
@[simp] theorem getElem?_cons_succ {l : List α} : (a::l)[i+1]? = l[i]? := by
simp [getElem?, decidableGetElem?, Nat.succ_lt_succ_iff]
theorem getElem?_cons : (a :: l)[i]? = if i = 0 then some a else l[i-1]? := by
cases i <;> simp [getElem?_cons_zero]
@[simp] theorem getElem?_eq_none_iff : l[i]? = none length l i :=
match l with
| [] => by simp
| _ :: l => by simp
@[simp] theorem none_eq_getElem?_iff {l : List α} {i : Nat} : none = l[i]? length l i := by
simp [eq_comm (a := none)]
theorem getElem?_eq_none (h : length l i) : l[i]? = none := getElem?_eq_none_iff.mpr h
@[simp] theorem getElem?_eq_getElem {l : List α} {i} (h : i < l.length) : l[i]? = some l[i] :=
getElem?_pos ..
theorem getElem?_eq_some_iff {l : List α} : l[i]? = some a h : i < l.length, l[i] = a :=
match l with
| [] => by simp
@@ -299,7 +295,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 +386,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]
@@ -531,24 +527,21 @@ theorem elem_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
/-! ### `isEmpty` -/
@[simp] theorem isEmpty_iff {l : List α} : l.isEmpty l = [] := by
theorem isEmpty_iff {l : List α} : l.isEmpty l = [] := by
cases l <;> simp
@[deprecated isEmpty_iff (since := "2025-02-17")]
abbrev isEmpty_eq_true := @isEmpty_iff
@[simp] theorem isEmpty_eq_false_iff {l : List α} : l.isEmpty = false l [] := by
cases l <;> simp
@[deprecated isEmpty_eq_false_iff (since := "2025-02-17")]
abbrev isEmpty_eq_false := @isEmpty_eq_false_iff
theorem isEmpty_eq_false_iff_exists_mem {xs : List α} :
xs.isEmpty = false x, x xs := by
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]
@[simp] theorem isEmpty_eq_true {l : List α} : l.isEmpty l = [] := by
cases l <;> simp
@[simp] theorem isEmpty_eq_false {l : List α} : l.isEmpty = false l [] := by
cases l <;> simp
/-! ### any / all -/
@@ -595,11 +588,11 @@ theorem all_bne' [BEq α] [PartialEquivBEq α] {l : List α} :
/-! ### set -/
-- As `List.set` is defined in `Init.Prelude`, we write the basic simplification lemmas here.
@[simp] theorem set_nil (i : Nat) (a : α) : [].set i a = [] := rfl
@[simp] theorem set_nil (n : Nat) (a : α) : [].set n a = [] := rfl
@[simp] theorem set_cons_zero (x : α) (xs : List α) (a : α) :
(x :: xs).set 0 a = a :: xs := rfl
@[simp] theorem set_cons_succ (x : α) (xs : List α) (i : Nat) (a : α) :
(x :: xs).set (i + 1) a = x :: xs.set i a := rfl
@[simp] theorem set_cons_succ (x : α) (xs : List α) (n : Nat) (a : α) :
(x :: xs).set (n + 1) a = x :: xs.set n a := rfl
@[simp] theorem getElem_set_self {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
(l.set i a)[i] = a :=
@@ -675,22 +668,22 @@ theorem getElem?_set' {l : List α} {i j : Nat} {a : α} :
rw [getElem_set]
split <;> simp_all
theorem set_eq_of_length_le {l : List α} {i : Nat} (h : l.length i) {a : α} :
l.set i a = l := by
induction l generalizing i with
theorem set_eq_of_length_le {l : List α} {n : Nat} (h : l.length n) {a : α} :
l.set n a = l := by
induction l generalizing n with
| nil => simp_all
| cons a l ih =>
induction i
induction n
· simp_all
· simp only [set_cons_succ, cons.injEq, true_and]
rw [ih]
exact Nat.succ_le_succ_iff.mp h
@[simp] theorem set_eq_nil_iff {l : List α} (i : Nat) (a : α) : l.set i a = [] l = [] := by
cases l <;> cases i <;> simp [set]
@[simp] theorem set_eq_nil_iff {l : List α} (n : Nat) (a : α) : l.set n a = [] l = [] := by
cases l <;> cases n <;> simp [set]
theorem set_comm (a b : α) : {i j : Nat} (l : List α), i j
(l.set i a).set j b = (l.set j b).set i a
theorem set_comm (a b : α) : {n m : Nat} (l : List α), n m
(l.set n a).set m b = (l.set m b).set n a
| _, _, [], _ => by simp
| _+1, 0, _ :: _, _ => by simp [set]
| 0, _+1, _ :: _, _ => by simp [set]
@@ -698,17 +691,17 @@ theorem set_comm (a b : α) : ∀ {i j : Nat} (l : List α), i ≠ j →
congrArg _ <| set_comm a b t fun h' => h <| Nat.succ_inj'.mpr h'
@[simp]
theorem set_set (a b : α) : (l : List α) (i : Nat), (l.set i a).set i b = l.set i b
theorem set_set (a b : α) : (l : List α) (n : Nat), (l.set n a).set n b = l.set n b
| [], _ => by simp
| _ :: _, 0 => by simp [set]
| _ :: _, _+1 => by simp [set, set_set]
theorem mem_set (l : List α) (i : Nat) (h : i < l.length) (a : α) :
a l.set i a := by
theorem mem_set (l : List α) (n : Nat) (h : n < l.length) (a : α) :
a l.set n a := by
simp [mem_iff_getElem]
exact i, (by simpa using h), by simp
exact n, (by simpa using h), by simp
theorem mem_or_eq_of_mem_set : {l : List α} {i : Nat} {a b : α}, a l.set i b a l a = b
theorem mem_or_eq_of_mem_set : {l : List α} {n : Nat} {a b : α}, a l.set n b a l a = b
| _ :: _, 0, _, _, h => ((mem_cons ..).1 h).symm.imp_left (.tail _)
| _ :: _, _+1, _, _, .head .. => .inl (.head ..)
| _ :: _, _+1, _, _, .tail _ h => (mem_or_eq_of_mem_set h).imp_left (.tail _)
@@ -763,10 +756,10 @@ theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l
simp
· intro h
constructor
intro l
induction l with
intro a
induction a with
| nil => simp only [List.instBEq, List.beq]
| cons _ _ ih =>
| cons a as ih =>
simp [List.instBEq, List.beq]
exact ih
@@ -785,9 +778,9 @@ theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l
simp
· intro h
constructor
· intro _ _ h
· intro a b h
simpa using h
· intro _
· intro a
simp
/-! ### isEqv -/
@@ -925,13 +918,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 +1011,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
@@ -1178,8 +1171,8 @@ theorem map_eq_foldr (f : α → β) (l : List α) : map f l = foldr (fun a bs =
| cons b l ih => cases i <;> simp_all
@[deprecated "Use the reverse direction of `map_set`." (since := "2024-09-20")]
theorem set_map {f : α β} {l : List α} {i : Nat} {a : α} :
(map f l).set i (f a) = map f (l.set i a) := by
theorem set_map {f : α β} {l : List α} {n : Nat} {a : α} :
(map f l).set n (f a) = map f (l.set n a) := by
simp
@[simp] theorem head_map (f : α β) (l : List α) (w) :
@@ -1634,16 +1627,16 @@ theorem append_right_inj {t₁ t₂ : List α} (s) : s ++ t₁ = s ++ t₂ ↔ t
theorem append_left_inj {s₁ s₂ : List α} (t) : s₁ ++ t = s₂ ++ t s₁ = s₂ :=
fun h => append_inj_left' h rfl, congrArg (· ++ _)
@[simp] theorem append_left_eq_self {xs ys : List α} : xs ++ ys = ys xs = [] := by
rw [ append_left_inj (s₁ := xs), nil_append]
@[simp] theorem append_left_eq_self {x y : List α} : x ++ y = y x = [] := by
rw [ append_left_inj (s₁ := x), nil_append]
@[simp] theorem self_eq_append_left {xs ys : List α} : ys = xs ++ ys xs = [] := by
@[simp] theorem self_eq_append_left {x y : List α} : y = x ++ y x = [] := by
rw [eq_comm, append_left_eq_self]
@[simp] theorem append_right_eq_self {xs ys : List α} : xs ++ ys = xs ys = [] := by
rw [ append_right_inj (t₁ := ys), append_nil]
@[simp] theorem append_right_eq_self {x y : List α} : x ++ y = x y = [] := by
rw [ append_right_inj (t₁ := y), append_nil]
@[simp] theorem self_eq_append_right {xs ys : List α} : xs = xs ++ ys ys = [] := by
@[simp] theorem self_eq_append_right {x y : List α} : x = x ++ y y = [] := by
rw [eq_comm, append_right_eq_self]
theorem getLast_concat {a : α} : (l : List α), getLast (l ++ [a]) (by simp) = a
@@ -1670,14 +1663,14 @@ theorem append_ne_nil_of_ne_nil_left {s : List α} (h : s ≠ []) (t : List α)
theorem append_ne_nil_of_ne_nil_right (s : List α) : t [] s ++ t [] := by simp_all
theorem append_eq_cons_iff :
as ++ bs = x :: c (as = [] bs = x :: c) ( as', as = x :: as' c = as' ++ bs) := by
cases as with simp | cons a as => ?_
exact fun h => as, by simp [h], fun as', aeq, aseq, h => aeq, by rw [aseq, h]
a ++ b = x :: c (a = [] b = x :: c) ( a', a = x :: a' c = a' ++ b) := by
cases a with simp | cons a as => ?_
exact fun h => as, by simp [h], fun a', aeq, aseq, h => aeq, by rw [aseq, h]
@[deprecated append_eq_cons_iff (since := "2024-07-24")] abbrev append_eq_cons := @append_eq_cons_iff
theorem cons_eq_append_iff :
x :: cs = as ++ bs (as = [] bs = x :: cs) ( as', as = x :: as' cs = as' ++ bs) := by
x :: c = a ++ b (a = [] b = x :: c) ( a', a = x :: a' c = a' ++ b) := by
rw [eq_comm, append_eq_cons_iff]
@[deprecated cons_eq_append_iff (since := "2024-07-24")] abbrev cons_eq_append := @cons_eq_append_iff
@@ -1690,11 +1683,11 @@ theorem singleton_eq_append_iff :
[x] = a ++ b (a = [] b = [x]) (a = [x] b = []) := by
cases a <;> cases b <;> simp [eq_comm]
theorem append_eq_append_iff {ws xs ys zs : List α} :
ws ++ xs = ys ++ zs ( as, ys = ws ++ as xs = as ++ zs) bs, ws = ys ++ bs zs = bs ++ xs := by
induction ws generalizing ys with
theorem append_eq_append_iff {a b c d : List α} :
a ++ b = c ++ d ( a', c = a ++ a' b = a' ++ d) c', a = c ++ c' d = c' ++ b := by
induction a generalizing c with
| nil => simp_all
| cons a as ih => cases ys <;> simp [eq_comm, and_assoc, ih, and_or_left]
| cons a as ih => cases c <;> simp [eq_comm, and_assoc, ih, and_or_left]
@[deprecated append_inj (since := "2024-07-24")] abbrev append_inj_of_length_left := @append_inj
@[deprecated append_inj' (since := "2024-07-24")] abbrev append_inj_of_length_right := @append_inj'
@@ -1785,7 +1778,7 @@ theorem filterMap_eq_append_iff {f : α → Option β} :
simp_all
· rename_i b w
intro h
rcases cons_eq_append_iff.mp h with (rfl, rfl | _, rfl, h)
rcases cons_eq_append_iff.mp h with (rfl, rfl | L₁, rfl, h)
· refine [], x :: l, ?_
simp [filterMap_cons, w]
· obtain l₁, l₂, rfl, rfl, rfl := ih _
@@ -1868,11 +1861,11 @@ theorem map_concat (f : α → β) (a : α) (l : List α) : map f (concat l a) =
| nil => rfl
| cons x xs ih => simp [ih]
theorem eq_nil_or_concat : l : List α, l = [] l' b, l = concat l' b
theorem eq_nil_or_concat : l : List α, l = [] L b, l = concat L b
| [] => .inl rfl
| a::l => match l, eq_nil_or_concat l with
| _, .inl rfl => .inr [], a, rfl
| _, .inr l', b, rfl => .inr a::l', b, rfl
| _, .inr L, b, rfl => .inr a::L, b, rfl
/-! ### flatten -/
@@ -1886,7 +1879,7 @@ theorem flatten_singleton (l : List α) : [l].flatten = l := by simp
@[simp] theorem mem_flatten : {L : List (List α)}, a L.flatten l, l L a l
| [] => by simp
| _ :: _ => by simp [mem_flatten, or_and_right, exists_or]
| b :: l => by simp [mem_flatten, or_and_right, exists_or]
@[simp] theorem flatten_eq_nil_iff {L : List (List α)} : L.flatten = [] l L, l = [] := by
induction L <;> simp_all
@@ -1894,7 +1887,7 @@ theorem flatten_singleton (l : List α) : [l].flatten = l := by simp
@[simp] theorem nil_eq_flatten_iff {L : List (List α)} : [] = L.flatten l L, l = [] := by
rw [eq_comm, flatten_eq_nil_iff]
theorem flatten_ne_nil_iff {xss : List (List α)} : xss.flatten [] xs, xs xss xs [] := by
theorem flatten_ne_nil_iff {xs : List (List α)} : xs.flatten [] x, x xs x [] := by
simp
theorem exists_of_mem_flatten : a flatten L l, l L a l := mem_flatten.1
@@ -1952,13 +1945,13 @@ theorem flatten_concat (L : List (List α)) (l : List α) : flatten (L ++ [l]) =
theorem flatten_flatten {L : List (List (List α))} : flatten (flatten L) = flatten (map flatten L) := by
induction L <;> simp_all
theorem flatten_eq_cons_iff {xss : List (List α)} {y : α} {ys : List α} :
xss.flatten = y :: ys
as bs cs, xss = as ++ (y :: bs) :: cs ( l, l as l = []) ys = bs ++ cs.flatten := by
theorem flatten_eq_cons_iff {xs : List (List α)} {y : α} {ys : List α} :
xs.flatten = y :: ys
as bs cs, xs = as ++ (y :: bs) :: cs ( l, l as l = []) ys = bs ++ cs.flatten := by
constructor
· induction xss with
· induction xs with
| nil => simp
| cons xs xss ih =>
| cons x xs ih =>
intro h
simp only [flatten_cons] at h
replace h := h.symm
@@ -1967,8 +1960,8 @@ theorem flatten_eq_cons_iff {xss : List (List α)} {y : α} {ys : List α} :
· obtain as, bs, cs, rfl, _, rfl := ih h
refine [] :: as, bs, cs, ?_
simpa
· obtain as', rfl, rfl := z
refine [], as', xss, ?_
· obtain a', rfl, rfl := z
refine [], a', xs, ?_
simp
· rintro as, bs, cs, rfl, h₁, rfl
simp [flatten_eq_nil_iff.mpr h₁]
@@ -1993,30 +1986,30 @@ theorem singleton_eq_flatten_iff {xs : List (List α)} {y : α} :
[y] = xs.flatten as bs, xs = as ++ [y] :: bs ( l, l as l = []) ( l, l bs l = []) := by
rw [eq_comm, flatten_eq_singleton_iff]
theorem flatten_eq_append_iff {xss : List (List α)} {ys zs : List α} :
xss.flatten = ys ++ zs
( as bs, xss = as ++ bs ys = as.flatten zs = bs.flatten)
as bs c cs ds, xss = as ++ (bs ++ c :: cs) :: ds ys = as.flatten ++ bs
theorem flatten_eq_append_iff {xs : List (List α)} {ys zs : List α} :
xs.flatten = ys ++ zs
( as bs, xs = as ++ bs ys = as.flatten zs = bs.flatten)
as bs c cs ds, xs = as ++ (bs ++ c :: cs) :: ds ys = as.flatten ++ bs
zs = c :: cs ++ ds.flatten := by
constructor
· induction xss generalizing ys with
· induction xs generalizing ys with
| nil =>
simp only [flatten_nil, nil_eq, append_eq_nil_iff, and_false, cons_append, false_and,
exists_const, exists_false, or_false, and_imp, List.cons_ne_nil]
rintro rfl rfl
exact [], [], by simp
| cons xs xss ih =>
| cons x xs ih =>
intro h
simp only [flatten_cons] at h
rw [append_eq_append_iff] at h
obtain (ys, rfl, h | bs, rfl, h) := h
obtain (ys, rfl, h | c', rfl, h) := h
· obtain (as, bs, rfl, rfl, rfl | as, bs, c, cs, ds, rfl, rfl, rfl) := ih h
· exact .inl xs :: as, bs, by simp
· exact .inr xs :: as, bs, c, cs, ds, by simp
· exact .inl x :: as, bs, by simp
· exact .inr x :: as, bs, c, cs, ds, by simp
· simp only [h]
cases bs with
| nil => exact .inl [ys], xss, by simp
| cons b bs => exact .inr [], ys, b, bs, xss, by simp
cases c' with
| nil => exact .inl [ys], xs, by simp
| cons x c' => exact .inr [], ys, x, c', xs, by simp
· rintro (as, bs, rfl, rfl, rfl | as, bs, c, cs, ds, rfl, rfl, rfl)
· simp
· simp
@@ -2033,8 +2026,8 @@ sublists. -/
theorem eq_iff_flatten_eq : {L L' : List (List α)},
L = L' L.flatten = L'.flatten map length L = map length L'
| _, [] => by simp_all
| [], _ :: _ => by simp_all
| _ :: _, _ :: _ => by
| [], x' :: L' => by simp_all
| x :: L, x' :: L' => by
simp
rw [eq_iff_flatten_eq]
constructor
@@ -2048,9 +2041,9 @@ theorem eq_iff_flatten_eq : ∀ {L L' : List (List α)},
theorem flatMap_def (l : List α) (f : α List β) : l.flatMap f = flatten (map f l) := by rfl
@[simp] theorem flatMap_id (L : List (List α)) : L.flatMap id = L.flatten := by simp [flatMap_def]
@[simp] theorem flatMap_id (l : List (List α)) : l.flatMap id = l.flatten := by simp [flatMap_def]
@[simp] theorem flatMap_id' (L : List (List α)) : L.flatMap (fun as => as) = L.flatten := by simp [flatMap_def]
@[simp] theorem flatMap_id' (l : List (List α)) : l.flatMap (fun a => a) = l.flatten := by simp [flatMap_def]
@[simp]
theorem length_flatMap (l : List α) (f : α List β) :
@@ -2173,16 +2166,16 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
@[deprecated replicate_eq_nil_iff (since := "2024-09-05")] abbrev replicate_eq_nil := @replicate_eq_nil_iff
@[simp] theorem getElem_replicate (a : α) {n : Nat} {i} (h : i < (replicate n a).length) :
(replicate n a)[i] = a :=
@[simp] theorem getElem_replicate (a : α) {n : Nat} {m} (h : m < (replicate n a).length) :
(replicate n a)[m] = a :=
eq_of_mem_replicate (getElem_mem _)
theorem getElem?_replicate : (replicate n a)[i]? = if i < n then some a else none := by
by_cases h : i < n
theorem getElem?_replicate : (replicate n a)[m]? = if m < n then some a else none := by
by_cases h : m < n
· rw [getElem?_eq_getElem (by simpa), getElem_replicate, if_pos h]
· rw [getElem?_eq_none (by simpa using h), if_neg h]
@[simp] theorem getElem?_replicate_of_lt {n : Nat} {i : Nat} (h : i < n) : (replicate n a)[i]? = some a := by
@[simp] theorem getElem?_replicate_of_lt {n : Nat} {m : Nat} (h : m < n) : (replicate n a)[m]? = some a := by
simp [getElem?_replicate, h]
theorem head?_replicate (a : α) (n : Nat) : (replicate n a).head? = if n = 0 then none else some a := by
@@ -2364,18 +2357,18 @@ theorem eq_replicate_or_eq_replicate_append_cons {α : Type _} (l : List α) :
/-- An induction principle for lists based on contiguous runs of identical elements. -/
-- A `Sort _` valued version would require a different design. (And associated `@[simp]` lemmas.)
theorem replicateRecOn {α : Type _} {p : List α Prop} (l : List α)
theorem replicateRecOn {α : Type _} {p : List α Prop} (m : List α)
(h0 : p []) (hr : a n, 0 < n p (replicate n a))
(hi : a b n l, a b 0 < n p (b :: l) p (replicate n a ++ b :: l)) : p l := by
rcases eq_replicate_or_eq_replicate_append_cons l with
(hi : a b n l, a b 0 < n p (b :: l) p (replicate n a ++ b :: l)) : p m := by
rcases eq_replicate_or_eq_replicate_append_cons m with
rfl | n, a, rfl, hn | n, a, b, l', w, hn, h
· exact h0
· exact hr _ _ hn
· have : (b :: l').length < l.length := by
· have : (b :: l').length < m.length := by
simpa [w] using Nat.lt_add_of_pos_left hn
subst w
exact hi _ _ _ _ h hn (replicateRecOn (b :: l') h0 hr hi)
termination_by l.length
termination_by m.length
@[simp] theorem sum_replicate_nat (n : Nat) (a : Nat) : (replicate n a).sum = n * a := by
induction n <;> simp_all [replicate_succ, Nat.add_mul, Nat.add_comm]
@@ -2402,9 +2395,6 @@ theorem mem_reverseAux {x : α} : ∀ {as bs}, x ∈ reverseAux as bs ↔ x ∈
theorem reverse_ne_nil_iff {xs : List α} : xs.reverse [] xs [] :=
not_congr reverse_eq_nil_iff
@[simp] theorem isEmpty_reverse {xs : List α} : xs.reverse.isEmpty = xs.isEmpty := by
cases xs <;> simp
/-- Variant of `getElem?_reverse` with a hypothesis giving the linear relation between the indices. -/
theorem getElem?_reverse' : {l : List α} (i j), i + j + 1 = length l
l.reverse[i]? = l[j]?
@@ -2559,7 +2549,7 @@ theorem foldr_eq_foldrM (f : α → β → β) (b) (l : List α) :
/-! ### foldl and foldr -/
@[simp] theorem foldr_cons_eq_append (l : List α) (f : α β) (l' : List β) :
l.foldr (fun x ys => f x :: ys) l' = l.map f ++ l' := by
l.foldr (fun x y => f x :: y) l' = l.map f ++ l' := by
induction l <;> simp [*]
/-- Variant of `foldr_cons_eq_append` specalized to `f = id`. -/
@@ -2570,7 +2560,7 @@ theorem foldr_eq_foldrM (f : α → β → β) (b) (l : List α) :
@[deprecated foldr_cons_eq_append (since := "2024-08-22")] abbrev foldr_self_append := @foldr_cons_eq_append
@[simp] theorem foldl_flip_cons_eq_append (l : List α) (f : α β) (l' : List β) :
l.foldl (fun xs y => f y :: xs) l' = (l.map f).reverse ++ l' := by
l.foldl (fun x y => f y :: x) l' = (l.map f).reverse ++ l' := by
induction l generalizing l' <;> simp [*]
@[simp] theorem foldr_append_eq_append (l : List α) (f : α List β) (l' : List β) :
@@ -2582,11 +2572,11 @@ theorem foldr_eq_foldrM (f : α → β → β) (b) (l : List α) :
induction l generalizing l'<;> simp [*]
@[simp] theorem foldr_flip_append_eq_append (l : List α) (f : α List β) (l' : List β) :
l.foldr (fun x ys => ys ++ f x) l' = l' ++ (l.map f).reverse.flatten := by
l.foldr (fun x y => y ++ f x) l' = l' ++ (l.map f).reverse.flatten := by
induction l generalizing l' <;> simp [*]
@[simp] theorem foldl_flip_append_eq_append (l : List α) (f : α List β) (l' : List β) :
l.foldl (fun xs y => f y ++ xs) l' = (l.map f).reverse.flatten ++ l' := by
l.foldl (fun x y => f y ++ x) l' = (l.map f).reverse.flatten ++ l' := by
induction l generalizing l' <;> simp [*]
theorem foldr_cons_nil (l : List α) : l.foldr cons [] = l := by simp
@@ -2805,8 +2795,9 @@ theorem getLast_eq_head_reverse {l : List α} (h : l ≠ []) :
l.getLast h = l.reverse.head (by simp_all) := by
rw [ head_reverse]
@[deprecated getLast_eq_iff_getLast?_eq_some (since := "2025-02-17")]
abbrev getLast_eq_iff_getLast_eq_some := @getLast_eq_iff_getLast?_eq_some
theorem getLast_eq_iff_getLast_eq_some {xs : List α} (h) : xs.getLast h = a xs.getLast? = some a := by
rw [getLast_eq_head_reverse, head_eq_iff_head?_eq_some]
simp
@[simp] theorem getLast?_eq_none_iff {xs : List α} : xs.getLast? = none xs = [] := by
rw [getLast?_eq_head?_reverse, head?_eq_none_iff, reverse_eq_nil_iff]
@@ -2875,8 +2866,8 @@ theorem getLast_filterMap_of_eq_some {f : α → Option β} {l : List α} {w : l
rw [head_filterMap_of_eq_some (by simp_all)]
simp_all
theorem getLast?_flatMap {l : List α} {f : α List β} :
(l.flatMap f).getLast? = l.reverse.findSome? fun a => (f a).getLast? := by
theorem getLast?_flatMap {L : List α} {f : α List β} :
(L.flatMap f).getLast? = L.reverse.findSome? fun a => (f a).getLast? := by
simp only [ head?_reverse, reverse_flatMap]
rw [head?_flatMap]
rfl
@@ -2898,7 +2889,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
@@ -3064,16 +3055,16 @@ We don't provide any API for `splitAt`, beyond the `@[simp]` lemma
which is proved in `Init.Data.List.TakeDrop`.
-/
theorem splitAt_go (i : Nat) (l acc : List α) :
splitAt.go l xs i acc =
if i < xs.length then (acc.reverse ++ xs.take i, xs.drop i) else (l, []) := by
induction xs generalizing i acc with
theorem splitAt_go (n : Nat) (l acc : List α) :
splitAt.go l xs n acc =
if n < xs.length then (acc.reverse ++ xs.take n, xs.drop n) else (l, []) := by
induction xs generalizing n acc with
| nil => simp [splitAt.go]
| cons x xs ih =>
cases i with
cases n with
| zero => simp [splitAt.go]
| succ i =>
rw [splitAt.go, take_succ_cons, drop_succ_cons, ih i (x :: acc),
| succ n =>
rw [splitAt.go, take_succ_cons, drop_succ_cons, ih n (x :: acc),
reverse_cons, append_assoc, singleton_append, length_cons]
simp only [Nat.succ_lt_succ_iff]
@@ -3086,12 +3077,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
@@ -3159,14 +3146,14 @@ theorem replace_append_right [LawfulBEq α] {l₁ l₂ : List α} (h : ¬ a ∈
(l₁ ++ l₂).replace a b = l₁ ++ l₂.replace a b := by
simp [replace_append, h]
theorem replace_take {l : List α} {i : Nat} :
(l.take i).replace a b = (l.replace a b).take i := by
induction l generalizing i with
theorem replace_take {l : List α} {n : Nat} :
(l.take n).replace a b = (l.replace a b).take n := by
induction l generalizing n with
| nil => simp
| cons x xs ih =>
cases i with
cases n with
| zero => simp [ih]
| succ i =>
| succ n =>
simp only [replace_cons, take_succ_cons]
split <;> simp_all
@@ -3174,7 +3161,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
@@ -3370,13 +3357,13 @@ theorem all_eq_not_any_not (l : List α) (p : α → Bool) : l.all p = !l.any (!
simp only [filterMap_cons]
split <;> simp_all
@[simp] theorem any_append {xs ys : List α} : (xs ++ ys).any f = (xs.any f || ys.any f) := by
induction xs with
@[simp] theorem any_append {x y : List α} : (x ++ y).any f = (x.any f || y.any f) := by
induction x with
| nil => rfl
| cons h t ih => simp_all [Bool.or_assoc]
@[simp] theorem all_append {xs ys : List α} : (xs ++ ys).all f = (xs.all f && ys.all f) := by
induction xs with
@[simp] theorem all_append {x y : List α} : (x ++ y).all f = (x.all f && y.all f) := by
induction x with
| nil => rfl
| cons h t ih => simp_all [Bool.and_assoc]
@@ -3436,7 +3423,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
@@ -3601,7 +3588,7 @@ theorem getElem?_eq (l : List α) (i : Nat) :
@[deprecated getElem?_eq_none (since := "2024-11-29")] abbrev getElem?_len_le := @getElem?_eq_none
@[deprecated _root_.isSome_getElem? (since := "2024-12-09")]
theorem isSome_getElem? {l : List α} {i : Nat} : l[i]?.isSome i < l.length := by
theorem isSome_getElem? {l : List α} {n : Nat} : l[n]?.isSome n < l.length := by
simp
@[deprecated _root_.isNone_getElem? (since := "2024-12-09")]

View File

@@ -7,9 +7,6 @@ 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.
namespace List
/-! ### Lexicographic ordering -/
@@ -170,7 +167,7 @@ protected theorem lt_of_le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
induction h₂ generalizing l₁ with
| nil => simp_all
| rel hab =>
rename_i a xs
rename_i a b
cases l₁ with
| nil => simp_all
| cons c l₁ =>

View File

@@ -11,9 +11,6 @@ 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.
namespace List
/-! ## Operations using indexes -/
@@ -134,10 +131,10 @@ theorem mapFinIdx_cons {l : List α} {a : α} {f : (i : Nat) → α → (h : i <
· simp
· rintro (_|i) h₁ h₂ <;> simp
theorem mapFinIdx_append {xs ys : List α} {f : (i : Nat) α (h : i < (xs ++ ys).length) β} :
(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.length) a (by simp; omega)) := by
theorem mapFinIdx_append {K L : List α} {f : (i : Nat) α (h : i < (K ++ L).length) β} :
(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.length) a (by simp; omega)) := by
apply ext_getElem
· simp
· intro i h₁ h₂
@@ -302,15 +299,15 @@ theorem mapFinIdx_eq_replicate_iff {l : List α} {f : (i : Nat) → α → (h :
theorem mapIdx_nil {f : Nat α β} : mapIdx f [] = [] :=
rfl
theorem mapIdx_go_length {acc : Array β} :
length (mapIdx.go f l acc) = length l + acc.size := by
induction l generalizing acc with
theorem mapIdx_go_length {arr : Array β} :
length (mapIdx.go f l arr) = length l + arr.size := by
induction l generalizing arr with
| nil => simp only [mapIdx.go, length_nil, Nat.zero_add]
| cons _ _ ih =>
simp only [mapIdx.go, ih, Array.size_push, Nat.add_succ, length_cons, Nat.add_comm]
theorem length_mapIdx_go : {l : List α} {acc : Array β},
(mapIdx.go f l acc).length = l.length + acc.size
theorem length_mapIdx_go : {l : List α} {arr : Array β},
(mapIdx.go f l arr).length = l.length + arr.size
| [], _ => by simp [mapIdx.go]
| a :: l, _ => by
simp only [mapIdx.go, length_cons]
@@ -321,13 +318,13 @@ theorem length_mapIdx_go : ∀ {l : List α} {acc : Array β},
@[simp] theorem length_mapIdx {l : List α} : (l.mapIdx f).length = l.length := by
simp [mapIdx, length_mapIdx_go]
theorem getElem?_mapIdx_go : {l : List α} {acc : Array β} {i : Nat},
(mapIdx.go f l acc)[i]? =
if h : i < acc.size then some acc[i] else Option.map (f i) l[i - acc.size]?
| [], acc, i => by
theorem getElem?_mapIdx_go : {l : List α} {arr : Array β} {i : Nat},
(mapIdx.go f l arr)[i]? =
if h : i < arr.size then some arr[i] else Option.map (f i) l[i - arr.size]?
| [], arr, i => by
simp only [mapIdx.go, Array.toListImpl_eq, getElem?_def, Array.length_toList,
Array.getElem_toList, length_nil, Nat.not_lt_zero, reduceDIte, Option.map_none']
| a :: l, acc, i => by
| a :: l, arr, i => by
rw [mapIdx.go, getElem?_mapIdx_go]
simp only [Array.size_push]
split <;> split
@@ -335,10 +332,10 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {acc : Array β} {i : Nat},
rw [ Array.getElem_toList]
simp only [Array.push_toList]
rw [getElem_append_left, Array.getElem_toList]
· have : i = acc.size := by omega
· have : i = arr.size := by omega
simp_all
· omega
· have : i - acc.size = i - (acc.size + 1) + 1 := by omega
· have : i - arr.size = i - (arr.size + 1) + 1 := by omega
simp_all
@[simp] theorem getElem?_mapIdx {l : List α} {i : Nat} :
@@ -374,9 +371,9 @@ theorem mapIdx_cons {l : List α} {a : α} :
mapIdx f (a :: l) = f 0 a :: mapIdx (fun i => f (i + 1)) l := by
simp [mapIdx_eq_zipIdx_map, List.zipIdx_succ]
theorem mapIdx_append {xs ys : List α} :
(xs ++ ys).mapIdx f = xs.mapIdx f ++ ys.mapIdx fun i => f (i + xs.length) := by
induction xs generalizing f with
theorem mapIdx_append {K L : List α} :
(K ++ L).mapIdx f = K.mapIdx f ++ L.mapIdx fun i => f (i + K.length) := by
induction K generalizing f with
| nil => rfl
| cons _ _ ih => simp [ih (f := fun i => f (i + 1)), Nat.add_assoc]

View File

@@ -10,9 +10,6 @@ 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.
namespace List
open Nat

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,21 +7,18 @@ 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.
namespace List
/-! ### isEqv -/
theorem isEqv_eq_decide (as bs : List α) (r) :
isEqv as bs r = if h : as.length = bs.length then
decide ( (i : Nat) (h' : i < as.length), r (as[i]'(h h')) (bs[i]'(h h'))) else false := by
induction as generalizing bs with
theorem isEqv_eq_decide (a b : List α) (r) :
isEqv a b r = if h : a.length = b.length then
decide ( (i : Nat) (h' : i < a.length), r (a[i]'(h h')) (b[i]'(h h'))) else false := by
induction a generalizing b with
| nil =>
cases bs <;> simp
cases b <;> simp
| cons a as ih =>
cases bs with
cases b with
| nil => simp
| cons b bs =>
simp only [isEqv, ih, length_cons, Nat.add_right_cancel_iff]
@@ -29,12 +26,12 @@ theorem isEqv_eq_decide (as bs : List α) (r) :
/-! ### beq -/
theorem beq_eq_isEqv [BEq α] (as bs : List α) : as.beq bs = isEqv as bs (· == ·) := by
induction as generalizing bs with
theorem beq_eq_isEqv [BEq α] (a b : List α) : a.beq b = isEqv a b (· == ·) := by
induction a generalizing b with
| nil =>
cases bs <;> simp
cases b <;> simp
| cons a as ih =>
cases bs with
cases b with
| nil => simp
| cons b bs =>
simp only [beq_cons₂, ih, isEqv_eq_decide, length_cons, Nat.add_right_cancel_iff,
@@ -42,9 +39,9 @@ theorem beq_eq_isEqv [BEq α] (as bs : List α) : as.beq bs = isEqv as bs (· ==
Bool.decide_eq_true]
split <;> simp
theorem beq_eq_decide [BEq α] (as bs : List α) :
(as == bs) = if h : as.length = bs.length then
decide ( (i : Nat) (h' : i < as.length), as[i] == bs[i]'(h h')) else false := by
theorem beq_eq_decide [BEq α] (a b : List α) :
(a == b) = if h : a.length = b.length then
decide ( (i : Nat) (h' : i < a.length), a[i] == b[i]'(h h')) else false := by
simp [BEq.beq, beq_eq_isEqv, isEqv_eq_decide]
end List

View File

@@ -15,9 +15,6 @@ 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.
open Nat
namespace List
@@ -44,42 +41,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 +60,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,9 +7,6 @@ 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.
namespace List
open Nat

View File

@@ -7,9 +7,6 @@ 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.
namespace List
theorem getElem?_eraseIdx (l : List α) (i : Nat) (j : Nat) :

View File

@@ -7,9 +7,6 @@ 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.
namespace List
open Nat
@@ -44,7 +41,7 @@ theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : List α} {p q : α → Boo
rw [findSome?_eq_some_iff] at h
simp only [Option.ite_none_right_eq_some, Option.some.injEq, ite_eq_right_iff, reduceCtorEq,
imp_false, Bool.not_eq_true, Prod.forall, exists_and_right, Prod.exists] at h
obtain xs, h₁, b, ys, h₂, hb, rfl, h₃ := h
obtain h, h₁, b, es, h₂, hb, rfl, h₃ := h
rw [zipIdx_eq_append_iff] at h₂
obtain l₁', l₂', rfl, rfl, h₂ := h₂
rw [eq_comm, zipIdx_eq_cons_iff] at h₂

View File

@@ -12,10 +12,9 @@ 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.
open Function
open Function Nat
open Nat
namespace List
@@ -36,31 +35,31 @@ theorem insertIdx_succ_nil (n : Nat) (a : α) : insertIdx (n + 1) a [] = [] :=
rfl
@[simp]
theorem insertIdx_succ_cons (s : List α) (hd x : α) (i : Nat) :
insertIdx (i + 1) x (hd :: s) = hd :: insertIdx i x s :=
theorem insertIdx_succ_cons (s : List α) (hd x : α) (n : Nat) :
insertIdx (n + 1) x (hd :: s) = hd :: insertIdx n x s :=
rfl
theorem length_insertIdx : i as, (insertIdx i a as).length = if i as.length then as.length + 1 else as.length
theorem length_insertIdx : n as, (insertIdx n a as).length = if n as.length then as.length + 1 else as.length
| 0, _ => by simp
| n + 1, [] => by simp
| n + 1, a :: as => by
simp only [insertIdx_succ_cons, length_cons, length_insertIdx, Nat.add_le_add_iff_right]
split <;> rfl
theorem length_insertIdx_of_le_length (h : i length as) : length (insertIdx i a as) = length as + 1 := by
theorem length_insertIdx_of_le_length (h : n length as) : length (insertIdx n a as) = length as + 1 := by
simp [length_insertIdx, h]
theorem length_insertIdx_of_length_lt (h : length as < i) : length (insertIdx i a as) = length as := by
theorem length_insertIdx_of_length_lt (h : length as < n) : length (insertIdx n a as) = length as := by
simp [length_insertIdx, h]
@[simp]
theorem eraseIdx_insertIdx (i : Nat) (l : List α) : (l.insertIdx i a).eraseIdx i = l := by
theorem eraseIdx_insertIdx (n : Nat) (l : List α) : (l.insertIdx n a).eraseIdx n = l := by
rw [eraseIdx_eq_modifyTailIdx, insertIdx, modifyTailIdx_modifyTailIdx_self]
exact modifyTailIdx_id _ _
theorem insertIdx_eraseIdx_of_ge :
i m as,
i < length as i m insertIdx m a (as.eraseIdx i) = (as.insertIdx (m + 1) a).eraseIdx i
n m as,
n < length as n m insertIdx m a (as.eraseIdx n) = (as.insertIdx (m + 1) a).eraseIdx n
| 0, 0, [], has, _ => (Nat.lt_irrefl _ has).elim
| 0, 0, _ :: as, _, _ => by simp [eraseIdx, insertIdx]
| 0, _ + 1, _ :: _, _, _ => rfl
@@ -69,8 +68,8 @@ theorem insertIdx_eraseIdx_of_ge :
insertIdx_eraseIdx_of_ge n m as (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn)
theorem insertIdx_eraseIdx_of_le :
i j as,
i < length as j i insertIdx j a (as.eraseIdx i) = (as.insertIdx j a).eraseIdx (i + 1)
n m as,
n < length as m n insertIdx m a (as.eraseIdx n) = (as.insertIdx m a).eraseIdx (n + 1)
| _, 0, _ :: _, _, _ => rfl
| n + 1, m + 1, a :: as, has, hmn =>
congrArg (cons a) <|
@@ -87,22 +86,22 @@ theorem insertIdx_comm (a b : α) :
exact insertIdx_comm a b i j l (Nat.le_of_succ_le_succ h₀) (Nat.le_of_succ_le_succ h₁)
theorem mem_insertIdx {a b : α} :
{i : Nat} {l : List α} (_ : i l.length), a l.insertIdx i b a = b a l
{n : Nat} {l : List α} (_ : n l.length), a l.insertIdx n b a = b a l
| 0, as, _ => by simp
| _ + 1, [], h => (Nat.not_succ_le_zero _ h).elim
| n + 1, a' :: as, h => by
rw [List.insertIdx_succ_cons, mem_cons, mem_insertIdx (Nat.le_of_succ_le_succ h),
or_assoc, @or_comm (a = a'), or_assoc, mem_cons]
theorem insertIdx_of_length_lt (l : List α) (x : α) (i : Nat) (h : l.length < i) :
insertIdx i x l = l := by
induction l generalizing i with
theorem insertIdx_of_length_lt (l : List α) (x : α) (n : Nat) (h : l.length < n) :
insertIdx n x l = l := by
induction l generalizing n with
| nil =>
cases i
cases n
· simp at h
· simp
| cons x l ih =>
cases i
cases n
· simp at h
· simp only [Nat.succ_lt_succ_iff, length] at h
simpa using ih _ h
@@ -113,84 +112,84 @@ theorem insertIdx_length_self (l : List α) (x : α) : insertIdx l.length x l =
| nil => simp
| cons x l ih => simpa using ih
theorem length_le_length_insertIdx (l : List α) (x : α) (i : Nat) :
l.length (insertIdx i x l).length := by
theorem length_le_length_insertIdx (l : List α) (x : α) (n : Nat) :
l.length (insertIdx n x l).length := by
simp only [length_insertIdx]
split <;> simp
theorem length_insertIdx_le_succ (l : List α) (x : α) (i : Nat) :
(insertIdx i x l).length l.length + 1 := by
theorem length_insertIdx_le_succ (l : List α) (x : α) (n : Nat) :
(insertIdx n x l).length l.length + 1 := by
simp only [length_insertIdx]
split <;> simp
theorem getElem_insertIdx_of_lt {l : List α} {x : α} {i j : Nat} (hn : j < i)
(hk : j < (insertIdx i x l).length) :
(insertIdx i x l)[j] = l[j]'(by simp [length_insertIdx] at hk; split at hk <;> omega) := by
induction i generalizing j l with
theorem getElem_insertIdx_of_lt {l : List α} {x : α} {n k : Nat} (hn : k < n)
(hk : k < (insertIdx n x l).length) :
(insertIdx n x l)[k] = l[k]'(by simp [length_insertIdx] at hk; split at hk <;> omega) := by
induction n generalizing k l with
| zero => simp at hn
| succ n ih =>
cases l with
| nil => simp
| cons _ _=>
cases j
cases k
· simp
· rw [Nat.succ_lt_succ_iff] at hn
simpa using ih hn _
@[simp]
theorem getElem_insertIdx_self {l : List α} {x : α} {i : Nat} (hi : i < (insertIdx i x l).length) :
(insertIdx i x l)[i] = x := by
induction l generalizing i with
theorem getElem_insertIdx_self {l : List α} {x : α} {n : Nat} (hn : n < (insertIdx n x l).length) :
(insertIdx n x l)[n] = x := by
induction l generalizing n with
| nil =>
simp [length_insertIdx] at hi
split at hi
simp [length_insertIdx] at hn
split at hn
· simp_all
· omega
| cons _ _ ih =>
cases i
cases n
· simp
· simp only [insertIdx_succ_cons, length_cons, length_insertIdx, Nat.add_lt_add_iff_right] at hi ih
simpa using ih hi
· simp only [insertIdx_succ_cons, length_cons, length_insertIdx, Nat.add_lt_add_iff_right] at hn ih
simpa using ih hn
theorem getElem_insertIdx_of_gt {l : List α} {x : α} {i j : Nat} (hn : i < j)
(hk : j < (insertIdx i x l).length) :
(insertIdx i x l)[j] = l[j - 1]'(by simp [length_insertIdx] at hk; split at hk <;> omega) := by
induction l generalizing i j with
theorem getElem_insertIdx_of_gt {l : List α} {x : α} {n k : Nat} (hn : n < k)
(hk : k < (insertIdx n x l).length) :
(insertIdx n x l)[k] = l[k - 1]'(by simp [length_insertIdx] at hk; split at hk <;> omega) := by
induction l generalizing n k with
| nil =>
cases i with
cases n with
| zero =>
simp only [insertIdx_zero, length_singleton, lt_one_iff] at hk
omega
| succ n => simp at hk
| cons _ _ ih =>
cases i with
cases n with
| zero =>
simp only [insertIdx_zero] at hk
cases j with
cases k with
| zero => omega
| succ j => simp
| succ k => simp
| succ n =>
cases j with
cases k with
| zero => simp
| succ j =>
| succ k =>
simp only [insertIdx_succ_cons, getElem_cons_succ]
rw [ih (by omega)]
cases j with
cases k with
| zero => omega
| succ j => simp
| succ k => simp
@[deprecated getElem_insertIdx_of_gt (since := "2025-02-04")]
abbrev getElem_insertIdx_of_ge := @getElem_insertIdx_of_gt
theorem getElem_insertIdx {l : List α} {x : α} {i j : Nat} (h : j < (insertIdx i x l).length) :
(insertIdx i x l)[j] =
if h₁ : j < i then
l[j]'(by simp [length_insertIdx] at h; split at h <;> omega)
theorem getElem_insertIdx {l : List α} {x : α} {n k : Nat} (h : k < (insertIdx n x l).length) :
(insertIdx n x l)[k] =
if h₁ : k < n then
l[k]'(by simp [length_insertIdx] at h; split at h <;> omega)
else
if h₂ : j = i then
if h₂ : k = n then
x
else
l[j-1]'(by simp [length_insertIdx] at h; split at h <;> omega) := by
l[k-1]'(by simp [length_insertIdx] at h; split at h <;> omega) := by
split <;> rename_i h₁
· rw [getElem_insertIdx_of_lt h₁]
· split <;> rename_i h₂
@@ -198,15 +197,15 @@ theorem getElem_insertIdx {l : List α} {x : α} {i j : Nat} (h : j < (insertIdx
rw [getElem_insertIdx_self h]
· rw [getElem_insertIdx_of_gt (by omega)]
theorem getElem?_insertIdx {l : List α} {x : α} {i j : Nat} :
(insertIdx i x l)[j]? =
if j < i then
l[j]?
theorem getElem?_insertIdx {l : List α} {x : α} {n k : Nat} :
(insertIdx n x l)[k]? =
if k < n then
l[k]?
else
if j = i then
if j l.length then some x else none
if k = n then
if k l.length then some x else none
else
l[j-1]? := by
l[k-1]? := by
rw [getElem?_def]
split <;> rename_i h
· rw [getElem_insertIdx h]
@@ -229,17 +228,17 @@ theorem getElem?_insertIdx {l : List α} {x : α} {i j : Nat} :
· rw [getElem?_eq_none]
split at h <;> omega
theorem getElem?_insertIdx_of_lt {l : List α} {x : α} {i j : Nat} (h : j < i) :
(insertIdx i x l)[j]? = l[j]? := by
theorem getElem?_insertIdx_of_lt {l : List α} {x : α} {n k : Nat} (h : k < n) :
(insertIdx n x l)[k]? = l[k]? := by
rw [getElem?_insertIdx, if_pos h]
theorem getElem?_insertIdx_self {l : List α} {x : α} {i : Nat} :
(insertIdx i x l)[i]? = if i l.length then some x else none := by
theorem getElem?_insertIdx_self {l : List α} {x : α} {n : Nat} :
(insertIdx n x l)[n]? = if n l.length then some x else none := by
rw [getElem?_insertIdx, if_neg (by omega)]
simp
theorem getElem?_insertIdx_of_gt {l : List α} {x : α} {i j : Nat} (h : i < j) :
(insertIdx i x l)[j]? = l[j - 1]? := by
theorem getElem?_insertIdx_of_gt {l : List α} {x : α} {n k : Nat} (h : n < k) :
(insertIdx n x l)[k]? = l[k - 1]? := by
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
@[deprecated getElem?_insertIdx_of_gt (since := "2025-02-04")]

View File

@@ -8,9 +8,6 @@ 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.
namespace List
/-! ### modifyHead -/
@@ -27,11 +24,11 @@ theorem modifyHead_eq_set [Inhabited α] (f : αα) (l : List α) :
@[simp] theorem modifyHead_modifyHead {l : List α} {f g : α α} :
(l.modifyHead f).modifyHead g = l.modifyHead (g f) := by cases l <;> simp [modifyHead]
theorem getElem_modifyHead {l : List α} {f : α α} {i} (h : i < (l.modifyHead f).length) :
(l.modifyHead f)[i] = if h' : i = 0 then f (l[0]'(by simp at h; omega)) else l[i]'(by simpa using h) := by
theorem getElem_modifyHead {l : List α} {f : α α} {n} (h : n < (l.modifyHead f).length) :
(l.modifyHead f)[n] = if h' : n = 0 then f (l[0]'(by simp at h; omega)) else l[n]'(by simpa using h) := by
cases l with
| nil => simp at h
| cons hd tl => cases i <;> simp
| cons hd tl => cases n <;> simp
@[simp] theorem getElem_modifyHead_zero {l : List α} {f : α α} {h} :
(l.modifyHead f)[0] = f (l[0]'(by simpa using h)) := by simp [getElem_modifyHead]
@@ -39,11 +36,11 @@ theorem getElem_modifyHead {l : List α} {f : αα} {i} (h : i < (l.modifyH
@[simp] theorem getElem_modifyHead_succ {l : List α} {f : α α} {n} (h : n + 1 < (l.modifyHead f).length) :
(l.modifyHead f)[n + 1] = l[n + 1]'(by simpa using h) := by simp [getElem_modifyHead]
theorem getElem?_modifyHead {l : List α} {f : α α} {i} :
(l.modifyHead f)[i]? = if i = 0 then l[i]?.map f else l[i]? := by
theorem getElem?_modifyHead {l : List α} {f : α α} {n} :
(l.modifyHead f)[n]? = if n = 0 then l[n]?.map f else l[n]? := by
cases l with
| nil => simp
| cons hd tl => cases i <;> simp
| cons hd tl => cases n <;> simp
@[simp] theorem getElem?_modifyHead_zero {l : List α} {f : α α} :
(l.modifyHead f)[0]? = l[0]?.map f := by simp [getElem?_modifyHead]
@@ -63,19 +60,19 @@ theorem getElem?_modifyHead {l : List α} {f : αα} {i} :
@[simp] theorem tail_modifyHead {f : α α} {l : List α} :
(l.modifyHead f).tail = l.tail := by cases l <;> simp
@[simp] theorem take_modifyHead {f : α α} {l : List α} {i} :
(l.modifyHead f).take i = (l.take i).modifyHead f := by
cases l <;> cases i <;> simp
@[simp] theorem take_modifyHead {f : α α} {l : List α} {n} :
(l.modifyHead f).take n = (l.take n).modifyHead f := by
cases l <;> cases n <;> simp
@[simp] theorem drop_modifyHead_of_pos {f : α α} {l : List α} {i} (h : 0 < i) :
(l.modifyHead f).drop i = l.drop i := by
cases l <;> cases i <;> simp_all
@[simp] theorem drop_modifyHead_of_pos {f : α α} {l : List α} {n} (h : 0 < n) :
(l.modifyHead f).drop n = l.drop n := by
cases l <;> cases n <;> simp_all
theorem eraseIdx_modifyHead_zero {f : α α} {l : List α} :
(l.modifyHead f).eraseIdx 0 = l.eraseIdx 0 := by simp
@[simp] theorem eraseIdx_modifyHead_of_pos {f : α α} {l : List α} {i} (h : 0 < i) :
(l.modifyHead f).eraseIdx i = (l.eraseIdx i).modifyHead f := by cases l <;> cases i <;> simp_all
@[simp] theorem eraseIdx_modifyHead_of_pos {f : α α} {l : List α} {n} (h : 0 < n) :
(l.modifyHead f).eraseIdx n = (l.eraseIdx n).modifyHead f := by cases l <;> cases n <;> simp_all
@[simp] theorem modifyHead_id : modifyHead (id : α α) = id := by funext l; cases l <;> simp
@@ -92,7 +89,7 @@ theorem eraseIdx_modifyHead_zero {f : αα} {l : List α} :
| _+1, [] => rfl
| n+1, a :: l => congrArg (cons a) (modifyTailIdx_id n l)
theorem eraseIdx_eq_modifyTailIdx : i (l : List α), eraseIdx l i = modifyTailIdx tail i l
theorem eraseIdx_eq_modifyTailIdx : n (l : List α), eraseIdx l n = modifyTailIdx tail n l
| 0, l => by cases l <;> rfl
| _+1, [] => rfl
| _+1, _ :: _ => congrArg (cons _) (eraseIdx_eq_modifyTailIdx _ _)
@@ -108,7 +105,7 @@ theorem modifyTailIdx_add (f : List α → List α) (n) (l₁ l₂ : List α) :
induction l₁ <;> simp [*, Nat.succ_add]
theorem modifyTailIdx_eq_take_drop (f : List α List α) (H : f [] = []) :
i l, modifyTailIdx f i l = take i l ++ f (drop i l)
n l, modifyTailIdx f n l = take n l ++ f (drop n l)
| 0, _ => rfl
| _ + 1, [] => H.symm
| n + 1, b :: l => congrArg (cons b) (modifyTailIdx_eq_take_drop f H n l)
@@ -140,57 +137,57 @@ 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]?
n (l : List α) m, (modify f n l)[m]? = (fun a => if n = m then f a else a) <$> l[m]?
| n, l, 0 => by cases l <;> cases n <;> simp
| n, [], _+1 => by cases n <;> rfl
| 0, _ :: l, j+1 => by cases h : l[j]? <;> simp [h, modify, j.succ_ne_zero.symm]
| i+1, a :: l, j+1 => by
| 0, _ :: l, m+1 => by cases h : l[m]? <;> simp [h, modify, m.succ_ne_zero.symm]
| n+1, a :: l, m+1 => by
simp only [modify_succ_cons, getElem?_cons_succ, Nat.reduceEqDiff, Option.map_eq_map]
refine (getElem?_modify f i l j).trans ?_
cases h' : l[j]? <;> by_cases h : i = j <;>
refine (getElem?_modify f n l m).trans ?_
cases h' : l[m]? <;> by_cases h : n = m <;>
simp [h, if_pos, if_neg, Option.map, mt Nat.succ.inj, not_false_iff, h']
@[simp] theorem length_modify (f : α α) : i l, length (modify f i l) = length l :=
@[simp] theorem length_modify (f : α α) : n l, length (modify f n l) = length l :=
length_modifyTailIdx _ fun l => by cases l <;> rfl
@[simp] theorem getElem?_modify_eq (f : α α) (i) (l : List α) :
(modify f i l)[i]? = f <$> l[i]? := by
@[simp] theorem getElem?_modify_eq (f : α α) (n) (l : List α) :
(modify f n l)[n]? = f <$> l[n]? := by
simp only [getElem?_modify, if_pos]
@[simp] theorem getElem?_modify_ne (f : α α) {i j} (l : List α) (h : i j) :
(modify f i l)[j]? = l[j]? := by
@[simp] theorem getElem?_modify_ne (f : α α) {m n} (l : List α) (h : m n) :
(modify f m l)[n]? = l[n]? := by
simp only [getElem?_modify, if_neg h, id_map']
theorem getElem_modify (f : α α) (i) (l : List α) (j) (h : j < (modify f i l).length) :
(modify f i l)[j] =
if i = j then f (l[j]'(by simp at h; omega)) else l[j]'(by simp at h; omega) := by
theorem getElem_modify (f : α α) (n) (l : List α) (m) (h : m < (modify f n l).length) :
(modify f n l)[m] =
if n = m then f (l[m]'(by simp at h; omega)) else l[m]'(by simp at h; omega) := by
rw [getElem_eq_iff, getElem?_modify]
simp at h
simp [h]
@[simp] theorem getElem_modify_eq (f : α α) (i) (l : List α) (h) :
(modify f i l)[i] = f (l[i]'(by simpa using h)) := by simp [getElem_modify]
@[simp] theorem getElem_modify_eq (f : α α) (n) (l : List α) (h) :
(modify f n l)[n] = f (l[n]'(by simpa using h)) := by simp [getElem_modify]
@[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]
@[simp] theorem getElem_modify_ne (f : α α) {m n} (l : List α) (h : m n) (h') :
(modify f m l)[n] = l[n]'(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,24 +195,24 @@ 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₂
simp only [getElem_modify, getElem_modify_ne, h₂]
split <;> split <;> first | rfl | omega
theorem modify_eq_set [Inhabited α] (f : α α) (i) (l : List α) :
modify f i l = l.set i (f (l[i]?.getD default)) := by
theorem modify_eq_set [Inhabited α] (f : α α) (n) (l : List α) :
modify f n l = l.set n (f (l[n]?.getD default)) := by
apply ext_getElem
· simp
· intro m h₁ h₂
@@ -227,36 +224,36 @@ theorem modify_eq_set [Inhabited α] (f : αα) (i) (l : List α) :
· rfl
theorem modify_eq_take_drop (f : α α) :
i l, modify f i l = take i l ++ modifyHead f (drop i l) :=
n l, modify f n l = take n l ++ modifyHead f (drop n l) :=
modifyTailIdx_eq_take_drop _ rfl
theorem modify_eq_take_cons_drop {f : α α} {i} {l : List α} (h : i < l.length) :
modify f i l = take i l ++ f l[i] :: drop (i + 1) l := by
theorem modify_eq_take_cons_drop {f : α α} {n} {l : List α} (h : n < l.length) :
modify f n l = take n l ++ f l[n] :: drop (n + 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 α) :
(modify f i l).take j = (take j l).modify f i := by
induction j generalizing l i with
theorem take_modify (f : α α) (n m) (l : List α) :
(modify f m l).take n = (take n l).modify f m := by
induction n generalizing l m with
| zero => simp
| succ n ih =>
cases l with
| nil => simp
| cons hd tl =>
cases i with
cases m with
| zero => simp
| succ i => simp [ih]
| succ m => simp [ih]
theorem drop_modify_of_lt (f : α α) (i j) (l : List α) (h : i < j) :
(modify f i l).drop j = l.drop j := by
theorem drop_modify_of_lt (f : α α) (n m) (l : List α) (h : n < m) :
(modify f n l).drop m = l.drop m := by
apply ext_getElem
· simp
· intro m' h₁ h₂
@@ -264,16 +261,16 @@ theorem drop_modify_of_lt (f : αα) (i j) (l : List α) (h : i < j) :
intro h'
omega
theorem drop_modify_of_ge (f : α α) (i j) (l : List α) (h : i j) :
(modify f i l).drop j = modify f (i - j) (drop j l) := by
theorem drop_modify_of_ge (f : α α) (n m) (l : List α) (h : n m) :
(modify f n l).drop m = modify f (n - m) (drop m l) := by
apply ext_getElem
· simp
· intro m' h₁ h₂
simp [getElem_drop, getElem_modify, ite_eq_right_iff]
split <;> split <;> first | rfl | omega
theorem eraseIdx_modify_of_eq (f : α α) (i) (l : List α) :
(modify f i l).eraseIdx i = l.eraseIdx i := by
theorem eraseIdx_modify_of_eq (f : α α) (n) (l : List α) :
(modify f n l).eraseIdx n = l.eraseIdx n := by
apply ext_getElem
· simp [length_eraseIdx]
· intro m h₁ h₂

View File

@@ -12,37 +12,31 @@ 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.
namespace List
set_option linter.listVariables false in
/-- Given a list `is` of monotonically increasing indices into `l`, getting each index
produces a sublist of `l`. -/
theorem map_getElem_sublist {l : List α} {is : List (Fin l.length)} (h : is.Pairwise (· < ·)) :
is.map (l[·]) <+ l := by
suffices j l', l' = l.drop j ( i is, j i) map (l[·]) is <+ l'
suffices n l', l' = l.drop n ( i is, n i) map (l[·]) is <+ l'
from this 0 l (by simp) (by simp)
rintro j l' rfl his
induction is generalizing j with
rintro n l' rfl his
induction is generalizing n with
| nil => simp
| cons hd tl IH =>
simp only [Fin.getElem_fin, map_cons]
have := IH h.of_cons (hd+1) (pairwise_cons.mp h).1
specialize his hd (.head _)
have := (drop_eq_getElem_cons ..).symm this.cons₂ (get l hd)
have := Sublist.append (nil_sublist (take hd l |>.drop j)) this
have := Sublist.append (nil_sublist (take hd l |>.drop n)) this
rwa [nil_append, (drop_append_of_le_length ?_), take_append_drop] at this
simp [Nat.min_eq_left (Nat.le_of_lt hd.isLt), his]
set_option linter.listVariables false in
@[deprecated map_getElem_sublist (since := "2024-07-30")]
theorem map_get_sublist {l : List α} {is : List (Fin l.length)} (h : is.Pairwise (·.val < ·.val)) :
is.map (get l) <+ l := by
simpa using map_getElem_sublist h
set_option linter.listVariables false in
/-- Given a sublist `l' <+ l`, there exists an increasing list of indices `is` such that
`l' = is.map fun i => l[i]`. -/
theorem sublist_eq_map_getElem {l l' : List α} (h : l' <+ l) : is : List (Fin l.length),
@@ -58,13 +52,11 @@ theorem sublist_eq_map_getElem {l l' : List α} (h : l' <+ l) : ∃ is : List (F
refine 0, by simp [Nat.zero_lt_succ] :: is.map (·.succ), ?_
simp [Function.comp_def, pairwise_map, IH, get_eq_getElem, get_cons_zero, get_cons_succ']
set_option linter.listVariables false in
@[deprecated sublist_eq_map_getElem (since := "2024-07-30")]
theorem sublist_eq_map_get (h : l' <+ l) : is : List (Fin l.length),
l' = map (get l) is is.Pairwise (· < ·) := by
simpa using sublist_eq_map_getElem h
set_option linter.listVariables false in
theorem pairwise_iff_getElem : Pairwise R l
(i j : Nat) (_hi : i < l.length) (_hj : j < l.length) (_hij : i < j), R l[i] l[j] := by
rw [pairwise_iff_forall_sublist]

View File

@@ -7,9 +7,6 @@ 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.
namespace List
/-- Helper lemma for `set_set_perm`-/

View File

@@ -14,9 +14,6 @@ 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.
namespace List
open Nat
@@ -45,7 +42,7 @@ theorem getLast?_range' (n : Nat) : (range' s n).getLast? = if n = 0 then none e
@[simp] theorem getLast_range' (n : Nat) (h) : (range' s n).getLast h = s + n - 1 := by
cases n with
| zero => simp at h
| succ n => simp [getLast?_range', getLast_eq_iff_getLast?_eq_some]
| succ n => simp [getLast?_range', getLast_eq_iff_getLast_eq_some]
theorem pairwise_lt_range' s n (step := 1) (pos : 0 < step := by simp) :
Pairwise (· < ·) (range' s n step) :=
@@ -96,7 +93,7 @@ theorem range'_eq_append_iff : range' s n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs =
simp only [range'_succ]
rw [cons_eq_append_iff]
constructor
· rintro (rfl, rfl | _, rfl, h)
· rintro (rfl, rfl | a, rfl, h)
· exact 0, by simp [range'_succ]
· simp only [ih] at h
obtain k, h, rfl, rfl := h
@@ -120,7 +117,7 @@ theorem range'_eq_append_iff : range' s n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs =
simp only [range'_eq_append_iff, eq_comm (a := i :: _), range'_eq_cons_iff]
intro h
constructor
· rintro as, _, k, h₁, rfl, rfl, h₂, rfl, h₃
· rintro as, x, k, h₁, rfl, rfl, h₂, rfl, h₃
constructor
· omega
· simpa using h₃
@@ -180,7 +177,7 @@ theorem pairwise_lt_range (n : Nat) : Pairwise (· < ·) (range n) := by
theorem pairwise_le_range (n : Nat) : Pairwise (· ·) (range n) :=
Pairwise.imp Nat.le_of_lt (pairwise_lt_range _)
@[simp] theorem take_range (i n : Nat) : take i (range n) = range (min i n) := by
@[simp] theorem take_range (m n : Nat) : take m (range n) = range (min m n) := by
apply List.ext_getElem
· simp
· simp +contextual [getElem_take, Nat.lt_min]
@@ -414,7 +411,7 @@ theorem fst_eq_of_mem_zipIdx {x : α × Nat} {l : List α} {k : Nat} (h : x ∈
| nil => cases h
| cons hd tl ih =>
cases h with
| head _ => simp
| head h => simp
| tail h m =>
specialize ih m
have : x.2 - k = x.2 - (k + 1) + 1 := by
@@ -465,12 +462,12 @@ theorem zipIdx_eq_append_iff {l : List α} {k : Nat} :
l₁' l₂', l = l₁' ++ l₂' l₁ = zipIdx l₁' k l₂ = zipIdx l₂' (k + l₁'.length) := by
rw [zipIdx_eq_zip_range', zip_eq_append_iff]
constructor
· rintro ws, xs, ys, zs, h, rfl, h', rfl, rfl
· rintro w, x, y, z, h, rfl, h', rfl, rfl
rw [range'_eq_append_iff] at h'
obtain k, -, rfl, rfl := h'
simp only [length_range'] at h
obtain rfl := h
refine ws, xs, rfl, ?_
refine w, x, rfl, ?_
simp only [zipIdx_eq_zip_range', length_append, true_and]
congr
omega
@@ -541,7 +538,7 @@ theorem snd_eq_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x
| nil => cases h
| cons hd tl ih =>
cases h with
| head _ => simp
| head h => simp
| tail h m =>
specialize ih m
have : x.1 - n = x.1 - (n + 1) + 1 := by
@@ -592,12 +589,12 @@ theorem enumFrom_eq_append_iff {l : List α} {n : Nat} :
l₁' l₂', l = l₁' ++ l₂' l₁ = l₁'.enumFrom n l₂ = l₂'.enumFrom (n + l₁'.length) := by
rw [enumFrom_eq_zip_range', zip_eq_append_iff]
constructor
· rintro ws, xs, ys, zs, h, h', rfl, rfl, rfl
· rintro w, x, y, z, h, h', rfl, rfl, rfl
rw [range'_eq_append_iff] at h'
obtain k, -, rfl, rfl := h'
simp only [length_range'] at h
obtain rfl := h
refine ys, zs, rfl, ?_
refine y, z, rfl, ?_
simp only [enumFrom_eq_zip_range', length_append, true_and]
congr
omega
@@ -627,7 +624,7 @@ theorem enum_length : (enum l).length = l.length :=
enumFrom_length
@[deprecated getElem?_zipIdx (since := "2025-01-21"), simp]
theorem getElem?_enum (l : List α) (i : Nat) : (enum l)[i]? = l[i]?.map fun a => (i, a) := by
theorem getElem?_enum (l : List α) (n : Nat) : (enum l)[n]? = l[n]?.map fun a => (n, a) := by
rw [enum, getElem?_enumFrom, Nat.zero_add]
@[deprecated getElem_zipIdx (since := "2025-01-21"), simp]

View File

@@ -16,13 +16,10 @@ 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.
namespace List
theorem IsSuffix.getElem {xs ys : List α} (h : xs <:+ ys) {i} (hn : i < xs.length) :
xs[i] = ys[ys.length - xs.length + i]'(by have := h.length_le; omega) := by
theorem IsSuffix.getElem {x y : List α} (h : x <:+ y) {n} (hn : n < x.length) :
x[n] = y[y.length - x.length + n]'(by have := h.length_le; omega) := by
rw [getElem_eq_getElem_reverse, h.reverse.getElem, getElem_reverse]
congr
have := h.length_le
@@ -95,11 +92,11 @@ theorem suffix_iff_eq_append : l₁ <:+ l₂ ↔ take (length l₂ - length l₁
by rintro r, rfl; simp only [length_append, Nat.add_sub_cancel_right, take_left], fun e =>
_, e
theorem prefix_take_iff {xs ys : List α} {i : Nat} : xs <+: ys.take i xs <+: ys xs.length i := by
theorem prefix_take_iff {x y : List α} {n : Nat} : x <+: y.take n x <+: y x.length n := by
constructor
· intro h
constructor
· exact List.IsPrefix.trans h <| List.take_prefix i ys
· exact List.IsPrefix.trans h <| List.take_prefix n y
· replace h := h.length_le
rw [length_take, Nat.le_min] at h
exact h.left
@@ -113,21 +110,21 @@ theorem suffix_iff_eq_drop : l₁ <:+ l₂ ↔ l₁ = drop (length l₂ - length
fun h => append_cancel_left <| (suffix_iff_eq_append.1 h).trans (take_append_drop _ _).symm,
fun e => e.symm drop_suffix _ _
theorem prefix_take_le_iff {xs : List α} (hm : i < xs.length) :
xs.take i <+: xs.take j i j := by
theorem prefix_take_le_iff {L : List α} (hm : m < L.length) :
L.take m <+: L.take n m n := by
simp only [prefix_iff_eq_take, length_take]
induction i generalizing xs j with
induction m generalizing L n with
| zero => simp [Nat.min_eq_left, eq_self_iff_true, Nat.zero_le, take]
| succ i IH =>
cases xs with
| succ m IH =>
cases L with
| nil => simp_all
| cons x xs =>
cases j with
| cons l ls =>
cases n with
| zero =>
simp
| succ j =>
| succ n =>
simp only [length_cons, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right] at hm
simp [ @IH j xs hm, Nat.min_eq_left, Nat.le_of_lt hm]
simp [ @IH n ls hm, Nat.min_eq_left, Nat.le_of_lt hm]
@[simp] theorem append_left_sublist_self {xs : List α} (ys : List α) : xs ++ ys <+ ys xs = [] := by
constructor
@@ -156,7 +153,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 +166,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,7 +16,6 @@ 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.
namespace List
@@ -39,16 +38,16 @@ theorem length_take_of_le (h : i ≤ length l) : length (take i l) = i := by sim
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
length `> i`. Version designed to rewrite from the big list to the small list. -/
theorem getElem_take' (xs : List α) {i j : Nat} (hi : i < xs.length) (hj : i < j) :
xs[i] = (xs.take j)[i]'(length_take .. Nat.lt_min.mpr hj, hi) :=
getElem_of_eq (take_append_drop j xs).symm _ getElem_append_left ..
theorem getElem_take' (L : List α) {i j : Nat} (hi : i < L.length) (hj : i < j) :
L[i] = (L.take j)[i]'(length_take .. Nat.lt_min.mpr hj, hi) :=
getElem_of_eq (take_append_drop j L).symm _ getElem_append_left ..
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
length `> i`. Version designed to rewrite from the small list to the big list. -/
@[simp] theorem getElem_take (xs : List α) {j i : Nat} {h : i < (xs.take j).length} :
(xs.take j)[i] =
xs[i]'(Nat.lt_of_lt_of_le h (length_take_le' _ _)) := by
rw [length_take, Nat.lt_min] at h; rw [getElem_take' xs _ h.1]
@[simp] theorem getElem_take (L : List α) {j i : Nat} {h : i < (L.take j).length} :
(L.take j)[i] =
L[i]'(Nat.lt_of_lt_of_le h (length_take_le' _ _)) := by
rw [length_take, Nat.lt_min] at h; rw [getElem_take' L _ h.1]
theorem getElem?_take_eq_none {l : List α} {i j : Nat} (h : i j) :
(l.take i)[j]? = none :=
@@ -115,12 +114,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]
@@ -149,23 +148,20 @@ theorem take_append {l₁ l₂ : List α} (i : Nat) :
rw [take_append_eq_append_take, take_of_length_le (Nat.le_add_right _ _), Nat.add_sub_cancel_left]
@[simp]
theorem take_eq_take_iff :
theorem take_eq_take :
{l : List α} {i j : Nat}, l.take i = l.take j min i l.length = min j l.length
| [], i, j => by simp [Nat.min_zero]
| _ :: xs, 0, 0 => by simp
| x :: xs, i + 1, 0 => by simp [Nat.zero_min, succ_min_succ]
| x :: xs, 0, j + 1 => by simp [Nat.zero_min, succ_min_succ]
| x :: xs, i + 1, j + 1 => by simp [succ_min_succ, take_eq_take_iff]
@[deprecated take_eq_take_iff (since := "2025-02-16")]
abbrev take_eq_take := @take_eq_take_iff
| x :: xs, i + 1, j + 1 => by simp [succ_min_succ, take_eq_take]
theorem take_add (l : List α) (i j : Nat) : l.take (i + j) = l.take i ++ (l.drop i).take j := by
suffices take (i + j) (take i l ++ drop i l) = take i l ++ take j (drop i l) by
rw [take_append_drop] at this
assumption
rw [take_append_eq_append_take, take_of_length_le, append_right_inj]
· simp only [take_eq_take_iff, length_take, length_drop]
· simp only [take_eq_take, length_take, length_drop]
omega
apply Nat.le_trans (m := i)
· apply length_take_le
@@ -213,31 +209,31 @@ theorem take_subset_take_left (l : List α) {i j : Nat} (h : i ≤ j) : take i l
/-! ### drop -/
theorem lt_length_drop (xs : List α) {i j : Nat} (h : i + j < xs.length) : j < (xs.drop i).length := by
have A : i < xs.length := Nat.lt_of_le_of_lt (Nat.le.intro rfl) h
rw [(take_append_drop i xs).symm] at h
theorem lt_length_drop (L : List α) {i j : Nat} (h : i + j < L.length) : j < (L.drop i).length := by
have A : i < L.length := Nat.lt_of_le_of_lt (Nat.le.intro rfl) h
rw [(take_append_drop i L).symm] at h
simpa only [Nat.le_of_lt A, Nat.min_eq_left, Nat.add_lt_add_iff_left, length_take,
length_append] using h
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
dropping the first `i` elements. Version designed to rewrite from the big list to the small list. -/
theorem getElem_drop' (xs : List α) {i j : Nat} (h : i + j < xs.length) :
xs[i + j] = (xs.drop i)[j]'(lt_length_drop xs h) := by
have : i xs.length := Nat.le_trans (Nat.le_add_right _ _) (Nat.le_of_lt h)
rw [getElem_of_eq (take_append_drop i xs).symm h, getElem_append_right]
theorem getElem_drop' (L : List α) {i j : Nat} (h : i + j < L.length) :
L[i + j] = (L.drop i)[j]'(lt_length_drop L h) := by
have : i L.length := Nat.le_trans (Nat.le_add_right _ _) (Nat.le_of_lt h)
rw [getElem_of_eq (take_append_drop i L).symm h, getElem_append_right]
· simp [Nat.min_eq_left this, Nat.add_sub_cancel_left]
· simp [Nat.min_eq_left this, Nat.le_add_right]
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
dropping the first `i` elements. Version designed to rewrite from the small list to the big list. -/
@[simp] theorem getElem_drop (xs : List α) {i : Nat} {j : Nat} {h : j < (xs.drop i).length} :
(xs.drop i)[j] = xs[i + j]'(by
@[simp] theorem getElem_drop (L : List α) {i : Nat} {j : Nat} {h : j < (L.drop i).length} :
(L.drop i)[j] = L[i + j]'(by
rw [Nat.add_comm]
exact Nat.add_lt_of_lt_sub (length_drop i xs h)) := by
exact Nat.add_lt_of_lt_sub (length_drop i L h)) := by
rw [getElem_drop']
@[simp]
theorem getElem?_drop (xs : List α) (i j : Nat) : (xs.drop i)[j]? = xs[i + j]? := by
theorem getElem?_drop (L : List α) (i j : Nat) : (L.drop i)[j]? = L[i + j]? := by
ext
simp only [getElem?_eq_some_iff, getElem_drop, Option.mem_def]
constructor <;> intro h, ha
@@ -354,6 +350,11 @@ theorem set_eq_take_append_cons_drop (l : List α) (i : Nat) (a : α) :
· rw [set_eq_of_length_le]
omega
theorem exists_of_set {i : Nat} {a' : α} {l : List α} (h : i < l.length) :
l₁ l₂, l = l₁ ++ l[i] :: l₂ l₁.length = i l.set i a' = l₁ ++ a' :: l₂ := by
refine l.take i, l.drop (i + 1), by simp, length_take_of_le (Nat.le_of_lt h), ?_
simp [set_eq_take_append_cons_drop, h]
theorem drop_set_of_lt (a : α) {i j : Nat} (l : List α)
(hnm : i < j) : drop j (l.set i a) = l.drop j :=
ext_getElem? fun k => by simpa only [getElem?_drop] using getElem?_set_ne (by omega)
@@ -376,18 +377,18 @@ theorem take_reverse {α} {xs : List α} {i : Nat} :
by_cases h : i xs.length
· induction xs generalizing i <;>
simp only [reverse_cons, drop, reverse_nil, Nat.zero_sub, length, take_nil]
next hd tl xs_ih =>
next xs_hd xs_tl xs_ih =>
cases Nat.lt_or_eq_of_le h with
| inl h' =>
have h' := Nat.le_of_succ_le_succ h'
rw [take_append_of_le_length, xs_ih h']
rw [show tl.length + 1 - i = succ (tl.length - i) from _, drop]
rw [show xs_tl.length + 1 - i = succ (xs_tl.length - i) from _, drop]
· rwa [succ_eq_add_one, Nat.sub_add_comm]
· rwa [length_reverse]
| inr h' =>
subst h'
rw [length, Nat.sub_self, drop]
suffices tl.length + 1 = (tl.reverse ++ [hd]).length by
suffices xs_tl.length + 1 = (xs_tl.reverse ++ [xs_hd]).length by
rw [this, take_length, reverse_cons]
rw [length_append, length_reverse]
rfl
@@ -473,16 +474,6 @@ theorem false_of_mem_take_findIdx {xs : List α} {p : α → Bool} (h : x ∈ xs
· simp
· rw [Nat.add_min_add_right]
@[simp] theorem min_findIdx_findIdx {xs : List α} {p q : α Bool} :
min (xs.findIdx p) (xs.findIdx q) = xs.findIdx (fun a => p a || q a) := by
induction xs with
| nil => simp
| cons x xs ih =>
simp [findIdx_cons, cond_eq_if, Bool.not_eq_eq_eq_not, Bool.not_true]
split <;> split <;> simp_all [Nat.add_min_add_right]
/-! ### findIdx? -/
@[simp] theorem findIdx?_take {xs : List α} {i : Nat} {p : α Bool} :
(xs.take i).findIdx? p = (xs.findIdx? p).bind (Option.guard (fun j => j < i)) := by
induction xs generalizing i with
@@ -495,6 +486,14 @@ theorem false_of_mem_take_findIdx {xs : List α} {p : α → Bool} (h : x ∈ xs
· simp
· simp [ih, Option.guard_comp, Option.bind_map]
@[simp] theorem min_findIdx_findIdx {xs : List α} {p q : α Bool} :
min (xs.findIdx p) (xs.findIdx q) = xs.findIdx (fun a => p a || q a) := by
induction xs with
| nil => simp
| cons x xs ih =>
simp [findIdx_cons, cond_eq_if, Bool.not_eq_eq_eq_not, Bool.not_true]
split <;> split <;> simp_all [Nat.add_min_add_right]
/-! ### takeWhile -/
theorem takeWhile_eq_take_findIdx_not {xs : List α} {p : α Bool} :

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
@@ -49,7 +49,7 @@ macro_rules
match i, skip with
| 0, _ => pure result
| i+1, true => expandListLit i false result
| i+1, false => expandListLit i true ( ``(List.cons $(elems.elemsAndSeps.get!Internal i) $result))
| i+1, false => expandListLit i true ( ``(List.cons $(elems.elemsAndSeps.get! i) $result))
let size := elems.elemsAndSeps.size
if size < 64 then
expandListLit size (size % 2 == 0) ( ``(List.nil))

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
@@ -209,15 +209,15 @@ theorem getLast?_range (n : Nat) : (range n).getLast? = if n = 0 then none else
@[simp] theorem getLast_range (n : Nat) (h) : (range n).getLast h = n - 1 := by
cases n with
| zero => simp at h
| succ n => simp [getLast?_range, getLast_eq_iff_getLast?_eq_some]
| succ n => simp [getLast?_range, getLast_eq_iff_getLast_eq_some]
/-! ### zipIdx -/
@[simp]
theorem zipIdx_eq_nil_iff {l : List α} {i : Nat} : List.zipIdx l i = [] l = [] := by
theorem zipIdx_eq_nil_iff {l : List α} {n : Nat} : List.zipIdx l n = [] l = [] := by
cases l <;> simp
@[simp] theorem length_zipIdx : {l : List α} {i}, (zipIdx l i).length = l.length
@[simp] theorem length_zipIdx : {l : List α} {n}, (zipIdx l n).length = l.length
| [], _ => rfl
| _ :: _, _ => congrArg Nat.succ length_zipIdx
@@ -231,16 +231,16 @@ theorem getElem?_zipIdx :
exact (getElem?_zipIdx l (n + 1) m).trans <| by rw [Nat.add_right_comm]; rfl
@[simp]
theorem getElem_zipIdx (l : List α) (j) (i : Nat) (h : i < (l.zipIdx j).length) :
(l.zipIdx j)[i] = (l[i]'(by simpa [length_zipIdx] using h), j + i) := by
theorem getElem_zipIdx (l : List α) (n) (i : Nat) (h : i < (l.zipIdx n).length) :
(l.zipIdx n)[i] = (l[i]'(by simpa [length_zipIdx] using h), n + i) := by
simp only [length_zipIdx] at h
rw [getElem_eq_getElem?_get]
simp only [getElem?_zipIdx, getElem?_eq_getElem h]
simp
@[simp]
theorem tail_zipIdx (l : List α) (i : Nat) : (zipIdx l i).tail = zipIdx l.tail (i + 1) := by
induction l generalizing i with
theorem tail_zipIdx (l : List α) (n : Nat) : (zipIdx l n).tail = zipIdx l.tail (n + 1) := by
induction l generalizing n with
| nil => simp
| cons _ l ih => simp [ih, zipIdx_cons]
@@ -248,44 +248,44 @@ theorem map_snd_add_zipIdx_eq_zipIdx (l : List α) (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
theorem zipIdx_cons' (i : Nat) (x : α) (xs : List α) :
zipIdx (x :: xs) i = (x, i) :: (zipIdx xs i).map (Prod.map id (· + 1)) := by
theorem zipIdx_cons' (n : Nat) (x : α) (xs : List α) :
zipIdx (x :: xs) n = (x, n) :: (zipIdx xs n).map (Prod.map id (· + 1)) := by
rw [zipIdx_cons, Nat.add_comm, map_snd_add_zipIdx_eq_zipIdx]
@[simp]
theorem zipIdx_map_snd (i) :
(l : List α), map Prod.snd (zipIdx l i) = range' i l.length
theorem zipIdx_map_snd (n) :
(l : List α), map Prod.snd (zipIdx l n) = range' n l.length
| [] => rfl
| _ :: _ => congrArg (cons _) (zipIdx_map_snd _ _)
@[simp]
theorem zipIdx_map_fst : (i) (l : List α), map Prod.fst (zipIdx l i) = l
theorem zipIdx_map_fst : (n) (l : List α), map Prod.fst (zipIdx l n) = l
| _, [] => rfl
| _, _ :: _ => congrArg (cons _) (zipIdx_map_fst _ _)
theorem zipIdx_eq_zip_range' (l : List α) {i : Nat} : l.zipIdx i = l.zip (range' i l.length) :=
theorem zipIdx_eq_zip_range' (l : List α) {n : Nat} : l.zipIdx n = l.zip (range' n l.length) :=
zip_of_prod (zipIdx_map_fst _ _) (zipIdx_map_snd _ _)
@[simp]
theorem unzip_zipIdx_eq_prod (l : List α) {i : Nat} :
(l.zipIdx i).unzip = (l, range' i l.length) := by
theorem unzip_zipIdx_eq_prod (l : List α) {n : Nat} :
(l.zipIdx n).unzip = (l, range' n l.length) := by
simp only [zipIdx_eq_zip_range', unzip_zip, length_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 (l : List α) (i : Nat) :
l.zipIdx (i + 1) = (l.zipIdx i).map (fun a, i => (a, i + 1)) := by
induction l generalizing i with
theorem zipIdx_succ (l : List α) (n : Nat) :
l.zipIdx (n + 1) = (l.zipIdx n).map (fun a, i => (a, i + 1)) := by
induction l generalizing n with
| nil => rfl
| cons _ _ ih => simp only [zipIdx_cons, ih (i + 1), map_cons]
| cons _ _ ih => simp only [zipIdx_cons, ih (n + 1), map_cons]
/-- Replace `zipIdx` with a starting index with `zipIdx` starting from 0,
followed by a `map` increasing the indices. -/
theorem zipIdx_eq_map_add (l : List α) (i : Nat) :
l.zipIdx i = l.zipIdx.map (fun a, j => (a, i + j)) := by
induction l generalizing i with
theorem zipIdx_eq_map_add (l : List α) (n : Nat) :
l.zipIdx n = l.zipIdx.map (fun a, i => (a, n + i)) := by
induction l generalizing n with
| nil => rfl
| cons _ _ ih => simp [ih (i+1), zipIdx_succ, Nat.add_assoc, Nat.add_comm 1]
| cons _ _ ih => simp [ih (n+1), zipIdx_succ, Nat.add_assoc, Nat.add_comm 1]
/-! ### enumFrom -/

View File

@@ -14,9 +14,6 @@ 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.
namespace List
/--

View File

@@ -31,9 +31,6 @@ 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.
open List
namespace List.MergeSort.Internal
@@ -79,18 +76,18 @@ def splitRevAt (n : Nat) (l : List α) : List α × List α := go l n [] where
| x :: xs, n+1, acc => go xs n (x :: acc)
| xs, _, acc => (acc, xs)
theorem splitRevAt_go (xs : List α) (i : Nat) (acc : List α) :
splitRevAt.go xs i acc = ((take i xs).reverse ++ acc, drop i xs) := by
induction xs generalizing i acc with
theorem splitRevAt_go (xs : List α) (n : Nat) (acc : List α) :
splitRevAt.go xs n acc = ((take n xs).reverse ++ acc, drop n xs) := by
induction xs generalizing n acc with
| nil => simp [splitRevAt.go]
| cons x xs ih =>
cases i with
cases n with
| zero => simp [splitRevAt.go]
| succ i =>
rw [splitRevAt.go, ih i (x :: acc), take_succ_cons, reverse_cons, drop_succ_cons,
| succ n =>
rw [splitRevAt.go, ih n (x :: acc), take_succ_cons, reverse_cons, drop_succ_cons,
append_assoc, singleton_append]
theorem splitRevAt_eq (i : Nat) (l : List α) : splitRevAt i l = ((l.take i).reverse, l.drop i) := by
theorem splitRevAt_eq (n : Nat) (l : List α) : splitRevAt n l = ((l.take n).reverse, l.drop n) := by
rw [splitRevAt, splitRevAt_go, append_nil]
/--

View File

@@ -21,9 +21,6 @@ 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.
namespace List
/-! ### splitInTwo -/
@@ -421,10 +418,10 @@ then `c` is still a sublist of `mergeSort le l`.
theorem sublist_mergeSort
(trans : (a b c : α), le a b le b c le a c)
(total : (a b : α), le a b || le b a) :
{ys : List α} (_ : ys.Pairwise le) (_ : ys <+ xs),
ys <+ mergeSort xs le
{c : List α} (_ : c.Pairwise le) (_ : c <+ l),
c <+ mergeSort l le
| _, _, .slnil => nil_sublist _
| ys, hc, @Sublist.cons _ _ l a h => by
| c, hc, @Sublist.cons _ _ l a h => by
obtain l₁, l₂, h₁, h₂, - := mergeSort_cons trans total a l
rw [h₁]
have h' := sublist_mergeSort trans total hc h
@@ -463,9 +460,9 @@ theorem map_merge {f : α → β} {r : αα → Bool} {s : β → β → Bo
(hl : a l, b l', r a b = s (f a) (f b)) :
(l.merge l' r).map f = (l.map f).merge (l'.map f) s := by
match l, l' with
| [], _ => simp
| _, [] => simp
| _ :: _, _ :: _ =>
| [], x' => simp
| x, [] => simp
| x :: xs, x' :: xs' =>
simp only [List.forall_mem_cons] at hl
simp only [forall_and] at hl
simp only [List.map, List.cons_merge_cons]

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)
@@ -149,7 +149,7 @@ theorem take_eq_nil_of_eq_nil : ∀ {as : List α} {i}, as = [] → as.take i =
theorem ne_nil_of_take_ne_nil {as : List α} {i : Nat} (h : as.take i []) : as [] :=
mt take_eq_nil_of_eq_nil h
theorem take_set {l : List α} {i j : Nat} {a : α} :
theorem set_take {l : List α} {i j : Nat} {a : α} :
(l.set j a).take i = (l.take i).set j a := by
induction i generalizing l j with
| zero => simp
@@ -158,9 +158,6 @@ theorem take_set {l : List α} {i j : Nat} {a : α} :
| nil => simp
| cons hd tl => cases j <;> simp_all
@[deprecated take_set (since := "2025-02-17")]
abbrev set_take := @take_set
theorem drop_set {l : List α} {i j : Nat} {a : α} :
(l.set j a).drop i = if j < i then l.drop i else (l.drop i).set (j - i) a := by
induction i generalizing l j with

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]
@@ -78,7 +68,7 @@ theorem toArray_cons (a : α) (l : List α) : (a :: l).toArray = #[a] ++ l.toArr
@[simp] theorem toArray_singleton (a : α) : (List.singleton a).toArray = Array.singleton a := rfl
@[simp] theorem back!_toArray [Inhabited α] (l : List α) : l.toArray.back! = l.getLast! := by
simp only [back!, size_toArray, getElem!_toArray, getLast!_eq_getElem!]
simp only [back!, size_toArray, Array.get!_eq_getElem!, getElem!_toArray, getLast!_eq_getElem!]
@[simp] theorem back?_toArray (l : List α) : l.toArray.back? = l.getLast? := by
simp [back?, List.getLast?_eq_getElem?]
@@ -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
@@ -207,7 +182,7 @@ theorem forM_toArray [Monad m] (l : List α) (f : α → m PUnit) :
@[simp] theorem foldl_push {l : List α} {as : Array α} : l.foldl Array.push as = as ++ l.toArray := by
induction l generalizing as <;> simp [*]
@[simp] theorem foldr_push {l : List α} {as : Array α} : l.foldr (fun a bs => push bs a) as = as ++ l.reverse.toArray := by
@[simp] theorem foldr_push {l : List α} {as : Array α} : l.foldr (fun a b => push b a) as = as ++ l.reverse.toArray := by
rw [foldr_eq_foldl_reverse, foldl_push]
@[simp] theorem findSomeM?_toArray [Monad m] [LawfulMonad m] (f : α m (Option β)) (l : List α) :
@@ -485,7 +460,7 @@ theorem zipWithAll_go_toArray (as : List α) (bs : List β) (f : Option α → O
theorem takeWhile_go_succ (p : α Bool) (a : α) (l : List α) (i : Nat) :
takeWhile.go p (a :: l).toArray (i+1) r = takeWhile.go p l.toArray i r := by
rw [takeWhile.go, takeWhile.go]
simp only [size_toArray, length_cons, Nat.add_lt_add_iff_right,
simp only [size_toArray, length_cons, Nat.add_lt_add_iff_right, Array.get_eq_getElem,
getElem_toArray, getElem_cons_succ]
split
rw [takeWhile_go_succ]
@@ -502,7 +477,7 @@ theorem takeWhile_go_toArray (p : α → Bool) (l : List α) (i : Nat) :
simp [takeWhile_go_succ, ih, takeWhile_cons]
split <;> simp
| succ i =>
simp only [size_toArray, length_cons, Nat.add_lt_add_iff_right,
simp only [size_toArray, length_cons, Nat.add_lt_add_iff_right, Array.get_eq_getElem,
getElem_toArray, getElem_cons_succ, drop_succ_cons]
split <;> rename_i h₁
· rw [takeWhile_go_succ, ih]
@@ -514,21 +489,6 @@ theorem takeWhile_go_toArray (p : α → Bool) (l : List α) (i : Nat) :
l.toArray.takeWhile p = (l.takeWhile p).toArray := by
simp [Array.takeWhile, takeWhile_go_toArray]
private theorem popWhile_toArray_aux (p : α Bool) (l : List α) :
l.reverse.toArray.popWhile p = (l.dropWhile p).reverse.toArray := by
induction l with
| nil => simp
| cons a l ih =>
unfold popWhile
simp [ih, dropWhile_cons]
split
· rfl
· simp
@[simp] theorem popWhile_toArray (p : α Bool) (l : List α) :
l.toArray.popWhile p = (l.reverse.dropWhile p).reverse.toArray := by
simp [ popWhile_toArray_aux]
@[simp] theorem setIfInBounds_toArray (l : List α) (i : Nat) (a : α) :
l.toArray.setIfInBounds i a = (l.set i a).toArray := by
apply ext'
@@ -539,8 +499,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 +618,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

@@ -726,48 +726,34 @@ protected theorem pow_add_one (n m : Nat) : n^(m + 1) = n^m * n :=
protected theorem pow_zero (n : Nat) : n^0 = 1 := rfl
theorem pow_le_pow_left {n m : Nat} (h : n m) : (i : Nat), n^i m^i
theorem pow_le_pow_of_le_left {n m : Nat} (h : n m) : (i : Nat), n^i m^i
| 0 => Nat.le_refl _
| succ i => Nat.mul_le_mul (pow_le_pow_left h i) h
| succ i => Nat.mul_le_mul (pow_le_pow_of_le_left h i) h
theorem pow_le_pow_right {n : Nat} (hx : n > 0) {i : Nat} : {j}, i j n^i n^j
theorem pow_le_pow_of_le_right {n : Nat} (hx : n > 0) {i : Nat} : {j}, i j n^i n^j
| 0, h =>
have : i = 0 := eq_zero_of_le_zero h
this.symm Nat.le_refl _
| succ j, h =>
match le_or_eq_of_le_succ h with
| Or.inl h => show n^i n^j * n from
have : n^i * 1 n^j * n := Nat.mul_le_mul (pow_le_pow_right hx h) hx
have : n^i * 1 n^j * n := Nat.mul_le_mul (pow_le_pow_of_le_right hx h) hx
Nat.mul_one (n^i) this
| Or.inr h =>
h.symm Nat.le_refl _
set_option linter.missingDocs false in
@[deprecated Nat.pow_le_pow_left (since := "2025-02-17")]
abbrev pow_le_pow_of_le_left := @pow_le_pow_left
set_option linter.missingDocs false in
@[deprecated Nat.pow_le_pow_right (since := "2025-02-17")]
abbrev pow_le_pow_of_le_right := @pow_le_pow_right
protected theorem pow_pos (h : 0 < a) : 0 < a^n :=
match n with
| 0 => Nat.zero_lt_one
| _ + 1 => Nat.mul_pos (Nat.pow_pos h) h
set_option linter.missingDocs false in
@[deprecated Nat.pow_pos (since := "2025-02-17")]
abbrev pos_pow_of_pos := @Nat.pow_pos
theorem pos_pow_of_pos {n : Nat} (m : Nat) (h : 0 < n) : 0 < n^m :=
pow_le_pow_of_le_right h (Nat.zero_le _)
@[simp] theorem zero_pow_of_pos (n : Nat) (h : 0 < n) : 0 ^ n = 0 := by
cases n with
| zero => cases h
| succ n => simp [Nat.pow_succ]
protected theorem two_pow_pos (w : Nat) : 0 < 2^w := Nat.pow_pos (by decide)
protected theorem two_pow_pos (w : Nat) : 0 < 2^w := Nat.pos_pow_of_pos _ (by decide)
instance {n m : Nat} [NeZero n] : NeZero (n^m) :=
Nat.ne_zero_iff_zero_lt.mpr (Nat.pow_pos (pos_of_neZero _))
Nat.ne_zero_iff_zero_lt.mpr (Nat.pos_pow_of_pos m (pos_of_neZero _))
/-! # min/max -/

View File

@@ -286,7 +286,7 @@ theorem testBit_two_pow_add_gt {i j : Nat} (j_lt_i : j < i) (x : Nat) :
· simp [i_lt_j]
· have x_lt : x < 2^i :=
calc x < 2^j := x_lt_j
_ 2^i := Nat.pow_le_pow_right Nat.zero_lt_two i_ge_j
_ 2^i := Nat.pow_le_pow_of_le_right Nat.zero_lt_two i_ge_j
simp [Nat.testBit_lt_two_pow x_lt]
· generalize y_eq : x - 2^j = y
have x_eq : x = y + 2^j := Nat.eq_add_of_sub_eq x_ge_j y_eq
@@ -490,7 +490,7 @@ theorem and_lt_two_pow (x : Nat) {y n : Nat} (right : y < 2^n) : (x &&& y) < 2^n
have yf : testBit y i = false := by
apply Nat.testBit_lt_two_pow
apply Nat.lt_of_lt_of_le right
exact pow_le_pow_right Nat.zero_lt_two i_ge_n
exact pow_le_pow_of_le_right Nat.zero_lt_two i_ge_n
simp [testBit_and, yf]
@[simp] theorem and_pow_two_sub_one_eq_mod (x n : Nat) : x &&& 2^n - 1 = x % 2^n := by
@@ -695,7 +695,7 @@ theorem mul_add_lt_is_or {b : Nat} (b_lt : b < 2^i) (a : Nat) : 2^i * a + b = 2^
have i_le : i j := Nat.le_of_not_lt j_lt
have b_lt_j :=
calc b < 2 ^ i := b_lt
_ 2 ^ j := Nat.pow_le_pow_right Nat.zero_lt_two i_le
_ 2 ^ j := Nat.pow_le_pow_of_le_right Nat.zero_lt_two i_le
simp [i_le, j_lt, testBit_lt_two_pow, b_lt_j]
/-! ### shiftLeft and shiftRight -/

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