mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-20 03:44:10 +00:00
Compare commits
58 Commits
count_repl
...
Poly_RArra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc95aadd6c | ||
|
|
6f4c33a31c | ||
|
|
3cbffee94b | ||
|
|
807182d63e | ||
|
|
a21377b9ec | ||
|
|
96fd2f195c | ||
|
|
5823d03283 | ||
|
|
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 |
@@ -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)
|
||||
|
||||
@@ -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 -/
|
||||
|
||||
|
||||
@@ -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]
|
||||
@@ -299,15 +299,14 @@ theorem count_replace {a b c : α} {xs : Array α} :
|
||||
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]
|
||||
|
||||
-- FIXME these theorems can be restored once `List.erase` and `Array.erase` have been related.
|
||||
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]
|
||||
|
||||
-- theorem count_erase (a b : α) (l : Array α) : count a (l.erase b) = count a l - if b == a then 1 else 0 := by
|
||||
-- sorry
|
||||
@[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_self (a : α) (l : Array α) :
|
||||
-- count a (l.erase a) = count a l - 1 := by rw [count_erase, if_pos (by simp)]
|
||||
|
||||
-- @[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_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
|
||||
|
||||
@@ -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
|
||||
@@ -70,7 +81,7 @@ 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 + 1)) ~ (ys.extract lo (hi + 1)) := by
|
||||
(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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -3707,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
|
||||
@@ -3981,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 -/
|
||||
|
||||
@@ -4914,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]
|
||||
|
||||
/--
|
||||
@@ -5152,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
|
||||
|
||||
@@ -5169,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 :=
|
||||
|
||||
@@ -566,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
|
||||
@@ -577,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
|
||||
|
||||
@@ -39,6 +40,39 @@ namespace Int
|
||||
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
|
||||
@@ -69,12 +103,24 @@ 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
|
||||
|
||||
@@ -116,6 +162,8 @@ 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
|
||||
|
||||
/-! ## 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
|
||||
by_cases 0 < s ∧ 0 < t
|
||||
@@ -167,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
|
||||
@@ -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
|
||||
@@ -585,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
|
||||
@@ -768,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
|
||||
@@ -780,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
|
||||
@@ -1020,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}
|
||||
@@ -1095,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
|
||||
|
||||
@@ -1183,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
|
||||
@@ -1209,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) ?_
|
||||
@@ -1233,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]
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -792,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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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₂ :=
|
||||
|
||||
@@ -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} :
|
||||
|
||||
@@ -546,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
|
||||
@@ -618,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)
|
||||
|
||||
@@ -641,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
|
||||
|
||||
@@ -657,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 _
|
||||
|
||||
@@ -714,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 :=
|
||||
@@ -1003,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]
|
||||
|
||||
@@ -1054,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
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -386,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]
|
||||
|
||||
@@ -694,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
|
||||
|
||||
|
||||
@@ -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) :=
|
||||
|
||||
@@ -26,11 +26,11 @@ See `RArray.ofFn` and `RArray.ofArray` in module `Lean.Data.RArray` for function
|
||||
It is not universe-polymorphic. ; smaller proof objects and no complication with the `ToExpr` type
|
||||
class.
|
||||
-/
|
||||
inductive RArray (α : Type) : Type where
|
||||
inductive RArray (α : Type u) : Type u where
|
||||
| leaf : α → RArray α
|
||||
| branch : Nat → RArray α → RArray α → RArray α
|
||||
|
||||
variable {α : Type}
|
||||
variable {α : Type u}
|
||||
|
||||
/-- The crucial operation, written with very little abstractional overhead -/
|
||||
noncomputable def RArray.get (a : RArray α) (n : Nat) : α :=
|
||||
|
||||
@@ -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]
|
||||
@@ -2921,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
|
||||
@@ -3076,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
|
||||
@@ -3322,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₁
|
||||
@@ -3330,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₁
|
||||
@@ -3338,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₁
|
||||
@@ -3346,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₁
|
||||
@@ -3354,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]
|
||||
|
||||
@@ -1666,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]
|
||||
@@ -1689,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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Kim Morrison
|
||||
prelude
|
||||
import Init.Data.Zero
|
||||
import Init.Data.Int.DivMod.Lemmas
|
||||
import Init.Data.Int.Pow
|
||||
import Init.TacticsExtra
|
||||
|
||||
/-!
|
||||
@@ -43,6 +44,12 @@ class CommRing (α : Type u) extends Add α, Mul α, Neg α, Sub α, HPow α Nat
|
||||
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
|
||||
|
||||
@@ -69,6 +76,9 @@ theorem zero_add (a : α) : 0 + a = a := by
|
||||
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]
|
||||
|
||||
@@ -78,6 +88,9 @@ 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]
|
||||
@@ -190,6 +203,16 @@ theorem intCast_mul (x y : Int) : ((x * y : Int) : α) = ((x : α) * (y : α)) :
|
||||
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
|
||||
@@ -216,7 +239,7 @@ theorem intCast_eq_zero_iff (x : Int) : (x : α) = 0 ↔ x % p = 0 :=
|
||||
rw [ofNat_eq_natCast] at this
|
||||
rw [this]
|
||||
simp only [Int.ofNat_dvd]
|
||||
simp only [← Nat.dvd_iff_mod_eq_zero, Int.natAbs_ofNat, Int.natCast_add,
|
||||
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]
|
||||
|
||||
751
src/Init/Grind/CommRing/SOM.lean
Normal file
751
src/Init/Grind/CommRing/SOM.lean
Normal file
@@ -0,0 +1,751 @@
|
||||
/-
|
||||
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 :=
|
||||
bif k == 0 then
|
||||
p
|
||||
else
|
||||
go p
|
||||
where
|
||||
go : Poly → Poly
|
||||
| .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' (go 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 bif k == 1 then
|
||||
p
|
||||
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))
|
||||
|
||||
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
|
||||
|
||||
/-!
|
||||
**Definitions for the `IsCharP` case**
|
||||
|
||||
We considered using a single set of definitions parameterized by `Option c`, but decided against it to avoid
|
||||
unnecessary kernel‑reduction overhead. Once we can specialize definitions before they reach the kernel,
|
||||
we can merge the two versions. Until then, the `IsCharP` definitions will carry the `C` suffix.
|
||||
-/
|
||||
def Poly.addConstC (p : Poly) (k : Int) (c : Nat) : Poly :=
|
||||
match p with
|
||||
| .num k' => .num ((k' + k) % c)
|
||||
| .add k' m p => .add k' m (addConstC p k c)
|
||||
|
||||
def Poly.insertC (k : Int) (m : Mon) (p : Poly) (c : Nat) : Poly :=
|
||||
let k := k % c
|
||||
bif k == 0 then
|
||||
p
|
||||
else
|
||||
go k p
|
||||
where
|
||||
go (k : Int) : Poly → Poly
|
||||
| .num k' => .add k m (.num k')
|
||||
| .add k' m' p =>
|
||||
match m.grevlex m' with
|
||||
| .eq =>
|
||||
let k'' := (k + k') % c
|
||||
bif k'' == 0 then
|
||||
p
|
||||
else
|
||||
.add k'' m p
|
||||
| .lt => .add k m (.add k' m' p)
|
||||
| .gt => .add k' m' (go k p)
|
||||
|
||||
def Poly.mulConstC (k : Int) (p : Poly) (c : Nat) : Poly :=
|
||||
let k := k % c
|
||||
bif k == 0 then
|
||||
.num 0
|
||||
else bif k == 1 then
|
||||
p
|
||||
else
|
||||
go p
|
||||
where
|
||||
go : Poly → Poly
|
||||
| .num k' => .num ((k*k') % c)
|
||||
| .add k' m p =>
|
||||
let k := (k*k') % c
|
||||
bif k == 0 then
|
||||
go p
|
||||
else
|
||||
.add k m (go p)
|
||||
|
||||
def Poly.mulMonC (k : Int) (m : Mon) (p : Poly) (c : Nat) : Poly :=
|
||||
let k := k % c
|
||||
bif k == 0 then
|
||||
.num 0
|
||||
else
|
||||
go p
|
||||
where
|
||||
go : Poly → Poly
|
||||
| .num k' =>
|
||||
let k := (k*k') % c
|
||||
bif k == 0 then
|
||||
.num 0
|
||||
else
|
||||
.add k m (.num 0)
|
||||
| .add k' m' p =>
|
||||
let k := (k*k') % c
|
||||
bif k == 0 then
|
||||
go p
|
||||
else
|
||||
.add k (m.mul m') (go p)
|
||||
|
||||
def Poly.combineC (p₁ p₂ : Poly) (c : Nat) : 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₂) % c)
|
||||
| .num k₁, .add k₂ m₂ p₂ => addConstC (.add k₂ m₂ p₂) k₁ c
|
||||
| .add k₁ m₁ p₁, .num k₂ => addConstC (.add k₁ m₁ p₁) k₂ c
|
||||
| .add k₁ m₁ p₁, .add k₂ m₂ p₂ =>
|
||||
match m₁.grevlex m₂ with
|
||||
| .eq =>
|
||||
let k := (k₁ + k₂) % c
|
||||
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.mulC (p₁ : Poly) (p₂ : Poly) (c : Nat) : Poly :=
|
||||
go p₁ (.num 0)
|
||||
where
|
||||
go (p₁ : Poly) (acc : Poly) : Poly :=
|
||||
match p₁ with
|
||||
| .num k => acc.combineC (p₂.mulConstC k c) c
|
||||
| .add k m p₁ => go p₁ (acc.combineC (p₂.mulMonC k m c) c)
|
||||
|
||||
def Poly.powC (p : Poly) (k : Nat) (c : Nat) : Poly :=
|
||||
match k with
|
||||
| 0 => .num 1
|
||||
| 1 => p
|
||||
| k+1 => p.mulC (powC p k c) c
|
||||
|
||||
def Expr.toPolyC (e : Expr) (c : Nat) : Poly :=
|
||||
go e
|
||||
where
|
||||
go : Expr → Poly
|
||||
| .num n => .num (n % c)
|
||||
| .var x => Poly.ofVar x
|
||||
| .add a b => (go a).combineC (go b) c
|
||||
| .mul a b => (go a).mulC (go b) c
|
||||
| .neg a => (go a).mulConstC (-1) c
|
||||
| .sub a b => (go a).combineC ((go b).mulConstC (-1) c) c
|
||||
| .pow a k =>
|
||||
match a with
|
||||
| .num n => .num ((n^k) % c)
|
||||
| .var x => Poly.ofMon (.leaf {x, k})
|
||||
| _ => (go a).powC k c
|
||||
|
||||
/-!
|
||||
Theorems for justifying the procedure for commutative rings in `grind`.
|
||||
-/
|
||||
|
||||
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
|
||||
simp [insert, cond_eq_if] <;> split
|
||||
next => simp [*, intCast_zero, zero_mul, zero_add]
|
||||
next =>
|
||||
fun_induction insert.go <;> simp_all +zetaDelta [insert.go, 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 =>
|
||||
split <;> try simp [*, intCast_one, one_mul]
|
||||
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]
|
||||
|
||||
theorem Poly.denote_addConstC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Int) : (addConstC p k c).denote ctx = p.denote ctx + k := by
|
||||
fun_induction addConstC <;> simp [addConstC, denote, *]
|
||||
next => rw [IsCharP.intCast_emod, intCast_add]
|
||||
next => simp [add_comm, add_left_comm, add_assoc]
|
||||
|
||||
theorem Poly.denote_insertC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (insertC k m p c).denote ctx = k * m.denote ctx + p.denote ctx := by
|
||||
simp [insertC, cond_eq_if] <;> split
|
||||
next =>
|
||||
rw [← IsCharP.intCast_emod (p := c)]
|
||||
simp +zetaDelta [*, intCast_zero, zero_mul, zero_add]
|
||||
next =>
|
||||
fun_induction insertC.go <;> simp_all +zetaDelta [insertC.go, denote, cond_eq_if]
|
||||
next h₁ _ h₂ => rw [IsCharP.intCast_emod]
|
||||
next h₁ _ h₂ =>
|
||||
rw [← add_assoc, Mon.eq_of_grevlex h₁, ← right_distrib, ← intCast_add, ← IsCharP.intCast_emod (p := c), h₂,
|
||||
intCast_zero, zero_mul, zero_add]
|
||||
next h₁ _ _ =>
|
||||
rw [IsCharP.intCast_emod, intCast_add, right_distrib, add_assoc, Mon.eq_of_grevlex h₁]
|
||||
next => rw [IsCharP.intCast_emod]
|
||||
next => rw [add_left_comm]
|
||||
|
||||
theorem Poly.denote_mulConstC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k : Int) (p : Poly)
|
||||
: (mulConstC k p c).denote ctx = k * p.denote ctx := by
|
||||
simp [mulConstC, cond_eq_if] <;> split
|
||||
next =>
|
||||
rw [← IsCharP.intCast_emod (p := c)]
|
||||
simp [denote, *, intCast_zero, zero_mul]
|
||||
next =>
|
||||
split
|
||||
next =>
|
||||
rw [← IsCharP.intCast_emod (p := c)]
|
||||
simp [*, intCast_one, one_mul]
|
||||
next =>
|
||||
fun_induction mulConstC.go <;> simp [mulConstC.go, denote, IsCharP.intCast_emod, cond_eq_if, *]
|
||||
next => rw [intCast_mul]
|
||||
next h _ =>
|
||||
simp +zetaDelta at h; simp [*]
|
||||
rw [left_distrib, ← mul_assoc, ← intCast_mul, ← IsCharP.intCast_emod (x := k * _) (p := c),
|
||||
h, intCast_zero, zero_mul, zero_add]
|
||||
next h _ =>
|
||||
simp +zetaDelta at h
|
||||
simp [*, denote, IsCharP.intCast_emod, intCast_mul, mul_assoc, left_distrib]
|
||||
|
||||
theorem Poly.denote_mulMonC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (mulMonC k m p c).denote ctx = k * m.denote ctx * p.denote ctx := by
|
||||
simp [mulMonC, cond_eq_if] <;> split
|
||||
next =>
|
||||
rw [← IsCharP.intCast_emod (p := c)]
|
||||
simp [denote, *, intCast_zero, zero_mul]
|
||||
next =>
|
||||
fun_induction mulMonC.go <;> simp [mulMonC.go, denote, *, cond_eq_if]
|
||||
next h =>
|
||||
simp +zetaDelta at h; simp [*, denote]
|
||||
rw [mul_assoc, mul_left_comm, ← intCast_mul, ← IsCharP.intCast_emod (x := k * _) (p := c), h]
|
||||
simp [intCast_zero, mul_zero]
|
||||
next h =>
|
||||
simp +zetaDelta at h; simp [*, denote, IsCharP.intCast_emod]
|
||||
simp [intCast_mul, intCast_zero, add_zero, mul_comm, mul_left_comm, mul_assoc]
|
||||
next h _ =>
|
||||
simp +zetaDelta at h; simp [*, denote, left_distrib]
|
||||
rw [mul_left_comm]
|
||||
conv => rhs; rw [← mul_assoc, ← mul_assoc, ← intCast_mul, ← IsCharP.intCast_emod (p := c)]
|
||||
rw [Int.mul_comm] at h
|
||||
simp [h, intCast_zero, zero_mul, zero_add]
|
||||
next h _ =>
|
||||
simp +zetaDelta at h
|
||||
simp [*, denote, IsCharP.intCast_emod, Mon.denote_mul, intCast_mul, left_distrib,
|
||||
mul_comm, mul_left_comm, mul_assoc]
|
||||
|
||||
theorem Poly.denote_combineC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (combineC p₁ p₂ c).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
unfold combineC; generalize hugeFuel = fuel
|
||||
fun_induction combineC.go
|
||||
<;> simp [combineC.go, *, denote_concat, denote_addConstC, denote, intCast_add,
|
||||
cond_eq_if, add_comm, add_left_comm, add_assoc, IsCharP.intCast_emod]
|
||||
next hg _ h _ =>
|
||||
simp +zetaDelta at h; simp [*]
|
||||
rw [← add_assoc, Mon.eq_of_grevlex hg, ← right_distrib, ← intCast_add,
|
||||
← IsCharP.intCast_emod (p := c),
|
||||
h, intCast_zero, zero_mul, zero_add]
|
||||
next hg _ h _ =>
|
||||
simp +zetaDelta at h; simp [*, denote, intCast_add, IsCharP.intCast_emod]
|
||||
rw [right_distrib, Mon.eq_of_grevlex hg, add_assoc]
|
||||
|
||||
theorem Poly.denote_mulC_go {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p₁ p₂ acc : Poly)
|
||||
: (mulC.go p₂ c p₁ acc).denote ctx = acc.denote ctx + p₁.denote ctx * p₂.denote ctx := by
|
||||
fun_induction mulC.go
|
||||
<;> simp [mulC.go, denote_combineC, denote_mulConstC, denote, *, right_distrib, denote_mulMonC, add_assoc]
|
||||
|
||||
theorem Poly.denote_mulC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (mulC p₁ p₂ c).denote ctx = p₁.denote ctx * p₂.denote ctx := by
|
||||
simp [mulC, denote_mulC_go, denote, intCast_zero, zero_add]
|
||||
|
||||
theorem Poly.denote_powC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Nat)
|
||||
: (powC p k c).denote ctx = p.denote ctx ^ k := by
|
||||
fun_induction powC <;> simp [powC, denote, intCast_one, pow_zero]
|
||||
next => simp [pow_succ, pow_zero, one_mul]
|
||||
next => simp [denote_mulC, *, pow_succ, mul_comm]
|
||||
|
||||
theorem Expr.denote_toPolyC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (e : Expr)
|
||||
: (e.toPolyC c).denote ctx = e.denote ctx := by
|
||||
unfold toPolyC
|
||||
fun_induction toPolyC.go
|
||||
<;> simp [toPolyC.go, denote, Poly.denote, Poly.denote_ofVar, Poly.denote_combineC,
|
||||
Poly.denote_mulC, Poly.denote_mulConstC, Poly.denote_powC, *]
|
||||
next => rw [IsCharP.intCast_emod]
|
||||
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 [IsCharP.intCast_emod, intCast_pow]
|
||||
next => simp [Poly.denote_ofMon, Mon.denote, Power.denote_eq]
|
||||
|
||||
end CommRing
|
||||
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
|
||||
|
||||
@@ -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,13 +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
|
||||
|
||||
@@ -8,6 +8,7 @@ import Lean.ProjFns
|
||||
import Lean.Meta.CtorRecognizer
|
||||
import Lean.Compiler.BorrowedAnnotation
|
||||
import Lean.Compiler.CSimpAttr
|
||||
import Lean.Compiler.ImplementedByAttr
|
||||
import Lean.Compiler.LCNF.Types
|
||||
import Lean.Compiler.LCNF.Bind
|
||||
import Lean.Compiler.LCNF.InferType
|
||||
@@ -302,7 +303,7 @@ are type formers. This can happen when we have a field whose type is, for exampl
|
||||
def applyToAny (type : Expr) : M Expr := do
|
||||
let toAny := (← get).toAny
|
||||
return type.replace fun
|
||||
| .fvar fvarId => if toAny.contains fvarId then some erasedExpr else none
|
||||
| .fvar fvarId => if toAny.contains fvarId then some anyExpr else none
|
||||
| _ => none
|
||||
|
||||
def toLCNFType (type : Expr) : M Expr := do
|
||||
@@ -567,6 +568,33 @@ where
|
||||
let result := .fvar auxDecl.fvarId
|
||||
mkOverApplication result args casesInfo.arity
|
||||
|
||||
visitCasesImplementedBy (casesInfo : CasesInfo) (f : Expr) (args : Array Expr) : M Arg := do
|
||||
let mut args := args
|
||||
let discr := args[casesInfo.discrPos]!
|
||||
if discr matches .fvar _ then
|
||||
let typeName := casesInfo.declName.getPrefix
|
||||
let .inductInfo indVal ← getConstInfo typeName | unreachable!
|
||||
args ← args.mapIdxM fun i arg => do
|
||||
unless casesInfo.altsRange.start <= i && i < casesInfo.altsRange.stop do return arg
|
||||
let altIdx := i - casesInfo.altsRange.start
|
||||
let numParams := casesInfo.altNumParams[altIdx]!
|
||||
let ctorName := indVal.ctors[altIdx]!
|
||||
|
||||
-- We simplify `casesOn` arguments that simply reconstruct the discriminant and replace
|
||||
-- them with the actual discriminant. This is required for hash consing to work correctly,
|
||||
-- and should eventually be fixed by changing the elaborated term to use the original
|
||||
-- variable.
|
||||
Meta.MetaM.run' <| Meta.lambdaBoundedTelescope arg numParams fun paramExprs body => do
|
||||
let fn := body.getAppFn
|
||||
let args := body.getAppArgs
|
||||
let args := args.map fun arg =>
|
||||
if arg.getAppFn.constName? == some ctorName && arg.getAppArgs == paramExprs then
|
||||
discr
|
||||
else
|
||||
arg
|
||||
Meta.mkLambdaFVars paramExprs (mkAppN fn args)
|
||||
visitAppDefaultConst f args
|
||||
|
||||
visitCtor (arity : Nat) (e : Expr) : M Arg :=
|
||||
etaIfUnderApplied e arity do
|
||||
visitAppDefaultConst e.getAppFn e.getAppArgs
|
||||
@@ -671,7 +699,7 @@ where
|
||||
visitApp (e : Expr) : M Arg := do
|
||||
if let some (args, n, t, v, b) := e.letFunAppArgs? then
|
||||
visitCore <| mkAppN (.letE n t v b (nonDep := true)) args
|
||||
else if let .const declName _ := CSimp.replaceConstants (← getEnv) e.getAppFn then
|
||||
else if let .const declName us := CSimp.replaceConstants (← getEnv) e.getAppFn then
|
||||
if declName == ``Quot.lift then
|
||||
visitQuotLift e
|
||||
else if declName == ``Quot.mk then
|
||||
@@ -687,7 +715,10 @@ where
|
||||
else if declName == ``False.rec || declName == ``Empty.rec || declName == ``False.casesOn || declName == ``Empty.casesOn then
|
||||
visitFalseRec e
|
||||
else if let some casesInfo ← getCasesInfo? declName then
|
||||
visitCases casesInfo e
|
||||
if (getImplementedBy? (← getEnv) declName).isSome then
|
||||
e.withApp (visitCasesImplementedBy casesInfo)
|
||||
else
|
||||
visitCases casesInfo e
|
||||
else if let some arity ← getCtorArity? declName then
|
||||
visitCtor arity e
|
||||
else if isNoConfusion (← getEnv) declName then
|
||||
|
||||
@@ -18,6 +18,9 @@ def anyExpr := mkConst ``lcAny
|
||||
def _root_.Lean.Expr.isErased (e : Expr) :=
|
||||
e.isAppOf ``lcErased
|
||||
|
||||
def _root_.Lean.Expr.isAny (e : Expr) :=
|
||||
e.isAppOf ``lcAny
|
||||
|
||||
def isPropFormerTypeQuick : Expr → Bool
|
||||
| .forallE _ _ b _ => isPropFormerTypeQuick b
|
||||
| .sort .zero => true
|
||||
@@ -132,7 +135,7 @@ partial def toLCNFType (type : Expr) : MetaM Expr := do
|
||||
| .forallE .. => visitForall type #[]
|
||||
| .app .. => type.withApp visitApp
|
||||
| .fvar .. => visitApp type #[]
|
||||
| _ => return erasedExpr
|
||||
| _ => return mkConst ``lcAny
|
||||
where
|
||||
whnfEta (type : Expr) : MetaM Expr := do
|
||||
let type ← whnf type
|
||||
@@ -156,10 +159,10 @@ where
|
||||
visitApp (f : Expr) (args : Array Expr) := do
|
||||
let fNew ← match f with
|
||||
| .const declName us =>
|
||||
let .inductInfo _ ← getConstInfo declName | return erasedExpr
|
||||
let .inductInfo _ ← getConstInfo declName | return anyExpr
|
||||
pure <| .const declName us
|
||||
| .fvar .. => pure f
|
||||
| _ => return erasedExpr
|
||||
| _ => return anyExpr
|
||||
let mut result := fNew
|
||||
for arg in args do
|
||||
if (← isProp arg) then
|
||||
@@ -169,13 +172,13 @@ where
|
||||
else if (← isTypeFormer arg) then
|
||||
result := mkApp result (← toLCNFType arg)
|
||||
else
|
||||
result := mkApp result erasedExpr
|
||||
result := mkApp result (mkConst ``lcAny)
|
||||
return result
|
||||
|
||||
mutual
|
||||
|
||||
partial def joinTypes (a b : Expr) : Expr :=
|
||||
joinTypes? a b |>.getD erasedExpr
|
||||
joinTypes? a b |>.getD (mkConst ``lcAny)
|
||||
|
||||
partial def joinTypes? (a b : Expr) : Option Expr := do
|
||||
if a.isErased || b.isErased then
|
||||
@@ -194,16 +197,16 @@ partial def joinTypes? (a b : Expr) : Option Expr := do
|
||||
| .app f a, .app g b =>
|
||||
(do return .app (← joinTypes? f g) (← joinTypes? a b))
|
||||
<|>
|
||||
return erasedExpr
|
||||
return (mkConst ``lcAny)
|
||||
| .forallE n d₁ b₁ _, .forallE _ d₂ b₂ _ =>
|
||||
(do return .forallE n (← joinTypes? d₁ d₂) (joinTypes b₁ b₂) .default)
|
||||
<|>
|
||||
return erasedExpr
|
||||
return (mkConst ``lcAny)
|
||||
| .lam n d₁ b₁ _, .lam _ d₂ b₂ _ =>
|
||||
(do return .lam n (← joinTypes? d₁ d₂) (joinTypes b₁ b₂) .default)
|
||||
<|>
|
||||
return erasedExpr
|
||||
| _, _ => return erasedExpr
|
||||
return (mkConst ``lcAny)
|
||||
| _, _ => return (mkConst ``lcAny)
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -303,6 +303,17 @@ private def mkFreshNameImp (n : Name) : CoreM Name := do
|
||||
let fresh ← modifyGet fun s => (s.nextMacroScope, { s with nextMacroScope := s.nextMacroScope + 1 })
|
||||
return addMacroScope (← getEnv).mainModule n fresh
|
||||
|
||||
/--
|
||||
Creates a name from `n` that is guaranteed to be unique.
|
||||
This is intended to be used for creating inaccessible user names for free variables and constants.
|
||||
|
||||
It works by adding a fresh macro scope to `n`.
|
||||
Applying `Lean.Name.eraseMacroScopes` to the resulting name yields `n`.
|
||||
|
||||
See also `Lean.LocalContext.getUnusedName` (for creating a new accessible user name that is
|
||||
unused in the local context) and `Lean.Meta.mkFreshBinderNameForTactic` (for creating names
|
||||
that are conditionally inaccessible, depending on the current value of the `tactic.hygiene` option).
|
||||
-/
|
||||
def mkFreshUserName (n : Name) : CoreM Name :=
|
||||
mkFreshNameImp n
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ Authors: Joachim Breitner
|
||||
|
||||
prelude
|
||||
import Init.Data.RArray
|
||||
import Lean.Meta.InferType
|
||||
import Lean.Meta.DecLevel
|
||||
import Lean.ToExpr
|
||||
|
||||
/-!
|
||||
@@ -54,22 +56,20 @@ theorem RArray.size_ofFn {n : Nat} (f : Fin n → α) (h : 0 < n) :
|
||||
where
|
||||
go lb ub h1 h2 : (ofFn.go f lb ub h1 h2).size = ub - lb := by
|
||||
induction lb, ub, h1, h2 using RArray.ofFn.go.induct (n := n)
|
||||
case case1 => simp [ofFn.go, size]; omega
|
||||
case case1 => simp [ofFn.go, size]
|
||||
case case2 ih1 ih2 hiu => rw [ofFn.go]; simp +zetaDelta [size, *]; omega
|
||||
|
||||
section Meta
|
||||
open Lean
|
||||
|
||||
def RArray.toExpr (ty : Expr) (f : α → Expr) : RArray α → Expr
|
||||
| .leaf x =>
|
||||
mkApp2 (mkConst ``RArray.leaf) ty (f x)
|
||||
| .branch p l r =>
|
||||
mkApp4 (mkConst ``RArray.branch) ty (mkRawNatLit p) (l.toExpr ty f) (r.toExpr ty f)
|
||||
|
||||
instance [ToExpr α] : ToExpr (RArray α) where
|
||||
toTypeExpr := mkApp (mkConst ``RArray) (toTypeExpr α)
|
||||
toExpr a := a.toExpr (toTypeExpr α) toExpr
|
||||
|
||||
end Meta
|
||||
open Meta in
|
||||
def RArray.toExpr (ty : Expr) (f : α → Expr) (a : RArray α) : MetaM Expr := do
|
||||
let u ← getDecLevel ty
|
||||
let leaf := mkConst ``RArray.leaf [u]
|
||||
let branch := mkConst ``RArray.branch [u]
|
||||
let rec go (a : RArray α) : MetaM Expr := do
|
||||
match a with
|
||||
| .leaf x =>
|
||||
return mkApp2 leaf ty (f x)
|
||||
| .branch p l r =>
|
||||
return mkApp4 branch ty (mkRawNatLit p) (← go l) (← go r)
|
||||
go a
|
||||
|
||||
end Lean
|
||||
|
||||
@@ -288,7 +288,7 @@ where
|
||||
let ras := Lean.RArray.ofArray as h
|
||||
let packedType := mkConst ``BVExpr.PackedBitVec
|
||||
let pack := fun (width, expr) => mkApp2 (mkConst ``BVExpr.PackedBitVec.mk) (toExpr width) expr
|
||||
let newAtomsAssignment := ras.toExpr packedType pack
|
||||
let newAtomsAssignment ← ras.toExpr packedType pack
|
||||
modify fun s => { s with atomsAssignmentCache := some newAtomsAssignment }
|
||||
return newAtomsAssignment
|
||||
else
|
||||
|
||||
@@ -45,24 +45,32 @@ def isSupportedMatch (declName : Name) : MetaM (Option MatchKind) := do
|
||||
let retTypeOk ← a.withApp fun fn arg =>
|
||||
return fn == motive && arg.size == 1 && arg[0]! == discr
|
||||
if !retTypeOk then return none
|
||||
|
||||
let numCtors := inductiveInfo.numCtors
|
||||
|
||||
/-
|
||||
At this point the control flow splits and tries to establish that the match is one of the kinds
|
||||
that we support.
|
||||
-/
|
||||
if xs.size == numCtors + 2 then
|
||||
-- Probably a full match
|
||||
/-
|
||||
This situation is most likely a full match but it could also be a match like:
|
||||
```
|
||||
inductive Foo where
|
||||
| a
|
||||
| b
|
||||
|
||||
-- Check that all parameters are `h_n EnumInductive.ctor`
|
||||
let mut handledCtors := Array.mkEmpty numCtors
|
||||
for i in [0:numCtors] do
|
||||
let argType ← inferType xs[i + 2]!
|
||||
let some (.const ``Unit [], (.app m (.const c []))) := argType.arrow? | return none
|
||||
if m != motive then return none
|
||||
let .ctorInfo ctorInfo ← getConstInfo c | return none
|
||||
handledCtors := handledCtors.push ctorInfo
|
||||
def isA (f : Foo) : Bool :=
|
||||
match f with
|
||||
| .a => true
|
||||
| _ => false
|
||||
```
|
||||
Where we have as many arms as constructors but the last arm is a default.
|
||||
-/
|
||||
|
||||
if !(← verifySimpleEnum defnInfo inductiveInfo handledCtors) then return none
|
||||
if let some kind ← trySimpleEnum defnInfo inductiveInfo xs numCtors motive then
|
||||
return kind
|
||||
|
||||
return some <| .simpleEnum inductiveInfo handledCtors
|
||||
else if xs.size > 2 then
|
||||
if xs.size > 2 then
|
||||
-- Probably a match with default case
|
||||
|
||||
-- Check that all parameters except the last are `h_n EnumInductive.ctor`
|
||||
@@ -90,6 +98,21 @@ def isSupportedMatch (declName : Name) : MetaM (Option MatchKind) := do
|
||||
else
|
||||
return none
|
||||
where
|
||||
trySimpleEnum (defnInfo : DefinitionVal) (inductiveInfo : InductiveVal) (xs : Array Expr)
|
||||
(numCtors : Nat) (motive : Expr) : MetaM (Option MatchKind) := do
|
||||
-- Check that all parameters are `h_n EnumInductive.ctor`
|
||||
let mut handledCtors := Array.mkEmpty numCtors
|
||||
for i in [0:numCtors] do
|
||||
let argType ← inferType xs[i + 2]!
|
||||
let some (.const ``Unit [], (.app m (.const c []))) := argType.arrow? | return none
|
||||
if m != motive then return none
|
||||
let .ctorInfo ctorInfo ← getConstInfo c | return none
|
||||
handledCtors := handledCtors.push ctorInfo
|
||||
|
||||
if !(← verifySimpleEnum defnInfo inductiveInfo handledCtors) then return none
|
||||
|
||||
return some <| .simpleEnum inductiveInfo handledCtors
|
||||
|
||||
verifySimpleCasesOnApp (inductiveInfo : InductiveVal) (fn : Expr) (args : Array Expr)
|
||||
(params : Array Expr) : MetaM Bool := do
|
||||
-- Body is an application of `EnumInductive.casesOn`
|
||||
|
||||
@@ -191,10 +191,10 @@ private def getOptRotation (stx : Syntax) : Nat :=
|
||||
let mvarIds ← getGoals
|
||||
let mut mvarIdsNew := #[]
|
||||
let mut abort := false
|
||||
let mut mctxSaved ← getMCtx
|
||||
for mvarId in mvarIds do
|
||||
unless (← mvarId.isAssigned) do
|
||||
setGoals [mvarId]
|
||||
let saved ← saveState
|
||||
abort ← Tactic.tryCatch
|
||||
(do
|
||||
evalTactic stx[1]
|
||||
@@ -202,13 +202,15 @@ private def getOptRotation (stx : Syntax) : Nat :=
|
||||
(fun ex => do
|
||||
if (← read).recover then
|
||||
logException ex
|
||||
let msgLog ← Core.getMessageLog
|
||||
saved.restore
|
||||
Core.setMessageLog msgLog
|
||||
admitGoal mvarId
|
||||
pure true
|
||||
else
|
||||
throw ex)
|
||||
mvarIdsNew := mvarIdsNew ++ (← getUnsolvedGoals)
|
||||
if abort then
|
||||
setMCtx mctxSaved
|
||||
mvarIds.forM fun mvarId => unless (← mvarId.isAssigned) do admitGoal mvarId
|
||||
throwAbortTactic
|
||||
setGoals mvarIdsNew.toList
|
||||
|
||||
|
||||
@@ -89,6 +89,8 @@ def elabGrindParams (params : Grind.Params) (ps : TSyntaxArray ``Parser.Tactic.
|
||||
params ← withRef p <| addEMatchTheorem params ctor .default
|
||||
else
|
||||
throwError "invalid use of `intro` modifier, `{declName}` is not an inductive predicate"
|
||||
| .ext =>
|
||||
throwError "`[grind ext]` cannot be set using parameters"
|
||||
| .infer =>
|
||||
if let some declName ← Grind.isCasesAttrCandidate? declName false then
|
||||
params := { params with casesTypes := params.casesTypes.insert declName false }
|
||||
|
||||
@@ -26,8 +26,10 @@ open Meta
|
||||
Given an `inductionAlt` of the form
|
||||
```
|
||||
syntax inductionAltLHS := "| " (group("@"? ident) <|> hole) (ident <|> hole)*
|
||||
syntax inductionAlt := ppDedent(ppLine) inductionAltLHS+ " => " (hole <|> syntheticHole <|> tacticSeq)
|
||||
syntax inductionAlt := ppDedent(ppLine) inductionAltLHS+ (" => " (hole <|> syntheticHole <|> tacticSeq))?
|
||||
```
|
||||
We assume that the syntax has been expanded. There is exactly one `inductionAltLHS`,
|
||||
and `" => " (hole <|> syntheticHole <|> tacticSeq)` is present
|
||||
-/
|
||||
private def getAltLhses (alt : Syntax) : Syntax :=
|
||||
alt[0]
|
||||
@@ -49,36 +51,40 @@ private def altHasExplicitModifier (alt : Syntax) : Bool :=
|
||||
private def getAltVars (alt : Syntax) : Array Syntax :=
|
||||
let lhs := getFirstAltLhs alt
|
||||
lhs[2].getArgs
|
||||
private def hasAltRHS (alt : Syntax) : Bool :=
|
||||
alt[1].getNumArgs > 0
|
||||
private def getAltRHS (alt : Syntax) : Syntax :=
|
||||
alt[2]
|
||||
alt[1][1]
|
||||
private def getAltDArrow (alt : Syntax) : Syntax :=
|
||||
alt[1]
|
||||
alt[1][0]
|
||||
|
||||
-- Return true if `stx` is a term occurring in the RHS of the induction/cases tactic
|
||||
def isHoleRHS (rhs : Syntax) : Bool :=
|
||||
rhs.isOfKind ``Parser.Term.syntheticHole || rhs.isOfKind ``Parser.Term.hole
|
||||
|
||||
def evalAlt (mvarId : MVarId) (alt : Syntax) (addInfo : TermElabM Unit) : TacticM Unit :=
|
||||
let rhs := getAltRHS alt
|
||||
withCaseRef (getAltDArrow alt) rhs do
|
||||
if isHoleRHS rhs then
|
||||
addInfo
|
||||
mvarId.withContext <| withTacticInfoContext rhs do
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
let val ← elabTermEnsuringType rhs mvarDecl.type
|
||||
mvarId.assign val
|
||||
let gs' ← getMVarsNoDelayed val
|
||||
tagUntaggedGoals mvarDecl.userName `induction gs'.toList
|
||||
setGoals <| (← getGoals) ++ gs'.toList
|
||||
else
|
||||
def evalAlt (mvarId : MVarId) (alt : Syntax) (addInfo : TermElabM Unit) : TacticM Unit := do
|
||||
if !hasAltRHS alt then
|
||||
throwErrorAt alt "(internal error) RHS was not expanded"
|
||||
else
|
||||
let rhs := getAltRHS alt
|
||||
withCaseRef (getAltDArrow alt) rhs do
|
||||
let goals ← getGoals
|
||||
setGoals []
|
||||
try
|
||||
setGoals [mvarId]
|
||||
closeUsingOrAdmit <|
|
||||
withTacticInfoContext (mkNullNode #[getAltLhses alt, getAltDArrow alt]) <|
|
||||
(addInfo *> evalTactic rhs)
|
||||
withTacticInfoContext (mkNullNode #[getAltLhses alt, getAltDArrow alt]) do
|
||||
addInfo
|
||||
if isHoleRHS rhs then
|
||||
mvarId.withContext do
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
-- Elaborate ensuring that `_` is interpreted as `?_`.
|
||||
let (val, gs') ← elabTermWithHoles rhs mvarDecl.type `induction (parentTag? := mvarDecl.userName) (allowNaturalHoles := true)
|
||||
mvarId.assign val
|
||||
setGoals gs'
|
||||
else
|
||||
closeUsingOrAdmit <| evalTactic rhs
|
||||
finally
|
||||
setGoals goals
|
||||
pushGoals goals
|
||||
|
||||
/-!
|
||||
Helper method for creating an user-defined eliminator/recursor application.
|
||||
@@ -432,7 +438,8 @@ where
|
||||
-- all previous alternatives have to be unchanged for reuse
|
||||
Term.withNarrowedArgTacticReuse (stx := mkNullNode altStxs) (argIdx := altStxIdx) fun altStx => do
|
||||
-- everything up to rhs has to be unchanged for reuse
|
||||
Term.withNarrowedArgTacticReuse (stx := altStx) (argIdx := 2) fun _rhs => do
|
||||
Term.withNarrowedArgTacticReuse (stx := altStx) (argIdx := 1) fun rhs? => do
|
||||
Term.withNarrowedArgTacticReuse (stx := rhs?) (argIdx := 1) fun _rhs => do
|
||||
-- disable reuse if rhs is run multiple times
|
||||
Term.withoutTacticIncrementality (altMVarIds.length != 1 || isWildcard altStx) do
|
||||
for altMVarId' in altMVarIds do
|
||||
@@ -531,13 +538,25 @@ private def withAltsOfOptInductionAlts (optInductionAlts : Syntax)
|
||||
private def getOptPreTacOfOptInductionAlts (optInductionAlts : Syntax) : Syntax :=
|
||||
if optInductionAlts.isNone then mkNullNode else optInductionAlts[0][1]
|
||||
|
||||
private def isMultiAlt (alt : Syntax) : Bool :=
|
||||
alt[0].getNumArgs > 1
|
||||
/--
|
||||
Returns true if the `Lean.Parser.Tactic.inductionAlt` either has more than one alternative
|
||||
or has no RHS.
|
||||
-/
|
||||
private def shouldExpandAlt (alt : Syntax) : Bool :=
|
||||
alt[0].getNumArgs > 1 || (1 < alt.getNumArgs && alt[1].getNumArgs == 0)
|
||||
|
||||
/-- Return `some #[alt_1, ..., alt_n]` if `alt` has multiple LHSs. -/
|
||||
private def expandMultiAlt? (alt : Syntax) : Option (Array Syntax) := Id.run do
|
||||
if isMultiAlt alt then
|
||||
some <| alt[0].getArgs.map fun lhs => alt.setArg 0 (mkNullNode #[lhs])
|
||||
/--
|
||||
Returns `some #[alt_1, ..., alt_n]` if `alt` has multiple LHSs or if `alt` has no RHS.
|
||||
If there is no RHS, it is filled in with a hole.
|
||||
-/
|
||||
private def expandAlt? (alt : Syntax) : Option (Array Syntax) := Id.run do
|
||||
if shouldExpandAlt alt then
|
||||
some <| alt[0].getArgs.map fun lhs =>
|
||||
let alt := alt.setArg 0 (mkNullNode #[lhs])
|
||||
if 1 < alt.getNumArgs && alt[1].getNumArgs == 0 then
|
||||
alt.setArg 1 <| mkNullNode #[mkAtomFrom lhs "=>", mkHole lhs]
|
||||
else
|
||||
alt
|
||||
else
|
||||
none
|
||||
|
||||
@@ -546,17 +565,17 @@ Given `inductionAlts` of the form
|
||||
```
|
||||
syntax inductionAlts := "with " (tactic)? withPosition( (colGe inductionAlt)*)
|
||||
```
|
||||
Return `some inductionAlts'` if one of the alternatives have multiple LHSs, in the new `inductionAlts'`
|
||||
all alternatives have a single LHS.
|
||||
Return `some inductionAlts'` if one of the alternatives has multiple LHSs or no RHS.
|
||||
In the new `inductionAlts'` all alternatives have a single LHS.
|
||||
|
||||
Remark: the `RHS` of alternatives with multi LHSs is copied.
|
||||
-/
|
||||
private def expandInductionAlts? (inductionAlts : Syntax) : Option Syntax := Id.run do
|
||||
let alts := getAltsOfInductionAlts inductionAlts
|
||||
if alts.any isMultiAlt then
|
||||
if alts.any shouldExpandAlt then
|
||||
let mut altsNew := #[]
|
||||
for alt in alts do
|
||||
if let some alt' := expandMultiAlt? alt then
|
||||
if let some alt' := expandAlt? alt then
|
||||
altsNew := altsNew ++ alt'
|
||||
else
|
||||
altsNew := altsNew.push alt
|
||||
|
||||
@@ -674,16 +674,19 @@ open Lean Elab Tactic Parser.Tactic
|
||||
def omegaTactic (cfg : OmegaConfig) : TacticM Unit := do
|
||||
let declName? ← Term.getDeclName?
|
||||
liftMetaFinishingTactic fun g => do
|
||||
let some g ← g.falseOrByContra | return ()
|
||||
g.withContext do
|
||||
let type ← g.getType
|
||||
let g' ← mkFreshExprSyntheticOpaqueMVar type
|
||||
let hyps := (← getLocalHyps).toList
|
||||
trace[omega] "analyzing {hyps.length} hypotheses:\n{← hyps.mapM inferType}"
|
||||
omega hyps g'.mvarId! cfg
|
||||
-- Omega proofs are typically rather large, so hide them in a separate definition
|
||||
let e ← mkAuxTheorem (prefix? := declName?) type (← instantiateMVarsProfiling g') (zetaDelta := true)
|
||||
g.assign e
|
||||
if debug.terminalTacticsAsSorry.get (← getOptions) then
|
||||
g.admit
|
||||
else
|
||||
let some g ← g.falseOrByContra | return ()
|
||||
g.withContext do
|
||||
let type ← g.getType
|
||||
let g' ← mkFreshExprSyntheticOpaqueMVar type
|
||||
let hyps := (← getLocalHyps).toList
|
||||
trace[omega] "analyzing {hyps.length} hypotheses:\n{← hyps.mapM inferType}"
|
||||
omega hyps g'.mvarId! cfg
|
||||
-- Omega proofs are typically rather large, so hide them in a separate definition
|
||||
let e ← mkAuxTheorem (prefix? := declName?) type (← instantiateMVarsProfiling g') (zetaDelta := true)
|
||||
g.assign e
|
||||
|
||||
|
||||
/-- The `omega` tactic, for resolving integer and natural linear arithmetic problems. This
|
||||
|
||||
@@ -908,8 +908,11 @@ def levelMVarToParam (e : Expr) (except : LMVarId → Bool := fun _ => false) :
|
||||
return r.expr
|
||||
|
||||
/--
|
||||
Auxiliary method for creating fresh binder names.
|
||||
Do not confuse with the method for creating fresh free/meta variable ids. -/
|
||||
Creates a fresh inaccessible binder name based on `x`.
|
||||
Equivalent to ``Lean.Core.mkFreshUserName `x``.
|
||||
|
||||
Do not confuse with `Lean.mkFreshId`, for creating fresh free variable and metavariable ids.
|
||||
-/
|
||||
def mkFreshBinderName [Monad m] [MonadQuotation m] : m Name :=
|
||||
withFreshMacroScope <| MonadQuotation.addMacroScope `x
|
||||
|
||||
|
||||
@@ -62,6 +62,15 @@ This is triggered by `attribute [-ext] name`.
|
||||
def ExtTheorems.eraseCore (d : ExtTheorems) (declName : Name) : ExtTheorems :=
|
||||
{ d with erased := d.erased.insert declName }
|
||||
|
||||
/-- Returns `true` if `d` contains theorem with name `declName`. -/
|
||||
def ExtTheorems.contains (d : ExtTheorems) (declName : Name) : Bool :=
|
||||
d.tree.containsValueP (·.declName == declName) && !d.erased.contains declName
|
||||
|
||||
/-- Returns `true` if `declName` is tagged with `[ext]` attribute. -/
|
||||
def isExtTheorem (declName : Name) : CoreM Bool := do
|
||||
let extTheorems := extExtension.getState (← getEnv)
|
||||
return extTheorems.contains declName
|
||||
|
||||
/--
|
||||
Erases a name marked as a `ext` attribute.
|
||||
Check that it does in fact have the `ext` attribute by making sure it names a `ExtTheorem`
|
||||
@@ -69,7 +78,7 @@ found somewhere in the state's tree, and is not erased.
|
||||
-/
|
||||
def ExtTheorems.erase [Monad m] [MonadError m] (d : ExtTheorems) (declName : Name) :
|
||||
m ExtTheorems := do
|
||||
unless d.tree.containsValueP (·.declName == declName) && !d.erased.contains declName do
|
||||
unless d.contains declName do
|
||||
throwError "'{declName}' does not have [ext] attribute"
|
||||
return d.eraseCore declName
|
||||
|
||||
|
||||
@@ -189,6 +189,16 @@ def lambdaTelescope1 {n} [MonadControlT MetaM n] [MonadError n] [MonadNameGenera
|
||||
throwError "lambdaTelescope1: expected lambda, got {e}"
|
||||
k xs[0]!.fvarId! body
|
||||
|
||||
/-- There are multiple variants of this function around in the code base, maybe unify at some point. -/
|
||||
private def elimTypeAnnotations (type : Expr) : CoreM Expr := do
|
||||
Core.transform type fun e =>
|
||||
if e.isOptParam || e.isAutoParam then
|
||||
return .visit e.appFn!.appArg!
|
||||
else if e.isOutParam || e.isSemiOutParam then
|
||||
return .visit e.appArg!
|
||||
else
|
||||
return .continue
|
||||
|
||||
/--
|
||||
A monad to help collecting inductive hypothesis.
|
||||
|
||||
@@ -746,7 +756,7 @@ where doRealize (inductName : Name) := do
|
||||
check e'
|
||||
|
||||
let eTyp ← inferType e'
|
||||
let eTyp ← elimOptParam eTyp
|
||||
let eTyp ← elimTypeAnnotations eTyp
|
||||
-- logInfo m!"eTyp: {eTyp}"
|
||||
let levelParams := (collectLevelParams {} eTyp).params
|
||||
-- Prune unused level parameters, preserving the original order
|
||||
@@ -1121,7 +1131,7 @@ where doRealize inductName := do
|
||||
check e'
|
||||
|
||||
let eTyp ← inferType e'
|
||||
let eTyp ← elimOptParam eTyp
|
||||
let eTyp ← elimTypeAnnotations eTyp
|
||||
-- logInfo m!"eTyp: {eTyp}"
|
||||
let levelParams := (collectLevelParams {} eTyp).params
|
||||
-- Prune unused level parameters, preserving the original order
|
||||
@@ -1199,7 +1209,7 @@ def deriveCases (name : Name) : MetaM Unit := do
|
||||
check e'
|
||||
|
||||
let eTyp ← inferType e'
|
||||
let eTyp ← elimOptParam eTyp
|
||||
let eTyp ← elimTypeAnnotations eTyp
|
||||
-- logInfo m!"eTyp: {eTyp}"
|
||||
let levelParams := (collectLevelParams {} eTyp).params
|
||||
-- Prune unused level parameters, preserving the original order
|
||||
|
||||
@@ -30,6 +30,7 @@ import Lean.Meta.Tactic.Grind.MatchCond
|
||||
import Lean.Meta.Tactic.Grind.MatchDiscrOnly
|
||||
import Lean.Meta.Tactic.Grind.Diseq
|
||||
import Lean.Meta.Tactic.Grind.MBTC
|
||||
import Lean.Meta.Tactic.Grind.Lookahead
|
||||
|
||||
namespace Lean
|
||||
|
||||
@@ -54,6 +55,10 @@ builtin_initialize registerTraceClass `grind.beta
|
||||
builtin_initialize registerTraceClass `grind.mbtc
|
||||
builtin_initialize registerTraceClass `grind.ext
|
||||
builtin_initialize registerTraceClass `grind.ext.candidate
|
||||
builtin_initialize registerTraceClass `grind.lookahead
|
||||
builtin_initialize registerTraceClass `grind.lookahead.add (inherited := true)
|
||||
builtin_initialize registerTraceClass `grind.lookahead.try (inherited := true)
|
||||
builtin_initialize registerTraceClass `grind.lookahead.assert (inherited := true)
|
||||
|
||||
/-! Trace options for `grind` developers -/
|
||||
builtin_initialize registerTraceClass `grind.debug
|
||||
|
||||
@@ -82,14 +82,14 @@ private def mkLetOfMap {_ : Hashable α} {_ : BEq α} (m : Std.HashMap α Expr)
|
||||
i := i - 1
|
||||
return e
|
||||
|
||||
private def toContextExprCore (vars : PArray Expr) (type : Expr) : Expr :=
|
||||
private def toContextExprCore (vars : PArray Expr) (type : Expr) : MetaM Expr :=
|
||||
if h : 0 < vars.size then
|
||||
RArray.toExpr type id (RArray.ofFn (vars[·]) h)
|
||||
else
|
||||
RArray.toExpr type id (RArray.leaf (mkIntLit 0))
|
||||
|
||||
private def toContextExpr : GoalM Expr := do
|
||||
return toContextExprCore (← getVars) (mkConst ``Int)
|
||||
toContextExprCore (← getVars) (mkConst ``Int)
|
||||
|
||||
private def withForeignContexts (k : Std.HashMap ForeignType Expr → GoalM α) : GoalM α := do
|
||||
go 1 (← get').foreignVars.toList {}
|
||||
@@ -99,8 +99,8 @@ where
|
||||
| [] => k r
|
||||
| (type, ctx) :: ctxs =>
|
||||
let typeExpr := type.denoteType
|
||||
let ctxExpr := toContextExprCore ctx typeExpr
|
||||
withLetDecl ((`ctx).appendIndexAfter i) (mkApp (mkConst ``RArray) typeExpr) ctxExpr fun ctx => do
|
||||
let ctxExpr ← toContextExprCore ctx typeExpr
|
||||
withLetDecl ((`ctx).appendIndexAfter i) (mkApp (mkConst ``RArray [levelZero]) typeExpr) ctxExpr fun ctx => do
|
||||
go (i+1) ctxs (r.insert type ctx)
|
||||
|
||||
private def getLetCtxVars : ProofM (Array Expr) := do
|
||||
@@ -110,7 +110,7 @@ private def getLetCtxVars : ProofM (Array Expr) := do
|
||||
return r
|
||||
|
||||
private abbrev withProofContext (x : ProofM Expr) : GoalM Expr := do
|
||||
withLetDecl `ctx (mkApp (mkConst ``RArray) (mkConst ``Int)) (← toContextExpr) fun ctx =>
|
||||
withLetDecl `ctx (mkApp (mkConst ``RArray [levelZero]) (mkConst ``Int)) (← toContextExpr) fun ctx =>
|
||||
withForeignContexts fun foreignCtxs =>
|
||||
go { ctx, foreignCtxs } |>.run' {}
|
||||
where
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Leonardo de Moura
|
||||
prelude
|
||||
import Lean.Meta.Tactic.Grind.EMatchTheorem
|
||||
import Lean.Meta.Tactic.Grind.Cases
|
||||
import Lean.Meta.Tactic.Grind.ExtAttr
|
||||
|
||||
namespace Lean.Meta.Grind
|
||||
|
||||
@@ -14,6 +15,7 @@ inductive AttrKind where
|
||||
| cases (eager : Bool)
|
||||
| intro
|
||||
| infer
|
||||
| ext
|
||||
|
||||
/-- Return theorem kind for `stx` of the form `Attr.grindThmMod` -/
|
||||
def getAttrKindCore (stx : Syntax) : CoreM AttrKind := do
|
||||
@@ -34,6 +36,7 @@ def getAttrKindCore (stx : Syntax) : CoreM AttrKind := do
|
||||
| `(Parser.Attr.grindMod| cases) => return .cases false
|
||||
| `(Parser.Attr.grindMod| cases eager) => return .cases true
|
||||
| `(Parser.Attr.grindMod| intro) => return .intro
|
||||
| `(Parser.Attr.grindMod| ext) => return .ext
|
||||
| _ => throwError "unexpected `grind` theorem kind: `{stx}`"
|
||||
|
||||
/-- Return theorem kind for `stx` of the form `(Attr.grindMod)?` -/
|
||||
@@ -78,6 +81,7 @@ builtin_initialize
|
||||
addEMatchAttr ctor attrKind .default
|
||||
else
|
||||
throwError "invalid `[grind intro]`, `{declName}` is not an inductive predicate"
|
||||
| .ext => addExtAttr declName attrKind
|
||||
| .infer =>
|
||||
if let some declName ← isCasesAttrCandidate? declName false then
|
||||
addCasesAttr declName false attrKind
|
||||
@@ -91,6 +95,8 @@ builtin_initialize
|
||||
erase := fun declName => MetaM.run' do
|
||||
if (← isCasesAttrCandidate declName false) then
|
||||
eraseCasesAttr declName
|
||||
else if (← isExtTheorem declName) then
|
||||
eraseExtAttr declName
|
||||
else
|
||||
eraseEMatchAttr declName
|
||||
}
|
||||
|
||||
43
src/Lean/Meta/Tactic/Grind/ExtAttr.lean
Normal file
43
src/Lean/Meta/Tactic/Grind/ExtAttr.lean
Normal file
@@ -0,0 +1,43 @@
|
||||
/-
|
||||
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Lean.Meta.Tactic.Ext
|
||||
|
||||
namespace Lean.Meta.Grind
|
||||
/-! Grind extensionality attribute to mark which `[ext]` theorems should be used. -/
|
||||
|
||||
/-- Extensionality theorems that can be used by `grind` -/
|
||||
abbrev ExtTheorems := PHashSet Name
|
||||
|
||||
builtin_initialize extTheoremsExt : SimpleScopedEnvExtension Name ExtTheorems ←
|
||||
registerSimpleScopedEnvExtension {
|
||||
initial := {}
|
||||
addEntry := fun s declName => s.insert declName
|
||||
}
|
||||
|
||||
def validateExtAttr (declName : Name) : CoreM Unit := do
|
||||
unless (← Ext.isExtTheorem declName) do
|
||||
throwError "invalid `[grind ext]`, `{declName}` is not tagged with `[ext]`"
|
||||
|
||||
def addExtAttr (declName : Name) (attrKind : AttributeKind) : CoreM Unit := do
|
||||
validateExtAttr declName
|
||||
extTheoremsExt.add declName attrKind
|
||||
|
||||
private def eraseDecl (s : ExtTheorems) (declName : Name) : CoreM ExtTheorems := do
|
||||
if s.contains declName then
|
||||
return s.erase declName
|
||||
else
|
||||
throwError "`{declName}` is not marked with the `[grind ext]` attribute"
|
||||
|
||||
def eraseExtAttr (declName : Name) : CoreM Unit := do
|
||||
let s := extTheoremsExt.getState (← getEnv)
|
||||
let s ← eraseDecl s declName
|
||||
modifyEnv fun env => extTheoremsExt.modifyState env fun _ => s
|
||||
|
||||
def isExtTheorem (declName : Name) : CoreM Bool := do
|
||||
return extTheoremsExt.getState (← getEnv) |>.contains declName
|
||||
|
||||
end Lean.Meta.Grind
|
||||
@@ -62,10 +62,10 @@ private def checkAndAddSplitCandidate (e : Expr) : GoalM Unit := do
|
||||
match e with
|
||||
| .app .. =>
|
||||
if (← getConfig).splitIte && (e.isIte || e.isDIte) then
|
||||
addSplitCandidate e
|
||||
addSplitCandidate (.default e)
|
||||
return ()
|
||||
if isMorallyIff e then
|
||||
addSplitCandidate e
|
||||
addSplitCandidate (.default e)
|
||||
return ()
|
||||
if (← getConfig).splitMatch then
|
||||
if (← isMatcherApp e) then
|
||||
@@ -74,7 +74,7 @@ private def checkAndAddSplitCandidate (e : Expr) : GoalM Unit := do
|
||||
-- and consequently don't need to be split.
|
||||
return ()
|
||||
else
|
||||
addSplitCandidate e
|
||||
addSplitCandidate (.default e)
|
||||
return ()
|
||||
let .const declName _ := e.getAppFn | return ()
|
||||
if forbiddenSplitTypes.contains declName then
|
||||
@@ -82,16 +82,21 @@ private def checkAndAddSplitCandidate (e : Expr) : GoalM Unit := do
|
||||
unless (← isInductivePredicate declName) do
|
||||
return ()
|
||||
if (← get).split.casesTypes.isSplit declName then
|
||||
addSplitCandidate e
|
||||
addSplitCandidate (.default e)
|
||||
else if (← getConfig).splitIndPred then
|
||||
addSplitCandidate e
|
||||
addSplitCandidate (.default e)
|
||||
| .fvar .. =>
|
||||
let .const declName _ := (← whnfD (← inferType e)).getAppFn | return ()
|
||||
if (← get).split.casesTypes.isSplit declName then
|
||||
addSplitCandidate e
|
||||
addSplitCandidate (.default e)
|
||||
| .forallE _ d _ _ =>
|
||||
if Arith.isRelevantPred d || (← getConfig).splitImp then
|
||||
addSplitCandidate e
|
||||
if (← getConfig).splitImp then
|
||||
addSplitCandidate (.default e)
|
||||
else if Arith.isRelevantPred d then
|
||||
if (← getConfig).lookahead then
|
||||
addLookaheadCandidate (.default e)
|
||||
else
|
||||
addSplitCandidate (.default e)
|
||||
| _ => pure ()
|
||||
|
||||
/--
|
||||
@@ -167,7 +172,7 @@ private def activateTheoremPatterns (fName : Name) (generation : Nat) : GoalM Un
|
||||
modify fun s => { s with ematch.thmMap := thmMap }
|
||||
let appMap := (← get).appMap
|
||||
for thm in thms do
|
||||
trace[grind.debug.ematch.activate] "`{fName}` => `{thm.origin.key}`"
|
||||
trace_goal[grind.debug.ematch.activate] "`{fName}` => `{thm.origin.key}`"
|
||||
unless (← get).ematch.thmMap.isErased thm.origin do
|
||||
let symbols := thm.symbols.filter fun sym => !appMap.contains sym
|
||||
let thm := { thm with symbols }
|
||||
@@ -208,13 +213,13 @@ private def extParentsToIgnore (declName : Name) : Bool :=
|
||||
|| declName == ``Exists || declName == ``Subtype
|
||||
|
||||
/--
|
||||
Given a term `e` that occurs as the argument at position `i` of an `f`-application `parent?`,
|
||||
we consider `e` as a candidate for case-splitting. For every other argument `e'` that also appears
|
||||
at position `i` in an `f`-application and has the same type as `e`, we add the case-split candidate `e = e'`.
|
||||
Given a term `arg` that occurs as the argument at position `i` of an `f`-application `parent?`,
|
||||
we consider `arg` as a candidate for case-splitting. For every other argument `arg'` that also appears
|
||||
at position `i` in an `f`-application and has the same type as `e`, we add the case-split candidate `arg = arg'`.
|
||||
|
||||
When performing the case split, we consider the following two cases:
|
||||
- `e = e'`, which may introduce a new congruence between the corresponding `f`-applications.
|
||||
- `¬(e = e')`, which may trigger extensionality theorems for the type of `e`.
|
||||
- `arg = arg'`, which may introduce a new congruence between the corresponding `f`-applications.
|
||||
- `¬(arg = arg')`, which may trigger extensionality theorems for the type of `arg`.
|
||||
|
||||
This feature enables `grind` to solve examples such as:
|
||||
```lean
|
||||
@@ -222,13 +227,13 @@ example (f : (Nat → Nat) → Nat) : a = b → f (fun x => a + x) = f (fun x =>
|
||||
grind
|
||||
```
|
||||
-/
|
||||
private def addSplitCandidatesForExt (e : Expr) (generation : Nat) (parent? : Option Expr := none) : GoalM Unit := do
|
||||
private def addSplitCandidatesForExt (arg : Expr) (generation : Nat) (parent? : Option Expr := none) : GoalM Unit := do
|
||||
let some parent := parent? | return ()
|
||||
unless parent.isApp do return ()
|
||||
let f := parent.getAppFn
|
||||
if let .const declName _ := f then
|
||||
if extParentsToIgnore declName then return ()
|
||||
let type ← inferType e
|
||||
let type ← inferType arg
|
||||
-- Remark: we currently do not perform function extensionality on functions that produce a type that is not a proposition.
|
||||
-- We may add an option to enable that in the future.
|
||||
let u? ← typeFormerTypeLevel type
|
||||
@@ -238,28 +243,31 @@ private def addSplitCandidatesForExt (e : Expr) (generation : Nat) (parent? : Op
|
||||
repeat
|
||||
if !it.isApp then return ()
|
||||
i := i - 1
|
||||
let arg := it.appArg!
|
||||
if isSameExpr arg e then
|
||||
found f i type
|
||||
if isSameExpr arg it.appArg! then
|
||||
found f i type parent
|
||||
it := it.appFn!
|
||||
where
|
||||
found (f : Expr) (i : Nat) (type : Expr) : GoalM Unit := do
|
||||
trace[grind.debug.ext] "{f}, {i}, {e}"
|
||||
let others := (← get).termsAt.find? (f, i) |>.getD []
|
||||
for (e', type') in others do
|
||||
if (← withDefault <| isDefEq type type') then
|
||||
let eq := mkApp3 (mkConst ``Eq [← getLevel type]) type e e'
|
||||
found (f : Expr) (i : Nat) (type : Expr) (parent : Expr) : GoalM Unit := do
|
||||
trace_goal[grind.debug.ext] "{f}, {i}, {arg}"
|
||||
let others := (← get).split.argsAt.find? (f, i) |>.getD []
|
||||
for other in others do
|
||||
if (← withDefault <| isDefEq type other.type) then
|
||||
let eq := mkApp3 (mkConst ``Eq [← getLevel type]) type arg other.arg
|
||||
let eq ← shareCommon eq
|
||||
internalize eq generation
|
||||
trace_goal[grind.ext.candidate] "{eq}"
|
||||
addSplitCandidate eq
|
||||
modify fun s => { s with termsAt := s.termsAt.insert (f, i) ((e, type) :: others) }
|
||||
-- We do not use lookahead here because it is too incomplete.
|
||||
-- if (← getConfig).lookahead then
|
||||
-- addLookaheadCandidate (.arg other.app parent i eq)
|
||||
-- else
|
||||
addSplitCandidate (.arg other.app parent i eq)
|
||||
modify fun s => { s with split.argsAt := s.split.argsAt.insert (f, i) ({ arg, type, app := parent } :: others) }
|
||||
return ()
|
||||
|
||||
/-- Applies `addSplitCandidatesForExt` if `funext` is enabled. -/
|
||||
private def addSplitCandidatesForFunext (e : Expr) (generation : Nat) (parent? : Option Expr := none) : GoalM Unit := do
|
||||
private def addSplitCandidatesForFunext (arg : Expr) (generation : Nat) (parent? : Option Expr := none) : GoalM Unit := do
|
||||
unless (← getConfig).funext do return ()
|
||||
addSplitCandidatesForExt e generation parent?
|
||||
addSplitCandidatesForExt arg generation parent?
|
||||
|
||||
@[export lean_grind_internalize]
|
||||
private partial def internalizeImpl (e : Expr) (generation : Nat) (parent? : Option Expr := none) : GoalM Unit := withIncRecDepth do
|
||||
|
||||
@@ -178,6 +178,12 @@ private def isEagerCasesCandidate (goal : Goal) (type : Expr) : Bool := Id.run d
|
||||
let .const declName _ := type.getAppFn | return false
|
||||
return goal.split.casesTypes.isEagerSplit declName
|
||||
|
||||
/-- Returns `true` if `type` is an inductive type with at most one constructor. -/
|
||||
private def isCheapInductive (type : Expr) : CoreM Bool := do
|
||||
let .const declName _ := type.getAppFn | return false
|
||||
let .inductInfo info ← getConstInfo declName | return false
|
||||
return info.numCtors <= 1
|
||||
|
||||
private def applyCases? (goal : Goal) (fvarId : FVarId) : GrindM (Option (List Goal)) := goal.mvarId.withContext do
|
||||
/-
|
||||
Remark: we used to use `whnfD`. This was a mistake, we don't want to unfold user-defined abstractions.
|
||||
@@ -185,6 +191,9 @@ private def applyCases? (goal : Goal) (fvarId : FVarId) : GrindM (Option (List G
|
||||
-/
|
||||
let type ← whnf (← fvarId.getType)
|
||||
if isEagerCasesCandidate goal type then
|
||||
if (← cheapCasesOnly) then
|
||||
unless (← isCheapInductive type) do
|
||||
return none
|
||||
if let .const declName _ := type.getAppFn then
|
||||
saveCases declName true
|
||||
let mvarIds ← cases goal.mvarId (mkFVar fvarId)
|
||||
@@ -205,7 +214,7 @@ private def exfalsoIfNotProp (goal : Goal) : MetaM Goal := goal.mvarId.withConte
|
||||
return { goal with mvarId := (← goal.mvarId.exfalso) }
|
||||
|
||||
/-- Introduce new hypotheses (and apply `by_contra`) until goal is of the form `... ⊢ False` -/
|
||||
partial def intros (generation : Nat) : GrindTactic' := fun goal => do
|
||||
partial def intros (generation : Nat) : GrindTactic' := fun goal => do
|
||||
let rec go (goal : Goal) : StateRefT (Array Goal) GrindM Unit := do
|
||||
if goal.inconsistent then
|
||||
return ()
|
||||
|
||||
101
src/Lean/Meta/Tactic/Grind/Lookahead.lean
Normal file
101
src/Lean/Meta/Tactic/Grind/Lookahead.lean
Normal file
@@ -0,0 +1,101 @@
|
||||
/-
|
||||
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Lean.Meta.Tactic.Grind.Types
|
||||
import Lean.Meta.Tactic.Grind.Intro
|
||||
import Lean.Meta.Tactic.Grind.Arith
|
||||
import Lean.Meta.Tactic.Grind.Split
|
||||
import Lean.Meta.Tactic.Grind.EMatch
|
||||
|
||||
namespace Lean.Meta.Grind
|
||||
|
||||
private partial def solve (generation : Nat) (goal : Goal) : GrindM Bool := do
|
||||
cont (← intros generation goal)
|
||||
where
|
||||
cont (goals : List Goal) : GrindM Bool := do
|
||||
match goals with
|
||||
| [] => return true
|
||||
| [goal] => loop goal
|
||||
| _ => throwError "`grind` lookahead internal error, unexpected number of goals"
|
||||
|
||||
loop (goal : Goal) : GrindM Bool := withIncRecDepth do
|
||||
if goal.inconsistent then
|
||||
return true
|
||||
else if let some goals ← assertNext goal then
|
||||
cont goals
|
||||
else if let some goals ← Arith.check goal then
|
||||
cont goals
|
||||
else if let some goals ← splitNext goal then
|
||||
cont goals
|
||||
else if let some goals ← ematchAndAssert goal then
|
||||
cont goals
|
||||
else
|
||||
return false
|
||||
|
||||
private def tryLookahead (e : Expr) : GoalM Bool := do
|
||||
-- TODO: if `e` is an arithmetic expression, we can avoid creating an auxiliary goal.
|
||||
-- We can assert it directly to the arithmetic module.
|
||||
-- Remark: We can simplify this code because the lookahead only really worked for arithmetic.
|
||||
trace_goal[grind.lookahead.try] "{e}"
|
||||
let proof? ← withoutModifyingState do
|
||||
let goal ← get
|
||||
let tag ← goal.mvarId.getTag
|
||||
let target ← mkArrow (mkNot e) (← getFalseExpr)
|
||||
let mvar ← mkFreshExprMVar target .syntheticOpaque tag
|
||||
let gen ← getGeneration e
|
||||
if (← solve gen { goal with mvarId := mvar.mvarId! }) then
|
||||
return some (← instantiateMVars mvar)
|
||||
else
|
||||
return none
|
||||
if let some proof := proof? then
|
||||
trace[grind.lookahead.assert] "{e}"
|
||||
pushEqTrue e <| mkApp2 (mkConst ``Grind.of_lookahead) e proof
|
||||
processNewFacts
|
||||
return true
|
||||
else
|
||||
return false
|
||||
|
||||
private def withLookaheadConfig (x : GrindM α) : GrindM α := do
|
||||
withTheReader Grind.Context
|
||||
(fun ctx => { ctx with config.qlia := true, cheapCases := true })
|
||||
x
|
||||
|
||||
def lookahead : GrindTactic := fun goal => do
|
||||
unless (← getConfig).lookahead do
|
||||
return none
|
||||
if goal.split.lookaheads.isEmpty then
|
||||
return none
|
||||
withLookaheadConfig do
|
||||
let (progress, goal) ← GoalM.run goal do
|
||||
let mut postponed := []
|
||||
let mut progress := false
|
||||
let infos := (← get).split.lookaheads
|
||||
modify fun s => { s with split.lookaheads := [] }
|
||||
for info in infos do
|
||||
if (← isInconsistent) then
|
||||
return true
|
||||
match (← checkSplitStatus info) with
|
||||
| .resolved => progress := true
|
||||
| .ready _ _ true
|
||||
| .notReady => postponed := info :: postponed
|
||||
| .ready _ _ false =>
|
||||
if (← tryLookahead info.getExpr) then
|
||||
progress := true
|
||||
else
|
||||
postponed := info :: postponed
|
||||
if progress then
|
||||
modify fun s => { s with
|
||||
split.lookaheads := s.split.lookaheads ++ postponed.reverse
|
||||
}
|
||||
return true
|
||||
else
|
||||
return false
|
||||
if progress then
|
||||
return some [goal]
|
||||
else
|
||||
return none
|
||||
|
||||
end Lean.Meta.Grind
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user