Skip to content

Commit 7a5526c

Browse files
authored
Merge branch 'master' into simpa_trailing_comment
2 parents 8c208d7 + 3f33cd6 commit 7a5526c

File tree

389 files changed

+612999
-582782
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

389 files changed

+612999
-582782
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ jobs:
217217
"release": true,
218218
"check-level": 2,
219219
"shell": "msys2 {0}",
220-
"CMAKE_OPTIONS": "-G \"Unix Makefiles\" -DUSE_GMP=OFF",
220+
"CMAKE_OPTIONS": "-G \"Unix Makefiles\"",
221221
// for reasons unknown, interactivetests are flaky on Windows
222222
"CTEST_OPTIONS": "--repeat until-pass:2",
223223
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-w64-windows-gnu.tar.zst",
@@ -227,7 +227,7 @@ jobs:
227227
{
228228
"name": "Linux aarch64",
229229
"os": "nscloud-ubuntu-22.04-arm64-4x8",
230-
"CMAKE_OPTIONS": "-DUSE_GMP=OFF -DLEAN_INSTALL_SUFFIX=-linux_aarch64",
230+
"CMAKE_OPTIONS": "-DLEAN_INSTALL_SUFFIX=-linux_aarch64",
231231
"release": true,
232232
"check-level": 2,
233233
"shell": "nix develop .#oldGlibcAArch -c bash -euxo pipefail {0}",

flake.nix

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@
3838
# more convenient `ctest` output
3939
CTEST_OUTPUT_ON_FAILURE = 1;
4040
} // pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
41-
GMP = pkgsDist.gmp.override { withStatic = true; };
41+
GMP = (pkgsDist.gmp.override { withStatic = true; }).overrideAttrs (attrs:
42+
pkgs.lib.optionalAttrs (pkgs.stdenv.system == "aarch64-linux") {
43+
# would need additional linking setup on Linux aarch64, we don't use it anywhere else either
44+
hardeningDisable = [ "stackprotector" ];
45+
});
4246
LIBUV = pkgsDist.libuv.overrideAttrs (attrs: {
4347
configureFlags = ["--enable-static"];
4448
hardeningDisable = [ "stackprotector" ];

src/Init/Control/Basic.lean

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ instance (priority := 500) instForInOfForIn' [ForIn' m ρ α d] : ForIn m ρ α
3535
simp [h]
3636
rfl
3737

38+
/-- Extract the value from a `ForInStep`, ignoring whether it is `done` or `yield`. -/
39+
def ForInStep.value (x : ForInStep α) : α :=
40+
match x with
41+
| ForInStep.done b => b
42+
| ForInStep.yield b => b
43+
44+
@[simp] theorem ForInStep.value_done (b : β) : (ForInStep.done b).value = b := rfl
45+
@[simp] theorem ForInStep.value_yield (b : β) : (ForInStep.yield b).value = b := rfl
46+
3847
@[reducible]
3948
def Functor.mapRev {f : Type u → Type v} [Functor f] {α β : Type u} : f α → (α → β) → f β :=
4049
fun a f => f <$> a

src/Init/Conv.lean

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Notation for operators defined at Prelude.lean
77
-/
88
prelude
99
import Init.Tactics
10+
import Init.Meta
1011

1112
namespace Lean.Parser.Tactic.Conv
1213

@@ -46,12 +47,20 @@ scoped syntax (name := withAnnotateState)
4647
/-- `skip` does nothing. -/
4748
syntax (name := skip) "skip" : conv
4849

49-
/-- Traverses into the left subterm of a binary operator.
50-
(In general, for an `n`-ary operator, it traverses into the second to last argument.) -/
50+
/--
51+
Traverses into the left subterm of a binary operator.
52+
53+
In general, for an `n`-ary operator, it traverses into the second to last argument.
54+
It is a synonym for `arg -2`.
55+
-/
5156
syntax (name := lhs) "lhs" : conv
5257

53-
/-- Traverses into the right subterm of a binary operator.
54-
(In general, for an `n`-ary operator, it traverses into the last argument.) -/
58+
/--
59+
Traverses into the right subterm of a binary operator.
60+
61+
In general, for an `n`-ary operator, it traverses into the last argument.
62+
It is a synonym for `arg -1`.
63+
-/
5564
syntax (name := rhs) "rhs" : conv
5665

5766
/-- Traverses into the function of a (unary) function application.
@@ -74,13 +83,17 @@ subgoals for all the function arguments. For example, if the target is `f x y` t
7483
`congr` produces two subgoals, one for `x` and one for `y`. -/
7584
syntax (name := congr) "congr" : conv
7685

86+
syntax argArg := "@"? "-"? num
87+
7788
/--
7889
* `arg i` traverses into the `i`'th argument of the target. For example if the
7990
target is `f a b c d` then `arg 1` traverses to `a` and `arg 3` traverses to `c`.
91+
The index may be negative; `arg -1` traverses into the last argument,
92+
`arg -2` into the second-to-last argument, and so on.
8093
* `arg @i` is the same as `arg i` but it counts all arguments instead of just the
8194
explicit arguments.
8295
* `arg 0` traverses into the function. If the target is `f a b c d`, `arg 0` traverses into `f`. -/
83-
syntax (name := arg) "arg " "@"? num : conv
96+
syntax (name := arg) "arg " argArg : conv
8497

8598
/-- `ext x` traverses into a binder (a `fun x => e` or `∀ x, e` expression)
8699
to target `e`, introducing name `x` in the process. -/
@@ -130,11 +143,11 @@ For example, if we are searching for `f _` in `f (f a) = f b`:
130143
syntax (name := pattern) "pattern " (occs)? term : conv
131144

132145
/-- `rw [thm]` rewrites the target using `thm`. See the `rw` tactic for more information. -/
133-
syntax (name := rewrite) "rewrite" (config)? rwRuleSeq : conv
146+
syntax (name := rewrite) "rewrite" optConfig rwRuleSeq : conv
134147

135148
/-- `simp [thm]` performs simplification using `thm` and marked `@[simp]` lemmas.
136149
See the `simp` tactic for more information. -/
137-
syntax (name := simp) "simp" (config)? (discharger)? (&" only")?
150+
syntax (name := simp) "simp" optConfig (discharger)? (&" only")?
138151
(" [" withoutPosition((simpStar <|> simpErase <|> simpLemma),*) "]")? : conv
139152

140153
/--
@@ -151,7 +164,7 @@ example (a : Nat): (0 + 0) = a - a := by
151164
rw [← Nat.sub_self a]
152165
```
153166
-/
154-
syntax (name := dsimp) "dsimp" (config)? (discharger)? (&" only")?
167+
syntax (name := dsimp) "dsimp" optConfig (discharger)? (&" only")?
155168
(" [" withoutPosition((simpErase <|> simpLemma),*) "]")? : conv
156169

157170
/-- `simp_match` simplifies match expressions. For example,
@@ -247,12 +260,12 @@ macro (name := failIfSuccess) tk:"fail_if_success " s:convSeq : conv =>
247260

248261
/-- `rw [rules]` applies the given list of rewrite rules to the target.
249262
See the `rw` tactic for more information. -/
250-
macro "rw" c:(config)? s:rwRuleSeq : conv => `(conv| rewrite $[$c]? $s)
263+
macro "rw" c:optConfig s:rwRuleSeq : conv => `(conv| rewrite $c:optConfig $s)
251264

252-
/-- `erw [rules]` is a shorthand for `rw (config := { transparency := .default }) [rules]`.
265+
/-- `erw [rules]` is a shorthand for `rw (transparency := .default) [rules]`.
253266
This does rewriting up to unfolding of regular definitions (by comparison to regular `rw`
254267
which only unfolds `@[reducible]` definitions). -/
255-
macro "erw" s:rwRuleSeq : conv => `(conv| rw (config := { transparency := .default }) $s:rwRuleSeq)
268+
macro "erw" c:optConfig s:rwRuleSeq : conv => `(conv| rw $[$(getConfigItems c)]* (transparency := .default) $s:rwRuleSeq)
256269

257270
/-- `args` traverses into all arguments. Synonym for `congr`. -/
258271
macro "args" : conv => `(conv| congr)
@@ -263,7 +276,7 @@ macro "right" : conv => `(conv| rhs)
263276
/-- `intro` traverses into binders. Synonym for `ext`. -/
264277
macro "intro" xs:(ppSpace colGt ident)* : conv => `(conv| ext $xs*)
265278

266-
syntax enterArg := ident <|> ("@"? num)
279+
syntax enterArg := ident <|> argArg
267280

268281
/-- `enter [arg, ...]` is a compact way to describe a path to a subterm.
269282
It is a shorthand for other conv tactics as follows:
@@ -272,12 +285,7 @@ It is a shorthand for other conv tactics as follows:
272285
* `enter [x]` (where `x` is an identifier) is equivalent to `ext x`.
273286
For example, given the target `f (g a (fun x => x b))`, `enter [1, 2, x, 1]`
274287
will traverse to the subterm `b`. -/
275-
syntax "enter" " [" withoutPosition(enterArg,+) "]" : conv
276-
macro_rules
277-
| `(conv| enter [$i:num]) => `(conv| arg $i)
278-
| `(conv| enter [@$i]) => `(conv| arg @$i)
279-
| `(conv| enter [$id:ident]) => `(conv| ext $id)
280-
| `(conv| enter [$arg, $args,*]) => `(conv| (enter [$arg]; enter [$args,*]))
288+
syntax (name := enter) "enter" " [" withoutPosition(enterArg,+) "]" : conv
281289

282290
/-- The `apply thm` conv tactic is the same as `apply thm` the tactic.
283291
There are no restrictions on `thm`, but strange results may occur if `thm`

src/Init/Data/Array/Lemmas.lean

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Init.Data.List.Monadic
1010
import Init.Data.List.Range
1111
import Init.Data.List.Nat.TakeDrop
1212
import Init.Data.List.Nat.Modify
13+
import Init.Data.List.Monadic
1314
import Init.Data.Array.Mem
1415
import Init.Data.Array.DecidableEq
1516
import Init.TacticsExtra
@@ -211,17 +212,25 @@ theorem foldrM_push [Monad m] (f : α → β → m β) (init : β) (arr : Array
211212
(arr.push a).foldrM f init = f a init >>= arr.foldrM f := by
212213
simp [foldrM_eq_reverse_foldlM_toList, -size_push]
213214

214-
/-- Variant of `foldrM_push` with the `start := arr.size + 1` rather than `(arr.push a).size`. -/
215-
@[simp] theorem foldrM_push' [Monad m] (f : α → β → m β) (init : β) (arr : Array α) (a : α) :
216-
(arr.push a).foldrM f init (start := arr.size + 1) = f a init >>= arr.foldrM f := by
217-
simp [← foldrM_push]
215+
/--
216+
Variant of `foldrM_push` with `h : start = arr.size + 1`
217+
rather than `(arr.push a).size` as the argument.
218+
-/
219+
@[simp] theorem foldrM_push' [Monad m] (f : α → β → m β) (init : β) (arr : Array α) (a : α)
220+
{start} (h : start = arr.size + 1) :
221+
(arr.push a).foldrM f init start = f a init >>= arr.foldrM f := by
222+
simp [← foldrM_push, h]
218223

219224
theorem foldr_push (f : α → β → β) (init : β) (arr : Array α) (a : α) :
220225
(arr.push a).foldr f init = arr.foldr f (f a init) := foldrM_push ..
221226

222-
/-- Variant of `foldr_push` with the `start := arr.size + 1` rather than `(arr.push a).size`. -/
223-
@[simp] theorem foldr_push' (f : α → β → β) (init : β) (arr : Array α) (a : α) :
224-
(arr.push a).foldr f init (start := arr.size + 1) = arr.foldr f (f a init) := foldrM_push' ..
227+
/--
228+
Variant of `foldr_push` with the `h : start = arr.size + 1`
229+
rather than `(arr.push a).size` as the argument.
230+
-/
231+
@[simp] theorem foldr_push' (f : α → β → β) (init : β) (arr : Array α) (a : α) {start}
232+
(h : start = arr.size + 1) : (arr.push a).foldr f init start = arr.foldr f (f a init) :=
233+
foldrM_push' _ _ _ _ h
225234

226235
/-- A more efficient version of `arr.toList.reverse`. -/
227236
@[inline] def toListRev (arr : Array α) : List α := arr.foldl (fun l t => t :: l) []
@@ -1608,6 +1617,13 @@ theorem filterMap_toArray (f : α → Option β) (l : List α) :
16081617

16091618
end List
16101619

1620+
namespace Array
1621+
1622+
@[simp] theorem mapM_id {l : Array α} {f : α → Id β} : l.mapM f = l.map f := by
1623+
induction l; simp_all
1624+
1625+
end Array
1626+
16111627
/-! ### Deprecations -/
16121628

16131629
namespace List

src/Init/Data/BitVec/Bitblast.lean

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,30 @@ theorem carry_succ (i : Nat) (x y : BitVec w) (c : Bool) :
174174
exact mod_two_pow_add_mod_two_pow_add_bool_lt_two_pow_succ ..
175175
cases x.toNat.testBit i <;> cases y.toNat.testBit i <;> (simp; omega)
176176

177+
theorem carry_succ_one (i : Nat) (x : BitVec w) (h : 0 < w) :
178+
carry (i+1) x (1#w) false = decide (∀ j ≤ i, x.getLsbD j = true) := by
179+
induction i with
180+
| zero => simp [carry_succ, h]
181+
| succ i ih =>
182+
rw [carry_succ, ih]
183+
simp only [getLsbD_one, add_one_ne_zero, decide_False, Bool.and_false, atLeastTwo_false_mid]
184+
cases hx : x.getLsbD (i+1)
185+
case false =>
186+
have : ∃ j ≤ i + 1, x.getLsbD j = false :=
187+
⟨i+1, by omega, hx⟩
188+
simpa
189+
case true =>
190+
suffices
191+
(∀ (j : Nat), j ≤ i → x.getLsbD j = true)
192+
↔ (∀ (j : Nat), j ≤ i + 1 → x.getLsbD j = true) by
193+
simpa
194+
constructor
195+
· intro h j hj
196+
rcases Nat.le_or_eq_of_le_succ hj with (hj' | rfl)
197+
· apply h; assumption
198+
· exact hx
199+
· intro h j hj; apply h; omega
200+
177201
/--
178202
If `x &&& y = 0`, then the carry bit `(x + y + 0)` is always `false` for any index `i`.
179203
Intuitively, this is because a carry is only produced when at least two of `x`, `y`, and the
@@ -352,6 +376,117 @@ theorem bit_neg_eq_neg (x : BitVec w) : -x = (adc (((iunfoldr (fun (i : Fin w) c
352376
simp [← sub_toAdd, BitVec.sub_add_cancel]
353377
· simp [bit_not_testBit x _]
354378

379+
/--
380+
Remember that negating a bitvector is equal to incrementing the complement
381+
by one, i.e., `-x = ~~~x + 1`. See also `neg_eq_not_add`.
382+
383+
This computation has two crucial properties:
384+
- The least significant bit of `-x` is the same as the least significant bit of `x`, and
385+
- The `i+1`-th least significant bit of `-x` is the complement of the `i+1`-th bit of `x`, unless
386+
all of the preceding bits are `false`, in which case the bit is equal to the `i+1`-th bit of `x`
387+
-/
388+
theorem getLsbD_neg {i : Nat} {x : BitVec w} :
389+
getLsbD (-x) i =
390+
(getLsbD x i ^^ decide (i < w) && decide (∃ j < i, getLsbD x j = true)) := by
391+
rw [neg_eq_not_add]
392+
by_cases hi : i < w
393+
· rw [getLsbD_add hi]
394+
have : 0 < w := by omega
395+
simp only [getLsbD_not, hi, decide_True, Bool.true_and, getLsbD_one, this, not_bne,
396+
_root_.true_and, not_eq_eq_eq_not]
397+
cases i with
398+
| zero =>
399+
have carry_zero : carry 0 ?x ?y false = false := by
400+
simp [carry]; omega
401+
simp [hi, carry_zero]
402+
| succ =>
403+
rw [carry_succ_one _ _ (by omega), ← Bool.xor_not, ← decide_not]
404+
simp only [add_one_ne_zero, decide_False, getLsbD_not, and_eq_true, decide_eq_true_eq,
405+
not_eq_eq_eq_not, Bool.not_true, false_bne, not_exists, _root_.not_and, not_eq_true,
406+
bne_left_inj, decide_eq_decide]
407+
constructor
408+
· rintro h j hj; exact And.right <| h j (by omega)
409+
· rintro h j hj; exact ⟨by omega, h j (by omega)⟩
410+
· have h_ge : w ≤ i := by omega
411+
simp [getLsbD_ge _ _ h_ge, h_ge, hi]
412+
413+
theorem getMsbD_neg {i : Nat} {x : BitVec w} :
414+
getMsbD (-x) i =
415+
(getMsbD x i ^^ decide (∃ j < w, i < j ∧ getMsbD x j = true)) := by
416+
simp only [getMsbD, getLsbD_neg, Bool.decide_and, Bool.and_eq_true, decide_eq_true_eq]
417+
by_cases hi : i < w
418+
case neg =>
419+
simp [hi]; omega
420+
case pos =>
421+
have h₁ : w - 1 - i < w := by omega
422+
simp only [hi, decide_True, h₁, Bool.true_and, Bool.bne_left_inj, decide_eq_decide]
423+
constructor
424+
· rintro ⟨j, hj, h⟩
425+
refine ⟨w - 1 - j, by omega, by omega, by omega, _root_.cast ?_ h⟩
426+
congr; omega
427+
· rintro ⟨j, hj₁, hj₂, -, h⟩
428+
exact ⟨w - 1 - j, by omega, h⟩
429+
430+
theorem msb_neg {w : Nat} {x : BitVec w} :
431+
(-x).msb = ((x != 0#w && x != intMin w) ^^ x.msb) := by
432+
simp only [BitVec.msb, getMsbD_neg]
433+
by_cases hmin : x = intMin _
434+
case pos =>
435+
have : (∃ j, j < w ∧ 0 < j ∧ 0 < w ∧ j = 0) ↔ False := by
436+
simp; omega
437+
simp [hmin, getMsbD_intMin, this]
438+
case neg =>
439+
by_cases hzero : x = 0#w
440+
case pos => simp [hzero]
441+
case neg =>
442+
have w_pos : 0 < w := by
443+
cases w
444+
· rw [@of_length_zero x] at hzero
445+
contradiction
446+
· omega
447+
suffices ∃ j, j < w ∧ 0 < j ∧ x.getMsbD j = true
448+
by simp [show x != 0#w by simpa, show x != intMin w by simpa, this]
449+
false_or_by_contra
450+
rename_i getMsbD_x
451+
simp only [not_exists, _root_.not_and, not_eq_true] at getMsbD_x
452+
/- `getMsbD` says that all bits except the msb are `false` -/
453+
cases hmsb : x.msb
454+
case true =>
455+
apply hmin
456+
apply eq_of_getMsbD_eq
457+
rintro ⟨i, hi⟩
458+
simp only [getMsbD_intMin, w_pos, decide_True, Bool.true_and]
459+
cases i
460+
case zero => exact hmsb
461+
case succ => exact getMsbD_x _ hi (by omega)
462+
case false =>
463+
apply hzero
464+
apply eq_of_getMsbD_eq
465+
rintro ⟨i, hi⟩
466+
simp only [getMsbD_zero]
467+
cases i
468+
case zero => exact hmsb
469+
case succ => exact getMsbD_x _ hi (by omega)
470+
471+
/-! ### abs -/
472+
473+
theorem msb_abs {w : Nat} {x : BitVec w} :
474+
x.abs.msb = (decide (x = intMin w) && decide (0 < w)) := by
475+
simp only [BitVec.abs, getMsbD_neg, ne_eq, decide_not, Bool.not_bne]
476+
by_cases h₀ : 0 < w
477+
· by_cases h₁ : x = intMin w
478+
· simp [h₁, msb_intMin]
479+
· simp only [neg_eq, h₁, decide_False]
480+
by_cases h₂ : x.msb
481+
· simp [h₂, msb_neg]
482+
and_intros
483+
· by_cases h₃ : x = 0#w
484+
· simp [h₃] at h₂
485+
· simp [h₃]
486+
· simp [h₁]
487+
· simp [h₂]
488+
· simp [BitVec.msb, show w = 0 by omega]
489+
355490
/-! ### Inequalities (le / lt) -/
356491

357492
theorem ult_eq_not_carry (x y : BitVec w) : x.ult y = !carry w x (~~~y) true := by

0 commit comments

Comments
 (0)