Compare commits

...

164 Commits

Author SHA1 Message Date
Kim Morrison
189070444f . 2024-12-19 21:17:40 +11:00
Kim Morrison
75772e3009 merge master 2024-12-16 21:13:19 +11:00
Kim Morrison
007b20395b feat: lemmas about lexicographic order on Array and Vector 2024-12-16 21:12:44 +11:00
Eric Wieser
1b15a0f27c fix: add missing fields in the profiler datastructures (#6363)
This PR fixes errors at load time in the comparison mode of the Firefox
profiler.

See https://github.com/firefox-devtools/profiler/issues/5254


6306555856/src/types/profile.js (L313)
suggests there are a _lot_ of missing fields in these structures, which
means the firefox profiler could at any point break any historic
profiler data.


https://profiler.firefox.com/compare/calltree/?globalTrackOrder=0w2&profiles[]=https%3A%2F%2Fprofiler.firefox.com%2Fpublic%2Fx1j7asq6jwsyc368j58m8brbqef6s8vqsx0mnzr%2Fcalltree%2F%3FglobalTrackOrder%3D0%26thread%3D0%26v%3D10&profiles[]=https%3A%2F%2Fprofiler.firefox.com%2Fpublic%2F55hw0v1q2zhe2w6ds3zckt04d55vsa6wd9kqb4r%2Fcalltree%2F%3FglobalTrackOrder%3D0%26thread%3D0%26v%3D10&thread=0&timelineType=category&v=10
is a demo of this working.
2024-12-16 08:23:51 +00:00
Leonardo de Moura
0340f904b3 fix: check must check projections (#6398)
This PR ensures `Meta.check` check projections.

closes #5660
2024-12-16 06:42:18 +00:00
Kim Morrison
791bea027f feat: lemmas about Std.Range (#6396)
This PR adds lemmas reducing for loops over `Std.Range` to for loops
over `List.range'`.

Equivalent theorems previously existed in Batteries, but the underlying
definitions have changed so these are written from scratch.
2024-12-16 03:16:46 +00:00
Kim Morrison
a8d323db33 merge 2024-12-16 13:54:38 +11:00
Kim Morrison
155813a396 finish lemmas 2024-12-16 13:52:25 +11:00
Eric Wieser
5c2ef51b44 chore: add gitpod configuration (#6382)
This PR adds a dockerfile for use with Gitpod.

This provides all the dependencies, and kicks off a build once the
editor is opened for the first time.

It can be tested by going to
https://gitpod.io/#https://github.com/leanprover/lean4/pull/6382

This should make it less painful for users hoping to contribute small
lemmas to `Init/` and `Std/`; they can open gitpod and wait, rather than
having to read the docs to run a series of commands.
2024-12-15 21:38:13 +00:00
Mac Malone
a8656c5812 feat: generalize panic to Sort (#6333)
This PR generalizes the panic functions to a type of `Sort u` rather
than `Type u`. This better supports universe polymorphic types and
avoids confusing errors.

An minimal (but somewhat contrived) example of such a confusing error
is:

```lean
/-
stuck at solving universe constraint
  ?u.59+1 =?= max 1 ?u.7
while trying to unify
  Subtype.{?u.7} P : Sort (max 1 ?u.7)
with
  Subtype.{?u.7} P : Sort (max 1 ?u.7)
-/
def assertSubtype! {P : α → Prop} [Inhabited (Subtype P)] (a : α) [Decidable (P a)] : Subtype P := -- errors on :=
  if h : P a then 
    ⟨a, h⟩ 
  else 
    panic! "Property not satisified"
```
2024-12-15 21:36:45 +00:00
Eric Wieser
a8dc619f8e doc: split the docstring of LocalContext (#6340)
This results in better hovers in VSCode, without duplicating information
in a way that might go out of sync.
2024-12-15 21:35:25 +00:00
Kim Morrison
80fb404a04 chore: require 0 < Range.step (#6391)
This PR requires that the step size in `Std.Range` is positive, to avoid
ill-specified behaviour.
2024-12-15 11:33:41 +00:00
Kim Morrison
49ad9d1821 . 2024-12-15 22:19:51 +11:00
Kim Morrison
a3588d9a70 . 2024-12-15 22:19:42 +11:00
Kim Morrison
63dea907aa merge master 2024-12-15 21:36:03 +11:00
Kim Morrison
195a93c22d Merge remote-tracking branch 'origin/master' into range_step_pos 2024-12-15 21:34:29 +11:00
Kim Morrison
0c010eb8fb fix 2024-12-15 21:34:07 +11:00
Kim Morrison
474adc8c9e feat: redefine Range.forIn' (#6390)
This PR redefines `Range.forIn'` and `Range.forM`, in preparation for
writing lemmas about them.
2024-12-15 09:47:50 +00:00
Kim Morrison
6893913683 feat: replace List.lt with List.Lex (#6379)
This PR replaces `List.lt` with `List.Lex`, from Mathlib, and adds the
new `Bool` valued lexicographic comparatory function `List.lex`. This
subtly changes the definition of `<` on Lists in some situations.

`List.lt` was a weaker relation: in particular if `l₁ < l₂`, then
`a :: l₁ < b :: l₂` may hold according to `List.lt` even if `a` and `b`
are merely incomparable
(either neither `a < b` nor `b < a`), whereas according to `List.Lex`
this would require `a = b`.

When `<` is total, in the sense that `¬ · < ·` is antisymmetric, then
the two relations coincide.

Mathlib was already overriding the order instances for `List α`,
so this change should not be noticed by anyone already using Mathlib.

We simultaneously add the boolean valued `List.lex` function,
parameterised by a `BEq` typeclass
and an arbitrary `lt` function. This will support the flexibility
previously provided for `List.lt`,
via a `==` function which is weaker than strict equality.
2024-12-15 08:22:39 +00:00
Kim Morrison
8af9462e9a chore: require 0 < Range.step 2024-12-15 18:25:39 +11:00
Leonardo de Moura
a8a160b091 fix: revertAll must clear auxiliary declarations (#6386)
This PR ensures that `revertAll` clears auxiliary declarations when
invoked directly by users.

closes #6263
2024-12-15 00:56:57 +00:00
Leonardo de Moura
e08d35cea1 fix: type incorrect term produced by contradiction (#6387)
This PR fixes a type error in the proof generated by the `contradiction`
tactic.

closes #4851
2024-12-15 00:21:15 +00:00
Leonardo de Moura
94641e88cf fix: simp_all? local declarations (#6385)
This PR fixes a bug in `simp_all?` that caused some local declarations
to be omitted from the `Try this:` suggestions.

closes #3519
2024-12-14 23:13:30 +00:00
Leonardo de Moura
b721c0f540 test: add test for issue #4585 (#6384)
This issue has been fixed by #6123

closes #4585
2024-12-14 22:12:00 +00:00
Leonardo de Moura
f790b1999f fix: new code generator must generate code for opaque declarations that are not @[extern] (#6383)
This PR ensures the new code generator produces code for `opaque`
definitions that are not tagged as `@[extern]`.
Remark: This is the behavior of the old code generator.
2024-12-14 20:26:14 +00:00
Leonardo de Moura
6571bc01d7 fix: withTrackingZetaDelta must reset cache (#6381)
This PR fixes a bug in `withTrackingZetaDelta` and
`withTrackingZetaDeltaSet`. The `MetaM` caches need to be reset. See new
test.
2024-12-14 18:23:32 +00:00
Kim Morrison
37122c3262 chore: move implementation details of mergeSort into namespace (#6380) 2024-12-14 11:24:15 +00:00
Mac Malone
280fcc9883 feat: lean --error=kind (#6362)
This PR adds the `--error=kind` option (shorthand: `-Ekind`) to the
`lean` CLI. When set, messages of `kind` (e.g.,
`linter.unusedVariables`) will be reported as errors. This setting does
nothing in interactive contexts (e.g., the server).

Closes #5194.

The spelling `--error` was chosen instead of the common `-Werror` both
for practical and behavioral reasons. Behaviorally, this option effects
not just warnings, but informational messages as well. Practically,
`-Werror` conflicts with the existing `-W` option for the worker and
`lean` also does not currently use long single-hyphen option names.
2024-12-14 01:31:14 +00:00
Leonardo de Moura
19eac5f341 fix: propagate Simp.Config when reducing terms and checking definitional equality in simp (#6123)
This PR ensures that the configuration in `Simp.Config` is used when
reducing terms and checking definitional equality in `simp`.

closes #5455

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2024-12-14 00:59:40 +00:00
Cameron Zwarich
aa00725624 chore: stop running compiler twice during tests (#6321)
The reason given for this in the comment seemingly no longer holds.

Co-authored-by: Cameron Zwarich <cameron@lean-fro.org>
2024-12-13 23:59:20 +00:00
Cameron Zwarich
7530fd6955 chore: remove Lean.Compiler.LCNF.ForEachExpr (#6313)
Co-authored-by: Cameron Zwarich <cameron@lean-fro.org>
2024-12-13 23:58:42 +00:00
Alissa Tung
58ffd15a8f doc: fix typo reference in doc of lazy discrimination tree (#6377)
This PR fix a bad reference in doc of lazy discrimination tree.
2024-12-13 07:41:04 +00:00
Kim Morrison
bac34c7767 feat: theorems about == on Vector (#6376)
This PR adds theorems about `==` on `Vector`, reproducing those already
on `List` and `Array`.
2024-12-13 02:07:12 +00:00
Kim Morrison
db354d2cde chore: run Batteries linter on Lean (#6364)
This PR makes fixes suggested by the Batteries environment linters,
particularly `simpNF`, and `unusedHavesSuffices`.
2024-12-13 01:28:53 +00:00
Leonardo de Moura
945abe0065 fix: unused let_fun elimination in simp (#6375)
This PR fixes a bug in the simplifier. It was producing terms with loose
bound variables when eliminating unused `let_fun` expressions.

This issue was affecting the example at #6374. The example is now timing
out.
2024-12-13 01:18:46 +00:00
Kim Morrison
48be424eaa feat: lemmas about Vector.any/all/set (#6369)
This PR adds lemmas about `Vector.set`, `anyM`, `any`, `allM`, and
`all`.

With these additions, `Vector` is now as in-sync with the `List` API as
`Array` is, and in future I'll be updating both simultaneously.
2024-12-12 04:48:34 +00:00
Kyle Miller
58f8e21502 feat: labeled and unique sorries (#5757)
This PR makes it harder to create "fake" theorems about definitions that
are stubbed-out with `sorry` by ensuring that each `sorry` is not
definitionally equal to any other. For example, this now fails:
```lean
example : (sorry : Nat) = sorry := rfl -- fails
```
However, this still succeeds, since the `sorry` is a single
indeterminate `Nat`:
```lean
def f (n : Nat) : Nat := sorry
example : f 0 = f 1 := rfl -- succeeds
```
One can be more careful by putting parameters to the right of the colon:
```lean
def f : (n : Nat) → Nat := sorry
example : f 0 = f 1 := rfl -- fails
```
Most sources of synthetic sorries (recall: a sorry that originates from
the elaborator) are now unique, except for elaboration errors, since
making these unique tends to cause a confusing cascade of errors. In
general, however, such sorries are labeled. This enables "go to
definition" on `sorry` in the Infoview, which brings you to its origin.
The option `set_option pp.sorrySource true` causes the pretty printer to
show source position information on sorries.

**Details:**

* Adds `Lean.Meta.mkLabeledSorry`, which creates a sorry that is labeled
with its source position. For example, `(sorry : Nat)` might elaborate
to
  ```
sorryAx (Lean.Name → Nat) false
`lean.foo.12.8.12.13.8.13._sorry._@.lean.foo._hyg.153
  ```
It can either be made unique (like the above) or merely labeled. Labeled
sorries use an encoding that does not impact defeq:
  ```
sorryAx (Unit → Nat) false (Function.const Lean.Name ()
`lean.foo.14.7.13.7.13.69._sorry._@.lean.foo._hyg.174)
  ```

* Makes the `sorry` term, the `sorry` tactic, and every elaboration
failure create labeled sorries. Most are unique sorries, but some
elaboration errors are labeled sorries.

* Renames `OmissionInfo` to `DelabTermInfo` and adds configuration
options to control LSP interactions. One field is a source position to
use for "go to definition". This is used to implement "go to definition"
on labeled sorries.

* Makes hovering over a labeled `sorry` show something friendlier than
that full `sorryAx` expression. Instead, the first hover shows the
simplified ``sorry `«lean.foo:48:11»``. Hovering over that hover shows
the full `sorryAx`. Setting `set_option pp.sorrySource true` makes
`sorry` always start with printing with this source position
information.

* Removes `Lean.Meta.mkSyntheticSorry` in favor of `Lean.Meta.mkSorry`
and `Lean.Meta.mkLabeledSorry`.

* Changes `sorryAx` so that the `synthetic` argument is no longer
optional.

* Gives `addPPExplicitToExposeDiff` awareness of labeled sorries. It can
set `pp.sorrySource` when source positions differ.

* Modifies the delaborator framework so that delaborators can set Info
themselves without it being overwritten.

Incidentally closes #4972.

Inspired by [this Zulip
thread](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/Is.20a.20.60definition_wanted.60.20keyword.20possible.3F/near/477260277).
2024-12-11 23:53:02 +00:00
Mac Malone
a64a17e914 feat: Nat.shiftRight_bitwise_distrib (#6334)
This PR adds `Nat` theorems for distributing `>>>` over bitwise
operations, paralleling those of `BitVec`.

This enables closing goals like the following using `simp`:

```lean
example (n : Nat) : (n <<< 2 ||| 3) >>> 2 = n := by simp [Nat.shiftRight_or_distrib]
```

It might be nice for these theorems to be `simp` lemmas, but they are
not currently in order to be consistent with the existing `BitVec` and
`div_two` theorems.
2024-12-11 23:30:54 +00:00
Sebastian Ullrich
b862e2d251 chore: preserve reported messages in MessageLog (#6307)
Fixes #4460 (and similar future changes) making prior messages
inaccessible to metaprograms such as linters
2024-12-11 12:24:00 +00:00
Kim Morrison
8709ca35e9 chore: DecidableRel allows a heterogeneous relation (#6341)
This PR generalizes `DecidableRel` to allow a heterogeneous relation.
2024-12-11 05:02:58 +00:00
Mac Malone
19fb1fb388 feat: do not propagate pretty printer errors through messages (#3696)
This PR makes all message constructors handle pretty printer errors.

Prior to this change, pretty printer errors in messages were not
uniformly handled. In core, some printers capture their errors (e.g.,
`ppExprWithInfos` and `ppTerm` ) and some do not (e.g., `ppGoal` and
`ppSignature`) propagate them to whatever serializes the message (e.g.,
the frontend).

To resolve this inconsistency and uniformly handle errors, the signature
for `ofLazy` now uses `BaseIO`. As such, all printers been adapted to
capture any errors within them and print similar messages to
`ppExprWithInfos` and `ppTerm` on such errors.
2024-12-11 04:10:09 +00:00
Kim Morrison
cb31ddc6ad feat: lemmas about indexing and membership for Vector (#6367)
This PR brings Vector lemmas about membership and indexing to parity
with List and Array.
2024-12-11 03:52:04 +00:00
Leonardo de Moura
633c825ff3 feat: add Float32 support (#6366)
This PR adds support for `Float32` and fixes a bug in the runtime.
2024-12-11 02:55:58 +00:00
Kim Morrison
c83ce020bf feat: alignment of Array.set lemmas with List lemmas (#6365)
This PR expands the `Array.set` and `Array.setIfInBounds` lemmas to
match existing lemmas for `List.set`.
2024-12-11 01:45:06 +00:00
Kyle Miller
cd909b0a98 fix: when pretty printing constant names, do not use aliases from "non-API exports" (#5689)
This PR adjusts the way the pretty printer unresolves names. It used to
make use of all `export`s when pretty printing, but now it only uses
`export`s that put names into parent namespaces (heuristic: these are
"API exports" that are intended by the library author), rather than
"horizontal exports" that put the names into an unrelated namespace,
which the dot notation feature in #6189 now incentivizes.

Closes the already closed #2524
2024-12-10 17:50:50 +00:00
Joachim Breitner
d27c5afa6e refactor: ArgsPacker.unpack to return Option (#6359)
so that it can be used in pure code and that the error message can be
adjusted
2024-12-10 15:23:13 +00:00
Joachim Breitner
938651121f refactor: elabWFRel to take names, not PreDefinition (#6358)
just to clarify what this function can or cannot do
2024-12-10 14:46:48 +00:00
Joachim Breitner
a9b6a9a975 refactor: WF.EqnInfo.hasInduct (#6357)
after #6355 not all functions with equation infos will support
functional induction, so prepare a flag to guide the name reservation.
2024-12-10 14:33:10 +00:00
Joachim Breitner
d5b565e95f refactor: make mkInhabitantFor error message configurable (#6356)
preparation for #6355
2024-12-10 14:32:19 +00:00
Kim Morrison
27c2323ef9 chore: alignment of Array.any/all lemmas with List (#6353)
This PR reproduces the API around `List.any/all` for `Array.any/all`.
2024-12-10 09:23:52 +00:00
Tobias Grosser
17865394d4 feat: BitVec.[toInt|toFin|getMsbD]_ofBool (#6317)
This PR completes the basic API for BitVec.ofBool.

---------

Co-authored-by: Kim Morrison <scott@tqft.net>
2024-12-10 08:46:24 +00:00
Sebastian Ullrich
a805946466 chore: adjust CODEOWNERS (#6327)
Remove some noise from my assignments
2024-12-10 08:37:20 +00:00
Lean stage0 autoupdater
8a3a806b1a chore: update stage0 2024-12-10 03:47:20 +00:00
Leonardo de Moura
5c333ef969 fix: Float32 runtime support (#6350)
This PR adds missing features and fixes bugs in the `Float32` support
2024-12-10 01:37:01 +00:00
Kim Morrison
e69bcb0757 chore: improve BitVec ext lemmas (#6349)
This PR modifies `BitVec` extensionality lemmas to prefer bounded Nats
over `Fin`, and avoids unnecessary use of `bif` in BitVec theorems.
2024-12-10 01:33:09 +00:00
Tobias Grosser
c5b82e0b16 feat: BitVec.[toFin|getMsbD]_setWidth and [getMsbD|msb]_signExtend (#6338)
This PR adds `BitVec.[toFin|getMsbD]_setWidth` and
`[getMsb|msb]_signExtend` as well as `ofInt_toInt`.

Also correct renamed the misnamed theorem for
`signExtend_eq_setWidth_of_msb_false`.

---------

Co-authored-by: Siddharth <siddu.druid@gmail.com>
2024-12-10 01:17:20 +00:00
Lean stage0 autoupdater
b6177bad9c chore: update stage0 2024-12-09 22:30:45 +00:00
Leonardo de Moura
2e11b8ac88 feat: add support for Float32 to the Lean runtime (#6348)
This PR adds support for `Float32` to the Lean runtime.

We need an update stage0, and then uncomment `Float32.lean` file.
2024-12-09 21:33:43 +00:00
Alex Keizer
ff3d12c8b5 doc: clarify difference between Expr.hasLooseBVars and Expr.hasLooseBVar (#6344)
This PR adds docstrings to `Expr.hasLooseBVars` and `Expr.hasLooseBVar`,
to clarify the difference between these functions, and to document that
the former traverses the expression, while the latter is constant-time,
using cached information.

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2024-12-09 21:15:16 +00:00
Kim Morrison
520d4b698f chore: cleanup of Array lemmas (#6343)
Continuing cleanup of Array lemmas.
2024-12-09 14:04:16 +00:00
Kim Morrison
c7b8c5c6a6 chore: alignment of Array and List lemmas (#6342)
Further alignment of `Array` and `List` lemmas. Moved lemmas about
`List.toArray` to a separate file, and aligned lemmas about membership.
2024-12-09 11:30:45 +00:00
Kyle Miller
3f791933f1 chore: release notes for 4.14.0 (#6339) 2024-12-09 05:30:50 +00:00
Kyle Miller
63791f0177 feat: _ separators in numeric literals (#6204)
This PR lets `_` be used in numeric literals as a separator. For
example, `1_000_000`, `0xff_ff` or `0b_10_11_01_00`. New lexical syntax:
```text
numeral10 : [0-9]+ ("_"+ [0-9]+)*
numeral2  : "0" [bB] ("_"* [0-1]+)+
numeral8  : "0" [oO] ("_"* [0-7]+)+
numeral16 : "0" [xX] ("_"* hex_char+)+
float     : numeral10 "." numeral10? [eE[+-]numeral10]
```

Closes #6199
2024-12-08 22:23:12 +00:00
Kim Morrison
6abb8aad43 chore: cleanup of Array lemmas (#6337)
This PRs continues cleaning up Array lemmas and improving alignment with
List.
2024-12-08 22:03:23 +00:00
Kim Morrison
4dd182c554 chore: remove deprecated aliases for Int.tdiv and Int.tmod (#6322)
This PR removes the deprecated aliases `Int.div := Int.tdiv` and
`Int.mod := Int.tmod`. Later we will rename `Int.ediv` to `Int.div` and
`Int.emod` to `Int.mod`.
2024-12-08 05:19:42 +00:00
jsr-p
762c5758f5 doc: missing (type := true) in reader monad example (#6196)
This PR adds missing `(types := true)` to `#reduce` example in [Readers
example](https://lean-lang.org/lean4/doc/monads/readers.lean.html).
Since [4.10](https://lean-lang.org/blog/2024-8-1-lean-4100/) the `(types
:= true)` is necessary for the `ReaderM Environment String` type to be
reduced into `Environment → String`.
2024-12-07 15:59:36 +00:00
Joachim Breitner
6447fda253 feat: FunInd: omit unused parameters (#6330)
This PR removes unnecessary parameters from the funcion induction
principles. This is a breaking change; broken code can typically be adjusted
simply by passing fewer parameters.

Part 2, adjusting after stage0 update.

Closes #6320
2024-12-07 04:19:21 +01:00
Joachim Breitner
279f36b4cc chore: update stage0 2024-12-07 04:19:21 +01:00
Joachim Breitner
d2853ecbc4 feat: FunInd: omit unused parameters (#6330)
This PR removes unnecessary parameters from the funcion induction
principles. This is a breaking change; broken code can typically be adjusted
simply by passing fewer parameters.

Part 1, before stage0 update.

Closes #6320
2024-12-07 04:19:21 +01:00
Kim Morrison
6e60d13084 feat: getElem lemmas for Vector operations (#6324)
This PR adds `GetElem` lemmas for the basic `Vector` operations.

The `Vector` API is still very sparse, but I'm hoping to infill rapidly.
2024-12-06 01:45:19 +00:00
Kim Morrison
019f8e175f chore: protect Fin.cast and BitVec.cast (#6315)
This PR adds `protected` to `Fin.cast` and `BitVec.cast`, to avoid
confusion with `_root_.cast`. These should mostly be used via
dot-notation in any case.
2024-12-05 06:11:45 +00:00
Kim Morrison
c366a291ca chore: generalize universe in Array.find? (#6318)
This PR generalizes the universe level for `Array.find?`, by giving it a
separate implementation from `Array.findM?`.
2024-12-05 06:11:40 +00:00
Alex Keizer
1400b95ffb feat: upstream ToLevel from mathlib (#6285)
This PR upstreams the `ToLevel` typeclass from mathlib and uses it to
fix the existing `ToExpr` instances so that they are truly universe
polymorphic (previously it generated malformed expressions when the
universe level was nonzero). We improve on the mathlib definition of
`ToLevel` to ensure the class always lives in `Type`, irrespective of
the universe parameter.

This implements part one of the plan to upstream a derive handler for
`ToExpr`, as discussed in #5906 and #5909.

---------

Co-authored-by: Kyle Miller <kmill31415@gmail.com>
Co-authored-by: Tobias Grosser <tobias@grosser.es>
2024-12-05 05:50:32 +00:00
Kim Morrison
00c7b85261 feat: lemmas about for loops over Option (#6316)
This PR adds lemmas simplifying `for` loops over `Option` into
`Option.pelim`, giving parity with lemmas simplifying `for` loops of
`List` into `List.fold`.
2024-12-05 05:09:07 +00:00
Leonardo de Moura
f6e88e5a05 fix: missing HEq support at ToLCNF (#6311)
This PR adds support for `HEq` to the new code generator.
2024-12-04 19:49:16 +00:00
Sebastian Ullrich
88573c802d test: do not filter output for non-diff tests (#6308) 2024-12-04 17:49:35 +00:00
Henrik Böving
faf07e58db chore: remove unused imports (#6305)
This PR removes an unused import in the time library that can yield to
import cycles when building stuff that gets imported by `Std.Internal`
but also wants to import `Std.Time`.
2024-12-04 12:46:08 +00:00
Tobias Grosser
c5181569f9 feat: BitVec.[toInt|toFin]_concat and Bool.toInt (#6182)
This PR adds `BitVec.[toInt|toFin]_concat` and moves a couple of
theorems into the concat section, as `BitVec.msb_concat` is needed for
the `toInt_concat` proof.

We also add `Bool.toInt`.
2024-12-04 01:53:30 +00:00
Siddharth
77211029da feat: BitVec.toFin/ToInt BitVec.ushiftRight (#6238)
This PR adds theorems characterizing the value of the unsigned shift
right of a bitvector in terms of its 2s complement interpretation as an
integer.
Unsigned shift right by at least one bit makes the value of the
bitvector less than or equal to `2^(w-1)`,
makes the interpretation of the bitvector `Int` and `Nat` agree.
In the case when `n = 0`, then the shift right value equals the integer
interpretation.

```lean
theorem toInt_ushiftRight_eq_ite {x : BitVec w} {n : Nat} :
  (x >>> n).toInt = if n = 0 then x.toInt else x.toNat >>> n
```

```lean
theorem toFin_uShiftRight {x : BitVec w} {n : Nat} :
  (x >>> n).toFin = x.toFin / (Fin.ofNat' (2^w) (2^n))
```

---------

Co-authored-by: Harun Khan <harun19@stanford.edu>
Co-authored-by: Tobias Grosser <github@grosser.es>
2024-12-04 01:49:58 +00:00
Lean stage0 autoupdater
da9a0c4190 chore: update stage0 2024-12-04 00:04:00 +00:00
Leonardo de Moura
b9bf94313a feat: add debug.proofAsSorry (#6300)
This PR adds the `debug.proofAsSorry` option. When enabled, the proofs
of theorems are ignored and replaced with `sorry`.
2024-12-03 23:21:38 +00:00
Sebastian Ullrich
2a891a3889 chore: CMAKE_CXX_SYSROOT_FLAG is also needed for linking (#6297)
Fixes #6296
2024-12-03 16:14:22 +00:00
Sebastian Ullrich
00718c3959 chore: clean up Elab.async handling (#6299)
* Make sure metaprogramming users cannot be surprised by its
introduction
* Make `#guard_msgs` compatible with its use
2024-12-03 12:42:02 +00:00
Sebastian Ullrich
473274f145 chore: update stage0 2024-12-03 13:59:37 +01:00
Kim Morrison
7b98fbece4 feat: reverse HashMap.toList, so it agrees with HashMap.toArray (#6244)
This PR changes the implementation of `HashMap.toList`, so the ordering
agrees with `HashMap.toArray`.

Currently there are no verification lemmas about `HashMap.toList`, so no
contract is being broken yet!
2024-12-03 12:25:35 +00:00
Henrik Böving
24b412ebe3 refactor: move IO.Channel and IO.Mutex to Std.Sync (#6282)
This PR moves `IO.Channel` and `IO.Mutex` from `Init` to `Std.Sync` and
renames them to `Std.Channel` and `Std.Mutex`.

Note that the original files are retained and the deprecation is written
manually as we cannot import `Std` from `Init` so this is the only way
to deprecate without a hard breaking change. In particular we do not yet
move `Std.Queue` from `Init` to `Std` both because it needs to be
retained for this deprecation to work but also because it is already
within the `Std` namespace and as such we cannot maintain two copies of
the file at once. After the deprecation period is finished `Std.Queue`
will find a new home in `Std.Data.Queue`.
2024-12-03 09:36:50 +00:00
Kim Morrison
cb600ed9b4 chore: restore broken proofs
This reverts commit d099f560f72b5f18695c7fb586a9da93af0cb17e.
2024-12-03 17:59:23 +11:00
Kim Morrison
57d83c835e feat: add simp configuration to norm_cast macros 2024-12-03 17:59:23 +11:00
Kim Morrison
ce27d49e31 chore: update stage0 2024-12-03 17:59:23 +11:00
Kim Morrison
8a7889d602 chore: temporarily sorry broken proofs 2024-12-03 17:59:23 +11:00
Kim Morrison
69340297be chore: add simp configuration to norm_cast syntax
chore: define NormCastConfig earlier
2024-12-03 17:59:23 +11:00
Kim Morrison
222abdd43d feat: simprocs for other Fin operations (#6295)
This PR sets up simprocs for all the remaining operations defined in
`Init.Data.Fin.Basic`
2024-12-03 04:42:17 +00:00
François G. Dorais
490be9282e chore: specialize fold loops (#6293)
This PR adds `specialize` and `semireducible` attributes to loops for
`Fin.fold[lr]M?`
2024-12-03 02:44:19 +00:00
Kim Morrison
cda6d5c67a chore: upstream List.length_flatMap (#6294)
This PR upstreams `List.length_flatMap`, `countP_flatMap` and
`count_flatMap` from Mathlib. These were not possible to state before we
upstreamed `List.sum`.
2024-12-03 01:59:32 +00:00
Kim Morrison
904404303b chore: robustify for byAsSorry (#6287)
This PR makes some proofs more robust so they will still work with
`byAsSorry`. Unfortunately, they are not a complete fix and there are
remaining problems building with `byAsSorry`.
2024-12-02 23:53:16 +00:00
Mac Malone
f6bc6b2eb1 fix: lake: properly prepend job log in ensureJob (#6291)
This PR ensures the the log error position is properly preserved when
prepending stray log entries to the job log. It also adds comparison
support for `Log.Pos`.
2024-12-02 23:43:12 +00:00
Mac Malone
d9d54c1f99 chore: lake: use & check prelude (#6289)
This PR adapts Lake modules to use `prelude` and includes them in the
`check-prelude` CI.
2024-12-02 19:55:05 +00:00
Henrik Böving
b2336fd980 perf: speed up bv_decide reflection using Lean.RArray (#6288)
This PR uses Lean.RArray in bv_decide's reflection proofs. Giving
speedups on problems with lots of variables.

Implement like #6068, speedup:
```
# before
λ hyperfine "lean +nightly-2024-12-02 tests/lean/run/bv_reflection_stress.lean"
Benchmark 1: lean +nightly-2024-12-02 tests/lean/run/bv_reflection_stress.lean
  Time (mean ± σ):      1.939 s ±  0.007 s    [User: 1.549 s, System: 0.104 s]
  Range (min … max):    1.928 s …  1.947 s    10 runs
# after
λ hyperfine "lean tests/lean/run/bv_reflection_stress.lean"                                                                                                                                                                                                                        
Benchmark 1: lean tests/lean/run/bv_reflection_stress.lean
  Time (mean ± σ):      1.409 s ±  0.006 s    [User: 1.058 s, System: 0.073 s]
  Range (min … max):    1.401 s …  1.419 s    10 runs
```
2024-12-02 17:44:58 +00:00
Mac Malone
f156f22d7c feat: lake: build without leanc (#6176)
This PR changes Lake's build process to no longer use `leanc` for
compiling C files or linking shared libraries and executables. Instead,
it directly invokes the bundled compiler (or the native compiler if
none) using the necessary flags.
2024-12-02 17:11:27 +00:00
dependabot[bot]
3c348d4526 chore: CI: bump dawidd6/action-download-artifact from 6 to 7 (#6274)
Bumps
[dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact)
from 6 to 7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dawidd6/action-download-artifact/releases">dawidd6/action-download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v7</h2>
<h2>What's Changed</h2>
<ul>
<li>build(deps): bump fast-xml-parser from 4.4.0 to 4.4.1 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/299">dawidd6/action-download-artifact#299</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.7 to
2.1.9 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/300">dawidd6/action-download-artifact#300</a></li>
<li>build(deps): bump adm-zip from 0.5.14 to 0.5.15 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/301">dawidd6/action-download-artifact#301</a></li>
<li>build(deps): bump adm-zip from 0.5.15 to 0.5.16 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/306">dawidd6/action-download-artifact#306</a></li>
<li>build(deps): bump path-to-regexp from 6.2.2 to 6.3.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/307">dawidd6/action-download-artifact#307</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.9 to
2.1.10 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/311">dawidd6/action-download-artifact#311</a></li>
<li>build(deps): bump <code>@​actions/core</code> from 1.10.1 to 1.11.0
by <a href="https://github.com/dependabot"><code>@​dependabot</code></a>
in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/310">dawidd6/action-download-artifact#310</a></li>
<li>build(deps): bump <code>@​actions/core</code> from 1.11.0 to 1.11.1
by <a href="https://github.com/dependabot"><code>@​dependabot</code></a>
in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/312">dawidd6/action-download-artifact#312</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.10 to
2.1.11 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/313">dawidd6/action-download-artifact#313</a></li>
<li>build(deps): Fix cross-spawn &gt;=7.0.0 &lt;= 7.0.5 vulnerability by
<a href="https://github.com/alexcouret"><code>@​alexcouret</code></a> in
<a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/317">dawidd6/action-download-artifact#317</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/alexcouret"><code>@​alexcouret</code></a> made
their first contribution in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/317">dawidd6/action-download-artifact#317</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v6...v7">https://github.com/dawidd6/action-download-artifact/compare/v6...v7</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="80620a5d27"><code>80620a5</code></a>
node_modules: update</li>
<li><a
href="b15e003f46"><code>b15e003</code></a>
node_modules: install</li>
<li><a
href="1ee9a455fd"><code>1ee9a45</code></a>
build(deps): Fix cross-spawn &gt;=7.0.0 &lt;= 7.0.5 vulnerability (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/317">#317</a>)</li>
<li><a
href="b2f2706ac4"><code>b2f2706</code></a>
build(deps): bump <code>@​actions/artifact</code> from 2.1.10 to 2.1.11
(<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/313">#313</a>)</li>
<li><a
href="fdbeba027c"><code>fdbeba0</code></a>
build(deps): bump <code>@​actions/core</code> from 1.11.0 to 1.11.1 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/312">#312</a>)</li>
<li><a
href="a74b42987a"><code>a74b429</code></a>
build(deps): bump <code>@​actions/core</code> from 1.10.1 to 1.11.0 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/310">#310</a>)</li>
<li><a
href="24e807a70c"><code>24e807a</code></a>
build(deps): bump <code>@​actions/artifact</code> from 2.1.9 to 2.1.10
(<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/311">#311</a>)</li>
<li><a
href="9592e3c4ab"><code>9592e3c</code></a>
build(deps): bump path-to-regexp from 6.2.2 to 6.3.0 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/307">#307</a>)</li>
<li><a
href="5f966b63eb"><code>5f966b6</code></a>
build(deps): bump adm-zip from 0.5.15 to 0.5.16 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/306">#306</a>)</li>
<li><a
href="db9477a3eb"><code>db9477a</code></a>
build(deps): bump adm-zip from 0.5.14 to 0.5.15 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/301">#301</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/dawidd6/action-download-artifact/compare/v6...v7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dawidd6/action-download-artifact&package-manager=github_actions&previous-version=6&new-version=7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-02 16:09:50 +00:00
Sebastian Ullrich
0b8f50f78d feat: async linting (#4460)
This PR runs all linters for a single command (together) on a separate
thread from further elaboration, making a first step towards
parallelizing the elaborator.
2024-12-02 14:37:03 +00:00
Henrik Böving
0d89f0194b perf: bv_decide uses rfl in reflection if possible (#6286)
This PR ensure `bv_decide` uses definitional equality in its reflection
procedure as much as possible. Previously it would build up explicit
congruence proofs for the kernel to check. This reduces the size of
proof terms passed to kernel speeds up checking of large reflection
proofs.
2024-12-02 14:27:49 +00:00
Kim Morrison
e157fcbcd1 chore: missing Array/Vector injectivity lemmas (#6284) 2024-12-02 11:00:03 +00:00
Henrik Böving
95dbac26cf chore: shake Std.Time (#6283)
This PR reduces the import closure of `Std.Time` such that it doesn't
have to be rebuilt on every change in `Init.Data`.

Noticed while working on `Init` refactorings.
2024-12-02 10:52:43 +00:00
dependabot[bot]
be63c8280e chore: CI: bump dcarbone/install-jq-action from 2.1.0 to 3.0.1 (#6275)
Bumps
[dcarbone/install-jq-action](https://github.com/dcarbone/install-jq-action)
from 2.1.0 to 3.0.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dcarbone/install-jq-action/releases">dcarbone/install-jq-action's
releases</a>.</em></p>
<blockquote>
<h2>v3.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Use sh in action by <a
href="https://github.com/dcarbone"><code>@​dcarbone</code></a> in <a
href="https://redirect.github.com/dcarbone/install-jq-action/pull/15">dcarbone/install-jq-action#15</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dcarbone/install-jq-action/compare/v3.0.0...v3.0.1">https://github.com/dcarbone/install-jq-action/compare/v3.0.0...v3.0.1</a></p>
<h2>v3.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>updating matrix versions by <a
href="https://github.com/dcarbone"><code>@​dcarbone</code></a> in <a
href="https://redirect.github.com/dcarbone/install-jq-action/pull/12">dcarbone/install-jq-action#12</a></li>
<li>trying out posix sh by <a
href="https://github.com/dcarbone"><code>@​dcarbone</code></a> in <a
href="https://redirect.github.com/dcarbone/install-jq-action/pull/14">dcarbone/install-jq-action#14</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dcarbone/install-jq-action/compare/v2...v3.0.0">https://github.com/dcarbone/install-jq-action/compare/v2...v3.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e397bd8743"><code>e397bd8</code></a>
Use sh in action (<a
href="https://redirect.github.com/dcarbone/install-jq-action/issues/15">#15</a>)</li>
<li><a
href="36b228ee68"><code>36b228e</code></a>
Add dependabot for github-actions</li>
<li><a
href="d5935278d5"><code>d593527</code></a>
updating examples</li>
<li><a
href="ca8101273e"><code>ca81012</code></a>
trying out posix sh (<a
href="https://redirect.github.com/dcarbone/install-jq-action/issues/14">#14</a>)</li>
<li><a
href="de7c0d1fb1"><code>de7c0d1</code></a>
updating matrix versions (<a
href="https://redirect.github.com/dcarbone/install-jq-action/issues/12">#12</a>)</li>
<li>See full diff in <a
href="https://github.com/dcarbone/install-jq-action/compare/v2.1.0...v3.0.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dcarbone/install-jq-action&package-manager=github_actions&previous-version=2.1.0&new-version=3.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-02 10:33:27 +00:00
Sebastian Ullrich
6fcf35e930 chore: script/mathlib-bench (#6280)
A simple approach to benchmarking lean4 PRs against Mathlib
2024-12-02 10:00:57 +00:00
Marc Huisinga
b3e0c9c3fa fix: use sensible notion of indentation in structure instance field completion (#6279)
This PR fixes a bug in structure instance field completion that caused
it to not function correctly for bracketed structure instances written
in Mathlib style.
2024-12-02 09:37:12 +00:00
Kim Morrison
3c5e612dc5 chore: begin development cycle for v4.16.0 (#6277) 2024-12-02 04:11:10 +00:00
Kim Morrison
29e84fa7ea feat: omega doesn't get stuck on bare Int.negSucc (#6276)
This PR ensures `omega` doesn't get stuck on bare `Int.negSucc` terms in
goals.

This came up in https://github.com/ImperialCollegeLondon/FLT/pull/260.
2024-12-01 23:57:15 +00:00
Mac Malone
6bf8ff32f0 feat: more UInt bitwise theorems (#6188)
This PR completes the `toNat` theorems for the bitwise operations
(`and`, `or`, `xor`, `shiftLeft`, `shiftRight`) of the UInt types and
adds `toBitVec` theorems as well. It also renames `and_toNat` to
`toNat_and` to fit with the current naming convention.
2024-12-01 22:38:49 +00:00
Henrik Böving
62b8238782 chore: remove accidentally added file (#6262)
This PR removes an accidentally comitted file.
2024-12-01 21:11:44 +00:00
Kyle Miller
0a2a8e8aa4 feat: make "foo has been deprecated" warning be hoverable (#6273)
This PR modifies the "foo has been deprecated: use betterFoo instead"
warning so that foo and betterFoo are hoverable.
2024-12-01 19:12:42 +00:00
Kyle Miller
23236ef520 fix: have Lean.Meta.isConstructorApp'? be aware of n + k Nat offsets (#6270)
This PR fixes a bug that could cause the `injectivity` tactic to fail in
reducible mode, which could cause unfolding lemma generation to fail
(used by tactics such as `unfold`). In particular,
`Lean.Meta.isConstructorApp'?` was not aware that `n + 1` is equivalent
to `Nat.succ n`.

Closes #5064
2024-12-01 18:04:32 +00:00
Kim Morrison
b2f70dad52 feat: Array.swap_perm (#6272)
This PR introduces the basic theory of permutations of `Array`s and
proves `Array.swap_perm`.

The API falls well short of what is available for `List` at this point.
2024-12-01 08:35:28 +00:00
Kim Morrison
819cb879e1 chore: upstream Vector lemmas (#6271)
This PR upstreams existing lemmas about `Vector` from Batteries.

Thanks to @fgdorais for preparing these in
https://github.com/leanprover-community/batteries/pull/1062. Further
contributions to the `Vector` API welcome via PR here.
2024-12-01 06:44:14 +00:00
Kim Morrison
3ee2842e77 feat: remove runtime bounds checks and partial from qsort (#6241)
This PR refactors `Array.qsort` to remove runtime array bounds checks,
and avoids the use of `partial`. We use the `Vector` API, along with
auto_params, to avoid having to write any proofs. The new code
benchmarks indistinguishably from the old.
2024-12-01 06:26:00 +00:00
Kyle Miller
7b8504cf06 chore: post-stage0 cleanup for #6165 (#6268)
This PR puts code in terms of syntax quotations now that there has been
a stage0 update. Fixes a lingering bug in StructInst where some
intermediate syntax was malformed, but this had no observable effects
outside of some debug messages.
2024-12-01 00:20:59 +00:00
Lean stage0 autoupdater
ca96922b4b chore: update stage0 2024-11-30 21:22:30 +00:00
Kyle Miller
a1c3a36433 feat: parity between structure instance notation and where notation (#6165)
This PR modifies structure instance notation and `where` notation to use
the same notation for fields. Structure instance notation now admits
binders, type ascriptions, and equations, and `where` notation admits
full structure lvals. Examples of these for structure instance notation:
```lean
structure PosFun where
  f : Nat → Nat
  pos : ∀ n, 0 < f n

def p : PosFun :=
  { f n := n + 1
    pos := by simp }

def p' : PosFun :=
  { f | 0 => 1
      | n + 1 => n + 1
    pos := by rintro (_|_) <;> simp }
```
Just like for the structure `where` notation, a field `f x y z : ty :=
val` expands to `f := fun x y z => (val : ty)`. The type ascription is
optional.

The PR also is setting things up for future expansion. Pending some
discussion, in the future structure/`where` notation could have have
embedded `where` clauses; rather than `{ a := { x := 1, y := z } }` one
could write `{ a where x := 1; y := z }`.
2024-11-30 20:27:25 +00:00
Lean stage0 autoupdater
734ea3071d chore: update stage0 2024-11-30 12:58:59 +00:00
Kyle Miller
f3f00451c8 feat: add structInstFieldDecl syntax category (#6265)
This PR is preparation for changes to structure instance notation in
#6165. It adds a syntax category that will be used for field syntax.
2024-11-30 12:12:53 +00:00
Leonardo de Moura
27df5e968a feat: Simp.Config.implicitDefEqProofs (#4595)
This PR implements `Simp.Config.implicitDefEqsProofs`. When `true`
(default: `true`), `simp` will **not** create a proof term for a
rewriting rule associated with an `rfl`-theorem. Rewriting rules are
provided by users by annotating theorems with the attribute `@[simp]`.
If the proof of the theorem is just `rfl` (reflexivity), and
`implicitDefEqProofs := true`, `simp` will **not** create a proof term
which is an application of the annotated theorem.

The default setting does change the existing behavior. Users can use
`simp -implicitDefEqProofs` to force `simp` to create a proof term for
`rfl`-theorems. This can positively impact proof checking time in the
kernel.

This PR also fixes an issue in the `split` tactic that has been exposed
by this feature. It was looking for `split` candidates in proofs and
implicit arguments. See new test for issue exposed by the previous
feature.

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2024-11-29 22:29:27 +00:00
Lean stage0 autoupdater
3752241edd chore: update stage0 2024-11-29 21:32:14 +00:00
Marc Huisinga
39bffb6fda fix: don't walk full project file tree on every file save (#6246)
This PR fixes a performance issue where the Lean language server would
walk the full project file tree every time a file was saved, blocking
the processing of all other requests and notifications and significantly
increasing overall language server latency after saving.

This issue was originally reported at
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Compiling.20too.20slow/near/484386515
and uncovered in a lengthy investigation. The performance bug that
causes the Lean language server to walk the full project file tree when
the file watcher for .ilean files is triggered was introduced when the
.ileans were first introduced, whereas the specific issue of file saving
also triggering the walk was introduced by #3247 in 4.8.0 and the use of
the file watcher for .lean files, which would then also trigger the
directory walk. Combining this with VS Code's auto-save feature causes
the language server to walk the full project file tree on every change
of the document.

It somehow hasn't really been much of an issue until now, but we still
do way too much work in the watchdog main loop. I'll look into resolving
that more general issue in the future.
2024-11-29 15:34:44 +00:00
Sebastian Ullrich
86f303774a chore: harden markPersistent uses (#6257)
This API may or may not have been a footgun, better to be safe than
`sorry`
2024-11-29 14:33:33 +00:00
Sebastian Ullrich
d97af36867 feat: simpler trace timing annotation logic (#6259)
This PR ensures that nesting trace nodes are annotated with timing
information iff `trace.profiler` is active.

The previous connection to the otherwise unrelated `profiler` option was
a remnant from before `trace.profiler` existed; if users want to
annotate explicitly activated trace classes only, they can instead
increase `trace.profiler.threshold`.
2024-11-29 14:03:01 +00:00
Mac Malone
27cc0c8039 feat: USize.reduceToNat (#6190)
This PR adds the builtin simproc `USize.reduceToNat` which reduces the
`USize.toNat` operation on literals less than `UInt32.size` (i.e.,
`4294967296`).
2024-11-29 08:24:40 +00:00
Mac Malone
c9ee66fb1f chore: lake: fix typo in materialize error (#6250) 2024-11-29 06:20:51 +00:00
Kim Morrison
5c7e027b03 chore: cleanup of List/Array lemmas (#6249)
This PR performs further cleanup of `List/Lemmas.lean` and
`Array/Lemmas.lean`, trying to make them more parallel.

Still a long way to go.
2024-11-29 06:12:38 +00:00
Mac Malone
4969ec9cdb feat: more UInt lemmas (#6205)
This PR upstreams some UInt theorems from Batteries and adds more
`toNat`-related theorems. It also adds the missing `UInt8` and `UInt16`
to/from `USize` conversions so that the the interface is uniform across
the UInt types.

**Summary of all changes:**

* Upstreamed and added `toNat` constructors lemmas: `toNat_mk`,
`ofNat_toNat`, `toNat_ofNat`, `toNat_ofNatCore`, and
`USize.toNat_ofNat32`
* Upstreamed and added `toNat` canonicalization; `val_val_eq_toNat` and
`toNat_toBitVec_eq_toNat`
* Added injectivity iffs: `toBitVec_inj`, `toNat_inj`, and `val_inj`
* Added inequality iffs: `le_iff_toNat_le` and `lt_iff_toNat_lt`
* Upstreamed antisymmetry lemmas: `le_antisymm` and `le_antisymm_iff`
* Upstreamed missing `toNat` lemmas on arithmetic operations:
`toNat_add`, `toNat_sub`, `toNat_mul`
* Upstreamed and added missing conversion lemmas: `toNat_toUInt*` and
`toNat_USize`
* Added missing `USize` conversions: `USize.toUInt8`, `UInt8.toUSize`,
`USize.toUInt16`, `UInt16.toUSize`
2024-11-29 02:08:52 +00:00
Mac Malone
827062f807 feat: System.Platform.numBits inequalities (#6247)
This PR adds the theorems `numBits_pos`, `le_numBits`, `numBits_le` ,
which make proving inequalities about `System.Platform.numBits` easier.
2024-11-28 21:20:47 +00:00
Kim Morrison
6d495586a1 chore: deprecate Fin.ofNat (replaced by Fin.ofNat', subsequently to be renamed) (#6242)
This PR deprecates `Fin.ofNat` in favour of `Fin.ofNat'` (which takes an
`[NeZero]` instance, rather than returning an element of `Fin (n+1)`).

After leaving the deprecation warning in place for some time, we will
then rename `ofNat'` back to `ofNat`.
2024-11-28 05:23:23 +00:00
Kim Morrison
10d1d2cc25 chore: cleanup in Array/Lemmas (#6243) 2024-11-28 03:50:41 +00:00
Wojciech Nawrocki
2325f5c7b9 doc: explain abstraction order (#6239)
This PR explains the order in which `Expr.abstract` introduces de Bruijn
indices.
2024-11-28 01:37:30 +00:00
Sofia Rodrigues
88e3a2b1ab fix: improve directory fallback on Linux and trim local time identifier (#6221)
This PR fixes:
- Problems in other linux distributions that the default `tzdata`
directory is not the same as previously defined by ensuring it with a
fallback behavior when directory is missing.
- Trim unnecessary characters from local time identifier.
2024-11-27 14:52:35 +00:00
Lean stage0 autoupdater
b378fe98a7 chore: update stage0 2024-11-27 14:20:47 +00:00
Sebastian Ullrich
5f1ff42a15 fix: Runtime.markPersistent is unsafe (#6209)
This PR documents under which conditions `Runtime.markPersistent` is
unsafe and adjusts the elaborator accordingly
2024-11-27 13:32:05 +00:00
Jens Petersen
30d01f7a9a fix: add cmake COPY_CADICAL option to allow turning off install copy (#5931)
This PR adds a cmake knob to allow turning off installing a copy of
`cadical`.
This can be useful for custom builds/installs where cadical is already
available in the system.

Closes: #5603
2024-11-27 13:21:20 +00:00
Sebastian Ullrich
81b85d8e2f fix: reparsing may need to backtrack two commands (#6236)
This PR fixes an issue where edits to a command containing a nested
docstring fail to reparse the entire command.

Fixes #6227
2024-11-27 13:06:57 +00:00
Sebastian Ullrich
5982a6d230 chore: default parseQuotWithCurrentStage to true in stage 0 (#6212)
Use the default that solves bootstrapping issues in exchange for an
insignificant(?) perf overhead
2024-11-27 12:58:44 +00:00
Mac Malone
ac1197ff59 feat: Lean.loadPlugin (#6130)
This PR adds `Lean.loadPlugin` which exposes functionality similar to
the `lean` executable's `--plugin` option to Lean code.

This will allow custom Lean frontends (e.g., Lake, the Lean language
server) to also load plugins.

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-11-27 09:56:31 +00:00
Kim Morrison
609346f5e0 feat: relate Nat.fold/foldRev/any/all to List.finRange (#6235)
This PR relates that operations `Nat.fold`/`foldRev`/`any`/`all` to the
corresponding List operations over `List.finRange`.
2024-11-27 05:38:18 +00:00
Mac Malone
04f80a1f9f feat: lake: detailed Reservoir fetch error (#6231)
This PR improves the errors Lake produces when it fails to fetch a
dependency from Reservoir. If the package is not indexed, it will
produce a suggestion about how to require it from GitHub.

Closes #5330.
2024-11-27 05:07:09 +00:00
Kim Morrison
7e9dd5668b feat: upstream List.finRange from Batteries (#6234)
This PR upstreams the definition and basic lemmas about `List.finRange`
from Batteries.

Thanks for contributors to Batteries and Mathlib who've previously
worked on this material. Further PRs are welcome here. I'll be adding
more API later.
2024-11-27 04:27:22 +00:00
Kim Morrison
79f050b816 feat: upstream Vector lemmas (#6233)
This PR upstreams lemmas about `Vector` from Batteries.

I'll be adding more soon, and PRs are welcome, particularly from those
who have previously contributed to `Vector` in Batteries.
2024-11-27 04:19:30 +00:00
Siddharth
af4a3f2251 feat: BitVec.toInt_abs (#6154)
This PR implements `BitVec.toInt_abs`.


The absolute value of `x : BitVec w` is naively a case split on the sign
of `x`.
However, recall that when `x = intMin w`, `-x = x`.
Thus, the full value of `abs x` is computed by the case split:
- If `x : BitVec w` is `intMin`, then its absolute value is also `intMin
w`, and
  thus `toInt` will equal `intMin.toInt`.
- Otherwise, if `x` is negative, then `x.abs.toInt = (-x).toInt`.
- Finally, when `x` is nonnegative, then `x.abs.toInt = x.toInt`.

```lean
theorem toInt_abs {x : BitVec w} :
  x.abs.toInt =
    if x = intMin w then (intMin w).toInt
    else if x.msb then -x.toInt
    else x.toInt
```

We also provide a variant of `toInt_abs` that
hides the case split for `x` being positive or negative by using
`natAbs`.
```lean
theorem toInt_abs_eq_natAbs {x : BitVec w} : x.abs.toInt =
    if x = intMin w then (intMin w).toInt else x.toInt.natAbs
```

Supercedes https://github.com/leanprover/lean4/pull/5787

---------

Co-authored-by: Tobias Grosser <github@grosser.es>
2024-11-27 03:50:55 +00:00
Siddharth
7692343720 feat: BitVec.toNat BitVec.signExtend (#6155)
This PR adds `toNat` theorems for `BitVec.signExtend.`

Sign extending to a larger bitwidth depends on the msb. If the msb is
false, then the result equals the original value. If the msb is true,
then we add a value of `(2^v - 2^w)`, which arises from the sign
extension.

```lean
theorem toNat_signExtend (x : BitVec w) {v : Nat} :
    (x.signExtend v).toNat = (x.setWidth v).toNat + if x.msb then 2^v - 2^w else 0
```

Co-authored-by: Harun Khan <harun19@stanford.edu>
2024-11-27 03:50:15 +00:00
Luisa Cicolini
597ef8cfee feat: add Nat.mod_eq_sub and fix dependencies from Nat.sub_mul_eq_mod_of_lt_of_le (#6160)
This PR adds theorem `mod_eq_sub`, makes theorem
`sub_mul_eq_mod_of_lt_of_le` not private anymore and moves its location
within the `rotate*` section to use it in other proofs.
2024-11-27 03:48:59 +00:00
Kim Morrison
321e148f51 feat: Array fold lemmas (#6230)
This PR copies some lemmas about `List.foldX` to `Array`.
2024-11-27 02:09:41 +00:00
Kyle Miller
ce692436f4 feat: expose diff at "synthesized type class instance is not definitionally equal" error (#6213)
This PR exposes the difference in "synthesized type class instance is
not definitionally equal" errors.
2024-11-27 00:52:58 +00:00
Mac Malone
23bec25fce feat: Nat.lt_pow_self (#6200)
This PR upstreams `Nat.lt_pow_self` and `Nat.lt_two_pow` from Mathlib
and uses them to prove the simp theorem `Nat.mod_two_pow`.

This simplifies expressions like `System.Platform.numBits % 2 ^
System.Platform.numBits = System.Platform.numBits`, which is needed for
#6188.
2024-11-26 23:42:23 +00:00
Mac Malone
3d511a582a feat: USize.size inequalities (#6203)
This PR adds the theorems `le_usize_size` and `usize_size_le`, which
make proving inequalities about `USize.size` easier.

It also deprecates `usize_size_gt_zero` in favor of `usize_size_pos` (as
that seems more consistent with our naming covention) and adds
`USize.toNat_ofNat_of_lt_32` for dealing with small USize literals.

It also moves `USize.ofNat32` and `USize.toUInt64` to
`Init.Data.UInt.Basic` as neither are used in `Init.Prelude` anymore.

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2024-11-26 23:42:15 +00:00
Mac Malone
51015bf5c0 fix: lake: eager logging when materializing deps (#6225)
This PR makes `lake build` also eagerly print package materialization
log lines. Previously, only a `lake update` performed eager logging.
2024-11-26 22:11:23 +00:00
Mac Malone
3ece36de9d feat: GitHub cloud releases do not clobber prebuilt artifacts (#6218)
This PR makes Lake no longer automatically fetch GitHub cloud releases
if the package build directory is already present (mirroring the
behavior of the Reservoir cache). This prevents the cache from
clobbering existing prebuilt artifacts. Users can still manually fetch
the cache and clobber the build directory by running `lake build
<pkg>:release`.
2024-11-26 22:10:42 +00:00
Leonardo de Moura
54c48363ca feat: proper let_fun support in simp (#6220)
This PR adds proper support for `let_fun` in `simp`.
2024-11-26 21:42:08 +00:00
Markus Himmel
0a22f8fa6f chore: improve consistency & documentation for hash table insert and insertMany (#6222)
This PR changes the definition of `HashSet.insertMany` and
`HashSet.Raw.insertMany` so that it is equivalent to repeatedly calling
`HashSet.insert`/`HashSet.Raw.insert`. It also clarifies the docstrings
of all the `insert` and `insertMany` functions.

---------

Co-authored-by: Kim Morrison <scott.morrison@gmail.com>
2024-11-26 11:22:23 +00:00
Kim Morrison
f70b7e5722 feat: @[deprecated] requires a replacement identifier or message, and a since field (#6112)
This PR makes stricter requirements for the `@[deprecated]` attribute,
requiring either a replacement identifier as `@[deprecated bar]` or
suggestion text `@[deprecated "Past its use by date"]`, and also
requires a `since := "..."` field.
2024-11-26 08:45:54 +00:00
Kim Morrison
9a17919ef1 feat: missing lemmas about List's BEq (#6217)
This PR adds `simp` lemmas about `List`'s `==` operation.
2024-11-25 22:55:03 +00:00
Kyle Miller
606aeddf06 feat: make dot notation be affected by export/open (#6189)
This PR changes how generalized field notation ("dot notation") resolves
the function. The new resolution rule is that if `x : S`, then `x.f`
resolves the name `S.f` relative to the root namespace (hence it now
affected by `export` and `open`). Breaking change: aliases now resolve
differently. Before, if `x : S`, and if `S.f` is an alias for `S'.f`,
then `x.f` would use `S'.f` and look for an argument of type `S'`. Now,
it looks for an argument of type `S`, which is more generally useful
behavior. Code making use of the old behavior should consider defining
`S` or `S'` in terms of the other, since dot notation can unfold
definitions during resolution.

This also fixes a bug in explicit-mode generalized field notation
(`@x.f`) where `x` could be passed as the wrong argument. This was not a
bug for explicit-mode structure projections.

Closes #3031. Addresses the `Function` namespace issue in #1629.
2024-11-25 18:38:17 +00:00
Kyle Miller
0eca3bd55d feat: add a coercion from List Nat to Lean.Meta.Occurrences (#6206)
This PR makes it possible to write `rw (occs := [1,2]) ...` instead of
`rw (occs := .pos [1,2]) ...` by adding a coercion from `List.Nat` to
`Lean.Meta.Occurrences`.
2024-11-25 13:19:23 +00:00
Kim Morrison
43dfc2a25f chore: fix Vector.indexOf? (#6208)
Just a better defeq.
2024-11-25 10:47:58 +00:00
Mac Malone
935fcfb6ec feat: non-opaque UInt64.toUSize (#6202)
This PR makes `USize.toUInt64` a regular non-opaque definition. 

It also moves it to `Init.Data.UInt.Basic`, as it is not actually used
in `Init.Prelude` anymore.
2024-11-25 08:33:53 +00:00
Kim Morrison
20acc72a29 feat: ensure Fin.foldl/r are semireducible (#6207)
This PR ensures the `Fin.foldl` and `Fin.foldr` are semireducible.
Without this the defeq `example (f : Fin 3 → ℕ) : List.ofFn f = [f 0, f
1, f 2] := rfl` was failing.

Thanks @eric-wieser and @digama0 for diagnosing on
[Zulip](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/.60List.2EfinRange.60.20in.20Mathlib/near/484191814).
2024-11-25 03:21:36 +00:00
Kim Morrison
c3948cba24 feat: upstream definition of Vector from Batteries (#6197)
This PR upstreams the definition of `Vector` from Batteries, along with
the basic functions.
2024-11-24 23:01:32 +00:00
1079 changed files with 13811 additions and 4376 deletions

View File

@@ -14,6 +14,7 @@ jobs:
sparse-checkout: |
src/Lean
src/Std
src/lake/Lake
- name: Check Prelude
run: |
failed_files=""
@@ -21,7 +22,7 @@ jobs:
if ! grep -q "^prelude$" "$file"; then
failed_files="$failed_files$file\n"
fi
done < <(find src/Lean src/Std -name '*.lean' -print0)
done < <(find src/Lean src/Std src/lake/Lake -name '*.lean' -print0)
if [ -n "$failed_files" ]; then
echo -e "The following files should use 'prelude':\n$failed_files"
exit 1

View File

@@ -34,7 +34,7 @@ jobs:
- name: Download artifact from the previous workflow.
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
id: download-artifact
uses: dawidd6/action-download-artifact@v6 # https://github.com/marketplace/actions/download-workflow-artifact
uses: dawidd6/action-download-artifact@v7 # https://github.com/marketplace/actions/download-workflow-artifact
with:
run_id: ${{ github.event.workflow_run.id }}
path: artifacts
@@ -111,7 +111,7 @@ jobs:
- name: 'Setup jq'
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
uses: dcarbone/install-jq-action@v2.1.0
uses: dcarbone/install-jq-action@v3.0.1
# Check that the most recently nightly coincides with 'git merge-base HEAD master'
- name: Check merge-base and nightly-testing-YYYY-MM-DD

14
.gitpod.Dockerfile vendored Normal file
View File

@@ -0,0 +1,14 @@
# You can find the new timestamped tags here: https://hub.docker.com/r/gitpod/workspace-full/tags
FROM gitpod/workspace-full
USER root
RUN apt-get update && apt-get install git libgmp-dev libuv1-dev cmake ccache clang -y && apt-get clean
USER gitpod
# Install and configure elan
RUN curl https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh -sSf | sh -s -- -y --default-toolchain none
ENV PATH="/home/gitpod/.elan/bin:${PATH}"
# Create a dummy toolchain so that we can pre-register it with elan
RUN mkdir -p /workspace/lean4/build/release/stage1/bin && touch /workspace/lean4/build/release/stage1/bin/lean && elan toolchain link lean4 /workspace/lean4/build/release/stage1
RUN mkdir -p /workspace/lean4/build/release/stage0/bin && touch /workspace/lean4/build/release/stage0/bin/lean && elan toolchain link lean4-stage0 /workspace/lean4/build/release/stage0

11
.gitpod.yml Normal file
View File

@@ -0,0 +1,11 @@
image:
file: .gitpod.Dockerfile
vscode:
extensions:
- leanprover.lean4
tasks:
- name: Release build
init: cmake --preset release
command: make -C build/release -j$(nproc || sysctl -n hw.logicalcpu)

View File

@@ -4,7 +4,7 @@
# Listed persons will automatically be asked by GitHub to review a PR touching these paths.
# If multiple names are listed, a review by any of them is considered sufficient by default.
/.github/ @Kha @kim-em
/.github/ @kim-em
/RELEASES.md @kim-em
/src/kernel/ @leodemoura
/src/lake/ @tydeu
@@ -14,9 +14,7 @@
/src/Lean/Elab/Tactic/ @kim-em
/src/Lean/Language/ @Kha
/src/Lean/Meta/Tactic/ @leodemoura
/src/Lean/Parser/ @Kha
/src/Lean/PrettyPrinter/ @Kha
/src/Lean/PrettyPrinter/Delaborator/ @kmill
/src/Lean/PrettyPrinter/ @kmill
/src/Lean/Server/ @mhuisi
/src/Lean/Widget/ @Vtec234
/src/Init/Data/ @kim-em

View File

@@ -8,15 +8,299 @@ This file contains work-in-progress notes for the upcoming release, as well as p
Please check the [releases](https://github.com/leanprover/lean4/releases) page for the current status
of each version.
v4.15.0
v4.16.0
----------
Development in progress.
v4.15.0
----------
Release candidate, release notes will be copied from the branch `releases/v4.15.0` once completed.
v4.14.0
----------
Release candidate, release notes will be copied from the branch `releases/v4.14.0` once completed.
**Full Changelog**: https://github.com/leanprover/lean4/compare/v4.13.0...v4.14.0
### Language features, tactics, and metaprograms
* `structure` and `inductive` commands
* [#5517](https://github.com/leanprover/lean4/pull/5517) improves universe level inference for the resulting type of an `inductive` or `structure.` Recall that a `Prop`-valued inductive type is a syntactic subsingleton if it has at most one constructor and all the arguments to the constructor are in `Prop`. Such types have large elimination, so they could be defined in `Type` or `Prop` without any trouble. The way inference has changed is that if a type is a syntactic subsingleton with exactly one constructor, and the constructor has at least one parameter/field, then the `inductive`/`structure` command will prefer creating a `Prop` instead of a `Type`. The upshot is that the `: Prop` in `structure S : Prop` is often no longer needed. (With @arthur-adjedj).
* [#5842](https://github.com/leanprover/lean4/pull/5842) and [#5783](https://github.com/leanprover/lean4/pull/5783) implement a feature where the `structure` command can now define recursive inductive types:
```lean
structure Tree where
n : Nat
children : Fin n → Tree
def Tree.size : Tree → Nat
| {n, children} => Id.run do
let mut s := 0
for h : i in [0 : n] do
s := s + (children ⟨i, h.2⟩).size
pure s
```
* [#5814](https://github.com/leanprover/lean4/pull/5814) fixes a bug where Mathlib's `Type*` elaborator could lead to incorrect universe parameters with the `inductive` command.
* [#3152](https://github.com/leanprover/lean4/pull/3152) and [#5844](https://github.com/leanprover/lean4/pull/5844) fix bugs in default value processing for structure instance notation (with @arthur-adjedj).
* [#5399](https://github.com/leanprover/lean4/pull/5399) promotes instance synthesis order calculation failure from a soft error to a hard error.
* [#5542](https://github.com/leanprover/lean4/pull/5542) deprecates `:=` variants of `inductive` and `structure` (see breaking changes).
* **Application elaboration improvements**
* [#5671](https://github.com/leanprover/lean4/pull/5671) makes `@[elab_as_elim]` require at least one discriminant, since otherwise there is no advantage to this alternative elaborator.
* [#5528](https://github.com/leanprover/lean4/pull/5528) enables field notation in explicit mode. The syntax `@x.f` elaborates as `@S.f` with `x` supplied to the appropriate parameter.
* [#5692](https://github.com/leanprover/lean4/pull/5692) modifies the dot notation resolution algorithm so that it can apply `CoeFun` instances. For example, Mathlib has `Multiset.card : Multiset α →+ Nat`, and now with `m : Multiset α`, the notation `m.card` resolves to `⇑Multiset.card m`.
* [#5658](https://github.com/leanprover/lean4/pull/5658) fixes a bug where 'don't know how to synthesize implicit argument' errors might have the incorrect local context when the eta arguments feature is activated.
* [#5933](https://github.com/leanprover/lean4/pull/5933) fixes a bug where `..` ellipses in patterns made use of optparams and autoparams.
* [#5770](https://github.com/leanprover/lean4/pull/5770) makes dot notation for structures resolve using *all* ancestors. Adds a *resolution order* for generalized field notation. This is the order of namespaces visited during resolution when trying to resolve names. The algorithm to compute a resolution order is the commonly used C3 linearization (used for example by Python), which when successful ensures that immediate parents' namespaces are considered before more distant ancestors' namespaces. By default we use a relaxed version of the algorithm that tolerates inconsistencies, but using `set_option structure.strictResolutionOrder true` makes inconsistent parent orderings into warnings.
* **Recursion and induction principles**
* [#5619](https://github.com/leanprover/lean4/pull/5619) fixes functional induction principle generation to avoid over-eta-expanding in the preprocessing step.
* [#5766](https://github.com/leanprover/lean4/pull/5766) fixes structural nested recursion so that it is not confused when a nested type appears first.
* [#5803](https://github.com/leanprover/lean4/pull/5803) fixes a bug in functional induction principle generation when there are `let` bindings.
* [#5904](https://github.com/leanprover/lean4/pull/5904) improves functional induction principle generation to unfold aux definitions more carefully.
* [#5850](https://github.com/leanprover/lean4/pull/5850) refactors code for `Predefinition.Structural`.
* **Error messages**
* [#5276](https://github.com/leanprover/lean4/pull/5276) fixes a bug in "type mismatch" errors that would structurally assign metavariables during the algorithm to expose differences.
* [#5919](https://github.com/leanprover/lean4/pull/5919) makes "type mismatch" errors add type ascriptions to expose differences for numeric literals.
* [#5922](https://github.com/leanprover/lean4/pull/5922) makes "type mismatch" errors expose differences in the bodies of functions and pi types.
* [#5888](https://github.com/leanprover/lean4/pull/5888) improves the error message for invalid induction alternative names in `match` expressions (@josojo).
* [#5719](https://github.com/leanprover/lean4/pull/5719) improves `calc` error messages.
* [#5627](https://github.com/leanprover/lean4/pull/5627) and [#5663](https://github.com/leanprover/lean4/pull/5663) improve the **`#eval` command** and introduce some new features.
* Now results can be pretty printed if there is a `ToExpr` instance, which means **hoverable output**. If `ToExpr` fails, it then tries looking for a `Repr` or `ToString` instance like before. Setting `set_option eval.pp false` disables making use of `ToExpr` instances.
* There is now **auto-derivation** of `Repr` instances, enabled with the `pp.derive.repr` option (default to **true**). For example:
```lean
inductive Baz
| a | b
#eval Baz.a
-- Baz.a
```
It simply does `deriving instance Repr for Baz` when there's no way to represent `Baz`.
* The option `eval.type` controls whether or not to include the type in the output. For now the default is false.
* Now expressions such as `#eval do return 2`, where monad is unknown, work. It tries unifying the monad with `CommandElabM`, `TermElabM`, or `IO`.
* The classes `Lean.Eval` and `Lean.MetaEval` have been removed. These each used to be responsible for adapting monads and printing results. Now the `MonadEval` class is responsible for adapting monads for evaluation (it is similar to `MonadLift`, but instances are allowed to use default data when initializing state), and representing results is handled through a separate process.
* Error messages about failed instance synthesis are now more precise. Once it detects that a `MonadEval` class applies, then the error message will be specific about missing `ToExpr`/`Repr`/`ToString` instances.
* Fixes bugs where evaluating `MetaM` and `CoreM` wouldn't collect log messages.
* Fixes a bug where `let rec` could not be used in `#eval`.
* `partial` definitions
* [#5780](https://github.com/leanprover/lean4/pull/5780) improves the error message when `partial` fails to prove a type is inhabited. Add delta deriving.
* [#5821](https://github.com/leanprover/lean4/pull/5821) gives `partial` inhabitation the ability to create local `Inhabited` instances from parameters.
* **New tactic configuration syntax.** The configuration syntax for all core tactics has been given an upgrade. Rather than `simp (config := { contextual := true, maxSteps := 22})`, one can now write `simp +contextual (maxSteps := 22)`. Tactic authors can migrate by switching from `(config)?` to `optConfig` in tactic syntaxes and potentially deleting `mkOptionalNode` in elaborators. [#5883](https://github.com/leanprover/lean4/pull/5883), [#5898](https://github.com/leanprover/lean4/pull/5898), [#5928](https://github.com/leanprover/lean4/pull/5928), and [#5932](https://github.com/leanprover/lean4/pull/5932). (Tactic authors, see breaking changes.)
* `simp` tactic
* [#5632](https://github.com/leanprover/lean4/pull/5632) fixes the simpproc for `Fin` literals to reduce more consistently.
* [#5648](https://github.com/leanprover/lean4/pull/5648) fixes a bug in `simpa ... using t` where metavariables in `t` were not properly accounted for, and also improves the type mismatch error.
* [#5838](https://github.com/leanprover/lean4/pull/5838) fixes the docstring of `simp!` to actually talk about `simp!`.
* [#5870](https://github.com/leanprover/lean4/pull/5870) adds support for `attribute [simp ←]` (note the reverse direction). This adds the reverse of a theorem as a global simp theorem.
* `decide` tactic
* [#5665](https://github.com/leanprover/lean4/pull/5665) adds `decide!` tactic for using kernel reduction (warning: this is renamed to `decide +kernel` in a future release).
* `bv_decide` tactic
* [#5714](https://github.com/leanprover/lean4/pull/5714) adds inequality regression tests (@alexkeizer).
* [#5608](https://github.com/leanprover/lean4/pull/5608) adds `bv_toNat` tag for `toNat_ofInt` (@bollu).
* [#5618](https://github.com/leanprover/lean4/pull/5618) adds support for `at` in `ac_nf` and uses it in `bv_normalize` (@tobiasgrosser).
* [#5628](https://github.com/leanprover/lean4/pull/5628) adds udiv support.
* [#5635](https://github.com/leanprover/lean4/pull/5635) adds auxiliary bitblasters for negation and subtraction.
* [#5637](https://github.com/leanprover/lean4/pull/5637) adds more `getLsbD` bitblaster theory.
* [#5652](https://github.com/leanprover/lean4/pull/5652) adds umod support.
* [#5653](https://github.com/leanprover/lean4/pull/5653) adds performance benchmark for modulo.
* [#5655](https://github.com/leanprover/lean4/pull/5655) reduces error on `bv_check` to warning.
* [#5670](https://github.com/leanprover/lean4/pull/5670) adds `~~~(-x)` support.
* [#5673](https://github.com/leanprover/lean4/pull/5673) disables `ac_nf` by default.
* [#5675](https://github.com/leanprover/lean4/pull/5675) fixes context tracking in `bv_decide` counter example.
* [#5676](https://github.com/leanprover/lean4/pull/5676) adds an error when the LRAT proof is invalid.
* [#5781](https://github.com/leanprover/lean4/pull/5781) introduces uninterpreted symbols everywhere.
* [#5823](https://github.com/leanprover/lean4/pull/5823) adds `BitVec.sdiv` support.
* [#5852](https://github.com/leanprover/lean4/pull/5852) adds `BitVec.ofBool` support.
* [#5855](https://github.com/leanprover/lean4/pull/5855) adds `if` support.
* [#5869](https://github.com/leanprover/lean4/pull/5869) adds support for all the SMTLIB BitVec divison/remainder operations.
* [#5886](https://github.com/leanprover/lean4/pull/5886) adds embedded constraint substitution.
* [#5918](https://github.com/leanprover/lean4/pull/5918) fixes loose mvars bug in `bv_normalize`.
* Documentation:
* [#5636](https://github.com/leanprover/lean4/pull/5636) adds remarks about multiplication.
* `conv` mode
* [#5861](https://github.com/leanprover/lean4/pull/5861) improves the `congr` conv tactic to handle "over-applied" functions.
* [#5894](https://github.com/leanprover/lean4/pull/5894) improves the `arg` conv tactic so that it can access more arguments and so that it can handle "over-applied" functions (it generates a specialized congruence lemma for the specific argument in question). Makes `arg 1` and `arg 2` apply to pi types in more situations. Adds negative indexing, for example `arg -2` is equivalent to the `lhs` tactic. Makes the `enter [...]` tactic show intermediate states like `rw`.
* **Other tactics**
* [#4846](https://github.com/leanprover/lean4/pull/4846) fixes a bug where `generalize ... at *` would apply to implementation details (@ymherklotz).
* [#5730](https://github.com/leanprover/lean4/pull/5730) upstreams the `classical` tactic combinator.
* [#5815](https://github.com/leanprover/lean4/pull/5815) improves the error message when trying to unfold a local hypothesis that is not a local definition.
* [#5862](https://github.com/leanprover/lean4/pull/5862) and [#5863](https://github.com/leanprover/lean4/pull/5863) change how `apply` and `simp` elaborate, making them not disable error recovery. This improves hovers and completions when the term has elaboration errors.
* `deriving` clauses
* [#5899](https://github.com/leanprover/lean4/pull/5899) adds declaration ranges for delta-derived instances.
* [#5265](https://github.com/leanprover/lean4/pull/5265) removes unused syntax in `deriving` clauses for providing arguments to deriving handlers (see breaking changes).
* [#5065](https://github.com/leanprover/lean4/pull/5065) upstreams and updates `#where`, a command that reports the current scope information.
* **Linters**
* [#5338](https://github.com/leanprover/lean4/pull/5338) makes the unused variables linter ignore variables defined in tactics by default now, avoiding performance bottlenecks.
* [#5644](https://github.com/leanprover/lean4/pull/5644) ensures that linters in general do not run on `#guard_msgs` itself.
* **Metaprogramming interface**
* [#5720](https://github.com/leanprover/lean4/pull/5720) adds `pushGoal`/`pushGoals` and `popGoal` for manipulating the goal state. These are an alternative to `replaceMainGoal` and `getMainGoal`, and with them you don't need to worry about making sure nothing clears assigned metavariables from the goal list between assigning the main goal and using `replaceMainGoal`. Modifies `closeMainGoalUsing`, which is like a `TacticM` version of `liftMetaTactic`. Now the callback is run in a context where the main goal is removed from the goal list, and the callback is free to modify the goal list. Furthermore, the `checkUnassigned` argument has been replaced with `checkNewUnassigned`, which checks whether the value assigned to the goal has any *new* metavariables, relative to the start of execution of the callback. Modifies `withCollectingNewGoalsFrom` to take the `parentTag` argument explicitly rather than indirectly via `getMainTag`. Modifies `elabTermWithHoles` to optionally take `parentTag?`.
* [#5563](https://github.com/leanprover/lean4/pull/5563) fixes `getFunInfo` and `inferType` to use `withAtLeastTransparency` rather than `withTransparency`.
* [#5679](https://github.com/leanprover/lean4/pull/5679) fixes `RecursorVal.getInduct` to return the name of major arguments type. This makes "structure eta" work for nested inductives.
* [#5681](https://github.com/leanprover/lean4/pull/5681) removes unused `mkRecursorInfoForKernelRec`.
* [#5686](https://github.com/leanprover/lean4/pull/5686) makes discrimination trees index the domains of foralls, for better performance of the simplify and type class search.
* [#5760](https://github.com/leanprover/lean4/pull/5760) adds `Lean.Expr.name?` recognizer for `Name` expressions.
* [#5800](https://github.com/leanprover/lean4/pull/5800) modifies `liftCommandElabM` to preserve more state, fixing an issue where using it would drop messages.
* [#5857](https://github.com/leanprover/lean4/pull/5857) makes it possible to use dot notation in `m!` strings, for example `m!"{.ofConstName n}"`.
* [#5841](https://github.com/leanprover/lean4/pull/5841) and [#5853](https://github.com/leanprover/lean4/pull/5853) record the complete list of `structure` parents in the `StructureInfo` environment extension.
* **Other fixes or improvements**
* [#5566](https://github.com/leanprover/lean4/pull/5566) fixes a bug introduced in [#4781](https://github.com/leanprover/lean4/pull/4781) where heartbeat exceptions were no longer being handled properly. Now such exceptions are tagged with `runtime.maxHeartbeats` (@eric-wieser).
* [#5708](https://github.com/leanprover/lean4/pull/5708) modifies the proof objects produced by the proof-by-reflection tactics `ac_nf0` and `simp_arith` so that the kernel is less prone to reducing expensive atoms.
* [#5768](https://github.com/leanprover/lean4/pull/5768) adds a `#version` command that prints Lean's version information.
* [#5822](https://github.com/leanprover/lean4/pull/5822) fixes elaborator algorithms to match kernel algorithms for primitive projections (`Expr.proj`).
* [#5811](https://github.com/leanprover/lean4/pull/5811) improves the docstring for the `rwa` tactic.
### Language server, widgets, and IDE extensions
* [#5224](https://github.com/leanprover/lean4/pull/5224) fixes `WorkspaceClientCapabilities` to make `applyEdit` optional, in accordance with the LSP specification (@pzread).
* [#5340](https://github.com/leanprover/lean4/pull/5340) fixes a server deadlock when shutting down the language server and a desync between client and language server after a file worker crash.
* [#5560](https://github.com/leanprover/lean4/pull/5560) makes `initialize` and `builtin_initialize` participate in the call hierarchy and other requests.
* [#5650](https://github.com/leanprover/lean4/pull/5650) makes references in attributes participate in the call hierarchy and other requests.
* [#5666](https://github.com/leanprover/lean4/pull/5666) add auto-completion in tactic blocks without having to type the first character of the tactic, and adds tactic completion docs to tactic auto-completion items.
* [#5677](https://github.com/leanprover/lean4/pull/5677) fixes several cases where goal states were not displayed in certain text cursor positions.
* [#5707](https://github.com/leanprover/lean4/pull/5707) indicates deprecations in auto-completion items.
* [#5736](https://github.com/leanprover/lean4/pull/5736), [#5752](https://github.com/leanprover/lean4/pull/5752), [#5763](https://github.com/leanprover/lean4/pull/5763), [#5802](https://github.com/leanprover/lean4/pull/5802), and [#5805](https://github.com/leanprover/lean4/pull/5805) fix various performance issues in the language server.
* [#5801](https://github.com/leanprover/lean4/pull/5801) distinguishes theorem auto-completions from non-theorem auto-completions.
### Pretty printing
* [#5640](https://github.com/leanprover/lean4/pull/5640) fixes a bug where goal states in messages might print newlines as spaces.
* [#5643](https://github.com/leanprover/lean4/pull/5643) adds option `pp.mvars.delayed` (default false), which when false causes delayed assignment metavariables to pretty print with what they are assigned to. Now `fun x : Nat => ?a` pretty prints as `fun x : Nat => ?a` rather than `fun x ↦ ?m.7 x`.
* [#5711](https://github.com/leanprover/lean4/pull/5711) adds options `pp.mvars.anonymous` and `pp.mvars.levels`, which when false respectively cause expression metavariables and level metavariables to pretty print as `?_`.
* [#5710](https://github.com/leanprover/lean4/pull/5710) adjusts the `` elaboration warning to mention `pp.maxSteps`.
* [#5759](https://github.com/leanprover/lean4/pull/5759) fixes the app unexpander for `sorryAx`.
* [#5827](https://github.com/leanprover/lean4/pull/5827) improves accuracy of binder names in the signature pretty printer (like in output of `#check`). Also fixes the issue where consecutive hygienic names pretty print without a space separating them, so we now have `(x✝ y✝ : Nat)` rather than `(x✝y✝ : Nat)`.
* [#5830](https://github.com/leanprover/lean4/pull/5830) makes sure all the core delaborators respond to `pp.explicit` when appropriate.
* [#5639](https://github.com/leanprover/lean4/pull/5639) makes sure name literals use escaping when pretty printing.
* [#5854](https://github.com/leanprover/lean4/pull/5854) adds delaborators for `<|>`, `<*>`, `>>`, `<*`, and `*>`.
### Library
* `Array`
* [#5687](https://github.com/leanprover/lean4/pull/5687) deprecates `Array.data`.
* [#5705](https://github.com/leanprover/lean4/pull/5705) uses a better default value for `Array.swapAt!`.
* [#5748](https://github.com/leanprover/lean4/pull/5748) moves `Array.mapIdx` lemmas to a new file.
* [#5749](https://github.com/leanprover/lean4/pull/5749) simplifies signature of `Array.mapIdx`.
* [#5758](https://github.com/leanprover/lean4/pull/5758) upstreams `Array.reduceOption`.
* [#5786](https://github.com/leanprover/lean4/pull/5786) adds simp lemmas for `Array.isEqv` and `BEq`.
* [#5796](https://github.com/leanprover/lean4/pull/5796) renames `Array.shrink` to `Array.take`, and relates it to `List.take`.
* [#5798](https://github.com/leanprover/lean4/pull/5798) upstreams `List.modify`, adds lemmas, relates to `Array.modify`.
* [#5799](https://github.com/leanprover/lean4/pull/5799) relates `Array.forIn` and `List.forIn`.
* [#5833](https://github.com/leanprover/lean4/pull/5833) adds `Array.forIn'`, and relates to `List`.
* [#5848](https://github.com/leanprover/lean4/pull/5848) fixes deprecations in `Init.Data.Array.Basic` to not recommend the deprecated constant.
* [#5895](https://github.com/leanprover/lean4/pull/5895) adds `LawfulBEq (Array α) ↔ LawfulBEq α`.
* [#5896](https://github.com/leanprover/lean4/pull/5896) moves `@[simp]` from `back_eq_back?` to `back_push`.
* [#5897](https://github.com/leanprover/lean4/pull/5897) renames `Array.back` to `back!`.
* `List`
* [#5605](https://github.com/leanprover/lean4/pull/5605) removes `List.redLength`.
* [#5696](https://github.com/leanprover/lean4/pull/5696) upstreams `List.mapIdx` and adds lemmas.
* [#5697](https://github.com/leanprover/lean4/pull/5697) upstreams `List.foldxM_map`.
* [#5701](https://github.com/leanprover/lean4/pull/5701) renames `List.join` to `List.flatten`.
* [#5703](https://github.com/leanprover/lean4/pull/5703) upstreams `List.sum`.
* [#5706](https://github.com/leanprover/lean4/pull/5706) marks `prefix_append_right_inj` as a simp lemma.
* [#5716](https://github.com/leanprover/lean4/pull/5716) fixes `List.drop_drop` addition order.
* [#5731](https://github.com/leanprover/lean4/pull/5731) renames `List.bind` and `Array.concatMap` to `flatMap`.
* [#5732](https://github.com/leanprover/lean4/pull/5732) renames `List.pure` to `List.singleton`.
* [#5742](https://github.com/leanprover/lean4/pull/5742) upstreams `ne_of_mem_of_not_mem`.
* [#5743](https://github.com/leanprover/lean4/pull/5743) upstreams `ne_of_apply_ne`.
* [#5816](https://github.com/leanprover/lean4/pull/5816) adds more `List.modify` lemmas.
* [#5879](https://github.com/leanprover/lean4/pull/5879) renames `List.groupBy` to `splitBy`.
* [#5913](https://github.com/leanprover/lean4/pull/5913) relates `for` loops over `List` with `foldlM`.
* `Nat`
* [#5694](https://github.com/leanprover/lean4/pull/5694) removes `instBEqNat`, which is redundant with `instBEqOfDecidableEq` but not defeq.
* [#5746](https://github.com/leanprover/lean4/pull/5746) deprecates `Nat.sum`.
* [#5785](https://github.com/leanprover/lean4/pull/5785) adds `Nat.forall_lt_succ` and variants.
* Fixed width integers
* [#5323](https://github.com/leanprover/lean4/pull/5323) redefine unsigned fixed width integers in terms of `BitVec`.
* [#5735](https://github.com/leanprover/lean4/pull/5735) adds `UIntX.[val_ofNat, toBitVec_ofNat]`.
* [#5790](https://github.com/leanprover/lean4/pull/5790) defines `Int8`.
* [#5901](https://github.com/leanprover/lean4/pull/5901) removes native code for `UInt8.modn`.
* `BitVec`
* [#5604](https://github.com/leanprover/lean4/pull/5604) completes `BitVec.[getMsbD|getLsbD|msb]` for shifts (@luisacicolini).
* [#5609](https://github.com/leanprover/lean4/pull/5609) adds lemmas for division when denominator is zero (@bollu).
* [#5620](https://github.com/leanprover/lean4/pull/5620) documents Bitblasting (@bollu)
* [#5623](https://github.com/leanprover/lean4/pull/5623) moves `BitVec.udiv/umod/sdiv/smod` after `add/sub/mul/lt` (@tobiasgrosser).
* [#5645](https://github.com/leanprover/lean4/pull/5645) defines `udiv` normal form to be `/`, resp. `umod` and `%` (@bollu).
* [#5646](https://github.com/leanprover/lean4/pull/5646) adds lemmas about arithmetic inequalities (@bollu).
* [#5680](https://github.com/leanprover/lean4/pull/5680) expands relationship with `toFin` (@tobiasgrosser).
* [#5691](https://github.com/leanprover/lean4/pull/5691) adds `BitVec.(getMSbD, msb)_(add, sub)` and `BitVec.getLsbD_sub` (@luisacicolini).
* [#5712](https://github.com/leanprover/lean4/pull/5712) adds `BitVec.[udiv|umod]_[zero|one|self]` (@tobiasgrosser).
* [#5718](https://github.com/leanprover/lean4/pull/5718) adds `BitVec.sdiv_[zero|one|self]` (@tobiasgrosser).
* [#5721](https://github.com/leanprover/lean4/pull/5721) adds `BitVec.(msb, getMsbD, getLsbD)_(neg, abs)` (@luisacicolini).
* [#5772](https://github.com/leanprover/lean4/pull/5772) adds `BitVec.toInt_sub`, simplifies `BitVec.toInt_neg` (@tobiasgrosser).
* [#5778](https://github.com/leanprover/lean4/pull/5778) prove that `intMin` the smallest signed bitvector (@alexkeizer).
* [#5851](https://github.com/leanprover/lean4/pull/5851) adds `(msb, getMsbD)_twoPow` (@luisacicolini).
* [#5858](https://github.com/leanprover/lean4/pull/5858) adds `BitVec.[zero_ushiftRight|zero_sshiftRight|zero_mul]` and cleans up BVDecide (@tobiasgrosser).
* [#5865](https://github.com/leanprover/lean4/pull/5865) adds `BitVec.(msb, getMsbD)_concat` (@luisacicolini).
* [#5881](https://github.com/leanprover/lean4/pull/5881) adds `Hashable (BitVec n)`
* `String`/`Char`
* [#5728](https://github.com/leanprover/lean4/pull/5728) upstreams `String.dropPrefix?`.
* [#5745](https://github.com/leanprover/lean4/pull/5745) changes `String.dropPrefix?` signature.
* [#5747](https://github.com/leanprover/lean4/pull/5747) adds `Hashable Char` instance
* `HashMap`
* [#5880](https://github.com/leanprover/lean4/pull/5880) adds interim implementation of `HashMap.modify`/`alter`
* **Other**
* [#5704](https://github.com/leanprover/lean4/pull/5704) removes `@[simp]` from `Option.isSome_eq_isSome`.
* [#5739](https://github.com/leanprover/lean4/pull/5739) upstreams material on `Prod`.
* [#5740](https://github.com/leanprover/lean4/pull/5740) moves `Antisymm` to `Std.Antisymm`.
* [#5741](https://github.com/leanprover/lean4/pull/5741) upstreams basic material on `Sum`.
* [#5756](https://github.com/leanprover/lean4/pull/5756) adds `Nat.log2_two_pow` (@spinylobster).
* [#5892](https://github.com/leanprover/lean4/pull/5892) removes duplicated `ForIn` instances.
* [#5900](https://github.com/leanprover/lean4/pull/5900) removes `@[simp]` from `Sum.forall` and `Sum.exists`.
* [#5812](https://github.com/leanprover/lean4/pull/5812) removes redundant `Decidable` assumptions (@FR-vdash-bot).
### Compiler, runtime, and FFI
* [#5685](https://github.com/leanprover/lean4/pull/5685) fixes help message flags, removes the `-f` flag and adds the `-g` flag (@James-Oswald).
* [#5930](https://github.com/leanprover/lean4/pull/5930) adds `--short-version` (`-V`) option to display short version (@juhp).
* [#5144](https://github.com/leanprover/lean4/pull/5144) switches all 64-bit platforms over to consistently using GMP for bignum arithmetic.
* [#5753](https://github.com/leanprover/lean4/pull/5753) raises the minimum supported Windows version to Windows 10 1903 (released May 2019).
### Lake
* [#5715](https://github.com/leanprover/lean4/pull/5715) changes `lake new math` to use `autoImplicit false` (@eric-wieser).
* [#5688](https://github.com/leanprover/lean4/pull/5688) makes `Lake` not create core aliases in the `Lake` namespace.
* [#5924](https://github.com/leanprover/lean4/pull/5924) adds a `text` option for `buildFile*` utilities.
* [#5789](https://github.com/leanprover/lean4/pull/5789) makes `lake init` not `git init` when inside git work tree (@haoxins).
* [#5684](https://github.com/leanprover/lean4/pull/5684) has Lake update a package's `lean-toolchain` file on `lake update` if it finds the package's direct dependencies use a newer compatible toolchain. To skip this step, use the `--keep-toolchain` CLI option. (See breaking changes.)
* [#6218](https://github.com/leanprover/lean4/pull/6218) makes Lake no longer automatically fetch GitHub cloud releases if the package build directory is already present (mirroring the behavior of the Reservoir cache). This prevents the cache from clobbering existing prebuilt artifacts. Users can still manually fetch the cache and clobber the build directory by running `lake build <pkg>:release`.
* [#6231](https://github.com/leanprover/lean4/pull/6231) improves the errors Lake produces when it fails to fetch a dependency from Reservoir. If the package is not indexed, it will produce a suggestion about how to require it from GitHub.
### Documentation
* [#5617](https://github.com/leanprover/lean4/pull/5617) fixes MSYS2 build instructions.
* [#5725](https://github.com/leanprover/lean4/pull/5725) points out that `OfScientific` is called with raw literals (@eric-wieser).
* [#5794](https://github.com/leanprover/lean4/pull/5794) adds a stub for application ellipsis notation (@eric-wieser).
### Breaking changes
* The syntax for providing arguments to deriving handlers has been removed, which was not used by any major Lean projects in the ecosystem. As a result, the `applyDerivingHandlers` now takes one fewer argument, `registerDerivingHandlerWithArgs` is now simply `registerDerivingHandler`, `DerivingHandler` no longer includes the unused parameter, and `DerivingHandlerNoArgs` has been deprecated. To migrate code, delete the unused `none` argument and use `registerDerivingHandler` and `DerivingHandler`. ([#5265](https://github.com/leanprover/lean4/pull/5265))
* The minimum supported Windows version has been raised to Windows 10 1903, released May 2019. ([#5753](https://github.com/leanprover/lean4/pull/5753))
* The `--lean` CLI option for `lake` was removed. Use the `LEAN` environment variable instead. ([#5684](https://github.com/leanprover/lean4/pull/5684))
* The `inductive ... :=`, `structure ... :=`, and `class ... :=` syntaxes have been deprecated in favor of the `... where` variants. The old syntax produces a warning, controlled by the `linter.deprecated` option. ([#5542](https://github.com/leanprover/lean4/pull/5542))
* The generated tactic configuration elaborators now land in `TacticM` to make use of the current recovery state. Commands that wish to elaborate configurations should now use `declare_command_config_elab` instead of `declare_config_elab` to get an elaborator landing in `CommandElabM`. Syntaxes should migrate to `optConfig` instead of `(config)?`, but the elaborators are reverse compatible. ([#5883](https://github.com/leanprover/lean4/pull/5883))
v4.13.0
----------
@@ -88,7 +372,7 @@ v4.13.0
* [#4768](https://github.com/leanprover/lean4/pull/4768) fixes a parse error when `..` appears with a `.` on the next line
* Metaprogramming
* [#3090](https://github.com/leanprover/lean4/pull/3090) handles level parameters in `Meta.evalExpr` (@eric-wieser)
* [#3090](https://github.com/leanprover/lean4/pull/3090) handles level parameters in `Meta.evalExpr` (@eric-wieser)
* [#5401](https://github.com/leanprover/lean4/pull/5401) instance for `Inhabited (TacticM α)` (@alexkeizer)
* [#5412](https://github.com/leanprover/lean4/pull/5412) expose Kernel.check for debugging purposes
* [#5556](https://github.com/leanprover/lean4/pull/5556) improves the "invalid projection" type inference error in `inferType`.

View File

@@ -1 +0,0 @@
[0829/202002.254:ERROR:crashpad_client_win.cc(868)] not connected

View File

@@ -103,10 +103,21 @@ your PR using rebase merge, bypassing the merge queue.
As written above, changes in meta code in the current stage usually will only
affect later stages. This is an issue in two specific cases.
* For the special case of *quotations*, it is desirable to have changes in builtin parsers affect them immediately: when the changes in the parser become active in the next stage, builtin macros implemented via quotations should generate syntax trees compatible with the new parser, and quotation patterns in builtin macros and elaborators should be able to match syntax created by the new parser and macros.
Since quotations capture the syntax tree structure during execution of the current stage and turn it into code for the next stage, we need to run the current stage's builtin parsers in quotations via the interpreter for this to work.
Caveats:
* We activate this behavior by default when building stage 1 by setting `-Dinternal.parseQuotWithCurrentStage=true`.
We force-disable it inside `macro/macro_rules/elab/elab_rules` via `suppressInsideQuot` as they are guaranteed not to run in the next stage and may need to be run in the current one, so the stage 0 parser is the correct one to use for them.
It may be necessary to extend this disabling to functions that contain quotations and are (exclusively) used by one of the mentioned commands. A function using quotations should never be used by both builtin and non-builtin macros/elaborators. Example: https://github.com/leanprover/lean4/blob/f70b7e5722da6101572869d87832494e2f8534b7/src/Lean/Elab/Tactic/Config.lean#L118-L122
* The parser needs to be reachable via an `import` statement, otherwise the version of the previous stage will silently be used.
* Only the parser code (`Parser.fn`) is affected; all metadata such as leading tokens is taken from the previous stage.
For an example, see https://github.com/leanprover/lean4/commit/f9dcbbddc48ccab22c7674ba20c5f409823b4cc1#diff-371387aed38bb02bf7761084fd9460e4168ae16d1ffe5de041b47d3ad2d22422R13
* For *non-builtin* meta code such as `notation`s or `macro`s in
`Notation.lean`, we expect changes to affect the current file and all later
files of the same stage immediately, just like outside the stdlib. To ensure
this, we need to build the stage using `-Dinterpreter.prefer_native=false` -
this, we build stage 1 using `-Dinterpreter.prefer_native=false` -
otherwise, when executing a macro, the interpreter would notice that there is
already a native symbol available for this function and run it instead of the
new IR, but the symbol is from the previous stage!
@@ -124,26 +135,11 @@ affect later stages. This is an issue in two specific cases.
further stages (e.g. after an `update-stage0`) will then need to be compiled
with the flag set to `false` again since they will expect the new signature.
For an example, see https://github.com/leanprover/lean4/commit/da4c46370d85add64ef7ca5e7cc4638b62823fbb.
When enabling `prefer_native`, we usually want to *disable* `parseQuotWithCurrentStage` as it would otherwise make quotations use the interpreter after all.
However, there is a specific case where we want to set both options to `true`: when we make changes to a non-builtin parser like `simp` that has a builtin elaborator, we cannot have the new parser be active outside of quotations in stage 1 as the builtin elaborator from stage 0 would not understand them; on the other hand, we need quotations in e.g. the builtin `simp` elaborator to produce the new syntax in the next stage.
As this issue usually affects only tactics, enabling `debug.byAsSorry` instead of `prefer_native` can be a simpler solution.
* For the special case of *quotations*, it is desirable to have changes in
built-in parsers affect them immediately: when the changes in the parser
become active in the next stage, macros implemented via quotations should
generate syntax trees compatible with the new parser, and quotation patterns
in macro and elaborators should be able to match syntax created by the new
parser and macros. Since quotations capture the syntax tree structure during
execution of the current stage and turn it into code for the next stage, we
need to run the current stage's built-in parsers in quotation via the
interpreter for this to work. Caveats:
* Since interpreting full parsers is not nearly as cheap and we rarely change
built-in syntax, this needs to be opted in using `-Dinternal.parseQuotWithCurrentStage=true`.
* The parser needs to be reachable via an `import` statement, otherwise the
version of the previous stage will silently be used.
* Only the parser code (`Parser.fn`) is affected; all metadata such as leading
tokens is taken from the previous stage.
For an example, see https://github.com/leanprover/lean4/commit/f9dcbbddc48ccab22c7674ba20c5f409823b4cc1#diff-371387aed38bb02bf7761084fd9460e4168ae16d1ffe5de041b47d3ad2d22422
(from before the flag defaulted to `false`).
For a `prefer_native` example, see https://github.com/leanprover/lean4/commit/da4c46370d85add64ef7ca5e7cc4638b62823fbb.
To modify either of these flags both for building and editing the stdlib, adjust
the code in `stage0/src/stdlib_flags.h`. The flags will automatically be reset

View File

@@ -29,7 +29,7 @@ def ex3 (declName : Name) : MetaM Unit := do
for x in xs do
trace[Meta.debug] "{x} : {← inferType x}"
def myMin [LT α] [DecidableRel (α := α) (·<·)] (a b : α) : α :=
def myMin [LT α] [DecidableLT α] (a b : α) : α :=
if a < b then
a
else

View File

@@ -12,17 +12,17 @@ Remark: this example is based on an example found in the Idris manual.
Vectors
--------
A `Vector` is a list of size `n` whose elements belong to a type `α`.
A `Vec` is a list of size `n` whose elements belong to a type `α`.
-/
inductive Vector (α : Type u) : Nat Type u
| nil : Vector α 0
| cons : α Vector α n Vector α (n+1)
inductive Vec (α : Type u) : Nat Type u
| nil : Vec α 0
| cons : α Vec α n Vec α (n+1)
/-!
We can overload the `List.cons` notation `::` and use it to create `Vector`s.
We can overload the `List.cons` notation `::` and use it to create `Vec`s.
-/
infix:67 " :: " => Vector.cons
infix:67 " :: " => Vec.cons
/-!
Now, we define the types of our simple functional language.
@@ -50,11 +50,11 @@ the builtin instance for `Add Int` as the solution.
/-!
Expressions are indexed by the types of the local variables, and the type of the expression itself.
-/
inductive HasType : Fin n Vector Ty n Ty Type where
inductive HasType : Fin n Vec Ty n Ty Type where
| stop : HasType 0 (ty :: ctx) ty
| pop : HasType k ctx ty HasType k.succ (u :: ctx) ty
inductive Expr : Vector Ty n Ty Type where
inductive Expr : Vec Ty n Ty Type where
| var : HasType i ctx ty Expr ctx ty
| val : Int Expr ctx Ty.int
| lam : Expr (a :: ctx) ty Expr ctx (Ty.fn a ty)
@@ -102,8 +102,8 @@ indexed over the types in scope. Since an environment is just another form of li
to the vector of local variable types, we overload again the notation `::` so that we can use the usual list syntax.
Given a proof that a variable is defined in the context, we can then produce a value from the environment.
-/
inductive Env : Vector Ty n Type where
| nil : Env Vector.nil
inductive Env : Vec Ty n Type where
| nil : Env Vec.nil
| cons : Ty.interp a Env ctx Env (a :: ctx)
infix:67 " :: " => Env.cons

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
source ../../tests/common.sh
exec_check lean -Dlinter.all=false "$f"
exec_check_raw lean -Dlinter.all=false "$f"

View File

@@ -128,16 +128,16 @@ Numeric literals can be specified in various bases.
```
numeral : numeral10 | numeral2 | numeral8 | numeral16
numeral10 : [0-9]+
numeral2 : "0" [bB] [0-1]+
numeral8 : "0" [oO] [0-7]+
numeral16 : "0" [xX] hex_char+
numeral10 : [0-9]+ ("_"+ [0-9]+)*
numeral2 : "0" [bB] ("_"* [0-1]+)+
numeral8 : "0" [oO] ("_"* [0-7]+)+
numeral16 : "0" [xX] ("_"* hex_char+)+
```
Floating point literals are also possible with optional exponent:
```
float : [0-9]+ "." [0-9]+ [[eE[+-][0-9]+]
float : numeral10 "." numeral10? [eE[+-]numeral10]
```
For example:
@@ -147,6 +147,7 @@ constant w : Int := 55
constant x : Nat := 26085
constant y : Nat := 0x65E5
constant z : Float := 2.548123e-05
constant b : Bool := 0b_11_01_10_00
```
Note: that negative numbers are created by applying the "-" negation prefix operator to the number, for example:

View File

@@ -139,7 +139,7 @@ You might be wondering, how does the context actually move through the `ReaderM`
add an input argument to a function by modifying its return type? There is a special command in
Lean that will show you the reduced types:
-/
#reduce ReaderM Environment String -- Environment → String
#reduce (types := true) ReaderM Environment String -- Environment → String
/-!
And you can see here that this type is actually a function! It's a function that takes an
`Environment` as input and returns a `String`.
@@ -196,4 +196,4 @@ entirely.
Now it's time to move on to [StateM Monad](states.lean.md) which is like a `ReaderM` that is
also updatable.
-/
-/

View File

@@ -0,0 +1,16 @@
We replace the inductive predicate `List.lt` with an upstreamed version of `List.Lex` from Mathlib.
(Previously `Lex.lt` was defined in terms of `<`; now it is generalized to take an arbitrary relation.)
This subtely changes the notion of ordering on `List α`.
`List.lt` was a weaker relation: in particular if `l₁ < l₂`, then
`a :: l₁ < b :: l₂` may hold according to `List.lt` even if `a` and `b` are merely incomparable
(either neither `a < b` nor `b < a`), whereas according to `List.Lex` this would require `a = b`.
When `<` is total, in the sense that `¬ · < ·` is antisymmetric, then the two relations coincide.
Mathlib was already overriding the order instances for `List α`,
so this change should not be noticed by anyone already using Mathlib.
We simultaneously add the boolean valued `List.lex` function, parameterised by a `BEq` typeclass
and an arbitrary `lt` function. This will support the flexibility previously provided for `List.lt`,
via a `==` function which is weaker than strict equality.

12
script/mathlib-bench Executable file
View File

@@ -0,0 +1,12 @@
#! /bin/env bash
# Open a Mathlib4 PR for benchmarking a given Lean 4 PR
set -euo pipefail
[ $# -eq 1 ] || (echo "usage: $0 <lean4 PR #>"; exit 1)
LEAN_PR=$1
PR_RESPONSE=$(gh api repos/leanprover-community/mathlib4/pulls -X POST -f head=lean-pr-testing-$LEAN_PR -f base=nightly-testing -f title="leanprover/lean4#$LEAN_PR benchmarking" -f draft=true -f body="ignore me")
PR_NUMBER=$(echo "$PR_RESPONSE" | jq '.number')
echo "opened https://github.com/leanprover-community/mathlib4/pull/$PR_NUMBER"
gh api repos/leanprover-community/mathlib4/issues/$PR_NUMBER/comments -X POST -f body="!bench" > /dev/null

View File

@@ -10,7 +10,7 @@ endif()
include(ExternalProject)
project(LEAN CXX C)
set(LEAN_VERSION_MAJOR 4)
set(LEAN_VERSION_MINOR 15)
set(LEAN_VERSION_MINOR 16)
set(LEAN_VERSION_PATCH 0)
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
@@ -51,6 +51,8 @@ option(LLVM "LLVM" OFF)
option(USE_GITHASH "GIT_HASH" ON)
# When ON we install LICENSE files to CMAKE_INSTALL_PREFIX
option(INSTALL_LICENSE "INSTALL_LICENSE" ON)
# When ON we install a copy of cadical
option(INSTALL_CADICAL "Install a copy of cadical" ON)
# When ON thread storage is automatically finalized, it assumes platform support pthreads.
# This option is important when using Lean as library that is invoked from a different programming language (e.g., Haskell).
option(AUTO_THREAD_FINALIZATION "AUTO_THREAD_FINALIZATION" ON)
@@ -120,7 +122,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
# From https://emscripten.org/docs/compiling/WebAssembly.html#backends:
# > The simple and safe thing is to pass all -s flags at both compile and link time.
set(EMSCRIPTEN_SETTINGS "-s ALLOW_MEMORY_GROWTH=1 -fwasm-exceptions -pthread -flto")
string(APPEND LEANC_EXTRA_FLAGS " -pthread")
string(APPEND LEANC_EXTRA_CC_FLAGS " -pthread")
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_EMSCRIPTEN ${EMSCRIPTEN_SETTINGS}")
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${EMSCRIPTEN_SETTINGS}")
endif()
@@ -155,11 +157,11 @@ if ((${MULTI_THREAD} MATCHES "ON") AND (${CMAKE_SYSTEM_NAME} MATCHES "Darwin"))
endif ()
# We want explicit stack probes in huge Lean stack frames for robust stack overflow detection
string(APPEND LEANC_EXTRA_FLAGS " -fstack-clash-protection")
string(APPEND LEANC_EXTRA_CC_FLAGS " -fstack-clash-protection")
# This makes signed integer overflow guaranteed to match 2's complement.
string(APPEND CMAKE_CXX_FLAGS " -fwrapv")
string(APPEND LEANC_EXTRA_FLAGS " -fwrapv")
string(APPEND LEANC_EXTRA_CC_FLAGS " -fwrapv")
if(NOT MULTI_THREAD)
message(STATUS "Disabled multi-thread support, it will not be safe to run multiple threads in parallel")
@@ -449,7 +451,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,-Bsymbolic")
endif()
string(APPEND CMAKE_CXX_FLAGS " -fPIC -ftls-model=initial-exec")
string(APPEND LEANC_EXTRA_FLAGS " -fPIC")
string(APPEND LEANC_EXTRA_CC_FLAGS " -fPIC")
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,-rpath=\\$$ORIGIN/..:\\$$ORIGIN")
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libLake.a.export -Wl,--no-whole-archive")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath=\\\$ORIGIN/../lib:\\\$ORIGIN/../lib/lean")
@@ -462,7 +464,7 @@ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
string(APPEND CMAKE_CXX_FLAGS " -fPIC")
string(APPEND LEANC_EXTRA_FLAGS " -fPIC")
string(APPEND LEANC_EXTRA_CC_FLAGS " -fPIC")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libLake_shared.dll.a -Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libLake.a.export -Wl,--no-whole-archive")
endif()
@@ -477,7 +479,7 @@ if(NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows") AND NOT(${CMAKE_SYSTEM_NAME} MATC
string(APPEND CMAKE_EXE_LINKER_FLAGS " -rdynamic")
# hide all other symbols
string(APPEND CMAKE_CXX_FLAGS " -fvisibility=hidden -fvisibility-inlines-hidden")
string(APPEND LEANC_EXTRA_FLAGS " -fvisibility=hidden")
string(APPEND LEANC_EXTRA_CC_FLAGS " -fvisibility=hidden")
endif()
# On Windows, add bcrypt for random number generation
@@ -542,9 +544,10 @@ include_directories(${CMAKE_BINARY_DIR}/include) # config.h etc., "public" head
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
string(APPEND LEANC_OPTS " ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}}")
# Do embed flag for finding system libraries in dev builds
# Do embed flag for finding system headers and libraries in dev builds
if(CMAKE_OSX_SYSROOT AND NOT LEAN_STANDALONE)
string(APPEND LEANC_EXTRA_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
string(APPEND LEANC_EXTRA_CC_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
endif()
add_subdirectory(initialize)
@@ -616,7 +619,7 @@ else()
OUTPUT_NAME leancpp)
endif()
if((${STAGE} GREATER 0) AND CADICAL)
if((${STAGE} GREATER 0) AND CADICAL AND INSTALL_CADICAL)
add_custom_target(copy-cadical
COMMAND cmake -E copy_if_different "${CADICAL}" "${CMAKE_BINARY_DIR}/bin/cadical${CMAKE_EXECUTABLE_SUFFIX}")
add_dependencies(leancpp copy-cadical)
@@ -738,7 +741,7 @@ file(COPY ${LEAN_SOURCE_DIR}/bin/leanmake DESTINATION ${CMAKE_BINARY_DIR}/bin)
install(DIRECTORY "${CMAKE_BINARY_DIR}/bin/" USE_SOURCE_PERMISSIONS DESTINATION bin)
if (${STAGE} GREATER 0 AND CADICAL)
if (${STAGE} GREATER 0 AND CADICAL AND INSTALL_CADICAL)
install(PROGRAMS "${CADICAL}" DESTINATION bin)
endif()

View File

@@ -106,7 +106,7 @@ theorem seq_eq_bind_map {α β : Type u} [Monad m] [LawfulMonad m] (f : m (α
theorem bind_congr [Bind m] {x : m α} {f g : α m β} (h : a, f a = g a) : x >>= f = x >>= g := by
simp [funext h]
@[simp] theorem bind_pure_unit [Monad m] [LawfulMonad m] {x : m PUnit} : (x >>= fun _ => pure ) = x := by
theorem bind_pure_unit [Monad m] [LawfulMonad m] {x : m PUnit} : (x >>= fun _ => pure ) = x := by
rw [bind_pure]
theorem map_congr [Functor m] {x : m α} {f g : α β} (h : a, f a = g a) : (f <$> x : m β) = g <$> x := by
@@ -133,7 +133,7 @@ theorem seqLeft_eq_bind [Monad m] [LawfulMonad m] (x : m α) (y : m β) : x <* y
rw [ bind_pure_comp]
simp only [bind_assoc, pure_bind]
@[simp] theorem Functor.map_unit [Monad m] [LawfulMonad m] {a : m PUnit} : (fun _ => PUnit.unit) <$> a = a := by
theorem Functor.map_unit [Monad m] [LawfulMonad m] {a : m PUnit} : (fun _ => PUnit.unit) <$> a = a := by
simp [map]
/--

View File

@@ -2116,14 +2116,37 @@ instance : Commutative Or := ⟨fun _ _ => propext or_comm⟩
instance : Commutative And := fun _ _ => propext and_comm
instance : Commutative Iff := fun _ _ => propext iff_comm
/-- `IsRefl X r` means the binary relation `r` on `X` is reflexive. -/
class Refl (r : α α Prop) : Prop where
/-- A reflexive relation satisfies `r a a`. -/
refl : a, r a a
/--
`Antisymm (·≤·)` says that `(·≤·)` is antisymmetric, that is, `a ≤ b → b ≤ a → a = b`.
-/
class Antisymm (r : α α Prop) : Prop where
/-- An antisymmetric relation `(·≤·)` satisfies `a ≤ b → b ≤ a → a = b`. -/
antisymm {a b : α} : r a b r b a a = b
antisymm (a b : α) : r a b r b a a = b
@[deprecated Antisymm (since := "2024-10-16"), inherit_doc Antisymm]
abbrev _root_.Antisymm (r : α α Prop) : Prop := Std.Antisymm r
/-- `Asymm X r` means that the binary relation `r` on `X` is asymmetric, that is,
`r a b → ¬ r b a`. -/
class Asymm (r : α α Prop) : Prop where
/-- An asymmetric relation satisfies `r a b → ¬ r b a`. -/
asymm : a b, r a b ¬r b a
/-- `Total X r` means that the binary relation `r` on `X` is total, that is, that for any
`x y : X` we have `r x y` or `r y x`. -/
class Total (r : α α Prop) : Prop where
/-- A total relation satisfies `r a b r b a`. -/
total : a b, r a b r b a
/-- `Irrefl X r` means the binary relation `r` on `X` is irreflexive (that is, `r x x` never
holds). -/
class Irrefl (r : α α Prop) : Prop where
/-- An irreflexive relation satisfies `¬ r a a`. -/
irrefl : a, ¬r a a
end Std

View File

@@ -21,6 +21,7 @@ import Init.Data.Fin
import Init.Data.UInt
import Init.Data.SInt
import Init.Data.Float
import Init.Data.Float32
import Init.Data.Option
import Init.Data.Ord
import Init.Data.Random
@@ -43,3 +44,4 @@ import Init.Data.Zero
import Init.Data.NeZero
import Init.Data.Function
import Init.Data.RArray
import Init.Data.Vector

View File

@@ -19,3 +19,7 @@ import Init.Data.Array.GetLit
import Init.Data.Array.MapIdx
import Init.Data.Array.Set
import Init.Data.Array.Monadic
import Init.Data.Array.FinRange
import Init.Data.Array.Perm
import Init.Data.Array.Find
import Init.Data.Array.Lex

View File

@@ -150,7 +150,6 @@ theorem attach_map_coe (l : Array α) (f : α → β) :
theorem attach_map_val (l : Array α) (f : α β) : (l.attach.map fun i => f i.val) = l.map f :=
attach_map_coe _ _
@[simp]
theorem attach_map_subtype_val (l : Array α) : l.attach.map Subtype.val = l := by
cases l; simp
@@ -162,7 +161,6 @@ theorem attachWith_map_val {p : α → Prop} (f : α → β) (l : Array α) (H :
((l.attachWith p H).map fun i => f i.val) = l.map f :=
attachWith_map_coe _ _ _
@[simp]
theorem attachWith_map_subtype_val {p : α Prop} (l : Array α) (H : a l, p a) :
(l.attachWith p H).map Subtype.val = l := by
cases l; simp
@@ -204,8 +202,8 @@ theorem pmap_ne_empty_iff {P : α → Prop} (f : (a : α) → P a → β) {xs :
(H : (a : α), a xs P a) : xs.pmap f H #[] xs #[] := by
cases xs; simp
theorem pmap_eq_self {l : Array α} {p : α Prop} (hp : (a : α), a l p a)
(f : (a : α) p a α) : l.pmap f hp = l a (h : a l), f a (hp a h) = a := by
theorem pmap_eq_self {l : Array α} {p : α Prop} {hp : (a : α), a l p a}
{f : (a : α) p a α} : l.pmap f hp = l a (h : a l), f a (hp a h) = a := by
cases l; simp [List.pmap_eq_self]
@[simp]
@@ -251,7 +249,7 @@ theorem getElem?_attach {xs : Array α} {i : Nat} :
theorem getElem_attachWith {xs : Array α} {P : α Prop} {H : a xs, P a}
{i : Nat} (h : i < (xs.attachWith P H).size) :
(xs.attachWith P H)[i] = xs[i]'(by simpa using h), H _ (getElem_mem (by simpa using h)) :=
getElem_pmap ..
getElem_pmap _ _ h
@[simp]
theorem getElem_attach {xs : Array α} {i : Nat} (h : i < xs.attach.size) :

View File

@@ -11,7 +11,7 @@ import Init.Data.UInt.BasicAux
import Init.Data.Repr
import Init.Data.ToString.Basic
import Init.GetElem
import Init.Data.List.ToArray
import Init.Data.List.ToArrayImpl
import Init.Data.Array.Set
universe u v w
@@ -79,12 +79,15 @@ theorem ext' {as bs : Array α} (h : as.toList = bs.toList) : as = bs := by
@[simp] theorem toArrayAux_eq (as : List α) (acc : Array α) : (as.toArrayAux acc).toList = acc.toList ++ as := by
induction as generalizing acc <;> simp [*, List.toArrayAux, Array.push, List.append_assoc, List.concat_eq_append]
@[simp] theorem toList_toArray (as : List α) : as.toArray.toList = as := rfl
-- This does not need to be a simp lemma, as already after the `whnfR` the right hand side is `as`.
theorem toList_toArray (as : List α) : as.toArray.toList = as := rfl
@[simp] theorem size_toArray (as : List α) : as.toArray.size = as.length := by simp [size]
@[simp] theorem getElem_toList {a : Array α} {i : Nat} (h : i < a.size) : a.toList[i] = a[i] := rfl
@[simp] theorem getElem?_toList {a : Array α} {i : Nat} : a.toList[i]? = a[i]? := rfl
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
-- NB: This is defined as a structure rather than a plain def so that a lemma
-- like `sizeOf_lt_of_mem` will not apply with no actual arrays around.
@@ -97,6 +100,9 @@ instance : Membership α (Array α) where
theorem mem_def {a : α} {as : Array α} : a as a as.toList :=
fun | .mk h => h, Array.Mem.mk
@[simp] theorem mem_toArray {a : α} {l : List α} : a l.toArray a l := by
simp [mem_def]
@[simp] theorem getElem_mem {l : Array α} {i : Nat} (h : i < l.size) : l[i] l := by
rw [Array.mem_def, getElem_toList]
apply List.getElem_mem
@@ -203,7 +209,7 @@ instance : EmptyCollection (Array α) := ⟨Array.empty⟩
instance : Inhabited (Array α) where
default := Array.empty
@[simp] def isEmpty (a : Array α) : Bool :=
def isEmpty (a : Array α) : Bool :=
a.size = 0
@[specialize]
@@ -242,7 +248,7 @@ def singleton (v : α) : Array α :=
mkArray 1 v
def back! [Inhabited α] (a : Array α) : α :=
a.get! (a.size - 1)
a[a.size - 1]!
@[deprecated back! (since := "2024-10-31")] abbrev back := @back!
@@ -474,6 +480,10 @@ def findSomeM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f
| _ => pure
return none
/--
Note that the universe level is contrained to `Type` here,
to avoid having to have the predicate live in `p : α → m (ULift Bool)`.
-/
@[inline]
def findM? {α : Type} {m : Type Type} [Monad m] (p : α m Bool) (as : Array α) : m (Option α) := do
for a in as do
@@ -585,8 +595,12 @@ def zipWithIndex (arr : Array α) : Array (α × Nat) :=
arr.mapIdx fun i a => (a, i)
@[inline]
def find? {α : Type} (p : α Bool) (as : Array α) : Option α :=
Id.run <| as.findM? p
def find? {α : Type u} (p : α Bool) (as : Array α) : Option α :=
Id.run do
for a in as do
if p a then
return a
return none
@[inline]
def findSome? {α : Type u} {β : Type v} (f : α Option β) (as : Array α) : Option β :=
@@ -649,9 +663,15 @@ def any (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool
def all (as : Array α) (p : α Bool) (start := 0) (stop := as.size) : Bool :=
Id.run <| as.allM p start stop
/-- `as.contains a` is true if there is some element `b` in `as` such that `a == b`. -/
def contains [BEq α] (as : Array α) (a : α) : Bool :=
as.any (· == a)
as.any (a == ·)
/--
Variant of `Array.contains` with arguments reversed.
For verification purposes, we simplify this to `contains`.
-/
def elem [BEq α] (a : α) (as : Array α) : Bool :=
as.contains a
@@ -801,7 +821,7 @@ decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
induction a, i, h using Array.eraseIdx.induct with
| @case1 a i h h' a' ih =>
unfold eraseIdx
simp [h', a', ih]
simp +zetaDelta [h', a', ih]
| case2 a i h h' =>
unfold eraseIdx
simp [h']
@@ -924,6 +944,13 @@ def split (as : Array α) (p : α → Bool) : Array α × Array α :=
as.foldl (init := (#[], #[])) fun (as, bs) a =>
if p a then (as.push a, bs) else (as, bs.push a)
/-! ### Lexicographic ordering -/
instance instLT [LT α] : LT (Array α) := fun as bs => as.toList < bs.toList
instance instLE [LT α] : LE (Array α) := fun as bs => as.toList bs.toList
-- See `Init.Data.Array.Lex.Basic` for the boolean valued lexicographic comparator.
/-! ## Auxiliary functions used in metaprogramming.
We do not currently intend to provide verification theorems for these functions.

View File

@@ -32,10 +32,8 @@ private theorem List.of_toArrayAux_eq_toArrayAux {as bs : List α} {cs ds : Arra
have := Array.of_push_eq_push ih₂
simp [this]
@[simp] theorem List.toArray_eq_toArray_eq (as bs : List α) : (as.toArray = bs.toArray) = (as = bs) := by
apply propext; apply Iff.intro
· intro h; simpa [toArray] using h
· intro h; rw [h]
theorem List.toArray_eq_toArray_eq (as bs : List α) : (as.toArray = bs.toArray) = (as = bs) := by
simp
def Array.mapM' [Monad m] (f : α m β) (as : Array α) : m { bs : Array β // bs.size = as.size } :=
go 0 mkEmpty as.size, rfl (by simp)

View File

@@ -23,7 +23,7 @@ theorem foldlM_toList.aux [Monad m]
· cases Nat.not_le_of_gt _ (Nat.zero_add _ H)
· rename_i i; rw [Nat.succ_add] at H
simp [foldlM_toList.aux f arr i (j+1) H]
rw (occs := .pos [2]) [ List.getElem_cons_drop_succ_eq_drop _]
rw (occs := [2]) [ List.getElem_cons_drop_succ_eq_drop _]
rfl
· rw [List.drop_of_length_le (Nat.ge_of_not_lt _)]; rfl
@@ -93,11 +93,14 @@ theorem foldrM_eq_reverse_foldlM_toList [Monad m] (f : α → β → m β) (init
@[simp] theorem appendList_eq_append
(arr : Array α) (l : List α) : arr.appendList l = arr ++ l := rfl
@[simp] theorem appendList_toList (arr : Array α) (l : List α) :
@[simp] theorem toList_appendList (arr : Array α) (l : List α) :
(arr ++ l).toList = arr.toList ++ l := by
rw [ appendList_eq_append]; unfold Array.appendList
induction l generalizing arr <;> simp [*]
@[deprecated toList_appendList (since := "2024-12-11")]
abbrev appendList_toList := @toList_appendList
@[deprecated "Use the reverse direction of `foldrM_toList`." (since := "2024-11-13")]
theorem foldrM_eq_foldrM_toList [Monad m]
(f : α β m β) (init : β) (arr : Array α) :
@@ -149,7 +152,7 @@ abbrev pop_data := @pop_toList
@[deprecated toList_append (since := "2024-09-09")]
abbrev append_data := @toList_append
@[deprecated appendList_toList (since := "2024-09-09")]
abbrev appendList_data := @appendList_toList
@[deprecated toList_appendList (since := "2024-09-09")]
abbrev appendList_data := @toList_appendList
end Array

View File

@@ -42,7 +42,7 @@ theorem rel_of_isEqv {r : αα → Bool} {a b : Array α} :
· exact fun h' => h, fun i => rel_of_isEqvAux h (Nat.le_refl ..) h'
· intro; contradiction
theorem isEqv_iff_rel (a b : Array α) (r) :
theorem isEqv_iff_rel {a b : Array α} {r} :
Array.isEqv a b r h : a.size = b.size, (i : Nat) (h' : i < a.size), r (a[i]) (b[i]'(h h')) :=
rel_of_isEqv, fun h, w => by
simp only [isEqv, h, reduceDIte]

View File

@@ -0,0 +1,14 @@
/-
Copyright (c) 2024 François G. Dorais. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: François G. Dorais
-/
prelude
import Init.Data.List.FinRange
namespace Array
/-- `finRange n` is the array of all elements of `Fin n` in order. -/
protected def finRange (n : Nat) : Array (Fin n) := ofFn fun i => i
end Array

View File

@@ -81,7 +81,7 @@ theorem getElem_zero_flatten.proof {L : Array (Array α)} (h : 0 < L.flatten.siz
(L.findSome? fun l => l[0]?).isSome := by
cases L using array_array_induction
simp only [List.findSome?_toArray, List.findSome?_map, Function.comp_def, List.getElem?_toArray,
List.findSome?_isSome_iff, List.isSome_getElem?]
List.findSome?_isSome_iff, isSome_getElem?]
simp only [flatten_toArray_map_toArray, size_toArray, List.length_flatten,
Nat.sum_pos_iff_exists_pos, List.mem_map] at h
obtain _, xs, m, rfl, h := h
@@ -99,7 +99,7 @@ theorem back?_flatten {L : Array (Array α)} :
simp [List.getLast?_flatten, List.map_reverse, List.findSome?_map, Function.comp_def]
theorem findSome?_mkArray : findSome? f (mkArray n a) = if n = 0 then none else f a := by
simp [mkArray_eq_toArray_replicate, List.findSome?_replicate]
simp [ List.toArray_replicate, List.findSome?_replicate]
@[simp] theorem findSome?_mkArray_of_pos (h : 0 < n) : findSome? f (mkArray n a) = f a := by
simp [findSome?_mkArray, Nat.ne_of_gt h]
@@ -246,7 +246,7 @@ theorem find?_flatMap_eq_none {xs : Array α} {f : α → Array β} {p : β →
theorem find?_mkArray :
find? p (mkArray n a) = if n = 0 then none else if p a then some a else none := by
simp [mkArray_eq_toArray_replicate, List.find?_replicate]
simp [ List.toArray_replicate, List.find?_replicate]
@[simp] theorem find?_mkArray_of_length_pos (h : 0 < n) :
find? p (mkArray n a) = if p a then some a else none := by
@@ -262,15 +262,15 @@ theorem find?_mkArray :
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
theorem find?_mkArray_eq_none {n : Nat} {a : α} {p : α Bool} :
(mkArray n a).find? p = none n = 0 !p a := by
simp [mkArray_eq_toArray_replicate, List.find?_replicate_eq_none, Classical.or_iff_not_imp_left]
simp [ List.toArray_replicate, List.find?_replicate_eq_none, Classical.or_iff_not_imp_left]
@[simp] theorem find?_mkArray_eq_some {n : Nat} {a b : α} {p : α Bool} :
(mkArray n a).find? p = some b n 0 p a a = b := by
simp [mkArray_eq_toArray_replicate]
simp [ List.toArray_replicate]
@[simp] theorem get_find?_mkArray (n : Nat) (a : α) (p : α Bool) (h) :
((mkArray n a).find? p).get h = a := by
simp [mkArray_eq_toArray_replicate]
simp [ List.toArray_replicate]
theorem find?_pmap {P : α Prop} (f : (a : α) P a β) (xs : Array α)
(H : (a : α), a xs P a) (p : β Bool) :

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
/-
Copyright (c) 2024 Lean FRO. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Kim Morrison
-/
prelude
import Init.Data.Array.Lex.Basic
import Init.Data.Array.Lex.Lemmas

View File

@@ -0,0 +1,30 @@
/-
Copyright (c) 2024 Lean FRO. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Kim Morrison
-/
prelude
import Init.Data.Array.Basic
import Init.Data.Nat.Lemmas
import Init.Data.Range
namespace Array
/--
Lexicographic comparator for arrays.
`lex as bs lt` is true if
- `bs` is larger than `as` and `as` is pairwise equivalent via `==` to the initial segment of `bs`, or
- there is an index `i` such that `lt as[i] bs[i]`, and for all `j < i`, `as[j] == bs[j]`.
-/
def lex [BEq α] (as bs : Array α) (lt : α α Bool := by exact (· < ·)) : Bool := Id.run do
for h : i in [0 : min as.size bs.size] do
-- TODO: `omega` should be able to find this itself.
have : i < min as.size bs.size := Membership.get_elem_helper h rfl
if lt as[i] bs[i] then
return true
else if as[i] != bs[i] then
return false
return as.size < bs.size
end Array

View File

@@ -0,0 +1,216 @@
/-
Copyright (c) 2024 Lean FRO. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Kim Morrison
-/
prelude
import Init.Data.Array.Lemmas
import Init.Data.List.Lex
namespace Array
/-! ### Lexicographic ordering -/
@[simp] theorem lt_toArray [LT α] (l₁ l₂ : List α) : l₁.toArray < l₂.toArray l₁ < l₂ := Iff.rfl
@[simp] theorem le_toArray [LT α] (l₁ l₂ : List α) : l₁.toArray l₂.toArray l₁ l₂ := Iff.rfl
theorem not_lt_iff_ge [LT α] (l₁ l₂ : List α) : ¬ l₁ < l₂ l₂ l₁ := Iff.rfl
theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] (l₁ l₂ : List α) :
¬ l₁ l₂ l₂ < l₁ :=
Decidable.not_not
@[simp] theorem lex_empty [BEq α] {lt : α α Bool} (l : Array α) : l.lex #[] lt = false := by
simp [lex, Id.run]
@[simp] theorem singleton_lex_singleton [BEq α] {lt : α α Bool} : #[a].lex #[b] lt = lt a b := by
simp only [lex, List.getElem_toArray, List.getElem_singleton]
cases lt a b <;> cases a != b <;> simp [Id.run]
private theorem cons_lex_cons [BEq α] {lt : α α Bool} {a b : α} {xs ys : Array α} :
(#[a] ++ xs).lex (#[b] ++ ys) lt =
(lt a b || a == b && xs.lex ys lt) := by
simp only [lex, Id.run]
simp only [Std.Range.forIn'_eq_forIn'_range', size_append, size_toArray, List.length_singleton,
Nat.add_comm 1]
simp [Nat.add_min_add_right, List.range'_succ, getElem_append_left, List.range'_succ_left,
getElem_append_right]
cases lt a b
· rw [bne]
cases a == b <;> simp
· simp
@[simp] theorem _root_.List.lex_toArray [BEq α] (lt : α α Bool) (l₁ l₂ : List α) :
l₁.toArray.lex l₂.toArray lt = l₁.lex l₂ lt := by
induction l₁ generalizing l₂ with
| nil => cases l₂ <;> simp [lex, Id.run]
| cons x l₁ ih =>
cases l₂ with
| nil => simp [lex, Id.run]
| cons y l₂ =>
rw [List.toArray_cons, List.toArray_cons y, cons_lex_cons, List.lex, ih]
@[simp] theorem lex_toList [BEq α] (lt : α α Bool) (l₁ l₂ : Array α) :
l₁.toList.lex l₂.toList lt = l₁.lex l₂ lt := by
cases l₁ <;> cases l₂ <;> simp
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α α Prop)] (l : Array α) : ¬ l < l :=
List.lt_irrefl l.toList
instance ltIrrefl [LT α] [Std.Irrefl (· < · : α α Prop)] : Std.Irrefl (α := Array α) (· < ·) where
irrefl := Array.lt_irrefl
@[simp] theorem empty_le [LT α] (l : Array α) : #[] l := List.nil_le l.toList
@[simp] theorem le_empty [LT α] (l : Array α) : l #[] l = #[] := by
cases l
simp
@[simp] theorem empty_lt_push [LT α] (l : Array α) (a : α) : #[] < l.push a := by
rcases l with (_ | x, l) <;> simp
protected theorem le_refl [LT α] [i₀ : Std.Irrefl (· < · : α α Prop)] (l : Array α) : l l :=
List.le_refl l.toList
instance [LT α] [Std.Irrefl (· < · : α α Prop)] : Std.Refl (· · : Array α Array α Prop) where
refl := Array.le_refl
protected theorem lt_trans [LT α] [DecidableLT α]
[i₁ : Trans (· < · : α α Prop) (· < ·) (· < ·)]
{l₁ l₂ l₃ : Array α} (h₁ : l₁ < l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
List.lt_trans h₁ h₂
instance [LT α] [DecidableLT α]
[Trans (· < · : α α Prop) (· < ·) (· < ·)] :
Trans (· < · : Array α Array α Prop) (· < ·) (· < ·) where
trans h₁ h₂ := Array.lt_trans h₁ h₂
protected theorem lt_of_le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
[i₀ : Std.Irrefl (· < · : α α Prop)]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
[i₃ : Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{l₁ l₂ l₃ : Array α} (h₁ : l₁ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
List.lt_of_le_of_lt h₁ h₂
protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{l₁ l₂ l₃ : Array α} (h₁ : l₁ l₂) (h₂ : l₂ l₃) : l₁ l₃ :=
fun h₃ => h₁ (Array.lt_of_le_of_lt h₂ h₃)
instance [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)] :
Trans (· · : Array α Array α Prop) (· ·) (· ·) where
trans h₁ h₂ := Array.le_trans h₁ h₂
protected theorem lt_asymm [DecidableEq α] [LT α] [DecidableLT α]
[i : Std.Asymm (· < · : α α Prop)]
{l₁ l₂ : Array α} (h : l₁ < l₂) : ¬ l₂ < l₁ := List.lt_asymm h
instance [DecidableEq α] [LT α] [DecidableLT α]
[Std.Asymm (· < · : α α Prop)] :
Std.Asymm (· < · : Array α Array α Prop) where
asymm _ _ := Array.lt_asymm
protected theorem le_total [DecidableEq α] [LT α] [DecidableLT α]
[i : Std.Total (¬ · < · : α α Prop)] {l₁ l₂ : Array α} : l₁ l₂ l₂ l₁ :=
List.le_total
instance [DecidableEq α] [LT α] [DecidableLT α]
[Std.Total (¬ · < · : α α Prop)] :
Std.Total (· · : Array α Array α Prop) where
total _ _ := Array.le_total
@[simp] theorem lex_eq_true_iff_lt [DecidableEq α] [LT α] [DecidableLT α]
{l₁ l₂ : Array α} : lex l₁ l₂ = true l₁ < l₂ := by
cases l₁
cases l₂
simp
@[simp] theorem lex_eq_false_iff_ge [DecidableEq α] [LT α] [DecidableLT α]
{l₁ l₂ : Array α} : lex l₁ l₂ = false l₂ l₁ := by
cases l₁
cases l₂
simp [List.not_lt_iff_ge]
instance [DecidableEq α] [LT α] [DecidableLT α] : DecidableLT (Array α) :=
fun l₁ l₂ => decidable_of_iff (lex l₁ l₂ = true) lex_eq_true_iff_lt
instance [DecidableEq α] [LT α] [DecidableLT α] : DecidableLE (Array α) :=
fun l₁ l₂ => decidable_of_iff (lex l₂ l₁ = false) lex_eq_false_iff_ge
/--
`l₁` is lexicographically less than `l₂` if either
- `l₁` is pairwise equivalent under `· == ·` to `l₂.take l₁.size`,
and `l₁` is shorter than `l₂` or
- there exists an index `i` such that
- for all `j < i`, `l₁[j] == l₂[j]` and
- `l₁[i] < l₂[i]`
-/
theorem lex_eq_true_iff_exists [BEq α] (lt : α α Bool) :
lex l₁ l₂ lt = true
(l₁.isEqv (l₂.take l₁.size) (· == ·) l₁.size < l₂.size)
( (i : Nat) (h₁ : i < l₁.size) (h₂ : i < l₂.size),
( j, (hj : j < i)
l₁[j]'(Nat.lt_trans hj h₁) == l₂[j]'(Nat.lt_trans hj h₂)) lt l₁[i] l₂[i]) := by
cases l₁
cases l₂
simp [List.lex_eq_true_iff_exists]
/--
`l₁` is *not* lexicographically less than `l₂`
(which you might think of as "`l₂` is lexicographically greater than or equal to `l₁`"") if either
- `l₁` is pairwise equivalent under `· == ·` to `l₂.take l₁.length` or
- there exists an index `i` such that
- for all `j < i`, `l₁[j] == l₂[j]` and
- `l₂[i] < l₁[i]`
This formulation requires that `==` and `lt` are compatible in the following senses:
- `==` is symmetric
(we unnecessarily further assume it is transitive, to make use of the existing typeclasses)
- `lt` is irreflexive with respect to `==` (i.e. if `x == y` then `lt x y = false`
- `lt` is asymmmetric (i.e. `lt x y = true → lt y x = false`)
- `lt` is antisymmetric with respect to `==` (i.e. `lt x y = false → lt y x = false → x == y`)
-/
theorem lex_eq_false_iff_exists [BEq α] [PartialEquivBEq α] (lt : α α Bool)
(lt_irrefl : x y, x == y lt x y = false)
(lt_asymm : x y, lt x y = true lt y x = false)
(lt_antisymm : x y, lt x y = false lt y x = false x == y) :
lex l₁ l₂ lt = false
(l₂.isEqv (l₁.take l₂.size) (· == ·))
( (i : Nat) (h₁ : i < l₁.size) (h₂ : i < l₂.size),
( j, (hj : j < i)
l₁[j]'(Nat.lt_trans hj h₁) == l₂[j]'(Nat.lt_trans hj h₂)) lt l₂[i] l₁[i]) := by
cases l₁
cases l₂
simp_all [List.lex_eq_false_iff_exists]
theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {l₁ l₂ : Array α} :
l₁ < l₂
(l₁ = l₂.take l₁.size l₁.size < l₂.size)
( (i : Nat) (h₁ : i < l₁.size) (h₂ : i < l₂.size),
( j, (hj : j < i)
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) l₁[i] < l₂[i]) := by
cases l₁
cases l₂
simp [List.lt_iff_exists]
theorem le_iff_exists [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)] {l₁ l₂ : Array α} :
l₁ l₂
(l₁ = l₂.take l₁.size)
( (i : Nat) (h₁ : i < l₁.size) (h₂ : i < l₂.size),
( j, (hj : j < i)
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) l₁[i] < l₂[i]) := by
cases l₁
cases l₂
simp [List.le_iff_exists]
end Array

View File

@@ -79,8 +79,31 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β
rw [List.filter_toArray] -- Why doesn't this fire via `simp`?
simp [List.foldrM_filter]
/-! ### forM -/
@[congr] theorem forM_congr [Monad m] {as bs : Array α} (w : as = bs)
{f : α m PUnit} :
forM f as = forM f bs := by
cases as <;> cases bs
simp_all
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (l : Array α) (g : α β) (f : β m PUnit) :
(l.map g).forM f = l.forM (fun a => f (g a)) := by
cases l
simp
/-! ### forIn' -/
@[congr] theorem forIn'_congr [Monad m] {as bs : Array α} (w : as = bs)
{b b' : β} (hb : b = b')
{f : (a' : α) a' as β m (ForInStep β)}
{g : (a' : α) a' bs β m (ForInStep β)}
(h : a m b, f a (by simpa [w] using m) b = g a m b) :
forIn' as b f = forIn' bs b' g := by
cases as <;> cases bs
simp only [mk.injEq, mem_toArray, List.forIn'_toArray] at w h
exact List.forIn'_congr w hb h
/--
We can express a for loop over an array as a fold,
in which whenever we reach `.done b` we keep that value through the rest of the fold.
@@ -120,6 +143,12 @@ theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
cases l
simp [List.foldl_map]
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
(l : Array α) (g : α β) (f : (b : β) b l.map g γ m (ForInStep γ)) :
forIn' (l.map g) init f = forIn' l init fun a h y => f (g a) (mem_map_of_mem g h) y := by
cases l
simp
/--
We can express a for loop over an array as a fold,
in which whenever we reach `.done b` we keep that value through the rest of the fold.
@@ -156,4 +185,10 @@ theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
cases l
simp [List.foldl_map]
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
(l : Array α) (g : α β) (f : β γ m (ForInStep γ)) :
forIn (l.map g) init f = forIn l init fun a y => f (g a) y := by
cases l
simp
end Array

View File

@@ -0,0 +1,65 @@
/-
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.List.Nat.Perm
import Init.Data.Array.Lemmas
namespace Array
open List
/--
`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 : Array α) : Prop :=
as.toList ~ bs.toList
@[inherit_doc] scoped infixl:50 " ~ " => Perm
theorem perm_iff_toList_perm {as bs : Array α} : as ~ bs as.toList ~ bs.toList := Iff.rfl
@[simp] theorem perm_toArray (as bs : List α) : as.toArray ~ bs.toArray as ~ bs := by
simp [perm_iff_toList_perm]
@[simp, refl] protected theorem Perm.refl (l : Array α) : l ~ l := by
cases l
simp
protected theorem Perm.rfl {l : List α} : l ~ l := .refl _
theorem Perm.of_eq {l₁ l₂ : Array α} (h : l₁ = l₂) : l₁ ~ l₂ := h .rfl
protected theorem Perm.symm {l₁ l₂ : Array α} (h : l₁ ~ l₂) : l₂ ~ l₁ := by
cases l₁; cases l₂
simp only [perm_toArray] at h
simpa using h.symm
protected theorem Perm.trans {l₁ l₂ l₃ : Array α} (h₁ : l₁ ~ l₂) (h₂ : l₂ ~ l₃) : l₁ ~ l₃ := by
cases l₁; cases l₂; cases l₃
simp only [perm_toArray] at h₁ h₂
simpa using h₁.trans h₂
instance : Trans (Perm (α := α)) (Perm (α := α)) (Perm (α := α)) where
trans h₁ h₂ := Perm.trans h₁ h₂
theorem perm_comm {l₁ l₂ : Array α} : l₁ ~ l₂ l₂ ~ l₁ := Perm.symm, Perm.symm
theorem Perm.push (x y : α) {l₁ l₂ : Array α} (p : l₁ ~ l₂) :
(l₁.push x).push y ~ (l₂.push y).push x := by
cases l₁; cases l₂
simp only [perm_toArray] at p
simp only [push_toArray, List.append_assoc, singleton_append, perm_toArray]
exact p.append (Perm.swap' _ _ Perm.nil)
theorem swap_perm {as : Array α} {i j : Nat} (h₁ : i < as.size) (h₂ : j < as.size) :
as.swap i j ~ as := by
simp only [swap, perm_iff_toList_perm, toList_set]
apply set_set_perm
end Array

View File

@@ -4,46 +4,46 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Init.Data.Array.Basic
import Init.Data.Vector.Basic
import Init.Data.Ord
namespace Array
-- TODO: remove the [Inhabited α] parameters as soon as we have the tactic framework for automating proof generation and using Array.fget
def qpartition (as : Array α) (lt : α α Bool) (lo hi : Nat) : Nat × Array α :=
if h : as.size = 0 then (0, as) else have : Inhabited α := as[0]'(by revert h; cases as.size <;> simp) -- TODO: remove
private def qpartition {n} (as : Vector α n) (lt : α α Bool) (lo hi : Nat)
(hlo : lo < n := by omega) (hhi : hi < n := by omega) : {n : Nat // lo n} × Vector α n :=
let mid := (lo + hi) / 2
let as := if lt (as.get! mid) (as.get! lo) then as.swapIfInBounds lo mid else as
let as := if lt (as.get! hi) (as.get! lo) then as.swapIfInBounds lo hi else as
let as := if lt (as.get! mid) (as.get! hi) then as.swapIfInBounds mid hi else as
let pivot := as.get! hi
let rec loop (as : Array α) (i j : Nat) :=
let as := if lt as[mid] as[lo] then as.swap lo mid else as
let as := if lt as[hi] as[lo] then as.swap lo hi else as
let as := if lt as[mid] as[hi] then as.swap mid hi else as
let pivot := as[hi]
let rec loop (as : Vector α n) (i j : Nat)
(ilo : lo i := by omega) (jh : j < n := by omega) (w : i j := by omega) :=
if h : j < hi then
if lt (as.get! j) pivot then
let as := as.swapIfInBounds i j
loop as (i+1) (j+1)
if lt as[j] pivot then
loop (as.swap i j) (i+1) (j+1)
else
loop as i (j+1)
else
let as := as.swapIfInBounds i hi
(i, as)
termination_by hi - j
decreasing_by all_goals simp_wf; decreasing_trivial_pre_omega
(i, ilo, as.swap i hi)
loop as lo lo
@[inline] partial def qsort (as : Array α) (lt : α α Bool) (low := 0) (high := as.size - 1) : Array α :=
let rec @[specialize] sort (as : Array α) (low high : Nat) :=
if low < high then
let p := qpartition as lt low high;
-- TODO: fix `partial` support in the equation compiler, it breaks if we use `let (mid, as) := partition as lt low high`
let mid := p.1
let as := p.2
if mid >= high then as
@[inline] def qsort (as : Array α) (lt : α α Bool := by exact (· < ·))
(low := 0) (high := as.size - 1) : Array α :=
let rec @[specialize] sort {n} (as : Vector α n) (lo hi : Nat)
(hlo : lo < n := by omega) (hhi : hi < n := by omega) :=
if h₁ : lo < hi then
let mid, hmid, as := qpartition as lt lo hi
if h₂ : mid hi then
as
else
let as := sort as low mid
sort as (mid+1) high
sort (sort as lo mid) (mid+1) hi
else as
sort as low high
if h : as.size = 0 then
as
else
let low := min low (as.size - 1)
let high := min high (as.size - 1)
sort as, rfl low high |>.toArray
set_option linter.unusedVariables.funArgs false in
/--

View File

@@ -12,7 +12,7 @@ namespace Array
theorem exists_of_uset (self : Array α) (i d h) :
l₁ l₂, self.toList = l₁ ++ self[i] :: l₂ List.length l₁ = i.toNat
(self.uset i d h).toList = l₁ ++ d :: l₂ := by
simpa only [ugetElem_eq_getElem, getElem_eq_getElem_toList, uset, toList_set] using
simpa only [ugetElem_eq_getElem, getElem_toList, uset, toList_set] using
List.exists_of_set _
end Array

View File

@@ -40,6 +40,9 @@ theorem BEq.symm [BEq α] [PartialEquivBEq α] {a b : α} : a == b → b == a :=
theorem BEq.comm [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = (b == a) :=
Bool.eq_iff_iff.2 BEq.symm, BEq.symm
theorem bne_comm [BEq α] [PartialEquivBEq α] {a b : α} : (a != b) = (b != a) := by
rw [bne, BEq.comm, bne]
theorem BEq.symm_false [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = false (b == a) = false :=
BEq.comm (α := α) id

View File

@@ -351,17 +351,17 @@ end relations
section cast
/-- `cast eq x` embeds `x` into an equal `BitVec` type. -/
@[inline] def cast (eq : n = m) (x : BitVec n) : BitVec m := .ofNatLt x.toNat (eq x.isLt)
@[inline] protected def cast (eq : n = m) (x : BitVec n) : BitVec m := .ofNatLt x.toNat (eq x.isLt)
@[simp] theorem cast_ofNat {n m : Nat} (h : n = m) (x : Nat) :
cast h (BitVec.ofNat n x) = BitVec.ofNat m x := by
(BitVec.ofNat n x).cast h = BitVec.ofNat m x := by
subst h; rfl
@[simp] theorem cast_cast {n m k : Nat} (h₁ : n = m) (h₂ : m = k) (x : BitVec n) :
cast h (cast h x) = cast (h₁ h₂) x :=
(x.cast h).cast h = x.cast (h₁ h₂) :=
rfl
@[simp] theorem cast_eq {n : Nat} (h : n = n) (x : BitVec n) : cast h x = x := rfl
@[simp] theorem cast_eq {n : Nat} (h : n = n) (x : BitVec n) : x.cast h = x := rfl
/--
Extraction of bits `start` to `start + len - 1` from a bit vector of size `n` to yield a

View File

@@ -462,7 +462,7 @@ theorem msb_neg {w : Nat} {x : BitVec w} :
case true =>
apply hmin
apply eq_of_getMsbD_eq
rintro i, hi
intro i hi
simp only [getMsbD_intMin, w_pos, decide_true, Bool.true_and]
cases i
case zero => exact hmsb
@@ -470,7 +470,7 @@ theorem msb_neg {w : Nat} {x : BitVec w} :
case false =>
apply hzero
apply eq_of_getMsbD_eq
rintro i, hi
intro i hi
simp only [getMsbD_zero]
cases i
case zero => exact hmsb
@@ -573,11 +573,11 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow (x : BitVec w) (i
setWidth w (x.setWidth (i + 1)) =
setWidth w (x.setWidth i) + (x &&& twoPow w i) := by
rw [add_eq_or_of_and_eq_zero]
· ext k
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
· ext k h
simp only [getLsbD_setWidth, h, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
by_cases hik : i = k
· subst hik
simp
simp [h]
· simp only [getLsbD_twoPow, hik, decide_false, Bool.and_false, Bool.or_false]
by_cases hik' : k < (i + 1)
· have hik'' : k < i := by omega

File diff suppressed because it is too large Load Diff

View File

@@ -225,7 +225,7 @@ theorem bne_not_self : ∀ (x : Bool), (x != !x) = true := by decide
Added for equivalence with `Bool.not_beq_self` and needed for confluence
due to `beq_iff_eq`.
-/
@[simp] theorem not_eq_self : (b : Bool), ((!b) = b) False := by decide
theorem not_eq_self : (b : Bool), ((!b) = b) False := by simp
@[simp] theorem eq_not_self : (b : Bool), (b = (!b)) False := by decide
@[simp] theorem beq_self_left : (a b : Bool), (a == (a == b)) = b := by decide
@@ -384,6 +384,15 @@ theorem toNat_lt (b : Bool) : b.toNat < 2 :=
@[simp] theorem toNat_eq_one {b : Bool} : b.toNat = 1 b = true := by
cases b <;> simp
/-! ## toInt -/
/-- convert a `Bool` to an `Int`, `false -> 0`, `true -> 1` -/
def toInt (b : Bool) : Int := cond b 1 0
@[simp] theorem toInt_false : false.toInt = 0 := rfl
@[simp] theorem toInt_true : true.toInt = 1 := rfl
/-! ### ite -/
@[simp] theorem if_true_left (p : Prop) [h : Decidable p] (f : Bool) :
@@ -411,7 +420,7 @@ theorem toNat_lt (b : Bool) : b.toNat < 2 :=
@[simp] theorem ite_eq_true_else_eq_false {q : Prop} :
(if b = true then q else b = false) (b = true q) := by
cases b <;> simp
cases b <;> simp [not_eq_self]
/-
`not_ite_eq_true_eq_true` and related theorems below are added for

View File

@@ -8,6 +8,8 @@ import Init.Data.Queue
import Init.System.Promise
import Init.System.Mutex
set_option linter.deprecated false
namespace IO
/--
@@ -15,6 +17,7 @@ Internal state of an `Channel`.
We maintain the invariant that at all times either `consumers` or `values` is empty.
-/
@[deprecated "Use Std.Channel.State from Std.Sync.Channel instead" (since := "2024-12-02")]
structure Channel.State (α : Type) where
values : Std.Queue α :=
consumers : Std.Queue (Promise (Option α)) :=
@@ -27,12 +30,14 @@ FIFO channel with unbounded buffer, where `recv?` returns a `Task`.
A channel can be closed. Once it is closed, all `send`s are ignored, and
`recv?` returns `none` once the queue is empty.
-/
@[deprecated "Use Std.Channel from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel (α : Type) : Type := Mutex (Channel.State α)
instance : Nonempty (Channel α) :=
inferInstanceAs (Nonempty (Mutex _))
/-- Creates a new `Channel`. -/
@[deprecated "Use Std.Channel.new from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.new : BaseIO (Channel α) :=
Mutex.new {}
@@ -41,6 +46,7 @@ Sends a message on an `Channel`.
This function does not block.
-/
@[deprecated "Use Std.Channel.send from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.send (ch : Channel α) (v : α) : BaseIO Unit :=
ch.atomically do
let st get
@@ -54,6 +60,7 @@ def Channel.send (ch : Channel α) (v : α) : BaseIO Unit :=
/--
Closes an `Channel`.
-/
@[deprecated "Use Std.Channel.close from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.close (ch : Channel α) : BaseIO Unit :=
ch.atomically do
let st get
@@ -67,6 +74,7 @@ Every message is only received once.
Returns `none` if the channel is closed and the queue is empty.
-/
@[deprecated "Use Std.Channel.recv? from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.recv? (ch : Channel α) : BaseIO (Task (Option α)) :=
ch.atomically do
let st get
@@ -85,6 +93,7 @@ def Channel.recv? (ch : Channel α) : BaseIO (Task (Option α)) :=
Note that if this function is called twice, each `forAsync` only gets half the messages.
-/
@[deprecated "Use Std.Channel.forAsync from Std.Sync.Channel instead" (since := "2024-12-02")]
partial def Channel.forAsync (f : α BaseIO Unit) (ch : Channel α)
(prio : Task.Priority := .default) : BaseIO (Task Unit) := do
BaseIO.bindTask (prio := prio) ( ch.recv?) fun
@@ -96,11 +105,13 @@ Receives all currently queued messages from the channel.
Those messages are dequeued and will not be returned by `recv?`.
-/
@[deprecated "Use Std.Channel.recvAllCurrent from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.recvAllCurrent (ch : Channel α) : BaseIO (Array α) :=
ch.atomically do
modifyGet fun st => (st.values.toArray, { st with values := })
/-- Type tag for synchronous (blocking) operations on a `Channel`. -/
@[deprecated "Use Std.Channel.Sync from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.Sync := Channel
/--
@@ -110,6 +121,7 @@ For example, `ch.sync.recv?` blocks until the next message,
and `for msg in ch.sync do ...` iterates synchronously over the channel.
These functions should only be used in dedicated threads.
-/
@[deprecated "Use Std.Channel.sync from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.sync (ch : Channel α) : Channel.Sync α := ch
/--
@@ -118,9 +130,11 @@ Synchronously receives a message from the channel.
Every message is only received once.
Returns `none` if the channel is closed and the queue is empty.
-/
@[deprecated "Use Std.Channel.Sync.recv? from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.Sync.recv? (ch : Channel.Sync α) : BaseIO (Option α) := do
IO.wait ( Channel.recv? ch)
@[deprecated "Use Std.Channel.Sync.forIn from Std.Sync.Channel instead" (since := "2024-12-02")]
private partial def Channel.Sync.forIn [Monad m] [MonadLiftT BaseIO m]
(ch : Channel.Sync α) (f : α β m (ForInStep β)) : β m β := fun b => do
match ch.recv? with

View File

@@ -9,6 +9,9 @@ import Init.Data.UInt.Lemmas
namespace Char
@[ext] protected theorem ext : {a b : Char} a.val = b.val a = b
| _,_, _,_, rfl => rfl
theorem le_def {a b : Char} : a b a.1 b.1 := .rfl
theorem lt_def {a b : Char} : a < b a.1 < b.1 := .rfl
theorem lt_iff_val_lt_val {a b : Char} : a < b a.val < b.val := Iff.rfl
@@ -19,9 +22,44 @@ theorem lt_iff_val_lt_val {a b : Char} : a < b ↔ a.val < b.val := Iff.rfl
protected theorem le_trans {a b c : Char} : a b b c a c := UInt32.le_trans
protected theorem lt_trans {a b c : Char} : a < b b < c a < c := UInt32.lt_trans
protected theorem le_total (a b : Char) : a b b a := UInt32.le_total a.1 b.1
protected theorem le_antisymm {a b : Char} : a b b a a = b :=
fun h₁ h₂ => Char.ext (UInt32.le_antisymm h₁ h₂)
protected theorem lt_asymm {a b : Char} (h : a < b) : ¬ b < a := UInt32.lt_asymm h
protected theorem ne_of_lt {a b : Char} (h : a < b) : a b := Char.ne_of_val_ne (UInt32.ne_of_lt h)
instance ltIrrefl : Std.Irrefl (· < · : Char Char Prop) where
irrefl := Char.lt_irrefl
instance leRefl : Std.Refl (· · : Char Char Prop) where
refl := Char.le_refl
instance leTrans : Trans (· · : Char Char Prop) (· ·) (· ·) where
trans := Char.le_trans
instance ltTrans : Trans (· < · : Char Char Prop) (· < ·) (· < ·) where
trans := Char.lt_trans
-- This instance is useful while setting up instances for `String`.
def notLTTrans : Trans (¬ · < · : Char Char Prop) (¬ · < ·) (¬ · < ·) where
trans h₁ h₂ := by simpa using Char.le_trans (by simpa using h₂) (by simpa using h₁)
instance leAntisymm : Std.Antisymm (· · : Char Char Prop) where
antisymm _ _ := Char.le_antisymm
-- This instance is useful while setting up instances for `String`.
def notLTAntisymm : Std.Antisymm (¬ · < · : Char Char Prop) where
antisymm _ _ h₁ h₂ := Char.le_antisymm (by simpa using h₂) (by simpa using h₁)
instance ltAsymm : Std.Asymm (· < · : Char Char Prop) where
asymm _ _ := Char.lt_asymm
instance leTotal : Std.Total (· · : Char Char Prop) where
total := Char.le_total
-- This instance is useful while setting up instances for `String`.
def notLTTotal : Std.Total (¬ · < · : Char Char Prop) where
total := fun x y => by simpa using Char.le_total y x
theorem utf8Size_eq (c : Char) : c.utf8Size = 1 c.utf8Size = 2 c.utf8Size = 3 c.utf8Size = 4 := by
have := c.utf8Size_pos
have := c.utf8Size_le_four
@@ -31,9 +69,6 @@ theorem utf8Size_eq (c : Char) : c.utf8Size = 1 c.utf8Size = 2 c.utf8Siz
rw [Char.ofNat, dif_pos]
rfl
@[ext] protected theorem ext : {a b : Char} a.val = b.val a = b
| _,_, _,_, rfl => rfl
end Char
@[deprecated Char.utf8Size (since := "2024-06-04")] abbrev String.csize := Char.utf8Size

View File

@@ -36,12 +36,6 @@ def succ : Fin n → Fin (n + 1)
variable {n : Nat}
/--
Returns `a` modulo `n + 1` as a `Fin n.succ`.
-/
protected def ofNat {n : Nat} (a : Nat) : Fin (n + 1) :=
a % (n+1), Nat.mod_lt _ (Nat.zero_lt_succ _)
/--
Returns `a` modulo `n` as a `Fin n`.
@@ -50,9 +44,12 @@ The assumption `NeZero n` ensures that `Fin n` is nonempty.
protected def ofNat' (n : Nat) [NeZero n] (a : Nat) : Fin n :=
a % n, Nat.mod_lt _ (pos_of_neZero n)
-- We intend to deprecate `Fin.ofNat` in favor of `Fin.ofNat'` (and later rename).
-- This is waiting on https://github.com/leanprover/lean4/pull/5323
-- attribute [deprecated Fin.ofNat' (since := "2024-09-16")] Fin.ofNat
/--
Returns `a` modulo `n + 1` as a `Fin n.succ`.
-/
@[deprecated Fin.ofNat' (since := "2024-11-27")]
protected def ofNat {n : Nat} (a : Nat) : Fin (n + 1) :=
a % (n+1), Nat.mod_lt _ (Nat.zero_lt_succ _)
private theorem mlt {b : Nat} : {a : Nat} a < n b % n < n
| 0, h => Nat.mod_lt _ h
@@ -179,7 +176,7 @@ protected theorem pos (i : Fin n) : 0 < n :=
@[inline] def castLE (h : n m) (i : Fin n) : Fin m := i, Nat.lt_of_lt_of_le i.2 h
/-- `cast eq i` embeds `i` into an equal `Fin` type. -/
@[inline] def cast (eq : n = m) (i : Fin n) : Fin m := i, eq i.2
@[inline] protected def cast (eq : n = m) (i : Fin n) : Fin m := i, eq i.2
/-- `castAdd m i` embeds `i : Fin n` in `Fin (n+m)`. See also `Fin.natAdd` and `Fin.addNat`. -/
@[inline] def castAdd (m) : Fin n Fin (n + m) :=

View File

@@ -13,17 +13,17 @@ namespace Fin
/-- Folds over `Fin n` from the left: `foldl 3 f x = f (f (f x 0) 1) 2`. -/
@[inline] def foldl (n) (f : α Fin n α) (init : α) : α := loop init 0 where
/-- Inner loop for `Fin.foldl`. `Fin.foldl.loop n f x i = f (f (f x i) ...) (n-1)` -/
loop (x : α) (i : Nat) : α :=
@[semireducible, specialize] loop (x : α) (i : Nat) : α :=
if h : i < n then loop (f x i, h) (i+1) else x
termination_by n - i
decreasing_by decreasing_trivial_pre_omega
/-- Folds over `Fin n` from the right: `foldr 3 f x = f 0 (f 1 (f 2 x))`. -/
@[inline] def foldr (n) (f : Fin n α α) (init : α) : α := loop n, Nat.le_refl n init where
@[inline] def foldr (n) (f : Fin n α α) (init : α) : α := loop n (Nat.le_refl n) init where
/-- Inner loop for `Fin.foldr`. `Fin.foldr.loop n f i x = f 0 (f ... (f (i-1) x))` -/
loop : {i // i n} α α
| 0, _, x => x
| i+1, h, x => loop i, Nat.le_of_lt h (f i, h x)
@[specialize] loop : (i : _) i n α α
| 0, _, x => x
| i+1, h, x => loop i (Nat.le_of_lt h) (f i, h x)
termination_by structural i => i
/--
Folds a monadic function over `Fin n` from left to right:
@@ -47,7 +47,7 @@ Fin.foldlM n f x₀ = do
pure xₙ
```
-/
loop (x : α) (i : Nat) : m α := do
@[semireducible, specialize] loop (x : α) (i : Nat) : m α := do
if h : i < n then f x i, h >>= (loop · (i+1)) else pure x
termination_by n - i
decreasing_by decreasing_trivial_pre_omega
@@ -76,7 +76,7 @@ Fin.foldrM n f xₙ = do
pure x₀
```
-/
loop : {i // i n} α m α
@[semireducible, specialize] loop : {i // i n} α m α
| 0, _, x => pure x
| i+1, h, x => f i, h x >>= loop i, Nat.le_of_lt h
@@ -125,7 +125,7 @@ theorem foldrM_loop [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x
| zero =>
rw [foldrM_loop_zero, foldrM_loop_succ, pure_bind]
conv => rhs; rw [bind_pure (f 0 x)]
congr; funext; exact foldrM_loop_zero ..
congr; funext
| succ i ih =>
rw [foldrM_loop_succ, foldrM_loop_succ, bind_assoc]
congr; funext; exact ih ..
@@ -176,17 +176,19 @@ theorem foldl_eq_foldlM (f : α → Fin n → α) (x) :
/-! ### foldr -/
theorem foldr_loop_zero (f : Fin n α α) (x) :
foldr.loop n f 0, Nat.zero_le _ x = x := by
foldr.loop n f 0 (Nat.zero_le _) x = x := by
rw [foldr.loop]
theorem foldr_loop_succ (f : Fin n α α) (x) (h : i < n) :
foldr.loop n f i+1, h x = foldr.loop n f i, Nat.le_of_lt h (f i, h x) := by
foldr.loop n f (i+1) h x = foldr.loop n f i (Nat.le_of_lt h) (f i, h x) := by
rw [foldr.loop]
theorem foldr_loop (f : Fin (n+1) α α) (x) (h : i+1 n+1) :
foldr.loop (n+1) f i+1, h x =
f 0 (foldr.loop n (fun j => f j.succ) i, Nat.le_of_succ_le_succ h x) := by
induction i generalizing x <;> simp [foldr_loop_zero, foldr_loop_succ, *]
foldr.loop (n+1) f (i+1) h x =
f 0 (foldr.loop n (fun j => f j.succ) i (Nat.le_of_succ_le_succ h) x) := by
induction i generalizing x with
| zero => simp [foldr_loop_succ, foldr_loop_zero]
| succ i ih => rw [foldr_loop_succ, ih]; rfl
@[simp] theorem foldr_zero (f : Fin 0 α α) (x) : foldr 0 f x = x :=
foldr_loop_zero ..

View File

@@ -370,25 +370,25 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
Fin.castLE mn Fin.castLE km = Fin.castLE (Nat.le_trans km mn) :=
funext (castLE_castLE km mn)
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (cast h i : Nat) = i := rfl
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : cast h (last n) = last n' :=
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : (last n).cast h = last n' :=
Fin.ext (by rw [coe_cast, val_last, val_last, Nat.succ.inj h])
@[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : cast h i, hn = i, h hn := rfl
@[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : Fin.cast h i, hn = i, h hn := rfl
@[simp] theorem cast_refl (n : Nat) (h : n = n) : cast h = id := by
@[simp] theorem cast_refl (n : Nat) (h : n = n) : Fin.cast h = id := by
ext
simp
@[simp] theorem cast_trans {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
cast h' (cast h i) = cast (Eq.trans h h') i := rfl
(i.cast h).cast h' = i.cast (Eq.trans h h') := rfl
theorem castLE_of_eq {m n : Nat} (h : m = n) {h' : m n} : castLE h' = Fin.cast h := rfl
@[simp] theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
@[simp] theorem castAdd_zero : (castAdd 0 : Fin n Fin (n + 0)) = cast rfl := rfl
@[simp] theorem castAdd_zero : (castAdd 0 : Fin n Fin (n + 0)) = Fin.cast rfl := rfl
theorem castAdd_lt {m : Nat} (n : Nat) (i : Fin m) : (castAdd n i : Nat) < m := by simp
@@ -406,37 +406,37 @@ theorem castAdd_cast {n n' : Nat} (m : Nat) (i : Fin n') (h : n' = n) :
castAdd m (Fin.cast h i) = Fin.cast (congrArg (. + m) h) (castAdd m i) := Fin.ext rfl
theorem cast_castAdd_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
cast h (castAdd m i) = castAdd m (cast (Nat.add_right_cancel h) i) := rfl
(i.castAdd m).cast h = (i.cast (Nat.add_right_cancel h)).castAdd m := rfl
@[simp] theorem cast_castAdd_right {n m m' : Nat} (i : Fin n) (h : n + m' = n + m) :
cast h (castAdd m' i) = castAdd m i := rfl
(i.castAdd m').cast h = i.castAdd m := rfl
theorem castAdd_castAdd {m n p : Nat} (i : Fin m) :
castAdd p (castAdd n i) = cast (Nat.add_assoc ..).symm (castAdd (n + p) i) := rfl
(i.castAdd n).castAdd p = (i.castAdd (n + p)).cast (Nat.add_assoc ..).symm := rfl
/-- The cast of the successor is the successor of the cast. See `Fin.succ_cast_eq` for rewriting in
the reverse direction. -/
@[simp] theorem cast_succ_eq {n' : Nat} (i : Fin n) (h : n.succ = n'.succ) :
cast h i.succ = (cast (Nat.succ.inj h) i).succ := rfl
i.succ.cast h = (i.cast (Nat.succ.inj h)).succ := rfl
theorem succ_cast_eq {n' : Nat} (i : Fin n) (h : n = n') :
(cast h i).succ = cast (by rw [h]) i.succ := rfl
(i.cast h).succ = i.succ.cast (by rw [h]) := rfl
@[simp] theorem coe_castSucc (i : Fin n) : (Fin.castSucc i : Nat) = i := rfl
@[simp] theorem coe_castSucc (i : Fin n) : (i.castSucc : Nat) = i := rfl
@[simp] theorem castSucc_mk (n i : Nat) (h : i < n) : castSucc i, h = i, Nat.lt.step h := rfl
@[simp] theorem cast_castSucc {n' : Nat} {h : n + 1 = n' + 1} {i : Fin n} :
cast h (castSucc i) = castSucc (cast (Nat.succ.inj h) i) := rfl
i.castSucc.cast h = (i.cast (Nat.succ.inj h)).castSucc := rfl
theorem castSucc_lt_succ (i : Fin n) : Fin.castSucc i < i.succ :=
theorem castSucc_lt_succ (i : Fin n) : i.castSucc < i.succ :=
lt_def.2 <| by simp only [coe_castSucc, val_succ, Nat.lt_succ_self]
theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i Fin.castSucc j i < j.succ := by
theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i j.castSucc i < j.succ := by
simpa only [lt_def, le_def] using Nat.add_one_le_add_one_iff.symm
theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
Fin.castSucc i < j i.succ j := .rfl
i.castSucc < j i.succ j := .rfl
@[simp] theorem succ_last (n : Nat) : (last n).succ = last n.succ := rfl
@@ -444,48 +444,48 @@ theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
i.succ = last (n + 1) i = last n := by rw [ succ_last, succ_inj]
@[simp] theorem castSucc_castLT (i : Fin (n + 1)) (h : (i : Nat) < n) :
castSucc (castLT i h) = i := rfl
(castLT i h).castSucc = i := rfl
@[simp] theorem castLT_castSucc {n : Nat} (a : Fin n) (h : (a : Nat) < n) :
castLT (castSucc a) h = a := rfl
castLT a.castSucc h = a := rfl
@[simp] theorem castSucc_lt_castSucc_iff {a b : Fin n} :
Fin.castSucc a < Fin.castSucc b a < b := .rfl
a.castSucc < b.castSucc a < b := .rfl
theorem castSucc_inj {a b : Fin n} : castSucc a = castSucc b a = b := by simp [Fin.ext_iff]
theorem castSucc_inj {a b : Fin n} : a.castSucc = b.castSucc a = b := by simp [Fin.ext_iff]
theorem castSucc_lt_last (a : Fin n) : castSucc a < last n := a.is_lt
theorem castSucc_lt_last (a : Fin n) : a.castSucc < last n := a.is_lt
@[simp] theorem castSucc_zero : castSucc (0 : Fin (n + 1)) = 0 := rfl
@[simp] theorem castSucc_one {n : Nat} : castSucc (1 : Fin (n + 2)) = 1 := rfl
/-- `castSucc i` is positive when `i` is positive -/
theorem castSucc_pos {i : Fin (n + 1)} (h : 0 < i) : 0 < castSucc i := by
theorem castSucc_pos {i : Fin (n + 1)} (h : 0 < i) : 0 < i.castSucc := by
simpa [lt_def] using h
@[simp] theorem castSucc_eq_zero_iff {a : Fin (n + 1)} : castSucc a = 0 a = 0 := by simp [Fin.ext_iff]
@[simp] theorem castSucc_eq_zero_iff {a : Fin (n + 1)} : a.castSucc = 0 a = 0 := by simp [Fin.ext_iff]
theorem castSucc_ne_zero_iff {a : Fin (n + 1)} : castSucc a 0 a 0 :=
theorem castSucc_ne_zero_iff {a : Fin (n + 1)} : a.castSucc 0 a 0 :=
not_congr <| castSucc_eq_zero_iff
theorem castSucc_fin_succ (n : Nat) (j : Fin n) :
castSucc (Fin.succ j) = Fin.succ (castSucc j) := by simp [Fin.ext_iff]
j.succ.castSucc = (j.castSucc).succ := by simp [Fin.ext_iff]
@[simp]
theorem coeSucc_eq_succ {a : Fin n} : castSucc a + 1 = a.succ := by
theorem coeSucc_eq_succ {a : Fin n} : a.castSucc + 1 = a.succ := by
cases n
· exact a.elim0
· simp [Fin.ext_iff, add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ a.is_lt)]
theorem lt_succ {a : Fin n} : castSucc a < a.succ := by
theorem lt_succ {a : Fin n} : a.castSucc < a.succ := by
rw [castSucc, lt_def, coe_castAdd, val_succ]; exact Nat.lt_succ_self a.val
theorem exists_castSucc_eq {n : Nat} {i : Fin (n + 1)} : ( j, castSucc j = i) i last n :=
fun j, hj => hj Fin.ne_of_lt j.castSucc_lt_last,
fun hi => i.castLT <| Fin.val_lt_last hi, rfl
theorem succ_castSucc {n : Nat} (i : Fin n) : i.castSucc.succ = castSucc i.succ := rfl
theorem succ_castSucc {n : Nat} (i : Fin n) : i.castSucc.succ = i.succ.castSucc := rfl
@[simp] theorem coe_addNat (m : Nat) (i : Fin n) : (addNat i m : Nat) = i + m := rfl
@@ -502,17 +502,17 @@ theorem le_coe_addNat (m : Nat) (i : Fin n) : m ≤ addNat i m :=
addNat i, hi n = i + n, Nat.add_lt_add_right hi n := rfl
@[simp] theorem cast_addNat_zero {n n' : Nat} (i : Fin n) (h : n + 0 = n') :
cast h (addNat i 0) = cast ((Nat.add_zero _).symm.trans h) i := rfl
(addNat i 0).cast h = i.cast ((Nat.add_zero _).symm.trans h) := rfl
/-- For rewriting in the reverse direction, see `Fin.cast_addNat_left`. -/
theorem addNat_cast {n n' m : Nat} (i : Fin n') (h : n' = n) :
addNat (cast h i) m = cast (congrArg (. + m) h) (addNat i m) := rfl
addNat (i.cast h) m = (addNat i m).cast (congrArg (. + m) h) := rfl
theorem cast_addNat_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
cast h (addNat i m) = addNat (cast (Nat.add_right_cancel h) i) m := rfl
(addNat i m).cast h = addNat (i.cast (Nat.add_right_cancel h)) m := rfl
@[simp] theorem cast_addNat_right {n m m' : Nat} (i : Fin n) (h : n + m' = n + m) :
cast h (addNat i m') = addNat i m :=
(addNat i m').cast h = addNat i m :=
Fin.ext <| (congrArg ((· + ·) (i : Nat)) (Nat.add_left_cancel h) : _)
@[simp] theorem coe_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
@@ -522,46 +522,44 @@ theorem cast_addNat_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
theorem le_coe_natAdd (m : Nat) (i : Fin n) : m natAdd m i := Nat.le_add_right ..
@[simp] theorem natAdd_zero {n : Nat} : natAdd 0 = cast (Nat.zero_add n).symm := by ext; simp
@[simp] theorem natAdd_zero {n : Nat} : natAdd 0 = Fin.cast (Nat.zero_add n).symm := by ext; simp
/-- For rewriting in the reverse direction, see `Fin.cast_natAdd_right`. -/
theorem natAdd_cast {n n' : Nat} (m : Nat) (i : Fin n') (h : n' = n) :
natAdd m (cast h i) = cast (congrArg _ h) (natAdd m i) := rfl
natAdd m (i.cast h) = (natAdd m i).cast (congrArg _ h) := rfl
theorem cast_natAdd_right {n n' m : Nat} (i : Fin n') (h : m + n' = m + n) :
cast h (natAdd m i) = natAdd m (cast (Nat.add_left_cancel h) i) := rfl
(natAdd m i).cast h = natAdd m (i.cast (Nat.add_left_cancel h)) := rfl
@[simp] theorem cast_natAdd_left {n m m' : Nat} (i : Fin n) (h : m' + n = m + n) :
cast h (natAdd m' i) = natAdd m i :=
(natAdd m' i).cast h = natAdd m i :=
Fin.ext <| (congrArg (· + (i : Nat)) (Nat.add_right_cancel h) : _)
theorem castAdd_natAdd (p m : Nat) {n : Nat} (i : Fin n) :
castAdd p (natAdd m i) = cast (Nat.add_assoc ..).symm (natAdd m (castAdd p i)) := rfl
castAdd p (natAdd m i) = (natAdd m (castAdd p i)).cast (Nat.add_assoc ..).symm := rfl
theorem natAdd_castAdd (p m : Nat) {n : Nat} (i : Fin n) :
natAdd m (castAdd p i) = cast (Nat.add_assoc ..) (castAdd p (natAdd m i)) := rfl
natAdd m (castAdd p i) = (castAdd p (natAdd m i)).cast (Nat.add_assoc ..) := rfl
theorem natAdd_natAdd (m n : Nat) {p : Nat} (i : Fin p) :
natAdd m (natAdd n i) = cast (Nat.add_assoc ..) (natAdd (m + n) i) :=
natAdd m (natAdd n i) = (natAdd (m + n) i).cast (Nat.add_assoc ..) :=
Fin.ext <| (Nat.add_assoc ..).symm
@[simp]
theorem cast_natAdd_zero {n n' : Nat} (i : Fin n) (h : 0 + n = n') :
cast h (natAdd 0 i) = cast ((Nat.zero_add _).symm.trans h) i :=
Fin.ext <| Nat.zero_add _
(natAdd 0 i).cast h = i.cast ((Nat.zero_add _).symm.trans h) := by simp
@[simp]
theorem cast_natAdd (n : Nat) {m : Nat} (i : Fin m) :
cast (Nat.add_comm ..) (natAdd n i) = addNat i n := Fin.ext <| Nat.add_comm ..
(natAdd n i).cast (Nat.add_comm ..) = addNat i n := Fin.ext <| Nat.add_comm ..
@[simp]
theorem cast_addNat {n : Nat} (m : Nat) (i : Fin n) :
cast (Nat.add_comm ..) (addNat i m) = natAdd m i := Fin.ext <| Nat.add_comm ..
(addNat i m).cast (Nat.add_comm ..) = natAdd m i := Fin.ext <| Nat.add_comm ..
@[simp] theorem natAdd_last {m n : Nat} : natAdd n (last m) = last (n + m) := rfl
@[simp] theorem addNat_last (n : Nat) :
addNat (last n) m = cast (by omega) (last (n + m)) := by
addNat (last n) m = (last (n + m)).cast (by omega) := by
ext
simp
@@ -657,7 +655,7 @@ theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
subNat m (addNat i m) h = i := Fin.ext <| Nat.add_sub_cancel i m
@[simp] theorem natAdd_subNat_cast {i : Fin (n + m)} (h : n i) :
natAdd n (subNat n (cast (Nat.add_comm ..) i) h) = i := by simp [ cast_addNat]
natAdd n (subNat n (i.cast (Nat.add_comm ..)) h) = i := by simp [ cast_addNat]
/-! ### recursion and induction principles -/

179
src/Init/Data/Float32.lean Normal file
View File

@@ -0,0 +1,179 @@
/-
Copyright (c) 2023 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.Core
import Init.Data.Int.Basic
import Init.Data.ToString.Basic
import Init.Data.Float
-- Just show FloatSpec is inhabited.
opaque float32Spec : FloatSpec := {
float := Unit,
val := (),
lt := fun _ _ => True,
le := fun _ _ => True,
decLt := fun _ _ => inferInstanceAs (Decidable True),
decLe := fun _ _ => inferInstanceAs (Decidable True)
}
/-- Native floating point type, corresponding to the IEEE 754 *binary32* format
(`float` in C or `f32` in Rust). -/
structure Float32 where
val : float32Spec.float
instance : Nonempty Float32 := { val := float32Spec.val }
@[extern "lean_float32_add"] opaque Float32.add : Float32 Float32 Float32
@[extern "lean_float32_sub"] opaque Float32.sub : Float32 Float32 Float32
@[extern "lean_float32_mul"] opaque Float32.mul : Float32 Float32 Float32
@[extern "lean_float32_div"] opaque Float32.div : Float32 Float32 Float32
@[extern "lean_float32_negate"] opaque Float32.neg : Float32 Float32
set_option bootstrap.genMatcherCode false
def Float32.lt : Float32 Float32 Prop := fun a b =>
match a, b with
| a, b => float32Spec.lt a b
def Float32.le : Float32 Float32 Prop := fun a b =>
float32Spec.le a.val b.val
/--
Raw transmutation from `UInt32`.
Float32s and UInts have the same endianness on all supported platforms.
IEEE 754 very precisely specifies the bit layout of floats.
-/
@[extern "lean_float32_of_bits"] opaque Float32.ofBits : UInt32 Float32
/--
Raw transmutation to `UInt32`.
Float32s and UInts have the same endianness on all supported platforms.
IEEE 754 very precisely specifies the bit layout of floats.
Note that this function is distinct from `Float32.toUInt32`, which attempts
to preserve the numeric value, and not the bitwise value.
-/
@[extern "lean_float32_to_bits"] opaque Float32.toBits : Float32 UInt32
instance : Add Float32 := Float32.add
instance : Sub Float32 := Float32.sub
instance : Mul Float32 := Float32.mul
instance : Div Float32 := Float32.div
instance : Neg Float32 := Float32.neg
instance : LT Float32 := Float32.lt
instance : LE Float32 := Float32.le
/-- Note: this is not reflexive since `NaN != NaN`.-/
@[extern "lean_float32_beq"] opaque Float32.beq (a b : Float32) : Bool
instance : BEq Float32 := Float32.beq
@[extern "lean_float32_decLt"] opaque Float32.decLt (a b : Float32) : Decidable (a < b) :=
match a, b with
| a, b => float32Spec.decLt a b
@[extern "lean_float32_decLe"] opaque Float32.decLe (a b : Float32) : Decidable (a b) :=
match a, b with
| a, b => float32Spec.decLe a b
instance float32DecLt (a b : Float32) : Decidable (a < b) := Float32.decLt a b
instance float32DecLe (a b : Float32) : Decidable (a b) := Float32.decLe a b
@[extern "lean_float32_to_string"] opaque Float32.toString : Float32 String
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
If negative or NaN, returns `0`.
If larger than the maximum value for `UInt8` (including Inf), returns the maximum value of `UInt8`
(i.e. `UInt8.size - 1`).
-/
@[extern "lean_float32_to_uint8"] opaque Float32.toUInt8 : Float32 UInt8
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
If negative or NaN, returns `0`.
If larger than the maximum value for `UInt16` (including Inf), returns the maximum value of `UInt16`
(i.e. `UInt16.size - 1`).
-/
@[extern "lean_float32_to_uint16"] opaque Float32.toUInt16 : Float32 UInt16
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
If negative or NaN, returns `0`.
If larger than the maximum value for `UInt32` (including Inf), returns the maximum value of `UInt32`
(i.e. `UInt32.size - 1`).
-/
@[extern "lean_float32_to_uint32"] opaque Float32.toUInt32 : Float32 UInt32
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
If negative or NaN, returns `0`.
If larger than the maximum value for `UInt64` (including Inf), returns the maximum value of `UInt64`
(i.e. `UInt64.size - 1`).
-/
@[extern "lean_float32_to_uint64"] opaque Float32.toUInt64 : Float32 UInt64
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
If negative or NaN, returns `0`.
If larger than the maximum value for `USize` (including Inf), returns the maximum value of `USize`
(i.e. `USize.size - 1`). This value is platform dependent).
-/
@[extern "lean_float32_to_usize"] opaque Float32.toUSize : Float32 USize
@[extern "lean_float32_isnan"] opaque Float32.isNaN : Float32 Bool
@[extern "lean_float32_isfinite"] opaque Float32.isFinite : Float32 Bool
@[extern "lean_float32_isinf"] opaque Float32.isInf : Float32 Bool
/-- Splits the given float `x` into a significand/exponent pair `(s, i)`
such that `x = s * 2^i` where `s ∈ (-1;-0.5] [0.5; 1)`.
Returns an undefined value if `x` is not finite.
-/
@[extern "lean_float32_frexp"] opaque Float32.frExp : Float32 Float32 × Int
instance : ToString Float32 where
toString := Float32.toString
@[extern "lean_uint64_to_float32"] opaque UInt64.toFloat32 (n : UInt64) : Float32
instance : Inhabited Float32 where
default := UInt64.toFloat32 0
instance : Repr Float32 where
reprPrec n prec := if n < UInt64.toFloat32 0 then Repr.addAppParen (toString n) prec else toString n
instance : ReprAtom Float32 :=
@[extern "sinf"] opaque Float32.sin : Float32 Float32
@[extern "cosf"] opaque Float32.cos : Float32 Float32
@[extern "tanf"] opaque Float32.tan : Float32 Float32
@[extern "asinf"] opaque Float32.asin : Float32 Float32
@[extern "acosf"] opaque Float32.acos : Float32 Float32
@[extern "atanf"] opaque Float32.atan : Float32 Float32
@[extern "atan2f"] opaque Float32.atan2 : Float32 Float32 Float32
@[extern "sinhf"] opaque Float32.sinh : Float32 Float32
@[extern "coshf"] opaque Float32.cosh : Float32 Float32
@[extern "tanhf"] opaque Float32.tanh : Float32 Float32
@[extern "asinhf"] opaque Float32.asinh : Float32 Float32
@[extern "acoshf"] opaque Float32.acosh : Float32 Float32
@[extern "atanhf"] opaque Float32.atanh : Float32 Float32
@[extern "expf"] opaque Float32.exp : Float32 Float32
@[extern "exp2f"] opaque Float32.exp2 : Float32 Float32
@[extern "logf"] opaque Float32.log : Float32 Float32
@[extern "log2f"] opaque Float32.log2 : Float32 Float32
@[extern "log10f"] opaque Float32.log10 : Float32 Float32
@[extern "powf"] opaque Float32.pow : Float32 Float32 Float32
@[extern "sqrtf"] opaque Float32.sqrt : Float32 Float32
@[extern "cbrtf"] opaque Float32.cbrt : Float32 Float32
@[extern "ceilf"] opaque Float32.ceil : Float32 Float32
@[extern "floorf"] opaque Float32.floor : Float32 Float32
@[extern "roundf"] opaque Float32.round : Float32 Float32
@[extern "fabsf"] opaque Float32.abs : Float32 Float32
instance : HomogeneousPow Float32 := Float32.pow
instance : Min Float32 := minOfLe
instance : Max Float32 := maxOfLe
/--
Efficiently computes `x * 2^i`.
-/
@[extern "lean_float32_scaleb"]
opaque Float32.scaleB (x : Float32) (i : @& Int) : Float32
@[extern "lean_float32_to_float"] opaque Float32.toFloat : Float32 Float
@[extern "lean_float_to_float32"] opaque Float.toFloat32 : Float Float32

View File

@@ -7,7 +7,7 @@ The integers, with addition, multiplication, and subtraction.
-/
prelude
import Init.Data.Cast
import Init.Data.Nat.Div
import Init.Data.Nat.Div.Basic
set_option linter.missingDocs true -- keep it documented
open Nat

View File

@@ -34,4 +34,8 @@ theorem shiftRight_eq_div_pow (m : Int) (n : Nat) :
theorem zero_shiftRight (n : Nat) : (0 : Int) >>> n = 0 := by
simp [Int.shiftRight_eq_div_pow]
@[simp]
theorem shiftRight_zero (n : Int) : n >>> 0 = n := by
simp [Int.shiftRight_eq_div_pow]
end Int

View File

@@ -29,6 +29,8 @@ At that time, we did not rename `div` and `mod` to `tdiv` and `tmod` (along with
In September 2024, we decided to do this rename (with deprecations in place),
and later we intend to rename `ediv` and `emod` to `div` and `mod`, as nearly all users will only
ever need to use these functions and their associated lemmas.
In December 2024, we removed `tdiv` and `tmod`, but have not yet renamed `ediv` and `emod`.
-/
/-! ### T-rounding division -/
@@ -71,8 +73,6 @@ def tdiv : (@& Int) → (@& Int) → Int
| -[m +1], ofNat n => -ofNat (succ m / n)
| -[m +1], -[n +1] => ofNat (succ m / succ n)
@[deprecated tdiv (since := "2024-09-11")] abbrev div := tdiv
/-- Integer modulo. This function uses the
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention
to pair with `Int.tdiv`, meaning that `tmod a b + b * (tdiv a b) = a`
@@ -107,8 +107,6 @@ def tmod : (@& Int) → (@& Int) → Int
| -[m +1], ofNat n => -ofNat (succ m % n)
| -[m +1], -[n +1] => -ofNat (succ m % succ n)
@[deprecated tmod (since := "2024-09-11")] abbrev mod := tmod
/-! ### F-rounding division
This pair satisfies `fdiv x y = floor (x / y)`.
-/
@@ -251,8 +249,6 @@ instance : Mod Int where
theorem ofNat_tdiv (m n : Nat) : (m / n) = tdiv m n := rfl
@[deprecated ofNat_tdiv (since := "2024-09-11")] abbrev ofNat_div := ofNat_tdiv
theorem ofNat_fdiv : m n : Nat, (m / n) = fdiv m n
| 0, _ => by simp [fdiv]
| succ _, _ => rfl

View File

@@ -125,7 +125,7 @@ theorem eq_one_of_mul_eq_one_right {a b : Int} (H : 0 ≤ a) (H' : a * b = 1) :
eq_one_of_dvd_one H b, H'.symm
theorem eq_one_of_mul_eq_one_left {a b : Int} (H : 0 b) (H' : a * b = 1) : b = 1 :=
eq_one_of_mul_eq_one_right H <| by rw [Int.mul_comm, H']
eq_one_of_mul_eq_one_right (b := a) H <| by rw [Int.mul_comm, H']
/-! ### *div zero -/
@@ -1315,65 +1315,3 @@ theorem bmod_natAbs_plus_one (x : Int) (w : 1 < x.natAbs) : bmod x (x.natAbs + 1
all_goals decide
· exact ofNat_nonneg x
· exact succ_ofNat_pos (x + 1)
/-! ### Deprecations -/
@[deprecated Int.zero_tdiv (since := "2024-09-11")] protected abbrev zero_div := @Int.zero_tdiv
@[deprecated Int.tdiv_zero (since := "2024-09-11")] protected abbrev div_zero := @Int.tdiv_zero
@[deprecated tdiv_eq_ediv (since := "2024-09-11")] abbrev div_eq_ediv := @tdiv_eq_ediv
@[deprecated fdiv_eq_tdiv (since := "2024-09-11")] abbrev fdiv_eq_div := @fdiv_eq_tdiv
@[deprecated zero_tmod (since := "2024-09-11")] abbrev zero_mod := @zero_tmod
@[deprecated tmod_zero (since := "2024-09-11")] abbrev mod_zero := @tmod_zero
@[deprecated tmod_add_tdiv (since := "2024-09-11")] abbrev mod_add_div := @tmod_add_tdiv
@[deprecated tdiv_add_tmod (since := "2024-09-11")] abbrev div_add_mod := @tdiv_add_tmod
@[deprecated tmod_add_tdiv' (since := "2024-09-11")] abbrev mod_add_div' := @tmod_add_tdiv'
@[deprecated tdiv_add_tmod' (since := "2024-09-11")] abbrev div_add_mod' := @tdiv_add_tmod'
@[deprecated tmod_def (since := "2024-09-11")] abbrev mod_def := @tmod_def
@[deprecated tmod_eq_emod (since := "2024-09-11")] abbrev mod_eq_emod := @tmod_eq_emod
@[deprecated fmod_eq_tmod (since := "2024-09-11")] abbrev fmod_eq_mod := @fmod_eq_tmod
@[deprecated Int.tdiv_one (since := "2024-09-11")] protected abbrev div_one := @Int.tdiv_one
@[deprecated Int.tdiv_neg (since := "2024-09-11")] protected abbrev div_neg := @Int.tdiv_neg
@[deprecated Int.neg_tdiv (since := "2024-09-11")] protected abbrev neg_div := @Int.neg_tdiv
@[deprecated Int.neg_tdiv_neg (since := "2024-09-11")] protected abbrev neg_div_neg := @Int.neg_tdiv_neg
@[deprecated Int.tdiv_nonneg (since := "2024-09-11")] protected abbrev div_nonneg := @Int.tdiv_nonneg
@[deprecated Int.tdiv_nonpos (since := "2024-09-11")] protected abbrev div_nonpos := @Int.tdiv_nonpos
@[deprecated Int.tdiv_eq_zero_of_lt (since := "2024-09-11")] abbrev div_eq_zero_of_lt := @Int.tdiv_eq_zero_of_lt
@[deprecated Int.mul_tdiv_cancel (since := "2024-09-11")] protected abbrev mul_div_cancel := @Int.mul_tdiv_cancel
@[deprecated Int.mul_tdiv_cancel_left (since := "2024-09-11")] protected abbrev mul_div_cancel_left := @Int.mul_tdiv_cancel_left
@[deprecated Int.tdiv_self (since := "2024-09-11")] protected abbrev div_self := @Int.tdiv_self
@[deprecated Int.mul_tdiv_cancel_of_tmod_eq_zero (since := "2024-09-11")] abbrev mul_div_cancel_of_mod_eq_zero := @Int.mul_tdiv_cancel_of_tmod_eq_zero
@[deprecated Int.tdiv_mul_cancel_of_tmod_eq_zero (since := "2024-09-11")] abbrev div_mul_cancel_of_mod_eq_zero := @Int.tdiv_mul_cancel_of_tmod_eq_zero
@[deprecated Int.dvd_of_tmod_eq_zero (since := "2024-09-11")] abbrev dvd_of_mod_eq_zero := @Int.dvd_of_tmod_eq_zero
@[deprecated Int.mul_tdiv_assoc (since := "2024-09-11")] protected abbrev mul_div_assoc := @Int.mul_tdiv_assoc
@[deprecated Int.mul_tdiv_assoc' (since := "2024-09-11")] protected abbrev mul_div_assoc' := @Int.mul_tdiv_assoc'
@[deprecated Int.tdiv_dvd_tdiv (since := "2024-09-11")] abbrev div_dvd_div := @Int.tdiv_dvd_tdiv
@[deprecated Int.natAbs_tdiv (since := "2024-09-11")] abbrev natAbs_div := @Int.natAbs_tdiv
@[deprecated Int.tdiv_eq_of_eq_mul_right (since := "2024-09-11")] protected abbrev div_eq_of_eq_mul_right := @Int.tdiv_eq_of_eq_mul_right
@[deprecated Int.eq_tdiv_of_mul_eq_right (since := "2024-09-11")] protected abbrev eq_div_of_mul_eq_right := @Int.eq_tdiv_of_mul_eq_right
@[deprecated Int.ofNat_tmod (since := "2024-09-11")] abbrev ofNat_mod := @Int.ofNat_tmod
@[deprecated Int.tmod_one (since := "2024-09-11")] abbrev mod_one := @Int.tmod_one
@[deprecated Int.tmod_eq_of_lt (since := "2024-09-11")] abbrev mod_eq_of_lt := @Int.tmod_eq_of_lt
@[deprecated Int.tmod_lt_of_pos (since := "2024-09-11")] abbrev mod_lt_of_pos := @Int.tmod_lt_of_pos
@[deprecated Int.tmod_nonneg (since := "2024-09-11")] abbrev mod_nonneg := @Int.tmod_nonneg
@[deprecated Int.tmod_neg (since := "2024-09-11")] abbrev mod_neg := @Int.tmod_neg
@[deprecated Int.mul_tmod_left (since := "2024-09-11")] abbrev mul_mod_left := @Int.mul_tmod_left
@[deprecated Int.mul_tmod_right (since := "2024-09-11")] abbrev mul_mod_right := @Int.mul_tmod_right
@[deprecated Int.tmod_eq_zero_of_dvd (since := "2024-09-11")] abbrev mod_eq_zero_of_dvd := @Int.tmod_eq_zero_of_dvd
@[deprecated Int.dvd_iff_tmod_eq_zero (since := "2024-09-11")] abbrev dvd_iff_mod_eq_zero := @Int.dvd_iff_tmod_eq_zero
@[deprecated Int.neg_mul_tmod_right (since := "2024-09-11")] abbrev neg_mul_mod_right := @Int.neg_mul_tmod_right
@[deprecated Int.neg_mul_tmod_left (since := "2024-09-11")] abbrev neg_mul_mod_left := @Int.neg_mul_tmod_left
@[deprecated Int.tdiv_mul_cancel (since := "2024-09-11")] protected abbrev div_mul_cancel := @Int.tdiv_mul_cancel
@[deprecated Int.mul_tdiv_cancel' (since := "2024-09-11")] protected abbrev mul_div_cancel' := @Int.mul_tdiv_cancel'
@[deprecated Int.eq_mul_of_tdiv_eq_right (since := "2024-09-11")] protected abbrev eq_mul_of_div_eq_right := @Int.eq_mul_of_tdiv_eq_right
@[deprecated Int.tmod_self (since := "2024-09-11")] abbrev mod_self := @Int.tmod_self
@[deprecated Int.neg_tmod_self (since := "2024-09-11")] abbrev neg_mod_self := @Int.neg_tmod_self
@[deprecated Int.lt_tdiv_add_one_mul_self (since := "2024-09-11")] abbrev lt_div_add_one_mul_self := @Int.lt_tdiv_add_one_mul_self
@[deprecated Int.tdiv_eq_iff_eq_mul_right (since := "2024-09-11")] protected abbrev div_eq_iff_eq_mul_right := @Int.tdiv_eq_iff_eq_mul_right
@[deprecated Int.tdiv_eq_iff_eq_mul_left (since := "2024-09-11")] protected abbrev div_eq_iff_eq_mul_left := @Int.tdiv_eq_iff_eq_mul_left
@[deprecated Int.eq_mul_of_tdiv_eq_left (since := "2024-09-11")] protected abbrev eq_mul_of_div_eq_left := @Int.eq_mul_of_tdiv_eq_left
@[deprecated Int.tdiv_eq_of_eq_mul_left (since := "2024-09-11")] protected abbrev div_eq_of_eq_mul_left := @Int.tdiv_eq_of_eq_mul_left
@[deprecated Int.eq_zero_of_tdiv_eq_zero (since := "2024-09-11")] protected abbrev eq_zero_of_div_eq_zero := @Int.eq_zero_of_tdiv_eq_zero
@[deprecated Int.tdiv_left_inj (since := "2024-09-11")] protected abbrev div_left_inj := @Int.tdiv_left_inj
@[deprecated Int.tdiv_sign (since := "2024-09-11")] abbrev div_sign := @Int.tdiv_sign
@[deprecated Int.sign_eq_tdiv_abs (since := "2024-09-11")] protected abbrev sign_eq_div_abs := @Int.sign_eq_tdiv_abs
@[deprecated Int.tdiv_eq_ediv_of_dvd (since := "2024-09-11")] abbrev div_eq_ediv_of_dvd := @Int.tdiv_eq_ediv_of_dvd

View File

@@ -24,5 +24,8 @@ import Init.Data.List.Zip
import Init.Data.List.Perm
import Init.Data.List.Sort
import Init.Data.List.ToArray
import Init.Data.List.ToArrayImpl
import Init.Data.List.MapIdx
import Init.Data.List.OfFn
import Init.Data.List.FinRange
import Init.Data.List.Lex

View File

@@ -118,7 +118,6 @@ theorem attach_map_coe (l : List α) (f : α → β) :
theorem attach_map_val (l : List α) (f : α β) : (l.attach.map fun i => f i.val) = l.map f :=
attach_map_coe _ _
@[simp]
theorem attach_map_subtype_val (l : List α) : l.attach.map Subtype.val = l :=
(attach_map_coe _ _).trans (List.map_id _)
@@ -130,7 +129,6 @@ theorem attachWith_map_val {p : α → Prop} (f : α → β) (l : List α) (H :
((l.attachWith p H).map fun i => f i.val) = l.map f :=
attachWith_map_coe _ _ _
@[simp]
theorem attachWith_map_subtype_val {p : α Prop} (l : List α) (H : a l, p a) :
(l.attachWith p H).map Subtype.val = l :=
(attachWith_map_coe _ _ _).trans (List.map_id _)
@@ -174,8 +172,8 @@ theorem pmap_ne_nil_iff {P : α → Prop} (f : (a : α) → P a → β) {xs : Li
(H : (a : α), a xs P a) : xs.pmap f H [] xs [] := by
simp
theorem pmap_eq_self {l : List α} {p : α Prop} (hp : (a : α), a l p a)
(f : (a : α) p a α) : l.pmap f hp = l a (h : a l), f a (hp a h) = a := by
theorem pmap_eq_self {l : List α} {p : α Prop} {hp : (a : α), a l p a}
{f : (a : α) p a α} : l.pmap f hp = l a (h : a l), f a (hp a h) = a := by
rw [pmap_eq_map_attach]
conv => lhs; rhs; rw [ attach_map_subtype_val l]
rw [map_inj_left]

View File

@@ -162,46 +162,74 @@ theorem isEqv_cons₂ : isEqv (a::as) (b::bs) eqv = (eqv a b && isEqv as bs eqv)
/-! ## Lexicographic ordering -/
/--
The lexicographic order on lists.
`[] < a::as`, and `a::as < b::bs` if `a < b` or if `a` and `b` are equivalent and `as < bs`.
-/
inductive lt [LT α] : List α List α Prop where
/-- Lexicographic ordering for lists. -/
inductive Lex (r : α α Prop) : List α List α Prop
/-- `[]` is the smallest element in the order. -/
| nil (b : α) (bs : List α) : lt [] (b::bs)
| nil {a l} : Lex r [] (a :: l)
/-- If `a` is indistinguishable from `b` and `as < bs`, then `a::as < b::bs`. -/
| cons {a l₁ l₂} (h : Lex r l₁ l₂) : Lex r (a :: l₁) (a :: l₂)
/-- If `a < b` then `a::as < b::bs`. -/
| head {a : α} (as : List α) {b : α} (bs : List α) : a < b lt (a::as) (b::bs)
/-- If `a` and `b` are equivalent and `as < bs`, then `a::as < b::bs`. -/
| tail {a : α} {as : List α} {b : α} {bs : List α} : ¬ a < b ¬ b < a lt as bs lt (a::as) (b::bs)
| rel {a l₁ a₂ l₂} (h : r a₁ a₂) : Lex r (a₁ :: l) (a :: l₂)
instance [LT α] : LT (List α) := List.lt
instance hasDecidableLt [LT α] [h : DecidableRel (α := α) (· < ·)] : (l₁ l₂ : List α) Decidable (l₁ < l₂)
| [], [] => isFalse nofun
| [], _::_ => isTrue (List.lt.nil _ _)
| _::_, [] => isFalse nofun
instance decidableLex [DecidableEq α] (r : α α Prop) [h : DecidableRel r] :
(l₁ l₂ : List α) Decidable (Lex r l₁ l₂)
| [], [] => isFalse nofun
| [], _::_ => isTrue Lex.nil
| _::_, [] => isFalse nofun
| a::as, b::bs =>
match h a b with
| isTrue h₁ => isTrue (List.lt.head _ _ h₁)
| isTrue h₁ => isTrue (Lex.rel h₁)
| isFalse h₁ =>
match h b a with
| isTrue h₂ => isFalse (fun h => match h with
| List.lt.head _ _ h₁' => absurd h₁' h
| List.lt.tail _ h₂' _ => absurd h₂ h₂')
| isFalse h₂ =>
match hasDecidableLt as bs with
| isTrue h₃ => isTrue (List.lt.tail h₁ h₂ h₃)
if h : a = b then
match decidableLex r as bs with
| isTrue h₃ => isTrue (h₂ Lex.cons h)
| isFalse h₃ => isFalse (fun h => match h with
| List.lt.head _ _ h₁' => absurd h₁' h₁
| List.lt.tail _ _ h₃' => absurd h₃' h₃)
| Lex.rel h₁' => absurd h₁' h₁
| Lex.cons h₃' => absurd h₃' h₃)
else
isFalse (fun h => match h with
| Lex.rel h₁' => absurd h₁' h₁
| Lex.cons h₂' => h₂ rfl)
@[inherit_doc Lex]
protected abbrev lt [LT α] : List α List α Prop := Lex (· < ·)
instance instLT [LT α] : LT (List α) := List.lt
/-- Decidability of lexicographic ordering. -/
instance decidableLT [DecidableEq α] [LT α] [DecidableLT α] (l₁ l₂ : List α) :
Decidable (l₁ < l₂) := decidableLex (· < ·) l₁ l₂
@[deprecated decidableLT (since := "2024-12-13"), inherit_doc decidableLT]
abbrev hasDecidableLt := @decidableLT
/-- The lexicographic order on lists. -/
@[reducible] protected def le [LT α] (a b : List α) : Prop := ¬ b < a
instance [LT α] : LE (List α) := List.le
instance instLE [LT α] : LE (List α) := List.le
instance [LT α] [DecidableRel ((· < ·) : α α Prop)] : (l₁ l₂ : List α) Decidable (l₁ l₂) :=
fun _ _ => inferInstanceAs (Decidable (Not _))
instance decidableLE [DecidableEq α] [LT α] [DecidableLT α] (l₁ l₂ : List α) :
Decidable (l₁ l₂) :=
inferInstanceAs (Decidable (Not _))
/--
Lexicographic comparator for lists.
* `lex lt [] (b :: bs)` is true.
* `lex lt as []` is false.
* `lex lt (a :: as) (b :: bs)` is true if `lt a b` or `a == b` and `lex lt as bs` is true.
-/
def lex [BEq α] (l₁ l₂ : List α) (lt : α α Bool := by exact (· < ·)) : Bool :=
match l₁, l₂ with
| [], _ :: _ => true
| _, [] => false
| a :: as, b :: bs => lt a b || (a == b && lex as bs lt)
@[simp] theorem lex_nil_nil [BEq α] : lex ([] : List α) [] lt = false := rfl
@[simp] theorem lex_nil_cons [BEq α] {b} {bs : List α} : lex [] (b :: bs) lt = true := rfl
@[simp] theorem lex_cons_nil [BEq α] {a} {as : List α} : lex (a :: as) [] lt = false := rfl
@[simp] theorem lex_cons_cons [BEq α] {a b} {as bs : List α} :
lex (a :: as) (b :: bs) lt = (lt a b || (a == b && lex as bs lt)) := rfl
/-! ## Alternative getters -/
@@ -231,7 +259,7 @@ theorem ext_get? : ∀ {l₁ l₂ : List α}, (∀ n, l₁.get? n = l₂.get? n)
injection h0 with aa; simp only [aa, ext_get? fun n => h (n+1)]
/-- Deprecated alias for `ext_get?`. The preferred extensionality theorem is now `ext_getElem?`. -/
@[deprecated (since := "2024-06-07")] abbrev ext := @ext_get?
@[deprecated ext_get? (since := "2024-06-07")] abbrev ext := @ext_get?
/-! ### getD -/
@@ -666,10 +694,14 @@ def isEmpty : List α → Bool
/-! ### elem -/
/--
`O(|l|)`. `elem a l` or `l.contains a` is true if there is an element in `l` equal to `a`.
`O(|l|)`.
`l.contains a` or `elem a l` is true if there is an element in `l` equal (according to `==`) to `a`.
* `elem 3 [1, 4, 2, 3, 3, 7] = true`
* `elem 5 [1, 4, 2, 3, 3, 7] = false`
* `[1, 4, 2, 3, 3, 7].contains 3 = true`
* `[1, 4, 2, 3, 3, 7].contains 5 = false`
The preferred simp normal form is `l.contains a`, and when `LawfulBEq α` is available,
`l.contains a = true ↔ a ∈ l` and `l.contains a = false ↔ a ∉ l`.
-/
def elem [BEq α] (a : α) : List α Bool
| [] => false
@@ -682,7 +714,7 @@ theorem elem_cons [BEq α] {a : α} :
(b::bs).elem a = match a == b with | true => true | false => bs.elem a := rfl
/-- `notElem a l` is `!(elem a l)`. -/
@[deprecated (since := "2024-06-15")]
@[deprecated "Use `!(elem a l)` instead."(since := "2024-06-15")]
def notElem [BEq α] (a : α) (as : List α) : Bool :=
!(as.elem a)

View File

@@ -155,7 +155,8 @@ def mapMono (as : List α) (f : αα) : List α :=
/-! ## Additional lemmas required for bootstrapping `Array`. -/
theorem getElem_append_left {as bs : List α} (h : i < as.length) {h'} : (as ++ bs)[i] = as[i] := by
theorem getElem_append_left {as bs : List α} (h : i < as.length) {h' : i < (as ++ bs).length} :
(as ++ bs)[i] = as[i] := by
induction as generalizing i with
| nil => trivial
| cons a as ih =>
@@ -232,25 +233,34 @@ theorem sizeOf_get [SizeOf α] (as : List α) (i : Fin as.length) : sizeOf (as.g
apply Nat.lt_trans ih
simp_arith
theorem le_antisymm [LT α] [s : Std.Antisymm (¬ · < · : α α Prop)]
{as bs : List α} (h₁ : as bs) (h₂ : bs as) : as = bs :=
theorem not_lex_antisymm [DecidableEq α] {r : α α Prop} [DecidableRel r]
(antisymm : x y : α, ¬ r x y ¬ r y x x = y)
{as bs : List α} (h₁ : ¬ Lex r bs as) (h₂ : ¬ Lex r as bs) : as = bs :=
match as, bs with
| [], [] => rfl
| [], _::_ => False.elim <| h₂ (List.lt.nil ..)
| _::_, [] => False.elim <| h₁ (List.lt.nil ..)
| [], _::_ => False.elim <| h₂ (List.Lex.nil ..)
| _::_, [] => False.elim <| h₁ (List.Lex.nil ..)
| a::as, b::bs => by
by_cases hab : a < b
· exact False.elim <| h₂ (List.lt.head _ _ hab)
· by_cases hba : b < a
· exact False.elim <| h₁ (List.lt.head _ _ hba)
· have h₁ : as bs := fun h => h₁ (List.lt.tail hba hab h)
have h₂ : bs as := fun h => h₂ (List.lt.tail hab hba h)
have ih : as = bs := le_antisymm h₁ h₂
have : a = b := s.antisymm hab hba
simp [this, ih]
by_cases hab : r a b
· exact False.elim <| h₂ (List.Lex.rel hab)
· by_cases eq : a = b
· subst eq
have h₁ : ¬ Lex r bs as := fun h => h₁ (List.Lex.cons h)
have h₂ : ¬ Lex r as bs := fun h => h₂ (List.Lex.cons h)
simp [not_lex_antisymm antisymm h₁ h₂]
· exfalso
by_cases hba : r b a
· exact h₁ (Lex.rel hba)
· exact eq (antisymm _ _ hab hba)
instance [LT α] [Std.Antisymm (¬ · < · : α α Prop)] :
protected theorem le_antisymm [DecidableEq α] [LT α] [DecidableLT α]
[i : Std.Antisymm (¬ · < · : α α Prop)]
{as bs : List α} (h₁ : as bs) (h₂ : bs as) : as = bs :=
not_lex_antisymm i.antisymm h₁ h₂
instance [DecidableEq α] [LT α] [DecidableLT α]
[s : Std.Antisymm (¬ · < · : α α Prop)] :
Std.Antisymm (· · : List α List α Prop) where
antisymm h₁ h₂ := le_antisymm h₁ h₂
antisymm _ _ h₁ h₂ := List.le_antisymm h₁ h₂
end List

View File

@@ -162,6 +162,10 @@ theorem countP_filterMap (p : β → Bool) (f : α → Option β) (l : List α)
@[deprecated countP_flatten (since := "2024-10-14")] abbrev countP_join := @countP_flatten
theorem countP_flatMap (p : β Bool) (l : List α) (f : α List β) :
countP p (l.flatMap f) = sum (map (countP p f) l) := by
rw [List.flatMap, countP_flatten, map_map]
@[simp] theorem countP_reverse (l : List α) : countP p l.reverse = countP p l := by
simp [countP_eq_length_filter, filter_reverse]
@@ -326,6 +330,9 @@ theorem count_filterMap {α} [BEq β] (b : β) (f : α → Option β) (l : List
· simp
· simp
theorem count_flatMap {α} [BEq β] (l : List α) (f : α List β) (x : β) :
count x (l.flatMap f) = sum (map (count x f) l) := countP_flatMap _ _ _
theorem count_erase (a b : α) :
l : List α, count a (l.erase b) = count a l - if b == a then 1 else 0
| [] => by simp

View File

@@ -0,0 +1,48 @@
/-
Copyright (c) 2024 François G. Dorais. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: François G. Dorais
-/
prelude
import Init.Data.List.OfFn
namespace List
/-- `finRange n` lists all elements of `Fin n` in order -/
def finRange (n : Nat) : List (Fin n) := ofFn fun i => i
@[simp] theorem length_finRange (n) : (List.finRange n).length = n := by
simp [List.finRange]
@[simp] theorem getElem_finRange (i : Nat) (h : i < (List.finRange n).length) :
(finRange n)[i] = Fin.cast (length_finRange n) i, h := by
simp [List.finRange]
@[simp] theorem finRange_zero : finRange 0 = [] := by simp [finRange, ofFn]
theorem finRange_succ (n) : finRange (n+1) = 0 :: (finRange n).map Fin.succ := by
apply List.ext_getElem; simp; intro i; cases i <;> simp
theorem finRange_succ_last (n) :
finRange (n+1) = (finRange n).map Fin.castSucc ++ [Fin.last n] := by
apply List.ext_getElem
· simp
· intros
simp only [List.finRange, List.getElem_ofFn, getElem_append, length_map, length_ofFn,
getElem_map, Fin.castSucc_mk, getElem_singleton]
split
· rfl
· next h => exact Fin.eq_last_of_not_lt h
theorem finRange_reverse (n) : (finRange n).reverse = (finRange n).map Fin.rev := by
induction n with
| zero => simp
| succ n ih =>
conv => lhs; rw [finRange_succ_last]
conv => rhs; rw [finRange_succ]
rw [reverse_append, reverse_cons, reverse_nil, nil_append, singleton_append, map_reverse,
map_cons, ih, map_map, map_map]
congr; funext
simp [Fin.rev_succ]
end List

View File

@@ -566,7 +566,6 @@ theorem not_of_lt_findIdx {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs
| inl e => simpa [e, Fin.zero_eta, get_cons_zero]
| inr e =>
have ipm := Nat.succ_pred_eq_of_pos e
have ilt := Nat.le_trans ho (findIdx_le_length p)
simp +singlePass only [ ipm, getElem_cons_succ]
rw [ ipm, Nat.succ_lt_succ_iff] at h
simpa using ih h

View File

@@ -332,7 +332,7 @@ def enumFromTR (n : Nat) (l : List α) : List (Nat × α) :=
rw [ show _ + as.length = n + (a::as).length from Nat.succ_add .., foldr, go as]
simp [enumFrom, f]
rw [ Array.foldr_toList]
simp [go]
simp +zetaDelta [go]
/-! ## Other list operations -/

File diff suppressed because it is too large Load Diff

430
src/Init/Data/List/Lex.lean Normal file
View File

@@ -0,0 +1,430 @@
/-
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.List.Lemmas
namespace List
/-! ### Lexicographic ordering -/
@[simp] theorem lex_lt [LT α] (l₁ l₂ : List α) : Lex (· < ·) l₁ l₂ l₁ < l₂ := Iff.rfl
@[simp] theorem not_lex_lt [LT α] (l₁ l₂ : List α) : ¬ Lex (· < ·) l₁ l₂ l₂ l₁ := Iff.rfl
theorem not_lt_iff_ge [LT α] (l₁ l₂ : List α) : ¬ l₁ < l₂ l₂ l₁ := Iff.rfl
theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] (l₁ l₂ : List α) :
¬ l₁ l₂ l₂ < l₁ :=
Decidable.not_not
theorem lex_irrefl {r : α α Prop} (irrefl : x, ¬r x x) (l : List α) : ¬Lex r l l := by
induction l with
| nil => nofun
| cons a l ih => intro
| .rel h => exact irrefl _ h
| .cons h => exact ih h
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α α Prop)] (l : List α) : ¬ l < l :=
lex_irrefl Std.Irrefl.irrefl l
instance ltIrrefl [LT α] [Std.Irrefl (· < · : α α Prop)] : Std.Irrefl (α := List α) (· < ·) where
irrefl := List.lt_irrefl
@[simp] theorem not_lex_nil : ¬Lex r l [] := fun h => nomatch h
@[simp] theorem nil_le [LT α] (l : List α) : [] l := fun h => nomatch h
@[simp] theorem not_nil_lex_iff : ¬Lex r [] l l = [] := by
constructor
· rintro h
match l, h with
| [], h => rfl
| a :: _, h => exact False.elim (h Lex.nil)
· rintro rfl
exact not_lex_nil
@[simp] theorem le_nil [LT α] (l : List α) : l [] l = [] := not_nil_lex_iff
@[simp] theorem nil_lex_cons : Lex r [] (a :: l) := Lex.nil
@[simp] theorem nil_lt_cons [LT α] (a : α) (l : List α) : [] < a :: l := Lex.nil
theorem cons_lex_cons_iff : Lex r (a :: l₁) (b :: l₂) r a b a = b Lex r l₁ l₂ :=
fun | .rel h => .inl h | .cons h => .inr rfl, h,
fun | .inl h => Lex.rel h | .inr rfl, h => Lex.cons h
theorem cons_lt_cons_iff [LT α] {a b} {l₁ l₂ : List α} :
(a :: l₁) < (b :: l₂) a < b a = b l₁ < l₂ := by
dsimp only [instLT, List.lt]
simp [cons_lex_cons_iff]
theorem not_cons_lex_cons_iff [DecidableEq α] [DecidableRel r] {a b} {l₁ l₂ : List α} :
¬ Lex r (a :: l₁) (b :: l₂) (¬ r a b a b) (¬ r a b ¬ Lex r l₁ l₂) := by
rw [cons_lex_cons_iff, not_or, Decidable.not_and_iff_or_not, and_or_left]
theorem cons_le_cons_iff [DecidableEq α] [LT α] [DecidableLT α]
[i₀ : Std.Irrefl (· < · : α α Prop)]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
{a b} {l₁ l₂ : List α} :
(a :: l₁) (b :: l₂) a < b a = b l₁ l₂ := by
dsimp only [instLE, instLT, List.le, List.lt]
simp only [not_cons_lex_cons_iff, ne_eq]
constructor
· rintro (h₁, h₂ | h₁, h₂)
· left
apply Decidable.byContradiction
intro h₃
apply h₂
exact i₂.antisymm _ _ h₁ h₃
· if h₃ : a < b then
exact .inl h₃
else
right
exact i₂.antisymm _ _ h₃ h₁, h₂
· rintro (h | h₁, h₂)
· left
exact i₁.asymm _ _ h, fun w => i₀.irrefl _ (w h)
· right
exact fun w => i₀.irrefl _ (h₁ w), h₂
theorem not_lt_of_cons_le_cons [DecidableEq α] [LT α] [DecidableLT α]
[i₀ : Std.Irrefl (· < · : α α Prop)]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
{a b : α} {l₁ l₂ : List α} (h : a :: l₁ b :: l₂) : ¬ b < a := by
rw [cons_le_cons_iff] at h
rcases h with h | rfl, h
· exact i₁.asymm _ _ h
· exact i₀.irrefl _
theorem le_of_cons_le_cons [DecidableEq α] [LT α] [DecidableLT α]
[i₀ : Std.Irrefl (· < · : α α Prop)]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
{a} {l₁ l₂ : List α} (h : a :: l₁ a :: l₂) : l₁ l₂ := by
rw [cons_le_cons_iff] at h
rcases h with h | _, h
· exact False.elim (i₀.irrefl _ h)
· exact h
protected theorem le_refl [LT α] [i₀ : Std.Irrefl (· < · : α α Prop)] (l : List α) : l l := by
induction l with
| nil => simp
| cons a l ih =>
intro
| .rel h => exact i₀.irrefl _ h
| .cons h₃ => exact ih h₃
instance [LT α] [Std.Irrefl (· < · : α α Prop)] : Std.Refl (· · : List α List α Prop) where
refl := List.le_refl
theorem lex_trans {r : α α Prop} [DecidableRel r]
(lt_trans : {x y z : α}, r x y r y z r x z)
(h₁ : Lex r l₁ l₂) (h₂ : Lex r l₂ l₃) : Lex r l₁ l₃ := by
induction h₁ generalizing l₃ with
| nil => let _::_ := l₃; exact List.Lex.nil ..
| @rel a l₁ b l₂ ab =>
match h₂ with
| .rel bc => exact List.Lex.rel (lt_trans ab bc)
| .cons ih =>
exact List.Lex.rel ab
| @cons a l₁ l₂ h₁ ih2 =>
match h₂ with
| .rel bc =>
exact List.Lex.rel bc
| .cons ih =>
exact List.Lex.cons (ih2 ih)
protected theorem lt_trans [LT α] [DecidableLT α]
[i₁ : Trans (· < · : α α Prop) (· < ·) (· < ·)]
{l₁ l₂ l₃ : List α} (h₁ : l₁ < l₂) (h₂ : l₂ < l₃) : l₁ < l₃ := by
simp only [instLT, List.lt] at h₁ h₂
exact lex_trans (fun h₁ h₂ => i₁.trans h₁ h₂) h₁ h₂
instance [LT α] [DecidableLT α]
[Trans (· < · : α α Prop) (· < ·) (· < ·)] :
Trans (· < · : List α List α Prop) (· < ·) (· < ·) where
trans h₁ h₂ := List.lt_trans h₁ h₂
@[deprecated List.le_antisymm (since := "2024-12-13")]
protected abbrev lt_antisymm := @List.le_antisymm
protected theorem lt_of_le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
[i₀ : Std.Irrefl (· < · : α α Prop)]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
[i₃ : Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{l₁ l₂ l₃ : List α} (h₁ : l₁ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ := by
induction h₂ generalizing l₁ with
| nil => simp_all
| rel hab =>
rename_i a b
cases l₁ with
| nil => simp_all
| cons c l₁ =>
apply Lex.rel
replace h₁ := not_lt_of_cons_le_cons h₁
apply Decidable.byContradiction
intro h₂
have := i₃.trans h₁ h₂
contradiction
| cons w₃ ih =>
rename_i a as bs
cases l₁ with
| nil => simp_all
| cons c l₁ =>
have w₄ := not_lt_of_cons_le_cons h₁
by_cases w₅ : a = c
· subst w₅
exact Lex.cons (ih (le_of_cons_le_cons h₁))
· exact Lex.rel (Decidable.byContradiction fun w₆ => w₅ (i₂.antisymm _ _ w₄ w₆))
protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{l₁ l₂ l₃ : List α} (h₁ : l₁ l₂) (h₂ : l₂ l₃) : l₁ l₃ :=
fun h₃ => h₁ (List.lt_of_le_of_lt h₂ h₃)
instance [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)] :
Trans (· · : List α List α Prop) (· ·) (· ·) where
trans h₁ h₂ := List.le_trans h₁ h₂
theorem lex_asymm {r : α α Prop} [DecidableRel r]
(h : {x y : α}, r x y ¬ r y x) : {l₁ l₂ : List α}, Lex r l₁ l₂ ¬ Lex r l₂ l₁
| nil, _, .nil => by simp
| x :: l₁, y :: l₂, .rel h₁ =>
fun
| .rel h₂ => h h₁ h₂
| .cons h₂ => h h₁ h₁
| x :: l₁, _ :: l₂, .cons h₁ =>
fun
| .rel h₂ => h h₂ h₂
| .cons h₂ => lex_asymm h h₁ h₂
protected theorem lt_asymm [DecidableEq α] [LT α] [DecidableLT α]
[i : Std.Asymm (· < · : α α Prop)]
{l₁ l₂ : List α} (h : l₁ < l₂) : ¬ l₂ < l₁ := lex_asymm (i.asymm _ _) h
instance [DecidableEq α] [LT α] [DecidableLT α]
[Std.Asymm (· < · : α α Prop)] :
Std.Asymm (· < · : List α List α Prop) where
asymm _ _ := List.lt_asymm
theorem not_lex_total [DecidableEq α] {r : α α Prop} [DecidableRel r]
(h : x y : α, ¬ r x y ¬ r y x) (l₁ l₂ : List α) : ¬ Lex r l₁ l₂ ¬ Lex r l₂ l₁ := by
rw [Decidable.or_iff_not_imp_left, Decidable.not_not]
intro w₁ w₂
match l₁, l₂, w₁, w₂ with
| nil, _ :: _, .nil, w₂ => simp at w₂
| x :: _, y :: _, .rel _, .rel _ =>
obtain (_ | _) := h x y <;> contradiction
| x :: _, _ :: _, .rel _, .cons _ =>
obtain (_ | _) := h x x <;> contradiction
| x :: _, _ :: _, .cons _, .rel _ =>
obtain (_ | _) := h x x <;> contradiction
| _ :: l₁, _ :: l₂, .cons _, .cons _ =>
obtain (_ | _) := not_lex_total h l₁ l₂ <;> contradiction
protected theorem le_total [DecidableEq α] [LT α] [DecidableLT α]
[i : Std.Total (¬ · < · : α α Prop)] {l₁ l₂ : List α} : l₁ l₂ l₂ l₁ :=
not_lex_total i.total l₂ l₁
instance [DecidableEq α] [LT α] [DecidableLT α]
[Std.Total (¬ · < · : α α Prop)] :
Std.Total (· · : List α List α Prop) where
total _ _ := List.le_total
theorem lex_eq_decide_lex [DecidableEq α] (lt : α α Bool) :
lex l₁ l₂ lt = decide (Lex (fun x y => lt x y) l₁ l₂) := by
induction l₁ generalizing l₂ with
| nil =>
cases l₂ with
| nil => simp [lex]
| cons b bs => simp [lex]
| cons a l₁ ih =>
cases l₂ with
| nil => simp [lex]
| cons b bs =>
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) :
lex l₁ l₂ lt = true Lex (fun x y => lt x y) l₁ l₂ := by
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) :
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 α]
{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 α]
{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
attribute [local simp] Nat.add_one_lt_add_one_iff in
/--
`l₁` is lexicographically less than `l₂` if either
- `l₁` is pairwise equivalent under `· == ·` to `l₂.take l₁.length`,
and `l₁` is shorter than `l₂` or
- there exists an index `i` such that
- for all `j < i`, `l₁[j] == l₂[j]` and
- `l₁[i] < l₂[i]`
-/
theorem lex_eq_true_iff_exists [BEq α] (lt : α α Bool) :
lex l₁ l₂ lt = true
(l₁.isEqv (l₂.take l₁.length) (· == ·) l₁.length < l₂.length)
( (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length),
( j, (hj : j < i)
l₁[j]'(Nat.lt_trans hj h₁) == l₂[j]'(Nat.lt_trans hj h₂)) lt l₁[i] l₂[i]) := by
induction l₁ generalizing l₂ with
| nil =>
cases l₂ with
| nil => simp [lex]
| cons b bs => simp [lex]
| cons a l₁ ih =>
cases l₂ with
| nil => simp [lex]
| cons b l₂ =>
simp only [lex_cons_cons, Bool.or_eq_true, Bool.and_eq_true, ih, isEqv, length_cons]
constructor
· rintro (hab | hab, h₁, h₂ | i, h₁, h₂, w₁, w₂)
· exact .inr 0, by simp [hab]
· exact .inl hab, h₁, by simpa using h₂
· refine .inr i + 1, by simp [h₁],
by simp [h₂], ?_, ?_
· intro j hj
cases j with
| zero => simp [hab]
| succ j =>
simp only [getElem_cons_succ]
rw [w₁]
simpa using hj
· simpa using w₂
· rintro (h₁, h₂, h₃ | i, h₁, h₂, w₁, w₂)
· exact .inr h₁, .inl h₂, by simpa using h₃
· cases i with
| zero =>
left
simpa using w₂
| succ i =>
right
refine by simpa using w₁ 0 (by simp), ?_
right
refine i, by simpa using h₁, by simpa using h₂, ?_, ?_
· intro j hj
simpa using w₁ (j + 1) (by simpa)
· simpa using w₂
attribute [local simp] Nat.add_one_lt_add_one_iff in
/--
`l₁` is *not* lexicographically less than `l₂`
(which you might think of as "`l₂` is lexicographically greater than or equal to `l₁`"") if either
- `l₁` is pairwise equivalent under `· == ·` to `l₂.take l₁.length` or
- there exists an index `i` such that
- for all `j < i`, `l₁[j] == l₂[j]` and
- `l₂[i] < l₁[i]`
This formulation requires that `==` and `lt` are compatible in the following senses:
- `==` is symmetric
(we unnecessarily further assume it is transitive, to make use of the existing typeclasses)
- `lt` is irreflexive with respect to `==` (i.e. if `x == y` then `lt x y = false`
- `lt` is asymmmetric (i.e. `lt x y = true → lt y x = false`)
- `lt` is antisymmetric with respect to `==` (i.e. `lt x y = false → lt y x = false → x == y`)
-/
theorem lex_eq_false_iff_exists [BEq α] [PartialEquivBEq α] (lt : α α Bool)
(lt_irrefl : x y, x == y lt x y = false)
(lt_asymm : x y, lt x y = true lt y x = false)
(lt_antisymm : x y, lt x y = false lt y x = false x == y) :
lex l₁ l₂ lt = false
(l₂.isEqv (l₁.take l₂.length) (· == ·))
( (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length),
( j, (hj : j < i)
l₁[j]'(Nat.lt_trans hj h₁) == l₂[j]'(Nat.lt_trans hj h₂)) lt l₂[i] l₁[i]) := by
induction l₁ generalizing l₂ with
| nil =>
cases l₂ with
| nil => simp [lex]
| cons b bs => simp [lex]
| cons a l₁ ih =>
cases l₂ with
| nil => simp [lex]
| cons b l₂ =>
simp only [lex_cons_cons, Bool.or_eq_false_iff, Bool.and_eq_false_imp, ih, isEqv,
Bool.and_eq_true, length_cons]
constructor
· rintro hab, h
if eq : b == a then
specialize h (BEq.symm eq)
obtain (h | i, h₁, h₂, w₁, w₂) := h
· exact .inl eq, h
· refine .inr i + 1, by simpa using h₁, by simpa using h₂, ?_, ?_
· intro j hj
cases j with
| zero => simpa using BEq.symm eq
| succ j =>
simp only [getElem_cons_succ]
rw [w₁]
simpa using hj
· simpa using w₂
else
right
have hba : lt b a :=
Decidable.byContradiction fun hba => eq (lt_antisymm _ _ (by simpa using hba) hab)
exact 0, by simp, by simp, by simpa
· rintro (eq, h | i, h₁, h₂, w₁, w₂)
· exact lt_irrefl _ _ (BEq.symm eq), fun _ => .inl h
· cases i with
| zero =>
simp at w₂
refine lt_asymm _ _ w₂, ?_
intro eq
exfalso
simp [lt_irrefl _ _ (BEq.symm eq)] at w₂
| succ i =>
refine lt_irrefl _ _ (by simpa using w₁ 0 (by simp)), ?_
refine fun _ => .inr i, by simpa using h₁, by simpa using h₂, ?_, ?_
· intro j hj
simpa using w₁ (j + 1) (by simpa)
· simpa using w₂
theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {l₁ l₂ : List α} :
l₁ < l₂
(l₁ = l₂.take l₁.length l₁.length < l₂.length)
( (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length),
( j, (hj : j < i)
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) l₁[i] < l₂[i]) := by
rw [ lex_eq_true_iff_lt, lex_eq_true_iff_exists]
simp
theorem le_iff_exists [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)] {l₁ l₂ : List α} :
l₁ l₂
(l₁ = l₂.take l₁.length)
( (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length),
( j, (hj : j < i)
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) l₁[i] < l₂[i]) := by
rw [ lex_eq_false_iff_ge, lex_eq_false_iff_exists]
· simp only [isEqv_eq, beq_iff_eq, decide_eq_true_eq]
simp only [eq_comm]
conv => lhs; simp +singlePass [exists_comm]
· simpa using Std.Irrefl.irrefl
· simpa using Std.Asymm.asymm
· simpa using Std.Antisymm.antisymm
end List

View File

@@ -87,8 +87,8 @@ theorem mapFinIdx_eq_ofFn {as : List α} {f : Fin as.length → α → β} :
apply ext_getElem <;> simp
@[simp] theorem getElem?_mapFinIdx {l : List α} {f : Fin l.length α β} {i : Nat} :
(l.mapFinIdx f)[i]? = l[i]?.pbind fun x m => f i, by simp [getElem?_eq_some] at m; exact m.1 x := by
simp only [getElem?_eq, length_mapFinIdx, getElem_mapFinIdx]
(l.mapFinIdx f)[i]? = l[i]?.pbind fun x m => f i, by simp [getElem?_eq_some_iff] at m; exact m.1 x := by
simp only [getElem?_def, length_mapFinIdx, getElem_mapFinIdx]
split <;> simp
@[simp]
@@ -126,7 +126,8 @@ theorem mapFinIdx_singleton {a : α} {f : Fin 1 → α → β} :
theorem mapFinIdx_eq_enum_map {l : List α} {f : Fin l.length α β} :
l.mapFinIdx f = l.enum.attach.map
fun i, x, m => f i, by rw [mk_mem_enum_iff_getElem?, getElem?_eq_some] at m; exact m.1 x := by
fun i, x, m =>
f i, by rw [mk_mem_enum_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1 x := by
apply ext_getElem <;> simp
@[simp]
@@ -235,16 +236,16 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {arr : Array β} {i : Nat},
(mapIdx.go f l arr)[i]? =
if h : i < arr.size then some arr[i] else Option.map (f i) l[i - arr.size]?
| [], arr, i => by
simp only [mapIdx.go, Array.toListImpl_eq, getElem?_eq, Array.length_toList,
Array.getElem_eq_getElem_toList, length_nil, Nat.not_lt_zero, reduceDIte, Option.map_none']
simp only [mapIdx.go, Array.toListImpl_eq, getElem?_def, Array.length_toList,
Array.getElem_toList, length_nil, Nat.not_lt_zero, reduceDIte, Option.map_none']
| a :: l, arr, i => by
rw [mapIdx.go, getElem?_mapIdx_go]
simp only [Array.size_push]
split <;> split
· simp only [Option.some.injEq]
rw [Array.getElem_eq_getElem_toList]
rw [ Array.getElem_toList]
simp only [Array.push_toList]
rw [getElem_append_left, Array.getElem_eq_getElem_toList]
rw [getElem_append_left, Array.getElem_toList]
· have : i = arr.size := by omega
simp_all
· omega

View File

@@ -85,7 +85,7 @@ theorem min?_eq_some_iff [Min α] [LE α] [anti : Std.Antisymm ((· : α) ≤ ·
cases xs with
| nil => simp at h₁
| cons x xs =>
exact congrArg some <| anti.1
exact congrArg some <| anti.1 _ _
((le_min?_iff le_min_iff (xs := x::xs) rfl).1 (le_refl _) _ h₁)
(h₂ _ (min?_mem min_eq_or (xs := x::xs) rfl))
@@ -156,7 +156,7 @@ theorem max?_eq_some_iff [Max α] [LE α] [anti : Std.Antisymm ((· : α) ≤ ·
cases xs with
| nil => simp at h₁
| cons x xs =>
exact congrArg some <| anti.1
exact congrArg some <| anti.1 _ _
(h₂ _ (max?_mem max_eq_or (xs := x::xs) rfl))
((max?_le_iff max_le_iff (xs := x::xs) rfl).1 (le_refl _) _ h₁)

View File

@@ -124,7 +124,8 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β
/-! ### forM -/
-- We use `List.forM` as the simp normal form, rather that `ForM.forM`.
-- We currently use `List.forM` as the simp normal form, rather that `ForM.forM`.
-- (This should probably be revisited.)
-- As such we need to replace `List.forM_nil` and `List.forM_cons`:
@[simp] theorem forM_nil' [Monad m] : ([] : List α).forM f = (pure .unit : m PUnit) := rfl
@@ -137,6 +138,10 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β
(l₁ ++ l₂).forM f = (do l₁.forM f; l₂.forM f) := by
induction l₁ <;> simp [*]
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (l : List α) (g : α β) (f : β m PUnit) :
(l.map g).forM f = l.forM (fun a => f (g a)) := by
induction l <;> simp [*]
/-! ### forIn' -/
theorem forIn'_loop_congr [Monad m] {as bs : List α}
@@ -259,6 +264,11 @@ theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
generalize l.attach = l'
induction l' generalizing init <;> simp_all
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
(l : List α) (g : α β) (f : (b : β) b l.map g γ m (ForInStep γ)) :
forIn' (l.map g) init f = forIn' l init fun a h y => f (g a) (mem_map_of_mem g h) y := by
induction l generalizing init <;> simp_all
/--
We can express a for loop over a list as a fold,
in which whenever we reach `.done b` we keep that value through the rest of the fold.
@@ -307,6 +317,11 @@ theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
simp only [forIn_eq_foldlM]
induction l generalizing init <;> simp_all
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
(l : List α) (g : α β) (f : β γ m (ForInStep γ)) :
forIn (l.map g) init f = forIn l init fun a y => f (g a) y := by
induction l generalizing init <;> simp_all
/-! ### allM -/
theorem allM_eq_not_anyM_not [Monad m] [LawfulMonad m] (p : α m Bool) (as : List α) :

View File

@@ -15,3 +15,4 @@ import Init.Data.List.Nat.Find
import Init.Data.List.Nat.BEq
import Init.Data.List.Nat.Modify
import Init.Data.List.Nat.InsertIdx
import Init.Data.List.Nat.Perm

View File

@@ -68,8 +68,8 @@ theorem getElem?_modifyHead {l : List α} {f : αα} {n} :
(l.modifyHead f).drop n = l.drop n := by
cases l <;> cases n <;> simp_all
@[simp] theorem eraseIdx_modifyHead_zero {f : α α} {l : List α} :
(l.modifyHead f).eraseIdx 0 = l.eraseIdx 0 := by cases l <;> simp
theorem eraseIdx_modifyHead_zero {f : α α} {l : List α} :
(l.modifyHead f).eraseIdx 0 = l.eraseIdx 0 := by simp
@[simp] theorem eraseIdx_modifyHead_of_pos {f : α α} {l : List α} {n} (h : 0 < n) :
(l.modifyHead f).eraseIdx n = (l.eraseIdx n).modifyHead f := by cases l <;> cases n <;> simp_all
@@ -142,7 +142,7 @@ theorem modifyTailIdx_modifyTailIdx_self {f g : List α → List α} (n : Nat) (
theorem modifyHead_eq_modify_zero (f : α α) (l : List α) :
l.modifyHead f = l.modify f 0 := by cases l <;> simp
@[simp] theorem modify_eq_nil_iff (f : α α) (n) (l : List α) :
@[simp] theorem modify_eq_nil_iff {f : α α} {n} {l : List α} :
l.modify f n = [] l = [] := by cases l <;> cases n <;> simp
theorem getElem?_modify (f : α α) :

View File

@@ -0,0 +1,54 @@
/-
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.List.Nat.TakeDrop
import Init.Data.List.Perm
namespace List
/-- Helper lemma for `set_set_perm`-/
private theorem set_set_perm' {as : List α} {i j : Nat} (h₁ : i < as.length) (h₂ : i + j < as.length)
(hj : 0 < j) :
(as.set i as[i + j]).set (i + j) as[i] ~ as := by
have : as =
as.take i ++ as[i] :: (as.take (i + j)).drop (i + 1) ++ as[i + j] :: as.drop (i + j + 1) := by
simp only [getElem_cons_drop, append_assoc, cons_append]
rw [ drop_append_of_le_length]
· simp
· simp; omega
conv => lhs; congr; congr; rw [this]
conv => rhs; rw [this]
rw [set_append_left _ _ (by simp; omega)]
rw [set_append_right _ _ (by simp; omega)]
rw [set_append_right _ _ (by simp; omega)]
simp only [length_append, length_take, length_set, length_cons, length_drop]
rw [(show i - min i as.length = 0 by omega)]
rw [(show i + j - (min i as.length + (min (i + j) as.length - (i + 1) + 1)) = 0 by omega)]
simp only [set_cons_zero]
simp only [append_assoc]
apply Perm.append_left
apply cons_append_cons_perm
theorem set_set_perm {as : List α} {i j : Nat} (h₁ : i < as.length) (h₂ : j < as.length) :
(as.set i as[j]).set j as[i] ~ as := by
if h₃ : i = j then
simp [h₃]
else
if h₃ : i < j then
let j' := j - i
have t : j = i + j' := by omega
generalize j' = j' at t
subst t
exact set_set_perm' _ _ (by omega)
else
rw [set_comm _ _ _ (by omega)]
let i' := i - j
have t : i = j + i' := by omega
generalize i' = i' at t
subst t
apply set_set_perm' _ _ (by omega)
end List

View File

@@ -345,7 +345,7 @@ theorem drop_append {l₁ l₂ : List α} (i : Nat) : drop (l₁.length + i) (l
rw [drop_append_eq_append_drop, drop_eq_nil_of_le] <;>
simp [Nat.add_sub_cancel_left, Nat.le_add_right]
theorem set_eq_take_append_cons_drop {l : List α} {n : Nat} {a : α} :
theorem set_eq_take_append_cons_drop (l : List α) (n : Nat) (a : α) :
l.set n a = if n < l.length then l.take n ++ a :: l.drop (n + 1) else l := by
split <;> rename_i h
· ext1 m

View File

@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
-/
prelude
import Init.Data.Nat.Div
import Init.Data.Nat.Div.Basic
/-!
# Notation for `List` literals.

View File

@@ -39,6 +39,9 @@ protected theorem Perm.symm {l₁ l₂ : List α} (h : l₁ ~ l₂) : l₂ ~ l
| swap => exact swap ..
| trans _ _ ih₁ ih₂ => exact trans ih₂ ih₁
instance : Trans (Perm (α := α)) (Perm (α := α)) (Perm (α := α)) where
trans h₁ h₂ := Perm.trans h₁ h₂
theorem perm_comm {l₁ l₂ : List α} : l₁ ~ l₂ l₂ ~ l₁ := Perm.symm, Perm.symm
theorem Perm.swap' (x y : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : y :: x :: l₁ ~ x :: y :: l₂ :=
@@ -102,7 +105,7 @@ theorem perm_append_comm : ∀ {l₁ l₂ : List α}, l₁ ++ l₂ ~ l₂ ++ l
| _ :: _, _ => (perm_append_comm.cons _).trans perm_middle.symm
theorem perm_append_comm_assoc (l₁ l₂ l₃ : List α) :
Perm (l₁ ++ (l₂ ++ l₃)) (l₂ ++ (l₁ ++ l₃)) := by
(l₁ ++ (l₂ ++ l₃)) ~ (l₂ ++ (l₁ ++ l₃)) := by
simpa only [List.append_assoc] using perm_append_comm.append_right _
theorem concat_perm (l : List α) (a : α) : concat l a ~ a :: l := by simp
@@ -133,7 +136,7 @@ theorem Perm.nil_eq {l : List α} (p : [] ~ l) : [] = l := p.symm.eq_nil.symm
theorem not_perm_nil_cons (x : α) (l : List α) : ¬[] ~ x :: l := (nomatch ·.symm.eq_nil)
theorem not_perm_cons_nil {l : List α} {a : α} : ¬(Perm (a::l) []) :=
theorem not_perm_cons_nil {l : List α} {a : α} : ¬((a::l) ~ []) :=
fun h => by simpa using h.length_eq
theorem Perm.isEmpty_eq {l l' : List α} (h : Perm l l') : l.isEmpty = l'.isEmpty := by
@@ -478,6 +481,15 @@ theorem Perm.flatten {l₁ l₂ : List (List α)} (h : l₁ ~ l₂) : l₁.flatt
@[deprecated Perm.flatten (since := "2024-10-14")] abbrev Perm.join := @Perm.flatten
theorem cons_append_cons_perm {a b : α} {as bs : List α} :
a :: as ++ b :: bs ~ b :: as ++ a :: bs := by
suffices [[a], as, [b], bs].flatten ~ [[b], as, [a], bs].flatten by simpa
apply Perm.flatten
calc
[[a], as, [b], bs] ~ [as, [a], [b], bs] := Perm.swap as [a] _
_ ~ [as, [b], [a], bs] := Perm.cons _ (Perm.swap [b] [a] _)
_ ~ [[b], as, [a], bs] := Perm.swap [b] as _
theorem Perm.flatMap_right {l₁ l₂ : List α} (f : α List β) (p : l₁ ~ l₂) : l₁.flatMap f ~ l₂.flatMap f :=
(p.map _).flatten

View File

@@ -84,11 +84,15 @@ theorem head?_range' (n : Nat) : (range' s n).head? = if n = 0 then none else so
@[simp] theorem head_range' (n : Nat) (h) : (range' s n).head h = s := by
repeat simp_all [head?_range', head_eq_iff_head?_eq_some]
@[simp]
theorem map_add_range' (a) : s n step, map (a + ·) (range' s n step) = range' (a + s) n step
| _, 0, _ => rfl
| s, n + 1, step => by simp [range', map_add_range' _ (s + step) n step, Nat.add_assoc]
theorem range'_succ_left : range' (s + 1) n step = (range' s n step).map (· + 1) := by
apply ext_getElem
· simp
· simp [Nat.add_right_comm]
theorem range'_append : s m n step : Nat,
range' s m step ++ range' (s + step * m) n step = range' s (n + m) step
| _, 0, _, _ => rfl

View File

@@ -40,12 +40,15 @@ def merge (xs ys : List α) (le : αα → Bool := by exact fun a b => a
/--
Split a list in two equal parts. If the length is odd, the first part will be one element longer.
This is an implementation detail of `mergeSort`.
-/
def splitInTwo (l : { l : List α // l.length = n }) :
def MergeSort.Internal.splitInTwo (l : { l : List α // l.length = n }) :
{ l : List α // l.length = (n+1)/2 } × { l : List α // l.length = n/2 } :=
let r := splitAt ((n+1)/2) l.1
(r.1, by simp [r, splitAt_eq, l.2]; omega, r.2, by simp [r, splitAt_eq, l.2]; omega)
open MergeSort.Internal in
set_option linter.unusedVariables false in
/--
Simplified implementation of stable merge sort.

View File

@@ -147,23 +147,21 @@ where
mergeTR (run' r) (run l) le
theorem splitRevInTwo'_fst (l : { l : List α // l.length = n }) :
(splitRevInTwo' l).1 = (splitInTwo l.1.reverse, by simpa using l.2).2.1, by have := l.2; simp; omega := by
(splitRevInTwo' l).1 = (splitInTwo l.1.reverse, by simpa using l.2).2.1, by simp; omega := by
simp only [splitRevInTwo', splitRevAt_eq, reverse_take, splitInTwo_snd]
congr
have := l.2
omega
theorem splitRevInTwo'_snd (l : { l : List α // l.length = n }) :
(splitRevInTwo' l).2 = (splitInTwo l.1.reverse, by simpa using l.2).1.1.reverse, by have := l.2; simp; omega := by
(splitRevInTwo' l).2 = (splitInTwo l.1.reverse, by simpa using l.2).1.1.reverse, by simp; omega := by
simp only [splitRevInTwo', splitRevAt_eq, reverse_take, splitInTwo_fst, reverse_reverse]
congr 2
have := l.2
simp
omega
theorem splitRevInTwo_fst (l : { l : List α // l.length = n }) :
(splitRevInTwo l).1 = (splitInTwo l).1.1.reverse, by have := l.2; simp; omega := by
(splitRevInTwo l).1 = (splitInTwo l).1.1.reverse, by simp; omega := by
simp only [splitRevInTwo, splitRevAt_eq, reverse_take, splitInTwo_fst]
theorem splitRevInTwo_snd (l : { l : List α // l.length = n }) :
(splitRevInTwo l).2 = (splitInTwo l).2.1, by have := l.2; simp; omega := by
(splitRevInTwo l).2 = (splitInTwo l).2.1, by simp; omega := by
simp only [splitRevInTwo, splitRevAt_eq, reverse_take, splitInTwo_snd]
theorem mergeSortTR_run_eq_mergeSort : {n : Nat} (l : { l : List α // l.length = n }) mergeSortTR.run le l = mergeSort l.1 le

View File

@@ -25,6 +25,8 @@ namespace List
/-! ### splitInTwo -/
namespace MergeSort.Internal
@[simp] theorem splitInTwo_fst (l : { l : List α // l.length = n }) :
(splitInTwo l).1 = l.1.take ((n+1)/2), by simp [splitInTwo, splitAt_eq, l.2]; omega := by
simp [splitInTwo, splitAt_eq]
@@ -82,6 +84,10 @@ theorem splitInTwo_fst_le_splitInTwo_snd {l : { l : List α // l.length = n }} (
intro a b ma mb
exact h.rel_of_mem_take_of_mem_drop ma mb
end MergeSort.Internal
open MergeSort.Internal
/-! ### enumLE -/
variable {le : α α Bool}
@@ -285,15 +291,13 @@ theorem sorted_mergeSort
| [] => by simp [mergeSort]
| [a] => by simp [mergeSort]
| a :: b :: xs => by
have : (splitInTwo a :: b :: xs, rfl).1.1.length < xs.length + 1 + 1 := by simp [splitInTwo_fst]; omega
have : (splitInTwo a :: b :: xs, rfl).2.1.length < xs.length + 1 + 1 := by simp [splitInTwo_snd]; omega
rw [mergeSort]
apply sorted_merge @trans @total
apply sorted_mergeSort trans total
apply sorted_mergeSort trans total
termination_by l => l.length
@[deprecated (since := "2024-09-02")] abbrev mergeSort_sorted := @sorted_mergeSort
@[deprecated sorted_mergeSort (since := "2024-09-02")] abbrev mergeSort_sorted := @sorted_mergeSort
/--
If the input list is already sorted, then `mergeSort` does not change the list.
@@ -429,7 +433,8 @@ theorem sublist_mergeSort
((fun w => Sublist.of_sublist_append_right w h') fun b m₁ m₃ =>
(Bool.eq_not_self true).mp ((rel_of_pairwise_cons hc m₁).symm.trans (h₃ b m₃))))
@[deprecated (since := "2024-09-02")] abbrev mergeSort_stable := @sublist_mergeSort
@[deprecated sublist_mergeSort (since := "2024-09-02")]
abbrev mergeSort_stable := @sublist_mergeSort
/--
Another statement of stability of merge sort.
@@ -442,7 +447,8 @@ theorem pair_sublist_mergeSort
(hab : le a b) (h : [a, b] <+ l) : [a, b] <+ mergeSort l le :=
sublist_mergeSort trans total (pairwise_pair.mpr hab) h
@[deprecated (since := "2024-09-02")] abbrev mergeSort_stable_pair := @pair_sublist_mergeSort
@[deprecated pair_sublist_mergeSort(since := "2024-09-02")]
abbrev mergeSort_stable_pair := @pair_sublist_mergeSort
theorem map_merge {f : α β} {r : α α Bool} {s : β β Bool} {l l' : List α}
(hl : a l, b l', r a b = s (f a) (f b)) :

View File

@@ -835,13 +835,13 @@ theorem isPrefix_iff : l₁ <+: l₂ ↔ ∀ i (h : i < l₁.length), l₂[i]? =
simpa using 0, by simp
| cons b l₂ =>
simp only [cons_append, cons_prefix_cons, ih]
rw (occs := .pos [2]) [ Nat.and_forall_add_one]
rw (occs := [2]) [ Nat.and_forall_add_one]
simp [Nat.succ_lt_succ_iff, eq_comm]
theorem isPrefix_iff_getElem {l₁ l₂ : List α} :
l₁ <+: l₂ (h : l₁.length l₂.length), x (hx : x < l₁.length),
l₁[x] = l₂[x]'(Nat.lt_of_lt_of_le hx h) where
mp h := h.length_le, fun _ _ h.getElem _
mp h := h.length_le, fun _ h' h.getElem h'
mpr h := by
obtain hl, h := h
induction l₂ generalizing l₁ with

View File

@@ -65,13 +65,13 @@ theorem lt_length_of_take_ne_self {l : List α} {n} (h : l.take n ≠ l) : n < l
theorem getElem_cons_drop : (l : List α) (i : Nat) (h : i < l.length),
l[i] :: drop (i + 1) l = drop i l
| _::_, 0, _ => rfl
| _::_, i+1, _ => getElem_cons_drop _ i _
| _::_, i+1, h => getElem_cons_drop _ i (Nat.add_one_lt_add_one_iff.mp h)
@[deprecated getElem_cons_drop (since := "2024-06-12")]
theorem get_cons_drop (l : List α) (i) : get l i :: drop (i + 1) l = drop i l := by
simp
theorem drop_eq_getElem_cons {n} {l : List α} (h) : drop n l = l[n] :: drop (n + 1) l :=
theorem drop_eq_getElem_cons {n} {l : List α} (h : n < l.length) : drop n l = l[n] :: drop (n + 1) l :=
(getElem_cons_drop _ n h).symm
@[deprecated drop_eq_getElem_cons (since := "2024-06-12")]
@@ -192,6 +192,24 @@ theorem take_concat_get (l : List α) (i : Nat) (h : i < l.length) :
Eq.symm <| (append_left_inj _).1 <| (take_append_drop (i+1) l).trans <| by
rw [concat_eq_append, append_assoc, singleton_append, getElem_cons_drop_succ_eq_drop, take_append_drop]
@[simp] theorem take_append_getElem (l : List α) (i : Nat) (h : i < l.length) :
(l.take i) ++ [l[i]] = l.take (i+1) := by
simpa using take_concat_get l i h
@[simp] theorem take_append_getLast (l : List α) (h : l []) :
(l.take (l.length - 1)) ++ [l.getLast h] = l := by
rw [getLast_eq_getElem]
cases l
· contradiction
· simp
@[simp] theorem take_append_getLast? (l : List α) :
(l.take (l.length - 1)) ++ l.getLast?.toList = l := by
match l with
| [] => simp
| x :: xs =>
simpa using take_append_getLast (x :: xs) (by simp)
@[deprecated take_succ_cons (since := "2024-07-25")]
theorem take_cons_succ : (a::as).take (i+1) = a :: as.take i := rfl
@@ -224,7 +242,7 @@ theorem take_succ {l : List α} {n : Nat} : l.take (n + 1) = l.take n ++ l[n]?.t
· simp only [take, Option.toList, getElem?_cons_zero, nil_append]
· simp only [take, hl, getElem?_cons_succ, cons_append]
@[deprecated (since := "2024-07-25")]
@[deprecated "Deprecated without replacement." (since := "2024-07-25")]
theorem drop_sizeOf_le [SizeOf α] (l : List α) (n : Nat) : sizeOf (l.drop n) sizeOf l := by
induction l generalizing n with
| nil => rw [drop_nil]; apply Nat.le_refl

View File

@@ -1,23 +1,397 @@
/-
Copyright (c) 2024 Lean FRO. All rights reserved.
Copyright (c) 2022 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Henrik Böving
Authors: Mario Carneiro
-/
prelude
import Init.Data.List.Basic
import Init.Data.List.Impl
import Init.Data.List.Nat.Erase
import Init.Data.List.Monadic
import Init.Data.Array.Lex.Basic
/--
Auxiliary definition for `List.toArray`.
`List.toArrayAux as r = r ++ as.toArray`
/-! ### Lemmas about `List.toArray`.
We prefer to pull `List.toArray` outwards past `Array` operations.
-/
@[inline_if_reduce]
def List.toArrayAux : List α Array α Array α
| nil, r => r
| cons a as, r => toArrayAux as (r.push a)
namespace List
/-- Convert a `List α` into an `Array α`. This is O(n) in the length of the list. -/
-- This function is exported to C, where it is called by `Array.mk`
-- (the constructor) to implement this functionality.
@[inline, match_pattern, pp_nodot, export lean_list_to_array]
def List.toArrayImpl (as : List α) : Array α :=
as.toArrayAux (Array.mkEmpty as.length)
open Array
theorem toArray_inj {a b : List α} (h : a.toArray = b.toArray) : a = b := by
cases a with
| nil => simpa using h
| cons a as =>
cases b with
| nil => simp at h
| cons b bs => simpa using h
@[simp] theorem size_toArrayAux {a : List α} {b : Array α} :
(a.toArrayAux b).size = b.size + a.length := by
simp [size]
-- This is not a `@[simp]` lemma because it is pushing `toArray` inwards.
theorem toArray_cons (a : α) (l : List α) : (a :: l).toArray = #[a] ++ l.toArray := by
apply ext'
simp
@[simp] theorem push_toArray (l : List α) (a : α) : l.toArray.push a = (l ++ [a]).toArray := by
apply ext'
simp
/-- Unapplied variant of `push_toArray`, useful for monadic reasoning. -/
@[simp] theorem push_toArray_fun (l : List α) : l.toArray.push = fun a => (l ++ [a]).toArray := by
funext a
simp
@[simp] theorem isEmpty_toArray (l : List α) : l.toArray.isEmpty = l.isEmpty := by
cases l <;> simp [Array.isEmpty]
@[simp] theorem toArray_singleton (a : α) : (List.singleton a).toArray = singleton a := rfl
@[simp] theorem back!_toArray [Inhabited α] (l : List α) : l.toArray.back! = l.getLast! := by
simp only [back!, size_toArray, Array.get!_eq_getElem!, getElem!_toArray, getLast!_eq_getElem!]
@[simp] theorem back?_toArray (l : List α) : l.toArray.back? = l.getLast? := by
simp [back?, List.getLast?_eq_getElem?]
@[simp] theorem set_toArray (l : List α) (i : Nat) (a : α) (h : i < l.length) :
(l.toArray.set i a) = (l.set i a).toArray := rfl
@[simp] theorem forIn'_loop_toArray [Monad m] (l : List α) (f : (a : α) a l.toArray β m (ForInStep β)) (i : Nat)
(h : i l.length) (b : β) :
Array.forIn'.loop l.toArray f i h b =
forIn' (l.drop (l.length - i)) b (fun a m b => f a (by simpa using mem_of_mem_drop m) b) := by
induction i generalizing l b with
| zero =>
simp [Array.forIn'.loop]
| succ i ih =>
simp only [Array.forIn'.loop, size_toArray, getElem_toArray, ih]
have t : drop (l.length - (i + 1)) l = l[l.length - i - 1] :: drop (l.length - i) l := by
simp only [Nat.sub_add_eq]
rw [List.drop_sub_one (by omega), List.getElem?_eq_getElem (by omega)]
simp only [Option.toList_some, singleton_append]
simp [t]
have t : l.length - 1 - i = l.length - i - 1 := by omega
simp only [t]
congr
@[simp] theorem forIn'_toArray [Monad m] (l : List α) (b : β) (f : (a : α) a l.toArray β m (ForInStep β)) :
forIn' l.toArray b f = forIn' l b (fun a m b => f a (mem_toArray.mpr m) b) := by
change Array.forIn' _ _ _ = List.forIn' _ _ _
rw [Array.forIn', forIn'_loop_toArray]
simp
@[simp] theorem forIn_toArray [Monad m] (l : List α) (b : β) (f : α β m (ForInStep β)) :
forIn l.toArray b f = forIn l b f := by
simpa using forIn'_toArray l b fun a m b => f a b
theorem foldrM_toArray [Monad m] (f : α β m β) (init : β) (l : List α) :
l.toArray.foldrM f init = l.foldrM f init := by
rw [foldrM_eq_reverse_foldlM_toList]
simp
theorem foldlM_toArray [Monad m] (f : β α m β) (init : β) (l : List α) :
l.toArray.foldlM f init = l.foldlM f init := by
rw [foldlM_toList]
theorem foldr_toArray (f : α β β) (init : β) (l : List α) :
l.toArray.foldr f init = l.foldr f init := by
rw [foldr_toList]
theorem foldl_toArray (f : β α β) (init : β) (l : List α) :
l.toArray.foldl f init = l.foldl f init := by
rw [foldl_toList]
/-- Variant of `foldrM_toArray` with a side condition for the `start` argument. -/
@[simp] theorem foldrM_toArray' [Monad m] (f : α β m β) (init : β) (l : List α)
(h : start = l.toArray.size) :
l.toArray.foldrM f init start 0 = l.foldrM f init := by
subst h
rw [foldrM_eq_reverse_foldlM_toList]
simp
/-- Variant of `foldlM_toArray` with a side condition for the `stop` argument. -/
@[simp] theorem foldlM_toArray' [Monad m] (f : β α m β) (init : β) (l : List α)
(h : stop = l.toArray.size) :
l.toArray.foldlM f init 0 stop = l.foldlM f init := by
subst h
rw [foldlM_toList]
/-- Variant of `forM_toArray` with a side condition for the `stop` argument. -/
@[simp] theorem forM_toArray' [Monad m] (l : List α) (f : α m PUnit) (h : stop = l.toArray.size) :
(l.toArray.forM f 0 stop) = l.forM f := by
subst h
rw [Array.forM]
simp only [size_toArray, foldlM_toArray']
induction l <;> simp_all
theorem forM_toArray [Monad m] (l : List α) (f : α m PUnit) :
(l.toArray.forM f) = l.forM f := by
simp
/-- Variant of `foldr_toArray` with a side condition for the `start` argument. -/
@[simp] theorem foldr_toArray' (f : α β β) (init : β) (l : List α)
(h : start = l.toArray.size) :
l.toArray.foldr f init start 0 = l.foldr f init := by
subst h
rw [foldr_toList]
/-- Variant of `foldl_toArray` with a side condition for the `stop` argument. -/
@[simp] theorem foldl_toArray' (f : β α β) (init : β) (l : List α)
(h : stop = l.toArray.size) :
l.toArray.foldl f init 0 stop = l.foldl f init := by
subst h
rw [foldl_toList]
@[simp] theorem append_toArray (l₁ l₂ : List α) :
l₁.toArray ++ l₂.toArray = (l₁ ++ l₂).toArray := by
apply ext'
simp
@[simp] theorem push_append_toArray {as : Array α} {a : α} {bs : List α} : as.push a ++ bs.toArray = as ++ (a ::bs).toArray := by
cases as
simp
@[simp] theorem foldl_push {l : List α} {as : Array α} : l.foldl Array.push as = as ++ l.toArray := by
induction l generalizing as <;> simp [*]
@[simp] theorem foldr_push {l : List α} {as : Array α} : l.foldr (fun a b => push b a) as = as ++ l.reverse.toArray := by
rw [foldr_eq_foldl_reverse, foldl_push]
@[simp] theorem findSomeM?_toArray [Monad m] [LawfulMonad m] (f : α m (Option β)) (l : List α) :
l.toArray.findSomeM? f = l.findSomeM? f := by
rw [Array.findSomeM?]
simp only [bind_pure_comp, map_pure, forIn_toArray]
induction l with
| nil => simp
| cons a l ih =>
simp only [forIn_cons, LawfulMonad.bind_assoc, findSomeM?]
congr
ext1 (_|_) <;> simp [ih]
theorem findSomeRevM?_find_toArray [Monad m] [LawfulMonad m] (f : α m (Option β)) (l : List α)
(i : Nat) (h) :
findSomeRevM?.find f l.toArray i h = (l.take i).reverse.findSomeM? f := by
induction i generalizing l with
| zero => simp [Array.findSomeRevM?.find.eq_def]
| succ i ih =>
rw [size_toArray] at h
rw [Array.findSomeRevM?.find, take_succ, getElem?_eq_getElem (by omega)]
simp only [ih, reverse_append]
congr
ext1 (_|_) <;> simp
-- This is not marked as `@[simp]` as later we simplify all occurrences of `findSomeRevM?`.
theorem findSomeRevM?_toArray [Monad m] [LawfulMonad m] (f : α m (Option β)) (l : List α) :
l.toArray.findSomeRevM? f = l.reverse.findSomeM? f := by
simp [Array.findSomeRevM?, findSomeRevM?_find_toArray]
-- This is not marked as `@[simp]` as later we simplify all occurrences of `findRevM?`.
theorem findRevM?_toArray [Monad m] [LawfulMonad m] (f : α m Bool) (l : List α) :
l.toArray.findRevM? f = l.reverse.findM? f := by
rw [Array.findRevM?, findSomeRevM?_toArray, findM?_eq_findSomeM?]
@[simp] theorem findM?_toArray [Monad m] [LawfulMonad m] (f : α m Bool) (l : List α) :
l.toArray.findM? f = l.findM? f := by
rw [Array.findM?]
simp only [bind_pure_comp, map_pure, forIn_toArray]
induction l with
| nil => simp
| cons a l ih =>
simp only [forIn_cons, LawfulMonad.bind_assoc, findM?]
congr
ext1 (_|_) <;> simp [ih]
@[simp] theorem findSome?_toArray (f : α Option β) (l : List α) :
l.toArray.findSome? f = l.findSome? f := by
rw [Array.findSome?, findSomeM?_id, findSomeM?_toArray, Id.run]
@[simp] theorem find?_toArray (f : α Bool) (l : List α) :
l.toArray.find? f = l.find? f := by
rw [Array.find?]
simp only [Id.run, Id, Id.pure_eq, Id.bind_eq, forIn_toArray]
induction l with
| nil => simp
| cons a l ih =>
simp only [forIn_cons, Id.pure_eq, Id.bind_eq, find?]
by_cases f a <;> simp_all
theorem isPrefixOfAux_toArray_succ [BEq α] (l₁ l₂ : List α) (hle : l₁.length l₂.length) (i : Nat) :
Array.isPrefixOfAux l₁.toArray l₂.toArray hle (i + 1) =
Array.isPrefixOfAux l₁.tail.toArray l₂.tail.toArray (by simp; omega) i := by
rw [Array.isPrefixOfAux]
conv => rhs; rw [Array.isPrefixOfAux]
simp only [size_toArray, getElem_toArray, Bool.if_false_right, length_tail, getElem_tail]
split <;> rename_i h₁ <;> split <;> rename_i h₂
· rw [isPrefixOfAux_toArray_succ]
· omega
· omega
· rfl
theorem isPrefixOfAux_toArray_succ' [BEq α] (l₁ l₂ : List α) (hle : l₁.length l₂.length) (i : Nat) :
Array.isPrefixOfAux l₁.toArray l₂.toArray hle (i + 1) =
Array.isPrefixOfAux (l₁.drop (i+1)).toArray (l₂.drop (i+1)).toArray (by simp; omega) 0 := by
induction i generalizing l₁ l₂ with
| zero => simp [isPrefixOfAux_toArray_succ]
| succ i ih =>
rw [isPrefixOfAux_toArray_succ, ih]
simp
theorem isPrefixOfAux_toArray_zero [BEq α] (l₁ l₂ : List α) (hle : l₁.length l₂.length) :
Array.isPrefixOfAux l₁.toArray l₂.toArray hle 0 =
l₁.isPrefixOf l₂ := by
rw [Array.isPrefixOfAux]
match l₁, l₂ with
| [], _ => rw [dif_neg] <;> simp
| _::_, [] => simp at hle
| a::l₁, b::l₂ =>
simp [isPrefixOf_cons₂, isPrefixOfAux_toArray_succ', isPrefixOfAux_toArray_zero]
@[simp] theorem isPrefixOf_toArray [BEq α] (l₁ l₂ : List α) :
l₁.toArray.isPrefixOf l₂.toArray = l₁.isPrefixOf l₂ := by
rw [Array.isPrefixOf]
split <;> rename_i h
· simp [isPrefixOfAux_toArray_zero]
· simp only [Bool.false_eq]
induction l₁ generalizing l₂ with
| nil => simp at h
| cons a l₁ ih =>
cases l₂ with
| nil => simp
| cons b l₂ =>
simp only [isPrefixOf_cons₂, Bool.and_eq_false_imp]
intro w
rw [ih]
simp_all
theorem zipWithAux_toArray_succ (as : List α) (bs : List β) (f : α β γ) (i : Nat) (cs : Array γ) :
zipWithAux as.toArray bs.toArray f (i + 1) cs = zipWithAux as.tail.toArray bs.tail.toArray f i cs := by
rw [zipWithAux]
conv => rhs; rw [zipWithAux]
simp only [size_toArray, getElem_toArray, length_tail, getElem_tail]
split <;> rename_i h₁
· split <;> rename_i h₂
· rw [dif_pos (by omega), dif_pos (by omega), zipWithAux_toArray_succ]
· rw [dif_pos (by omega)]
rw [dif_neg (by omega)]
· rw [dif_neg (by omega)]
theorem zipWithAux_toArray_succ' (as : List α) (bs : List β) (f : α β γ) (i : Nat) (cs : Array γ) :
zipWithAux as.toArray bs.toArray f (i + 1) cs = zipWithAux (as.drop (i+1)).toArray (bs.drop (i+1)).toArray f 0 cs := by
induction i generalizing as bs cs with
| zero => simp [zipWithAux_toArray_succ]
| succ i ih =>
rw [zipWithAux_toArray_succ, ih]
simp
theorem zipWithAux_toArray_zero (f : α β γ) (as : List α) (bs : List β) (cs : Array γ) :
zipWithAux as.toArray bs.toArray f 0 cs = cs ++ (List.zipWith f as bs).toArray := by
rw [Array.zipWithAux]
match as, bs with
| [], _ => simp
| _, [] => simp
| a :: as, b :: bs =>
simp [zipWith_cons_cons, zipWithAux_toArray_succ', zipWithAux_toArray_zero, push_append_toArray]
@[simp] theorem zipWith_toArray (as : List α) (bs : List β) (f : α β γ) :
Array.zipWith as.toArray bs.toArray f = (List.zipWith f as bs).toArray := by
rw [Array.zipWith]
simp [zipWithAux_toArray_zero]
@[simp] theorem zip_toArray (as : List α) (bs : List β) :
Array.zip as.toArray bs.toArray = (List.zip as bs).toArray := by
simp [Array.zip, zipWith_toArray, zip]
theorem zipWithAll_go_toArray (as : List α) (bs : List β) (f : Option α Option β γ) (i : Nat) (cs : Array γ) :
zipWithAll.go f as.toArray bs.toArray i cs = cs ++ (List.zipWithAll f (as.drop i) (bs.drop i)).toArray := by
unfold zipWithAll.go
split <;> rename_i h
· rw [zipWithAll_go_toArray]
simp at h
simp only [getElem?_toArray, push_append_toArray]
if ha : i < as.length then
if hb : i < bs.length then
rw [List.drop_eq_getElem_cons ha, List.drop_eq_getElem_cons hb]
simp only [ha, hb, getElem?_eq_getElem, zipWithAll_cons_cons]
else
simp only [Nat.not_lt] at hb
rw [List.drop_eq_getElem_cons ha]
rw [(drop_eq_nil_iff (l := bs)).mpr (by omega), (drop_eq_nil_iff (l := bs)).mpr (by omega)]
simp only [zipWithAll_nil, map_drop, map_cons]
rw [getElem?_eq_getElem ha]
rw [getElem?_eq_none hb]
else
if hb : i < bs.length then
simp only [Nat.not_lt] at ha
rw [List.drop_eq_getElem_cons hb]
rw [(drop_eq_nil_iff (l := as)).mpr (by omega), (drop_eq_nil_iff (l := as)).mpr (by omega)]
simp only [nil_zipWithAll, map_drop, map_cons]
rw [getElem?_eq_getElem hb]
rw [getElem?_eq_none ha]
else
omega
· simp only [size_toArray, Nat.not_lt] at h
rw [drop_eq_nil_of_le (by omega), drop_eq_nil_of_le (by omega)]
simp
termination_by max as.length bs.length - i
decreasing_by simp_wf; decreasing_trivial_pre_omega
@[simp] theorem zipWithAll_toArray (f : Option α Option β γ) (as : List α) (bs : List β) :
Array.zipWithAll as.toArray bs.toArray f = (List.zipWithAll f as bs).toArray := by
simp [Array.zipWithAll, zipWithAll_go_toArray]
@[simp] theorem toArray_appendList (l₁ l₂ : List α) :
l₁.toArray ++ l₂ = (l₁ ++ l₂).toArray := by
apply ext'
simp
@[simp] theorem pop_toArray (l : List α) : l.toArray.pop = l.dropLast.toArray := by
apply ext'
simp
theorem takeWhile_go_succ (p : α Bool) (a : α) (l : List α) (i : Nat) :
takeWhile.go p (a :: l).toArray (i+1) r = takeWhile.go p l.toArray i r := by
rw [takeWhile.go, takeWhile.go]
simp only [size_toArray, length_cons, Nat.add_lt_add_iff_right, Array.get_eq_getElem,
getElem_toArray, getElem_cons_succ]
split
rw [takeWhile_go_succ]
rfl
theorem takeWhile_go_toArray (p : α Bool) (l : List α) (i : Nat) :
Array.takeWhile.go p l.toArray i r = r ++ (takeWhile p (l.drop i)).toArray := by
induction l generalizing i r with
| nil => simp [takeWhile.go]
| cons a l ih =>
rw [takeWhile.go]
cases i with
| zero =>
simp [takeWhile_go_succ, ih, takeWhile_cons]
split <;> simp
| succ i =>
simp only [size_toArray, length_cons, Nat.add_lt_add_iff_right, Array.get_eq_getElem,
getElem_toArray, getElem_cons_succ, drop_succ_cons]
split <;> rename_i h₁
· rw [takeWhile_go_succ, ih]
rw [ getElem_cons_drop_succ_eq_drop h₁, takeWhile_cons]
split <;> simp_all
· simp_all [drop_eq_nil_of_le]
@[simp] theorem takeWhile_toArray (p : α Bool) (l : List α) :
l.toArray.takeWhile p = (l.takeWhile p).toArray := by
simp [Array.takeWhile, takeWhile_go_toArray]
@[simp] theorem setIfInBounds_toArray (l : List α) (i : Nat) (a : α) :
l.toArray.setIfInBounds i a = (l.set i a).toArray := by
apply ext'
simp only [setIfInBounds]
split
· simp
· simp_all [List.set_eq_of_length_le]
@[simp] theorem toArray_replicate (n : Nat) (v : α) : (List.replicate n v).toArray = mkArray n v := rfl
@[deprecated toArray_replicate (since := "2024-12-13")]
abbrev _root_.Array.mkArray_eq_toArray_replicate := @toArray_replicate
end List

View File

@@ -0,0 +1,23 @@
/-
Copyright (c) 2024 Lean FRO. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Henrik Böving
-/
prelude
import Init.Data.List.Basic
/--
Auxiliary definition for `List.toArray`.
`List.toArrayAux as r = r ++ as.toArray`
-/
@[inline_if_reduce]
def List.toArrayAux : List α Array α Array α
| nil, r => r
| cons a as, r => toArrayAux as (r.push a)
/-- Convert a `List α` into an `Array α`. This is O(n) in the length of the list. -/
-- This function is exported to C, where it is called by `Array.mk`
-- (the constructor) to implement this functionality.
@[inline, match_pattern, pp_nodot, export lean_list_to_array]
def List.toArrayImpl (as : List α) : Array α :=
as.toArrayAux (Array.mkEmpty as.length)

View File

@@ -5,7 +5,7 @@ Authors: Leonardo de Moura
-/
prelude
import Init.Data.Nat.Basic
import Init.Data.Nat.Div
import Init.Data.Nat.Div.Basic
import Init.Data.Nat.Dvd
import Init.Data.Nat.Gcd
import Init.Data.Nat.MinMax

View File

@@ -445,10 +445,10 @@ protected theorem le_antisymm_iff {a b : Nat} : a = b ↔ a ≤ b ∧ b ≤ a :=
protected theorem eq_iff_le_and_ge : {a b : Nat}, a = b a b b a := @Nat.le_antisymm_iff
instance : Std.Antisymm ( . . : Nat Nat Prop) where
antisymm h₁ h₂ := Nat.le_antisymm h₁ h₂
antisymm _ _ h₁ h₂ := Nat.le_antisymm h₁ h₂
instance : Std.Antisymm (¬ . < . : Nat Nat Prop) where
antisymm h₁ h₂ := Nat.le_antisymm (Nat.ge_of_not_lt h₂) (Nat.ge_of_not_lt h₁)
antisymm _ _ h₁ h₂ := Nat.le_antisymm (Nat.ge_of_not_lt h₂) (Nat.ge_of_not_lt h₁)
protected theorem add_le_add_left {n m : Nat} (h : n m) (k : Nat) : k + n k + m :=
match le.dest h with
@@ -789,7 +789,7 @@ theorem pred_lt_of_lt {n m : Nat} (h : m < n) : pred n < n :=
pred_lt (not_eq_zero_of_lt h)
set_option linter.missingDocs false in
@[deprecated (since := "2024-06-01")] abbrev pred_lt' := @pred_lt_of_lt
@[deprecated pred_lt_of_lt (since := "2024-06-01")] abbrev pred_lt' := @pred_lt_of_lt
theorem sub_one_lt_of_lt {n m : Nat} (h : m < n) : n - 1 < n :=
sub_one_lt (not_eq_zero_of_lt h)
@@ -1075,7 +1075,7 @@ theorem pred_mul (n m : Nat) : pred n * m = n * m - m := by
| succ n => rw [Nat.pred_succ, succ_mul, Nat.add_sub_cancel]
set_option linter.missingDocs false in
@[deprecated (since := "2024-06-01")] abbrev mul_pred_left := @pred_mul
@[deprecated pred_mul (since := "2024-06-01")] abbrev mul_pred_left := @pred_mul
protected theorem sub_one_mul (n m : Nat) : (n - 1) * m = n * m - m := by
cases n with
@@ -1087,7 +1087,7 @@ theorem mul_pred (n m : Nat) : n * pred m = n * m - n := by
rw [Nat.mul_comm, pred_mul, Nat.mul_comm]
set_option linter.missingDocs false in
@[deprecated (since := "2024-06-01")] abbrev mul_pred_right := @mul_pred
@[deprecated mul_pred (since := "2024-06-01")] abbrev mul_pred_right := @mul_pred
theorem mul_sub_one (n m : Nat) : n * (m - 1) = n * m - n := by
rw [Nat.mul_comm, Nat.sub_one_mul , Nat.mul_comm]

View File

@@ -5,7 +5,7 @@ Authors: Leonardo de Moura
-/
prelude
import Init.Data.Nat.Basic
import Init.Data.Nat.Div
import Init.Data.Nat.Div.Basic
import Init.Coe
namespace Nat
@@ -71,6 +71,9 @@ theorem shiftRight_eq_div_pow (m : Nat) : ∀ n, m >>> n = m / 2 ^ n
rw [shiftRight_add, shiftRight_eq_div_pow m k]
simp [Nat.div_div_eq_div_mul, Nat.pow_succ, shiftRight_succ]
theorem shiftRight_eq_zero (m n : Nat) (hn : m < 2^n) : m >>> n = 0 := by
simp [Nat.shiftRight_eq_div_pow, Nat.div_eq_of_lt hn]
/-!
### testBit
We define an operation for testing individual bits in the binary representation

View File

@@ -106,9 +106,21 @@ theorem testBit_add_one (x i : Nat) : testBit x (i + 1) = testBit (x/2) i := by
unfold testBit
simp [shiftRight_succ_inside]
theorem testBit_add (x i n : Nat) : testBit x (i + n) = testBit (x / 2 ^ n) i := by
revert x
induction n with
| zero => simp
| succ n ih =>
intro x
rw [ Nat.add_assoc, testBit_add_one, ih (x / 2),
Nat.pow_succ, Nat.div_div_eq_div_mul, Nat.mul_comm]
theorem testBit_div_two (x i : Nat) : testBit (x / 2) i = testBit x (i + 1) := by
simp
theorem testBit_div_two_pow (x i : Nat) : testBit (x / 2 ^ n) i = testBit x (i + n) :=
testBit_add .. |>.symm
theorem testBit_to_div_mod {x : Nat} : testBit x i = decide (x / 2^i % 2 = 1) := by
induction i generalizing x with
| zero =>
@@ -365,7 +377,7 @@ theorem testBit_two_pow_of_ne {n m : Nat} (hm : n ≠ m) : testBit (2 ^ n) m = f
/-! ### bitwise -/
theorem testBit_bitwise (false_false_axiom : f false false = false) (x y i : Nat) :
theorem testBit_bitwise (of_false_false : f false false = false) (x y i : Nat) :
(bitwise f x y).testBit i = f (x.testBit i) (y.testBit i) := by
induction i using Nat.strongRecOn generalizing x y with
| ind i hyp =>
@@ -373,12 +385,12 @@ theorem testBit_bitwise (false_false_axiom : f false false = false) (x y i : Nat
if x_zero : x = 0 then
cases p : f false true <;>
cases yi : testBit y i <;>
simp [x_zero, p, yi, false_false_axiom]
simp [x_zero, p, yi, of_false_false]
else if y_zero : y = 0 then
simp [x_zero, y_zero]
cases p : f true false <;>
cases xi : testBit x i <;>
simp [p, xi, false_false_axiom]
simp [p, xi, of_false_false]
else
simp only [x_zero, y_zero, Nat.two_mul]
cases i with
@@ -440,6 +452,11 @@ theorem bitwise_lt_two_pow (left : x < 2^n) (right : y < 2^n) : (Nat.bitwise f x
case neg =>
apply Nat.add_lt_add <;> exact hyp1
theorem bitwise_div_two_pow (of_false_false : f false false = false := by rfl) :
(bitwise f x y) / 2 ^ n = bitwise f (x / 2 ^ n) (y / 2 ^ n) := by
apply Nat.eq_of_testBit_eq
simp [testBit_bitwise of_false_false, testBit_div_two_pow]
/-! ### and -/
@[simp] theorem testBit_and (x y i : Nat) : (x &&& y).testBit i = (x.testBit i && y.testBit i) := by
@@ -495,9 +512,11 @@ theorem and_pow_two_sub_one_of_lt_two_pow {x : Nat} (lt : x < 2^n) : x &&& 2^n -
rw [testBit_and]
simp
theorem and_div_two : (a &&& b) / 2 = a / 2 &&& b / 2 := by
apply Nat.eq_of_testBit_eq
simp [testBit_and, testBit_add_one]
theorem and_div_two_pow : (a &&& b) / 2 ^ n = a / 2 ^ n &&& b / 2 ^ n :=
bitwise_div_two_pow
theorem and_div_two : (a &&& b) / 2 = a / 2 &&& b / 2 :=
and_div_two_pow (n := 1)
/-! ### lor -/
@@ -563,9 +582,11 @@ theorem or_lt_two_pow {x y n : Nat} (left : x < 2^n) (right : y < 2^n) : x ||| y
rw [testBit_or]
simp
theorem or_div_two : (a ||| b) / 2 = a / 2 ||| b / 2 := by
apply Nat.eq_of_testBit_eq
simp [testBit_or, testBit_add_one]
theorem or_div_two_pow : (a ||| b) / 2 ^ n = a / 2 ^ n ||| b / 2 ^ n :=
bitwise_div_two_pow
theorem or_div_two : (a ||| b) / 2 = a / 2 ||| b / 2 :=
or_div_two_pow (n := 1)
/-! ### xor -/
@@ -619,9 +640,11 @@ theorem and_xor_distrib_left {a b c : Nat} : a &&& (b ^^^ c) = (a &&& b) ^^^ (a
rw [testBit_xor]
simp
theorem xor_div_two : (a ^^^ b) / 2 = a / 2 ^^^ b / 2 := by
apply Nat.eq_of_testBit_eq
simp [testBit_xor, testBit_add_one]
theorem xor_div_two_pow : (a ^^^ b) / 2 ^ n = a / 2 ^ n ^^^ b / 2 ^ n :=
bitwise_div_two_pow
theorem xor_div_two : (a ^^^ b) / 2 = a / 2 ^^^ b / 2 :=
xor_div_two_pow (n := 1)
/-! ### Arithmetic -/
@@ -693,6 +716,19 @@ theorem mul_add_lt_is_or {b : Nat} (b_lt : b < 2^i) (a : Nat) : 2^i * a + b = 2^
simp only [testBit, one_and_eq_mod_two, mod_two_bne_zero]
exact (Bool.beq_eq_decide_eq _ _).symm
theorem shiftRight_bitwise_distrib {a b : Nat} (of_false_false : f false false = false := by rfl) :
(bitwise f a b) >>> i = bitwise f (a >>> i) (b >>> i) := by
simp [shiftRight_eq_div_pow, bitwise_div_two_pow of_false_false]
theorem shiftRight_and_distrib {a b : Nat} : (a &&& b) >>> i = a >>> i &&& b >>> i :=
shiftRight_bitwise_distrib
theorem shiftRight_or_distrib {a b : Nat} : (a ||| b) >>> i = a >>> i ||| b >>> i :=
shiftRight_bitwise_distrib
theorem shiftRight_xor_distrib {a b : Nat} : (a ^^^ b) >>> i = a >>> i ^^^ b >>> i :=
shiftRight_bitwise_distrib
/-! ### le -/
theorem le_of_testBit {n m : Nat} (h : i, n.testBit i = true m.testBit i = true) : n m := by

View File

@@ -1,418 +1,8 @@
/-
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
Authors: Kim Morrison
-/
prelude
import Init.WF
import Init.WFTactics
import Init.Data.Nat.Basic
namespace Nat
/--
Divisibility of natural numbers. `a b` (typed as `\|`) says that
there is some `c` such that `b = a * c`.
-/
instance : Dvd Nat where
dvd a b := Exists (fun c => b = a * c)
theorem div_rec_lemma {x y : Nat} : 0 < y y x x - y < x :=
fun ypos, ylex => sub_lt (Nat.lt_of_lt_of_le ypos ylex) ypos
@[extern "lean_nat_div"]
protected def div (x y : @& Nat) : Nat :=
if 0 < y y x then
Nat.div (x - y) y + 1
else
0
decreasing_by apply div_rec_lemma; assumption
instance instDiv : Div Nat := Nat.div
theorem div_eq (x y : Nat) : x / y = if 0 < y y x then (x - y) / y + 1 else 0 := by
show Nat.div x y = _
rw [Nat.div]
rfl
def div.inductionOn.{u}
{motive : Nat Nat Sort u}
(x y : Nat)
(ind : x y, 0 < y y x motive (x - y) y motive x y)
(base : x y, ¬(0 < y y x) motive x y)
: motive x y :=
if h : 0 < y y x then
ind x y h (inductionOn (x - y) y ind base)
else
base x y h
decreasing_by apply div_rec_lemma; assumption
theorem div_le_self (n k : Nat) : n / k n := by
induction n using Nat.strongRecOn with
| ind n ih =>
rw [div_eq]
-- Note: manual split to avoid Classical.em which is not yet defined
cases (inferInstance : Decidable (0 < k k n)) with
| isFalse h => simp [h]
| isTrue h =>
suffices (n - k) / k + 1 n by simp [h, this]
have hK, hKN := h
have hSub : n - k < n := sub_lt (Nat.lt_of_lt_of_le hK hKN) hK
have : (n - k) / k n - k := ih (n - k) hSub
exact succ_le_of_lt (Nat.lt_of_le_of_lt this hSub)
theorem div_lt_self {n k : Nat} (hLtN : 0 < n) (hLtK : 1 < k) : n / k < n := by
rw [div_eq]
cases (inferInstance : Decidable (0 < k k n)) with
| isFalse h => simp [hLtN, h]
| isTrue h =>
suffices (n - k) / k + 1 < n by simp [h, this]
have _, hKN := h
have : (n - k) / k n - k := div_le_self (n - k) k
have := Nat.add_le_of_le_sub hKN this
exact Nat.lt_of_lt_of_le (Nat.add_lt_add_left hLtK _) this
@[extern "lean_nat_mod"]
protected def modCore (x y : @& Nat) : Nat :=
if 0 < y y x then
Nat.modCore (x - y) y
else
x
decreasing_by apply div_rec_lemma; assumption
@[extern "lean_nat_mod"]
protected def mod : @& Nat @& Nat Nat
/-
Nat.modCore is defined by well-founded recursion and thus irreducible. Nevertheless it is
desirable if trivial `Nat.mod` calculations, namely
* `Nat.mod 0 m` for all `m`
* `Nat.mod n (m+n)` for concrete literals `n`
reduce definitionally.
This property is desirable for `Fin n` literals, as it means `(ofNat 0 : Fin n).val = 0` by
definition.
-/
| 0, _ => 0
| n@(_ + 1), m =>
if m n -- NB: if n < m does not reduce as well as `m ≤ n`!
then Nat.modCore n m
else n
instance instMod : Mod Nat := Nat.mod
protected theorem modCore_eq_mod (n m : Nat) : Nat.modCore n m = n % m := by
show Nat.modCore n m = Nat.mod n m
match n, m with
| 0, _ =>
rw [Nat.modCore]
exact if_neg fun hlt, hle => Nat.lt_irrefl _ (Nat.lt_of_lt_of_le hlt hle)
| (_ + 1), _ =>
rw [Nat.mod]; dsimp
refine iteInduction (fun _ => rfl) (fun h => ?false) -- cannot use `split` this early yet
rw [Nat.modCore]
exact if_neg fun _hlt, hle => h hle
theorem mod_eq (x y : Nat) : x % y = if 0 < y y x then (x - y) % y else x := by
rw [Nat.modCore_eq_mod, Nat.modCore_eq_mod, Nat.modCore]
def mod.inductionOn.{u}
{motive : Nat Nat Sort u}
(x y : Nat)
(ind : x y, 0 < y y x motive (x - y) y motive x y)
(base : x y, ¬(0 < y y x) motive x y)
: motive x y :=
div.inductionOn x y ind base
@[simp] theorem mod_zero (a : Nat) : a % 0 = a :=
have : (if 0 < 0 0 a then (a - 0) % 0 else a) = a :=
have h : ¬ (0 < 0 0 a) := fun h₁, _ => absurd h₁ (Nat.lt_irrefl _)
if_neg h
(mod_eq a 0).symm this
theorem mod_eq_of_lt {a b : Nat} (h : a < b) : a % b = a :=
have : (if 0 < b b a then (a - b) % b else a) = a :=
have h' : ¬(0 < b b a) := fun _, h₁ => absurd h₁ (Nat.not_le_of_gt h)
if_neg h'
(mod_eq a b).symm this
@[simp] theorem one_mod_eq_zero_iff {n : Nat} : 1 % n = 0 n = 1 := by
match n with
| 0 => simp
| 1 => simp
| n + 2 =>
rw [mod_eq_of_lt (by exact Nat.lt_of_sub_eq_succ rfl)]
simp only [add_one_ne_zero, false_iff, ne_eq]
exact ne_of_beq_eq_false rfl
@[simp] theorem Nat.zero_eq_one_mod_iff {n : Nat} : 0 = 1 % n n = 1 := by
rw [eq_comm]
simp
theorem mod_eq_sub_mod {a b : Nat} (h : a b) : a % b = (a - b) % b :=
match eq_zero_or_pos b with
| Or.inl h₁ => h₁.symm (Nat.sub_zero a).symm rfl
| Or.inr h₁ => (mod_eq a b).symm if_pos h₁, h
theorem mod_lt (x : Nat) {y : Nat} : y > 0 x % y < y := by
induction x, y using mod.inductionOn with
| base x y h₁ =>
intro h₂
have h₁ : ¬ 0 < y ¬ y x := Decidable.not_and_iff_or_not.mp h₁
match h₁ with
| Or.inl h₁ => exact absurd h₂ h₁
| Or.inr h₁ =>
have hgt : y > x := gt_of_not_le h₁
have heq : x % y = x := mod_eq_of_lt hgt
rw [ heq] at hgt
exact hgt
| ind x y h h₂ =>
intro h₃
have _, h₁ := h
rw [mod_eq_sub_mod h₁]
exact h₂ h₃
@[simp] protected theorem sub_mod_add_mod_cancel (a b : Nat) [NeZero a] : a - b % a + b % a = a := by
rw [Nat.sub_add_cancel]
cases a with
| zero => simp_all
| succ a =>
exact Nat.le_of_lt (mod_lt b (zero_lt_succ a))
theorem mod_le (x y : Nat) : x % y x := by
match Nat.lt_or_ge x y with
| Or.inl h₁ => rw [mod_eq_of_lt h₁]; apply Nat.le_refl
| Or.inr h₁ => match eq_zero_or_pos y with
| Or.inl h₂ => rw [h₂, Nat.mod_zero x]; apply Nat.le_refl
| Or.inr h₂ => exact Nat.le_trans (Nat.le_of_lt (mod_lt _ h₂)) h₁
@[simp] theorem zero_mod (b : Nat) : 0 % b = 0 := by
rw [mod_eq]
have : ¬ (0 < b b = 0) := by
intro h₁, h₂
simp_all
simp [this]
@[simp] theorem mod_self (n : Nat) : n % n = 0 := by
rw [mod_eq_sub_mod (Nat.le_refl _), Nat.sub_self, zero_mod]
theorem mod_one (x : Nat) : x % 1 = 0 := by
have h : x % 1 < 1 := mod_lt x (by decide)
have : (y : Nat) y < 1 y = 0 := by
intro y
cases y with
| zero => intro _; rfl
| succ y => intro h; apply absurd (Nat.lt_of_succ_lt_succ h) (Nat.not_lt_zero y)
exact this _ h
theorem div_add_mod (m n : Nat) : n * (m / n) + m % n = m := by
rw [div_eq, mod_eq]
have h : Decidable (0 < n n m) := inferInstance
cases h with
| isFalse h => simp [h]
| isTrue h =>
simp [h]
have ih := div_add_mod (m - n) n
rw [Nat.left_distrib, Nat.mul_one, Nat.add_assoc, Nat.add_left_comm, ih, Nat.add_comm, Nat.sub_add_cancel h.2]
decreasing_by apply div_rec_lemma; assumption
theorem div_eq_sub_div (h₁ : 0 < b) (h₂ : b a) : a / b = (a - b) / b + 1 := by
rw [div_eq a, if_pos]; constructor <;> assumption
theorem mod_add_div (m k : Nat) : m % k + k * (m / k) = m := by
induction m, k using mod.inductionOn with rw [div_eq, mod_eq]
| base x y h => simp [h]
| ind x y h IH => simp [h]; rw [Nat.mul_succ, Nat.add_assoc, IH, Nat.sub_add_cancel h.2]
theorem mod_def (m k : Nat) : m % k = m - k * (m / k) := by
rw [Nat.sub_eq_of_eq_add]
apply (Nat.mod_add_div _ _).symm
@[simp] protected theorem div_one (n : Nat) : n / 1 = n := by
have := mod_add_div n 1
rwa [mod_one, Nat.zero_add, Nat.one_mul] at this
@[simp] protected theorem div_zero (n : Nat) : n / 0 = 0 := by
rw [div_eq]; simp [Nat.lt_irrefl]
@[simp] protected theorem zero_div (b : Nat) : 0 / b = 0 :=
(div_eq 0 b).trans <| if_neg <| And.rec Nat.not_le_of_gt
theorem le_div_iff_mul_le (k0 : 0 < k) : x y / k x * k y := by
induction y, k using mod.inductionOn generalizing x with
(rw [div_eq]; simp [h]; cases x with | zero => simp [zero_le] | succ x => ?_)
| base y k h =>
simp only [add_one, succ_mul, false_iff, Nat.not_le, Nat.succ_ne_zero]
refine Nat.lt_of_lt_of_le ?_ (Nat.le_add_left ..)
exact Nat.not_le.1 fun h' => h k0, h'
| ind y k h IH =>
rw [Nat.add_le_add_iff_right, IH k0, succ_mul,
Nat.add_sub_cancel (x*k) k, Nat.sub_le_sub_iff_right h.2, Nat.add_sub_cancel]
protected theorem div_div_eq_div_mul (m n k : Nat) : m / n / k = m / (n * k) := by
cases eq_zero_or_pos k with
| inl k0 => rw [k0, Nat.mul_zero, Nat.div_zero, Nat.div_zero] | inr kpos => ?_
cases eq_zero_or_pos n with
| inl n0 => rw [n0, Nat.zero_mul, Nat.div_zero, Nat.zero_div] | inr npos => ?_
apply Nat.le_antisymm
apply (le_div_iff_mul_le (Nat.mul_pos npos kpos)).2
rw [Nat.mul_comm n k, Nat.mul_assoc]
apply (le_div_iff_mul_le npos).1
apply (le_div_iff_mul_le kpos).1
(apply Nat.le_refl)
apply (le_div_iff_mul_le kpos).2
apply (le_div_iff_mul_le npos).2
rw [Nat.mul_assoc, Nat.mul_comm n k]
apply (le_div_iff_mul_le (Nat.mul_pos kpos npos)).1
apply Nat.le_refl
theorem div_mul_le_self : (m n : Nat), m / n * n m
| m, 0 => by simp
| _, _+1 => (le_div_iff_mul_le (Nat.succ_pos _)).1 (Nat.le_refl _)
theorem div_lt_iff_lt_mul (Hk : 0 < k) : x / k < y x < y * k := by
rw [ Nat.not_le, Nat.not_le]; exact not_congr (le_div_iff_mul_le Hk)
@[simp] theorem add_div_right (x : Nat) {z : Nat} (H : 0 < z) : (x + z) / z = (x / z) + 1 := by
rw [div_eq_sub_div H (Nat.le_add_left _ _), Nat.add_sub_cancel]
@[simp] theorem add_div_left (x : Nat) {z : Nat} (H : 0 < z) : (z + x) / z = (x / z) + 1 := by
rw [Nat.add_comm, add_div_right x H]
theorem add_mul_div_left (x z : Nat) {y : Nat} (H : 0 < y) : (x + y * z) / y = x / y + z := by
induction z with
| zero => rw [Nat.mul_zero, Nat.add_zero, Nat.add_zero]
| succ z ih => rw [mul_succ, Nat.add_assoc, add_div_right _ H, ih]; rfl
theorem add_mul_div_right (x y : Nat) {z : Nat} (H : 0 < z) : (x + y * z) / z = x / z + y := by
rw [Nat.mul_comm, add_mul_div_left _ _ H]
@[simp] theorem add_mod_right (x z : Nat) : (x + z) % z = x % z := by
rw [mod_eq_sub_mod (Nat.le_add_left ..), Nat.add_sub_cancel]
@[simp] theorem add_mod_left (x z : Nat) : (x + z) % x = z % x := by
rw [Nat.add_comm, add_mod_right]
@[simp] theorem add_mul_mod_self_left (x y z : Nat) : (x + y * z) % y = x % y := by
match z with
| 0 => rw [Nat.mul_zero, Nat.add_zero]
| succ z => rw [mul_succ, Nat.add_assoc, add_mod_right, add_mul_mod_self_left (z := z)]
@[simp] theorem add_mul_mod_self_right (x y z : Nat) : (x + y * z) % z = x % z := by
rw [Nat.mul_comm, add_mul_mod_self_left]
@[simp] theorem mul_mod_right (m n : Nat) : (m * n) % m = 0 := by
rw [ Nat.zero_add (m * n), add_mul_mod_self_left, zero_mod]
@[simp] theorem mul_mod_left (m n : Nat) : (m * n) % n = 0 := by
rw [Nat.mul_comm, mul_mod_right]
protected theorem div_eq_of_lt_le (lo : k * n m) (hi : m < (k + 1) * n) : m / n = k :=
have npos : 0 < n := (eq_zero_or_pos _).resolve_left fun hn => by
rw [hn, Nat.mul_zero] at hi lo; exact absurd lo (Nat.not_le_of_gt hi)
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
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
| zero => rw [Nat.mul_zero, Nat.sub_zero, Nat.sub_zero]
| succ p IH =>
have h₂ : n * p x := Nat.le_trans (Nat.mul_le_mul_left _ (le_succ _)) h₁
have h₃ : x - n * p n := by
apply Nat.le_of_add_le_add_right
rw [Nat.sub_add_cancel h₂, Nat.add_comm]
rw [mul_succ] at h₁
exact h₁
rw [sub_succ, IH h₂, div_eq_sub_div h₀ h₃]
simp [Nat.pred_succ, mul_succ, Nat.sub_sub]
theorem mul_sub_div (x n p : Nat) (h₁ : x < n*p) : (n * p - (x + 1)) / n = p - ((x / n) + 1) := by
have npos : 0 < n := (eq_zero_or_pos _).resolve_left fun n0 => by
rw [n0, Nat.zero_mul] at h₁; exact not_lt_zero _ h₁
apply Nat.div_eq_of_lt_le
focus
rw [Nat.mul_sub_right_distrib, Nat.mul_comm]
exact Nat.sub_le_sub_left ((div_lt_iff_lt_mul npos).1 (lt_succ_self _)) _
focus
show succ (pred (n * p - x)) (succ (pred (p - x / n))) * n
rw [succ_pred_eq_of_pos (Nat.sub_pos_of_lt h₁),
fun h => succ_pred_eq_of_pos (Nat.sub_pos_of_lt h)] -- TODO: why is the function needed?
focus
rw [Nat.mul_sub_right_distrib, Nat.mul_comm]
exact Nat.sub_le_sub_left (div_mul_le_self ..) _
focus
rwa [div_lt_iff_lt_mul npos, Nat.mul_comm]
theorem mul_mod_mul_left (z x y : Nat) : (z * x) % (z * y) = z * (x % y) :=
if y0 : y = 0 then by
rw [y0, Nat.mul_zero, mod_zero, mod_zero]
else if z0 : z = 0 then by
rw [z0, Nat.zero_mul, Nat.zero_mul, Nat.zero_mul, mod_zero]
else by
induction x using Nat.strongRecOn with
| _ n IH =>
have y0 : y > 0 := Nat.pos_of_ne_zero y0
have z0 : z > 0 := Nat.pos_of_ne_zero z0
cases Nat.lt_or_ge n y with
| inl yn => rw [mod_eq_of_lt yn, mod_eq_of_lt (Nat.mul_lt_mul_of_pos_left yn z0)]
| inr yn =>
rw [mod_eq_sub_mod yn, mod_eq_sub_mod (Nat.mul_le_mul_left z yn),
Nat.mul_sub_left_distrib]
exact IH _ (sub_lt (Nat.lt_of_lt_of_le y0 yn) y0)
theorem div_eq_of_lt (h₀ : a < b) : a / b = 0 := by
rw [div_eq a, if_neg]
intro h₁
apply Nat.not_le_of_gt h₀ h₁.right
protected theorem mul_div_cancel (m : Nat) {n : Nat} (H : 0 < n) : m * n / n = m := by
let t := add_mul_div_right 0 m H
rwa [Nat.zero_add, Nat.zero_div, Nat.zero_add] at t
protected theorem mul_div_cancel_left (m : Nat) {n : Nat} (H : 0 < n) : n * m / n = m := by
rw [Nat.mul_comm, Nat.mul_div_cancel _ H]
protected theorem div_le_of_le_mul {m n : Nat} : {k}, m k * n m / k n
| 0, _ => by simp [Nat.div_zero, n.zero_le]
| succ k, h => by
suffices succ k * (m / succ k) succ k * n from
Nat.le_of_mul_le_mul_left this (zero_lt_succ _)
have h1 : succ k * (m / succ k) m % succ k + succ k * (m / succ k) := Nat.le_add_left _ _
have h2 : m % succ k + succ k * (m / succ k) = m := by rw [mod_add_div]
have h3 : m succ k * n := h
rw [ h2] at h3
exact Nat.le_trans h1 h3
@[simp] theorem mul_div_right (n : Nat) {m : Nat} (H : 0 < m) : m * n / m = n := by
induction n <;> simp_all [mul_succ]
@[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
let t := add_div_right 0 H
rwa [Nat.zero_add, Nat.zero_div] at t
protected theorem div_eq_of_eq_mul_left (H1 : 0 < n) (H2 : m = k * n) : m / n = k :=
by rw [H2, Nat.mul_div_cancel _ H1]
protected theorem div_eq_of_eq_mul_right (H1 : 0 < n) (H2 : m = n * k) : m / n = k :=
by rw [H2, Nat.mul_div_cancel_left _ H1]
protected theorem mul_div_mul_left {m : Nat} (n k : Nat) (H : 0 < m) :
m * n / (m * k) = n / k := by rw [ Nat.div_div_eq_div_mul, Nat.mul_div_cancel_left _ H]
protected theorem mul_div_mul_right {m : Nat} (n k : Nat) (H : 0 < m) :
n * m / (k * m) = n / k := by rw [Nat.mul_comm, Nat.mul_comm k, Nat.mul_div_mul_left _ _ H]
theorem mul_div_le (m n : Nat) : n * (m / n) m := by
match n, Nat.eq_zero_or_pos n with
| _, Or.inl rfl => rw [Nat.zero_mul]; exact m.zero_le
| n, Or.inr h => rw [Nat.mul_comm, Nat.le_div_iff_mul_le h]; exact Nat.le_refl _
end Nat
import Init.Data.Nat.Div.Basic
import Init.Data.Nat.Div.Lemmas

View File

@@ -0,0 +1,437 @@
/-
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Init.WF
import Init.WFTactics
import Init.Data.Nat.Basic
namespace Nat
/--
Divisibility of natural numbers. `a b` (typed as `\|`) says that
there is some `c` such that `b = a * c`.
-/
instance : Dvd Nat where
dvd a b := Exists (fun c => b = a * c)
theorem div_rec_lemma {x y : Nat} : 0 < y y x x - y < x :=
fun ypos, ylex => sub_lt (Nat.lt_of_lt_of_le ypos ylex) ypos
@[extern "lean_nat_div"]
protected def div (x y : @& Nat) : Nat :=
if 0 < y y x then
Nat.div (x - y) y + 1
else
0
decreasing_by apply div_rec_lemma; assumption
instance instDiv : Div Nat := Nat.div
theorem div_eq (x y : Nat) : x / y = if 0 < y y x then (x - y) / y + 1 else 0 := by
show Nat.div x y = _
rw [Nat.div]
rfl
def div.inductionOn.{u}
{motive : Nat Nat Sort u}
(x y : Nat)
(ind : x y, 0 < y y x motive (x - y) y motive x y)
(base : x y, ¬(0 < y y x) motive x y)
: motive x y :=
if h : 0 < y y x then
ind x y h (inductionOn (x - y) y ind base)
else
base x y h
decreasing_by apply div_rec_lemma; assumption
theorem div_le_self (n k : Nat) : n / k n := by
induction n using Nat.strongRecOn with
| ind n ih =>
rw [div_eq]
-- Note: manual split to avoid Classical.em which is not yet defined
cases (inferInstance : Decidable (0 < k k n)) with
| isFalse h => simp [h]
| isTrue h =>
suffices (n - k) / k + 1 n by simp [h, this]
have hK, hKN := h
have hSub : n - k < n := sub_lt (Nat.lt_of_lt_of_le hK hKN) hK
have : (n - k) / k n - k := ih (n - k) hSub
exact succ_le_of_lt (Nat.lt_of_le_of_lt this hSub)
theorem div_lt_self {n k : Nat} (hLtN : 0 < n) (hLtK : 1 < k) : n / k < n := by
rw [div_eq]
cases (inferInstance : Decidable (0 < k k n)) with
| isFalse h => simp [hLtN, h]
| isTrue h =>
suffices (n - k) / k + 1 < n by simp [h, this]
have _, hKN := h
have : (n - k) / k n - k := div_le_self (n - k) k
have := Nat.add_le_of_le_sub hKN this
exact Nat.lt_of_lt_of_le (Nat.add_lt_add_left hLtK _) this
@[extern "lean_nat_mod"]
protected def modCore (x y : @& Nat) : Nat :=
if 0 < y y x then
Nat.modCore (x - y) y
else
x
decreasing_by apply div_rec_lemma; assumption
@[extern "lean_nat_mod"]
protected def mod : @& Nat @& Nat Nat
/-
Nat.modCore is defined by well-founded recursion and thus irreducible. Nevertheless it is
desirable if trivial `Nat.mod` calculations, namely
* `Nat.mod 0 m` for all `m`
* `Nat.mod n (m+n)` for concrete literals `n`
reduce definitionally.
This property is desirable for `Fin n` literals, as it means `(ofNat 0 : Fin n).val = 0` by
definition.
-/
| 0, _ => 0
| n@(_ + 1), m =>
if m n -- NB: if n < m does not reduce as well as `m ≤ n`!
then Nat.modCore n m
else n
instance instMod : Mod Nat := Nat.mod
protected theorem modCore_eq_mod (n m : Nat) : Nat.modCore n m = n % m := by
show Nat.modCore n m = Nat.mod n m
match n, m with
| 0, _ =>
rw [Nat.modCore]
exact if_neg fun hlt, hle => Nat.lt_irrefl _ (Nat.lt_of_lt_of_le hlt hle)
| (_ + 1), _ =>
rw [Nat.mod]; dsimp
refine iteInduction (fun _ => rfl) (fun h => ?false) -- cannot use `split` this early yet
rw [Nat.modCore]
exact if_neg fun _hlt, hle => h hle
theorem mod_eq (x y : Nat) : x % y = if 0 < y y x then (x - y) % y else x := by
rw [Nat.modCore_eq_mod, Nat.modCore_eq_mod, Nat.modCore]
def mod.inductionOn.{u}
{motive : Nat Nat Sort u}
(x y : Nat)
(ind : x y, 0 < y y x motive (x - y) y motive x y)
(base : x y, ¬(0 < y y x) motive x y)
: motive x y :=
div.inductionOn x y ind base
@[simp] theorem mod_zero (a : Nat) : a % 0 = a :=
have : (if 0 < 0 0 a then (a - 0) % 0 else a) = a :=
have h : ¬ (0 < 0 0 a) := fun h₁, _ => absurd h₁ (Nat.lt_irrefl _)
if_neg h
(mod_eq a 0).symm this
theorem mod_eq_of_lt {a b : Nat} (h : a < b) : a % b = a :=
have : (if 0 < b b a then (a - b) % b else a) = a :=
have h' : ¬(0 < b b a) := fun _, h₁ => absurd h₁ (Nat.not_le_of_gt h)
if_neg h'
(mod_eq a b).symm this
@[simp] theorem one_mod_eq_zero_iff {n : Nat} : 1 % n = 0 n = 1 := by
match n with
| 0 => simp
| 1 => simp
| n + 2 =>
rw [mod_eq_of_lt (by exact Nat.lt_of_sub_eq_succ rfl)]
simp only [add_one_ne_zero, false_iff, ne_eq]
exact ne_of_beq_eq_false rfl
@[simp] theorem Nat.zero_eq_one_mod_iff {n : Nat} : 0 = 1 % n n = 1 := by
rw [eq_comm]
simp
theorem mod_eq_sub_mod {a b : Nat} (h : a b) : a % b = (a - b) % b :=
match eq_zero_or_pos b with
| Or.inl h₁ => h₁.symm (Nat.sub_zero a).symm rfl
| Or.inr h₁ => (mod_eq a b).symm if_pos h₁, h
theorem mod_lt (x : Nat) {y : Nat} : y > 0 x % y < y := by
induction x, y using mod.inductionOn with
| base x y h₁ =>
intro h₂
have h₁ : ¬ 0 < y ¬ y x := Decidable.not_and_iff_or_not.mp h₁
match h₁ with
| Or.inl h₁ => exact absurd h₂ h₁
| Or.inr h₁ =>
have hgt : y > x := gt_of_not_le h₁
have heq : x % y = x := mod_eq_of_lt hgt
rw [ heq] at hgt
exact hgt
| ind x y h h₂ =>
intro h₃
have _, h₁ := h
rw [mod_eq_sub_mod h₁]
exact h₂ h₃
@[simp] protected theorem sub_mod_add_mod_cancel (a b : Nat) [NeZero a] : a - b % a + b % a = a := by
rw [Nat.sub_add_cancel]
cases a with
| zero => simp_all
| succ a =>
exact Nat.le_of_lt (mod_lt b (zero_lt_succ a))
theorem mod_le (x y : Nat) : x % y x := by
match Nat.lt_or_ge x y with
| Or.inl h₁ => rw [mod_eq_of_lt h₁]; apply Nat.le_refl
| Or.inr h₁ => match eq_zero_or_pos y with
| Or.inl h₂ => rw [h₂, Nat.mod_zero x]; apply Nat.le_refl
| Or.inr h₂ => exact Nat.le_trans (Nat.le_of_lt (mod_lt _ h₂)) h₁
@[simp] theorem zero_mod (b : Nat) : 0 % b = 0 := by
rw [mod_eq]
have : ¬ (0 < b b = 0) := by
intro h₁, h₂
simp_all
simp [this]
@[simp] theorem mod_self (n : Nat) : n % n = 0 := by
rw [mod_eq_sub_mod (Nat.le_refl _), Nat.sub_self, zero_mod]
theorem mod_one (x : Nat) : x % 1 = 0 := by
have h : x % 1 < 1 := mod_lt x (by decide)
have : (y : Nat) y < 1 y = 0 := by
intro y
cases y with
| zero => intro _; rfl
| succ y => intro h; apply absurd (Nat.lt_of_succ_lt_succ h) (Nat.not_lt_zero y)
exact this _ h
theorem div_add_mod (m n : Nat) : n * (m / n) + m % n = m := by
rw [div_eq, mod_eq]
have h : Decidable (0 < n n m) := inferInstance
cases h with
| isFalse h => simp [h]
| isTrue h =>
simp [h]
have ih := div_add_mod (m - n) n
rw [Nat.left_distrib, Nat.mul_one, Nat.add_assoc, Nat.add_left_comm, ih, Nat.add_comm, Nat.sub_add_cancel h.2]
decreasing_by apply div_rec_lemma; assumption
theorem div_eq_sub_div (h₁ : 0 < b) (h₂ : b a) : a / b = (a - b) / b + 1 := by
rw [div_eq a, if_pos]; constructor <;> assumption
theorem mod_add_div (m k : Nat) : m % k + k * (m / k) = m := by
induction m, k using mod.inductionOn with rw [div_eq, mod_eq]
| base x y h => simp [h]
| ind x y h IH => simp [h]; rw [Nat.mul_succ, Nat.add_assoc, IH, Nat.sub_add_cancel h.2]
theorem mod_def (m k : Nat) : m % k = m - k * (m / k) := by
rw [Nat.sub_eq_of_eq_add]
apply (Nat.mod_add_div _ _).symm
theorem mod_eq_sub_mul_div {x k : Nat} : x % k = x - k * (x / k) := mod_def _ _
theorem mod_eq_sub_div_mul {x k : Nat} : x % k = x - (x / k) * k := by
rw [mod_eq_sub_mul_div, Nat.mul_comm]
@[simp] protected theorem div_one (n : Nat) : n / 1 = n := by
have := mod_add_div n 1
rwa [mod_one, Nat.zero_add, Nat.one_mul] at this
@[simp] protected theorem div_zero (n : Nat) : n / 0 = 0 := by
rw [div_eq]; simp [Nat.lt_irrefl]
@[simp] protected theorem zero_div (b : Nat) : 0 / b = 0 :=
(div_eq 0 b).trans <| if_neg <| And.rec Nat.not_le_of_gt
theorem le_div_iff_mul_le (k0 : 0 < k) : x y / k x * k y := by
induction y, k using mod.inductionOn generalizing x with
(rw [div_eq]; simp [h]; cases x with | zero => simp [zero_le] | succ x => ?_)
| base y k h =>
simp only [add_one, succ_mul, false_iff, Nat.not_le, Nat.succ_ne_zero]
refine Nat.lt_of_lt_of_le ?_ (Nat.le_add_left ..)
exact Nat.not_le.1 fun h' => h k0, h'
| ind y k h IH =>
rw [Nat.add_le_add_iff_right, IH k0, succ_mul,
Nat.add_sub_cancel (x*k) k, Nat.sub_le_sub_iff_right h.2, Nat.add_sub_cancel]
protected theorem div_div_eq_div_mul (m n k : Nat) : m / n / k = m / (n * k) := by
cases eq_zero_or_pos k with
| inl k0 => rw [k0, Nat.mul_zero, Nat.div_zero, Nat.div_zero] | inr kpos => ?_
cases eq_zero_or_pos n with
| inl n0 => rw [n0, Nat.zero_mul, Nat.div_zero, Nat.zero_div] | inr npos => ?_
apply Nat.le_antisymm
apply (le_div_iff_mul_le (Nat.mul_pos npos kpos)).2
rw [Nat.mul_comm n k, Nat.mul_assoc]
apply (le_div_iff_mul_le npos).1
apply (le_div_iff_mul_le kpos).1
(apply Nat.le_refl)
apply (le_div_iff_mul_le kpos).2
apply (le_div_iff_mul_le npos).2
rw [Nat.mul_assoc, Nat.mul_comm n k]
apply (le_div_iff_mul_le (Nat.mul_pos kpos npos)).1
apply Nat.le_refl
theorem div_mul_le_self : (m n : Nat), m / n * n m
| m, 0 => by simp
| _, _+1 => (le_div_iff_mul_le (Nat.succ_pos _)).1 (Nat.le_refl _)
theorem div_lt_iff_lt_mul (Hk : 0 < k) : x / k < y x < y * k := by
rw [ Nat.not_le, Nat.not_le]; exact not_congr (le_div_iff_mul_le Hk)
theorem pos_of_div_pos {a b : Nat} (h : 0 < a / b) : 0 < a := by
cases b with
| zero => simp at h
| succ b =>
match a, h with
| 0, h => simp at h
| a + 1, _ => exact zero_lt_succ a
@[simp] theorem add_div_right (x : Nat) {z : Nat} (H : 0 < z) : (x + z) / z = (x / z) + 1 := by
rw [div_eq_sub_div H (Nat.le_add_left _ _), Nat.add_sub_cancel]
@[simp] theorem add_div_left (x : Nat) {z : Nat} (H : 0 < z) : (z + x) / z = (x / z) + 1 := by
rw [Nat.add_comm, add_div_right x H]
theorem add_mul_div_left (x z : Nat) {y : Nat} (H : 0 < y) : (x + y * z) / y = x / y + z := by
induction z with
| zero => rw [Nat.mul_zero, Nat.add_zero, Nat.add_zero]
| succ z ih => rw [mul_succ, Nat.add_assoc, add_div_right _ H, ih]; rfl
theorem add_mul_div_right (x y : Nat) {z : Nat} (H : 0 < z) : (x + y * z) / z = x / z + y := by
rw [Nat.mul_comm, add_mul_div_left _ _ H]
@[simp] theorem add_mod_right (x z : Nat) : (x + z) % z = x % z := by
rw [mod_eq_sub_mod (Nat.le_add_left ..), Nat.add_sub_cancel]
@[simp] theorem add_mod_left (x z : Nat) : (x + z) % x = z % x := by
rw [Nat.add_comm, add_mod_right]
@[simp] theorem add_mul_mod_self_left (x y z : Nat) : (x + y * z) % y = x % y := by
match z with
| 0 => rw [Nat.mul_zero, Nat.add_zero]
| succ z => rw [mul_succ, Nat.add_assoc, add_mod_right, add_mul_mod_self_left (z := z)]
@[simp] theorem mul_add_mod_self_left (a b c : Nat) : (a * b + c) % a = c % a := by
rw [Nat.add_comm, Nat.add_mul_mod_self_left]
@[simp] theorem add_mul_mod_self_right (x y z : Nat) : (x + y * z) % z = x % z := by
rw [Nat.mul_comm, add_mul_mod_self_left]
@[simp] theorem mul_add_mod_self_right (a b c : Nat) : (a * b + c) % b = c % b := by
rw [Nat.add_comm, Nat.add_mul_mod_self_right]
@[simp] theorem mul_mod_right (m n : Nat) : (m * n) % m = 0 := by
rw [ Nat.zero_add (m * n), add_mul_mod_self_left, zero_mod]
@[simp] theorem mul_mod_left (m n : Nat) : (m * n) % n = 0 := by
rw [Nat.mul_comm, mul_mod_right]
protected theorem div_eq_of_lt_le (lo : k * n m) (hi : m < (k + 1) * n) : m / n = k :=
have npos : 0 < n := (eq_zero_or_pos _).resolve_left fun hn => by
rw [hn, Nat.mul_zero] at hi lo; exact absurd lo (Nat.not_le_of_gt hi)
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
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
| zero => rw [Nat.mul_zero, Nat.sub_zero, Nat.sub_zero]
| succ p IH =>
have h₂ : n * p x := Nat.le_trans (Nat.mul_le_mul_left _ (le_succ _)) h₁
have h₃ : x - n * p n := by
apply Nat.le_of_add_le_add_right
rw [Nat.sub_add_cancel h₂, Nat.add_comm]
rw [mul_succ] at h₁
exact h₁
rw [sub_succ, IH h₂, div_eq_sub_div h₀ h₃]
simp [Nat.pred_succ, mul_succ, Nat.sub_sub]
theorem mul_sub_div (x n p : Nat) (h₁ : x < n*p) : (n * p - (x + 1)) / n = p - ((x / n) + 1) := by
have npos : 0 < n := (eq_zero_or_pos _).resolve_left fun n0 => by
rw [n0, Nat.zero_mul] at h₁; exact not_lt_zero _ h₁
apply Nat.div_eq_of_lt_le
focus
rw [Nat.mul_sub_right_distrib, Nat.mul_comm]
exact Nat.sub_le_sub_left ((div_lt_iff_lt_mul npos).1 (lt_succ_self _)) _
focus
show succ (pred (n * p - x)) (succ (pred (p - x / n))) * n
rw [succ_pred_eq_of_pos (Nat.sub_pos_of_lt h₁),
fun h => succ_pred_eq_of_pos (Nat.sub_pos_of_lt h)] -- TODO: why is the function needed?
focus
rw [Nat.mul_sub_right_distrib, Nat.mul_comm]
exact Nat.sub_le_sub_left (div_mul_le_self ..) _
focus
rwa [div_lt_iff_lt_mul npos, Nat.mul_comm]
theorem mul_mod_mul_left (z x y : Nat) : (z * x) % (z * y) = z * (x % y) :=
if y0 : y = 0 then by
rw [y0, Nat.mul_zero, mod_zero, mod_zero]
else if z0 : z = 0 then by
rw [z0, Nat.zero_mul, Nat.zero_mul, Nat.zero_mul, mod_zero]
else by
induction x using Nat.strongRecOn with
| _ n IH =>
have y0 : y > 0 := Nat.pos_of_ne_zero y0
have z0 : z > 0 := Nat.pos_of_ne_zero z0
cases Nat.lt_or_ge n y with
| inl yn => rw [mod_eq_of_lt yn, mod_eq_of_lt (Nat.mul_lt_mul_of_pos_left yn z0)]
| inr yn =>
rw [mod_eq_sub_mod yn, mod_eq_sub_mod (Nat.mul_le_mul_left z yn),
Nat.mul_sub_left_distrib]
exact IH _ (sub_lt (Nat.lt_of_lt_of_le y0 yn) y0)
theorem div_eq_of_lt (h₀ : a < b) : a / b = 0 := by
rw [div_eq a, if_neg]
intro h₁
apply Nat.not_le_of_gt h₀ h₁.right
protected theorem mul_div_cancel (m : Nat) {n : Nat} (H : 0 < n) : m * n / n = m := by
let t := add_mul_div_right 0 m H
rwa [Nat.zero_add, Nat.zero_div, Nat.zero_add] at t
protected theorem mul_div_cancel_left (m : Nat) {n : Nat} (H : 0 < n) : n * m / n = m := by
rw [Nat.mul_comm, Nat.mul_div_cancel _ H]
protected theorem div_le_of_le_mul {m n : Nat} : {k}, m k * n m / k n
| 0, _ => by simp [Nat.div_zero, n.zero_le]
| succ k, h => by
suffices succ k * (m / succ k) succ k * n from
Nat.le_of_mul_le_mul_left this (zero_lt_succ _)
have h1 : succ k * (m / succ k) m % succ k + succ k * (m / succ k) := Nat.le_add_left _ _
have h2 : m % succ k + succ k * (m / succ k) = m := by rw [mod_add_div]
have h3 : m succ k * n := h
rw [ h2] at h3
exact Nat.le_trans h1 h3
@[simp] theorem mul_div_right (n : Nat) {m : Nat} (H : 0 < m) : m * n / m = n := by
induction n <;> simp_all [mul_succ]
@[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
let t := add_div_right 0 H
rwa [Nat.zero_add, Nat.zero_div] at t
protected theorem div_eq_of_eq_mul_left (H1 : 0 < n) (H2 : m = k * n) : m / n = k :=
by rw [H2, Nat.mul_div_cancel _ H1]
protected theorem div_eq_of_eq_mul_right (H1 : 0 < n) (H2 : m = n * k) : m / n = k :=
by rw [H2, Nat.mul_div_cancel_left _ H1]
protected theorem mul_div_mul_left {m : Nat} (n k : Nat) (H : 0 < m) :
m * n / (m * k) = n / k := by rw [ Nat.div_div_eq_div_mul, Nat.mul_div_cancel_left _ H]
protected theorem mul_div_mul_right {m : Nat} (n k : Nat) (H : 0 < m) :
n * m / (k * m) = n / k := by rw [Nat.mul_comm, Nat.mul_comm k, Nat.mul_div_mul_left _ _ H]
theorem mul_div_le (m n : Nat) : n * (m / n) m := by
match n, Nat.eq_zero_or_pos n with
| _, Or.inl rfl => rw [Nat.zero_mul]; exact m.zero_le
| n, Or.inr h => rw [Nat.mul_comm, Nat.le_div_iff_mul_le h]; exact Nat.le_refl _
end Nat

View File

@@ -0,0 +1,52 @@
/-
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.Omega
import Init.Data.Nat.Lemmas
/-!
# Further lemmas about `Nat.div` and `Nat.mod`, with the convenience of having `omega` available.
-/
namespace Nat
theorem lt_div_iff_mul_lt (h : 0 < k) : x < y / k x * k < y - (k - 1) := by
have t := le_div_iff_mul_le h (x := x + 1) (y := y)
rw [succ_le, add_one_mul] at t
have s : k = k - 1 + 1 := by omega
conv at t => rhs; lhs; rhs; rw [s]
rw [ Nat.add_assoc, succ_le, add_lt_iff_lt_sub_right] at t
exact t
theorem div_le_iff_le_mul (h : 0 < k) : x / k y x y * k + k - 1 := by
rw [le_iff_lt_add_one, Nat.div_lt_iff_lt_mul h, Nat.add_one_mul]
omega
-- TODO: reprove `div_eq_of_lt_le` in terms of this:
theorem div_eq_iff (h : 0 < k) : x / k = y x y * k + k - 1 y * k x := by
rw [Nat.eq_iff_le_and_ge, le_div_iff_mul_le h, Nat.div_le_iff_le_mul h]
theorem lt_of_div_eq_zero (h : 0 < k) (h' : x / k = 0) : x < k := by
rw [div_eq_iff h] at h'
omega
theorem div_eq_zero_iff_lt (h : 0 < k) : x / k = 0 x < k :=
lt_of_div_eq_zero h, fun h' => Nat.div_eq_of_lt h'
theorem div_mul_self_eq_mod_sub_self {x k : Nat} : (x / k) * k = x - (x % k) := by
have := mod_eq_sub_div_mul (x := x) (k := k)
have := div_mul_le_self x k
omega
theorem mul_div_self_eq_mod_sub_self {x k : Nat} : k * (x / k) = x - (x % k) := by
rw [Nat.mul_comm, div_mul_self_eq_mod_sub_self]
theorem lt_div_mul_self (h : 0 < k) (w : k x) : x - k < x / k * k := by
rw [div_mul_self_eq_mod_sub_self]
have : x % k < k := mod_lt x h
omega
end Nat

View File

@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
-/
prelude
import Init.Data.Nat.Div
import Init.Data.Nat.Div.Basic
import Init.Meta
namespace Nat
@@ -39,9 +39,9 @@ protected theorem dvd_add_iff_right {k m n : Nat} (h : k m) : k n ↔ k
protected theorem dvd_add_iff_left {k m n : Nat} (h : k n) : k m k m + n := by
rw [Nat.add_comm]; exact Nat.dvd_add_iff_right h
theorem dvd_mod_iff {k m n : Nat} (h: k n) : k m % n k m :=
have := Nat.dvd_add_iff_left <| Nat.dvd_trans h <| Nat.dvd_mul_right n (m / n)
by rwa [mod_add_div] at this
theorem dvd_mod_iff {k m n : Nat} (h: k n) : k m % n k m := by
have := Nat.dvd_add_iff_left (m := m % n) <| Nat.dvd_trans h <| Nat.dvd_mul_right n (m / n)
rwa [mod_add_div] at this
theorem le_of_dvd {m n : Nat} (h : 0 < n) : m n m n
| k, e => by
@@ -77,7 +77,7 @@ theorem dvd_of_mod_eq_zero {m n : Nat} (H : n % m = 0) : m n := by
theorem dvd_iff_mod_eq_zero {m n : Nat} : m n n % m = 0 :=
mod_eq_zero_of_dvd, dvd_of_mod_eq_zero
instance decidable_dvd : @DecidableRel Nat (··) :=
instance decidable_dvd : @DecidableRel Nat Nat (··) :=
fun _ _ => decidable_of_decidable_of_iff dvd_iff_mod_eq_zero.symm
theorem emod_pos_of_not_dvd {a b : Nat} (h : ¬ a b) : 0 < b % a := by
@@ -92,7 +92,7 @@ protected theorem div_mul_cancel {n m : Nat} (H : n m) : m / n * n = m := by
rw [Nat.mul_comm, Nat.mul_div_cancel' H]
@[simp] theorem mod_mod_of_dvd (a : Nat) (h : c b) : a % b % c = a % c := by
rw (occs := .pos [2]) [ mod_add_div a b]
rw (occs := [2]) [ mod_add_div a b]
have x, h := h
subst h
rw [Nat.mul_assoc, add_mul_mod_self_left]

View File

@@ -5,6 +5,7 @@ Authors: Floris van Doorn, Leonardo de Moura, Kim Morrison
-/
prelude
import Init.Omega
import Init.Data.List.FinRange
set_option linter.missingDocs true -- keep it documented
universe u
@@ -137,6 +138,54 @@ theorem allTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bo
omega
go n 0 f
@[simp] theorem fold_zero {α : Type u} (f : (i : Nat) i < 0 α α) (init : α) :
fold 0 f init = init := by simp [fold]
@[simp] theorem fold_succ {α : Type u} (n : Nat) (f : (i : Nat) i < n + 1 α α) (init : α) :
fold (n + 1) f init = f n (by omega) (fold n (fun i h => f i (by omega)) init) := by simp [fold]
theorem fold_eq_finRange_foldl {α : Type u} (n : Nat) (f : (i : Nat) i < n α α) (init : α) :
fold n f init = (List.finRange n).foldl (fun acc i, h => f i h acc) init := by
induction n with
| zero => simp
| succ n ih =>
simp [ih, List.finRange_succ_last, List.foldl_map]
@[simp] theorem foldRev_zero {α : Type u} (f : (i : Nat) i < 0 α α) (init : α) :
foldRev 0 f init = init := by simp [foldRev]
@[simp] theorem foldRev_succ {α : Type u} (n : Nat) (f : (i : Nat) i < n + 1 α α) (init : α) :
foldRev (n + 1) f init = foldRev n (fun i h => f i (by omega)) (f n (by omega) init) := by
simp [foldRev]
theorem foldRev_eq_finRange_foldr {α : Type u} (n : Nat) (f : (i : Nat) i < n α α) (init : α) :
foldRev n f init = (List.finRange n).foldr (fun i, h acc => f i h acc) init := by
induction n generalizing init with
| zero => simp
| succ n ih => simp [ih, List.finRange_succ_last, List.foldr_map]
@[simp] theorem any_zero {f : (i : Nat) i < 0 Bool} : any 0 f = false := by simp [any]
@[simp] theorem any_succ {n : Nat} (f : (i : Nat) i < n + 1 Bool) :
any (n + 1) f = (any n (fun i h => f i (by omega)) || f n (by omega)) := by simp [any]
theorem any_eq_finRange_any {n : Nat} (f : (i : Nat) i < n Bool) :
any n f = (List.finRange n).any (fun i, h => f i h) := by
induction n with
| zero => simp
| succ n ih => simp [ih, List.finRange_succ_last, List.any_map, Function.comp_def]
@[simp] theorem all_zero {f : (i : Nat) i < 0 Bool} : all 0 f = true := by simp [all]
@[simp] theorem all_succ {n : Nat} (f : (i : Nat) i < n + 1 Bool) :
all (n + 1) f = (all n (fun i h => f i (by omega)) && f n (by omega)) := by simp [all]
theorem all_eq_finRange_all {n : Nat} (f : (i : Nat) i < n Bool) :
all n f = (List.finRange n).all (fun i, h => f i h) := by
induction n with
| zero => simp
| succ n ih => simp [ih, List.finRange_succ_last, List.all_map, Function.comp_def]
end Nat
namespace Prod

View File

@@ -176,6 +176,9 @@ protected theorem add_pos_right (m) (h : 0 < n) : 0 < m + n :=
protected theorem add_self_ne_one : n, n + n 1
| n+1, h => by rw [Nat.succ_add, Nat.succ.injEq] at h; contradiction
theorem le_iff_lt_add_one : x y x < y + 1 := by
omega
/-! ## sub -/
protected theorem sub_one (n) : n - 1 = pred n := rfl
@@ -225,6 +228,9 @@ protected theorem sub_le_iff_le_add' {a b c : Nat} : a - b ≤ c ↔ a ≤ b + c
protected theorem le_sub_iff_add_le {n : Nat} (h : k m) : n m - k n + k m :=
Nat.add_le_of_le_sub h, Nat.le_sub_of_add_le
theorem add_lt_iff_lt_sub_right {a b c : Nat} : a + b < c a < c - b := by
omega
protected theorem add_le_of_le_sub' {n k m : Nat} (h : m k) : n k - m m + n k :=
Nat.add_comm .. Nat.add_le_of_le_sub h
@@ -651,8 +657,8 @@ theorem sub_mul_mod {x k n : Nat} (h₁ : n*k ≤ x) : (x - n*k) % n = x % n :=
| .inr npos => Nat.mod_eq_of_lt (mod_lt _ npos)
theorem mul_mod (a b n : Nat) : a * b % n = (a % n) * (b % n) % n := by
rw (occs := .pos [1]) [ mod_add_div a n]
rw (occs := .pos [1]) [ mod_add_div b n]
rw (occs := [1]) [ mod_add_div a n]
rw (occs := [1]) [ mod_add_div b n]
rw [Nat.add_mul, Nat.mul_add, Nat.mul_add,
Nat.mul_assoc, Nat.mul_assoc, Nat.mul_add n, add_mul_mod_self_left,
Nat.mul_comm _ (n * (b / n)), Nat.mul_assoc, add_mul_mod_self_left]
@@ -679,6 +685,10 @@ theorem add_mod (a b n : Nat) : (a + b) % n = ((a % n) + (b % n)) % n := by
@[simp] theorem mod_mul_mod {a b c : Nat} : (a % c * b) % c = a * b % c := by
rw [mul_mod, mod_mod, mul_mod]
theorem mod_eq_sub (x w : Nat) : x % w = x - w * (x / w) := by
conv => rhs; congr; rw [ mod_add_div x w]
simp
/-! ### pow -/
theorem pow_succ' {m n : Nat} : m ^ n.succ = m * m ^ n := by
@@ -846,6 +856,18 @@ protected theorem pow_lt_pow_iff_pow_mul_le_pow {a n m : Nat} (h : 1 < a) :
rw [Nat.pow_add_one, Nat.pow_le_pow_iff_right (by omega), Nat.pow_lt_pow_iff_right (by omega)]
omega
protected theorem lt_pow_self {n a : Nat} (h : 1 < a) : n < a ^ n := by
induction n with
| zero => exact Nat.zero_lt_one
| succ _ ih => exact Nat.lt_of_lt_of_le (Nat.add_lt_add_right ih 1) (Nat.pow_lt_pow_succ h)
protected theorem lt_two_pow_self : n < 2 ^ n :=
Nat.lt_pow_self Nat.one_lt_two
@[simp]
protected theorem mod_two_pow_self : n % 2 ^ n = n :=
Nat.mod_eq_of_lt Nat.lt_two_pow_self
@[simp]
theorem two_pow_pred_mul_two (h : 0 < w) :
2 ^ (w - 1) * 2 = 2 ^ w := by
@@ -1030,6 +1052,25 @@ instance decidableExistsLE [DecidablePred p] : DecidablePred fun n => ∃ m : Na
fun n => decidable_of_iff ( m, m < n + 1 p m)
(exists_congr fun _ => and_congr_left' Nat.lt_succ_iff)
/-- Dependent version of `decidableExistsLT`. -/
instance decidableExistsLT' {p : (m : Nat) m < k Prop} [I : m h, Decidable (p m h)] :
Decidable ( m : Nat, h : m < k, p m h) :=
match k, p, I with
| 0, _, _ => isFalse (by simp)
| (k + 1), p, I => @decidable_of_iff _ (( m, h : m < k, p m (by omega)) p k (by omega))
by rintro (m, h, w | w); exact m, by omega, w; exact k, by omega, w,
fun m, h, w => if h' : m < k then .inl m, h', w else
by obtain rfl := (by omega : m = k); exact .inr w
(@instDecidableOr _ _
(decidableExistsLT' (p := fun m h => p m (by omega)) (I := fun m h => I m (by omega)))
inferInstance)
/-- Dependent version of `decidableExistsLE`. -/
instance decidableExistsLE' {p : (m : Nat) m k Prop} [I : m h, Decidable (p m h)] :
Decidable ( m : Nat, h : m k, p m h) :=
decidable_of_iff ( m, h : m < k + 1, p m (by omega)) (exists_congr fun _ =>
fun h, w => le_of_lt_succ h, w, fun h, w => lt_add_one_of_le h, w)
/-! ### Results about `List.sum` specialized to `Nat` -/
protected theorem sum_pos_iff_exists_pos {l : List Nat} : 0 < l.sum x l, 0 < x := by

View File

@@ -36,3 +36,7 @@ theorem neZero_iff {n : R} : NeZero n ↔ n ≠ 0 :=
@[simp] theorem neZero_zero_iff_false {α : Type _} [Zero α] : NeZero (0 : α) False :=
fun _ NeZero.ne (0 : α) rfl, fun h h.elim
instance {p : Prop} [Decidable p] {n m : Nat} [NeZero n] [NeZero m] :
NeZero (if p then n else m) := by
split <;> infer_instance

View File

@@ -6,6 +6,7 @@ Authors: Leonardo de Moura
prelude
import Init.Meta
import Init.Data.Float
import Init.Data.Float32
import Init.Data.Nat.Log2
/-- For decimal and scientific numbers (e.g., `1.23`, `3.12e10`).
@@ -56,3 +57,34 @@ instance : OfNat Float n := ⟨Float.ofNat n⟩
abbrev Nat.toFloat (n : Nat) : Float :=
Float.ofNat n
/-- Computes `m * 2^e`. -/
def Float32.ofBinaryScientific (m : Nat) (e : Int) : Float32 :=
let s := m.log2 - 63
let m := (m >>> s).toUInt64
let e := e + s
m.toFloat32.scaleB e
protected opaque Float32.ofScientific (m : Nat) (s : Bool) (e : Nat) : Float32 :=
if s then
let s := 64 - m.log2 -- ensure we have 64 bits of mantissa left after division
let m := (m <<< (3 * e + s)) / 5^e
Float32.ofBinaryScientific m (-4 * e - s)
else
Float32.ofBinaryScientific (m * 5^e) e
instance : OfScientific Float32 where
ofScientific := Float32.ofScientific
@[export lean_float32_of_nat]
def Float32.ofNat (n : Nat) : Float32 :=
OfScientific.ofScientific n false 0
def Float32.ofInt : Int Float
| Int.ofNat n => Float.ofNat n
| Int.negSucc n => Float.neg (Float.ofNat (Nat.succ n))
instance : OfNat Float32 n := Float32.ofNat n
abbrev Nat.toFloat32 (n : Nat) : Float32 :=
Float32.ofNat n

View File

@@ -10,3 +10,4 @@ import Init.Data.Option.Instances
import Init.Data.Option.Lemmas
import Init.Data.Option.Attach
import Init.Data.Option.List
import Init.Data.Option.Monadic

View File

@@ -56,7 +56,6 @@ theorem attach_map_val (o : Option α) (f : α → β) :
(o.attach.map fun i => f i.val) = o.map f :=
attach_map_coe _ _
@[simp]
theorem attach_map_subtype_val (o : Option α) :
o.attach.map Subtype.val = o :=
(attach_map_coe _ _).trans (congrFun Option.map_id _)
@@ -69,12 +68,11 @@ theorem attachWith_map_val {p : α → Prop} (f : α → β) (o : Option α) (H
((o.attachWith p H).map fun i => f i.val) = o.map f :=
attachWith_map_coe _ _ _
@[simp]
theorem attachWith_map_subtype_val {p : α Prop} (o : Option α) (H : a o, p a) :
(o.attachWith p H).map Subtype.val = o :=
(attachWith_map_coe _ _ _).trans (congrFun Option.map_id _)
@[simp] theorem mem_attach : (o : Option α) (x : {x // x o}), x o.attach
theorem mem_attach : (o : Option α) (x : {x // x o}), x o.attach
| none, x, h => by simp at h
| some a, x, h => by simpa using h
@@ -92,14 +90,14 @@ theorem attachWith_map_subtype_val {p : α → Prop} (o : Option α) (H : ∀ a
(o.attachWith p H).isSome = o.isSome := by
cases o <;> simp
@[simp] theorem attach_eq_none_iff (o : Option α) : o.attach = none o = none := by
@[simp] theorem attach_eq_none_iff {o : Option α} : o.attach = none o = none := by
cases o <;> simp
@[simp] theorem attach_eq_some_iff {o : Option α} {x : {x // x o}} :
o.attach = some x o = some x.val := by
cases o <;> cases x <;> simp
@[simp] theorem attachWith_eq_none_iff {p : α Prop} (o : Option α) (H : a o, p a) :
@[simp] theorem attachWith_eq_none_iff {p : α Prop} {o : Option α} (H : a o, p a) :
o.attachWith p H = none o = none := by
cases o <;> simp
@@ -119,10 +117,14 @@ theorem attachWith_map_subtype_val {p : α → Prop} (o : Option α) (H : ∀ a
· simp at h
· simp [get_some]
@[simp] theorem toList_attach (o : Option α) :
theorem toList_attach (o : Option α) :
o.attach.toList = o.toList.attach.map fun x, h => x, by simpa using h := by
cases o <;> simp
@[simp] theorem attach_toList (o : Option α) :
o.toList.attach = (o.attach.map fun a, h => a, by simpa using h).toList := by
cases o <;> simp
theorem attach_map {o : Option α} (f : α β) :
(o.map f).attach = o.attach.map (fun x, h => f x, mem_map_of_mem f h) := by
cases o <;> simp

View File

@@ -96,12 +96,12 @@ This is similar to `<|>`/`orElse`, but it is strict in the second argument. -/
| some a, _ => some a
| none, b => b
@[inline] protected def lt (r : α α Prop) : Option α Option α Prop
@[inline] protected def lt (r : α β Prop) : Option α Option β Prop
| none, some _ => True
| some x, some y => r x y
| _, _ => False
instance (r : α α Prop) [s : DecidableRel r] : DecidableRel (Option.lt r)
instance (r : α β Prop) [s : DecidableRel r] : DecidableRel (Option.lt r)
| none, some _ => isTrue trivial
| some x, some y => s x y
| some _, none => isFalse not_false

View File

@@ -70,6 +70,13 @@ satisfy `p`, using the proof to apply `f`.
| none, _ => none
| some a, H => f a (H a rfl)
/-- Partial elimination. If `o : Option α` and `f : (a : α) → a ∈ o → β`, then `o.pelim b f` is
the same as `o.elim b f` but `f` is passed the proof that `a ∈ o`. -/
@[inline] def pelim (o : Option α) (b : β) (f : (a : α) a o β) : β :=
match o with
| none => b
| some a => f a rfl
/-- Map a monadic function which returns `Unit` over an `Option`. -/
@[inline] protected def forM [Pure m] : Option α (α m PUnit) m PUnit
| none , _ => pure

View File

@@ -629,4 +629,12 @@ theorem pbind_eq_some_iff {o : Option α} {f : (a : α) → a ∈ o → Option
· rintro h, rfl
rfl
/-! ### pelim -/
@[simp] theorem pelim_none : pelim none b f = b := rfl
@[simp] theorem pelim_some : pelim (some a) b f = f a rfl := rfl
@[simp] theorem pelim_eq_elim : pelim o b (fun a _ => f a) = o.elim b f := by
cases o <;> simp
end Option

View File

@@ -15,17 +15,25 @@ namespace Option
forIn' none b f = pure b := by
rfl
@[simp] theorem forIn'_some [Monad m] (a : α) (b : β) (f : (a' : α) a' some a β m (ForInStep β)) :
forIn' (some a) b f = bind (f a rfl b) (fun | .done r | .yield r => pure r) := by
rfl
@[simp] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) a' some a β m (ForInStep β)) :
forIn' (some a) b f = bind (f a rfl b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn', bind_pure_comp]
rw [map_eq_pure_bind]
congr
funext x
split <;> rfl
@[simp] theorem forIn_none [Monad m] (b : β) (f : α β m (ForInStep β)) :
forIn none b f = pure b := by
rfl
@[simp] theorem forIn_some [Monad m] (a : α) (b : β) (f : α β m (ForInStep β)) :
forIn (some a) b f = bind (f a b) (fun | .done r | .yield r => pure r) := by
rfl
@[simp] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α β m (ForInStep β)) :
forIn (some a) b f = bind (f a b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn, forIn', bind_pure_comp]
rw [map_eq_pure_bind]
congr
funext x
split <;> rfl
@[simp] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) a o.toList β m (ForInStep β)) :
forIn' o.toList b f = forIn' o b fun a m b => f a (by simpa using m) b := by
@@ -35,4 +43,20 @@ namespace Option
forIn o.toList b f = forIn o b f := by
cases o <;> rfl
@[simp] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α β m α) :
o.toList.foldlM f a = o.elim (pure a) (fun b => f a b) := by
cases o <;> simp
@[simp] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β α m α) :
o.toList.foldrM f a = o.elim (pure a) (fun b => f b a) := by
cases o <;> simp
@[simp] theorem foldl_toList (o : Option β) (a : α) (f : α β α) :
o.toList.foldl f a = o.elim a (fun b => f a b) := by
cases o <;> simp
@[simp] theorem foldr_toList (o : Option β) (a : α) (f : β α α) :
o.toList.foldr f a = o.elim a (fun b => f b a) := by
cases o <;> simp
end Option

View File

@@ -0,0 +1,95 @@
/-
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.Option.Attach
import Init.Control.Lawful.Basic
namespace Option
@[simp] theorem forM_none [Monad m] (f : α m PUnit) :
none.forM f = pure .unit := rfl
@[simp] theorem forM_some [Monad m] (f : α m PUnit) (a : α) :
(some a).forM f = f a := rfl
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α β) (f : β m PUnit) :
(o.map g).forM f = o.forM (fun a => f (g a)) := by
cases o <;> simp
@[congr] theorem forIn'_congr [Monad m] [LawfulMonad m] {as bs : Option α} (w : as = bs)
{b b' : β} (hb : b = b')
{f : (a' : α) a' as β m (ForInStep β)}
{g : (a' : α) a' bs β m (ForInStep β)}
(h : a m b, f a (by simpa [w] using m) b = g a m b) :
forIn' as b f = forIn' bs b' g := by
cases as <;> cases bs
· simp [hb]
· simp at w
· simp at w
· simp only [some.injEq] at w
subst w
simp [hb, h]
theorem forIn'_eq_pelim [Monad m] [LawfulMonad m]
(o : Option α) (f : (a : α) a o β m (ForInStep β)) (b : β) :
forIn' o b f =
o.pelim (pure b) (fun a h => ForInStep.value <$> f a h b) := by
cases o <;> simp
@[simp] theorem forIn'_yield_eq_pelim [Monad m] [LawfulMonad m] (o : Option α)
(f : (a : α) a o β m γ) (g : (a : α) a o β γ β) (b : β) :
forIn' o b (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
o.pelim (pure b) (fun a h => g a h b <$> f a h b) := by
cases o <;> simp
theorem forIn'_pure_yield_eq_pelim [Monad m] [LawfulMonad m]
(o : Option α) (f : (a : α) a o β β) (b : β) :
forIn' o b (fun a m b => pure (.yield (f a m b))) =
pure (f := m) (o.pelim b (fun a h => f a h b)) := by
cases o <;> simp
@[simp] theorem forIn'_id_yield_eq_pelim
(o : Option α) (f : (a : α) a o β β) (b : β) :
forIn' (m := Id) o b (fun a m b => .yield (f a m b)) =
o.pelim b (fun a h => f a h b) := by
cases o <;> simp
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
(o : Option α) (g : α β) (f : (b : β) b o.map g γ m (ForInStep γ)) :
forIn' (o.map g) init f = forIn' o init fun a h y => f (g a) (mem_map_of_mem g h) y := by
cases o <;> simp
theorem forIn_eq_elim [Monad m] [LawfulMonad m]
(o : Option α) (f : (a : α) β m (ForInStep β)) (b : β) :
forIn o b f =
o.elim (pure b) (fun a => ForInStep.value <$> f a b) := by
cases o <;> simp
@[simp] theorem forIn_yield_eq_elim [Monad m] [LawfulMonad m] (o : Option α)
(f : (a : α) β m γ) (g : (a : α) β γ β) (b : β) :
forIn o b (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
o.elim (pure b) (fun a => g a b <$> f a b) := by
cases o <;> simp
theorem forIn_pure_yield_eq_elim [Monad m] [LawfulMonad m]
(o : Option α) (f : (a : α) β β) (b : β) :
forIn o b (fun a b => pure (.yield (f a b))) =
pure (f := m) (o.elim b (fun a => f a b)) := by
cases o <;> simp
@[simp] theorem forIn_id_yield_eq_elim
(o : Option α) (f : (a : α) β β) (b : β) :
forIn (m := Id) o b (fun a b => .yield (f a b)) =
o.elim b (fun a => f a b) := by
cases o <;> simp
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
(o : Option α) (g : α β) (f : β γ m (ForInStep γ)) :
forIn (o.map g) init f = forIn o init fun a y => f (g a) y := by
cases o <;> simp
end Option

View File

@@ -210,12 +210,18 @@ Derive an `LT` instance from an `Ord` instance.
protected def toLT (_ : Ord α) : LT α :=
ltOfOrd
instance [i : Ord α] : DecidableRel (@LT.lt _ (Ord.toLT i)) :=
inferInstanceAs (DecidableRel (fun a b => compare a b = Ordering.lt))
/--
Derive an `LE` instance from an `Ord` instance.
-/
protected def toLE (_ : Ord α) : LE α :=
leOfOrd
instance [i : Ord α] : DecidableRel (@LE.le _ (Ord.toLE i)) :=
inferInstanceAs (DecidableRel (fun a b => (compare a b).isLE))
/--
Invert the order of an `Ord` instance.
-/
@@ -248,6 +254,6 @@ protected def arrayOrd [a : Ord α] : Ord (Array α) where
compare x y :=
let _ : LT α := a.toLT
let _ : BEq α := a.toBEq
compareOfLessAndBEq x.toList y.toList
if List.lex x.toList y.toList then .lt else if x == y then .eq else .gt
end Ord

View File

@@ -1,74 +1,8 @@
/-
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
Authors: Kim Morrison
-/
prelude
import Init.Meta
namespace Std
-- We put `Range` in `Init` because we want the notation `[i:j]` without importing `Std`
-- We don't put `Range` in the top-level namespace to avoid collisions with user defined types
structure Range where
start : Nat := 0
stop : Nat
step : Nat := 1
instance : Membership Nat Range where
mem r i := r.start i i < r.stop
namespace Range
universe u v
@[inline] protected def forIn' {β : Type u} {m : Type u Type v} [Monad m] (range : Range) (init : β) (f : (i : Nat) i range β m (ForInStep β)) : m β :=
let rec @[specialize] loop (start stop step : Nat) (f : (i : Nat) start i i < stop β m (ForInStep β)) (fuel i : Nat) (hl : start i) (b : β) : m β := do
if hu : i < stop then
match fuel with
| 0 => pure b
| fuel+1 => match ( f i hl, hu b) with
| ForInStep.done b => pure b
| ForInStep.yield b => loop start stop step f fuel (i + step) (Nat.le_trans hl (Nat.le_add_right ..)) b
else
return b
loop range.start range.stop range.step f range.stop range.start (Nat.le_refl ..) init
instance : ForIn' m Range Nat inferInstance where
forIn' := Range.forIn'
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
@[inline] protected def forM {m : Type u Type v} [Monad m] (range : Range) (f : Nat m PUnit) : m PUnit :=
let rec @[specialize] loop (fuel i stop step : Nat) : m PUnit := do
if i stop then
pure
else match fuel with
| 0 => pure
| fuel+1 => f i; loop fuel (i + step) stop step
loop range.stop range.start range.stop range.step
instance : ForM m Range Nat where
forM := Range.forM
syntax:max "[" withoutPosition(":" term) "]" : term
syntax:max "[" withoutPosition(term ":" term) "]" : term
syntax:max "[" withoutPosition(":" term ":" term) "]" : term
syntax:max "[" withoutPosition(term ":" term ":" term) "]" : term
macro_rules
| `([ : $stop]) => `({ stop := $stop : Range })
| `([ $start : $stop ]) => `({ start := $start, stop := $stop : Range })
| `([ $start : $stop : $step ]) => `({ start := $start, stop := $stop, step := $step : Range })
| `([ : $stop : $step ]) => `({ stop := $stop, step := $step : Range })
end Range
end Std
theorem Membership.mem.upper {i : Nat} {r : Std.Range} (h : i r) : i < r.stop := h.2
theorem Membership.mem.lower {i : Nat} {r : Std.Range} (h : i r) : r.start i := h.1
theorem Membership.get_elem_helper {i n : Nat} {r : Std.Range} (h₁ : i r) (h₂ : r.stop = n) :
i < n := h₂ h₁.2
macro_rules
| `(tactic| get_elem_tactic_trivial) => `(tactic| apply Membership.get_elem_helper; assumption; rfl)
import Init.Data.Range.Basic
import Init.Data.Range.Lemmas

View File

@@ -0,0 +1,86 @@
/-
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Init.Meta
import Init.Omega
namespace Std
-- We put `Range` in `Init` because we want the notation `[i:j]` without importing `Std`
-- We don't put `Range` in the top-level namespace to avoid collisions with user defined types
structure Range where
start : Nat := 0
stop : Nat
step : Nat := 1
step_pos : 0 < step
instance : Membership Nat Range where
mem r i := r.start i i < r.stop (i - r.start) % r.step = 0
namespace Range
universe u v
/-- The number of elements in the range. -/
@[simp] def size (r : Range) : Nat := (r.stop - r.start + r.step - 1) / r.step
@[inline] protected def forIn' [Monad m] (range : Range) (init : β)
(f : (i : Nat) i range β m (ForInStep β)) : m β :=
let rec @[specialize] loop (b : β) (i : Nat)
(hs : (i - range.start) % range.step = 0) (hl : range.start i := by omega) : m β := do
if h : i < range.stop then
match ( f i hl, by omega, hs b) with
| .done b => pure b
| .yield b =>
have := range.step_pos
loop b (i + range.step) (by rwa [Nat.add_comm, Nat.add_sub_assoc hl, Nat.add_mod_left])
else
pure b
have := range.step_pos
loop init range.start (by simp)
instance : ForIn' m Range Nat inferInstance where
forIn' := Range.forIn'
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
@[inline] protected def forM [Monad m] (range : Range) (f : Nat m PUnit) : m PUnit :=
let rec @[specialize] loop (i : Nat): m PUnit := do
if i < range.stop then
f i
have := range.step_pos
loop (i + range.step)
else
pure
have := range.step_pos
loop range.start
instance : ForM m Range Nat where
forM := Range.forM
syntax:max "[" withoutPosition(":" term) "]" : term
syntax:max "[" withoutPosition(term ":" term) "]" : term
syntax:max "[" withoutPosition(":" term ":" term) "]" : term
syntax:max "[" withoutPosition(term ":" term ":" term) "]" : term
macro_rules
| `([ : $stop]) => `({ stop := $stop, step_pos := Nat.zero_lt_one : Range })
| `([ $start : $stop ]) => `({ start := $start, stop := $stop, step_pos := Nat.zero_lt_one : Range })
| `([ $start : $stop : $step ]) => `({ start := $start, stop := $stop, step := $step, step_pos := by decide : Range })
| `([ : $stop : $step ]) => `({ stop := $stop, step := $step, step_pos := by decide : Range })
end Range
end Std
theorem Membership.mem.upper {i : Nat} {r : Std.Range} (h : i r) : i < r.stop := h.2.1
theorem Membership.mem.lower {i : Nat} {r : Std.Range} (h : i r) : r.start i := h.1
theorem Membership.mem.step {i : Nat} {r : Std.Range} (h : i r) : (i - r.start) % r.step = 0 := h.2.2
theorem Membership.get_elem_helper {i n : Nat} {r : Std.Range} (h₁ : i r) (h₂ : r.stop = n) :
i < n := h₂ h₁.2.1
macro_rules
| `(tactic| get_elem_tactic_trivial) => `(tactic| apply Membership.get_elem_helper; assumption; rfl)

View File

@@ -0,0 +1,103 @@
/-
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Range.Basic
import Init.Data.List.Range
import Init.Data.List.Monadic
import Init.Data.Nat.Div.Lemmas
/-!
# Lemmas about `Std.Range`
We provide lemmas rewriting for loops over `Std.Range` in terms of `List.range'`.
-/
namespace Std.Range
/-- Generalization of `mem_of_mem_range'` used in `forIn'_loop_eq_forIn'_range'` below. -/
private theorem mem_of_mem_range'_aux {r : Range} {a : Nat} (w₁ : (i - r.start) % r.step = 0)
(w₂ : r.start i)
(h : a List.range' i ((r.stop - i + r.step - 1) / r.step) r.step) : a r := by
obtain j, h', rfl := List.mem_range'.1 h
refine by omega, ?_
rw [Nat.lt_div_iff_mul_lt r.step_pos, Nat.mul_comm] at h'
constructor
· omega
· rwa [Nat.add_comm, Nat.add_sub_assoc w₂, Nat.mul_add_mod_self_left]
theorem mem_of_mem_range' {r : Range} (h : x List.range' r.start r.size r.step) : x r := by
unfold size at h
apply mem_of_mem_range'_aux (by simp) (by simp) h
private theorem size_eq (r : Std.Range) (h : i < r.stop) :
(r.stop - i + r.step - 1) / r.step =
(r.stop - (i + r.step) + r.step - 1) / r.step + 1 := by
have w := r.step_pos
if i + r.step < r.stop then -- Not sure this case split is strictly necessary.
rw [Nat.div_eq_iff w, Nat.add_one_mul]
have : (r.stop - (i + r.step) + r.step - 1) / r.step * r.step
(r.stop - (i + r.step) + r.step - 1) := Nat.div_mul_le_self _ _
have : r.stop - (i + r.step) + r.step - 1 - r.step <
(r.stop - (i + r.step) + r.step - 1) / r.step * r.step :=
Nat.lt_div_mul_self w (by omega)
omega
else
have : (r.stop - i + r.step - 1) / r.step = 1 := by
rw [Nat.div_eq_iff w, Nat.one_mul]
omega
have : (r.stop - (i + r.step) + r.step - 1) / r.step = 0 := by
rw [Nat.div_eq_iff] <;> omega
omega
private theorem forIn'_loop_eq_forIn'_range' [Monad m] (r : Std.Range)
(init : β) (f : (a : Nat) a r β m (ForInStep β)) (i) (w₁) (w₂) :
forIn'.loop r f init i w₁ w₂ =
forIn' (List.range' i ((r.stop - i + r.step - 1) / r.step) r.step) init
fun a h => f a (mem_of_mem_range'_aux w₁ w₂ h) := by
have w := r.step_pos
rw [forIn'.loop]
split <;> rename_i h
· simp only [size_eq r h, List.range'_succ, List.forIn'_cons]
congr 1
funext step
split
· simp
· rw [forIn'_loop_eq_forIn'_range']
· have : (r.stop - i + r.step - 1) / r.step = 0 := by
rw [Nat.div_eq_iff] <;> omega
simp [this]
@[simp] theorem forIn'_eq_forIn'_range' [Monad m] (r : Std.Range)
(init : β) (f : (a : Nat) a r β m (ForInStep β)) :
forIn' r init f =
forIn' (List.range' r.start r.size r.step) init (fun a h => f a (mem_of_mem_range' h)) := by
conv => lhs; simp only [forIn', Range.forIn']
simp only [size]
rw [forIn'_loop_eq_forIn'_range']
@[simp] theorem forIn_eq_forIn_range' [Monad m] (r : Std.Range)
(init : β) (f : Nat β m (ForInStep β)) :
forIn r init f = forIn (List.range' r.start r.size r.step) init f := by
simp only [forIn, forIn'_eq_forIn'_range']
private theorem forM_loop_eq_forM_range' [Monad m] (r : Std.Range) (f : Nat m PUnit) :
forM.loop r f i = forM (List.range' i ((r.stop - i + r.step - 1) / r.step) r.step) f := by
have w := r.step_pos
rw [forM.loop]
split <;> rename_i h
· simp [size_eq r h, List.range'_succ, List.forM_cons]
congr 1
funext
rw [forM_loop_eq_forM_range']
· have : (r.stop - i + r.step - 1) / r.step = 0 := by
rw [Nat.div_eq_iff] <;> omega
simp [this]
@[simp] theorem forM_eq_forM_range' [Monad m] (r : Std.Range) (f : Nat m PUnit) :
forM r f = forM (List.range' r.start r.size r.step) f := by
simp only [forM, Range.forM, forM_loop_eq_forM_range', size]
end Std.Range

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