mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-19 11:24:07 +00:00
Compare commits
96 Commits
UIntX.ofIn
...
RArray2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f20f69ef74 | ||
|
|
c8da6a878d | ||
|
|
d981fa0faf | ||
|
|
7b292090ce | ||
|
|
f0033cd15e | ||
|
|
7bbcfdf712 | ||
|
|
130e2d93a5 | ||
|
|
5b16ea98f5 | ||
|
|
acfc9c50d5 | ||
|
|
5af99cc840 | ||
|
|
85f5a81f17 | ||
|
|
a81169bbe4 | ||
|
|
fdc62faa0f | ||
|
|
eaf46dfab1 | ||
|
|
d52b8e3cc1 | ||
|
|
2a5373258f | ||
|
|
d71e9cb96b | ||
|
|
a3a11ffaf9 | ||
|
|
9d57ed83a9 | ||
|
|
7cca594a4a | ||
|
|
eed8a4828b | ||
|
|
4bea52c48e | ||
|
|
5a34ffb9b0 | ||
|
|
020b8834c3 | ||
|
|
7423e570f4 | ||
|
|
b51115dac5 | ||
|
|
46769b64c9 | ||
|
|
7d26c7c4f3 | ||
|
|
dd84829282 | ||
|
|
17d3daca8a | ||
|
|
712bb070f9 | ||
|
|
525fd2697c | ||
|
|
c82159e09b | ||
|
|
c3996aadb8 | ||
|
|
bb2f51a230 | ||
|
|
d5027c1a29 | ||
|
|
bfb02be281 | ||
|
|
0076ba03d4 | ||
|
|
8e9da7a1bc | ||
|
|
ac738a8e81 | ||
|
|
689acab1d3 | ||
|
|
de25524dd6 | ||
|
|
48a9bfb73d | ||
|
|
7c9519e60c | ||
|
|
4e1dbe1ae8 | ||
|
|
a0b63deb04 | ||
|
|
c5e20c980c | ||
|
|
cd5b495573 | ||
|
|
2337b95676 | ||
|
|
973f521c46 | ||
|
|
069456ea9c | ||
|
|
aa2cae8801 | ||
|
|
f513c35742 | ||
|
|
d7cc0fd754 | ||
|
|
5f8847151d | ||
|
|
8bc9c4f154 | ||
|
|
dd7ca772d8 | ||
|
|
85a0232e87 | ||
|
|
8ea6465e6d | ||
|
|
38ed4346c2 | ||
|
|
2657f4e62c | ||
|
|
d4767a08b0 | ||
|
|
f562e72e59 | ||
|
|
5a6d45817d | ||
|
|
264095be7f | ||
|
|
0669a04704 | ||
|
|
5cd352588c | ||
|
|
e9cc776f22 | ||
|
|
e79fef15df | ||
|
|
c672934f11 | ||
|
|
582877d2d3 | ||
|
|
39ce3d14f4 | ||
|
|
32758aa712 | ||
|
|
0f6e35dc63 | ||
|
|
2528188dde | ||
|
|
1cdadfd47a | ||
|
|
e07c59c831 | ||
|
|
cbd38ceadd | ||
|
|
c46f1e941c | ||
|
|
cf3b257ccd | ||
|
|
09ab15dc6d | ||
|
|
e631efd817 | ||
|
|
d2f4ce0158 | ||
|
|
69536808ca | ||
|
|
3d5dd15de4 | ||
|
|
91c245663b | ||
|
|
1421b6145e | ||
|
|
bffa642ad6 | ||
|
|
deef1c2739 | ||
|
|
acf42bd30b | ||
|
|
4947215325 | ||
|
|
6e7209dfa3 | ||
|
|
97a00b3881 | ||
|
|
d758b4c862 | ||
|
|
61d7716ad8 | ||
|
|
05f16ed279 |
2
.github/workflows/build-template.yml
vendored
2
.github/workflows/build-template.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_COMPRESS: true
|
||||
# current cache limit
|
||||
CCACHE_MAXSIZE: 600M
|
||||
CCACHE_MAXSIZE: 400M
|
||||
# squelch error message about missing nixpkgs channel
|
||||
NIX_BUILD_SHELL: bash
|
||||
LSAN_OPTIONS: max_leaks=10
|
||||
|
||||
23
.github/workflows/ci.yml
vendored
23
.github/workflows/ci.yml
vendored
@@ -256,17 +256,18 @@ jobs:
|
||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-linux-gnu.tar.zst",
|
||||
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*"
|
||||
},
|
||||
{
|
||||
"name": "Linux 32bit",
|
||||
"os": "ubuntu-latest",
|
||||
// Use 32bit on stage0 and stage1 to keep oleans compatible
|
||||
"CMAKE_OPTIONS": "-DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DLEAN_EXTRA_CXX_FLAGS='-m32' -DLEANC_OPTS='-m32' -DMMAP=OFF -DLEAN_INSTALL_SUFFIX=-linux_x86 -DCMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DSTAGE0_CMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DPKG_CONFIG_EXECUTABLE=/usr/bin/i386-linux-gnu-pkg-config",
|
||||
"cmultilib": true,
|
||||
"release": true,
|
||||
"check-level": 2,
|
||||
"cross": true,
|
||||
"shell": "bash -euxo pipefail {0}"
|
||||
}
|
||||
// Started running out of memory building expensive modules, a 2GB heap is just not that much even before fragmentation
|
||||
//{
|
||||
// "name": "Linux 32bit",
|
||||
// "os": "ubuntu-latest",
|
||||
// // Use 32bit on stage0 and stage1 to keep oleans compatible
|
||||
// "CMAKE_OPTIONS": "-DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DLEAN_EXTRA_CXX_FLAGS='-m32' -DLEANC_OPTS='-m32' -DMMAP=OFF -DLEAN_INSTALL_SUFFIX=-linux_x86 -DCMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DSTAGE0_CMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DPKG_CONFIG_EXECUTABLE=/usr/bin/i386-linux-gnu-pkg-config",
|
||||
// "cmultilib": true,
|
||||
// "release": true,
|
||||
// "check-level": 2,
|
||||
// "cross": true,
|
||||
// "shell": "bash -euxo pipefail {0}"
|
||||
//}
|
||||
// {
|
||||
// "name": "Web Assembly",
|
||||
// "os": "ubuntu-latest",
|
||||
|
||||
@@ -108,6 +108,7 @@ ExternalProject_add(stage2
|
||||
INSTALL_COMMAND ""
|
||||
DEPENDS stage1
|
||||
EXCLUDE_FROM_ALL ON
|
||||
STEP_TARGETS configure
|
||||
)
|
||||
ExternalProject_add(stage3
|
||||
SOURCE_DIR "${LEAN_SOURCE_DIR}"
|
||||
|
||||
@@ -780,12 +780,11 @@ add_custom_target(clean-olean
|
||||
DEPENDS clean-stdlib)
|
||||
|
||||
install(DIRECTORY "${CMAKE_BINARY_DIR}/lib/" DESTINATION lib
|
||||
PATTERN temp
|
||||
PATTERN "*.export"
|
||||
PATTERN "*.hash"
|
||||
PATTERN "*.trace"
|
||||
PATTERN "*.rsp"
|
||||
EXCLUDE)
|
||||
PATTERN temp EXCLUDE
|
||||
PATTERN "*.export" EXCLUDE
|
||||
PATTERN "*.hash" EXCLUDE
|
||||
PATTERN "*.trace" EXCLUDE
|
||||
PATTERN "*.rsp" EXCLUDE)
|
||||
|
||||
# symlink source into expected installation location for go-to-definition, if file system allows it
|
||||
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/src)
|
||||
|
||||
@@ -59,6 +59,9 @@ instance : Monad (OptionT m) where
|
||||
pure := OptionT.pure
|
||||
bind := OptionT.bind
|
||||
|
||||
instance {m : Type u → Type v} [Pure m] : Inhabited (OptionT m α) where
|
||||
default := pure (f:=m) default
|
||||
|
||||
/--
|
||||
Recovers from failures. Typically used via the `<|>` operator.
|
||||
-/
|
||||
|
||||
@@ -738,6 +738,20 @@ Unlike `x ≠ y` (which is notation for `Ne x y`), this is `Bool` valued instead
|
||||
|
||||
recommended_spelling "bne" for "!=" in [bne, «term_!=_»]
|
||||
|
||||
/-- `ReflBEq α` says that the `BEq` implementation is reflexive. -/
|
||||
class ReflBEq (α) [BEq α] : Prop where
|
||||
/-- `==` is reflexive, that is, `(a == a) = true`. -/
|
||||
protected rfl {a : α} : a == a
|
||||
|
||||
@[simp] theorem BEq.rfl [BEq α] [ReflBEq α] {a : α} : a == a := ReflBEq.rfl
|
||||
theorem BEq.refl [BEq α] [ReflBEq α] (a : α) : a == a := BEq.rfl
|
||||
|
||||
theorem beq_of_eq [BEq α] [ReflBEq α] {a b : α} : a = b → a == b
|
||||
| rfl => BEq.rfl
|
||||
|
||||
theorem not_eq_of_beq_eq_false [BEq α] [ReflBEq α] {a b : α} (h : (a == b) = false) : ¬a = b := by
|
||||
intro h'; subst h'; have : true = false := BEq.rfl.symm.trans h; contradiction
|
||||
|
||||
/--
|
||||
A Boolean equality test coincides with propositional equality.
|
||||
|
||||
@@ -745,11 +759,9 @@ In other words:
|
||||
* `a == b` implies `a = b`.
|
||||
* `a == a` is true.
|
||||
-/
|
||||
class LawfulBEq (α : Type u) [BEq α] : Prop where
|
||||
class LawfulBEq (α : Type u) [BEq α] : Prop extends ReflBEq α where
|
||||
/-- If `a == b` evaluates to `true`, then `a` and `b` are equal in the logic. -/
|
||||
eq_of_beq : {a b : α} → a == b → a = b
|
||||
/-- `==` is reflexive, that is, `(a == a) = true`. -/
|
||||
protected rfl : {a : α} → a == a
|
||||
|
||||
export LawfulBEq (eq_of_beq)
|
||||
|
||||
@@ -761,6 +773,15 @@ instance [DecidableEq α] : LawfulBEq α where
|
||||
eq_of_beq := of_decide_eq_true
|
||||
rfl := of_decide_eq_self_eq_true _
|
||||
|
||||
/--
|
||||
Non-instance for `DecidableEq` from `LawfulBEq`.
|
||||
To use this, add `attribute [local instance 5] instDecidableEqOfLawfulBEq` at the top of a file.
|
||||
-/
|
||||
def instDecidableEqOfLawfulBEq [BEq α] [LawfulBEq α] : DecidableEq α := fun x y =>
|
||||
match h : x == y with
|
||||
| false => .isFalse (not_eq_of_beq_eq_false h)
|
||||
| true => .isTrue (eq_of_beq h)
|
||||
|
||||
instance : LawfulBEq Char := inferInstance
|
||||
|
||||
instance : LawfulBEq String := inferInstance
|
||||
@@ -855,8 +876,8 @@ theorem Bool.of_not_eq_false : {b : Bool} → ¬ (b = false) → b = true
|
||||
| true, _ => rfl
|
||||
| false, h => absurd rfl h
|
||||
|
||||
theorem ne_of_beq_false [BEq α] [LawfulBEq α] {a b : α} (h : (a == b) = false) : a ≠ b := by
|
||||
intro h'; subst h'; have : true = false := Eq.trans LawfulBEq.rfl.symm h; contradiction
|
||||
theorem ne_of_beq_false [BEq α] [ReflBEq α] {a b : α} (h : (a == b) = false) : a ≠ b :=
|
||||
not_eq_of_beq_eq_false h
|
||||
|
||||
theorem beq_false_of_ne [BEq α] [LawfulBEq α] {a b : α} (h : a ≠ b) : (a == b) = false :=
|
||||
have : ¬ (a == b) = true := by
|
||||
@@ -1296,6 +1317,15 @@ theorem eta (a : {x // p x}) (h : p (val a)) : mk (val a) h = a := by
|
||||
cases a
|
||||
exact rfl
|
||||
|
||||
instance {α : Type u} {p : α → Prop} [BEq α] : BEq {x : α // p x} :=
|
||||
⟨fun x y => x.1 == y.1⟩
|
||||
|
||||
instance {α : Type u} {p : α → Prop} [BEq α] [ReflBEq α] : ReflBEq {x : α // p x} where
|
||||
rfl {x} := BEq.refl x.1
|
||||
|
||||
instance {α : Type u} {p : α → Prop} [BEq α] [LawfulBEq α] : LawfulBEq {x : α // p x} where
|
||||
eq_of_beq h := Subtype.eq (eq_of_beq h)
|
||||
|
||||
instance {α : Type u} {p : α → Prop} [DecidableEq α] : DecidableEq {x : α // p x} :=
|
||||
fun ⟨a, h₁⟩ ⟨b, h₂⟩ =>
|
||||
if h : a = b then isTrue (by subst h; exact rfl)
|
||||
@@ -1564,7 +1594,7 @@ theorem Nat.succ.injEq (u v : Nat) : (u.succ = v.succ) = (u = v) :=
|
||||
Eq.propIntro Nat.succ.inj (congrArg Nat.succ)
|
||||
|
||||
@[simp] theorem beq_iff_eq [BEq α] [LawfulBEq α] {a b : α} : a == b ↔ a = b :=
|
||||
⟨eq_of_beq, by intro h; subst h; exact LawfulBEq.rfl⟩
|
||||
⟨eq_of_beq, beq_of_eq⟩
|
||||
|
||||
/-! # Prop lemmas -/
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ import Init.Data.Stream
|
||||
import Init.Data.Prod
|
||||
import Init.Data.AC
|
||||
import Init.Data.Queue
|
||||
import Init.Data.Channel
|
||||
import Init.Data.Sum
|
||||
import Init.Data.BEq
|
||||
import Init.Data.Subtype
|
||||
|
||||
@@ -525,7 +525,7 @@ theorem countP_attachWith {p : α → Prop} {q : α → Bool} {xs : Array α} {H
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem count_attach [DecidableEq α] {xs : Array α} {a : {x // x ∈ xs}} :
|
||||
theorem count_attach [BEq α] {xs : Array α} {a : {x // x ∈ xs}} :
|
||||
xs.attach.count a = xs.count ↑a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.count_toArray]
|
||||
@@ -534,7 +534,7 @@ theorem count_attach [DecidableEq α] {xs : Array α} {a : {x // x ∈ xs}} :
|
||||
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}} :
|
||||
theorem count_attachWith [BEq α] {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
|
||||
simp
|
||||
|
||||
@@ -257,8 +257,8 @@ theorem filter_beq {xs : Array α} (a : α) : xs.filter (· == a) = replicate (c
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.filter_beq]
|
||||
|
||||
theorem filter_eq {α} [DecidableEq α] {xs : Array α} (a : α) : xs.filter (· = a) = replicate (count a xs) a :=
|
||||
filter_beq a
|
||||
theorem filter_eq {α} [BEq α] [LawfulBEq α] [DecidableEq α] {xs : Array α} (a : α) : xs.filter (· = a) = replicate (count a xs) a :=
|
||||
funext (Bool.beq_eq_decide_eq · a) ▸ filter_beq a
|
||||
|
||||
theorem replicate_count_eq_of_count_eq_size {xs : Array α} (h : count a xs = xs.size) :
|
||||
replicate (count a xs) a = xs := by
|
||||
@@ -273,7 +273,7 @@ abbrev mkArray_count_eq_of_count_eq_size := @replicate_count_eq_of_count_eq_size
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.count_filter, h]
|
||||
|
||||
theorem count_le_count_map [DecidableEq β] {xs : Array α} {f : α → β} {x : α} :
|
||||
theorem count_le_count_map [BEq β] [LawfulBEq β] {xs : Array α} {f : α → β} {x : α} :
|
||||
count x xs ≤ count (f x) (map f xs) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.count_le_count_map, countP_map]
|
||||
@@ -288,15 +288,25 @@ theorem count_flatMap {α} [BEq β] {xs : Array α} {f : α → Array β} {x :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.count_flatMap, countP_flatMap, Function.comp_def]
|
||||
|
||||
-- FIXME these theorems can be restored once `List.erase` and `Array.erase` have been related.
|
||||
theorem countP_replace {a b : α} {xs : Array α} {p : α → Bool} :
|
||||
(xs.replace a b).countP p =
|
||||
if xs.contains a then xs.countP p + (if p b then 1 else 0) - (if p a then 1 else 0) else xs.countP p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.countP_replace]
|
||||
|
||||
-- theorem count_erase (a b : α) (l : Array α) : count a (l.erase b) = count a l - if b == a then 1 else 0 := by
|
||||
-- sorry
|
||||
theorem count_replace {a b c : α} {xs : Array α} :
|
||||
(xs.replace a b).count c =
|
||||
if xs.contains a then xs.count c + (if b == c then 1 else 0) - (if a == c then 1 else 0) else xs.count c := by
|
||||
simp [count_eq_countP, countP_replace]
|
||||
|
||||
-- @[simp] theorem count_erase_self (a : α) (l : Array α) :
|
||||
-- count a (l.erase a) = count a l - 1 := by rw [count_erase, if_pos (by simp)]
|
||||
theorem count_erase (a b : α) (xs : Array α) : count a (xs.erase b) = count a xs - if b == a then 1 else 0 := by
|
||||
rcases xs with ⟨l⟩
|
||||
simp [List.count_erase]
|
||||
|
||||
-- @[simp] theorem count_erase_of_ne (ab : a ≠ b) (l : Array α) : count a (l.erase b) = count a l := by
|
||||
-- rw [count_erase, if_neg (by simpa using ab.symm), Nat.sub_zero]
|
||||
@[simp] theorem count_erase_self (a : α) (xs : Array α) :
|
||||
count a (xs.erase a) = count a xs - 1 := by rw [count_erase, if_pos (by simp)]
|
||||
|
||||
@[simp] theorem count_erase_of_ne (ab : a ≠ b) (xs : Array α) : count a (xs.erase b) = count a xs := by
|
||||
rw [count_erase, if_neg (by simpa using ab.symm), Nat.sub_zero]
|
||||
|
||||
end count
|
||||
|
||||
@@ -114,8 +114,10 @@ end List
|
||||
|
||||
namespace Array
|
||||
|
||||
instance [BEq α] [LawfulBEq α] : LawfulBEq (Array α) where
|
||||
instance [BEq α] [ReflBEq α] : ReflBEq (Array α) where
|
||||
rfl := by simp [BEq.beq, isEqv_self_beq]
|
||||
|
||||
instance [BEq α] [LawfulBEq α] : LawfulBEq (Array α) where
|
||||
eq_of_beq := by
|
||||
rintro ⟨_⟩ ⟨_⟩ h
|
||||
simpa using h
|
||||
|
||||
@@ -59,7 +59,7 @@ theorem exists_or_eq_self_of_eraseP (p) (xs : Array α) :
|
||||
@[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
|
||||
rw [e₂]; simp [size_append, e₁]; omega
|
||||
rw [e₂]; simp [size_append, e₁]
|
||||
|
||||
theorem size_eraseP {xs : Array α} : (xs.eraseP p).size = if xs.any p then xs.size - 1 else xs.size := by
|
||||
split <;> rename_i h
|
||||
|
||||
@@ -446,11 +446,13 @@ theorem findIdx?_eq_none_iff {xs : Array α} {p : α → Bool} :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem findIdx?_isSome {xs : Array α} {p : α → Bool} :
|
||||
(xs.findIdx? p).isSome = xs.any p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.findIdx?_isSome]
|
||||
|
||||
@[simp]
|
||||
theorem findIdx?_isNone {xs : Array α} {p : α → Bool} :
|
||||
(xs.findIdx? p).isNone = xs.all (¬p ·) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -591,6 +593,18 @@ theorem findFinIdx?_eq_some_iff {xs : Array α} {p : α → Bool} {i : Fin xs.si
|
||||
· rintro ⟨h, w⟩
|
||||
exact ⟨i, ⟨i.2, h, fun j hji => w ⟨j, by omega⟩ hji⟩, rfl⟩
|
||||
|
||||
@[simp]
|
||||
theorem isSome_findFinIdx? {xs : Array α} {p : α → Bool} :
|
||||
(xs.findFinIdx? p).isSome = xs.any p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem isNone_findFinIdx? {xs : Array α} {p : α → Bool} :
|
||||
(xs.findFinIdx? p).isNone = xs.all (fun x => ¬ p x) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[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
|
||||
@@ -636,6 +650,20 @@ The lemmas below should be made consistent with those for `findIdx?` (and proved
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.idxOf?_eq_none_iff]
|
||||
|
||||
@[simp]
|
||||
theorem isSome_idxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.idxOf? a).isSome ↔ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem isNone_idxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.idxOf? a).isNone = ¬ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
|
||||
|
||||
/-! ### finIdxOf?
|
||||
|
||||
The verification API for `finIdxOf?` is still incomplete.
|
||||
@@ -658,4 +686,16 @@ theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : Array α} {a : α} :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.finIdxOf?_eq_some_iff]
|
||||
|
||||
@[simp]
|
||||
theorem isSome_finIdxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.finIdxOf? a).isSome ↔ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem isNone_finIdxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.finIdxOf? a).isNone = ¬ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
end Array
|
||||
|
||||
@@ -135,6 +135,9 @@ theorem getElem?_eq_none {xs : Array α} (h : xs.size ≤ i) : xs[i]? = none :=
|
||||
theorem getElem?_eq_some_iff {xs : Array α} : xs[i]? = some b ↔ ∃ h : i < xs.size, xs[i] = b := by
|
||||
simp [getElem?_def]
|
||||
|
||||
theorem getElem_of_getElem? {xs : Array α} : xs[i]? = some a → ∃ h : i < xs.size, xs[i] = a :=
|
||||
getElem?_eq_some_iff.mp
|
||||
|
||||
theorem some_eq_getElem?_iff {xs : Array α} : some b = xs[i]? ↔ ∃ h : i < xs.size, xs[i] = b := by
|
||||
rw [eq_comm, getElem?_eq_some_iff]
|
||||
|
||||
@@ -826,9 +829,6 @@ theorem contains_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : Array α}
|
||||
@[deprecated contains_eq_true_of_mem (since := "2024-12-12")]
|
||||
abbrev elem_eq_true_of_mem := @contains_eq_true_of_mem
|
||||
|
||||
instance [BEq α] [LawfulBEq α] (a : α) (as : Array α) : Decidable (a ∈ as) :=
|
||||
decidable_of_decidable_of_iff (Iff.intro mem_of_contains_eq_true contains_eq_true_of_mem)
|
||||
|
||||
@[simp] theorem elem_eq_contains [BEq α] {a : α} {xs : Array α} :
|
||||
elem a xs = xs.contains a := by
|
||||
simp [elem]
|
||||
@@ -839,6 +839,9 @@ theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
xs.contains a = true ↔ a ∈ xs := ⟨mem_of_contains_eq_true, contains_eq_true_of_mem⟩
|
||||
|
||||
instance [BEq α] [LawfulBEq α] (a : α) (as : Array α) : Decidable (a ∈ as) :=
|
||||
decidable_of_decidable_of_iff elem_iff
|
||||
|
||||
theorem elem_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
elem a xs = decide (a ∈ xs) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
|
||||
|
||||
@@ -1091,33 +1094,23 @@ private theorem beq_of_beq_singleton [BEq α] {a b : α} : #[a] == #[b] → a ==
|
||||
apply beq_of_beq_singleton
|
||||
simp
|
||||
· intro h
|
||||
constructor
|
||||
apply Array.isEqv_self_beq
|
||||
infer_instance
|
||||
|
||||
@[simp] theorem lawfulBEq_iff [BEq α] : LawfulBEq (Array α) ↔ LawfulBEq α := by
|
||||
constructor
|
||||
· intro h
|
||||
have : ReflBEq α := reflBEq_iff.mp inferInstance
|
||||
constructor
|
||||
· intro a b h
|
||||
apply singleton_inj.1
|
||||
apply eq_of_beq
|
||||
simpa [instBEq, isEqv, isEqvAux]
|
||||
· intro a
|
||||
apply beq_of_beq_singleton
|
||||
simp
|
||||
intro a b h
|
||||
apply singleton_inj.1
|
||||
apply eq_of_beq
|
||||
simpa [instBEq, isEqv, isEqvAux]
|
||||
· intro h
|
||||
constructor
|
||||
· intro xs ys h
|
||||
obtain ⟨hs, hi⟩ := isEqv_iff_rel.mp h
|
||||
ext i h₁ h₂
|
||||
· exact hs
|
||||
· simpa using hi _ h₁
|
||||
· intro xs
|
||||
apply Array.isEqv_self_beq
|
||||
infer_instance
|
||||
|
||||
/-! ### isEqv -/
|
||||
|
||||
@[simp] theorem isEqv_eq [DecidableEq α] {xs ys : Array α} : xs.isEqv ys (· == ·) = (xs = ys) := by
|
||||
@[simp] theorem isEqv_eq [BEq α] [LawfulBEq α] {xs ys : Array α} : xs.isEqv ys (· == ·) = (xs = ys) := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp
|
||||
@@ -3035,7 +3028,7 @@ theorem foldrM_start_stop {m} [Monad m] {xs : Array α} {f : α → β → m β}
|
||||
simp
|
||||
| succ i ih =>
|
||||
unfold foldrM.fold
|
||||
simp only [beq_iff_eq, Nat.add_right_eq_self, Nat.add_one_ne_zero, ↓reduceIte, Nat.add_eq,
|
||||
simp only [beq_iff_eq, Nat.add_eq_left, Nat.add_one_ne_zero, ↓reduceIte, Nat.add_eq,
|
||||
getElem_extract]
|
||||
congr
|
||||
funext b
|
||||
@@ -3777,14 +3770,8 @@ variable [LawfulBEq α]
|
||||
theorem getElem?_replace {xs : Array α} {i : Nat} :
|
||||
(xs.replace a b)[i]? = if xs[i]? == some a then if a ∈ xs.take i then some a else some b else xs[i]? := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.replace_toArray, List.getElem?_toArray, List.getElem?_replace, beq_iff_eq,
|
||||
take_eq_extract, List.extract_toArray, List.extract_eq_drop_take, Nat.sub_zero, List.drop_zero,
|
||||
mem_toArray]
|
||||
split <;> rename_i h
|
||||
· rw (occs := [2]) [if_pos]
|
||||
simpa using h
|
||||
· rw [if_neg]
|
||||
simpa using h
|
||||
simp only [List.replace_toArray, List.getElem?_toArray, List.getElem?_replace, take_eq_extract,
|
||||
List.extract_toArray, List.extract_eq_drop_take, Nat.sub_zero, List.drop_zero, mem_toArray]
|
||||
|
||||
theorem getElem?_replace_of_ne {xs : Array α} {i : Nat} (h : xs[i]? ≠ some a) :
|
||||
(xs.replace a b)[i]? = xs[i]? := by
|
||||
@@ -4276,11 +4263,9 @@ theorem getElem?_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size]? = some
|
||||
|
||||
/-! ### contains -/
|
||||
|
||||
theorem contains_def [DecidableEq α] {a : α} {xs : Array α} : xs.contains a ↔ a ∈ xs := by
|
||||
rw [mem_def, contains, ← any_toList, List.any_eq_true]; simp [and_comm]
|
||||
|
||||
instance [DecidableEq α] (a : α) (xs : Array α) : Decidable (a ∈ xs) :=
|
||||
decidable_of_iff _ contains_def
|
||||
@[deprecated contains_iff (since := "2025-04-07")]
|
||||
abbrev contains_def [DecidableEq α] {a : α} {xs : Array α} : xs.contains a ↔ a ∈ xs :=
|
||||
contains_iff
|
||||
|
||||
/-! ### isPrefixOf -/
|
||||
|
||||
|
||||
@@ -150,13 +150,13 @@ instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
Std.Total (· ≤ · : Array α → Array α → Prop) where
|
||||
total := Array.le_total
|
||||
|
||||
@[simp] theorem lex_eq_true_iff_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
@[simp] theorem lex_eq_true_iff_lt [BEq α] [LawfulBEq α] [LT α] [DecidableLT α]
|
||||
{xs ys : Array α} : lex xs ys = true ↔ xs < ys := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp
|
||||
|
||||
@[simp] theorem lex_eq_false_iff_ge [DecidableEq α] [LT α] [DecidableLT α]
|
||||
@[simp] theorem lex_eq_false_iff_ge [BEq α] [LawfulBEq α] [LT α] [DecidableLT α]
|
||||
{xs ys : Array α} : lex xs ys = false ↔ ys ≤ xs := by
|
||||
cases xs
|
||||
cases ys
|
||||
|
||||
@@ -34,7 +34,7 @@ theorem perm_iff_toList_perm {as bs : Array α} : as ~ bs ↔ as.toList ~ bs.toL
|
||||
cases xs
|
||||
simp
|
||||
|
||||
protected theorem Perm.rfl {xs : List α} : xs ~ xs := .refl _
|
||||
protected theorem Perm.rfl {xs : Array α} : xs ~ xs := .refl _
|
||||
|
||||
theorem Perm.of_eq {xs ys : Array α} (h : xs = ys) : xs ~ ys := h ▸ .rfl
|
||||
|
||||
@@ -53,6 +53,17 @@ instance : Trans (Perm (α := α)) (Perm (α := α)) (Perm (α := α)) where
|
||||
|
||||
theorem perm_comm {xs ys : Array α} : xs ~ ys ↔ ys ~ xs := ⟨Perm.symm, Perm.symm⟩
|
||||
|
||||
theorem Perm.length_eq {xs ys : Array α} (p : xs ~ ys) : xs.size = ys.size := by
|
||||
cases xs; cases ys
|
||||
simp only [perm_toArray] at p
|
||||
simpa using p.length_eq
|
||||
|
||||
theorem Perm.mem_iff {a : α} {xs ys : Array α} (p : xs ~ ys) : a ∈ xs ↔ a ∈ ys := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp at p
|
||||
simpa using p.mem_iff
|
||||
|
||||
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
|
||||
@@ -65,4 +76,20 @@ theorem swap_perm {xs : Array α} {i j : Nat} (h₁ : i < xs.size) (h₂ : j < x
|
||||
simp only [swap, perm_iff_toList_perm, toList_set]
|
||||
apply set_set_perm
|
||||
|
||||
namespace Perm
|
||||
|
||||
set_option linter.indexVariables false in
|
||||
theorem extract {xs ys : Array α} (h : xs ~ ys) {lo hi : Nat}
|
||||
(wlo : ∀ i, i < lo → xs[i]? = ys[i]?) (whi : ∀ i, hi ≤ i → xs[i]? = ys[i]?) :
|
||||
(xs.extract lo hi) ~ (ys.extract lo hi) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp_all only [perm_toArray, List.getElem?_toArray, List.extract_toArray,
|
||||
List.extract_eq_drop_take]
|
||||
apply List.Perm.take_of_getElem? (w := fun i h => by simpa using whi (lo + i) (by omega))
|
||||
apply List.Perm.drop_of_getElem? (w := wlo)
|
||||
exact h
|
||||
|
||||
end Perm
|
||||
|
||||
end Array
|
||||
|
||||
@@ -19,21 +19,9 @@ class PartialEquivBEq (α) [BEq α] : Prop where
|
||||
/-- Transitivity for `BEq`. If `a == b` and `b == c` then `a == c`. -/
|
||||
trans : (a : α) == b → b == c → a == c
|
||||
|
||||
/-- `ReflBEq α` says that the `BEq` implementation is reflexive. -/
|
||||
class ReflBEq (α) [BEq α] : Prop where
|
||||
/-- Reflexivity for `BEq`. -/
|
||||
refl : (a : α) == a
|
||||
|
||||
/-- `EquivBEq` says that the `BEq` implementation is an equivalence relation. -/
|
||||
class EquivBEq (α) [BEq α] : Prop extends PartialEquivBEq α, ReflBEq α
|
||||
|
||||
@[simp]
|
||||
theorem BEq.refl [BEq α] [ReflBEq α] {a : α} : a == a :=
|
||||
ReflBEq.refl
|
||||
|
||||
theorem beq_of_eq [BEq α] [ReflBEq α] {a b : α} : a = b → a == b
|
||||
| rfl => BEq.refl
|
||||
|
||||
theorem BEq.symm [BEq α] [PartialEquivBEq α] {a b : α} : a == b → b == a :=
|
||||
PartialEquivBEq.symm
|
||||
|
||||
@@ -66,6 +54,5 @@ theorem BEq.neq_of_beq_of_neq [BEq α] [PartialEquivBEq α] {a b c : α} :
|
||||
fun h₁ h₂ => Bool.eq_false_iff.2 fun h₃ => Bool.eq_false_iff.1 h₂ (BEq.trans (BEq.symm h₁) h₃)
|
||||
|
||||
instance (priority := low) [BEq α] [LawfulBEq α] : EquivBEq α where
|
||||
refl := LawfulBEq.rfl
|
||||
symm h := beq_iff_eq.2 <| Eq.symm <| beq_iff_eq.1 h
|
||||
trans hab hbc := beq_iff_eq.2 <| (beq_iff_eq.1 hab).trans <| beq_iff_eq.1 hbc
|
||||
|
||||
@@ -227,6 +227,20 @@ SMT-LIB name: `bvmul`.
|
||||
protected def mul (x y : BitVec n) : BitVec n := BitVec.ofNat n (x.toNat * y.toNat)
|
||||
instance : Mul (BitVec n) := ⟨.mul⟩
|
||||
|
||||
/--
|
||||
Raises a bitvector to a natural number power. Usually accessed via the `^` operator.
|
||||
|
||||
Note that this is currently an inefficient implementation,
|
||||
and should be replaced via an `@[extern]` with a native implementation.
|
||||
See https://github.com/leanprover/lean4/issues/7887.
|
||||
-/
|
||||
protected def pow (x : BitVec n) (y : Nat) : BitVec n :=
|
||||
match y with
|
||||
| 0 => 1
|
||||
| y + 1 => x.pow y * x
|
||||
instance : Pow (BitVec n) Nat where
|
||||
pow x y := x.pow y
|
||||
|
||||
/--
|
||||
Unsigned division of bitvectors using the Lean convention where division by zero returns zero.
|
||||
Usually accessed via the `/` operator.
|
||||
|
||||
@@ -566,7 +566,7 @@ theorem ult_eq_msb_of_msb_neq {x y : BitVec w} (h : x.msb ≠ y.msb) :
|
||||
theorem slt_eq_not_ult_of_msb_neq {x y : BitVec w} (h : x.msb ≠ y.msb) :
|
||||
x.slt y = !x.ult y := by
|
||||
simp only [BitVec.slt, toInt_eq_msb_cond, Bool.eq_not_of_ne h, ult_eq_msb_of_msb_neq h]
|
||||
cases y.msb <;> (simp; omega)
|
||||
cases y.msb <;> (simp [-Int.natCast_pow]; omega)
|
||||
|
||||
theorem slt_eq_ult {x y : BitVec w} :
|
||||
x.slt y = (x.msb != y.msb).xor (x.ult y) := by
|
||||
@@ -1332,7 +1332,7 @@ theorem saddOverflow_eq {w : Nat} (x y : BitVec w) :
|
||||
simp only [← decide_or, msb_eq_toInt, decide_beq_decide, toInt_add, ← decide_not, ← decide_and,
|
||||
decide_eq_decide]
|
||||
rw_mod_cast [Int.bmod_neg_iff (by omega) (by omega)]
|
||||
simp
|
||||
simp only [Nat.add_one_sub_one, ge_iff_le]
|
||||
omega
|
||||
|
||||
theorem usubOverflow_eq {w : Nat} (x y : BitVec w) :
|
||||
@@ -1456,7 +1456,6 @@ theorem udiv_intMin_of_msb_false {x : BitVec w} (h : x.msb = false) :
|
||||
have wpos : 0 < w := by omega
|
||||
have := Nat.two_pow_pos (w-1)
|
||||
simp [toNat_eq, wpos]
|
||||
rw [Nat.div_eq_zero_iff_lt (by omega)]
|
||||
exact toNat_lt_of_msb_false h
|
||||
|
||||
theorem sdiv_intMin {x : BitVec w} :
|
||||
@@ -1571,7 +1570,8 @@ theorem intMin_udiv_eq_intMin_iff (x : BitVec w) :
|
||||
· intro h
|
||||
rw [← toInt_inj, toInt_eq_msb_cond] at h
|
||||
have : (intMin w / x).msb = false := by simp [msb_udiv, msb_intMin, wpos, hx]
|
||||
simp [this, wpos, toInt_intMin] at h
|
||||
simp only [this, false_eq_true, ↓reduceIte, toNat_udiv, toNat_intMin, wpos,
|
||||
Nat.two_pow_pred_mod_two_pow, Int.natCast_ediv, toInt_intMin] at h
|
||||
omega
|
||||
· intro h
|
||||
subst h
|
||||
@@ -1612,11 +1612,11 @@ theorem toInt_sdiv_of_ne_or_ne (a b : BitVec w) (h : a ≠ intMin w ∨ b ≠ -1
|
||||
Nat.two_pow_pred_mod_two_pow, Int.neg_tdiv, Int.neg_neg]
|
||||
rw [Int.tdiv_self (by omega)]
|
||||
· by_cases ha_nonneg : 0 ≤ a.toInt
|
||||
· simp [Int.tdiv_eq_zero_of_lt ha_nonneg (by norm_cast at *), ha_intMin]
|
||||
· simp [Int.tdiv_eq_zero_of_lt ha_nonneg (by norm_cast at *), ha_intMin, -Int.natCast_pow]
|
||||
· simp only [ne_eq, ← toInt_inj, toInt_intMin, wpos, Nat.two_pow_pred_mod_two_pow] at h
|
||||
rw [← Int.neg_tdiv, Int.tdiv_eq_zero_of_lt (by omega)]
|
||||
· simp [ha_intMin]
|
||||
· simp [wpos, ← toInt_ne, toInt_intMin] at ha_intMin
|
||||
· simp [wpos, ← toInt_ne, toInt_intMin, -Int.natCast_pow] at ha_intMin
|
||||
omega
|
||||
|
||||
· by_cases ha : a.msb <;> by_cases hb : b.msb
|
||||
|
||||
@@ -68,6 +68,9 @@ theorem getElem?_eq_some_iff {l : BitVec w} : l[n]? = some a ↔ ∃ h : n < w,
|
||||
· simp_all
|
||||
· simp; omega
|
||||
|
||||
theorem getElem_of_getElem? {l : BitVec w} : l[n]? = some a → ∃ h : n < w, l[n] = a :=
|
||||
getElem?_eq_some_iff.mp
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getElem?_eq_some_iff (since := "2025-02-17")]
|
||||
abbrev getElem?_eq_some := @getElem?_eq_some_iff
|
||||
@@ -449,7 +452,7 @@ theorem getLsbD_ofNat (n : Nat) (x : Nat) (i : Nat) :
|
||||
@[simp] theorem sub_add_bmod_cancel {x y : BitVec w} :
|
||||
((((2 ^ w : Nat) - y.toNat) : Int) + x.toNat).bmod (2 ^ w) =
|
||||
((x.toNat : Int) - y.toNat).bmod (2 ^ w) := by
|
||||
rw [Int.sub_eq_add_neg, Int.add_assoc, Int.add_comm, Int.bmod_add_cancel, Int.add_comm,
|
||||
rw [Int.sub_eq_add_neg, Int.add_assoc, Int.add_comm, Int.add_bmod_right, Int.add_comm,
|
||||
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 :=
|
||||
@@ -655,20 +658,19 @@ theorem toInt_ne {x y : BitVec n} : x.toInt ≠ y.toInt ↔ x ≠ y := by
|
||||
unfold BitVec.ofInt
|
||||
simp
|
||||
|
||||
theorem toInt_ofNat {n : Nat} (x : Nat) :
|
||||
(BitVec.ofNat n x).toInt = (x : Int).bmod (2^n) := by
|
||||
simp [toInt_eq_toNat_bmod]
|
||||
theorem toInt_ofNat {n : Nat} (x : Nat) : (BitVec.ofNat n x).toInt = (x : Int).bmod (2^n) := by
|
||||
simp [toInt_eq_toNat_bmod, -Int.natCast_pow]
|
||||
|
||||
@[simp] theorem toInt_ofInt {n : Nat} (i : Int) :
|
||||
(BitVec.ofInt n i).toInt = i.bmod (2^n) := by
|
||||
have _ := Nat.two_pow_pos n
|
||||
have p : 0 ≤ i % (2^n : Nat) := by omega
|
||||
simp [toInt_eq_toNat_bmod, Int.toNat_of_nonneg p]
|
||||
simp [toInt_eq_toNat_bmod, Int.toNat_of_nonneg p, -Int.natCast_pow]
|
||||
|
||||
theorem toInt_ofInt_eq_self {w : Nat} (hw : 0 < w) {n : Int}
|
||||
(h : -2 ^ (w - 1) ≤ n) (h' : n < 2 ^ (w - 1)) : (BitVec.ofInt w n).toInt = n := by
|
||||
have hw : w = (w - 1) + 1 := by omega
|
||||
rw [toInt_ofInt, Int.bmod_eq_self_of_le] <;> (rw [hw]; simp [Int.natCast_pow]; omega)
|
||||
rw [toInt_ofInt, Int.bmod_eq_of_le] <;> (rw [hw]; simp [Int.natCast_pow]; omega)
|
||||
|
||||
@[simp] theorem ofInt_natCast (w n : Nat) :
|
||||
BitVec.ofInt w (n : Int) = BitVec.ofNat w n := rfl
|
||||
@@ -676,16 +678,13 @@ theorem toInt_ofInt_eq_self {w : Nat} (hw : 0 < w) {n : Int}
|
||||
@[simp] theorem ofInt_ofNat (w n : Nat) :
|
||||
BitVec.ofInt w (no_index (OfNat.ofNat n)) = BitVec.ofNat w (OfNat.ofNat n) := rfl
|
||||
|
||||
@[simp] theorem ofInt_toInt {x : BitVec w} : BitVec.ofInt w x.toInt = x := by
|
||||
by_cases h : 2 * x.toNat < 2^w <;> ext <;> simp [←getLsbD_eq_getElem, getLsbD, h, BitVec.toInt]
|
||||
|
||||
theorem toInt_neg_iff {w : Nat} {x : BitVec w} :
|
||||
BitVec.toInt x < 0 ↔ 2 ^ w ≤ 2 * x.toNat := by
|
||||
simp [toInt_eq_toNat_cond]; omega
|
||||
simp only [toInt_eq_toNat_cond]; omega
|
||||
|
||||
theorem toInt_pos_iff {w : Nat} {x : BitVec w} :
|
||||
0 ≤ BitVec.toInt x ↔ 2 * x.toNat < 2 ^ w := by
|
||||
simp [toInt_eq_toNat_cond]; omega
|
||||
simp only [toInt_eq_toNat_cond]; omega
|
||||
|
||||
theorem eq_zero_or_eq_one (a : BitVec 1) : a = 0#1 ∨ a = 1#1 := by
|
||||
obtain ⟨a, ha⟩ := a
|
||||
@@ -777,6 +776,12 @@ theorem le_toInt {w : Nat} (x : BitVec w) : -2 ^ (w - 1) ≤ x.toInt := by
|
||||
rw [(show w = w - 1 + 1 by omega), Int.pow_succ] at this
|
||||
omega
|
||||
|
||||
@[simp] theorem ofInt_toInt {x : BitVec w} : BitVec.ofInt w x.toInt = x := by
|
||||
apply eq_of_toInt_eq
|
||||
rw [toInt_ofInt, Int.bmod_eq_of_le_mul_two]
|
||||
· simpa [Int.mul_comm _ 2] using le_two_mul_toInt
|
||||
· simpa [Int.mul_comm _ 2] using two_mul_toInt_lt
|
||||
|
||||
/-! ### sle/slt -/
|
||||
|
||||
/--
|
||||
@@ -795,7 +800,7 @@ theorem slt_zero_iff_msb_cond {x : BitVec w} : x.slt 0#w ↔ x.msb = true := by
|
||||
omega /- Can't have `x.toInt` which is equal to `x.toNat` be strictly less than zero -/
|
||||
· intros h
|
||||
simp only [h, ↓reduceIte] at this
|
||||
simp [BitVec.slt, this]
|
||||
simp only [BitVec.slt, this, toInt_zero, decide_eq_true_eq]
|
||||
omega
|
||||
|
||||
theorem slt_zero_eq_msb {w : Nat} {x : BitVec w} : x.slt 0#w = x.msb := by
|
||||
@@ -866,7 +871,7 @@ theorem zeroExtend_eq_setWidth {v : Nat} {x : BitVec w} :
|
||||
|
||||
@[simp] theorem toInt_setWidth (x : BitVec w) :
|
||||
(x.setWidth v).toInt = Int.bmod x.toNat (2^v) := by
|
||||
simp [toInt_eq_toNat_bmod, toNat_setWidth, Int.emod_bmod]
|
||||
simp [toInt_eq_toNat_bmod, toNat_setWidth, Int.emod_bmod, -Int.natCast_pow]
|
||||
|
||||
@[simp] theorem toFin_setWidth {x : BitVec w} :
|
||||
(x.setWidth v).toFin = Fin.ofNat' (2^v) x.toNat := by
|
||||
@@ -1059,7 +1064,7 @@ and the second `setWidth` is a non-trivial extension.
|
||||
theorem toInt_setWidth' {m n : Nat} (p : m ≤ n) {x : BitVec m} :
|
||||
(setWidth' p x).toInt = if m = n then x.toInt else x.toNat := by
|
||||
split
|
||||
case isTrue h => simp [h, toInt_eq_toNat_bmod]
|
||||
case isTrue h => simp [h, toInt_eq_toNat_bmod, -Int.natCast_pow]
|
||||
case isFalse h => rw [toInt_setWidth'_of_lt (by omega)]
|
||||
|
||||
@[simp] theorem toFin_setWidth' {m n : Nat} (p : m ≤ n) (x : BitVec m) :
|
||||
@@ -1267,7 +1272,7 @@ theorem extractLsb'_eq_zero {x : BitVec w} {start : Nat} :
|
||||
· subst h
|
||||
simp
|
||||
· have : 1 < 2 ^ w := by simp [h]
|
||||
simp [BitVec.toInt]
|
||||
simp [BitVec.toInt, -Int.natCast_pow]
|
||||
omega
|
||||
|
||||
@[simp] theorem toFin_allOnes : (allOnes w).toFin = Fin.ofNat' (2^w) (2^w - 1) := by
|
||||
@@ -1627,7 +1632,8 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
|
||||
@[simp] theorem toInt_not {x : BitVec w} :
|
||||
(~~~x).toInt = Int.bmod (2^w - 1 - x.toNat) (2^w) := by
|
||||
rw_mod_cast [BitVec.toInt, BitVec.toNat_not, Int.bmod_def]
|
||||
simp [show ((2^w : Nat) : Int) - 1 - x.toNat = ((2^w - 1 - x.toNat) : Nat) by omega]
|
||||
simp [show ((2^w : Nat) : Int) - 1 - x.toNat = ((2^w - 1 - x.toNat) : Nat) by omega,
|
||||
-Int.natCast_pow]
|
||||
rw_mod_cast [Nat.mod_eq_of_lt (by omega)]
|
||||
omega
|
||||
|
||||
@@ -1803,7 +1809,7 @@ theorem not_xor_right {x y : BitVec w} : ~~~ (x ^^^ y) = x ^^^ ~~~ y := by
|
||||
@[simp] theorem toInt_shiftLeft {x : BitVec w} :
|
||||
(x <<< n).toInt = (x.toNat <<< n : Int).bmod (2^w) := by
|
||||
rw [toInt_eq_toNat_bmod, toNat_shiftLeft, Nat.shiftLeft_eq]
|
||||
simp
|
||||
simp [-Int.natCast_pow]
|
||||
|
||||
@[simp] theorem toFin_shiftLeft {n : Nat} (x : BitVec w) :
|
||||
(x <<< n).toFin = Fin.ofNat' (2^w) (x.toNat <<< n) := rfl
|
||||
@@ -2032,7 +2038,6 @@ theorem toInt_ushiftRight_of_lt {x : BitVec w} {n : Nat} (hn : 0 < n) :
|
||||
have : 2^w ≤ 2^n := Nat.pow_le_pow_of_le (by decide) (by omega)
|
||||
omega
|
||||
simp [this] at h
|
||||
omega
|
||||
|
||||
/--
|
||||
Unsigned shift right by at least one bit makes the interpretations of the bitvector as an `Int` or `Nat` agree,
|
||||
@@ -2137,8 +2142,8 @@ theorem sshiftRight_eq_of_msb_true {x : BitVec w} {s : Nat} (h : x.msb = true) :
|
||||
simp only [hxbound, ↓reduceIte, toNat_ofInt, toNat_not, toNat_ushiftRight]
|
||||
rw [← Int.subNatNat_eq_coe, Int.subNatNat_of_lt (by omega),
|
||||
Nat.pred_eq_sub_one, Int.negSucc_shiftRight,
|
||||
Int.emod_negSucc, Int.natAbs_ofNat, Nat.succ_eq_add_one,
|
||||
Int.subNatNat_of_le (by omega), Int.toNat_ofNat, Nat.mod_eq_of_lt,
|
||||
Int.emod_negSucc, Int.natAbs_natCast, Nat.succ_eq_add_one,
|
||||
Int.subNatNat_of_le (by omega), Int.toNat_natCast, Nat.mod_eq_of_lt,
|
||||
Nat.sub_right_comm]
|
||||
omega
|
||||
· rw [Nat.shiftRight_eq_div_pow]
|
||||
@@ -2334,7 +2339,7 @@ theorem toInt_sshiftRight {x : BitVec w} {n : Nat} :
|
||||
have := @toInt_shiftRight_lt w x n
|
||||
have := @le_toInt_shiftRight w x n
|
||||
norm_cast at *
|
||||
exact Int.bmod_eq_self_of_le (by omega) (by omega)
|
||||
exact Int.bmod_eq_of_le (by omega) (by omega)
|
||||
|
||||
/-! ### sshiftRight reductions from BitVec to Nat -/
|
||||
|
||||
@@ -2427,9 +2432,9 @@ theorem signExtend_eq_not_setWidth_not_of_msb_true {x : BitVec w} {v : Nat} (hms
|
||||
toNat_setWidth, hmsb, ↓reduceIte]
|
||||
norm_cast
|
||||
rw [Int.ofNat_sub_ofNat_of_lt, Int.negSucc_emod]
|
||||
simp only [Int.natAbs_ofNat, Nat.succ_eq_add_one]
|
||||
simp only [Int.natAbs_natCast, Nat.succ_eq_add_one]
|
||||
rw [Int.subNatNat_of_le]
|
||||
· rw [Int.toNat_ofNat, Nat.add_comm, Nat.sub_add_eq]
|
||||
· rw [Int.toNat_natCast, Nat.add_comm, Nat.sub_add_eq]
|
||||
· apply Nat.le_trans
|
||||
· apply Nat.succ_le_of_lt
|
||||
apply Nat.mod_lt
|
||||
@@ -2539,7 +2544,7 @@ where
|
||||
simp only [this, toNat_setWidth, Int.natCast_add, Int.ofNat_emod, Int.natCast_mul]
|
||||
by_cases h : x.msb
|
||||
<;> norm_cast
|
||||
<;> simp [h, Nat.mod_eq_of_lt (Nat.lt_of_lt_of_le x.isLt H)]
|
||||
<;> simp [h, Nat.mod_eq_of_lt (Nat.lt_of_lt_of_le x.isLt H), -Int.natCast_pow]
|
||||
omega
|
||||
|
||||
/--
|
||||
@@ -3314,7 +3319,7 @@ theorem setWidth_add (x y : BitVec w) (h : i ≤ w) :
|
||||
|
||||
@[simp, bitvec_to_nat] theorem toInt_add (x y : BitVec w) :
|
||||
(x + y).toInt = (x.toInt + y.toInt).bmod (2^w) := by
|
||||
simp [toInt_eq_toNat_bmod]
|
||||
simp [toInt_eq_toNat_bmod, -Int.natCast_pow]
|
||||
|
||||
theorem ofInt_add {n} (x y : Int) : BitVec.ofInt n (x + y) =
|
||||
BitVec.ofInt n x + BitVec.ofInt n y := by
|
||||
@@ -3344,7 +3349,7 @@ theorem sub_def {n} (x y : BitVec n) : x - y = .ofNat n ((2^n - y.toNat) + x.toN
|
||||
|
||||
@[simp, bitvec_to_nat] theorem toInt_sub {x y : BitVec w} :
|
||||
(x - y).toInt = (x.toInt - y.toInt).bmod (2 ^ w) := by
|
||||
simp [toInt_eq_toNat_bmod, @Int.ofNat_sub y.toNat (2 ^ w) (by omega)]
|
||||
simp [toInt_eq_toNat_bmod, @Int.ofNat_sub y.toNat (2 ^ w) (by omega), -Int.natCast_pow]
|
||||
|
||||
theorem toInt_sub_toInt_lt_twoPow_iff {x y : BitVec w} :
|
||||
(x.toInt - y.toInt < - 2 ^ (w - 1))
|
||||
@@ -3356,7 +3361,7 @@ theorem toInt_sub_toInt_lt_twoPow_iff {x y : BitVec w} :
|
||||
simp only [Nat.add_one_sub_one]
|
||||
constructor
|
||||
· intros h
|
||||
rw_mod_cast [← Int.bmod_add_cancel, Int.bmod_eq_self_of_le]
|
||||
rw_mod_cast [← Int.add_bmod_right, Int.bmod_eq_of_le]
|
||||
<;> omega
|
||||
· have := Int.bmod_neg_iff (x := x.toInt - y.toInt) (m := 2 ^ (w + 1))
|
||||
push_cast at this
|
||||
@@ -3373,7 +3378,7 @@ theorem twoPow_le_toInt_sub_toInt_iff {x y : BitVec w} :
|
||||
constructor
|
||||
· intros h
|
||||
simp only [show 0 ≤ x.toInt by omega, show y.toInt < 0 by omega, _root_.true_and]
|
||||
rw_mod_cast [← Int.bmod_sub_cancel, Int.bmod_eq_self_of_le (by omega) (by omega)]
|
||||
rw_mod_cast [← Int.sub_bmod_right, Int.bmod_eq_of_le (by omega) (by omega)]
|
||||
omega
|
||||
· have := Int.bmod_neg_iff (x := x.toInt - y.toInt) (m := 2 ^ (w + 1))
|
||||
push_cast at this
|
||||
@@ -3653,6 +3658,13 @@ theorem mul_def {n} {x y : BitVec n} : x * y = (ofFin <| x.toFin * y.toFin) := b
|
||||
@[simp, bitvec_to_nat] theorem toNat_mul (x y : BitVec n) : (x * y).toNat = (x.toNat * y.toNat) % 2 ^ n := rfl
|
||||
@[simp] theorem toFin_mul (x y : BitVec n) : (x * y).toFin = (x.toFin * y.toFin) := rfl
|
||||
|
||||
theorem ofNat_mul {n} (x y : Nat) : BitVec.ofNat n (x * y) = BitVec.ofNat n x * BitVec.ofNat n y := by
|
||||
apply eq_of_toNat_eq
|
||||
simp [BitVec.ofNat, Fin.ofNat'_mul]
|
||||
|
||||
theorem ofNat_mul_ofNat {n} (x y : Nat) : BitVec.ofNat n x * BitVec.ofNat n y = BitVec.ofNat n (x * y) :=
|
||||
(ofNat_mul x y).symm
|
||||
|
||||
protected theorem mul_comm (x y : BitVec w) : x * y = y * x := by
|
||||
apply eq_of_toFin_eq; simpa using Fin.mul_comm ..
|
||||
instance : Std.Commutative (fun (x y : BitVec w) => x * y) := ⟨BitVec.mul_comm⟩
|
||||
@@ -3700,7 +3712,7 @@ theorem two_mul {x : BitVec w} : 2#w * x = x + x := by rw [BitVec.mul_comm, mul_
|
||||
|
||||
@[simp, bitvec_to_nat] theorem toInt_mul (x y : BitVec w) :
|
||||
(x * y).toInt = (x.toInt * y.toInt).bmod (2^w) := by
|
||||
simp [toInt_eq_toNat_bmod]
|
||||
simp [toInt_eq_toNat_bmod, -Int.natCast_pow]
|
||||
|
||||
theorem ofInt_mul {n} (x y : Int) : BitVec.ofInt n (x * y) =
|
||||
BitVec.ofInt n x * BitVec.ofInt n y := by
|
||||
@@ -3746,6 +3758,22 @@ theorem setWidth_mul (x y : BitVec w) (h : i ≤ w) :
|
||||
have dvd : 2^i ∣ 2^w := Nat.pow_dvd_pow _ h
|
||||
simp [bitvec_to_nat, h, Nat.mod_mod_of_dvd _ dvd]
|
||||
|
||||
/-! ### pow -/
|
||||
|
||||
@[simp]
|
||||
protected theorem pow_zero {x : BitVec w} : x ^ 0 = 1#w := rfl
|
||||
|
||||
protected theorem pow_succ {x : BitVec w} : x ^ (n + 1) = x ^ n * x := rfl
|
||||
|
||||
@[simp]
|
||||
protected theorem pow_one {x : BitVec w} : x ^ 1 = x := by simp [BitVec.pow_succ]
|
||||
|
||||
protected theorem pow_add {x : BitVec w} {n m : Nat}: x ^ (n + m) = (x ^ n) * (x ^ m):= by
|
||||
induction m with
|
||||
| zero => simp
|
||||
| succ m ih =>
|
||||
rw [← Nat.add_assoc, BitVec.pow_succ, ih, BitVec.mul_assoc, BitVec.pow_succ]
|
||||
|
||||
/-! ### le and lt -/
|
||||
|
||||
@[bitvec_to_nat] theorem le_def {x y : BitVec n} :
|
||||
@@ -3958,7 +3986,6 @@ then `x / y` is nonnegative, thus `toInt` and `toNat` coincide.
|
||||
theorem toInt_udiv_of_msb {x : BitVec w} (h : x.msb = false) (y : BitVec w) :
|
||||
(x / y).toInt = x.toNat / y.toNat := by
|
||||
simp [toInt_eq_msb_cond, msb_udiv_eq_false_of h]
|
||||
norm_cast
|
||||
|
||||
/-! ### umod -/
|
||||
|
||||
@@ -4891,7 +4918,6 @@ theorem intMin_eq_zero_iff {w : Nat} : intMin w = 0#w ↔ w = 0 := by
|
||||
· constructor
|
||||
· have := Nat.two_pow_pos (w - 1)
|
||||
simp [toNat_eq, show 0 < w by omega]
|
||||
omega
|
||||
· simp [h]
|
||||
|
||||
/--
|
||||
@@ -5129,7 +5155,7 @@ theorem two_pow_le_toInt_mul_toInt_iff {x y : BitVec w} :
|
||||
toInt_intMax, Nat.add_one_sub_one]
|
||||
push_cast
|
||||
rw [← Nat.two_pow_pred_add_two_pow_pred (by omega),
|
||||
Int.bmod_eq_self_of_le_mul_two (by rw [← Nat.mul_two]; push_cast; omega)
|
||||
Int.bmod_eq_of_le_mul_two (by rw [← Nat.mul_two]; push_cast; omega)
|
||||
(by rw [← Nat.mul_two]; push_cast; omega)]
|
||||
omega
|
||||
|
||||
@@ -5146,14 +5172,14 @@ theorem toInt_mul_toInt_lt_neg_two_pow_iff {x y : BitVec w} :
|
||||
simp only [toInt_twoPow, show ¬w + 1 ≤ w by omega, ↓reduceIte]
|
||||
push_cast
|
||||
rw [← Nat.two_pow_pred_add_two_pow_pred (by omega),
|
||||
Int.bmod_eq_self_of_le_mul_two (by rw [← Nat.mul_two]; push_cast; omega)
|
||||
Int.bmod_eq_of_le_mul_two (by rw [← Nat.mul_two]; push_cast; omega)
|
||||
(by rw [← Nat.mul_two]; push_cast; omega)]
|
||||
|
||||
/-! ### neg -/
|
||||
|
||||
theorem msb_eq_toInt {x : BitVec w}:
|
||||
x.msb = decide (x.toInt < 0) := by
|
||||
by_cases h : x.msb <;> simp [h, toInt_eq_msb_cond] <;> omega
|
||||
by_cases h : x.msb <;> simp [h, toInt_eq_msb_cond, -Int.natCast_pow] <;> omega
|
||||
|
||||
theorem msb_eq_toNat {x : BitVec w}:
|
||||
x.msb = decide (x.toNat ≥ 2 ^ (w - 1)) := by
|
||||
|
||||
@@ -690,9 +690,5 @@ def boolRelToRel : Coe (α → α → Bool) (α → α → Prop) where
|
||||
|
||||
/-! ### subtypes -/
|
||||
|
||||
@[simp] theorem Subtype.beq_iff {α : Type u} [DecidableEq α] {p : α → Prop} {x y : {a : α // p a}} :
|
||||
(x == y) = (x.1 == y.1) := by
|
||||
cases x
|
||||
cases y
|
||||
rw [Bool.eq_iff_iff]
|
||||
simp [beq_iff_eq]
|
||||
@[simp] theorem Subtype.beq_iff {α : Type u} [BEq α] {p : α → Prop} {x y : {a : α // p a}} :
|
||||
(x == y) = (x.1 == y.1) := rfl
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2022 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Gabriel Ebner
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Queue
|
||||
import Init.System.Promise
|
||||
import Init.System.Mutex
|
||||
|
||||
set_option linter.deprecated false
|
||||
|
||||
namespace IO
|
||||
|
||||
/--
|
||||
Internal state of an `Channel`.
|
||||
|
||||
We maintain the invariant that at all times either `consumers` or `values` is empty.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.State from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
structure Channel.State (α : Type) where
|
||||
values : Std.Queue α := ∅
|
||||
consumers : Std.Queue (Promise (Option α)) := ∅
|
||||
closed := false
|
||||
deriving Inhabited
|
||||
|
||||
/--
|
||||
FIFO channel with unbounded buffer, where `recv?` returns a `Task`.
|
||||
|
||||
A channel can be closed. Once it is closed, all `send`s are ignored, and
|
||||
`recv?` returns `none` once the queue is empty.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel (α : Type) : Type := Mutex (Channel.State α)
|
||||
|
||||
instance : Nonempty (Channel α) :=
|
||||
inferInstanceAs (Nonempty (Mutex _))
|
||||
|
||||
/-- Creates a new `Channel`. -/
|
||||
@[deprecated "Use Std.Channel.new from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.new : BaseIO (Channel α) :=
|
||||
Mutex.new {}
|
||||
|
||||
/--
|
||||
Sends a message on an `Channel`.
|
||||
|
||||
This function does not block.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.send from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.send (ch : Channel α) (v : α) : BaseIO Unit :=
|
||||
ch.atomically do
|
||||
let st ← get
|
||||
if st.closed then return
|
||||
if let some (consumer, consumers) := st.consumers.dequeue? then
|
||||
consumer.resolve (some v)
|
||||
set { st with consumers }
|
||||
else
|
||||
set { st with values := st.values.enqueue v }
|
||||
|
||||
/--
|
||||
Closes an `Channel`.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.close from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.close (ch : Channel α) : BaseIO Unit :=
|
||||
ch.atomically do
|
||||
let st ← get
|
||||
for consumer in st.consumers.toArray do consumer.resolve none
|
||||
set { st with closed := true, consumers := ∅ }
|
||||
|
||||
/--
|
||||
Receives a message, without blocking.
|
||||
The returned task waits for the message.
|
||||
Every message is only received once.
|
||||
|
||||
Returns `none` if the channel is closed and the queue is empty.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.recv? from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.recv? (ch : Channel α) : BaseIO (Task (Option α)) :=
|
||||
ch.atomically do
|
||||
let st ← get
|
||||
if let some (a, values) := st.values.dequeue? then
|
||||
set { st with values }
|
||||
return .pure a
|
||||
else if !st.closed then
|
||||
let promise ← Promise.new
|
||||
set { st with consumers := st.consumers.enqueue promise }
|
||||
return promise.result
|
||||
else
|
||||
return .pure none
|
||||
|
||||
/--
|
||||
`ch.forAsync f` calls `f` for every messages received on `ch`.
|
||||
|
||||
Note that if this function is called twice, each `forAsync` only gets half the messages.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.forAsync from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
partial def Channel.forAsync (f : α → BaseIO Unit) (ch : Channel α)
|
||||
(prio : Task.Priority := .default) : BaseIO (Task Unit) := do
|
||||
BaseIO.bindTask (prio := prio) (← ch.recv?) fun
|
||||
| none => return .pure ()
|
||||
| some v => do f v; ch.forAsync f prio
|
||||
|
||||
/--
|
||||
Receives all currently queued messages from the channel.
|
||||
|
||||
Those messages are dequeued and will not be returned by `recv?`.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.recvAllCurrent from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.recvAllCurrent (ch : Channel α) : BaseIO (Array α) :=
|
||||
ch.atomically do
|
||||
modifyGet fun st => (st.values.toArray, { st with values := ∅ })
|
||||
|
||||
/-- Type tag for synchronous (blocking) operations on a `Channel`. -/
|
||||
@[deprecated "Use Std.Channel.Sync from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.Sync := Channel
|
||||
|
||||
/--
|
||||
Accesses synchronous (blocking) version of channel operations.
|
||||
|
||||
For example, `ch.sync.recv?` blocks until the next message,
|
||||
and `for msg in ch.sync do ...` iterates synchronously over the channel.
|
||||
These functions should only be used in dedicated threads.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.sync from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.sync (ch : Channel α) : Channel.Sync α := ch
|
||||
|
||||
/--
|
||||
Synchronously receives a message from the channel.
|
||||
|
||||
Every message is only received once.
|
||||
Returns `none` if the channel is closed and the queue is empty.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.Sync.recv? from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.Sync.recv? (ch : Channel.Sync α) : BaseIO (Option α) := do
|
||||
IO.wait (← Channel.recv? ch)
|
||||
|
||||
@[deprecated "Use Std.Channel.Sync.forIn from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
private partial def Channel.Sync.forIn [Monad m] [MonadLiftT BaseIO m]
|
||||
(ch : Channel.Sync α) (f : α → β → m (ForInStep β)) : β → m β := fun b => do
|
||||
match ← ch.recv? with
|
||||
| some a =>
|
||||
match ← f a b with
|
||||
| .done b => pure b
|
||||
| .yield b => ch.forIn f b
|
||||
| none => pure b
|
||||
|
||||
/-- `for msg in ch.sync do ...` receives all messages in the channel until it is closed. -/
|
||||
instance [MonadLiftT BaseIO m] : ForIn m (Channel.Sync α) α where
|
||||
forIn ch b f := ch.forIn f b
|
||||
@@ -976,6 +976,16 @@ theorem coe_sub_iff_lt {a b : Fin n} : (↑(a - b) : Nat) = n + a - b ↔ a < b
|
||||
|
||||
/-! ### mul -/
|
||||
|
||||
theorem ofNat'_mul [NeZero n] (x : Nat) (y : Fin n) :
|
||||
Fin.ofNat' n x * y = Fin.ofNat' n (x * y.val) := by
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat', Fin.mul_def]
|
||||
|
||||
theorem mul_ofNat' [NeZero n] (x : Fin n) (y : Nat) :
|
||||
x * Fin.ofNat' n y = Fin.ofNat' n (x.val * y) := by
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat', Fin.mul_def]
|
||||
|
||||
theorem val_mul {n : Nat} : ∀ a b : Fin n, (a * b).val = a.val * b.val % n
|
||||
| ⟨_, _⟩, ⟨_, _⟩ => rfl
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Leonardo de Moura
|
||||
prelude
|
||||
import Init.Data.Int.Basic
|
||||
import Init.Data.Int.Bitwise
|
||||
import Init.Data.Int.Compare
|
||||
import Init.Data.Int.DivMod
|
||||
import Init.Data.Int.Gcd
|
||||
import Init.Data.Int.Lemmas
|
||||
|
||||
@@ -420,6 +420,8 @@ instance : IntCast Int where intCast n := n
|
||||
protected def Int.cast {R : Type u} [IntCast R] : Int → R :=
|
||||
IntCast.intCast
|
||||
|
||||
@[simp] theorem Int.cast_eq (x : Int) : Int.cast x = x := rfl
|
||||
|
||||
-- see the notes about coercions into arbitrary types in the module doc-string
|
||||
instance [IntCast R] : CoeTail Int R where coe := Int.cast
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ theorem shiftRight_eq_div_pow (m : Int) (n : Nat) :
|
||||
m >>> n = m / ((2 ^ n) : Nat) := by
|
||||
simp only [shiftRight_eq, Int.shiftRight, Nat.shiftRight_eq_div_pow]
|
||||
split
|
||||
· simp; norm_cast
|
||||
· simp
|
||||
· rw [negSucc_ediv _ (by norm_cast; exact Nat.pow_pos (Nat.zero_lt_two))]
|
||||
rfl
|
||||
|
||||
|
||||
@@ -18,9 +18,6 @@ namespace Int
|
||||
protected theorem lt_or_eq_of_le {n m : Int} (h : n ≤ m) : n < m ∨ n = m := by
|
||||
omega
|
||||
|
||||
protected theorem le_iff_lt_or_eq {n m : Int} : n ≤ m ↔ n < m ∨ n = m :=
|
||||
⟨Int.lt_or_eq_of_le, fun | .inl h => Int.le_of_lt h | .inr rfl => Int.le_refl _⟩
|
||||
|
||||
theorem compare_eq_ite_lt (a b : Int) :
|
||||
compare a b = if a < b then .lt else if b < a then .gt else .eq := by
|
||||
simp only [compare, compareOfLessAndEq]
|
||||
|
||||
@@ -45,9 +45,9 @@ protected theorem dvd_trans : ∀ {a b c : Int}, a ∣ b → b ∣ c → a ∣ c
|
||||
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⟩
|
||||
@[simp] 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 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⟩ =>
|
||||
@@ -59,13 +59,13 @@ protected theorem dvd_mul_left (a b : Int) : b ∣ a * b := ⟨_, Int.mul_comm .
|
||||
|
||||
@[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
|
||||
rw [← natAbs_natCast 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]
|
||||
rw [← natAbs_dvd_natAbs, natAbs_natCast]
|
||||
|
||||
/-! ### ediv zero -/
|
||||
|
||||
@@ -156,7 +156,7 @@ theorem add_mul_ediv_right (a b : Int) {c : Int} (H : c ≠ 0) : (a + b * c) / c
|
||||
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]
|
||||
rw [Nat.mul_comm, Nat.sub_mul_div_of_le]; rwa [Nat.mul_comm]
|
||||
|
||||
theorem add_mul_ediv_left (a : Int) {b : Int}
|
||||
(c : Int) (H : b ≠ 0) : (a + b * c) / b = a / b + c :=
|
||||
@@ -198,7 +198,7 @@ theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < b :=
|
||||
| ofNat _, _, ⟨_, rfl⟩ => ofNat_lt.2 (Nat.mod_lt _ (Nat.succ_pos _))
|
||||
| -[_+1], _, ⟨_, rfl⟩ => Int.sub_lt_self _ (ofNat_lt.2 <| Nat.succ_pos _)
|
||||
|
||||
@[simp] theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
|
||||
@[simp] theorem add_mul_emod_self_right (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
|
||||
@@ -206,7 +206,17 @@ theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < 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]
|
||||
rw [Int.mul_comm, add_mul_emod_self_right]
|
||||
|
||||
@[simp] theorem mul_add_emod_self_right (a b c : Int) : (a * b + c) % b = c % b := by
|
||||
rw [Int.add_comm, add_mul_emod_self_right]
|
||||
|
||||
@[simp] theorem mul_add_emod_self_left (a b c : Int) : (a * b + c) % a = c % a := by
|
||||
rw [Int.add_comm, add_mul_emod_self_left]
|
||||
|
||||
@[deprecated add_mul_emod_self_right (since := "2025-04-11")]
|
||||
theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
|
||||
add_mul_emod_self_right ..
|
||||
|
||||
@[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
|
||||
@@ -229,7 +239,7 @@ theorem emod_add_cancel_right {m n k : Int} (i) : (m + i) % n = (k + i) % n ↔
|
||||
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]
|
||||
rw [← Int.zero_add (a * b), add_mul_emod_self_right, Int.zero_emod]
|
||||
|
||||
@[simp] theorem mul_emod_right (a b : Int) : (a * b) % a = 0 := by
|
||||
rw [Int.mul_comm, mul_emod_left]
|
||||
@@ -238,7 +248,7 @@ 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]
|
||||
← Int.mul_assoc, add_mul_emod_self_right]
|
||||
|
||||
@[simp] theorem emod_self {a : Int} : a % a = 0 := by
|
||||
have := mul_emod_left 1 a; rwa [Int.one_mul] at this
|
||||
@@ -324,10 +334,10 @@ theorem lt_mul_ediv_self_add {x k : Int} (h : 0 < k) : x < k * (x / k) + k :=
|
||||
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 :=
|
||||
if (x % m) < (m + 1) / 2 then
|
||||
x % m
|
||||
else
|
||||
(x % m) - m :=
|
||||
rfl
|
||||
|
||||
end Int
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -135,7 +135,7 @@ theorem natAbs_div_gcd_pos_of_ne_zero_right (a : Int) (h : b ≠ 0) : 0 < b.natA
|
||||
Nat.div_gcd_pos_of_pos_right _ (natAbs_pos.2 h)
|
||||
|
||||
theorem ediv_gcd_ne_zero_of_ne_zero_left (b : Int) (h : a ≠ 0) : a / gcd a b ≠ 0 := by
|
||||
rw [← natAbs_pos, natAbs_ediv_of_dvd (gcd_dvd_left _ _), natAbs_ofNat]
|
||||
rw [← natAbs_pos, natAbs_ediv_of_dvd (gcd_dvd_left _ _), natAbs_natCast]
|
||||
exact natAbs_div_gcd_pos_of_ne_zero_left _ h
|
||||
|
||||
theorem ediv_gcd_ne_zero_if_ne_zero_right (a : Int) (h : b ≠ 0) : b / gcd a b ≠ 0 := by
|
||||
@@ -393,12 +393,12 @@ theorem pow_gcd_pow_of_gcd_eq_one {n m : Int} {k l : Nat} (h : gcd n m = 1) : gc
|
||||
|
||||
theorem gcd_ediv_gcd_ediv_gcd_of_ne_zero_left {n m : Int} (h : n ≠ 0) :
|
||||
gcd (n / gcd n m) (m / gcd n m) = 1 := by
|
||||
rw [gcd_ediv (gcd_dvd_left _ _) (gcd_dvd_right _ _), natAbs_ofNat,
|
||||
rw [gcd_ediv (gcd_dvd_left _ _) (gcd_dvd_right _ _), natAbs_natCast,
|
||||
Nat.div_self (gcd_pos_of_ne_zero_left _ h)]
|
||||
|
||||
theorem gcd_ediv_gcd_ediv_gcd_of_ne_zero_right {n m : Int} (h : m ≠ 0) :
|
||||
gcd (n / gcd n m) (m / gcd n m) = 1 := by
|
||||
rw [gcd_ediv (gcd_dvd_left _ _) (gcd_dvd_right _ _), natAbs_ofNat,
|
||||
rw [gcd_ediv (gcd_dvd_left _ _) (gcd_dvd_right _ _), natAbs_natCast,
|
||||
Nat.div_self (gcd_pos_of_ne_zero_right _ h)]
|
||||
|
||||
theorem gcd_ediv_gcd_ediv_gcd {i j : Int} (h : 0 < gcd i j) : gcd (i / gcd i j) (j / gcd i j) = 1 :=
|
||||
|
||||
@@ -377,6 +377,11 @@ theorem toNat_of_nonpos : ∀ {z : Int}, z ≤ 0 → z.toNat = 0
|
||||
@[simp] theorem negSucc_add_one_eq_neg_ofNat_iff {a b : Nat} : -[a+1] + 1 = - (b : Int) ↔ a = b := by
|
||||
rw [eq_comm, neg_ofNat_eq_negSucc_add_one_iff, eq_comm]
|
||||
|
||||
protected theorem sub_eq_iff_eq_add {b a c : Int} : a - b = c ↔ a = c + b := by
|
||||
refine ⟨fun h => ?_, fun h => ?_⟩ <;> subst h <;> simp
|
||||
protected theorem sub_eq_iff_eq_add' {b a c : Int} : a - b = c ↔ a = b + c := by
|
||||
rw [Int.sub_eq_iff_eq_add, Int.add_comm]
|
||||
|
||||
/- ## add/sub injectivity -/
|
||||
|
||||
@[simp] protected theorem add_left_inj {i j : Int} (k : Int) : (i + k = j + k) ↔ i = j := by
|
||||
@@ -561,7 +566,11 @@ theorem eq_one_of_mul_eq_self_left {a b : Int} (Hpos : a ≠ 0) (H : b * a = a)
|
||||
theorem eq_one_of_mul_eq_self_right {a b : Int} (Hpos : b ≠ 0) (H : b * a = b) : a = 1 :=
|
||||
Int.eq_of_mul_eq_mul_left Hpos <| by rw [Int.mul_one, H]
|
||||
|
||||
/-! NatCast lemmas -/
|
||||
protected theorem two_mul (n : Int) : 2 * n = n + n := calc
|
||||
2 * n = (1 + 1) * n := rfl
|
||||
_ = n + n := by simp only [Int.add_mul, Int.one_mul]
|
||||
|
||||
/-! ## NatCast lemmas -/
|
||||
|
||||
/-!
|
||||
The following lemmas are later subsumed by e.g. `Nat.cast_add` and `Nat.cast_mul` in Mathlib
|
||||
@@ -572,10 +581,8 @@ protected theorem natCast_zero : ((0 : Nat) : Int) = (0 : Int) := rfl
|
||||
|
||||
protected theorem natCast_one : ((1 : Nat) : Int) = (1 : Int) := rfl
|
||||
|
||||
@[simp] protected theorem natCast_add (a b : Nat) : ((a + b : Nat) : Int) = (a : Int) + (b : Int) := by
|
||||
-- Note this only works because of local simp attributes in this file,
|
||||
-- so it still makes sense to tag the lemmas with `@[simp]`.
|
||||
simp
|
||||
@[simp, norm_cast] protected theorem natCast_add (a b : Nat) : ((a + b : Nat) : Int) = (a : Int) + (b : Int) := by
|
||||
rfl
|
||||
|
||||
protected theorem natCast_succ (n : Nat) : ((n + 1 : Nat) : Int) = (n : Int) + 1 := rfl
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Int.Order
|
||||
import Init.Data.Int.Pow
|
||||
import Init.Data.Int.DivMod.Lemmas
|
||||
import Init.Omega
|
||||
|
||||
@@ -19,9 +20,6 @@ namespace Int
|
||||
|
||||
@[simp] theorem natCast_le_zero : {n : Nat} → (n : Int) ≤ 0 ↔ n = 0 := by omega
|
||||
|
||||
protected theorem sub_eq_iff_eq_add {b a c : Int} : a - b = c ↔ a = c + b := by omega
|
||||
protected theorem sub_eq_iff_eq_add' {b a c : Int} : a - b = c ↔ a = b + c := by omega
|
||||
|
||||
@[simp] protected theorem neg_nonpos_iff (i : Int) : -i ≤ 0 ↔ 0 ≤ i := by omega
|
||||
|
||||
@[simp] theorem zero_le_ofNat (n : Nat) : 0 ≤ ((no_index (OfNat.ofNat n)) : Int) :=
|
||||
@@ -42,6 +40,39 @@ protected theorem sub_eq_iff_eq_add' {b a c : Int} : a - b = c ↔ a = b + c :=
|
||||
theorem neg_lt_self_iff {n : Int} : -n < n ↔ 0 < n := by
|
||||
omega
|
||||
|
||||
protected theorem ofNat_add_out (m n : Nat) : ↑m + ↑n = (↑(m + n) : Int) := rfl
|
||||
|
||||
protected theorem ofNat_mul_out (m n : Nat) : ↑m * ↑n = (↑(m * n) : Int) := rfl
|
||||
|
||||
protected theorem ofNat_add_one_out (n : Nat) : ↑n + (1 : Int) = ↑(Nat.succ n) := rfl
|
||||
|
||||
@[simp] theorem ofNat_eq_natCast (n : Nat) : Int.ofNat n = n := rfl
|
||||
|
||||
@[norm_cast] theorem natCast_inj {m n : Nat} : (m : Int) = (n : Int) ↔ m = n := ofNat_inj
|
||||
|
||||
@[simp, norm_cast] theorem natAbs_cast (n : Nat) : natAbs ↑n = n := rfl
|
||||
|
||||
@[norm_cast]
|
||||
protected theorem natCast_sub {n m : Nat} : n ≤ m → (↑(m - n) : Int) = ↑m - ↑n := ofNat_sub
|
||||
|
||||
@[simp high] theorem natCast_eq_zero {n : Nat} : (n : Int) = 0 ↔ n = 0 := by omega
|
||||
|
||||
theorem natCast_ne_zero {n : Nat} : (n : Int) ≠ 0 ↔ n ≠ 0 := by omega
|
||||
|
||||
theorem natCast_ne_zero_iff_pos {n : Nat} : (n : Int) ≠ 0 ↔ 0 < n := by omega
|
||||
|
||||
@[simp high] theorem natCast_pos {n : Nat} : (0 : Int) < n ↔ 0 < n := by omega
|
||||
|
||||
theorem natCast_succ_pos (n : Nat) : 0 < (n.succ : Int) := natCast_pos.2 n.succ_pos
|
||||
|
||||
@[simp high] theorem natCast_nonpos_iff {n : Nat} : (n : Int) ≤ 0 ↔ n = 0 := by omega
|
||||
|
||||
theorem natCast_nonneg (n : Nat) : 0 ≤ (n : Int) := ofNat_le.2 (Nat.zero_le _)
|
||||
|
||||
@[simp] theorem sign_natCast_add_one (n : Nat) : sign (n + 1) = 1 := rfl
|
||||
|
||||
@[simp, norm_cast] theorem cast_id {n : Int} : Int.cast n = n := rfl
|
||||
|
||||
/-! ### toNat -/
|
||||
|
||||
@[simp] theorem toNat_sub' (a : Int) (b : Nat) : (a - b).toNat = a.toNat - b := by
|
||||
@@ -72,24 +103,27 @@ theorem neg_lt_self_iff {n : Int} : -n < n ↔ 0 < n := by
|
||||
|
||||
@[simp] theorem toNat_le {m : Int} {n : Nat} : m.toNat ≤ n ↔ m ≤ n := by omega
|
||||
@[simp] theorem toNat_lt' {m : Int} {n : Nat} (hn : 0 < n) : m.toNat < n ↔ m < n := by omega
|
||||
@[simp] theorem lt_toNat {m : Nat} {n : Int} : m < toNat n ↔ m < n := by omega
|
||||
theorem lt_of_toNat_lt {a b : Int} (h : toNat a < toNat b) : a < b := by omega
|
||||
|
||||
theorem toNat_sub_of_le {a b : Int} (h : b ≤ a) : (toNat (a - b) : Int) = a - b := by omega
|
||||
|
||||
theorem pos_iff_toNat_pos {n : Int} : 0 < n ↔ 0 < n.toNat := by
|
||||
omega
|
||||
|
||||
theorem ofNat_toNat_eq_self {a : Int} : a.toNat = a ↔ 0 ≤ a := by omega
|
||||
theorem eq_ofNat_toNat {a : Int} : a = a.toNat ↔ 0 ≤ a := by omega
|
||||
theorem natCast_toNat_eq_self {a : Int} : a.toNat = a ↔ 0 ≤ a := by omega
|
||||
|
||||
@[deprecated natCast_toNat_eq_self (since := "2025-04-16")]
|
||||
theorem ofNat_toNat_eq_self {a : Int} : a.toNat = a ↔ 0 ≤ a := natCast_toNat_eq_self
|
||||
|
||||
theorem eq_natCast_toNat {a : Int} : a = a.toNat ↔ 0 ≤ a := by omega
|
||||
|
||||
@[deprecated eq_natCast_toNat (since := "2025-04-16")]
|
||||
theorem eq_ofNat_toNat {a : Int} : a = a.toNat ↔ 0 ≤ a := eq_natCast_toNat
|
||||
|
||||
theorem toNat_le_toNat {n m : Int} (h : n ≤ m) : n.toNat ≤ m.toNat := by omega
|
||||
theorem toNat_lt_toNat {n m : Int} (hn : 0 < m) : n.toNat < m.toNat ↔ n < m := by omega
|
||||
|
||||
/-! ### natAbs -/
|
||||
|
||||
theorem eq_zero_of_dvd_of_natAbs_lt_natAbs {d n : Int} (h : d ∣ n) (h₁ : n.natAbs < d.natAbs) :
|
||||
n = 0 := by
|
||||
obtain ⟨a, rfl⟩ := h
|
||||
rw [natAbs_mul] at h₁
|
||||
suffices ¬ 0 < a.natAbs by simp [Int.natAbs_eq_zero.1 (Nat.eq_zero_of_not_pos this)]
|
||||
exact fun h => Nat.lt_irrefl _ (Nat.lt_of_le_of_lt (Nat.le_mul_of_pos_right d.natAbs h) h₁)
|
||||
|
||||
/-! ### min and max -/
|
||||
|
||||
@[simp] protected theorem min_assoc : ∀ (a b c : Int), min (min a b) c = min a (min b c) := by omega
|
||||
@@ -128,32 +162,7 @@ protected theorem sub_min_sub_left (a b c : Int) : min (a - b) (a - c) = a - max
|
||||
|
||||
protected theorem sub_max_sub_left (a b c : Int) : max (a - b) (a - c) = a - min b c := by omega
|
||||
|
||||
/-! ### bmod -/
|
||||
|
||||
theorem bmod_neg_iff {m : Nat} {x : Int} (h2 : -m ≤ x) (h1 : x < m) :
|
||||
(x.bmod m) < 0 ↔ (-(m / 2) ≤ x ∧ x < 0) ∨ ((m + 1) / 2 ≤ x) := by
|
||||
simp only [Int.bmod_def]
|
||||
by_cases xpos : 0 ≤ x
|
||||
· rw [Int.emod_eq_of_lt xpos (by omega)]; omega
|
||||
· rw [Int.add_emod_self.symm, Int.emod_eq_of_lt (by omega) (by omega)]; omega
|
||||
|
||||
theorem bmod_eq_self_of_le {n : Int} {m : Nat} (hn' : -(m / 2) ≤ n) (hn : n < (m + 1) / 2) :
|
||||
n.bmod m = n := by
|
||||
rw [← Int.sub_eq_zero]
|
||||
have := le_bmod (x := n) (m := m) (by omega)
|
||||
have := bmod_lt (x := n) (m := m) (by omega)
|
||||
apply eq_zero_of_dvd_of_natAbs_lt_natAbs Int.dvd_bmod_sub_self
|
||||
omega
|
||||
|
||||
theorem bmod_bmod_of_dvd {a : Int} {n m : Nat} (hnm : n ∣ m) :
|
||||
(a.bmod m).bmod n = a.bmod n := by
|
||||
rw [← Int.sub_eq_iff_eq_add.2 (bmod_add_bdiv a m).symm]
|
||||
obtain ⟨k, rfl⟩ := hnm
|
||||
simp [Int.mul_assoc]
|
||||
|
||||
theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt : x * 2 < y) :
|
||||
x.bmod y = x := by
|
||||
apply bmod_eq_self_of_le (by omega) (by omega)
|
||||
/-! ## mul -/
|
||||
|
||||
theorem mul_le_mul_of_natAbs_le {x y : Int} {s t : Nat} (hx : x.natAbs ≤ s) (hy : y.natAbs ≤ t) :
|
||||
x * y ≤ s * t := by
|
||||
@@ -206,4 +215,9 @@ theorem neg_mul_le_mul {x y : Int} {s t : Nat} (lbx : -s ≤ x) (ubx : x < s) (l
|
||||
norm_cast
|
||||
omega
|
||||
|
||||
/-! ## pow -/
|
||||
|
||||
theorem natAbs_pow_two (a : Int) : (natAbs a : Int) ^ 2 = a ^ 2 := by
|
||||
simp [Int.pow_succ]
|
||||
|
||||
end Int
|
||||
|
||||
@@ -191,9 +191,9 @@ theorem cmod_nonpos (a : Int) {b : Int} (h : b ≠ 0) : cmod a b ≤ 0 := by
|
||||
|
||||
theorem cmod_eq_zero_iff_emod_eq_zero (a b : Int) : cmod a b = 0 ↔ a%b = 0 := by
|
||||
unfold cmod
|
||||
have := @Int.emod_eq_emod_iff_emod_sub_eq_zero b b a
|
||||
simp at this
|
||||
simp [Int.neg_emod_eq_sub_emod, ← this, Eq.comm]
|
||||
have := @Int.emod_eq_emod_iff_emod_sub_eq_zero b b a
|
||||
simp only [emod_self, sub_emod_left] at this
|
||||
rw [Int.neg_eq_zero, ← this, Eq.comm]
|
||||
|
||||
private abbrev div_mul_cancel_of_mod_zero :=
|
||||
@Int.ediv_mul_cancel_of_emod_eq_zero
|
||||
@@ -435,7 +435,7 @@ def norm_eq_coeff_cert (lhs rhs : Expr) (p : Poly) (k : Int) : Bool :=
|
||||
theorem norm_eq_coeff (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int)
|
||||
: norm_eq_coeff_cert lhs rhs p k → (lhs.denote ctx = rhs.denote ctx) = (p.denote' ctx = 0) := by
|
||||
simp [norm_eq_coeff_cert]
|
||||
rw [norm_eq ctx lhs rhs (lhs.sub rhs).norm BEq.refl, Poly.denote'_eq_denote]
|
||||
rw [norm_eq ctx lhs rhs (lhs.sub rhs).norm BEq.rfl, Poly.denote'_eq_denote]
|
||||
apply norm_eq_coeff'
|
||||
|
||||
private theorem mul_le_zero_iff (a k : Int) (h₁ : k > 0) : k * a ≤ 0 ↔ a ≤ 0 := by
|
||||
@@ -454,7 +454,7 @@ private theorem norm_le_coeff' (ctx : Context) (p p' : Poly) (k : Int) : p = p'.
|
||||
theorem norm_le_coeff (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int)
|
||||
: norm_eq_coeff_cert lhs rhs p k → (lhs.denote ctx ≤ rhs.denote ctx) = (p.denote' ctx ≤ 0) := by
|
||||
simp [norm_eq_coeff_cert]
|
||||
rw [norm_le ctx lhs rhs (lhs.sub rhs).norm BEq.refl, Poly.denote'_eq_denote]
|
||||
rw [norm_le ctx lhs rhs (lhs.sub rhs).norm BEq.rfl, Poly.denote'_eq_denote]
|
||||
apply norm_le_coeff'
|
||||
|
||||
private theorem mul_add_cmod_le_iff {a k b : Int} (h : k > 0) : a*k + cmod b k ≤ 0 ↔ a ≤ 0 := by
|
||||
@@ -499,7 +499,7 @@ def norm_le_coeff_tight_cert (lhs rhs : Expr) (p : Poly) (k : Int) : Bool :=
|
||||
theorem norm_le_coeff_tight (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int)
|
||||
: norm_le_coeff_tight_cert lhs rhs p k → (lhs.denote ctx ≤ rhs.denote ctx) = (p.denote' ctx ≤ 0) := by
|
||||
simp [norm_le_coeff_tight_cert]
|
||||
rw [norm_le ctx lhs rhs (lhs.sub rhs).norm BEq.refl, Poly.denote'_eq_denote]
|
||||
rw [norm_le ctx lhs rhs (lhs.sub rhs).norm BEq.rfl, Poly.denote'_eq_denote]
|
||||
apply eq_of_norm_eq_of_divCoeffs
|
||||
|
||||
def Poly.isUnsatEq (p : Poly) : Bool :=
|
||||
@@ -665,7 +665,7 @@ theorem norm_dvd (ctx : Context) (k : Int) (e : Expr) (p : Poly) : e.norm == p
|
||||
simp; intro h; simp [← h]
|
||||
|
||||
theorem dvd_eq_false (ctx : Context) (k : Int) (e : Expr) (h : e.norm.isUnsatDvd k) : (k ∣ e.denote ctx) = False := by
|
||||
rw [norm_dvd ctx k e e.norm BEq.refl]
|
||||
rw [norm_dvd ctx k e e.norm BEq.rfl]
|
||||
apply dvd_eq_false' ctx k e.norm h
|
||||
|
||||
def dvd_coeff_cert (k₁ : Int) (p₁ : Poly) (k₂ : Int) (p₂ : Poly) (k : Int) : Bool :=
|
||||
|
||||
@@ -84,6 +84,11 @@ theorem ofNat_succ_pos (n : Nat) : 0 < (succ n : Int) := ofNat_lt.2 <| Nat.succ_
|
||||
@[simp] protected theorem le_refl (a : Int) : a ≤ a :=
|
||||
le.intro _ (Int.add_zero a)
|
||||
|
||||
protected theorem le_rfl {a : Int} : a ≤ a := a.le_refl
|
||||
|
||||
protected theorem le_of_eq {a b : Int} (hab : a = b) : a ≤ b := by rw [hab]; exact Int.le_rfl
|
||||
protected theorem ge_of_eq {a b : Int} (hab : a = b) : b ≤ a := Int.le_of_eq hab.symm
|
||||
|
||||
protected theorem le_trans {a b c : Int} (h₁ : a ≤ b) (h₂ : b ≤ c) : a ≤ c :=
|
||||
let ⟨n, hn⟩ := le.dest h₁; let ⟨m, hm⟩ := le.dest h₂
|
||||
le.intro (n + m) <| by rw [← hm, ← hn, Int.add_assoc, ofNat_add]
|
||||
@@ -94,6 +99,9 @@ protected theorem le_antisymm {a b : Int} (h₁ : a ≤ b) (h₂ : b ≤ a) : a
|
||||
have := Int.ofNat.inj <| Int.add_left_cancel <| this.trans (Int.add_zero _).symm
|
||||
rw [← hn, Nat.eq_zero_of_add_eq_zero_left this, ofNat_zero, Int.add_zero a]
|
||||
|
||||
protected theorem le_antisymm_iff {a b : Int} : a = b ↔ a ≤ b ∧ b ≤ a :=
|
||||
⟨fun h ↦ ⟨Int.le_of_eq h, Int.ge_of_eq h⟩, fun h ↦ Int.le_antisymm h.1 h.2⟩
|
||||
|
||||
@[simp] protected theorem lt_irrefl (a : Int) : ¬a < a := fun H =>
|
||||
let ⟨n, hn⟩ := lt.dest H
|
||||
have : (a+Nat.succ n) = a+0 := by
|
||||
@@ -119,6 +127,12 @@ protected theorem lt_succ (a : Int) : a < a + 1 := Int.le_refl _
|
||||
|
||||
protected theorem zero_lt_one : (0 : Int) < 1 := ⟨_⟩
|
||||
|
||||
protected theorem one_pos : 0 < (1 : Int) := Int.zero_lt_one
|
||||
|
||||
protected theorem one_ne_zero : (1 : Int) ≠ 0 := by decide
|
||||
|
||||
protected theorem one_nonneg : 0 ≤ (1 : Int) := Int.le_of_lt Int.zero_lt_one
|
||||
|
||||
protected theorem lt_iff_le_not_le {a b : Int} : a < b ↔ a ≤ b ∧ ¬b ≤ a := by
|
||||
rw [Int.lt_iff_le_and_ne]
|
||||
constructor <;> refine fun ⟨h, h'⟩ => ⟨h, h'.imp fun h' => ?_⟩
|
||||
@@ -137,6 +151,10 @@ protected theorem not_le_of_gt {a b : Int} (h : b < a) : ¬a ≤ b :=
|
||||
@[simp] protected theorem not_lt {a b : Int} : ¬a < b ↔ b ≤ a :=
|
||||
by rw [← Int.not_le, Decidable.not_not]
|
||||
|
||||
protected theorem lt_asymm {a b : Int} : a < b → ¬ b < a := by rw [Int.not_lt]; exact Int.le_of_lt
|
||||
|
||||
protected theorem lt_or_le (a b : Int) : a < b ∨ b ≤ a := by rw [← Int.not_lt]; exact Decidable.em _
|
||||
|
||||
protected theorem le_of_not_gt {a b : Int} (h : ¬ a > b) : a ≤ b :=
|
||||
Int.not_lt.mp h
|
||||
|
||||
@@ -161,12 +179,23 @@ protected theorem ne_iff_lt_or_gt {a b : Int} : a ≠ b ↔ a < b ∨ b < a := b
|
||||
|
||||
protected theorem lt_or_gt_of_ne {a b : Int} : a ≠ b → a < b ∨ b < a:= Int.ne_iff_lt_or_gt.mp
|
||||
|
||||
protected theorem lt_or_lt_of_ne {a b : Int} : a ≠ b → a < b ∨ b < a := Int.lt_or_gt_of_ne
|
||||
|
||||
protected theorem eq_iff_le_and_ge {x y : Int} : x = y ↔ x ≤ y ∧ y ≤ x := by
|
||||
constructor
|
||||
· simp_all
|
||||
· intro ⟨h₁, h₂⟩
|
||||
exact Int.le_antisymm h₁ h₂
|
||||
|
||||
protected theorem le_iff_eq_or_lt {a b : Int} : a ≤ b ↔ a = b ∨ a < b :=
|
||||
match Int.lt_trichotomy a b with
|
||||
| Or.inl h => by simp [h, Int.le_of_lt]
|
||||
| Or.inr (Or.inl h) => by simp [h]
|
||||
| Or.inr (Or.inr h) => by simp [h, Int.not_le_of_gt, Int.ne_of_gt, Int.le_of_lt]
|
||||
|
||||
protected theorem le_iff_lt_or_eq {a b : Int} : a ≤ b ↔ a < b ∨ a = b := by
|
||||
rw [Int.le_iff_eq_or_lt, or_comm]
|
||||
|
||||
protected theorem lt_of_le_of_lt {a b c : Int} (h₁ : a ≤ b) (h₂ : b < c) : a < c :=
|
||||
Int.not_le.1 fun h => Int.not_le.2 h₂ (Int.le_trans h h₁)
|
||||
|
||||
@@ -283,9 +312,8 @@ protected theorem neg_lt_neg {a b : Int} (h : a < b) : -b < -a := by
|
||||
@[simp] protected theorem zero_lt_neg_iff {a : Int} : 0 < -a ↔ a < 0 := by
|
||||
rw [← Int.neg_zero, Int.neg_lt_neg_iff, Int.neg_zero]
|
||||
|
||||
protected theorem neg_neg_of_pos {a : Int} (h : 0 < a) : -a < 0 := by
|
||||
have : -a < -0 := Int.neg_lt_neg h
|
||||
rwa [Int.neg_zero] at this
|
||||
protected theorem neg_neg_of_pos {a : Int} (h : 0 < a) : -a < 0 :=
|
||||
Int.neg_lt_zero_iff.2 h
|
||||
|
||||
protected theorem neg_pos_of_neg {a : Int} (h : a < 0) : 0 < -a := by
|
||||
have : -0 < -a := Int.neg_lt_neg h
|
||||
@@ -329,9 +357,9 @@ protected theorem le_iff_lt_add_one {a b : Int} : a ≤ b ↔ a < b + 1 := by
|
||||
|
||||
/- ### min and max -/
|
||||
|
||||
protected theorem min_def (n m : Int) : min n m = if n ≤ m then n else m := rfl
|
||||
@[grind =] protected theorem min_def (n m : Int) : min n m = if n ≤ m then n else m := rfl
|
||||
|
||||
protected theorem max_def (n m : Int) : max n m = if n ≤ m then m else n := rfl
|
||||
@[grind =] protected theorem max_def (n m : Int) : max n m = if n ≤ m then m else n := rfl
|
||||
|
||||
@[simp] protected theorem neg_min_neg (a b : Int) : min (-a) (-b) = -max a b := by
|
||||
rw [Int.min_def, Int.max_def]
|
||||
@@ -507,7 +535,17 @@ protected theorem mul_le_mul_of_nonpos_left {a b c : Int}
|
||||
|
||||
/- ## natAbs -/
|
||||
|
||||
@[simp, norm_cast] theorem natAbs_ofNat (n : Nat) : natAbs ↑n = n := rfl
|
||||
@[simp, norm_cast] theorem natAbs_natCast (n : Nat) : natAbs ↑n = n := rfl
|
||||
|
||||
@[deprecated natAbs_natCast (since := "2025-04-16")]
|
||||
theorem natAbs_ofNat (n : Nat) : natAbs ↑n = n := natAbs_natCast n
|
||||
|
||||
/-
|
||||
TODO: rename `natAbs_ofNat'` to `natAbs_ofNat` once the current deprecated alias
|
||||
`natAbs_ofNat := natAbs_natCast` is removed
|
||||
-/
|
||||
@[simp] theorem natAbs_ofNat' (n : Nat) : natAbs (ofNat n) = n := rfl
|
||||
|
||||
@[simp] theorem natAbs_negSucc (n : Nat) : natAbs -[n+1] = n.succ := rfl
|
||||
@[simp] theorem natAbs_zero : natAbs (0 : Int) = (0 : Nat) := rfl
|
||||
@[simp] theorem natAbs_one : natAbs (1 : Int) = (1 : Nat) := rfl
|
||||
@@ -518,7 +556,8 @@ protected theorem mul_le_mul_of_nonpos_left {a b c : Int}
|
||||
| -[_+1] => absurd H (succ_ne_zero _),
|
||||
fun e => e ▸ rfl⟩
|
||||
|
||||
theorem natAbs_pos : 0 < natAbs a ↔ a ≠ 0 := by rw [Nat.pos_iff_ne_zero, Ne, natAbs_eq_zero]
|
||||
@[simp] theorem natAbs_pos : 0 < natAbs a ↔ a ≠ 0 := by
|
||||
rw [Nat.pos_iff_ne_zero, Ne, natAbs_eq_zero]
|
||||
|
||||
@[simp] theorem natAbs_neg : ∀ (a : Int), natAbs (-a) = natAbs a
|
||||
| 0 => rfl
|
||||
@@ -562,6 +601,16 @@ theorem natAbs_sub_of_nonneg_of_le {a b : Int} (h₁ : 0 ≤ b) (h₂ : b ≤ a)
|
||||
· rwa [← Int.ofNat_le, natAbs_of_nonneg h₁, natAbs_of_nonneg (Int.le_trans h₁ h₂)]
|
||||
· exact Int.sub_nonneg_of_le h₂
|
||||
|
||||
theorem eq_zero_of_dvd_of_natAbs_lt_natAbs {d n : Int} (h : d ∣ n) (h₁ : n.natAbs < d.natAbs) :
|
||||
n = 0 := by
|
||||
let ⟨a, ha⟩ := h
|
||||
subst ha
|
||||
rw [natAbs_mul] at h₁
|
||||
suffices ¬ 0 < a.natAbs by simp [Int.natAbs_eq_zero.1 (Nat.eq_zero_of_not_pos this)]
|
||||
refine fun h => Nat.lt_irrefl _ (Nat.lt_of_le_of_lt ?_ h₁)
|
||||
rw (occs := [1]) [← Nat.mul_one d.natAbs]
|
||||
exact Nat.mul_le_mul (Nat.le_refl _) h
|
||||
|
||||
/-! ### toNat -/
|
||||
|
||||
theorem toNat_eq_max : ∀ a : Int, (toNat a : Int) = max a 0
|
||||
@@ -575,12 +624,18 @@ theorem toNat_eq_max : ∀ a : Int, (toNat a : Int) = max a 0
|
||||
theorem toNat_of_nonneg {a : Int} (h : 0 ≤ a) : (toNat a : Int) = a := by
|
||||
rw [toNat_eq_max, Int.max_eq_left h]
|
||||
|
||||
@[simp] theorem toNat_ofNat (n : Nat) : toNat ↑n = n := rfl
|
||||
@[simp] theorem toNat_natCast (n : Nat) : toNat ↑n = n := rfl
|
||||
|
||||
@[deprecated toNat_natCast (since := "2025-04-16")]
|
||||
theorem toNat_ofNat (n : Nat) : toNat ↑n = n := toNat_natCast n
|
||||
|
||||
@[simp] theorem toNat_negSucc (n : Nat) : (Int.negSucc n).toNat = 0 := by
|
||||
simp [toNat]
|
||||
|
||||
@[simp] theorem toNat_ofNat_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := rfl
|
||||
@[simp] theorem toNat_natCast_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := rfl
|
||||
|
||||
@[deprecated toNat_natCast_add_one (since := "2025-04-16")]
|
||||
theorem toNat_ofNat_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := toNat_natCast_add_one
|
||||
|
||||
@[simp] theorem ofNat_toNat (a : Int) : (a.toNat : Int) = max a 0 := by
|
||||
match a with
|
||||
@@ -599,6 +654,18 @@ theorem toNat_add {a b : Int} (ha : 0 ≤ a) (hb : 0 ≤ b) : (a + b).toNat = a.
|
||||
match a, b, eq_ofNat_of_zero_le ha, eq_ofNat_of_zero_le hb with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => rfl
|
||||
|
||||
theorem toNat_mul {a b : Int} (ha : 0 ≤ a) (hb : 0 ≤ b) : (a * b).toNat = a.toNat * b.toNat :=
|
||||
match a, b, eq_ofNat_of_zero_le ha, eq_ofNat_of_zero_le hb with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => rfl
|
||||
|
||||
/--
|
||||
Variant of `Int.toNat_sub` taking non-negativity hypotheses,
|
||||
rather than expecting the arguments to be casts of natural numbers.
|
||||
-/
|
||||
theorem toNat_sub'' {a b : Int} (ha : 0 ≤ a) (hb : 0 ≤ b) : (a - b).toNat = a.toNat - b.toNat :=
|
||||
match a, b, eq_ofNat_of_zero_le ha, eq_ofNat_of_zero_le hb with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => toNat_sub _ _
|
||||
|
||||
theorem toNat_add_nat {a : Int} (ha : 0 ≤ a) (n : Nat) : (a + n).toNat = a.toNat + n :=
|
||||
match a, eq_ofNat_of_zero_le ha with | _, ⟨_, rfl⟩ => rfl
|
||||
|
||||
@@ -746,6 +813,16 @@ protected theorem neg_lt_of_neg_lt {a b : Int} (h : -a < b) : -b < a := by
|
||||
have h := Int.neg_lt_neg h
|
||||
rwa [Int.neg_neg] at h
|
||||
|
||||
@[simp high]
|
||||
protected theorem neg_pos : 0 < -a ↔ a < 0 := ⟨Int.neg_of_neg_pos, Int.neg_pos_of_neg⟩
|
||||
|
||||
@[simp high]
|
||||
protected theorem neg_nonneg : 0 ≤ -a ↔ a ≤ 0 :=
|
||||
⟨Int.nonpos_of_neg_nonneg, Int.neg_nonneg_of_nonpos⟩
|
||||
|
||||
@[simp high]
|
||||
protected theorem neg_neg_iff_pos : -a < 0 ↔ 0 < a := ⟨Int.pos_of_neg_neg, Int.neg_neg_of_pos⟩
|
||||
|
||||
protected theorem sub_nonpos_of_le {a b : Int} (h : a ≤ b) : a - b ≤ 0 := by
|
||||
have h := Int.add_le_add_right h (-b)
|
||||
rwa [Int.add_right_neg] at h
|
||||
@@ -758,6 +835,14 @@ protected theorem sub_neg_of_lt {a b : Int} (h : a < b) : a - b < 0 := by
|
||||
have h := Int.add_lt_add_right h (-b)
|
||||
rwa [Int.add_right_neg] at h
|
||||
|
||||
@[simp high]
|
||||
protected theorem sub_pos {a b : Int} : 0 < a - b ↔ b < a :=
|
||||
⟨Int.lt_of_sub_pos, Int.sub_pos_of_lt⟩
|
||||
|
||||
@[simp high]
|
||||
protected theorem sub_nonneg {a b : Int} : 0 ≤ a - b ↔ b ≤ a :=
|
||||
⟨Int.le_of_sub_nonneg, Int.sub_nonneg_of_le⟩
|
||||
|
||||
protected theorem lt_of_sub_neg {a b : Int} (h : a - b < 0) : a < b := by
|
||||
have h := Int.add_lt_add_right h b
|
||||
rwa [Int.sub_add_cancel, Int.zero_add] at h
|
||||
@@ -998,6 +1083,33 @@ theorem le_sub_one_of_lt {a b : Int} (H : a < b) : a ≤ b - 1 := Int.le_sub_rig
|
||||
|
||||
theorem lt_of_le_sub_one {a b : Int} (H : a ≤ b - 1) : a < b := Int.add_le_of_le_sub_right H
|
||||
|
||||
theorem le_add_one_iff {m n : Int} : m ≤ n + 1 ↔ m ≤ n ∨ m = n + 1 := by
|
||||
rw [Int.le_iff_lt_or_eq, ← Int.le_iff_lt_add_one]
|
||||
|
||||
theorem sub_one_lt_iff {m n : Int} : m - 1 < n ↔ m ≤ n :=
|
||||
⟨le_of_sub_one_lt, sub_one_lt_of_le⟩
|
||||
|
||||
theorem le_sub_one_iff {m n : Int} : m ≤ n - 1 ↔ m < n :=
|
||||
⟨lt_of_le_sub_one, le_sub_one_of_lt⟩
|
||||
|
||||
protected theorem add_le_iff_le_sub {a b c : Int} : a + b ≤ c ↔ a ≤ c - b :=
|
||||
⟨Int.le_sub_right_of_add_le, Int.add_le_of_le_sub_right⟩
|
||||
|
||||
protected theorem le_add_iff_sub_le {a b c : Int} : a ≤ b + c ↔ a - c ≤ b :=
|
||||
⟨Int.sub_right_le_of_le_add, Int.le_add_of_sub_right_le⟩
|
||||
|
||||
protected theorem add_le_zero_iff_le_neg {a b : Int} : a + b ≤ 0 ↔ a ≤ -b := by
|
||||
rw [Int.add_le_iff_le_sub, Int.zero_sub]
|
||||
|
||||
protected theorem add_le_zero_iff_le_neg' {a b : Int} : a + b ≤ 0 ↔ b ≤ -a := by
|
||||
rw [Int.add_comm, Int.add_le_zero_iff_le_neg]
|
||||
|
||||
protected theorem add_nonnneg_iff_neg_le {a b : Int} : 0 ≤ a + b ↔ -b ≤ a := by
|
||||
rw [Int.le_add_iff_sub_le, Int.zero_sub]
|
||||
|
||||
protected theorem add_nonnneg_iff_neg_le' {a b : Int} : 0 ≤ a + b ↔ -a ≤ b := by
|
||||
rw [Int.add_comm, Int.add_nonnneg_iff_neg_le]
|
||||
|
||||
/- ### Order properties and multiplication -/
|
||||
|
||||
protected theorem mul_lt_mul {a b c d : Int}
|
||||
@@ -1073,13 +1185,21 @@ theorem sign_neg_one : sign (-1) = -1 := rfl
|
||||
theorem natAbs_sign (z : Int) : z.sign.natAbs = if z = 0 then 0 else 1 :=
|
||||
match z with | 0 | succ _ | -[_+1] => rfl
|
||||
|
||||
theorem natAbs_sign_of_nonzero {z : Int} (hz : z ≠ 0) : z.sign.natAbs = 1 := by
|
||||
theorem natAbs_sign_of_ne_zero {z : Int} (hz : z ≠ 0) : z.sign.natAbs = 1 := by
|
||||
rw [Int.natAbs_sign, if_neg hz]
|
||||
|
||||
theorem sign_ofNat_of_nonzero {n : Nat} (hn : n ≠ 0) : Int.sign n = 1 :=
|
||||
@[deprecated natAbs_sign_of_ne_zero (since := "2025-04-16")]
|
||||
theorem natAbs_sign_of_nonzero {z : Int} (hz : z ≠ 0) : z.sign.natAbs = 1 :=
|
||||
natAbs_sign_of_ne_zero hz
|
||||
|
||||
theorem sign_natCast_of_ne_zero {n : Nat} (hn : n ≠ 0) : Int.sign n = 1 :=
|
||||
match n, Nat.exists_eq_succ_of_ne_zero hn with
|
||||
| _, ⟨n, rfl⟩ => Int.sign_of_add_one n
|
||||
|
||||
@[deprecated sign_natCast_of_ne_zero (since := "2025-04-16")]
|
||||
theorem sign_ofNat_of_nonzero {n : Nat} (hn : n ≠ 0) : Int.sign n = 1 :=
|
||||
sign_natCast_of_ne_zero hn
|
||||
|
||||
@[simp] theorem sign_neg (z : Int) : Int.sign (-z) = -Int.sign z := by
|
||||
match z with | 0 | succ _ | -[_+1] => rfl
|
||||
|
||||
@@ -1161,7 +1281,7 @@ theorem neg_of_sign_eq_neg_one : ∀ {a : Int}, sign a = -1 → a < 0
|
||||
|
||||
@[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
|
||||
@[simp] theorem sign_mul_self (i : Int) : sign i * i = natAbs i := by
|
||||
rw [Int.mul_comm, mul_sign_self]
|
||||
|
||||
theorem sign_trichotomy (a : Int) : sign a = 1 ∨ sign a = 0 ∨ sign a = -1 := by
|
||||
@@ -1187,15 +1307,15 @@ theorem natAbs_mul_natAbs_eq {a b : Int} {c : Nat}
|
||||
rw [← Int.ofNat_mul, natAbs_mul_self]
|
||||
|
||||
theorem natAbs_eq_iff {a : Int} {n : Nat} : a.natAbs = n ↔ a = n ∨ a = -↑n := by
|
||||
rw [← Int.natAbs_eq_natAbs_iff, Int.natAbs_ofNat]
|
||||
rw [← Int.natAbs_eq_natAbs_iff, Int.natAbs_natCast]
|
||||
|
||||
theorem natAbs_add_le (a b : Int) : natAbs (a + b) ≤ natAbs a + natAbs b := by
|
||||
suffices ∀ a b : Nat, natAbs (subNatNat a b.succ) ≤ (a + b).succ by
|
||||
match a, b with
|
||||
| (a:Nat), (b:Nat) => rw [← ofNat_add, natAbs_ofNat]; apply Nat.le_refl
|
||||
| (a:Nat), -[b+1] => rw [natAbs_ofNat, natAbs_negSucc]; apply this
|
||||
| (a:Nat), (b:Nat) => rw [← ofNat_add, natAbs_natCast]; apply Nat.le_refl
|
||||
| (a:Nat), -[b+1] => rw [natAbs_natCast, natAbs_negSucc]; apply this
|
||||
| -[a+1], (b:Nat) =>
|
||||
rw [natAbs_negSucc, natAbs_ofNat, Nat.succ_add, Nat.add_comm a b]; apply this
|
||||
rw [natAbs_negSucc, natAbs_natCast, Nat.succ_add, Nat.add_comm a b]; apply this
|
||||
| -[a+1], -[b+1] => rw [natAbs_negSucc, succ_add]; apply Nat.le_refl
|
||||
refine fun a b => subNatNat_elim a b.succ
|
||||
(fun m n i => n = b.succ → natAbs i ≤ (m + b).succ) ?_
|
||||
@@ -1211,6 +1331,15 @@ theorem natAbs_add_le (a b : Int) : natAbs (a + b) ≤ natAbs a + natAbs b := by
|
||||
theorem natAbs_sub_le (a b : Int) : natAbs (a - b) ≤ natAbs a + natAbs b := by
|
||||
rw [← Int.natAbs_neg b]; apply natAbs_add_le
|
||||
|
||||
theorem natAbs_add_of_nonneg : ∀ {a b : Int}, 0 ≤ a → 0 ≤ b → natAbs (a + b) = natAbs a + natAbs b
|
||||
| ofNat _, ofNat _, _, _ => rfl
|
||||
|
||||
theorem natAbs_add_of_nonpos {a b : Int} (ha : a ≤ 0) (hb : b ≤ 0) :
|
||||
natAbs (a + b) = natAbs a + natAbs b := by
|
||||
rw [← Int.neg_neg a, ← Int.neg_neg b, ← Int.neg_add, natAbs_neg,
|
||||
natAbs_add_of_nonneg (Int.neg_nonneg_of_nonpos ha) (Int.neg_nonneg_of_nonpos hb),
|
||||
natAbs_neg (-a), natAbs_neg (-b)]
|
||||
|
||||
@[deprecated negSucc_eq (since := "2025-03-11")]
|
||||
theorem negSucc_eq' (m : Nat) : -[m+1] = -m - 1 := by simp only [negSucc_eq, Int.neg_add]; rfl
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ abbrev pow_le_pow_of_le_right := @Nat.pow_le_pow_right
|
||||
@[deprecated Nat.pow_pos (since := "2025-02-17")]
|
||||
abbrev pos_pow_of_pos := @Nat.pow_pos
|
||||
|
||||
@[norm_cast]
|
||||
@[simp, norm_cast]
|
||||
protected theorem natCast_pow (b n : Nat) : ((b^n : Nat) : Int) = (b : Int) ^ n := by
|
||||
match n with
|
||||
| 0 => rfl
|
||||
@@ -54,7 +54,7 @@ protected theorem two_pow_pred_sub_two_pow' {w : Nat} (h : 0 < w) :
|
||||
(2 : Int) ^ (w - 1) - (2 : Int) ^ w = - (2 : Int) ^ (w - 1) := by
|
||||
norm_cast
|
||||
rw [← Nat.two_pow_pred_add_two_pow_pred h]
|
||||
simp [h]
|
||||
simp [h, -Int.natCast_pow]
|
||||
|
||||
theorem pow_lt_pow_of_lt {a : Int} {b c : Nat} (ha : 1 < a) (hbc : b < c):
|
||||
a ^ b < a ^ c := by
|
||||
@@ -63,7 +63,7 @@ theorem pow_lt_pow_of_lt {a : Int} {b c : Nat} (ha : 1 < a) (hbc : b < c):
|
||||
simp only [Int.ofNat_lt]
|
||||
omega
|
||||
|
||||
theorem natAbs_pow (n : Int) : (k : Nat) → (n ^ k).natAbs = n.natAbs ^ k
|
||||
@[simp] theorem natAbs_pow (n : Int) : (k : Nat) → (n ^ k).natAbs = n.natAbs ^ k
|
||||
| 0 => rfl
|
||||
| k + 1 => by rw [Int.pow_succ, natAbs_mul, natAbs_pow, Nat.pow_succ]
|
||||
|
||||
|
||||
@@ -477,7 +477,7 @@ theorem attach_filterMap {l : List α} {f : α → Option β} :
|
||||
· simp only [h]
|
||||
rfl
|
||||
rw [ih]
|
||||
simp only [map_filterMap, Option.map_pbind, Option.map_some']
|
||||
simp only [map_filterMap, Option.map_pbind, Option.map_some]
|
||||
rfl
|
||||
· simp only [Option.pbind_eq_some_iff] at h
|
||||
obtain ⟨a, h, w⟩ := h
|
||||
@@ -640,12 +640,12 @@ theorem countP_attachWith {p : α → Prop} {q : α → Bool} {l : List α} (H :
|
||||
simp only [← Function.comp_apply (g := Subtype.val), ← countP_map, attachWith_map_subtype_val]
|
||||
|
||||
@[simp]
|
||||
theorem count_attach [DecidableEq α] {l : List α} {a : {x // x ∈ l}} :
|
||||
theorem count_attach [BEq α] {l : List α} {a : {x // x ∈ l}} :
|
||||
l.attach.count a = l.count ↑a :=
|
||||
Eq.trans (countP_congr fun _ _ => by simp [Subtype.ext_iff]) <| countP_attach
|
||||
|
||||
@[simp]
|
||||
theorem count_attachWith [DecidableEq α] {p : α → Prop} {l : List α} (H : ∀ a ∈ l, p a) {a : {x // p x}} :
|
||||
theorem count_attachWith [BEq α] {p : α → Prop} {l : List α} (H : ∀ a ∈ l, p a) {a : {x // p x}} :
|
||||
(l.attachWith p H).count a = l.count ↑a :=
|
||||
Eq.trans (countP_congr fun _ _ => by simp [Subtype.ext_iff]) <| countP_attachWith _
|
||||
|
||||
|
||||
@@ -131,6 +131,12 @@ theorem beq_cons₂ [BEq α] {a b : α} {as bs : List α} : List.beq (a::as) (b:
|
||||
|
||||
instance [BEq α] : BEq (List α) := ⟨List.beq⟩
|
||||
|
||||
instance [BEq α] [ReflBEq α] : ReflBEq (List α) where
|
||||
rfl {as} := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih => simp [BEq.beq, List.beq]; exact ih
|
||||
|
||||
instance [BEq α] [LawfulBEq α] : LawfulBEq (List α) where
|
||||
eq_of_beq {as bs} := by
|
||||
induction as generalizing bs with
|
||||
@@ -142,10 +148,6 @@ instance [BEq α] [LawfulBEq α] : LawfulBEq (List α) where
|
||||
simp [show (a::as == b::bs) = (a == b && as == bs) from rfl, -and_imp]
|
||||
intro ⟨h₁, h₂⟩
|
||||
exact ⟨h₁, ih h₂⟩
|
||||
rfl {as} := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih => simp [BEq.beq, List.beq, LawfulBEq.rfl]; exact ih
|
||||
|
||||
/--
|
||||
Returns `true` if `as` and `bs` have the same length and they are pairwise related by `eqv`.
|
||||
@@ -900,10 +902,10 @@ theorem mem_of_elem_eq_true [BEq α] [LawfulBEq α] {a : α} {as : List α} : el
|
||||
next h => intros; simp [BEq.beq] at h; subst h; apply Mem.head
|
||||
next _ => intro h; exact Mem.tail _ (mem_of_elem_eq_true h)
|
||||
|
||||
theorem elem_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : List α} (h : a ∈ as) : elem a as = true := by
|
||||
theorem elem_eq_true_of_mem [BEq α] [ReflBEq α] {a : α} {as : List α} (h : a ∈ as) : elem a as = true := by
|
||||
induction h with
|
||||
| head _ => simp [elem]
|
||||
| tail _ _ ih => simp [elem]; split; rfl; assumption
|
||||
| tail _ _ ih => simp only [elem]; split; rfl; assumption
|
||||
|
||||
instance [BEq α] [LawfulBEq α] (a : α) (as : List α) : Decidable (a ∈ as) :=
|
||||
decidable_of_decidable_of_iff (Iff.intro mem_of_elem_eq_true elem_eq_true_of_mem)
|
||||
|
||||
@@ -298,8 +298,8 @@ theorem filter_beq {l : List α} (a : α) : l.filter (· == a) = replicate (coun
|
||||
simp only [count, countP_eq_length_filter, eq_replicate_iff, mem_filter, beq_iff_eq]
|
||||
exact ⟨trivial, fun _ h => h.2⟩
|
||||
|
||||
theorem filter_eq {α} [DecidableEq α] {l : List α} (a : α) : l.filter (· = a) = replicate (count a l) a :=
|
||||
filter_beq a
|
||||
theorem filter_eq [DecidableEq α] {l : List α} (a : α) : l.filter (· = a) = replicate (count a l) a :=
|
||||
funext (Bool.beq_eq_decide_eq · a) ▸ filter_beq a
|
||||
|
||||
theorem le_count_iff_replicate_sublist {l : List α} : n ≤ count a l ↔ replicate n a <+ l := by
|
||||
refine ⟨fun h => ?_, fun h => ?_⟩
|
||||
@@ -314,7 +314,7 @@ theorem replicate_count_eq_of_count_eq_length {l : List α} (h : count a l = len
|
||||
rw [count, countP_filter]; congr; funext b
|
||||
simp; rintro rfl; exact h
|
||||
|
||||
theorem count_le_count_map [DecidableEq β] {l : List α} {f : α → β} {x : α} :
|
||||
theorem count_le_count_map {β} [BEq β] [LawfulBEq β] {l : List α} {f : α → β} {x : α} :
|
||||
count x l ≤ count (f x) (map f l) := by
|
||||
rw [count, count, countP_map]
|
||||
apply countP_mono_left; simp +contextual
|
||||
|
||||
@@ -88,7 +88,7 @@ theorem exists_or_eq_self_of_eraseP (p) (l : List α) :
|
||||
@[simp] theorem length_eraseP_of_mem (al : a ∈ l) (pa : p a) :
|
||||
length (l.eraseP p) = length l - 1 := by
|
||||
let ⟨_, l₁, l₂, _, _, e₁, e₂⟩ := exists_of_eraseP al pa
|
||||
rw [e₂]; simp [length_append, e₁]; rfl
|
||||
rw [e₂]; simp [length_append, e₁]
|
||||
|
||||
theorem length_eraseP {l : List α} : (l.eraseP p).length = if l.any p then l.length - 1 else l.length := by
|
||||
split <;> rename_i h
|
||||
@@ -542,7 +542,7 @@ theorem eraseIdx_eq_take_drop_succ :
|
||||
match l, i with
|
||||
| [], _
|
||||
| a::l, 0
|
||||
| a::l, i + 1 => simp [Nat.succ_inj']
|
||||
| a::l, i + 1 => simp [Nat.succ_inj]
|
||||
|
||||
@[deprecated eraseIdx_eq_nil_iff (since := "2025-01-30")]
|
||||
abbrev eraseIdx_eq_nil := @eraseIdx_eq_nil_iff
|
||||
@@ -551,7 +551,7 @@ theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2
|
||||
match l with
|
||||
| []
|
||||
| [a]
|
||||
| a::b::l => simp [Nat.succ_inj']
|
||||
| a::b::l => simp [Nat.succ_inj]
|
||||
|
||||
@[deprecated eraseIdx_ne_nil_iff (since := "2025-01-30")]
|
||||
abbrev eraseIdx_ne_nil := @eraseIdx_ne_nil_iff
|
||||
|
||||
@@ -95,10 +95,10 @@ theorem findSome?_eq_some_iff {f : α → Option β} {l : List α} {b : β} :
|
||||
| cons x xs ih =>
|
||||
simp [guard, findSome?, find?]
|
||||
split <;> rename_i h
|
||||
· simp only [Option.guard_eq_some] at h
|
||||
· simp only [Option.guard_eq_some_iff] at h
|
||||
obtain ⟨rfl, h⟩ := h
|
||||
simp [h]
|
||||
· simp only [Option.guard_eq_none] at h
|
||||
· simp only [Option.guard_eq_none_iff] at h
|
||||
simp [ih, h]
|
||||
|
||||
theorem find?_eq_findSome?_guard {l : List α} : find? p l = findSome? (Option.guard fun x => p x) l :=
|
||||
@@ -700,6 +700,7 @@ theorem findIdx?_eq_none_iff {xs : List α} {p : α → Bool} :
|
||||
simp only [findIdx?_cons]
|
||||
split <;> simp_all [cond_eq_if]
|
||||
|
||||
@[simp]
|
||||
theorem findIdx?_isSome {xs : List α} {p : α → Bool} :
|
||||
(xs.findIdx? p).isSome = xs.any p := by
|
||||
induction xs with
|
||||
@@ -708,6 +709,7 @@ theorem findIdx?_isSome {xs : List α} {p : α → Bool} :
|
||||
simp only [findIdx?_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp]
|
||||
theorem findIdx?_isNone {xs : List α} {p : α → Bool} :
|
||||
(xs.findIdx? p).isNone = xs.all (¬p ·) := by
|
||||
induction xs with
|
||||
@@ -768,7 +770,7 @@ theorem findIdx?_eq_some_iff_getElem {xs : List α} {p : α → Bool} {i : Nat}
|
||||
not_and, Classical.not_forall, Bool.not_eq_false]
|
||||
intros
|
||||
refine ⟨0, zero_lt_succ i, ‹_›⟩
|
||||
· simp only [Option.map_eq_some', ih, Bool.not_eq_true, length_cons]
|
||||
· simp only [Option.map_eq_some_iff, ih, Bool.not_eq_true, length_cons]
|
||||
constructor
|
||||
· rintro ⟨a, ⟨⟨h, h₁, h₂⟩, rfl⟩⟩
|
||||
refine ⟨Nat.succ_lt_succ_iff.mpr h, by simpa, fun j hj => ?_⟩
|
||||
@@ -790,7 +792,7 @@ theorem of_findIdx?_eq_some {xs : List α} {p : α → Bool} (w : xs.findIdx? p
|
||||
| nil => simp_all
|
||||
| cons x xs ih =>
|
||||
simp_all only [findIdx?_cons, Nat.zero_add]
|
||||
split at w <;> cases i <;> simp_all [succ_inj']
|
||||
split at w <;> cases i <;> simp_all [succ_inj]
|
||||
|
||||
@[deprecated of_findIdx?_eq_some (since := "2025-02-02")]
|
||||
abbrev findIdx?_of_eq_some := @of_findIdx?_eq_some
|
||||
@@ -824,7 +826,7 @@ abbrev findIdx?_of_eq_none := @of_findIdx?_eq_none
|
||||
(xs ++ ys : List α).findIdx? p =
|
||||
(xs.findIdx? p).or ((ys.findIdx? p).map fun i => i + xs.length) := by
|
||||
induction xs with simp
|
||||
| cons _ _ _ => split <;> simp_all [Option.map_or', Option.map_map]; rfl
|
||||
| cons _ _ _ => split <;> simp_all [Option.map_or, Option.map_map]; rfl
|
||||
|
||||
theorem findIdx?_flatten {l : List (List α)} {p : α → Bool} :
|
||||
l.flatten.findIdx? p =
|
||||
@@ -984,6 +986,24 @@ theorem findFinIdx?_eq_some_iff {xs : List α} {p : α → Bool} {i : Fin xs.len
|
||||
· rintro ⟨h, w⟩
|
||||
exact ⟨i, ⟨i.2, h, fun j hji => w ⟨j, by omega⟩ hji⟩, rfl⟩
|
||||
|
||||
@[simp]
|
||||
theorem isSome_findFinIdx? {l : List α} {p : α → Bool} :
|
||||
(l.findFinIdx? p).isSome = l.any p := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [findFinIdx?_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp]
|
||||
theorem isNone_findFinIdx? {l : List α} {p : α → Bool} :
|
||||
(l.findFinIdx? p).isNone = l.all (fun x => ¬ p x) := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [findFinIdx?_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[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
|
||||
@@ -1084,6 +1104,24 @@ theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : List α} {a : α} :
|
||||
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]
|
||||
|
||||
@[simp]
|
||||
theorem isSome_finIdxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
(l.finIdxOf? a).isSome ↔ a ∈ l := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [finIdxOf?_cons]
|
||||
split <;> simp_all [@eq_comm _ x a]
|
||||
|
||||
@[simp]
|
||||
theorem isNone_finIdxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
(l.finIdxOf? a).isNone = ¬ a ∈ l := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [finIdxOf?_cons]
|
||||
split <;> simp_all [@eq_comm _ x a]
|
||||
|
||||
/-! ### idxOf?
|
||||
|
||||
The verification API for `idxOf?` is still incomplete.
|
||||
@@ -1109,6 +1147,25 @@ 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
|
||||
|
||||
@[simp]
|
||||
theorem isSome_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
(l.idxOf? a).isSome ↔ a ∈ l := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [idxOf?_cons]
|
||||
split <;> simp_all [@eq_comm _ x a]
|
||||
|
||||
@[simp]
|
||||
theorem isNone_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
(l.idxOf? a).isNone = ¬ a ∈ l := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [idxOf?_cons]
|
||||
split <;> simp_all [@eq_comm _ x a]
|
||||
|
||||
|
||||
/-! ### lookup -/
|
||||
|
||||
section lookup
|
||||
|
||||
@@ -105,7 +105,7 @@ abbrev length_eq_zero := @length_eq_zero_iff
|
||||
theorem eq_nil_iff_length_eq_zero : l = [] ↔ length l = 0 :=
|
||||
length_eq_zero_iff.symm
|
||||
|
||||
@[grind] theorem length_pos_of_mem {a : α} : ∀ {l : List α}, a ∈ l → 0 < length l
|
||||
@[grind →] theorem length_pos_of_mem {a : α} : ∀ {l : List α}, a ∈ l → 0 < length l
|
||||
| _::_, _ => Nat.zero_lt_succ _
|
||||
|
||||
theorem exists_mem_of_length_pos : ∀ {l : List α}, 0 < length l → ∃ a, a ∈ l
|
||||
@@ -185,7 +185,7 @@ theorem singleton_inj {α : Type _} {a b : α} : [a] = [b] ↔ a = b := by
|
||||
We simplify `l.get i` to `l[i.1]'i.2` and `l.get? i` to `l[i]?`.
|
||||
-/
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem get_eq_getElem {l : List α} {i : Fin l.length} : l.get i = l[i.1]'i.2 := rfl
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@@ -225,7 +225,7 @@ theorem get?_eq_getElem? {l : List α} {i : Nat} : l.get? i = l[i]? := by
|
||||
We simplify `l[i]!` to `(l[i]?).getD default`.
|
||||
-/
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getElem!_eq_getElem?_getD [Inhabited α] {l : List α} {i : Nat} :
|
||||
l[i]! = (l[i]?).getD (default : α) := by
|
||||
simp only [getElem!_def]
|
||||
@@ -235,16 +235,16 @@ theorem getElem!_eq_getElem?_getD [Inhabited α] {l : List α} {i : Nat} :
|
||||
|
||||
/-! ### getElem? and getElem -/
|
||||
|
||||
@[simp, grind] theorem getElem?_nil {i : Nat} : ([] : List α)[i]? = none := rfl
|
||||
@[simp, grind =] theorem getElem?_nil {i : Nat} : ([] : List α)[i]? = none := rfl
|
||||
|
||||
theorem getElem_cons {l : List α} (w : i < (a :: l).length) :
|
||||
(a :: l)[i] =
|
||||
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
|
||||
|
||||
@[grind] theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := rfl
|
||||
@[grind =] theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := rfl
|
||||
|
||||
@[simp, grind] theorem getElem?_cons_succ {l : List α} : (a::l)[i+1]? = l[i]? := rfl
|
||||
@[simp, grind =] theorem getElem?_cons_succ {l : List α} : (a::l)[i+1]? = l[i]? := rfl
|
||||
|
||||
theorem getElem?_cons : (a :: l)[i]? = if i = 0 then some a else l[i-1]? := by
|
||||
cases i <;> simp [getElem?_cons_zero]
|
||||
@@ -259,6 +259,9 @@ theorem getElem?_eq_some_iff {l : List α} : l[i]? = some a ↔ ∃ h : i < l.le
|
||||
· match i, h with
|
||||
| i + 1, h => simp [getElem?_eq_some_iff, Nat.succ_lt_succ_iff]
|
||||
|
||||
theorem getElem_of_getElem? {l : List α} : l[i]? = some a → ∃ h : i < l.length, l[i] = a :=
|
||||
getElem?_eq_some_iff.mp
|
||||
|
||||
theorem some_eq_getElem?_iff {l : List α} : some a = l[i]? ↔ ∃ h : i < l.length, l[i] = a := by
|
||||
rw [eq_comm, getElem?_eq_some_iff]
|
||||
|
||||
@@ -337,7 +340,7 @@ We simplify away `getD`, replacing `getD l n a` with `(l[n]?).getD a`.
|
||||
Because of this, there is only minimal API for `getD`.
|
||||
-/
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getD_eq_getElem?_getD {l : List α} {i : Nat} {a : α} : getD l i a = (l[i]?).getD a := by
|
||||
simp [getD]
|
||||
|
||||
@@ -701,7 +704,7 @@ theorem set_comm (a b : α) : ∀ {i j : Nat} {l : List α}, i ≠ j →
|
||||
| _+1, 0, _ :: _, _ => by simp [set]
|
||||
| 0, _+1, _ :: _, _ => by simp [set]
|
||||
| _+1, _+1, _ :: t, h =>
|
||||
congrArg _ <| set_comm a b fun h' => h <| Nat.succ_inj'.mpr h'
|
||||
congrArg _ <| set_comm a b 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
|
||||
@@ -711,8 +714,8 @@ theorem set_set (a : α) {b : α} : ∀ {l : List α} {i : Nat}, (l.set i a).set
|
||||
|
||||
theorem mem_set {l : List α} {i : Nat} (h : i < l.length) (a : α) :
|
||||
a ∈ l.set i a := by
|
||||
simp [mem_iff_getElem]
|
||||
exact ⟨i, (by simpa using h), by simp⟩
|
||||
simp only [mem_iff_getElem]
|
||||
exact ⟨i, 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
|
||||
| _ :: _, 0, _, _, h => ((mem_cons ..).1 h).symm.imp_left (.tail _)
|
||||
@@ -774,37 +777,24 @@ theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l
|
||||
simpa only [List.instBEq, List.beq, Bool.and_true]
|
||||
simp
|
||||
· intro h
|
||||
constructor
|
||||
intro l
|
||||
induction l with
|
||||
| nil => simp only [List.instBEq, List.beq]
|
||||
| cons _ _ ih =>
|
||||
simp [List.instBEq, List.beq]
|
||||
exact ih
|
||||
infer_instance
|
||||
|
||||
@[simp] theorem lawfulBEq_iff [BEq α] : LawfulBEq (List α) ↔ LawfulBEq α := by
|
||||
constructor
|
||||
· intro h
|
||||
have : ReflBEq α := reflBEq_iff.mp inferInstance
|
||||
constructor
|
||||
· intro a b h
|
||||
apply singleton_inj.1
|
||||
apply eq_of_beq
|
||||
simp only [List.instBEq, List.beq]
|
||||
simpa
|
||||
· intro a
|
||||
suffices ([a] == [a]) = true by
|
||||
simpa only [List.instBEq, List.beq, Bool.and_true]
|
||||
simp
|
||||
intro a b h
|
||||
apply singleton_inj.1
|
||||
apply eq_of_beq
|
||||
simp only [List.instBEq, List.beq]
|
||||
simpa
|
||||
· intro h
|
||||
constructor
|
||||
· intro _ _ h
|
||||
simpa using h
|
||||
· intro _
|
||||
simp
|
||||
infer_instance
|
||||
|
||||
/-! ### isEqv -/
|
||||
|
||||
@[simp] theorem isEqv_eq [DecidableEq α] {l₁ l₂ : List α} : l₁.isEqv l₂ (· == ·) = (l₁ = l₂) := by
|
||||
@[simp] theorem isEqv_eq [BEq α] [LawfulBEq α] {l₁ l₂ : List α} : l₁.isEqv l₂ (· == ·) = (l₁ = l₂) := by
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil => cases l₂ <;> simp
|
||||
| cons a l₁ ih =>
|
||||
@@ -827,9 +817,15 @@ theorem getElem_length_sub_one_eq_getLast {l : List α} (h : l.length - 1 < l.le
|
||||
l[l.length - 1] = getLast l (by cases l; simp at h; simp) := by
|
||||
rw [← getLast_eq_getElem]
|
||||
|
||||
@[simp] theorem getLast_cons_cons {a : α} {l : List α} :
|
||||
getLast (a :: b :: l) (by simp) = getLast (b :: l) (by simp) := by
|
||||
rfl
|
||||
|
||||
theorem getLast_cons {a : α} {l : List α} : ∀ (h : l ≠ nil),
|
||||
getLast (a :: l) (cons_ne_nil a l) = getLast l h := by
|
||||
induction l <;> intros; {contradiction}; rfl
|
||||
induction l <;> intros
|
||||
· contradiction
|
||||
· rfl
|
||||
|
||||
theorem getLast_eq_getLastD {a l} (h) : @getLast α (a::l) h = getLastD l a := by
|
||||
cases l <;> rfl
|
||||
@@ -1296,7 +1292,7 @@ abbrev filter_length_eq_length := @length_filter_eq_length_iff
|
||||
|
||||
@[simp] theorem mem_filter : x ∈ filter p as ↔ x ∈ as ∧ p x := by
|
||||
induction as with
|
||||
| nil => simp [filter]
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
by_cases h : p a
|
||||
· simp_all [or_and_left]
|
||||
@@ -1362,12 +1358,9 @@ theorem filter_eq_cons_iff {l} {a} {as} :
|
||||
split at h <;> rename_i w
|
||||
· simp only [cons.injEq] at h
|
||||
obtain ⟨rfl, rfl⟩ := h
|
||||
refine ⟨[], l, ?_⟩
|
||||
simp [w]
|
||||
· specialize ih h
|
||||
obtain ⟨l₁, l₂, rfl, w₁, w₂, w₃⟩ := ih
|
||||
refine ⟨x :: l₁, l₂, ?_⟩
|
||||
simp_all
|
||||
exact ⟨[], l, by simp [w]⟩
|
||||
· obtain ⟨l₁, l₂, rfl, w₁, w₂, w₃⟩ := ih h
|
||||
exact ⟨x :: l₁, l₂, by simp_all⟩
|
||||
· rintro ⟨l₁, l₂, rfl, h₁, h, h₂⟩
|
||||
simp [h₂, filter_cons, filter_eq_nil_iff.mpr h₁, h]
|
||||
|
||||
@@ -2046,7 +2039,7 @@ theorem eq_iff_flatten_eq : ∀ {L L' : List (List α)},
|
||||
| _, [] => by simp_all
|
||||
| [], _ :: _ => by simp_all
|
||||
| _ :: _, _ :: _ => by
|
||||
simp
|
||||
simp only [cons.injEq, flatten_cons, map_cons]
|
||||
rw [eq_iff_flatten_eq]
|
||||
constructor
|
||||
· rintro ⟨rfl, h₁, h₂⟩
|
||||
@@ -2154,7 +2147,7 @@ theorem replicate_succ' : replicate (n + 1) a = replicate n a ++ [a] := by
|
||||
| 0 => by simp
|
||||
| n+1 => by simp [replicate_succ, mem_replicate, Nat.succ_ne_zero]
|
||||
|
||||
@[deprecated mem_replicate (since := "2024-09-05")]
|
||||
@[simp]
|
||||
theorem contains_replicate [BEq α] {n : Nat} {a b : α} :
|
||||
(replicate n b).contains a = (a == b && !n == 0) := by
|
||||
induction n with
|
||||
@@ -2165,9 +2158,9 @@ theorem contains_replicate [BEq α] {n : Nat} {a b : α} :
|
||||
|
||||
@[deprecated mem_replicate (since := "2024-09-05")]
|
||||
theorem decide_mem_replicate [BEq α] [LawfulBEq α] {a b : α} :
|
||||
∀ {n}, decide (b ∈ replicate n a) = ((¬ n == 0) && b == a)
|
||||
| 0 => by simp
|
||||
| n+1 => by simp [replicate_succ, decide_mem_replicate, Nat.succ_ne_zero]
|
||||
∀ {n}, decide (b ∈ replicate n a) = ((¬ n == 0) && b == a) := by
|
||||
have : DecidableEq α := instDecidableEqOfLawfulBEq
|
||||
simp [Bool.beq_eq_decide_eq]
|
||||
|
||||
theorem eq_of_mem_replicate {a b : α} {n} (h : b ∈ replicate n a) : b = a := (mem_replicate.1 h).2
|
||||
|
||||
@@ -2709,12 +2702,12 @@ theorem foldr_assoc {op : α → α → α} [ha : Std.Associative op] :
|
||||
-- The argument `f : α₁ → α₂` is intentionally explicit, as it is sometimes not found by unification.
|
||||
theorem foldl_hom (f : α₁ → α₂) {g₁ : α₁ → β → α₁} {g₂ : α₂ → β → α₂} {l : List β} {init : α₁}
|
||||
(H : ∀ x y, g₂ (f x) y = f (g₁ x y)) : l.foldl g₂ (f init) = f (l.foldl g₁ init) := by
|
||||
induction l generalizing init <;> simp [*, H]
|
||||
induction l generalizing init <;> simp [*]
|
||||
|
||||
-- The argument `f : β₁ → β₂` is intentionally explicit, as it is sometimes not found by unification.
|
||||
theorem foldr_hom (f : β₁ → β₂) {g₁ : α → β₁ → β₁} {g₂ : α → β₂ → β₂} {l : List α} {init : β₁}
|
||||
(H : ∀ x y, g₂ x (f y) = f (g₁ x y)) : l.foldr g₂ (f init) = f (l.foldr g₁ init) := by
|
||||
induction l <;> simp [*, H]
|
||||
induction l <;> simp [*]
|
||||
|
||||
/--
|
||||
A reasoning principle for proving propositions about the result of `List.foldl` by establishing an
|
||||
@@ -3260,6 +3253,10 @@ theorem eq_or_mem_of_mem_insert {l : List α} (h : a ∈ l.insert b) : a = b ∨
|
||||
@[simp] theorem length_insert_of_not_mem {l : List α} (h : a ∉ l) :
|
||||
length (l.insert a) = length l + 1 := by rw [insert_of_not_mem h]; rfl
|
||||
|
||||
theorem length_insert {l : List α} :
|
||||
(l.insert a).length = l.length + if a ∈ l then 0 else 1 := by
|
||||
split <;> simp_all
|
||||
|
||||
theorem length_le_length_insert {l : List α} {a : α} : l.length ≤ (l.insert a).length := by
|
||||
by_cases h : a ∈ l
|
||||
· rw [length_insert_of_mem h]
|
||||
|
||||
@@ -281,7 +281,7 @@ protected theorem le_iff_lt_or_eq [DecidableEq α] [LT α] [DecidableLT α]
|
||||
· exact List.le_of_lt h
|
||||
· exact List.le_refl l₁
|
||||
|
||||
theorem lex_eq_decide_lex [DecidableEq α] (lt : α → α → Bool) :
|
||||
theorem lex_eq_decide_lex [BEq α] [LawfulBEq α] [DecidableEq α] (lt : α → α → Bool) :
|
||||
lex l₁ l₂ lt = decide (Lex (fun x y => lt x y) l₁ l₂) := by
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil =>
|
||||
@@ -295,21 +295,22 @@ theorem lex_eq_decide_lex [DecidableEq α] (lt : α → α → Bool) :
|
||||
simp [lex, ih, cons_lex_cons_iff, Bool.beq_eq_decide_eq]
|
||||
|
||||
/-- Variant of `lex_eq_true_iff` using an arbitrary comparator. -/
|
||||
@[simp] theorem lex_eq_true_iff_lex [DecidableEq α] (lt : α → α → Bool) :
|
||||
@[simp] theorem lex_eq_true_iff_lex [BEq α] [LawfulBEq α] (lt : α → α → Bool) :
|
||||
lex l₁ l₂ lt = true ↔ Lex (fun x y => lt x y) l₁ l₂ := by
|
||||
have : DecidableEq α := instDecidableEqOfLawfulBEq
|
||||
simp [lex_eq_decide_lex]
|
||||
|
||||
/-- Variant of `lex_eq_false_iff` using an arbitrary comparator. -/
|
||||
@[simp] theorem lex_eq_false_iff_not_lex [DecidableEq α] (lt : α → α → Bool) :
|
||||
@[simp] theorem lex_eq_false_iff_not_lex [BEq α] [LawfulBEq α] (lt : α → α → Bool) :
|
||||
lex l₁ l₂ lt = false ↔ ¬ Lex (fun x y => lt x y) l₁ l₂ := by
|
||||
simp [Bool.eq_false_iff, lex_eq_true_iff_lex]
|
||||
|
||||
@[simp] theorem lex_eq_true_iff_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
@[simp] theorem lex_eq_true_iff_lt [BEq α] [LawfulBEq α] [LT α] [DecidableLT α]
|
||||
{l₁ l₂ : List α} : lex l₁ l₂ = true ↔ l₁ < l₂ := by
|
||||
simp only [lex_eq_true_iff_lex, decide_eq_true_eq]
|
||||
exact Iff.rfl
|
||||
|
||||
@[simp] theorem lex_eq_false_iff_ge [DecidableEq α] [LT α] [DecidableLT α]
|
||||
@[simp] theorem lex_eq_false_iff_ge [BEq α] [LawfulBEq α] [LT α] [DecidableLT α]
|
||||
{l₁ l₂ : List α} : lex l₁ l₂ = false ↔ l₂ ≤ l₁ := by
|
||||
simp only [lex_eq_false_iff_not_lex, decide_eq_true_eq]
|
||||
exact Iff.rfl
|
||||
|
||||
@@ -339,7 +339,7 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {acc : Array β} {i : Nat},
|
||||
if h : i < acc.size then some acc[i] else Option.map (f i) l[i - acc.size]?
|
||||
| [], acc, 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']
|
||||
← Array.getElem_toList, length_nil, Nat.not_lt_zero, ↓reduceDIte, Option.map_none]
|
||||
| a :: l, acc, i => by
|
||||
rw [mapIdx.go, getElem?_mapIdx_go]
|
||||
simp only [Array.size_push]
|
||||
|
||||
@@ -118,7 +118,7 @@ theorem mem_eraseIdx_iff_getElem {x : α} :
|
||||
| a::l, 0 => by simp [mem_iff_getElem, Nat.succ_lt_succ_iff]
|
||||
| a::l, k+1 => by
|
||||
rw [← Nat.or_exists_add_one]
|
||||
simp [mem_eraseIdx_iff_getElem, @eq_comm _ a, succ_inj', Nat.succ_lt_succ_iff]
|
||||
simp [mem_eraseIdx_iff_getElem, @eq_comm _ a, succ_inj, Nat.succ_lt_succ_iff]
|
||||
|
||||
theorem mem_eraseIdx_iff_getElem? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i ≠ k, l[i]? = some x := by
|
||||
simp only [mem_eraseIdx_iff_getElem, getElem_eq_iff, exists_and_left]
|
||||
|
||||
@@ -31,6 +31,33 @@ theorem count_set [BEq α] {a b : α} {l : List α} {i : Nat} (h : i < l.length)
|
||||
(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]
|
||||
|
||||
theorem countP_replace [BEq α] [LawfulBEq α] {a b : α} {l : List α} {p : α → Bool} :
|
||||
(l.replace a b).countP p =
|
||||
if l.contains a then l.countP p + (if p b then 1 else 0) - (if p a then 1 else 0) else l.countP p := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x l ih =>
|
||||
simp [replace_cons]
|
||||
split <;> rename_i h
|
||||
· simp at h
|
||||
simp [h, ih, countP_cons]
|
||||
omega
|
||||
· simp only [beq_eq_false_iff_ne, ne_eq] at h
|
||||
simp only [countP_cons, ih, contains_eq_mem, decide_eq_true_eq, mem_cons, h, false_or]
|
||||
split <;> rename_i h'
|
||||
· by_cases h'' : p a
|
||||
· have : countP p l > 0 := countP_pos_iff.mpr ⟨a, h', h''⟩
|
||||
simp [h'']
|
||||
omega
|
||||
· simp [h'']
|
||||
omega
|
||||
· omega
|
||||
|
||||
theorem count_replace [BEq α] [LawfulBEq α] {a b c : α} {l : List α} :
|
||||
(l.replace a b).count c =
|
||||
if l.contains a then l.count c + (if b == c then 1 else 0) - (if a == c then 1 else 0) else l.count c := by
|
||||
simp [count_eq_countP, countP_replace]
|
||||
|
||||
/--
|
||||
The number of elements satisfying a predicate in a sublist is at least the number of elements satisfying the predicate in the list,
|
||||
minus the difference in the lengths.
|
||||
|
||||
@@ -54,4 +54,23 @@ theorem set_set_perm {as : List α} {i j : Nat} (h₁ : i < as.length) (h₂ : j
|
||||
subst t
|
||||
apply set_set_perm' _ _ (by omega)
|
||||
|
||||
namespace Perm
|
||||
|
||||
/-- Variant of `List.Perm.take` specifying the the permutation is constant after `i` elementwise. -/
|
||||
theorem take_of_getElem? {l₁ l₂ : List α} (h : l₁ ~ l₂) {i : Nat} (w : ∀ j, i ≤ j → l₁[j]? = l₂[j]?) :
|
||||
l₁.take i ~ l₂.take i := by
|
||||
refine h.take (Perm.of_eq ?_)
|
||||
ext1 j
|
||||
simpa using w (i + j) (by omega)
|
||||
|
||||
/-- Variant of `List.Perm.drop` specifying the the permutation is constant before `i` elementwise. -/
|
||||
theorem drop_of_getElem? {l₁ l₂ : List α} (h : l₁ ~ l₂) {i : Nat} (w : ∀ j, j < i → l₁[j]? = l₂[j]?) :
|
||||
l₁.drop i ~ l₂.drop i := by
|
||||
refine h.drop (Perm.of_eq ?_)
|
||||
ext1
|
||||
simp only [getElem?_take]
|
||||
split <;> simp_all
|
||||
|
||||
end Perm
|
||||
|
||||
end List
|
||||
|
||||
@@ -40,7 +40,6 @@ theorem getLast?_range' {n : Nat} : (range' s n).getLast? = if n = 0 then none e
|
||||
simp [h]
|
||||
· rw [if_neg h]
|
||||
simp
|
||||
omega
|
||||
|
||||
@[simp] theorem getLast_range' {n : Nat} (h) : (range' s n).getLast h = s + n - 1 := by
|
||||
cases n with
|
||||
@@ -358,7 +357,7 @@ theorem zipIdx_singleton {x : α} {k : Nat} : zipIdx [x] k = [(x, k)] :=
|
||||
@[simp] theorem getLast?_zipIdx {l : List α} {k : Nat} :
|
||||
(zipIdx l k).getLast? = l.getLast?.map fun a => (a, k + l.length - 1) := by
|
||||
simp [getLast?_eq_getElem?]
|
||||
cases l <;> simp; omega
|
||||
cases l <;> simp
|
||||
|
||||
theorem mk_add_mem_zipIdx_iff_getElem? {k i : Nat} {x : α} {l : List α} :
|
||||
(x, k + i) ∈ zipIdx l k ↔ l[i]? = some x := by
|
||||
@@ -497,7 +496,7 @@ theorem head?_enumFrom (n : Nat) (l : List α) :
|
||||
theorem getLast?_enumFrom (n : Nat) (l : List α) :
|
||||
(enumFrom n l).getLast? = l.getLast?.map fun a => (n + l.length - 1, a) := by
|
||||
simp [getLast?_eq_getElem?]
|
||||
cases l <;> simp; omega
|
||||
cases l <;> simp
|
||||
|
||||
@[deprecated mk_add_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
theorem mk_add_mem_enumFrom_iff_getElem? {n i : Nat} {x : α} {l : List α} :
|
||||
|
||||
@@ -532,7 +532,7 @@ theorem dropWhile_eq_drop_findIdx_not {xs : List α} {p : α → Bool} :
|
||||
| zero => simp
|
||||
| succ n =>
|
||||
suffices 1 < m → m - (m - (n + 1) % m) + min (m - (n + 1) % m) m = m by
|
||||
simpa [rotateRight]
|
||||
simp [rotateRight]
|
||||
intro h
|
||||
have : (n + 1) % m < m := Nat.mod_lt _ (by omega)
|
||||
rw [Nat.min_eq_left (by omega)]
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
|
||||
prelude
|
||||
import Init.Data.List.Pairwise
|
||||
import Init.Data.List.Erase
|
||||
import Init.Data.List.Find
|
||||
|
||||
/-!
|
||||
# List Permutations
|
||||
@@ -178,7 +179,7 @@ theorem Perm.singleton_eq (h : [a] ~ l) : [a] = l := singleton_perm.mp h
|
||||
|
||||
theorem singleton_perm_singleton {a b : α} : [a] ~ [b] ↔ a = b := by simp
|
||||
|
||||
theorem perm_cons_erase [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) : l ~ a :: l.erase a :=
|
||||
theorem perm_cons_erase [BEq α] [LawfulBEq α] {a : α} {l : List α} (h : a ∈ l) : l ~ a :: l.erase a :=
|
||||
let ⟨_, _, _, e₁, e₂⟩ := exists_erase_eq h
|
||||
e₂ ▸ e₁ ▸ perm_middle
|
||||
|
||||
@@ -201,6 +202,9 @@ theorem Perm.pmap {p : α → Prop} (f : ∀ a, p a → β) {l₁ l₂ : List α
|
||||
| swap x y => simp [swap]
|
||||
| trans _p₁ p₂ IH₁ IH₂ => exact IH₁.trans (IH₂ (H₁ := fun a m => H₂ a (p₂.subset m)))
|
||||
|
||||
theorem Perm.unattach {α : Type u} {p : α → Prop} {l₁ l₂ : List { x // p x }} (h : l₁ ~ l₂) :
|
||||
l₁.unattach.Perm l₂.unattach := h.map _
|
||||
|
||||
theorem Perm.filter (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) :
|
||||
filter p l₁ ~ filter p l₂ := by rw [← filterMap_eq_filter]; apply s.filterMap
|
||||
|
||||
@@ -268,7 +272,7 @@ theorem countP_eq_countP_filter_add (l : List α) (p q : α → Bool) :
|
||||
l.countP p = (l.filter q).countP p + (l.filter fun a => !q a).countP p :=
|
||||
countP_append .. ▸ Perm.countP_eq _ (filter_append_perm _ _).symm
|
||||
|
||||
theorem Perm.count_eq [DecidableEq α] {l₁ l₂ : List α} (p : l₁ ~ l₂) (a) :
|
||||
theorem Perm.count_eq [BEq α] {l₁ l₂ : List α} (p : l₁ ~ l₂) (a) :
|
||||
count a l₁ = count a l₂ := p.countP_eq _
|
||||
|
||||
/-
|
||||
@@ -369,9 +373,9 @@ theorem perm_append_right_iff {l₁ l₂ : List α} (l) : l₁ ++ l ~ l₂ ++ l
|
||||
refine ⟨fun p => ?_, .append_right _⟩
|
||||
exact (perm_append_left_iff _).1 <| perm_append_comm.trans <| p.trans perm_append_comm
|
||||
|
||||
section DecidableEq
|
||||
section LawfulBEq
|
||||
|
||||
variable [DecidableEq α]
|
||||
variable [BEq α] [LawfulBEq α]
|
||||
|
||||
theorem Perm.erase (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.erase a ~ l₂.erase a :=
|
||||
if h₁ : a ∈ l₁ then
|
||||
@@ -401,14 +405,14 @@ theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l
|
||||
refine ((IH fun b => ?_).cons a).trans (perm_cons_erase this).symm
|
||||
specialize H b
|
||||
rw [(perm_cons_erase this).count_eq] at H
|
||||
by_cases h : b = a <;> simpa [h, count_cons, Nat.succ_inj'] using H
|
||||
by_cases h : b = a <;> simpa [h, count_cons, Nat.succ_inj] using H
|
||||
|
||||
theorem isPerm_iff : ∀ {l₁ l₂ : List α}, l₁.isPerm l₂ ↔ l₁ ~ l₂
|
||||
| [], [] => by simp [isPerm, isEmpty]
|
||||
| [], _ :: _ => by simp [isPerm, isEmpty, Perm.nil_eq]
|
||||
| a :: l₁, l₂ => by simp [isPerm, isPerm_iff, cons_perm_iff_perm_erase]
|
||||
|
||||
instance decidablePerm (l₁ l₂ : List α) : Decidable (l₁ ~ l₂) := decidable_of_iff _ isPerm_iff
|
||||
instance decidablePerm {α} [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ ~ l₂) := decidable_of_iff _ isPerm_iff
|
||||
|
||||
protected theorem Perm.insert (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) :
|
||||
l₁.insert a ~ l₂.insert a := by
|
||||
@@ -425,7 +429,7 @@ theorem perm_insert_swap (x y : α) (l : List α) :
|
||||
simp [List.insert, xl, yl, xy, Ne.symm xy]
|
||||
constructor
|
||||
|
||||
end DecidableEq
|
||||
end LawfulBEq
|
||||
|
||||
theorem Perm.pairwise_iff {R : α → α → Prop} (S : ∀ {x y}, R x y → R y x) :
|
||||
∀ {l₁ l₂ : List α} (_p : l₁ ~ l₂), Pairwise R l₁ ↔ Pairwise R l₂ :=
|
||||
@@ -536,4 +540,22 @@ theorem perm_insertIdx {α} (x : α) (l : List α) {i} (h : i ≤ l.length) :
|
||||
simp only [insertIdx, modifyTailIdx]
|
||||
refine .trans (.cons _ (ih (Nat.le_of_succ_le_succ h))) (.swap ..)
|
||||
|
||||
namespace Perm
|
||||
|
||||
theorem take {l₁ l₂ : List α} (h : l₁ ~ l₂) {n : Nat} (w : l₁.drop n ~ l₂.drop n) :
|
||||
l₁.take n ~ l₂.take n := by
|
||||
classical
|
||||
rw [perm_iff_count] at h w ⊢
|
||||
rw [← take_append_drop n l₁, ← take_append_drop n l₂] at h
|
||||
simpa only [count_append, w, Nat.add_right_cancel_iff] using h
|
||||
|
||||
theorem drop {l₁ l₂ : List α} (h : l₁ ~ l₂) {n : Nat} (w : l₁.take n ~ l₂.take n) :
|
||||
l₁.drop n ~ l₂.drop n := by
|
||||
classical
|
||||
rw [perm_iff_count] at h w ⊢
|
||||
rw [← take_append_drop n l₁, ← take_append_drop n l₂] at h
|
||||
simpa only [count_append, w, Nat.add_left_cancel_iff] using h
|
||||
|
||||
end Perm
|
||||
|
||||
end List
|
||||
|
||||
@@ -69,7 +69,7 @@ theorem mem_range' : ∀ {n}, m ∈ range' s n step ↔ ∃ i < n, m = s + step
|
||||
| 0 => by simp [range', Nat.not_lt_zero]
|
||||
| n + 1 => by
|
||||
have h (i) : i ≤ n ↔ i = 0 ∨ ∃ j, i = succ j ∧ j < n := by
|
||||
cases i <;> simp [Nat.succ_le, Nat.succ_inj']
|
||||
cases i <;> simp [Nat.succ_le, Nat.succ_inj]
|
||||
simp [range', mem_range', Nat.lt_succ, h]; simp only [← exists_and_right, and_assoc]
|
||||
rw [exists_comm]; simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm]
|
||||
|
||||
|
||||
@@ -220,7 +220,7 @@ theorem zipWith_eq_append_iff {f : α → β → γ} {l₁ : List α} {l₂ : Li
|
||||
· simp_all
|
||||
· obtain (⟨rfl, rfl⟩ | ⟨_, rfl, rfl⟩) := h₃
|
||||
· simp_all
|
||||
· simp_all [zipWith_append, Nat.succ_inj']
|
||||
· simp_all [zipWith_append, Nat.succ_inj]
|
||||
|
||||
/-- See also `List.zipWith_replicate` in `Init.Data.List.TakeDrop` for a generalization with different lengths. -/
|
||||
@[simp] theorem zipWith_replicate' {a : α} {b : β} {n : Nat} :
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Floris van Doorn, Leonardo de Moura
|
||||
prelude
|
||||
import Init.SimpLemmas
|
||||
import Init.Data.NeZero
|
||||
import Init.Grind.Tactics
|
||||
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
universe u
|
||||
@@ -545,6 +546,10 @@ protected theorem le_of_add_le_add_right {a b c : Nat} : a + b ≤ c + b → a
|
||||
|
||||
/-! ### le/lt -/
|
||||
|
||||
attribute [simp] not_lt_zero
|
||||
|
||||
example : (default : Nat) = 0 := rfl
|
||||
|
||||
protected theorem lt_asymm {a b : Nat} (h : a < b) : ¬ b < a := Nat.not_lt.2 (Nat.le_of_lt h)
|
||||
/-- Alias for `Nat.lt_asymm`. -/
|
||||
protected abbrev not_lt_of_gt := @Nat.lt_asymm
|
||||
@@ -617,7 +622,7 @@ protected theorem eq_zero_of_not_pos (h : ¬0 < n) : n = 0 :=
|
||||
|
||||
attribute [simp] zero_lt_succ
|
||||
|
||||
theorem succ_ne_self (n) : succ n ≠ n := Nat.ne_of_gt (lt_succ_self n)
|
||||
@[simp] theorem succ_ne_self (n) : succ n ≠ n := Nat.ne_of_gt (lt_succ_self n)
|
||||
|
||||
theorem add_one_ne_self (n) : n + 1 ≠ n := Nat.ne_of_gt (lt_succ_self n)
|
||||
|
||||
@@ -640,13 +645,20 @@ theorem eq_zero_or_eq_succ_pred : ∀ n, n = 0 ∨ n = succ (pred n)
|
||||
| 0 => .inl rfl
|
||||
| _+1 => .inr rfl
|
||||
|
||||
theorem succ_inj' : succ a = succ b ↔ a = b := (Nat.succ.injEq a b).to_iff
|
||||
theorem succ_inj : succ a = succ b ↔ a = b := (Nat.succ.injEq a b).to_iff
|
||||
|
||||
@[deprecated succ_inj (since := "2025-04-14")]
|
||||
theorem succ_inj' : succ a = succ b ↔ a = b := succ_inj
|
||||
|
||||
theorem succ_le_succ_iff : succ a ≤ succ b ↔ a ≤ b := ⟨le_of_succ_le_succ, succ_le_succ⟩
|
||||
|
||||
theorem succ_lt_succ_iff : succ a < succ b ↔ a < b := ⟨lt_of_succ_lt_succ, succ_lt_succ⟩
|
||||
|
||||
theorem add_one_inj : a + 1 = b + 1 ↔ a = b := succ_inj'
|
||||
theorem succ_ne_succ_iff : succ a ≠ succ b ↔ a ≠ b := by simp [Nat.succ.injEq]
|
||||
|
||||
theorem succ_succ_ne_one (a : Nat) : succ (succ a) ≠ 1 := nofun
|
||||
|
||||
theorem add_one_inj : a + 1 = b + 1 ↔ a = b := succ_inj
|
||||
|
||||
theorem ne_add_one (n : Nat) : n ≠ n + 1 := fun h => by cases h
|
||||
|
||||
@@ -656,6 +668,10 @@ theorem add_one_le_add_one_iff : a + 1 ≤ b + 1 ↔ a ≤ b := succ_le_succ_iff
|
||||
|
||||
theorem add_one_lt_add_one_iff : a + 1 < b + 1 ↔ a < b := succ_lt_succ_iff
|
||||
|
||||
theorem add_one_ne_add_one_iff : a + 1 ≠ b + 1 ↔ a ≠ b := succ_ne_succ_iff
|
||||
|
||||
theorem add_one_add_one_ne_one : a + 1 + 1 ≠ 1 := nofun
|
||||
|
||||
theorem pred_inj : ∀ {a b}, 0 < a → 0 < b → pred a = pred b → a = b
|
||||
| _+1, _+1, _, _ => congrArg _
|
||||
|
||||
@@ -713,16 +729,18 @@ theorem exists_eq_add_one_of_ne_zero : ∀ {n}, n ≠ 0 → Exists fun k => n =
|
||||
theorem ctor_eq_zero : Nat.zero = 0 :=
|
||||
rfl
|
||||
|
||||
protected theorem one_ne_zero : 1 ≠ (0 : Nat) :=
|
||||
@[simp] protected theorem one_ne_zero : 1 ≠ (0 : Nat) :=
|
||||
fun h => Nat.noConfusion h
|
||||
|
||||
protected theorem zero_ne_one : 0 ≠ (1 : Nat) :=
|
||||
@[simp] protected theorem zero_ne_one : 0 ≠ (1 : Nat) :=
|
||||
fun h => Nat.noConfusion h
|
||||
|
||||
theorem succ_ne_zero (n : Nat) : succ n ≠ 0 := by simp
|
||||
@[simp] theorem succ_ne_zero (n : Nat) : succ n ≠ 0 := by simp
|
||||
|
||||
instance instNeZeroSucc {n : Nat} : NeZero (n + 1) := ⟨succ_ne_zero n⟩
|
||||
|
||||
@[simp] theorem default_eq_zero : default = 0 := rfl
|
||||
|
||||
/-! # mul + order -/
|
||||
|
||||
theorem mul_le_mul_left {n m : Nat} (k : Nat) (h : n ≤ m) : k * n ≤ k * m :=
|
||||
@@ -867,7 +885,7 @@ Examples:
|
||||
-/
|
||||
protected abbrev min (n m : Nat) := min n m
|
||||
|
||||
protected theorem min_def {n m : Nat} : min n m = if n ≤ m then n else m := rfl
|
||||
@[grind =] protected theorem min_def {n m : Nat} : min n m = if n ≤ m then n else m := rfl
|
||||
|
||||
instance : Max Nat := maxOfLe
|
||||
|
||||
@@ -884,7 +902,7 @@ Examples:
|
||||
-/
|
||||
protected abbrev max (n m : Nat) := max n m
|
||||
|
||||
protected theorem max_def {n m : Nat} : max n m = if n ≤ m then m else n := rfl
|
||||
@[grind =] protected theorem max_def {n m : Nat} : max n m = if n ≤ m then m else n := rfl
|
||||
|
||||
|
||||
/-! # Auxiliary theorems for well-founded recursion -/
|
||||
@@ -1002,7 +1020,7 @@ protected theorem add_sub_add_left (k n m : Nat) : (k + n) - (k + m) = n - m :=
|
||||
suffices n + m - (0 + m) = n by rw [Nat.zero_add] at this; assumption
|
||||
by rw [Nat.add_sub_add_right, Nat.sub_zero]
|
||||
|
||||
protected theorem add_sub_cancel_left (n m : Nat) : n + m - n = m :=
|
||||
@[simp] protected theorem add_sub_cancel_left (n m : Nat) : n + m - n = m :=
|
||||
show n + m - (n + 0) = m from
|
||||
by rw [Nat.add_sub_add_left, Nat.sub_zero]
|
||||
|
||||
@@ -1053,7 +1071,7 @@ protected theorem sub_self_add (n m : Nat) : n - (n + m) = 0 := by
|
||||
show (n + 0) - (n + m) = 0
|
||||
rw [Nat.add_sub_add_left, Nat.zero_sub]
|
||||
|
||||
protected theorem sub_eq_zero_of_le {n m : Nat} (h : n ≤ m) : n - m = 0 := by
|
||||
@[simp] protected theorem sub_eq_zero_of_le {n m : Nat} (h : n ≤ m) : n - m = 0 := by
|
||||
match le.dest h with
|
||||
| ⟨k, hk⟩ => rw [← hk, Nat.sub_self_add]
|
||||
|
||||
|
||||
@@ -473,7 +473,8 @@ Nat.le_antisymm
|
||||
(le_of_lt_succ ((Nat.div_lt_iff_lt_mul npos).2 hi))
|
||||
((Nat.le_div_iff_mul_le npos).2 lo)
|
||||
|
||||
theorem sub_mul_div (x n p : Nat) (h₁ : n*p ≤ x) : (x - n*p) / n = x / n - p := by
|
||||
/-- See also `sub_mul_div` for a strictly more general version. -/
|
||||
theorem sub_mul_div_of_le (x n p : Nat) (h₁ : n*p ≤ x) : (x - n*p) / n = x / n - p := by
|
||||
match eq_zero_or_pos n with
|
||||
| .inl h₀ => rw [h₀, Nat.div_zero, Nat.div_zero, Nat.zero_sub]
|
||||
| .inr h₀ => induction p with
|
||||
@@ -551,7 +552,7 @@ protected theorem div_le_of_le_mul {m n : Nat} : ∀ {k}, m ≤ k * n → m / k
|
||||
@[simp] theorem mul_div_left (m : Nat) {n : Nat} (H : 0 < n) : m * n / n = m := by
|
||||
rw [Nat.mul_comm, mul_div_right _ H]
|
||||
|
||||
protected theorem div_self (H : 0 < n) : n / n = 1 := by
|
||||
@[simp] protected theorem div_self (H : 0 < n) : n / n = 1 := by
|
||||
let t := add_div_right 0 H
|
||||
rwa [Nat.zero_add, Nat.zero_div] at t
|
||||
|
||||
|
||||
@@ -84,6 +84,10 @@ theorem div_le_div_left (hcb : c ≤ b) (hc : 0 < c) : a / b ≤ a / c :=
|
||||
(Nat.le_div_iff_mul_le hc).2 <|
|
||||
Nat.le_trans (Nat.mul_le_mul_left _ hcb) (Nat.div_mul_le_self a b)
|
||||
|
||||
protected theorem div_le_div {a b c d : Nat} (h1 : a ≤ b) (h2 : d ≤ c) (h3 : d ≠ 0) : a / c ≤ b / d :=
|
||||
calc a / c ≤ b / c := Nat.div_le_div_right h1
|
||||
_ ≤ b / d := Nat.div_le_div_left h2 (Nat.pos_of_ne_zero h3)
|
||||
|
||||
theorem div_add_le_right {z : Nat} (h : 0 < z) (x y : Nat) :
|
||||
x / (y + z) ≤ x / z :=
|
||||
div_le_div_left (Nat.le_add_left z y) h
|
||||
@@ -104,7 +108,7 @@ theorem succ_div_of_dvd {a b : Nat} (h : b ∣ a + 1) :
|
||||
Nat.add_right_cancel_iff] at h
|
||||
subst h
|
||||
rw [Nat.add_sub_cancel, ← Nat.add_one_mul, mul_div_right _ (zero_lt_succ _), Nat.add_comm,
|
||||
Nat.add_mul_div_left _ _ (zero_lt_succ _), Nat.self_eq_add_left, div_eq_of_lt le.refl]
|
||||
Nat.add_mul_div_left _ _ (zero_lt_succ _), Nat.right_eq_add, div_eq_of_lt le.refl]
|
||||
· simp only [Nat.not_le] at h'
|
||||
replace h' : a + 1 < b + 1 := Nat.add_lt_add_right h' 1
|
||||
rw [Nat.mod_eq_of_lt h'] at h
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Copyright (c) 2014 Floris van Doorn (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
|
||||
Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro, Floris van Doorn
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Nat.MinMax
|
||||
import Init.Data.Nat.Log2
|
||||
import Init.Data.Nat.Power2
|
||||
import Init.Data.Nat.Mod
|
||||
import Init.Omega
|
||||
|
||||
/-! # Basic lemmas about natural numbers
|
||||
/-! # Basic theorems about natural numbers
|
||||
|
||||
The primary purpose of the lemmas in this file is to assist with reasoning
|
||||
The primary purpose of the theorems in this file is to assist with reasoning
|
||||
about sizes of objects, array indices and such.
|
||||
|
||||
This file was upstreamed from Std,
|
||||
and later these lemmas should be organised into other files more systematically.
|
||||
The content of this file was upstreamed from Batteries and mathlib,
|
||||
and later these theorems should be organised into other files more systematically.
|
||||
-/
|
||||
|
||||
namespace Nat
|
||||
@@ -100,13 +101,94 @@ theorem exists_lt_succ_left {p : Nat → Prop} :
|
||||
(∃ m, m < n + 1 ∧ p m) ↔ p 0 ∨ (∃ m, m < n ∧ p (m + 1)) := by
|
||||
simpa using exists_lt_succ_left' (p := fun m _ => p m)
|
||||
|
||||
/-! ## succ/pred -/
|
||||
|
||||
protected theorem sub_one (n) : n - 1 = pred n := rfl
|
||||
|
||||
theorem one_add (n) : 1 + n = succ n := Nat.add_comm ..
|
||||
|
||||
theorem succ_ne_succ : succ m ≠ succ n ↔ m ≠ n :=
|
||||
⟨mt (congrArg Nat.succ ·), mt succ.inj⟩
|
||||
|
||||
theorem one_lt_succ_succ (n : Nat) : 1 < n.succ.succ := succ_lt_succ <| succ_pos _
|
||||
|
||||
theorem not_succ_lt_self : ¬ succ n < n := Nat.not_lt_of_ge n.le_succ
|
||||
|
||||
theorem succ_le_iff : succ m ≤ n ↔ m < n := ⟨lt_of_succ_le, succ_le_of_lt⟩
|
||||
|
||||
theorem le_succ_iff {m n : Nat} : m ≤ n.succ ↔ m ≤ n ∨ m = n.succ := by
|
||||
refine ⟨fun hmn ↦ (Nat.lt_or_eq_of_le hmn).imp_left le_of_lt_succ, ?_⟩
|
||||
rintro (hmn | rfl)
|
||||
· exact le_succ_of_le hmn
|
||||
· exact Nat.le_refl _
|
||||
|
||||
theorem lt_iff_le_pred : ∀ {n}, 0 < n → (m < n ↔ m ≤ n - 1) | _ + 1, _ => Nat.lt_succ_iff
|
||||
|
||||
-- TODO: state LHS using `- 1` instead?
|
||||
theorem le_of_pred_lt : ∀ {m}, pred m < n → m ≤ n
|
||||
| 0 => Nat.le_of_lt
|
||||
| _ + 1 => id
|
||||
|
||||
theorem lt_iff_add_one_le : m < n ↔ m + 1 ≤ n := by rw [succ_le_iff]
|
||||
|
||||
theorem lt_one_add_iff : m < 1 + n ↔ m ≤ n := by simp only [Nat.add_comm, Nat.lt_succ_iff]
|
||||
|
||||
theorem one_add_le_iff : 1 + m ≤ n ↔ m < n := by simp only [Nat.add_comm, add_one_le_iff]
|
||||
|
||||
theorem one_le_iff_ne_zero : 1 ≤ n ↔ n ≠ 0 := Nat.pos_iff_ne_zero
|
||||
|
||||
theorem one_lt_iff_ne_zero_and_ne_one : ∀ {n : Nat}, 1 < n ↔ n ≠ 0 ∧ n ≠ 1
|
||||
| 0 => by decide
|
||||
| 1 => by decide
|
||||
| n + 2 => by omega
|
||||
|
||||
theorem le_one_iff_eq_zero_or_eq_one : ∀ {n : Nat}, n ≤ 1 ↔ n = 0 ∨ n = 1 := by simp [le_succ_iff]
|
||||
|
||||
theorem one_le_of_lt (h : a < b) : 1 ≤ b := Nat.lt_of_le_of_lt (Nat.zero_le _) h
|
||||
|
||||
theorem pred_one_add (n : Nat) : pred (1 + n) = n := by rw [Nat.add_comm, add_one, Nat.pred_succ]
|
||||
|
||||
theorem pred_eq_self_iff : n.pred = n ↔ n = 0 := by cases n <;> simp [(Nat.succ_ne_self _).symm]
|
||||
|
||||
theorem pred_eq_of_eq_succ {m n : Nat} (H : m = n.succ) : m.pred = n := by simp [H]
|
||||
|
||||
@[simp] theorem pred_eq_succ_iff : n - 1 = m + 1 ↔ n = m + 2 := by
|
||||
cases n <;> constructor <;> rintro ⟨⟩ <;> rfl
|
||||
|
||||
@[simp] theorem add_succ_sub_one (m n : Nat) : m + succ n - 1 = m + n := rfl
|
||||
|
||||
@[simp]
|
||||
theorem succ_add_sub_one (n m : Nat) : succ m + n - 1 = m + n := by rw [succ_add, Nat.add_one_sub_one]
|
||||
|
||||
theorem pred_sub (n m : Nat) : pred n - m = pred (n - m) := by
|
||||
rw [← Nat.sub_one, Nat.sub_sub, one_add, sub_succ]
|
||||
|
||||
theorem self_add_sub_one : ∀ n, n + (n - 1) = 2 * n - 1
|
||||
| 0 => rfl
|
||||
| n + 1 => by rw [Nat.two_mul]; exact (add_succ_sub_one (Nat.succ _) _).symm
|
||||
|
||||
theorem sub_one_add_self (n : Nat) : (n - 1) + n = 2 * n - 1 := Nat.add_comm _ n ▸ self_add_sub_one n
|
||||
|
||||
theorem self_add_pred (n : Nat) : n + pred n = (2 * n).pred := self_add_sub_one n
|
||||
theorem pred_add_self (n : Nat) : pred n + n = (2 * n).pred := sub_one_add_self n
|
||||
|
||||
theorem pred_le_iff : pred m ≤ n ↔ m ≤ succ n :=
|
||||
⟨le_succ_of_pred_le, by
|
||||
cases m
|
||||
· exact fun _ ↦ zero_le n
|
||||
· exact le_of_succ_le_succ⟩
|
||||
|
||||
theorem lt_of_lt_pred (h : m < n - 1) : m < n := by omega
|
||||
|
||||
theorem le_add_pred_of_pos (a : Nat) (hb : b ≠ 0) : a ≤ b + (a - 1) := by omega
|
||||
|
||||
theorem lt_pred_iff : a < pred b ↔ succ a < b := by simp; omega
|
||||
|
||||
/-! ## add -/
|
||||
|
||||
protected theorem add_add_add_comm (a b c d : Nat) : (a + b) + (c + d) = (a + c) + (b + d) := by
|
||||
rw [Nat.add_assoc, Nat.add_assoc, Nat.add_left_comm b]
|
||||
|
||||
theorem one_add (n) : 1 + n = succ n := Nat.add_comm ..
|
||||
|
||||
theorem succ_eq_one_add (n) : succ n = 1 + n := (one_add _).symm
|
||||
|
||||
theorem succ_add_eq_add_succ (a b) : succ a + b = a + succ b := Nat.succ_add ..
|
||||
@@ -114,19 +196,31 @@ theorem succ_add_eq_add_succ (a b) : succ a + b = a + succ b := Nat.succ_add ..
|
||||
protected theorem eq_zero_of_add_eq_zero_right (h : n + m = 0) : n = 0 :=
|
||||
(Nat.eq_zero_of_add_eq_zero h).1
|
||||
|
||||
@[simp] protected theorem add_eq_zero_iff : n + m = 0 ↔ n = 0 ∧ m = 0 :=
|
||||
protected theorem add_eq_zero_iff : n + m = 0 ↔ n = 0 ∧ m = 0 :=
|
||||
⟨Nat.eq_zero_of_add_eq_zero, fun ⟨h₁, h₂⟩ => h₂.symm ▸ h₁⟩
|
||||
|
||||
@[simp] protected theorem add_left_cancel_iff {n : Nat} : n + m = n + k ↔ m = k :=
|
||||
@[simp high] protected theorem add_left_cancel_iff {n : Nat} : n + m = n + k ↔ m = k :=
|
||||
⟨Nat.add_left_cancel, fun | rfl => rfl⟩
|
||||
|
||||
@[simp] protected theorem add_right_cancel_iff {n : Nat} : m + n = k + n ↔ m = k :=
|
||||
@[simp high] protected theorem add_right_cancel_iff {n : Nat} : m + n = k + n ↔ m = k :=
|
||||
⟨Nat.add_right_cancel, fun | rfl => rfl⟩
|
||||
|
||||
@[simp] protected theorem add_left_eq_self {a b : Nat} : a + b = b ↔ a = 0 := by omega
|
||||
@[simp] protected theorem add_right_eq_self {a b : Nat} : a + b = a ↔ b = 0 := by omega
|
||||
@[simp] protected theorem self_eq_add_right {a b : Nat} : a = a + b ↔ b = 0 := by omega
|
||||
@[simp] protected theorem self_eq_add_left {a b : Nat} : a = b + a ↔ b = 0 := by omega
|
||||
protected theorem add_left_inj {n : Nat} : m + n = k + n ↔ m = k := Nat.add_right_cancel_iff
|
||||
protected theorem add_right_inj {n : Nat} : n + m = n + k ↔ m = k := Nat.add_left_cancel_iff
|
||||
|
||||
@[simp high] protected theorem add_eq_left {a b : Nat} : a + b = a ↔ b = 0 := by omega
|
||||
@[simp high] protected theorem add_eq_right {a b : Nat} : a + b = b ↔ a = 0 := by omega
|
||||
@[simp high] protected theorem left_eq_add {a b : Nat} : a = a + b ↔ b = 0 := by omega
|
||||
@[simp high] protected theorem right_eq_add {a b : Nat} : b = a + b ↔ a = 0 := by omega
|
||||
|
||||
@[deprecated Nat.add_eq_right (since := "2025-04-15")]
|
||||
protected theorem add_left_eq_self {a b : Nat} : a + b = b ↔ a = 0 := Nat.add_eq_right
|
||||
@[deprecated Nat.add_eq_left (since := "2025-04-15")]
|
||||
protected theorem add_right_eq_self {a b : Nat} : a + b = a ↔ b = 0 := Nat.add_eq_left
|
||||
@[deprecated Nat.left_eq_add (since := "2025-04-15")]
|
||||
protected theorem self_eq_add_right {a b : Nat} : a = a + b ↔ b = 0 := Nat.left_eq_add
|
||||
@[deprecated Nat.right_eq_add (since := "2025-04-15")]
|
||||
protected theorem self_eq_add_left {a b : Nat} : a = b + a ↔ b = 0 := Nat.right_eq_add
|
||||
|
||||
protected theorem lt_of_add_lt_add_right : ∀ {n : Nat}, k + n < m + n → k < m
|
||||
| 0, h => h
|
||||
@@ -173,9 +267,28 @@ protected theorem add_self_ne_one : ∀ n, n + n ≠ 1
|
||||
theorem le_iff_lt_add_one : x ≤ y ↔ x < y + 1 := by
|
||||
omega
|
||||
|
||||
/-! ## sub -/
|
||||
@[simp high] protected theorem add_eq_zero : m + n = 0 ↔ m = 0 ∧ n = 0 := by omega
|
||||
|
||||
protected theorem sub_one (n) : n - 1 = pred n := rfl
|
||||
theorem add_pos_iff_pos_or_pos : 0 < m + n ↔ 0 < m ∨ 0 < n := by omega
|
||||
|
||||
theorem add_eq_one_iff : m + n = 1 ↔ m = 0 ∧ n = 1 ∨ m = 1 ∧ n = 0 := by omega
|
||||
|
||||
theorem add_eq_two_iff : m + n = 2 ↔ m = 0 ∧ n = 2 ∨ m = 1 ∧ n = 1 ∨ m = 2 ∧ n = 0 := by
|
||||
omega
|
||||
|
||||
theorem add_eq_three_iff :
|
||||
m + n = 3 ↔ m = 0 ∧ n = 3 ∨ m = 1 ∧ n = 2 ∨ m = 2 ∧ n = 1 ∨ m = 3 ∧ n = 0 := by
|
||||
omega
|
||||
|
||||
theorem le_add_one_iff : m ≤ n + 1 ↔ m ≤ n ∨ m = n + 1 := by omega
|
||||
|
||||
theorem le_and_le_add_one_iff : n ≤ m ∧ m ≤ n + 1 ↔ m = n ∨ m = n + 1 := by omega
|
||||
|
||||
theorem add_succ_lt_add (hab : a < b) (hcd : c < d) : a + c + 1 < b + d := by omega
|
||||
|
||||
theorem le_or_le_of_add_eq_add_pred (h : a + c = b + d - 1) : b ≤ a ∨ d ≤ c := by omega
|
||||
|
||||
/-! ## sub -/
|
||||
|
||||
protected theorem one_sub : ∀ n, 1 - n = if n = 0 then 1 else 0
|
||||
| 0 => rfl
|
||||
@@ -213,7 +326,7 @@ protected theorem sub_eq_zero_iff_le : n - m = 0 ↔ n ≤ m :=
|
||||
protected theorem sub_pos_iff_lt : 0 < n - m ↔ m < n :=
|
||||
⟨Nat.lt_of_sub_pos, Nat.sub_pos_of_lt⟩
|
||||
|
||||
protected theorem sub_le_iff_le_add {a b c : Nat} : a - b ≤ c ↔ a ≤ c + b :=
|
||||
@[simp] protected theorem sub_le_iff_le_add {a b c : Nat} : a - b ≤ c ↔ a ≤ c + b :=
|
||||
⟨Nat.le_add_of_sub_le, sub_le_of_le_add⟩
|
||||
|
||||
protected theorem sub_le_iff_le_add' {a b c : Nat} : a - b ≤ c ↔ a ≤ b + c := by
|
||||
@@ -274,6 +387,25 @@ protected theorem exists_eq_add_of_le' (h : m ≤ n) : ∃ k : Nat, n = k + m :=
|
||||
protected theorem exists_eq_add_of_lt (h : m < n) : ∃ k : Nat, n = m + k + 1 :=
|
||||
⟨n - (m + 1), by rw [Nat.add_right_comm, add_sub_of_le h]⟩
|
||||
|
||||
/-- A version of `Nat.sub_succ` in the form `_ - 1` instead of `Nat.pred _`. -/
|
||||
theorem sub_succ' (m n : Nat) : m - n.succ = m - n - 1 := rfl
|
||||
|
||||
protected theorem sub_eq_of_eq_add' {a b c : Nat} (h : a = b + c) : a - b = c := by omega
|
||||
protected theorem eq_sub_of_add_eq {a b c : Nat} (h : c + b = a) : c = a - b := by omega
|
||||
protected theorem eq_sub_of_add_eq' {a b c : Nat} (h : b + c = a) : c = a - b := by omega
|
||||
|
||||
protected theorem lt_sub_iff_add_lt {a b c : Nat} : a < c - b ↔ a + b < c := ⟨add_lt_of_lt_sub, lt_sub_of_add_lt⟩
|
||||
protected theorem lt_sub_iff_add_lt' {a b c : Nat} : a < c - b ↔ b + a < c := by omega
|
||||
protected theorem sub_lt_iff_lt_add {a b c : Nat} (hba : b ≤ a) : a - b < c ↔ a < c + b := by omega
|
||||
protected theorem sub_lt_iff_lt_add' {a b c : Nat} (hba : b ≤ a) : a - b < c ↔ a < b + c := by omega
|
||||
|
||||
-- TODO: variants
|
||||
protected theorem sub_sub_sub_cancel_right {a b c : Nat} (h : c ≤ b) : a - c - (b - c) = a - b := by omega
|
||||
protected theorem add_sub_sub_cancel {a b c : Nat} (h : c ≤ a) : a + b - (a - c) = b + c := by omega
|
||||
protected theorem sub_add_sub_cancel {a b c : Nat} (hab : b ≤ a) (hcb : c ≤ b) : a - b + (b - c) = a - c := by omega
|
||||
|
||||
protected theorem sub_lt_sub_iff_right {a b c : Nat} (h : c ≤ a) : a - c < b - c ↔ a < b := by omega
|
||||
|
||||
/-! ### min/max -/
|
||||
|
||||
theorem succ_min_succ (x y) : min (succ x) (succ y) = succ (min x y) := by
|
||||
@@ -417,6 +549,24 @@ protected theorem sub_min_sub_left (a b c : Nat) : min (a - b) (a - c) = a - max
|
||||
protected theorem sub_max_sub_left (a b c : Nat) : max (a - b) (a - c) = a - min b c := by
|
||||
omega
|
||||
|
||||
protected theorem min_left_comm (a b c : Nat) : min a (min b c) = min b (min a c) := by
|
||||
rw [← Nat.min_assoc, ← Nat.min_assoc, b.min_comm]
|
||||
|
||||
protected theorem max_left_comm (a b c : Nat) : max a (max b c) = max b (max a c) := by
|
||||
rw [← Nat.max_assoc, ← Nat.max_assoc, b.max_comm]
|
||||
|
||||
protected theorem min_right_comm (a b c : Nat) : min (min a b) c = min (min a c) b := by
|
||||
rw [Nat.min_assoc, Nat.min_assoc, b.min_comm]
|
||||
|
||||
protected theorem max_right_comm (a b c : Nat) : max (max a b) c = max (max a c) b := by
|
||||
rw [Nat.max_assoc, Nat.max_assoc, b.max_comm]
|
||||
|
||||
@[simp] theorem min_eq_zero_iff : min m n = 0 ↔ m = 0 ∨ n = 0 := by omega
|
||||
@[simp] theorem max_eq_zero_iff : max m n = 0 ↔ m = 0 ∧ n = 0 := by omega
|
||||
|
||||
theorem add_eq_max_iff : m + n = max m n ↔ m = 0 ∨ n = 0 := by omega
|
||||
theorem add_eq_min_iff : m + n = min m n ↔ m = 0 ∧ n = 0 := by omega
|
||||
|
||||
/-! ### mul -/
|
||||
|
||||
protected theorem mul_right_comm (n m k : Nat) : n * m * k = n * k * m := by
|
||||
@@ -538,6 +688,101 @@ protected theorem mul_dvd_mul_iff_left {a b c : Nat} (h : 0 < a) : a * b ∣ a *
|
||||
protected theorem mul_dvd_mul_iff_right {a b c : Nat} (h : 0 < c) : a * c ∣ b * c ↔ a ∣ b := by
|
||||
rw [Nat.mul_comm _ c, Nat.mul_comm _ c, Nat.mul_dvd_mul_iff_left h]
|
||||
|
||||
protected theorem zero_eq_mul : 0 = m * n ↔ m = 0 ∨ n = 0 := by rw [eq_comm, Nat.mul_eq_zero]
|
||||
|
||||
-- TODO: Replace `Nat.mul_right_cancel_iff` with `Nat.mul_left_inj`
|
||||
protected theorem mul_left_inj (ha : a ≠ 0) : b * a = c * a ↔ b = c :=
|
||||
Nat.mul_right_cancel_iff (Nat.pos_iff_ne_zero.2 ha)
|
||||
|
||||
-- TODO: Replace `Nat.mul_left_cancel_iff` with `Nat.mul_right_inj`
|
||||
protected theorem mul_right_inj (ha : a ≠ 0) : a * b = a * c ↔ b = c :=
|
||||
Nat.mul_left_cancel_iff (Nat.pos_iff_ne_zero.2 ha)
|
||||
|
||||
protected theorem mul_ne_mul_left (ha : a ≠ 0) : b * a ≠ c * a ↔ b ≠ c :=
|
||||
not_congr (Nat.mul_left_inj ha)
|
||||
|
||||
protected theorem mul_ne_mul_right (ha : a ≠ 0) : a * b ≠ a * c ↔ b ≠ c :=
|
||||
not_congr (Nat.mul_right_inj ha)
|
||||
|
||||
theorem mul_eq_left (ha : a ≠ 0) : a * b = a ↔ b = 1 := by simpa using Nat.mul_right_inj ha (c := 1)
|
||||
theorem mul_eq_right (hb : b ≠ 0) : a * b = b ↔ a = 1 := by simpa using Nat.mul_left_inj hb (c := 1)
|
||||
|
||||
/-- The product of two natural numbers is greater than 1 if and only if
|
||||
at least one of them is greater than 1 and both are positive. -/
|
||||
theorem one_lt_mul_iff : 1 < m * n ↔ 0 < m ∧ 0 < n ∧ (1 < m ∨ 1 < n) := by
|
||||
constructor <;> intro h
|
||||
· refine Decidable.by_contra (fun h' => ?_)
|
||||
simp only [Nat.le_zero, Decidable.not_and_iff_not_or_not, not_or, Nat.not_lt] at h'
|
||||
obtain rfl | rfl | h' := h'
|
||||
· simp at h
|
||||
· simp at h
|
||||
· exact Nat.not_lt_of_le (Nat.mul_le_mul h'.1 h'.2) h
|
||||
· obtain hm | hn := h.2.2
|
||||
· exact Nat.mul_lt_mul_of_lt_of_le' hm h.2.1 Nat.zero_lt_one
|
||||
· exact Nat.mul_lt_mul_of_le_of_lt h.1 hn h.1
|
||||
|
||||
theorem eq_one_of_mul_eq_one_right (H : m * n = 1) : m = 1 := eq_one_of_dvd_one ⟨n, H.symm⟩
|
||||
|
||||
theorem eq_one_of_mul_eq_one_left (H : m * n = 1) : n = 1 :=
|
||||
eq_one_of_mul_eq_one_right (n := m) (by rwa [Nat.mul_comm])
|
||||
|
||||
@[simp] protected theorem lt_mul_iff_one_lt_left (hb : 0 < b) : b < a * b ↔ 1 < a := by
|
||||
simpa using Nat.mul_lt_mul_right (b := 1) hb
|
||||
|
||||
@[simp] protected theorem lt_mul_iff_one_lt_right (ha : 0 < a) : a < a * b ↔ 1 < b := by
|
||||
simpa using Nat.mul_lt_mul_left (b := 1) ha
|
||||
|
||||
theorem eq_zero_of_two_mul_le (h : 2 * n ≤ n) : n = 0 := by omega
|
||||
|
||||
theorem eq_zero_of_mul_le (hb : 2 ≤ n) (h : n * m ≤ m) : m = 0 :=
|
||||
eq_zero_of_two_mul_le <| Nat.le_trans (Nat.mul_le_mul_right _ hb) h
|
||||
|
||||
theorem succ_mul_pos (m : Nat) (hn : 0 < n) : 0 < succ m * n := Nat.mul_pos m.succ_pos hn
|
||||
|
||||
theorem mul_self_le_mul_self {m n : Nat} (h : m ≤ n) : m * m ≤ n * n := Nat.mul_le_mul h h
|
||||
|
||||
-- This name is consistent with mathlib's top level definitions for groups with zero, where there
|
||||
-- are `mul_lt_mul`, `mul_lt_mul'` and `mul_lt_mul''`, all with different sets of hypotheses.
|
||||
theorem mul_lt_mul'' {a b c d : Nat} (hac : a < c) (hbd : b < d) : a * b < c * d :=
|
||||
Nat.mul_lt_mul_of_lt_of_le hac (Nat.le_of_lt hbd) <| by omega
|
||||
|
||||
protected theorem lt_iff_lt_of_mul_eq_mul (ha : a ≠ 0) (hbd : a = b * d) (hce : a = c * e) :
|
||||
c < b ↔ d < e where
|
||||
mp hcb := Nat.lt_of_not_le fun hed ↦ Nat.not_lt_of_le (Nat.le_of_eq <| hbd.symm.trans hce) <|
|
||||
Nat.mul_lt_mul_of_lt_of_le hcb hed <| by simp [hbd, Nat.mul_eq_zero] at ha; omega
|
||||
mpr hde := Nat.lt_of_not_le fun hbc ↦ Nat.not_lt_of_le (Nat.le_of_eq <| hce.symm.trans hbd) <|
|
||||
Nat.mul_lt_mul_of_le_of_lt hbc hde <| by simp [hce, Nat.mul_eq_zero] at ha; omega
|
||||
|
||||
theorem mul_self_lt_mul_self {m n : Nat} (h : m < n) : m * m < n * n := mul_lt_mul'' h h
|
||||
|
||||
theorem mul_self_le_mul_self_iff {m n : Nat} : m * m ≤ n * n ↔ m ≤ n :=
|
||||
⟨fun h => Nat.le_of_not_lt fun h' => Nat.not_le_of_gt (mul_self_lt_mul_self h') h,
|
||||
mul_self_le_mul_self⟩
|
||||
|
||||
theorem mul_self_lt_mul_self_iff {m n : Nat} : m * m < n * n ↔ m < n := by
|
||||
simp only [← Nat.not_le, mul_self_le_mul_self_iff]
|
||||
|
||||
theorem le_mul_self : ∀ n : Nat, n ≤ n * n
|
||||
| 0 => Nat.le_refl _
|
||||
| n + 1 => by simp [Nat.mul_add]
|
||||
|
||||
theorem mul_self_inj {m n : Nat} : m * m = n * n ↔ m = n := by
|
||||
simp [Nat.le_antisymm_iff, mul_self_le_mul_self_iff]
|
||||
|
||||
@[simp] theorem lt_mul_self_iff : ∀ {n : Nat}, n < n * n ↔ 1 < n
|
||||
| 0 => by simp
|
||||
| n + 1 => Nat.lt_mul_iff_one_lt_left n.succ_pos
|
||||
|
||||
theorem add_sub_one_le_mul (ha : a ≠ 0) (hb : b ≠ 0) : a + b - 1 ≤ a * b := by
|
||||
cases a
|
||||
· cases ha rfl
|
||||
· rw [succ_add, Nat.add_one_sub_one, succ_mul]
|
||||
exact Nat.add_le_add_right (Nat.le_mul_of_pos_right _ <| Nat.pos_iff_ne_zero.2 hb) _
|
||||
|
||||
protected theorem add_le_mul {a : Nat} (ha : 2 ≤ a) : ∀ {b : Nat} (_ : 2 ≤ b), a + b ≤ a * b
|
||||
| 2, _ => by omega
|
||||
| b + 3, _ => by have := Nat.add_le_mul ha (Nat.le_add_left _ b); rw [mul_succ]; omega
|
||||
|
||||
/-! ### div/mod -/
|
||||
|
||||
theorem mod_two_eq_zero_or_one (n : Nat) : n % 2 = 0 ∨ n % 2 = 1 :=
|
||||
@@ -629,6 +874,203 @@ theorem div_eq_self {m n : Nat} : m / n = m ↔ m = 0 ∨ n = 1 := by
|
||||
· exact hn
|
||||
· exact False.elim (absurd h (Nat.ne_of_lt (Nat.div_lt_self hm hn)))
|
||||
|
||||
@[simp] protected theorem div_eq_zero_iff : a / b = 0 ↔ b = 0 ∨ a < b where
|
||||
mp h := by
|
||||
rw [← mod_add_div a b, h, Nat.mul_zero, Nat.add_zero, Decidable.or_iff_not_imp_left]
|
||||
exact mod_lt _ ∘ Nat.pos_iff_ne_zero.2
|
||||
mpr := by
|
||||
obtain rfl | hb := Decidable.em (b = 0)
|
||||
· simp
|
||||
simp only [hb, false_or]
|
||||
rw [← Nat.mul_right_inj hb, ← Nat.add_left_cancel_iff, mod_add_div]
|
||||
simp +contextual [mod_eq_of_lt]
|
||||
|
||||
protected theorem div_ne_zero_iff : a / b ≠ 0 ↔ b ≠ 0 ∧ b ≤ a := by simp
|
||||
|
||||
@[simp] protected theorem div_pos_iff : 0 < a / b ↔ 0 < b ∧ b ≤ a := by
|
||||
simp [Nat.pos_iff_ne_zero]
|
||||
|
||||
theorem lt_mul_of_div_lt (h : a / c < b) (hc : 0 < c) : a < b * c :=
|
||||
Nat.lt_of_not_ge <| Nat.not_le_of_gt h ∘ (Nat.le_div_iff_mul_le hc).2
|
||||
|
||||
theorem mul_div_le_mul_div_assoc (a b c : Nat) : a * (b / c) ≤ a * b / c :=
|
||||
if hc0 : c = 0 then by simp [hc0] else
|
||||
(Nat.le_div_iff_mul_le (Nat.pos_of_ne_zero hc0)).2
|
||||
(by rw [Nat.mul_assoc]; exact Nat.mul_le_mul_left _ (Nat.div_mul_le_self _ _))
|
||||
|
||||
protected theorem eq_mul_of_div_eq_right {a b c : Nat} (H1 : b ∣ a) (H2 : a / b = c) :
|
||||
a = b * c := by
|
||||
rw [← H2, Nat.mul_div_cancel' H1]
|
||||
|
||||
protected theorem eq_mul_of_div_eq_left {a b c : Nat} (H1 : b ∣ a) (H2 : a / b = c) : a = c * b := by
|
||||
rw [Nat.mul_comm, Nat.eq_mul_of_div_eq_right H1 H2]
|
||||
|
||||
protected theorem mul_div_cancel_left' {a b : Nat} (Hd : a ∣ b) : a * (b / a) = b := by
|
||||
rw [Nat.mul_comm, Nat.div_mul_cancel Hd]
|
||||
|
||||
theorem lt_div_mul_add {a b : Nat} (hb : 0 < b) : a < a / b * b + b := by
|
||||
rw [← Nat.succ_mul, ← Nat.div_lt_iff_lt_mul hb]; exact Nat.lt_succ_self _
|
||||
|
||||
@[simp]
|
||||
protected theorem div_left_inj {a b d : Nat} (hda : d ∣ a) (hdb : d ∣ b) :
|
||||
a / d = b / d ↔ a = b := by
|
||||
refine ⟨fun h ↦ ?_, congrArg fun b ↦ b / d⟩
|
||||
rw [← Nat.mul_div_cancel' hda, ← Nat.mul_div_cancel' hdb, h]
|
||||
|
||||
theorem div_le_iff_le_mul_add_pred (hb : 0 < b) : a / b ≤ c ↔ a ≤ b * c + (b - 1) := by
|
||||
rw [← Nat.lt_succ_iff, div_lt_iff_lt_mul hb, succ_mul, Nat.mul_comm]
|
||||
cases hb <;> exact Nat.lt_succ_iff
|
||||
|
||||
theorem one_le_div_iff {a b : Nat} (hb : 0 < b) : 1 ≤ a / b ↔ b ≤ a := by
|
||||
rw [le_div_iff_mul_le hb, Nat.one_mul]
|
||||
|
||||
theorem div_lt_one_iff (hb : 0 < b) : a / b < 1 ↔ a < b := by
|
||||
simp only [← Nat.not_le, one_le_div_iff hb]
|
||||
|
||||
protected theorem div_le_div_right {a b c : Nat} (h : a ≤ b) : a / c ≤ b / c :=
|
||||
(c.eq_zero_or_pos.elim fun hc ↦ by simp [hc]) fun hc ↦
|
||||
(le_div_iff_mul_le hc).2 <| Nat.le_trans (Nat.div_mul_le_self _ _) h
|
||||
|
||||
theorem lt_of_div_lt_div {a b c : Nat} (h : a / c < b / c) : a < b :=
|
||||
Nat.lt_of_not_le fun hab ↦ Nat.not_le_of_lt h <| Nat.div_le_div_right hab
|
||||
|
||||
theorem sub_mul_div (a b c : Nat) : (a - b * c) / b = a / b - c := by
|
||||
obtain h | h := Nat.le_total (b * c) a
|
||||
· rw [Nat.sub_mul_div_of_le _ _ _ h]
|
||||
· rw [Nat.sub_eq_zero_of_le h, Nat.zero_div]
|
||||
by_cases hn : b = 0
|
||||
· simp only [hn, Nat.div_zero, zero_le, Nat.sub_eq_zero_of_le]
|
||||
· have h2 : a / b ≤ (b * c) / b := Nat.div_le_div_right h
|
||||
rw [Nat.mul_div_cancel_left _ (zero_lt_of_ne_zero hn)] at h2
|
||||
rw [Nat.sub_eq_zero_of_le h2]
|
||||
|
||||
theorem mul_sub_div_of_dvd {b c : Nat} (hc : c ≠ 0) (hcb : c ∣ b) (a : Nat) : (c * a - b) / c = a - b / c := by
|
||||
obtain ⟨_, hx⟩ := hcb
|
||||
simp only [hx, ← Nat.mul_sub_left_distrib, Nat.mul_div_right, zero_lt_of_ne_zero hc]
|
||||
|
||||
theorem mul_add_mul_div_of_dvd (hb : b ≠ 0) (hd : d ≠ 0) (hba : b ∣ a) (hdc : d ∣ c) :
|
||||
(a * d + b * c) / (b * d) = a / b + c / d := by
|
||||
obtain ⟨n, hn⟩ := hba
|
||||
obtain ⟨_, hm⟩ := hdc
|
||||
rw [hn, hm, Nat.mul_assoc b n d, Nat.mul_comm n d, ← Nat.mul_assoc, ← Nat.mul_assoc,
|
||||
← Nat.mul_add,
|
||||
Nat.mul_div_right _ (zero_lt_of_ne_zero hb),
|
||||
Nat.mul_div_right _ (zero_lt_of_ne_zero hd),
|
||||
Nat.mul_div_right _ (zero_lt_of_ne_zero <| Nat.mul_ne_zero hb hd)]
|
||||
|
||||
theorem mul_sub_mul_div_of_dvd (hb : b ≠ 0) (hd : d ≠ 0) (hba : b ∣ a) (hdc : d ∣ c) :
|
||||
(a * d - b * c) / (b * d) = a / b - c / d := by
|
||||
obtain ⟨n, hn⟩ := hba
|
||||
obtain ⟨m, hm⟩ := hdc
|
||||
rw [hn, hm]
|
||||
rw [Nat.mul_assoc,Nat.mul_comm n d, ← Nat.mul_assoc,← Nat.mul_assoc, ← Nat.mul_sub_left_distrib,
|
||||
Nat.mul_div_right _ (zero_lt_of_ne_zero hb), Nat.mul_div_right _ (zero_lt_of_ne_zero hd),
|
||||
Nat.mul_div_right _ (zero_lt_of_ne_zero <| Nat.mul_ne_zero hb hd)]
|
||||
|
||||
protected theorem div_mul_right_comm {a b : Nat} (hba : b ∣ a) (c : Nat) : a / b * c = a * c / b := by
|
||||
rw [Nat.mul_comm, ← Nat.mul_div_assoc _ hba, Nat.mul_comm]
|
||||
|
||||
protected theorem mul_div_right_comm {a b : Nat} (hba : b ∣ a) (c : Nat) : a * c / b = a / b * c :=
|
||||
(Nat.div_mul_right_comm hba _).symm
|
||||
|
||||
protected theorem div_eq_iff_eq_mul_right {a b c : Nat} (H : 0 < b) (H' : b ∣ a) :
|
||||
a / b = c ↔ a = b * c :=
|
||||
⟨Nat.eq_mul_of_div_eq_right H', Nat.div_eq_of_eq_mul_right H⟩
|
||||
|
||||
protected theorem div_eq_iff_eq_mul_left {a b c : Nat} (H : 0 < b) (H' : b ∣ a) :
|
||||
a / b = c ↔ a = c * b := by
|
||||
rw [Nat.mul_comm]; exact Nat.div_eq_iff_eq_mul_right H H'
|
||||
|
||||
theorem eq_div_iff_mul_eq_left (hc : c ≠ 0) (hcb : c ∣ b) : a = b / c ↔ b = a * c := by
|
||||
rw [eq_comm, Nat.div_eq_iff_eq_mul_left (zero_lt_of_ne_zero hc) hcb]
|
||||
|
||||
theorem div_mul_div_comm {a b c d : Nat} : b ∣ a → d ∣ c → (a / b) * (c / d) = (a * c) / (b * d) := by
|
||||
rintro ⟨x, rfl⟩ ⟨y, rfl⟩
|
||||
obtain rfl | hb := b.eq_zero_or_pos
|
||||
· simp
|
||||
obtain rfl | hd := d.eq_zero_or_pos
|
||||
· simp
|
||||
rw [Nat.mul_div_cancel_left _ hb, Nat.mul_div_cancel_left _ hd, Nat.mul_assoc b,
|
||||
Nat.mul_left_comm x, ← Nat.mul_assoc b, Nat.mul_div_cancel_left _ (Nat.mul_pos hb hd)]
|
||||
|
||||
protected theorem mul_div_mul_comm {a b c d : Nat} (hba : b ∣ a) (hdc : d ∣ c) : a * c / (b * d) = a / b * (c / d) :=
|
||||
(div_mul_div_comm hba hdc).symm
|
||||
|
||||
theorem eq_zero_of_le_div (hn : 2 ≤ n) (h : m ≤ m / n) : m = 0 :=
|
||||
eq_zero_of_mul_le hn <| by
|
||||
rw [Nat.mul_comm]; exact (Nat.le_div_iff_mul_le (Nat.lt_of_lt_of_le (by decide) hn)).1 h
|
||||
|
||||
theorem div_mul_div_le_div (a b c : Nat) : a / c * b / a ≤ b / c := by
|
||||
obtain rfl | ha := Nat.eq_zero_or_pos a
|
||||
· simp
|
||||
· calc
|
||||
a / c * b / a ≤ b * a / c / a :=
|
||||
Nat.div_le_div_right (by rw [Nat.mul_comm]; exact mul_div_le_mul_div_assoc _ _ _)
|
||||
_ = b / c := by rw [Nat.div_div_eq_div_mul, Nat.mul_comm b, Nat.mul_comm c,
|
||||
Nat.mul_div_mul_left _ _ ha]
|
||||
|
||||
theorem eq_zero_of_le_div_two (h : n ≤ n / 2) : n = 0 := eq_zero_of_le_div (Nat.le_refl _) h
|
||||
|
||||
theorem le_div_two_of_div_two_lt_sub (h : a / 2 < a - b) : b ≤ a / 2 := by
|
||||
omega
|
||||
|
||||
theorem div_two_le_of_sub_le_div_two (h : a - b ≤ a / 2) : a / 2 ≤ b := by
|
||||
omega
|
||||
|
||||
protected theorem div_le_div_of_mul_le_mul (hd : d ≠ 0) (hdc : d ∣ c) (h : a * d ≤ c * b) :
|
||||
a / b ≤ c / d :=
|
||||
Nat.div_le_of_le_mul <| by
|
||||
rwa [← Nat.mul_div_assoc _ hdc, Nat.le_div_iff_mul_le (Nat.pos_iff_ne_zero.2 hd), b.mul_comm]
|
||||
|
||||
theorem div_eq_sub_mod_div {m n : Nat} : m / n = (m - m % n) / n := by
|
||||
obtain rfl | hn := n.eq_zero_or_pos
|
||||
· rw [Nat.div_zero, Nat.div_zero]
|
||||
· have : m - m % n = n * (m / n) := by
|
||||
rw [Nat.sub_eq_iff_eq_add (Nat.mod_le _ _), Nat.add_comm, mod_add_div]
|
||||
rw [this, mul_div_right _ hn]
|
||||
|
||||
protected theorem eq_div_of_mul_eq_left (hc : c ≠ 0) (h : a * c = b) : a = b / c := by
|
||||
rw [← h, Nat.mul_div_cancel _ (Nat.pos_iff_ne_zero.2 hc)]
|
||||
|
||||
protected theorem eq_div_of_mul_eq_right (hc : c ≠ 0) (h : c * a = b) : a = b / c := by
|
||||
rw [← h, Nat.mul_div_cancel_left _ (Nat.pos_iff_ne_zero.2 hc)]
|
||||
|
||||
protected theorem mul_le_of_le_div (k x y : Nat) (h : x ≤ y / k) : x * k ≤ y := by
|
||||
if hk : k = 0 then
|
||||
rw [hk, Nat.mul_zero]; exact zero_le _
|
||||
else
|
||||
rwa [← le_div_iff_mul_le (Nat.pos_iff_ne_zero.2 hk)]
|
||||
|
||||
theorem div_le_iff_le_mul_of_dvd (hb : b ≠ 0) (hba : b ∣ a) : a / b ≤ c ↔ a ≤ c * b := by
|
||||
obtain ⟨_, hx⟩ := hba
|
||||
simp only [hx]
|
||||
rw [Nat.mul_div_right _ (zero_lt_of_ne_zero hb), Nat.mul_comm]
|
||||
exact ⟨mul_le_mul_right b, fun h ↦ Nat.le_of_mul_le_mul_right h (zero_lt_of_ne_zero hb)⟩
|
||||
|
||||
protected theorem div_lt_div_right (ha : a ≠ 0) : a ∣ b → a ∣ c → (b / a < c / a ↔ b < c) := by
|
||||
rintro ⟨d, rfl⟩ ⟨e, rfl⟩; simp [Nat.mul_div_cancel, Nat.pos_iff_ne_zero.2 ha]
|
||||
|
||||
protected theorem div_lt_div_left (ha : a ≠ 0) (hba : b ∣ a) (hca : c ∣ a) :
|
||||
a / b < a / c ↔ c < b := by
|
||||
obtain ⟨d, hd⟩ := hba
|
||||
obtain ⟨e, he⟩ := hca
|
||||
rw [Nat.div_eq_of_eq_mul_right _ hd, Nat.div_eq_of_eq_mul_right _ he,
|
||||
Nat.lt_iff_lt_of_mul_eq_mul ha hd he] <;>
|
||||
rw [Nat.pos_iff_ne_zero] <;> rintro rfl <;> simp at * <;> contradiction
|
||||
|
||||
theorem lt_div_iff_mul_lt_of_dvd (hc : c ≠ 0) (hcb : c ∣ b) : a < b / c ↔ a * c < b := by
|
||||
simp [← Nat.div_lt_div_right _ _ hcb, hc, Nat.pos_iff_ne_zero, Nat.dvd_mul_left]
|
||||
|
||||
protected theorem div_mul_div_le (a b c d : Nat) :
|
||||
(a / b) * (c / d) ≤ (a * c) / (b * d) := by
|
||||
if hb : b = 0 then simp [hb] else
|
||||
if hd : d = 0 then simp [hd] else
|
||||
have hbd : b * d ≠ 0 := Nat.mul_ne_zero hb hd
|
||||
rw [le_div_iff_mul_le (Nat.pos_of_ne_zero hbd)]
|
||||
refine Nat.le_trans (m := ((a / b) * b) * ((c / d) * d)) ?_ ?_
|
||||
· apply Nat.le_of_eq; simp only [Nat.mul_assoc, Nat.mul_left_comm]
|
||||
· apply Nat.mul_le_mul <;> apply div_mul_le_self
|
||||
|
||||
/-! ### pow -/
|
||||
|
||||
theorem pow_succ' {m n : Nat} : m ^ n.succ = m * m ^ n := by
|
||||
@@ -802,6 +1244,74 @@ theorem le_pow {a b : Nat} (h : 0 < b) : a ≤ a ^ b := by
|
||||
rw [(show b = b - 1 + 1 by omega), Nat.pow_succ]
|
||||
exact Nat.le_mul_of_pos_left _ (Nat.pow_pos ha)
|
||||
|
||||
protected theorem pow_lt_pow_right (ha : 1 < a) (h : m < n) : a ^ m < a ^ n :=
|
||||
(Nat.pow_lt_pow_iff_right ha).2 h
|
||||
|
||||
protected theorem pow_le_pow_iff_left {a b n : Nat} (hn : n ≠ 0) : a ^ n ≤ b ^ n ↔ a ≤ b where
|
||||
mp := by simpa only [← Nat.not_le, Decidable.not_imp_not] using (Nat.pow_lt_pow_left · hn)
|
||||
mpr h := Nat.pow_le_pow_left h _
|
||||
|
||||
protected theorem pow_lt_pow_iff_left {a b n : Nat} (hn : n ≠ 0) : a ^ n < b ^ n ↔ a < b := by
|
||||
simp only [← Nat.not_le, Nat.pow_le_pow_iff_left hn]
|
||||
|
||||
@[simp high] protected theorem pow_eq_zero {a : Nat} : ∀ {n : Nat}, a ^ n = 0 ↔ a = 0 ∧ n ≠ 0
|
||||
| 0 => by simp
|
||||
| n + 1 => by rw [Nat.pow_succ, mul_eq_zero, Nat.pow_eq_zero]; omega
|
||||
|
||||
theorem le_self_pow (hn : n ≠ 0) : ∀ a : Nat, a ≤ a ^ n
|
||||
| 0 => zero_le _
|
||||
| a + 1 => by simpa using Nat.pow_le_pow_right a.succ_pos (Nat.one_le_iff_ne_zero.2 hn)
|
||||
|
||||
theorem one_le_pow (n m : Nat) (h : 0 < m) : 1 ≤ m ^ n := by simpa using Nat.pow_le_pow_left h n
|
||||
|
||||
theorem one_lt_pow (hn : n ≠ 0) (ha : 1 < a) : 1 < a ^ n := by simpa using Nat.pow_lt_pow_left ha hn
|
||||
|
||||
theorem two_pow_succ (n : Nat) : 2 ^ (n + 1) = 2 ^ n + 2 ^ n := by simp [Nat.pow_succ, Nat.mul_two]
|
||||
|
||||
theorem one_lt_pow' (n m : Nat) : 1 < (m + 2) ^ (n + 1) :=
|
||||
one_lt_pow n.succ_ne_zero (Nat.lt_of_sub_eq_succ rfl)
|
||||
|
||||
@[simp] theorem one_lt_pow_iff {n : Nat} (hn : n ≠ 0) : ∀ {a}, 1 < a ^ n ↔ 1 < a
|
||||
| 0 => by simp [Nat.zero_pow (Nat.pos_of_ne_zero hn)]
|
||||
| 1 => by simp
|
||||
| a + 2 => by simp [one_lt_pow hn]
|
||||
|
||||
theorem one_lt_two_pow' (n : Nat) : 1 < 2 ^ (n + 1) := one_lt_pow n.succ_ne_zero (by decide)
|
||||
|
||||
theorem mul_lt_mul_pow_succ (ha : 0 < a) (hb : 1 < b) : n * b < a * b ^ (n + 1) := by
|
||||
rw [Nat.pow_succ, ← Nat.mul_assoc, Nat.mul_lt_mul_right (Nat.lt_trans Nat.zero_lt_one hb)]
|
||||
exact Nat.lt_of_le_of_lt (Nat.le_mul_of_pos_left _ ha)
|
||||
((Nat.mul_lt_mul_left ha).2 <| Nat.lt_pow_self hb)
|
||||
|
||||
|
||||
theorem pow_two_sub_pow_two (a b : Nat) : a ^ 2 - b ^ 2 = (a + b) * (a - b) := by
|
||||
simpa [Nat.pow_succ] using Nat.mul_self_sub_mul_self_eq a b
|
||||
|
||||
protected theorem pow_pos_iff : 0 < a ^ n ↔ 0 < a ∨ n = 0 := by
|
||||
simp [Nat.pos_iff_ne_zero, Decidable.imp_iff_not_or]
|
||||
|
||||
theorem pow_self_pos : 0 < n ^ n := by simp [Nat.pow_pos_iff, n.eq_zero_or_pos.symm]
|
||||
|
||||
theorem pow_self_mul_pow_self_le : m ^ m * n ^ n ≤ (m + n) ^ (m + n) := by
|
||||
rw [Nat.pow_add]
|
||||
exact Nat.mul_le_mul (Nat.pow_le_pow_left (le_add_right ..) _)
|
||||
(Nat.pow_le_pow_left (le_add_left ..) _)
|
||||
|
||||
protected theorem pow_right_inj (ha : 1 < a) : a ^ m = a ^ n ↔ m = n := by
|
||||
simp [Nat.le_antisymm_iff, Nat.pow_le_pow_iff_right ha]
|
||||
|
||||
@[simp] protected theorem pow_eq_one : a ^ n = 1 ↔ a = 1 ∨ n = 0 := by
|
||||
obtain rfl | hn := Decidable.em (n = 0)
|
||||
· simp
|
||||
· simpa [hn] using Nat.pow_left_inj hn (b := 1)
|
||||
|
||||
/-- For `a > 1`, `a ^ b = a` iff `b = 1`. -/
|
||||
theorem pow_eq_self_iff {a b : Nat} (ha : 1 < a) : a ^ b = a ↔ b = 1 := by
|
||||
rw [← Nat.pow_right_inj (m := b) ha, Nat.pow_one]
|
||||
|
||||
@[simp] protected theorem pow_le_one_iff (hn : n ≠ 0) : a ^ n ≤ 1 ↔ a ≤ 1 := by
|
||||
rw [← Nat.not_lt, one_lt_pow_iff hn, Nat.not_lt]
|
||||
|
||||
/-! ### log2 -/
|
||||
|
||||
@[simp]
|
||||
@@ -835,19 +1345,7 @@ theorem lt_log2_self : n < 2 ^ (n.log2 + 1) :=
|
||||
| 0 => by simp
|
||||
| n+1 => (log2_lt n.succ_ne_zero).1 (Nat.le_refl _)
|
||||
|
||||
/-! ### dvd -/
|
||||
|
||||
protected theorem eq_mul_of_div_eq_right {a b c : Nat} (H1 : b ∣ a) (H2 : a / b = c) :
|
||||
a = b * c := by
|
||||
rw [← H2, Nat.mul_div_cancel' H1]
|
||||
|
||||
protected theorem div_eq_iff_eq_mul_right {a b c : Nat} (H : 0 < b) (H' : b ∣ a) :
|
||||
a / b = c ↔ a = b * c :=
|
||||
⟨Nat.eq_mul_of_div_eq_right H', Nat.div_eq_of_eq_mul_right H⟩
|
||||
|
||||
protected theorem div_eq_iff_eq_mul_left {a b c : Nat} (H : 0 < b) (H' : b ∣ a) :
|
||||
a / b = c ↔ a = c * b := by
|
||||
rw [Nat.mul_comm]; exact Nat.div_eq_iff_eq_mul_right H H'
|
||||
/-! ### mod, dvd -/
|
||||
|
||||
theorem pow_dvd_pow_iff_pow_le_pow {k l : Nat} :
|
||||
∀ {x : Nat}, 0 < x → (x ^ k ∣ x ^ l ↔ x ^ k ≤ x ^ l)
|
||||
@@ -903,48 +1401,151 @@ protected theorem div_pow {a b c : Nat} (h : a ∣ b) : (b / a) ^ c = b ^ c / a
|
||||
rw [Nat.pow_succ (b / a), Nat.pow_succ a, Nat.mul_comm _ a, Nat.mul_assoc, ← Nat.mul_assoc _ a,
|
||||
Nat.div_mul_cancel h, Nat.mul_comm b, ← Nat.mul_assoc, ← ih, Nat.pow_succ]
|
||||
|
||||
/-! ### shiftLeft and shiftRight -/
|
||||
@[simp] theorem mod_two_not_eq_one : ¬n % 2 = 1 ↔ n % 2 = 0 := by
|
||||
cases mod_two_eq_zero_or_one n <;> simp [*]
|
||||
|
||||
@[simp] theorem shiftLeft_zero : n <<< 0 = n := rfl
|
||||
@[simp] theorem mod_two_not_eq_zero : ¬n % 2 = 0 ↔ n % 2 = 1 := by
|
||||
cases mod_two_eq_zero_or_one n <;> simp [*]
|
||||
|
||||
/-- Shiftleft on successor with multiple moved inside. -/
|
||||
theorem shiftLeft_succ_inside (m n : Nat) : m <<< (n+1) = (2*m) <<< n := rfl
|
||||
theorem mod_two_ne_one : n % 2 ≠ 1 ↔ n % 2 = 0 := mod_two_not_eq_one
|
||||
theorem mod_two_ne_zero : n % 2 ≠ 0 ↔ n % 2 = 1 := mod_two_not_eq_zero
|
||||
|
||||
/-- Shiftleft on successor with multiple moved to outside. -/
|
||||
theorem shiftLeft_succ : ∀(m n), m <<< (n + 1) = 2 * (m <<< n)
|
||||
| _, 0 => rfl
|
||||
| _, k + 1 => by
|
||||
rw [shiftLeft_succ_inside _ (k+1)]
|
||||
rw [shiftLeft_succ _ k, shiftLeft_succ_inside]
|
||||
/-- Variant of `Nat.lt_div_iff_mul_lt` that assumes `d ∣ n`. -/
|
||||
protected theorem lt_div_iff_mul_lt' (hdn : d ∣ n) (a : Nat) : a < n / d ↔ d * a < n := by
|
||||
obtain rfl | hd := d.eq_zero_or_pos
|
||||
· simp [Nat.zero_dvd.1 hdn]
|
||||
· rw [← Nat.mul_lt_mul_left hd, ← Nat.eq_mul_of_div_eq_right hdn rfl]
|
||||
|
||||
/-- Shiftright on successor with division moved inside. -/
|
||||
theorem shiftRight_succ_inside : ∀m n, m >>> (n+1) = (m/2) >>> n
|
||||
| _, 0 => rfl
|
||||
| _, k + 1 => by
|
||||
rw [shiftRight_succ _ (k+1)]
|
||||
rw [shiftRight_succ_inside _ k, shiftRight_succ]
|
||||
theorem mul_div_eq_iff_dvd {n d : Nat} : d * (n / d) = n ↔ d ∣ n :=
|
||||
calc
|
||||
d * (n / d) = n ↔ d * (n / d) = d * (n / d) + (n % d) := by rw [div_add_mod]
|
||||
_ ↔ d ∣ n := by rw [eq_comm, Nat.add_eq_left, dvd_iff_mod_eq_zero]
|
||||
|
||||
@[simp] theorem zero_shiftLeft : ∀ n, 0 <<< n = 0
|
||||
| 0 => by simp [shiftLeft]
|
||||
| n + 1 => by simp [shiftLeft, zero_shiftLeft n, shiftLeft_succ]
|
||||
theorem mul_div_lt_iff_not_dvd {n d : Nat} : d * (n / d) < n ↔ ¬ d ∣ n := by
|
||||
simp [Nat.lt_iff_le_and_ne, mul_div_eq_iff_dvd, mul_div_le]
|
||||
|
||||
@[simp] theorem zero_shiftRight : ∀ n, 0 >>> n = 0
|
||||
| 0 => by simp [shiftRight]
|
||||
| n + 1 => by simp [shiftRight, zero_shiftRight n, shiftRight_succ]
|
||||
theorem div_eq_iff_eq_of_dvd_dvd (hn : n ≠ 0) (ha : a ∣ n) (hb : b ∣ n) : n / a = n / b ↔ a = b := by
|
||||
constructor <;> intro h
|
||||
· rw [← Nat.mul_right_inj hn]
|
||||
apply Nat.eq_mul_of_div_eq_left (Nat.dvd_trans hb (Nat.dvd_mul_right _ _))
|
||||
rw [eq_comm, Nat.mul_comm, Nat.mul_div_assoc _ hb]
|
||||
exact Nat.eq_mul_of_div_eq_right ha h
|
||||
· rw [h]
|
||||
|
||||
theorem shiftLeft_add (m n : Nat) : ∀ k, m <<< (n + k) = (m <<< n) <<< k
|
||||
| 0 => rfl
|
||||
| k + 1 => by simp [← Nat.add_assoc, shiftLeft_add _ _ k, shiftLeft_succ]
|
||||
theorem le_iff_ne_zero_of_dvd (ha : a ≠ 0) (hab : a ∣ b) : a ≤ b ↔ b ≠ 0 where
|
||||
mp := by rw [← Nat.pos_iff_ne_zero] at ha ⊢; exact Nat.lt_of_lt_of_le ha
|
||||
mpr hb := Nat.le_of_dvd (Nat.pos_iff_ne_zero.2 hb) hab
|
||||
|
||||
@[simp] theorem shiftLeft_shiftRight (x n : Nat) : x <<< n >>> n = x := by
|
||||
rw [Nat.shiftLeft_eq, Nat.shiftRight_eq_div_pow, Nat.mul_div_cancel _ (Nat.two_pow_pos _)]
|
||||
theorem div_ne_zero_iff_of_dvd (hba : b ∣ a) : a / b ≠ 0 ↔ a ≠ 0 ∧ b ≠ 0 := by
|
||||
obtain rfl | hb := Decidable.em (b = 0) <;>
|
||||
simp [Nat.div_ne_zero_iff, Nat.le_iff_ne_zero_of_dvd, *]
|
||||
|
||||
theorem pow_mod (a b n : Nat) : a ^ b % n = (a % n) ^ b % n := by
|
||||
induction b with
|
||||
| zero => rfl
|
||||
| succ b ih => simp [Nat.pow_succ, Nat.mul_mod, ih]
|
||||
|
||||
theorem lt_of_pow_dvd_right (hb : b ≠ 0) (ha : 2 ≤ a) (h : a ^ n ∣ b) : n < b := by
|
||||
rw [← Nat.pow_lt_pow_iff_right (succ_le_iff.1 ha)]
|
||||
exact Nat.lt_of_le_of_lt (le_of_dvd (Nat.pos_iff_ne_zero.2 hb) h) (Nat.lt_pow_self ha)
|
||||
|
||||
theorem div_dvd_of_dvd {n m : Nat} (h : n ∣ m) : m / n ∣ m := ⟨n, (Nat.div_mul_cancel h).symm⟩
|
||||
|
||||
protected theorem div_div_self (h : n ∣ m) (hm : m ≠ 0) : m / (m / n) = n := by
|
||||
rcases h with ⟨_, rfl⟩
|
||||
rw [Nat.mul_ne_zero_iff] at hm
|
||||
rw [mul_div_right _ (Nat.pos_of_ne_zero hm.1), mul_div_left _ (Nat.pos_of_ne_zero hm.2)]
|
||||
|
||||
theorem not_dvd_of_pos_of_lt (h1 : 0 < n) (h2 : n < m) : ¬m ∣ n := by
|
||||
rintro ⟨k, rfl⟩
|
||||
rcases Nat.eq_zero_or_pos k with (rfl | hk)
|
||||
· exact Nat.lt_irrefl 0 h1
|
||||
· exact Nat.not_lt.2 (Nat.le_mul_of_pos_right _ hk) h2
|
||||
|
||||
theorem eq_of_dvd_of_lt_two_mul (ha : a ≠ 0) (hdvd : b ∣ a) (hlt : a < 2 * b) : a = b := by
|
||||
obtain ⟨_ | _ | c, rfl⟩ := hdvd
|
||||
· simp at ha
|
||||
· exact Nat.mul_one _
|
||||
· rw [Nat.mul_comm] at hlt
|
||||
cases Nat.not_le_of_lt hlt (Nat.mul_le_mul_right _ (by omega))
|
||||
|
||||
theorem mod_eq_iff_lt (hn : n ≠ 0) : m % n = m ↔ m < n :=
|
||||
⟨fun h ↦ by rw [← h]; exact mod_lt _ <| Nat.pos_iff_ne_zero.2 hn, mod_eq_of_lt⟩
|
||||
|
||||
@[simp]
|
||||
theorem mod_succ_eq_iff_lt {m n : Nat} : m % n.succ = m ↔ m < n.succ :=
|
||||
mod_eq_iff_lt (succ_ne_zero _)
|
||||
|
||||
@[simp] theorem mod_succ (n : Nat) : n % n.succ = n := mod_eq_of_lt n.lt_succ_self
|
||||
|
||||
theorem mod_add_div' (a b : Nat) : a % b + a / b * b = a := by rw [Nat.mul_comm]; exact mod_add_div _ _
|
||||
|
||||
theorem div_add_mod' (a b : Nat) : a / b * b + a % b = a := by rw [Nat.mul_comm]; exact div_add_mod _ _
|
||||
|
||||
/-- See also `Nat.divModEquiv` for a similar statement as an `Equiv`. -/
|
||||
protected theorem div_mod_unique (h : 0 < b) :
|
||||
a / b = d ∧ a % b = c ↔ c + b * d = a ∧ c < b :=
|
||||
⟨fun ⟨e₁, e₂⟩ ↦ e₁ ▸ e₂ ▸ ⟨mod_add_div _ _, mod_lt _ h⟩, fun ⟨h₁, h₂⟩ ↦ h₁ ▸ by
|
||||
rw [add_mul_div_left _ _ h, add_mul_mod_self_left]; simp [div_eq_of_lt, mod_eq_of_lt, h₂]⟩
|
||||
|
||||
/-- If `m` and `n` are equal mod `k`, `m - n` is zero mod `k`. -/
|
||||
theorem sub_mod_eq_zero_of_mod_eq (h : m % k = n % k) : (m - n) % k = 0 := by
|
||||
rw [← Nat.mod_add_div m k, ← Nat.mod_add_div n k, ← h, ← Nat.sub_sub,
|
||||
Nat.add_sub_cancel_left, ← k.mul_sub, Nat.mul_mod_right]
|
||||
|
||||
@[simp] theorem one_mod (n : Nat) : 1 % (n + 2) = 1 :=
|
||||
Nat.mod_eq_of_lt (Nat.add_lt_add_right n.succ_pos 1)
|
||||
|
||||
theorem one_mod_eq_one : ∀ {n : Nat}, 1 % n = 1 ↔ n ≠ 1
|
||||
| 0 | 1 | n + 2 => by simp; try omega
|
||||
|
||||
theorem dvd_sub_mod (k : Nat) : n ∣ k - k % n :=
|
||||
⟨k / n, Nat.sub_eq_of_eq_add (Nat.div_add_mod k n).symm⟩
|
||||
|
||||
theorem add_mod_eq_ite {m n : Nat} :
|
||||
(m + n) % k = if k ≤ m % k + n % k then m % k + n % k - k else m % k + n % k := by
|
||||
cases k with
|
||||
| zero => simp
|
||||
| succ k =>
|
||||
rw [Nat.add_mod]
|
||||
by_cases h : k + 1 ≤ m % (k + 1) + n % (k + 1)
|
||||
· rw [if_pos h, Nat.mod_eq_sub_mod h, Nat.mod_eq_of_lt]
|
||||
exact (Nat.sub_lt_iff_lt_add h).mpr (Nat.add_lt_add (m.mod_lt (zero_lt_succ _))
|
||||
(n.mod_lt (zero_lt_succ _)))
|
||||
· rw [if_neg h]
|
||||
exact Nat.mod_eq_of_lt (Nat.lt_of_not_ge h)
|
||||
|
||||
-- TODO: Replace `Nat.dvd_add_iff_left`
|
||||
protected theorem dvd_add_left {a b c : Nat} (h : a ∣ c) : a ∣ b + c ↔ a ∣ b := (Nat.dvd_add_iff_left h).symm
|
||||
|
||||
protected theorem dvd_add_right {a b c : Nat} (h : a ∣ b) : a ∣ b + c ↔ a ∣ c := (Nat.dvd_add_iff_right h).symm
|
||||
|
||||
theorem add_mod_eq_add_mod_right (c : Nat) (H : a % d = b % d) : (a + c) % d = (b + c) % d := by
|
||||
rw [← mod_add_mod, ← mod_add_mod b, H]
|
||||
|
||||
theorem add_mod_eq_add_mod_left (c : Nat) (H : a % d = b % d) : (c + a) % d = (c + b) % d := by
|
||||
rw [Nat.add_comm, add_mod_eq_add_mod_right _ H, Nat.add_comm]
|
||||
|
||||
theorem mul_dvd_of_dvd_div {a b c : Nat} (hcb : c ∣ b) (h : a ∣ b / c) : c * a ∣ b :=
|
||||
have ⟨d, hd⟩ := h
|
||||
⟨d, by simpa [Nat.mul_comm, Nat.mul_left_comm] using Nat.eq_mul_of_div_eq_left hcb hd⟩
|
||||
|
||||
theorem eq_of_dvd_of_div_eq_one (hab : a ∣ b) (h : b / a = 1) : a = b := by
|
||||
rw [← Nat.div_mul_cancel hab, h, Nat.one_mul]
|
||||
|
||||
theorem eq_zero_of_dvd_of_div_eq_zero (hab : a ∣ b) (h : b / a = 0) : b = 0 := by
|
||||
rw [← Nat.div_mul_cancel hab, h, Nat.zero_mul]
|
||||
|
||||
theorem lt_mul_div_succ (a : Nat) (hb : 0 < b) : a < b * (a / b + 1) := by
|
||||
rw [Nat.mul_comm, ← Nat.div_lt_iff_lt_mul hb]
|
||||
exact lt_succ_self _
|
||||
|
||||
theorem mul_add_div {m : Nat} (m_pos : m > 0) (x y : Nat) : (m * x + y) / m = x + y / m := by
|
||||
match x with
|
||||
| 0 => simp
|
||||
| x + 1 =>
|
||||
rw [Nat.mul_succ, Nat.add_assoc _ m, mul_add_div m_pos x (m+y), div_eq]
|
||||
simp +arith [m_pos]; rw [Nat.add_comm, Nat.add_sub_cancel]
|
||||
simp +arith [m_pos]
|
||||
|
||||
theorem mul_add_mod (m x y : Nat) : (m * x + y) % m = y % m := by
|
||||
match x with
|
||||
@@ -952,6 +1553,13 @@ theorem mul_add_mod (m x y : Nat) : (m * x + y) % m = y % m := by
|
||||
| x + 1 =>
|
||||
simp [Nat.mul_succ, Nat.add_assoc _ m, mul_add_mod _ x]
|
||||
|
||||
-- TODO: make naming and statements consistent across all variations of `mod`, `gcd` etc. across
|
||||
-- `Nat` and `Int`.
|
||||
theorem mul_add_mod' (a b c : Nat) : (a * b + c) % b = c % b := by rw [Nat.mul_comm, Nat.mul_add_mod]
|
||||
|
||||
theorem mul_add_mod_of_lt {a b c : Nat} (h : c < b) : (a * b + c) % b = c := by
|
||||
rw [Nat.mul_add_mod', Nat.mod_eq_of_lt h]
|
||||
|
||||
@[simp] theorem mod_div_self (m n : Nat) : m % n / n = 0 := by
|
||||
cases n
|
||||
· exact (m % 0).div_zero
|
||||
@@ -1009,6 +1617,113 @@ theorem succ_mod_succ_eq_zero_iff {a b : Nat} :
|
||||
subst h
|
||||
simp [Nat.add_mul]
|
||||
|
||||
|
||||
theorem dvd_iff_div_mul_eq (n d : Nat) : d ∣ n ↔ n / d * d = n :=
|
||||
⟨fun h => Nat.div_mul_cancel h, fun h => by rw [← h]; exact Nat.dvd_mul_left _ _⟩
|
||||
|
||||
theorem dvd_iff_le_div_mul (n d : Nat) : d ∣ n ↔ n ≤ n / d * d :=
|
||||
((dvd_iff_div_mul_eq _ _).trans Nat.le_antisymm_iff).trans (and_iff_right (div_mul_le_self n d))
|
||||
|
||||
theorem dvd_iff_dvd_dvd (n d : Nat) : d ∣ n ↔ ∀ k : Nat, k ∣ d → k ∣ n :=
|
||||
⟨fun h _ hkd => Nat.dvd_trans hkd h, fun h => h _ (Nat.dvd_refl _)⟩
|
||||
|
||||
theorem dvd_div_of_mul_dvd {a b c : Nat} (h : a * b ∣ c) : b ∣ c / a :=
|
||||
if ha : a = 0 then by simp [ha]
|
||||
else
|
||||
have ha : 0 < a := Nat.pos_of_ne_zero ha
|
||||
have h1 : ∃ d, c = a * b * d := h
|
||||
let ⟨d, hd⟩ := h1
|
||||
have h2 : c / a = b * d := Nat.div_eq_of_eq_mul_right ha (by simpa [Nat.mul_assoc] using hd)
|
||||
show ∃ d, c / a = b * d from ⟨d, h2⟩
|
||||
|
||||
@[simp] theorem dvd_div_iff_mul_dvd {a b c : Nat} (hbc : c ∣ b) : a ∣ b / c ↔ c * a ∣ b :=
|
||||
⟨fun h => mul_dvd_of_dvd_div hbc h, fun h => dvd_div_of_mul_dvd h⟩
|
||||
|
||||
theorem dvd_mul_of_div_dvd {a b c : Nat} (h : b ∣ a) (hdiv : a / b ∣ c) : a ∣ b * c := by
|
||||
obtain ⟨e, rfl⟩ := hdiv
|
||||
rw [← Nat.mul_assoc, Nat.mul_comm _ (a / b), Nat.div_mul_cancel h]
|
||||
exact Nat.dvd_mul_right a e
|
||||
|
||||
@[simp] theorem div_div_div_eq_div {a b c : Nat} (dvd : b ∣ a) (dvd2 : a ∣ c) : c / (a / b) / b = c / a :=
|
||||
match a, b, c with
|
||||
| 0, _, _ => by simp
|
||||
| a + 1, 0, _ => by simp at dvd
|
||||
| a + 1, c + 1, _ => by
|
||||
have a_split : a + 1 ≠ 0 := succ_ne_zero a
|
||||
have c_split : c + 1 ≠ 0 := succ_ne_zero c
|
||||
rcases dvd2 with ⟨k, rfl⟩
|
||||
rcases dvd with ⟨k2, pr⟩
|
||||
have k2_nonzero : k2 ≠ 0 := fun k2_zero => by simp [k2_zero] at pr
|
||||
rw [Nat.mul_div_cancel_left k (Nat.pos_of_ne_zero a_split), pr,
|
||||
Nat.mul_div_cancel_left k2 (Nat.pos_of_ne_zero c_split), Nat.mul_comm ((c + 1) * k2) k, ←
|
||||
Nat.mul_assoc k (c + 1) k2, Nat.mul_div_cancel _ (Nat.pos_of_ne_zero k2_nonzero),
|
||||
Nat.mul_div_cancel _ (Nat.pos_of_ne_zero c_split)]
|
||||
|
||||
/-- If a small natural number is divisible by a larger natural number,
|
||||
the small number is zero. -/
|
||||
theorem eq_zero_of_dvd_of_lt (w : a ∣ b) (h : b < a) : b = 0 :=
|
||||
Nat.eq_zero_of_dvd_of_div_eq_zero w (by simp [h])
|
||||
|
||||
theorem le_of_lt_add_of_dvd {a b : Nat} (h : a < b + n) : n ∣ a → n ∣ b → a ≤ b := by
|
||||
rintro ⟨a, rfl⟩ ⟨b, rfl⟩
|
||||
rw [← mul_succ] at h
|
||||
exact Nat.mul_le_mul_left _ (Nat.lt_succ_iff.1 <| Nat.lt_of_mul_lt_mul_left h)
|
||||
|
||||
/-- `m` is not divisible by `n` if it is between `n * k` and `n * (k + 1)` for some `k`. -/
|
||||
theorem not_dvd_of_lt_of_lt_mul_succ (h1 : n * k < m) (h2 : m < n * (k + 1)) : ¬n ∣ m := by
|
||||
rintro ⟨d, rfl⟩
|
||||
have := Nat.lt_of_mul_lt_mul_left h1
|
||||
have := Nat.lt_of_mul_lt_mul_left h2
|
||||
omega
|
||||
|
||||
/-- `n` is not divisible by `a` iff it is between `a * k` and `a * (k + 1)` for some `k`. -/
|
||||
theorem not_dvd_iff_lt_mul_succ (n : Nat) {a : Nat} (ha : 0 < a) :
|
||||
¬a ∣ n ↔ (∃ k : Nat, a * k < n ∧ n < a * (k + 1)) := by
|
||||
refine Iff.symm
|
||||
⟨fun ⟨k, hk1, hk2⟩ => not_dvd_of_lt_of_lt_mul_succ hk1 hk2, fun han =>
|
||||
⟨n / a, ⟨Nat.lt_of_le_of_ne (mul_div_le n a) ?_, lt_mul_div_succ _ ha⟩⟩⟩
|
||||
exact mt (⟨n / a, Eq.symm ·⟩) han
|
||||
|
||||
theorem div_lt_div_of_lt_of_dvd {a b d : Nat} (hdb : d ∣ b) (h : a < b) : a / d < b / d := by
|
||||
rw [Nat.lt_div_iff_mul_lt' hdb]
|
||||
exact Nat.lt_of_le_of_lt (mul_div_le a d) h
|
||||
|
||||
/-! ### shiftLeft and shiftRight -/
|
||||
|
||||
@[simp] theorem shiftLeft_zero : n <<< 0 = n := rfl
|
||||
|
||||
/-- Shiftleft on successor with multiple moved inside. -/
|
||||
theorem shiftLeft_succ_inside (m n : Nat) : m <<< (n+1) = (2*m) <<< n := rfl
|
||||
|
||||
/-- Shiftleft on successor with multiple moved to outside. -/
|
||||
theorem shiftLeft_succ : ∀(m n), m <<< (n + 1) = 2 * (m <<< n)
|
||||
| _, 0 => rfl
|
||||
| _, k + 1 => by
|
||||
rw [shiftLeft_succ_inside _ (k+1)]
|
||||
rw [shiftLeft_succ _ k, shiftLeft_succ_inside]
|
||||
|
||||
/-- Shiftright on successor with division moved inside. -/
|
||||
theorem shiftRight_succ_inside : ∀m n, m >>> (n+1) = (m/2) >>> n
|
||||
| _, 0 => rfl
|
||||
| _, k + 1 => by
|
||||
rw [shiftRight_succ _ (k+1)]
|
||||
rw [shiftRight_succ_inside _ k, shiftRight_succ]
|
||||
|
||||
@[simp] theorem zero_shiftLeft : ∀ n, 0 <<< n = 0
|
||||
| 0 => by simp [shiftLeft]
|
||||
| n + 1 => by simp [shiftLeft, zero_shiftLeft n, shiftLeft_succ]
|
||||
|
||||
@[simp] theorem zero_shiftRight : ∀ n, 0 >>> n = 0
|
||||
| 0 => by simp [shiftRight]
|
||||
| n + 1 => by simp [shiftRight, zero_shiftRight n, shiftRight_succ]
|
||||
|
||||
theorem shiftLeft_add (m n : Nat) : ∀ k, m <<< (n + k) = (m <<< n) <<< k
|
||||
| 0 => rfl
|
||||
| k + 1 => by simp [← Nat.add_assoc, shiftLeft_add _ _ k, shiftLeft_succ]
|
||||
|
||||
@[simp] theorem shiftLeft_shiftRight (x n : Nat) : x <<< n >>> n = x := by
|
||||
rw [Nat.shiftLeft_eq, Nat.shiftRight_eq_div_pow, Nat.mul_div_cancel _ (Nat.two_pow_pos _)]
|
||||
|
||||
/-! ### Decidability of predicates -/
|
||||
|
||||
instance decidableBallLT :
|
||||
|
||||
@@ -146,7 +146,7 @@ instance : LawfulBEq PolyCnstr where
|
||||
rfl {a} := by
|
||||
cases a; rename_i eq lhs rhs
|
||||
show (eq == eq && (lhs == lhs && rhs == rhs)) = true
|
||||
simp [LawfulBEq.rfl]
|
||||
simp
|
||||
|
||||
structure ExprCnstr where
|
||||
eq : Bool
|
||||
|
||||
@@ -52,8 +52,8 @@ protected theorem min_le_right (a b : Nat) : min a b ≤ b := by
|
||||
protected theorem min_le_left (a b : Nat) : min a b ≤ a :=
|
||||
Nat.min_comm .. ▸ Nat.min_le_right ..
|
||||
|
||||
protected theorem min_eq_left {a b : Nat} (h : a ≤ b) : min a b = a := if_pos h
|
||||
protected theorem min_eq_right {a b : Nat} (h : b ≤ a) : min a b = b :=
|
||||
@[simp] protected theorem min_eq_left {a b : Nat} (h : a ≤ b) : min a b = a := if_pos h
|
||||
@[simp] protected theorem min_eq_right {a b : Nat} (h : b ≤ a) : min a b = b :=
|
||||
Nat.min_comm .. ▸ Nat.min_eq_left h
|
||||
|
||||
protected theorem le_min_of_le_of_le {a b c : Nat} : a ≤ b → a ≤ c → a ≤ min b c := by
|
||||
@@ -111,9 +111,9 @@ protected theorem le_max_left (a b : Nat) : a ≤ max a b := by
|
||||
protected theorem le_max_right (a b : Nat) : b ≤ max a b :=
|
||||
Nat.max_comm .. ▸ Nat.le_max_left ..
|
||||
|
||||
protected theorem max_eq_right {a b : Nat} (h : a ≤ b) : max a b = b := if_pos h
|
||||
@[simp] protected theorem max_eq_right {a b : Nat} (h : a ≤ b) : max a b = b := if_pos h
|
||||
|
||||
protected theorem max_eq_left {a b : Nat} (h : b ≤ a) : max a b = a :=
|
||||
@[simp] protected theorem max_eq_left {a b : Nat} (h : b ≤ a) : max a b = a :=
|
||||
Nat.max_comm .. ▸ Nat.max_eq_right h
|
||||
|
||||
protected theorem max_le_of_le_of_le {a b c : Nat} : a ≤ c → b ≤ c → max a b ≤ c := by
|
||||
|
||||
@@ -141,11 +141,11 @@ theorem toList_attach (o : Option α) :
|
||||
cases o <;> simp
|
||||
|
||||
theorem attach_map {o : Option α} (f : α → β) :
|
||||
(o.map f).attach = o.attach.map (fun ⟨x, h⟩ => ⟨f x, map_eq_some.2 ⟨_, h, rfl⟩⟩) := by
|
||||
(o.map f).attach = o.attach.map (fun ⟨x, h⟩ => ⟨f x, map_eq_some_iff.2 ⟨_, h, rfl⟩⟩) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem attachWith_map {o : Option α} (f : α → β) {P : β → Prop} {H : ∀ (b : β), o.map f = some b → P b} :
|
||||
(o.map f).attachWith P H = (o.attachWith (P ∘ f) (fun _ h => H _ (map_eq_some.2 ⟨_, h, rfl⟩))).map
|
||||
(o.map f).attachWith P H = (o.attachWith (P ∘ f) (fun _ h => H _ (map_eq_some_iff.2 ⟨_, h, rfl⟩))).map
|
||||
fun ⟨x, h⟩ => ⟨f x, h⟩ := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -174,7 +174,7 @@ theorem map_attach_eq_attachWith {o : Option α} {p : α → Prop} (f : ∀ a, o
|
||||
|
||||
theorem attach_bind {o : Option α} {f : α → Option β} :
|
||||
(o.bind f).attach =
|
||||
o.attach.bind fun ⟨x, h⟩ => (f x).attach.map fun ⟨y, h'⟩ => ⟨y, bind_eq_some.2 ⟨_, h, h'⟩⟩ := by
|
||||
o.attach.bind fun ⟨x, h⟩ => (f x).attach.map fun ⟨y, h'⟩ => ⟨y, bind_eq_some_iff.2 ⟨_, h, h'⟩⟩ := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem bind_attach {o : Option α} {f : {x // o = some x} → Option β} :
|
||||
@@ -262,7 +262,7 @@ and simplifies these to the function directly taking the value.
|
||||
|
||||
@[simp] theorem bind_subtype {p : α → Prop} {o : Option { x // p x }}
|
||||
{f : { x // p x } → Option β} {g : α → Option β} (hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
(o.bind f) = o.unattach.bind g := by
|
||||
o.bind f = o.unattach.bind g := by
|
||||
cases o <;> simp [hf]
|
||||
|
||||
@[simp] theorem unattach_filter {p : α → Prop} {o : Option { x // p x }}
|
||||
|
||||
@@ -231,13 +231,12 @@ def merge (fn : α → α → α) : Option α → Option α → Option α
|
||||
@[simp] theorem getD_none : getD none a = a := rfl
|
||||
@[simp] theorem getD_some : getD (some a) b = a := rfl
|
||||
|
||||
@[simp] theorem map_none' (f : α → β) : none.map f = none := rfl
|
||||
@[simp] theorem map_some' (a) (f : α → β) : (some a).map f = some (f a) := rfl
|
||||
@[simp] theorem map_none (f : α → β) : none.map f = none := rfl
|
||||
@[simp] theorem map_some (a) (f : α → β) : (some a).map f = some (f a) := rfl
|
||||
|
||||
@[simp] theorem none_bind (f : α → Option β) : none.bind f = none := rfl
|
||||
@[simp] theorem some_bind (a) (f : α → Option β) : (some a).bind f = f a := rfl
|
||||
|
||||
|
||||
/--
|
||||
A case analysis function for `Option`.
|
||||
|
||||
@@ -387,11 +386,13 @@ This is the monadic analogue of `Option.getD`.
|
||||
| some a => pure a
|
||||
| none => y
|
||||
|
||||
instance (α) [BEq α] [LawfulBEq α] : LawfulBEq (Option α) where
|
||||
instance (α) [BEq α] [ReflBEq α] : ReflBEq (Option α) where
|
||||
rfl {x} :=
|
||||
match x with
|
||||
| some _ => LawfulBEq.rfl (α := α)
|
||||
| some _ => BEq.rfl (α := α)
|
||||
| none => rfl
|
||||
|
||||
instance (α) [BEq α] [LawfulBEq α] : LawfulBEq (Option α) where
|
||||
eq_of_beq {x y h} := by
|
||||
match x, y with
|
||||
| some x, some y => rw [LawfulBEq.eq_of_beq (α := α) h]
|
||||
|
||||
@@ -39,18 +39,24 @@ This is not an instance because it is not definitionally equal to the standard i
|
||||
|
||||
Try to use the Boolean comparisons `Option.isNone` or `Option.isSome` instead.
|
||||
-/
|
||||
@[inline] def decidable_eq_none {o : Option α} : Decidable (o = none) :=
|
||||
@[inline] def decidableEqNone {o : Option α} : Decidable (o = none) :=
|
||||
decidable_of_decidable_of_iff isNone_iff_eq_none
|
||||
|
||||
instance {p : α → Prop} [DecidablePred p] : ∀ o : Option α, Decidable (∀ a, a ∈ o → p a)
|
||||
| none => isTrue nofun
|
||||
| some a =>
|
||||
if h : p a then isTrue fun _ e => some_inj.1 e ▸ h
|
||||
else isFalse <| mt (· _ rfl) h
|
||||
@[deprecated decidableEqNone (since := "2025-04-10"), inline]
|
||||
def decidable_eq_none {o : Option α} : Decidable (o = none) :=
|
||||
decidableEqNone
|
||||
|
||||
instance {p : α → Prop} [DecidablePred p] : ∀ o : Option α, Decidable (Exists fun a => a ∈ o ∧ p a)
|
||||
| none => isFalse nofun
|
||||
| some a => if h : p a then isTrue ⟨_, rfl, h⟩ else isFalse fun ⟨_, ⟨rfl, hn⟩⟩ => h hn
|
||||
instance decidableForallMem {p : α → Prop} [DecidablePred p] :
|
||||
∀ o : Option α, Decidable (∀ a, a ∈ o → p a)
|
||||
| none => isTrue nofun
|
||||
| some a =>
|
||||
if h : p a then isTrue fun _ e => some_inj.1 e ▸ h
|
||||
else isFalse <| mt (· _ rfl) h
|
||||
|
||||
instance decidableExistsMem {p : α → Prop} [DecidablePred p] :
|
||||
∀ o : Option α, Decidable (Exists fun a => a ∈ o ∧ p a)
|
||||
| none => isFalse nofun
|
||||
| some a => if h : p a then isTrue ⟨_, rfl, h⟩ else isFalse fun ⟨_, ⟨rfl, hn⟩⟩ => h hn
|
||||
|
||||
/--
|
||||
Given an optional value and a function that can be applied when the value is `some`, returns the
|
||||
|
||||
@@ -17,6 +17,8 @@ theorem mem_iff {a : α} {b : Option α} : a ∈ b ↔ b = some a := .rfl
|
||||
|
||||
theorem mem_some {a b : α} : a ∈ some b ↔ b = a := by simp
|
||||
|
||||
theorem mem_some_iff {a b : α} : a ∈ some b ↔ b = a := mem_some
|
||||
|
||||
theorem mem_some_self (a : α) : a ∈ some a := rfl
|
||||
|
||||
theorem some_ne_none (x : α) : some x ≠ none := nofun
|
||||
@@ -29,6 +31,9 @@ protected theorem «exists» {p : Option α → Prop} :
|
||||
⟨fun | ⟨none, hx⟩ => .inl hx | ⟨some x, hx⟩ => .inr ⟨x, hx⟩,
|
||||
fun | .inl h => ⟨_, h⟩ | .inr ⟨_, hx⟩ => ⟨_, hx⟩⟩
|
||||
|
||||
theorem eq_none_or_eq_some (a : Option α) : a = none ∨ ∃ x, a = some x :=
|
||||
Option.exists.mp exists_eq'
|
||||
|
||||
theorem get_mem : ∀ {o : Option α} (h : isSome o), o.get h ∈ o
|
||||
| some _, _ => rfl
|
||||
|
||||
@@ -88,6 +93,9 @@ set_option Elab.async false
|
||||
theorem eq_none_iff_forall_ne_some : o = none ↔ ∀ a, o ≠ some a := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem eq_none_iff_forall_some_ne : o = none ↔ ∀ a, some a ≠ o := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem eq_none_iff_forall_not_mem : o = none ↔ ∀ a, a ∉ o :=
|
||||
eq_none_iff_forall_ne_some
|
||||
|
||||
@@ -102,9 +110,30 @@ theorem isSome_of_mem {x : Option α} {y : α} (h : y ∈ x) : x.isSome := by
|
||||
theorem isSome_of_eq_some {x : Option α} {y : α} (h : x = some y) : x.isSome := by
|
||||
cases x <;> trivial
|
||||
|
||||
@[simp] theorem not_isSome : isSome a = false ↔ a.isNone = true := by
|
||||
@[simp] theorem isSome_eq_false_iff : isSome a = false ↔ a.isNone = true := by
|
||||
cases a <;> simp
|
||||
|
||||
@[simp] theorem isNone_eq_false_iff : isNone a = false ↔ a.isSome = true := by
|
||||
cases a <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem not_isSome (a : Option α) : (!a.isSome) = a.isNone := by
|
||||
cases a <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem not_comp_isSome : (! ·) ∘ @Option.isSome α = Option.isNone := by
|
||||
funext
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem not_isNone (a : Option α) : (!a.isNone) = a.isSome := by
|
||||
cases a <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem not_comp_isNone : (!·) ∘ @Option.isNone α = Option.isSome := by
|
||||
funext x
|
||||
simp
|
||||
|
||||
theorem eq_some_iff_get_eq : o = some a ↔ ∃ h : o.isSome, o.get h = a := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -146,17 +175,25 @@ abbrev ball_ne_none := @forall_ne_none
|
||||
|
||||
@[simp] theorem bind_eq_bind : bind = @Option.bind α β := rfl
|
||||
|
||||
@[simp] theorem orElse_eq_orElse : HOrElse.hOrElse = @Option.orElse α := rfl
|
||||
|
||||
@[simp] theorem bind_some (x : Option α) : x.bind some = x := by cases x <;> rfl
|
||||
|
||||
@[simp] theorem bind_none (x : Option α) : x.bind (fun _ => none (α := β)) = none := by
|
||||
cases x <;> rfl
|
||||
|
||||
theorem bind_eq_some : x.bind f = some b ↔ ∃ a, x = some a ∧ f a = some b := by
|
||||
theorem bind_eq_some_iff : x.bind f = some b ↔ ∃ a, x = some a ∧ f a = some b := by
|
||||
cases x <;> simp
|
||||
|
||||
@[simp] theorem bind_eq_none {o : Option α} {f : α → Option β} :
|
||||
@[deprecated bind_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev bind_eq_some := @bind_eq_some_iff
|
||||
|
||||
@[simp] theorem bind_eq_none_iff {o : Option α} {f : α → Option β} :
|
||||
o.bind f = none ↔ ∀ a, o = some a → f a = none := by cases o <;> simp
|
||||
|
||||
@[deprecated bind_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev bind_eq_none := @bind_eq_none_iff
|
||||
|
||||
theorem bind_eq_none' {o : Option α} {f : α → Option β} :
|
||||
o.bind f = none ↔ ∀ b a, o = some a → f a ≠ some b := by
|
||||
cases o <;> simp [eq_none_iff_forall_ne_some]
|
||||
@@ -193,50 +230,67 @@ theorem isSome_apply_of_isSome_bind {α β : Type _} {x : Option α} {f : α →
|
||||
(isSome_apply_of_isSome_bind h) := by
|
||||
cases x <;> trivial
|
||||
|
||||
theorem join_eq_some : x.join = some a ↔ x = some (some a) := by
|
||||
simp [bind_eq_some]
|
||||
theorem join_eq_some_iff : x.join = some a ↔ x = some (some a) := by
|
||||
simp [bind_eq_some_iff]
|
||||
|
||||
@[deprecated join_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev join_eq_some := @join_eq_some_iff
|
||||
|
||||
theorem join_ne_none : x.join ≠ none ↔ ∃ z, x = some (some z) := by
|
||||
simp only [ne_none_iff_exists', join_eq_some, iff_self]
|
||||
simp only [ne_none_iff_exists', join_eq_some_iff, iff_self]
|
||||
|
||||
theorem join_ne_none' : ¬x.join = none ↔ ∃ z, x = some (some z) :=
|
||||
join_ne_none
|
||||
|
||||
theorem join_eq_none : o.join = none ↔ o = none ∨ o = some none :=
|
||||
theorem join_eq_none_iff : o.join = none ↔ o = none ∨ o = some none :=
|
||||
match o with | none | some none | some (some _) => by simp
|
||||
|
||||
@[deprecated join_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev join_eq_none := @join_eq_none_iff
|
||||
|
||||
theorem bind_id_eq_join {x : Option (Option α)} : x.bind id = x.join := rfl
|
||||
|
||||
@[simp] theorem map_eq_map : Functor.map f = Option.map f := rfl
|
||||
|
||||
theorem map_none : f <$> none = none := rfl
|
||||
@[deprecated map_none (since := "2025-04-10")]
|
||||
abbrev map_none' := @map_none
|
||||
|
||||
theorem map_some : f <$> some a = some (f a) := rfl
|
||||
@[deprecated map_some (since := "2025-04-10")]
|
||||
abbrev map_some' := @map_some
|
||||
|
||||
@[simp] theorem map_eq_some' : x.map f = some b ↔ ∃ a, x = some a ∧ f a = b := by cases x <;> simp
|
||||
|
||||
theorem map_eq_some : f <$> x = some b ↔ ∃ a, x = some a ∧ f a = b := map_eq_some'
|
||||
|
||||
@[simp] theorem map_eq_none' : x.map f = none ↔ x = none := by
|
||||
cases x <;> simp [map_none', map_some', eq_self_iff_true]
|
||||
|
||||
theorem isSome_map {x : Option α} : (f <$> x).isSome = x.isSome := by
|
||||
@[simp] theorem map_eq_some_iff : x.map f = some b ↔ ∃ a, x = some a ∧ f a = b := by
|
||||
cases x <;> simp
|
||||
|
||||
@[simp] theorem isSome_map' {x : Option α} : (x.map f).isSome = x.isSome := by
|
||||
@[deprecated map_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev map_eq_some := @map_eq_some_iff
|
||||
|
||||
@[deprecated map_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev map_eq_some' := @map_eq_some_iff
|
||||
|
||||
@[simp] theorem map_eq_none_iff : x.map f = none ↔ x = none := by
|
||||
cases x <;> simp [map_none, map_some, eq_self_iff_true]
|
||||
|
||||
@[deprecated map_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev map_eq_none := @map_eq_none_iff
|
||||
|
||||
@[deprecated map_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev map_eq_none' := @map_eq_none_iff
|
||||
|
||||
@[simp] theorem isSome_map {x : Option α} : (x.map f).isSome = x.isSome := by
|
||||
cases x <;> simp
|
||||
|
||||
@[simp] theorem isNone_map' {x : Option α} : (x.map f).isNone = x.isNone := by
|
||||
cases x <;> simp
|
||||
@[deprecated isSome_map (since := "2025-04-10")]
|
||||
abbrev isSome_map' := @isSome_map
|
||||
|
||||
theorem map_eq_none : f <$> x = none ↔ x = none := map_eq_none'
|
||||
@[simp] theorem isNone_map {x : Option α} : (x.map f).isNone = x.isNone := by
|
||||
cases x <;> simp
|
||||
|
||||
theorem map_eq_bind {x : Option α} : x.map f = x.bind (some ∘ f) := by
|
||||
cases x <;> simp [Option.bind]
|
||||
|
||||
theorem map_congr {x : Option α} (h : ∀ a, x = some a → f a = g a) :
|
||||
x.map f = x.map g := by
|
||||
cases x <;> simp only [map_none', map_some', h]
|
||||
cases x <;> simp only [map_none, map_some, h]
|
||||
|
||||
@[simp] theorem map_id_fun {α : Type u} : Option.map (id : α → α) = id := by
|
||||
funext; simp [map_id]
|
||||
@@ -254,7 +308,7 @@ theorem get_map {f : α → β} {o : Option α} {h : (o.map f).isSome} :
|
||||
|
||||
@[simp] theorem map_map (h : β → γ) (g : α → β) (x : Option α) :
|
||||
(x.map g).map h = x.map (h ∘ g) := by
|
||||
cases x <;> simp only [map_none', map_some', ·∘·]
|
||||
cases x <;> simp only [map_none, map_some, ·∘·]
|
||||
|
||||
theorem comp_map (h : β → γ) (g : α → β) (x : Option α) : x.map (h ∘ g) = (x.map g).map h :=
|
||||
(map_map ..).symm
|
||||
@@ -262,7 +316,7 @@ theorem comp_map (h : β → γ) (g : α → β) (x : Option α) : x.map (h ∘
|
||||
@[simp] theorem map_comp_map (f : α → β) (g : β → γ) :
|
||||
Option.map g ∘ Option.map f = Option.map (g ∘ f) := by funext x; simp
|
||||
|
||||
theorem mem_map_of_mem (g : α → β) (h : a ∈ x) : g a ∈ Option.map g x := h.symm ▸ map_some' ..
|
||||
theorem mem_map_of_mem (g : α → β) (h : a ∈ x) : g a ∈ Option.map g x := h.symm ▸ map_some ..
|
||||
|
||||
theorem map_inj_right {f : α → β} {o o' : Option α} (w : ∀ x y, f x = f y → x = y) :
|
||||
o.map f = o'.map f ↔ o = o' := by
|
||||
@@ -292,11 +346,14 @@ theorem isSome_of_isSome_filter (p : α → Bool) (o : Option α) (h : (o.filter
|
||||
@[deprecated isSome_of_isSome_filter (since := "2025-03-18")]
|
||||
abbrev isSome_filter_of_isSome := @isSome_of_isSome_filter
|
||||
|
||||
@[simp] theorem filter_eq_none {o : Option α} {p : α → Bool} :
|
||||
@[simp] theorem filter_eq_none_iff {o : Option α} {p : α → Bool} :
|
||||
o.filter p = none ↔ ∀ a, o = some a → ¬ p a := by
|
||||
cases o <;> simp [filter_some]
|
||||
|
||||
@[simp] theorem filter_eq_some {o : Option α} {p : α → Bool} :
|
||||
@[deprecated filter_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev filter_eq_none := @filter_eq_none_iff
|
||||
|
||||
@[simp] theorem filter_eq_some_iff {o : Option α} {p : α → Bool} :
|
||||
o.filter p = some a ↔ o = some a ∧ p a := by
|
||||
cases o with
|
||||
| none => simp
|
||||
@@ -310,6 +367,9 @@ abbrev isSome_filter_of_isSome := @isSome_of_isSome_filter
|
||||
rintro rfl
|
||||
simpa using h
|
||||
|
||||
@[deprecated filter_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev filter_eq_some := @filter_eq_some_iff
|
||||
|
||||
theorem mem_filter_iff {p : α → Bool} {a : α} {o : Option α} :
|
||||
a ∈ o.filter p ↔ a ∈ o ∧ p a := by
|
||||
simp
|
||||
@@ -383,29 +443,43 @@ theorem join_join {x : Option (Option (Option α))} : x.join.join = (x.map join)
|
||||
cases x <;> simp
|
||||
|
||||
theorem mem_of_mem_join {a : α} {x : Option (Option α)} (h : a ∈ x.join) : some a ∈ x :=
|
||||
h.symm ▸ join_eq_some.1 h
|
||||
h.symm ▸ join_eq_some_iff.1 h
|
||||
|
||||
@[simp] theorem some_orElse (a : α) (x : Option α) : (some a <|> x) = some a := rfl
|
||||
@[simp] theorem some_orElse (a : α) (f) : (some a).orElse f = some a := rfl
|
||||
|
||||
@[simp] theorem none_orElse (x : Option α) : (none <|> x) = x := rfl
|
||||
@[simp] theorem none_orElse (f : Unit → Option α) : none.orElse f = f () := rfl
|
||||
|
||||
@[simp] theorem orElse_none (x : Option α) : (x <|> none) = x := by cases x <;> rfl
|
||||
@[simp] theorem orElse_none (x : Option α) : x.orElse (fun _ => none) = x := by cases x <;> rfl
|
||||
|
||||
theorem map_orElse {x y : Option α} : (x <|> y).map f = (x.map f <|> y.map f) := by
|
||||
theorem orElse_eq_some_iff (o : Option α) (f) (x : α) :
|
||||
(o.orElse f) = some x ↔ o = some x ∨ o = none ∧ f () = some x := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem orElse_eq_none_iff (o : Option α) (f) : (o.orElse f) = none ↔ o = none ∧ f () = none := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem map_orElse {x : Option α} {y} :
|
||||
(x.orElse y).map f = (x.map f).orElse (fun _ => (y ()).map f) := by
|
||||
cases x <;> simp
|
||||
|
||||
@[simp] theorem guard_eq_some [DecidablePred p] : guard p a = some b ↔ a = b ∧ p a :=
|
||||
@[simp] theorem guard_eq_some_iff [DecidablePred p] : guard p a = some b ↔ a = b ∧ p a :=
|
||||
if h : p a then by simp [Option.guard, h] else by simp [Option.guard, h]
|
||||
|
||||
@[deprecated guard_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev guard_eq_some := @guard_eq_some_iff
|
||||
|
||||
@[simp] theorem isSome_guard [DecidablePred p] : (Option.guard p a).isSome ↔ p a :=
|
||||
if h : p a then by simp [Option.guard, h] else by simp [Option.guard, h]
|
||||
|
||||
@[deprecated isSome_guard (since := "2025-03-18")]
|
||||
abbrev guard_isSome := @isSome_guard
|
||||
|
||||
@[simp] theorem guard_eq_none [DecidablePred p] : Option.guard p a = none ↔ ¬ p a :=
|
||||
@[simp] theorem guard_eq_none_iff [DecidablePred p] : Option.guard p a = none ↔ ¬ p a :=
|
||||
if h : p a then by simp [Option.guard, h] else by simp [Option.guard, h]
|
||||
|
||||
@[deprecated guard_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev guard_eq_none := @guard_eq_none_iff
|
||||
|
||||
@[simp] theorem guard_pos [DecidablePred p] (h : p a) : Option.guard p a = some a := by
|
||||
simp [Option.guard, h]
|
||||
|
||||
@@ -475,6 +549,22 @@ theorem liftOrGet_none_right {f} {a : Option α} : merge f a none = a :=
|
||||
theorem liftOrGet_some_some {f} {a b : α} : merge f (some a) (some b) = f a b :=
|
||||
merge_some_some
|
||||
|
||||
instance commutative_merge (f : α → α → α) [Std.Commutative f] :
|
||||
Std.Commutative (merge f) :=
|
||||
⟨fun a b ↦ by cases a <;> cases b <;> simp [merge, Std.Commutative.comm]⟩
|
||||
|
||||
instance associative_merge (f : α → α → α) [Std.Associative f] :
|
||||
Std.Associative (merge f) :=
|
||||
⟨fun a b c ↦ by cases a <;> cases b <;> cases c <;> simp [merge, Std.Associative.assoc]⟩
|
||||
|
||||
instance idempotentOp_merge (f : α → α → α) [Std.IdempotentOp f] :
|
||||
Std.IdempotentOp (merge f) :=
|
||||
⟨fun a ↦ by cases a <;> simp [merge, Std.IdempotentOp.idempotent]⟩
|
||||
|
||||
instance lawfulIdentity_merge (f : α → α → α) : Std.LawfulIdentity (merge f) none where
|
||||
left_id a := by cases a <;> simp [merge]
|
||||
right_id a := by cases a <;> simp [merge]
|
||||
|
||||
@[simp] theorem elim_none (x : β) (f : α → β) : none.elim x f = x := rfl
|
||||
|
||||
@[simp] theorem elim_some (x : β) (f : α → β) (a : α) : (some a).elim x f = f a := rfl
|
||||
@@ -535,12 +625,18 @@ theorem or_eq_bif : or o o' = bif o.isSome then o else o' := by
|
||||
@[simp] theorem isNone_or : (or o o').isNone = (o.isNone && o'.isNone) := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp] theorem or_eq_none : or o o' = none ↔ o = none ∧ o' = none := by
|
||||
@[simp] theorem or_eq_none_iff : or o o' = none ↔ o = none ∧ o' = none := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem or_eq_some : or o o' = some a ↔ o = some a ∨ (o = none ∧ o' = some a) := by
|
||||
@[deprecated or_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev or_eq_none := @or_eq_none_iff
|
||||
|
||||
@[simp] theorem or_eq_some_iff : or o o' = some a ↔ o = some a ∨ (o = none ∧ o' = some a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[deprecated or_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev or_eq_some := @or_eq_some_iff
|
||||
|
||||
theorem or_assoc : or (or o₁ o₂) o₃ = or o₁ (or o₂ o₃) := by
|
||||
cases o₁ <;> cases o₂ <;> rfl
|
||||
instance : Std.Associative (or (α := α)) := ⟨@or_assoc _⟩
|
||||
@@ -564,11 +660,11 @@ instance : Std.IdempotentOp (or (α := α)) := ⟨@or_self _⟩
|
||||
theorem or_eq_orElse : or o o' = o.orElse (fun _ => o') := by
|
||||
cases o <;> rfl
|
||||
|
||||
theorem map_or : f <$> or o o' = (f <$> o).or (f <$> o') := by
|
||||
theorem map_or : (or o o').map f = (o.map f).or (o'.map f) := by
|
||||
cases o <;> rfl
|
||||
|
||||
theorem map_or' : (or o o').map f = (o.map f).or (o'.map f) := by
|
||||
cases o <;> rfl
|
||||
@[deprecated map_or (since := "2025-04-10")]
|
||||
abbrev map_or' := @map_or
|
||||
|
||||
theorem or_of_isSome {o o' : Option α} (h : o.isSome) : o.or o' = o := by
|
||||
match o, h with
|
||||
@@ -598,27 +694,19 @@ variable [BEq α]
|
||||
simpa only [some_beq_some]
|
||||
simp
|
||||
· intro h
|
||||
constructor
|
||||
· rintro (_ | a) <;> simp
|
||||
infer_instance
|
||||
|
||||
@[simp] theorem lawfulBEq_iff : LawfulBEq (Option α) ↔ LawfulBEq α := by
|
||||
constructor
|
||||
· intro h
|
||||
have : ReflBEq α := reflBEq_iff.mp inferInstance
|
||||
constructor
|
||||
· intro a b h
|
||||
apply Option.some.inj
|
||||
apply eq_of_beq
|
||||
simpa
|
||||
· intro a
|
||||
suffices (some a == some a) = true by
|
||||
simpa only [some_beq_some]
|
||||
simp
|
||||
intro a b h
|
||||
apply Option.some.inj
|
||||
apply eq_of_beq
|
||||
simpa
|
||||
· intro h
|
||||
constructor
|
||||
· intro a b h
|
||||
simpa using h
|
||||
· intro a
|
||||
simp
|
||||
infer_instance
|
||||
|
||||
end beq
|
||||
|
||||
@@ -804,7 +892,7 @@ theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (o H)
|
||||
|
||||
theorem pmap_map (o : Option α) (f : α → β) {p : β → Prop} (g : ∀ b, p b → γ) (H) :
|
||||
pmap g (o.map f) H =
|
||||
pmap (fun a h => g (f a) h) o (fun a m => H (f a) (map_eq_some.2 ⟨_, m, rfl⟩)) := by
|
||||
pmap (fun a h => g (f a) h) o (fun a m => H (f a) (map_eq_some_iff.2 ⟨_, m, rfl⟩)) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem pmap_pred_congr {α : Type u}
|
||||
|
||||
@@ -9,11 +9,13 @@ import Init.NotationExtra
|
||||
|
||||
namespace Prod
|
||||
|
||||
instance [BEq α] [BEq β] [ReflBEq α] [ReflBEq β] : ReflBEq (α × β) where
|
||||
rfl {a} := by cases a; simp [BEq.beq]
|
||||
|
||||
instance [BEq α] [BEq β] [LawfulBEq α] [LawfulBEq β] : LawfulBEq (α × β) where
|
||||
eq_of_beq {a b} (h : a.1 == b.1 && a.2 == b.2) := by
|
||||
cases a; cases b
|
||||
refine congr (congrArg _ (eq_of_beq ?_)) (eq_of_beq ?_) <;> simp_all
|
||||
rfl {a} := by cases a; simp [BEq.beq, LawfulBEq.rfl]
|
||||
|
||||
@[simp]
|
||||
protected theorem «forall» {p : α × β → Prop} : (∀ x, p x) ↔ ∀ a b, p (a, b) :=
|
||||
|
||||
@@ -239,6 +239,17 @@ Examples:
|
||||
@[extern "lean_int8_div"]
|
||||
protected def Int8.div (a b : Int8) : Int8 := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
/--
|
||||
The power operation, raising an 8-bit signed integer to a natural number power,
|
||||
wrapping around on overflow. Usually accessed via the `^` operator.
|
||||
|
||||
This function is currently *not* overridden at runtime with an efficient implementation,
|
||||
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
|
||||
-/
|
||||
protected def Int8.pow (x : Int8) (n : Nat) : Int8 :=
|
||||
match n with
|
||||
| 0 => 1
|
||||
| n + 1 => Int8.mul (Int8.pow x n) x
|
||||
/--
|
||||
The modulo operator for 8-bit signed integers, which computes the remainder when dividing one
|
||||
integer by another with the T-rounding convention used by `Int8.div`. Usually accessed via the `%`
|
||||
operator.
|
||||
@@ -366,6 +377,7 @@ instance : Inhabited Int8 where
|
||||
instance : Add Int8 := ⟨Int8.add⟩
|
||||
instance : Sub Int8 := ⟨Int8.sub⟩
|
||||
instance : Mul Int8 := ⟨Int8.mul⟩
|
||||
instance : Pow Int8 Nat := ⟨Int8.pow⟩
|
||||
instance : Mod Int8 := ⟨Int8.mod⟩
|
||||
instance : Div Int8 := ⟨Int8.div⟩
|
||||
instance : LT Int8 := ⟨Int8.lt⟩
|
||||
@@ -598,6 +610,17 @@ Examples:
|
||||
@[extern "lean_int16_div"]
|
||||
protected def Int16.div (a b : Int16) : Int16 := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
/--
|
||||
The power operation, raising a 16-bit signed integer to a natural number power,
|
||||
wrapping around on overflow. Usually accessed via the `^` operator.
|
||||
|
||||
This function is currently *not* overridden at runtime with an efficient implementation,
|
||||
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
|
||||
-/
|
||||
protected def Int16.pow (x : Int16) (n : Nat) : Int16 :=
|
||||
match n with
|
||||
| 0 => 1
|
||||
| n + 1 => Int16.mul (Int16.pow x n) x
|
||||
/--
|
||||
The modulo operator for 16-bit signed integers, which computes the remainder when dividing one
|
||||
integer by another with the T-rounding convention used by `Int16.div`. Usually accessed via the `%`
|
||||
operator.
|
||||
@@ -725,6 +748,7 @@ instance : Inhabited Int16 where
|
||||
instance : Add Int16 := ⟨Int16.add⟩
|
||||
instance : Sub Int16 := ⟨Int16.sub⟩
|
||||
instance : Mul Int16 := ⟨Int16.mul⟩
|
||||
instance : Pow Int16 Nat := ⟨Int16.pow⟩
|
||||
instance : Mod Int16 := ⟨Int16.mod⟩
|
||||
instance : Div Int16 := ⟨Int16.div⟩
|
||||
instance : LT Int16 := ⟨Int16.lt⟩
|
||||
@@ -973,6 +997,17 @@ Examples:
|
||||
@[extern "lean_int32_div"]
|
||||
protected def Int32.div (a b : Int32) : Int32 := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
/--
|
||||
The power operation, raising a 32-bit signed integer to a natural number power,
|
||||
wrapping around on overflow. Usually accessed via the `^` operator.
|
||||
|
||||
This function is currently *not* overridden at runtime with an efficient implementation,
|
||||
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
|
||||
-/
|
||||
protected def Int32.pow (x : Int32) (n : Nat) : Int32 :=
|
||||
match n with
|
||||
| 0 => 1
|
||||
| n + 1 => Int32.mul (Int32.pow x n) x
|
||||
/--
|
||||
The modulo operator for 32-bit signed integers, which computes the remainder when dividing one
|
||||
integer by another with the T-rounding convention used by `Int32.div`. Usually accessed via the `%`
|
||||
operator.
|
||||
@@ -1100,6 +1135,7 @@ instance : Inhabited Int32 where
|
||||
instance : Add Int32 := ⟨Int32.add⟩
|
||||
instance : Sub Int32 := ⟨Int32.sub⟩
|
||||
instance : Mul Int32 := ⟨Int32.mul⟩
|
||||
instance : Pow Int32 Nat := ⟨Int32.pow⟩
|
||||
instance : Mod Int32 := ⟨Int32.mod⟩
|
||||
instance : Div Int32 := ⟨Int32.div⟩
|
||||
instance : LT Int32 := ⟨Int32.lt⟩
|
||||
@@ -1368,6 +1404,17 @@ Examples:
|
||||
@[extern "lean_int64_div"]
|
||||
protected def Int64.div (a b : Int64) : Int64 := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
/--
|
||||
The power operation, raising a 64-bit signed integer to a natural number power,
|
||||
wrapping around on overflow. Usually accessed via the `^` operator.
|
||||
|
||||
This function is currently *not* overridden at runtime with an efficient implementation,
|
||||
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
|
||||
-/
|
||||
protected def Int64.pow (x : Int64) (n : Nat) : Int64 :=
|
||||
match n with
|
||||
| 0 => 1
|
||||
| n + 1 => Int64.mul (Int64.pow x n) x
|
||||
/--
|
||||
The modulo operator for 64-bit signed integers, which computes the remainder when dividing one
|
||||
integer by another with the T-rounding convention used by `Int64.div`. Usually accessed via the `%`
|
||||
operator.
|
||||
@@ -1495,6 +1542,7 @@ instance : Inhabited Int64 where
|
||||
instance : Add Int64 := ⟨Int64.add⟩
|
||||
instance : Sub Int64 := ⟨Int64.sub⟩
|
||||
instance : Mul Int64 := ⟨Int64.mul⟩
|
||||
instance : Pow Int64 Nat := ⟨Int64.pow⟩
|
||||
instance : Mod Int64 := ⟨Int64.mod⟩
|
||||
instance : Div Int64 := ⟨Int64.div⟩
|
||||
instance : LT Int64 := ⟨Int64.lt⟩
|
||||
@@ -1746,6 +1794,17 @@ Examples:
|
||||
@[extern "lean_isize_div"]
|
||||
protected def ISize.div (a b : ISize) : ISize := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
/--
|
||||
The power operation, raising a word-sized signed integer to a natural number power,
|
||||
wrapping around on overflow. Usually accessed via the `^` operator.
|
||||
|
||||
This function is currently *not* overridden at runtime with an efficient implementation,
|
||||
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
|
||||
-/
|
||||
protected def ISize.pow (x : ISize) (n : Nat) : ISize :=
|
||||
match n with
|
||||
| 0 => 1
|
||||
| n + 1 => ISize.mul (ISize.pow x n) x
|
||||
/--
|
||||
The modulo operator for word-sized signed integers, which computes the remainder when dividing one
|
||||
integer by another with the T-rounding convention used by `ISize.div`. Usually accessed via the `%`
|
||||
operator.
|
||||
@@ -1875,6 +1934,7 @@ instance : Inhabited ISize where
|
||||
instance : Add ISize := ⟨ISize.add⟩
|
||||
instance : Sub ISize := ⟨ISize.sub⟩
|
||||
instance : Mul ISize := ⟨ISize.mul⟩
|
||||
instance : Pow ISize Nat := ⟨ISize.pow⟩
|
||||
instance : Mod ISize := ⟨ISize.mod⟩
|
||||
instance : Div ISize := ⟨ISize.div⟩
|
||||
instance : LT ISize := ⟨ISize.lt⟩
|
||||
|
||||
@@ -183,18 +183,18 @@ theorem ISize.neg_ofNat {n : Nat} : -ofNat n = ofInt (-n) := by
|
||||
rw [← neg_ofInt, ofInt_eq_ofNat]
|
||||
|
||||
theorem Int8.toNatClampNeg_ofNat_of_lt {n : Nat} (h : n < 2 ^ 7) : toNatClampNeg (ofNat n) = n := by
|
||||
rw [toNatClampNeg, ← ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_ofNat]
|
||||
rw [toNatClampNeg, ← ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_natCast]
|
||||
theorem Int16.toNatClampNeg_ofNat_of_lt {n : Nat} (h : n < 2 ^ 15) : toNatClampNeg (ofNat n) = n := by
|
||||
rw [toNatClampNeg, ← ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_ofNat]
|
||||
rw [toNatClampNeg, ← ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_natCast]
|
||||
theorem Int32.toNatClampNeg_ofNat_of_lt {n : Nat} (h : n < 2 ^ 31) : toNatClampNeg (ofNat n) = n := by
|
||||
rw [toNatClampNeg, ← ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_ofNat]
|
||||
rw [toNatClampNeg, ← ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_natCast]
|
||||
theorem Int64.toNatClampNeg_ofNat_of_lt {n : Nat} (h : n < 2 ^ 63) : toNatClampNeg (ofNat n) = n := by
|
||||
rw [toNatClampNeg, ← ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_ofNat]
|
||||
rw [toNatClampNeg, ← ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_natCast]
|
||||
theorem ISize.toNatClampNeg_ofNat_of_lt {n : Nat} (h : n < 2 ^ 31) : toNatClampNeg (ofNat n) = n := by
|
||||
rw [toNatClampNeg, ← ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_ofNat]
|
||||
rw [toNatClampNeg, ← ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_natCast]
|
||||
theorem ISize.toNatClampNeg_ofNat_of_lt_two_pow_numBits {n : Nat} (h : n < 2 ^ (System.Platform.numBits - 1)) :
|
||||
toNatClampNeg (ofNat n) = n := by
|
||||
rw [toNatClampNeg, ← ofInt_eq_ofNat, toInt_ofInt_of_two_pow_numBits_le, Int.toNat_ofNat]
|
||||
rw [toNatClampNeg, ← ofInt_eq_ofNat, toInt_ofInt_of_two_pow_numBits_le, Int.toNat_natCast]
|
||||
· cases System.Platform.numBits_eq <;> simp_all <;> omega
|
||||
· cases System.Platform.numBits_eq <;> simp_all <;> omega
|
||||
|
||||
@@ -537,41 +537,41 @@ theorem ISize.toFin_toBitVec (x : ISize) : x.toBitVec.toFin = x.toUSize.toFin :=
|
||||
@[simp] theorem Int64.toBitVec_ofIntLE (x : Int) (h₁ h₂) : (Int64.ofIntLE x h₁ h₂).toBitVec = BitVec.ofInt 64 x := rfl
|
||||
@[simp] theorem ISize.toBitVec_ofIntLE (x : Int) (h₁ h₂) : (ISize.ofIntLE x h₁ h₂).toBitVec = BitVec.ofInt System.Platform.numBits x := rfl
|
||||
|
||||
@[simp] theorem Int8.toInt_bmod (x : Int8) : x.toInt.bmod 256 = x.toInt := Int.bmod_eq_self_of_le x.le_toInt x.toInt_lt
|
||||
@[simp] theorem Int16.toInt_bmod (x : Int16) : x.toInt.bmod 65536 = x.toInt := Int.bmod_eq_self_of_le x.le_toInt x.toInt_lt
|
||||
@[simp] theorem Int32.toInt_bmod (x : Int32) : x.toInt.bmod 4294967296 = x.toInt := Int.bmod_eq_self_of_le x.le_toInt x.toInt_lt
|
||||
@[simp] theorem Int64.toInt_bmod (x : Int64) : x.toInt.bmod 18446744073709551616 = x.toInt := Int.bmod_eq_self_of_le x.le_toInt x.toInt_lt
|
||||
@[simp] theorem Int8.toInt_bmod (x : Int8) : x.toInt.bmod 256 = x.toInt := Int.bmod_eq_of_le x.le_toInt x.toInt_lt
|
||||
@[simp] theorem Int16.toInt_bmod (x : Int16) : x.toInt.bmod 65536 = x.toInt := Int.bmod_eq_of_le x.le_toInt x.toInt_lt
|
||||
@[simp] theorem Int32.toInt_bmod (x : Int32) : x.toInt.bmod 4294967296 = x.toInt := Int.bmod_eq_of_le x.le_toInt x.toInt_lt
|
||||
@[simp] theorem Int64.toInt_bmod (x : Int64) : x.toInt.bmod 18446744073709551616 = x.toInt := Int.bmod_eq_of_le x.le_toInt x.toInt_lt
|
||||
@[simp] theorem ISize.toInt_bmod_two_pow_numBits (x : ISize) : x.toInt.bmod (2 ^ System.Platform.numBits) = x.toInt := by
|
||||
refine Int.bmod_eq_self_of_le ?_ ?_
|
||||
refine Int.bmod_eq_of_le ?_ ?_
|
||||
· have := x.two_pow_numBits_le_toInt
|
||||
cases System.Platform.numBits_eq <;> simp_all
|
||||
· have := x.toInt_lt_two_pow_numBits
|
||||
cases System.Platform.numBits_eq <;> simp_all
|
||||
|
||||
@[simp] theorem Int8.toInt_bmod_65536 (x : Int8) : x.toInt.bmod 65536 = x.toInt :=
|
||||
Int.bmod_eq_self_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
|
||||
Int.bmod_eq_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
|
||||
@[simp] theorem Int8.toInt_bmod_4294967296 (x : Int8) : x.toInt.bmod 4294967296 = x.toInt :=
|
||||
Int.bmod_eq_self_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
|
||||
Int.bmod_eq_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
|
||||
@[simp] theorem Int16.toInt_bmod_4294967296 (x : Int16) : x.toInt.bmod 4294967296 = x.toInt :=
|
||||
Int.bmod_eq_self_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
|
||||
Int.bmod_eq_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
|
||||
@[simp] theorem Int8.toInt_bmod_18446744073709551616 (x : Int8) : x.toInt.bmod 18446744073709551616 = x.toInt :=
|
||||
Int.bmod_eq_self_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
|
||||
Int.bmod_eq_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
|
||||
@[simp] theorem Int16.toInt_bmod_18446744073709551616 (x : Int16) : x.toInt.bmod 18446744073709551616 = x.toInt :=
|
||||
Int.bmod_eq_self_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
|
||||
Int.bmod_eq_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
|
||||
@[simp] theorem Int32.toInt_bmod_18446744073709551616 (x : Int32) : x.toInt.bmod 18446744073709551616 = x.toInt :=
|
||||
Int.bmod_eq_self_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
|
||||
Int.bmod_eq_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
|
||||
@[simp] theorem ISize.toInt_bmod_18446744073709551616 (x : ISize) : x.toInt.bmod 18446744073709551616 = x.toInt :=
|
||||
Int.bmod_eq_self_of_le x.le_toInt x.toInt_lt
|
||||
Int.bmod_eq_of_le x.le_toInt x.toInt_lt
|
||||
@[simp] theorem Int8.toInt_bmod_two_pow_numBits (x : Int8) : x.toInt.bmod (2 ^ System.Platform.numBits) = x.toInt := by
|
||||
refine Int.bmod_eq_self_of_le (Int.le_trans ?_ x.iSizeMinValue_le_toInt)
|
||||
refine Int.bmod_eq_of_le (Int.le_trans ?_ x.iSizeMinValue_le_toInt)
|
||||
(Int.lt_of_le_sub_one (Int.le_trans x.toInt_le_iSizeMaxValue ?_))
|
||||
all_goals cases System.Platform.numBits_eq <;> simp_all [ISize.toInt_minValue, ISize.toInt_maxValue]
|
||||
@[simp] theorem Int16.toInt_bmod_two_pow_numBits (x : Int16) : x.toInt.bmod (2 ^ System.Platform.numBits) = x.toInt := by
|
||||
refine Int.bmod_eq_self_of_le (Int.le_trans ?_ x.iSizeMinValue_le_toInt)
|
||||
refine Int.bmod_eq_of_le (Int.le_trans ?_ x.iSizeMinValue_le_toInt)
|
||||
(Int.lt_of_le_sub_one (Int.le_trans x.toInt_le_iSizeMaxValue ?_))
|
||||
all_goals cases System.Platform.numBits_eq <;> simp_all [ISize.toInt_minValue, ISize.toInt_maxValue]
|
||||
@[simp] theorem Int32.toInt_bmod_two_pow_numBits (x : Int32) : x.toInt.bmod (2 ^ System.Platform.numBits) = x.toInt := by
|
||||
refine Int.bmod_eq_self_of_le (Int.le_trans ?_ x.iSizeMinValue_le_toInt)
|
||||
refine Int.bmod_eq_of_le (Int.le_trans ?_ x.iSizeMinValue_le_toInt)
|
||||
(Int.lt_of_le_sub_one (Int.le_trans x.toInt_le_iSizeMaxValue ?_))
|
||||
all_goals cases System.Platform.numBits_eq <;> simp_all [ISize.toInt_minValue, ISize.toInt_maxValue]
|
||||
|
||||
@@ -2066,7 +2066,7 @@ theorem ISize.toInt_maxValue_add_one : maxValue.toInt + 1 = 2 ^ (System.Platform
|
||||
theorem Int8.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a ≤ maxValue.toInt)
|
||||
(hb₁ : minValue.toInt ≤ b) (hb₂ : b ≤ maxValue.toInt) : Int8.ofInt (a.tdiv b) = Int8.ofInt a / Int8.ofInt b := by
|
||||
rw [Int8.ofInt_eq_iff_bmod_eq_toInt, toInt_div, toInt_ofInt, toInt_ofInt,
|
||||
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
|
||||
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
|
||||
· exact hb₁
|
||||
· exact Int.lt_of_le_sub_one hb₂
|
||||
· exact ha₁
|
||||
@@ -2074,7 +2074,7 @@ theorem Int8.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
|
||||
theorem Int16.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a ≤ maxValue.toInt)
|
||||
(hb₁ : minValue.toInt ≤ b) (hb₂ : b ≤ maxValue.toInt) : Int16.ofInt (a.tdiv b) = Int16.ofInt a / Int16.ofInt b := by
|
||||
rw [Int16.ofInt_eq_iff_bmod_eq_toInt, toInt_div, toInt_ofInt, toInt_ofInt,
|
||||
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
|
||||
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
|
||||
· exact hb₁
|
||||
· exact Int.lt_of_le_sub_one hb₂
|
||||
· exact ha₁
|
||||
@@ -2082,7 +2082,7 @@ theorem Int16.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
|
||||
theorem Int32.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a ≤ maxValue.toInt)
|
||||
(hb₁ : minValue.toInt ≤ b) (hb₂ : b ≤ maxValue.toInt) : Int32.ofInt (a.tdiv b) = Int32.ofInt a / Int32.ofInt b := by
|
||||
rw [Int32.ofInt_eq_iff_bmod_eq_toInt, toInt_div, toInt_ofInt, toInt_ofInt,
|
||||
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
|
||||
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
|
||||
· exact hb₁
|
||||
· exact Int.lt_of_le_sub_one hb₂
|
||||
· exact ha₁
|
||||
@@ -2090,7 +2090,7 @@ theorem Int32.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
|
||||
theorem Int64.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a ≤ maxValue.toInt)
|
||||
(hb₁ : minValue.toInt ≤ b) (hb₂ : b ≤ maxValue.toInt) : Int64.ofInt (a.tdiv b) = Int64.ofInt a / Int64.ofInt b := by
|
||||
rw [Int64.ofInt_eq_iff_bmod_eq_toInt, toInt_div, toInt_ofInt, toInt_ofInt,
|
||||
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
|
||||
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
|
||||
· exact hb₁
|
||||
· exact Int.lt_of_le_sub_one hb₂
|
||||
· exact ha₁
|
||||
@@ -2098,7 +2098,7 @@ theorem Int64.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
|
||||
theorem ISize.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a ≤ maxValue.toInt)
|
||||
(hb₁ : minValue.toInt ≤ b) (hb₂ : b ≤ maxValue.toInt) : ISize.ofInt (a.tdiv b) = ISize.ofInt a / ISize.ofInt b := by
|
||||
rw [ISize.ofInt_eq_iff_bmod_eq_toInt, toInt_div, toInt_ofInt, toInt_ofInt,
|
||||
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
|
||||
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
|
||||
· exact le_of_eq_of_le (by cases System.Platform.numBits_eq <;> simp_all [size, toInt_ofInt, toInt_neg]) hb₁
|
||||
· refine Int.lt_of_le_sub_one (le_of_le_of_eq hb₂ ?_)
|
||||
cases System.Platform.numBits_eq <;> simp_all [size, toInt_ofInt]
|
||||
@@ -2625,6 +2625,17 @@ instance : Std.LawfulCommIdentity (α := ISize) (· * ·) 1 where
|
||||
@[simp] theorem Int64.zero_mul {a : Int64} : 0 * a = 0 := Int64.toBitVec_inj.1 BitVec.zero_mul
|
||||
@[simp] theorem ISize.zero_mul {a : ISize} : 0 * a = 0 := ISize.toBitVec_inj.1 BitVec.zero_mul
|
||||
|
||||
@[simp] protected theorem Int8.pow_zero (x : Int8) : x ^ 0 = 1 := rfl
|
||||
protected theorem Int8.pow_succ (x : Int8) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
|
||||
@[simp] protected theorem Int16.pow_zero (x : Int16) : x ^ 0 = 1 := rfl
|
||||
protected theorem Int16.pow_succ (x : Int16) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
|
||||
@[simp] protected theorem Int32.pow_zero (x : Int32) : x ^ 0 = 1 := rfl
|
||||
protected theorem Int32.pow_succ (x : Int32) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
|
||||
@[simp] protected theorem Int64.pow_zero (x : Int64) : x ^ 0 = 1 := rfl
|
||||
protected theorem Int64.pow_succ (x : Int64) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
|
||||
@[simp] protected theorem ISize.pow_zero (x : ISize) : x ^ 0 = 1 := rfl
|
||||
protected theorem ISize.pow_succ (x : ISize) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
|
||||
|
||||
protected theorem Int8.mul_add {a b c : Int8} : a * (b + c) = a * b + a * c :=
|
||||
Int8.toBitVec_inj.1 BitVec.mul_add
|
||||
protected theorem Int16.mul_add {a b c : Int16} : a * (b + c) = a * b + a * c :=
|
||||
@@ -2910,7 +2921,7 @@ protected theorem ISize.div_self {a : ISize} : a / a = if a = 0 then 0 else 1 :=
|
||||
simp [← ISize.toInt_inj]
|
||||
split
|
||||
· simp_all
|
||||
· rw [Int.tdiv_self, Int.bmod_eq_self_of_le]
|
||||
· rw [Int.tdiv_self, Int.bmod_eq_of_le]
|
||||
· simp
|
||||
· cases System.Platform.numBits_eq <;> simp_all
|
||||
· cases System.Platform.numBits_eq <;> simp_all
|
||||
@@ -3065,15 +3076,15 @@ protected theorem Int64.lt_or_eq_of_le {a b : Int64} : a ≤ b → a < b ∨ a =
|
||||
protected theorem ISize.lt_or_eq_of_le {a b : ISize} : a ≤ b → a < b ∨ a = b := ISize.le_iff_lt_or_eq.mp
|
||||
|
||||
theorem Int8.toInt_eq_toNatClampNeg {a : Int8} (ha : 0 ≤ a) : a.toInt = a.toNatClampNeg := by
|
||||
simpa only [← toNat_toInt, Int.eq_ofNat_toNat, le_iff_toInt_le] using ha
|
||||
simpa only [← toNat_toInt, Int.eq_natCast_toNat, le_iff_toInt_le] using ha
|
||||
theorem Int16.toInt_eq_toNatClampNeg {a : Int16} (ha : 0 ≤ a) : a.toInt = a.toNatClampNeg := by
|
||||
simpa only [← toNat_toInt, Int.eq_ofNat_toNat, le_iff_toInt_le] using ha
|
||||
simpa only [← toNat_toInt, Int.eq_natCast_toNat, le_iff_toInt_le] using ha
|
||||
theorem Int32.toInt_eq_toNatClampNeg {a : Int32} (ha : 0 ≤ a) : a.toInt = a.toNatClampNeg := by
|
||||
simpa only [← toNat_toInt, Int.eq_ofNat_toNat, le_iff_toInt_le] using ha
|
||||
simpa only [← toNat_toInt, Int.eq_natCast_toNat, le_iff_toInt_le] using ha
|
||||
theorem Int64.toInt_eq_toNatClampNeg {a : Int64} (ha : 0 ≤ a) : a.toInt = a.toNatClampNeg := by
|
||||
simpa only [← toNat_toInt, Int.eq_ofNat_toNat, le_iff_toInt_le] using ha
|
||||
simpa only [← toNat_toInt, Int.eq_natCast_toNat, le_iff_toInt_le] using ha
|
||||
theorem ISize.toInt_eq_toNatClampNeg {a : ISize} (ha : 0 ≤ a) : a.toInt = a.toNatClampNeg := by
|
||||
simpa only [← toNat_toInt, Int.eq_ofNat_toNat, le_iff_toInt_le, toInt_zero] using ha
|
||||
simpa only [← toNat_toInt, Int.eq_natCast_toNat, le_iff_toInt_le, toInt_zero] using ha
|
||||
|
||||
@[simp] theorem UInt8.toInt8_add (a b : UInt8) : (a + b).toInt8 = a.toInt8 + b.toInt8 := rfl
|
||||
@[simp] theorem UInt16.toInt16_add (a b : UInt16) : (a + b).toInt16 = a.toInt16 + b.toInt16 := rfl
|
||||
@@ -3311,7 +3322,7 @@ protected theorem ISize.ne_of_lt {a b : ISize} : a < b → a ≠ b := by
|
||||
theorem Int8.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a ≤ maxValue.toInt)
|
||||
(hb₁ : minValue.toInt ≤ b) (hb₂ : b ≤ maxValue.toInt) : Int8.ofInt (a.tmod b) = Int8.ofInt a % Int8.ofInt b := by
|
||||
rw [Int8.ofInt_eq_iff_bmod_eq_toInt, ← toInt_bmod_size, toInt_mod, toInt_ofInt, toInt_ofInt,
|
||||
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
|
||||
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
|
||||
· exact hb₁
|
||||
· exact Int.lt_of_le_sub_one hb₂
|
||||
· exact ha₁
|
||||
@@ -3319,7 +3330,7 @@ theorem Int8.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
|
||||
theorem Int16.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a ≤ maxValue.toInt)
|
||||
(hb₁ : minValue.toInt ≤ b) (hb₂ : b ≤ maxValue.toInt) : Int16.ofInt (a.tmod b) = Int16.ofInt a % Int16.ofInt b := by
|
||||
rw [Int16.ofInt_eq_iff_bmod_eq_toInt, ← toInt_bmod_size, toInt_mod, toInt_ofInt, toInt_ofInt,
|
||||
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
|
||||
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
|
||||
· exact hb₁
|
||||
· exact Int.lt_of_le_sub_one hb₂
|
||||
· exact ha₁
|
||||
@@ -3327,7 +3338,7 @@ theorem Int16.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
|
||||
theorem Int32.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a ≤ maxValue.toInt)
|
||||
(hb₁ : minValue.toInt ≤ b) (hb₂ : b ≤ maxValue.toInt) : Int32.ofInt (a.tmod b) = Int32.ofInt a % Int32.ofInt b := by
|
||||
rw [Int32.ofInt_eq_iff_bmod_eq_toInt, ← toInt_bmod_size, toInt_mod, toInt_ofInt, toInt_ofInt,
|
||||
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
|
||||
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
|
||||
· exact hb₁
|
||||
· exact Int.lt_of_le_sub_one hb₂
|
||||
· exact ha₁
|
||||
@@ -3335,7 +3346,7 @@ theorem Int32.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
|
||||
theorem Int64.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a ≤ maxValue.toInt)
|
||||
(hb₁ : minValue.toInt ≤ b) (hb₂ : b ≤ maxValue.toInt) : Int64.ofInt (a.tmod b) = Int64.ofInt a % Int64.ofInt b := by
|
||||
rw [Int64.ofInt_eq_iff_bmod_eq_toInt, ← toInt_bmod_size, toInt_mod, toInt_ofInt, toInt_ofInt,
|
||||
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
|
||||
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
|
||||
· exact hb₁
|
||||
· exact Int.lt_of_le_sub_one hb₂
|
||||
· exact ha₁
|
||||
@@ -3343,7 +3354,7 @@ theorem Int64.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
|
||||
theorem ISize.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a ≤ maxValue.toInt)
|
||||
(hb₁ : minValue.toInt ≤ b) (hb₂ : b ≤ maxValue.toInt) : ISize.ofInt (a.tmod b) = ISize.ofInt a % ISize.ofInt b := by
|
||||
rw [ISize.ofInt_eq_iff_bmod_eq_toInt, ← toInt_bmod_size, toInt_mod, toInt_ofInt, toInt_ofInt,
|
||||
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
|
||||
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
|
||||
· exact le_of_eq_of_le (by cases System.Platform.numBits_eq <;> simp_all [size, toInt_ofInt, toInt_neg]) hb₁
|
||||
· refine Int.lt_of_le_sub_one (le_of_le_of_eq hb₂ ?_)
|
||||
cases System.Platform.numBits_eq <;> simp_all [size, toInt_ofInt]
|
||||
|
||||
@@ -20,6 +20,9 @@ def UInt8.mk (bitVec : BitVec 8) : UInt8 :=
|
||||
def UInt8.ofNatCore (n : Nat) (h : n < UInt8.size) : UInt8 :=
|
||||
UInt8.ofNatLT n h
|
||||
|
||||
/-- Converts an `Int` to a `UInt8` by taking the (non-negative remainder of the division by `2 ^ 8`. -/
|
||||
def UInt8.ofInt (x : Int) : UInt8 := ofNat (x % 2 ^ 8).toNat
|
||||
|
||||
/--
|
||||
Adds two 8-bit unsigned integers, wrapping around on overflow. Usually accessed via the `+`
|
||||
operator.
|
||||
@@ -55,6 +58,17 @@ This function is overridden at runtime with an efficient implementation.
|
||||
@[extern "lean_uint8_div"]
|
||||
protected def UInt8.div (a b : UInt8) : UInt8 := ⟨BitVec.udiv a.toBitVec b.toBitVec⟩
|
||||
/--
|
||||
The power operation, raising an 8-bit unsigned integer to a natural number power,
|
||||
wrapping around on overflow. Usually accessed via the `^` operator.
|
||||
|
||||
This function is currently *not* overridden at runtime with an efficient implementation,
|
||||
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
|
||||
-/
|
||||
protected def UInt8.pow (x : UInt8) (n : Nat) : UInt8 :=
|
||||
match n with
|
||||
| 0 => 1
|
||||
| n + 1 => UInt8.mul (UInt8.pow x n) x
|
||||
/--
|
||||
The modulo operator for 8-bit unsigned integers, which computes the remainder when dividing one
|
||||
integer by another. Usually accessed via the `%` operator.
|
||||
|
||||
@@ -129,6 +143,7 @@ protected def UInt8.le (a b : UInt8) : Prop := a.toBitVec ≤ b.toBitVec
|
||||
instance : Add UInt8 := ⟨UInt8.add⟩
|
||||
instance : Sub UInt8 := ⟨UInt8.sub⟩
|
||||
instance : Mul UInt8 := ⟨UInt8.mul⟩
|
||||
instance : Pow UInt8 Nat := ⟨UInt8.pow⟩
|
||||
instance : Mod UInt8 := ⟨UInt8.mod⟩
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@@ -217,6 +232,9 @@ def UInt16.mk (bitVec : BitVec 16) : UInt16 :=
|
||||
def UInt16.ofNatCore (n : Nat) (h : n < UInt16.size) : UInt16 :=
|
||||
UInt16.ofNatLT n h
|
||||
|
||||
/-- Converts an `Int` to a `UInt16` by taking the (non-negative remainder of the division by `2 ^ 16`. -/
|
||||
def UInt16.ofInt (x : Int) : UInt16 := ofNat (x % 2 ^ 16).toNat
|
||||
|
||||
/--
|
||||
Adds two 16-bit unsigned integers, wrapping around on overflow. Usually accessed via the `+`
|
||||
operator.
|
||||
@@ -252,6 +270,17 @@ This function is overridden at runtime with an efficient implementation.
|
||||
@[extern "lean_uint16_div"]
|
||||
protected def UInt16.div (a b : UInt16) : UInt16 := ⟨BitVec.udiv a.toBitVec b.toBitVec⟩
|
||||
/--
|
||||
The power operation, raising a 16-bit unsigned integer to a natural number power,
|
||||
wrapping around on overflow. Usually accessed via the `^` operator.
|
||||
|
||||
This function is currently *not* overridden at runtime with an efficient implementation,
|
||||
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
|
||||
-/
|
||||
protected def UInt16.pow (x : UInt16) (n : Nat) : UInt16 :=
|
||||
match n with
|
||||
| 0 => 1
|
||||
| n + 1 => UInt16.mul (UInt16.pow x n) x
|
||||
/--
|
||||
The modulo operator for 16-bit unsigned integers, which computes the remainder when dividing one
|
||||
integer by another. Usually accessed via the `%` operator.
|
||||
|
||||
@@ -289,7 +318,7 @@ This function is overridden at runtime with an efficient implementation.
|
||||
@[extern "lean_uint16_lor"]
|
||||
protected def UInt16.lor (a b : UInt16) : UInt16 := ⟨a.toBitVec ||| b.toBitVec⟩
|
||||
/--
|
||||
Bitwise exclusive or for 8-bit unsigned integers. Usually accessed via the `^^^` operator.
|
||||
Bitwise exclusive or for 16-bit unsigned integers. Usually accessed via the `^^^` operator.
|
||||
|
||||
Each bit of the resulting integer is set if exactly one of the corresponding bits of both input
|
||||
integers are set.
|
||||
@@ -326,6 +355,7 @@ protected def UInt16.le (a b : UInt16) : Prop := a.toBitVec ≤ b.toBitVec
|
||||
instance : Add UInt16 := ⟨UInt16.add⟩
|
||||
instance : Sub UInt16 := ⟨UInt16.sub⟩
|
||||
instance : Mul UInt16 := ⟨UInt16.mul⟩
|
||||
instance : Pow UInt16 Nat := ⟨UInt16.pow⟩
|
||||
instance : Mod UInt16 := ⟨UInt16.mod⟩
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@@ -416,6 +446,9 @@ def UInt32.mk (bitVec : BitVec 32) : UInt32 :=
|
||||
def UInt32.ofNatCore (n : Nat) (h : n < UInt32.size) : UInt32 :=
|
||||
UInt32.ofNatLT n h
|
||||
|
||||
/-- Converts an `Int` to a `UInt32` by taking the (non-negative remainder of the division by `2 ^ 32`. -/
|
||||
def UInt32.ofInt (x : Int) : UInt32 := ofNat (x % 2 ^ 32).toNat
|
||||
|
||||
/--
|
||||
Adds two 32-bit unsigned integers, wrapping around on overflow. Usually accessed via the `+`
|
||||
operator.
|
||||
@@ -451,6 +484,17 @@ This function is overridden at runtime with an efficient implementation.
|
||||
@[extern "lean_uint32_div"]
|
||||
protected def UInt32.div (a b : UInt32) : UInt32 := ⟨BitVec.udiv a.toBitVec b.toBitVec⟩
|
||||
/--
|
||||
The power operation, raising a 32-bit unsigned integer to a natural number power,
|
||||
wrapping around on overflow. Usually accessed via the `^` operator.
|
||||
|
||||
This function is currently *not* overridden at runtime with an efficient implementation,
|
||||
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
|
||||
-/
|
||||
protected def UInt32.pow (x : UInt32) (n : Nat) : UInt32 :=
|
||||
match n with
|
||||
| 0 => 1
|
||||
| n + 1 => UInt32.mul (UInt32.pow x n) x
|
||||
/--
|
||||
The modulo operator for 32-bit unsigned integers, which computes the remainder when dividing one
|
||||
integer by another. Usually accessed via the `%` operator.
|
||||
|
||||
@@ -525,6 +569,7 @@ protected def UInt32.le (a b : UInt32) : Prop := a.toBitVec ≤ b.toBitVec
|
||||
instance : Add UInt32 := ⟨UInt32.add⟩
|
||||
instance : Sub UInt32 := ⟨UInt32.sub⟩
|
||||
instance : Mul UInt32 := ⟨UInt32.mul⟩
|
||||
instance : Pow UInt32 Nat := ⟨UInt32.pow⟩
|
||||
instance : Mod UInt32 := ⟨UInt32.mod⟩
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@@ -577,6 +622,9 @@ def UInt64.mk (bitVec : BitVec 64) : UInt64 :=
|
||||
def UInt64.ofNatCore (n : Nat) (h : n < UInt64.size) : UInt64 :=
|
||||
UInt64.ofNatLT n h
|
||||
|
||||
/-- Converts an `Int` to a `UInt64` by taking the (non-negative remainder of the division by `2 ^ 64`. -/
|
||||
def UInt64.ofInt (x : Int) : UInt64 := ofNat (x % 2 ^ 64).toNat
|
||||
|
||||
/--
|
||||
Adds two 64-bit unsigned integers, wrapping around on overflow. Usually accessed via the `+`
|
||||
operator.
|
||||
@@ -612,6 +660,17 @@ This function is overridden at runtime with an efficient implementation.
|
||||
@[extern "lean_uint64_div"]
|
||||
protected def UInt64.div (a b : UInt64) : UInt64 := ⟨BitVec.udiv a.toBitVec b.toBitVec⟩
|
||||
/--
|
||||
The power operation, raising a 64-bit unsigned integer to a natural number power,
|
||||
wrapping around on overflow. Usually accessed via the `^` operator.
|
||||
|
||||
This function is currently *not* overridden at runtime with an efficient implementation,
|
||||
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
|
||||
-/
|
||||
protected def UInt64.pow (x : UInt64) (n : Nat) : UInt64 :=
|
||||
match n with
|
||||
| 0 => 1
|
||||
| n + 1 => UInt64.mul (UInt64.pow x n) x
|
||||
/--
|
||||
The modulo operator for 64-bit unsigned integers, which computes the remainder when dividing one
|
||||
integer by another. Usually accessed via the `%` operator.
|
||||
|
||||
@@ -686,6 +745,7 @@ protected def UInt64.le (a b : UInt64) : Prop := a.toBitVec ≤ b.toBitVec
|
||||
instance : Add UInt64 := ⟨UInt64.add⟩
|
||||
instance : Sub UInt64 := ⟨UInt64.sub⟩
|
||||
instance : Mul UInt64 := ⟨UInt64.mul⟩
|
||||
instance : Pow UInt64 Nat := ⟨UInt64.pow⟩
|
||||
instance : Mod UInt64 := ⟨UInt64.mod⟩
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@@ -706,7 +766,7 @@ This function is overridden at runtime with an efficient implementation.
|
||||
@[extern "lean_uint64_complement"]
|
||||
protected def UInt64.complement (a : UInt64) : UInt64 := ⟨~~~a.toBitVec⟩
|
||||
/--
|
||||
Negation of 32-bit unsigned integers, computed modulo `UInt64.size`.
|
||||
Negation of 64-bit unsigned integers, computed modulo `UInt64.size`.
|
||||
|
||||
`UInt64.neg a` is equivalent to `18_446_744_073_709_551_615 - a + 1`.
|
||||
|
||||
@@ -774,6 +834,9 @@ def USize.mk (bitVec : BitVec System.Platform.numBits) : USize :=
|
||||
def USize.ofNatCore (n : Nat) (h : n < USize.size) : USize :=
|
||||
USize.ofNatLT n h
|
||||
|
||||
/-- Converts an `Int` to a `USize` by taking the (non-negative remainder of the division by `2 ^ numBits`. -/
|
||||
def USize.ofInt (x : Int) : USize := ofNat (x % 2 ^ System.Platform.numBits).toNat
|
||||
|
||||
@[simp] theorem USize.le_size : 2 ^ 32 ≤ USize.size := by cases USize.size_eq <;> simp_all
|
||||
@[simp] theorem USize.size_le : USize.size ≤ 2 ^ 64 := by cases USize.size_eq <;> simp_all
|
||||
|
||||
@@ -804,6 +867,17 @@ This function is overridden at runtime with an efficient implementation.
|
||||
@[extern "lean_usize_div"]
|
||||
protected def USize.div (a b : USize) : USize := ⟨a.toBitVec / b.toBitVec⟩
|
||||
/--
|
||||
The power operation, raising a word-sized unsigned integer to a natural number power,
|
||||
wrapping around on overflow. Usually accessed via the `^` operator.
|
||||
|
||||
This function is currently *not* overridden at runtime with an efficient implementation,
|
||||
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
|
||||
-/
|
||||
protected def USize.pow (x : USize) (n : Nat) : USize :=
|
||||
match n with
|
||||
| 0 => 1
|
||||
| n + 1 => USize.mul (USize.pow x n) x
|
||||
/--
|
||||
The modulo operator for word-sized unsigned integers, which computes the remainder when dividing one
|
||||
integer by another. Usually accessed via the `%` operator.
|
||||
|
||||
@@ -937,6 +1011,7 @@ def USize.toUInt64 (a : USize) : UInt64 :=
|
||||
UInt64.ofNatLT a.toBitVec.toNat (Nat.lt_of_lt_of_le a.toBitVec.isLt USize.size_le)
|
||||
|
||||
instance : Mul USize := ⟨USize.mul⟩
|
||||
instance : Pow USize Nat := ⟨USize.pow⟩
|
||||
instance : Mod USize := ⟨USize.mod⟩
|
||||
|
||||
set_option linter.deprecated false in
|
||||
|
||||
@@ -286,6 +286,17 @@ declare_uint_theorems USize System.Platform.numBits
|
||||
theorem USize.toNat_ofNat_of_lt_32 {n : Nat} (h : n < 4294967296) : toNat (ofNat n) = n :=
|
||||
toNat_ofNat_of_lt (Nat.lt_of_lt_of_le h USize.le_size)
|
||||
|
||||
theorem UInt8.ofNat_mod_size : ofNat (x % 2 ^ 8) = ofNat x := by
|
||||
simp [ofNat, BitVec.ofNat, Fin.ofNat']
|
||||
theorem UInt16.ofNat_mod_size : ofNat (x % 2 ^ 16) = ofNat x := by
|
||||
simp [ofNat, BitVec.ofNat, Fin.ofNat']
|
||||
theorem UInt32.ofNat_mod_size : ofNat (x % 2 ^ 32) = ofNat x := by
|
||||
simp [ofNat, BitVec.ofNat, Fin.ofNat']
|
||||
theorem UInt64.ofNat_mod_size : ofNat (x % 2 ^ 64) = ofNat x := by
|
||||
simp [ofNat, BitVec.ofNat, Fin.ofNat']
|
||||
theorem USize.ofNat_mod_size : ofNat (x % 2 ^ System.Platform.numBits) = ofNat x := by
|
||||
simp [ofNat, BitVec.ofNat, Fin.ofNat']
|
||||
|
||||
theorem UInt8.lt_ofNat_iff {n : UInt8} {m : Nat} (h : m < size) : n < ofNat m ↔ n.toNat < m := by
|
||||
rw [lt_iff_toNat_lt, toNat_ofNat_of_lt' h]
|
||||
theorem UInt8.ofNat_lt_iff {n : UInt8} {m : Nat} (h : m < size) : ofNat m < n ↔ m < n.toNat := by
|
||||
@@ -1655,7 +1666,7 @@ theorem USize.toUInt32_eq (a b : USize) : a.toUInt32 = b.toUInt32 ↔ a % 429496
|
||||
simp [← UInt32.toNat_inj, ← USize.toNat_inj, USize.toNat_ofNat]
|
||||
have := Nat.mod_eq_of_lt a.toNat_lt_two_pow_numBits
|
||||
have := Nat.mod_eq_of_lt b.toNat_lt_two_pow_numBits
|
||||
cases System.Platform.numBits_eq <;> simp_all
|
||||
cases System.Platform.numBits_eq <;> simp_all [Nat.mod_eq_of_lt]
|
||||
|
||||
theorem UInt8.toUInt16_eq_mod_256_iff (a : UInt8) (b : UInt16) : a.toUInt16 = b % 256 ↔ a = b.toUInt8 := by
|
||||
simp [← UInt8.toNat_inj, ← UInt16.toNat_inj]
|
||||
@@ -1678,7 +1689,7 @@ theorem UInt32.toUInt64_eq_mod_4294967296_iff (a : UInt32) (b : UInt64) : a.toUI
|
||||
theorem UInt32.toUSize_eq_mod_4294967296_iff (a : UInt32) (b : USize) : a.toUSize = b % 4294967296 ↔ a = b.toUInt32 := by
|
||||
simp [← UInt32.toNat_inj, ← USize.toNat_inj, USize.toNat_ofNat]
|
||||
have := Nat.mod_eq_of_lt b.toNat_lt_two_pow_numBits
|
||||
cases System.Platform.numBits_eq <;> simp_all
|
||||
cases System.Platform.numBits_eq <;> simp_all [Nat.mod_eq_of_lt]
|
||||
|
||||
theorem USize.toUInt64_eq_mod_usizeSize_iff (a : USize) (b : UInt64) : a.toUInt64 = b % UInt64.ofNat USize.size ↔ a = b.toUSize := by
|
||||
simp [← USize.toNat_inj, ← UInt64.toNat_inj, USize.size_eq_two_pow]
|
||||
@@ -2081,6 +2092,23 @@ theorem USize.ofNat_eq_iff_mod_eq_toNat (a : Nat) (b : USize) : USize.ofNat a =
|
||||
USize.ofNatLT (a % b) (Nat.mod_lt_of_lt ha) = USize.ofNatLT a ha % USize.ofNatLT b hb := by
|
||||
simp [USize.ofNatLT_eq_ofNat, USize.ofNat_mod ha hb]
|
||||
|
||||
@[simp] theorem UInt8.ofInt_one : ofInt 1 = 1 := rfl
|
||||
@[simp] theorem UInt8.ofInt_neg_one : ofInt (-1) = -1 := rfl
|
||||
@[simp] theorem UInt16.ofInt_one : ofInt 1 = 1 := rfl
|
||||
@[simp] theorem UInt16.ofInt_neg_one : ofInt (-1) = -1 := rfl
|
||||
@[simp] theorem UInt32.ofInt_one : ofInt 1 = 1 := rfl
|
||||
@[simp] theorem UInt32.ofInt_neg_one : ofInt (-1) = -1 := rfl
|
||||
@[simp] theorem UInt64.ofInt_one : ofInt 1 = 1 := rfl
|
||||
@[simp] theorem UInt64.ofInt_neg_one : ofInt (-1) = -1 := rfl
|
||||
@[simp] theorem USize.ofInt_one : ofInt 1 = 1 := by
|
||||
rcases System.Platform.numBits_eq with h | h <;>
|
||||
· apply USize.toNat_inj.mp
|
||||
simp_all [USize.ofInt, USize.ofNat, size, toNat]
|
||||
@[simp] theorem USize.ofInt_neg_one : ofInt (-1) = -1 := by
|
||||
rcases System.Platform.numBits_eq with h | h <;>
|
||||
· apply USize.toNat_inj.mp
|
||||
simp_all [USize.ofInt, USize.ofNat, size, toNat]
|
||||
|
||||
@[simp] theorem UInt8.ofNat_add (a b : Nat) : UInt8.ofNat (a + b) = UInt8.ofNat a + UInt8.ofNat b := by
|
||||
simp [UInt8.ofNat_eq_iff_mod_eq_toNat]
|
||||
@[simp] theorem UInt16.ofNat_add (a b : Nat) : UInt16.ofNat (a + b) = UInt16.ofNat a + UInt16.ofNat b := by
|
||||
@@ -2092,6 +2120,70 @@ theorem USize.ofNat_eq_iff_mod_eq_toNat (a : Nat) (b : USize) : USize.ofNat a =
|
||||
@[simp] theorem USize.ofNat_add (a b : Nat) : USize.ofNat (a + b) = USize.ofNat a + USize.ofNat b := by
|
||||
simp [USize.ofNat_eq_iff_mod_eq_toNat]
|
||||
|
||||
@[simp] theorem UInt8.ofInt_add (x y : Int) : ofInt (x + y) = ofInt x + ofInt y := by
|
||||
dsimp only [UInt8.ofInt]
|
||||
rw [Int.add_emod]
|
||||
have h₁ : 0 ≤ x % 2 ^ 8 := Int.emod_nonneg _ (by decide)
|
||||
have h₂ : 0 ≤ y % 2 ^ 8 := Int.emod_nonneg _ (by decide)
|
||||
have h₃ : 0 ≤ x % 2 ^ 8 + y % 2 ^ 8 := Int.add_nonneg h₁ h₂
|
||||
rw [Int.toNat_emod h₃ (by decide), Int.toNat_add h₁ h₂]
|
||||
have : (2 ^ 8 : Int).toNat = 2 ^ 8 := rfl
|
||||
rw [this, UInt8.ofNat_mod_size, UInt8.ofNat_add]
|
||||
@[simp] theorem UInt16.ofInt_add (x y : Int) : UInt16.ofInt (x + y) = UInt16.ofInt x + UInt16.ofInt y := by
|
||||
dsimp only [UInt16.ofInt]
|
||||
rw [Int.add_emod]
|
||||
have h₁ : 0 ≤ x % 2 ^ 16 := Int.emod_nonneg _ (by decide)
|
||||
have h₂ : 0 ≤ y % 2 ^ 16 := Int.emod_nonneg _ (by decide)
|
||||
have h₃ : 0 ≤ x % 2 ^ 16 + y % 2 ^ 16 := Int.add_nonneg h₁ h₂
|
||||
rw [Int.toNat_emod h₃ (by decide), Int.toNat_add h₁ h₂]
|
||||
have : (2 ^ 16 : Int).toNat = 2 ^ 16 := rfl
|
||||
rw [this, UInt16.ofNat_mod_size, UInt16.ofNat_add]
|
||||
@[simp] theorem UInt32.ofInt_add (x y : Int) : UInt32.ofInt (x + y) = UInt32.ofInt x + UInt32.ofInt y := by
|
||||
dsimp only [UInt32.ofInt]
|
||||
rw [Int.add_emod]
|
||||
have h₁ : 0 ≤ x % 2 ^ 32 := Int.emod_nonneg _ (by decide)
|
||||
have h₂ : 0 ≤ y % 2 ^ 32 := Int.emod_nonneg _ (by decide)
|
||||
have h₃ : 0 ≤ x % 2 ^ 32 + y % 2 ^ 32 := Int.add_nonneg h₁ h₂
|
||||
rw [Int.toNat_emod h₃ (by decide), Int.toNat_add h₁ h₂]
|
||||
have : (2 ^ 32 : Int).toNat = 2 ^ 32 := rfl
|
||||
rw [this, UInt32.ofNat_mod_size, UInt32.ofNat_add]
|
||||
@[simp] theorem UInt64.ofInt_add (x y : Int) : UInt64.ofInt (x + y) = UInt64.ofInt x + UInt64.ofInt y := by
|
||||
dsimp only [UInt64.ofInt]
|
||||
rw [Int.add_emod]
|
||||
have h₁ : 0 ≤ x % 2 ^ 64 := Int.emod_nonneg _ (by decide)
|
||||
have h₂ : 0 ≤ y % 2 ^ 64 := Int.emod_nonneg _ (by decide)
|
||||
have h₃ : 0 ≤ x % 2 ^ 64 + y % 2 ^ 64 := Int.add_nonneg h₁ h₂
|
||||
rw [Int.toNat_emod h₃ (by decide), Int.toNat_add h₁ h₂]
|
||||
have : (2 ^ 64 : Int).toNat = 2 ^ 64 := rfl
|
||||
rw [this, UInt64.ofNat_mod_size, UInt64.ofNat_add]
|
||||
|
||||
namespace System.Platform
|
||||
|
||||
theorem two_pow_numBits_nonneg : 0 ≤ (2 ^ System.Platform.numBits : Int) := by
|
||||
rcases System.Platform.numBits_eq with h | h <;>
|
||||
· rw [h]
|
||||
decide
|
||||
theorem two_pow_numBits_ne_zero : (2 ^ System.Platform.numBits : Int) ≠ 0 := by
|
||||
rcases System.Platform.numBits_eq with h | h <;>
|
||||
· rw [h]
|
||||
decide
|
||||
|
||||
end System.Platform
|
||||
|
||||
open System.Platform in
|
||||
@[simp] theorem USize.ofInt_add (x y : Int) : USize.ofInt (x + y) = USize.ofInt x + USize.ofInt y := by
|
||||
dsimp only [USize.ofInt]
|
||||
rw [Int.add_emod]
|
||||
have h₁ : 0 ≤ x % 2 ^ numBits := Int.emod_nonneg _ two_pow_numBits_ne_zero
|
||||
have h₂ : 0 ≤ y % 2 ^ numBits := Int.emod_nonneg _ two_pow_numBits_ne_zero
|
||||
have h₃ : 0 ≤ x % 2 ^ numBits + y % 2 ^ numBits := Int.add_nonneg h₁ h₂
|
||||
rw [Int.toNat_emod h₃ two_pow_numBits_nonneg, Int.toNat_add h₁ h₂]
|
||||
have : (2 ^ numBits : Int).toNat = 2 ^ numBits := by
|
||||
rcases System.Platform.numBits_eq with h | h <;>
|
||||
· rw [h]
|
||||
decide
|
||||
rw [this, USize.ofNat_mod_size, USize.ofNat_add]
|
||||
|
||||
@[simp] theorem UInt8.ofNatLT_add {a b : Nat} (hab : a + b < 2 ^ 8) :
|
||||
UInt8.ofNatLT (a + b) hab = UInt8.ofNatLT a (Nat.lt_of_add_right_lt hab) + UInt8.ofNatLT b (Nat.lt_of_add_left_lt hab) := by
|
||||
simp [UInt8.ofNatLT_eq_ofNat]
|
||||
@@ -2176,6 +2268,56 @@ theorem USize.ofNatLT_sub {a b : Nat} (ha : a < 2 ^ System.Platform.numBits) (ha
|
||||
@[simp] theorem USize.ofNat_mul (a b : Nat) : USize.ofNat (a * b) = USize.ofNat a * USize.ofNat b := by
|
||||
simp [USize.ofNat_eq_iff_mod_eq_toNat]
|
||||
|
||||
@[simp] theorem UInt8.ofInt_mul (x y : Int) : ofInt (x * y) = ofInt x * ofInt y := by
|
||||
dsimp only [UInt8.ofInt]
|
||||
rw [Int.mul_emod]
|
||||
have h₁ : 0 ≤ x % 2 ^ 8 := Int.emod_nonneg _ (by decide)
|
||||
have h₂ : 0 ≤ y % 2 ^ 8 := Int.emod_nonneg _ (by decide)
|
||||
have h₃ : 0 ≤ (x % 2 ^ 8) * (y % 2 ^ 8) := Int.mul_nonneg h₁ h₂
|
||||
rw [Int.toNat_emod h₃ (by decide), Int.toNat_mul h₁ h₂]
|
||||
have : (2 ^ 8 : Int).toNat = 2 ^ 8 := rfl
|
||||
rw [this, UInt8.ofNat_mod_size, UInt8.ofNat_mul]
|
||||
@[simp] theorem UInt16.ofInt_mul (x y : Int) : ofInt (x * y) = ofInt x * ofInt y := by
|
||||
dsimp only [UInt16.ofInt]
|
||||
rw [Int.mul_emod]
|
||||
have h₁ : 0 ≤ x % 2 ^ 16 := Int.emod_nonneg _ (by decide)
|
||||
have h₂ : 0 ≤ y % 2 ^ 16 := Int.emod_nonneg _ (by decide)
|
||||
have h₃ : 0 ≤ (x % 2 ^ 16) * (y % 2 ^ 16) := Int.mul_nonneg h₁ h₂
|
||||
rw [Int.toNat_emod h₃ (by decide), Int.toNat_mul h₁ h₂]
|
||||
have : (2 ^ 16 : Int).toNat = 2 ^ 16 := rfl
|
||||
rw [this, UInt16.ofNat_mod_size, UInt16.ofNat_mul]
|
||||
@[simp] theorem UInt32.ofInt_mul (x y : Int) : ofInt (x * y) = ofInt x * ofInt y := by
|
||||
dsimp only [UInt32.ofInt]
|
||||
rw [Int.mul_emod]
|
||||
have h₁ : 0 ≤ x % 2 ^ 32 := Int.emod_nonneg _ (by decide)
|
||||
have h₂ : 0 ≤ y % 2 ^ 32 := Int.emod_nonneg _ (by decide)
|
||||
have h₃ : 0 ≤ (x % 2 ^ 32) * (y % 2 ^ 32) := Int.mul_nonneg h₁ h₂
|
||||
rw [Int.toNat_emod h₃ (by decide), Int.toNat_mul h₁ h₂]
|
||||
have : (2 ^ 32 : Int).toNat = 2 ^ 32 := rfl
|
||||
rw [this, UInt32.ofNat_mod_size, UInt32.ofNat_mul]
|
||||
@[simp] theorem UInt64.ofInt_mul (x y : Int) : ofInt (x * y) = ofInt x * ofInt y := by
|
||||
dsimp only [UInt64.ofInt]
|
||||
rw [Int.mul_emod]
|
||||
have h₁ : 0 ≤ x % 2 ^ 64 := Int.emod_nonneg _ (by decide)
|
||||
have h₂ : 0 ≤ y % 2 ^ 64 := Int.emod_nonneg _ (by decide)
|
||||
have h₃ : 0 ≤ (x % 2 ^ 64) * (y % 2 ^ 64) := Int.mul_nonneg h₁ h₂
|
||||
rw [Int.toNat_emod h₃ (by decide), Int.toNat_mul h₁ h₂]
|
||||
have : (2 ^ 64 : Int).toNat = 2 ^ 64 := rfl
|
||||
rw [this, UInt64.ofNat_mod_size, UInt64.ofNat_mul]
|
||||
open System.Platform in
|
||||
@[simp] theorem USize.ofInt_mul (x y : Int) : ofInt (x * y) = ofInt x * ofInt y := by
|
||||
dsimp only [USize.ofInt]
|
||||
rw [Int.mul_emod]
|
||||
have h₁ : 0 ≤ x % 2 ^ numBits := Int.emod_nonneg _ two_pow_numBits_ne_zero
|
||||
have h₂ : 0 ≤ y % 2 ^ numBits := Int.emod_nonneg _ two_pow_numBits_ne_zero
|
||||
have h₃ : 0 ≤ (x % 2 ^ numBits) * (y % 2 ^ numBits) := Int.mul_nonneg h₁ h₂
|
||||
rw [Int.toNat_emod h₃ two_pow_numBits_nonneg, Int.toNat_mul h₁ h₂]
|
||||
have : (2 ^ numBits : Int).toNat = 2 ^ numBits := by
|
||||
rcases System.Platform.numBits_eq with h | h <;>
|
||||
· rw [h]
|
||||
decide
|
||||
rw [this, USize.ofNat_mod_size, USize.ofNat_mul]
|
||||
|
||||
@[simp] theorem UInt8.ofNatLT_mul {a b : Nat} (ha : a < 2 ^ 8) (hb : b < 2 ^ 8) (hab : a * b < 2 ^ 8) :
|
||||
UInt8.ofNatLT (a * b) hab = UInt8.ofNatLT a ha * UInt8.ofNatLT b hb := by
|
||||
simp [UInt8.ofNatLT_eq_ofNat]
|
||||
@@ -2467,6 +2609,17 @@ protected theorem USize.neg_add {a b : USize} : - (a + b) = -a - b := USize.toBi
|
||||
@[simp] protected theorem USize.neg_sub {a b : USize} : -(a - b) = b - a := by
|
||||
rw [USize.sub_eq_add_neg, USize.neg_add, USize.sub_neg, USize.add_comm, ← USize.sub_eq_add_neg]
|
||||
|
||||
@[simp] protected theorem UInt8.ofInt_neg (x : Int) : ofInt (-x) = -ofInt x := by
|
||||
rw [Int.neg_eq_neg_one_mul, ofInt_mul, ofInt_neg_one, ← UInt8.neg_eq_neg_one_mul]
|
||||
@[simp] protected theorem UInt16.ofInt_neg (x : Int) : ofInt (-x) = -ofInt x := by
|
||||
rw [Int.neg_eq_neg_one_mul, ofInt_mul, ofInt_neg_one, ← UInt16.neg_eq_neg_one_mul]
|
||||
@[simp] protected theorem UInt32.ofInt_neg (x : Int) : ofInt (-x) = -ofInt x := by
|
||||
rw [Int.neg_eq_neg_one_mul, ofInt_mul, ofInt_neg_one, ← UInt32.neg_eq_neg_one_mul]
|
||||
@[simp] protected theorem UInt64.ofInt_neg (x : Int) : ofInt (-x) = -ofInt x := by
|
||||
rw [Int.neg_eq_neg_one_mul, ofInt_mul, ofInt_neg_one, ← UInt64.neg_eq_neg_one_mul]
|
||||
@[simp] protected theorem USize.ofInt_neg (x : Int) : ofInt (-x) = -ofInt x := by
|
||||
rw [Int.neg_eq_neg_one_mul, ofInt_mul, ofInt_neg_one, ← USize.neg_eq_neg_one_mul]
|
||||
|
||||
@[simp] protected theorem UInt8.add_left_inj {a b : UInt8} (c : UInt8) : (a + c = b + c) ↔ a = b := by
|
||||
simp [← UInt8.toBitVec_inj]
|
||||
@[simp] protected theorem UInt16.add_left_inj {a b : UInt16} (c : UInt16) : (a + c = b + c) ↔ a = b := by
|
||||
@@ -2614,6 +2767,17 @@ instance : Std.LawfulCommIdentity (α := USize) (· * ·) 1 where
|
||||
@[simp] theorem UInt64.zero_mul {a : UInt64} : 0 * a = 0 := UInt64.toBitVec_inj.1 BitVec.zero_mul
|
||||
@[simp] theorem USize.zero_mul {a : USize} : 0 * a = 0 := USize.toBitVec_inj.1 BitVec.zero_mul
|
||||
|
||||
@[simp] protected theorem UInt8.pow_zero (x : UInt8) : x ^ 0 = 1 := rfl
|
||||
protected theorem UInt8.pow_succ (x : UInt8) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
|
||||
@[simp] protected theorem UInt16.pow_zero (x : UInt16) : x ^ 0 = 1 := rfl
|
||||
protected theorem UInt16.pow_succ (x : UInt16) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
|
||||
@[simp] protected theorem UInt32.pow_zero (x : UInt32) : x ^ 0 = 1 := rfl
|
||||
protected theorem UInt32.pow_succ (x : UInt32) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
|
||||
@[simp] protected theorem UInt64.pow_zero (x : UInt64) : x ^ 0 = 1 := rfl
|
||||
protected theorem UInt64.pow_succ (x : UInt64) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
|
||||
@[simp] protected theorem USize.pow_zero (x : USize) : x ^ 0 = 1 := rfl
|
||||
protected theorem USize.pow_succ (x : USize) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
|
||||
|
||||
protected theorem UInt8.mul_add {a b c : UInt8} : a * (b + c) = a * b + a * c :=
|
||||
UInt8.toBitVec_inj.1 BitVec.mul_add
|
||||
protected theorem UInt16.mul_add {a b c : UInt16} : a * (b + c) = a * b + a * c :=
|
||||
|
||||
@@ -18,3 +18,4 @@ import Init.Data.Vector.Monadic
|
||||
import Init.Data.Vector.InsertIdx
|
||||
import Init.Data.Vector.FinRange
|
||||
import Init.Data.Vector.Extract
|
||||
import Init.Data.Vector.Perm
|
||||
|
||||
@@ -432,13 +432,13 @@ theorem countP_attachWith {p : α → Prop} {q : α → Bool} {xs : Vector α n}
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem count_attach [DecidableEq α] {xs : Vector α n} {a : {x // x ∈ xs}} :
|
||||
theorem count_attach [BEq α] {xs : Vector α n} {a : {x // x ∈ xs}} :
|
||||
xs.attach.count a = xs.count ↑a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem count_attachWith [DecidableEq α] {p : α → Prop} {xs : Vector α n} (H : ∀ a ∈ xs, p a) {a : {x // p x}} :
|
||||
theorem count_attachWith [BEq α] {p : α → Prop} {xs : Vector α n} (H : ∀ a ∈ xs, p a) {a : {x // p x}} :
|
||||
(xs.attachWith p H).count a = xs.count ↑a := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@@ -229,7 +229,7 @@ theorem count_replicate {a b : α} {n : Nat} : count a (replicate n b) = if b ==
|
||||
@[deprecated count_replicate (since := "2025-03-18")]
|
||||
abbrev count_mkVector := @count_replicate
|
||||
|
||||
theorem count_le_count_map [DecidableEq β] {xs : Vector α n} {f : α → β} {x : α} :
|
||||
theorem count_le_count_map [BEq β] [LawfulBEq β] {xs : Vector α n} {f : α → β} {x : α} :
|
||||
count x xs ≤ count (f x) (map f xs) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.count_le_count_map]
|
||||
@@ -239,4 +239,15 @@ theorem count_flatMap {α} [BEq β] {xs : Vector α n} {f : α → Vector β m}
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.count_flatMap, Function.comp_def]
|
||||
|
||||
theorem countP_replace {a b : α} {xs : Vector α n} {p : α → Bool} :
|
||||
(xs.replace a b).countP p =
|
||||
if xs.contains a then xs.countP p + (if p b then 1 else 0) - (if p a then 1 else 0) else xs.countP p := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.countP_replace]
|
||||
|
||||
theorem count_replace {a b c : α} {xs : Vector α n} :
|
||||
(xs.replace a b).count c =
|
||||
if xs.contains a then xs.count c + (if b == c then 1 else 0) - (if a == c then 1 else 0) else xs.count c := by
|
||||
simp [count_eq_countP, countP_replace]
|
||||
|
||||
end count
|
||||
|
||||
@@ -62,8 +62,10 @@ theorem beq_eq_decide [BEq α] (xs ys : Vector α n) :
|
||||
@[simp] theorem beq_toList [BEq α] (xs ys : Vector α n) : (xs.toList == ys.toList) = (xs == ys) := by
|
||||
simp [beq_eq_decide, List.beq_eq_decide]
|
||||
|
||||
instance [BEq α] [LawfulBEq α] : LawfulBEq (Vector α n) where
|
||||
instance [BEq α] [ReflBEq α] : ReflBEq (Vector α n) where
|
||||
rfl := by simp [BEq.beq, isEqv_self_beq]
|
||||
|
||||
instance [BEq α] [LawfulBEq α] : LawfulBEq (Vector α n) where
|
||||
eq_of_beq := by
|
||||
rintro ⟨xs, rfl⟩ ⟨ys, h⟩ h'
|
||||
simpa using h'
|
||||
|
||||
@@ -294,6 +294,18 @@ theorem find?_eq_some_iff_getElem {xs : Vector α n} {p : α → Bool} {b : α}
|
||||
subst w
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem isSome_findFinIdx? {xs : Vector α n} {p : α → Bool} :
|
||||
(xs.findFinIdx? p).isSome = xs.any p := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem isNone_findFinIdx? {xs : Vector α n} {p : α → Bool} :
|
||||
(xs.findFinIdx? p).isNone = xs.all (fun x => ¬ p x) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem findFinIdx?_subtype {p : α → Prop} {xs : Vector { x // p x } n}
|
||||
{f : { x // p x } → Bool} {g : α → Bool} (hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
xs.findFinIdx? f = xs.unattach.findFinIdx? g := by
|
||||
|
||||
@@ -824,6 +824,9 @@ theorem getElem?_eq_none {xs : Vector α n} (h : n ≤ i) : xs[i]? = none := by
|
||||
theorem getElem?_eq_some_iff {xs : Vector α n} : xs[i]? = some b ↔ ∃ h : i < n, xs[i] = b := by
|
||||
simp [getElem?_def]
|
||||
|
||||
theorem getElem_of_getElem? {xs : Vector α n} : xs[i]? = some a → ∃ h : i < n, xs[i] = a :=
|
||||
getElem?_eq_some_iff.mp
|
||||
|
||||
theorem some_eq_getElem?_iff {xs : Vector α n} : some b = xs[i]? ↔ ∃ h : i < n, xs[i] = b := by
|
||||
rw [eq_comm, getElem?_eq_some_iff]
|
||||
|
||||
@@ -1179,20 +1182,20 @@ theorem all_bne' [BEq α] [PartialEquivBEq α] {xs : Vector α n} :
|
||||
theorem mem_of_contains_eq_true [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
|
||||
as.contains a = true → a ∈ as := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
simp [Array.mem_of_contains_eq_true]
|
||||
simp
|
||||
|
||||
theorem contains_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} (h : a ∈ as) :
|
||||
as.contains a = true := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
simp only [mem_mk] at h
|
||||
simp [Array.contains_eq_true_of_mem, h]
|
||||
|
||||
instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈ as) :=
|
||||
decidable_of_decidable_of_iff (Iff.intro mem_of_contains_eq_true contains_eq_true_of_mem)
|
||||
simp [h]
|
||||
|
||||
theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
|
||||
as.contains a = true ↔ a ∈ as := ⟨mem_of_contains_eq_true, contains_eq_true_of_mem⟩
|
||||
|
||||
instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈ as) :=
|
||||
decidable_of_decidable_of_iff contains_iff
|
||||
|
||||
@[simp] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
|
||||
as.contains a = decide (a ∈ as) := by
|
||||
rw [Bool.eq_iff_iff, contains_iff, decide_eq_true_iff]
|
||||
@@ -1348,36 +1351,31 @@ abbrev mkVector_beq_mkVector := @replicate_beq_replicate
|
||||
· intro h
|
||||
constructor
|
||||
rintro ⟨xs, h⟩
|
||||
simpa using Array.isEqv_self_beq ..
|
||||
simp
|
||||
|
||||
@[simp] theorem lawfulBEq_iff [BEq α] [NeZero n] : LawfulBEq (Vector α n) ↔ LawfulBEq α := by
|
||||
match n, NeZero.ne n with
|
||||
| n + 1, _ =>
|
||||
constructor
|
||||
· intro h
|
||||
have : ReflBEq α := reflBEq_iff.mp h.toReflBEq
|
||||
constructor
|
||||
· intro a b h
|
||||
have := replicate_inj (n := n+1) (a := a) (b := b)
|
||||
simp only [Nat.add_one_ne_zero, false_or] at this
|
||||
rw [← this]
|
||||
apply eq_of_beq
|
||||
rw [replicate_beq_replicate]
|
||||
simpa
|
||||
· intro a
|
||||
suffices (replicate (n + 1) a == replicate (n + 1) a) = true by
|
||||
rw [replicate_beq_replicate] at this
|
||||
simpa
|
||||
simp
|
||||
intro a b h
|
||||
have := replicate_inj (n := n+1) (a := a) (b := b)
|
||||
simp only [Nat.add_one_ne_zero, false_or] at this
|
||||
rw [← this]
|
||||
apply eq_of_beq
|
||||
rw [replicate_beq_replicate]
|
||||
simpa
|
||||
· intro h
|
||||
have : ReflBEq (Vector α (n + 1)) := reflBEq_iff.mpr inferInstance
|
||||
constructor
|
||||
· rintro ⟨as, ha⟩ ⟨bs, hb⟩ h
|
||||
simp_all
|
||||
· rintro ⟨as, ha⟩
|
||||
simp
|
||||
rintro ⟨as, ha⟩ ⟨bs, hb⟩ h
|
||||
simp_all
|
||||
|
||||
/-! ### isEqv -/
|
||||
|
||||
@[simp] theorem isEqv_eq [DecidableEq α] {xs ys : Vector α n} : xs.isEqv ys (· == ·) = (xs = ys) := by
|
||||
@[simp] theorem isEqv_eq [BEq α] [LawfulBEq α] {xs ys : Vector α n} : xs.isEqv ys (· == ·) = (xs = ys) := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp
|
||||
@@ -1511,7 +1509,7 @@ theorem map_eq_iff {f : α → β} {as : Vector α n} {bs : Vector β n} :
|
||||
if h : i < as.size then
|
||||
simpa [h, h'] using w i h
|
||||
else
|
||||
rw [getElem?_neg, getElem?_neg, Option.map_none'] <;> omega
|
||||
rw [getElem?_neg, getElem?_neg, Option.map_none] <;> omega
|
||||
|
||||
@[simp] theorem map_set {f : α → β} {xs : Vector α n} {i : Nat} {h : i < n} {a : α} :
|
||||
(xs.set i a).map f = (xs.map f).set i (f a) (by simpa using h) := by
|
||||
@@ -1717,12 +1715,12 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
|
||||
constructor
|
||||
· rintro (⟨as, rfl, rfl⟩ | ⟨cs, rfl, rfl⟩)
|
||||
· rw [dif_pos (by simp)]
|
||||
exact ⟨as.toVector.cast (by simp; omega), by simp⟩
|
||||
exact ⟨as.toVector.cast (by simp), by simp⟩
|
||||
· split <;> rename_i h
|
||||
· have hc : cs.size = 0 := by simp at h; omega
|
||||
simp at hc
|
||||
exact ⟨#v[].cast (by simp; omega), by simp_all⟩
|
||||
· exact ⟨cs.toVector.cast (by simp; omega), by simp⟩
|
||||
exact ⟨#v[].cast (by simp), by simp_all⟩
|
||||
· exact ⟨cs.toVector.cast (by simp), by simp⟩
|
||||
· split <;> rename_i h
|
||||
· rintro ⟨as, hc, rfl⟩
|
||||
left
|
||||
@@ -2677,12 +2675,7 @@ variable [LawfulBEq α]
|
||||
theorem getElem?_replace {xs : Vector α n} {i : Nat} :
|
||||
(xs.replace a b)[i]? = if xs[i]? == some a then if a ∈ xs.take i then some a else some b else xs[i]? := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.getElem?_replace]
|
||||
split <;> rename_i h
|
||||
· rw (occs := [2]) [if_pos]
|
||||
simpa using h
|
||||
· rw [if_neg]
|
||||
simpa using h
|
||||
simp [Array.getElem?_replace, -beq_iff_eq]
|
||||
|
||||
theorem getElem?_replace_of_ne {xs : Vector α n} {i : Nat} (h : xs[i]? ≠ some a) :
|
||||
(xs.replace a b)[i]? = xs[i]? := by
|
||||
|
||||
@@ -148,13 +148,13 @@ protected theorem le_iff_lt_or_eq [DecidableEq α] [LT α] [DecidableLT α]
|
||||
{xs ys : Vector α n} : xs ≤ ys ↔ xs < ys ∨ xs = ys := by
|
||||
simpa using Array.le_iff_lt_or_eq (xs := xs.toArray) (ys := ys.toArray)
|
||||
|
||||
@[simp] theorem lex_eq_true_iff_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
@[simp] theorem lex_eq_true_iff_lt [BEq α] [LawfulBEq α] [LT α] [DecidableLT α]
|
||||
{xs ys : Vector α n} : lex xs ys = true ↔ xs < ys := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp
|
||||
|
||||
@[simp] theorem lex_eq_false_iff_ge [DecidableEq α] [LT α] [DecidableLT α]
|
||||
@[simp] theorem lex_eq_false_iff_ge [BEq α] [LawfulBEq α] [LT α] [DecidableLT α]
|
||||
{xs ys : Vector α n} : lex xs ys = false ↔ ys ≤ xs := by
|
||||
cases xs
|
||||
cases ys
|
||||
|
||||
104
src/Init/Data/Vector/Perm.lean
Normal file
104
src/Init/Data/Vector/Perm.lean
Normal file
@@ -0,0 +1,104 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Perm
|
||||
import Init.Data.Vector.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 Vector
|
||||
|
||||
open List Array
|
||||
|
||||
/--
|
||||
`Perm as bs` asserts that `as` and `bs` are permutations of each other.
|
||||
|
||||
This is a wrapper around `List.Perm`, and for now has much less API.
|
||||
For more complicated verification, use `perm_iff_toList_perm` and the `List` API.
|
||||
-/
|
||||
def Perm (as bs : Vector α n) : Prop :=
|
||||
as.toArray ~ bs.toArray
|
||||
|
||||
@[inherit_doc] scoped infixl:50 " ~ " => Perm
|
||||
|
||||
theorem perm_iff_toList_perm {as bs : Vector α n} : as ~ bs ↔ as.toList ~ bs.toList := Iff.rfl
|
||||
theorem perm_iff_toArray_perm {as bs : Vector α n} : as ~ bs ↔ as.toArray ~ bs.toArray := Iff.rfl
|
||||
|
||||
@[simp] theorem perm_mk (as bs : Array α) (ha : as.size = n) (hb : bs.size = n) :
|
||||
mk as ha ~ mk bs hb ↔ as ~ bs := by
|
||||
simp [perm_iff_toArray_perm, ha, hb]
|
||||
|
||||
theorem toArray_perm_iff (xs : Vector α n) (ys : Array α) : xs.toArray ~ ys ↔ ∃ h, xs ~ Vector.mk ys h := by
|
||||
constructor
|
||||
· intro h
|
||||
refine ⟨by simp [← h.length_eq], h⟩
|
||||
· intro ⟨h, p⟩
|
||||
exact p
|
||||
|
||||
theorem perm_toArray_iff (xs : Array α) (ys : Vector α n) : xs ~ ys.toArray ↔ ∃ h, Vector.mk xs h ~ ys := by
|
||||
constructor
|
||||
· intro h
|
||||
refine ⟨by simp [h.length_eq], h⟩
|
||||
· intro ⟨h, p⟩
|
||||
exact p
|
||||
|
||||
@[simp, refl] protected theorem Perm.refl (xs : Vector α n) : xs ~ xs := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
protected theorem Perm.rfl {xs : List α} : xs ~ xs := .refl _
|
||||
|
||||
theorem Perm.of_eq {xs ys : Vector α n} (h : xs = ys) : xs ~ ys := h ▸ .rfl
|
||||
|
||||
protected theorem Perm.symm {xs ys : Vector α n} (h : xs ~ ys) : ys ~ xs := by
|
||||
cases xs; cases ys
|
||||
simp only [perm_mk] at h
|
||||
simpa using h.symm
|
||||
|
||||
protected theorem Perm.trans {xs ys zs : Vector α n} (h₁ : xs ~ ys) (h₂ : ys ~ zs) : xs ~ zs := by
|
||||
cases xs; cases ys; cases zs
|
||||
simp only [perm_mk] at h₁ h₂
|
||||
simpa using h₁.trans h₂
|
||||
|
||||
instance : Trans (Perm (α := α) (n := n)) (Perm (α := α) (n := n)) (Perm (α := α) (n := n)) where
|
||||
trans h₁ h₂ := Perm.trans h₁ h₂
|
||||
|
||||
theorem perm_comm {xs ys : Vector α n} : xs ~ ys ↔ ys ~ xs := ⟨Perm.symm, Perm.symm⟩
|
||||
|
||||
theorem Perm.mem_iff {a : α} {xs ys : Vector α n} (p : xs ~ ys) : a ∈ xs ↔ a ∈ ys := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp at p
|
||||
simpa using p.mem_iff
|
||||
|
||||
theorem Perm.push (x y : α) {xs ys : Vector α n} (p : xs ~ ys) :
|
||||
(xs.push x).push y ~ (ys.push y).push x := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, h⟩
|
||||
simp only [perm_mk] at p
|
||||
simp only [push_mk, List.append_assoc, singleton_append, perm_toArray]
|
||||
simpa using Array.Perm.push x y p
|
||||
|
||||
theorem swap_perm {xs : Vector α n} {i j : Nat} (h₁ : i < n) (h₂ : j < n) :
|
||||
xs.swap i j ~ xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp only [swap, perm_iff_toList_perm, toList_set]
|
||||
apply set_set_perm
|
||||
|
||||
namespace Perm
|
||||
|
||||
set_option linter.indexVariables false in
|
||||
theorem extract {xs ys : Vector α n} (h : xs ~ ys) {lo hi : Nat}
|
||||
(wlo : ∀ i, i < lo → xs[i]? = ys[i]?) (whi : ∀ i, hi ≤ i → xs[i]? = ys[i]?) :
|
||||
(xs.extract lo hi) ~ (ys.extract lo hi) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, h⟩
|
||||
exact Array.Perm.extract h (by simpa using wlo) (by simpa using whi)
|
||||
|
||||
end Perm
|
||||
|
||||
end Vector
|
||||
@@ -101,9 +101,8 @@ theorem range'_eq_append_iff : range' s (n + m) = xs ++ ys ↔ xs = range' s n
|
||||
simp_all
|
||||
subst w
|
||||
simp_all
|
||||
omega
|
||||
· rintro ⟨h₁, h₂⟩
|
||||
exact ⟨n, by omega, by simp_all; omega⟩
|
||||
exact ⟨n, by omega, by simp_all⟩
|
||||
|
||||
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range' s n).find? p = some i ↔ p i ∧ i ∈ range' s n ∧ ∀ j, s ≤ j → j < i → !p j := by
|
||||
|
||||
@@ -13,3 +13,4 @@ import Init.Grind.Util
|
||||
import Init.Grind.Offset
|
||||
import Init.Grind.PP
|
||||
import Init.Grind.CommRing
|
||||
import Init.Grind.Ext
|
||||
|
||||
@@ -5,14 +5,31 @@ Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Zero
|
||||
import Init.Data.Int.DivMod.Lemmas
|
||||
import Init.Data.Int.Pow
|
||||
import Init.TacticsExtra
|
||||
|
||||
/-!
|
||||
# A monolithic commutative ring typeclass for internal use in `grind`.
|
||||
|
||||
The `Lean.Grind.CommRing` class will be used to convert expressions into the internal representation via polynomials,
|
||||
with coefficients expressed via `OfNat` and `Neg`.
|
||||
|
||||
The `IsCharP α p` typeclass expresses that the ring has characteristic `p`,
|
||||
i.e. that a coefficient `OfNat.ofNat x : α` is zero if and only if `x % p = 0` (in `Nat`).
|
||||
See
|
||||
```
|
||||
theorem ofNat_ext_iff {x y : Nat} : OfNat.ofNat (α := α) x = OfNat.ofNat (α := α) y ↔ x % p = y % p
|
||||
theorem ofNat_emod (x : Nat) : OfNat.ofNat (α := α) (x % p) = OfNat.ofNat x
|
||||
theorem ofNat_eq_iff_of_lt {x y : Nat} (h₁ : x < p) (h₂ : y < p) :
|
||||
OfNat.ofNat (α := α) x = OfNat.ofNat (α := α) y ↔ x = y
|
||||
```
|
||||
-/
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
class CommRing (α : Type u) extends Add α, Zero α, Mul α, One α, Neg α where
|
||||
class CommRing (α : Type u) extends Add α, Mul α, Neg α, Sub α, HPow α Nat α where
|
||||
[ofNat : ∀ n, OfNat α n]
|
||||
add_assoc : ∀ a b c : α, a + b + c = a + (b + c)
|
||||
add_comm : ∀ a b : α, a + b = b + a
|
||||
add_zero : ∀ a : α, a + 0 = a
|
||||
@@ -22,17 +39,46 @@ class CommRing (α : Type u) extends Add α, Zero α, Mul α, One α, Neg α whe
|
||||
mul_one : ∀ a : α, a * 1 = a
|
||||
left_distrib : ∀ a b c : α, a * (b + c) = a * b + a * c
|
||||
zero_mul : ∀ a : α, 0 * a = 0
|
||||
sub_eq_add_neg : ∀ a b : α, a - b = a + -b
|
||||
pow_zero : ∀ a : α, a ^ 0 = 1
|
||||
pow_succ : ∀ a : α, ∀ n : Nat, a ^ (n + 1) = (a ^ n) * a
|
||||
ofNat_succ : ∀ a : Nat, OfNat.ofNat (α := α) (a + 1) = OfNat.ofNat a + 1 := by intros; rfl
|
||||
|
||||
-- We reduce the priority of these parent instances,
|
||||
-- so that in downstream libraries with their own `CommRing` class,
|
||||
-- the path `CommRing -> Add` is found before `CommRing -> Lean.Grind.CommRing -> Add`.
|
||||
-- (And similarly for the other parents.)
|
||||
attribute [instance 100] CommRing.toAdd CommRing.toMul CommRing.toNeg CommRing.toSub CommRing.toHPow
|
||||
|
||||
-- This is a low-priority instance, to avoid conflicts with existing `OfNat` instances.
|
||||
attribute [instance 100] CommRing.ofNat
|
||||
|
||||
namespace CommRing
|
||||
|
||||
variable {α : Type u} [CommRing α]
|
||||
|
||||
instance : NatCast α where
|
||||
natCast n := OfNat.ofNat n
|
||||
|
||||
theorem natCast_zero : ((0 : Nat) : α) = 0 := rfl
|
||||
theorem ofNat_eq_natCast (n : Nat) : OfNat.ofNat n = (n : α) := rfl
|
||||
|
||||
theorem ofNat_add (a b : Nat) : OfNat.ofNat (α := α) (a + b) = OfNat.ofNat a + OfNat.ofNat b := by
|
||||
induction b with
|
||||
| zero => simp [Nat.add_zero, add_zero]
|
||||
| succ b ih => rw [Nat.add_succ, ofNat_succ, ih, ofNat_succ b, add_assoc]
|
||||
|
||||
theorem natCast_succ (n : Nat) : ((n + 1 : Nat) : α) = ((n : α) + 1) := ofNat_add _ _
|
||||
|
||||
theorem zero_add (a : α) : 0 + a = a := by
|
||||
rw [add_comm, add_zero]
|
||||
|
||||
theorem add_neg_cancel (a : α) : a + -a = 0 := by
|
||||
rw [add_comm, neg_add_cancel]
|
||||
|
||||
theorem add_left_comm (a b c : α) : a + (b + c) = b + (a + c) := by
|
||||
rw [← add_assoc, ← add_assoc, add_comm a]
|
||||
|
||||
theorem one_mul (a : α) : 1 * a = a := by
|
||||
rw [mul_comm, mul_one]
|
||||
|
||||
@@ -42,6 +88,217 @@ theorem right_distrib (a b c : α) : (a + b) * c = a * c + b * c := by
|
||||
theorem mul_zero (a : α) : a * 0 = 0 := by
|
||||
rw [mul_comm, zero_mul]
|
||||
|
||||
theorem mul_left_comm (a b c : α) : a * (b * c) = b * (a * c) := by
|
||||
rw [← mul_assoc, ← mul_assoc, mul_comm a]
|
||||
|
||||
theorem ofNat_mul (a b : Nat) : OfNat.ofNat (α := α) (a * b) = OfNat.ofNat a * OfNat.ofNat b := by
|
||||
induction b with
|
||||
| zero => simp [Nat.mul_zero, mul_zero]
|
||||
| succ a ih => rw [Nat.mul_succ, ofNat_add, ih, ofNat_add, left_distrib, mul_one]
|
||||
|
||||
theorem add_left_inj {a b : α} (c : α) : a + c = b + c ↔ a = b :=
|
||||
⟨fun h => by simpa [add_assoc, add_neg_cancel, add_zero] using (congrArg (· + -c) h),
|
||||
fun g => congrArg (· + c) g⟩
|
||||
|
||||
theorem add_right_inj (a b c : α) : a + b = a + c ↔ b = c := by
|
||||
rw [add_comm a b, add_comm a c, add_left_inj]
|
||||
|
||||
theorem neg_zero : (-0 : α) = 0 := by
|
||||
rw [← add_left_inj 0, neg_add_cancel, add_zero]
|
||||
|
||||
theorem neg_neg (a : α) : -(-a) = a := by
|
||||
rw [← add_left_inj (-a), neg_add_cancel, add_neg_cancel]
|
||||
|
||||
theorem neg_eq_zero (a : α) : -a = 0 ↔ a = 0 :=
|
||||
⟨fun h => by
|
||||
replace h := congrArg (-·) h
|
||||
simpa [neg_neg, neg_zero] using h,
|
||||
fun h => by rw [h, neg_zero]⟩
|
||||
|
||||
theorem neg_add (a b : α) : -(a + b) = -a + -b := by
|
||||
rw [← add_left_inj (a + b), neg_add_cancel, add_assoc (-a), add_comm a b, ← add_assoc (-b),
|
||||
neg_add_cancel, zero_add, neg_add_cancel]
|
||||
|
||||
theorem neg_sub (a b : α) : -(a - b) = b - a := by
|
||||
rw [sub_eq_add_neg, neg_add, neg_neg, sub_eq_add_neg, add_comm]
|
||||
|
||||
theorem sub_self (a : α) : a - a = 0 := by
|
||||
rw [sub_eq_add_neg, add_neg_cancel]
|
||||
|
||||
instance : IntCast α where
|
||||
intCast n := match n with
|
||||
| Int.ofNat n => OfNat.ofNat n
|
||||
| Int.negSucc n => -OfNat.ofNat (n + 1)
|
||||
|
||||
theorem intCast_zero : ((0 : Int) : α) = 0 := rfl
|
||||
theorem intCast_one : ((1 : Int) : α) = 1 := rfl
|
||||
theorem intCast_neg_one : ((-1 : Int) : α) = -1 := rfl
|
||||
theorem intCast_ofNat (n : Nat) : ((n : Int) : α) = (n : α) := rfl
|
||||
theorem intCast_ofNat_add_one (n : Nat) : ((n + 1 : Int) : α) = (n : α) + 1 := ofNat_add _ _
|
||||
theorem intCast_negSucc (n : Nat) : ((-(n + 1) : Int) : α) = -((n : α) + 1) := congrArg (- ·) (ofNat_add _ _)
|
||||
theorem intCast_neg (x : Int) : ((-x : Int) : α) = - (x : α) :=
|
||||
match x with
|
||||
| (0 : Nat) => neg_zero.symm
|
||||
| (n + 1 : Nat) => by
|
||||
rw [Int.natCast_add, Int.cast_ofNat_Int, intCast_negSucc, intCast_ofNat_add_one]
|
||||
| -((n : Nat) + 1) => by
|
||||
rw [Int.neg_neg, intCast_ofNat_add_one, intCast_negSucc, neg_neg]
|
||||
theorem intCast_nat_add {x y : Nat} : ((x + y : Int) : α) = ((x : α) + (y : α)) := ofNat_add _ _
|
||||
theorem intCast_nat_sub {x y : Nat} (h : x ≥ y) : (((x - y : Nat) : Int) : α) = ((x : α) - (y : α)) := by
|
||||
induction x with
|
||||
| zero =>
|
||||
have : y = 0 := by omega
|
||||
simp [this, intCast_zero, natCast_zero, sub_eq_add_neg, zero_add, neg_zero]
|
||||
| succ x ih =>
|
||||
by_cases h : x + 1 = y
|
||||
· simp [h, intCast_zero, sub_self]
|
||||
· have : ((x + 1 - y : Nat) : Int) = (x - y : Nat) + 1 := by omega
|
||||
rw [this, intCast_ofNat_add_one]
|
||||
specialize ih (by omega)
|
||||
rw [intCast_ofNat] at ih
|
||||
rw [ih, natCast_succ, sub_eq_add_neg, sub_eq_add_neg, add_assoc, add_comm _ 1, ← add_assoc]
|
||||
theorem intCast_add (x y : Int) : ((x + y : Int) : α) = ((x : α) + (y : α)) :=
|
||||
match x, y with
|
||||
| (x : Nat), (y : Nat) => ofNat_add _ _
|
||||
| (x : Nat), (-(y + 1 : Nat)) => by
|
||||
by_cases h : x ≥ y + 1
|
||||
· have : (x + -(y+1 : Nat) : Int) = ((x - (y + 1) : Nat) : Int) := by omega
|
||||
rw [this, intCast_neg, intCast_nat_sub h, intCast_ofNat, intCast_ofNat, sub_eq_add_neg]
|
||||
· have : (x + -(y+1 : Nat) : Int) = (-(y + 1 - x : Nat) : Int) := by omega
|
||||
rw [this, intCast_neg, intCast_nat_sub (by omega), intCast_ofNat, intCast_neg, intCast_ofNat,
|
||||
neg_sub, sub_eq_add_neg]
|
||||
| (-(x + 1 : Nat)), (y : Nat) => by
|
||||
by_cases h : y ≥ x+ 1
|
||||
· have : (-(x+1 : Nat) + y : Int) = ((y - (x + 1) : Nat) : Int) := by omega
|
||||
rw [this, intCast_neg, intCast_nat_sub h, intCast_ofNat, intCast_ofNat, sub_eq_add_neg, add_comm]
|
||||
· have : (-(x+1 : Nat) + y : Int) = (-(x + 1 - y : Nat) : Int) := by omega
|
||||
rw [this, intCast_neg, intCast_nat_sub (by omega), intCast_ofNat, intCast_neg, intCast_ofNat,
|
||||
neg_sub, sub_eq_add_neg, add_comm]
|
||||
| (-(x + 1 : Nat)), (-(y + 1 : Nat)) => by
|
||||
rw [← Int.neg_add, intCast_neg, intCast_nat_add, neg_add, intCast_neg, intCast_neg, intCast_ofNat, intCast_ofNat]
|
||||
theorem intCast_sub (x y : Int) : ((x - y : Int) : α) = ((x : α) - (y : α)) := by
|
||||
rw [Int.sub_eq_add_neg, intCast_add, intCast_neg, sub_eq_add_neg]
|
||||
|
||||
theorem neg_eq_neg_one_mul (a : α) : -a = (-1) * a := by
|
||||
rw [← add_left_inj a, neg_add_cancel]
|
||||
conv => rhs; arg 2; rw [← one_mul a]
|
||||
rw [← right_distrib, ← intCast_neg_one, ← intCast_one (α := α)]
|
||||
simp [← intCast_add, intCast_zero, zero_mul]
|
||||
|
||||
theorem neg_mul (a b : α) : (-a) * b = -(a * b) := by
|
||||
rw [neg_eq_neg_one_mul a, neg_eq_neg_one_mul (a * b), mul_assoc]
|
||||
|
||||
theorem mul_neg (a b : α) : a * (-b) = -(a * b) := by
|
||||
rw [mul_comm, neg_mul, mul_comm]
|
||||
|
||||
theorem intCast_nat_mul (x y : Nat) : ((x * y : Int) : α) = ((x : α) * (y : α)) := ofNat_mul _ _
|
||||
theorem intCast_mul (x y : Int) : ((x * y : Int) : α) = ((x : α) * (y : α)) :=
|
||||
match x, y with
|
||||
| (x : Nat), (y : Nat) => ofNat_mul _ _
|
||||
| (x : Nat), (-(y + 1 : Nat)) => by
|
||||
rw [Int.mul_neg, intCast_neg, intCast_nat_mul, intCast_neg, mul_neg, intCast_ofNat, intCast_ofNat]
|
||||
| (-(x + 1 : Nat)), (y : Nat) => by
|
||||
rw [Int.neg_mul, intCast_neg, intCast_nat_mul, intCast_neg, neg_mul, intCast_ofNat, intCast_ofNat]
|
||||
| (-(x + 1 : Nat)), (-(y + 1 : Nat)) => by
|
||||
rw [Int.neg_mul_neg, intCast_neg, intCast_neg, neg_mul, mul_neg, neg_neg, intCast_nat_mul,
|
||||
intCast_ofNat, intCast_ofNat]
|
||||
|
||||
theorem intCast_pow (x : Int) (k : Nat) : ((x ^ k : Int) : α) = (x : α) ^ k := by
|
||||
induction k
|
||||
next => simp [pow_zero, Int.pow_zero, intCast_one]
|
||||
next k ih => simp [pow_succ, Int.pow_succ, intCast_mul, *]
|
||||
|
||||
theorem pow_add (a : α) (k₁ k₂ : Nat) : a ^ (k₁ + k₂) = a^k₁ * a^k₂ := by
|
||||
induction k₂
|
||||
next => simp [pow_zero, mul_one]
|
||||
next k₂ ih => rw [Nat.add_succ, pow_succ, pow_succ, ih, mul_assoc]
|
||||
|
||||
end CommRing
|
||||
|
||||
open CommRing
|
||||
|
||||
class IsCharP (α : Type u) [CommRing α] (p : Nat) where
|
||||
ofNat_eq_zero_iff (p) : ∀ (x : Nat), OfNat.ofNat (α := α) x = 0 ↔ x % p = 0
|
||||
|
||||
namespace IsCharP
|
||||
|
||||
variable (p) {α : Type u} [CommRing α] [IsCharP α p]
|
||||
|
||||
theorem natCast_eq_zero_iff (x : Nat) : (x : α) = 0 ↔ x % p = 0 :=
|
||||
ofNat_eq_zero_iff p x
|
||||
|
||||
theorem intCast_eq_zero_iff (x : Int) : (x : α) = 0 ↔ x % p = 0 :=
|
||||
match x with
|
||||
| (x : Nat) => by
|
||||
have := ofNat_eq_zero_iff (α := α) p (x := x)
|
||||
rw [Int.ofNat_mod_ofNat]
|
||||
norm_cast
|
||||
| -(x + 1 : Nat) => by
|
||||
rw [Int.neg_emod, Int.ofNat_mod_ofNat, intCast_neg, intCast_ofNat, neg_eq_zero]
|
||||
have := ofNat_eq_zero_iff (α := α) p (x := x + 1)
|
||||
rw [ofNat_eq_natCast] at this
|
||||
rw [this]
|
||||
simp only [Int.ofNat_dvd]
|
||||
simp only [← Nat.dvd_iff_mod_eq_zero, Int.natAbs_natCast, Int.natCast_add,
|
||||
Int.cast_ofNat_Int, ite_eq_left_iff]
|
||||
by_cases h : p ∣ x + 1
|
||||
· simp [h]
|
||||
· simp only [h, not_false_eq_true, Int.natCast_add, Int.cast_ofNat_Int,
|
||||
forall_const, false_iff, ne_eq]
|
||||
by_cases w : p = 0
|
||||
· simp [w]
|
||||
omega
|
||||
· have : ((x + 1) % p) < p := Nat.mod_lt _ (by omega)
|
||||
omega
|
||||
|
||||
theorem intCast_ext_iff {x y : Int} : (x : α) = (y : α) ↔ x % p = y % p := by
|
||||
constructor
|
||||
· intro h
|
||||
replace h : ((x - y : Int) : α) = 0 := by rw [intCast_sub, h, sub_self]
|
||||
exact Int.emod_eq_emod_iff_emod_sub_eq_zero.mpr ((intCast_eq_zero_iff p _).mp h)
|
||||
· intro h
|
||||
have : ((x - y : Int) : α) = 0 :=
|
||||
(intCast_eq_zero_iff p _).mpr (by rw [Int.sub_emod, h, Int.sub_self, Int.zero_emod])
|
||||
replace this := congrArg (· + (y : α)) this
|
||||
simpa [intCast_sub, zero_add, sub_eq_add_neg, add_assoc, neg_add_cancel, add_zero] using this
|
||||
|
||||
theorem ofNat_ext_iff {x y : Nat} : OfNat.ofNat (α := α) x = OfNat.ofNat (α := α) y ↔ x % p = y % p := by
|
||||
have := intCast_ext_iff (α := α) p (x := x) (y := y)
|
||||
simp only [intCast_ofNat, ← Int.ofNat_emod] at this
|
||||
simp only [ofNat_eq_natCast]
|
||||
norm_cast at this
|
||||
|
||||
theorem ofNat_ext {x y : Nat} (h : x % p = y % p) : OfNat.ofNat (α := α) x = OfNat.ofNat (α := α) y := (ofNat_ext_iff p).mpr h
|
||||
|
||||
theorem natCast_ext {x y : Nat} (h : x % p = y % p) : (x : α) = (y : α) := ofNat_ext _ h
|
||||
|
||||
theorem natCast_ext_iff {x y : Nat} : (x : α) = (y : α) ↔ x % p = y % p :=
|
||||
ofNat_ext_iff p
|
||||
|
||||
theorem intCast_emod (x : Int) : ((x % p : Int) : α) = (x : α) := by
|
||||
rw [intCast_ext_iff p, Int.emod_emod]
|
||||
|
||||
theorem natCast_emod (x : Nat) : ((x % p : Nat) : α) = (x : α) := by
|
||||
simp only [← intCast_ofNat]
|
||||
rw [Int.ofNat_emod, intCast_emod]
|
||||
|
||||
theorem ofNat_emod (x : Nat) : OfNat.ofNat (α := α) (x % p) = OfNat.ofNat x :=
|
||||
natCast_emod _ _
|
||||
|
||||
theorem ofNat_eq_zero_iff_of_lt {x : Nat} (h : x < p) : OfNat.ofNat (α := α) x = 0 ↔ x = 0 := by
|
||||
rw [ofNat_eq_zero_iff p, Nat.mod_eq_of_lt h]
|
||||
|
||||
theorem ofNat_eq_iff_of_lt {x y : Nat} (h₁ : x < p) (h₂ : y < p) :
|
||||
OfNat.ofNat (α := α) x = OfNat.ofNat (α := α) y ↔ x = y := by
|
||||
rw [ofNat_ext_iff p, Nat.mod_eq_of_lt h₁, Nat.mod_eq_of_lt h₂]
|
||||
|
||||
theorem natCast_eq_zero_iff_of_lt {x : Nat} (h : x < p) : (x : α) = 0 ↔ x = 0 := by
|
||||
rw [natCast_eq_zero_iff p, Nat.mod_eq_of_lt h]
|
||||
|
||||
theorem natCast_eq_iff_of_lt {x y : Nat} (h₁ : x < p) (h₂ : y < p) :
|
||||
(x : α) = (y : α) ↔ x = y := by
|
||||
rw [natCast_ext_iff p, Nat.mod_eq_of_lt h₁, Nat.mod_eq_of_lt h₂]
|
||||
|
||||
end IsCharP
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -19,5 +19,12 @@ instance : CommRing (BitVec w) where
|
||||
mul_one := BitVec.mul_one
|
||||
left_distrib _ _ _ := BitVec.mul_add
|
||||
zero_mul _ := BitVec.zero_mul
|
||||
sub_eq_add_neg := BitVec.sub_eq_add_neg
|
||||
pow_zero _ := BitVec.pow_zero
|
||||
pow_succ _ _ := BitVec.pow_succ
|
||||
ofNat_succ x := BitVec.ofNat_add x 1
|
||||
|
||||
instance : IsCharP (BitVec w) (2 ^ w) where
|
||||
ofNat_eq_zero_iff {x} := by simp [BitVec.ofInt, BitVec.toNat_eq]
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -19,5 +19,12 @@ instance : CommRing Int where
|
||||
mul_one := Int.mul_one
|
||||
left_distrib := Int.mul_add
|
||||
zero_mul := Int.zero_mul
|
||||
pow_zero _ := rfl
|
||||
pow_succ _ _ := rfl
|
||||
ofNat_succ _ := rfl
|
||||
sub_eq_add_neg _ _ := Int.sub_eq_add_neg
|
||||
|
||||
instance : IsCharP Int 0 where
|
||||
ofNat_eq_zero_iff {x} := by erw [Int.ofNat_eq_zero]; simp
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -9,6 +9,9 @@ import Init.Data.SInt.Lemmas
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
instance : IntCast Int8 where
|
||||
intCast x := Int8.ofInt x
|
||||
|
||||
instance : CommRing Int8 where
|
||||
add_assoc := Int8.add_assoc
|
||||
add_comm := Int8.add_comm
|
||||
@@ -19,6 +22,20 @@ instance : CommRing Int8 where
|
||||
mul_one := Int8.mul_one
|
||||
left_distrib _ _ _ := Int8.mul_add
|
||||
zero_mul _ := Int8.zero_mul
|
||||
sub_eq_add_neg := Int8.sub_eq_add_neg
|
||||
pow_zero := Int8.pow_zero
|
||||
pow_succ := Int8.pow_succ
|
||||
ofNat_succ x := Int8.ofNat_add x 1
|
||||
|
||||
instance : IsCharP Int8 (2 ^ 8) where
|
||||
ofNat_eq_zero_iff {x} := by
|
||||
have : OfNat.ofNat x = Int8.ofInt x := rfl
|
||||
rw [this]
|
||||
simp [Int8.ofInt_eq_iff_bmod_eq_toInt,
|
||||
← Int.dvd_iff_bmod_eq_zero, ← Nat.dvd_iff_mod_eq_zero, Int.ofNat_dvd_right]
|
||||
|
||||
instance : IntCast Int16 where
|
||||
intCast x := Int16.ofInt x
|
||||
|
||||
instance : CommRing Int16 where
|
||||
add_assoc := Int16.add_assoc
|
||||
@@ -30,6 +47,20 @@ instance : CommRing Int16 where
|
||||
mul_one := Int16.mul_one
|
||||
left_distrib _ _ _ := Int16.mul_add
|
||||
zero_mul _ := Int16.zero_mul
|
||||
sub_eq_add_neg := Int16.sub_eq_add_neg
|
||||
pow_zero := Int16.pow_zero
|
||||
pow_succ := Int16.pow_succ
|
||||
ofNat_succ x := Int16.ofNat_add x 1
|
||||
|
||||
instance : IsCharP Int16 (2 ^ 16) where
|
||||
ofNat_eq_zero_iff {x} := by
|
||||
have : OfNat.ofNat x = Int16.ofInt x := rfl
|
||||
rw [this]
|
||||
simp [Int16.ofInt_eq_iff_bmod_eq_toInt,
|
||||
← Int.dvd_iff_bmod_eq_zero, ← Nat.dvd_iff_mod_eq_zero, Int.ofNat_dvd_right]
|
||||
|
||||
instance : IntCast Int32 where
|
||||
intCast x := Int32.ofInt x
|
||||
|
||||
instance : CommRing Int32 where
|
||||
add_assoc := Int32.add_assoc
|
||||
@@ -41,6 +72,20 @@ instance : CommRing Int32 where
|
||||
mul_one := Int32.mul_one
|
||||
left_distrib _ _ _ := Int32.mul_add
|
||||
zero_mul _ := Int32.zero_mul
|
||||
sub_eq_add_neg := Int32.sub_eq_add_neg
|
||||
pow_zero := Int32.pow_zero
|
||||
pow_succ := Int32.pow_succ
|
||||
ofNat_succ x := Int32.ofNat_add x 1
|
||||
|
||||
instance : IsCharP Int32 (2 ^ 32) where
|
||||
ofNat_eq_zero_iff {x} := by
|
||||
have : OfNat.ofNat x = Int32.ofInt x := rfl
|
||||
rw [this]
|
||||
simp [Int32.ofInt_eq_iff_bmod_eq_toInt,
|
||||
← Int.dvd_iff_bmod_eq_zero, ← Nat.dvd_iff_mod_eq_zero, Int.ofNat_dvd_right]
|
||||
|
||||
instance : IntCast Int64 where
|
||||
intCast x := Int64.ofInt x
|
||||
|
||||
instance : CommRing Int64 where
|
||||
add_assoc := Int64.add_assoc
|
||||
@@ -52,6 +97,20 @@ instance : CommRing Int64 where
|
||||
mul_one := Int64.mul_one
|
||||
left_distrib _ _ _ := Int64.mul_add
|
||||
zero_mul _ := Int64.zero_mul
|
||||
sub_eq_add_neg := Int64.sub_eq_add_neg
|
||||
pow_zero := Int64.pow_zero
|
||||
pow_succ := Int64.pow_succ
|
||||
ofNat_succ x := Int64.ofNat_add x 1
|
||||
|
||||
instance : IsCharP Int64 (2 ^ 64) where
|
||||
ofNat_eq_zero_iff {x} := by
|
||||
have : OfNat.ofNat x = Int64.ofInt x := rfl
|
||||
rw [this]
|
||||
simp [Int64.ofInt_eq_iff_bmod_eq_toInt,
|
||||
← Int.dvd_iff_bmod_eq_zero, ← Nat.dvd_iff_mod_eq_zero, Int.ofNat_dvd_right]
|
||||
|
||||
instance : IntCast ISize where
|
||||
intCast x := ISize.ofInt x
|
||||
|
||||
instance : CommRing ISize where
|
||||
add_assoc := ISize.add_assoc
|
||||
@@ -63,5 +122,18 @@ instance : CommRing ISize where
|
||||
mul_one := ISize.mul_one
|
||||
left_distrib _ _ _ := ISize.mul_add
|
||||
zero_mul _ := ISize.zero_mul
|
||||
sub_eq_add_neg := ISize.sub_eq_add_neg
|
||||
pow_zero := ISize.pow_zero
|
||||
pow_succ := ISize.pow_succ
|
||||
ofNat_succ x := ISize.ofNat_add x 1
|
||||
|
||||
open System.Platform (numBits)
|
||||
|
||||
instance : IsCharP ISize (2 ^ numBits) where
|
||||
ofNat_eq_zero_iff {x} := by
|
||||
have : OfNat.ofNat x = ISize.ofInt x := rfl
|
||||
rw [this]
|
||||
simp [ISize.ofInt_eq_iff_bmod_eq_toInt,
|
||||
← Int.dvd_iff_bmod_eq_zero, ← Nat.dvd_iff_mod_eq_zero, Int.ofNat_dvd_right]
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
503
src/Init/Grind/CommRing/SOM.lean
Normal file
503
src/Init/Grind/CommRing/SOM.lean
Normal file
@@ -0,0 +1,503 @@
|
||||
/-
|
||||
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.Nat.Lemmas
|
||||
import Init.Data.Ord
|
||||
import Init.Grind.CommRing.Basic
|
||||
|
||||
namespace Lean.Grind
|
||||
namespace CommRing
|
||||
|
||||
abbrev Var := Nat
|
||||
|
||||
inductive Expr where
|
||||
| num (v : Int)
|
||||
| var (i : Var)
|
||||
| neg (a : Expr)
|
||||
| add (a b : Expr)
|
||||
| sub (a b : Expr)
|
||||
| mul (a b : Expr)
|
||||
| pow (a : Expr) (k : Nat)
|
||||
deriving Inhabited, BEq
|
||||
|
||||
-- TODO: add support for universes to Lean.RArray
|
||||
inductive RArray (α : Type u) : Type u where
|
||||
| leaf : α → RArray α
|
||||
| branch : Nat → RArray α → RArray α → RArray α
|
||||
|
||||
def RArray.get (a : RArray α) (n : Nat) : α :=
|
||||
match a with
|
||||
| .leaf x => x
|
||||
| .branch p l r => if n < p then l.get n else r.get n
|
||||
|
||||
abbrev Context (α : Type u) := RArray α
|
||||
|
||||
def Var.denote (ctx : Context α) (v : Var) : α :=
|
||||
ctx.get v
|
||||
|
||||
def Expr.denote [CommRing α] (ctx : Context α) : Expr → α
|
||||
| .add a b => denote ctx a + denote ctx b
|
||||
| .sub a b => denote ctx a - denote ctx b
|
||||
| .mul a b => denote ctx a * denote ctx b
|
||||
| .neg a => -denote ctx a
|
||||
| .num k => k
|
||||
| .var v => v.denote ctx
|
||||
| .pow a k => denote ctx a ^ k
|
||||
|
||||
structure Power where
|
||||
x : Var
|
||||
k : Nat
|
||||
deriving BEq, Repr
|
||||
|
||||
def Power.varLt (p₁ p₂ : Power) : Bool :=
|
||||
p₁.x.blt p₂.x
|
||||
|
||||
def Power.denote [CommRing α] (ctx : Context α) : Power → α
|
||||
| {x, k} =>
|
||||
match k with
|
||||
| 0 => 1
|
||||
| 1 => x.denote ctx
|
||||
| k => x.denote ctx ^ k
|
||||
|
||||
inductive Mon where
|
||||
| leaf (p : Power)
|
||||
| cons (p : Power) (m : Mon)
|
||||
deriving BEq, Repr
|
||||
|
||||
def Mon.denote [CommRing α] (ctx : Context α) : Mon → α
|
||||
| .leaf p => p.denote ctx
|
||||
| .cons p m => p.denote ctx * denote ctx m
|
||||
|
||||
def Mon.denote' [CommRing α] (ctx : Context α) : Mon → α
|
||||
| .leaf p => p.denote ctx
|
||||
| .cons p m => go (p.denote ctx) m
|
||||
where
|
||||
go (acc : α) : Mon → α
|
||||
| .leaf p => acc * p.denote ctx
|
||||
| .cons p m => go (acc * p.denote ctx) m
|
||||
|
||||
def Mon.ofVar (x : Var) : Mon :=
|
||||
.leaf { x, k := 1 }
|
||||
|
||||
def Mon.concat (m₁ m₂ : Mon) : Mon :=
|
||||
match m₁ with
|
||||
| .leaf p => .cons p m₂
|
||||
| .cons p m₁ => .cons p (concat m₁ m₂)
|
||||
|
||||
def Mon.mulPow (p : Power) (m : Mon) : Mon :=
|
||||
match m with
|
||||
| .leaf p' =>
|
||||
bif p.varLt p' then
|
||||
.cons p m
|
||||
else bif p'.varLt p then
|
||||
.cons p' (.leaf p)
|
||||
else
|
||||
.leaf { x := p.x, k := p.k + p'.k }
|
||||
| .cons p' m =>
|
||||
bif p.varLt p' then
|
||||
.cons p (.cons p' m)
|
||||
else bif p'.varLt p then
|
||||
.cons p' (mulPow p m)
|
||||
else
|
||||
.cons { x := p.x, k := p.k + p'.k } m
|
||||
|
||||
def Mon.length : Mon → Nat
|
||||
| .leaf _ => 1
|
||||
| .cons _ m => 1 + length m
|
||||
|
||||
def hugeFuel := 1000000
|
||||
|
||||
def Mon.mul (m₁ m₂ : Mon) : Mon :=
|
||||
-- We could use `m₁.length + m₂.length` to avoid hugeFuel
|
||||
go hugeFuel m₁ m₂
|
||||
where
|
||||
go (fuel : Nat) (m₁ m₂ : Mon) : Mon :=
|
||||
match fuel with
|
||||
| 0 => concat m₁ m₂
|
||||
| fuel + 1 =>
|
||||
match m₁, m₂ with
|
||||
| m₁, .leaf p => m₁.mulPow p
|
||||
| .leaf p, m₂ => m₂.mulPow p
|
||||
| .cons p₁ m₁, .cons p₂ m₂ =>
|
||||
bif p₁.varLt p₂ then
|
||||
.cons p₁ (go fuel m₁ (.cons p₂ m₂))
|
||||
else bif p₂.varLt p₁ then
|
||||
.cons p₂ (go fuel (.cons p₁ m₁) m₂)
|
||||
else
|
||||
.cons { x := p₁.x, k := p₁.k + p₂.k } (go fuel m₁ m₂)
|
||||
|
||||
def Mon.degree : Mon → Nat
|
||||
| .leaf p => p.k
|
||||
| .cons p m => p.k + degree m
|
||||
|
||||
def Var.revlex (x y : Var) : Ordering :=
|
||||
bif x.blt y then .gt
|
||||
else bif y.blt x then .lt
|
||||
else .eq
|
||||
|
||||
def powerRevlex (k₁ k₂ : Nat) : Ordering :=
|
||||
bif k₁.blt k₂ then .gt
|
||||
else bif k₂.blt k₁ then .lt
|
||||
else .eq
|
||||
|
||||
def Power.revlex (p₁ p₂ : Power) : Ordering :=
|
||||
p₁.x.revlex p₂.x |>.then (powerRevlex p₁.k p₂.k)
|
||||
|
||||
def Mon.revlexWF (m₁ m₂ : Mon) : Ordering :=
|
||||
match m₁, m₂ with
|
||||
| .leaf p₁, .leaf p₂ => p₁.revlex p₂
|
||||
| .leaf p₁, .cons p₂ m₂ =>
|
||||
bif p₁.x.ble p₂.x then
|
||||
.gt
|
||||
else
|
||||
revlexWF (.leaf p₁) m₂ |>.then .gt
|
||||
| .cons p₁ m₁, .leaf p₂ =>
|
||||
bif p₂.x.ble p₁.x then
|
||||
.lt
|
||||
else
|
||||
revlexWF m₁ (.leaf p₂) |>.then .lt
|
||||
| .cons p₁ m₁, .cons p₂ m₂ =>
|
||||
bif p₁.x == p₂.x then
|
||||
revlexWF m₁ m₂ |>.then (powerRevlex p₁.k p₂.k)
|
||||
else bif p₁.x.blt p₂.x then
|
||||
revlexWF m₁ (.cons p₂ m₂) |>.then .gt
|
||||
else
|
||||
revlexWF (.cons p₁ m₁) m₂ |>.then .lt
|
||||
|
||||
def Mon.revlexFuel (fuel : Nat) (m₁ m₂ : Mon) : Ordering :=
|
||||
match fuel with
|
||||
| 0 =>
|
||||
-- This branch is not reachable in practice, but we add it here
|
||||
-- to ensure we can prove helper theorems
|
||||
revlexWF m₁ m₂
|
||||
| fuel + 1 =>
|
||||
match m₁, m₂ with
|
||||
| .leaf p₁, .leaf p₂ => p₁.revlex p₂
|
||||
| .leaf p₁, .cons p₂ m₂ =>
|
||||
bif p₁.x.ble p₂.x then
|
||||
.gt
|
||||
else
|
||||
revlexFuel fuel (.leaf p₁) m₂ |>.then .gt
|
||||
| .cons p₁ m₁, .leaf p₂ =>
|
||||
bif p₂.x.ble p₁.x then
|
||||
.lt
|
||||
else
|
||||
revlexFuel fuel m₁ (.leaf p₂) |>.then .lt
|
||||
| .cons p₁ m₁, .cons p₂ m₂ =>
|
||||
bif p₁.x == p₂.x then
|
||||
revlexFuel fuel m₁ m₂ |>.then (powerRevlex p₁.k p₂.k)
|
||||
else bif p₁.x.blt p₂.x then
|
||||
revlexFuel fuel m₁ (.cons p₂ m₂) |>.then .gt
|
||||
else
|
||||
revlexFuel fuel (.cons p₁ m₁) m₂ |>.then .lt
|
||||
|
||||
def Mon.revlex (m₁ m₂ : Mon) : Ordering :=
|
||||
revlexFuel hugeFuel m₁ m₂
|
||||
|
||||
def Mon.grevlex (m₁ m₂ : Mon) : Ordering :=
|
||||
compare m₁.degree m₂.degree |>.then (revlex m₁ m₂)
|
||||
|
||||
inductive Poly where
|
||||
| num (k : Int)
|
||||
| add (k : Int) (v : Mon) (p : Poly)
|
||||
deriving BEq
|
||||
|
||||
def Poly.denote [CommRing α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .num k => Int.cast k
|
||||
| .add k m p => Int.cast k * m.denote ctx + denote ctx p
|
||||
|
||||
def Poly.ofMon (m : Mon) : Poly :=
|
||||
.add 1 m (.num 0)
|
||||
|
||||
def Poly.ofVar (x : Var) : Poly :=
|
||||
ofMon (Mon.ofVar x)
|
||||
|
||||
def Poly.addConst (p : Poly) (k : Int) : Poly :=
|
||||
match p with
|
||||
| .num k' => .num (k' + k)
|
||||
| .add k' m p => .add k' m (addConst p k)
|
||||
|
||||
def Poly.insert (k : Int) (m : Mon) (p : Poly) : Poly :=
|
||||
match p with
|
||||
| .num k' => .add k m (.num k')
|
||||
| .add k' m' p =>
|
||||
match m.grevlex m' with
|
||||
| .eq =>
|
||||
let k'' := k + k'
|
||||
bif k'' == 0 then
|
||||
p
|
||||
else
|
||||
.add k'' m p
|
||||
| .lt => .add k m (.add k' m' p)
|
||||
| .gt => .add k' m' (insert k m p)
|
||||
|
||||
def Poly.concat (p₁ p₂ : Poly) : Poly :=
|
||||
match p₁ with
|
||||
| .num k₁ => p₂.addConst k₁
|
||||
| .add k m p₁ => .add k m (concat p₁ p₂)
|
||||
|
||||
def Poly.mulConst (k : Int) (p : Poly) : Poly :=
|
||||
bif k == 0 then
|
||||
.num 0
|
||||
else
|
||||
go p
|
||||
where
|
||||
go : Poly → Poly
|
||||
| .num k' => .num (k*k')
|
||||
| .add k' m p => .add (k*k') m (go p)
|
||||
|
||||
def Poly.mulMon (k : Int) (m : Mon) (p : Poly) : Poly :=
|
||||
bif k == 0 then
|
||||
.num 0
|
||||
else
|
||||
go p
|
||||
where
|
||||
go : Poly → Poly
|
||||
| .num k' => .add (k*k') m (.num 0)
|
||||
| .add k' m' p => .add (k*k') (m.mul m') (go p)
|
||||
|
||||
def Poly.combine (p₁ p₂ : Poly) : Poly :=
|
||||
go hugeFuel p₁ p₂
|
||||
where
|
||||
go (fuel : Nat) (p₁ p₂ : Poly) : Poly :=
|
||||
match fuel with
|
||||
| 0 => p₁.concat p₂
|
||||
| fuel + 1 => match p₁, p₂ with
|
||||
| .num k₁, .num k₂ => .num (k₁ + k₂)
|
||||
| .num k₁, .add k₂ m₂ p₂ => addConst (.add k₂ m₂ p₂) k₁
|
||||
| .add k₁ m₁ p₁, .num k₂ => addConst (.add k₁ m₁ p₁) k₂
|
||||
| .add k₁ m₁ p₁, .add k₂ m₂ p₂ =>
|
||||
match m₁.grevlex m₂ with
|
||||
| .eq =>
|
||||
let k := k₁ + k₂
|
||||
bif k == 0 then
|
||||
go fuel p₁ p₂
|
||||
else
|
||||
.add k m₁ (go fuel p₁ p₂)
|
||||
| .lt => .add k₁ m₁ (go fuel p₁ (.add k₂ m₂ p₂))
|
||||
| .gt => .add k₂ m₂ (go fuel (.add k₁ m₁ p₁) p₂)
|
||||
|
||||
def Poly.mul (p₁ : Poly) (p₂ : Poly) : Poly :=
|
||||
go p₁ (.num 0)
|
||||
where
|
||||
go (p₁ : Poly) (acc : Poly) : Poly :=
|
||||
match p₁ with
|
||||
| .num k => acc.combine (p₂.mulConst k)
|
||||
| .add k m p₁ => go p₁ (acc.combine (p₂.mulMon k m))
|
||||
|
||||
-- TODO: optimize
|
||||
def Poly.pow (p : Poly) (k : Nat) : Poly :=
|
||||
match k with
|
||||
| 0 => .num 1
|
||||
| 1 => p
|
||||
| k+1 => p.mul (pow p k)
|
||||
|
||||
def Expr.toPoly : Expr → Poly
|
||||
| .num n => .num n
|
||||
| .var x => Poly.ofVar x
|
||||
| .add a b => a.toPoly.combine b.toPoly
|
||||
| .mul a b => a.toPoly.mul b.toPoly
|
||||
| .neg a => a.toPoly.mulConst (-1)
|
||||
| .sub a b => a.toPoly.combine (b.toPoly.mulConst (-1))
|
||||
| .pow a k =>
|
||||
match a with
|
||||
| .num n => .num (n^k)
|
||||
| .var x => Poly.ofMon (.leaf {x, k})
|
||||
| _ => a.toPoly.pow k
|
||||
|
||||
theorem Power.denote_eq [CommRing α] (ctx : Context α) (p : Power)
|
||||
: p.denote ctx = p.x.denote ctx ^ p.k := by
|
||||
cases p <;> simp [Power.denote] <;> split <;> simp [pow_zero, pow_succ, one_mul]
|
||||
|
||||
theorem Mon.denote'_go_eq_denote [CommRing α] (ctx : Context α) (a : α) (m : Mon)
|
||||
: denote'.go ctx a m = a * denote ctx m := by
|
||||
induction m generalizing a <;> simp [Mon.denote, Mon.denote'.go]
|
||||
next p' m ih =>
|
||||
simp [Mon.denote] at ih
|
||||
rw [ih, mul_assoc]
|
||||
|
||||
theorem Mon.denote'_eq_denote [CommRing α] (ctx : Context α) (m : Mon)
|
||||
: denote' ctx m = denote ctx m := by
|
||||
cases m <;> simp [Mon.denote, Mon.denote']
|
||||
next p m => apply denote'_go_eq_denote
|
||||
|
||||
theorem Mon.denote_ofVar [CommRing α] (ctx : Context α) (x : Var)
|
||||
: denote ctx (ofVar x) = x.denote ctx := by
|
||||
simp [denote, ofVar, Power.denote_eq, pow_succ, pow_zero, one_mul]
|
||||
|
||||
theorem Mon.denote_concat [CommRing α] (ctx : Context α) (m₁ m₂ : Mon)
|
||||
: denote ctx (concat m₁ m₂) = m₁.denote ctx * m₂.denote ctx := by
|
||||
induction m₁ <;> simp [concat, denote, *]
|
||||
next p₁ m₁ ih => rw [mul_assoc]
|
||||
|
||||
private theorem le_of_blt_false {a b : Nat} : a.blt b = false → b ≤ a := by
|
||||
intro h; apply Nat.le_of_not_gt; show ¬a < b
|
||||
rw [← Nat.blt_eq, h]; simp
|
||||
|
||||
private theorem eq_of_blt_false {a b : Nat} : a.blt b = false → b.blt a = false → a = b := by
|
||||
intro h₁ h₂
|
||||
replace h₁ := le_of_blt_false h₁
|
||||
replace h₂ := le_of_blt_false h₂
|
||||
exact Nat.le_antisymm h₂ h₁
|
||||
|
||||
theorem Mon.denote_mulPow [CommRing α] (ctx : Context α) (p : Power) (m : Mon)
|
||||
: denote ctx (mulPow p m) = p.denote ctx * m.denote ctx := by
|
||||
fun_induction mulPow <;> simp [mulPow, *]
|
||||
next => simp [denote]
|
||||
next => simp [denote]; rw [mul_comm]
|
||||
next p' h₁ h₂ =>
|
||||
have := eq_of_blt_false h₁ h₂
|
||||
simp [denote, Power.denote_eq, this, pow_add]
|
||||
next => simp [denote]
|
||||
next => simp [denote, mul_assoc, mul_comm, mul_left_comm, *]
|
||||
next h₁ h₂ =>
|
||||
have := eq_of_blt_false h₁ h₂
|
||||
simp [denote, Power.denote_eq, pow_add, this, mul_assoc]
|
||||
|
||||
theorem Mon.denote_mul [CommRing α] (ctx : Context α) (m₁ m₂ : Mon)
|
||||
: denote ctx (mul m₁ m₂) = m₁.denote ctx * m₂.denote ctx := by
|
||||
unfold mul
|
||||
generalize hugeFuel = fuel
|
||||
fun_induction mul.go <;> simp [mul.go, denote, denote_concat, denote_mulPow, *]
|
||||
next => rw [mul_comm]
|
||||
next => simp [mul_assoc]
|
||||
next => simp [mul_assoc, mul_left_comm, mul_comm]
|
||||
next h₁ h₂ _ =>
|
||||
have := eq_of_blt_false h₁ h₂
|
||||
simp [Power.denote_eq, pow_add, mul_assoc, mul_left_comm, mul_comm, this]
|
||||
|
||||
theorem Var.eq_of_revlex {x₁ x₂ : Var} : x₁.revlex x₂ = .eq → x₁ = x₂ := by
|
||||
simp [revlex, cond_eq_if] <;> split <;> simp
|
||||
next h₁ => intro h₂; exact Nat.le_antisymm h₂ (Nat.ge_of_not_lt h₁)
|
||||
|
||||
theorem eq_of_powerRevlex {k₁ k₂ : Nat} : powerRevlex k₁ k₂ = .eq → k₁ = k₂ := by
|
||||
simp [powerRevlex, cond_eq_if] <;> split <;> simp
|
||||
next h₁ => intro h₂; exact Nat.le_antisymm h₂ (Nat.ge_of_not_lt h₁)
|
||||
|
||||
theorem Power.eq_of_revlex (p₁ p₂ : Power) : p₁.revlex p₂ = .eq → p₁ = p₂ := by
|
||||
cases p₁; cases p₂; simp [revlex, Ordering.then]; split
|
||||
next h₁ => intro h₂; simp [Var.eq_of_revlex h₁, eq_of_powerRevlex h₂]
|
||||
next h₁ => intro h₂; simp [h₂] at h₁
|
||||
|
||||
private theorem then_gt (o : Ordering) : ¬ o.then .gt = .eq := by
|
||||
cases o <;> simp [Ordering.then]
|
||||
|
||||
private theorem then_lt (o : Ordering) : ¬ o.then .lt = .eq := by
|
||||
cases o <;> simp [Ordering.then]
|
||||
|
||||
private theorem then_eq (o₁ o₂ : Ordering) : o₁.then o₂ = .eq ↔ o₁ = .eq ∧ o₂ = .eq := by
|
||||
cases o₁ <;> cases o₂ <;> simp [Ordering.then]
|
||||
|
||||
theorem Mon.eq_of_revlexWF {m₁ m₂ : Mon} : m₁.revlexWF m₂ = .eq → m₁ = m₂ := by
|
||||
fun_induction revlexWF <;> simp [revlexWF, *, then_gt, then_lt, then_eq]
|
||||
next => apply Power.eq_of_revlex
|
||||
next p₁ m₁ p₂ m₂ h ih =>
|
||||
cases p₁; cases p₂; intro h₁ h₂; simp [ih h₁, h]
|
||||
simp at h h₂
|
||||
simp [h, eq_of_powerRevlex h₂]
|
||||
|
||||
theorem Mon.eq_of_revlexFuel {fuel : Nat} {m₁ m₂ : Mon} : revlexFuel fuel m₁ m₂ = .eq → m₁ = m₂ := by
|
||||
fun_induction revlexFuel <;> simp [revlexFuel, *, then_gt, then_lt, then_eq]
|
||||
next => apply eq_of_revlexWF
|
||||
next => apply Power.eq_of_revlex
|
||||
next p₁ m₁ p₂ m₂ h ih =>
|
||||
cases p₁; cases p₂; intro h₁ h₂; simp [ih h₁, h]
|
||||
simp at h h₂
|
||||
simp [h, eq_of_powerRevlex h₂]
|
||||
|
||||
theorem Mon.eq_of_revlex {m₁ m₂ : Mon} : revlex m₁ m₂ = .eq → m₁ = m₂ := by
|
||||
apply eq_of_revlexFuel
|
||||
|
||||
theorem Mon.eq_of_grevlex {m₁ m₂ : Mon} : grevlex m₁ m₂ = .eq → m₁ = m₂ := by
|
||||
simp [grevlex, then_eq]; intro; apply eq_of_revlex
|
||||
|
||||
theorem Poly.denote_ofMon [CommRing α] (ctx : Context α) (m : Mon)
|
||||
: denote ctx (ofMon m) = m.denote ctx := by
|
||||
simp [ofMon, denote, intCast_one, intCast_zero, one_mul, add_zero]
|
||||
|
||||
theorem Poly.denote_ofVar [CommRing α] (ctx : Context α) (x : Var)
|
||||
: denote ctx (ofVar x) = x.denote ctx := by
|
||||
simp [ofVar, denote_ofMon, Mon.denote_ofVar]
|
||||
|
||||
theorem Poly.denote_addConst [CommRing α] (ctx : Context α) (p : Poly) (k : Int) : (addConst p k).denote ctx = p.denote ctx + k := by
|
||||
fun_induction addConst <;> simp [addConst, denote, *]
|
||||
next => rw [intCast_add]
|
||||
next => simp [add_comm, add_left_comm, add_assoc]
|
||||
|
||||
theorem Poly.denote_insert [CommRing α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (insert k m p).denote ctx = k * m.denote ctx + p.denote ctx := by
|
||||
fun_induction insert <;> simp_all +zetaDelta [insert, denote, cond_eq_if]
|
||||
next h₁ _ h₂ =>
|
||||
rw [← add_assoc, Mon.eq_of_grevlex h₁, ← right_distrib, ← intCast_add, h₂, intCast_zero, zero_mul, zero_add]
|
||||
next h₁ _ _ =>
|
||||
rw [intCast_add, right_distrib, add_assoc, Mon.eq_of_grevlex h₁]
|
||||
next =>
|
||||
rw [add_left_comm]
|
||||
|
||||
theorem Poly.denote_concat [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (concat p₁ p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
fun_induction concat <;> simp [concat, *, denote_addConst, denote]
|
||||
next => rw [add_comm]
|
||||
next => rw [add_assoc]
|
||||
|
||||
theorem Poly.denote_mulConst [CommRing α] (ctx : Context α) (k : Int) (p : Poly)
|
||||
: (mulConst k p).denote ctx = k * p.denote ctx := by
|
||||
simp [mulConst, cond_eq_if] <;> split
|
||||
next => simp [denote, *, intCast_zero, zero_mul]
|
||||
next =>
|
||||
fun_induction mulConst.go <;> simp [mulConst.go, denote, *]
|
||||
next => rw [intCast_mul]
|
||||
next => rw [intCast_mul, left_distrib, mul_assoc]
|
||||
|
||||
theorem Poly.denote_mulMon [CommRing α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (mulMon k m p).denote ctx = k * m.denote ctx * p.denote ctx := by
|
||||
simp [mulMon, cond_eq_if] <;> split
|
||||
next => simp [denote, *, intCast_zero, zero_mul]
|
||||
next =>
|
||||
fun_induction mulMon.go <;> simp [mulMon.go, denote, *]
|
||||
next => simp [intCast_mul, intCast_zero, add_zero, mul_comm, mul_left_comm, mul_assoc]
|
||||
next => simp [Mon.denote_mul, intCast_mul, left_distrib, mul_comm, mul_left_comm, mul_assoc]
|
||||
|
||||
theorem Poly.denote_combine [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (combine p₁ p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
unfold combine; generalize hugeFuel = fuel
|
||||
fun_induction combine.go
|
||||
<;> simp [combine.go, *, denote_concat, denote_addConst, denote, intCast_add, cond_eq_if, add_comm, add_left_comm, add_assoc]
|
||||
next hg _ h _ =>
|
||||
simp +zetaDelta at h; simp [*]
|
||||
rw [← add_assoc, Mon.eq_of_grevlex hg, ← right_distrib, ← intCast_add, h, intCast_zero, zero_mul, zero_add]
|
||||
next hg _ h _ =>
|
||||
simp +zetaDelta at h; simp [*, denote, intCast_add]
|
||||
rw [right_distrib, Mon.eq_of_grevlex hg, add_assoc]
|
||||
|
||||
theorem Poly.denote_mul_go [CommRing α] (ctx : Context α) (p₁ p₂ acc : Poly)
|
||||
: (mul.go p₂ p₁ acc).denote ctx = acc.denote ctx + p₁.denote ctx * p₂.denote ctx := by
|
||||
fun_induction mul.go
|
||||
<;> simp [mul.go, denote_combine, denote_mulConst, denote, *, right_distrib, denote_mulMon, add_assoc]
|
||||
|
||||
theorem Poly.denote_mul [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (mul p₁ p₂).denote ctx = p₁.denote ctx * p₂.denote ctx := by
|
||||
simp [mul, denote_mul_go, denote, intCast_zero, zero_add]
|
||||
|
||||
theorem Poly.denote_pow [CommRing α] (ctx : Context α) (p : Poly) (k : Nat)
|
||||
: (pow p k).denote ctx = p.denote ctx ^ k := by
|
||||
fun_induction pow <;> simp [pow, denote, intCast_one, pow_zero]
|
||||
next => simp [pow_succ, pow_zero, one_mul]
|
||||
next => simp [denote_mul, *, pow_succ, mul_comm]
|
||||
|
||||
theorem Expr.denote_toPoly [CommRing α] (ctx : Context α) (e : Expr)
|
||||
: e.toPoly.denote ctx = e.denote ctx := by
|
||||
fun_induction toPoly
|
||||
<;> simp [toPoly, denote, Poly.denote, Poly.denote_ofVar, Poly.denote_combine,
|
||||
Poly.denote_mul, Poly.denote_mulConst, Poly.denote_pow, *]
|
||||
next => rw [intCast_neg, neg_mul, intCast_one, one_mul]
|
||||
next => rw [intCast_neg, neg_mul, intCast_one, one_mul, sub_eq_add_neg]
|
||||
next => rw [intCast_pow]
|
||||
next => simp [Poly.denote_ofMon, Mon.denote, Power.denote_eq]
|
||||
|
||||
end CommRing
|
||||
end Lean.Grind
|
||||
@@ -7,6 +7,53 @@ prelude
|
||||
import Init.Grind.CommRing.Basic
|
||||
import Init.Data.UInt.Lemmas
|
||||
|
||||
|
||||
namespace UInt8
|
||||
|
||||
/-- Variant of `UInt8.ofNat_mod_size` replacing `2 ^ 8` with `256`.-/
|
||||
theorem ofNat_mod_size' : ofNat (x % 256) = ofNat x := ofNat_mod_size
|
||||
|
||||
instance : IntCast UInt8 where
|
||||
intCast x := UInt8.ofInt x
|
||||
|
||||
end UInt8
|
||||
|
||||
namespace UInt16
|
||||
|
||||
/-- Variant of `UInt16.ofNat_mod_size` replacing `2 ^ 16` with `65536`.-/
|
||||
theorem ofNat_mod_size' : ofNat (x % 65536) = ofNat x := ofNat_mod_size
|
||||
|
||||
instance : IntCast UInt16 where
|
||||
intCast x := UInt16.ofInt x
|
||||
|
||||
end UInt16
|
||||
|
||||
namespace UInt32
|
||||
|
||||
/-- Variant of `UInt32.ofNat_mod_size` replacing `2 ^ 32` with `4294967296`.-/
|
||||
theorem ofNat_mod_size' : ofNat (x % 4294967296) = ofNat x := ofNat_mod_size
|
||||
|
||||
instance : IntCast UInt32 where
|
||||
intCast x := UInt32.ofInt x
|
||||
|
||||
end UInt32
|
||||
|
||||
namespace UInt64
|
||||
|
||||
/-- Variant of `UInt64.ofNat_mod_size` replacing `2 ^ 64` with `18446744073709551616`.-/
|
||||
theorem ofNat_mod_size' : ofNat (x % 18446744073709551616) = ofNat x := ofNat_mod_size
|
||||
|
||||
instance : IntCast UInt64 where
|
||||
intCast x := UInt64.ofInt x
|
||||
|
||||
end UInt64
|
||||
|
||||
namespace USize
|
||||
|
||||
instance : IntCast USize where
|
||||
intCast x := USize.ofInt x
|
||||
|
||||
end USize
|
||||
namespace Lean.Grind
|
||||
|
||||
instance : CommRing UInt8 where
|
||||
@@ -19,6 +66,15 @@ instance : CommRing UInt8 where
|
||||
mul_one := UInt8.mul_one
|
||||
left_distrib _ _ _ := UInt8.mul_add
|
||||
zero_mul _ := UInt8.zero_mul
|
||||
sub_eq_add_neg := UInt8.sub_eq_add_neg
|
||||
pow_zero := UInt8.pow_zero
|
||||
pow_succ := UInt8.pow_succ
|
||||
ofNat_succ x := UInt8.ofNat_add x 1
|
||||
|
||||
instance : IsCharP UInt8 (2 ^ 8) where
|
||||
ofNat_eq_zero_iff {x} := by
|
||||
have : OfNat.ofNat x = UInt8.ofNat x := rfl
|
||||
simp [this, UInt8.ofNat_eq_iff_mod_eq_toNat]
|
||||
|
||||
instance : CommRing UInt16 where
|
||||
add_assoc := UInt16.add_assoc
|
||||
@@ -30,6 +86,15 @@ instance : CommRing UInt16 where
|
||||
mul_one := UInt16.mul_one
|
||||
left_distrib _ _ _ := UInt16.mul_add
|
||||
zero_mul _ := UInt16.zero_mul
|
||||
sub_eq_add_neg := UInt16.sub_eq_add_neg
|
||||
pow_zero := UInt16.pow_zero
|
||||
pow_succ := UInt16.pow_succ
|
||||
ofNat_succ x := UInt16.ofNat_add x 1
|
||||
|
||||
instance : IsCharP UInt16 (2 ^ 16) where
|
||||
ofNat_eq_zero_iff {x} := by
|
||||
have : OfNat.ofNat x = UInt16.ofNat x := rfl
|
||||
simp [this, UInt16.ofNat_eq_iff_mod_eq_toNat]
|
||||
|
||||
instance : CommRing UInt32 where
|
||||
add_assoc := UInt32.add_assoc
|
||||
@@ -41,6 +106,15 @@ instance : CommRing UInt32 where
|
||||
mul_one := UInt32.mul_one
|
||||
left_distrib _ _ _ := UInt32.mul_add
|
||||
zero_mul _ := UInt32.zero_mul
|
||||
sub_eq_add_neg := UInt32.sub_eq_add_neg
|
||||
pow_zero := UInt32.pow_zero
|
||||
pow_succ := UInt32.pow_succ
|
||||
ofNat_succ x := UInt32.ofNat_add x 1
|
||||
|
||||
instance : IsCharP UInt32 (2 ^ 32) where
|
||||
ofNat_eq_zero_iff {x} := by
|
||||
have : OfNat.ofNat x = UInt32.ofNat x := rfl
|
||||
simp [this, UInt32.ofNat_eq_iff_mod_eq_toNat]
|
||||
|
||||
instance : CommRing UInt64 where
|
||||
add_assoc := UInt64.add_assoc
|
||||
@@ -52,6 +126,15 @@ instance : CommRing UInt64 where
|
||||
mul_one := UInt64.mul_one
|
||||
left_distrib _ _ _ := UInt64.mul_add
|
||||
zero_mul _ := UInt64.zero_mul
|
||||
sub_eq_add_neg := UInt64.sub_eq_add_neg
|
||||
pow_zero := UInt64.pow_zero
|
||||
pow_succ := UInt64.pow_succ
|
||||
ofNat_succ x := UInt64.ofNat_add x 1
|
||||
|
||||
instance : IsCharP UInt64 (2 ^ 64) where
|
||||
ofNat_eq_zero_iff {x} := by
|
||||
have : OfNat.ofNat x = UInt64.ofNat x := rfl
|
||||
simp [this, UInt64.ofNat_eq_iff_mod_eq_toNat]
|
||||
|
||||
instance : CommRing USize where
|
||||
add_assoc := USize.add_assoc
|
||||
@@ -63,5 +146,16 @@ instance : CommRing USize where
|
||||
mul_one := USize.mul_one
|
||||
left_distrib _ _ _ := USize.mul_add
|
||||
zero_mul _ := USize.zero_mul
|
||||
sub_eq_add_neg := USize.sub_eq_add_neg
|
||||
pow_zero := USize.pow_zero
|
||||
pow_succ := USize.pow_succ
|
||||
ofNat_succ x := USize.ofNat_add x 1
|
||||
|
||||
open System.Platform
|
||||
|
||||
instance : IsCharP USize (2 ^ numBits) where
|
||||
ofNat_eq_zero_iff {x} := by
|
||||
have : OfNat.ofNat x = USize.ofNat x := rfl
|
||||
simp [this, USize.ofNat_eq_iff_mod_eq_toNat]
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
10
src/Init/Grind/Ext.lean
Normal file
10
src/Init/Grind/Ext.lean
Normal file
@@ -0,0 +1,10 @@
|
||||
/-
|
||||
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.Ext
|
||||
import Init.Grind.Tactics
|
||||
|
||||
attribute [grind ext] funext
|
||||
@@ -165,4 +165,9 @@ theorem of_decide_eq_false {p : Prop} {_ : Decidable p} : decide p = false → p
|
||||
theorem decide_eq_true {p : Prop} {_ : Decidable p} : p = True → decide p = true := by simp
|
||||
theorem decide_eq_false {p : Prop} {_ : Decidable p} : p = False → decide p = false := by simp
|
||||
|
||||
/-! Lookahead -/
|
||||
|
||||
theorem of_lookahead (p : Prop) (h : (¬ p) → False) : p = True := by
|
||||
simp at h; simp [h]
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -74,11 +74,11 @@ theorem bne_eq_decide_not_eq {_ : BEq α} [LawfulBEq α] [DecidableEq α] (a b :
|
||||
theorem xor_eq (a b : Bool) : (a ^^ b) = (a != b) := by
|
||||
rfl
|
||||
|
||||
theorem natCast_div (a b : Nat) : (↑(a / b) : Int) = ↑a / ↑b := by
|
||||
rfl
|
||||
|
||||
theorem natCast_mod (a b : Nat) : (↑(a % b) : Int) = ↑a % ↑b := by
|
||||
rfl
|
||||
theorem natCast_eq [NatCast α] (a : Nat) : (Nat.cast a : α) = (NatCast.natCast a : α) := rfl
|
||||
theorem natCast_div (a b : Nat) : (NatCast.natCast (a / b) : Int) = (NatCast.natCast a) / (NatCast.natCast b) := rfl
|
||||
theorem natCast_mod (a b : Nat) : (NatCast.natCast (a % b) : Int) = (NatCast.natCast a) % (NatCast.natCast b) := rfl
|
||||
theorem natCast_add (a b : Nat) : (NatCast.natCast (a + b : Nat) : Int) = (NatCast.natCast a : Int) + (NatCast.natCast b : Int) := rfl
|
||||
theorem natCast_mul (a b : Nat) : (NatCast.natCast (a * b : Nat) : Int) = (NatCast.natCast a : Int) * (NatCast.natCast b : Int) := rfl
|
||||
|
||||
theorem Nat.pow_one (a : Nat) : a ^ 1 = a := by
|
||||
simp
|
||||
@@ -153,8 +153,10 @@ init_grind_norm
|
||||
Int.emod_neg Int.ediv_neg
|
||||
Int.ediv_zero Int.emod_zero
|
||||
Int.ediv_one Int.emod_one
|
||||
Int.natCast_add Int.natCast_mul Int.natCast_pow
|
||||
Int.natCast_zero natCast_div natCast_mod
|
||||
|
||||
natCast_eq natCast_div natCast_mod
|
||||
natCast_add natCast_mul
|
||||
|
||||
Int.pow_zero Int.pow_one
|
||||
-- GT GE
|
||||
ge_eq gt_eq
|
||||
|
||||
@@ -25,7 +25,8 @@ syntax grindUsr := &"usr "
|
||||
syntax grindCases := &"cases "
|
||||
syntax grindCasesEager := atomic(&"cases" &"eager ")
|
||||
syntax grindIntro := &"intro "
|
||||
syntax grindMod := grindEqBoth <|> grindEqRhs <|> grindEq <|> grindEqBwd <|> grindBwd <|> grindFwd <|> grindRL <|> grindLR <|> grindUsr <|> grindCasesEager <|> grindCases <|> grindIntro
|
||||
syntax grindExt := &"ext "
|
||||
syntax grindMod := grindEqBoth <|> grindEqRhs <|> grindEq <|> grindEqBwd <|> grindBwd <|> grindFwd <|> grindRL <|> grindLR <|> grindUsr <|> grindCasesEager <|> grindCases <|> grindIntro <|> grindExt
|
||||
syntax (name := grind) "grind" (grindMod)? : attr
|
||||
end Attr
|
||||
end Lean.Parser
|
||||
@@ -68,8 +69,17 @@ structure Config where
|
||||
failures : Nat := 1
|
||||
/-- Maximum number of heartbeats (in thousands) the canonicalizer can spend per definitional equality test. -/
|
||||
canonHeartbeats : Nat := 1000
|
||||
/-- If `ext` is `true`, `grind` uses extensionality theorems available in the environment. -/
|
||||
/-- If `ext` is `true`, `grind` uses extensionality theorems that have been marked with `[grind ext]`. -/
|
||||
ext : Bool := true
|
||||
/-- If `extAll` is `true`, `grind` uses any extensionality theorems available in the environment. -/
|
||||
extAll : Bool := false
|
||||
/--
|
||||
If `funext` is `true`, `grind` creates new opportunities for applying function extensionality by case-splitting
|
||||
on equalities between lambda expressions.
|
||||
-/
|
||||
funext : Bool := true
|
||||
/-- TODO -/
|
||||
lookahead : Bool := true
|
||||
/-- If `verbose` is `false`, additional diagnostics information is not collected. -/
|
||||
verbose : Bool := true
|
||||
/-- If `clean` is `true`, `grind` uses `expose_names` and only generates accessible names. -/
|
||||
|
||||
@@ -275,6 +275,14 @@ class MonadNameGenerator (m : Type → Type) where
|
||||
|
||||
export MonadNameGenerator (getNGen setNGen)
|
||||
|
||||
/--
|
||||
Creates a globally unique `Name`, without any semantic interpretation.
|
||||
The names are not intended to be user-visible.
|
||||
With the default name generator, names use `_uniq` as a base and have a numeric suffix.
|
||||
|
||||
This is used for example by `Lean.mkFreshFVarId`, `Lean.mkFreshMVarId`, and `Lean.mkFreshLMVarId`.
|
||||
To create fresh user-visible identifiers, use functions such as `Lean.Core.mkFreshUserName` instead.
|
||||
-/
|
||||
def mkFreshId {m : Type → Type} [Monad m] [MonadNameGenerator m] : m Name := do
|
||||
let ngen ← getNGen
|
||||
let r := ngen.curr
|
||||
|
||||
@@ -286,7 +286,7 @@ theorem gcd_cons_div_right : gcd (x::xs) ∣ gcd xs := by
|
||||
apply Nat.gcd_dvd_right
|
||||
|
||||
theorem gcd_cons_div_right' : (gcd (x::xs) : Int) ∣ (gcd xs : Int) := by
|
||||
rw [Int.ofNat_dvd_left, Int.natAbs_ofNat]
|
||||
rw [Int.ofNat_dvd_left, Int.natAbs_natCast]
|
||||
exact gcd_cons_div_right
|
||||
|
||||
theorem gcd_dvd (xs : IntList) {a : Int} (m : a ∈ xs) : (xs.gcd : Int) ∣ a := by
|
||||
|
||||
@@ -1003,7 +1003,7 @@ class BEq (α : Type u) where
|
||||
|
||||
open BEq (beq)
|
||||
|
||||
instance [DecidableEq α] : BEq α where
|
||||
instance (priority := 500) [DecidableEq α] : BEq α where
|
||||
beq a b := decide (Eq a b)
|
||||
|
||||
|
||||
|
||||
@@ -287,8 +287,8 @@ theorem not_decide_eq_true [h : Decidable p] : ((!decide p) = true) = ¬ p := by
|
||||
@[simp] theorem cond_true (a b : α) : cond true a b = a := rfl
|
||||
@[simp] theorem cond_false (a b : α) : cond false a b = b := rfl
|
||||
|
||||
@[simp] theorem beq_self_eq_true [BEq α] [LawfulBEq α] (a : α) : (a == a) = true := LawfulBEq.rfl
|
||||
theorem beq_self_eq_true' [DecidableEq α] (a : α) : (a == a) = true := by simp
|
||||
theorem beq_self_eq_true [BEq α] [ReflBEq α] (a : α) : (a == a) = true := BEq.rfl
|
||||
theorem beq_self_eq_true' [DecidableEq α] (a : α) : (a == a) = true := BEq.rfl
|
||||
|
||||
@[simp] theorem bne_self_eq_false [BEq α] [LawfulBEq α] (a : α) : (a != a) = false := by simp [bne]
|
||||
theorem bne_self_eq_false' [DecidableEq α] (a : α) : (a != a) = false := by simp
|
||||
|
||||
@@ -1355,6 +1355,8 @@ structure SpawnArgs extends StdioConfig where
|
||||
and `some` sets the variable to the new value, adding it if necessary. Variables are processed from left to right.
|
||||
-/
|
||||
env : Array (String × Option String) := #[]
|
||||
/-- Inherit environment variables from the spawning process. -/
|
||||
inheritEnv : Bool := true
|
||||
/--
|
||||
Starts the child process in a new session and process group using `setsid`. Currently a no-op on
|
||||
non-POSIX platforms.
|
||||
|
||||
@@ -819,12 +819,12 @@ The left hand side of an induction arm, `| foo a b c` or `| @foo a b c`
|
||||
where `foo` is a constructor of the inductive type and `a b c` are the arguments
|
||||
to the constructor.
|
||||
-/
|
||||
syntax inductionAltLHS := "| " (("@"? ident) <|> hole) (ident <|> hole)*
|
||||
syntax inductionAltLHS := withPosition("| " (("@"? ident) <|> hole) (colGt (ident <|> hole))*)
|
||||
/--
|
||||
In induction alternative, which can have 1 or more cases on the left
|
||||
and `_`, `?_`, or a tactic sequence after the `=>`.
|
||||
-/
|
||||
syntax inductionAlt := ppDedent(ppLine) inductionAltLHS+ " => " (hole <|> syntheticHole <|> tacticSeq)
|
||||
syntax inductionAlt := ppDedent(ppLine) inductionAltLHS+ (" => " (hole <|> syntheticHole <|> tacticSeq))?
|
||||
/--
|
||||
After `with`, there is an optional tactic that runs on all branches, and
|
||||
then a list of alternatives.
|
||||
@@ -1752,7 +1752,7 @@ attribute @[simp ←] and_assoc
|
||||
```
|
||||
|
||||
When multiple simp theorems are applicable, the simplifier uses the one with highest priority.
|
||||
The equational theorems of function are applied at very low priority (100 and below).
|
||||
The equational theorems of functions are applied at very low priority (100 and below).
|
||||
If there are several with the same priority, it is uses the "most recent one". Example:
|
||||
```lean
|
||||
@[simp high] theorem cond_true (a b : α) : cond true a b = a := rfl
|
||||
|
||||
@@ -17,9 +17,16 @@ private opaque getLeancExtraFlags : Unit → String
|
||||
private def flagsStringToArray (s : String) : Array String :=
|
||||
s.splitOn.toArray |>.filter (· ≠ "")
|
||||
|
||||
/--
|
||||
Return C compiler flags for including Lean's headers.
|
||||
Unlike `getCFlags`, this does not contain the Lean include directory.
|
||||
-/
|
||||
def getCFlags' : Array String :=
|
||||
flagsStringToArray (getLeancExtraFlags ())
|
||||
|
||||
/-- Return C compiler flags for including Lean's headers. -/
|
||||
def getCFlags (leanSysroot : FilePath) : Array String :=
|
||||
#["-I", (leanSysroot / "include").toString] ++ flagsStringToArray (getLeancExtraFlags ())
|
||||
#["-I", (leanSysroot / "include").toString] ++ getCFlags'
|
||||
|
||||
@[extern "lean_get_leanc_internal_flags"]
|
||||
private opaque getLeancInternalFlags : Unit → String
|
||||
@@ -31,9 +38,16 @@ def getInternalCFlags (leanSysroot : FilePath) : Array String :=
|
||||
@[extern "lean_get_linker_flags"]
|
||||
private opaque getBuiltinLinkerFlags (linkStatic : Bool) : String
|
||||
|
||||
/--
|
||||
Return linker flags for linking against Lean's libraries.
|
||||
Unlike `getLinkerFlags`, this does not contain the Lean library directory.
|
||||
-/
|
||||
def getLinkerFlags' (linkStatic := true) : Array String :=
|
||||
flagsStringToArray (getBuiltinLinkerFlags linkStatic)
|
||||
|
||||
/-- Return linker flags for linking against Lean's libraries. -/
|
||||
def getLinkerFlags (leanSysroot : FilePath) (linkStatic := true) : Array String :=
|
||||
#["-L", (leanSysroot / "lib" / "lean").toString] ++ flagsStringToArray (getBuiltinLinkerFlags linkStatic)
|
||||
#["-L", (leanSysroot / "lib" / "lean").toString] ++ getLinkerFlags' linkStatic
|
||||
|
||||
@[extern "lean_get_internal_linker_flags"]
|
||||
private opaque getBuiltinInternalLinkerFlags : Unit → String
|
||||
|
||||
@@ -44,7 +44,7 @@ def replaceFun (decl : FunDecl) (fvarId : FVarId) : M Unit := do
|
||||
eraseFunDecl decl
|
||||
addFVarSubst decl.fvarId fvarId
|
||||
|
||||
partial def _root_.Lean.Compiler.LCNF.Code.cse (code : Code) : CompilerM Code :=
|
||||
partial def _root_.Lean.Compiler.LCNF.Code.cse (shouldElimFunDecls : Bool) (code : Code) : CompilerM Code :=
|
||||
go code |>.run' {}
|
||||
where
|
||||
goFunDecl (decl : FunDecl) : M FunDecl := do
|
||||
@@ -67,14 +67,18 @@ where
|
||||
addEntry key decl.fvarId
|
||||
return code.updateLet! decl (← go k)
|
||||
| .fun decl k =>
|
||||
let decl ← goFunDecl decl
|
||||
let value := decl.toExpr
|
||||
match (← get).map.find? value with
|
||||
| some fvarId' =>
|
||||
replaceFun decl fvarId'
|
||||
go k
|
||||
| none =>
|
||||
addEntry value decl.fvarId
|
||||
if shouldElimFunDecls then
|
||||
let decl ← goFunDecl decl
|
||||
let value := decl.toExpr
|
||||
match (← get).map.find? value with
|
||||
| some fvarId' =>
|
||||
replaceFun decl fvarId'
|
||||
go k
|
||||
| none =>
|
||||
addEntry value decl.fvarId
|
||||
return code.updateFun! decl (← go k)
|
||||
else
|
||||
let decl ← goFunDecl decl
|
||||
return code.updateFun! decl (← go k)
|
||||
| .jp decl k =>
|
||||
let decl ← goFunDecl decl
|
||||
@@ -101,12 +105,12 @@ end CSE
|
||||
/--
|
||||
Common sub-expression elimination
|
||||
-/
|
||||
def Decl.cse (decl : Decl) : CompilerM Decl := do
|
||||
let value ← decl.value.mapCodeM (·.cse)
|
||||
def Decl.cse (shouldElimFunDecls : Bool) (decl : Decl) : CompilerM Decl := do
|
||||
let value ← decl.value.mapCodeM (·.cse shouldElimFunDecls)
|
||||
return { decl with value }
|
||||
|
||||
def cse (phase : Phase := .base) (occurrence := 0) : Pass :=
|
||||
.mkPerDeclaration `cse Decl.cse phase occurrence
|
||||
def cse (phase : Phase := .base) (shouldElimFunDecls := false) (occurrence := 0) : Pass :=
|
||||
.mkPerDeclaration `cse (Decl.cse shouldElimFunDecls) phase occurrence
|
||||
|
||||
builtin_initialize
|
||||
registerTraceClass `Compiler.cse (inherited := true)
|
||||
|
||||
@@ -142,7 +142,7 @@ mutual
|
||||
fType := instantiateRevRangeArgs fType j i args |>.headBeta
|
||||
match fType with
|
||||
| .forallE _ _ b _ => j := i; fType := b
|
||||
| _ => return erasedExpr
|
||||
| _ => return anyExpr
|
||||
return instantiateRevRangeArgs fType j args.size args |>.headBeta
|
||||
|
||||
partial def inferAppType (e : Expr) : InferTypeM Expr := do
|
||||
@@ -157,7 +157,7 @@ mutual
|
||||
fType := fType.instantiateRevRange j i args |>.headBeta
|
||||
match fType with
|
||||
| .forallE _ _ b _ => j := i; fType := b
|
||||
| _ => return erasedExpr
|
||||
| _ => return anyExpr
|
||||
return fType.instantiateRevRange j args.size args |>.headBeta
|
||||
|
||||
partial def inferProjType (structName : Name) (idx : Nat) (s : FVarId) : InferTypeM Expr := do
|
||||
@@ -167,6 +167,8 @@ mutual
|
||||
if structType.isErased then
|
||||
/- TODO: after we erase universe variables, we can just extract a better type using just `structName` and `idx`. -/
|
||||
return erasedExpr
|
||||
else if structType.isAny then
|
||||
return anyExpr
|
||||
else
|
||||
matchConstStructure structType.getAppFn failed fun structVal structLvls ctorVal =>
|
||||
let structTypeArgs := structType.getAppArgs
|
||||
@@ -179,7 +181,7 @@ mutual
|
||||
| .forallE _ _ body _ =>
|
||||
if body.hasLooseBVars then
|
||||
-- This can happen when one of the fields is a type or type former.
|
||||
ctorType := body.instantiate1 erasedExpr
|
||||
ctorType := body.instantiate1 anyExpr
|
||||
else
|
||||
ctorType := body
|
||||
| _ =>
|
||||
|
||||
@@ -178,16 +178,8 @@ def eagerLambdaLifting : Pass where
|
||||
name := `eagerLambdaLifting
|
||||
run := fun decls => do
|
||||
decls.foldlM (init := #[]) fun decls decl => do
|
||||
if (← Meta.isInstance decl.name) then
|
||||
/-
|
||||
Recall that we lambda lift local functions in instances to control code blowup, and make sure they are cheap to inline.
|
||||
It is not worth to lift tiny ones. TODO: evaluate whether we should add a compiler option to control the min size.
|
||||
|
||||
Recall that when performing eager lambda lifting in instances, we progatate the `[inline]` annotations to the new auxiliary functions.
|
||||
|
||||
Note: we have tried `if decl.inlineable then return decls.push decl`, but it didn't help in our preliminary experiments.
|
||||
-/
|
||||
return decls ++ (← decl.lambdaLifting (liftInstParamOnly := false) (suffix := `_elam) (inheritInlineAttrs := true) (minSize := 3))
|
||||
if decl.inlineAttr || (← Meta.isInstance decl.name) then
|
||||
return decls.push decl
|
||||
else
|
||||
return decls ++ (← decl.lambdaLifting (liftInstParamOnly := true) (suffix := `_elam))
|
||||
|
||||
|
||||
@@ -85,7 +85,11 @@ partial def toMonoType (type : Expr) : CoreM Expr := do
|
||||
where
|
||||
visitApp (f : Expr) (args : Array Expr) : CoreM Expr := do
|
||||
match f with
|
||||
| .const ``lcErased _ => return erasedExpr
|
||||
| .const ``lcErased _ =>
|
||||
if args.all (·.isErased) then
|
||||
return erasedExpr
|
||||
else
|
||||
return anyExpr
|
||||
| .const ``lcAny _ => return anyExpr
|
||||
| .const ``Decidable _ => return mkConst ``Bool
|
||||
| .const declName us =>
|
||||
@@ -101,7 +105,7 @@ where
|
||||
if d matches .const ``lcErased _ | .sort _ then
|
||||
result := mkApp result (← toMonoType arg)
|
||||
else
|
||||
result := mkApp result erasedExpr
|
||||
result := mkApp result anyExpr
|
||||
type := b.instantiate1 arg
|
||||
return result
|
||||
| _ => return anyExpr
|
||||
|
||||
@@ -46,7 +46,7 @@ def builtinPassManager : PassManager := {
|
||||
passes := #[
|
||||
init,
|
||||
pullInstances,
|
||||
cse,
|
||||
cse (shouldElimFunDecls := false),
|
||||
simp,
|
||||
floatLetIn,
|
||||
findJoinPoints,
|
||||
@@ -61,7 +61,7 @@ def builtinPassManager : PassManager := {
|
||||
eagerLambdaLifting,
|
||||
specialize,
|
||||
simp (occurrence := 2),
|
||||
cse (occurrence := 1),
|
||||
cse (shouldElimFunDecls := false) (occurrence := 1),
|
||||
saveBase, -- End of base phase
|
||||
toMono,
|
||||
simp (occurrence := 3) (phase := .mono),
|
||||
|
||||
@@ -69,9 +69,14 @@ mutual
|
||||
partial def pullDecls (code : Code) : PullM Code := do
|
||||
match code with
|
||||
| .cases c =>
|
||||
withCheckpoint do
|
||||
let alts ← c.alts.mapMonoM pullAlt
|
||||
return code.updateAlts! alts
|
||||
-- At the present time, we can't correctly enforce the dependencies required for lifting
|
||||
-- out of a cases expression on Decidable, so we disable this optimization.
|
||||
if c.typeName == ``Decidable then
|
||||
return code
|
||||
else
|
||||
withCheckpoint do
|
||||
let alts ← c.alts.mapMonoM pullAlt
|
||||
return code.updateAlts! alts
|
||||
| .let decl k =>
|
||||
if (← shouldPull decl) then
|
||||
pullDecls k
|
||||
|
||||
@@ -42,30 +42,13 @@ def Decl.simp? (decl : Decl) : SimpM (Option Decl) := do
|
||||
partial def Decl.simp (decl : Decl) (config : Config) : CompilerM Decl := do
|
||||
let mut config := config
|
||||
if (← isTemplateLike decl) then
|
||||
let mut inlineDefs := config.inlineDefs
|
||||
/-
|
||||
At the base phase, we don't inline definitions occurring in instances.
|
||||
Reason: we eagerly lambda lift local functions occurring at instances before saving their code at the end of the base
|
||||
phase. The goal is to make them cheap to inline in actual code. By inlining definitions we would be just generating extra
|
||||
work for the lambda lifter.
|
||||
|
||||
There is an exception: inlineable instances. This is important for auxiliary instances such as
|
||||
```
|
||||
@[always_inline]
|
||||
instance : Monad TermElabM := let i := inferInstanceAs (Monad TermElabM); { pure := i.pure, bind := i.bind }
|
||||
```
|
||||
by keeping `inlineDefs := true`, we can pre-compute the `pure` and `bind` methods for `TermElabM`.
|
||||
-/
|
||||
if (← inBasePhase <&&> Meta.isInstance decl.name) then
|
||||
unless decl.inlineable do
|
||||
inlineDefs := false
|
||||
/-
|
||||
We do not eta-expand or inline partial applications in template like code.
|
||||
Recall we don't want to generate code for them.
|
||||
Remark: by eta-expanding partial applications in instances, we also make the simplifier
|
||||
work harder when inlining instance projections.
|
||||
-/
|
||||
config := { config with etaPoly := false, inlinePartial := false, inlineDefs }
|
||||
config := { config with etaPoly := false, inlinePartial := false }
|
||||
go decl config
|
||||
where
|
||||
go (decl : Decl) (config : Config) : CompilerM Decl := do
|
||||
|
||||
@@ -261,6 +261,9 @@ def getRemainingArgs (paramsInfo : Array SpecParamInfo) (args : Array Arg) : Arr
|
||||
result := result.push arg
|
||||
return result ++ args[paramsInfo.size:]
|
||||
|
||||
def paramsToVarSet (params : Array Param) : FVarIdSet :=
|
||||
params.foldl (fun r p => r.insert p.fvarId) {}
|
||||
|
||||
mutual
|
||||
/--
|
||||
Try to specialize the function application in the given let-declaration.
|
||||
@@ -295,7 +298,8 @@ mutual
|
||||
specDecl.saveBase
|
||||
let specDecl ← specDecl.simp {}
|
||||
let specDecl ← specDecl.simp { etaPoly := true, inlinePartial := true, implementedBy := true }
|
||||
let value ← withReader (fun _ => { declName := specDecl.name }) do
|
||||
let ground := paramsToVarSet specDecl.params
|
||||
let value ← withReader (fun _ => { declName := specDecl.name, ground }) do
|
||||
withParams specDecl.params <| specDecl.value.mapCodeM visitCode
|
||||
let specDecl := { specDecl with value }
|
||||
modify fun s => { s with decls := s.decls.push specDecl }
|
||||
@@ -337,7 +341,8 @@ def main (decl : Decl) : SpecializeM Decl := do
|
||||
end Specialize
|
||||
|
||||
partial def Decl.specialize (decl : Decl) : CompilerM (Array Decl) := do
|
||||
let (decl, s) ← Specialize.main decl |>.run { declName := decl.name } |>.run {}
|
||||
let ground := Specialize.paramsToVarSet decl.params
|
||||
let (decl, s) ← Specialize.main decl |>.run { declName := decl.name, ground } |>.run {}
|
||||
return s.decls.push decl
|
||||
|
||||
def specialize : Pass where
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user