Compare commits

..

76 Commits

Author SHA1 Message Date
Kim Morrison
896b3f8933 copy across some Find API to Array 2025-02-26 16:44:05 +11:00
Kim Morrison
816fadb57b feat: add Array/Vector.replace 2025-02-26 16:33:16 +11:00
Cameron Zwarich
c3402b85ab fix: make the stage2 Leanc build use stage2 oleans rather than stage1 oleans (#7190)
This PR makes the stage2 Leanc build use the stage2 oleans rather than
stage1 oleans. This was happening because Leanc's own OLEAN_OUT is at
the build root rather than the lib/lean subdirectory, so when the build
added this OLEAN_OUT to LEAN_PATH no oleans were found there and the
search fell back to the stage1 installation location.
2025-02-25 06:20:50 +00:00
Mac Malone
a68b986616 feat: lake: compute jobs asynchronously (#7211)
This PR changes the job monitor to perform run job computation itself as
a separate job. Now progress will be reported eagerly, even before all
outstanding jobs have been discovered. Thus, the total job number
reported can now grow while jobs are still being computed (e.g., the `Y`
in `[X/Y[` may increase).
2025-02-25 04:03:17 +00:00
Leonardo de Moura
a2dc17055b feat: missing cases for equality propagation from core to cutsat (#7220)
This PR implements the missing cases for equality propagation from the
`grind` core to the cutsat module.
2025-02-25 01:09:05 +00:00
Kim Morrison
c9c85c7d83 chore: List.leftpad typo (#7219) 2025-02-25 00:53:37 +00:00
Kim Morrison
d615e615d9 chore: align List.dropLast/Array.pop lemmas (#7208)
This PR aligns lemmas for `List.dropLast` / `Array.pop` / `Vector.pop`.
2025-02-25 00:13:00 +00:00
Leonardo de Moura
a84639f63e feat: improve equality support in cutsat (#7217)
This PR improves the support for equalities in cutsat.
2025-02-24 23:35:04 +00:00
Kim Morrison
d9ab758af5 chore: re-enable List variable linter (#7215)
Turns back on the variable names linters across List/Array/Vector.
2025-02-24 23:34:01 +00:00
Leonardo de Moura
5cbeb22564 feat: add ForIn instance for PHashSet (#7214)
This PR adds a `ForIn` instance for the `PersistentHashSet` type.
2025-02-24 20:37:45 +00:00
Tobias Grosser
77e0fa4efe chore: use getElem in RHS of getElem theorems (#7187)
This PR moves the RHS of getElem theorems to use getElem. This is a
cleanup after the recent move to getElem as simp normal form.

We also turn `((!decide (i < n)) && getLsbD x (i - n))` into `if h' : i
< n then false else x[i - n]` to preserve the bounds, but keep the
decide if the dependent if is not needed to maintain a getElem on the
RHS.
2025-02-24 18:32:48 +00:00
Mac Malone
69efb78319 fix: lake: MSYS2 OSTYPE change (#7209)
This PR fixes broken Lake tests on Windows' new MSYS2. As of MSYS2
0.0.20250221, `OSTYPE` is now reported as `cygwin` instead of `msys`,
which must be accounted for in a few Lake tests.

See https://www.msys2.org/news/#2025-02-14-moving-msys2-closer-to-cygwin
for more details.
2025-02-24 17:10:13 +00:00
Luisa Cicolini
32a9392a11 feat: add BitVec.toFin_abs (#7206)
This PR adds theorem `BitVec.toFin_abs`, completing the API for
`BitVec.*_abs`.

---------

Co-authored-by: Tobias Grosser <github@grosser.es>
2025-02-24 17:02:51 +00:00
Paul Reichert
af741abbf5 feat: TreeMap lemmas for 'get?' (#7167)
This PR provides tree map lemmas for the interaction of `get?` with the
other operations for which lemmas already exist.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-24 15:34:37 +00:00
Markus Himmel
36723d38b9 feat: UIntX conversion lemmas (part 1/n) (#7174)
This PR adds the first batch of lemmas about iterated conversions
between finite types starting with something of type `UIntX`.
2025-02-24 12:48:37 +00:00
Kim Morrison
3ebce4e190 feat: align lemmas about List.getLast(!?) with Array/Vector.back(!?) (#7205)
This PR completes alignment of
`List.getLast`/`List.getLast!`/`List.getLast?` lemmas with the
corresponding lemmas for Array and Vector.
2025-02-24 11:48:43 +00:00
Paul Reichert
c934e6c247 feat: tree map lemmas about containsThenInsert(IfNew) (#7165)
This PR provides tree map lemmas about the interaction of
`containsThenInsert(IfNew)` with `contains` and `insert(IfNew)`.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-24 09:01:45 +00:00
Eric Wieser
57c8ab269b feat: allow line-wrapping when printing DiscrTree.Keys (#7200)
This PR allows the debug form of DiscrTree.Key to line-wrap.
2025-02-24 07:52:47 +00:00
Leonardo de Moura
e7dc0d31f4 feat: improve support for equations in cutsat (#7203)
This PR improves the support for equalities in cutsat. It also
simplifies a few support theorems used to justify cutsat rules.
2025-02-24 04:48:14 +00:00
Leonardo de Moura
1819dc88ff feat: cutsat relevant-term internalization (#7202)
This PR adds support for internalizing terms relevant to the cutsat
module. This is required to implement equality propagation.
2025-02-24 01:49:51 +00:00
Kim Morrison
e1fade23ec feat: align List/Array/Vector.leftpad (#7201)
This PR adds `Array/Vector.left/rightpad`. These will not receive any
verification theorems; simp just unfolds them to an `++` operation.
2025-02-24 01:39:01 +00:00
Kim Morrison
27e1391e6d feat: complete comparison theorems for ediv/tdiv/fdiv and emod/tmod/fmod (#7199)
This PR adds theorems comparing `Int.ediv` with `tdiv` and `fdiv`, for
all signs of arguments. (Previously we just had the statements about the
cases in which they agree.)
2025-02-24 01:01:40 +00:00
Kim Morrison
da32bdd79c chore: additional newline before 'additional diagnostic information' message (#7169)
This PR adds an addition newline before the "Additional diagnostic
information may be available using the `set_option ... true` command."
messages, to provide better visual separation from the main error
message.
2025-02-23 23:27:33 +00:00
Kyle Miller
b863ca9ae9 chore: post-#7100 cleanup (#7196)
This PR does some stage0 cleanup after #7100, and enables a warning when
the old `structure S extends P : Type` syntax is used. It also updates
the library to put resulting types in the new correct place (`structure
S : Type extends P`).

The `structure` elaborator also has some additional docstrings, and
`StructFieldKind.fromParent` is renamed to
`StructFieldKind.fromSubobject`.
2025-02-23 22:46:22 +00:00
euprunin
c3b01fbd53 doc: remove Trepplein example (Lean 3) (#7197)
This PR removes a reference to Trepplein (Lean 3) in the documentation.

Co-authored-by: euprunin <euprunin@users.noreply.github.com>
2025-02-23 21:39:45 +00:00
Leonardo de Moura
ad1e04c826 feat: simp diagnostics in grind (#6902)
This PR ensures `simp` diagnostic information in included in the `grind`
diagnostic message.
2025-02-23 17:55:17 +00:00
Leonardo de Moura
c8dc66b6c1 feat: helper theorems for solving equality in cutsat (#7194)
This PR adds support theorems for solving equality in cutsat.
2025-02-23 03:26:12 +00:00
Leonardo de Moura
d234b78cc0 chore: cutsat equality infrastructure (#7193)
This PR adds basic infrastructure for adding support for equalities in
cutsat.
2025-02-23 02:27:53 +00:00
Leonardo de Moura
1ae084b5f8 chore: cutsat cleanup (#7189)
This PR also removes unnecessary `mkExpectedTypeHint`s.
2025-02-22 18:35:02 +00:00
Leonardo de Moura
ddeb5ac535 refactor: cutsat (#7186)
This PR simplifies the proofs and data structures used by cutsat.
2025-02-22 17:25:42 +00:00
Sebastian Ullrich
6ff5c4c278 chore: don't forget about namespace reservation for async-unsupported constant kinds (#6987) 2025-02-22 16:45:40 +00:00
Sebastian Ullrich
087f0b4a69 perf: optimize sorry detection in unused variables linter (#7129)
This PR optimizes the performance of the unused variables linter in the
case of a definition with a huge `Expr` representation
2025-02-22 16:43:39 +00:00
Marc Huisinga
a7bdc55244 fix: inlay hint race conditions (#7188)
This PR fixes several inlay hint race conditions that could result in a
violation of the monotonic progress assumption, introduced in #7149.

Specifically:
- In rare circumstances, it could happen that stateful LSP requests were
executed out-of-order with their `didChange` handlers, as both requests
and the `didChange` handlers waited on `lake setup-file` to complete,
with the latter running those handlers in a dedicated task afterwards.
This meant that a request could be added to the stateful LSP handler
request queue before the corresponding `didChange` call that actually
came before it. This PR resolves this issue by folding the task that
waits for `lake setup-file` into the `RequestContext`, which ensures
that we only need to wait for it when actually executing the request
handler.
- While #7164 fixed the monotonic progress assertion violation that was
caused by `$/cancelRequest`, it did not account for our internal notion
of silent request cancellation in stateful LSP requests, which we use to
cancel the inlay hint edit delay when VS Code fails to emit a
`$/cancelRequest` notification. This issue is resolved by always
producing the full finished prefix of the command snapshot queue, even
on cancellation. Additionally, this also fixes an issue where in the
same circumstances, the language server could produce an empty inlay
hint response when a request was cancelled by our internal notion of
silent request cancellation.
- For clients that use `fullChange` `didChange` notifications (e.g. not
VS Code), we would get several aspects of stateful LSP request
`didChange` state handling wrong, which is also addressed by this PR.
2025-02-22 16:35:30 +00:00
Cameron Zwarich
647573d269 feat: support LEAN_BACKTRACE on macOS (#7184)
This PR adds support for LEAN_BACKTRACE on macOS. This previously only
worked with glibc, but it can not be enabled for all Unix-like systems,
since e.g. Musl does not support it.
2025-02-22 15:29:37 +00:00
Sebastian Ullrich
788a7ec502 test: avoid re-elaboration of interactive runner (#7177)
Before/after:
```
make -C build/release test ARGS="-j$(nproc) -R interactive"  208.10s user 20.93s system 1982% cpu 11.552 total
make -C build/release test ARGS="-j$(nproc) -R interactive"  87.22s user 22.58s system 1454% cpu 7.548 total
```
2025-02-22 10:36:25 +00:00
Mac Malone
3aef45c45b fix: lake: setup-file on an invalid Lean config (#7182)
This PR makes `lake setup-file` succeed on an invalid Lean configuration
file.

The server will disable interactivity if `setup-file` fails. When
editing the workspace configuration file, this behavior has the prior
effect of making the configuration file noninteractive if saved with an
invalid configuration.
2025-02-22 04:48:48 +00:00
Leonardo de Moura
1f5c66db79 feat: improve cutsat model search procedure (#7183)
This PR improves the cutsat model search procedure.
2025-02-21 23:51:53 +00:00
Sebastian Ullrich
d42d6c5246 fix: do not cancel async elaboration tasks (#7175)
This PR fixes an `Elab.async` regression where elaboration tasks are
cancelled on document edit even though their result may be reused in the
new document version, reporting an incomplete result.

While this PR fixes the functional regression, it does so as an
over-approximation by never cancelling such tasks. A follow-up PR will
implement the correct behavior of only cancelling the tasks that are not
reused.
2025-02-21 17:24:36 +00:00
Leonardo de Moura
d1aba29b57 feat: model construction for divisibility constraints in cutsat (#7176)
This PR implements model construction for divisibility constraints in
the cutsat procedure.
2025-02-21 16:17:32 +00:00
Johannes Tantow
0c35ca2e39 feat: verify fold/for variants for Hashmaps (#7137)
This PR verifies the various fold and for variants for hashmaps.

---------

Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
2025-02-21 16:08:33 +00:00
Sebastian Ullrich
6e77bee098 feat: Elab.Deriving trace on applyDerivingHandlers (#7173)
This PR introduces a trace node for each deriving handlers invocation
for the benefit of `trace.profiler`
2025-02-21 09:27:41 +00:00
Mac Malone
1ee21c17fc feat: use Lake plugin for Lake imports (#7157)
This PR changes `lake setup-file` to now use Lake as a plugin for files
which import Lake (or one of its submodules). Thus, the server will now
load Lake as a plugin when editing a Lake configuration written in Lean.
This further enables the use of builtin language extensions in Lake.
2025-02-21 05:07:13 +00:00
Mac Malone
aea58113cb feat: run setup-file on lakefiles (#7153)
This PR changes the server to run `lake setup-file` on Lake
configuration files (e.g., `lakefile.lean`).

This is needed to support Lake passing the server its own Lake plugin to
load when elaborating the configuration file.
2025-02-21 04:04:10 +00:00
Mac Malone
36c798964e feat: staged CMake build with Lake as a plugin (#6929)
This PR passes the shared library of the previous stage's Lake as a
plugin to the next stage's Lake in the CMake build. This enables Lake to
use its own builtin elaborators / initializers at build time.
2025-02-21 04:03:50 +00:00
Kim Morrison
6c609028b3 feat: upgrade Int.tdiv_eq_ediv to an unconditional equivalence (#7163)
This PR gives an unconditional theorem expressing `Int.tdiv` in terms of
`Int.ediv`, not just for non-negative arguments.
2025-02-20 23:46:11 +00:00
Paul Reichert
a3a99d3875 feat: more tree map lemmas about empty, isEmpty, contains, size, insert, erase (#7161)
This PR adds all missing tree map lemmas about the interactions of the
functions `empty`, `isEmpty`, `contains`, `size`, `insert(IfNew)` and
`erase`.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-20 15:33:41 +00:00
Marc Huisinga
970732ea11 fix: inlay hint assertion violation (#7164)
This PR fixes an assertion violation introduced in #7149 where the
monotonic progress assumption was violated by request cancellation.
2025-02-20 13:03:44 +00:00
Kim Morrison
2eb478787f chore: split Int.DivModLemmas into Bootstrap and Lemmas (#7162)
This PR splits `Int.DivModLemmas` into a `Bootstrap` and `Lemmas` file,
where it is possible to use `omega` in `Lemmas`.

I'm going to add more theory, particularly about `fdiv` and `tdiv` to
the `Lemmas` file, and would prefer to have access to `omega`.
2025-02-20 12:05:09 +00:00
Marc Huisinga
b49ec19167 feat: more robust server parallelism (#7087)
This PR ensures that all tasks in the language server either use
dedicated tasks or reuse an existing thread from the thread pool. This
ensures that elaboration tasks cannot prevent language server tasks from
being scheduled. This is especially important with parallelism right
around the corner and elaboration becoming more likely to starve the
language server of computation, which could drive up language server
latencies significantly on machines with few cores.

Specifically, all language server tasks are refactored to use a new thin
`ServerTask` API wrapper with a single "costly" vs "cheap" dimension,
where costly tasks are always scheduled as dedicated tasks, and cheap
tasks are always made to either run on the calling thread or to reuse
the thread of the task being mapped on by using the `sync` flag.

ProofWidgets4 adaption PR:
https://github.com/leanprover-community/ProofWidgets4/pull/106

### Other changes
- This PR makes several tasks dedicated that weren't dedicated before,
and uses `sync := true` for some others. The rules for this are
described in the module docstring of `ServerTask.lean`.
- Most notably, the reporting task in the file worker was *not* a
dedicated task before this PR, which could easily lead to thread pool
starvation on successive changes. It also did not support cancellation.
This PR ensures that it does.

### Breaking changes

- `RequestTask` and the request-oriented snapshot API are refactored to
use `ServerTask` instead of `Task`. All functions in `Task` have close
analogues in `ServerTask`, and functions on `RequestTask` now need to
distinguish between whether a `map` or a `bind` is cheap or costly. This
affects all downstream users of `RequestM`, e.g. tools that extend the
language server with their own requests, or some users of the RPC
mechanism.
- The following unused functions of the `AsyncList` API have been
deleted: `append`, `unfoldAsync`, `getAll`, `waitHead?`, `cancel`
2025-02-20 10:54:22 +00:00
Paul Reichert
adcba851f0 feat: modify and alter functions for the tree map (#7118)
This PR implements the functions `modify` and `alter` on the tree map.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2025-02-20 09:50:10 +00:00
Marc Huisinga
cc94cff735 feat: fast path for inlay hints (#7149)
This PR adds a fast path to the inlay hint request that makes it re-use
already computed inlay hints from previous requests instead of
re-computing them. This is necessary because for some reason VS Code
emits an inlay hint request for every line you scroll, so we need to be
able to respond to these requests against the same document state
quickly. Otherwise, every single scrolled line would result in a request
that can take a few dozen ms to be responded to in long files, putting
unnecessary pressure on the CPU.
It also filters the result set by the inlay hints that have been
requested.
2025-02-20 09:26:16 +00:00
Kim Morrison
2960b384af feat: strengthen Int.tdiv_eq_ediv (#7158)
This PR strengthens `Int.tdiv_eq_ediv`, by dropping an unnecessary
hypothesis, in preparation for further work on `ediv`/`tdiv`/`fdiv`
lemmas.
2025-02-20 05:57:47 +00:00
Leonardo de Moura
2c2b3641f1 feat: helper theorem for cutsat (#7156)
This PR adds a helper theorem that will be used in divisibility
constraint conflict resolution during model construction.
2025-02-20 05:39:49 +00:00
Leonardo de Moura
746e3a9f42 feat: model search skeleton for cutsat (#7155)
This PR implements some infrastructure for the model search procedure in
cutsat.
2025-02-20 03:41:39 +00:00
Kim Morrison
6a4225bf04 chore: complete variable name linting for Vector (#7154) 2025-02-20 02:42:50 +00:00
Leonardo de Moura
c86073830f feat: infrastructure for inequalities constraints in cutsat (#7152)
This PR implements the infrastructure for supporting integer inequality
constraints in the cutsat procedure.
2025-02-19 23:09:12 +00:00
Joachim Breitner
8672186a4e refactor: use more fun_induction in Init.Data.Int.Linear (#7142)
This uses the improved functional induction theorems from #7140.
2025-02-19 22:56:23 +00:00
Joachim Breitner
5bee3288ac refactor: update proofs after stage0 update for #7140 2025-02-19 20:59:01 +01:00
Joachim Breitner
eeb74ecf4d chore: update stage0 2025-02-19 20:59:01 +01:00
Joachim Breitner
36704e33bd feat: FunInd to split on bif as well
This PR treats `bif` (aka `cond`) like `if` in functional induction principles. It
introduces the `Bool.dcond` definition, with a docstring indicating that
this is for internal use.
2025-02-19 20:59:01 +01:00
Kim Morrison
8a2e21cfc4 chore: linting variable names in List/Array (#7146) 2025-02-19 12:45:02 +00:00
Lean stage0 autoupdater
3deda3c6df chore: update stage0 2025-02-19 12:38:31 +00:00
Joachim Breitner
e288e9c57e test: add f91 definition using partial_fixpoint (#7144) 2025-02-19 11:13:53 +00:00
Marc Huisinga
26dba92ce9 feat: faster auto-completion (#7134)
This PR significantly improves the performance of auto-completion by
optimizing individual requests by a factor of ~2 and by giving language
clients like VS Code the opportunity to reuse the state of previous
completion requests, thus greatly reducing the latency for the
auto-completion list to update when adding more characters to an
identifier.

In my testing: 
- The latency of completing `C` in a file with `import Mathlib` was
reduced from ~1650ms to ~800ms
- The latency of completing `Cat` in a file with `import Mathlib` was
reduced from ~800ms to ~430ms
- The latency of completing dot notation was mostly unaffected
- Successive completions are now practically instant, e.g. if we were to
complete `C` and then type it out to `Cat`, before it would take roughly
~1650ms + ~800ms, whereas now there is only a significant latency for
completing `C` (~800ms) and the completion list is updated practically
instantly when typing out `Cat`.

<details> 
  <summary>(Video) Auto-completion latency before this PR</summary>

![Auto-completion latency before this
PR](https://github.com/user-attachments/assets/125bc1ba-b14c-477b-9580-d8067c641342)
</details>

<details> 
  <summary>(Video) Auto-completion latency after this PR</summary>

![Auto-completion latency after this
PR](https://github.com/user-attachments/assets/43d4b587-d51f-4877-aaef-424ecc771490)
</details>

In detail, this PR makes the following changes:
- Set `isIncomplete` to `false` in non-synthetic completion responses so
that the client can re-use these completion states.
- Replace the server side fuzzy matching with a simple and fast check
that all characters in the identifier thus far are present in the same
order in the declaration to match against. There are some examples where
the simple and fast check yields a completion item that the fuzzy
matching would filter, but since VS Code filters the completion items
with its own fuzzy matching after that anyways, these extra completion
items are never actually displayed to the user.
- Remove all notions of scoring and sorting completion items from the
language server. We now rely entirely on the client to sort the
completion items as it sees fit. In my testing, the only significant
change as a result of this is that while the language server would
sometimes penalize namespaces with lots of components, VS Code instead
uses a strictly alphabetic order. Even before this change, we never
actually really prioritized local variables over global variables, so
the penalty wasn't very helpful in practice. We might add some small
form of local variable prioritization in the future, though.
- Remove the empty completion list hack that was introduced in #1885. It
does not appear to be necessary anymore.
2025-02-19 10:05:18 +00:00
Leonardo de Moura
1cbd2bd199 feat: create a let-expression for storing the context in cutsat proofs (#7139)
This PR uses a `let`-expression for storing the (shared) context in
proofs produced by the cutsat procedure in `grind`.
2025-02-19 03:36:13 +00:00
Mac Malone
a41fb49e25 feat: smarter plugin loading (#7090)
This PR strips `lib` prefixes and `_shared` suffixes from plugin names.
It also moves most of the dynlib processing code to Lean to make such
preprocessing more standard.
2025-02-18 23:03:52 +00:00
Leonardo de Moura
dfce31e2a2 feat: proof production for divisibility constraint solver in grind (#7138)
This PR implements proof generation for the divisibility constraint
solver in `grind`.
2025-02-18 22:38:30 +00:00
Kim Morrison
1d9b19189a chore: deprecate Array.get
fix test
2025-02-19 08:48:33 +11:00
Kim Morrison
d3c36bd7cf chore: use as[i] instead of as.get i 2025-02-19 08:48:33 +11:00
Kim Morrison
950fbc9d8f chore: update stage0 2025-02-19 08:48:33 +11:00
Kim Morrison
167e0ab301 chore: add Array.getInternal, also @[extern] 2025-02-19 08:48:33 +11:00
Joachim Breitner
2fed93462d feat: try? to use fun_induction (#7082)
This PR makes `try?` use `fun_induction` instead of `induction … using
foo.induct`. It uses the argument-free short-hand `fun_induction foo` if
that is unambiguous. Avoids `expose_names` if not necessary by simply
trying without first.
2025-02-18 16:06:58 +00:00
Kyle Miller
2d4c0017b8 chore: review uses of generalize (#7126)
This PR looks at some uses of the `generalize` tactic, especially when
used in conjunction with `induction`.
2025-02-18 14:07:40 +00:00
Markus Himmel
3a22035dad feat: IntX.abs (#7131)
This PR adds `IntX.abs` functions. These are specified by `BitVec.abs`,
so they map `IntX.minValue` to `IntX.minValue`, similar to Rust's
`i8::abs`. In the future we might also have versions which take values
in `UIntX` and/or `Nat`.
2025-02-18 13:16:30 +00:00
Johannes Tantow
010c6c36f1 feat: verify toList for hash maps (#6954)
This PR verifies the `toList`function for hash maps and dependent hash
maps.
2025-02-18 13:10:03 +00:00
Joachim Breitner
a3b76aa825 feat: fun_induction foo (no arguments) (#7101)
This PR implements `fun_induction foo`, which is like `fun_induction foo
x y z`, only that it picks the arguments to use from a unique suitable
call to `foo` in the goal.
2025-02-18 12:27:21 +00:00
825 changed files with 17385 additions and 10498 deletions

View File

@@ -764,11 +764,12 @@ Structures and Records
The ``structure`` command in Lean is used to define an inductive data type with a single constructor and to define its projections at the same time. The syntax is as follows:
```
structure Foo (a : α) extends Bar, Baz : Sort u :=
structure Foo (a : α) : Sort u extends Bar, Baz :=
constructor :: (field₁ : β₁) ... (fieldₙ : βₙ)
```
Here ``(a : α)`` is a telescope, that is, the parameters to the inductive definition. The name ``constructor`` followed by the double colon is optional; if it is not present, the name ``mk`` is used by default. The keyword ``extends`` followed by a list of previously defined structures is also optional; if it is present, an instance of each of these structures is included among the fields to ``Foo``, and the types ``βᵢ`` can refer to their fields as well. The output type, ``Sort u``, can be omitted, in which case Lean infers to smallest non-``Prop`` sort possible. Finally, ``(field₁ : β₁) ... (fieldₙ : βₙ)`` is a telescope relative to ``(a : α)`` and the fields in ``bar`` and ``baz``.
Here ``(a : α)`` is a telescope, that is, the parameters to the inductive definition. The name ``constructor`` followed by the double colon is optional; if it is not present, the name ``mk`` is used by default. The keyword ``extends`` followed by a list of previously defined structures is also optional; if it is present, an instance of each of these structures is included among the fields to ``Foo``, and the types ``βᵢ`` can refer to their fields as well. The output type, ``Sort u``, can be omitted, in which case Lean infers to smallest non-``Prop`` sort possible (unless all the fields are ``Prop``, in which case it infers ``Prop``).
Finally, ``(field₁ : β₁) ... (fieldₙ : βₙ)`` is a telescope relative to ``(a : α)`` and the fields in ``bar`` and ``baz``.
The declaration above is syntactic sugar for an inductive type declaration, and so results in the addition of the following constants to the environment:

View File

@@ -239,3 +239,22 @@ If an acronym is typically spelled using mixed case, this mixed spelling may be
Simp sets centered around a conversion function should be called `source_to_target`. For example, a simp set for the `BitVec.toNat` function, which goes from `BitVec` to
`Nat`, should be called `bitvec_to_nat`.
## Variable names
We make the following recommendations for variable names, but without insisting on them:
* Simple hypotheses should be named `h`, `h'`, or using a numerical sequence `h₁`, `h₂`, etc.
* Another common name for a simple hypothesis is `w` (for "witness").
* `List`s should be named `l`, `l'`, `l₁`, etc, or `as`, `bs`, etc.
(Use of `as`, `bs` is encouraged when the lists are of different types, e.g. `as : List α` and `bs : List β`.)
`xs`, `ys`, `zs` are allowed, but it is better if these are reserved for `Array` and `Vector`.
A list of lists may be named `L`.
* `Array`s should be named `xs`, `ys`, `zs`, although `as`, `bs` are encouraged when the arrays are of different types, e.g. `as : Array α` and `bs : Array β`.
An array of arrays may be named `xss`.
* `Vector`s should be named `xs`, `ys`, `zs`, although `as`, `bs` are encouraged when the vectors are of different types, e.g. `as : Vector α n` and `bs : Vector β n`.
A vector of vectors may be named `xss`.
* A common exception for `List` / `Array` / `Vector` is to use `acc` for an accumulator in a recursive function.
* `i`, `j`, `k` are preferred for numerical indices.
Descriptive names such as `start`, `stop`, `lo`, and `hi` are encouraged when they increase readability.
* `n`, `m` are preferred for sizes, e.g. in `Vector α n` or `xs.size = n`.
* `w` is preferred for the width of a `BitVec`.

View File

@@ -144,11 +144,12 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
# do not import the world from windows.h using appropriately named flag
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D WIN32_LEAN_AND_MEAN")
# DLLs must go next to executables on Windows
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_RELATIVE_LIBRARY_OUTPUT_DIRECTORY "bin")
else()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/lean")
set(CMAKE_RELATIVE_LIBRARY_OUTPUT_DIRECTORY "lib/lean")
endif()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_RELATIVE_LIBRARY_OUTPUT_DIRECTORY}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/lean")
# OSX default thread stack size is very small. Moreover, in Debug mode, each new stack frame consumes a lot of extra memory.

View File

@@ -78,7 +78,7 @@ Error recovery and state can interact subtly. For example, the implementation of
-/
-- NB: List instance is in mathlib. Once upstreamed, add
-- * `List`, where `failure` is the empty list and `<|>` concatenates.
class Alternative (f : Type u Type v) extends Applicative f : Type (max (u+1) v) where
class Alternative (f : Type u Type v) : Type (max (u+1) v) extends Applicative f where
/--
Produces an empty collection or recoverable failure. The `<|>` operator collects values or recovers
from failures. See `Alternative` for more details.

View File

@@ -47,7 +47,7 @@ pure f <*> pure x = pure (f x)
u <*> pure y = pure (· y) <*> u
```
-/
class LawfulApplicative (f : Type u Type v) [Applicative f] extends LawfulFunctor f : Prop where
class LawfulApplicative (f : Type u Type v) [Applicative f] : Prop extends LawfulFunctor f where
seqLeft_eq (x : f α) (y : f β) : x <* y = const β <$> x <*> y
seqRight_eq (x : f α) (y : f β) : x *> y = const α id <$> x <*> y
pure_seq (g : α β) (x : f α) : pure g <*> x = g <$> x
@@ -77,7 +77,7 @@ x >>= f >>= g = x >>= (fun x => f x >>= g)
`LawfulMonad.mk'` is an alternative constructor containing useful defaults for many fields.
-/
class LawfulMonad (m : Type u Type v) [Monad m] extends LawfulApplicative m : Prop where
class LawfulMonad (m : Type u Type v) [Monad m] : Prop extends LawfulApplicative m where
bind_pure_comp (f : α β) (x : m α) : x >>= (fun a => pure (f a)) = f <$> x
bind_map {α β : Type u} (f : m (α β)) (x : m α) : f >>= (. <$> x) = f <*> x
pure_bind (x : α) (f : α m β) : pure x >>= f = f x

View File

@@ -2020,7 +2020,7 @@ free variables. The frontend automatically declares a fresh auxiliary constant `
Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base.
This is extra 30k lines of code. More importantly, you will probably not be able to check your development using
external type checkers (e.g., Trepplein) that do not implement this feature.
external type checkers that do not implement this feature.
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
So, you are mainly losing the capability of type checking your development using external checkers.
@@ -2055,7 +2055,7 @@ decidability instance can be evaluated to `true` using the lean compiler / inter
Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base.
This is extra 30k lines of code. More importantly, you will probably not be able to check your development using
external type checkers (e.g., Trepplein) that do not implement this feature.
external type checkers that do not implement this feature.
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
So, you are mainly losing the capability of type checking your development using external checkers.
-/
@@ -2066,7 +2066,7 @@ The axiom `ofReduceNat` is used to perform proofs by reflection. See `reduceBool
Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base.
This is extra 30k lines of code. More importantly, you will probably not be able to check your development using
external type checkers (e.g., Trepplein) that do not implement this feature.
external type checkers that do not implement this feature.
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
So, you are mainly losing the capability of type checking your development using external checkers.
-/
@@ -2125,7 +2125,7 @@ class LeftIdentity (op : α → β → β) (o : outParam α) : Prop
`LawfulLeftIdentify op o` indicates `o` is a verified left identity of
`op`.
-/
class LawfulLeftIdentity (op : α β β) (o : outParam α) extends LeftIdentity op o : Prop where
class LawfulLeftIdentity (op : α β β) (o : outParam α) : Prop extends LeftIdentity op o where
/-- Left identity `o` is an identity. -/
left_id : a, op o a = a
@@ -2141,7 +2141,7 @@ class RightIdentity (op : α → β → α) (o : outParam β) : Prop
`LawfulRightIdentify op o` indicates `o` is a verified right identity of
`op`.
-/
class LawfulRightIdentity (op : α β α) (o : outParam β) extends RightIdentity op o : Prop where
class LawfulRightIdentity (op : α β α) (o : outParam β) : Prop extends RightIdentity op o where
/-- Right identity `o` is an identity. -/
right_id : a, op a o = a
@@ -2151,13 +2151,13 @@ class LawfulRightIdentity (op : α → β → α) (o : outParam β) extends Righ
This class does not require a proof that `o` is an identity, and is used
primarily for inferring the identity using class resolution.
-/
class Identity (op : α α α) (o : outParam α) extends LeftIdentity op o, RightIdentity op o : Prop
class Identity (op : α α α) (o : outParam α) : Prop extends LeftIdentity op o, RightIdentity op o
/--
`LawfulIdentity op o` indicates `o` is a verified left and right
identity of `op`.
-/
class LawfulIdentity (op : α α α) (o : outParam α) extends Identity op o, LawfulLeftIdentity op o, LawfulRightIdentity op o : Prop
class LawfulIdentity (op : α α α) (o : outParam α) : Prop extends Identity op o, LawfulLeftIdentity op o, LawfulRightIdentity op o
/--
`LawfulCommIdentity` can simplify defining instances of `LawfulIdentity`
@@ -2168,7 +2168,7 @@ This class is intended for simplifying defining instances of
`LawfulIdentity` and functions needed commutative operations with
identity should just add a `LawfulIdentity` constraint.
-/
class LawfulCommIdentity (op : α α α) (o : outParam α) [hc : Commutative op] extends LawfulIdentity op o : Prop where
class LawfulCommIdentity (op : α α α) (o : outParam α) [hc : Commutative op] : Prop extends LawfulIdentity op o where
left_id a := Eq.trans (hc.comm o a) (right_id a)
right_id a := Eq.trans (hc.comm a o) (left_id a)

View File

@@ -9,6 +9,9 @@ import Init.Data.Array.Lemmas
import Init.Data.Array.Count
import Init.Data.List.Attach
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/--
@@ -19,8 +22,8 @@ to apply `f`.
We replace this at runtime with a more efficient version via the `csimp` lemma `pmap_eq_pmapImpl`.
-/
def pmap {P : α Prop} (f : a, P a β) (l : Array α) (H : a l, P a) : Array β :=
(l.toList.pmap f (fun a m => H a (mem_def.mpr m))).toArray
def pmap {P : α Prop} (f : a, P a β) (xs : Array α) (H : a xs, P a) : Array β :=
(xs.toList.pmap f (fun a m => H a (mem_def.mpr m))).toArray
/--
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
@@ -51,25 +54,25 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
l.toArray.pmap f H = (l.pmap f (by simpa using H)).toArray := by
simp [pmap]
@[simp] theorem toList_attachWith {l : Array α} {P : α Prop} {H : x l, P x} :
(l.attachWith P H).toList = l.toList.attachWith P (by simpa [mem_toList] using H) := by
@[simp] theorem toList_attachWith {xs : Array α} {P : α Prop} {H : x xs, P x} :
(xs.attachWith P H).toList = xs.toList.attachWith P (by simpa [mem_toList] using H) := by
simp [attachWith]
@[simp] theorem toList_attach {α : Type _} {l : Array α} :
l.attach.toList = l.toList.attachWith (· l) (by simp [mem_toList]) := by
@[simp] theorem toList_attach {xs : Array α} :
xs.attach.toList = xs.toList.attachWith (· xs) (by simp [mem_toList]) := by
simp [attach]
@[simp] theorem toList_pmap {l : Array α} {P : α Prop} {f : a, P a β} {H : a l, P a} :
(l.pmap f H).toList = l.toList.pmap f (fun a m => H a (mem_def.mpr m)) := by
@[simp] theorem toList_pmap {xs : Array α} {P : α Prop} {f : a, P a β} {H : a xs, P a} :
(xs.pmap f H).toList = xs.toList.pmap f (fun a m => H a (mem_def.mpr m)) := by
simp [pmap]
/-- Implementation of `pmap` using the zero-copy version of `attach`. -/
@[inline] private def pmapImpl {P : α Prop} (f : a, P a β) (l : Array α) (H : a l, P a) :
Array β := (l.attachWith _ H).map fun x, h' => f x h'
@[inline] private def pmapImpl {P : α Prop} (f : a, P a β) (xs : Array α) (H : a xs, P a) :
Array β := (xs.attachWith _ H).map fun x, h' => f x h'
@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by
funext α β p f L h'
cases L
funext α β p f xs H
cases xs
simp only [pmap, pmapImpl, List.attachWith_toArray, List.map_toArray, mk.injEq, List.map_attachWith_eq_pmap]
apply List.pmap_congr_left
intro a m h₁ h₂
@@ -77,9 +80,9 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
@[simp] theorem pmap_empty {P : α Prop} (f : a, P a β) : pmap f #[] (by simp) = #[] := rfl
@[simp] theorem pmap_push {P : α Prop} (f : a, P a β) (a : α) (l : Array α) (h : b l.push a, P b) :
pmap f (l.push a) h =
(pmap f l (fun a m => by simp at h; exact h a (.inl m))).push (f a (h a (by simp))) := by
@[simp] theorem pmap_push {P : α Prop} (f : a, P a β) (a : α) (xs : Array α) (h : b xs.push a, P b) :
pmap f (xs.push a) h =
(pmap f xs (fun a m => by simp at h; exact h a (.inl m))).push (f a (h a (by simp))) := by
simp [pmap]
@[simp] theorem attach_empty : (#[] : Array α).attach = #[] := rfl
@@ -94,158 +97,158 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
simp
@[simp]
theorem pmap_eq_map (p : α Prop) (f : α β) (l : Array α) (H) :
@pmap _ _ p (fun a _ => f a) l H = map f l := by
cases l; simp
theorem pmap_eq_map (p : α Prop) (f : α β) (xs : Array α) (H) :
@pmap _ _ p (fun a _ => f a) xs H = map f xs := by
cases xs; simp
theorem pmap_congr_left {p q : α Prop} {f : a, p a β} {g : a, q a β} (l : Array α) {H₁ H₂}
(h : a l, (h₁ h₂), f a h₁ = g a h₂) : pmap f l H₁ = pmap g l H₂ := by
cases l
theorem pmap_congr_left {p q : α Prop} {f : a, p a β} {g : a, q a β} (xs : Array α) {H₁ H₂}
(h : a xs, (h₁ h₂), f a h₁ = g a h₂) : pmap f xs H₁ = pmap g xs H₂ := by
cases xs
simp only [mem_toArray] at h
simp only [List.pmap_toArray, mk.injEq]
rw [List.pmap_congr_left _ h]
theorem map_pmap {p : α Prop} (g : β γ) (f : a, p a β) (l H) :
map g (pmap f l H) = pmap (fun a h => g (f a h)) l H := by
cases l
theorem map_pmap {p : α Prop} (g : β γ) (f : a, p a β) (xs H) :
map g (pmap f xs H) = pmap (fun a h => g (f a h)) xs H := by
cases xs
simp [List.map_pmap]
theorem pmap_map {p : β Prop} (g : b, p b γ) (f : α β) (l H) :
pmap g (map f l) H = pmap (fun a h => g (f a) h) l fun _ h => H _ (mem_map_of_mem _ h) := by
cases l
theorem pmap_map {p : β Prop} (g : b, p b γ) (f : α β) (xs H) :
pmap g (map f xs) H = pmap (fun a h => g (f a) h) xs fun _ h => H _ (mem_map_of_mem _ h) := by
cases xs
simp [List.pmap_map]
theorem attach_congr {l₁ l₂ : Array α} (h : l₁ = l₂) :
l₁.attach = l₂.attach.map (fun x => x.1, h x.2) := by
theorem attach_congr {xs ys : Array α} (h : xs = ys) :
xs.attach = ys.attach.map (fun x => x.1, h x.2) := by
subst h
simp
theorem attachWith_congr {l₁ l₂ : Array α} (w : l₁ = l₂) {P : α Prop} {H : x l₁, P x} :
l₁.attachWith P H = l₂.attachWith P fun _ h => H _ (w h) := by
theorem attachWith_congr {xs ys : Array α} (w : xs = ys) {P : α Prop} {H : x xs, P x} :
xs.attachWith P H = ys.attachWith P fun _ h => H _ (w h) := by
subst w
simp
@[simp] theorem attach_push {a : α} {l : Array α} :
(l.push a).attach =
(l.attach.map (fun x, h => x, mem_push_of_mem a h)).push a, by simp := by
cases l
@[simp] theorem attach_push {a : α} {xs : Array α} :
(xs.push a).attach =
(xs.attach.map (fun x, h => x, mem_push_of_mem a h)).push a, by simp := by
cases xs
rw [attach_congr (List.push_toArray _ _)]
simp [Function.comp_def]
@[simp] theorem attachWith_push {a : α} {l : Array α} {P : α Prop} {H : x l.push a, P x} :
(l.push a).attachWith P H =
(l.attachWith P (fun x h => by simp at H; exact H x (.inl h))).push a, H a (by simp) := by
cases l
@[simp] theorem attachWith_push {a : α} {xs : Array α} {P : α Prop} {H : x xs.push a, P x} :
(xs.push a).attachWith P H =
(xs.attachWith P (fun x h => by simp at H; exact H x (.inl h))).push a, H a (by simp) := by
cases xs
simp [attachWith_congr (List.push_toArray _ _)]
theorem pmap_eq_map_attach {p : α Prop} (f : a, p a β) (l H) :
pmap f l H = l.attach.map fun x => f x.1 (H _ x.2) := by
cases l
theorem pmap_eq_map_attach {p : α Prop} (f : a, p a β) (xs H) :
pmap f xs H = xs.attach.map fun x => f x.1 (H _ x.2) := by
cases xs
simp [List.pmap_eq_map_attach]
@[simp]
theorem pmap_eq_attachWith {p q : α Prop} (f : a, p a q a) (l H) :
pmap (fun a h => a, f a h) l H = l.attachWith q (fun x h => f x (H x h)) := by
cases l
theorem pmap_eq_attachWith {p q : α Prop} (f : a, p a q a) (xs H) :
pmap (fun a h => a, f a h) xs H = xs.attachWith q (fun x h => f x (H x h)) := by
cases xs
simp [List.pmap_eq_attachWith]
theorem attach_map_val (l : Array α) (f : α β) :
(l.attach.map fun (i : {i // i l}) => f i) = l.map f := by
cases l
theorem attach_map_val (xs : Array α) (f : α β) :
(xs.attach.map fun (i : {i // i xs}) => f i) = xs.map f := by
cases xs
simp
@[deprecated attach_map_val (since := "2025-02-17")]
abbrev attach_map_coe := @attach_map_val
theorem attach_map_subtype_val (l : Array α) : l.attach.map Subtype.val = l := by
cases l; simp
theorem attach_map_subtype_val (xs : Array α) : xs.attach.map Subtype.val = xs := by
cases xs; simp
theorem attachWith_map_val {p : α Prop} (f : α β) (l : Array α) (H : a l, p a) :
((l.attachWith p H).map fun (i : { i // p i}) => f i) = l.map f := by
cases l; simp
theorem attachWith_map_val {p : α Prop} (f : α β) (xs : Array α) (H : a xs, p a) :
((xs.attachWith p H).map fun (i : { i // p i}) => f i) = xs.map f := by
cases xs; simp
@[deprecated attachWith_map_val (since := "2025-02-17")]
abbrev attachWith_map_coe := @attachWith_map_val
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
theorem attachWith_map_subtype_val {p : α Prop} (xs : Array α) (H : a xs, p a) :
(xs.attachWith p H).map Subtype.val = xs := by
cases xs; simp
@[simp]
theorem mem_attach (l : Array α) : x, x l.attach
theorem mem_attach (xs : Array α) : x, x xs.attach
| a, h => by
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
rcases this with _, _, m, rfl
exact m
@[simp]
theorem mem_attachWith (l : Array α) {q : α Prop} (H) (x : {x // q x}) :
x l.attachWith q H x.1 l := by
cases l
theorem mem_attachWith (xs : Array α) {q : α Prop} (H) (x : {x // q x}) :
x xs.attachWith q H x.1 xs := by
cases xs
simp
@[simp]
theorem mem_pmap {p : α Prop} {f : a, p a β} {l H b} :
b pmap f l H (a : _) (h : a l), f a (H a h) = b := by
theorem mem_pmap {p : α Prop} {f : a, p a β} {xs H b} :
b pmap f xs H (a : _) (h : a xs), f a (H a h) = b := by
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
theorem mem_pmap_of_mem {p : α Prop} {f : a, p a β} {l H} {a} (h : a l) :
f a (H a h) pmap f l H := by
theorem mem_pmap_of_mem {p : α Prop} {f : a, p a β} {xs H} {a} (h : a xs) :
f a (H a h) pmap f xs H := by
rw [mem_pmap]
exact a, h, rfl
@[simp]
theorem size_pmap {p : α Prop} {f : a, p a β} {l H} : (pmap f l H).size = l.size := by
cases l; simp
theorem size_pmap {p : α Prop} {f : a, p a β} {xs H} : (pmap f xs H).size = xs.size := by
cases xs; simp
@[simp]
theorem size_attach {L : Array α} : L.attach.size = L.size := by
cases L; simp
theorem size_attach {xs : Array α} : xs.attach.size = xs.size := by
cases xs; simp
@[simp]
theorem size_attachWith {p : α Prop} {l : Array α} {H} : (l.attachWith p H).size = l.size := by
cases l; simp
theorem size_attachWith {p : α Prop} {xs : Array α} {H} : (xs.attachWith p H).size = xs.size := by
cases xs; simp
@[simp]
theorem pmap_eq_empty_iff {p : α Prop} {f : a, p a β} {l H} : pmap f l H = #[] l = #[] := by
cases l; simp
theorem pmap_eq_empty_iff {p : α Prop} {f : a, p a β} {xs H} : pmap f xs H = #[] xs = #[] := by
cases xs; simp
theorem pmap_ne_empty_iff {P : α Prop} (f : (a : α) P a β) {xs : Array α}
(H : (a : α), a xs P a) : xs.pmap f H #[] xs #[] := by
cases xs; simp
theorem pmap_eq_self {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]
theorem pmap_eq_self {xs : Array α} {p : α Prop} {hp : (a : α), a xs p a}
{f : (a : α) p a α} : xs.pmap f hp = xs a (h : a xs), f a (hp a h) = a := by
cases xs; simp [List.pmap_eq_self]
@[simp]
theorem attach_eq_empty_iff {l : Array α} : l.attach = #[] l = #[] := by
cases l; simp
theorem attach_eq_empty_iff {xs : Array α} : xs.attach = #[] xs = #[] := by
cases xs; simp
theorem attach_ne_empty_iff {l : Array α} : l.attach #[] l #[] := by
cases l; simp
theorem attach_ne_empty_iff {xs : Array α} : xs.attach #[] xs #[] := by
cases xs; simp
@[simp]
theorem attachWith_eq_empty_iff {l : Array α} {P : α Prop} {H : a l, P a} :
l.attachWith P H = #[] l = #[] := by
cases l; simp
theorem attachWith_eq_empty_iff {xs : Array α} {P : α Prop} {H : a xs, P a} :
xs.attachWith P H = #[] xs = #[] := by
cases xs; simp
theorem attachWith_ne_empty_iff {l : Array α} {P : α Prop} {H : a l, P a} :
l.attachWith P H #[] l #[] := by
cases l; simp
theorem attachWith_ne_empty_iff {xs : Array α} {P : α Prop} {H : a xs, P a} :
xs.attachWith P H #[] xs #[] := by
cases xs; simp
@[simp]
theorem getElem?_pmap {p : α Prop} (f : a, p a β) {l : Array α} (h : a l, p a) (i : Nat) :
(pmap f l h)[i]? = Option.pmap f l[i]? fun x H => h x (mem_of_getElem? H) := by
cases l; simp
theorem getElem?_pmap {p : α Prop} (f : a, p a β) {xs : Array α} (h : a xs, p a) (i : Nat) :
(pmap f xs h)[i]? = Option.pmap f xs[i]? fun x H => h x (mem_of_getElem? H) := by
cases xs; simp
@[simp]
theorem getElem_pmap {p : α Prop} (f : a, p a β) {l : Array α} (h : a l, p a) {i : Nat}
(hi : i < (pmap f l h).size) :
(pmap f l h)[i] =
f (l[i]'(@size_pmap _ _ p f l h hi))
(h _ (getElem_mem (@size_pmap _ _ p f l h hi))) := by
cases l; simp
theorem getElem_pmap {p : α Prop} (f : a, p a β) {xs : Array α} (h : a xs, p a) {i : Nat}
(hi : i < (pmap f xs h).size) :
(pmap f xs h)[i] =
f (xs[i]'(@size_pmap _ _ p f xs h hi))
(h _ (getElem_mem (@size_pmap _ _ p f xs h hi))) := by
cases xs; simp
@[simp]
theorem getElem?_attachWith {xs : Array α} {i : Nat} {P : α Prop} {H : a xs, P a} :
@@ -268,40 +271,40 @@ theorem getElem_attach {xs : Array α} {i : Nat} (h : i < xs.attach.size) :
xs.attach[i] = xs[i]'(by simpa using h), getElem_mem (by simpa using h) :=
getElem_attachWith h
@[simp] theorem pmap_attach (l : Array α) {p : {x // x l} Prop} (f : a, p a β) (H) :
pmap f l.attach H =
l.pmap (P := fun a => h : a l, p a, h)
@[simp] theorem pmap_attach (xs : Array α) {p : {x // x xs} Prop} (f : a, p a β) (H) :
pmap f xs.attach H =
xs.pmap (P := fun a => h : a xs, p a, h)
(fun a h => f a, h.1 h.2) (fun a h => h, H a, h (by simp)) := by
ext <;> simp
@[simp] theorem pmap_attachWith (l : Array α) {p : {x // q x} Prop} (f : a, p a β) (H₁ H₂) :
pmap f (l.attachWith q H₁) H₂ =
l.pmap (P := fun a => h : q a, p a, h)
@[simp] theorem pmap_attachWith (xs : Array α) {p : {x // q x} Prop} (f : a, p a β) (H₁ H₂) :
pmap f (xs.attachWith q H₁) H₂ =
xs.pmap (P := fun a => h : q a, p a, h)
(fun a h => f a, h.1 h.2) (fun a h => H₁ _ h, H₂ a, H₁ _ h (by simpa)) := by
ext <;> simp
theorem foldl_pmap (l : Array α) {P : α Prop} (f : (a : α) P a β)
(H : (a : α), a l P a) (g : γ β γ) (x : γ) :
(l.pmap f H).foldl g x = l.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
theorem foldl_pmap (xs : Array α) {P : α Prop} (f : (a : α) P a β)
(H : (a : α), a xs P a) (g : γ β γ) (x : γ) :
(xs.pmap f H).foldl g x = xs.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
rw [pmap_eq_map_attach, foldl_map]
theorem foldr_pmap (l : Array α) {P : α Prop} (f : (a : α) P a β)
(H : (a : α), a l P a) (g : β γ γ) (x : γ) :
(l.pmap f H).foldr g x = l.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
theorem foldr_pmap (xs : Array α) {P : α Prop} (f : (a : α) P a β)
(H : (a : α), a xs P a) (g : β γ γ) (x : γ) :
(xs.pmap f H).foldr g x = xs.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
rw [pmap_eq_map_attach, foldr_map]
@[simp] theorem foldl_attachWith
(l : Array α) {q : α Prop} (H : a, a l q a) {f : β { x // q x} β} {b} (w : stop = l.size) :
(l.attachWith q H).foldl f b 0 stop = l.attach.foldl (fun b a, h => f b a, H _ h) b := by
(xs : Array α) {q : α Prop} (H : a, a xs q a) {f : β { x // q x} β} {b} (w : stop = xs.size) :
(xs.attachWith q H).foldl f b 0 stop = xs.attach.foldl (fun b a, h => f b a, H _ h) b := by
subst w
rcases l with l
rcases xs with xs
simp [List.foldl_attachWith, List.foldl_map]
@[simp] theorem foldr_attachWith
(l : Array α) {q : α Prop} (H : a, a l q a) {f : { x // q x} β β} {b} (w : start = l.size) :
(l.attachWith q H).foldr f b start 0 = l.attach.foldr (fun a acc => f a.1, H _ a.2 acc) b := by
(xs : Array α) {q : α Prop} (H : a, a xs q a) {f : { x // q x} β β} {b} (w : start = xs.size) :
(xs.attachWith q H).foldr f b start 0 = xs.attach.foldr (fun a acc => f a.1, H _ a.2 acc) b := by
subst w
rcases l with l
rcases xs with xs
simp [List.foldr_attachWith, List.foldr_map]
/--
@@ -314,9 +317,9 @@ Unfortunately this can't be applied by `simp` because of the higher order unific
and even when rewriting we need to specify the function explicitly.
See however `foldl_subtype` below.
-/
theorem foldl_attach (l : Array α) (f : β α β) (b : β) :
l.attach.foldl (fun acc t => f acc t.1) b = l.foldl f b := by
rcases l with l
theorem foldl_attach (xs : Array α) (f : β α β) (b : β) :
xs.attach.foldl (fun acc t => f acc t.1) b = xs.foldl f b := by
rcases xs with xs
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
List.length_pmap, List.foldl_toArray', mem_toArray, List.foldl_subtype]
congr
@@ -333,101 +336,101 @@ Unfortunately this can't be applied by `simp` because of the higher order unific
and even when rewriting we need to specify the function explicitly.
See however `foldr_subtype` below.
-/
theorem foldr_attach (l : Array α) (f : α β β) (b : β) :
l.attach.foldr (fun t acc => f t.1 acc) b = l.foldr f b := by
rcases l with l
theorem foldr_attach (xs : Array α) (f : α β β) (b : β) :
xs.attach.foldr (fun t acc => f t.1 acc) b = xs.foldr f b := by
rcases xs with xs
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
List.length_pmap, List.foldr_toArray', mem_toArray, List.foldr_subtype]
congr
ext
simpa using fun a => List.mem_of_getElem? a
theorem attach_map {l : Array α} (f : α β) :
(l.map f).attach = l.attach.map (fun x, h => f x, mem_map_of_mem f h) := by
cases l
theorem attach_map {xs : Array α} (f : α β) :
(xs.map f).attach = xs.attach.map (fun x, h => f x, mem_map_of_mem f h) := by
cases xs
ext <;> simp
theorem attachWith_map {l : Array α} (f : α β) {P : β Prop} {H : (b : β), b l.map f P b} :
(l.map f).attachWith P H = (l.attachWith (P f) (fun _ h => H _ (mem_map_of_mem f h))).map
theorem attachWith_map {xs : Array α} (f : α β) {P : β Prop} {H : (b : β), b xs.map f P b} :
(xs.map f).attachWith P H = (xs.attachWith (P f) (fun _ h => H _ (mem_map_of_mem f h))).map
fun x, h => f x, h := by
cases l
cases xs
simp [List.attachWith_map]
@[simp] theorem map_attachWith {l : Array α} {P : α Prop} {H : (a : α), a l P a}
@[simp] theorem map_attachWith {xs : Array α} {P : α Prop} {H : (a : α), a xs P a}
(f : { x // P x } β) :
(l.attachWith P H).map f = l.attach.map fun x, h => f x, H _ h := by
cases l <;> simp_all
(xs.attachWith P H).map f = xs.attach.map fun x, h => f x, H _ h := by
cases xs <;> simp_all
theorem map_attachWith_eq_pmap {l : Array α} {P : α Prop} {H : (a : α), a l P a}
theorem map_attachWith_eq_pmap {xs : Array α} {P : α Prop} {H : (a : α), a xs P a}
(f : { x // P x } β) :
(l.attachWith P H).map f =
l.pmap (fun a (h : a l P a) => f a, H _ h.1) (fun a h => h, H a h) := by
cases l
(xs.attachWith P H).map f =
xs.pmap (fun a (h : a xs P a) => f a, H _ h.1) (fun a h => h, H a h) := by
cases xs
ext <;> simp
/-- See also `pmap_eq_map_attach` for writing `pmap` in terms of `map` and `attach`. -/
theorem map_attach_eq_pmap {l : Array α} (f : { x // x l } β) :
l.attach.map f = l.pmap (fun a h => f a, h) (fun _ => id) := by
cases l
theorem map_attach_eq_pmap {xs : Array α} (f : { x // x xs } β) :
xs.attach.map f = xs.pmap (fun a h => f a, h) (fun _ => id) := by
cases xs
ext <;> simp
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
abbrev map_attach := @map_attach_eq_pmap
theorem attach_filterMap {l : Array α} {f : α Option β} :
(l.filterMap f).attach = l.attach.filterMap
theorem attach_filterMap {xs : Array α} {f : α Option β} :
(xs.filterMap f).attach = xs.attach.filterMap
fun x, h => (f x).pbind (fun b m => some b, mem_filterMap.mpr x, h, m) := by
cases l
cases xs
rw [attach_congr (List.filterMap_toArray f _)]
simp [List.attach_filterMap, List.map_filterMap, Function.comp_def]
theorem attach_filter {l : Array α} (p : α Bool) :
(l.filter p).attach = l.attach.filterMap
theorem attach_filter {xs : Array α} (p : α Bool) :
(xs.filter p).attach = xs.attach.filterMap
fun x => if w : p x.1 then some x.1, mem_filter.mpr x.2, w else none := by
cases l
cases xs
rw [attach_congr (List.filter_toArray p _)]
simp [List.attach_filter, List.map_filterMap, Function.comp_def]
-- We are still missing here `attachWith_filterMap` and `attachWith_filter`.
@[simp]
theorem filterMap_attachWith {q : α Prop} {l : Array α} {f : {x // q x} Option β} (H)
(w : stop = (l.attachWith q H).size) :
(l.attachWith q H).filterMap f 0 stop = l.attach.filterMap (fun x, h => f x, H _ h) := by
theorem filterMap_attachWith {q : α Prop} {xs : Array α} {f : {x // q x} Option β} (H)
(w : stop = (xs.attachWith q H).size) :
(xs.attachWith q H).filterMap f 0 stop = xs.attach.filterMap (fun x, h => f x, H _ h) := by
subst w
cases l
cases xs
simp [Function.comp_def]
@[simp]
theorem filter_attachWith {q : α Prop} {l : Array α} {p : {x // q x} Bool} (H)
(w : stop = (l.attachWith q H).size) :
(l.attachWith q H).filter p 0 stop =
(l.attach.filter (fun x, h => p x, H _ h)).map (fun x, h => x, H _ h) := by
theorem filter_attachWith {q : α Prop} {xs : Array α} {p : {x // q x} Bool} (H)
(w : stop = (xs.attachWith q H).size) :
(xs.attachWith q H).filter p 0 stop =
(xs.attach.filter (fun x, h => p x, H _ h)).map (fun x, h => x, H _ h) := by
subst w
cases l
cases xs
simp [Function.comp_def, List.filter_map]
theorem pmap_pmap {p : α Prop} {q : β Prop} (g : a, p a β) (f : b, q b γ) (l H₁ H₂) :
pmap f (pmap g l H₁) H₂ =
pmap (α := { x // x l }) (fun a h => f (g a h) (H₂ (g a h) (mem_pmap_of_mem a.2))) l.attach
theorem pmap_pmap {p : α Prop} {q : β Prop} (g : a, p a β) (f : b, q b γ) (xs H₁ H₂) :
pmap f (pmap g xs H₁) H₂ =
pmap (α := { x // x xs }) (fun a h => f (g a h) (H₂ (g a h) (mem_pmap_of_mem a.2))) xs.attach
(fun a _ => H₁ a a.2) := by
cases l
cases xs
simp [List.pmap_pmap, List.pmap_map]
@[simp] theorem pmap_append {p : ι Prop} (f : a : ι, p a α) (l₁ l₂ : Array ι)
(h : a l₁ ++ l₂, p a) :
(l₁ ++ l₂).pmap f h =
(l₁.pmap f fun a ha => h a (mem_append_left l₂ ha)) ++
l₂.pmap f fun a ha => h a (mem_append_right l₁ ha) := by
cases l₁
cases l₂
@[simp] theorem pmap_append {p : ι Prop} (f : a : ι, p a α) (xs ys : Array ι)
(h : a xs ++ ys, p a) :
(xs ++ ys).pmap f h =
(xs.pmap f fun a ha => h a (mem_append_left ys ha)) ++
ys.pmap f fun a ha => h a (mem_append_right xs ha) := by
cases xs
cases ys
simp
theorem pmap_append' {p : α Prop} (f : a : α, p a β) (l₁ l₂ : Array α)
(h₁ : a l₁, p a) (h₂ : a l₂, p a) :
((l₁ ++ l₂).pmap f fun a ha => (mem_append.1 ha).elim (h₁ a) (h₂ a)) =
l₁.pmap f h₁ ++ l₂.pmap f h₂ :=
pmap_append f l₁ l₂ _
theorem pmap_append' {p : α Prop} (f : a : α, p a β) (xs ys : Array α)
(h₁ : a xs, p a) (h₂ : a ys, p a) :
((xs ++ ys).pmap f fun a ha => (mem_append.1 ha).elim (h₁ a) (h₂ a)) =
xs.pmap f h₁ ++ ys.pmap f h₂ :=
pmap_append f xs ys _
@[simp] theorem attach_append (xs ys : Array α) :
(xs ++ ys).attach = xs.attach.map (fun x, h => x, mem_append_left ys h) ++
@@ -496,35 +499,35 @@ theorem back?_attach {xs : Array α} :
simp
@[simp]
theorem countP_attach (l : Array α) (p : α Bool) :
l.attach.countP (fun a : {x // x l} => p a) = l.countP p := by
cases l
theorem countP_attach (xs : Array α) (p : α Bool) :
xs.attach.countP (fun a : {x // x xs} => p a) = xs.countP p := by
cases xs
simp [Function.comp_def]
@[simp]
theorem countP_attachWith {p : α Prop} (l : Array α) (H : a l, p a) (q : α Bool) :
(l.attachWith p H).countP (fun a : {x // p x} => q a) = l.countP q := by
cases l
theorem countP_attachWith {p : α Prop} (xs : Array α) (H : a xs, p a) (q : α Bool) :
(xs.attachWith p H).countP (fun a : {x // p x} => q a) = xs.countP q := by
cases xs
simp
@[simp]
theorem count_attach [DecidableEq α] (l : Array α) (a : {x // x l}) :
l.attach.count a = l.count a := by
rcases l with l
theorem count_attach [DecidableEq α] (xs : Array α) (a : {x // x xs}) :
xs.attach.count a = xs.count a := by
rcases xs with xs
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.count_toArray]
rw [List.map_attach_eq_pmap, List.count_eq_countP]
simp only [Subtype.beq_iff]
rw [List.countP_pmap, List.countP_attach (p := (fun x => x == a.1)), List.count]
@[simp]
theorem count_attachWith [DecidableEq α] {p : α Prop} (l : Array α) (H : a l, p a) (a : {x // p x}) :
(l.attachWith p H).count a = l.count a := by
cases l
theorem count_attachWith [DecidableEq α] {p : α Prop} (xs : Array α) (H : a xs, p a) (a : {x // p x}) :
(xs.attachWith p H).count a = xs.count a := by
cases xs
simp
@[simp] theorem countP_pmap {p : α Prop} (g : a, p a β) (f : β Bool) (l : Array α) (H₁) :
(l.pmap g H₁).countP f =
l.attach.countP (fun a, m => f (g a (H₁ a m))) := by
@[simp] theorem countP_pmap {p : α Prop} (g : a, p a β) (f : β Bool) (xs : Array α) (H₁) :
(xs.pmap g H₁).countP f =
xs.attach.countP (fun a, m => f (g a (H₁ a m))) := by
simp [pmap_eq_map_attach, countP_map, Function.comp_def]
/-! ## unattach
@@ -545,43 +548,43 @@ and is ideally subsequently simplified away by `unattach_attach`.
If not, usually the right approach is `simp [Array.unattach, -Array.map_subtype]` to unfold.
-/
def unattach {α : Type _} {p : α Prop} (l : Array { x // p x }) : Array α := l.map (·.val)
def unattach {α : Type _} {p : α Prop} (xs : Array { x // p x }) : Array α := xs.map (·.val)
@[simp] theorem unattach_nil {p : α Prop} : (#[] : Array { x // p x }).unattach = #[] := rfl
@[simp] theorem unattach_push {p : α Prop} {a : { x // p x }} {l : Array { x // p x }} :
(l.push a).unattach = l.unattach.push a.1 := by
@[simp] theorem unattach_push {p : α Prop} {a : { x // p x }} {xs : Array { x // p x }} :
(xs.push a).unattach = xs.unattach.push a.1 := by
simp only [unattach, Array.map_push]
@[simp] theorem size_unattach {p : α Prop} {l : Array { x // p x }} :
l.unattach.size = l.size := by
@[simp] theorem size_unattach {p : α Prop} {xs : Array { x // p x }} :
xs.unattach.size = xs.size := by
unfold unattach
simp
@[simp] theorem _root_.List.unattach_toArray {p : α Prop} {l : List { x // p x }} :
l.toArray.unattach = l.unattach.toArray := by
@[simp] theorem _root_.List.unattach_toArray {p : α Prop} {xs : List { x // p x }} :
xs.toArray.unattach = xs.unattach.toArray := by
simp only [unattach, List.map_toArray, List.unattach]
@[simp] theorem toList_unattach {p : α Prop} {l : Array { x // p x }} :
l.unattach.toList = l.toList.unattach := by
@[simp] theorem toList_unattach {p : α Prop} {xs : Array { x // p x }} :
xs.unattach.toList = xs.toList.unattach := by
simp only [unattach, toList_map, List.unattach]
@[simp] theorem unattach_attach {l : Array α} : l.attach.unattach = l := by
cases l
@[simp] theorem unattach_attach {xs : Array α} : xs.attach.unattach = xs := by
cases xs
simp only [List.attach_toArray, List.unattach_toArray, List.unattach_attachWith]
@[simp] theorem unattach_attachWith {p : α Prop} {l : Array α}
{H : a l, p a} :
(l.attachWith p H).unattach = l := by
cases l
@[simp] theorem unattach_attachWith {p : α Prop} {xs : Array α}
{H : a xs, p a} :
(xs.attachWith p H).unattach = xs := by
cases xs
simp
@[simp] theorem getElem?_unattach {p : α Prop} {l : Array { x // p x }} (i : Nat) :
l.unattach[i]? = l[i]?.map Subtype.val := by
@[simp] theorem getElem?_unattach {p : α Prop} {xs : Array { x // p x }} (i : Nat) :
xs.unattach[i]? = xs[i]?.map Subtype.val := by
simp [unattach]
@[simp] theorem getElem_unattach
{p : α Prop} {l : Array { x // p x }} (i : Nat) (h : i < l.unattach.size) :
l.unattach[i] = (l[i]'(by simpa using h)).1 := by
{p : α Prop} {xs : Array { x // p x }} (i : Nat) (h : i < xs.unattach.size) :
xs.unattach[i] = (xs[i]'(by simpa using h)).1 := by
simp [unattach]
/-! ### Recognizing higher order functions using a function that only depends on the value. -/
@@ -590,20 +593,20 @@ def unattach {α : Type _} {p : α → Prop} (l : Array { x // p x }) : Array α
This lemma identifies folds over arrays of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
theorem foldl_subtype {p : α Prop} {l : Array { x // p x }}
theorem foldl_subtype {p : α Prop} {xs : Array { x // p x }}
{f : β { x // p x } β} {g : β α β} {x : β}
(hf : b x h, f b x, h = g b x) :
l.foldl f x = l.unattach.foldl g x := by
cases l
xs.foldl f x = xs.unattach.foldl g x := by
cases xs
simp only [List.foldl_toArray', List.unattach_toArray]
rw [List.foldl_subtype] -- Why can't simp do this?
simp [hf]
/-- Variant of `foldl_subtype` with side condition to check `stop = l.size`. -/
@[simp] theorem foldl_subtype' {p : α Prop} {l : Array { x // p x }}
@[simp] theorem foldl_subtype' {p : α Prop} {xs : Array { x // p x }}
{f : β { x // p x } β} {g : β α β} {x : β}
(hf : b x h, f b x, h = g b x) (h : stop = l.size) :
l.foldl f x 0 stop = l.unattach.foldl g x := by
(hf : b x h, f b x, h = g b x) (h : stop = xs.size) :
xs.foldl f x 0 stop = xs.unattach.foldl g x := by
subst h
rwa [foldl_subtype]
@@ -611,20 +614,20 @@ theorem foldl_subtype {p : α → Prop} {l : Array { x // p x }}
This lemma identifies folds over arrays of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
theorem foldr_subtype {p : α Prop} {l : Array { x // p x }}
theorem foldr_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } β β} {g : α β β} {x : β}
(hf : x h b, f x, h b = g x b) :
l.foldr f x = l.unattach.foldr g x := by
cases l
xs.foldr f x = xs.unattach.foldr g x := by
cases xs
simp only [List.foldr_toArray', List.unattach_toArray]
rw [List.foldr_subtype]
simp [hf]
/-- Variant of `foldr_subtype` with side condition to check `stop = l.size`. -/
@[simp] theorem foldr_subtype' {p : α Prop} {l : Array { x // p x }}
@[simp] theorem foldr_subtype' {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } β β} {g : α β β} {x : β}
(hf : x h b, f x, h b = g x b) (h : start = l.size) :
l.foldr f x start 0 = l.unattach.foldr g x := by
(hf : x h b, f x, h b = g x b) (h : start = xs.size) :
xs.foldr f x start 0 = xs.unattach.foldr g x := by
subst h
rwa [foldr_subtype]
@@ -632,70 +635,70 @@ theorem foldr_subtype {p : α → Prop} {l : Array { x // p x }}
This lemma identifies maps over arrays of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
@[simp] theorem map_subtype {p : α Prop} {l : Array { x // p x }}
@[simp] theorem map_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } β} {g : α β} (hf : x h, f x, h = g x) :
l.map f = l.unattach.map g := by
cases l
xs.map f = xs.unattach.map g := by
cases xs
simp only [List.map_toArray, List.unattach_toArray]
rw [List.map_subtype]
simp [hf]
@[simp] theorem filterMap_subtype {p : α Prop} {l : Array { x // p x }}
@[simp] theorem filterMap_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Option β} {g : α Option β} (hf : x h, f x, h = g x) :
l.filterMap f = l.unattach.filterMap g := by
cases l
xs.filterMap f = xs.unattach.filterMap g := by
cases xs
simp only [List.size_toArray, List.filterMap_toArray', List.unattach_toArray, List.length_unattach,
mk.injEq]
rw [List.filterMap_subtype]
simp [hf]
@[simp] theorem flatMap_subtype {p : α Prop} {l : Array { x // p x }}
@[simp] theorem flatMap_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Array β} {g : α Array β} (hf : x h, f x, h = g x) :
(l.flatMap f) = l.unattach.flatMap g := by
cases l
(xs.flatMap f) = xs.unattach.flatMap g := by
cases xs
simp only [List.size_toArray, List.flatMap_toArray, List.unattach_toArray, List.length_unattach,
mk.injEq]
rw [List.flatMap_subtype]
simp [hf]
@[simp] theorem findSome?_subtype {p : α Prop} {l : Array { x // p x }}
@[simp] theorem findSome?_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Option β} {g : α Option β} (hf : x h, f x, h = g x) :
l.findSome? f = l.unattach.findSome? g := by
cases l
xs.findSome? f = xs.unattach.findSome? g := by
cases xs
simp
rw [List.findSome?_subtype hf]
@[simp] theorem find?_subtype {p : α Prop} {l : Array { x // p x }}
@[simp] theorem find?_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
(l.find? f).map Subtype.val = l.unattach.find? g := by
cases l
(xs.find? f).map Subtype.val = xs.unattach.find? g := by
cases xs
simp
rw [List.find?_subtype hf]
/-! ### Simp lemmas pushing `unattach` inwards. -/
@[simp] theorem unattach_filter {p : α Prop} {l : Array { x // p x }}
@[simp] theorem unattach_filter {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
(l.filter f).unattach = l.unattach.filter g := by
cases l
(xs.filter f).unattach = xs.unattach.filter g := by
cases xs
simp [hf]
@[simp] theorem unattach_reverse {p : α Prop} {l : Array { x // p x }} :
l.reverse.unattach = l.unattach.reverse := by
cases l
@[simp] theorem unattach_reverse {p : α Prop} {xs : Array { x // p x }} :
xs.reverse.unattach = xs.unattach.reverse := by
cases xs
simp
@[simp] theorem unattach_append {p : α Prop} {l l : Array { x // p x }} :
(l ++ l).unattach = l.unattach ++ l.unattach := by
cases l
cases l
@[simp] theorem unattach_append {p : α Prop} {xs xs : Array { x // p x }} :
(xs ++ xs).unattach = xs.unattach ++ xs.unattach := by
cases xs
cases xs
simp
@[simp] theorem unattach_flatten {p : α Prop} {l : Array (Array { x // p x })} :
l.flatten.unattach = (l.map unattach).flatten := by
@[simp] theorem unattach_flatten {p : α Prop} {xs : Array (Array { x // p x })} :
xs.flatten.unattach = (xs.map unattach).flatten := by
unfold unattach
cases l using array₂_induction
cases xs using array₂_induction
simp only [flatten_toArray, List.map_map, Function.comp_def, List.map_id_fun', id_eq,
List.map_toArray, List.map_flatten, map_subtype, map_id_fun', List.unattach_toArray, mk.injEq]
simp only [List.unattach]

View File

@@ -14,6 +14,9 @@ import Init.GetElem
import Init.Data.List.ToArrayImpl
import Init.Data.Array.Set
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
universe u v w
/-! ### Array literal syntax -/
@@ -35,28 +38,28 @@ namespace Array
/-! ### Preliminary theorems -/
@[simp] theorem size_set (a : Array α) (i : Nat) (v : α) (h : i < a.size) :
(set a i v h).size = a.size :=
@[simp] theorem size_set (xs : Array α) (i : Nat) (v : α) (h : i < xs.size) :
(set xs i v h).size = xs.size :=
List.length_set ..
@[simp] theorem size_push (a : Array α) (v : α) : (push a v).size = a.size + 1 :=
@[simp] theorem size_push (xs : Array α) (v : α) : (push xs v).size = xs.size + 1 :=
List.length_concat ..
theorem ext (a b : Array α)
(h₁ : a.size = b.size)
(h₂ : (i : Nat) (hi₁ : i < a.size) (hi₂ : i < b.size) a[i] = b[i])
: a = b := by
let rec extAux (a b : List α)
(h₁ : a.length = b.length)
(h₂ : (i : Nat) (hi₁ : i < a.length) (hi₂ : i < b.length) a[i] = b[i])
: a = b := by
induction a generalizing b with
theorem ext (xs ys : Array α)
(h₁ : xs.size = ys.size)
(h₂ : (i : Nat) (hi₁ : i < xs.size) (hi₂ : i < ys.size) xs[i] = ys[i])
: xs = ys := by
let rec extAux (as bs : List α)
(h₁ : as.length = bs.length)
(h₂ : (i : Nat) (hi₁ : i < as.length) (hi₂ : i < bs.length) as[i] = bs[i])
: as = bs := by
induction as generalizing bs with
| nil =>
cases b with
cases bs with
| nil => rfl
| cons b bs => rw [List.length_cons] at h₁; injection h₁
| cons a as ih =>
cases b with
cases bs with
| nil => rw [List.length_cons] at h₁; injection h₁
| cons b bs =>
have hz₁ : 0 < (a::as).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
@@ -71,23 +74,23 @@ theorem ext (a b : Array α)
apply this
have tailEq : as = bs := ih bs h₁' h₂'
rw [headEq, tailEq]
cases a; cases b
cases xs; cases ys
apply congrArg
apply extAux
assumption
assumption
theorem ext' {as bs : Array α} (h : as.toList = bs.toList) : as = bs := by
cases as; cases bs; simp at h; rw [h]
theorem ext' {xs ys : Array α} (h : xs.toList = ys.toList) : xs = ys := by
cases xs; cases ys; simp at h; rw [h]
@[simp] theorem toArrayAux_eq (as : List α) (acc : Array α) : (as.toArrayAux acc).toList = acc.toList ++ as := by
induction as generalizing acc <;> simp [*, List.toArrayAux, Array.push, List.append_assoc, List.concat_eq_append]
@[simp] theorem toArray_toList (a : Array α) : a.toList.toArray = a := rfl
@[simp] theorem toArray_toList (xs : Array α) : xs.toList.toArray = xs := rfl
@[simp] theorem getElem_toList {a : Array α} {i : Nat} (h : i < a.size) : a.toList[i] = a[i] := rfl
@[simp] theorem getElem_toList {xs : Array α} {i : Nat} (h : i < xs.size) : xs.toList[i] = xs[i] := rfl
@[simp] theorem getElem?_toList {a : Array α} {i : Nat} : a.toList[i]? = a[i]? := by
@[simp] theorem getElem?_toList {xs : Array α} {i : Nat} : xs.toList[i]? = xs[i]? := by
simp [getElem?_def]
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
@@ -105,7 +108,7 @@ theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
@[simp] theorem mem_toArray {a : α} {l : List α} : a l.toArray a l := by
simp [mem_def]
@[simp] theorem getElem_mem {l : Array α} {i : Nat} (h : i < l.size) : l[i] l := by
@[simp] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] xs := by
rw [Array.mem_def, getElem_toList]
apply List.getElem_mem
@@ -127,14 +130,14 @@ abbrev _root_.Array.toList_toArray := @List.toList_toArray
@[deprecated size_toArray (since := "2025-02-17")]
abbrev _root_.Array.size_toArray := @List.size_toArray
@[simp] theorem getElem_toArray {a : List α} {i : Nat} (h : i < a.toArray.size) :
a.toArray[i] = a[i]'(by simpa using h) := rfl
@[simp] theorem getElem_toArray {xs : List α} {i : Nat} (h : i < xs.toArray.size) :
xs.toArray[i] = xs[i]'(by simpa using h) := rfl
@[simp] theorem getElem?_toArray {a : List α} {i : Nat} : a.toArray[i]? = a[i]? := by
@[simp] theorem getElem?_toArray {xs : List α} {i : Nat} : xs.toArray[i]? = xs[i]? := by
simp [getElem?_def]
@[simp] theorem getElem!_toArray [Inhabited α] {a : List α} {i : Nat} :
a.toArray[i]! = a[i]! := by
@[simp] theorem getElem!_toArray [Inhabited α] {xs : List α} {i : Nat} :
xs.toArray[i]! = xs[i]! := by
simp [getElem!_def]
end List
@@ -165,15 +168,15 @@ def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
`Fin` values are represented as tag pointers in the Lean runtime. Thus,
`fset` may be slightly slower than `uset`. -/
@[extern "lean_array_uset"]
def uset (a : Array α) (i : USize) (v : α) (h : i.toNat < a.size) : Array α :=
a.set i.toNat v h
def uset (xs : Array α) (i : USize) (v : α) (h : i.toNat < xs.size) : Array α :=
xs.set i.toNat v h
@[extern "lean_array_pop"]
def pop (a : Array α) : Array α where
toList := a.toList.dropLast
def pop (xs : Array α) : Array α where
toList := xs.toList.dropLast
@[simp] theorem size_pop (a : Array α) : a.pop.size = a.size - 1 := by
match a with
@[simp] theorem size_pop (xs : Array α) : xs.pop.size = xs.size - 1 := by
match xs with
| [] => rfl
| a::as => simp [pop, Nat.succ_sub_succ_eq_sub, size]
@@ -188,15 +191,15 @@ This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[extern "lean_array_fswap"]
def swap (a : Array α) (i j : @& Nat) (hi : i < a.size := by get_elem_tactic) (hj : j < a.size := by get_elem_tactic) : Array α :=
let v₁ := a[i]
let v₂ := a[j]
let a' := a.set i v₂
a'.set j v₁ (Nat.lt_of_lt_of_eq hj (size_set a i v₂ _).symm)
def swap (xs : Array α) (i j : @& Nat) (hi : i < xs.size := by get_elem_tactic) (hj : j < xs.size := by get_elem_tactic) : Array α :=
let v₁ := xs[i]
let v₂ := xs[j]
let xs' := xs.set i v₂
xs'.set j v₁ (Nat.lt_of_lt_of_eq hj (size_set xs i v₂ _).symm)
@[simp] theorem size_swap (a : Array α) (i j : Nat) {hi hj} : (a.swap i j hi hj).size = a.size := by
show ((a.set i a[j]).set j a[i]
(Nat.lt_of_lt_of_eq hj (size_set a i a[j] _).symm)).size = a.size
@[simp] theorem size_swap (xs : Array α) (i j : Nat) {hi hj} : (xs.swap i j hi hj).size = xs.size := by
show ((xs.set i xs[j]).set j xs[i]
(Nat.lt_of_lt_of_eq hj (size_set xs i xs[j] _).symm)).size = xs.size
rw [size_set, size_set]
/--
@@ -206,11 +209,11 @@ This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[extern "lean_array_swap"]
def swapIfInBounds (a : Array α) (i j : @& Nat) : Array α :=
if h₁ : i < a.size then
if h₂ : j < a.size then swap a i j
else a
else a
def swapIfInBounds (xs : Array α) (i j : @& Nat) : Array α :=
if h₁ : i < xs.size then
if h₂ : j < xs.size then swap xs i j
else xs
else xs
@[deprecated swapIfInBounds (since := "2024-11-24")] abbrev swap! := @swapIfInBounds
@@ -225,24 +228,24 @@ instance : EmptyCollection (Array α) := ⟨Array.empty⟩
instance : Inhabited (Array α) where
default := Array.empty
def isEmpty (a : Array α) : Bool :=
a.size = 0
def isEmpty (xs : Array α) : Bool :=
xs.size = 0
@[specialize]
def isEqvAux (a b : Array α) (hsz : a.size = b.size) (p : α α Bool) :
(i : Nat) (_ : i a.size), Bool
def isEqvAux (xs ys : Array α) (hsz : xs.size = ys.size) (p : α α Bool) :
(i : Nat) (_ : i xs.size), Bool
| 0, _ => true
| i+1, h =>
p a[i] (b[i]'(hsz h)) && isEqvAux a b hsz p i (Nat.le_trans (Nat.le_add_right i 1) h)
p xs[i] (ys[i]'(hsz h)) && isEqvAux xs ys hsz p i (Nat.le_trans (Nat.le_add_right i 1) h)
@[inline] def isEqv (a b : Array α) (p : α α Bool) : Bool :=
if h : a.size = b.size then
isEqvAux a b h p a.size (Nat.le_refl a.size)
@[inline] def isEqv (xs ys : Array α) (p : α α Bool) : Bool :=
if h : xs.size = ys.size then
isEqvAux xs ys h p xs.size (Nat.le_refl xs.size)
else
false
instance [BEq α] : BEq (Array α) :=
fun a b => isEqv a b BEq.beq
fun xs ys => isEqv xs ys BEq.beq
/--
`ofFn f` with `f : Fin n → α` returns the list whose ith element is `f i`.
@@ -272,8 +275,8 @@ Return the last element of an array, or panic if the array is empty.
See `back` for the version that requires a proof the array is non-empty,
or `back?` for the version that returns an option.
-/
def back! [Inhabited α] (a : Array α) : α :=
a[a.size - 1]!
def back! [Inhabited α] (xs : Array α) : α :=
xs[xs.size - 1]!
/--
Return the last element of an array, given a proof that the array is not empty.
@@ -281,8 +284,8 @@ Return the last element of an array, given a proof that the array is not empty.
See `back!` for the version that panics if the array is empty,
or `back?` for the version that returns an option.
-/
def back (a : Array α) (h : 0 < a.size := by get_elem_tactic) : α :=
a[a.size - 1]'(Nat.sub_one_lt_of_lt h)
def back (xs : Array α) (h : 0 < xs.size := by get_elem_tactic) : α :=
xs[xs.size - 1]'(Nat.sub_one_lt_of_lt h)
/--
Return the last element of an array, or `none` if the array is empty.
@@ -290,72 +293,73 @@ Return the last element of an array, or `none` if the array is empty.
See `back!` for the version that panics if the array is empty,
or `back` for the version that requires a proof the array is non-empty.
-/
def back? (a : Array α) : Option α :=
a[a.size - 1]?
def back? (xs : Array α) : Option α :=
xs[xs.size - 1]?
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12")]
def get? (a : Array α) (i : Nat) : Option α :=
if h : i < a.size then some a[i] else none
def get? (xs : Array α) (i : Nat) : Option α :=
if h : i < xs.size then some xs[i] else none
@[inline] def swapAt (a : Array α) (i : Nat) (v : α) (hi : i < a.size := by get_elem_tactic) : α × Array α :=
let e := a[i]
let a := a.set i v
(e, a)
@[inline] def swapAt (xs : Array α) (i : Nat) (v : α) (hi : i < xs.size := by get_elem_tactic) : α × Array α :=
let e := xs[i]
let xs' := xs.set i v
(e, xs')
@[inline]
def swapAt! (a : Array α) (i : Nat) (v : α) : α × Array α :=
if h : i < a.size then
swapAt a i v
def swapAt! (xs : Array α) (i : Nat) (v : α) : α × Array α :=
if h : i < xs.size then
swapAt xs i v
else
have : Inhabited (α × Array α) := (v, a)
have : Inhabited (α × Array α) := (v, xs)
panic! ("index " ++ toString i ++ " out of bounds")
/-- `shrink a n` returns the first `n` elements of `a`, implemented by repeatedly popping the last element. -/
def shrink (a : Array α) (n : Nat) : Array α :=
def shrink (xs : Array α) (n : Nat) : Array α :=
let rec loop
| 0, a => a
| n+1, a => loop n a.pop
loop (a.size - n) a
| 0, xs => xs
| n+1, xs => loop n xs.pop
loop (xs.size - n) xs
/-- `take a n` returns the first `n` elements of `a`, implemented by copying the first `n` elements. -/
abbrev take (a : Array α) (n : Nat) : Array α := extract a 0 n
abbrev take (xs : Array α) (i : Nat) : Array α := extract xs 0 i
@[simp] theorem take_eq_extract (a : Array α) (n : Nat) : a.take n = a.extract 0 n := rfl
@[simp] theorem take_eq_extract (xs : Array α) (i : Nat) : xs.take i = xs.extract 0 i := rfl
/-- `drop a n` removes the first `n` elements of `a`, implemented by copying the remaining elements. -/
abbrev drop (a : Array α) (n : Nat) : Array α := extract a n a.size
abbrev drop (xs : Array α) (i : Nat) : Array α := extract xs i xs.size
@[simp] theorem drop_eq_extract (a : Array α) (n : Nat) : a.drop n = a.extract n a.size := rfl
@[simp] theorem drop_eq_extract (xs : Array α) (i : Nat) : xs.drop i = xs.extract i xs.size := rfl
@[inline]
unsafe def modifyMUnsafe [Monad m] (a : Array α) (i : Nat) (f : α m α) : m (Array α) := do
if h : i < a.size then
let v := a[i]
unsafe def modifyMUnsafe [Monad m] (xs : Array α) (i : Nat) (f : α m α) : m (Array α) := do
if h : i < xs.size then
let v := xs[i]
-- Replace a[i] by `box(0)`. This ensures that `v` remains unshared if possible.
-- Note: we assume that arrays have a uniform representation irrespective
-- of the element type, and that it is valid to store `box(0)` in any array.
let a' := a.set i (unsafeCast ())
let xs' := xs.set i (unsafeCast ())
let v f v
pure <| a'.set i v (Nat.lt_of_lt_of_eq h (size_set a ..).symm)
pure <| xs'.set i v (Nat.lt_of_lt_of_eq h (size_set xs ..).symm)
else
pure a
pure xs
@[implemented_by modifyMUnsafe]
def modifyM [Monad m] (a : Array α) (i : Nat) (f : α m α) : m (Array α) := do
if h : i < a.size then
let v := a[i]
def modifyM [Monad m] (xs : Array α) (i : Nat) (f : α m α) : m (Array α) := do
if h : i < xs.size then
let v := xs[i]
let v f v
pure <| a.set i v
pure <| xs.set i v
else
pure a
pure xs
@[inline]
def modify (a : Array α) (i : Nat) (f : α α) : Array α :=
Id.run <| modifyM a i f
def modify (xs : Array α) (i : Nat) (f : α α) : Array α :=
Id.run <| modifyM xs i f
set_option linter.indexVariables false in -- Changing `idx` causes bootstrapping issues, haven't investigated.
@[inline]
def modifyOp (self : Array α) (idx : Nat) (f : α α) : Array α :=
self.modify idx f
def modifyOp (xs : Array α) (idx : Nat) (f : α α) : Array α :=
xs.modify idx f
/--
We claim this unsafe implementation is correct because an array cannot have more than `usizeSz` elements in our runtime.
@@ -474,17 +478,17 @@ def foldrM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
@[inline]
unsafe def mapMUnsafe {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m β) (as : Array α) : m (Array β) :=
let sz := as.usize
let rec @[specialize] map (i : USize) (r : Array NonScalar) : m (Array PNonScalar.{v}) := do
let rec @[specialize] map (i : USize) (bs : Array NonScalar) : m (Array PNonScalar.{v}) := do
if i < sz then
let v := r.uget i lcProof
-- Replace r[i] by `box(0)`. This ensures that `v` remains unshared if possible.
let v := bs.uget i lcProof
-- Replace bs[i] by `box(0)`. This ensures that `v` remains unshared if possible.
-- Note: we assume that arrays have a uniform representation irrespective
-- of the element type, and that it is valid to store `box(0)` in any array.
let r := r.uset i default lcProof
let bs' := bs.uset i default lcProof
let vNew f (unsafeCast v)
map (i+1) (r.uset i (unsafeCast vNew) lcProof)
map (i+1) (bs'.uset i (unsafeCast vNew) lcProof)
else
pure (unsafeCast r)
pure (unsafeCast bs)
unsafeCast <| map 0 (unsafeCast as)
/-- Reference implementation for `mapM` -/
@@ -493,11 +497,11 @@ def mapM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
-- Note: we cannot use `foldlM` here for the reference implementation because this calls
-- `bind` and `pure` too many times. (We are not assuming `m` is a `LawfulMonad`)
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
map (i : Nat) (r : Array β) : m (Array β) := do
map (i : Nat) (bs : Array β) : m (Array β) := do
if hlt : i < as.size then
map (i+1) (r.push ( f as[i]))
map (i+1) (bs.push ( f as[i]))
else
pure r
pure bs
decreasing_by simp_wf; decreasing_trivial_pre_omega
map 0 (mkEmpty as.size)
@@ -678,8 +682,8 @@ def mapIdx {α : Type u} {β : Type v} (f : Nat → α → β) (as : Array α) :
Id.run <| as.mapIdxM f
/-- Turns `#[a, b]` into `#[(a, 0), (b, 1)]`. -/
def zipIdx (arr : Array α) (start := 0) : Array (α × Nat) :=
arr.mapIdx fun i a => (a, start + i)
def zipIdx (xs : Array α) (start := 0) : Array (α × Nat) :=
xs.mapIdx fun i a => (a, start + i)
@[deprecated zipIdx (since := "2025-01-21")] abbrev zipWithIndex := @zipIdx
@@ -696,8 +700,8 @@ def findSome? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α)
Id.run <| as.findSomeM? f
@[inline]
def findSome! {α : Type u} {β : Type v} [Inhabited β] (f : α Option β) (a : Array α) : β :=
match a.findSome? f with
def findSome! {α : Type u} {β : Type v} [Inhabited β] (f : α Option β) (xs : Array α) : β :=
match xs.findSome? f with
| some b => b
| none => panic! "failed to find element"
@@ -751,18 +755,18 @@ theorem findIdx?_eq_map_findFinIdx?_val {xs : Array α} {p : α → Bool} :
def findIdx (p : α Bool) (as : Array α) : Nat := (as.findIdx? p).getD as.size
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def idxOfAux [BEq α] (a : Array α) (v : α) (i : Nat) : Option (Fin a.size) :=
if h : i < a.size then
if a[i] == v then some i, h
else idxOfAux a v (i+1)
def idxOfAux [BEq α] (xs : Array α) (v : α) (i : Nat) : Option (Fin xs.size) :=
if h : i < xs.size then
if xs[i] == v then some i, h
else idxOfAux xs v (i+1)
else none
decreasing_by simp_wf; decreasing_trivial_pre_omega
@[deprecated idxOfAux (since := "2025-01-29")]
abbrev indexOfAux := @idxOfAux
def finIdxOf? [BEq α] (a : Array α) (v : α) : Option (Fin a.size) :=
idxOfAux a v 0
def finIdxOf? [BEq α] (xs : Array α) (v : α) : Option (Fin xs.size) :=
idxOfAux xs v 0
@[deprecated "`Array.indexOf?` has been deprecated, use `idxOf?` or `finIdxOf?` instead." (since := "2025-01-29")]
abbrev indexOf? := @finIdxOf?
@@ -770,12 +774,12 @@ abbrev indexOf? := @finIdxOf?
/-- Returns the index of the first element equal to `a`, or the length of the array otherwise. -/
def idxOf [BEq α] (a : α) : Array α Nat := findIdx (· == a)
def idxOf? [BEq α] (a : Array α) (v : α) : Option Nat :=
(a.finIdxOf? v).map (·.val)
def idxOf? [BEq α] (xs : Array α) (v : α) : Option Nat :=
(xs.finIdxOf? v).map (·.val)
@[deprecated idxOf? (since := "2024-11-20")]
def getIdx? [BEq α] (a : Array α) (v : α) : Option Nat :=
a.findIdx? fun a => a == v
def getIdx? [BEq α] (xs : Array α) (v : α) : Option Nat :=
xs.findIdx? fun a => a == v
@[inline]
def any (as : Array α) (p : α Bool) (start := 0) (stop := as.size) : Bool :=
@@ -810,12 +814,12 @@ def toListAppend (as : Array α) (l : List α) : List α :=
as.foldr List.cons l
protected def append (as : Array α) (bs : Array α) : Array α :=
bs.foldl (init := as) fun r v => r.push v
bs.foldl (init := as) fun xs v => xs.push v
instance : Append (Array α) := Array.append
protected def appendList (as : Array α) (bs : List α) : Array α :=
bs.foldl (init := as) fun r v => r.push v
bs.foldl (init := as) fun xs v => xs.push v
instance : HAppend (Array α) (List α) (Array α) := Array.appendList
@@ -835,8 +839,8 @@ def flatMap (f : α → Array β) (as : Array α) : Array β :=
`flatten #[#[a₁, a₂, ⋯], #[b₁, b₂, ⋯], ⋯]` = `#[a₁, a₂, ⋯, b₁, b₂, ⋯]`
-/
@[inline] def flatten (as : Array (Array α)) : Array α :=
as.foldl (init := empty) fun r a => r ++ a
@[inline] def flatten (xss : Array (Array α)) : Array α :=
xss.foldl (init := empty) fun acc xs => acc ++ xs
def reverse (as : Array α) : Array α :=
if h : as.size 1 then
@@ -858,18 +862,18 @@ where
@[inline]
def filter (p : α Bool) (as : Array α) (start := 0) (stop := as.size) : Array α :=
as.foldl (init := #[]) (start := start) (stop := stop) fun r a =>
if p a then r.push a else r
as.foldl (init := #[]) (start := start) (stop := stop) fun acc a =>
if p a then acc.push a else acc
@[inline]
def filterM {α : Type} [Monad m] (p : α m Bool) (as : Array α) (start := 0) (stop := as.size) : m (Array α) :=
as.foldlM (init := #[]) (start := start) (stop := stop) fun r a => do
if ( p a) then return r.push a else return r
as.foldlM (init := #[]) (start := start) (stop := stop) fun acc a => do
if ( p a) then return acc.push a else return acc
@[inline]
def filterRevM {α : Type} [Monad m] (p : α m Bool) (as : Array α) (start := as.size) (stop := 0) : m (Array α) :=
reverse <$> as.foldrM (init := #[]) (start := start) (stop := stop) fun a r => do
if ( p a) then return r.push a else return r
reverse <$> as.foldrM (init := #[]) (start := start) (stop := stop) fun a acc => do
if ( p a) then return acc.push a else return acc
@[specialize]
def filterMapM [Monad m] (f : α m (Option β)) (as : Array α) (start := 0) (stop := as.size) : m (Array β) :=
@@ -919,15 +923,15 @@ decreasing_by simp_wf; decreasing_trivial_pre_omega
def takeWhile (p : α Bool) (as : Array α) : Array α :=
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
go (i : Nat) (r : Array α) : Array α :=
go (i : Nat) (acc : Array α) : Array α :=
if h : i < as.size then
let a := as[i]
if p a then
go (i+1) (r.push a)
go (i+1) (acc.push a)
else
r
acc
else
r
acc
decreasing_by simp_wf; decreasing_trivial_pre_omega
go 0 #[]
@@ -938,22 +942,22 @@ using a `Nat` index and a tactic-provided bound.
This function takes worst case O(n) time because
it has to backshift all elements at positions greater than `i`.-/
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def eraseIdx (a : Array α) (i : Nat) (h : i < a.size := by get_elem_tactic) : Array α :=
if h' : i + 1 < a.size then
let a' := a.swap (i + 1) i
a'.eraseIdx (i + 1) (by simp [a', h'])
def eraseIdx (xs : Array α) (i : Nat) (h : i < xs.size := by get_elem_tactic) : Array α :=
if h' : i + 1 < xs.size then
let xs' := xs.swap (i + 1) i
xs'.eraseIdx (i + 1) (by simp [xs', h'])
else
a.pop
termination_by a.size - i
xs.pop
termination_by xs.size - i
decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
-- This is required in `Lean.Data.PersistentHashMap`.
@[simp] theorem size_eraseIdx (a : Array α) (i : Nat) (h) : (a.eraseIdx i h).size = a.size - 1 := by
induction a, i, h using Array.eraseIdx.induct with
| @case1 a i h h' a' ih =>
@[simp] theorem size_eraseIdx (xs : Array α) (i : Nat) (h) : (xs.eraseIdx i h).size = xs.size - 1 := by
induction xs, i, h using Array.eraseIdx.induct with
| @case1 xs i h h' xs' ih =>
unfold eraseIdx
simp +zetaDelta [h', a', ih]
| case2 a i h h' =>
simp +zetaDelta [h', xs', ih]
| case2 xs i h h' =>
unfold eraseIdx
simp [h']
@@ -961,15 +965,15 @@ decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
This function takes worst case O(n) time because
it has to backshift all elements at positions greater than `i`.-/
def eraseIdxIfInBounds (a : Array α) (i : Nat) : Array α :=
if h : i < a.size then a.eraseIdx i h else a
def eraseIdxIfInBounds (xs : Array α) (i : Nat) : Array α :=
if h : i < xs.size then xs.eraseIdx i h else xs
/-- Remove the element at a given index from an array, or panic if the index is out of bounds.
This function takes worst case O(n) time because
it has to backshift all elements at positions greater than `i`. -/
def eraseIdx! (a : Array α) (i : Nat) : Array α :=
if h : i < a.size then a.eraseIdx i h else panic! "invalid index"
def eraseIdx! (xs : Array α) (i : Nat) : Array α :=
if h : i < xs.size then xs.eraseIdx i h else panic! "invalid index"
/-- Remove a specified element from an array, or do nothing if it is not present.
@@ -1086,6 +1090,11 @@ def split (as : Array α) (p : α → Bool) : Array α × Array α :=
as.foldl (init := (#[], #[])) fun (as, bs) a =>
if p a then (as.push a, bs) else (as, bs.push a)
def replace [BEq α] (xs : Array α) (a b : α) : Array α :=
match xs.finIdxOf? a with
| none => xs
| some i => xs.set i b
/-! ### Lexicographic ordering -/
instance instLT [LT α] : LT (Array α) := fun as bs => as.toList < bs.toList
@@ -1098,6 +1107,20 @@ instance instLE [LT α] : LE (Array α) := ⟨fun as bs => as.toList ≤ bs.toLi
We do not currently intend to provide verification theorems for these functions.
-/
/-! ### leftpad and rightpad -/
/--
Pads `l : Array α` on the left with repeated occurrences of `a : α` until it is of size `n`.
If `l` is initially larger than `n`, just return `l`.
-/
def leftpad (n : Nat) (a : α) (xs : Array α) : Array α := mkArray (n - xs.size) a ++ xs
/--
Pads `l : Array α` on the right with repeated occurrences of `a : α` until it is of size `n`.
If `l` is initially larger than `n`, just return `l`.
-/
def rightpad (n : Nat) (a : α) (xs : Array α) : Array α := xs ++ mkArray (n - xs.size) a
/- ### reduceOption -/
/-- Drop `none`s from a Array, and replace each remaining `some a` with `a`. -/
@@ -1112,9 +1135,9 @@ We do not currently intend to provide verification theorems for these functions.
-/
def eraseReps {α} [BEq α] (as : Array α) : Array α :=
if h : 0 < as.size then
let last, r := as.foldl (init := (as[0], #[])) fun last, r a =>
if a == last then last, r else a, r.push last
r.push last
let last, acc := as.foldl (init := (as[0], #[])) fun last, acc a =>
if a == last then last, acc else a, acc.push last
acc.push last
else
#[]
@@ -1140,24 +1163,24 @@ def allDiff [BEq α] (as : Array α) : Bool :=
/-! ### getEvenElems -/
@[inline] def getEvenElems (as : Array α) : Array α :=
(·.2) <| as.foldl (init := (true, Array.empty)) fun (even, r) a =>
(·.2) <| as.foldl (init := (true, Array.empty)) fun (even, acc) a =>
if even then
(false, r.push a)
(false, acc.push a)
else
(true, r)
(true, acc)
/-! ### Repr and ToString -/
instance {α : Type u} [Repr α] : Repr (Array α) where
reprPrec a _ :=
reprPrec xs _ :=
let _ : Std.ToFormat α := repr
if a.size == 0 then
if xs.size == 0 then
"#[]"
else
Std.Format.bracketFill "#[" (Std.Format.joinSep (toList a) ("," ++ Std.Format.line)) "]"
Std.Format.bracketFill "#[" (Std.Format.joinSep (toList xs) ("," ++ Std.Format.line)) "]"
instance [ToString α] : ToString (Array α) where
toString a := "#" ++ toString a.toList
toString xs := "#" ++ toString xs.toList
end Array

View File

@@ -8,6 +8,9 @@ import Init.Data.Array.Basic
import Init.Data.Nat.Linear
import Init.NotationExtra
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
theorem Array.of_push_eq_push {as bs : Array α} (h : as.push a = bs.push b) : as = bs a = b := by
simp only [push, mk.injEq] at h
have h₁, h₂ := List.of_concat_eq_concat h

View File

@@ -5,9 +5,13 @@ Authors: Leonardo de Moura
-/
prelude
import Init.Data.Array.Basic
import Init.Data.Int.DivMod.Lemmas
import Init.Omega
universe u v
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- We do not use `linter.indexVariables` here as it is helpful to name the index variables as `lo`, `mid`, and `hi`.
namespace Array
@[specialize] def binSearchAux {α : Type u} {β : Type v} (lt : α α Bool) (found : Option α β) (as : Array α) (k : α) :

View File

@@ -13,6 +13,9 @@ import Init.Data.List.TakeDrop
This file contains some theorems about `Array` and `List` needed for `Init.Data.List.Impl`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/--
@@ -39,122 +42,122 @@ def get! {α : Type u} [Inhabited α] (a : @& Array α) (i : @& Nat) : α :=
Array.getD a i default
theorem foldlM_toList.aux [Monad m]
(f : β α m β) (arr : Array α) (i j) (H : arr.size i + j) (b) :
foldlM.loop f arr arr.size (Nat.le_refl _) i j b = (arr.toList.drop j).foldlM f b := by
(f : β α m β) (xs : Array α) (i j) (H : xs.size i + j) (b) :
foldlM.loop f xs xs.size (Nat.le_refl _) i j b = (xs.toList.drop j).foldlM f b := by
unfold foldlM.loop
split; split
· cases Nat.not_le_of_gt _ (Nat.zero_add _ H)
· rename_i i; rw [Nat.succ_add] at H
simp [foldlM_toList.aux f arr i (j+1) H]
simp [foldlM_toList.aux f xs i (j+1) H]
rw (occs := [2]) [ List.getElem_cons_drop_succ_eq_drop _]
rfl
· rw [List.drop_of_length_le (Nat.ge_of_not_lt _)]; rfl
@[simp] theorem foldlM_toList [Monad m]
(f : β α m β) (init : β) (arr : Array α) :
arr.toList.foldlM f init = arr.foldlM f init := by
(f : β α m β) (init : β) (xs : Array α) :
xs.toList.foldlM f init = xs.foldlM f init := by
simp [foldlM, foldlM_toList.aux]
@[simp] theorem foldl_toList (f : β α β) (init : β) (arr : Array α) :
arr.toList.foldl f init = arr.foldl f init :=
@[simp] theorem foldl_toList (f : β α β) (init : β) (xs : Array α) :
xs.toList.foldl f init = xs.foldl f init :=
List.foldl_eq_foldlM .. foldlM_toList ..
theorem foldrM_eq_reverse_foldlM_toList.aux [Monad m]
(f : α β m β) (arr : Array α) (init : β) (i h) :
(arr.toList.take i).reverse.foldlM (fun x y => f y x) init = foldrM.fold f arr 0 i h init := by
(f : α β m β) (xs : Array α) (init : β) (i h) :
(xs.toList.take i).reverse.foldlM (fun x y => f y x) init = foldrM.fold f xs 0 i h init := by
unfold foldrM.fold
match i with
| 0 => simp [List.foldlM, List.take]
| i+1 => rw [ List.take_concat_get _ _ h]; simp [ (aux f arr · i)]
| i+1 => rw [ List.take_concat_get _ _ h]; simp [ (aux f xs · i)]
theorem foldrM_eq_reverse_foldlM_toList [Monad m] (f : α β m β) (init : β) (arr : Array α) :
arr.foldrM f init = arr.toList.reverse.foldlM (fun x y => f y x) init := by
have : arr = #[] 0 < arr.size :=
match arr with | [] => .inl rfl | a::l => .inr (Nat.zero_lt_succ _)
match arr, this with | _, .inl rfl => rfl | arr, .inr h => ?_
theorem foldrM_eq_reverse_foldlM_toList [Monad m] (f : α β m β) (init : β) (xs : Array α) :
xs.foldrM f init = xs.toList.reverse.foldlM (fun x y => f y x) init := by
have : xs = #[] 0 < xs.size :=
match xs with | [] => .inl rfl | a::l => .inr (Nat.zero_lt_succ _)
match xs, this with | _, .inl rfl => rfl | xs, .inr h => ?_
simp [foldrM, h, foldrM_eq_reverse_foldlM_toList.aux, List.take_length]
@[simp] theorem foldrM_toList [Monad m]
(f : α β m β) (init : β) (arr : Array α) :
arr.toList.foldrM f init = arr.foldrM f init := by
(f : α β m β) (init : β) (xs : Array α) :
xs.toList.foldrM f init = xs.foldrM f init := by
rw [foldrM_eq_reverse_foldlM_toList, List.foldlM_reverse]
@[simp] theorem foldr_toList (f : α β β) (init : β) (arr : Array α) :
arr.toList.foldr f init = arr.foldr f init :=
@[simp] theorem foldr_toList (f : α β β) (init : β) (xs : Array α) :
xs.toList.foldr f init = xs.foldr f init :=
List.foldr_eq_foldrM .. foldrM_toList ..
@[simp] theorem push_toList (arr : Array α) (a : α) : (arr.push a).toList = arr.toList ++ [a] := by
@[simp] theorem push_toList (xs : Array α) (a : α) : (xs.push a).toList = xs.toList ++ [a] := by
simp [push, List.concat_eq_append]
@[simp] theorem toListAppend_eq (arr : Array α) (l) : arr.toListAppend l = arr.toList ++ l := by
@[simp] theorem toListAppend_eq (xs : Array α) (l : List α) : xs.toListAppend l = xs.toList ++ l := by
simp [toListAppend, foldr_toList]
@[simp] theorem toListImpl_eq (arr : Array α) : arr.toListImpl = arr.toList := by
@[simp] theorem toListImpl_eq (xs : Array α) : xs.toListImpl = xs.toList := by
simp [toListImpl, foldr_toList]
@[simp] theorem toList_pop (a : Array α) : a.pop.toList = a.toList.dropLast := rfl
@[simp] theorem toList_pop (xs : Array α) : xs.pop.toList = xs.toList.dropLast := rfl
@[deprecated toList_pop (since := "2025-02-17")]
abbrev pop_toList := @Array.toList_pop
@[simp] theorem append_eq_append (arr arr' : Array α) : arr.append arr' = arr ++ arr' := rfl
@[simp] theorem append_eq_append (xs ys : Array α) : xs.append ys = xs ++ ys := rfl
@[simp] theorem toList_append (arr arr' : Array α) :
(arr ++ arr').toList = arr.toList ++ arr'.toList := by
@[simp] theorem toList_append (xs ys : Array α) :
(xs ++ ys).toList = xs.toList ++ ys.toList := by
rw [ append_eq_append]; unfold Array.append
rw [ foldl_toList]
induction arr'.toList generalizing arr <;> simp [*]
induction ys.toList generalizing xs <;> simp [*]
@[simp] theorem toList_empty : (#[] : Array α).toList = [] := rfl
@[simp] theorem append_empty (as : Array α) : as ++ #[] = as := by
@[simp] theorem append_empty (xs : Array α) : xs ++ #[] = xs := by
apply ext'; simp only [toList_append, toList_empty, List.append_nil]
@[deprecated append_empty (since := "2025-01-13")]
abbrev append_nil := @append_empty
@[simp] theorem empty_append (as : Array α) : #[] ++ as = as := by
@[simp] theorem empty_append (xs : Array α) : #[] ++ xs = xs := by
apply ext'; simp only [toList_append, toList_empty, List.nil_append]
@[deprecated empty_append (since := "2025-01-13")]
abbrev nil_append := @empty_append
@[simp] theorem append_assoc (as bs cs : Array α) : as ++ bs ++ cs = as ++ (bs ++ cs) := by
@[simp] theorem append_assoc (xs ys zs : Array α) : xs ++ ys ++ zs = xs ++ (ys ++ zs) := by
apply ext'; simp only [toList_append, List.append_assoc]
@[simp] theorem appendList_eq_append
(arr : Array α) (l : List α) : arr.appendList l = arr ++ l := rfl
(xs : Array α) (l : List α) : xs.appendList l = xs ++ l := rfl
@[simp] theorem toList_appendList (arr : Array α) (l : List α) :
(arr ++ l).toList = arr.toList ++ l := by
@[simp] theorem toList_appendList (xs : Array α) (l : List α) :
(xs ++ l).toList = xs.toList ++ l := by
rw [ appendList_eq_append]; unfold Array.appendList
induction l generalizing arr <;> simp [*]
induction l generalizing xs <;> 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 α) :
arr.foldrM f init = arr.toList.foldrM f init := by
(f : α β m β) (init : β) (xs : Array α) :
xs.foldrM f init = xs.toList.foldrM f init := by
simp
@[deprecated "Use the reverse direction of `foldlM_toList`." (since := "2024-11-13")]
theorem foldlM_eq_foldlM_toList [Monad m]
(f : β α m β) (init : β) (arr : Array α) :
arr.foldlM f init = arr.toList.foldlM f init:= by
(f : β α m β) (init : β) (xs : Array α) :
xs.foldlM f init = xs.toList.foldlM f init:= by
simp
@[deprecated "Use the reverse direction of `foldr_toList`." (since := "2024-11-13")]
theorem foldr_eq_foldr_toList
(f : α β β) (init : β) (arr : Array α) :
arr.foldr f init = arr.toList.foldr f init := by
(f : α β β) (init : β) (xs : Array α) :
xs.foldr f init = xs.toList.foldr f init := by
simp
@[deprecated "Use the reverse direction of `foldl_toList`." (since := "2024-11-13")]
theorem foldl_eq_foldl_toList
(f : β α β) (init : β) (arr : Array α) :
arr.foldl f init = arr.toList.foldl f init:= by
(f : β α β) (init : β) (xs : Array α) :
xs.foldl f init = xs.toList.foldl f init:= by
simp
@[deprecated foldlM_toList (since := "2024-09-09")]

View File

@@ -11,6 +11,9 @@ import Init.Data.List.Nat.Count
# Lemmas about `Array.countP` and `Array.count`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
@@ -22,120 +25,120 @@ variable (p q : α → Bool)
@[simp] theorem countP_empty : countP p #[] = 0 := rfl
@[simp] theorem countP_push_of_pos (l) (pa : p a) : countP p (l.push a) = countP p l + 1 := by
rcases l with l
@[simp] theorem countP_push_of_pos (xs) (pa : p a) : countP p (xs.push a) = countP p xs + 1 := by
rcases xs with xs
simp_all
@[simp] theorem countP_push_of_neg (l) (pa : ¬p a) : countP p (l.push a) = countP p l := by
rcases l with l
@[simp] theorem countP_push_of_neg (xs) (pa : ¬p a) : countP p (xs.push a) = countP p xs := by
rcases xs with xs
simp_all
theorem countP_push (a : α) (l) : countP p (l.push a) = countP p l + if p a then 1 else 0 := by
rcases l with l
theorem countP_push (a : α) (xs) : countP p (xs.push a) = countP p xs + if p a then 1 else 0 := by
rcases xs with xs
simp_all
@[simp] theorem countP_singleton (a : α) : countP p #[a] = if p a then 1 else 0 := by
simp [countP_push]
theorem size_eq_countP_add_countP (l) : l.size = countP p l + countP (fun a => ¬p a) l := by
cases l
theorem size_eq_countP_add_countP (xs) : xs.size = countP p xs + countP (fun a => ¬p a) xs := by
rcases xs with xs
simp [List.length_eq_countP_add_countP (p := p)]
theorem countP_eq_size_filter (l) : countP p l = (filter p l).size := by
cases l
theorem countP_eq_size_filter (xs) : countP p xs = (filter p xs).size := by
rcases xs with xs
simp [List.countP_eq_length_filter]
theorem countP_eq_size_filter' : countP p = size filter p := by
funext l
funext xs
apply countP_eq_size_filter
theorem countP_le_size : countP p l l.size := by
theorem countP_le_size : countP p xs xs.size := by
simp only [countP_eq_size_filter]
apply size_filter_le
@[simp] theorem countP_append (l₁ l₂) : countP p (l₁ ++ l₂) = countP p l₁ + countP p l₂ := by
cases l₁
cases l₂
@[simp] theorem countP_append (xs ys) : countP p (xs ++ ys) = countP p xs + countP p ys := by
rcases xs with xs
rcases ys with ys
simp
@[simp] theorem countP_pos_iff {p} : 0 < countP p l a l, p a := by
cases l
@[simp] theorem countP_pos_iff {p} : 0 < countP p xs a xs, p a := by
rcases xs with xs
simp
@[simp] theorem one_le_countP_iff {p} : 1 countP p l a l, p a :=
@[simp] theorem one_le_countP_iff {p} : 1 countP p xs a xs, p a :=
countP_pos_iff
@[simp] theorem countP_eq_zero {p} : countP p l = 0 a l, ¬p a := by
cases l
@[simp] theorem countP_eq_zero {p} : countP p xs = 0 a xs, ¬p a := by
rcases xs with xs
simp
@[simp] theorem countP_eq_size {p} : countP p l = l.size a l, p a := by
cases l
@[simp] theorem countP_eq_size {p} : countP p xs = xs.size a xs, p a := by
rcases xs with xs
simp
theorem countP_mkArray (p : α Bool) (a : α) (n : Nat) :
countP p (mkArray n a) = if p a then n else 0 := by
simp [ List.toArray_replicate, List.countP_replicate]
theorem boole_getElem_le_countP (p : α Bool) (l : Array α) (i : Nat) (h : i < l.size) :
(if p l[i] then 1 else 0) l.countP p := by
cases l
theorem boole_getElem_le_countP (p : α Bool) (xs : Array α) (i : Nat) (h : i < xs.size) :
(if p xs[i] then 1 else 0) xs.countP p := by
rcases xs with xs
simp [List.boole_getElem_le_countP]
theorem countP_set (p : α Bool) (l : Array α) (i : Nat) (a : α) (h : i < l.size) :
(l.set i a).countP p = l.countP p - (if p l[i] then 1 else 0) + (if p a then 1 else 0) := by
cases l
theorem countP_set (p : α Bool) (xs : Array α) (i : Nat) (a : α) (h : i < xs.size) :
(xs.set i a).countP p = xs.countP p - (if p xs[i] then 1 else 0) + (if p a then 1 else 0) := by
rcases xs with xs
simp [List.countP_set, h]
theorem countP_filter (l : Array α) :
countP p (filter q l) = countP (fun a => p a && q a) l := by
cases l
theorem countP_filter (xs : Array α) :
countP p (filter q xs) = countP (fun a => p a && q a) xs := by
rcases xs with xs
simp [List.countP_filter]
@[simp] theorem countP_true : (countP fun (_ : α) => true) = size := by
funext l
funext xs
simp
@[simp] theorem countP_false : (countP fun (_ : α) => false) = Function.const _ 0 := by
funext l
funext xs
simp
@[simp] theorem countP_map (p : β Bool) (f : α β) (l : Array α) :
countP p (map f l) = countP (p f) l := by
cases l
@[simp] theorem countP_map (p : β Bool) (f : α β) (xs : Array α) :
countP p (map f xs) = countP (p f) xs := by
rcases xs with xs
simp
theorem size_filterMap_eq_countP (f : α Option β) (l : Array α) :
(filterMap f l).size = countP (fun a => (f a).isSome) l := by
cases l
theorem size_filterMap_eq_countP (f : α Option β) (xs : Array α) :
(filterMap f xs).size = countP (fun a => (f a).isSome) xs := by
rcases xs with xs
simp [List.length_filterMap_eq_countP]
theorem countP_filterMap (p : β Bool) (f : α Option β) (l : Array α) :
countP p (filterMap f l) = countP (fun a => ((f a).map p).getD false) l := by
cases l
theorem countP_filterMap (p : β Bool) (f : α Option β) (xs : Array α) :
countP p (filterMap f xs) = countP (fun a => ((f a).map p).getD false) xs := by
rcases xs with xs
simp [List.countP_filterMap]
@[simp] theorem countP_flatten (l : Array (Array α)) :
countP p l.flatten = (l.map (countP p)).sum := by
cases l using array₂_induction
@[simp] theorem countP_flatten (xss : Array (Array α)) :
countP p xss.flatten = (xss.map (countP p)).sum := by
cases xss using array₂_induction
simp [List.countP_flatten, Function.comp_def]
theorem countP_flatMap (p : β Bool) (l : Array α) (f : α Array β) :
countP p (l.flatMap f) = sum (map (countP p f) l) := by
cases l
theorem countP_flatMap (p : β Bool) (xs : Array α) (f : α Array β) :
countP p (xs.flatMap f) = sum (map (countP p f) xs) := by
rcases xs with xs
simp [List.countP_flatMap, Function.comp_def]
@[simp] theorem countP_reverse (l : Array α) : countP p l.reverse = countP p l := by
cases l
@[simp] theorem countP_reverse (xs : Array α) : countP p xs.reverse = countP p xs := by
rcases xs with xs
simp [List.countP_reverse]
variable {p q}
theorem countP_mono_left (h : x l, p x q x) : countP p l countP q l := by
cases l
theorem countP_mono_left (h : x xs, p x q x) : countP p xs countP q xs := by
rcases xs with xs
simpa using List.countP_mono_left (by simpa using h)
theorem countP_congr (h : x l, p x q x) : countP p l = countP q l :=
theorem countP_congr (h : x xs, p x q x) : countP p xs = countP q xs :=
Nat.le_antisymm
(countP_mono_left fun x hx => (h x hx).1)
(countP_mono_left fun x hx => (h x hx).2)
@@ -149,71 +152,71 @@ variable [BEq α]
@[simp] theorem count_empty (a : α) : count a #[] = 0 := rfl
theorem count_push (a b : α) (l : Array α) :
count a (l.push b) = count a l + if b == a then 1 else 0 := by
theorem count_push (a b : α) (xs : Array α) :
count a (xs.push b) = count a xs + if b == a then 1 else 0 := by
simp [count, countP_push]
theorem count_eq_countP (a : α) (l : Array α) : count a l = countP (· == a) l := rfl
theorem count_eq_countP (a : α) (xs : Array α) : count a xs = countP (· == a) xs := rfl
theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
funext l
funext xs
apply count_eq_countP
theorem count_le_size (a : α) (l : Array α) : count a l l.size := countP_le_size _
theorem count_le_size (a : α) (xs : Array α) : count a xs xs.size := countP_le_size _
theorem count_le_count_push (a b : α) (l : Array α) : count a l count a (l.push b) := by
theorem count_le_count_push (a b : α) (xs : Array α) : count a xs count a (xs.push b) := by
simp [count_push]
theorem count_singleton (a b : α) : count a #[b] = if b == a then 1 else 0 := by
simp [count_eq_countP]
@[simp] theorem count_append (a : α) : l₁ l₂, count a (l₁ ++ l₂) = count a l₁ + count a l₂ :=
@[simp] theorem count_append (a : α) : xs ys, count a (xs ++ ys) = count a xs + count a ys :=
countP_append _
@[simp] theorem count_flatten (a : α) (l : Array (Array α)) :
count a l.flatten = (l.map (count a)).sum := by
cases l using array₂_induction
@[simp] theorem count_flatten (a : α) (xss : Array (Array α)) :
count a xss.flatten = (xss.map (count a)).sum := by
cases xss using array₂_induction
simp [List.count_flatten, Function.comp_def]
@[simp] theorem count_reverse (a : α) (l : Array α) : count a l.reverse = count a l := by
cases l
@[simp] theorem count_reverse (a : α) (xs : Array α) : count a xs.reverse = count a xs := by
rcases xs with xs
simp
theorem boole_getElem_le_count (a : α) (l : Array α) (i : Nat) (h : i < l.size) :
(if l[i] == a then 1 else 0) l.count a := by
theorem boole_getElem_le_count (a : α) (xs : Array α) (i : Nat) (h : i < xs.size) :
(if xs[i] == a then 1 else 0) xs.count a := by
rw [count_eq_countP]
apply boole_getElem_le_countP (· == a)
theorem count_set (a b : α) (l : Array α) (i : Nat) (h : i < l.size) :
(l.set i a).count b = l.count b - (if l[i] == b then 1 else 0) + (if a == b then 1 else 0) := by
theorem count_set (a b : α) (xs : Array α) (i : Nat) (h : i < xs.size) :
(xs.set i a).count b = xs.count b - (if xs[i] == b then 1 else 0) + (if a == b then 1 else 0) := by
simp [count_eq_countP, countP_set, h]
variable [LawfulBEq α]
@[simp] theorem count_push_self (a : α) (l : Array α) : count a (l.push a) = count a l + 1 := by
@[simp] theorem count_push_self (a : α) (xs : Array α) : count a (xs.push a) = count a xs + 1 := by
simp [count_push]
@[simp] theorem count_push_of_ne (h : b a) (l : Array α) : count a (l.push b) = count a l := by
@[simp] theorem count_push_of_ne (h : b a) (xs : Array α) : count a (xs.push b) = count a xs := by
simp_all [count_push, h]
theorem count_singleton_self (a : α) : count a #[a] = 1 := by simp
@[simp]
theorem count_pos_iff {a : α} {l : Array α} : 0 < count a l a l := by
theorem count_pos_iff {a : α} {xs : Array α} : 0 < count a xs a xs := by
simp only [count, countP_pos_iff, beq_iff_eq, exists_eq_right]
@[simp] theorem one_le_count_iff {a : α} {l : Array α} : 1 count a l a l :=
@[simp] theorem one_le_count_iff {a : α} {xs : Array α} : 1 count a xs a xs :=
count_pos_iff
theorem count_eq_zero_of_not_mem {a : α} {l : Array α} (h : a l) : count a l = 0 :=
theorem count_eq_zero_of_not_mem {a : α} {xs : Array α} (h : a xs) : count a xs = 0 :=
Decidable.byContradiction fun h' => h <| count_pos_iff.1 (Nat.pos_of_ne_zero h')
theorem not_mem_of_count_eq_zero {a : α} {l : Array α} (h : count a l = 0) : a l :=
theorem not_mem_of_count_eq_zero {a : α} {xs : Array α} (h : count a xs = 0) : a xs :=
fun h' => Nat.ne_of_lt (count_pos_iff.2 h') h.symm
theorem count_eq_zero {l : Array α} : count a l = 0 a l :=
theorem count_eq_zero {xs : Array α} : count a xs = 0 a xs :=
not_mem_of_count_eq_zero, count_eq_zero_of_not_mem
theorem count_eq_size {l : Array α} : count a l = l.size b l, a = b := by
theorem count_eq_size {xs : Array α} : count a xs = xs.size b xs, a = b := by
rw [count, countP_eq_size]
refine fun h b hb => Eq.symm ?_, fun h b hb => ?_
· simpa using h b hb
@@ -225,36 +228,37 @@ theorem count_eq_size {l : Array α} : count a l = l.size ↔ ∀ b ∈ l, a = b
theorem count_mkArray (a b : α) (n : Nat) : count a (mkArray n b) = if b == a then n else 0 := by
simp [ List.toArray_replicate, List.count_replicate]
theorem filter_beq (l : Array α) (a : α) : l.filter (· == a) = mkArray (count a l) a := by
cases l
theorem filter_beq (xs : Array α) (a : α) : xs.filter (· == a) = mkArray (count a xs) a := by
rcases xs with xs
simp [List.filter_beq]
theorem filter_eq {α} [DecidableEq α] (l : Array α) (a : α) : l.filter (· = a) = mkArray (count a l) a :=
filter_beq l a
theorem filter_eq {α} [DecidableEq α] (xs : Array α) (a : α) : xs.filter (· = a) = mkArray (count a xs) a :=
filter_beq xs a
theorem mkArray_count_eq_of_count_eq_size {l : Array α} (h : count a l = l.size) :
mkArray (count a l) a = l := by
cases l
theorem mkArray_count_eq_of_count_eq_size {xs : Array α} (h : count a xs = xs.size) :
mkArray (count a xs) a = xs := by
rcases xs with xs
rw [ toList_inj]
simp [List.replicate_count_eq_of_count_eq_length (by simpa using h)]
@[simp] theorem count_filter {l : Array α} (h : p a) : count a (filter p l) = count a l := by
cases l
@[simp] theorem count_filter {xs : Array α} (h : p a) : count a (filter p xs) = count a xs := by
rcases xs with xs
simp [List.count_filter, h]
theorem count_le_count_map [DecidableEq β] (l : Array α) (f : α β) (x : α) :
count x l count (f x) (map f l) := by
cases l
theorem count_le_count_map [DecidableEq β] (xs : Array α) (f : α β) (x : α) :
count x xs count (f x) (map f xs) := by
rcases xs with xs
simp [List.count_le_count_map, countP_map]
theorem count_filterMap {α} [BEq β] (b : β) (f : α Option β) (l : Array α) :
count b (filterMap f l) = countP (fun a => f a == some b) l := by
cases l
theorem count_filterMap {α} [BEq β] (b : β) (f : α Option β) (xs : Array α) :
count b (filterMap f xs) = countP (fun a => f a == some b) xs := by
rcases xs with xs
simp [List.count_filterMap, countP_filterMap]
theorem count_flatMap {α} [BEq β] (l : Array α) (f : α Array β) (x : β) :
count x (l.flatMap f) = sum (map (count x f) l) := by
simp [count_eq_countP, countP_flatMap, Function.comp_def]
theorem count_flatMap {α} [BEq β] (xs : Array α) (f : α Array β) (x : β) :
count x (xs.flatMap f) = sum (map (count x f) xs) := by
rcases xs with xs
simp [List.count_flatMap, countP_flatMap, Function.comp_def]
-- FIXME these theorems can be restored once `List.erase` and `Array.erase` have been related.

View File

@@ -9,6 +9,9 @@ import Init.Data.BEq
import Init.Data.List.Nat.BEq
import Init.ByCases
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
private theorem rel_of_isEqvAux
@@ -84,9 +87,9 @@ theorem isEqv_self [DecidableEq α] (xs : Array α) : Array.isEqv xs xs (· = ·
simp [isEqv, isEqvAux_self]
instance [DecidableEq α] : DecidableEq (Array α) :=
fun a b =>
match h:isEqv a b (fun a b => a = b) with
| true => isTrue (eq_of_isEqv a b h)
fun xs ys =>
match h:isEqv xs ys (fun a b => a = b) with
| true => isTrue (eq_of_isEqv xs ys h)
| false => isFalse fun h' => by subst h'; rw [isEqv_self] at h; contradiction
theorem beq_eq_decide [BEq α] (xs ys : Array α) :

View File

@@ -12,6 +12,9 @@ import Init.Data.List.Nat.Basic
# Lemmas about `Array.eraseP`, `Array.erase`, and `Array.eraseIdx`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
@@ -20,11 +23,11 @@ open Nat
@[simp] theorem eraseP_empty : #[].eraseP p = #[] := rfl
theorem eraseP_of_forall_mem_not {l : Array α} (h : a, a l ¬p a) : l.eraseP p = l := by
cases l
theorem eraseP_of_forall_mem_not {xs : Array α} (h : a, a xs ¬p a) : xs.eraseP p = xs := by
rcases xs with xs
simp_all [List.eraseP_of_forall_not]
theorem eraseP_of_forall_getElem_not {l : Array α} (h : i, (h : i < l.size) ¬p l[i]) : l.eraseP p = l :=
theorem eraseP_of_forall_getElem_not {xs : Array α} (h : i, (h : i < xs.size) ¬p xs[i]) : xs.eraseP p = xs :=
eraseP_of_forall_mem_not fun a m => by
rw [mem_iff_getElem] at m
obtain i, w, rfl := m
@@ -37,86 +40,86 @@ theorem eraseP_of_forall_getElem_not {l : Array α} (h : ∀ i, (h : i < l.size)
theorem eraseP_ne_empty_iff {xs : Array α} {p : α Bool} : xs.eraseP p #[] xs #[] x, p x xs #[x] := by
simp
theorem exists_of_eraseP {l : Array α} {a} (hm : a l) (hp : p a) :
a l₁ l₂, ( b l₁, ¬p b) p a l = l₁.push a ++ l₂ l.eraseP p = l₁ ++ l₂ := by
rcases l with l
theorem exists_of_eraseP {xs : Array α} {a} (hm : a xs) (hp : p a) :
a ys zs, ( b ys, ¬p b) p a xs = ys.push a ++ zs xs.eraseP p = ys ++ zs := by
rcases xs with xs
obtain a, l₁, l₂, h₁, h₂, rfl, h₃ := List.exists_of_eraseP (by simpa using hm) (hp)
refine a, l₁, l₂, by simpa using h₁, h₂, by simp, by simpa using h₃
theorem exists_or_eq_self_of_eraseP (p) (l : Array α) :
l.eraseP p = l
a l₁ l₂, ( b l₁, ¬p b) p a l = l₁.push a ++ l₂ l.eraseP p = l₁ ++ l₂ :=
if h : a l, p a then
theorem exists_or_eq_self_of_eraseP (p) (xs : Array α) :
xs.eraseP p = xs
a ys zs, ( b ys, ¬p b) p a xs = ys.push a ++ zs xs.eraseP p = ys ++ zs :=
if h : a xs, p a then
let _, ha, pa := h
.inr (exists_of_eraseP ha pa)
else
.inl (eraseP_of_forall_mem_not (h ·, ·, ·))
@[simp] theorem size_eraseP_of_mem {l : Array α} (al : a l) (pa : p a) :
(l.eraseP p).size = l.size - 1 := by
let _, l₁, l₂, _, _, e₁, e₂ := exists_of_eraseP al pa
@[simp] theorem size_eraseP_of_mem {xs : Array α} (al : a xs) (pa : p a) :
(xs.eraseP p).size = xs.size - 1 := by
let _, ys, zs, _, _, e₁, e₂ := exists_of_eraseP al pa
rw [e₂]; simp [size_append, e₁]; omega
theorem size_eraseP {l : Array α} : (l.eraseP p).size = if l.any p then l.size - 1 else l.size := by
theorem size_eraseP {xs : Array α} : (xs.eraseP p).size = if xs.any p then xs.size - 1 else xs.size := by
split <;> rename_i h
· simp only [any_eq_true] at h
obtain i, h, w := h
simp [size_eraseP_of_mem (l := l) (by simp) w]
simp [size_eraseP_of_mem (xs := xs) (by simp) w]
· simp only [any_eq_true] at h
rw [eraseP_of_forall_getElem_not]
simp_all
theorem size_eraseP_le (l : Array α) : (l.eraseP p).size l.size := by
rcases l with l
simpa using List.length_eraseP_le l
theorem size_eraseP_le (xs : Array α) : (xs.eraseP p).size xs.size := by
rcases xs with xs
simpa using List.length_eraseP_le xs
theorem le_size_eraseP (l : Array α) : l.size - 1 (l.eraseP p).size := by
rcases l with l
simpa using List.le_length_eraseP l
theorem le_size_eraseP (xs : Array α) : xs.size - 1 (xs.eraseP p).size := by
rcases xs with xs
simpa using List.le_length_eraseP xs
theorem mem_of_mem_eraseP {l : Array α} : a l.eraseP p a l := by
rcases l with l
theorem mem_of_mem_eraseP {xs : Array α} : a xs.eraseP p a xs := by
rcases xs with xs
simpa using List.mem_of_mem_eraseP
@[simp] theorem mem_eraseP_of_neg {l : Array α} (pa : ¬p a) : a l.eraseP p a l := by
rcases l with l
@[simp] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a xs.eraseP p a xs := by
rcases xs with xs
simpa using List.mem_eraseP_of_neg pa
@[simp] theorem eraseP_eq_self_iff {p} {l : Array α} : l.eraseP p = l a l, ¬ p a := by
rcases l with l
@[simp] theorem eraseP_eq_self_iff {xs : Array α} : xs.eraseP p = xs a xs, ¬ p a := by
rcases xs with xs
simp
theorem eraseP_map (f : β α) (l : Array β) : (map f l).eraseP p = map f (l.eraseP (p f)) := by
rcases l with l
simpa using List.eraseP_map f l
theorem eraseP_map (f : β α) (xs : Array β) : (xs.map f).eraseP p = (xs.eraseP (p f)).map f := by
rcases xs with xs
simpa using List.eraseP_map f xs
theorem eraseP_filterMap (f : α Option β) (l : Array α) :
(filterMap f l).eraseP p = filterMap f (l.eraseP (fun x => match f x with | some y => p y | none => false)) := by
rcases l with l
simpa using List.eraseP_filterMap f l
theorem eraseP_filterMap (f : α Option β) (xs : Array α) :
(filterMap f xs).eraseP p = filterMap f (xs.eraseP (fun x => match f x with | some y => p y | none => false)) := by
rcases xs with xs
simpa using List.eraseP_filterMap f xs
theorem eraseP_filter (f : α Bool) (l : Array α) :
(filter f l).eraseP p = filter f (l.eraseP (fun x => p x && f x)) := by
rcases l with l
simpa using List.eraseP_filter f l
theorem eraseP_filter (f : α Bool) (xs : Array α) :
(filter f xs).eraseP p = filter f (xs.eraseP (fun x => p x && f x)) := by
rcases xs with xs
simpa using List.eraseP_filter f xs
theorem eraseP_append_left {a : α} (pa : p a) {l₁ : Array α} l₂ (h : a l₁) :
(l₁ ++ l₂).eraseP p = l₁.eraseP p ++ l₂ := by
rcases l₁ with l₁
rcases l₂ with l₂
simpa using List.eraseP_append_left pa l₂ (by simpa using h)
theorem eraseP_append_left {a : α} (pa : p a) {xs : Array α} {ys : Array α} (h : a xs) :
(xs ++ ys).eraseP p = xs.eraseP p ++ ys := by
rcases xs with xs
rcases ys with ys
simpa using List.eraseP_append_left pa ys (by simpa using h)
theorem eraseP_append_right {l₁ : Array α} l₂ (h : b l₁, ¬p b) :
(l₁ ++ l₂).eraseP p = l₁ ++ l₂.eraseP p := by
rcases l₁ with l₁
rcases l₂ with l₂
simpa using List.eraseP_append_right l₂ (by simpa using h)
theorem eraseP_append_right {xs : Array α} ys (h : b xs, ¬p b) :
(xs ++ ys).eraseP p = xs ++ ys.eraseP p := by
rcases xs with xs
rcases ys with ys
simpa using List.eraseP_append_right ys (by simpa using h)
theorem eraseP_append (l₁ l₂ : Array α) :
(l₁ ++ l₂).eraseP p = if l₁.any p then l₁.eraseP p ++ l₂ else l₁ ++ l₂.eraseP p := by
rcases l₁ with l₁
rcases l₂ with l₂
simp only [List.append_toArray, List.eraseP_toArray, List.eraseP_append l₁ l₂, List.any_toArray']
theorem eraseP_append {xs : Array α} {ys : Array α} :
(xs ++ ys).eraseP p = if xs.any p then xs.eraseP p ++ ys else xs ++ ys.eraseP p := by
rcases xs with xs
rcases ys with ys
simp only [List.append_toArray, List.eraseP_toArray, List.eraseP_append, List.any_toArray]
split <;> simp
theorem eraseP_mkArray (n : Nat) (a : α) (p : α Bool) :
@@ -134,24 +137,24 @@ theorem eraseP_mkArray (n : Nat) (a : α) (p : α → Bool) :
simp only [ List.toArray_replicate, List.eraseP_toArray]
simp [h]
theorem eraseP_eq_iff {p} {l : Array α} :
l.eraseP p = l'
(( a l, ¬ p a) l = l')
a l₁ l₂, ( b l₁, ¬ p b) p a l = l₁.push a ++ l₂ l' = l₁ ++ l₂ := by
rcases l with l
rcases l' with l'
theorem eraseP_eq_iff {p} {xs : Array α} :
xs.eraseP p = ys
(( a xs, ¬ p a) xs = ys)
a as bs, ( b as, ¬ p b) p a xs = as.push a ++ bs ys = as ++ bs := by
rcases xs with l
rcases ys with ys
simp [List.eraseP_eq_iff]
constructor
· rintro (h | a, l₁, h₁, h₂, x, rfl, rfl)
· rintro (h | a, l₁, h₁, h₂, l, rfl, rfl)
· exact Or.inl h
· exact Or.inr a, l₁, by simpa using h₁, h₂, x, by simp
· rintro (h | a, l₁, h₁, h₂, x, rfl, rfl)
· exact Or.inr a, l₁, by simpa using h₁, h₂, l, by simp
· rintro (h | a, l₁, h₁, h₂, l, rfl, rfl)
· exact Or.inl h
· exact Or.inr a, l₁, by simpa using h₁, h₂, x, by simp
· exact Or.inr a, l₁, by simpa using h₁, h₂, l, by simp
theorem eraseP_comm {l : Array α} (h : a l, ¬ p a ¬ q a) :
(l.eraseP p).eraseP q = (l.eraseP q).eraseP p := by
rcases l with l
theorem eraseP_comm {xs : Array α} (h : a xs, ¬ p a ¬ q a) :
(xs.eraseP p).eraseP q = (xs.eraseP q).eraseP p := by
rcases xs with xs
simpa using List.eraseP_comm (by simpa using h)
/-! ### erase -/
@@ -159,16 +162,16 @@ theorem eraseP_comm {l : Array α} (h : ∀ a ∈ l, ¬ p a ¬ q a) :
section erase
variable [BEq α]
theorem erase_of_not_mem [LawfulBEq α] {a : α} {l : Array α} (h : a l) : l.erase a = l := by
rcases l with l
theorem erase_of_not_mem [LawfulBEq α] {a : α} {xs : Array α} (h : a xs) : xs.erase a = xs := by
rcases xs with xs
simp [List.erase_of_not_mem (by simpa using h)]
theorem erase_eq_eraseP' (a : α) (l : Array α) : l.erase a = l.eraseP (· == a) := by
rcases l with l
theorem erase_eq_eraseP' (a : α) (xs : Array α) : xs.erase a = xs.eraseP (· == a) := by
rcases xs with xs
simp [List.erase_eq_eraseP']
theorem erase_eq_eraseP [LawfulBEq α] (a : α) (l : Array α) : l.erase a = l.eraseP (a == ·) := by
rcases l with l
theorem erase_eq_eraseP [LawfulBEq α] (a : α) (xs : Array α) : xs.erase a = xs.eraseP (a == ·) := by
rcases xs with xs
simp [List.erase_eq_eraseP]
@[simp] theorem erase_eq_empty_iff [LawfulBEq α] {xs : Array α} {a : α} :
@@ -181,62 +184,62 @@ theorem erase_ne_empty_iff [LawfulBEq α] {xs : Array α} {a : α} :
rcases xs with xs
simp [List.erase_ne_nil_iff]
theorem exists_erase_eq [LawfulBEq α] {a : α} {l : Array α} (h : a l) :
l₁ l₂, a l₁ l = l₁.push a ++ l₂ l.erase a = l₁ ++ l₂ := by
let _, l₁, l₂, h₁, e, h₂, h₃ := exists_of_eraseP h (beq_self_eq_true _)
rw [erase_eq_eraseP]; exact l₁, l₂, fun h => h₁ _ h (beq_self_eq_true _), eq_of_beq e h₂, h₃
theorem exists_erase_eq [LawfulBEq α] {a : α} {xs : Array α} (h : a xs) :
ys zs, a ys xs = ys.push a ++ zs xs.erase a = ys ++ zs := by
let _, ys, zs, h₁, e, h₂, h₃ := exists_of_eraseP h (beq_self_eq_true _)
rw [erase_eq_eraseP]; exact ys, zs, fun h => h₁ _ h (beq_self_eq_true _), eq_of_beq e h₂, h₃
@[simp] theorem size_erase_of_mem [LawfulBEq α] {a : α} {l : Array α} (h : a l) :
(l.erase a).size = l.size - 1 := by
@[simp] theorem size_erase_of_mem [LawfulBEq α] {a : α} {xs : Array α} (h : a xs) :
(xs.erase a).size = xs.size - 1 := by
rw [erase_eq_eraseP]; exact size_eraseP_of_mem h (beq_self_eq_true a)
theorem size_erase [LawfulBEq α] (a : α) (l : Array α) :
(l.erase a).size = if a l then l.size - 1 else l.size := by
theorem size_erase [LawfulBEq α] (a : α) (xs : Array α) :
(xs.erase a).size = if a xs then xs.size - 1 else xs.size := by
rw [erase_eq_eraseP, size_eraseP]
congr
simp [mem_iff_getElem, eq_comm (a := a)]
theorem size_erase_le (a : α) (l : Array α) : (l.erase a).size l.size := by
rcases l with l
simpa using List.length_erase_le a l
theorem size_erase_le (a : α) (xs : Array α) : (xs.erase a).size xs.size := by
rcases xs with xs
simpa using List.length_erase_le a xs
theorem le_size_erase [LawfulBEq α] (a : α) (l : Array α) : l.size - 1 (l.erase a).size := by
rcases l with l
simpa using List.le_length_erase a l
theorem le_size_erase [LawfulBEq α] (a : α) (xs : Array α) : xs.size - 1 (xs.erase a).size := by
rcases xs with xs
simpa using List.le_length_erase a xs
theorem mem_of_mem_erase {a b : α} {l : Array α} (h : a l.erase b) : a l := by
rcases l with l
theorem mem_of_mem_erase {a b : α} {xs : Array α} (h : a xs.erase b) : a xs := by
rcases xs with xs
simpa using List.mem_of_mem_erase (by simpa using h)
@[simp] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : Array α} (ab : a b) :
a l.erase b a l :=
erase_eq_eraseP b l mem_eraseP_of_neg (mt eq_of_beq ab.symm)
@[simp] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a b) :
a xs.erase b a xs :=
erase_eq_eraseP b xs mem_eraseP_of_neg (mt eq_of_beq ab.symm)
@[simp] theorem erase_eq_self_iff [LawfulBEq α] {l : Array α} : l.erase a = l a l := by
@[simp] theorem erase_eq_self_iff [LawfulBEq α] {xs : Array α} : xs.erase a = xs a xs := by
rw [erase_eq_eraseP', eraseP_eq_self_iff]
simp [forall_mem_ne']
theorem erase_filter [LawfulBEq α] (f : α Bool) (l : Array α) :
(filter f l).erase a = filter f (l.erase a) := by
rcases l with l
simpa using List.erase_filter f l
theorem erase_filter [LawfulBEq α] (f : α Bool) (xs : Array α) :
(filter f xs).erase a = filter f (xs.erase a) := by
rcases xs with xs
simpa using List.erase_filter f xs
theorem erase_append_left [LawfulBEq α] {l₁ : Array α} (l₂) (h : a l₁) :
(l₁ ++ l₂).erase a = l₁.erase a ++ l₂ := by
rcases l₁ with l₁
rcases l₂ with l₂
simpa using List.erase_append_left l₂ (by simpa using h)
theorem erase_append_left [LawfulBEq α] {xs : Array α} (ys) (h : a xs) :
(xs ++ ys).erase a = xs.erase a ++ ys := by
rcases xs with xs
rcases ys with ys
simpa using List.erase_append_left ys (by simpa using h)
theorem erase_append_right [LawfulBEq α] {a : α} {l₁ : Array α} (l₂ : Array α) (h : a l₁) :
(l₁ ++ l₂).erase a = (l₁ ++ l₂.erase a) := by
rcases l₁ with l₁
rcases l₂ with l₂
simpa using List.erase_append_right l₂ (by simpa using h)
theorem erase_append_right [LawfulBEq α] {a : α} {xs : Array α} (ys : Array α) (h : a xs) :
(xs ++ ys).erase a = (xs ++ ys.erase a) := by
rcases xs with xs
rcases ys with ys
simpa using List.erase_append_right ys (by simpa using h)
theorem erase_append [LawfulBEq α] {a : α} {l₁ l₂ : Array α} :
(l₁ ++ l₂).erase a = if a l₁ then l₁.erase a ++ l₂ else l₁ ++ l₂.erase a := by
rcases l₁ with l₁
rcases l₂ with l₂
theorem erase_append [LawfulBEq α] {a : α} {xs ys : Array α} :
(xs ++ ys).erase a = if a xs then xs.erase a ++ ys else xs ++ ys.erase a := by
rcases xs with xs
rcases ys with ys
simp only [List.append_toArray, List.erase_toArray, List.erase_append, mem_toArray]
split <;> simp
@@ -246,24 +249,24 @@ theorem erase_mkArray [LawfulBEq α] (n : Nat) (a b : α) :
simp only [List.erase_replicate, beq_iff_eq, List.toArray_replicate]
split <;> simp
theorem erase_comm [LawfulBEq α] (a b : α) (l : Array α) :
(l.erase a).erase b = (l.erase b).erase a := by
rcases l with l
simpa using List.erase_comm a b l
theorem erase_comm [LawfulBEq α] (a b : α) (xs : Array α) :
(xs.erase a).erase b = (xs.erase b).erase a := by
rcases xs with xs
simpa using List.erase_comm a b xs
theorem erase_eq_iff [LawfulBEq α] {a : α} {l : Array α} :
l.erase a = l'
(a l l = l')
l₁ l₂, a l₁ l = l₁.push a ++ l₂ l' = l₁ ++ l₂ := by
theorem erase_eq_iff [LawfulBEq α] {a : α} {xs : Array α} :
xs.erase a = ys
(a xs xs = ys)
as bs, a as xs = as.push a ++ bs ys = as ++ bs := by
rw [erase_eq_eraseP', eraseP_eq_iff]
simp only [beq_iff_eq, forall_mem_ne', exists_and_left]
constructor
· rintro (h, rfl | a', l', h, rfl, x, rfl, rfl)
· rintro (h, rfl | a', as, h, rfl, bs, rfl, rfl)
· left; simp_all
· right; refine l', h, x, by simp
· rintro (h, rfl | l₁, h, x, rfl, rfl)
· right; refine as, h, bs, by simp
· rintro (h, rfl | as, h, bs, rfl, rfl)
· left; simp_all
· right; refine a, l₁, h, rfl, x, by simp
· right; refine a, as, h, rfl, bs, by simp
@[simp] theorem erase_mkArray_self [LawfulBEq α] {a : α} :
(mkArray n a).erase a = mkArray (n - 1) a := by
@@ -279,8 +282,8 @@ end erase
/-! ### eraseIdx -/
theorem eraseIdx_eq_take_drop_succ (l : Array α) (i : Nat) (h) : l.eraseIdx i = l.take i ++ l.drop (i + 1) := by
rcases l with l
theorem eraseIdx_eq_take_drop_succ (xs : Array α) (i : Nat) (h) : xs.eraseIdx i = xs.take i ++ xs.drop (i + 1) := by
rcases xs with xs
simp only [List.size_toArray] at h
simp only [List.eraseIdx_toArray, List.eraseIdx_eq_take_drop_succ, take_eq_extract,
List.extract_toArray, List.extract_eq_drop_take, Nat.sub_zero, List.drop_zero, drop_eq_extract,
@@ -288,61 +291,61 @@ theorem eraseIdx_eq_take_drop_succ (l : Array α) (i : Nat) (h) : l.eraseIdx i =
rw [List.take_of_length_le]
simp
theorem getElem?_eraseIdx (l : Array α) (i : Nat) (h : i < l.size) (j : Nat) :
(l.eraseIdx i)[j]? = if j < i then l[j]? else l[j + 1]? := by
rcases l with l
theorem getElem?_eraseIdx (xs : Array α) (i : Nat) (h : i < xs.size) (j : Nat) :
(xs.eraseIdx i)[j]? = if j < i then xs[j]? else xs[j + 1]? := by
rcases xs with xs
simp [List.getElem?_eraseIdx]
theorem getElem?_eraseIdx_of_lt (l : Array α) (i : Nat) (h : i < l.size) (j : Nat) (h' : j < i) :
(l.eraseIdx i)[j]? = l[j]? := by
theorem getElem?_eraseIdx_of_lt (xs : Array α) (i : Nat) (h : i < xs.size) (j : Nat) (h' : j < i) :
(xs.eraseIdx i)[j]? = xs[j]? := by
rw [getElem?_eraseIdx]
simp [h']
theorem getElem?_eraseIdx_of_ge (l : Array α) (i : Nat) (h : i < l.size) (j : Nat) (h' : i j) :
(l.eraseIdx i)[j]? = l[j + 1]? := by
theorem getElem?_eraseIdx_of_ge (xs : Array α) (i : Nat) (h : i < xs.size) (j : Nat) (h' : i j) :
(xs.eraseIdx i)[j]? = xs[j + 1]? := by
rw [getElem?_eraseIdx]
simp only [dite_eq_ite, ite_eq_right_iff]
intro h'
omega
theorem getElem_eraseIdx (l : Array α) (i : Nat) (h : i < l.size) (j : Nat) (h' : j < (l.eraseIdx i).size) :
(l.eraseIdx i)[j] = if h'' : j < i then
l[j]
theorem getElem_eraseIdx (xs : Array α) (i : Nat) (h : i < xs.size) (j : Nat) (h' : j < (xs.eraseIdx i).size) :
(xs.eraseIdx i)[j] = if h'' : j < i then
xs[j]
else
l[j + 1]'(by rw [size_eraseIdx] at h'; omega) := by
xs[j + 1]'(by rw [size_eraseIdx] at h'; omega) := by
apply Option.some.inj
rw [ getElem?_eq_getElem, getElem?_eraseIdx]
split <;> simp
@[simp] theorem eraseIdx_eq_empty_iff {l : Array α} {i : Nat} {h} : eraseIdx l i = #[] l.size = 1 i = 0 := by
rcases l with l
@[simp] theorem eraseIdx_eq_empty_iff {xs : Array α} {i : Nat} {h} : xs.eraseIdx i = #[] xs.size = 1 i = 0 := by
rcases xs with xs
simp only [List.eraseIdx_toArray, mk.injEq, List.eraseIdx_eq_nil_iff, List.size_toArray,
or_iff_right_iff_imp]
rintro rfl
simp_all
theorem eraseIdx_ne_empty_iff {l : Array α} {i : Nat} {h} : eraseIdx l i #[] 2 l.size := by
rcases l with _ | a, (_ | b, l)
theorem eraseIdx_ne_empty_iff {xs : Array α} {i : Nat} {h} : xs.eraseIdx i #[] 2 xs.size := by
rcases xs with _ | a, (_ | b, l)
· simp
· simp at h
simp [h]
· simp
theorem mem_of_mem_eraseIdx {l : Array α} {i : Nat} {h} {a : α} (h : a l.eraseIdx i) : a l := by
rcases l with l
theorem mem_of_mem_eraseIdx {xs : Array α} {i : Nat} {h} {a : α} (h : a xs.eraseIdx i) : a xs := by
rcases xs with xs
simpa using List.mem_of_mem_eraseIdx (by simpa using h)
theorem eraseIdx_append_of_lt_size {l : Array α} {k : Nat} (hk : k < l.size) (l' : Array α) (h) :
eraseIdx (l ++ l') k = eraseIdx l k ++ l' := by
rcases l with l
rcases l' with l'
theorem eraseIdx_append_of_lt_size {xs : Array α} {k : Nat} (hk : k < xs.size) (ys : Array α) (h) :
eraseIdx (xs ++ ys) k = eraseIdx xs k ++ ys := by
rcases xs with l
rcases ys with l'
simp at hk
simp [List.eraseIdx_append_of_lt_length, *]
theorem eraseIdx_append_of_length_le {l : Array α} {k : Nat} (hk : l.size k) (l' : Array α) (h) :
eraseIdx (l ++ l') k = l ++ eraseIdx l' (k - l.size) (by simp at h; omega) := by
rcases l with l
rcases l' with l'
theorem eraseIdx_append_of_length_le {xs : Array α} {k : Nat} (hk : xs.size k) (ys : Array α) (h) :
eraseIdx (xs ++ ys) k = xs ++ eraseIdx ys (k - xs.size) (by simp at h; omega) := by
rcases xs with l
rcases ys with l'
simp at hk
simp [List.eraseIdx_append_of_length_le, *]
@@ -352,49 +355,49 @@ theorem eraseIdx_mkArray {n : Nat} {a : α} {k : Nat} {h} :
simp only [ List.toArray_replicate, List.eraseIdx_toArray]
simp [List.eraseIdx_replicate, h]
theorem mem_eraseIdx_iff_getElem {x : α} {l} {k} {h} : x eraseIdx l k h i w, i k l[i]'w = x := by
rcases l with l
theorem mem_eraseIdx_iff_getElem {x : α} {xs : Array α} {k} {h} : x xs.eraseIdx k h i w, i k xs[i]'w = x := by
rcases xs with xs
simp [List.mem_eraseIdx_iff_getElem, *]
theorem mem_eraseIdx_iff_getElem? {x : α} {l} {k} {h} : x eraseIdx l k h i k, l[i]? = some x := by
rcases l with l
theorem mem_eraseIdx_iff_getElem? {x : α} {xs : Array α} {k} {h} : x xs.eraseIdx k h i k, xs[i]? = some x := by
rcases xs with xs
simp [List.mem_eraseIdx_iff_getElem?, *]
theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α] (l : Array α) (a : α) (i : Nat) (w : l.idxOf a = i) (h : i < l.size) :
l.erase a = l.eraseIdx i := by
rcases l with l
theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α] (xs : Array α) (a : α) (i : Nat) (w : xs.idxOf a = i) (h : i < xs.size) :
xs.erase a = xs.eraseIdx i := by
rcases xs with xs
simp at w
simp [List.erase_eq_eraseIdx_of_idxOf, *]
theorem getElem_eraseIdx_of_lt (l : Array α) (i : Nat) (w : i < l.size) (j : Nat) (h : j < (l.eraseIdx i).size) (h' : j < i) :
(l.eraseIdx i)[j] = l[j] := by
rcases l with l
theorem getElem_eraseIdx_of_lt (xs : Array α) (i : Nat) (w : i < xs.size) (j : Nat) (h : j < (xs.eraseIdx i).size) (h' : j < i) :
(xs.eraseIdx i)[j] = xs[j] := by
rcases xs with xs
simp [List.getElem_eraseIdx_of_lt, *]
theorem getElem_eraseIdx_of_ge (l : Array α) (i : Nat) (w : i < l.size) (j : Nat) (h : j < (l.eraseIdx i).size) (h' : i j) :
(l.eraseIdx i)[j] = l[j + 1]'(by simp at h; omega) := by
rcases l with l
theorem getElem_eraseIdx_of_ge (xs : Array α) (i : Nat) (w : i < xs.size) (j : Nat) (h : j < (xs.eraseIdx i).size) (h' : i j) :
(xs.eraseIdx i)[j] = xs[j + 1]'(by simp at h; omega) := by
rcases xs with xs
simp [List.getElem_eraseIdx_of_ge, *]
theorem eraseIdx_set_eq {l : Array α} {i : Nat} {a : α} {h : i < l.size} :
(l.set i a).eraseIdx i (by simp; omega) = l.eraseIdx i := by
rcases l with l
theorem eraseIdx_set_eq {xs : Array α} {i : Nat} {a : α} {h : i < xs.size} :
(xs.set i a).eraseIdx i (by simp; omega) = xs.eraseIdx i := by
rcases xs with xs
simp [List.eraseIdx_set_eq, *]
theorem eraseIdx_set_lt {l : Array α} {i : Nat} {w : i < l.size} {j : Nat} {a : α} (h : j < i) :
(l.set i a).eraseIdx j (by simp; omega) = (l.eraseIdx j).set (i - 1) a (by simp; omega) := by
rcases l with l
theorem eraseIdx_set_lt {xs : Array α} {i : Nat} {w : i < xs.size} {j : Nat} {a : α} (h : j < i) :
(xs.set i a).eraseIdx j (by simp; omega) = (xs.eraseIdx j).set (i - 1) a (by simp; omega) := by
rcases xs with xs
simp [List.eraseIdx_set_lt, *]
theorem eraseIdx_set_gt {l : Array α} {i : Nat} {j : Nat} {a : α} (h : i < j) {w : j < l.size} :
(l.set i a).eraseIdx j (by simp; omega) = (l.eraseIdx j).set i a (by simp; omega) := by
rcases l with l
theorem eraseIdx_set_gt {xs : Array α} {i : Nat} {j : Nat} {a : α} (h : i < j) {w : j < xs.size} :
(xs.set i a).eraseIdx j (by simp; omega) = (xs.eraseIdx j).set i a (by simp; omega) := by
rcases xs with xs
simp [List.eraseIdx_set_gt, *]
@[simp] theorem set_getElem_succ_eraseIdx_succ
{l : Array α} {i : Nat} (h : i + 1 < l.size) :
(l.eraseIdx (i + 1)).set i l[i + 1] (by simp; omega) = l.eraseIdx i := by
rcases l with l
{xs : Array α} {i : Nat} (h : i + 1 < xs.size) :
(xs.eraseIdx (i + 1)).set i xs[i + 1] (by simp; omega) = xs.eraseIdx i := by
rcases xs with xs
simp [List.set_getElem_succ_eraseIdx_succ, *]
end Array

View File

@@ -13,6 +13,9 @@ import Init.Data.List.Nat.TakeDrop
This file follows the contents of `Init.Data.List.TakeDrop` and `Init.Data.List.Nat.TakeDrop`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Nat
namespace Array
@@ -354,10 +357,10 @@ theorem takeWhile_append {xs ys : Array α} :
simp only [List.append_toArray, List.takeWhile_toArray, List.takeWhile_append, List.size_toArray]
split <;> rfl
@[simp] theorem takeWhile_append_of_pos {p : α Bool} {l₁ l₂ : Array α} (h : a l₁, p a) :
(l₁ ++ l₂).takeWhile p = l₁ ++ l₂.takeWhile p := by
rcases l₁ with l₁
rcases l₂ with l₂
@[simp] theorem takeWhile_append_of_pos {p : α Bool} {xs ys : Array α} (h : a xs, p a) :
(xs ++ ys).takeWhile p = xs ++ ys.takeWhile p := by
rcases xs with xs
rcases ys with ys
simp at h
simp [List.takeWhile_append_of_pos h]
@@ -374,10 +377,10 @@ theorem popWhile_append {xs ys : Array α} :
· rfl
· simp
@[simp] theorem popWhile_append_of_pos {p : α Bool} {l₁ l₂ : Array α} (h : a l₂, p a) :
(l₁ ++ l₂).popWhile p = l₁.popWhile p := by
rcases l₁ with l₁
rcases l₂ with l₂
@[simp] theorem popWhile_append_of_pos {p : α Bool} {xs ys : Array α} (h : a ys, p a) :
(xs ++ ys).popWhile p = xs.popWhile p := by
rcases xs with xs
rcases ys with ys
simp at h
simp only [List.append_toArray, List.popWhile_toArray, List.reverse_append, mk.injEq,
List.reverse_inj]

View File

@@ -7,6 +7,9 @@ prelude
import Init.Data.List.FinRange
import Init.Data.Array.OfFn
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/-- `finRange n` is the array of all elements of `Fin n` in order. -/

View File

@@ -13,77 +13,79 @@ import Init.Data.Array.Range
# Lemmas about `Array.findSome?`, `Array.find?, `Array.findIdx`, `Array.findIdx?`, `Array.idxOf`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
/-! ### findSome? -/
@[simp] theorem findSomeRev?_push_of_isSome (l : Array α) (h : (f a).isSome) : (l.push a).findSomeRev? f = f a := by
cases l; simp_all
@[simp] theorem findSomeRev?_push_of_isSome (xs : Array α) (h : (f a).isSome) : (xs.push a).findSomeRev? f = f a := by
cases xs; simp_all
@[simp] theorem findSomeRev?_push_of_isNone (l : Array α) (h : (f a).isNone) : (l.push a).findSomeRev? f = l.findSomeRev? f := by
cases l; simp_all
@[simp] theorem findSomeRev?_push_of_isNone (xs : Array α) (h : (f a).isNone) : (xs.push a).findSomeRev? f = xs.findSomeRev? f := by
cases xs; simp_all
theorem exists_of_findSome?_eq_some {f : α Option β} {l : Array α} (w : l.findSome? f = some b) :
a, a l f a = b := by
cases l; simp_all [List.exists_of_findSome?_eq_some]
theorem exists_of_findSome?_eq_some {f : α Option β} {xs : Array α} (w : xs.findSome? f = some b) :
a, a xs f a = b := by
cases xs; simp_all [List.exists_of_findSome?_eq_some]
@[simp] theorem findSome?_eq_none_iff : findSome? p l = none x l, p x = none := by
cases l; simp
@[simp] theorem findSome?_eq_none_iff : findSome? p xs = none x xs, p x = none := by
cases xs; simp
@[simp] theorem findSome?_isSome_iff {f : α Option β} {l : Array α} :
(l.findSome? f).isSome x, x l (f x).isSome := by
cases l; simp
@[simp] theorem findSome?_isSome_iff {f : α Option β} {xs : Array α} :
(xs.findSome? f).isSome x, x xs (f x).isSome := by
cases xs; simp
theorem findSome?_eq_some_iff {f : α Option β} {l : Array α} {b : β} :
l.findSome? f = some b (l₁ : Array α) (a : α) (l₂ : Array α), l = l₁.push a ++ l₂ f a = some b x l₁, f x = none := by
cases l
theorem findSome?_eq_some_iff {f : α Option β} {xs : Array α} {b : β} :
xs.findSome? f = some b (ys : Array α) (a : α) (zs : Array α), xs = ys.push a ++ zs f a = some b x ys, f x = none := by
cases xs
simp only [List.findSome?_toArray, List.findSome?_eq_some_iff]
constructor
· rintro l₁, a, l₂, rfl, h₁, h₂
exact l₁.toArray, a, l₂.toArray, by simp_all
· rintro l₁, a, l₂, h₀, h₁, h₂
exact l₁.toList, a, l₂.toList, by simpa using congrArg toList h₀, h₁, by simpa
· rintro xs, a, ys, h₀, h₁, h₂
exact xs.toList, a, ys.toList, by simpa using congrArg toList h₀, h₁, by simpa
@[simp] theorem findSome?_guard (l : Array α) : findSome? (Option.guard fun x => p x) l = find? p l := by
cases l; simp
@[simp] theorem findSome?_guard (xs : Array α) : findSome? (Option.guard fun x => p x) xs = find? p xs := by
cases xs; simp
theorem find?_eq_findSome?_guard (l : Array α) : find? p l = findSome? (Option.guard fun x => p x) l :=
(findSome?_guard l).symm
theorem find?_eq_findSome?_guard (xs : Array α) : find? p xs = findSome? (Option.guard fun x => p x) xs :=
(findSome?_guard xs).symm
@[simp] theorem getElem?_zero_filterMap (f : α Option β) (l : Array α) : (l.filterMap f)[0]? = l.findSome? f := by
cases l; simp [ List.head?_eq_getElem?]
@[simp] theorem getElem?_zero_filterMap (f : α Option β) (xs : Array α) : (xs.filterMap f)[0]? = xs.findSome? f := by
cases xs; simp [ List.head?_eq_getElem?]
@[simp] theorem getElem_zero_filterMap (f : α Option β) (l : Array α) (h) :
(l.filterMap f)[0] = (l.findSome? f).get (by cases l; simpa [List.length_filterMap_eq_countP] using h) := by
cases l; simp [ List.head_eq_getElem, getElem?_zero_filterMap]
@[simp] theorem getElem_zero_filterMap (f : α Option β) (xs : Array α) (h) :
(xs.filterMap f)[0] = (xs.findSome? f).get (by cases xs; simpa [List.length_filterMap_eq_countP] using h) := by
cases xs; simp [ List.head_eq_getElem, getElem?_zero_filterMap]
@[simp] theorem back?_filterMap (f : α Option β) (l : Array α) : (l.filterMap f).back? = l.findSomeRev? f := by
cases l; simp
@[simp] theorem back?_filterMap (f : α Option β) (xs : Array α) : (xs.filterMap f).back? = xs.findSomeRev? f := by
cases xs; simp
@[simp] theorem back!_filterMap [Inhabited β] (f : α Option β) (l : Array α) :
(l.filterMap f).back! = (l.findSomeRev? f).getD default := by
cases l; simp
@[simp] theorem back!_filterMap [Inhabited β] (f : α Option β) (xs : Array α) :
(xs.filterMap f).back! = (xs.findSomeRev? f).getD default := by
cases xs; simp
@[simp] theorem map_findSome? (f : α Option β) (g : β γ) (l : Array α) :
(l.findSome? f).map g = l.findSome? (Option.map g f) := by
cases l; simp
@[simp] theorem map_findSome? (f : α Option β) (g : β γ) (xs : Array α) :
(xs.findSome? f).map g = xs.findSome? (Option.map g f) := by
cases xs; simp
theorem findSome?_map (f : β γ) (l : Array β) : findSome? p (l.map f) = l.findSome? (p f) := by
cases l; simp [List.findSome?_map]
theorem findSome?_map (f : β γ) (xs : Array β) : findSome? p (xs.map f) = xs.findSome? (p f) := by
cases xs; simp [List.findSome?_map]
theorem findSome?_append {l₁ l₂ : Array α} : (l₁ ++ l₂).findSome? f = (l₁.findSome? f).or (l₂.findSome? f) := by
cases l₁; cases l₂; simp [List.findSome?_append]
theorem findSome?_append {xs ys : Array α} : (xs ++ ys).findSome? f = (xs.findSome? f).or (ys.findSome? f) := by
cases xs; cases ys; simp [List.findSome?_append]
theorem getElem?_zero_flatten (L : Array (Array α)) :
(flatten L)[0]? = L.findSome? fun l => l[0]? := by
cases L using array₂_induction
theorem getElem?_zero_flatten (xss : Array (Array α)) :
(flatten xss)[0]? = xss.findSome? fun xs => xs[0]? := by
cases xss using array₂_induction
simp [ List.head?_eq_getElem?, List.head?_flatten, List.findSome?_map, Function.comp_def]
theorem getElem_zero_flatten.proof {L : Array (Array α)} (h : 0 < L.flatten.size) :
(L.findSome? fun l => l[0]?).isSome := by
cases L using array₂_induction
theorem getElem_zero_flatten.proof {xss : Array (Array α)} (h : 0 < xss.flatten.size) :
(xss.findSome? fun xs => xs[0]?).isSome := by
cases xss using array₂_induction
simp only [List.findSome?_toArray, List.findSome?_map, Function.comp_def, List.getElem?_toArray,
List.findSome?_isSome_iff, isSome_getElem?]
simp only [flatten_toArray_map_toArray, List.size_toArray, List.length_flatten,
@@ -91,17 +93,12 @@ theorem getElem_zero_flatten.proof {L : Array (Array α)} (h : 0 < L.flatten.siz
obtain _, xs, m, rfl, h := h
exact xs, m, by simpa using h
theorem getElem_zero_flatten {L : Array (Array α)} (h) :
(flatten L)[0] = (L.findSome? fun l => l[0]?).get (getElem_zero_flatten.proof h) := by
have t := getElem?_zero_flatten L
theorem getElem_zero_flatten {xss : Array (Array α)} (h) :
(flatten xss)[0] = (xss.findSome? fun xs => xs[0]?).get (getElem_zero_flatten.proof h) := by
have t := getElem?_zero_flatten xss
simp [getElem?_eq_getElem, h] at t
simp [ t]
theorem back?_flatten {L : Array (Array α)} :
(flatten L).back? = (L.findSomeRev? fun l => l.back?) := by
cases L using array₂_induction
simp [List.getLast?_flatten, List.map_reverse, List.findSome?_map, Function.comp_def]
theorem findSome?_mkArray : findSome? f (mkArray n a) = if n = 0 then none else f a := by
simp [ List.toArray_replicate, List.findSome?_replicate]
@@ -124,16 +121,16 @@ theorem findSome?_mkArray : findSome? f (mkArray n a) = if n = 0 then none else
#[a].find? p = if p a then some a else none := by
simp [singleton_eq_toArray_singleton]
@[simp] theorem findRev?_push_of_pos (l : Array α) (h : p a) :
findRev? p (l.push a) = some a := by
cases l; simp [h]
@[simp] theorem findRev?_push_of_pos (xs : Array α) (h : p a) :
findRev? p (xs.push a) = some a := by
cases xs; simp [h]
@[simp] theorem findRev?_cons_of_neg (l : Array α) (h : ¬p a) :
findRev? p (l.push a) = findRev? p l := by
cases l; simp [h]
@[simp] theorem findRev?_cons_of_neg (xs : Array α) (h : ¬p a) :
findRev? p (xs.push a) = findRev? p xs := by
cases xs; simp [h]
@[simp] theorem find?_eq_none : find? p l = none x l, ¬ p x := by
cases l; simp
@[simp] theorem find?_eq_none : find? p xs = none x xs, ¬ p x := by
cases xs; simp
theorem find?_eq_some_iff_append {xs : Array α} :
xs.find? p = some b p b (as bs : Array α), xs = as.push b ++ bs a as, !p a := by
@@ -142,10 +139,10 @@ theorem find?_eq_some_iff_append {xs : Array α} :
Bool.not_true, exists_and_right, and_congr_right_iff]
intro w
constructor
· rintro as, x, rfl, h
exact as.toArray, x.toArray, by simp , by simpa using h
· rintro as, x, h', h
exact as.toList, x.toList, by simpa using congrArg Array.toList h',
· rintro as, xs, rfl, h
exact as.toArray, xs.toArray, by simp , by simpa using h
· rintro as, l, h', h
exact as.toList, l, by simpa using congrArg Array.toList h',
by simpa using h
@[simp]
@@ -174,22 +171,22 @@ theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
(xs.filter p).find? q = xs.find? (fun a => p a q a) := by
cases xs; simp
@[simp] theorem getElem?_zero_filter (p : α Bool) (l : Array α) :
(l.filter p)[0]? = l.find? p := by
cases l; simp [ List.head?_eq_getElem?]
@[simp] theorem getElem?_zero_filter (p : α Bool) (xs : Array α) :
(xs.filter p)[0]? = xs.find? p := by
cases xs; simp [ List.head?_eq_getElem?]
@[simp] theorem getElem_zero_filter (p : α Bool) (l : Array α) (h) :
(l.filter p)[0] =
(l.find? p).get (by cases l; simpa [ List.countP_eq_length_filter] using h) := by
cases l
@[simp] theorem getElem_zero_filter (p : α Bool) (xs : Array α) (h) :
(xs.filter p)[0] =
(xs.find? p).get (by cases xs; simpa [ List.countP_eq_length_filter] using h) := by
cases xs
simp [List.getElem_zero_eq_head]
@[simp] theorem back?_filter (p : α Bool) (l : Array α) : (l.filter p).back? = l.findRev? p := by
cases l; simp
@[simp] theorem back?_filter (p : α Bool) (xs : Array α) : (xs.filter p).back? = xs.findRev? p := by
cases xs; simp
@[simp] theorem back!_filter [Inhabited α] (p : α Bool) (l : Array α) :
(l.filter p).back! = (l.findRev? p).get! := by
cases l; simp [Option.get!_eq_getD]
@[simp] theorem back!_filter [Inhabited α] (p : α Bool) (xs : Array α) :
(xs.filter p).back! = (xs.findRev? p).get! := by
cases xs; simp [Option.get!_eq_getD]
@[simp] theorem find?_filterMap (xs : Array α) (f : α Option β) (p : β Bool) :
(xs.filterMap f).find? p = (xs.find? (fun a => (f a).any p)).bind f := by
@@ -199,19 +196,19 @@ theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
find? p (xs.map f) = (xs.find? (p f)).map f := by
cases xs; simp
@[simp] theorem find?_append {l₁ l₂ : Array α} :
(l₁ ++ l₂).find? p = (l₁.find? p).or (l₂.find? p) := by
cases l₁
cases l₂
@[simp] theorem find?_append {xs ys : Array α} :
(xs ++ ys).find? p = (xs.find? p).or (ys.find? p) := by
cases xs
cases ys
simp
@[simp] theorem find?_flatten (xs : Array (Array α)) (p : α Bool) :
xs.flatten.find? p = xs.findSome? (·.find? p) := by
cases xs using array₂_induction
@[simp] theorem find?_flatten (xss : Array (Array α)) (p : α Bool) :
xss.flatten.find? p = xss.findSome? (·.find? p) := by
cases xss using array₂_induction
simp [List.findSome?_map, Function.comp_def]
theorem find?_flatten_eq_none_iff {xs : Array (Array α)} {p : α Bool} :
xs.flatten.find? p = none ys xs, x ys, !p x := by
theorem find?_flatten_eq_none_iff {xss : Array (Array α)} {p : α Bool} :
xss.flatten.find? p = none ys xss, x ys, !p x := by
simp
@[deprecated find?_flatten_eq_none_iff (since := "2025-02-03")]
@@ -222,12 +219,12 @@ If `find? p` returns `some a` from `xs.flatten`, then `p a` holds, and
some array in `xs` contains `a`, and no earlier element of that array satisfies `p`.
Moreover, no earlier array in `xs` has an element satisfying `p`.
-/
theorem find?_flatten_eq_some_iff {xs : Array (Array α)} {p : α Bool} {a : α} :
xs.flatten.find? p = some a
theorem find?_flatten_eq_some_iff {xss : Array (Array α)} {p : α Bool} {a : α} :
xss.flatten.find? p = some a
p a (as : Array (Array α)) (ys zs : Array α) (bs : Array (Array α)),
xs = as.push (ys.push a ++ zs) ++ bs
( a as, x a, !p x) ( x ys, !p x) := by
cases xs using array₂_induction
xss = as.push (ys.push a ++ zs) ++ bs
( ws as, x ws, !p x) ( x ys, !p x) := by
cases xss using array₂_induction
simp only [flatten_toArray_map_toArray, List.find?_toArray, List.find?_flatten_eq_some_iff]
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, and_congr_right_iff]
intro w
@@ -302,24 +299,6 @@ theorem find?_eq_some_iff_getElem {xs : Array α} {p : α → Bool} {b : α} :
rcases xs with xs
simp [List.find?_eq_some_iff_getElem]
/-! ### findFinIdx? -/
@[simp] theorem findFinIdx?_empty {p : α Bool} : findFinIdx? p #[] = none := rfl
-- We can't mark this as a `@[congr]` lemma since the head of the RHS is not `findFinIdx?`.
theorem findFinIdx?_congr {p : α Bool} {l₁ : Array α} {l₂ : Array α} (w : l₁ = l₂) :
findFinIdx? p l₁ = (findFinIdx? p l₂).map (fun i => i.cast (by simp [w])) := by
subst w
simp
@[simp] theorem findFinIdx?_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findFinIdx? f = (l.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
cases l
simp only [List.findFinIdx?_toArray, hf, List.findFinIdx?_subtype]
rw [findFinIdx?_congr List.unattach_toArray]
simp [Function.comp_def]
/-! ### findIdx -/
theorem findIdx_of_getElem?_eq_some {xs : Array α} (w : xs[xs.findIdx p]? = some y) : p y := by
@@ -395,21 +374,21 @@ theorem findIdx_eq {p : α → Bool} {xs : Array α} {i : Nat} (h : i < xs.size)
simp at h3
simp_all [not_of_lt_findIdx h3]
theorem findIdx_append (p : α Bool) (l₁ l₂ : Array α) :
(l₁ ++ l₂).findIdx p =
if l₁.findIdx p < l₁.size then l₁.findIdx p else l₂.findIdx p + l₁.size := by
rcases l₁ with l₁
rcases l₂ with l₂
theorem findIdx_append (p : α Bool) (xs ys : Array α) :
(xs ++ ys).findIdx p =
if xs.findIdx p < xs.size then xs.findIdx p else ys.findIdx p + xs.size := by
rcases xs with xs
rcases ys with ys
simp [List.findIdx_append]
theorem findIdx_le_findIdx {l : Array α} {p q : α Bool} (h : x l, p x q x) : l.findIdx q l.findIdx p := by
rcases l with l
theorem findIdx_le_findIdx {xs : Array α} {p q : α Bool} (h : x xs, p x q x) : xs.findIdx q xs.findIdx p := by
rcases xs with xs
simp_all [List.findIdx_le_findIdx]
@[simp] theorem findIdx_subtype {p : α Prop} {l : Array { x // p x }}
@[simp] theorem findIdx_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findIdx f = l.unattach.findIdx g := by
cases l
xs.findIdx f = xs.unattach.findIdx g := by
cases xs
simp [hf]
theorem false_of_mem_extract_findIdx {xs : Array α} {p : α Bool} (h : x xs.extract 0 (xs.findIdx p)) :
@@ -483,8 +462,8 @@ theorem of_findIdx?_eq_none {xs : Array α} {p : α → Bool} (w : xs.findIdx? p
rcases xs with xs
simpa using List.of_findIdx?_eq_none (by simpa using w)
@[simp] theorem findIdx?_map (f : β α) (l : Array β) : findIdx? p (l.map f) = l.findIdx? (p f) := by
rcases l with l
@[simp] theorem findIdx?_map (f : β α) (xs : Array β) : findIdx? p (xs.map f) = xs.findIdx? (p f) := by
rcases xs with xs
simp [List.findIdx?_map]
@[simp] theorem findIdx?_append :
@@ -494,12 +473,12 @@ theorem of_findIdx?_eq_none {xs : Array α} {p : α → Bool} (w : xs.findIdx? p
rcases ys with ys
simp [List.findIdx?_append]
theorem findIdx?_flatten {l : Array (Array α)} {p : α Bool} :
l.flatten.findIdx? p =
(l.findIdx? (·.any p)).map
fun i => ((l.take i).map Array.size).sum +
(l[i]?.map fun xs => xs.findIdx p).getD 0 := by
cases l using array₂_induction
theorem findIdx?_flatten {xss : Array (Array α)} {p : α Bool} :
xss.flatten.findIdx? p =
(xss.findIdx? (·.any p)).map
fun i => ((xss.take i).map Array.size).sum +
(xss[i]?.map fun xs => xs.findIdx p).getD 0 := by
cases xss using array₂_induction
simp [List.findIdx?_flatten, Function.comp_def]
@[simp] theorem findIdx?_mkArray :
@@ -534,10 +513,10 @@ theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : Array α} {p q : α → Bo
rcases xs with xs
simp [List.findIdx?_eq_some_le_of_findIdx?_eq_some (by simpa using w) (by simpa using h)]
@[simp] theorem findIdx?_subtype {p : α Prop} {l : Array { x // p x }}
@[simp] theorem findIdx?_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findIdx? f = l.unattach.findIdx? g := by
cases l
xs.findIdx? f = xs.unattach.findIdx? g := by
cases xs
simp [hf]
@[simp] theorem findIdx?_take {xs : Array α} {i : Nat} {p : α Bool} :
@@ -545,14 +524,55 @@ theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : Array α} {p q : α → Bo
cases xs
simp
/-! ### findFinIdx? -/
@[simp] theorem findFinIdx?_empty {p : α Bool} : findFinIdx? p #[] = none := rfl
-- We can't mark this as a `@[congr]` lemma since the head of the RHS is not `findFinIdx?`.
theorem findFinIdx?_congr {p : α Bool} {xs ys : Array α} (w : xs = ys) :
findFinIdx? p xs = (findFinIdx? p ys).map (fun i => i.cast (by simp [w])) := by
subst w
simp
theorem findFinIdx?_eq_pmap_findIdx? {xs : Array α} {p : α Bool} :
xs.findFinIdx? p =
(xs.findIdx? p).pmap
(fun i m => by simp [findIdx?_eq_some_iff_getElem] at m; exact i, m.choose)
(fun i h => h) := by
simp [findIdx?_eq_map_findFinIdx?_val, Option.pmap_map]
@[simp] theorem findFinIdx?_eq_none_iff {xs : Array α} {p : α Bool} :
xs.findFinIdx? p = none x, x xs ¬ p x := by
simp [findFinIdx?_eq_pmap_findIdx?]
@[simp]
theorem findFinIdx?_eq_some_iff {xs : Array α} {p : α Bool} {i : Fin xs.size} :
xs.findFinIdx? p = some i
p xs[i] j (hji : j < i), ¬p (xs[j]'(Nat.lt_trans hji i.2)) := by
simp only [findFinIdx?_eq_pmap_findIdx?, Option.pmap_eq_some_iff, findIdx?_eq_some_iff_getElem,
Bool.not_eq_true, Option.mem_def, exists_and_left, and_exists_self, Fin.getElem_fin]
constructor
· rintro a, h, w₁, w₂, rfl
exact w₁, fun j hji => by simpa using w₂ j hji
· rintro h, w
exact i, i.2, h, fun j hji => w j, by omega hji, rfl
@[simp] theorem findFinIdx?_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
xs.findFinIdx? f = (xs.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
cases xs
simp only [List.findFinIdx?_toArray, hf, List.findFinIdx?_subtype]
rw [findFinIdx?_congr List.unattach_toArray]
simp [Function.comp_def]
/-! ### idxOf
The verification API for `idxOf` is still incomplete.
The lemmas below should be made consistent with those for `findIdx` (and proved using them).
-/
theorem idxOf_append [BEq α] [LawfulBEq α] {l₁ l₂ : Array α} {a : α} :
(l₁ ++ l₂).idxOf a = if a l₁ then l₁.idxOf a else l₂.idxOf a + l₁.size := by
theorem idxOf_append [BEq α] [LawfulBEq α] {xs ys : Array α} {a : α} :
(xs ++ ys).idxOf a = if a xs then xs.idxOf a else ys.idxOf a + xs.size := by
rw [idxOf, findIdx_append]
split <;> rename_i h
· rw [if_pos]
@@ -560,12 +580,12 @@ theorem idxOf_append [BEq α] [LawfulBEq α] {l₁ l₂ : Array α} {a : α} :
· rw [if_neg]
simpa using h
theorem idxOf_eq_size [BEq α] [LawfulBEq α] {l : Array α} (h : a l) : l.idxOf a = l.size := by
rcases l with l
theorem idxOf_eq_size [BEq α] [LawfulBEq α] {xs : Array α} (h : a xs) : xs.idxOf a = xs.size := by
rcases xs with xs
simp [List.idxOf_eq_length (by simpa using h)]
theorem idxOf_lt_length [BEq α] [LawfulBEq α] {l : Array α} (h : a l) : l.idxOf a < l.size := by
rcases l with l
theorem idxOf_lt_length [BEq α] [LawfulBEq α] {xs : Array α} (h : a xs) : xs.idxOf a < xs.size := by
rcases xs with xs
simp [List.idxOf_lt_length (by simpa using h)]
@@ -577,15 +597,31 @@ The lemmas below should be made consistent with those for `findIdx?` (and proved
@[simp] theorem idxOf?_empty [BEq α] : (#[] : Array α).idxOf? a = none := rfl
@[simp] theorem idxOf?_eq_none_iff [BEq α] [LawfulBEq α] {l : Array α} {a : α} :
l.idxOf? a = none a l := by
rcases l with l
@[simp] theorem idxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
xs.idxOf? a = none a xs := by
rcases xs with xs
simp [List.idxOf?_eq_none_iff]
/-! ### finIdxOf? -/
/-! ### finIdxOf?
The verification API for `finIdxOf?` is still incomplete.
The lemmas below should be made consistent with those for `findFinIdx?` (and proved using them).
-/
theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : Array α} {a : α} :
xs.idxOf? a = (xs.finIdxOf? a).map (·.val) := by
simp [idxOf?, finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
@[simp] theorem finIdxOf?_empty [BEq α] : (#[] : Array α).finIdxOf? a = none := rfl
@[simp] theorem finIdxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
xs.finIdxOf? a = none a xs := by
rcases xs with xs
simp [List.finIdxOf?_eq_none_iff]
@[simp] theorem finIdxOf?_eq_some_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} {i : Fin xs.size} :
xs.finIdxOf? a = some i xs[i] = a j (_ : j < i), ¬xs[j] = a := by
rcases xs with xs
simp [List.finIdxOf?_eq_some_iff]
end Array

View File

@@ -7,40 +7,43 @@ Authors: Leonardo de Moura
prelude
import Init.Data.Array.Basic
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/-! ### getLit -/
-- auxiliary declaration used in the equation compiler when pattern matching array literals.
abbrev getLit {α : Type u} {n : Nat} (a : Array α) (i : Nat) (h₁ : a.size = n) (h₂ : i < n) : α :=
abbrev getLit {α : Type u} {n : Nat} (xs : Array α) (i : Nat) (h₁ : xs.size = n) (h₂ : i < n) : α :=
have := h₁.symm h₂
a[i]
xs[i]
theorem extLit {n : Nat}
(a b : Array α)
(hsz₁ : a.size = n) (hsz₂ : b.size = n)
(h : (i : Nat) (hi : i < n) a.getLit i hsz₁ hi = b.getLit i hsz₂ hi) : a = b :=
Array.ext a b (hsz₁.trans hsz₂.symm) fun i hi₁ _ => h i (hsz₁ hi₁)
(xs ys : Array α)
(hsz₁ : xs.size = n) (hsz₂ : ys.size = n)
(h : (i : Nat) (hi : i < n) xs.getLit i hsz₁ hi = ys.getLit i hsz₂ hi) : xs = ys :=
Array.ext xs ys (hsz₁.trans hsz₂.symm) fun i hi₁ _ => h i (hsz₁ hi₁)
def toListLitAux (a : Array α) (n : Nat) (hsz : a.size = n) : (i : Nat), i a.size List α List α
def toListLitAux (xs : Array α) (n : Nat) (hsz : xs.size = n) : (i : Nat), i xs.size List α List α
| 0, _, acc => acc
| (i+1), hi, acc => toListLitAux a n hsz i (Nat.le_of_succ_le hi) (a.getLit i hsz (Nat.lt_of_lt_of_eq (Nat.lt_of_lt_of_le (Nat.lt_succ_self i) hi) hsz) :: acc)
| (i+1), hi, acc => toListLitAux xs n hsz i (Nat.le_of_succ_le hi) (xs.getLit i hsz (Nat.lt_of_lt_of_eq (Nat.lt_of_lt_of_le (Nat.lt_succ_self i) hi) hsz) :: acc)
def toArrayLit (a : Array α) (n : Nat) (hsz : a.size = n) : Array α :=
List.toArray <| toListLitAux a n hsz n (hsz Nat.le_refl _) []
def toArrayLit (xs : Array α) (n : Nat) (hsz : xs.size = n) : Array α :=
List.toArray <| toListLitAux xs n hsz n (hsz Nat.le_refl _) []
theorem toArrayLit_eq (as : Array α) (n : Nat) (hsz : as.size = n) : as = toArrayLit as n hsz := by
theorem toArrayLit_eq (xs : Array α) (n : Nat) (hsz : xs.size = n) : xs = toArrayLit xs n hsz := by
apply ext'
simp [toArrayLit, List.toList_toArray]
have hle : n as.size := hsz Nat.le_refl _
have hge : as.size n := hsz Nat.le_refl _
have hle : n xs.size := hsz Nat.le_refl _
have hge : xs.size n := hsz Nat.le_refl _
have := go n hle
rw [List.drop_eq_nil_of_le hge] at this
rw [this]
where
getLit_eq (as : Array α) (i : Nat) (h₁ : as.size = n) (h₂ : i < n) : as.getLit i h₁ h₂ = getElem as.toList i ((id (α := as.toList.length = n) h₁) h₂) :=
getLit_eq (xs : Array α) (i : Nat) (h₁ : xs.size = n) (h₂ : i < n) : xs.getLit i h₁ h₂ = getElem xs.toList i ((id (α := xs.toList.length = n) h₁) h₂) :=
rfl
go (i : Nat) (hi : i as.size) : toListLitAux as n hsz i hi (as.toList.drop i) = as.toList := by
go (i : Nat) (hi : i xs.size) : toListLitAux xs n hsz i hi (xs.toList.drop i) = xs.toList := by
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.getElem_cons_drop_succ_eq_drop, *]
end Array

View File

@@ -13,6 +13,9 @@ import Init.Data.List.Nat.InsertIdx
Proves various lemmas about `Array.insertIdx`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Function
open Nat
@@ -27,23 +30,23 @@ section InsertIdx
variable {a : α}
@[simp] theorem toList_insertIdx (a : Array α) (i x) (h) :
(a.insertIdx i x h).toList = a.toList.insertIdx i x := by
rcases a with a
@[simp] theorem toList_insertIdx (xs : Array α) (i x) (h) :
(xs.insertIdx i x h).toList = xs.toList.insertIdx i x := by
rcases xs with xs
simp
@[simp]
theorem insertIdx_zero (s : Array α) (x : α) : s.insertIdx 0 x = #[x] ++ s := by
cases s
theorem insertIdx_zero (xs : Array α) (x : α) : xs.insertIdx 0 x = #[x] ++ xs := by
rcases xs with xs
simp
@[simp] theorem size_insertIdx {as : Array α} (h : n as.size) : (as.insertIdx n a).size = as.size + 1 := by
cases as
@[simp] theorem size_insertIdx {xs : Array α} (h : i xs.size) : (xs.insertIdx i a).size = xs.size + 1 := by
rcases xs with xs
simp [List.length_insertIdx, h]
theorem eraseIdx_insertIdx (i : Nat) (l : Array α) (h : i l.size) :
(l.insertIdx i a).eraseIdx i (by simp; omega) = l := by
cases l
theorem eraseIdx_insertIdx (i : Nat) (xs : Array α) (h : i xs.size) :
(xs.insertIdx i a).eraseIdx i (by simp; omega) = xs := by
rcases xs with xs
simp_all
theorem insertIdx_eraseIdx_of_ge {as : Array α}
@@ -60,68 +63,68 @@ theorem insertIdx_eraseIdx_of_le {as : Array α}
cases as
simpa using List.insertIdx_eraseIdx_of_le _ _ _ (by simpa) (by simpa)
theorem insertIdx_comm (a b : α) (i j : Nat) (l : Array α) (_ : i j) (_ : j l.size) :
(l.insertIdx i a).insertIdx (j + 1) b (by simpa) =
(l.insertIdx j b).insertIdx i a (by simp; omega) := by
cases l
theorem insertIdx_comm (a b : α) (i j : Nat) (xs : Array α) (_ : i j) (_ : j xs.size) :
(xs.insertIdx i a).insertIdx (j + 1) b (by simpa) =
(xs.insertIdx j b).insertIdx i a (by simp; omega) := by
rcases xs with xs
simpa using List.insertIdx_comm a b i j _ (by simpa) (by simpa)
theorem mem_insertIdx {l : Array α} {h : i l.size} : a l.insertIdx i b h a = b a l := by
cases l
theorem mem_insertIdx {xs : Array α} {h : i xs.size} : a xs.insertIdx i b h a = b a xs := by
rcases xs with xs
simpa using List.mem_insertIdx (by simpa)
@[simp]
theorem insertIdx_size_self (l : Array α) (x : α) : l.insertIdx l.size x = l.push x := by
cases l
theorem insertIdx_size_self (xs : Array α) (x : α) : xs.insertIdx xs.size x = xs.push x := by
rcases xs with xs
simp
theorem getElem_insertIdx {as : Array α} {x : α} {i k : Nat} (w : i as.size) (h : k < (as.insertIdx i x).size) :
(as.insertIdx i x)[k] =
theorem getElem_insertIdx {xs : Array α} {x : α} {i k : Nat} (w : i xs.size) (h : k < (xs.insertIdx i x).size) :
(xs.insertIdx i x)[k] =
if h₁ : k < i then
as[k]'(by simp [size_insertIdx] at h; omega)
xs[k]'(by simp [size_insertIdx] at h; omega)
else
if h₂ : k = i then
x
else
as[k-1]'(by simp [size_insertIdx] at h; omega) := by
cases as
xs[k-1]'(by simp [size_insertIdx] at h; omega) := by
cases xs
simp [List.getElem_insertIdx, w]
theorem getElem_insertIdx_of_lt {as : Array α} {x : α} {i k : Nat} (w : i as.size) (h : k < i) :
(as.insertIdx i x)[k]'(by simp; omega) = as[k] := by
theorem getElem_insertIdx_of_lt {xs : Array α} {x : α} {i k : Nat} (w : i xs.size) (h : k < i) :
(xs.insertIdx i x)[k]'(by simp; omega) = xs[k] := by
simp [getElem_insertIdx, w, h]
theorem getElem_insertIdx_self {as : Array α} {x : α} {i : Nat} (w : i as.size) :
(as.insertIdx i x)[i]'(by simp; omega) = x := by
theorem getElem_insertIdx_self {xs : Array α} {x : α} {i : Nat} (w : i xs.size) :
(xs.insertIdx i x)[i]'(by simp; omega) = x := by
simp [getElem_insertIdx, w]
theorem getElem_insertIdx_of_gt {as : Array α} {x : α} {i k : Nat} (w : k as.size) (h : k > i) :
(as.insertIdx i x)[k]'(by simp; omega) = as[k - 1]'(by omega) := by
theorem getElem_insertIdx_of_gt {xs : Array α} {x : α} {i k : Nat} (w : k xs.size) (h : k > i) :
(xs.insertIdx i x)[k]'(by simp; omega) = xs[k - 1]'(by omega) := by
simp [getElem_insertIdx, w, h]
rw [dif_neg (by omega), dif_neg (by omega)]
theorem getElem?_insertIdx {l : Array α} {x : α} {i k : Nat} (h : i l.size) :
(l.insertIdx i x)[k]? =
theorem getElem?_insertIdx {xs : Array α} {x : α} {i k : Nat} (h : i xs.size) :
(xs.insertIdx i x)[k]? =
if k < i then
l[k]?
xs[k]?
else
if k = i then
if k l.size then some x else none
if k xs.size then some x else none
else
l[k-1]? := by
cases l
xs[k-1]? := by
cases xs
simp [List.getElem?_insertIdx, h]
theorem getElem?_insertIdx_of_lt {l : Array α} {x : α} {i k : Nat} (w : i l.size) (h : k < i) :
(l.insertIdx i x)[k]? = l[k]? := by
theorem getElem?_insertIdx_of_lt {xs : Array α} {x : α} {i k : Nat} (w : i xs.size) (h : k < i) :
(xs.insertIdx i x)[k]? = xs[k]? := by
rw [getElem?_insertIdx, if_pos h]
theorem getElem?_insertIdx_self {l : Array α} {x : α} {i : Nat} (w : i l.size) :
(l.insertIdx i x)[i]? = some x := by
theorem getElem?_insertIdx_self {xs : Array α} {x : α} {i : Nat} (w : i xs.size) :
(xs.insertIdx i x)[i]? = some x := by
rw [getElem?_insertIdx, if_neg (by omega), if_pos rfl, if_pos w]
theorem getElem?_insertIdx_of_ge {l : Array α} {x : α} {i k : Nat} (w : i < k) (h : k l.size) :
(l.insertIdx i x)[k]? = l[k - 1]? := by
theorem getElem?_insertIdx_of_ge {xs : Array α} {x : α} {i k : Nat} (w : i < k) (h : k xs.size) :
(xs.insertIdx i x)[k]? = xs[k - 1]? := by
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
end InsertIdx

View File

@@ -6,23 +6,26 @@ Authors: Leonardo de Moura
prelude
import Init.Data.Array.Basic
@[inline] def Array.insertionSort (a : Array α) (lt : α α Bool := by exact (· < ·)) : Array α :=
traverse a 0 a.size
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
@[inline] def Array.insertionSort (xs : Array α) (lt : α α Bool := by exact (· < ·)) : Array α :=
traverse xs 0 xs.size
where
@[specialize] traverse (a : Array α) (i : Nat) (fuel : Nat) : Array α :=
@[specialize] traverse (xs : Array α) (i : Nat) (fuel : Nat) : Array α :=
match fuel with
| 0 => a
| 0 => xs
| fuel+1 =>
if h : i < a.size then
traverse (swapLoop a i h) (i+1) fuel
if h : i < xs.size then
traverse (swapLoop xs i h) (i+1) fuel
else
a
@[specialize] swapLoop (a : Array α) (j : Nat) (h : j < a.size) : Array α :=
xs
@[specialize] swapLoop (xs : Array α) (j : Nat) (h : j < xs.size) : Array α :=
match (generalizing := false) he:j with -- using `generalizing` because we don't want to refine the type of `h`
| 0 => a
| 0 => xs
| j'+1 =>
have h' : j' < a.size := by subst j; exact Nat.lt_trans (Nat.lt_succ_self _) h
if lt a[j] a[j'] then
swapLoop (a.swap j j') j' (by rw [size_swap]; assumption; done)
have h' : j' < xs.size := by subst j; exact Nat.lt_trans (Nat.lt_succ_self _) h
if lt xs[j] xs[j'] then
swapLoop (xs.swap j j') j' (by rw [size_swap]; assumption; done)
else
a
xs

File diff suppressed because it is too large Load Diff

View File

@@ -8,8 +8,8 @@ import Init.Data.Array.Basic
import Init.Data.Nat.Lemmas
import Init.Data.Range
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array

View File

@@ -7,6 +7,9 @@ prelude
import Init.Data.Array.Lemmas
import Init.Data.List.Lex
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/-! ### Lexicographic ordering -/
@@ -14,15 +17,15 @@ namespace Array
@[simp] theorem _root_.List.lt_toArray [LT α] (l₁ l₂ : List α) : l₁.toArray < l₂.toArray l₁ < l₂ := Iff.rfl
@[simp] theorem _root_.List.le_toArray [LT α] (l₁ l₂ : List α) : l₁.toArray l₂.toArray l₁ l₂ := Iff.rfl
@[simp] theorem lt_toList [LT α] (l₁ l₂ : Array α) : l₁.toList < l₂.toList l₁ < l₂ := Iff.rfl
@[simp] theorem le_toList [LT α] (l₁ l₂ : Array α) : l₁.toList l₂.toList l₁ l₂ := Iff.rfl
@[simp] theorem lt_toList [LT α] (xs ys : Array α) : xs.toList < ys.toList xs < ys := Iff.rfl
@[simp] theorem le_toList [LT α] (xs ys : Array α) : xs.toList ys.toList xs ys := Iff.rfl
protected theorem not_lt_iff_ge [LT α] (l₁ l₂ : List α) : ¬ l₁ < l₂ l₂ l₁ := Iff.rfl
protected theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] (l₁ l₂ : List α) :
¬ l₁ l₂ l₂ < l₁ :=
Decidable.not_not
@[simp] theorem lex_empty [BEq α] {lt : α α Bool} (l : Array α) : l.lex #[] lt = false := by
@[simp] theorem lex_empty [BEq α] {lt : α α Bool} (xs : Array α) : xs.lex #[] lt = false := by
simp [lex, Id.run]
@[simp] theorem singleton_lex_singleton [BEq α] {lt : α α Bool} : #[a].lex #[b] lt = lt a b := by
@@ -52,35 +55,35 @@ private theorem cons_lex_cons [BEq α] {lt : αα → Bool} {a b : α} {xs
| cons y l₂ =>
rw [List.toArray_cons, List.toArray_cons y, cons_lex_cons, List.lex, ih]
@[simp] theorem lex_toList [BEq α] (lt : α α Bool) (l₁ l₂ : Array α) :
l₁.toList.lex l₂.toList lt = l₁.lex l₂ lt := by
cases l₁ <;> cases l₂ <;> simp
@[simp] theorem lex_toList [BEq α] (lt : α α Bool) (xs ys : Array α) :
xs.toList.lex ys.toList lt = xs.lex ys lt := by
cases xs <;> cases ys <;> simp
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α α Prop)] (l : Array α) : ¬ l < l :=
List.lt_irrefl l.toList
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α α Prop)] (xs : Array α) : ¬ xs < xs :=
List.lt_irrefl xs.toList
instance ltIrrefl [LT α] [Std.Irrefl (· < · : α α Prop)] : Std.Irrefl (α := Array α) (· < ·) where
irrefl := Array.lt_irrefl
@[simp] theorem not_lt_empty [LT α] (l : Array α) : ¬ l < #[] := List.not_lt_nil l.toList
@[simp] theorem empty_le [LT α] (l : Array α) : #[] l := List.nil_le l.toList
@[simp] theorem not_lt_empty [LT α] (xs : Array α) : ¬ xs < #[] := List.not_lt_nil xs.toList
@[simp] theorem empty_le [LT α] (xs : Array α) : #[] xs := List.nil_le xs.toList
@[simp] theorem le_empty [LT α] (l : Array α) : l #[] l = #[] := by
cases l
@[simp] theorem le_empty [LT α] (xs : Array α) : xs #[] xs = #[] := by
cases xs
simp
@[simp] theorem empty_lt_push [LT α] (l : Array α) (a : α) : #[] < l.push a := by
rcases l with (_ | x, l) <;> simp
@[simp] theorem empty_lt_push [LT α] (xs : Array α) (a : α) : #[] < xs.push a := by
rcases xs with (_ | x, xs) <;> simp
protected theorem le_refl [LT α] [i₀ : Std.Irrefl (· < · : α α Prop)] (l : Array α) : l l :=
List.le_refl l.toList
protected theorem le_refl [LT α] [i₀ : Std.Irrefl (· < · : α α Prop)] (xs : Array α) : xs xs :=
List.le_refl xs.toList
instance [LT α] [Std.Irrefl (· < · : α α Prop)] : Std.Refl (· · : Array α Array α Prop) where
refl := Array.le_refl
protected theorem lt_trans [LT α]
[i₁ : Trans (· < · : α α Prop) (· < ·) (· < ·)]
{l₁ l₂ l₃ : Array α} (h₁ : l₁ < l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
{xs ys zs : Array α} (h₁ : xs < ys) (h₂ : ys < zs) : xs < zs :=
List.lt_trans h₁ h₂
instance [LT α] [Trans (· < · : α α Prop) (· < ·) (· < ·)] :
@@ -92,7 +95,7 @@ protected theorem lt_of_le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
[i₃ : Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{l₁ l₂ l₃ : Array α} (h₁ : l₁ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
{xs ys zs : Array α} (h₁ : xs ys) (h₂ : ys < zs) : xs < zs :=
List.lt_of_le_of_lt h₁ h₂
protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
@@ -100,7 +103,7 @@ protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{l₁ l₂ l₃ : Array α} (h₁ : l₁ l₂) (h₂ : l₂ l₃) : l₁ l₃ :=
{xs ys zs : Array α} (h₁ : xs ys) (h₂ : ys zs) : xs zs :=
fun h₃ => h₁ (Array.lt_of_le_of_lt h₂ h₃)
instance [DecidableEq α] [LT α] [DecidableLT α]
@@ -113,7 +116,7 @@ instance [DecidableEq α] [LT α] [DecidableLT α]
protected theorem lt_asymm [LT α]
[i : Std.Asymm (· < · : α α Prop)]
{l₁ l₂ : Array α} (h : l₁ < l₂) : ¬ l₂ < l₁ := List.lt_asymm h
{xs ys : Array α} (h : xs < ys) : ¬ ys < xs := List.lt_asymm h
instance [DecidableEq α] [LT α] [DecidableLT α]
[Std.Asymm (· < · : α α Prop)] :
@@ -121,26 +124,26 @@ instance [DecidableEq α] [LT α] [DecidableLT α]
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 _ _
[i : Std.Total (¬ · < · : α α Prop)] (xs ys : Array α) : xs ys ys xs :=
List.le_total xs.toList ys.toList
@[simp] protected theorem not_lt [LT α]
{l₁ l₂ : Array α} : ¬ l₁ < l₂ l₂ l₁ := Iff.rfl
{xs ys : Array α} : ¬ xs < ys ys xs := Iff.rfl
@[simp] protected theorem not_le [DecidableEq α] [LT α] [DecidableLT α]
{l₁ l₂ : Array α} : ¬ l₂ l₁ l₁ < l₂ := Decidable.not_not
{xs ys : Array α} : ¬ ys xs xs < ys := Decidable.not_not
protected theorem le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
[i : Std.Total (¬ · < · : α α Prop)]
{l₁ l₂ : Array α} (h : l₁ < l₂) : l₁ l₂ :=
{xs ys : Array α} (h : xs < ys) : xs ys :=
List.le_of_lt h
protected theorem le_iff_lt_or_eq [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Std.Total (¬ · < · : α α Prop)]
{l₁ l₂ : Array α} : l₁ l₂ l₁ < l₂ l₁ = l₂ := by
simpa using List.le_iff_lt_or_eq (l₁ := l₁.toList) (l₂ := l₂.toList)
{xs ys : Array α} : xs ys xs < ys xs = ys := by
simpa using List.le_iff_lt_or_eq (l₁ := xs.toList) (l₂ := ys.toList)
instance [DecidableEq α] [LT α] [DecidableLT α]
[Std.Total (¬ · < · : α α Prop)] :
@@ -148,22 +151,22 @@ instance [DecidableEq α] [LT α] [DecidableLT α]
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₂
{xs ys : Array α} : lex xs ys = true xs < ys := by
cases xs
cases ys
simp
@[simp] theorem lex_eq_false_iff_ge [DecidableEq α] [LT α] [DecidableLT α]
{l₁ l₂ : Array α} : lex l₁ l₂ = false l₂ l₁ := by
cases l₁
cases l₂
{xs ys : Array α} : lex xs ys = false ys xs := by
cases xs
cases ys
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
fun xs ys => decidable_of_iff (lex xs ys = 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
fun xs ys => decidable_of_iff (lex ys xs = false) lex_eq_false_iff_ge
/--
`l₁` is lexicographically less than `l₂` if either
@@ -211,58 +214,58 @@ theorem lex_eq_false_iff_exists [BEq α] [PartialEquivBEq α] (lt : αα
cases l₂
simp_all [List.lex_eq_false_iff_exists]
protected theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {l₁ l₂ : Array α} :
l₁ < l₂
(l₁ = l₂.take l₁.size l₁.size < l₂.size)
( (i : Nat) (h₁ : i < l₁.size) (h₂ : i < l₂.size),
protected theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {xs ys : Array α} :
xs < ys
(xs = ys.take xs.size xs.size < ys.size)
( (i : Nat) (h₁ : i < xs.size) (h₂ : i < ys.size),
( 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₂
xs[j]'(Nat.lt_trans hj h₁) = ys[j]'(Nat.lt_trans hj h₂)) xs[i] < ys[i]) := by
cases xs
cases ys
simp [List.lt_iff_exists]
protected 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),
[Std.Antisymm (¬ · < · : α α Prop)] {xs ys : Array α} :
xs ys
(xs = ys.take xs.size)
( (i : Nat) (h₁ : i < xs.size) (h₂ : i < ys.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₂
xs[j]'(Nat.lt_trans hj h₁) = ys[j]'(Nat.lt_trans hj h₂)) xs[i] < ys[i]) := by
cases xs
cases ys
simp [List.le_iff_exists]
theorem append_left_lt [LT α] {l₁ l₂ l₃ : Array α} (h : l₂ < l₃) :
l₁ ++ l₂ < l₁ ++ l₃ := by
cases l₁
cases l₂
cases l₃
theorem append_left_lt [LT α] {xs ys zs : Array α} (h : ys < zs) :
xs ++ ys < xs ++ zs := by
cases xs
cases ys
cases zs
simpa using List.append_left_lt h
theorem append_left_le [DecidableEq α] [LT α] [DecidableLT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
{l₁ l₂ l₃ : Array α} (h : l₂ l₃) :
l₁ ++ l₂ l₁ ++ l₃ := by
cases l₁
cases l₂
cases l₃
{xs ys zs : Array α} (h : ys zs) :
xs ++ ys xs ++ zs := by
cases xs
cases ys
cases zs
simpa using List.append_left_le h
theorem le_append_left [LT α] [Std.Irrefl (· < · : α α Prop)]
{l₁ l₂ : Array α} : l₁ l₁ ++ l₂ := by
cases l₁
cases l₂
{xs ys : Array α} : xs xs ++ ys := by
cases xs
cases ys
simpa using List.le_append_left
protected theorem map_lt [LT α] [LT β]
{l₁ l₂ : Array α} {f : α β} (w : x y, x < y f x < f y) (h : l₁ < l₂) :
map f l₁ < map f l₂ := by
cases l₁
cases l₂
{xs ys : Array α} {f : α β} (w : x y, x < y f x < f y) (h : xs < ys) :
map f xs < map f ys := by
cases xs
cases ys
simpa using List.map_lt w h
protected theorem map_le [DecidableEq α] [LT α] [DecidableLT α] [DecidableEq β] [LT β] [DecidableLT β]
@@ -272,10 +275,10 @@ protected theorem map_le [DecidableEq α] [LT α] [DecidableLT α] [DecidableEq
[Std.Irrefl (· < · : β β Prop)]
[Std.Asymm (· < · : β β Prop)]
[Std.Antisymm (¬ · < · : β β Prop)]
{l₁ l₂ : Array α} {f : α β} (w : x y, x < y f x < f y) (h : l₁ l₂) :
map f l₁ map f l₂ := by
cases l₁
cases l₂
{xs ys : Array α} {f : α β} (w : x y, x < y f x < f y) (h : xs ys) :
map f xs map f ys := by
cases xs
cases ys
simpa using List.map_le w h
end Array

View File

@@ -8,26 +8,29 @@ import Init.Data.Array.Lemmas
import Init.Data.Array.Attach
import Init.Data.List.MapIdx
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
/-! ### mapFinIdx -/
-- This could also be proved from `SatisfiesM_mapIdxM` in Batteries.
theorem mapFinIdx_induction (as : Array α) (f : (i : Nat) α (h : i < as.size) β)
theorem mapFinIdx_induction (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β)
(motive : Nat Prop) (h0 : motive 0)
(p : (i : Nat) β (h : i < as.size) Prop)
(hs : i h, motive i p i (f i as[i] h) h motive (i + 1)) :
motive as.size eq : (Array.mapFinIdx as f).size = as.size,
i h, p i ((Array.mapFinIdx as f)[i]) h := by
(p : (i : Nat) β (h : i < xs.size) Prop)
(hs : i h, motive i p i (f i xs[i] h) h motive (i + 1)) :
motive xs.size eq : (Array.mapFinIdx xs f).size = xs.size,
i h, p i ((Array.mapFinIdx xs f)[i]) h := by
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : i h h', p i bs[i] h) (hm : motive j) :
let arr : Array β := Array.mapFinIdxM.map (m := Id) as f i j h bs
motive as.size eq : arr.size = as.size, i h, p i arr[i] h := by
let as : Array β := Array.mapFinIdxM.map (m := Id) xs f i j h bs
motive xs.size eq : as.size = xs.size, i h, p i as[i] h := by
induction i generalizing j bs with simp [mapFinIdxM.map]
| zero =>
have := (Nat.zero_add _).symm.trans h
exact this hm, h₁ this, fun _ _ => h₂ ..
| succ i ih =>
apply @ih (bs.push (f j as[j] (by omega))) (j + 1) (by omega) (by simp; omega)
apply @ih (bs.push (f j xs[j] (by omega))) (j + 1) (by omega) (by simp; omega)
· intro i i_lt h'
rw [getElem_push]
split
@@ -38,67 +41,67 @@ theorem mapFinIdx_induction (as : Array α) (f : (i : Nat) → α → (h : i < a
· exact (hs j (by omega) hm).2
simp [mapFinIdx, mapFinIdxM]; exact go rfl nofun h0
theorem mapFinIdx_spec (as : Array α) (f : (i : Nat) α (h : i < as.size) β)
(p : (i : Nat) β (h : i < as.size) Prop) (hs : i h, p i (f i as[i] h) h) :
eq : (Array.mapFinIdx as f).size = as.size,
i h, p i ((Array.mapFinIdx as f)[i]) h :=
theorem mapFinIdx_spec (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β)
(p : (i : Nat) β (h : i < xs.size) Prop) (hs : i h, p i (f i xs[i] h) h) :
eq : (Array.mapFinIdx xs f).size = xs.size,
i h, p i ((Array.mapFinIdx xs f)[i]) h :=
(mapFinIdx_induction _ _ (fun _ => True) trivial p fun _ _ _ => hs .., trivial).2
@[simp] theorem size_mapFinIdx (a : Array α) (f : (i : Nat) α (h : i < a.size) β) :
(a.mapFinIdx f).size = a.size :=
@[simp] theorem size_mapFinIdx (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β) :
(xs.mapFinIdx f).size = xs.size :=
(mapFinIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
@[simp] theorem size_zipIdx (as : Array α) (k : Nat) : (as.zipIdx k).size = as.size :=
@[simp] theorem size_zipIdx (xs : Array α) (k : Nat) : (xs.zipIdx k).size = xs.size :=
Array.size_mapFinIdx _ _
@[deprecated size_zipIdx (since := "2025-01-21")] abbrev size_zipWithIndex := @size_zipIdx
@[simp] theorem getElem_mapFinIdx (a : Array α) (f : (i : Nat) α (h : i < a.size) β) (i : Nat)
(h : i < (mapFinIdx a f).size) :
(a.mapFinIdx f)[i] = f i (a[i]'(by simp_all)) (by simp_all) :=
(mapFinIdx_spec _ _ (fun i b h => b = f i a[i] h) fun _ _ => rfl).2 i _
@[simp] theorem getElem_mapFinIdx (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β) (i : Nat)
(h : i < (xs.mapFinIdx f).size) :
(xs.mapFinIdx f)[i] = f i (xs[i]'(by simp_all)) (by simp_all) :=
(mapFinIdx_spec _ _ (fun i b h => b = f i xs[i] h) fun _ _ => rfl).2 i _
@[simp] theorem getElem?_mapFinIdx (a : Array α) (f : (i : Nat) α (h : i < a.size) β) (i : Nat) :
(a.mapFinIdx f)[i]? =
a[i]?.pbind fun b h => f i b (getElem?_eq_some_iff.1 h).1 := by
@[simp] theorem getElem?_mapFinIdx (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β) (i : Nat) :
(xs.mapFinIdx f)[i]? =
xs[i]?.pbind fun b h => f i b (getElem?_eq_some_iff.1 h).1 := by
simp only [getElem?_def, size_mapFinIdx, getElem_mapFinIdx]
split <;> simp_all
@[simp] theorem toList_mapFinIdx (a : Array α) (f : (i : Nat) α (h : i < a.size) β) :
(a.mapFinIdx f).toList = a.toList.mapFinIdx (fun i a h => f i a (by simpa)) := by
@[simp] theorem toList_mapFinIdx (xs : Array α) (f : (i : Nat) α (h : i < xs.size) β) :
(xs.mapFinIdx f).toList = xs.toList.mapFinIdx (fun i a h => f i a (by simpa)) := by
apply List.ext_getElem <;> simp
/-! ### mapIdx -/
theorem mapIdx_induction (f : Nat α β) (as : Array α)
theorem mapIdx_induction (f : Nat α β) (xs : Array α)
(motive : Nat Prop) (h0 : motive 0)
(p : (i : Nat) β (h : i < as.size) Prop)
(hs : i h, motive i p i (f i as[i]) h motive (i + 1)) :
motive as.size eq : (as.mapIdx f).size = as.size,
i h, p i ((as.mapIdx f)[i]) h :=
mapFinIdx_induction as (fun i a _ => f i a) motive h0 p hs
(p : (i : Nat) β (h : i < xs.size) Prop)
(hs : i h, motive i p i (f i xs[i]) h motive (i + 1)) :
motive xs.size eq : (xs.mapIdx f).size = xs.size,
i h, p i ((xs.mapIdx f)[i]) h :=
mapFinIdx_induction xs (fun i a _ => f i a) motive h0 p hs
theorem mapIdx_spec (f : Nat α β) (as : Array α)
(p : (i : Nat) β (h : i < as.size) Prop) (hs : i h, p i (f i as[i]) h) :
eq : (as.mapIdx f).size = as.size,
i h, p i ((as.mapIdx f)[i]) h :=
theorem mapIdx_spec (f : Nat α β) (xs : Array α)
(p : (i : Nat) β (h : i < xs.size) Prop) (hs : i h, p i (f i xs[i]) h) :
eq : (xs.mapIdx f).size = xs.size,
i h, p i ((xs.mapIdx f)[i]) h :=
(mapIdx_induction _ _ (fun _ => True) trivial p fun _ _ _ => hs .., trivial).2
@[simp] theorem size_mapIdx (f : Nat α β) (as : Array α) : (as.mapIdx f).size = as.size :=
@[simp] theorem size_mapIdx (f : Nat α β) (xs : Array α) : (xs.mapIdx f).size = xs.size :=
(mapIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
@[simp] theorem getElem_mapIdx (f : Nat α β) (as : Array α) (i : Nat)
(h : i < (as.mapIdx f).size) :
(as.mapIdx f)[i] = f i (as[i]'(by simp_all)) :=
(mapIdx_spec _ _ (fun i b h => b = f i as[i]) fun _ _ => rfl).2 i (by simp_all)
@[simp] theorem getElem_mapIdx (f : Nat α β) (xs : Array α) (i : Nat)
(h : i < (xs.mapIdx f).size) :
(xs.mapIdx f)[i] = f i (xs[i]'(by simp_all)) :=
(mapIdx_spec _ _ (fun i b h => b = f i xs[i]) fun _ _ => rfl).2 i (by simp_all)
@[simp] theorem getElem?_mapIdx (f : Nat α β) (as : Array α) (i : Nat) :
(as.mapIdx f)[i]? =
as[i]?.map (f i) := by
@[simp] theorem getElem?_mapIdx (f : Nat α β) (xs : Array α) (i : Nat) :
(xs.mapIdx f)[i]? =
xs[i]?.map (f i) := by
simp [getElem?_def, size_mapIdx, getElem_mapIdx]
@[simp] theorem toList_mapIdx (f : Nat α β) (as : Array α) :
(as.mapIdx f).toList = as.toList.mapIdx (fun i a => f i a) := by
@[simp] theorem toList_mapIdx (f : Nat α β) (xs : Array α) :
(xs.mapIdx f).toList = xs.toList.mapIdx (fun i a => f i a) := by
apply List.ext_getElem <;> simp
end Array
@@ -119,8 +122,8 @@ namespace Array
/-! ### zipIdx -/
@[simp] theorem getElem_zipIdx (a : Array α) (k : Nat) (i : Nat) (h : i < (a.zipIdx k).size) :
(a.zipIdx k)[i] = (a[i]'(by simp_all), k + i) := by
@[simp] theorem getElem_zipIdx (xs : Array α) (k : Nat) (i : Nat) (h : i < (xs.zipIdx k).size) :
(xs.zipIdx k)[i] = (xs[i]'(by simp_all), k + i) := by
simp [zipIdx]
@[deprecated getElem_zipIdx (since := "2025-01-21")]
@@ -133,35 +136,35 @@ abbrev getElem_zipWithIndex := @getElem_zipIdx
@[deprecated zipIdx_toArray (since := "2025-01-21")]
abbrev zipWithIndex_toArray := @zipIdx_toArray
@[simp] theorem toList_zipIdx (a : Array α) (k : Nat) :
(a.zipIdx k).toList = a.toList.zipIdx k := by
rcases a with a
@[simp] theorem toList_zipIdx (xs : Array α) (k : Nat) :
(xs.zipIdx k).toList = xs.toList.zipIdx k := by
rcases xs with xs
simp
@[deprecated toList_zipIdx (since := "2025-01-21")]
abbrev toList_zipWithIndex := @toList_zipIdx
theorem mk_mem_zipIdx_iff_le_and_getElem?_sub {k i : Nat} {x : α} {l : Array α} :
(x, i) zipIdx l k k i l[i - k]? = some x := by
rcases l with l
theorem mk_mem_zipIdx_iff_le_and_getElem?_sub {k i : Nat} {x : α} {xs : Array α} :
(x, i) xs.zipIdx k k i xs[i - k]? = some x := by
rcases xs with xs
simp [List.mk_mem_zipIdx_iff_le_and_getElem?_sub]
/-- Variant of `mk_mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
to avoid the inequality and the subtraction. -/
theorem mk_mem_zipIdx_iff_getElem? {x : α} {i : Nat} {l : Array α} :
(x, i) l.zipIdx l[i]? = x := by
theorem mk_mem_zipIdx_iff_getElem? {x : α} {i : Nat} {xs : Array α} :
(x, i) xs.zipIdx xs[i]? = x := by
rw [mk_mem_zipIdx_iff_le_and_getElem?_sub]
simp
theorem mem_zipIdx_iff_le_and_getElem?_sub {x : α × Nat} {l : Array α} {k : Nat} :
x zipIdx l k k x.2 l[x.2 - k]? = some x.1 := by
theorem mem_zipIdx_iff_le_and_getElem?_sub {x : α × Nat} {xs : Array α} {k : Nat} :
x xs.zipIdx k k x.2 xs[x.2 - k]? = some x.1 := by
cases x
simp [mk_mem_zipIdx_iff_le_and_getElem?_sub]
/-- Variant of `mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
to avoid the inequality and the subtraction. -/
theorem mem_zipIdx_iff_getElem? {x : α × Nat} {l : Array α} :
x l.zipIdx l[x.2]? = some x.1 := by
theorem mem_zipIdx_iff_getElem? {x : α × Nat} {xs : Array α} :
x xs.zipIdx xs[x.2]? = some x.1 := by
rw [mk_mem_zipIdx_iff_getElem?]
@[deprecated mk_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
@@ -182,31 +185,31 @@ abbrev mem_zipWithIndex_iff_getElem? := @mem_zipIdx_iff_getElem?
theorem mapFinIdx_empty {f : (i : Nat) α (h : i < 0) β} : mapFinIdx #[] f = #[] :=
rfl
theorem mapFinIdx_eq_ofFn {as : Array α} {f : (i : Nat) α (h : i < as.size) β} :
as.mapFinIdx f = Array.ofFn fun i : Fin as.size => f i as[i] i.2 := by
cases as
theorem mapFinIdx_eq_ofFn {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = Array.ofFn fun i : Fin xs.size => f i xs[i] i.2 := by
cases xs
simp [List.mapFinIdx_eq_ofFn]
theorem mapFinIdx_append {K L : Array α} {f : (i : Nat) α (h : i < (K ++ L).size) β} :
(K ++ L).mapFinIdx f =
K.mapFinIdx (fun i a h => f i a (by simp; omega)) ++
L.mapFinIdx (fun i a h => f (i + K.size) a (by simp; omega)) := by
cases K
cases L
theorem mapFinIdx_append {xs ys : Array α} {f : (i : Nat) α (h : i < (xs ++ ys).size) β} :
(xs ++ ys).mapFinIdx f =
xs.mapFinIdx (fun i a h => f i a (by simp; omega)) ++
ys.mapFinIdx (fun i a h => f (i + xs.size) a (by simp; omega)) := by
cases xs
cases ys
simp [List.mapFinIdx_append]
@[simp]
theorem mapFinIdx_push {l : Array α} {a : α} {f : (i : Nat) α (h : i < (l.push a).size) β} :
mapFinIdx (l.push a) f =
(mapFinIdx l (fun i a h => f i a (by simp; omega))).push (f l.size a (by simp)) := by
theorem mapFinIdx_push {xs : Array α} {a : α} {f : (i : Nat) α (h : i < (xs.push a).size) β} :
mapFinIdx (xs.push a) f =
(mapFinIdx xs (fun i a h => f i a (by simp; omega))).push (f xs.size a (by simp)) := by
simp [ append_singleton, mapFinIdx_append]
theorem mapFinIdx_singleton {a : α} {f : (i : Nat) α (h : i < 1) β} :
#[a].mapFinIdx f = #[f 0 a (by simp)] := by
simp
theorem mapFinIdx_eq_zipIdx_map {l : Array α} {f : (i : Nat) α (h : i < l.size) β} :
l.mapFinIdx f = l.zipIdx.attach.map
theorem mapFinIdx_eq_zipIdx_map {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = xs.zipIdx.attach.map
fun x, i, m =>
f i x (by simp [mk_mem_zipIdx_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1) := by
ext <;> simp
@@ -215,44 +218,44 @@ theorem mapFinIdx_eq_zipIdx_map {l : Array α} {f : (i : Nat) → α → (h : i
abbrev mapFinIdx_eq_zipWithIndex_map := @mapFinIdx_eq_zipIdx_map
@[simp]
theorem mapFinIdx_eq_empty_iff {l : Array α} {f : (i : Nat) α (h : i < l.size) β} :
l.mapFinIdx f = #[] l = #[] := by
cases l
theorem mapFinIdx_eq_empty_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = #[] xs = #[] := by
cases xs
simp
theorem mapFinIdx_ne_empty_iff {l : Array α} {f : (i : Nat) α (h : i < l.size) β} :
l.mapFinIdx f #[] l #[] := by
theorem mapFinIdx_ne_empty_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f #[] xs #[] := by
simp
theorem exists_of_mem_mapFinIdx {b : β} {l : Array α} {f : (i : Nat) α (h : i < l.size) β}
(h : b l.mapFinIdx f) : (i : Nat) (h : i < l.size), f i l[i] h = b := by
rcases l with l
theorem exists_of_mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β}
(h : b xs.mapFinIdx f) : (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
rcases xs with xs
exact List.exists_of_mem_mapFinIdx (by simpa using h)
@[simp] theorem mem_mapFinIdx {b : β} {l : Array α} {f : (i : Nat) α (h : i < l.size) β} :
b l.mapFinIdx f (i : Nat) (h : i < l.size), f i l[i] h = b := by
rcases l with l
@[simp] theorem mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} :
b xs.mapFinIdx f (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
rcases xs with xs
simp
theorem mapFinIdx_eq_iff {l : Array α} {f : (i : Nat) α (h : i < l.size) β} :
l.mapFinIdx f = l' h : l'.size = l.size, (i : Nat) (h : i < l.size), l'[i] = f i l[i] h := by
rcases l with l
rcases l' with l'
theorem mapFinIdx_eq_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {ys : Array β} :
xs.mapFinIdx f = ys h : ys.size = xs.size, (i : Nat) (h : i < xs.size), ys[i] = f i xs[i] h := by
rcases xs with xs
rcases ys with ys
simpa using List.mapFinIdx_eq_iff
@[simp] theorem mapFinIdx_eq_singleton_iff {l : Array α} {f : (i : Nat) α (h : i < l.size) β} {b : β} :
l.mapFinIdx f = #[b] (a : α) (w : l = #[a]), f 0 a (by simp [w]) = b := by
rcases l with l
@[simp] theorem mapFinIdx_eq_singleton_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {b : β} :
xs.mapFinIdx f = #[b] (a : α) (w : xs = #[a]), f 0 a (by simp [w]) = b := by
rcases xs with xs
simp
theorem mapFinIdx_eq_append_iff {l : Array α} {f : (i : Nat) α (h : i < l.size) β} {l₁ l₂ : Array β} :
l.mapFinIdx f = l₁ ++ l₂
(l₁' : Array α) (l₂' : Array α) (w : l = l₁' ++ l₂'),
l₁'.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = l₁
l₂'.mapFinIdx (fun i a h => f (i + l₁'.size) a (by simp [w]; omega)) = l₂ := by
rcases l with l
rcases l₁ with l₁
rcases l₂ with l₂
theorem mapFinIdx_eq_append_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {ys zs : Array β} :
xs.mapFinIdx f = ys ++ zs
(ys' : Array α) (zs' : Array α) (w : xs = ys' ++ zs'),
ys'.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = ys
zs'.mapFinIdx (fun i a h => f (i + ys'.size) a (by simp [w]; omega)) = zs := by
rcases xs with l
rcases ys with l₁
rcases zs with l₂
simp only [List.mapFinIdx_toArray, List.append_toArray, mk.injEq, List.mapFinIdx_eq_append_iff,
toArray_eq_append_iff]
constructor
@@ -264,39 +267,39 @@ theorem mapFinIdx_eq_append_iff {l : Array α} {f : (i : Nat) → α → (h : i
obtain rfl := h₂
refine l₁, l₂, by simp_all
theorem mapFinIdx_eq_push_iff {l : Array α} {b : β} {f : (i : Nat) α (h : i < l.size) β} :
l.mapFinIdx f = l₂.push b
(l₁ : Array α) (a : α) (w : l = l₁.push a),
l₁.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = l₂ b = f (l.size - 1) a (by simp [w]) := by
theorem mapFinIdx_eq_push_iff {xs : Array α} {b : β} {f : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = ys.push b
(zs : Array α) (a : α) (w : xs = zs.push a),
zs.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = ys b = f (xs.size - 1) a (by simp [w]) := by
rw [push_eq_append, mapFinIdx_eq_append_iff]
constructor
· rintro l₁, l₂, rfl, rfl, h₂
· rintro ys', zs', rfl, rfl, h₂
simp only [mapFinIdx_eq_singleton_iff, Nat.zero_add] at h₂
obtain a, rfl, rfl := h₂
exact l₁, a, by simp
· rintro l₁, a, rfl, rfl, rfl
exact l₁, #[a], by simp
exact ys', a, by simp
· rintro zs, a, rfl, rfl, rfl
exact zs, #[a], by simp
theorem mapFinIdx_eq_mapFinIdx_iff {l : Array α} {f g : (i : Nat) α (h : i < l.size) β} :
l.mapFinIdx f = l.mapFinIdx g (i : Nat) (h : i < l.size), f i l[i] h = g i l[i] h := by
theorem mapFinIdx_eq_mapFinIdx_iff {xs : Array α} {f g : (i : Nat) α (h : i < xs.size) β} :
xs.mapFinIdx f = xs.mapFinIdx g (i : Nat) (h : i < xs.size), f i xs[i] h = g i xs[i] h := by
rw [eq_comm, mapFinIdx_eq_iff]
simp
@[simp] theorem mapFinIdx_mapFinIdx {l : Array α}
{f : (i : Nat) α (h : i < l.size) β}
{g : (i : Nat) β (h : i < (l.mapFinIdx f).size) γ} :
(l.mapFinIdx f).mapFinIdx g = l.mapFinIdx (fun i a h => g i (f i a h) (by simpa using h)) := by
@[simp] theorem mapFinIdx_mapFinIdx {xs : Array α}
{f : (i : Nat) α (h : i < xs.size) β}
{g : (i : Nat) β (h : i < (xs.mapFinIdx f).size) γ} :
(xs.mapFinIdx f).mapFinIdx g = xs.mapFinIdx (fun i a h => g i (f i a h) (by simpa using h)) := by
simp [mapFinIdx_eq_iff]
theorem mapFinIdx_eq_mkArray_iff {l : Array α} {f : (i : Nat) α (h : i < l.size) β} {b : β} :
l.mapFinIdx f = mkArray l.size b (i : Nat) (h : i < l.size), f i l[i] h = b := by
rcases l with l
theorem mapFinIdx_eq_mkArray_iff {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {b : β} :
xs.mapFinIdx f = mkArray xs.size b (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
rcases xs with l
rw [ toList_inj]
simp [List.mapFinIdx_eq_replicate_iff]
@[simp] theorem mapFinIdx_reverse {l : Array α} {f : (i : Nat) α (h : i < l.reverse.size) β} :
l.reverse.mapFinIdx f = (l.mapFinIdx (fun i a h => f (l.size - 1 - i) a (by simp; omega))).reverse := by
rcases l with l
@[simp] theorem mapFinIdx_reverse {xs : Array α} {f : (i : Nat) α (h : i < xs.reverse.size) β} :
xs.reverse.mapFinIdx f = (xs.mapFinIdx (fun i a h => f (xs.size - 1 - i) a (by simp; omega))).reverse := by
rcases xs with l
simp [List.mapFinIdx_reverse]
/-! ### mapIdx -/
@@ -305,52 +308,52 @@ theorem mapFinIdx_eq_mkArray_iff {l : Array α} {f : (i : Nat) → α → (h : i
theorem mapIdx_empty {f : Nat α β} : mapIdx f #[] = #[] :=
rfl
@[simp] theorem mapFinIdx_eq_mapIdx {l : Array α} {f : (i : Nat) α (h : i < l.size) β} {g : Nat α β}
(h : (i : Nat) (h : i < l.size), f i l[i] h = g i l[i]) :
l.mapFinIdx f = l.mapIdx g := by
@[simp] theorem mapFinIdx_eq_mapIdx {xs : Array α} {f : (i : Nat) α (h : i < xs.size) β} {g : Nat α β}
(h : (i : Nat) (h : i < xs.size), f i xs[i] h = g i xs[i]) :
xs.mapFinIdx f = xs.mapIdx g := by
simp_all [mapFinIdx_eq_iff]
theorem mapIdx_eq_mapFinIdx {l : Array α} {f : Nat α β} :
l.mapIdx f = l.mapFinIdx (fun i a _ => f i a) := by
theorem mapIdx_eq_mapFinIdx {xs : Array α} {f : Nat α β} :
xs.mapIdx f = xs.mapFinIdx (fun i a _ => f i a) := by
simp [mapFinIdx_eq_mapIdx]
theorem mapIdx_eq_zipIdx_map {l : Array α} {f : Nat α β} :
l.mapIdx f = l.zipIdx.map fun a, i => f i a := by
theorem mapIdx_eq_zipIdx_map {xs : Array α} {f : Nat α β} :
xs.mapIdx f = xs.zipIdx.map fun a, i => f i a := by
ext <;> simp
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-21")]
abbrev mapIdx_eq_zipWithIndex_map := @mapIdx_eq_zipIdx_map
theorem mapIdx_append {K L : Array α} :
(K ++ L).mapIdx f = K.mapIdx f ++ L.mapIdx fun i => f (i + K.size) := by
rcases K with K
rcases L with L
theorem mapIdx_append {xs ys : Array α} :
(xs ++ ys).mapIdx f = xs.mapIdx f ++ ys.mapIdx (fun i => f (i + xs.size)) := by
rcases xs with xs
rcases ys with ys
simp [List.mapIdx_append]
@[simp]
theorem mapIdx_push {l : Array α} {a : α} :
mapIdx f (l.push a) = (mapIdx f l).push (f l.size a) := by
theorem mapIdx_push {xs : Array α} {a : α} :
mapIdx f (xs.push a) = (mapIdx f xs).push (f xs.size a) := by
simp [ append_singleton, mapIdx_append]
theorem mapIdx_singleton {a : α} : mapIdx f #[a] = #[f 0 a] := by
simp
@[simp]
theorem mapIdx_eq_empty_iff {l : Array α} : mapIdx f l = #[] l = #[] := by
rcases l with l
theorem mapIdx_eq_empty_iff {xs : Array α} : mapIdx f xs = #[] xs = #[] := by
rcases xs with xs
simp
theorem mapIdx_ne_empty_iff {l : Array α} :
mapIdx f l #[] l #[] := by
theorem mapIdx_ne_empty_iff {xs : Array α} :
mapIdx f xs #[] xs #[] := by
simp
theorem exists_of_mem_mapIdx {b : β} {l : Array α}
(h : b mapIdx f l) : (i : Nat) (h : i < l.size), f i l[i] = b := by
theorem exists_of_mem_mapIdx {b : β} {xs : Array α}
(h : b mapIdx f xs) : (i : Nat) (h : i < xs.size), f i xs[i] = b := by
rw [mapIdx_eq_mapFinIdx] at h
simpa [Fin.exists_iff] using exists_of_mem_mapFinIdx h
@[simp] theorem mem_mapIdx {b : β} {l : Array α} :
b mapIdx f l (i : Nat) (h : i < l.size), f i l[i] = b := by
@[simp] theorem mem_mapIdx {b : β} {xs : Array α} :
b mapIdx f xs (i : Nat) (h : i < xs.size), f i xs[i] = b := by
constructor
· intro h
exact exists_of_mem_mapIdx h
@@ -358,30 +361,30 @@ theorem exists_of_mem_mapIdx {b : β} {l : Array α}
rw [mem_iff_getElem]
exact i, by simpa using h, by simp
theorem mapIdx_eq_push_iff {l : Array α} {b : β} :
mapIdx f l = l₂.push b
(a : α) (l₁ : Array α), l = l₁.push a mapIdx f l₁ = l₂ f l₁.size a = b := by
theorem mapIdx_eq_push_iff {xs : Array α} {b : β} :
mapIdx f xs = ys.push b
(a : α) (zs : Array α), xs = zs.push a mapIdx f zs = ys f zs.size a = b := by
rw [mapIdx_eq_mapFinIdx, mapFinIdx_eq_push_iff]
simp only [mapFinIdx_eq_mapIdx, exists_and_left, exists_prop]
constructor
· rintro l₁, rfl, a, rfl, rfl
exact a, l₁, by simp
· rintro a, l₁, rfl, rfl, rfl
exact l₁, rfl, a, by simp
· rintro zs, rfl, a, rfl, rfl
exact a, zs, by simp
· rintro a, zs, rfl, rfl, rfl
exact zs, rfl, a, by simp
@[simp] theorem mapIdx_eq_singleton_iff {l : Array α} {f : Nat α β} {b : β} :
mapIdx f l = #[b] (a : α), l = #[a] f 0 a = b := by
rcases l with l
@[simp] theorem mapIdx_eq_singleton_iff {xs : Array α} {f : Nat α β} {b : β} :
mapIdx f xs = #[b] (a : α), xs = #[a] f 0 a = b := by
rcases xs with xs
simp [List.mapIdx_eq_singleton_iff]
theorem mapIdx_eq_append_iff {l : Array α} {f : Nat α β} {l₁ l₂ : Array β} :
mapIdx f l = l₁ ++ l₂
(l₁' : Array α) (l₂' : Array α), l = l₁' ++ l₂'
l₁'.mapIdx f = l₁
l₂'.mapIdx (fun i => f (i + l₁'.size)) = l₂ := by
rcases l with l
rcases l₁ with l₁
rcases l₂ with l₂
theorem mapIdx_eq_append_iff {xs : Array α} {f : Nat α β} {ys zs : Array β} :
mapIdx f xs = ys ++ zs
(xs' : Array α) (zs' : Array α), xs = xs' ++ zs'
xs'.mapIdx f = ys
zs'.mapIdx (fun i => f (i + xs'.size)) = zs := by
rcases xs with xs
rcases ys with ys
rcases zs with zs
simp only [List.mapIdx_toArray, List.append_toArray, mk.injEq, List.mapIdx_eq_append_iff,
toArray_eq_append_iff]
constructor
@@ -393,49 +396,49 @@ theorem mapIdx_eq_append_iff {l : Array α} {f : Nat → α → β} {l₁ l₂ :
obtain rfl := h₂
exact l₁, l₂, by simp
theorem mapIdx_eq_iff {l : Array α} : mapIdx f l = l' i : Nat, l'[i]? = l[i]?.map (f i) := by
rcases l with l
rcases l' with l'
theorem mapIdx_eq_iff {xs : Array α} : mapIdx f xs = ys i : Nat, ys[i]? = xs[i]?.map (f i) := by
rcases xs with xs
rcases ys with ys
simp [List.mapIdx_eq_iff]
theorem mapIdx_eq_mapIdx_iff {l : Array α} :
mapIdx f l = mapIdx g l i : Nat, (h : i < l.size) f i l[i] = g i l[i] := by
rcases l with l
theorem mapIdx_eq_mapIdx_iff {xs : Array α} :
mapIdx f xs = mapIdx g xs i : Nat, (h : i < xs.size) f i xs[i] = g i xs[i] := by
rcases xs with xs
simp [List.mapIdx_eq_mapIdx_iff]
@[simp] theorem mapIdx_set {l : Array α} {i : Nat} {h : i < l.size} {a : α} :
(l.set i a).mapIdx f = (l.mapIdx f).set i (f i a) (by simpa) := by
rcases l with l
@[simp] theorem mapIdx_set {xs : Array α} {i : Nat} {h : i < xs.size} {a : α} :
(xs.set i a).mapIdx f = (xs.mapIdx f).set i (f i a) (by simpa) := by
rcases xs with xs
simp [List.mapIdx_set]
@[simp] theorem mapIdx_setIfInBounds {l : Array α} {i : Nat} {a : α} :
(l.setIfInBounds i a).mapIdx f = (l.mapIdx f).setIfInBounds i (f i a) := by
rcases l with l
@[simp] theorem mapIdx_setIfInBounds {xs : Array α} {i : Nat} {a : α} :
(xs.setIfInBounds i a).mapIdx f = (xs.mapIdx f).setIfInBounds i (f i a) := by
rcases xs with xs
simp [List.mapIdx_set]
@[simp] theorem back?_mapIdx {l : Array α} {f : Nat α β} :
(mapIdx f l).back? = (l.back?).map (f (l.size - 1)) := by
rcases l with l
@[simp] theorem back?_mapIdx {xs : Array α} {f : Nat α β} :
(mapIdx f xs).back? = (xs.back?).map (f (xs.size - 1)) := by
rcases xs with xs
simp [List.getLast?_mapIdx]
@[simp] theorem back_mapIdx {l : Array α} {f : Nat α β} (h) :
(l.mapIdx f).back h = f (l.size - 1) (l.back (by simpa using h)) := by
rcases l with l
@[simp] theorem back_mapIdx {xs : Array α} {f : Nat α β} (h) :
(xs.mapIdx f).back h = f (xs.size - 1) (xs.back (by simpa using h)) := by
rcases xs with xs
simp [List.getLast_mapIdx]
@[simp] theorem mapIdx_mapIdx {l : Array α} {f : Nat α β} {g : Nat β γ} :
(l.mapIdx f).mapIdx g = l.mapIdx (fun i => g i f i) := by
@[simp] theorem mapIdx_mapIdx {xs : Array α} {f : Nat α β} {g : Nat β γ} :
(xs.mapIdx f).mapIdx g = xs.mapIdx (fun i => g i f i) := by
simp [mapIdx_eq_iff]
theorem mapIdx_eq_mkArray_iff {l : Array α} {f : Nat α β} {b : β} :
mapIdx f l = mkArray l.size b (i : Nat) (h : i < l.size), f i l[i] = b := by
rcases l with l
theorem mapIdx_eq_mkArray_iff {xs : Array α} {f : Nat α β} {b : β} :
mapIdx f xs = mkArray xs.size b (i : Nat) (h : i < xs.size), f i xs[i] = b := by
rcases xs with xs
rw [ toList_inj]
simp [List.mapIdx_eq_replicate_iff]
@[simp] theorem mapIdx_reverse {l : Array α} {f : Nat α β} :
l.reverse.mapIdx f = (mapIdx (fun i => f (l.size - 1 - i)) l).reverse := by
rcases l with l
@[simp] theorem mapIdx_reverse {xs : Array α} {f : Nat α β} :
xs.reverse.mapIdx f = (mapIdx (fun i => f (xs.size - 1 - i)) xs).reverse := by
rcases xs with xs
simp [List.mapIdx_reverse]
end Array
@@ -480,15 +483,15 @@ end List
namespace Array
theorem toList_mapFinIdxM [Monad m] [LawfulMonad m] (l : Array α)
(f : (i : Nat) α (h : i < l.size) m β) :
toList <$> l.mapFinIdxM f = l.toList.mapFinIdxM f := by
theorem toList_mapFinIdxM [Monad m] [LawfulMonad m] (xs : Array α)
(f : (i : Nat) α (h : i < xs.size) m β) :
toList <$> xs.mapFinIdxM f = xs.toList.mapFinIdxM f := by
rw [List.mapFinIdxM_toArray]
simp only [Functor.map_map, id_map']
theorem toList_mapIdxM [Monad m] [LawfulMonad m] (l : Array α)
theorem toList_mapIdxM [Monad m] [LawfulMonad m] (xs : Array α)
(f : Nat α m β) :
toList <$> l.mapIdxM f = l.toList.mapIdxM f := by
toList <$> xs.mapIdxM f = xs.toList.mapIdxM f := by
rw [List.mapIdxM_toArray]
simp only [Functor.map_map, id_map']

View File

@@ -8,6 +8,9 @@ import Init.Data.Array.Basic
import Init.Data.Nat.Linear
import Init.Data.List.BasicAux
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
theorem sizeOf_lt_of_mem [SizeOf α] {as : Array α} (h : a as) : sizeOf a < sizeOf as := by

View File

@@ -12,6 +12,9 @@ import Init.Data.List.Monadic
# Lemmas about `Array.forIn'` and `Array.forIn`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
@@ -20,90 +23,90 @@ open Nat
/-! ### mapM -/
@[simp] theorem mapM_append [Monad m] [LawfulMonad m] (f : α m β) {l₁ l₂ : Array α} :
(l₁ ++ l₂).mapM f = (return ( l₁.mapM f) ++ ( l₂.mapM f)) := by
rcases l₁ with l₁
rcases l₂ with l₂
@[simp] theorem mapM_append [Monad m] [LawfulMonad m] (f : α m β) {xs ys : Array α} :
(xs ++ ys).mapM f = (return ( xs.mapM f) ++ ( ys.mapM f)) := by
rcases xs with xs
rcases ys with ys
simp
theorem mapM_eq_foldlM_push [Monad m] [LawfulMonad m] (f : α m β) (l : Array α) :
mapM f l = l.foldlM (fun acc a => return (acc.push ( f a))) #[] := by
rcases l with l
theorem mapM_eq_foldlM_push [Monad m] [LawfulMonad m] (f : α m β) (xs : Array α) :
mapM f xs = xs.foldlM (fun acc a => return (acc.push ( f a))) #[] := by
rcases xs with xs
simp only [List.mapM_toArray, bind_pure_comp, List.size_toArray, List.foldlM_toArray']
rw [List.mapM_eq_reverse_foldlM_cons]
simp only [bind_pure_comp, Functor.map_map]
suffices (k), (fun a => a.reverse.toArray) <$> List.foldlM (fun acc a => (fun a => a :: acc) <$> f a) k l =
List.foldlM (fun acc a => acc.push <$> f a) k.reverse.toArray l by
suffices (l), (fun l' => l'.reverse.toArray) <$> List.foldlM (fun acc a => (fun a => a :: acc) <$> f a) l xs =
List.foldlM (fun acc a => acc.push <$> f a) l.reverse.toArray xs by
exact this []
intro k
induction l generalizing k with
intro l
induction xs generalizing l with
| nil => simp
| cons a as ih =>
simp [ih, List.foldlM_cons]
/-! ### foldlM and foldrM -/
theorem foldlM_map [Monad m] (f : β₁ β₂) (g : α β₂ m α) (l : Array β₁) (init : α) (w : stop = l.size) :
(l.map f).foldlM g init 0 stop = l.foldlM (fun x y => g x (f y)) init 0 stop := by
theorem foldlM_map [Monad m] (f : β₁ β₂) (g : α β₂ m α) (xs : Array β₁) (init : α) (w : stop = xs.size) :
(xs.map f).foldlM g init 0 stop = xs.foldlM (fun x y => g x (f y)) init 0 stop := by
subst w
cases l
cases xs
simp [List.foldlM_map]
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ β₂) (g : β₂ α m α) (l : Array β₁)
(init : α) (w : start = l.size) :
(l.map f).foldrM g init start 0 = l.foldrM (fun x y => g (f x) y) init start 0 := by
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ β₂) (g : β₂ α m α) (xs : Array β₁)
(init : α) (w : start = xs.size) :
(xs.map f).foldrM g init start 0 = xs.foldrM (fun x y => g (f x) y) init start 0 := by
subst w
cases l
cases xs
simp [List.foldrM_map]
theorem foldlM_filterMap [Monad m] [LawfulMonad m] (f : α Option β) (g : γ β m γ)
(l : Array α) (init : γ) (w : stop = (l.filterMap f).size) :
(l.filterMap f).foldlM g init 0 stop =
l.foldlM (fun x y => match f y with | some b => g x b | none => pure x) init := by
(xs : Array α) (init : γ) (w : stop = (xs.filterMap f).size) :
(xs.filterMap f).foldlM g init 0 stop =
xs.foldlM (fun x y => match f y with | some b => g x b | none => pure x) init := by
subst w
cases l
cases xs
simp [List.foldlM_filterMap]
rfl
theorem foldrM_filterMap [Monad m] [LawfulMonad m] (f : α Option β) (g : β γ m γ)
(l : Array α) (init : γ) (w : start = (l.filterMap f).size) :
(l.filterMap f).foldrM g init start 0 =
l.foldrM (fun x y => match f x with | some b => g b y | none => pure y) init := by
(xs : Array α) (init : γ) (w : start = (xs.filterMap f).size) :
(xs.filterMap f).foldrM g init start 0 =
xs.foldrM (fun x y => match f x with | some b => g b y | none => pure y) init := by
subst w
cases l
cases xs
simp [List.foldrM_filterMap]
rfl
theorem foldlM_filter [Monad m] [LawfulMonad m] (p : α Bool) (g : β α m β)
(l : Array α) (init : β) (w : stop = (l.filter p).size) :
(l.filter p).foldlM g init 0 stop =
l.foldlM (fun x y => if p y then g x y else pure x) init := by
(xs : Array α) (init : β) (w : stop = (xs.filter p).size) :
(xs.filter p).foldlM g init 0 stop =
xs.foldlM (fun x y => if p y then g x y else pure x) init := by
subst w
cases l
cases xs
simp [List.foldlM_filter]
theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α Bool) (g : α β m β)
(l : Array α) (init : β) (w : start = (l.filter p).size) :
(l.filter p).foldrM g init start 0 =
l.foldrM (fun x y => if p x then g x y else pure y) init := by
(xs : Array α) (init : β) (w : start = (xs.filter p).size) :
(xs.filter p).foldrM g init start 0 =
xs.foldrM (fun x y => if p x then g x y else pure y) init := by
subst w
cases l
cases xs
simp [List.foldrM_filter]
@[simp] theorem foldlM_attachWith [Monad m]
(l : Array α) {q : α Prop} (H : a, a l q a) {f : β { x // q x} m β} {b} (w : stop = l.size):
(l.attachWith q H).foldlM f b 0 stop =
l.attach.foldlM (fun b a, h => f b a, H _ h) b := by
(xs : Array α) {q : α Prop} (H : a, a xs q a) {f : β { x // q x} m β} {b} (w : stop = xs.size):
(xs.attachWith q H).foldlM f b 0 stop =
xs.attach.foldlM (fun b a, h => f b a, H _ h) b := by
subst w
rcases l with l
rcases xs with xs
simp [List.foldlM_map]
@[simp] theorem foldrM_attachWith [Monad m] [LawfulMonad m]
(l : Array α) {q : α Prop} (H : a, a l q a) {f : { x // q x} β m β} {b} (w : start = l.size):
(l.attachWith q H).foldrM f b start 0 =
l.attach.foldrM (fun a acc => f a.1, H _ a.2 acc) b := by
(xs : Array α) {q : α Prop} (H : a, a xs q a) {f : { x // q x} β m β} {b} (w : start = xs.size):
(xs.attachWith q H).foldrM f b start 0 =
xs.attach.foldrM (fun a acc => f a.1, H _ a.2 acc) b := by
subst w
rcases l with l
rcases xs with xs
simp [List.foldrM_map]
/-! ### forM -/
@@ -114,15 +117,15 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β
cases as <;> cases bs
simp_all
@[simp] theorem forM_append [Monad m] [LawfulMonad m] (l₁ l₂ : Array α) (f : α m PUnit) :
forM (l₁ ++ l₂) f = (do forM l₁ f; forM l₂ f) := by
rcases l₁ with l₁
rcases l₂ with l₂
@[simp] theorem forM_append [Monad m] [LawfulMonad m] (xs ys : Array α) (f : α m PUnit) :
forM (xs ++ ys) f = (do forM xs f; forM ys f) := by
rcases xs with xs
rcases ys with ys
simp
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (l : Array α) (g : α β) (f : β m PUnit) :
forM (l.map g) f = forM l (fun a => f (g a)) := by
cases l
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (xs : Array α) (g : α β) (f : β m PUnit) :
forM (xs.map g) f = forM xs (fun a => f (g a)) := by
rcases xs with xs
simp
/-! ### forIn' -/
@@ -142,41 +145,41 @@ We can express a for loop over an array as a fold,
in which whenever we reach `.done b` we keep that value through the rest of the fold.
-/
theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
(l : Array α) (f : (a : α) a l β m (ForInStep β)) (init : β) :
forIn' l init f = ForInStep.value <$>
l.attach.foldlM (fun b a, m => match b with
(xs : Array α) (f : (a : α) a xs β m (ForInStep β)) (init : β) :
forIn' xs init f = ForInStep.value <$>
xs.attach.foldlM (fun b a, m => match b with
| .yield b => f a m b
| .done b => pure (.done b)) (ForInStep.yield init) := by
cases l
rcases xs with xs
simp [List.forIn'_eq_foldlM, List.foldlM_map]
congr
/-- We can express a for loop over an array which always yields as a fold. -/
@[simp] theorem forIn'_yield_eq_foldlM [Monad m] [LawfulMonad m]
(l : Array α) (f : (a : α) a l β m γ) (g : (a : α) a l β γ β) (init : β) :
forIn' l init (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
l.attach.foldlM (fun b a, m => g a m b <$> f a m b) init := by
cases l
(xs : Array α) (f : (a : α) a xs β m γ) (g : (a : α) a xs β γ β) (init : β) :
forIn' xs init (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
xs.attach.foldlM (fun b a, m => g a m b <$> f a m b) init := by
rcases xs with xs
simp [List.foldlM_map]
theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
(l : Array α) (f : (a : α) a l β β) (init : β) :
forIn' l init (fun a m b => pure (.yield (f a m b))) =
pure (f := m) (l.attach.foldl (fun b a, h => f a h b) init) := by
cases l
(xs : Array α) (f : (a : α) a xs β β) (init : β) :
forIn' xs init (fun a m b => pure (.yield (f a m b))) =
pure (f := m) (xs.attach.foldl (fun b a, h => f a h b) init) := by
rcases xs with xs
simp [List.forIn'_pure_yield_eq_foldl, List.foldl_map]
@[simp] theorem forIn'_yield_eq_foldl
(l : Array α) (f : (a : α) a l β β) (init : β) :
forIn' (m := Id) l init (fun a m b => .yield (f a m b)) =
l.attach.foldl (fun b a, h => f a h b) init := by
cases l
(xs : Array α) (f : (a : α) a xs β β) (init : β) :
forIn' (m := Id) xs init (fun a m b => .yield (f a m b)) =
xs.attach.foldl (fun b a, h => f a h b) init := by
rcases xs with xs
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
(xs : Array α) (g : α β) (f : (b : β) b xs.map g γ m (ForInStep γ)) :
forIn' (xs.map g) init f = forIn' xs init fun a h y => f (g a) (mem_map_of_mem g h) y := by
rcases xs with xs
simp
/--
@@ -184,41 +187,41 @@ We can express a for loop over an array as a fold,
in which whenever we reach `.done b` we keep that value through the rest of the fold.
-/
theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
(f : α β m (ForInStep β)) (init : β) (l : Array α) :
forIn l init f = ForInStep.value <$>
l.foldlM (fun b a => match b with
(f : α β m (ForInStep β)) (init : β) (xs : Array α) :
forIn xs init f = ForInStep.value <$>
xs.foldlM (fun b a => match b with
| .yield b => f a b
| .done b => pure (.done b)) (ForInStep.yield init) := by
cases l
rcases xs with xs
simp only [List.forIn_toArray, List.forIn_eq_foldlM, List.size_toArray, List.foldlM_toArray']
congr
/-- We can express a for loop over an array which always yields as a fold. -/
@[simp] theorem forIn_yield_eq_foldlM [Monad m] [LawfulMonad m]
(l : Array α) (f : α β m γ) (g : α β γ β) (init : β) :
forIn l init (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
l.foldlM (fun b a => g a b <$> f a b) init := by
cases l
(xs : Array α) (f : α β m γ) (g : α β γ β) (init : β) :
forIn xs init (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
xs.foldlM (fun b a => g a b <$> f a b) init := by
rcases xs with xs
simp [List.foldlM_map]
theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
(l : Array α) (f : α β β) (init : β) :
forIn l init (fun a b => pure (.yield (f a b))) =
pure (f := m) (l.foldl (fun b a => f a b) init) := by
cases l
(xs : Array α) (f : α β β) (init : β) :
forIn xs init (fun a b => pure (.yield (f a b))) =
pure (f := m) (xs.foldl (fun b a => f a b) init) := by
rcases xs with xs
simp [List.forIn_pure_yield_eq_foldl, List.foldl_map]
@[simp] theorem forIn_yield_eq_foldl
(l : Array α) (f : α β β) (init : β) :
forIn (m := Id) l init (fun a b => .yield (f a b)) =
l.foldl (fun b a => f a b) init := by
cases l
(xs : Array α) (f : α β β) (init : β) :
forIn (m := Id) xs init (fun a b => .yield (f a b)) =
xs.foldl (fun b a => f a b) init := by
rcases xs with xs
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
(xs : Array α) (g : α β) (f : β γ m (ForInStep γ)) :
forIn (xs.map g) init f = forIn xs init fun a y => f (g a) y := by
rcases xs with xs
simp
end Array
@@ -284,7 +287,7 @@ theorem filterMapM_toArray [Monad m] [LawfulMonad m] (l : List α) (f : α → m
| nil => simp only [foldlM_nil, flatMapM.loop, map_pure]
| cons x xs ih =>
simp only [foldlM_cons, bind_map_left, flatMapM.loop, _root_.map_bind]
congr; funext a
congr; funext xs
conv => lhs; rw [Array.toArray_append, flatten_concat, reverse_cons]
exact ih _
@@ -316,23 +319,23 @@ namespace Array
subst w
simp [flatMapM, h]
theorem toList_filterM [Monad m] [LawfulMonad m] (a : Array α) (p : α m Bool) :
toList <$> a.filterM p = a.toList.filterM p := by
theorem toList_filterM [Monad m] [LawfulMonad m] (xs : Array α) (p : α m Bool) :
toList <$> xs.filterM p = xs.toList.filterM p := by
rw [List.filterM_toArray]
simp only [Functor.map_map, id_map']
theorem toList_filterRevM [Monad m] [LawfulMonad m] (a : Array α) (p : α m Bool) :
toList <$> a.filterRevM p = a.toList.filterRevM p := by
theorem toList_filterRevM [Monad m] [LawfulMonad m] (xs : Array α) (p : α m Bool) :
toList <$> xs.filterRevM p = xs.toList.filterRevM p := by
rw [List.filterRevM_toArray]
simp only [Functor.map_map, id_map']
theorem toList_filterMapM [Monad m] [LawfulMonad m] (a : Array α) (f : α m (Option β)) :
toList <$> a.filterMapM f = a.toList.filterMapM f := by
theorem toList_filterMapM [Monad m] [LawfulMonad m] (xs : Array α) (f : α m (Option β)) :
toList <$> xs.filterMapM f = xs.toList.filterMapM f := by
rw [List.filterMapM_toArray]
simp only [Functor.map_map, id_map']
theorem toList_flatMapM [Monad m] [LawfulMonad m] (a : Array α) (f : α m (Array β)) :
toList <$> a.flatMapM f = a.toList.flatMapM (fun a => toList <$> f a) := by
theorem toList_flatMapM [Monad m] [LawfulMonad m] (xs : Array α) (f : α m (Array β)) :
toList <$> xs.flatMapM f = xs.toList.flatMapM (fun a => toList <$> f a) := by
rw [List.flatMapM_toArray]
simp only [Functor.map_map, id_map']
@@ -342,12 +345,12 @@ theorem toList_flatMapM [Monad m] [LawfulMonad m] (a : Array α) (f : α → m (
This lemma identifies monadic folds over lists of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
@[simp] theorem foldlM_subtype [Monad m] {p : α Prop} {l : Array { x // p x }}
@[simp] theorem foldlM_subtype [Monad m] {p : α Prop} {xs : Array { x // p x }}
{f : β { x // p x } m β} {g : β α m β} {x : β}
(hf : b x h, f b x, h = g b x) (w : stop = l.size) :
l.foldlM f x 0 stop = l.unattach.foldlM g x 0 stop := by
(hf : b x h, f b x, h = g b x) (w : stop = xs.size) :
xs.foldlM f x 0 stop = xs.unattach.foldlM g x 0 stop := by
subst w
rcases l with l
rcases xs with l
simp
rw [List.foldlM_subtype hf]
@@ -365,12 +368,12 @@ and simplifies these to the function directly taking the value.
This lemma identifies monadic folds over lists of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
@[simp] theorem foldrM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {l : Array { x // p x }}
@[simp] theorem foldrM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } β m β} {g : α β m β} {x : β}
(hf : x h b, f x, h b = g x b) (w : start = l.size) :
l.foldrM f x start 0 = l.unattach.foldrM g x start 0:= by
(hf : x h b, f x, h b = g x b) (w : start = xs.size) :
xs.foldrM f x start 0 = xs.unattach.foldrM g x start 0:= by
subst w
rcases l with l
rcases xs with xs
simp
rw [List.foldrM_subtype hf]
@@ -389,10 +392,10 @@ and simplifies these to the function directly taking the value.
This lemma identifies monadic maps over lists of subtypes, where the function only depends on the value, not the proposition,
and simplifies these to the function directly taking the value.
-/
@[simp] theorem mapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {l : Array { x // p x }}
@[simp] theorem mapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } m β} {g : α m β} (hf : x h, f x, h = g x) :
l.mapM f = l.unattach.mapM g := by
rcases l with l
xs.mapM f = xs.unattach.mapM g := by
rcases xs with xs
simp
rw [List.mapM_subtype hf]
@@ -405,11 +408,11 @@ and simplifies these to the function directly taking the value.
binderNameHint x f <| binderNameHint h () <| f (wfParam x) := by
simp [wfParam]
@[simp] theorem filterMapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } m (Option β)} {g : α m (Option β)} (hf : x h, f x, h = g x) (w : stop = l.size) :
l.filterMapM f 0 stop = l.unattach.filterMapM g := by
@[simp] theorem filterMapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } m (Option β)} {g : α m (Option β)} (hf : x h, f x, h = g x) (w : stop = xs.size) :
xs.filterMapM f 0 stop = xs.unattach.filterMapM g := by
subst w
rcases l with l
rcases xs with xs
simp
rw [List.filterMapM_subtype hf]
@@ -425,15 +428,14 @@ and simplifies these to the function directly taking the value.
binderNameHint x f <| binderNameHint h () <| f (wfParam x) := by
simp [wfParam]
@[simp] theorem flatMapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {l : Array { x // p x }}
@[simp] theorem flatMapM_subtype [Monad m] [LawfulMonad m] {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } m (Array β)} {g : α m (Array β)} (hf : x h, f x, h = g x) :
(l.flatMapM f) = l.unattach.flatMapM g := by
rcases l with l
(xs.flatMapM f) = xs.unattach.flatMapM g := by
rcases xs with xs
simp
rw [List.flatMapM_subtype]
simp [hf]
@[wf_preprocess] theorem flatMapM_wfParam [Monad m] [LawfulMonad m]
(xs : Array α) (f : α m (Array β)) :
(wfParam xs).flatMapM f = xs.attach.unattach.flatMapM f := by

View File

@@ -11,6 +11,9 @@ import Init.Data.List.OfFn
# Theorems about `Array.ofFn`
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
@[simp]

View File

@@ -7,6 +7,9 @@ prelude
import Init.Data.List.Nat.Perm
import Init.Data.Array.Lemmas
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open List
@@ -27,38 +30,38 @@ theorem perm_iff_toList_perm {as bs : Array α} : as ~ bs ↔ as.toList ~ bs.toL
@[simp] theorem perm_toArray (as bs : List α) : as.toArray ~ bs.toArray as ~ bs := by
simp [perm_iff_toList_perm]
@[simp, refl] protected theorem Perm.refl (l : Array α) : l ~ l := by
cases l
@[simp, refl] protected theorem Perm.refl (xs : Array α) : xs ~ xs := by
cases xs
simp
protected theorem Perm.rfl {l : List α} : l ~ l := .refl _
protected theorem Perm.rfl {xs : List α} : xs ~ xs := .refl _
theorem Perm.of_eq {l₁ l₂ : Array α} (h : l₁ = l₂) : l₁ ~ l₂ := h .rfl
theorem Perm.of_eq {xs ys : Array α} (h : xs = ys) : xs ~ ys := h .rfl
protected theorem Perm.symm {l₁ l₂ : Array α} (h : l₁ ~ l₂) : l₂ ~ l₁ := by
cases l₁; cases l₂
protected theorem Perm.symm {xs ys : Array α} (h : xs ~ ys) : ys ~ xs := by
cases xs; cases ys
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₃
protected theorem Perm.trans {xs ys zs : Array α} (h₁ : xs ~ ys) (h₂ : ys ~ zs) : xs ~ zs := by
cases xs; cases ys; cases zs
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_comm {xs ys : Array α} : xs ~ ys ys ~ xs := 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₂
theorem Perm.push (x y : α) {xs ys : Array α} (p : xs ~ ys) :
(xs.push x).push y ~ (ys.push y).push x := by
cases xs; cases ys
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
theorem swap_perm {xs : Array α} {i j : Nat} (h₁ : i < xs.size) (h₂ : j < xs.size) :
xs.swap i j ~ xs := by
simp only [swap, perm_iff_toList_perm, toList_set]
apply set_set_perm

View File

@@ -7,6 +7,9 @@ prelude
import Init.Data.Vector.Basic
import Init.Data.Ord
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- We do not enable `linter.indexVariables` because it is helpful to name index variables `lo`, `mid`, `hi`, etc.
namespace Array
private def qpartition {n} (as : Vector α n) (lt : α α Bool) (lo hi : Nat)

View File

@@ -15,6 +15,9 @@ import Init.Data.List.Nat.Range
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
@@ -28,7 +31,7 @@ theorem range'_succ (s n step) : range' s (n + 1) step = #[s] ++ range' (s + ste
simp [List.range'_succ]
@[simp] theorem range'_eq_empty_iff : range' s n step = #[] n = 0 := by
rw [ size_eq_zero, size_range']
rw [ size_eq_zero_iff, size_range']
theorem range'_ne_empty_iff (s : Nat) {n step : Nat} : range' s n step #[] n 0 := by
cases n <;> simp
@@ -133,7 +136,7 @@ theorem range'_eq_map_range (s n : Nat) : range' s n = map (s + ·) (range n) :=
rw [range_eq_range', map_add_range']; rfl
@[simp] theorem range_eq_empty_iff {n : Nat} : range n = #[] n = 0 := by
rw [ size_eq_zero, size_range]
rw [ size_eq_zero_iff, size_range]
theorem range_ne_empty_iff {n : Nat} : range n #[] n 0 := by
cases n <;> simp
@@ -146,9 +149,9 @@ theorem range_succ (n : Nat) : range (succ n) = range n ++ #[n] := by
dite_eq_ite]
split <;> omega
theorem range_add (a b : Nat) : range (a + b) = range a ++ (range b).map (a + ·) := by
theorem range_add (n m : Nat) : range (n + m) = range n ++ (range m).map (n + ·) := by
rw [ range'_eq_map_range]
simpa [range_eq_range', Nat.add_comm] using (range'_append_1 0 a b).symm
simpa [range_eq_range', Nat.add_comm] using (range'_append_1 0 n m).symm
theorem reverse_range' (s n : Nat) : reverse (range' s n) = map (s + n - 1 - ·) (range n) := by
simp [ toList_inj, List.reverse_range']
@@ -161,7 +164,7 @@ theorem not_mem_range_self {n : Nat} : n ∉ range n := by simp
theorem self_mem_range_succ (n : Nat) : n range (n + 1) := by simp
@[simp] theorem take_range (m n : Nat) : take (range n) m = range (min m n) := by
@[simp] theorem take_range (i n : Nat) : take (range n) i = range (min i n) := by
ext <;> simp
@[simp] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat Bool} :
@@ -179,48 +182,48 @@ theorem erase_range : (range n).erase i = range (min n i) ++ range' (i + 1) (n -
/-! ### zipIdx -/
@[simp]
theorem zipIdx_eq_empty_iff {l : Array α} {n : Nat} : l.zipIdx n = #[] l = #[] := by
cases l
theorem zipIdx_eq_empty_iff {xs : Array α} {i : Nat} : xs.zipIdx i = #[] xs = #[] := by
cases xs
simp
@[simp]
theorem getElem?_zipIdx (l : Array α) (n m) : (zipIdx l n)[m]? = l[m]?.map fun a => (a, n + m) := by
theorem getElem?_zipIdx (xs : Array α) (i j) : (zipIdx xs i)[j]? = xs[j]?.map fun a => (a, i + j) := by
simp [getElem?_def]
theorem map_snd_add_zipIdx_eq_zipIdx (l : Array α) (n k : Nat) :
map (Prod.map id (· + n)) (zipIdx l k) = zipIdx l (n + k) :=
theorem map_snd_add_zipIdx_eq_zipIdx (xs : Array α) (n k : Nat) :
map (Prod.map id (· + n)) (zipIdx xs k) = zipIdx xs (n + k) :=
ext_getElem? fun i by simp [(· ·), Nat.add_comm, Nat.add_left_comm]; rfl
@[simp]
theorem zipIdx_map_snd (n) (l : Array α) : map Prod.snd (zipIdx l n) = range' n l.size := by
cases l
theorem zipIdx_map_snd (i) (xs : Array α) : map Prod.snd (zipIdx xs i) = range' i xs.size := by
cases xs
simp
@[simp]
theorem zipIdx_map_fst (n) (l : Array α) : map Prod.fst (zipIdx l n) = l := by
cases l
theorem zipIdx_map_fst (i) (xs : Array α) : map Prod.fst (zipIdx xs i) = xs := by
cases xs
simp
theorem zipIdx_eq_zip_range' (l : Array α) {n : Nat} : l.zipIdx n = l.zip (range' n l.size) := by
theorem zipIdx_eq_zip_range' (xs : Array α) {i : Nat} : xs.zipIdx i = xs.zip (range' i xs.size) := by
simp [zip_of_prod (zipIdx_map_fst _ _) (zipIdx_map_snd _ _)]
@[simp]
theorem unzip_zipIdx_eq_prod (l : Array α) {n : Nat} :
(l.zipIdx n).unzip = (l, range' n l.size) := by
theorem unzip_zipIdx_eq_prod (xs : Array α) {i : Nat} :
(xs.zipIdx i).unzip = (xs, range' i xs.size) := by
simp only [zipIdx_eq_zip_range', unzip_zip, size_range']
/-- Replace `zipIdx` with a starting index `n+1` with `zipIdx` starting from `n`,
followed by a `map` increasing the indices by one. -/
theorem zipIdx_succ (l : Array α) (n : Nat) :
l.zipIdx (n + 1) = (l.zipIdx n).map (fun a, i => (a, i + 1)) := by
cases l
theorem zipIdx_succ (xs : Array α) (i : Nat) :
xs.zipIdx (i + 1) = (xs.zipIdx i).map (fun a, j => (a, j + 1)) := by
cases xs
simp [List.zipIdx_succ]
/-- Replace `zipIdx` with a starting index with `zipIdx` starting from 0,
followed by a `map` increasing the indices. -/
theorem zipIdx_eq_map_add (l : Array α) (n : Nat) :
l.zipIdx n = l.zipIdx.map (fun a, i => (a, n + i)) := by
cases l
theorem zipIdx_eq_map_add (xs : Array α) (i : Nat) :
xs.zipIdx i = (xs.zipIdx 0).map (fun a, j => (a, i + j)) := by
cases xs
simp only [zipIdx_toArray, List.map_toArray, mk.injEq]
rw [List.zipIdx_eq_map_add]
@@ -228,33 +231,33 @@ theorem zipIdx_eq_map_add (l : Array α) (n : Nat) :
theorem zipIdx_singleton (x : α) (k : Nat) : zipIdx #[x] k = #[(x, k)] :=
rfl
theorem mk_add_mem_zipIdx_iff_getElem? {k i : Nat} {x : α} {l : Array α} :
(x, k + i) zipIdx l k l[i]? = some x := by
theorem mk_add_mem_zipIdx_iff_getElem? {k i : Nat} {x : α} {xs : Array α} :
(x, k + i) zipIdx xs k xs[i]? = some x := by
simp [mem_iff_getElem?, and_left_comm]
theorem le_snd_of_mem_zipIdx {x : α × Nat} {k : Nat} {l : Array α} (h : x zipIdx l k) :
theorem le_snd_of_mem_zipIdx {x : α × Nat} {k : Nat} {xs : Array α} (h : x zipIdx xs k) :
k x.2 :=
(mk_mem_zipIdx_iff_le_and_getElem?_sub.1 h).1
theorem snd_lt_add_of_mem_zipIdx {x : α × Nat} {l : Array α} {k : Nat} (h : x zipIdx l k) :
x.2 < k + l.size := by
theorem snd_lt_add_of_mem_zipIdx {x : α × Nat} {k : Nat} {xs : Array α} (h : x zipIdx xs k) :
x.2 < k + xs.size := by
rcases mem_iff_getElem.1 h with i, h', rfl
simpa using h'
theorem snd_lt_of_mem_zipIdx {x : α × Nat} {l : Array α} {k : Nat} (h : x l.zipIdx k) : x.2 < l.size + k := by
theorem snd_lt_of_mem_zipIdx {x : α × Nat} {k : Nat} {xs : Array α} (h : x zipIdx xs k) : x.2 < xs.size + k := by
simpa [Nat.add_comm] using snd_lt_add_of_mem_zipIdx h
theorem map_zipIdx (f : α β) (l : Array α) (k : Nat) :
map (Prod.map f id) (zipIdx l k) = zipIdx (l.map f) k := by
cases l
theorem map_zipIdx (f : α β) (xs : Array α) (k : Nat) :
map (Prod.map f id) (zipIdx xs k) = zipIdx (xs.map f) k := by
cases xs
simp [List.map_zipIdx]
theorem fst_mem_of_mem_zipIdx {x : α × Nat} {l : Array α} {k : Nat} (h : x zipIdx l k) : x.1 l :=
zipIdx_map_fst k l mem_map_of_mem _ h
theorem fst_mem_of_mem_zipIdx {x : α × Nat} {xs : Array α} {k : Nat} (h : x zipIdx xs k) : x.1 xs :=
zipIdx_map_fst k xs mem_map_of_mem _ h
theorem fst_eq_of_mem_zipIdx {x : α × Nat} {l : Array α} {k : Nat} (h : x zipIdx l k) :
x.1 = l[x.2 - k]'(by have := le_snd_of_mem_zipIdx h; have := snd_lt_add_of_mem_zipIdx h; omega) := by
cases l
theorem fst_eq_of_mem_zipIdx {x : α × Nat} {xs : Array α} {k : Nat} (h : x zipIdx xs k) :
x.1 = xs[x.2 - k]'(by have := le_snd_of_mem_zipIdx h; have := snd_lt_add_of_mem_zipIdx h; omega) := by
cases xs
exact List.fst_eq_of_mem_zipIdx (by simpa using h)
theorem mem_zipIdx {x : α} {i : Nat} {xs : Array α} {k : Nat} (h : (x, i) xs.zipIdx k) :
@@ -267,9 +270,9 @@ theorem mem_zipIdx' {x : α} {i : Nat} {xs : Array α} (h : (x, i) ∈ xs.zipIdx
i < xs.size x = xs[i]'(by have := le_snd_of_mem_zipIdx h; have := snd_lt_add_of_mem_zipIdx h; omega) :=
by simpa using snd_lt_add_of_mem_zipIdx h, fst_eq_of_mem_zipIdx h
theorem zipIdx_map (l : Array α) (k : Nat) (f : α β) :
zipIdx (l.map f) k = (zipIdx l k).map (Prod.map f id) := by
cases l
theorem zipIdx_map (xs : Array α) (k : Nat) (f : α β) :
zipIdx (xs.map f) k = (zipIdx xs k).map (Prod.map f id) := by
cases xs
simp [List.zipIdx_map]
theorem zipIdx_append (xs ys : Array α) (k : Nat) :
@@ -278,12 +281,12 @@ theorem zipIdx_append (xs ys : Array α) (k : Nat) :
cases ys
simp [List.zipIdx_append]
theorem zipIdx_eq_append_iff {l : Array α} {k : Nat} :
zipIdx l k = l₁ ++ l₂
l₁' l₂', l = l₁' ++ l₂' l₁ = zipIdx l₁' k l₂ = zipIdx l₂' (k + l₁'.size) := by
rcases l with l
rcases l₁ with l₁
rcases l₂ with l₂
theorem zipIdx_eq_append_iff {xs : Array α} {k : Nat} :
zipIdx xs k = ys ++ zs
ys' zs', xs = ys' ++ zs' ys = zipIdx ys' k zs = zipIdx zs' (k + ys'.size) := by
rcases xs with xs
rcases ys with ys
rcases zs with zs
simp only [zipIdx_toArray, List.append_toArray, mk.injEq, List.zipIdx_eq_append_iff,
toArray_eq_append_iff]
constructor

View File

@@ -6,6 +6,9 @@ Authors: Leonardo de Moura, Mario Carneiro
prelude
import Init.Tactics
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
/--
Set an element in an array, using a proof that the index is in bounds.
@@ -15,9 +18,9 @@ This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[extern "lean_array_fset"]
def Array.set (a : Array α) (i : @& Nat) (v : α) (h : i < a.size := by get_elem_tactic) :
def Array.set (xs : Array α) (i : @& Nat) (v : α) (h : i < xs.size := by get_elem_tactic) :
Array α where
toList := a.toList.set i v
toList := xs.toList.set i v
/--
Set an element in an array, or do nothing if the index is out of bounds.
@@ -25,8 +28,8 @@ Set an element in an array, or do nothing if the index is out of bounds.
This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[inline] def Array.setIfInBounds (a : Array α) (i : Nat) (v : α) : Array α :=
dite (LT.lt i a.size) (fun h => a.set i v h) (fun _ => a)
@[inline] def Array.setIfInBounds (xs : Array α) (i : Nat) (v : α) : Array α :=
dite (LT.lt i xs.size) (fun h => xs.set i v h) (fun _ => xs)
@[deprecated Array.setIfInBounds (since := "2024-11-24")] abbrev Array.setD := @Array.setIfInBounds
@@ -37,5 +40,5 @@ This will perform the update destructively provided that `a` has a reference
count of 1 when called.
-/
@[extern "lean_array_set"]
def Array.set! (a : Array α) (i : @& Nat) (v : α) : Array α :=
Array.setIfInBounds a i v
def Array.set! (xs : Array α) (i : @& Nat) (v : α) : Array α :=
Array.setIfInBounds xs i v

View File

@@ -6,6 +6,8 @@ Authors: Leonardo de Moura
prelude
import Init.Data.Array.Basic
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
universe u v w
structure Subarray (α : Type u) where

View File

@@ -15,6 +15,9 @@ automation. Placing them in another module breaks an import cycle, because `omeg
array library.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Subarray
/--
Splits a subarray into two parts.

View File

@@ -12,6 +12,9 @@ These lemmas are used in the internals of HashMap.
They should find a new home and/or be reformulated.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
theorem exists_of_set {i : Nat} {a' : α} {l : List α} (h : i < l.length) :
@@ -23,9 +26,9 @@ end List
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
theorem exists_of_uset (xs : Array α) (i d h) :
l₁ l₂, xs.toList = l₁ ++ xs[i] :: l₂ List.length l₁ = i.toNat
(xs.uset i d h).toList = l₁ ++ d :: l₂ := by
simpa only [ugetElem_eq_getElem, getElem_toList, uset, toList_set] using
List.exists_of_set _

View File

@@ -11,6 +11,9 @@ import Init.Data.List.Zip
# Lemmas about `Array.zip`, `Array.zipWith`, `Array.zipWithAll`, and `Array.unzip`.
-/
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
open Nat
@@ -19,20 +22,20 @@ open Nat
/-! ### zipWith -/
theorem zipWith_comm (f : α β γ) (la : Array α) (lb : Array β) :
zipWith f la lb = zipWith (fun b a => f a b) lb la := by
cases la
cases lb
theorem zipWith_comm (f : α β γ) (as : Array α) (bs : Array β) :
zipWith f as bs = zipWith (fun b a => f a b) bs as := by
cases as
cases bs
simpa using List.zipWith_comm _ _ _
theorem zipWith_comm_of_comm (f : α α β) (comm : x y : α, f x y = f y x) (l l' : Array α) :
zipWith f l l' = zipWith f l' l := by
theorem zipWith_comm_of_comm (f : α α β) (comm : x y : α, f x y = f y x) (xs ys : Array α) :
zipWith f xs ys = zipWith f ys xs := by
rw [zipWith_comm]
simp only [comm]
@[simp]
theorem zipWith_self (f : α α δ) (l : Array α) : zipWith f l l = l.map fun a => f a a := by
cases l
theorem zipWith_self (f : α α δ) (xs : Array α) : zipWith f xs xs = xs.map fun a => f a a := by
cases xs
simp
/--
@@ -54,15 +57,15 @@ theorem getElem?_zipWith' {f : α → β → γ} {i : Nat} :
cases l₂
simp [List.getElem?_zipWith']
theorem getElem?_zipWith_eq_some {f : α β γ} {l₁ : Array α} {l₂ : Array β} {z : γ} {i : Nat} :
(zipWith f l₁ l₂)[i]? = some z
x y, l₁[i]? = some x l₂[i]? = some y f x y = z := by
cases l₁
cases l₂
theorem getElem?_zipWith_eq_some {f : α β γ} {as : Array α} {bs : Array β} {z : γ} {i : Nat} :
(zipWith f as bs)[i]? = some z
x y, as[i]? = some x bs[i]? = some y f x y = z := by
cases as
cases bs
simp [List.getElem?_zipWith_eq_some]
theorem getElem?_zip_eq_some {l₁ : Array α} {l₂ : Array β} {z : α × β} {i : Nat} :
(zip l₁ l₂)[i]? = some z l₁[i]? = some z.1 l₂[i]? = some z.2 := by
theorem getElem?_zip_eq_some {as : Array α} {bs : Array β} {z : α × β} {i : Nat} :
(zip as bs)[i]? = some z as[i]? = some z.1 bs[i]? = some z.2 := by
cases z
rw [zip, getElem?_zipWith_eq_some]; constructor
· rintro x, y, h₀, h₁, h₂
@@ -71,210 +74,210 @@ theorem getElem?_zip_eq_some {l₁ : Array α} {l₂ : Array β} {z : α × β}
exact _, _, h₀, h₁, rfl
@[simp]
theorem zipWith_map {μ} (f : γ δ μ) (g : α γ) (h : β δ) (l₁ : Array α) (l₂ : Array β) :
zipWith f (l₁.map g) (l₂.map h) = zipWith (fun a b => f (g a) (h b)) l₁ l₂ := by
cases l₁
cases l₂
theorem zipWith_map {μ} (f : γ δ μ) (g : α γ) (h : β δ) (as : Array α) (bs : Array β) :
zipWith f (as.map g) (bs.map h) = zipWith (fun a b => f (g a) (h b)) as bs := by
cases as
cases bs
simp [List.zipWith_map]
theorem zipWith_map_left (l₁ : Array α) (l₂ : Array β) (f : α α') (g : α' β γ) :
zipWith g (l₁.map f) l₂ = zipWith (fun a b => g (f a) b) l₁ l₂ := by
cases l₁
cases l₂
theorem zipWith_map_left (as : Array α) (bs : Array β) (f : α α') (g : α' β γ) :
zipWith g (as.map f) bs = zipWith (fun a b => g (f a) b) as bs := by
cases as
cases bs
simp [List.zipWith_map_left]
theorem zipWith_map_right (l₁ : Array α) (l₂ : Array β) (f : β β') (g : α β' γ) :
zipWith g l₁ (l₂.map f) = zipWith (fun a b => g a (f b)) l₁ l₂ := by
cases l₁
cases l₂
theorem zipWith_map_right (as : Array α) (bs : Array β) (f : β β') (g : α β' γ) :
zipWith g as (bs.map f) = zipWith (fun a b => g a (f b)) as bs := by
cases as
cases bs
simp [List.zipWith_map_right]
theorem zipWith_foldr_eq_zip_foldr {f : α β γ} (i : δ):
(zipWith f l₁ l₂).foldr g i = (zip l₁ l₂).foldr (fun p r => g (f p.1 p.2) r) i := by
cases l₁
cases l₂
(zipWith f as bs).foldr g i = (zip as bs).foldr (fun p r => g (f p.1 p.2) r) i := by
cases as
cases bs
simp [List.zipWith_foldr_eq_zip_foldr]
theorem zipWith_foldl_eq_zip_foldl {f : α β γ} (i : δ):
(zipWith f l₁ l₂).foldl g i = (zip l₁ l₂).foldl (fun r p => g r (f p.1 p.2)) i := by
cases l₁
cases l₂
(zipWith f as bs).foldl g i = (zip as bs).foldl (fun r p => g r (f p.1 p.2)) i := by
cases as
cases bs
simp [List.zipWith_foldl_eq_zip_foldl]
@[simp]
theorem zipWith_eq_empty_iff {f : α β γ} {l l'} : zipWith f l l' = #[] l = #[] l' = #[] := by
cases l <;> cases l' <;> simp
theorem zipWith_eq_empty_iff {f : α β γ} {as : Array α} {bs : Array β} : zipWith f as bs = #[] as = #[] bs = #[] := by
cases as <;> cases bs <;> simp
theorem map_zipWith {δ : Type _} (f : α β) (g : γ δ α) (l : Array γ) (l' : Array δ) :
map f (zipWith g l l') = zipWith (fun x y => f (g x y)) l l' := by
cases l
cases l'
theorem map_zipWith {δ : Type _} (f : α β) (g : γ δ α) (cs : Array γ) (ds : Array δ) :
map f (zipWith g cs ds) = zipWith (fun x y => f (g x y)) cs ds := by
cases cs
cases ds
simp [List.map_zipWith]
theorem take_zipWith : (zipWith f l l').take n = zipWith f (l.take n) (l'.take n) := by
cases l
cases l'
theorem take_zipWith : (zipWith f as bs).take i = zipWith f (as.take i) (bs.take i) := by
cases as
cases bs
simp [List.take_zipWith]
theorem extract_zipWith : (zipWith f l l').extract m n = zipWith f (l.extract m n) (l'.extract m n) := by
cases l
cases l'
theorem extract_zipWith : (zipWith f as bs).extract i j = zipWith f (as.extract i j) (bs.extract i j) := by
cases as
cases bs
simp [List.drop_zipWith, List.take_zipWith]
theorem zipWith_append (f : α β γ) (l la : Array α) (l' lb : Array β)
(h : l.size = l'.size) :
zipWith f (l ++ la) (l' ++ lb) = zipWith f l l' ++ zipWith f la lb := by
cases l
cases l'
cases la
cases lb
theorem zipWith_append (f : α β γ) (as as' : Array α) (bs bs' : Array β)
(h : as.size = bs.size) :
zipWith f (as ++ as') (bs ++ bs') = zipWith f as bs ++ zipWith f as' bs' := by
cases as
cases bs
cases as'
cases bs'
simp at h
simp [List.zipWith_append, h]
theorem zipWith_eq_append_iff {f : α β γ} {l₁ : Array α} {l₂ : Array β} :
zipWith f l₁ l₂ = l₁' ++ l₂'
w x y z, w.size = y.size l₁ = w ++ x l₂ = y ++ z l₁' = zipWith f w y l₂' = zipWith f x z := by
cases l₁
cases l₂
cases l₁'
cases l₂'
theorem zipWith_eq_append_iff {f : α β γ} {as : Array α} {bs : Array β} :
zipWith f as bs = xs ++ ys
as₁ as₂ bs₁ bs₂, as₁.size = bs₁.size as = as₁ ++ as₂ bs = bs₁ ++ bs₂ xs = zipWith f as₁ bs₁ ys = zipWith f as₂ bs₂ := by
cases as
cases bs
cases xs
cases ys
simp only [List.zipWith_toArray, List.append_toArray, mk.injEq, List.zipWith_eq_append_iff,
toArray_eq_append_iff]
constructor
· rintro w, x, y, z, h, rfl, rfl, rfl, rfl
exact w.toArray, x.toArray, y.toArray, z.toArray, by simp [h]
· rintro w, x, y, z, h, rfl, rfl, h₁, h₂
exact w, x, y, z, by simp_all
· rintro ws, xs, ys, zs, h, rfl, rfl, rfl, rfl
exact ws.toArray, xs.toArray, ys.toArray, zs.toArray, by simp [h]
· rintro ws, xs, ys, zs, h, rfl, rfl, h₁, h₂
exact ws, xs, ys, zs, by simp_all
@[simp] theorem zipWith_mkArray {a : α} {b : β} {m n : Nat} :
zipWith f (mkArray m a) (mkArray n b) = mkArray (min m n) (f a b) := by
simp [ List.toArray_replicate]
theorem map_uncurry_zip_eq_zipWith (f : α β γ) (l : Array α) (l' : Array β) :
map (Function.uncurry f) (l.zip l') = zipWith f l l' := by
cases l
cases l'
theorem map_uncurry_zip_eq_zipWith (f : α β γ) (as : Array α) (bs : Array β) :
map (Function.uncurry f) (as.zip bs) = zipWith f as bs := by
cases as
cases bs
simp [List.map_uncurry_zip_eq_zipWith]
theorem map_zip_eq_zipWith (f : α × β γ) (l : Array α) (l' : Array β) :
map f (l.zip l') = zipWith (Function.curry f) l l' := by
cases l
cases l'
theorem map_zip_eq_zipWith (f : α × β γ) (as : Array α) (bs : Array β) :
map f (as.zip bs) = zipWith (Function.curry f) as bs := by
cases as
cases bs
simp [List.map_zip_eq_zipWith]
theorem lt_size_left_of_zipWith {f : α β γ} {i : Nat} {l : Array α} {l' : Array β}
(h : i < (zipWith f l l').size) : i < l.size := by rw [size_zipWith] at h; omega
theorem lt_size_left_of_zipWith {f : α β γ} {i : Nat} {as : Array α} {bs : Array β}
(h : i < (zipWith f as bs).size) : i < as.size := by rw [size_zipWith] at h; omega
theorem lt_size_right_of_zipWith {f : α β γ} {i : Nat} {l : Array α} {l' : Array β}
(h : i < (zipWith f l l').size) : i < l'.size := by rw [size_zipWith] at h; omega
theorem lt_size_right_of_zipWith {f : α β γ} {i : Nat} {as : Array α} {bs : Array β}
(h : i < (zipWith f as bs).size) : i < bs.size := by rw [size_zipWith] at h; omega
theorem zipWith_eq_zipWith_take_min (l₁ : Array α) (l₂ : Array β) :
zipWith f l₁ l₂ = zipWith f (l₁.take (min l₁.size l₂.size)) (l₂.take (min l₁.size l₂.size)) := by
cases l₁
cases l₂
theorem zipWith_eq_zipWith_take_min (as : Array α) (bs : Array β) :
zipWith f as bs = zipWith f (as.take (min as.size bs.size)) (bs.take (min as.size bs.size)) := by
cases as
cases bs
simp
rw [List.zipWith_eq_zipWith_take_min]
theorem reverse_zipWith (h : l.size = l'.size) :
(zipWith f l l').reverse = zipWith f l.reverse l'.reverse := by
cases l
cases l'
theorem reverse_zipWith (h : as.size = bs.size) :
(zipWith f as bs).reverse = zipWith f as.reverse bs.reverse := by
cases as
cases bs
simp [List.reverse_zipWith (by simpa using h)]
/-! ### zip -/
theorem lt_size_left_of_zip {i : Nat} {l : Array α} {l' : Array β} (h : i < (zip l l').size) :
i < l.size :=
theorem lt_size_left_of_zip {i : Nat} {as : Array α} {bs : Array β} (h : i < (zip as bs).size) :
i < as.size :=
lt_size_left_of_zipWith h
theorem lt_size_right_of_zip {i : Nat} {l : Array α} {l' : Array β} (h : i < (zip l l').size) :
i < l'.size :=
theorem lt_size_right_of_zip {i : Nat} {as : Array α} {bs : Array β} (h : i < (zip as bs).size) :
i < bs.size :=
lt_size_right_of_zipWith h
@[simp]
theorem getElem_zip {l : Array α} {l' : Array β} {i : Nat} {h : i < (zip l l').size} :
(zip l l')[i] =
(l[i]'(lt_size_left_of_zip h), l'[i]'(lt_size_right_of_zip h)) :=
theorem getElem_zip {as : Array α} {bs : Array β} {i : Nat} {h : i < (zip as bs).size} :
(zip as bs)[i] =
(as[i]'(lt_size_left_of_zip h), bs[i]'(lt_size_right_of_zip h)) :=
getElem_zipWith (hi := by simpa using h)
theorem zip_eq_zipWith (l₁ : Array α) (l₂ : Array β) : zip l₁ l₂ = zipWith Prod.mk l₁ l₂ := by
cases l₁
cases l₂
theorem zip_eq_zipWith (as : Array α) (bs : Array β) : zip as bs = zipWith Prod.mk as bs := by
cases as
cases bs
simp [List.zip_eq_zipWith]
theorem zip_map (f : α γ) (g : β δ) (l₁ : Array α) (l₂ : Array β) :
zip (l₁.map f) (l₂.map g) = (zip l₁ l₂).map (Prod.map f g) := by
cases l₁
cases l₂
theorem zip_map (f : α γ) (g : β δ) (as : Array α) (bs : Array β) :
zip (as.map f) (bs.map g) = (zip as bs).map (Prod.map f g) := by
cases as
cases bs
simp [List.zip_map]
theorem zip_map_left (f : α γ) (l₁ : Array α) (l₂ : Array β) :
zip (l₁.map f) l₂ = (zip l₁ l₂).map (Prod.map f id) := by rw [ zip_map, map_id]
theorem zip_map_left (f : α γ) (as : Array α) (bs : Array β) :
zip (as.map f) bs = (zip as bs).map (Prod.map f id) := by rw [ zip_map, map_id]
theorem zip_map_right (f : β γ) (l₁ : Array α) (l₂ : Array β) :
zip l₁ (l₂.map f) = (zip l₁ l₂).map (Prod.map id f) := by rw [ zip_map, map_id]
theorem zip_map_right (f : β γ) (as : Array α) (bs : Array β) :
zip as (bs.map f) = (zip as bs).map (Prod.map id f) := by rw [ zip_map, map_id]
theorem zip_append {l₁ r₁ : Array α} {l₂ r₂ : Array β} (_h : l₁.size = l₂.size) :
zip (l₁ ++ r₁) (l₂ ++ r₂) = zip l₁ l₂ ++ zip r₁ r₂ := by
cases l₁
cases l₂
cases r₁
cases r₂
theorem zip_append {as bs : Array α} {cs ds : Array β} (_h : as.size = cs.size) :
zip (as ++ bs) (cs ++ ds) = zip as cs ++ zip bs ds := by
cases as
cases cs
cases bs
cases ds
simp_all [List.zip_append]
theorem zip_map' (f : α β) (g : α γ) (l : Array α) :
zip (l.map f) (l.map g) = l.map fun a => (f a, g a) := by
cases l
theorem zip_map' (f : α β) (g : α γ) (xs : Array α) :
zip (xs.map f) (xs.map g) = xs.map fun a => (f a, g a) := by
cases xs
simp [List.zip_map']
theorem of_mem_zip {a b} {l₁ : Array α} {l₂ : Array β} : (a, b) zip l₁ l₂ a l₁ b l₂ := by
cases l₁
cases l₂
theorem of_mem_zip {a b} {as : Array α} {bs : Array β} : (a, b) zip as bs a as b bs := by
cases as
cases bs
simpa using List.of_mem_zip
theorem map_fst_zip (l₁ : Array α) (l₂ : Array β) (h : l₁.size l₂.size) :
map Prod.fst (zip l₁ l₂) = l₁ := by
cases l₁
cases l₂
theorem map_fst_zip (as : Array α) (bs : Array β) (h : as.size bs.size) :
map Prod.fst (zip as bs) = as := by
cases as
cases bs
simp_all [List.map_fst_zip]
theorem map_snd_zip (l₁ : Array α) (l₂ : Array β) (h : l₂.size l₁.size) :
map Prod.snd (zip l₁ l₂) = l₂ := by
cases l₁
cases l₂
theorem map_snd_zip (as : Array α) (bs : Array β) (h : bs.size as.size) :
map Prod.snd (zip as bs) = bs := by
cases as
cases bs
simp_all [List.map_snd_zip]
theorem map_prod_left_eq_zip {l : Array α} (f : α β) :
(l.map fun x => (x, f x)) = l.zip (l.map f) := by
theorem map_prod_left_eq_zip {xs : Array α} (f : α β) :
(xs.map fun x => (x, f x)) = xs.zip (xs.map f) := by
rw [ zip_map']
congr
simp
theorem map_prod_right_eq_zip {l : Array α} (f : α β) :
(l.map fun x => (f x, x)) = (l.map f).zip l := by
theorem map_prod_right_eq_zip {xs : Array α} (f : α β) :
(xs.map fun x => (f x, x)) = (xs.map f).zip xs := by
rw [ zip_map']
congr
simp
@[simp] theorem zip_eq_empty_iff {l₁ : Array α} {l₂ : Array β} :
zip l₁ l₂ = #[] l₁ = #[] l₂ = #[] := by
cases l₁
cases l₂
@[simp] theorem zip_eq_empty_iff {as : Array α} {bs : Array β} :
zip as bs = #[] as = #[] bs = #[] := by
cases as
cases bs
simp [List.zip_eq_nil_iff]
theorem zip_eq_append_iff {l₁ : Array α} {l₂ : Array β} :
zip l₁ l₂ = l₁' ++ l₂'
w x y z, w.size = y.size l₁ = w ++ x l₂ = y ++ z l₁' = zip w y l₂' = zip x z := by
theorem zip_eq_append_iff {as : Array α} {bs : Array β} :
zip as bs = xs ++ ys
as₁ as₂ bs₁ bs₂, as₁.size = bs₁.size as = as₁ ++ as₂ bs = bs₁ ++ bs₂ xs = zip as₁ bs₁ ys = zip as₂ bs₂ := by
simp [zip_eq_zipWith, zipWith_eq_append_iff]
@[simp] theorem zip_mkArray {a : α} {b : β} {m n : Nat} :
zip (mkArray m a) (mkArray n b) = mkArray (min m n) (a, b) := by
simp [ List.toArray_replicate]
theorem zip_eq_zip_take_min (l₁ : Array α) (l₂ : Array β) :
zip l₁ l₂ = zip (l₁.take (min l₁.size l₂.size)) (l₂.take (min l₁.size l₂.size)) := by
cases l₁
cases l₂
theorem zip_eq_zip_take_min (as : Array α) (bs : Array β) :
zip as bs = zip (as.take (min as.size bs.size)) (bs.take (min as.size bs.size)) := by
cases as
cases bs
simp only [List.zip_toArray, List.size_toArray, List.take_toArray, mk.injEq]
rw [List.zip_eq_zip_take_min]
@@ -289,31 +292,30 @@ theorem getElem?_zipWithAll {f : Option α → Option β → γ} {i : Nat} :
simp [List.getElem?_zipWithAll]
rfl
theorem zipWithAll_map {μ} (f : Option γ Option δ μ) (g : α γ) (h : β δ) (l₁ : Array α) (l₂ : Array β) :
zipWithAll f (l₁.map g) (l₂.map h) = zipWithAll (fun a b => f (g <$> a) (h <$> b)) l₁ l₂ := by
cases l₁
cases l₂
theorem zipWithAll_map {μ} (f : Option γ Option δ μ) (g : α γ) (h : β δ) (as : Array α) (bs : Array β) :
zipWithAll f (as.map g) (bs.map h) = zipWithAll (fun a b => f (g <$> a) (h <$> b)) as bs := by
cases as
cases bs
simp [List.zipWithAll_map]
theorem zipWithAll_map_left (l₁ : Array α) (l₂ : Array β) (f : α α') (g : Option α' Option β γ) :
zipWithAll g (l₁.map f) l₂ = zipWithAll (fun a b => g (f <$> a) b) l₁ l₂ := by
cases l₁
cases l₂
theorem zipWithAll_map_left (as : Array α) (bs : Array β) (f : α α') (g : Option α' Option β γ) :
zipWithAll g (as.map f) bs = zipWithAll (fun a b => g (f <$> a) b) as bs := by
cases as
cases bs
simp [List.zipWithAll_map_left]
theorem zipWithAll_map_right (l₁ : Array α) (l₂ : Array β) (f : β β') (g : Option α Option β' γ) :
zipWithAll g l₁ (l₂.map f) = zipWithAll (fun a b => g a (f <$> b)) l₁ l₂ := by
cases l₁
cases l₂
theorem zipWithAll_map_right (as : Array α) (bs : Array β) (f : β β') (g : Option α Option β' γ) :
zipWithAll g as (bs.map f) = zipWithAll (fun a b => g a (f <$> b)) as bs := by
cases as
cases bs
simp [List.zipWithAll_map_right]
theorem map_zipWithAll {δ : Type _} (f : α β) (g : Option γ Option δ α) (l : Array γ) (l' : Array δ) :
map f (zipWithAll g l l') = zipWithAll (fun x y => f (g x y)) l l' := by
cases l
cases l'
theorem map_zipWithAll {δ : Type _} (f : α β) (g : Option γ Option δ α) (cs : Array γ) (ds : Array δ) :
map f (zipWithAll g cs ds) = zipWithAll (fun x y => f (g x y)) cs ds := by
cases cs
cases ds
simp [List.map_zipWithAll]
@[simp] theorem zipWithAll_replicate {a : α} {b : β} {n : Nat} :
zipWithAll f (mkArray n a) (mkArray n b) = mkArray n (f a b) := by
simp [ List.toArray_replicate]
@@ -326,37 +328,37 @@ theorem map_zipWithAll {δ : Type _} (f : α → β) (g : Option γ → Option
@[simp] theorem unzip_snd : (unzip l).snd = l.map Prod.snd := by
induction l <;> simp_all
theorem unzip_eq_map (l : Array (α × β)) : unzip l = (l.map Prod.fst, l.map Prod.snd) := by
cases l
theorem unzip_eq_map (xs : Array (α × β)) : unzip xs = (xs.map Prod.fst, xs.map Prod.snd) := by
cases xs
simp [List.unzip_eq_map]
theorem zip_unzip (l : Array (α × β)) : zip (unzip l).1 (unzip l).2 = l := by
cases l
theorem zip_unzip (xs : Array (α × β)) : zip (unzip xs).1 (unzip xs).2 = xs := by
cases xs
simp only [List.unzip_toArray, Prod.map_fst, Prod.map_snd, List.zip_toArray, List.zip_unzip]
theorem unzip_zip_left {l₁ : Array α} {l₂ : Array β} (h : l₁.size l₂.size) :
(unzip (zip l₁ l₂)).1 = l₁ := by
cases l₁
cases l₂
theorem unzip_zip_left {as : Array α} {bs : Array β} (h : as.size bs.size) :
(unzip (zip as bs)).1 = as := by
cases as
cases bs
simp_all only [List.size_toArray, List.zip_toArray, List.unzip_toArray, Prod.map_fst,
List.unzip_zip_left]
theorem unzip_zip_right {l₁ : Array α} {l₂ : Array β} (h : l₂.size l₁.size) :
(unzip (zip l₁ l₂)).2 = l₂ := by
cases l₁
cases l₂
theorem unzip_zip_right {as : Array α} {bs : Array β} (h : bs.size as.size) :
(unzip (zip as bs)).2 = bs := by
cases as
cases bs
simp_all only [List.size_toArray, List.zip_toArray, List.unzip_toArray, Prod.map_snd,
List.unzip_zip_right]
theorem unzip_zip {l₁ : Array α} {l₂ : Array β} (h : l₁.size = l₂.size) :
unzip (zip l₁ l₂) = (l₁, l₂) := by
cases l₁
cases l₂
theorem unzip_zip {as : Array α} {bs : Array β} (h : as.size = bs.size) :
unzip (zip as bs) = (as, bs) := by
cases as
cases bs
simp_all only [List.size_toArray, List.zip_toArray, List.unzip_toArray, List.unzip_zip, Prod.map_apply]
theorem zip_of_prod {l : Array α} {l' : Array β} {lp : Array (α × β)} (hl : lp.map Prod.fst = l)
(hr : lp.map Prod.snd = l') : lp = l.zip l' := by
rw [ hl, hr, zip_unzip lp, unzip_fst, unzip_snd, zip_unzip, zip_unzip]
theorem zip_of_prod {as : Array α} {bs : Array β} {xs : Array (α × β)} (hl : xs.map Prod.fst = as)
(hr : xs.map Prod.snd = bs) : xs = as.zip bs := by
rw [ hl, hr, zip_unzip xs, unzip_fst, unzip_snd, zip_unzip, zip_unzip]
@[simp] theorem unzip_mkArray {n : Nat} {a : α} {b : β} :
unzip (mkArray n (a, b)) = (mkArray n a, mkArray n b) := by

View File

@@ -25,7 +25,7 @@ class ReflBEq (α) [BEq α] : Prop where
refl : (a : α) == a
/-- `EquivBEq` says that the `BEq` implementation is an equivalence relation. -/
class EquivBEq (α) [BEq α] extends PartialEquivBEq α, ReflBEq α : Prop
class EquivBEq (α) [BEq α] : Prop extends PartialEquivBEq α, ReflBEq α
@[simp]
theorem BEq.refl [BEq α] [ReflBEq α] {a : α} : a == a :=

View File

@@ -907,7 +907,7 @@ The input to the shift subtractor is a legal input to `divrem`, and we also need
input bit to perform shift subtraction on, and thus we need `0 < wn`.
-/
structure DivModState.Poised {w : Nat} (args : DivModArgs w) (qr : DivModState w)
extends DivModState.Lawful args qr : Type where
extends DivModState.Lawful args qr where
/-- Only perform a round of shift-subtract if we have dividend bits. -/
hwn_lt : 0 < qr.wn
@@ -1034,11 +1034,10 @@ theorem divRec_succ (m : Nat) (args : DivModArgs w) (qr : DivModState w) :
theorem lawful_divRec {args : DivModArgs w} {qr : DivModState w}
(h : DivModState.Lawful args qr) :
DivModState.Lawful args (divRec qr.wn args qr) := by
generalize hm : qr.wn = m
induction m generalizing qr
case zero =>
induction hm : qr.wn generalizing qr with
| zero =>
exact h
case succ wn' ih =>
| succ wn' ih =>
simp only [divRec_succ]
apply ih
· apply lawful_divSubtractShift
@@ -1052,11 +1051,10 @@ theorem lawful_divRec {args : DivModArgs w} {qr : DivModState w}
@[simp]
theorem wn_divRec (args : DivModArgs w) (qr : DivModState w) :
(divRec qr.wn args qr).wn = 0 := by
generalize hm : qr.wn = m
induction m generalizing qr
case zero =>
induction hm : qr.wn generalizing qr with
| zero =>
assumption
case succ wn' ih =>
| succ wn' ih =>
apply ih
simp only [divSubtractShift, hm]
split <;> rfl

View File

@@ -1517,8 +1517,8 @@ theorem zero_shiftLeft (n : Nat) : 0#w <<< n = 0#w := by
all_goals { simp_all <;> omega }
@[simp] theorem getElem_shiftLeft {x : BitVec m} {n : Nat} (h : i < m) :
(x <<< n)[i] = (!decide (i < n) && getLsbD x (i - n)) := by
rw [ testBit_toNat, getElem_eq_testBit_toNat]
(x <<< n)[i] = (!decide (i < n) && x[i - n]) := by
rw [getElem_eq_testBit_toNat, getElem_eq_testBit_toNat]
simp only [toNat_shiftLeft, Nat.testBit_mod_two_pow, Nat.testBit_shiftLeft, ge_iff_le]
-- This step could be a case bashing tactic.
cases h₁ : decide (i < m) <;> cases h₂ : decide (n i) <;> cases h₃ : decide (i < n)
@@ -1568,8 +1568,8 @@ theorem shiftLeftZeroExtend_eq {x : BitVec w} :
· omega
@[simp] theorem getElem_shiftLeftZeroExtend {x : BitVec m} {n : Nat} (h : i < m + n) :
(shiftLeftZeroExtend x n)[i] = ((! decide (i < n)) && getLsbD x (i - n)) := by
rw [shiftLeftZeroExtend_eq, getLsbD]
(shiftLeftZeroExtend x n)[i] = if h' : i < n then false else x[i - n] := by
rw [shiftLeftZeroExtend_eq]
simp only [getElem_eq_testBit_toNat, getLsbD_shiftLeft, getLsbD_setWidth]
cases h₁ : decide (i < n) <;> cases h₂ : decide (i - n < m + n)
<;> simp_all [h]
@@ -1598,8 +1598,8 @@ theorem shiftLeftZeroExtend_eq {x : BitVec w} :
theorem shiftLeft_add {w : Nat} (x : BitVec w) (n m : Nat) :
x <<< (n + m) = (x <<< n) <<< m := by
ext i
simp only [getElem_shiftLeft, Fin.is_lt, decide_true, Bool.true_and]
rw [show i - (n + m) = (i - m - n) by omega]
simp only [getElem_shiftLeft]
rw [show x[i - (n + m)] = x[i - m - n] by congr 1; omega]
cases h₂ : decide (i < m) <;>
cases h₃ : decide (i - m < w) <;>
cases h₄ : decide (i - m < n) <;>
@@ -1632,7 +1632,7 @@ theorem getLsbD_shiftLeft' {x : BitVec w₁} {y : BitVec w₂} {i : Nat} :
simp [shiftLeft_eq', getLsbD_shiftLeft]
theorem getElem_shiftLeft' {x : BitVec w₁} {y : BitVec w₂} {i : Nat} (h : i < w₁) :
(x <<< y)[i] = (!decide (i < y.toNat) && x.getLsbD (i - y.toNat)) := by
(x <<< y)[i] = (!decide (i < y.toNat) && x[i - y.toNat]) := by
simp
@[simp] theorem shiftLeft_eq_zero {x : BitVec w} {n : Nat} (hn : w n) : x <<< n = 0#w := by
@@ -1844,13 +1844,10 @@ theorem getLsbD_sshiftRight (x : BitVec w) (s i : Nat) :
omega
theorem getElem_sshiftRight {x : BitVec w} {s i : Nat} (h : i < w) :
(x.sshiftRight s)[i] = (if s + i < w then x.getLsbD (s + i) else x.msb) := by
rcases hmsb : x.msb with rfl | rfl
· simp only [sshiftRight_eq_of_msb_false hmsb, getElem_ushiftRight, Bool.if_false_right,
Bool.iff_and_self, decide_eq_true_eq]
intros hlsb
apply BitVec.lt_of_getLsbD hlsb
· simp [sshiftRight_eq_of_msb_true hmsb]
(x.sshiftRight s)[i] = (if h : s + i < w then x[s + i] else x.msb) := by
rw [ getLsbD_eq_getElem, getLsbD_sshiftRight]
simp only [show ¬(w i) by omega, decide_false, Bool.not_false, Bool.true_and]
by_cases h' : s + i < w <;> simp [h']
theorem sshiftRight_xor_distrib (x y : BitVec w) (n : Nat) :
(x ^^^ y).sshiftRight n = (x.sshiftRight n) ^^^ (y.sshiftRight n) := by
@@ -1957,9 +1954,8 @@ theorem getLsbD_sshiftRight' {x y : BitVec w} {i : Nat} :
-- This should not be a `@[simp]` lemma as the left hand side is not in simp normal form.
theorem getElem_sshiftRight' {x y : BitVec w} {i : Nat} (h : i < w) :
(x.sshiftRight' y)[i] =
(!decide (w i) && if y.toNat + i < w then x.getLsbD (y.toNat + i) else x.msb) := by
simp only [ getLsbD_eq_getElem, BitVec.sshiftRight', BitVec.getLsbD_sshiftRight]
(x.sshiftRight' y)[i] = (if h : y.toNat + i < w then x[y.toNat + i] else x.msb) := by
simp [show ¬ w i by omega, getElem_sshiftRight]
theorem getMsbD_sshiftRight' {x y: BitVec w} {i : Nat} :
(x.sshiftRight y.toNat).getMsbD i =
@@ -2030,9 +2026,8 @@ theorem getMsbD_signExtend {x : BitVec w} {v i : Nat} :
by_cases h : i < v <;> by_cases h' : v - w i <;> simp [h, h'] <;> omega
theorem getElem_signExtend {x : BitVec w} {v i : Nat} (h : i < v) :
(x.signExtend v)[i] = if i < w then x.getLsbD i else x.msb := by
rw [getLsbD_eq_getElem, getLsbD_signExtend]
simp [h]
(x.signExtend v)[i] = if h : i < w then x[i] else x.msb := by
simp [getLsbD_eq_getElem, getLsbD_signExtend, h]
theorem msb_signExtend {x : BitVec w} :
(x.signExtend v).msb = (decide (0 < v) && if w v then x.getMsbD (w - v) else x.msb) := by
@@ -2044,9 +2039,7 @@ theorem msb_signExtend {x : BitVec w} :
theorem signExtend_eq_setWidth_of_lt (x : BitVec w) {v : Nat} (hv : v w):
x.signExtend v = x.setWidth v := by
ext i h
simp only [getElem_signExtend, h, decide_true, Bool.true_and, getElem_setWidth,
ite_eq_left_iff, Nat.not_lt]
omega
simp [getElem_signExtend, show i < w by omega]
/-- Sign extending to the same bitwidth is a no op. -/
theorem signExtend_eq (x : BitVec w) : x.signExtend w = x := by
@@ -2101,6 +2094,7 @@ theorem toInt_signExtend_of_lt {x : BitVec w} (hv : w < v):
have : (x.signExtend v).msb = x.msb := by
rw [msb_eq_getLsbD_last, getLsbD_eq_getElem (Nat.sub_one_lt_of_lt hv)]
simp [getElem_signExtend, Nat.le_sub_one_of_lt hv]
omega
have H : 2^w 2^v := Nat.pow_le_pow_right (by omega) (by omega)
simp only [this, toNat_setWidth, Int.natCast_add, Int.ofNat_emod, Int.natCast_mul]
by_cases h : x.msb
@@ -2282,11 +2276,11 @@ theorem ushiftRight_eq_extractLsb'_of_lt {x : BitVec w} {n : Nat} (hn : n < w) :
theorem shiftLeft_eq_concat_of_lt {x : BitVec w} {n : Nat} (hn : n < w) :
x <<< n = (x.extractLsb' 0 (w - n) ++ 0#n).cast (by omega) := by
ext i hi
simp only [getElem_shiftLeft, getElem_cast, getElem_append, getLsbD_zero, getLsbD_extractLsb',
simp only [getElem_shiftLeft, getElem_cast, getElem_append, getElem_zero, getElem_extractLsb',
Nat.zero_add, Bool.if_false_left]
by_cases hi' : i < n
· simp [hi']
· simp [hi']
· simp [hi', show i - n < w by omega]
/-! ### rev -/
@@ -2336,7 +2330,7 @@ theorem getLsbD_cons (b : Bool) {n} (x : BitVec n) (i : Nat) :
simp [p1, p2, Nat.testBit_bool_to_nat]
theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
(cons b x)[i] = if i = n then b else getLsbD x i := by
(cons b x)[i] = if h : i = n then b else x[i] := by
simp only [getElem_eq_testBit_toNat, toNat_cons, Nat.testBit_or, getLsbD]
rw [Nat.testBit_shiftLeft]
rcases Nat.lt_trichotomy i n with i_lt_n | i_eq_n | n_lt_i
@@ -2444,7 +2438,7 @@ theorem getLsbD_concat (x : BitVec w) (b : Bool) (i : Nat) :
· simp [Nat.div_eq_of_lt b.toNat_lt, Nat.testBit_add_one]
theorem getElem_concat (x : BitVec w) (b : Bool) (i : Nat) (h : i < w + 1) :
(concat x b)[i] = if i = 0 then b else x.getLsbD (i - 1) := by
(concat x b)[i] = if h : i = 0 then b else x[i - 1] := by
simp only [concat, getElem_eq_testBit_toNat, getLsbD, toNat_append,
toNat_ofBool, Nat.testBit_or, Nat.shiftLeft_eq]
cases i
@@ -2484,10 +2478,7 @@ theorem msb_concat {w : Nat} {b : Bool} {x : BitVec w} :
simp only [BitVec.msb, getMsbD_eq_getLsbD, Nat.zero_lt_succ, decide_true, Nat.add_one_sub_one,
Nat.sub_zero, Bool.true_and]
by_cases h₀ : 0 < w
· simp only [Nat.lt_add_one, getLsbD_eq_getElem, getElem_concat, h₀, reduceIte, decide_true,
Bool.true_and, ite_eq_right_iff]
intro
omega
· simp [getElem_concat, h₀, show ¬ w = 0 by omega, show w - 1 < w by omega]
· simp [h₀, show w = 0 by omega]
@[simp] theorem toInt_concat (x : BitVec w) (b : Bool) :
@@ -4217,6 +4208,10 @@ theorem toInt_abs_eq_natAbs_of_ne_intMin {x : BitVec w} (hx : x ≠ intMin w) :
x.abs.toInt = x.toInt.natAbs := by
simp [toInt_abs_eq_natAbs, hx]
theorem toFin_abs {x : BitVec w} :
x.abs.toFin = if x.msb then Fin.ofNat' (2 ^ w) (2 ^ w - x.toNat) else x.toFin := by
by_cases h : x.msb <;> simp [BitVec.abs, h]
/-! ### Reverse -/
theorem getLsbD_reverse {i : Nat} {x : BitVec w} :

View File

@@ -7,7 +7,6 @@ prelude
import Init.Data.Int.Basic
import Init.Data.Int.Bitwise
import Init.Data.Int.DivMod
import Init.Data.Int.DivModLemmas
import Init.Data.Int.Gcd
import Init.Data.Int.Lemmas
import Init.Data.Int.LemmasAux

View File

@@ -6,6 +6,7 @@ Authors: Siddharth Bhat, Jeremy Avigad
prelude
import Init.Data.Nat.Bitwise.Lemmas
import Init.Data.Int.Bitwise
import Init.Data.Int.DivMod.Lemmas
namespace Int

View File

@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Int.DivModLemmas
import Init.Data.Int.DivMod.Lemmas
import Init.Data.Int.Gcd
/-!
@@ -99,7 +99,7 @@ def resolve_left' (a c d p x : Int) (h₁ : p ≤ a * x) : Nat := (add_of_le h
/-- `resolve_left` is nonnegative when `p ≤ a * x`. -/
theorem le_zero_resolve_left (a c d p x : Int) (h₁ : p a * x) :
0 resolve_left a c d p x := by
simpa [h₁] using Int.ofNat_nonneg _
simp [h₁]
/-- `resolve_left` is bounded above by `lcm a (a * d / gcd (a * d) c)`. -/
theorem resolve_left_lt_lcm (a c d p x : Int) (a_pos : 0 < a) (d_pos : 0 < d) (h₁ : p a * x) :

View File

@@ -1,328 +1,9 @@
/-
Copyright (c) 2016 Jeremy Avigad. All rights reserved.
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Mario Carneiro
Authors: Kim Morrison
-/
prelude
import Init.Data.Int.Basic
open Nat
namespace Int
/-! ## Quotient and remainder
There are three main conventions for integer division,
referred here as the E, F, T rounding conventions.
All three pairs satisfy the identity `x % y + (x / y) * y = x` unconditionally,
and satisfy `x / 0 = 0` and `x % 0 = x`.
### Historical notes
In early versions of Lean, the typeclasses provided by `/` and `%`
were defined in terms of `tdiv` and `tmod`, and these were named simply as `div` and `mod`.
However we decided it was better to use `ediv` and `emod`,
as they are consistent with the conventions used in SMTLib, and Mathlib,
and often mathematical reasoning is easier with these conventions.
At that time, we did not rename `div` and `mod` to `tdiv` and `tmod` (along with all their lemma).
In September 2024, we decided to do this rename (with deprecations in place),
and later we intend to rename `ediv` and `emod` to `div` and `mod`, as nearly all users will only
ever need to use these functions and their associated lemmas.
In December 2024, we removed `tdiv` and `tmod`, but have not yet renamed `ediv` and `emod`.
-/
/-! ### T-rounding division -/
/--
`tdiv` uses the [*"T-rounding"*][t-rounding]
(**T**runcation-rounding) convention, meaning that it rounds toward
zero. Also note that division by zero is defined to equal zero.
The relation between integer division and modulo is found in
`Int.tmod_add_tdiv` which states that
`tmod a b + b * (tdiv a b) = a`, unconditionally.
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862
[theo tmod_add_tdiv]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.tmod_add_tdiv#doc
Examples:
```
#eval (7 : Int).tdiv (0 : Int) -- 0
#eval (0 : Int).tdiv (7 : Int) -- 0
#eval (12 : Int).tdiv (6 : Int) -- 2
#eval (12 : Int).tdiv (-6 : Int) -- -2
#eval (-12 : Int).tdiv (6 : Int) -- -2
#eval (-12 : Int).tdiv (-6 : Int) -- 2
#eval (12 : Int).tdiv (7 : Int) -- 1
#eval (12 : Int).tdiv (-7 : Int) -- -1
#eval (-12 : Int).tdiv (7 : Int) -- -1
#eval (-12 : Int).tdiv (-7 : Int) -- 1
```
Implemented by efficient native code.
-/
@[extern "lean_int_div"]
def tdiv : (@& Int) (@& Int) Int
| ofNat m, ofNat n => ofNat (m / n)
| ofNat m, -[n +1] => -ofNat (m / succ n)
| -[m +1], ofNat n => -ofNat (succ m / n)
| -[m +1], -[n +1] => ofNat (succ m / succ n)
/-- Integer modulo. This function uses the
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention
to pair with `Int.tdiv`, meaning that `tmod a b + b * (tdiv a b) = a`
unconditionally (see [`Int.tmod_add_tdiv`][theo tmod_add_tdiv]). In
particular, `a % 0 = a`.
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862
[theo tmod_add_tdiv]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.tmod_add_tdiv#doc
Examples:
```
#eval (7 : Int).tmod (0 : Int) -- 7
#eval (0 : Int).tmod (7 : Int) -- 0
#eval (12 : Int).tmod (6 : Int) -- 0
#eval (12 : Int).tmod (-6 : Int) -- 0
#eval (-12 : Int).tmod (6 : Int) -- 0
#eval (-12 : Int).tmod (-6 : Int) -- 0
#eval (12 : Int).tmod (7 : Int) -- 5
#eval (12 : Int).tmod (-7 : Int) -- 5
#eval (-12 : Int).tmod (7 : Int) -- -5
#eval (-12 : Int).tmod (-7 : Int) -- -5
```
Implemented by efficient native code. -/
@[extern "lean_int_mod"]
def tmod : (@& Int) (@& Int) Int
| ofNat m, ofNat n => ofNat (m % n)
| ofNat m, -[n +1] => ofNat (m % succ n)
| -[m +1], ofNat n => -ofNat (succ m % n)
| -[m +1], -[n +1] => -ofNat (succ m % succ n)
/-! ### F-rounding division
This pair satisfies `fdiv x y = floor (x / y)`.
-/
/--
Integer division. This version of division uses the F-rounding convention
(flooring division), in which `Int.fdiv x y` satisfies `fdiv x y = floor (x / y)`
and `Int.fmod` is the unique function satisfying `fmod x y + (fdiv x y) * y = x`.
Examples:
```
#eval (7 : Int).fdiv (0 : Int) -- 0
#eval (0 : Int).fdiv (7 : Int) -- 0
#eval (12 : Int).fdiv (6 : Int) -- 2
#eval (12 : Int).fdiv (-6 : Int) -- -2
#eval (-12 : Int).fdiv (6 : Int) -- -2
#eval (-12 : Int).fdiv (-6 : Int) -- 2
#eval (12 : Int).fdiv (7 : Int) -- 1
#eval (12 : Int).fdiv (-7 : Int) -- -2
#eval (-12 : Int).fdiv (7 : Int) -- -2
#eval (-12 : Int).fdiv (-7 : Int) -- 1
```
-/
def fdiv : Int Int Int
| 0, _ => 0
| ofNat m, ofNat n => ofNat (m / n)
| ofNat (succ m), -[n+1] => -[m / succ n +1]
| -[_+1], 0 => 0
| -[m+1], ofNat (succ n) => -[m / succ n +1]
| -[m+1], -[n+1] => ofNat (succ m / succ n)
/--
Integer modulus. This version of `Int.mod` uses the F-rounding convention
(flooring division), in which `Int.fdiv x y` satisfies `fdiv x y = floor (x / y)`
and `Int.fmod` is the unique function satisfying `fmod x y + (fdiv x y) * y = x`.
Examples:
```
#eval (7 : Int).fmod (0 : Int) -- 7
#eval (0 : Int).fmod (7 : Int) -- 0
#eval (12 : Int).fmod (6 : Int) -- 0
#eval (12 : Int).fmod (-6 : Int) -- 0
#eval (-12 : Int).fmod (6 : Int) -- 0
#eval (-12 : Int).fmod (-6 : Int) -- 0
#eval (12 : Int).fmod (7 : Int) -- 5
#eval (12 : Int).fmod (-7 : Int) -- -2
#eval (-12 : Int).fmod (7 : Int) -- 2
#eval (-12 : Int).fmod (-7 : Int) -- -5
```
-/
def fmod : Int Int Int
| 0, _ => 0
| ofNat m, ofNat n => ofNat (m % n)
| ofNat (succ m), -[n+1] => subNatNat (m % succ n) n
| -[m+1], ofNat n => subNatNat n (succ (m % n))
| -[m+1], -[n+1] => -ofNat (succ m % succ n)
/-! ### E-rounding division
This pair satisfies `0 ≤ mod x y < natAbs y` for `y ≠ 0`.
-/
/--
Integer division. This version of `Int.div` uses the E-rounding convention
(euclidean division), in which `Int.emod x y` satisfies `0 ≤ mod x y < natAbs y` for `y ≠ 0`
and `Int.ediv` is the unique function satisfying `emod x y + (ediv x y) * y = x`.
This is the function powering the `/` notation on integers.
Examples:
```
#eval (7 : Int) / (0 : Int) -- 0
#eval (0 : Int) / (7 : Int) -- 0
#eval (12 : Int) / (6 : Int) -- 2
#eval (12 : Int) / (-6 : Int) -- -2
#eval (-12 : Int) / (6 : Int) -- -2
#eval (-12 : Int) / (-6 : Int) -- 2
#eval (12 : Int) / (7 : Int) -- 1
#eval (12 : Int) / (-7 : Int) -- -1
#eval (-12 : Int) / (7 : Int) -- -2
#eval (-12 : Int) / (-7 : Int) -- 2
```
Implemented by efficient native code.
-/
@[extern "lean_int_ediv"]
def ediv : (@& Int) (@& Int) Int
| ofNat m, ofNat n => ofNat (m / n)
| ofNat m, -[n+1] => -ofNat (m / succ n)
| -[_+1], 0 => 0
| -[m+1], ofNat (succ n) => -[m / succ n +1]
| -[m+1], -[n+1] => ofNat (succ (m / succ n))
/--
Integer modulus. This version of `Int.mod` uses the E-rounding convention
(euclidean division), in which `Int.emod x y` satisfies `0 ≤ emod x y < natAbs y` for `y ≠ 0`
and `Int.ediv` is the unique function satisfying `emod x y + (ediv x y) * y = x`.
This is the function powering the `%` notation on integers.
Examples:
```
#eval (7 : Int) % (0 : Int) -- 7
#eval (0 : Int) % (7 : Int) -- 0
#eval (12 : Int) % (6 : Int) -- 0
#eval (12 : Int) % (-6 : Int) -- 0
#eval (-12 : Int) % (6 : Int) -- 0
#eval (-12 : Int) % (-6 : Int) -- 0
#eval (12 : Int) % (7 : Int) -- 5
#eval (12 : Int) % (-7 : Int) -- 5
#eval (-12 : Int) % (7 : Int) -- 2
#eval (-12 : Int) % (-7 : Int) -- 2
```
Implemented by efficient native code.
-/
@[extern "lean_int_emod"]
def emod : (@& Int) (@& Int) Int
| ofNat m, n => ofNat (m % natAbs n)
| -[m+1], n => subNatNat (natAbs n) (succ (m % natAbs n))
/--
The Div and Mod syntax uses ediv and emod for compatibility with SMTLIb and mathematical
reasoning tends to be easier.
-/
instance : Div Int where
div := Int.ediv
instance : Mod Int where
mod := Int.emod
@[simp, norm_cast] theorem ofNat_ediv (m n : Nat) : ((m / n) : Int) = m / n := rfl
theorem ofNat_tdiv (m n : Nat) : (m / n) = tdiv m n := rfl
theorem ofNat_fdiv : m n : Nat, (m / n) = fdiv m n
| 0, _ => by simp [fdiv]
| succ _, _ => rfl
/-!
# `bmod` ("balanced" mod)
Balanced mod (and balanced div) are a division and modulus pair such
that `b * (Int.bdiv a b) + Int.bmod a b = a` and `-b/2 ≤ Int.bmod a b <
b/2` for all `a : Int` and `b > 0`.
This is used in Omega as well as signed bitvectors.
-/
/--
Balanced modulus. This version of Integer modulus uses the
balanced rounding convention, which guarantees that
`-m/2 ≤ bmod x m < m/2` for `m ≠ 0` and `bmod x m` is congruent
to `x` modulo `m`.
If `m = 0`, then `bmod x m = x`.
Examples:
```
#eval (7 : Int).bdiv 0 -- 0
#eval (0 : Int).bdiv 7 -- 0
#eval (12 : Int).bdiv 6 -- 2
#eval (12 : Int).bdiv 7 -- 2
#eval (12 : Int).bdiv 8 -- 2
#eval (12 : Int).bdiv 9 -- 1
#eval (-12 : Int).bdiv 6 -- -2
#eval (-12 : Int).bdiv 7 -- -2
#eval (-12 : Int).bdiv 8 -- -1
#eval (-12 : Int).bdiv 9 -- -1
```
-/
def bmod (x : Int) (m : Nat) : Int :=
let r := x % m
if r < (m + 1) / 2 then
r
else
r - m
/--
Balanced division. This returns the unique integer so that
`b * (Int.bdiv a b) + Int.bmod a b = a`.
Examples:
```
#eval (7 : Int).bmod 0 -- 7
#eval (0 : Int).bmod 7 -- 0
#eval (12 : Int).bmod 6 -- 0
#eval (12 : Int).bmod 7 -- -2
#eval (12 : Int).bmod 8 -- -4
#eval (12 : Int).bmod 9 -- 3
#eval (-12 : Int).bmod 6 -- 0
#eval (-12 : Int).bmod 7 -- 2
#eval (-12 : Int).bmod 8 -- -4
#eval (-12 : Int).bmod 9 -- -3
```
-/
def bdiv (x : Int) (m : Nat) : Int :=
if m = 0 then
0
else
let q := x / m
let r := x % m
if r < (m + 1) / 2 then
q
else
q + 1
end Int
import Init.Data.Int.DivMod.Basic
import Init.Data.Int.DivMod.Bootstrap
import Init.Data.Int.DivMod.Lemmas

View File

@@ -0,0 +1,336 @@
/-
Copyright (c) 2016 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Mario Carneiro
-/
prelude
import Init.Data.Int.Basic
open Nat
namespace Int
/-! ## Quotient and remainder
There are three main conventions for integer division,
referred here as the E, F, T rounding conventions.
All three pairs satisfy the identity `x % y + (x / y) * y = x` unconditionally,
and satisfy `x / 0 = 0` and `x % 0 = x`.
### Historical notes
In early versions of Lean, the typeclasses provided by `/` and `%`
were defined in terms of `tdiv` and `tmod`, and these were named simply as `div` and `mod`.
However we decided it was better to use `ediv` and `emod`,
as they are consistent with the conventions used in SMTLib, and Mathlib,
and often mathematical reasoning is easier with these conventions.
At that time, we did not rename `div` and `mod` to `tdiv` and `tmod` (along with all their lemma).
In September 2024, we decided to do this rename (with deprecations in place),
and later we intend to rename `ediv` and `emod` to `div` and `mod`, as nearly all users will only
ever need to use these functions and their associated lemmas.
In December 2024, we removed `tdiv` and `tmod`, but have not yet renamed `ediv` and `emod`.
-/
/-! ### E-rounding division
This pair satisfies `0 ≤ mod x y < natAbs y` for `y ≠ 0`.
-/
/--
Integer division. This version of `Int.div` uses the E-rounding convention
(euclidean division), in which `Int.emod x y` satisfies `0 ≤ mod x y < natAbs y` for `y ≠ 0`
and `Int.ediv` is the unique function satisfying `emod x y + (ediv x y) * y = x`.
This is the function powering the `/` notation on integers.
Examples:
```
#eval (7 : Int) / (0 : Int) -- 0
#eval (0 : Int) / (7 : Int) -- 0
#eval (12 : Int) / (6 : Int) -- 2
#eval (12 : Int) / (-6 : Int) -- -2
#eval (-12 : Int) / (6 : Int) -- -2
#eval (-12 : Int) / (-6 : Int) -- 2
#eval (12 : Int) / (7 : Int) -- 1
#eval (12 : Int) / (-7 : Int) -- -1
#eval (-12 : Int) / (7 : Int) -- -2
#eval (-12 : Int) / (-7 : Int) -- 2
```
Implemented by efficient native code.
-/
@[extern "lean_int_ediv"]
def ediv : (@& Int) (@& Int) Int
| ofNat m, ofNat n => ofNat (m / n)
| ofNat m, -[n+1] => -ofNat (m / succ n)
| -[_+1], 0 => 0
| -[m+1], ofNat (succ n) => -[m / succ n +1]
| -[m+1], -[n+1] => ofNat (succ (m / succ n))
/--
Integer modulus. This version of `Int.mod` uses the E-rounding convention
(euclidean division), in which `Int.emod x y` satisfies `0 ≤ emod x y < natAbs y` for `y ≠ 0`
and `Int.ediv` is the unique function satisfying `emod x y + (ediv x y) * y = x`.
This is the function powering the `%` notation on integers.
Examples:
```
#eval (7 : Int) % (0 : Int) -- 7
#eval (0 : Int) % (7 : Int) -- 0
#eval (12 : Int) % (6 : Int) -- 0
#eval (12 : Int) % (-6 : Int) -- 0
#eval (-12 : Int) % (6 : Int) -- 0
#eval (-12 : Int) % (-6 : Int) -- 0
#eval (12 : Int) % (7 : Int) -- 5
#eval (12 : Int) % (-7 : Int) -- 5
#eval (-12 : Int) % (7 : Int) -- 2
#eval (-12 : Int) % (-7 : Int) -- 2
```
Implemented by efficient native code.
-/
@[extern "lean_int_emod"]
def emod : (@& Int) (@& Int) Int
| ofNat m, n => ofNat (m % natAbs n)
| -[m+1], n => subNatNat (natAbs n) (succ (m % natAbs n))
/--
The Div and Mod syntax uses ediv and emod for compatibility with SMTLIb and mathematical
reasoning tends to be easier.
-/
instance : Div Int where
div := Int.ediv
instance : Mod Int where
mod := Int.emod
@[simp, norm_cast] theorem ofNat_ediv (m n : Nat) : ((m / n) : Int) = m / n := rfl
theorem ofNat_ediv_ofNat {a b : Nat} : (a / b : Int) = (a / b : Nat) := rfl
@[norm_cast]
theorem negSucc_ediv_ofNat_succ {a b : Nat} : ((-[a+1]) / (b+1) : Int) = -[a / succ b +1] := rfl
theorem negSucc_ediv_negSucc {a b : Nat} : ((-[a+1]) / (-[b+1]) : Int) = ((a / (b + 1)) + 1 : Nat) := rfl
theorem ofNat_ediv_negSucc {a b : Nat} : (ofNat a / (-[b+1])) = -(a / (b + 1) : Nat) := rfl
theorem negSucc_emod_ofNat {a b : Nat} : -[a+1] % (b : Int) = subNatNat b (succ (a % b)) := rfl
theorem negSucc_emod_negSucc {a b : Nat} : -[a+1] % -[b+1] = subNatNat (b + 1) (succ (a % (b + 1))) := rfl
/-! ### T-rounding division -/
/--
`tdiv` uses the [*"T-rounding"*][t-rounding]
(**T**runcation-rounding) convention, meaning that it rounds toward
zero. Also note that division by zero is defined to equal zero.
The relation between integer division and modulo is found in
`Int.tmod_add_tdiv` which states that
`tmod a b + b * (tdiv a b) = a`, unconditionally.
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862
[theo tmod_add_tdiv]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.tmod_add_tdiv#doc
Examples:
```
#eval (7 : Int).tdiv (0 : Int) -- 0
#eval (0 : Int).tdiv (7 : Int) -- 0
#eval (12 : Int).tdiv (6 : Int) -- 2
#eval (12 : Int).tdiv (-6 : Int) -- -2
#eval (-12 : Int).tdiv (6 : Int) -- -2
#eval (-12 : Int).tdiv (-6 : Int) -- 2
#eval (12 : Int).tdiv (7 : Int) -- 1
#eval (12 : Int).tdiv (-7 : Int) -- -1
#eval (-12 : Int).tdiv (7 : Int) -- -1
#eval (-12 : Int).tdiv (-7 : Int) -- 1
```
Implemented by efficient native code.
-/
@[extern "lean_int_div"]
def tdiv : (@& Int) (@& Int) Int
| ofNat m, ofNat n => ofNat (m / n)
| ofNat m, -[n +1] => -ofNat (m / succ n)
| -[m +1], ofNat n => -ofNat (succ m / n)
| -[m +1], -[n +1] => ofNat (succ m / succ n)
/-- Integer modulo. This function uses the
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention
to pair with `Int.tdiv`, meaning that `tmod a b + b * (tdiv a b) = a`
unconditionally (see [`Int.tmod_add_tdiv`][theo tmod_add_tdiv]). In
particular, `a % 0 = a`.
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862
[theo tmod_add_tdiv]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.tmod_add_tdiv#doc
Examples:
```
#eval (7 : Int).tmod (0 : Int) -- 7
#eval (0 : Int).tmod (7 : Int) -- 0
#eval (12 : Int).tmod (6 : Int) -- 0
#eval (12 : Int).tmod (-6 : Int) -- 0
#eval (-12 : Int).tmod (6 : Int) -- 0
#eval (-12 : Int).tmod (-6 : Int) -- 0
#eval (12 : Int).tmod (7 : Int) -- 5
#eval (12 : Int).tmod (-7 : Int) -- 5
#eval (-12 : Int).tmod (7 : Int) -- -5
#eval (-12 : Int).tmod (-7 : Int) -- -5
```
Implemented by efficient native code. -/
@[extern "lean_int_mod"]
def tmod : (@& Int) (@& Int) Int
| ofNat m, ofNat n => ofNat (m % n)
| ofNat m, -[n +1] => ofNat (m % succ n)
| -[m +1], ofNat n => -ofNat (succ m % n)
| -[m +1], -[n +1] => -ofNat (succ m % succ n)
theorem ofNat_tdiv (m n : Nat) : (m / n) = tdiv m n := rfl
/-! ### F-rounding division
This pair satisfies `fdiv x y = floor (x / y)`.
-/
/--
Integer division. This version of division uses the F-rounding convention
(flooring division), in which `Int.fdiv x y` satisfies `fdiv x y = floor (x / y)`
and `Int.fmod` is the unique function satisfying `fmod x y + (fdiv x y) * y = x`.
Examples:
```
#eval (7 : Int).fdiv (0 : Int) -- 0
#eval (0 : Int).fdiv (7 : Int) -- 0
#eval (12 : Int).fdiv (6 : Int) -- 2
#eval (12 : Int).fdiv (-6 : Int) -- -2
#eval (-12 : Int).fdiv (6 : Int) -- -2
#eval (-12 : Int).fdiv (-6 : Int) -- 2
#eval (12 : Int).fdiv (7 : Int) -- 1
#eval (12 : Int).fdiv (-7 : Int) -- -2
#eval (-12 : Int).fdiv (7 : Int) -- -2
#eval (-12 : Int).fdiv (-7 : Int) -- 1
```
-/
def fdiv : Int Int Int
| 0, _ => 0
| ofNat m, ofNat n => ofNat (m / n)
| ofNat (succ m), -[n+1] => -[m / succ n +1]
| -[_+1], 0 => 0
| -[m+1], ofNat (succ n) => -[m / succ n +1]
| -[m+1], -[n+1] => ofNat (succ m / succ n)
/--
Integer modulus. This version of `Int.mod` uses the F-rounding convention
(flooring division), in which `Int.fdiv x y` satisfies `fdiv x y = floor (x / y)`
and `Int.fmod` is the unique function satisfying `fmod x y + (fdiv x y) * y = x`.
Examples:
```
#eval (7 : Int).fmod (0 : Int) -- 7
#eval (0 : Int).fmod (7 : Int) -- 0
#eval (12 : Int).fmod (6 : Int) -- 0
#eval (12 : Int).fmod (-6 : Int) -- 0
#eval (-12 : Int).fmod (6 : Int) -- 0
#eval (-12 : Int).fmod (-6 : Int) -- 0
#eval (12 : Int).fmod (7 : Int) -- 5
#eval (12 : Int).fmod (-7 : Int) -- -2
#eval (-12 : Int).fmod (7 : Int) -- 2
#eval (-12 : Int).fmod (-7 : Int) -- -5
```
-/
def fmod : Int Int Int
| 0, _ => 0
| ofNat m, ofNat n => ofNat (m % n)
| ofNat (succ m), -[n+1] => subNatNat (m % succ n) n
| -[m+1], ofNat n => subNatNat n (succ (m % n))
| -[m+1], -[n+1] => -ofNat (succ m % succ n)
theorem ofNat_fdiv : m n : Nat, (m / n) = fdiv m n
| 0, _ => by simp [fdiv]
| succ _, _ => rfl
/-!
# `bmod` ("balanced" mod)
Balanced mod (and balanced div) are a division and modulus pair such
that `b * (Int.bdiv a b) + Int.bmod a b = a` and
`-b/2 ≤ Int.bmod a b < b/2` for all `a : Int` and `b > 0`.
This is used in Omega as well as signed bitvectors.
-/
/--
Balanced modulus. This version of Integer modulus uses the
balanced rounding convention, which guarantees that
`-m/2 ≤ bmod x m < m/2` for `m ≠ 0` and `bmod x m` is congruent
to `x` modulo `m`.
If `m = 0`, then `bmod x m = x`.
Examples:
```
#eval (7 : Int).bdiv 0 -- 0
#eval (0 : Int).bdiv 7 -- 0
#eval (12 : Int).bdiv 6 -- 2
#eval (12 : Int).bdiv 7 -- 2
#eval (12 : Int).bdiv 8 -- 2
#eval (12 : Int).bdiv 9 -- 1
#eval (-12 : Int).bdiv 6 -- -2
#eval (-12 : Int).bdiv 7 -- -2
#eval (-12 : Int).bdiv 8 -- -1
#eval (-12 : Int).bdiv 9 -- -1
```
-/
def bmod (x : Int) (m : Nat) : Int :=
let r := x % m
if r < (m + 1) / 2 then
r
else
r - m
/--
Balanced division. This returns the unique integer so that
`b * (Int.bdiv a b) + Int.bmod a b = a`.
Examples:
```
#eval (7 : Int).bmod 0 -- 7
#eval (0 : Int).bmod 7 -- 0
#eval (12 : Int).bmod 6 -- 0
#eval (12 : Int).bmod 7 -- -2
#eval (12 : Int).bmod 8 -- -4
#eval (12 : Int).bmod 9 -- 3
#eval (-12 : Int).bmod 6 -- 0
#eval (-12 : Int).bmod 7 -- 2
#eval (-12 : Int).bmod 8 -- -4
#eval (-12 : Int).bmod 9 -- -3
```
-/
def bdiv (x : Int) (m : Nat) : Int :=
if m = 0 then
0
else
let q := x / m
let r := x % m
if r < (m + 1) / 2 then
q
else
q + 1
end Int

View File

@@ -0,0 +1,322 @@
/-
Copyright (c) 2016 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Mario Carneiro
-/
prelude
import Init.Data.Int.DivMod.Basic
import Init.Data.Int.Order
import Init.Data.Nat.Dvd
import Init.RCases
/-!
# Lemmas about integer division needed to bootstrap `omega`.
-/
open Nat (succ)
namespace Int
-- /-! ### dvd -/
protected theorem dvd_def (a b : Int) : (a b) = Exists (fun c => b = a * c) := rfl
@[simp] protected theorem dvd_zero (n : Int) : n 0 := 0, (Int.mul_zero _).symm
@[simp] protected theorem dvd_refl (n : Int) : n n := 1, (Int.mul_one _).symm
@[simp] protected theorem one_dvd (n : Int) : 1 n := n, (Int.one_mul n).symm
protected theorem dvd_trans : {a b c : Int}, a b b c a c
| _, _, _, d, rfl, e, rfl => Exists.intro (d * e) (by rw [Int.mul_assoc])
@[norm_cast] theorem ofNat_dvd {m n : Nat} : (m : Int) n m n := by
refine fun a, ae => ?_, fun k, e => k, by rw [e, Int.ofNat_mul]
match Int.le_total a 0 with
| .inl h =>
have := ae.symm Int.mul_nonpos_of_nonneg_of_nonpos (ofNat_zero_le _) h
rw [Nat.le_antisymm (ofNat_le.1 this) (Nat.zero_le _)]
apply Nat.dvd_zero
| .inr h => match a, eq_ofNat_of_zero_le h with
| _, k, rfl => exact k, Int.ofNat.inj ae
@[simp] protected theorem zero_dvd {n : Int} : 0 n n = 0 :=
Iff.intro (fun k, e => by rw [e, Int.zero_mul])
(fun h => h.symm Int.dvd_refl _)
protected theorem dvd_mul_right (a b : Int) : a a * b := _, rfl
protected theorem dvd_mul_left (a b : Int) : b a * b := _, Int.mul_comm ..
@[simp] protected theorem neg_dvd {a b : Int} : -a b a b := by
constructor <;> exact fun k, e =>
-k, by simp [e, Int.neg_mul, Int.mul_neg, Int.neg_neg]
protected theorem dvd_neg {a b : Int} : a -b a b := by
constructor <;> exact fun k, e =>
-k, by simp [ e, Int.neg_mul, Int.mul_neg, Int.neg_neg]
@[simp] theorem natAbs_dvd_natAbs {a b : Int} : natAbs a natAbs b a b := by
refine fun k, hk => ?_, fun k, hk => natAbs k, hk.symm natAbs_mul a k
rw [ natAbs_ofNat k, natAbs_mul, natAbs_eq_natAbs_iff] at hk
cases hk <;> subst b
· apply Int.dvd_mul_right
· rw [ Int.mul_neg]; apply Int.dvd_mul_right
theorem ofNat_dvd_left {n : Nat} {z : Int} : (n : Int) z n z.natAbs := by
rw [ natAbs_dvd_natAbs, natAbs_ofNat]
/-! ### *div zero -/
@[simp] theorem zero_ediv : b : Int, 0 / b = 0
| ofNat _ => show ofNat _ = _ by simp
| -[_+1] => show -ofNat _ = _ by simp
@[simp] protected theorem ediv_zero : a : Int, a / 0 = 0
| ofNat _ => show ofNat _ = _ by simp
| -[_+1] => rfl
/-! ### mod zero -/
@[simp] theorem zero_emod (b : Int) : 0 % b = 0 := rfl
@[simp] theorem emod_zero : a : Int, a % 0 = a
| ofNat _ => congrArg ofNat <| Nat.mod_zero _
| -[_+1] => congrArg negSucc <| Nat.mod_zero _
/-! ### ofNat mod -/
@[simp, norm_cast] theorem ofNat_emod (m n : Nat) : ((m % n) : Int) = m % n := rfl
/-! ### mod definitions -/
theorem emod_add_ediv : a b : Int, a % b + b * (a / b) = a
| ofNat _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..
| ofNat m, -[n+1] => by
show (m % succ n + -(succ n) * -(m / succ n) : Int) = m
rw [Int.neg_mul_neg]; exact congrArg ofNat <| Nat.mod_add_div ..
| -[_+1], 0 => by rw [emod_zero]; rfl
| -[m+1], succ n => aux m n.succ
| -[m+1], -[n+1] => aux m n.succ
where
aux (m n : Nat) : n - (m % n + 1) - (n * (m / n) + n) = -[m+1] := by
rw [ ofNat_emod, ofNat_ediv, Int.sub_sub, negSucc_eq, Int.sub_sub n,
Int.neg_neg (_-_), Int.neg_sub, Int.sub_sub_self, Int.add_right_comm]
exact congrArg (fun x => -(ofNat x + 1)) (Nat.mod_add_div ..)
theorem emod_add_ediv' (a b : Int) : a % b + a / b * b = a := by
rw [Int.mul_comm]; exact emod_add_ediv ..
theorem ediv_add_emod (a b : Int) : b * (a / b) + a % b = a := by
rw [Int.add_comm]; exact emod_add_ediv ..
theorem emod_def (a b : Int) : a % b = a - b * (a / b) := by
rw [ Int.add_sub_cancel (a % b), emod_add_ediv]
/-! ### `/` ediv -/
@[simp] protected theorem ediv_neg : a b : Int, a / (-b) = -(a / b)
| ofNat m, 0 => show ofNat (m / 0) = -(m / 0) by rw [Nat.div_zero]; rfl
| ofNat _, -[_+1] => (Int.neg_neg _).symm
| ofNat _, succ _ | -[_+1], 0 | -[_+1], succ _ | -[_+1], -[_+1] => rfl
protected theorem div_def (a b : Int) : a / b = Int.ediv a b := rfl
theorem add_mul_ediv_right (a b : Int) {c : Int} (H : c 0) : (a + b * c) / c = a / c + b :=
suffices {{a b c : Int}}, 0 < c (a + b * c).ediv c = a.ediv c + b from
match Int.lt_trichotomy c 0 with
| Or.inl hlt => by
rw [ Int.neg_inj, Int.ediv_neg, Int.neg_add, Int.ediv_neg, Int.neg_mul_neg]
exact this (Int.neg_pos_of_neg hlt)
| Or.inr (Or.inl HEq) => absurd HEq H
| Or.inr (Or.inr hgt) => this hgt
suffices {k n : Nat} {a : Int}, (a + n * k.succ).ediv k.succ = a.ediv k.succ + n from
fun a b c H => match c, eq_succ_of_zero_lt H, b with
| _, _, rfl, ofNat _ => this
| _, k, rfl, -[n+1] => show (a - n.succ * k.succ).ediv k.succ = a.ediv k.succ - n.succ by
rw [ Int.add_sub_cancel (ediv ..), this, Int.sub_add_cancel]
fun {k n} => @fun
| ofNat _ => congrArg ofNat <| Nat.add_mul_div_right _ _ k.succ_pos
| -[m+1] => by
show ((n * k.succ : Nat) - m.succ : Int).ediv k.succ = n - (m / k.succ + 1 : Nat)
by_cases h : m < n * k.succ
· rw [ Int.ofNat_sub h, Int.ofNat_sub ((Nat.div_lt_iff_lt_mul k.succ_pos).2 h)]
apply congrArg ofNat
rw [Nat.mul_comm, Nat.mul_sub_div]; rwa [Nat.mul_comm]
· have h := Nat.not_lt.1 h
have H {a b : Nat} (h : a b) : (a : Int) + -((b : Int) + 1) = -[b - a +1] := by
rw [negSucc_eq, Int.ofNat_sub h]
simp only [Int.sub_eq_add_neg, Int.neg_add, Int.neg_neg, Int.add_left_comm, Int.add_assoc]
show ediv ((n * succ k) + -((m : Int) + 1)) (succ k) = n + -((m / succ k) + 1 : Int)
rw [H h, H ((Nat.le_div_iff_mul_le k.succ_pos).2 h)]
apply congrArg negSucc
rw [Nat.mul_comm, Nat.sub_mul_div]; rwa [Nat.mul_comm]
theorem add_ediv_of_dvd_right {a b c : Int} (H : c b) : (a + b) / c = a / c + b / c :=
if h : c = 0 then by simp [h] else by
let k, hk := H
rw [hk, Int.mul_comm c k, Int.add_mul_ediv_right _ _ h,
Int.zero_add (k * c), Int.add_mul_ediv_right _ _ h, Int.zero_ediv, Int.zero_add]
theorem add_ediv_of_dvd_left {a b c : Int} (H : c a) : (a + b) / c = a / c + b / c := by
rw [Int.add_comm, Int.add_ediv_of_dvd_right H, Int.add_comm]
@[simp] theorem mul_ediv_cancel (a : Int) {b : Int} (H : b 0) : (a * b) / b = a := by
have := Int.add_mul_ediv_right 0 a H
rwa [Int.zero_add, Int.zero_ediv, Int.zero_add] at this
@[simp] theorem mul_ediv_cancel_left (b : Int) (H : a 0) : (a * b) / a = b :=
Int.mul_comm .. Int.mul_ediv_cancel _ H
theorem div_nonneg_iff_of_pos {a b : Int} (h : 0 < b) : a / b 0 a 0 := by
rw [Int.div_def]
match b, h with
| Int.ofNat (b+1), _ =>
rcases a with a <;> simp [Int.ediv]
norm_cast
simp
/-! ### emod -/
theorem emod_nonneg : (a : Int) {b : Int}, b 0 0 a % b
| ofNat _, _, _ => ofNat_zero_le _
| -[_+1], _, H => Int.sub_nonneg_of_le <| ofNat_le.2 <| Nat.mod_lt _ (natAbs_pos.2 H)
theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < b :=
match a, b, eq_succ_of_zero_lt H with
| ofNat _, _, _, rfl => ofNat_lt.2 (Nat.mod_lt _ (Nat.succ_pos _))
| -[_+1], _, _, rfl => Int.sub_lt_self _ (ofNat_lt.2 <| Nat.succ_pos _)
theorem mul_ediv_self_le {x k : Int} (h : k 0) : k * (x / k) x :=
calc k * (x / k)
_ k * (x / k) + x % k := Int.le_add_of_nonneg_right (emod_nonneg x h)
_ = x := ediv_add_emod _ _
theorem lt_mul_ediv_self_add {x k : Int} (h : 0 < k) : x < k * (x / k) + k :=
calc x
_ = k * (x / k) + x % k := (ediv_add_emod _ _).symm
_ < k * (x / k) + k := Int.add_lt_add_left (emod_lt_of_pos x h) _
@[simp] theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
if cz : c = 0 then by
rw [cz, Int.mul_zero, Int.add_zero]
else by
rw [Int.emod_def, Int.emod_def, Int.add_mul_ediv_right _ _ cz, Int.add_comm _ b,
Int.mul_add, Int.mul_comm, Int.sub_sub, Int.add_sub_cancel]
@[simp] theorem add_mul_emod_self_left (a b c : Int) : (a + b * c) % b = a % b := by
rw [Int.mul_comm, Int.add_mul_emod_self]
@[simp] theorem emod_add_emod (m n k : Int) : (m % n + k) % n = (m + k) % n := by
have := (add_mul_emod_self_left (m % n + k) n (m / n)).symm
rwa [Int.add_right_comm, emod_add_ediv] at this
@[simp] theorem add_emod_emod (m n k : Int) : (m + n % k) % k = (m + n) % k := by
rw [Int.add_comm, emod_add_emod, Int.add_comm]
theorem add_emod (a b n : Int) : (a + b) % n = (a % n + b % n) % n := by
rw [add_emod_emod, emod_add_emod]
theorem add_emod_eq_add_emod_right {m n k : Int} (i : Int)
(H : m % n = k % n) : (m + i) % n = (k + i) % n := by
rw [ emod_add_emod, emod_add_emod k, H]
theorem emod_add_cancel_right {m n k : Int} (i) : (m + i) % n = (k + i) % n m % n = k % n :=
fun H => by
have := add_emod_eq_add_emod_right (-i) H
rwa [Int.add_neg_cancel_right, Int.add_neg_cancel_right] at this,
add_emod_eq_add_emod_right _
@[simp] theorem mul_emod_left (a b : Int) : (a * b) % b = 0 := by
rw [ Int.zero_add (a * b), Int.add_mul_emod_self, Int.zero_emod]
@[simp] theorem mul_emod_right (a b : Int) : (a * b) % a = 0 := by
rw [Int.mul_comm, mul_emod_left]
theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
conv => lhs; rw [
emod_add_ediv a n, emod_add_ediv' b n, Int.add_mul, Int.mul_add, Int.mul_add,
Int.mul_assoc, Int.mul_assoc, Int.mul_add n _ _, add_mul_emod_self_left,
Int.mul_assoc, add_mul_emod_self]
@[simp] theorem emod_self {a : Int} : a % a = 0 := by
have := mul_emod_left 1 a; rwa [Int.one_mul] at this
@[simp] theorem emod_emod_of_dvd (n : Int) {m k : Int}
(h : m k) : (n % k) % m = n % m := by
conv => rhs; rw [ emod_add_ediv n k]
match k, h with
| _, t, rfl => rw [Int.mul_assoc, add_mul_emod_self_left]
@[simp] theorem emod_emod (a b : Int) : (a % b) % b = a % b := by
conv => rhs; rw [ emod_add_ediv a b, add_mul_emod_self_left]
theorem sub_emod (a b n : Int) : (a - b) % n = (a % n - b % n) % n := by
apply (emod_add_cancel_right b).mp
rw [Int.sub_add_cancel, Int.add_emod_emod, Int.sub_add_cancel, emod_emod]
/-! ### properties of `/` and `%` -/
theorem mul_ediv_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : b * (a / b) = a := by
have := emod_add_ediv a b; rwa [H, Int.zero_add] at this
theorem ediv_mul_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : a / b * b = a := by
rw [Int.mul_comm, mul_ediv_cancel_of_emod_eq_zero H]
theorem dvd_of_emod_eq_zero {a b : Int} (H : b % a = 0) : a b :=
b / a, (mul_ediv_cancel_of_emod_eq_zero H).symm
theorem emod_eq_zero_of_dvd : {a b : Int}, a b b % a = 0
| _, _, _, rfl => mul_emod_right ..
theorem dvd_iff_emod_eq_zero {a b : Int} : a b b % a = 0 :=
emod_eq_zero_of_dvd, dvd_of_emod_eq_zero
protected theorem mul_ediv_assoc (a : Int) : {b c : Int}, c b (a * b) / c = a * (b / c)
| _, c, d, rfl =>
if cz : c = 0 then by simp [cz, Int.mul_zero] else by
rw [Int.mul_left_comm, Int.mul_ediv_cancel_left _ cz, Int.mul_ediv_cancel_left _ cz]
protected theorem mul_ediv_assoc' (b : Int) {a c : Int}
(h : c a) : (a * b) / c = a / c * b := by
rw [Int.mul_comm, Int.mul_ediv_assoc _ h, Int.mul_comm]
theorem neg_ediv_of_dvd : {a b : Int}, b a (-a) / b = -(a / b)
| _, b, c, rfl => by
by_cases bz : b = 0
· simp [bz]
· rw [Int.neg_mul_eq_mul_neg, Int.mul_ediv_cancel_left _ bz, Int.mul_ediv_cancel_left _ bz]
theorem sub_ediv_of_dvd (a : Int) {b c : Int}
(hcb : c b) : (a - b) / c = a / c - b / c := by
rw [Int.sub_eq_add_neg, Int.sub_eq_add_neg, Int.add_ediv_of_dvd_right (Int.dvd_neg.2 hcb)]
congr; exact Int.neg_ediv_of_dvd hcb
protected theorem ediv_mul_cancel {a b : Int} (H : b a) : a / b * b = a :=
ediv_mul_cancel_of_emod_eq_zero (emod_eq_zero_of_dvd H)
protected theorem mul_ediv_cancel' {a b : Int} (H : a b) : a * (b / a) = b := by
rw [Int.mul_comm, Int.ediv_mul_cancel H]
theorem emod_pos_of_not_dvd {a b : Int} (h : ¬ a b) : a = 0 0 < b % a := by
rw [dvd_iff_emod_eq_zero] at h
by_cases w : a = 0
· simp_all
· exact Or.inr (Int.lt_iff_le_and_ne.mpr emod_nonneg b w, Ne.symm h)
/-! ### bmod -/
@[simp] theorem bmod_emod : bmod x m % m = x % m := by
dsimp [bmod]
split <;> simp [Int.sub_emod]
theorem bmod_def (x : Int) (m : Nat) : bmod x m =
if (x % m) < (m + 1) / 2 then
x % m
else
(x % m) - m :=
rfl
end Int

View File

@@ -5,13 +5,16 @@ Authors: Jeremy Avigad, Mario Carneiro
-/
prelude
import Init.Data.Int.DivMod
import Init.Data.Int.DivMod.Bootstrap
import Init.Data.Nat.Lemmas
import Init.Data.Nat.Div.Lemmas
import Init.Data.Int.Order
import Init.Data.Int.Lemmas
import Init.Data.Nat.Dvd
import Init.RCases
/-!
# Lemmas about integer division needed to bootstrap `omega`.
# Further lemmas about integer division, now that `omega` is available.
-/
open Nat (succ)
@@ -20,58 +23,11 @@ namespace Int
/-! ### dvd -/
protected theorem dvd_def (a b : Int) : (a b) = Exists (fun c => b = a * c) := rfl
@[simp] protected theorem dvd_zero (n : Int) : n 0 := 0, (Int.mul_zero _).symm
@[simp] protected theorem dvd_refl (n : Int) : n n := 1, (Int.mul_one _).symm
@[simp] protected theorem one_dvd (n : Int) : 1 n := n, (Int.one_mul n).symm
protected theorem dvd_trans : {a b c : Int}, a b b c a c
| _, _, _, d, rfl, e, rfl => Exists.intro (d * e) (by rw [Int.mul_assoc])
@[norm_cast] theorem ofNat_dvd {m n : Nat} : (m : Int) n m n := by
refine fun a, ae => ?_, fun k, e => k, by rw [e, Int.ofNat_mul]
match Int.le_total a 0 with
| .inl h =>
have := ae.symm Int.mul_nonpos_of_nonneg_of_nonpos (ofNat_zero_le _) h
rw [Nat.le_antisymm (ofNat_le.1 this) (Nat.zero_le _)]
apply Nat.dvd_zero
| .inr h => match a, eq_ofNat_of_zero_le h with
| _, k, rfl => exact k, Int.ofNat.inj ae
theorem dvd_antisymm {a b : Int} (H1 : 0 a) (H2 : 0 b) : a b b a a = b := by
rw [ natAbs_of_nonneg H1, natAbs_of_nonneg H2]
rw [ofNat_dvd, ofNat_dvd, ofNat_inj]
apply Nat.dvd_antisymm
@[simp] protected theorem zero_dvd {n : Int} : 0 n n = 0 :=
Iff.intro (fun k, e => by rw [e, Int.zero_mul])
(fun h => h.symm Int.dvd_refl _)
protected theorem dvd_mul_right (a b : Int) : a a * b := _, rfl
protected theorem dvd_mul_left (a b : Int) : b a * b := _, Int.mul_comm ..
@[simp] protected theorem neg_dvd {a b : Int} : -a b a b := by
constructor <;> exact fun k, e =>
-k, by simp [e, Int.neg_mul, Int.mul_neg, Int.neg_neg]
protected theorem dvd_neg {a b : Int} : a -b a b := by
constructor <;> exact fun k, e =>
-k, by simp [ e, Int.neg_mul, Int.mul_neg, Int.neg_neg]
@[simp] theorem natAbs_dvd_natAbs {a b : Int} : natAbs a natAbs b a b := by
refine fun k, hk => ?_, fun k, hk => natAbs k, hk.symm natAbs_mul a k
rw [ natAbs_ofNat k, natAbs_mul, natAbs_eq_natAbs_iff] at hk
cases hk <;> subst b
· apply Int.dvd_mul_right
· rw [ Int.mul_neg]; apply Int.dvd_mul_right
theorem ofNat_dvd_left {n : Nat} {z : Int} : (n : Int) z n z.natAbs := by
rw [ natAbs_dvd_natAbs, natAbs_ofNat]
protected theorem dvd_add : {a b c : Int}, a b a c a b + c
| _, _, _, d, rfl, e, rfl => d + e, by rw [Int.mul_add]
@@ -117,6 +73,14 @@ theorem dvd_natAbs_self {a : Int} : a (a.natAbs : Int) := by
theorem ofNat_dvd_right {n : Nat} {z : Int} : z (n : Int) z.natAbs n := by
rw [ natAbs_dvd_natAbs, natAbs_ofNat]
@[simp] theorem negSucc_dvd {a : Nat} {b : Int} : -[a+1] b ((a + 1 : Nat) : Int) b := by
rw [ natAbs_dvd]
norm_cast
@[simp] theorem dvd_negSucc {a : Int} {b : Nat} : a -[b+1] a ((b + 1 : Nat) : Int) := by
rw [ dvd_natAbs]
norm_cast
theorem eq_one_of_dvd_one {a : Int} (H : 0 a) (H' : a 1) : a = 1 :=
match a, eq_ofNat_of_zero_le H, H' with
| _, _, rfl, H' => congrArg ofNat <| Nat.eq_one_of_dvd_one <| ofNat_dvd.1 H'
@@ -127,16 +91,11 @@ theorem eq_one_of_mul_eq_one_right {a b : Int} (H : 0 ≤ a) (H' : a * b = 1) :
theorem eq_one_of_mul_eq_one_left {a b : Int} (H : 0 b) (H' : a * b = 1) : b = 1 :=
eq_one_of_mul_eq_one_right (b := a) H <| by rw [Int.mul_comm, H']
instance decidableDvd : DecidableRel (α := Int) (· ·) := fun _ _ =>
decidable_of_decidable_of_iff (dvd_iff_emod_eq_zero ..).symm
/-! ### *div zero -/
@[simp] theorem zero_ediv : b : Int, 0 / b = 0
| ofNat _ => show ofNat _ = _ by simp
| -[_+1] => show -ofNat _ = _ by simp
@[simp] protected theorem ediv_zero : a : Int, a / 0 = 0
| ofNat _ => show ofNat _ = _ by simp
| -[_+1] => rfl
@[simp] protected theorem zero_tdiv : b : Int, tdiv 0 b = 0
| ofNat _ => show ofNat _ = _ by simp
| -[_+1] => show -ofNat _ = _ by simp
@@ -154,28 +113,129 @@ unseal Nat.div in
| succ _ => rfl
| -[_+1] => rfl
/-! ### preliminaries for div equivalences -/
theorem negSucc_emod_ofNat_succ_eq_zero_iff {a b : Nat} :
-[a+1] % (b + 1 : Int) = 0 (a + 1) % (b + 1) = 0 := by
rw [ natCast_one, natCast_add]
change Int.emod _ _ = 0 _
rw [emod, natAbs_ofNat]
simp only [Nat.succ_eq_add_one, subNat_eq_zero_iff, Nat.add_right_cancel_iff]
rw [eq_comm]
apply Nat.succ_mod_succ_eq_zero_iff.symm
theorem negSucc_emod_negSucc_eq_zero_iff {a b : Nat} :
-[a+1] % -[b+1] = 0 (a + 1) % (b + 1) = 0 := by
change Int.emod _ _ = 0 _
rw [emod, natAbs_negSucc]
simp only [Nat.succ_eq_add_one, subNat_eq_zero_iff, Nat.add_right_cancel_iff]
rw [eq_comm]
apply Nat.succ_mod_succ_eq_zero_iff.symm
/-! ### div equivalences -/
theorem tdiv_eq_ediv : {a b : Int}, 0 a 0 b a.tdiv b = a / b
| 0, _, _, _ | _, 0, _, _ => by simp
| succ _, succ _, _, _ => rfl
theorem tdiv_eq_ediv_of_nonneg : {a b : Int}, 0 a a.tdiv b = a / b
| 0, _, _
| _, 0, _ => by simp
| succ _, succ _, _ => rfl
| succ _, -[_+1], _ => rfl
theorem tdiv_eq_ediv {a b : Int} :
a.tdiv b = a / b + if 0 a b a then 0 else sign b := by
simp only [dvd_iff_emod_eq_zero]
match a, b with
| ofNat a, ofNat b => simp [tdiv_eq_ediv_of_nonneg]
| ofNat a, -[b+1] => simp [tdiv_eq_ediv_of_nonneg]
| -[a+1], 0 => simp
| -[a+1], ofNat (succ b) =>
simp only [tdiv, Nat.succ_eq_add_one, ofNat_eq_coe, natCast_add, Nat.cast_ofNat_Int,
negSucc_not_nonneg, sign_of_add_one]
simp only [negSucc_emod_ofNat_succ_eq_zero_iff]
norm_cast
simp only [subNat_eq_zero_iff, Nat.succ_eq_add_one, sign_negSucc, Int.sub_neg, false_or]
split <;> rename_i h
· rw [Int.add_zero, neg_ofNat_eq_negSucc_iff]
exact Nat.succ_div_of_mod_eq_zero h
· rw [neg_ofNat_eq_negSucc_add_one_iff]
exact Nat.succ_div_of_mod_ne_zero h
| -[a+1], -[b+1] =>
simp only [tdiv, ofNat_eq_coe, negSucc_not_nonneg, false_or, sign_negSucc]
norm_cast
simp only [negSucc_ediv_negSucc]
rw [natCast_add, natCast_one]
simp only [negSucc_emod_negSucc_eq_zero_iff]
split <;> rename_i h
· norm_cast
exact Nat.succ_div_of_mod_eq_zero h
· rw [ Int.sub_eq_add_neg, Int.add_sub_cancel]
norm_cast
exact Nat.succ_div_of_mod_ne_zero h
theorem fdiv_eq_ediv : (a : Int) {b : Int}, 0 b fdiv a b = a / b
theorem ediv_eq_tdiv {a b : Int} :
a / b = a.tdiv b - if 0 a b a then 0 else sign b := by
simp [tdiv_eq_ediv]
theorem fdiv_eq_ediv_of_nonneg : (a : Int) {b : Int}, 0 b fdiv a b = a / b
| 0, _, _ | -[_+1], 0, _ => by simp
| succ _, ofNat _, _ | -[_+1], succ _, _ => rfl
theorem fdiv_eq_tdiv {a b : Int} (Ha : 0 a) (Hb : 0 b) : fdiv a b = tdiv a b :=
tdiv_eq_ediv Ha Hb fdiv_eq_ediv _ Hb
theorem fdiv_eq_ediv {a b : Int} :
a.fdiv b = a / b - if 0 b b a then 0 else 1 := by
match a, b with
| ofNat a, ofNat b => simp [fdiv_eq_ediv_of_nonneg]
| -[a+1], ofNat b => simp [fdiv_eq_ediv_of_nonneg]
| 0, -[b+1] => simp
| ofNat (a + 1), -[b+1] =>
simp only [fdiv, ofNat_ediv_negSucc, negSucc_not_nonneg, negSucc_dvd, false_or]
simp only [ofNat_eq_coe, ofNat_dvd]
norm_cast
rw [Nat.succ_div, negSucc_eq]
split <;> rename_i h
· simp
· simp [Int.neg_add]
norm_cast
| -[a+1], -[b+1] =>
simp only [fdiv, ofNat_eq_coe, negSucc_ediv_negSucc, negSucc_not_nonneg, dvd_negSucc, negSucc_dvd,
false_or]
norm_cast
rw [natCast_add, natCast_one, Nat.succ_div]
split <;> simp
theorem ediv_eq_fdiv {a b : Int} :
a / b = a.fdiv b + if 0 b b a then 0 else 1 := by
simp [fdiv_eq_ediv]
theorem fdiv_eq_tdiv_of_nonneg {a b : Int} (Ha : 0 a) (Hb : 0 b) : fdiv a b = tdiv a b :=
tdiv_eq_ediv_of_nonneg Ha fdiv_eq_ediv_of_nonneg _ Hb
theorem fdiv_eq_tdiv {a b : Int} :
a.fdiv b = a.tdiv b -
if b a then 0
else
if 0 a then
if 0 b then 0
else 1
else
if 0 b then b.sign
else 1 + b.sign := by
rw [fdiv_eq_ediv, tdiv_eq_ediv]
by_cases h : b a <;> simp [h] <;> omega
theorem tdiv_eq_fdiv {a b : Int} :
a.tdiv b = a.fdiv b +
if b a then 0
else
if 0 a then
if 0 b then 0
else 1
else
if 0 b then b.sign
else 1 + b.sign := by
rw [fdiv_eq_tdiv]
omega
/-! ### mod zero -/
@[simp] theorem zero_emod (b : Int) : 0 % b = 0 := rfl
@[simp] theorem emod_zero : a : Int, a % 0 = a
| ofNat _ => congrArg ofNat <| Nat.mod_zero _
| -[_+1] => congrArg negSucc <| Nat.mod_zero _
@[simp] theorem zero_tmod (b : Int) : tmod 0 b = 0 := by cases b <;> simp [tmod]
@[simp] theorem tmod_zero : a : Int, tmod a 0 = a
@@ -189,39 +249,11 @@ theorem fdiv_eq_tdiv {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : fdiv a b = tdiv
| succ _ => congrArg ofNat <| Nat.mod_zero _
| -[_+1] => congrArg negSucc <| Nat.mod_zero _
/-! ### ofNat mod -/
@[simp, norm_cast] theorem ofNat_emod (m n : Nat) : ((m % n) : Int) = m % n := rfl
/-! ### mod definitions -/
theorem emod_add_ediv : a b : Int, a % b + b * (a / b) = a
| ofNat _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..
| ofNat m, -[n+1] => by
show (m % succ n + -(succ n) * -(m / succ n) : Int) = m
rw [Int.neg_mul_neg]; exact congrArg ofNat <| Nat.mod_add_div ..
| -[_+1], 0 => by rw [emod_zero]; rfl
| -[m+1], succ n => aux m n.succ
| -[m+1], -[n+1] => aux m n.succ
where
aux (m n : Nat) : n - (m % n + 1) - (n * (m / n) + n) = -[m+1] := by
rw [ ofNat_emod, ofNat_ediv, Int.sub_sub, negSucc_eq, Int.sub_sub n,
Int.neg_neg (_-_), Int.neg_sub, Int.sub_sub_self, Int.add_right_comm]
exact congrArg (fun x => -(ofNat x + 1)) (Nat.mod_add_div ..)
theorem emod_add_ediv' (a b : Int) : a % b + a / b * b = a := by
rw [Int.mul_comm]; exact emod_add_ediv ..
theorem ediv_add_emod (a b : Int) : b * (a / b) + a % b = a := by
rw [Int.add_comm]; exact emod_add_ediv ..
theorem ediv_add_emod' (a b : Int) : a / b * b + a % b = a := by
rw [Int.mul_comm]; exact ediv_add_emod ..
theorem emod_def (a b : Int) : a % b = a - b * (a / b) := by
rw [ Int.add_sub_cancel (a % b), emod_add_ediv]
theorem tmod_add_tdiv : a b : Int, tmod a b + b * (a.tdiv b) = a
| ofNat _, ofNat _ => congrArg ofNat (Nat.mod_add_div ..)
| ofNat m, -[n+1] => by
@@ -276,28 +308,70 @@ theorem fmod_def (a b : Int) : a.fmod b = a - b * a.fdiv b := by
/-! ### mod equivalences -/
theorem fmod_eq_emod (a : Int) {b : Int} (hb : 0 b) : fmod a b = a % b := by
simp [fmod_def, emod_def, fdiv_eq_ediv _ hb]
theorem fmod_eq_emod_of_nonneg (a : Int) {b : Int} (hb : 0 b) : fmod a b = a % b := by
simp [fmod_def, emod_def, fdiv_eq_ediv_of_nonneg _ hb]
theorem tmod_eq_emod {a b : Int} (ha : 0 a) (hb : 0 b) : tmod a b = a % b := by
simp [emod_def, tmod_def, tdiv_eq_ediv ha hb]
theorem fmod_eq_emod {a b : Int} :
fmod a b = a % b + if 0 b b a then 0 else b := by
simp [fmod_def, emod_def, fdiv_eq_ediv]
split <;> simp [Int.mul_sub]
omega
theorem fmod_eq_tmod {a b : Int} (Ha : 0 a) (Hb : 0 b) : fmod a b = tmod a b :=
tmod_eq_emod Ha Hb fmod_eq_emod _ Hb
theorem emod_eq_fmod {a b : Int} :
a % b = fmod a b - if 0 b b a then 0 else b := by
simp [fmod_eq_emod]
theorem tmod_eq_emod_of_nonneg {a b : Int} (ha : 0 a) : tmod a b = a % b := by
simp [emod_def, tmod_def, tdiv_eq_ediv_of_nonneg ha]
theorem tmod_eq_emod {a b : Int} :
tmod a b = a % b - if 0 a b a then 0 else b.natAbs := by
rw [tmod_def, tdiv_eq_ediv]
simp only [dvd_iff_emod_eq_zero]
split
· simp [emod_def]
· rw [Int.mul_add, Int.sub_sub, emod_def]
simp
theorem emod_eq_tmod {a b : Int} :
a % b = tmod a b + if 0 a b a then 0 else b.natAbs := by
simp [tmod_eq_emod]
theorem fmod_eq_tmod_of_nonneg {a b : Int} (ha : 0 a) (hb : 0 b) : fmod a b = tmod a b :=
tmod_eq_emod_of_nonneg ha fmod_eq_emod_of_nonneg _ hb
theorem fmod_eq_tmod {a b : Int} :
fmod a b = tmod a b +
if b a then 0
else
if 0 a then
if 0 b then 0
else b
else
if 0 b then b.natAbs
else 2 * b.toNat := by
simp [fmod_eq_emod, tmod_eq_emod]
by_cases h : b a <;> simp [h]
split <;> split <;> omega
theorem tmod_eq_fmod {a b : Int} :
tmod a b = fmod a b -
if b a then 0
else
if 0 a then
if 0 b then 0
else b
else
if 0 b then b.natAbs
else 2 * b.toNat := by
simp [fmod_eq_tmod]
/-! ### `/` ediv -/
@[simp] protected theorem ediv_neg : a b : Int, a / (-b) = -(a / b)
| ofNat m, 0 => show ofNat (m / 0) = -(m / 0) by rw [Nat.div_zero]; rfl
| ofNat _, -[_+1] => (Int.neg_neg _).symm
| ofNat _, succ _ | -[_+1], 0 | -[_+1], succ _ | -[_+1], -[_+1] => rfl
theorem ediv_neg' {a b : Int} (Ha : a < 0) (Hb : 0 < b) : a / b < 0 :=
match a, b, eq_negSucc_of_lt_zero Ha, eq_succ_of_zero_lt Hb with
| _, _, _, rfl, _, rfl => negSucc_lt_zero _
protected theorem div_def (a b : Int) : a / b = Int.ediv a b := rfl
theorem negSucc_ediv (m : Nat) {b : Int} (H : 0 < b) : -[m+1] / b = -(ediv m b + 1) :=
match b, eq_succ_of_zero_lt H with
| _, _, rfl => rfl
@@ -325,60 +399,6 @@ theorem ediv_nonneg_of_nonpos_of_nonpos {a b : Int} (Ha : a ≤ 0) (Hb : b ≤ 0
theorem ediv_nonpos {a b : Int} (Ha : 0 a) (Hb : b 0) : a / b 0 :=
Int.nonpos_of_neg_nonneg <| Int.ediv_neg .. Int.ediv_nonneg Ha (Int.neg_nonneg_of_nonpos Hb)
theorem add_mul_ediv_right (a b : Int) {c : Int} (H : c 0) : (a + b * c) / c = a / c + b :=
suffices {{a b c : Int}}, 0 < c (a + b * c).ediv c = a.ediv c + b from
match Int.lt_trichotomy c 0 with
| Or.inl hlt => by
rw [ Int.neg_inj, Int.ediv_neg, Int.neg_add, Int.ediv_neg, Int.neg_mul_neg]
exact this (Int.neg_pos_of_neg hlt)
| Or.inr (Or.inl HEq) => absurd HEq H
| Or.inr (Or.inr hgt) => this hgt
suffices {k n : Nat} {a : Int}, (a + n * k.succ).ediv k.succ = a.ediv k.succ + n from
fun a b c H => match c, eq_succ_of_zero_lt H, b with
| _, _, rfl, ofNat _ => this
| _, k, rfl, -[n+1] => show (a - n.succ * k.succ).ediv k.succ = a.ediv k.succ - n.succ by
rw [ Int.add_sub_cancel (ediv ..), this, Int.sub_add_cancel]
fun {k n} => @fun
| ofNat _ => congrArg ofNat <| Nat.add_mul_div_right _ _ k.succ_pos
| -[m+1] => by
show ((n * k.succ : Nat) - m.succ : Int).ediv k.succ = n - (m / k.succ + 1 : Nat)
by_cases h : m < n * k.succ
· rw [ Int.ofNat_sub h, Int.ofNat_sub ((Nat.div_lt_iff_lt_mul k.succ_pos).2 h)]
apply congrArg ofNat
rw [Nat.mul_comm, Nat.mul_sub_div]; rwa [Nat.mul_comm]
· have h := Nat.not_lt.1 h
have H {a b : Nat} (h : a b) : (a : Int) + -((b : Int) + 1) = -[b - a +1] := by
rw [negSucc_eq, Int.ofNat_sub h]
simp only [Int.sub_eq_add_neg, Int.neg_add, Int.neg_neg, Int.add_left_comm, Int.add_assoc]
show ediv ((n * succ k) + -((m : Int) + 1)) (succ k) = n + -((m / succ k) + 1 : Int)
rw [H h, H ((Nat.le_div_iff_mul_le k.succ_pos).2 h)]
apply congrArg negSucc
rw [Nat.mul_comm, Nat.sub_mul_div]; rwa [Nat.mul_comm]
theorem add_ediv_of_dvd_right {a b c : Int} (H : c b) : (a + b) / c = a / c + b / c :=
if h : c = 0 then by simp [h] else by
let k, hk := H
rw [hk, Int.mul_comm c k, Int.add_mul_ediv_right _ _ h,
Int.zero_add (k * c), Int.add_mul_ediv_right _ _ h, Int.zero_ediv, Int.zero_add]
theorem add_ediv_of_dvd_left {a b c : Int} (H : c a) : (a + b) / c = a / c + b / c := by
rw [Int.add_comm, Int.add_ediv_of_dvd_right H, Int.add_comm]
@[simp] theorem mul_ediv_cancel (a : Int) {b : Int} (H : b 0) : (a * b) / b = a := by
have := Int.add_mul_ediv_right 0 a H
rwa [Int.zero_add, Int.zero_ediv, Int.zero_add] at this
@[simp] theorem mul_ediv_cancel_left (b : Int) (H : a 0) : (a * b) / a = b :=
Int.mul_comm .. Int.mul_ediv_cancel _ H
theorem div_nonneg_iff_of_pos {a b : Int} (h : 0 < b) : a / b 0 a 0 := by
rw [Int.div_def]
match b, h with
| Int.ofNat (b+1), _ =>
rcases a with a <;> simp [Int.ediv]
exact decide_eq_decide.mp rfl
theorem ediv_eq_zero_of_lt {a b : Int} (H1 : 0 a) (H2 : a < b) : a / b = 0 :=
match a, b, eq_ofNat_of_zero_le H1, eq_succ_of_zero_lt (Int.lt_of_le_of_lt H1 H2) with
| _, _, _, rfl, _, rfl => congrArg Nat.cast <| Nat.div_eq_of_lt <| ofNat_lt.1 H2
@@ -440,35 +460,6 @@ theorem emod_negSucc (m : Nat) (n : Int) :
theorem ofNat_mod_ofNat (m n : Nat) : (m % n : Int) = (m % n) := rfl
theorem emod_nonneg : (a : Int) {b : Int}, b 0 0 a % b
| ofNat _, _, _ => ofNat_zero_le _
| -[_+1], _, H => Int.sub_nonneg_of_le <| ofNat_le.2 <| Nat.mod_lt _ (natAbs_pos.2 H)
theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < b :=
match a, b, eq_succ_of_zero_lt H with
| ofNat _, _, _, rfl => ofNat_lt.2 (Nat.mod_lt _ (Nat.succ_pos _))
| -[_+1], _, _, rfl => Int.sub_lt_self _ (ofNat_lt.2 <| Nat.succ_pos _)
theorem mul_ediv_self_le {x k : Int} (h : k 0) : k * (x / k) x :=
calc k * (x / k)
_ k * (x / k) + x % k := Int.le_add_of_nonneg_right (emod_nonneg x h)
_ = x := ediv_add_emod _ _
theorem lt_mul_ediv_self_add {x k : Int} (h : 0 < k) : x < k * (x / k) + k :=
calc x
_ = k * (x / k) + x % k := (ediv_add_emod _ _).symm
_ < k * (x / k) + k := Int.add_lt_add_left (emod_lt_of_pos x h) _
@[simp] theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
if cz : c = 0 then by
rw [cz, Int.mul_zero, Int.add_zero]
else by
rw [Int.emod_def, Int.emod_def, Int.add_mul_ediv_right _ _ cz, Int.add_comm _ b,
Int.mul_add, Int.mul_comm, Int.sub_sub, Int.add_sub_cancel]
@[simp] theorem add_mul_emod_self_left (a b c : Int) : (a + b * c) % b = a % b := by
rw [Int.mul_comm, Int.add_mul_emod_self]
@[simp] theorem add_neg_mul_emod_self {a b c : Int} : (a + -(b * c)) % c = a % c := by
rw [Int.neg_mul_eq_neg_mul, add_mul_emod_self]
@@ -487,53 +478,9 @@ theorem neg_emod {a b : Int} : -a % b = (b - a) % b := by
@[simp] theorem emod_neg (a b : Int) : a % -b = a % b := by
rw [emod_def, emod_def, Int.ediv_neg, Int.neg_mul_neg]
@[simp] theorem emod_add_emod (m n k : Int) : (m % n + k) % n = (m + k) % n := by
have := (add_mul_emod_self_left (m % n + k) n (m / n)).symm
rwa [Int.add_right_comm, emod_add_ediv] at this
@[simp] theorem add_emod_emod (m n k : Int) : (m + n % k) % k = (m + n) % k := by
rw [Int.add_comm, emod_add_emod, Int.add_comm]
theorem add_emod (a b n : Int) : (a + b) % n = (a % n + b % n) % n := by
rw [add_emod_emod, emod_add_emod]
theorem add_emod_eq_add_emod_right {m n k : Int} (i : Int)
(H : m % n = k % n) : (m + i) % n = (k + i) % n := by
rw [ emod_add_emod, emod_add_emod k, H]
theorem emod_add_cancel_right {m n k : Int} (i) : (m + i) % n = (k + i) % n m % n = k % n :=
fun H => by
have := add_emod_eq_add_emod_right (-i) H
rwa [Int.add_neg_cancel_right, Int.add_neg_cancel_right] at this,
add_emod_eq_add_emod_right _
@[simp] theorem mul_emod_left (a b : Int) : (a * b) % b = 0 := by
rw [ Int.zero_add (a * b), Int.add_mul_emod_self, Int.zero_emod]
@[simp] theorem mul_emod_right (a b : Int) : (a * b) % a = 0 := by
rw [Int.mul_comm, mul_emod_left]
theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
conv => lhs; rw [
emod_add_ediv a n, emod_add_ediv' b n, Int.add_mul, Int.mul_add, Int.mul_add,
Int.mul_assoc, Int.mul_assoc, Int.mul_add n _ _, add_mul_emod_self_left,
Int.mul_assoc, add_mul_emod_self]
@[simp] theorem emod_self {a : Int} : a % a = 0 := by
have := mul_emod_left 1 a; rwa [Int.one_mul] at this
@[simp] theorem neg_emod_self (a : Int) : -a % a = 0 := by
rw [neg_emod, Int.sub_self, zero_emod]
@[simp] theorem emod_emod_of_dvd (n : Int) {m k : Int}
(h : m k) : (n % k) % m = n % m := by
conv => rhs; rw [ emod_add_ediv n k]
match k, h with
| _, t, rfl => rw [Int.mul_assoc, add_mul_emod_self_left]
@[simp] theorem emod_emod (a b : Int) : (a % b) % b = a % b := by
conv => rhs; rw [ emod_add_ediv a b, add_mul_emod_self_left]
@[simp] theorem emod_sub_emod (m n k : Int) : (m % n - k) % n = (m - k) % n :=
Int.emod_add_emod m n (-k)
@@ -541,10 +488,6 @@ theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
apply (emod_add_cancel_right (n % k)).mp
rw [Int.sub_add_cancel, Int.add_emod_emod, Int.sub_add_cancel]
theorem sub_emod (a b n : Int) : (a - b) % n = (a % n - b % n) % n := by
apply (emod_add_cancel_right b).mp
rw [Int.sub_add_cancel, Int.add_emod_emod, Int.sub_add_cancel, emod_emod]
theorem emod_eq_of_lt {a b : Int} (H1 : 0 a) (H2 : a < b) : a % b = a :=
have b0 := Int.le_trans H1 (Int.le_of_lt H2)
match a, b, eq_ofNat_of_zero_le H1, eq_ofNat_of_zero_le b0 with
@@ -555,12 +498,6 @@ theorem emod_eq_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a % b = a :=
/-! ### properties of `/` and `%` -/
theorem mul_ediv_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : b * (a / b) = a := by
have := emod_add_ediv a b; rwa [H, Int.zero_add] at this
theorem ediv_mul_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : a / b * b = a := by
rw [Int.mul_comm, mul_ediv_cancel_of_emod_eq_zero H]
theorem emod_two_eq (x : Int) : x % 2 = 0 x % 2 = 1 := by
have h₁ : 0 x % 2 := Int.emod_nonneg x (by decide)
have h₂ : x % 2 < 2 := Int.emod_lt_of_pos x (by decide)
@@ -614,19 +551,10 @@ theorem ediv_le_self {a : Int} (b : Int) (Ha : 0 ≤ a) : a / b ≤ a := by
have := Int.le_trans le_natAbs (ofNat_le.2 <| natAbs_div_le_natAbs a b)
rwa [natAbs_of_nonneg Ha] at this
theorem dvd_of_emod_eq_zero {a b : Int} (H : b % a = 0) : a b :=
b / a, (mul_ediv_cancel_of_emod_eq_zero H).symm
theorem dvd_emod_sub_self {x : Int} {m : Nat} : (m : Int) x % m - x := by
apply dvd_of_emod_eq_zero
simp [sub_emod]
theorem emod_eq_zero_of_dvd : {a b : Int}, a b b % a = 0
| _, _, _, rfl => mul_emod_right ..
theorem dvd_iff_emod_eq_zero {a b : Int} : a b b % a = 0 :=
emod_eq_zero_of_dvd, dvd_of_emod_eq_zero
@[simp] theorem neg_mul_emod_left (a b : Int) : -(a * b) % b = 0 := by
rw [ dvd_iff_emod_eq_zero, Int.dvd_neg]
exact Int.dvd_mul_left a b
@@ -635,41 +563,12 @@ theorem dvd_iff_emod_eq_zero {a b : Int} : a b ↔ b % a = 0 :=
rw [ dvd_iff_emod_eq_zero, Int.dvd_neg]
exact Int.dvd_mul_right a b
instance decidableDvd : DecidableRel (α := Int) (· ·) := fun _ _ =>
decidable_of_decidable_of_iff (dvd_iff_emod_eq_zero ..).symm
theorem emod_pos_of_not_dvd {a b : Int} (h : ¬ a b) : a = 0 0 < b % a := by
rw [dvd_iff_emod_eq_zero] at h
by_cases w : a = 0
· simp_all
· exact Or.inr (Int.lt_iff_le_and_ne.mpr emod_nonneg b w, Ne.symm h)
protected theorem mul_ediv_assoc (a : Int) : {b c : Int}, c b (a * b) / c = a * (b / c)
| _, c, d, rfl =>
if cz : c = 0 then by simp [cz, Int.mul_zero] else by
rw [Int.mul_left_comm, Int.mul_ediv_cancel_left _ cz, Int.mul_ediv_cancel_left _ cz]
protected theorem mul_ediv_assoc' (b : Int) {a c : Int}
(h : c a) : (a * b) / c = a / c * b := by
rw [Int.mul_comm, Int.mul_ediv_assoc _ h, Int.mul_comm]
theorem neg_ediv_of_dvd : {a b : Int}, b a (-a) / b = -(a / b)
| _, b, c, rfl => by
by_cases bz : b = 0
· simp [bz]
· rw [Int.neg_mul_eq_mul_neg, Int.mul_ediv_cancel_left _ bz, Int.mul_ediv_cancel_left _ bz]
@[simp] theorem neg_mul_ediv_cancel (a b : Int) (h : b 0) : -(a * b) / b = -a := by
rw [neg_ediv_of_dvd (Int.dvd_mul_left a b), mul_ediv_cancel _ h]
@[simp] theorem neg_mul_ediv_cancel_left (a b : Int) (h : a 0) : -(a * b) / a = -b := by
rw [neg_ediv_of_dvd (Int.dvd_mul_right a b), mul_ediv_cancel_left _ h]
theorem sub_ediv_of_dvd (a : Int) {b c : Int}
(hcb : c b) : (a - b) / c = a / c - b / c := by
rw [Int.sub_eq_add_neg, Int.sub_eq_add_neg, Int.add_ediv_of_dvd_right (Int.dvd_neg.2 hcb)]
congr; exact Int.neg_ediv_of_dvd hcb
@[simp] theorem ediv_one : a : Int, a / 1 = a
| (_:Nat) => congrArg Nat.cast (Nat.div_one _)
| -[_+1] => congrArg negSucc (Nat.div_one _)
@@ -703,12 +602,6 @@ theorem dvd_sub_of_emod_eq {a b c : Int} (h : a % b = c) : b a - c := by
rw [Int.emod_emod, emod_sub_cancel_right c, Int.sub_self, zero_emod] at hx
exact dvd_of_emod_eq_zero hx
protected theorem ediv_mul_cancel {a b : Int} (H : b a) : a / b * b = a :=
ediv_mul_cancel_of_emod_eq_zero (emod_eq_zero_of_dvd H)
protected theorem mul_ediv_cancel' {a b : Int} (H : a b) : a * (b / a) = b := by
rw [Int.mul_comm, Int.ediv_mul_cancel H]
protected theorem eq_mul_of_ediv_eq_right {a b c : Int}
(H1 : b a) (H2 : a / b = c) : a = b * c := by rw [ H2, Int.mul_ediv_cancel' H1]
@@ -918,7 +811,7 @@ theorem ofNat_tmod (m n : Nat) : (↑(m % n) : Int) = tmod m n := rfl
simp [tmod_def, Int.tdiv_one, Int.one_mul, Int.sub_self]
theorem tmod_eq_of_lt {a b : Int} (H1 : 0 a) (H2 : a < b) : tmod a b = a := by
rw [tmod_eq_emod H1 (Int.le_trans H1 (Int.le_of_lt H2)), emod_eq_of_lt H1 H2]
rw [tmod_eq_emod_of_nonneg H1, emod_eq_of_lt H1 H2]
theorem tmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : tmod a b < b :=
match a, b, eq_succ_of_zero_lt H with
@@ -1027,7 +920,7 @@ theorem fdiv_neg' : ∀ {a b : Int}, a < 0 → 0 < b → a.fdiv b < 0
@[simp] theorem mul_fdiv_cancel (a : Int) {b : Int} (H : b 0) : fdiv (a * b) b = a :=
if b0 : 0 b then by
rw [fdiv_eq_ediv _ b0, mul_ediv_cancel _ H]
rw [fdiv_eq_ediv_of_nonneg _ b0, mul_ediv_cancel _ H]
else
match a, b, Int.not_le.1 b0 with
| 0, _, _ => by simp [Int.zero_mul]
@@ -1043,7 +936,7 @@ theorem fdiv_neg' : ∀ {a b : Int}, a < 0 → 0 < b → a.fdiv b < 0
have := Int.mul_fdiv_cancel 1 H; rwa [Int.one_mul] at this
theorem lt_fdiv_add_one_mul_self (a : Int) {b : Int} (H : 0 < b) : a < (a.fdiv b + 1) * b :=
Int.fdiv_eq_ediv _ (Int.le_of_lt H) lt_ediv_add_one_mul_self a H
Int.fdiv_eq_ediv_of_nonneg _ (Int.le_of_lt H) lt_ediv_add_one_mul_self a H
/-! ### fmod -/
@@ -1054,16 +947,16 @@ theorem ofNat_fmod (m n : Nat) : ↑(m % n) = fmod m n := by
simp [fmod_def, Int.one_mul, Int.sub_self]
theorem fmod_eq_of_lt {a b : Int} (H1 : 0 a) (H2 : a < b) : a.fmod b = a := by
rw [fmod_eq_emod _ (Int.le_trans H1 (Int.le_of_lt H2)), emod_eq_of_lt H1 H2]
rw [fmod_eq_emod_of_nonneg _ (Int.le_trans H1 (Int.le_of_lt H2)), emod_eq_of_lt H1 H2]
theorem fmod_nonneg {a b : Int} (ha : 0 a) (hb : 0 b) : 0 a.fmod b :=
fmod_eq_tmod ha hb tmod_nonneg _ ha
fmod_eq_tmod_of_nonneg ha hb tmod_nonneg _ ha
theorem fmod_nonneg' (a : Int) {b : Int} (hb : 0 < b) : 0 a.fmod b :=
fmod_eq_emod _ (Int.le_of_lt hb) emod_nonneg _ (Int.ne_of_lt hb).symm
fmod_eq_emod_of_nonneg _ (Int.le_of_lt hb) emod_nonneg _ (Int.ne_of_lt hb).symm
theorem fmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a.fmod b < b :=
fmod_eq_emod _ (Int.le_of_lt H) emod_lt_of_pos a H
fmod_eq_emod_of_nonneg _ (Int.le_of_lt H) emod_lt_of_pos a H
@[simp] theorem mul_fmod_left (a b : Int) : (a * b).fmod b = 0 :=
if h : b = 0 then by simp [h, Int.mul_zero] else by
@@ -1090,21 +983,10 @@ theorem fdiv_eq_ediv_of_dvd : ∀ {a b : Int}, b a → a.fdiv b = a / b
/-! ### bmod -/
@[simp] theorem bmod_emod : bmod x m % m = x % m := by
dsimp [bmod]
split <;> simp [Int.sub_emod]
@[simp]
theorem emod_bmod_congr (x : Int) (n : Nat) : Int.bmod (x%n) n = Int.bmod x n := by
simp [bmod, Int.emod_emod]
theorem bmod_def (x : Int) (m : Nat) : bmod x m =
if (x % m) < (m + 1) / 2 then
x % m
else
(x % m) - m :=
rfl
theorem bdiv_add_bmod (x : Int) (m : Nat) : m * bdiv x m + bmod x m = x := by
unfold bdiv bmod
split

View File

@@ -7,7 +7,7 @@ prelude
import Init.Data.Int.Basic
import Init.Data.Nat.Gcd
import Init.Data.Nat.Lcm
import Init.Data.Int.DivModLemmas
import Init.Data.Int.DivMod.Lemmas
/-!
Definition and lemmas for gcd and lcm over Int

View File

@@ -129,6 +129,17 @@ theorem subNatNat_of_le {m n : Nat} (h : n ≤ m) : subNatNat m n = ↑(m - n) :
theorem subNatNat_of_lt {m n : Nat} (h : m < n) : subNatNat m n = -[pred (n - m) +1] :=
subNatNat_of_sub_eq_succ <| (Nat.succ_pred_eq_of_pos (Nat.sub_pos_of_lt h)).symm
@[simp] theorem subNat_eq_zero_iff {a b : Nat} : subNatNat a b = 0 a = b := by
cases Nat.lt_or_ge a b with
| inl h =>
rw [subNatNat_of_lt h]
simpa using ne_of_lt h
| inr h =>
rw [subNatNat_of_le h]
norm_cast
rw [Nat.sub_eq_iff_eq_add' h]
simp
/- # Additive group properties -/
/- addition -/
@@ -330,6 +341,20 @@ theorem toNat_of_nonpos : ∀ {z : Int}, z ≤ 0 → z.toNat = 0
| 0, _ => rfl
| -[_+1], _ => rfl
@[simp] theorem neg_ofNat_eq_negSucc_iff {a b : Nat} : - (a : Int) = -[b+1] a = b + 1 := by
rw [Int.neg_eq_comm]
rw [Int.neg_negSucc]
norm_cast
simp [eq_comm]
@[simp] theorem neg_ofNat_eq_negSucc_add_one_iff {a b : Nat} : - (a : Int) = -[b+1] + 1 a = b := by
cases b with
| zero => simp; norm_cast
| succ b =>
rw [Int.neg_eq_comm, Int.negSucc_sub_one, Int.sub_add_cancel, Int.neg_negSucc]
norm_cast
simp [eq_comm]
/- ## add/sub injectivity -/
protected theorem add_left_inj {i j : Int} (k : Int) : (i + k = j + k) i = j := by

View File

@@ -5,6 +5,7 @@ Authors: Kim Morrison
-/
prelude
import Init.Data.Int.Order
import Init.Data.Int.DivMod.Lemmas
import Init.Omega

View File

@@ -8,7 +8,7 @@ import Init.ByCases
import Init.Data.Prod
import Init.Data.Int.Lemmas
import Init.Data.Int.LemmasAux
import Init.Data.Int.DivModLemmas
import Init.Data.Int.DivMod.Bootstrap
import Init.Data.Int.Gcd
import Init.Data.RArray
import Init.Data.AC
@@ -147,28 +147,9 @@ where
| .neg a => go (-coeff) a
/-- Converts the given expression into a polynomial, and then normalizes it. -/
def Expr.toPoly (e : Expr) : Poly :=
def Expr.norm (e : Expr) : Poly :=
e.toPoly'.norm
/-- Relational contraints: equality and inequality. -/
inductive RelCnstr where
| /-- `p = 0` constraint. -/
eq (p : Poly)
| /-- `p ≤ 0` contraint. -/
le (p : Poly)
deriving BEq
def RelCnstr.denote (ctx : Context) : RelCnstr Prop
| .eq p => p.denote ctx = 0
| .le p => p.denote ctx 0
def RelCnstr.denote' (ctx : Context) : RelCnstr Prop
| .eq p => p.denote' ctx = 0
| .le p => p.denote' ctx 0
theorem RelCnstr.denote'_eq_denote (ctx : Context) (c : RelCnstr) : c.denote' ctx = c.denote ctx := by
cases c <;> simp [denote, denote', Poly.denote'_eq_denote]
/--
Returns the ceiling of the division `a / b`. That is, the result is equivalent to `⌈a / b⌉`.
Examples:
@@ -278,79 +259,6 @@ def Poly.mul (p : Poly) (k : Int) : Poly :=
induction p <;> simp [mul, denote, *]
rw [Int.mul_assoc, Int.mul_add]
/-- Normalizes the polynomial of the given relational constraint. -/
def RelCnstr.norm : RelCnstr RelCnstr
| .eq p => .eq p.norm
| .le p => .le p.norm
/-- Returns `true` if `k` divides all coefficients and constant of the given relational constraint. -/
def RelCnstr.divAll (k : Int) : RelCnstr Bool
| .eq p | .le p => p.divAll k
/-- Returns `true` if `k` divides all coefficients of the given relational constraint. -/
def RelCnstr.divCoeffs (k : Int) : RelCnstr Bool
| .eq p | .le p => p.divCoeffs k
/-- Returns `true` if the given relational constraint is an inequality constraint of the form `p ≤ 0`. -/
def RelCnstr.isLe : RelCnstr Bool
| .eq _ => false
| .le _ => true
/--
Divides all coefficients and constants in the linear polynomial of the given constraint by `k`.
We rounds up the constant using `cdiv`.
-/
def RelCnstr.div (k : Int) : RelCnstr RelCnstr
| .eq p => .eq <| p.div k
| .le p => .le <| p.div k
/--
Multiplies all coefficients and constants in the linear polynomial of the given constraint by `k`.
-/
def RelCnstr.mul (k : Int) : RelCnstr RelCnstr
| .eq p => .eq <| p.mul k
| .le p => .le <| p.mul k
@[simp] theorem RelCnstr.denote_mul (ctx : Context) (c : RelCnstr) (k : Int) (h : k > 0) : (c.mul k).denote ctx = c.denote ctx := by
cases c <;> simp [mul, denote]
next =>
constructor
· intro h₁; cases (Int.mul_eq_zero.mp h₁)
next hz => simp [hz] at h
next => assumption
· intro h'; simp [*]
next =>
constructor
· intro h₁
conv at h₁ => rhs; rw [ Int.mul_zero k]
exact Int.le_of_mul_le_mul_left h₁ h
· intro h₂
have := Int.mul_le_mul_of_nonneg_left h₂ (Int.le_of_lt h)
simp at this; assumption
/-- Raw relational constraint. They are later converted into `RelCnstr`. -/
inductive RawRelCnstr where
| eq (p₁ p₂ : Expr)
| le (p₁ p₂ : Expr)
deriving Inhabited, BEq
/-- Returns `true` if the given relational constraint is an inequality constraint of the form `e₁ ≤ e₂`. -/
def RawRelCnstr.isLe : RawRelCnstr Bool
| .eq .. => false
| .le .. => true
def RawRelCnstr.denote (ctx : Context) : RawRelCnstr Prop
| .eq e₁ e₂ => e₁.denote ctx = e₂.denote ctx
| .le e₁ e₂ => e₁.denote ctx e₂.denote ctx
def RawRelCnstr.norm : RawRelCnstr RelCnstr
| .eq e₁ e₂ => .eq (e₁.sub e₂).toPoly.norm
| .le e₁ e₂ => .le (e₁.sub e₂).toPoly.norm
/-- A certificate for normalizing the coefficients of a raw relational constraint. -/
def divBy (c : RawRelCnstr) (c' : RelCnstr) (k : Int) : Bool :=
k > 0 && c.norm == c'.mul k
attribute [local simp] Int.add_comm Int.add_assoc Int.add_left_comm Int.add_mul Int.mul_add
attribute [local simp] Poly.insert Poly.denote Poly.norm Poly.addConst
@@ -361,13 +269,9 @@ attribute [local simp] Poly.denote_addConst
theorem Poly.denote_insert (ctx : Context) (k : Int) (v : Var) (p : Poly) :
(p.insert k v).denote ctx = p.denote ctx + k * v.denote ctx := by
induction p <;> simp [*]
next k' v' p' ih =>
by_cases h₁ : Nat.blt v' v <;> simp [*]
by_cases h₂ : Nat.beq v v' <;> simp [*]
by_cases h₃ : k + k' = 0 <;> simp [*, Nat.eq_of_beq_eq_true h₂]
rw [ Int.add_mul]
simp [*]
fun_induction p.insert k v <;>
simp only [insert, cond_true, cond_false, reduceIte, *] <;>
simp_all [ Int.add_mul]
attribute [local simp] Poly.denote_insert
@@ -382,26 +286,21 @@ theorem Poly.denote_append (ctx : Context) (p₁ p₂ : Poly) : (p₁.append p
attribute [local simp] Poly.denote_append
theorem Poly.denote_combine' (ctx : Context) (fuel : Nat) (p₁ p₂ : Poly) : (p₁.combine' fuel p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
induction fuel generalizing p₁ p₂ <;> simp [combine']
next ih =>
split <;> simp [*]
next a₁ x₁ p₁ a₂ x₂ p₂ =>
by_cases h₁ : Nat.beq x₁ x₂ <;> simp [*]
· simp at h₁; simp [h₁]
by_cases h₂ : a₁ + a₂ == 0 <;> simp [*]
· simp at h₂
rw [ Int.add_mul, h₂]; simp
· by_cases h₃ : Nat.blt x₂ x₁ <;> simp [*]
fun_induction p₁.combine' fuel p₂ <;>
simp +zetaDelta only [combine', cond_true, cond_false, *] <;>
simp_all +zetaDelta [denote, Int.add_mul]
theorem Poly.denote_combine (ctx : Context) (p₁ p₂ : Poly) : (p₁.combine p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
simp [combine, denote_combine']
attribute [local simp] Poly.denote_combine
theorem sub_fold (a b : Int) : a.sub b = a - b := rfl
theorem neg_fold (a : Int) : a.neg = -a := rfl
attribute [local simp] sub_fold neg_fold
attribute [local simp] Poly.div Poly.divAll RelCnstr.denote
attribute [local simp] Poly.div Poly.divAll
theorem Poly.denote_div_eq_of_divAll (ctx : Context) (p : Poly) (k : Int) : p.divAll k (p.div k).denote ctx * k = p.denote ctx := by
induction p with
@@ -425,43 +324,40 @@ theorem Poly.denote_div_eq_of_divCoeffs (ctx : Context) (p : Poly) (k : Int) : p
rw [ ih h₂]
rw [Int.mul_right_comm, h₁, Int.add_assoc]
attribute [local simp] RawRelCnstr.denote RawRelCnstr.norm Expr.denote
attribute [local simp] Expr.denote
theorem Expr.denote_toPoly'_go (ctx : Context) (e : Expr) :
(toPoly'.go k e p).denote ctx = k * e.denote ctx + p.denote ctx := by
induction k, e using Expr.toPoly'.go.induct generalizing p with
| case1 k k' =>
simp only [toPoly'.go]
by_cases h : k' == 0
· simp [h, eq_of_beq h]
· simp [h, Var.denote]
| case2 k i => simp [toPoly'.go]
| case3 k a b iha ihb => simp [toPoly'.go, iha, ihb]
| case4 k a b iha ihb =>
| case1 k k' h =>
simp only [toPoly'.go, h, cond_true]
simp [eq_of_beq h]
| case2 k k' h =>
simp only [toPoly'.go, h, cond_false]
simp [Var.denote]
| case3 k i => simp [toPoly'.go]
| case4 k a b iha ihb => simp [toPoly'.go, iha, ihb]
| case5 k a b iha ihb =>
simp [toPoly'.go, iha, ihb, Int.mul_sub]
rw [Int.sub_eq_add_neg, Int.neg_mul, Int.add_assoc]
| case5 k k' a ih
| case6 k a k' ih =>
simp only [toPoly'.go]
by_cases h : k' == 0
· simp [h, eq_of_beq h]
· simp [h, cond_false, Int.mul_assoc]
simp at ih
rw [ih]
rw [Int.mul_assoc, Int.mul_comm k']
| case7 k a ih => simp [toPoly'.go, ih]
| case6 k k' a h
| case8 k a k' h =>
simp only [toPoly'.go, h, cond_false]
simp [eq_of_beq h]
| case7 k a k' h ih =>
simp only [toPoly'.go, h, cond_false]
simpa [denote, Int.mul_assoc] using ih
| case9 k a h h ih =>
simp only [toPoly'.go, h, cond_false]
simp only [mul_def, denote]
rw [Int.mul_comm (denote _ _) _]
simpa [Int.mul_assoc] using ih
| case10 k a ih => simp [toPoly'.go, ih]
theorem Expr.denote_toPoly (ctx : Context) (e : Expr) : e.toPoly.denote ctx = e.denote ctx := by
simp [toPoly, toPoly', Expr.denote_toPoly'_go]
theorem Expr.denote_norm (ctx : Context) (e : Expr) : e.norm.denote ctx = e.denote ctx := by
simp [norm, toPoly', Expr.denote_toPoly'_go]
attribute [local simp] Expr.denote_toPoly RelCnstr.denote
theorem RawRelCnstr.denote_norm (ctx : Context) (c : RawRelCnstr) : c.norm.denote ctx = c.denote ctx := by
cases c <;> simp
· rw [Int.sub_eq_zero]
· constructor
· exact Int.le_of_sub_nonpos
· exact Int.sub_nonpos_of_le
attribute [local simp] Expr.denote_norm
instance : LawfulBEq Poly where
eq_of_beq {a} := by
@@ -474,54 +370,83 @@ instance : LawfulBEq Poly where
induction a <;> simp! [BEq.beq]
assumption
instance : LawfulBEq RelCnstr where
eq_of_beq {a b} := by
cases a <;> cases b <;> rename_i p₁ p₂ <;> simp_all! [BEq.beq]
· show (p₁ == p₂) = true _
simp
· show (p₁ == p₂) = true _
simp
rfl {a} := by
cases a <;> rename_i p <;> show (p == p) = true
<;> simp
attribute [local simp] Poly.denote'_eq_denote
theorem Expr.eq_of_toPoly_eq (ctx : Context) (e e' : Expr) (h : e.toPoly == e'.toPoly) : e.denote ctx = e'.denote ctx := by
theorem Expr.eq_of_norm_eq (ctx : Context) (e : Expr) (p : Poly) (h : e.norm == p) : e.denote ctx = p.denote' ctx := by
have h := congrArg (Poly.denote ctx) (eq_of_beq h)
simp [Poly.norm] at h
assumption
simp [*]
theorem RawRelCnstr.eq_of_norm_eq (ctx : Context) (c : RawRelCnstr) (c' : RelCnstr) (h : c.norm == c') : c.denote ctx = c'.denote' ctx := by
have h := congrArg (RelCnstr.denote ctx) (eq_of_beq h)
rw [denote_norm] at h
rw [RelCnstr.denote'_eq_denote, h]
def norm_eq_cert (lhs rhs : Expr) (p : Poly) : Bool :=
p == (lhs.sub rhs).norm
theorem RawRelCnstr.eq_of_norm_eq_var (ctx : Context) (x y : Var) (c : RawRelCnstr) (h : c.norm == .eq (.add 1 x (.add (-1) y (.num 0))))
: c.denote ctx = (x.denote ctx = y.denote ctx) := by
have h := congrArg (RelCnstr.denote ctx) (eq_of_beq h)
rw [denote_norm] at h
rw [h]; simp
rw [ Int.sub_eq_add_neg, Int.sub_eq_zero]
theorem norm_eq (ctx : Context) (lhs rhs : Expr) (p : Poly) (h : norm_eq_cert lhs rhs p) : (lhs.denote ctx = rhs.denote ctx) = (p.denote' ctx = 0) := by
simp [norm_eq_cert] at h; subst p
simp
rw [Int.sub_eq_zero]
theorem RawRelCnstr.eq_of_norm_eq_const (ctx : Context) (x : Var) (k : Int) (c : RawRelCnstr) (h : c.norm == .eq (.add 1 x (.num (-k))))
: c.denote ctx = (x.denote ctx = k) := by
have h := congrArg (RelCnstr.denote ctx) (eq_of_beq h)
rw [denote_norm] at h
rw [h]; simp
rw [Int.add_comm, Int.sub_eq_add_neg, Int.sub_eq_zero]
theorem norm_le (ctx : Context) (lhs rhs : Expr) (p : Poly) (h : norm_eq_cert lhs rhs p) : (lhs.denote ctx rhs.denote ctx) = (p.denote' ctx 0) := by
simp [norm_eq_cert] at h; subst p
simp
constructor
· exact Int.sub_nonpos_of_le
· exact Int.le_of_sub_nonpos
attribute [local simp] RelCnstr.divAll RelCnstr.div RelCnstr.mul
def norm_eq_var_cert (lhs rhs : Expr) (x y : Var) : Bool :=
(lhs.sub rhs).norm == .add 1 x (.add (-1) y (.num 0))
theorem RawRelCnstr.eq_of_norm_eq_mul (ctx : Context) (c : RawRelCnstr) (c' : RelCnstr) (k : Int) (hz : k > 0) (h : c.norm = c'.mul k) : c.denote ctx = c'.denote ctx := by
replace h := congrArg (RelCnstr.denote ctx) h
simp only [RawRelCnstr.denote_norm, RelCnstr.denote_mul, *] at h
assumption
theorem norm_eq_var (ctx : Context) (lhs rhs : Expr) (x y : Var) (h : norm_eq_var_cert lhs rhs x y)
: (lhs.denote ctx = rhs.denote ctx) = (x.denote ctx = y.denote ctx) := by
simp [norm_eq_var_cert] at h
replace h := congrArg (Poly.denote ctx) h
simp at h
rw [Int.sub_eq_zero, h, @Int.sub_eq_zero (Var.denote ctx x), Int.sub_eq_add_neg]
theorem RawRelCnstr.eq_of_divBy (ctx : Context) (c : RawRelCnstr) (c' : RelCnstr) (k : Int) : divBy c c' k c.denote ctx = c'.denote' ctx := by
intro h
simp only [RelCnstr.denote'_eq_denote]
simp only [divBy, Bool.and_eq_true, bne_iff_ne, ne_eq, beq_iff_eq, decide_eq_true_eq] at h
have h₁, h₂ := h
exact eq_of_norm_eq_mul ctx c c' k h₁ h
def norm_eq_var_const_cert (lhs rhs : Expr) (x : Var) (k : Int) : Bool :=
(lhs.sub rhs).norm == .add 1 x (.num (-k))
theorem norm_eq_var_const (ctx : Context) (lhs rhs : Expr) (x : Var) (k : Int) (h : norm_eq_var_const_cert lhs rhs x k)
: (lhs.denote ctx = rhs.denote ctx) = (x.denote ctx = k) := by
simp [norm_eq_var_const_cert] at h
replace h := congrArg (Poly.denote ctx) h
simp at h
rw [Int.sub_eq_zero, h, Int.add_comm, Int.sub_eq_add_neg, Int.sub_eq_zero]
private theorem mul_eq_zero_iff (a k : Int) (h₁ : k > 0) : k * a = 0 a = 0 := by
conv => lhs; rw [ Int.mul_zero k]
apply Int.mul_eq_mul_left_iff
exact Int.ne_of_gt h₁
theorem norm_eq_coeff' (ctx : Context) (p p' : Poly) (k : Int) : p = p'.mul k k > 0 (p.denote ctx = 0 p'.denote ctx = 0) := by
intro; subst p; intro h; simp [mul_eq_zero_iff, *]
def norm_eq_coeff_cert (lhs rhs : Expr) (p : Poly) (k : Int) : Bool :=
(lhs.sub rhs).norm == p.mul k && k > 0
theorem norm_eq_coeff (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int)
: norm_eq_coeff_cert lhs rhs p k (lhs.denote ctx = rhs.denote ctx) = (p.denote' ctx = 0) := by
simp [norm_eq_coeff_cert]
rw [norm_eq ctx lhs rhs (lhs.sub rhs).norm BEq.refl, Poly.denote'_eq_denote]
apply norm_eq_coeff'
private theorem mul_le_zero_iff (a k : Int) (h₁ : k > 0) : k * a 0 a 0 := by
constructor
· intro h
rw [ Int.mul_zero k] at h
exact Int.le_of_mul_le_mul_left h h₁
· intro h
replace h := Int.mul_le_mul_of_nonneg_left h (Int.le_of_lt h₁)
simp at h; assumption
private theorem norm_le_coeff' (ctx : Context) (p p' : Poly) (k : Int) : p = p'.mul k k > 0 (p.denote ctx 0 p'.denote ctx 0) := by
simp [norm_eq_coeff_cert]
intro; subst p; intro h; simp [mul_le_zero_iff, *]
theorem norm_le_coeff (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int)
: norm_eq_coeff_cert lhs rhs p k (lhs.denote ctx rhs.denote ctx) = (p.denote' ctx 0) := by
simp [norm_eq_coeff_cert]
rw [norm_le ctx lhs rhs (lhs.sub rhs).norm BEq.refl, Poly.denote'_eq_denote]
apply norm_le_coeff'
private theorem mul_add_cmod_le_iff {a k b : Int} (h : k > 0) : a*k + cmod b k 0 a 0 := by
constructor
@@ -547,57 +472,93 @@ private theorem mul_add_cmod_le_iff {a k b : Int} (h : k > 0) : a*k + cmod b k
simp at this
assumption
theorem RawRelCnstr.eq_of_norm_eq_of_divCoeffs (ctx : Context) (c : RawRelCnstr) (c : RelCnstr) (c₃ : RelCnstr) (k : Int)
: k > 0 c₂.divCoeffs k c.isLe c.norm = c₂ c₃ = c₂.div k c₁.denote ctx = c₃.denote ctx := by
intro h₀ h₁ h₂ h₃ h₄
private theorem eq_of_norm_eq_of_divCoeffs {ctx : Context} {p p : Poly} {k : Int}
: k > 0 p₁.divCoeffs k p = p.div k (p₁.denote ctx 0 p₂.denote ctx 0) := by
intro h₀ h₁ h₂
have hz : k 0 := Int.ne_of_gt h₀
cases c₂ <;> simp [RelCnstr.isLe] at h
clear h₂
next p =>
simp [RelCnstr.divCoeffs] at h₁
replace h₁ := Poly.denote_div_eq_of_divCoeffs ctx p k h₁
replace h₃ := congrArg (RelCnstr.denote ctx) h₃
simp only [RelCnstr.denote.eq_2, h₁] at h₃
replace h₄ := congrArg (RelCnstr.denote ctx) h₄
simp only [RelCnstr.denote.eq_2, RelCnstr.div] at h₄
rw [denote_norm] at h₃
rw [h₃, h₄]
apply propext
apply mul_add_cmod_le_iff
exact h₀
/-- Certificate for normalizing the coefficients of inequality constraint with bound tightening. -/
def divByLe (c : RawRelCnstr) (c' : RelCnstr) (k : Int) : Bool :=
k > 0 && c.isLe && c.norm.divCoeffs k && c' == c.norm.div k
theorem RawRelCnstr.eq_of_divByLe (ctx : Context) (c : RawRelCnstr) (c' : RelCnstr) (k : Int) : divByLe c c' k c.denote ctx = c'.denote' ctx := by
intro h
simp only [RelCnstr.denote'_eq_denote]
simp only [divByLe, Bool.and_eq_true, bne_iff_ne, ne_eq, beq_iff_eq, decide_eq_true_eq] at h
have h₀, h₁, h₂, h₃ := h
have hle : c.norm.isLe := by
cases c <;> simp [RawRelCnstr.isLe] at h₁
simp [RelCnstr.isLe]
apply eq_of_norm_eq_of_divCoeffs ctx c c.norm c' k h₀ h₂ hle rfl h₃
def RelCnstr.isUnsat : RelCnstr Bool
| .eq (.num k) => k != 0
| .eq _ => false
| .le (.num k) => k > 0
| .le _ => false
theorem RelCnstr.eq_false_of_isUnsat (ctx : Context) (c : RelCnstr) : c.isUnsat c.denote ctx = False := by
unfold isUnsat <;> split <;> simp <;> try contradiction
apply Int.not_le_of_gt
theorem RawRelCnstr.eq_false_of_isUnsat (ctx : Context) (c : RawRelCnstr) (h : c.norm.isUnsat) : c.denote ctx = False := by
have := RelCnstr.eq_false_of_isUnsat ctx c.norm h
rw [RawRelCnstr.denote_norm] at this
replace h₁ := Poly.denote_div_eq_of_divCoeffs ctx p₁ k h
replace h₂ := congrArg (Poly.denote ctx) h₂
simp at h₂
rw [h₂, h₁]; clear h₁ h₂
apply mul_add_cmod_le_iff
assumption
def RelCnstr.isUnsatCoeff (k : Int) : RelCnstr Bool
| .eq p => p.divCoeffs k && k > 0 && cmod p.getConst k < 0
| .le _ => false
def norm_le_coeff_tight_cert (lhs rhs : Expr) (p : Poly) (k : Int) : Bool :=
let p' := lhs.sub rhs |>.norm
k > 0 && (p'.divCoeffs k && p == p'.div k)
theorem norm_le_coeff_tight (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int)
: norm_le_coeff_tight_cert lhs rhs p k (lhs.denote ctx rhs.denote ctx) = (p.denote' ctx 0) := by
simp [norm_le_coeff_tight_cert]
rw [norm_le ctx lhs rhs (lhs.sub rhs).norm BEq.refl, Poly.denote'_eq_denote]
apply eq_of_norm_eq_of_divCoeffs
def Poly.isUnsatEq (p : Poly) : Bool :=
match p with
| .num k => k != 0
| _ => false
def Poly.isValidEq (p : Poly) : Bool :=
match p with
| .num k => k == 0
| _ => false
theorem eq_eq_false (ctx : Context) (lhs rhs : Expr) : (lhs.sub rhs).norm.isUnsatEq (lhs.denote ctx = rhs.denote ctx) = False := by
simp [Poly.isUnsatEq] <;> split <;> simp
next p k h =>
intro h'
replace h := congrArg (Poly.denote ctx) h
simp at h
rw [ Int.sub_eq_zero, h]
assumption
theorem eq_eq_true (ctx : Context) (lhs rhs : Expr) : (lhs.sub rhs).norm.isValidEq (lhs.denote ctx = rhs.denote ctx) = True := by
simp [Poly.isValidEq] <;> split <;> simp
next p k h =>
intro h'
replace h := congrArg (Poly.denote ctx) h
simp at h
rw [ Int.sub_eq_zero, h]
assumption
def Poly.isUnsatLe (p : Poly) : Bool :=
match p with
| .num k => k > 0
| _ => false
def Poly.isValidLe (p : Poly) : Bool :=
match p with
| .num k => k 0
| _ => false
theorem le_eq_false (ctx : Context) (lhs rhs : Expr) : (lhs.sub rhs).norm.isUnsatLe (lhs.denote ctx rhs.denote ctx) = False := by
simp [Poly.isUnsatLe] <;> split <;> simp
next p k h =>
intro h'
replace h := congrArg (Poly.denote ctx) h
simp at h
replace h := congrArg (Expr.denote ctx rhs + ·) h
simp at h
rw [Int.add_comm, Int.sub_add_cancel] at h
rw [h]; clear h
intro h
conv at h => rhs; rw [ Int.zero_add (Expr.denote ctx rhs)]
rw [Int.add_le_add_iff_right] at h
replace h := Int.lt_of_lt_of_le h' h
contradiction
theorem le_eq_true (ctx : Context) (lhs rhs : Expr) : (lhs.sub rhs).norm.isValidLe (lhs.denote ctx rhs.denote ctx) = True := by
simp [Poly.isValidLe] <;> split <;> simp
next p k h =>
intro h'
replace h := congrArg (Poly.denote ctx) h
simp at h
replace h := congrArg (Expr.denote ctx rhs + ·) h
simp at h
rw [Int.add_comm, Int.sub_add_cancel] at h
rw [h]; clear h; simp
conv => rhs; rw [ Int.zero_add (Expr.denote ctx rhs)]
rw [Int.add_le_add_iff_right]; assumption
private theorem contra {a b k : Int} (h₀ : 0 < k) (h₁ : -k < b) (h₂ : b < 0) (h₃ : a*k + b = 0) : False := by
have : b = -a*k := by
@@ -614,7 +575,7 @@ private theorem contra {a b k : Int} (h₀ : 0 < k) (h₁ : -k < b) (h₂ : b <
have : (1 : Int) < 1 := Int.lt_of_le_of_lt h₂ h₁
contradiction
private theorem RelCnstr.eq_false (ctx : Context) (p : Poly) (k : Int) : p.divCoeffs k k > 0 cmod p.getConst k < 0 (RelCnstr.eq p).denote ctx = False := by
private theorem poly_eq_zero_eq_false (ctx : Context) {p : Poly} {k : Int} : p.divCoeffs k k > 0 cmod p.getConst k < 0 (p.denote ctx = 0) = False := by
simp
intro h₁ h₂ h₃ h
have hnz : k 0 := by intro h; rw [h] at h₂; contradiction
@@ -624,30 +585,17 @@ private theorem RelCnstr.eq_false (ctx : Context) (p : Poly) (k : Int) : p.divCo
have high := h₃
exact contra h₂ low high this
theorem RawRelCnstr.eq_false_of_isUnsat_coeff (ctx : Context) (c : RawRelCnstr) (k : Int) : c.norm.isUnsatCoeff k c.denote ctx = False := by
intro h
cases c <;> simp [norm, RelCnstr.isUnsatCoeff] at h
next e₁ e₂ =>
have h₁, h₂, h₃ := h
have := RelCnstr.eq_false ctx _ _ h₁ h₂ h₃
simp at this
simp
intro he
simp [he] at this
def unsatEqDivCoeffCert (lhs rhs : Expr) (k : Int) : Bool :=
let p := (lhs.sub rhs).norm
p.divCoeffs k && k > 0 && cmod p.getConst k < 0
def RelCnstr.isValid : RelCnstr Bool
| .eq (.num k) => k == 0
| .eq _ => false
| .le (.num k) => k 0
| .le _ => false
theorem RelCnstr.eq_true_of_isValid (ctx : Context) (c : RelCnstr) : c.isValid c.denote ctx = True := by
unfold isValid <;> split <;> simp
theorem RawRelCnstr.eq_true_of_isValid (ctx : Context) (c : RawRelCnstr) (h : c.norm.isValid) : c.denote ctx = True := by
have := RelCnstr.eq_true_of_isValid ctx c.norm h
rw [RawRelCnstr.denote_norm] at this
assumption
theorem eq_eq_false_of_divCoeff (ctx : Context) (lhs rhs : Expr) (k : Int) : unsatEqDivCoeffCert lhs rhs k (lhs.denote ctx = rhs.denote ctx) = False := by
simp [unsatEqDivCoeffCert]
intro h₁ h₂ h₃
have h := poly_eq_zero_eq_false ctx h₁ h₂ h₃; clear h₁ h₂ h₃
simp at h
intro h'
simp [h'] at h
private def gcd (a b : Int) : Int :=
Int.ofNat <| Int.gcd a b
@@ -673,40 +621,24 @@ theorem Poly.gcd_dvd_const {ctx : Context} {p : Poly} {k : Int} (h : k p.den
rw [Int.add_comm] at h
exact ih (gcd_dvd_step h)
/-- Divibility constraint of the form `k p`. -/
structure DvdCnstr where
k : Int
p : Poly
def DvdCnstr.denote (ctx : Context) (c : DvdCnstr) : Prop :=
c.k c.p.denote ctx
def DvdCnstr.denote' (ctx : Context) (c : DvdCnstr) : Prop :=
c.k c.p.denote' ctx
theorem DvdCnstr.denote'_eq_denote (ctx : Context) (c : DvdCnstr) : c.denote' ctx = c.denote ctx := by
simp [denote', denote, Poly.denote'_eq_denote]
def DvdCnstr.isUnsat (c : DvdCnstr) : Bool :=
c.p.getConst % c.p.gcdCoeffs c.k != 0
def DvdCnstr.isEqv (c₁ c₂ : DvdCnstr) (k : Int) : Bool :=
k != 0 && c₁.k == k*c₂.k && c₁.p == c₂.p.mul k
def DvdCnstr.div (k' : Int) : DvdCnstr DvdCnstr
| { k, p } => { k := k / k', p := p.div k' }
def Poly.isUnsatDvd (k : Int) (p : Poly) : Bool :=
p.getConst % p.gcdCoeffs k != 0
private theorem not_dvd_of_not_mod_zero {a b : Int} (h : ¬ b % a = 0) : ¬ a b := by
intro h; have := Int.emod_eq_zero_of_dvd h; contradiction
def DvdCnstr.eq_false_of_isUnsat (ctx : Context) (c : DvdCnstr) : c.isUnsat c.denote ctx = False := by
rcases c with a, p
simp [isUnsat, denote]
private theorem dvd_eq_false' (ctx : Context) (k : Int) (p : Poly) : p.isUnsatDvd k (k p.denote' ctx) = False := by
simp [Poly.isUnsatDvd]
intro h₁ h₂
have := Poly.gcd_dvd_const h₂
have := not_dvd_of_not_mod_zero h₁
contradiction
theorem dvd_unsat (ctx : Context) (k : Int) (p : Poly) : p.isUnsatDvd k k p.denote' ctx False := by
intro h₁
rw [dvd_eq_false' ctx _ _ h₁]
intro; contradiction
@[local simp] private theorem mul_dvd_mul_eq {a b c : Int} (hnz : a 0) : a * b a * c b c := by
constructor
· intro h
@@ -719,43 +651,61 @@ def DvdCnstr.eq_false_of_isUnsat (ctx : Context) (c : DvdCnstr) : c.isUnsat →
exists k
rw [h, Int.mul_assoc]
@[local simp] theorem DvdCnstr.eq_of_isEqv (ctx : Context) (c₁ c₂ : DvdCnstr) (k : Int) (h : isEqv c₁ c₂ k) : c₁.denote ctx = c₂.denote ctx := by
rcases c₁ with a₁, e₁
rcases c₂ with a₂, e₂
simp [isEqv] at h
rcases h with h₁, h₂, h₃
theorem norm_dvd (ctx : Context) (k : Int) (e : Expr) (p : Poly) : e.norm == p (k e.denote ctx) = (k p.denote' ctx) := by
simp; intro h; simp [ h]
theorem dvd_eq_false (ctx : Context) (k : Int) (e : Expr) (h : e.norm.isUnsatDvd k) : (k e.denote ctx) = False := by
rw [norm_dvd ctx k e e.norm BEq.refl]
apply dvd_eq_false' ctx k e.norm h
def dvd_coeff_cert (k₁ : Int) (p₁ : Poly) (k₂ : Int) (p₂ : Poly) (k : Int) : Bool :=
k != 0 && (k₁ == k*k₂ && p₁ == p₂.mul k)
def norm_dvd_gcd_cert (k₁ : Int) (e₁ : Expr) (k₂ : Int) (p₂ : Poly) (k : Int) : Bool :=
dvd_coeff_cert k₁ e₁.norm k₂ p₂ k
theorem norm_dvd_gcd (ctx : Context) (k₁ : Int) (e₁ : Expr) (k₂ : Int) (p₂ : Poly) (g : Int)
: norm_dvd_gcd_cert k₁ e₁ k₂ p₂ g (k₁ e₁.denote ctx) = (k₂ p₂.denote' ctx) := by
simp [norm_dvd_gcd_cert, dvd_coeff_cert]
intro h₁ h₂ h₃
replace h₃ := congrArg (Poly.denote ctx) h₃
simp at h₃
simp [denote, *]
simp [*]
/-- Raw divisibility constraint of the form `k e`. -/
structure RawDvdCnstr where
k : Int
e : Expr
deriving BEq
theorem dvd_coeff (ctx : Context) (k₁ : Int) (p₁ : Poly) (k₂ : Int) (p₂ : Poly) (g : Int)
: dvd_coeff_cert k₁ p₁ k₂ p₂ g k₁ p₁.denote' ctx k₂ p₂.denote' ctx := by
simp [dvd_coeff_cert]
intro h₁ h₂ h₃
replace h₃ := congrArg (Poly.denote ctx) h₃
simp at h₃
simp [*]
def RawDvdCnstr.denote (ctx : Context) (c : RawDvdCnstr) : Prop :=
c.k c.e.denote ctx
private theorem dvd_gcd_of_dvd (d a x p : Int) (h : d a * x + p) : gcd d a p := by
rcases h with k, h
simp [Int.Linear.gcd]
replace h := congrArg (· - a*x) h
simp at h
rcases @Int.gcd_dvd_left d a with k₁, h₁
rcases @Int.gcd_dvd_right d a with k₂, h₂
conv at h => enter [2, 1]; rw [h₁]
conv at h => enter [2, 2]; rw [h₂]
rw [Int.mul_assoc, Int.mul_assoc, Int.mul_sub] at h
exists k₁ * k - k₂ * x
def RawDvdCnstr.norm (c : RawDvdCnstr) : DvdCnstr :=
{ k := c.k, p := c.e.toPoly }
def dvd_elim_cert (k₁ : Int) (p₁ : Poly) (k₂ : Int) (p₂ : Poly) : Bool :=
match p₁ with
| .add a _ p => k₂ == gcd k₁ a && p₂ == p
| _ => false
@[simp] theorem RawDvdCnstr.denote_norm_eq (ctx : Context) (c : RawDvdCnstr) : c.denote ctx = c.norm.denote ctx := by
simp [norm, denote, DvdCnstr.denote]
theorem dvd_elim (ctx : Context) (k₁ : Int) (p₁ : Poly) (k₂ : Int) (p₂ : Poly)
: dvd_elim_cert k₁ p₁ k₂ p₂ k₁ p₁.denote' ctx k₂ p₂.denote' ctx := by
rcases p₁ <;> simp [dvd_elim_cert]
next a _ p =>
intro _ _; subst k₂ p₂
rw [Int.add_comm]
apply dvd_gcd_of_dvd
def RawDvdCnstr.isEqv (c : RawDvdCnstr) (c' : DvdCnstr) (k : Int) : Bool :=
c.norm.isEqv c' k
def RawDvdCnstr.isUnsat (c : RawDvdCnstr) : Bool :=
c.norm.isUnsat
theorem RawDvdCnstr.eq_of_isEqv (ctx : Context) (c : RawDvdCnstr) (c' : DvdCnstr) (k : Int) (h : isEqv c c' k) : c.denote ctx = c'.denote' ctx := by
simp [DvdCnstr.eq_of_isEqv ctx c.norm c' k h, DvdCnstr.denote'_eq_denote]
theorem RawDvdCnstr.eq_false_of_isUnsat (ctx : Context) (c : RawDvdCnstr) (h : c.isUnsat) : c.denote ctx = False := by
simp [DvdCnstr.eq_false_of_isUnsat ctx c.norm h]
theorem solveCombine {x : Int} {d₁ a₁ p₁ : Int} {d₂ a₂ p₂ : Int} {α β d : Int}
private theorem dvd_solve_combine' {x : Int} {d₁ a₁ p₁ : Int} {d₂ a₂ p₂ : Int} {α β d : Int}
(h : α*a₁*d₂ + β*a₂*d₁ = d)
(h₁ : d₁ a₁*x + p₁)
(h₂ : d₂ a₂*x + p₂)
@@ -782,7 +732,7 @@ theorem solveCombine {x : Int} {d₁ a₁ p₁ : Int} {d₂ a₂ p₂ : Int} {α
rw [h, ac]
assumption
theorem solveElim {x : Int} {d₁ a₁ p₁ : Int} {d₂ a₂ p₂ : Int} {d : Int}
private theorem dvd_solve_elim' {x : Int} {d₁ a₁ p₁ : Int} {d₂ a₂ p₂ : Int} {d : Int}
(h : d = Int.gcd (a₁*d₂) (a₂*d₁))
(h₁ : d₁ a₁*x + p₁)
(h₂ : d₂ a₂*x + p₂)
@@ -804,61 +754,257 @@ theorem solveElim {x : Int} {d₁ a₁ p₁ : Int} {d₂ a₂ p₂ : Int} {d : I
rw [h₃, h₄, Int.mul_assoc, Int.mul_assoc, Int.mul_sub] at this
exact k₄ * k₁ - k₃ * k₂, this
def isSolveCombine (c c₂ c : DvdCnstr) (d α β : Int) : Bool :=
match c, c with
| { k := d₁, p := .add a₁ x₁ p₁ }, { k := d₂, p := .add a₂ x₂ p₂ } =>
def dvd_solve_combine_cert (d : Int) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d : Int) (p : Poly) (g α β : Int) : Bool :=
match p, p with
| .add a₁ x₁ p₁, .add a₂ x₂ p₂ =>
x₁ == x₂ &&
(d == α*a₁*d₂ + β*a₂*d₁ &&
(c.k == d₁*d₂ &&
c.p == .add d x₁ (p₁.mul (α*d₂) |>.combine (p₂.mul (β*d₁)))))
(g == α*a₁*d₂ + β*a₂*d₁ &&
(d == d₁*d₂ &&
p == .add g x₁ (p₁.mul (α*d₂) |>.combine (p₂.mul (β*d₁)))))
| _, _ => false
theorem DvdCnstr.solve_combine (ctx : Context) (c₁ c₂ c : DvdCnstr) (d α β : Int)
: isSolveCombine c c c d α β c.denote' ctx c.denote' ctx c.denote' ctx := by
simp [isSolveCombine]
split <;> simp <;> cases c <;> simp [denote', Poly.denote_combine, Poly.denote'_add]
next d₁ a₁ x₁ p₁ d₂ a₂ x₂ p₂ k p =>
intro _ hd _ hp; subst x₁ k p
simp [Poly.denote'_add, Poly.denote, Poly.denote_combine]
theorem dvd_solve_combine (ctx : Context) (d₁ : Int) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d : Int) (p : Poly) (g α β : Int)
: dvd_solve_combine_cert d p₁ d p₂ d p g α β d₁ p.denote' ctx d₂ p.denote' ctx d p.denote' ctx := by
simp [dvd_solve_combine_cert]
split <;> simp
next a₁ x₁ p₁ a₂ x₂ p₂ =>
intro _ hg hd hp; subst x₁ p
simp [Poly.denote'_add]
intro h₁ h₂
rw [Int.add_comm] at h₁ h₂
rw [Int.add_comm _ (d * x₂.denote ctx), Int.add_left_comm, Int.add_assoc]
exact solveCombine hd.symm h₁ h₂
rw [Int.add_comm _ (g * x₂.denote ctx), Int.add_left_comm, Int.add_assoc, hd]
exact dvd_solve_combine' hg.symm h₁ h₂
def isSolveElim (c c₂ c : DvdCnstr) (d : Int) : Bool :=
match c, c with
| { k := d₁, p := .add a₁ x₁ p₁ }, { k := d₂, p := .add a₂ x₂ p₂ } =>
def dvd_solve_elim_cert (d : Int) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d : Int) (p : Poly) : Bool :=
match p, p with
| .add a₁ x₁ p₁, .add a₂ x₂ p₂ =>
x₁ == x₂ &&
(d == Int.gcd (a₁*d₂) (a₂*d₁) &&
(c.k == d &&
c.p == (p₁.mul a₂ |>.combine (p₂.mul (- a₁)))))
p == (p₁.mul a₂ |>.combine (p₂.mul (- a₁))))
| _, _ => false
theorem DvdCnstr.solve_elim (ctx : Context) (c c₂ c : DvdCnstr) (d : Int)
: isSolveElim c c c d c.denote' ctx c.denote' ctx c.denote' ctx := by
simp [isSolveElim]
split <;> simp <;> cases c <;> simp [denote', Poly.denote_combine, Poly.denote'_add]
next d₁ a₁ x₁ p₁ d₂ a₂ x₂ p₂ k p =>
intro _ hd _ hp; subst x₁ k p
simp [Poly.denote'_eq_denote, Poly.denote_combine]
theorem dvd_solve_elim (ctx : Context) (d : Int) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d : Int) (p : Poly)
: dvd_solve_elim_cert d₁ p d p₂ d p d₁ p.denote' ctx d₂ p.denote' ctx d p.denote' ctx := by
simp [dvd_solve_elim_cert]
split <;> simp
next a₁ x₁ p₁ a₂ x₂ p₂ =>
intro _ hd _; subst x₁ p; simp
intro h₁ h₂
rw [Int.add_comm] at h₁ h₂
rw [ Int.sub_eq_add_neg]
exact solveElim hd h₁ h₂
exact dvd_solve_elim' hd h₁ h₂
def isNorm (c₁ c₂ : DvdCnstr) : Bool :=
c₁.k == c₂.k && c₁.p.norm == c₂.p
theorem dvd_norm (ctx : Context) (d : Int) (p₁ p₂ : Poly) : p₁.norm == p₂ d p₁.denote' ctx d p₂.denote' ctx := by
simp
intro; subst p₂
intro h₁
simp [Poly.denote_norm ctx p₁, h₁]
theorem DvdCnstr.of_isNorm (ctx : Context) (c₁ c : DvdCnstr)
: isNorm c₁ c₂ c₁.denote' ctx c₂.denote' ctx := by
cases c₁ <;> cases c₂ <;> simp [isNorm, denote', Poly.denote'_eq_denote]
next k₁ p₁ k₂ p₂ =>
intro; subst k₁; intro; subst p₂
intro h₁
simp [Poly.denote_norm ctx p₁, h₁]
theorem le_norm (ctx : Context) (p₁ p₂ : Poly) (h : p₁.norm == p) : p₁.denote' ctx 0 p₂.denote' ctx 0 := by
simp at h
replace h := congrArg (Poly.denote ctx) h
simp at h
simp [*]
theorem DvdCnstr.of_isEqv (ctx : Context) (c c : DvdCnstr) (k : Int) (h : isEqv c₁ c₂ k) : c₁.denote' ctx c₂.denote' ctx := by
simp [DvdCnstr.denote'_eq_denote, DvdCnstr.eq_of_isEqv ctx c₁ c k h]
def le_coeff_cert (p p : Poly) (k : Int) : Bool :=
k > 0 && (p₁.divCoeffs k && p == p₁.div k)
theorem le_coeff (ctx : Context) (p₁ p₂ : Poly) (k : Int) : le_coeff_cert p₁ p₂ k p₁.denote' ctx 0 p₂.denote' ctx 0 := by
simp [le_coeff_cert]
intro h₁ h₂ h₃
exact eq_of_norm_eq_of_divCoeffs h₁ h₂ h₃ |>.mp
def le_neg_cert (p₁ p₂ : Poly) : Bool :=
p₂ == (p₁.mul (-1) |>.addConst 1)
theorem le_neg (ctx : Context) (p₁ p₂ : Poly) : le_neg_cert p₁ p₂ ¬ p₁.denote' ctx 0 p₂.denote' ctx 0 := by
simp [le_neg_cert]
intro; subst p₂; simp; intro h
replace h : _ + 1 -0 := Int.neg_lt_neg <| Int.lt_of_not_ge h
simp at h
exact h
def Poly.leadCoeff (p : Poly) : Int :=
match p with
| .add a _ _ => a
| _ => 1
def le_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
let a₁ := p₁.leadCoeff.natAbs
let a₂ := p₂.leadCoeff.natAbs
p₃ == (p₁.mul a₂ |>.combine (p₂.mul a₁))
theorem le_combine (ctx : Context) (p₁ p₂ p₃ : Poly)
: le_combine_cert p₁ p₂ p₃ p₁.denote' ctx 0 p₂.denote' ctx 0 p₃.denote' ctx 0 := by
simp [le_combine_cert]
intro; subst p₃
intro h₁ h₂; simp
rw [ Int.add_zero 0]
apply Int.add_le_add
· rw [ Int.zero_mul (Poly.denote ctx p₂)]; apply Int.mul_le_mul_of_nonpos_right <;> simp [*]
· rw [ Int.zero_mul (Poly.denote ctx p₁)]; apply Int.mul_le_mul_of_nonpos_right <;> simp [*]
theorem le_unsat (ctx : Context) (p : Poly) : p.isUnsatLe p.denote' ctx 0 False := by
simp [Poly.isUnsatLe]; split <;> simp
intro h₁ h₂
have := Int.lt_of_le_of_lt h₂ h₁
simp at this
theorem eq_norm (ctx : Context) (p₁ p₂ : Poly) (h : p₁.norm == p₂) : p₁.denote' ctx = 0 p₂.denote' ctx = 0 := by
simp at h
replace h := congrArg (Poly.denote ctx) h
simp at h
simp [*]
def eq_coeff_cert (p p' : Poly) (k : Int) : Bool :=
p == p'.mul k && k > 0
theorem eq_coeff (ctx : Context) (p p' : Poly) (k : Int) : eq_coeff_cert p p' k p.denote' ctx = 0 p'.denote' ctx = 0 := by
simp [eq_coeff_cert]
intro _ _; simp [mul_eq_zero_iff, *]
theorem eq_unsat (ctx : Context) (p : Poly) : p.isUnsatEq p.denote' ctx = 0 False := by
simp [Poly.isUnsatEq] <;> split <;> simp
def eq_unsat_coeff_cert (p : Poly) (k : Int) : Bool :=
p.divCoeffs k && k > 0 && cmod p.getConst k < 0
theorem eq_unsat_coeff (ctx : Context) (p : Poly) (k : Int) : eq_unsat_coeff_cert p k p.denote' ctx = 0 False := by
simp [eq_unsat_coeff_cert]
intro h₁ h₂ h₃
have h := poly_eq_zero_eq_false ctx h₁ h₂ h₃; clear h₁ h₂ h₃
simp [h]
def Poly.coeff (p : Poly) (x : Var) : Int :=
match p with
| .add a y p => bif x == y then a else coeff p x
| .num _ => 0
private theorem eq_add_coeff_insert (ctx : Context) (p : Poly) (x : Var) : p.denote ctx = (p.coeff x) * (x.denote ctx) + (p.insert (-p.coeff x) x).denote ctx := by
simp; rw [ Int.add_assoc, Int.add_neg_cancel_right]
private theorem dvd_of_eq' {a x p : Int} : a*x + p = 0 a p := by
intro h
replace h := Int.neg_eq_of_add_eq_zero h
rw [Int.mul_comm, Int.neg_mul, Eq.comm, Int.mul_comm] at h
exact -x, h
private def abs (x : Int) : Int :=
Int.ofNat x.natAbs
private theorem abs_dvd {a p : Int} (h : a p) : abs a p := by
cases a <;> simp [abs]
· simp at h; assumption
· simp [Int.negSucc_eq] at h; assumption
def dvd_of_eq_cert (x : Var) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) : Bool :=
let a := p₁.coeff x
d₂ == abs a && p₂ == p₁.insert (-a) x
theorem dvd_of_eq (ctx : Context) (x : Var) (p₁ : Poly) (d₂ : Int) (p₂ : Poly)
: dvd_of_eq_cert x p₁ d₂ p₂ p₁.denote' ctx = 0 d₂ p₂.denote' ctx := by
simp [dvd_of_eq_cert]
intro h₁ h₂
have h := eq_add_coeff_insert ctx p₁ x
rw [ h₂] at h
rw [h, h₁]
intro h₃
apply abs_dvd
apply dvd_of_eq' h₃
private theorem eq_dvd_subst' {a x p d b q : Int} : a*x + p = 0 d b*x + q a*d a*q - b*p := by
intro h₁ z, h₂
have h : a*q - b*p = a*(b*x + q) - b*(a*x+p) := by
conv => rhs; rw [Int.sub_eq_add_neg]; rhs; rw [Int.mul_add, Int.neg_add]
rw [Int.mul_add, Int.add_assoc, Int.mul_left_comm a b x]
rw [Int.add_comm (b*(a*x)), Int.add_neg_cancel_right, Int.sub_eq_add_neg]
rw [h₁, h₂] at h
simp at h
rw [ Int.mul_assoc] at h
exact z, h
def eq_dvd_subst_cert (x : Var) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d₃ : Int) (p₃ : Poly) : Bool :=
let a := p₁.coeff x
let b := p₂.coeff x
let p := p₁.insert (-a) x
let q := p₂.insert (-b) x
d₃ == abs (a * d₂) &&
p₃ == (q.mul a |>.combine (p.mul (-b)))
theorem eq_dvd_subst (ctx : Context) (x : Var) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d₃ : Int) (p₃ : Poly)
: eq_dvd_subst_cert x p₁ d₂ p₂ d₃ p₃ p₁.denote' ctx = 0 d₂ p₂.denote' ctx d₃ p₃.denote' ctx := by
simp [eq_dvd_subst_cert]
have eq₁ := eq_add_coeff_insert ctx p₁ x
have eq₂ := eq_add_coeff_insert ctx p₂ x
revert eq₁ eq₂
generalize p₁.coeff x = a
generalize p₂.coeff x = b
generalize p₁.insert (-a) x = p
generalize p₂.insert (-b) x = q
intro eq₁; simp [eq₁]; clear eq₁
intro eq₂; simp [eq₂]; clear eq₂
intro; subst d₃
intro; subst p₃
intro h₁ h₂
rw [Int.add_comm] at h₁ h₂
have := eq_dvd_subst' h₁ h₂
rw [Int.sub_eq_add_neg, Int.add_comm] at this
apply abs_dvd
simp [this]
def eq_eq_subst_cert (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
let a := p₁.coeff x
let b := p₂.coeff x
p₃ == (p₁.mul b |>.combine (p₂.mul (-a)))
theorem eq_eq_subst (ctx : Context) (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
: eq_eq_subst_cert x p₁ p₂ p₃ p₁.denote' ctx = 0 p₂.denote' ctx = 0 p₃.denote' ctx = 0 := by
simp [eq_eq_subst_cert]
intro; subst p₃
intro h₁ h₂
simp [*]
def eq_le_subst_nonneg_cert (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
let a := p₁.coeff x
let b := p₂.coeff x
a 0 && p₃ == (p₂.mul a |>.combine (p₁.mul (-b)))
theorem eq_le_subst_nonneg (ctx : Context) (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
: eq_le_subst_nonneg_cert x p₁ p₂ p₃ p₁.denote' ctx = 0 p₂.denote' ctx 0 p₃.denote' ctx 0 := by
simp [eq_le_subst_nonneg_cert]
intro h
intro; subst p₃
intro h₁ h₂
replace h₂ := Int.mul_le_mul_of_nonneg_left h₂ h
simp at h₂
simp [*]
def eq_le_subst_nonpos_cert (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
let a := p₁.coeff x
let b := p₂.coeff x
a 0 && p₃ == (p₁.mul b |>.combine (p₂.mul (-a)))
theorem eq_le_subst_nonpos (ctx : Context) (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
: eq_le_subst_nonpos_cert x p₁ p₂ p₃ p₁.denote' ctx = 0 p₂.denote' ctx 0 p₃.denote' ctx 0 := by
simp [eq_le_subst_nonpos_cert]
intro h
intro; subst p₃
intro h₁ h₂
simp [*]
replace h₂ := Int.mul_le_mul_of_nonpos_left h₂ h; simp at h₂; clear h
rw [ Int.neg_zero]
apply Int.neg_le_neg
rw [Int.mul_comm]
assumption
def eq_of_core_cert (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
p₃ == p₁.combine (p₂.mul (-1))
theorem eq_of_core (ctx : Context) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
: eq_of_core_cert p₁ p₂ p₃ p₁.denote' ctx = p₂.denote' ctx p₃.denote' ctx = 0 := by
simp [eq_of_core_cert]
intro; subst p₃; simp
intro h; rw [h, Int.sub_eq_add_neg, Int.sub_self]
end Int.Linear

View File

@@ -56,7 +56,7 @@ protected theorem le_total (a b : Int) : a ≤ b b ≤ a :=
let k, (hk : m + k = n) := Nat.le.dest h
le.intro k (by rw [ hk]; rfl)
theorem ofNat_zero_le (n : Nat) : 0 (n : Int) := ofNat_le.2 n.zero_le
@[simp] theorem ofNat_zero_le (n : Nat) : 0 (n : Int) := ofNat_le.2 n.zero_le
theorem eq_ofNat_of_zero_le {a : Int} (h : 0 a) : n : Nat, a = n := by
have t := le.dest_sub h; rwa [Int.sub_zero] at t
@@ -1011,11 +1011,16 @@ theorem sign_eq_neg_one_iff_neg {a : Int} : sign a = -1 ↔ a < 0 :=
exact Int.le_add_one (ofNat_nonneg _)
| .negSucc _ => simp +decide [sign]
theorem mul_sign : i : Int, i * sign i = natAbs i
@[simp] theorem mul_sign_self : i : Int, i * sign i = natAbs i
| succ _ => Int.mul_one _
| 0 => Int.mul_zero _
| -[_+1] => Int.mul_neg_one _
@[deprecated mul_sign_self (since := "2025-02-24")] abbrev mul_sign := @mul_sign_self
@[simp] theorem sign_mul_self : sign i * i = natAbs i := by
rw [Int.mul_comm, mul_sign_self]
/- ## natAbs -/
theorem natAbs_ne_zero {a : Int} : a.natAbs 0 a 0 := not_congr Int.natAbs_eq_zero

View File

@@ -8,8 +8,8 @@ import Init.Data.List.Count
import Init.Data.Subtype
import Init.BinderNameHint
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -190,7 +190,7 @@ theorem length_attachWith {p : α → Prop} {l H} : length (l.attachWith p H) =
@[simp]
theorem pmap_eq_nil_iff {p : α Prop} {f : a, p a β} {l H} : pmap f l H = [] l = [] := by
rw [ length_eq_zero, length_pmap, length_eq_zero]
rw [ length_eq_zero_iff, length_pmap, length_eq_zero_iff]
theorem pmap_ne_nil_iff {P : α Prop} (f : (a : α) P a β) {xs : List α}
(H : (a : α), a xs P a) : xs.pmap f H [] xs [] := by

View File

@@ -58,8 +58,8 @@ Further operations are defined in `Init.Data.List.BasicAux`
-/
set_option linter.missingDocs true -- keep it documented
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Decidable List

View File

@@ -6,8 +6,8 @@ Author: Leonardo de Moura
prelude
import Init.Data.Nat.Linear
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
universe u

View File

@@ -9,8 +9,8 @@ import Init.Control.Id
import Init.Control.Lawful
import Init.Data.List.Basic
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
universe u v w u₁ u₂

View File

@@ -10,8 +10,8 @@ import Init.Data.List.Sublist
# Lemmas about `List.countP` and `List.count`.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -87,7 +87,7 @@ theorem countP_le_length : countP p l ≤ l.length := by
countP_pos_iff
@[simp] theorem countP_eq_zero {p} : countP p l = 0 a l, ¬p a := by
simp only [countP_eq_length_filter, length_eq_zero, filter_eq_nil_iff]
simp only [countP_eq_length_filter, length_eq_zero_iff, filter_eq_nil_iff]
@[simp] theorem countP_eq_length {p} : countP p l = l.length a l, p a := by
rw [countP_eq_length_filter, filter_length_eq_length]

View File

@@ -12,8 +12,8 @@ import Init.Data.List.Find
# Lemmas about `List.eraseP`, `List.erase`, and `List.eraseIdx`.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -137,7 +137,7 @@ theorem mem_of_mem_eraseP {l : List α} : a ∈ l.eraseP p → a ∈ l := (erase
@[simp] theorem eraseP_eq_self_iff {p} {l : List α} : l.eraseP p = l a l, ¬ p a := by
rw [ Sublist.length_eq (eraseP_sublist l), length_eraseP]
split <;> rename_i h
· simp only [any_eq_true, length_eq_zero] at h
· simp only [any_eq_true, length_eq_zero_iff] at h
constructor
· intro; simp_all [Nat.sub_one_eq_self]
· intro; obtain x, m, h := h; simp_all

View File

@@ -6,8 +6,8 @@ Authors: François G. Dorais
prelude
import Init.Data.List.OfFn
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -15,8 +15,8 @@ Lemmas about `List.findSome?`, `List.find?`, `List.findIdx`, `List.findIdx?`, `L
and `List.lookup`.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -514,47 +514,6 @@ private theorem findIdx?_go_eq {p : α → Bool} {xs : List α} {i : Nat} :
(x :: xs).findIdx? p = if p x then some 0 else (xs.findIdx? p).map fun i => i + 1 := by
simp [findIdx?, findIdx?_go_eq]
/-! ### findFinIdx? -/
@[simp] theorem findFinIdx?_nil {p : α Bool} : findFinIdx? p [] = none := rfl
theorem findIdx?_go_eq_map_findFinIdx?_go_val {xs : List α} {p : α Bool} {i : Nat} {h} :
List.findIdx?.go p xs i =
(List.findFinIdx?.go p l xs i h).map (·.val) := by
unfold findIdx?.go
unfold findFinIdx?.go
split
· simp_all
· simp only
split
· simp
· rw [findIdx?_go_eq_map_findFinIdx?_go_val]
theorem findIdx?_eq_map_findFinIdx?_val {xs : List α} {p : α Bool} :
xs.findIdx? p = (xs.findFinIdx? p).map (·.val) := by
simp [findIdx?, findFinIdx?]
rw [findIdx?_go_eq_map_findFinIdx?_go_val]
@[simp] theorem findFinIdx?_cons {p : α Bool} {x : α} {xs : List α} :
findFinIdx? p (x :: xs) = if p x then some 0 else (findFinIdx? p xs).map Fin.succ := by
rw [ Option.map_inj_right (f := Fin.val) (fun a b => Fin.eq_of_val_eq)]
rw [ findIdx?_eq_map_findFinIdx?_val]
rw [findIdx?_cons]
split
· simp
· rw [findIdx?_eq_map_findFinIdx?_val]
simp [Function.comp_def]
@[simp] theorem findFinIdx?_subtype {p : α Prop} {l : List { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findFinIdx? f = (l.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
unfold unattach
induction l with
| nil => simp
| cons a l ih =>
simp [hf, findFinIdx?_cons]
split <;> simp [ih, Function.comp_def]
/-! ### findIdx -/
theorem findIdx_cons (p : α Bool) (b : α) (l : List α) :
@@ -976,6 +935,71 @@ theorem findIdx_eq_getD_findIdx? {xs : List α} {p : α → Bool} :
simp [hf, findIdx?_cons]
split <;> simp [ih, Function.comp_def]
/-! ### findFinIdx? -/
@[simp] theorem findFinIdx?_nil {p : α Bool} : findFinIdx? p [] = none := rfl
theorem findIdx?_go_eq_map_findFinIdx?_go_val {xs : List α} {p : α Bool} {i : Nat} {h} :
List.findIdx?.go p xs i =
(List.findFinIdx?.go p l xs i h).map (·.val) := by
unfold findIdx?.go
unfold findFinIdx?.go
split
· simp_all
· simp only
split
· simp
· rw [findIdx?_go_eq_map_findFinIdx?_go_val]
theorem findIdx?_eq_map_findFinIdx?_val {xs : List α} {p : α Bool} :
xs.findIdx? p = (xs.findFinIdx? p).map (·.val) := by
simp [findIdx?, findFinIdx?]
rw [findIdx?_go_eq_map_findFinIdx?_go_val]
theorem findFinIdx?_eq_pmap_findIdx? {xs : List α} {p : α Bool} :
xs.findFinIdx? p =
(xs.findIdx? p).pmap
(fun i m => by simp [findIdx?_eq_some_iff_getElem] at m; exact i, m.choose)
(fun i h => h) := by
simp [findIdx?_eq_map_findFinIdx?_val, Option.pmap_map]
@[simp] theorem findFinIdx?_cons {p : α Bool} {x : α} {xs : List α} :
findFinIdx? p (x :: xs) = if p x then some 0 else (findFinIdx? p xs).map Fin.succ := by
rw [ Option.map_inj_right (f := Fin.val) (fun a b => Fin.eq_of_val_eq)]
rw [ findIdx?_eq_map_findFinIdx?_val]
rw [findIdx?_cons]
split
· simp
· rw [findIdx?_eq_map_findFinIdx?_val]
simp [Function.comp_def]
@[simp] theorem findFinIdx?_eq_none_iff {l : List α} {p : α Bool} :
l.findFinIdx? p = none x l, ¬ p x := by
simp [findFinIdx?_eq_pmap_findIdx?]
@[simp]
theorem findFinIdx?_eq_some_iff {xs : List α} {p : α Bool} {i : Fin xs.length} :
xs.findFinIdx? p = some i
p xs[i] j (hji : j < i), ¬p (xs[j]'(Nat.lt_trans hji i.2)) := by
simp only [findFinIdx?_eq_pmap_findIdx?, Option.pmap_eq_some_iff, findIdx?_eq_some_iff_getElem,
Bool.not_eq_true, Option.mem_def, exists_and_left, and_exists_self, Fin.getElem_fin]
constructor
· rintro a, h, w₁, w₂, rfl
exact w₁, fun j hji => by simpa using w₂ j hji
· rintro h, w
exact i, i.2, h, fun j hji => w j, by omega hji, rfl
@[simp] theorem findFinIdx?_subtype {p : α Prop} {l : List { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findFinIdx? f = (l.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
unfold unattach
induction l with
| nil => simp
| cons a l ih =>
simp [hf, findFinIdx?_cons]
split <;> simp [ih, Function.comp_def]
/-! ### idxOf
The verification API for `idxOf` is still incomplete.
@@ -1035,6 +1059,36 @@ theorem idxOf_lt_length [BEq α] [LawfulBEq α] {l : List α} (h : a ∈ l) : l.
@[deprecated idxOf_lt_length (since := "2025-01-29")]
abbrev indexOf_lt_length := @idxOf_lt_length
/-! ### finIdxOf?
The verification API for `finIdxOf?` is still incomplete.
The lemmas below should be made consistent with those for `findFinIdx?` (and proved using them).
-/
theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : List α} {a : α} :
xs.idxOf? a = (xs.finIdxOf? a).map (·.val) := by
simp [idxOf?, finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
@[simp] theorem finIdxOf?_nil [BEq α] : ([] : List α).finIdxOf? a = none := rfl
@[simp] theorem finIdxOf?_cons [BEq α] (a : α) (xs : List α) :
(a :: xs).finIdxOf? b =
if a == b then some 0, by simp else (xs.finIdxOf? b).map (·.succ) := by
simp [finIdxOf?]
@[simp] theorem finIdxOf?_eq_none_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} :
l.finIdxOf? a = none a l := by
simp only [finIdxOf?, findFinIdx?_eq_none_iff, beq_iff_eq]
constructor
· intro w m
exact w a m rfl
· rintro h a m rfl
exact h m
@[simp] theorem finIdxOf?_eq_some_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} {i : Fin l.length} :
l.finIdxOf? a = some i l[i] = a j (_ : j < i), ¬l[j] = a := by
simp only [finIdxOf?, findFinIdx?_eq_some_iff, beq_iff_eq]
/-! ### idxOf?
The verification API for `idxOf?` is still incomplete.
@@ -1060,12 +1114,6 @@ theorem idxOf?_cons [BEq α] (a : α) (xs : List α) (b : α) :
@[deprecated idxOf?_eq_none_iff (since := "2025-01-29")]
abbrev indexOf?_eq_none_iff := @idxOf?_eq_none_iff
/-! ### finIdxOf? -/
theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : List α} {a : α} :
xs.idxOf? a = (xs.finIdxOf? a).map (·.val) := by
simp [idxOf?, finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
/-! ### lookup -/
section lookup

View File

@@ -16,8 +16,8 @@ If you import `Init.Data.List.Basic` but do not import this file,
then at runtime you will get non-tail recursive versions of the following definitions.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -210,7 +210,7 @@ def modifyTR (f : αα) (n : Nat) (l : List α) : List α := go l n #[] whe
| a :: l, 0, acc => acc.toListAppend (f a :: l)
| a :: l, n+1, acc => go l n (acc.push a)
theorem modifyTR_go_eq : l n, modifyTR.go f l n acc = acc.toList ++ modify f n l
theorem modifyTR_go_eq : l i, modifyTR.go f l i acc = acc.toList ++ modify f i l
| [], n => by cases n <;> simp [modifyTR.go, modify]
| a :: l, 0 => by simp [modifyTR.go, modify]
| a :: l, n+1 => by simp [modifyTR.go, modify, modifyTR_go_eq l]

View File

@@ -74,8 +74,8 @@ Also
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -96,9 +96,15 @@ theorem ne_nil_of_length_eq_add_one (_ : length l = n + 1) : l ≠ [] := fun _ =
theorem ne_nil_of_length_pos (_ : 0 < length l) : l [] := fun _ => nomatch l
@[simp] theorem length_eq_zero : length l = 0 l = [] :=
@[simp] theorem length_eq_zero_iff : length l = 0 l = [] :=
eq_nil_of_length_eq_zero, fun h => h rfl
@[deprecated length_eq_zero_iff (since := "2025-02-24")]
abbrev length_eq_zero := @length_eq_zero_iff
theorem eq_nil_iff_length_eq_zero : l = [] length l = 0 :=
length_eq_zero_iff.symm
theorem length_pos_of_mem {a : α} : {l : List α}, a l 0 < length l
| _::_, _ => Nat.zero_lt_succ _
@@ -123,12 +129,21 @@ theorem exists_cons_of_length_eq_add_one :
{l : List α}, l.length = n + 1 h t, l = h :: t
| _::_, _ => _, _, rfl
theorem length_pos {l : List α} : 0 < length l l [] :=
Nat.pos_iff_ne_zero.trans (not_congr length_eq_zero)
theorem length_pos_iff {l : List α} : 0 < length l l [] :=
Nat.pos_iff_ne_zero.trans (not_congr length_eq_zero_iff)
theorem length_eq_one {l : List α} : length l = 1 a, l = [a] :=
@[deprecated length_pos_iff (since := "2025-02-24")]
abbrev length_pos := @length_pos_iff
theorem ne_nil_iff_length_pos {l : List α} : l [] 0 < length l :=
length_pos_iff.symm
theorem length_eq_one_iff {l : List α} : length l = 1 a, l = [a] :=
fun h => match l, h with | [_], _ => _, rfl, fun _, h => by simp [h]
@[deprecated length_eq_one_iff (since := "2025-02-24")]
abbrev length_eq_one := @length_eq_one_iff
/-! ### cons -/
theorem cons_ne_nil (a : α) (l : List α) : a :: l [] := nofun
@@ -284,7 +299,7 @@ such a rewrite, with `rw [getElem_of_eq h]`.
theorem getElem_of_eq {l l' : List α} (h : l = l') {i : Nat} (w : i < l.length) :
l[i] = l'[i]'(h w) := by cases h; rfl
theorem getElem_zero {l : List α} (h : 0 < l.length) : l[0] = l.head (length_pos.mp h) :=
theorem getElem_zero {l : List α} (h : 0 < l.length) : l[0] = l.head (length_pos_iff.mp h) :=
match l, h with
| _ :: _, _ => rfl
@@ -375,7 +390,7 @@ theorem eq_append_cons_of_mem {a : α} {xs : List α} (h : a ∈ xs) :
theorem mem_cons_of_mem (y : α) {a : α} {l : List α} : a l a y :: l := .tail _
theorem exists_mem_of_ne_nil (l : List α) (h : l []) : x, x l :=
exists_mem_of_length_pos (length_pos.2 h)
exists_mem_of_length_pos (length_pos_iff.2 h)
theorem eq_nil_iff_forall_not_mem {l : List α} : l = [] a, a l := by
cases l <;> simp [-not_or]
@@ -533,7 +548,7 @@ theorem isEmpty_eq_false_iff_exists_mem {xs : List α} :
cases xs <;> simp
theorem isEmpty_iff_length_eq_zero {l : List α} : l.isEmpty l.length = 0 := by
rw [isEmpty_iff, length_eq_zero]
rw [isEmpty_iff, length_eq_zero_iff]
/-! ### any / all -/
@@ -910,13 +925,13 @@ theorem head?_eq_getElem? : ∀ l : List α, head? l = l[0]?
| [] => rfl
| a :: l => by simp
theorem head_eq_getElem (l : List α) (h : l []) : head l h = l[0]'(length_pos.mpr h) := by
theorem head_eq_getElem (l : List α) (h : l []) : head l h = l[0]'(length_pos_iff.mpr h) := by
cases l with
| nil => simp at h
| cons _ _ => simp
theorem getElem_zero_eq_head (l : List α) (h : 0 < l.length) :
l[0] = head l (by simpa [length_pos] using h) := by
l[0] = head l (by simpa [length_pos_iff] using h) := by
cases l with
| nil => simp at h
| cons _ _ => simp
@@ -1003,7 +1018,7 @@ theorem one_lt_length_of_tail_ne_nil {l : List α} (h : l.tail ≠ []) : 1 < l.l
| nil => simp at h
| cons _ l =>
simp only [tail_cons, ne_eq] at h
exact Nat.lt_add_of_pos_left (length_pos.mpr h)
exact Nat.lt_add_of_pos_left (length_pos_iff.mpr h)
@[simp] theorem head_tail (l : List α) (h : l.tail []) :
(tail l).head h = l[1]'(one_lt_length_of_tail_ne_nil h) := by
@@ -2883,7 +2898,7 @@ theorem getLast?_replicate (a : α) (n : Nat) : (replicate n a).getLast? = if n
-- We unfold `leftpad` and `rightpad` for verification purposes.
attribute [simp] leftpad rightpad
-- `length_leftpad` is in `Init.Data.List.Nat.Basic`.
-- `length_leftpad` and `length_rightpad` are in `Init.Data.List.Nat.Basic`.
theorem leftpad_prefix (n : Nat) (a : α) (l : List α) :
replicate (n - length l) a <+: leftpad n a l := by
@@ -3071,8 +3086,12 @@ variable [BEq α]
@[simp] theorem replace_cons_self [LawfulBEq α] {a : α} : (a::as).replace a b = b::as := by
simp [replace_cons]
@[simp] theorem replace_of_not_mem {l : List α} (h : !l.elem a) : l.replace a b = l := by
induction l <;> simp_all [replace_cons]
@[simp] theorem replace_of_not_mem [LawfulBEq α] {l : List α} (h : a l) : l.replace a b = l := by
induction l with
| nil => rfl
| cons x xs ih =>
simp only [replace_cons]
split <;> simp_all
@[simp] theorem length_replace {l : List α} : (l.replace a b).length = l.length := by
induction l with
@@ -3155,7 +3174,7 @@ theorem replace_take {l : List α} {i : Nat} :
(replicate n a).replace a b = b :: replicate (n - 1) a := by
cases n <;> simp_all [replicate_succ, replace_cons]
@[simp] theorem replace_replicate_ne {a b c : α} (h : !b == a) :
@[simp] theorem replace_replicate_ne [LawfulBEq α] {a b c : α} (h : !b == a) :
(replicate n a).replace b c = replicate n a := by
rw [replace_of_not_mem]
simp_all
@@ -3417,7 +3436,7 @@ theorem get_cons_succ {as : List α} {h : i + 1 < (a :: as).length} :
theorem get_cons_succ' {as : List α} {i : Fin as.length} :
(a :: as).get i.succ = as.get i := rfl
theorem get_mk_zero : {l : List α} (h : 0 < l.length), l.get 0, h = l.head (length_pos.mp h)
theorem get_mk_zero : {l : List α} (h : 0 < l.length), l.get 0, h = l.head (length_pos_iff.mp h)
| _::_, _ => rfl
set_option linter.deprecated false in

View File

@@ -7,8 +7,8 @@ prelude
import Init.Data.List.Lemmas
import Init.Data.List.Nat.TakeDrop
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -11,8 +11,8 @@ import Init.Data.List.OfFn
import Init.Data.Fin.Lemmas
import Init.Data.Option.Attach
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -10,8 +10,8 @@ import Init.Data.List.Lemmas
# Lemmas about `List.min?` and `List.max?.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -11,8 +11,8 @@ import Init.Data.List.Attach
# Lemmas about `List.mapM` and `List.forM`.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -321,24 +321,21 @@ theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
forIn' l init (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
l.attach.foldlM (fun b a, m => g a m b <$> f a m b) init := by
simp only [forIn'_eq_foldlM]
generalize l.attach = l'
induction l' generalizing init <;> simp_all
induction l.attach generalizing init <;> simp_all
theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
(l : List α) (f : (a : α) a l β β) (init : β) :
forIn' l init (fun a m b => pure (.yield (f a m b))) =
pure (f := m) (l.attach.foldl (fun b a, h => f a h b) init) := by
simp only [forIn'_eq_foldlM]
generalize l.attach = l'
induction l' generalizing init <;> simp_all
induction l.attach generalizing init <;> simp_all
@[simp] theorem forIn'_yield_eq_foldl
(l : List α) (f : (a : α) a l β β) (init : β) :
forIn' (m := Id) l init (fun a m b => .yield (f a m b)) =
l.attach.foldl (fun b a, h => f a h b) init := by
simp only [forIn'_eq_foldlM]
generalize l.attach = l'
induction l' generalizing init <;> simp_all
induction l.attach generalizing init <;> simp_all
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
(l : List α) (g : α β) (f : (b : β) b l.map g γ m (ForInStep γ)) :

View File

@@ -7,8 +7,8 @@ prelude
import Init.Data.Nat.Lemmas
import Init.Data.List.Basic
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -15,8 +15,8 @@ import Init.Data.Nat.Lemmas
In particular, `omega` is available here.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Nat
@@ -44,10 +44,42 @@ theorem tail_dropLast (l : List α) : tail (dropLast l) = dropLast (tail l) := b
/-! ### filter -/
theorem length_filter_lt_length_iff_exists {l} :
length (filter p l) < length l x l, ¬p x := by
@[simp]
theorem length_filter_pos_iff {l : List α} {p : α Bool} :
0 < (filter p l).length x l, p x := by
simpa [length_eq_countP_add_countP p l, countP_eq_length_filter] using
countP_pos_iff (p := fun x => ¬p x)
countP_pos_iff (p := p)
@[simp]
theorem length_filter_lt_length_iff_exists {l} :
(filter p l).length < l.length x l, ¬p x := by
simp [length_eq_countP_add_countP p l, countP_eq_length_filter]
/-! ### filterMap -/
@[simp]
theorem length_filterMap_pos_iff {xs : List α} {f : α Option β} :
0 < (filterMap f xs).length (x : α) (_ : x xs) (b : β), f x = some b := by
induction xs with
| nil => simp
| cons x xs ih =>
simp only [filterMap, mem_cons, exists_prop, exists_eq_or_imp]
split
· simp_all [ih]
· simp_all
@[simp]
theorem length_filterMap_lt_length_iff_exists {xs : List α} {f : α Option β} :
(filterMap f xs).length < xs.length (x : α) (_ : x xs), f x = none := by
induction xs with
| nil => simp
| cons x xs ih =>
simp only [filterMap, mem_cons, exists_prop, exists_eq_or_imp]
split
· simp_all only [exists_prop, length_cons, true_or, iff_true]
have := length_filterMap_le f xs
omega
· simp_all
/-! ### reverse -/
@@ -63,10 +95,18 @@ theorem getElem_eq_getElem_reverse {l : List α} {i} (h : i < l.length) :
to the larger of `n` and `l.length` -/
-- We don't mark this as a `@[simp]` lemma since we allow `simp` to unfold `leftpad`,
-- so the left hand side simplifies directly to `n - l.length + l.length`.
theorem leftpad_length (n : Nat) (a : α) (l : List α) :
theorem length_leftpad (n : Nat) (a : α) (l : List α) :
(leftpad n a l).length = max n l.length := by
simp only [leftpad, length_append, length_replicate, Nat.sub_add_eq_max]
@[deprecated length_leftpad (since := "2025-02-24")]
abbrev leftpad_length := @length_leftpad
theorem length_rightpad (n : Nat) (a : α) (l : List α) :
(rightpad n a l).length = max n l.length := by
simp [rightpad]
omega
/-! ### eraseIdx -/
theorem mem_eraseIdx_iff_getElem {x : α} :

View File

@@ -7,8 +7,8 @@ prelude
import Init.Data.List.Count
import Init.Data.Nat.Lemmas
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -7,8 +7,8 @@ prelude
import Init.Data.List.Nat.TakeDrop
import Init.Data.List.Erase
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -7,8 +7,8 @@ prelude
import Init.Data.List.Nat.Range
import Init.Data.List.Find
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -12,8 +12,8 @@ import Init.Data.List.Nat.Modify
Proves various lemmas about `List.insertIdx`.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Function Nat

View File

@@ -8,8 +8,8 @@ prelude
import Init.Data.List.Nat.TakeDrop
import Init.Data.List.Nat.Erase
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -140,19 +140,19 @@ theorem modifyTailIdx_modifyTailIdx_self {f g : List α → List α} (n : Nat) (
/-! ### modify -/
@[simp] theorem modify_nil (f : α α) (n) : [].modify f n = [] := by cases n <;> rfl
@[simp] theorem modify_nil (f : α α) (i) : [].modify f i = [] := by cases i <;> rfl
@[simp] theorem modify_zero_cons (f : α α) (a : α) (l : List α) :
(a :: l).modify f 0 = f a :: l := rfl
@[simp] theorem modify_succ_cons (f : α α) (a : α) (l : List α) (n) :
(a :: l).modify f (n + 1) = a :: l.modify f n := by rfl
@[simp] theorem modify_succ_cons (f : α α) (a : α) (l : List α) (i) :
(a :: l).modify f (i + 1) = a :: l.modify f i := by rfl
theorem modifyHead_eq_modify_zero (f : α α) (l : List α) :
l.modifyHead f = l.modify f 0 := by cases l <;> simp
@[simp] theorem modify_eq_nil_iff {f : α α} {n} {l : List α} :
l.modify f n = [] l = [] := by cases l <;> cases n <;> simp
@[simp] theorem modify_eq_nil_iff {f : α α} {i} {l : List α} :
l.modify f i = [] l = [] := by cases l <;> cases i <;> simp
theorem getElem?_modify (f : α α) :
i (l : List α) j, (modify f i l)[j]? = (fun a => if i = j then f a else a) <$> l[j]?
@@ -189,8 +189,8 @@ theorem getElem_modify (f : αα) (i) (l : List α) (j) (h : j < (modify f
@[simp] theorem getElem_modify_ne (f : α α) {i j} (l : List α) (h : i j) (h') :
(modify f i l)[j] = l[j]'(by simpa using h') := by simp [getElem_modify, h]
theorem modify_eq_self {f : α α} {n} {l : List α} (h : l.length n) :
l.modify f n = l := by
theorem modify_eq_self {f : α α} {i} {l : List α} (h : l.length i) :
l.modify f i = l := by
apply ext_getElem
· simp
· intro m h₁ h₂
@@ -198,16 +198,16 @@ theorem modify_eq_self {f : αα} {n} {l : List α} (h : l.length ≤ n) :
intro h
omega
theorem modify_modify_eq (f g : α α) (n) (l : List α) :
(modify f n l).modify g n = modify (g f) n l := by
theorem modify_modify_eq (f g : α α) (i) (l : List α) :
(modify f i l).modify g i = modify (g f) i l := by
apply ext_getElem
· simp
· intro m h₁ h₂
simp only [getElem_modify, Function.comp_apply]
split <;> simp
theorem modify_modify_ne (f g : α α) {m n} (l : List α) (h : m n) :
(modify f m l).modify g n = (l.modify g n).modify f m := by
theorem modify_modify_ne (f g : α α) {i j} (l : List α) (h : i j) :
(modify f i l).modify g j = (l.modify g j).modify f i := by
apply ext_getElem
· simp
· intro m' h₁ h₂
@@ -234,13 +234,13 @@ theorem modify_eq_take_cons_drop {f : αα} {i} {l : List α} (h : i < l.le
modify f i l = take i l ++ f l[i] :: drop (i + 1) l := by
rw [modify_eq_take_drop, drop_eq_getElem_cons h]; rfl
theorem exists_of_modify (f : α α) {n} {l : List α} (h : n < l.length) :
l₁ a l₂, l = l₁ ++ a :: l₂ l₁.length = n modify f n l = l₁ ++ f a :: l₂ :=
theorem exists_of_modify (f : α α) {i} {l : List α} (h : i < l.length) :
l₁ a l₂, l = l₁ ++ a :: l₂ l₁.length = i modify f i l = l₁ ++ f a :: l₂ :=
match exists_of_modifyTailIdx _ (Nat.le_of_lt h) with
| _, _::_, eq, hl, H => _, _, _, eq, hl, H
| _, [], eq, hl, _ => nomatch Nat.ne_of_gt h (eq append_nil _ hl)
@[simp] theorem modify_id (n) (l : List α) : l.modify id n = l := by
@[simp] theorem modify_id (i) (l : List α) : l.modify id i = l := by
simp [modify]
theorem take_modify (f : α α) (i j) (l : List α) :

View File

@@ -12,8 +12,8 @@ import Init.Data.List.Pairwise
# Lemmas about `List.Pairwise`
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -7,8 +7,8 @@ prelude
import Init.Data.List.Nat.TakeDrop
import Init.Data.List.Perm
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -14,8 +14,8 @@ import Init.Data.List.Erase
# Lemmas about `List.range` and `List.enum`
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -16,8 +16,8 @@ These are in a separate file from most of the lemmas about `List.IsSuffix`
as they required importing more lemmas about natural numbers, and use `omega`.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -156,7 +156,7 @@ theorem append_sublist_of_sublist_left {xs ys zs : List α} (h : zs <+ xs) :
have hl' := h'.length_le
simp only [length_append] at hl'
have : ys.length = 0 := by omega
simp_all only [Nat.add_zero, length_eq_zero, true_and, append_nil]
simp_all only [Nat.add_zero, length_eq_zero_iff, true_and, append_nil]
exact Sublist.eq_of_length_le h' hl
· rintro rfl, rfl
simp
@@ -169,7 +169,7 @@ theorem append_sublist_of_sublist_right {xs ys zs : List α} (h : zs <+ ys) :
have hl' := h'.length_le
simp only [length_append] at hl'
have : xs.length = 0 := by omega
simp_all only [Nat.zero_add, length_eq_zero, true_and, append_nil]
simp_all only [Nat.zero_add, length_eq_zero_iff, true_and, append_nil]
exact Sublist.eq_of_length_le h' hl
· rintro rfl, rfl
simp

View File

@@ -16,8 +16,8 @@ These are in a separate file from most of the list lemmas
as they required importing more lemmas about natural numbers, and use `omega`.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -115,12 +115,12 @@ theorem take_set_of_le (a : α) {i j : Nat} (l : List α) (h : j ≤ i) :
@[deprecated take_set_of_le (since := "2025-02-04")]
abbrev take_set_of_lt := @take_set_of_le
@[simp] theorem take_replicate (a : α) : i j : Nat, take i (replicate j a) = replicate (min i j) a
@[simp] theorem take_replicate (a : α) : i n : Nat, take i (replicate n a) = replicate (min i n) a
| n, 0 => by simp [Nat.min_zero]
| 0, m => by simp [Nat.zero_min]
| succ n, succ m => by simp [replicate_succ, succ_min_succ, take_replicate]
@[simp] theorem drop_replicate (a : α) : i j : Nat, drop i (replicate j a) = replicate (j - i) a
@[simp] theorem drop_replicate (a : α) : i n : Nat, drop i (replicate n a) = replicate (n - i) a
| n, 0 => by simp
| 0, m => by simp
| succ n, succ m => by simp [replicate_succ, succ_sub_succ, drop_replicate]

View File

@@ -11,8 +11,8 @@ import Init.Data.Nat.Div.Basic
-/
set_option linter.missingDocs true -- keep it documented
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Decidable List

View File

@@ -11,8 +11,8 @@ import Init.Data.Fin.Fold
# Theorems about `List.ofFn`
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -11,8 +11,8 @@ import Init.Data.List.Attach
# Lemmas about `List.Pairwise` and `List.Nodup`.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -18,8 +18,8 @@ another.
The notation `~` is used for permutation equivalence.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open Nat

View File

@@ -14,8 +14,8 @@ Most of the results are deferred to `Data.Init.List.Nat.Range`, where more resul
natural arithmetic are available.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -33,7 +33,7 @@ theorem range'_succ (s n step) : range' s (n + 1) step = s :: range' (s + step)
| _ + 1 => congrArg succ (length_range' _ _ _)
@[simp] theorem range'_eq_nil_iff : range' s n step = [] n = 0 := by
rw [ length_eq_zero, length_range']
rw [ length_eq_zero_iff, length_range']
@[deprecated range'_eq_nil_iff (since := "2025-01-29")] abbrev range'_eq_nil := @range'_eq_nil_iff
@@ -74,7 +74,7 @@ theorem mem_range' : ∀{n}, m ∈ range' s n step ↔ ∃ i < n, m = s + step *
rw [exists_comm]; simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm]
theorem getElem?_range' (s step) :
{i j : Nat}, i < j (range' s j step)[i]? = some (s + step * i)
{i n : Nat}, i < n (range' s n step)[i]? = some (s + step * i)
| 0, n + 1, _ => by simp [range'_succ]
| m + 1, n + 1, h => by
simp only [range'_succ, getElem?_cons_succ]
@@ -147,10 +147,10 @@ theorem range_loop_range' : ∀ s n : Nat, range.loop s (range' s n) = range' 0
theorem range_eq_range' (n : Nat) : range n = range' 0 n :=
(range_loop_range' n 0).trans <| by rw [Nat.zero_add]
theorem getElem?_range {i j : Nat} (h : i < j) : (range j)[i]? = some i := by
theorem getElem?_range {i n : Nat} (h : i < n) : (range n)[i]? = some i := by
simp [range_eq_range', getElem?_range' _ _ h]
@[simp] theorem getElem_range {i : Nat} (j) (h : j < (range i).length) : (range i)[j] = j := by
@[simp] theorem getElem_range {n : Nat} (j) (h : j < (range n).length) : (range n)[j] = j := by
simp [range_eq_range']
theorem range_succ_eq_map (n : Nat) : range (n + 1) = 0 :: map succ (range n) := by
@@ -164,7 +164,7 @@ theorem range'_eq_map_range (s n : Nat) : range' s n = map (s + ·) (range n) :=
simp only [range_eq_range', length_range']
@[simp] theorem range_eq_nil {n : Nat} : range n = [] n = 0 := by
rw [ length_eq_zero, length_range]
rw [ length_eq_zero_iff, length_range]
theorem range_ne_nil {n : Nat} : range n [] n 0 := by
cases n <;> simp
@@ -183,9 +183,9 @@ theorem range_subset {m n : Nat} : range m ⊆ range n ↔ m ≤ n := by
theorem range_succ (n : Nat) : range (succ n) = range n ++ [n] := by
simp only [range_eq_range', range'_1_concat, Nat.zero_add]
theorem range_add (a b : Nat) : range (a + b) = range a ++ (range b).map (a + ·) := by
theorem range_add (n m : Nat) : range (n + m) = range n ++ (range m).map (n + ·) := by
rw [ range'_eq_map_range]
simpa [range_eq_range', Nat.add_comm] using (range'_append_1 0 a b).symm
simpa [range_eq_range', Nat.add_comm] using (range'_append_1 0 n m).symm
theorem head?_range (n : Nat) : (range n).head? = if n = 0 then none else some 0 := by
induction n with

View File

@@ -14,8 +14,8 @@ These definitions are intended for verification purposes,
and are replaced at runtime by efficient versions in `Init.Data.List.Sort.Impl`.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -31,8 +31,8 @@ as long as such improvements are carefully validated by benchmarking,
they can be done without changing the theory, as long as a `@[csimp]` lemma is provided.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
open List

View File

@@ -21,8 +21,8 @@ import Init.Data.Bool
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List

View File

@@ -11,8 +11,8 @@ import Init.Data.List.TakeDrop
# Lemmas about `List.Subset`, `List.Sublist`, `List.IsPrefix`, `List.IsSuffix`, and `List.IsInfix`.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -150,8 +150,8 @@ theorem Sublist.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ <+ l₂) (h₂ : l
| slnil => exact h₁
| cons _ _ IH => exact (IH h₁).cons _
| @cons₂ l₂ _ a _ IH =>
generalize e : a :: l₂ = l₂'
match e h₁ with
generalize e : a :: l₂ = l₂' at h₁
match h₁ with
| .slnil => apply nil_sublist
| .cons a' h₁' => cases e; apply (IH h₁').cons
| .cons₂ a' h₁' => cases e; apply (IH h₁').cons₂

View File

@@ -10,8 +10,8 @@ import Init.Data.List.Lemmas
# Lemmas about `List.take` and `List.drop`.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -45,7 +45,7 @@ theorem drop_one : ∀ l : List α, drop 1 l = tail l
_ = succ (length l) - succ i := (Nat.succ_sub_succ_eq_sub (length l) i).symm
theorem drop_of_length_le {l : List α} (h : l.length i) : drop i l = [] :=
length_eq_zero.1 (length_drop .. Nat.sub_eq_zero_of_le h)
length_eq_zero_iff.1 (length_drop .. Nat.sub_eq_zero_of_le h)
theorem length_lt_of_drop_ne_nil {l : List α} {i} (h : drop i l []) : i < l.length :=
gt_of_not_le (mt drop_of_length_le h)

View File

@@ -15,8 +15,8 @@ import Init.Data.Array.Lex.Basic
We prefer to pull `List.toArray` outwards past `Array` operations.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Array
@@ -44,6 +44,16 @@ theorem toArray_inj {as bs : List α} (h : as.toArray = bs.toArray) : as = bs :=
| nil => simp at h
| cons b bs => simpa using h
theorem toArray_eq_iff {as : List α} {bs : Array α} : as.toArray = bs as = bs.toList := by
cases bs
simp
-- We can't make this a `@[simp]` lemma because `#[] = [].toArray` at reducible transparency,
-- so this would loop with `toList_eq_nil_iff`
theorem eq_toArray_iff {as : Array α} {bs : List α} : as = bs.toArray as.toList = bs := by
cases as
simp
@[simp] theorem size_toArrayAux {as : List α} {xs : Array α} :
(as.toArrayAux xs).size = xs.size + as.length := by
simp [size]
@@ -77,6 +87,21 @@ theorem toArray_cons (a : α) (l : List α) : (a :: l).toArray = #[a] ++ l.toArr
l.toArray.back = l.getLast (by simp at h; exact ne_nil_of_length_pos h) := by
simp [back, List.getLast_eq_getElem]
@[simp] theorem _root_.Array.getLast!_toList [Inhabited α] (xs : Array α) :
xs.toList.getLast! = xs.back! := by
rcases xs with xs
simp
@[simp] theorem _root_.Array.getLast?_toList (xs : Array α) :
xs.toList.getLast? = xs.back? := by
rcases xs with xs
simp
@[simp] theorem _root_.Array.getLast_toList (xs : Array α) (h) :
xs.toList.getLast h = xs.back (by simpa [ne_nil_iff_length_pos] using h) := by
rcases xs with xs
simp
@[simp] theorem set_toArray (l : List α) (i : Nat) (a : α) (h : i < l.length) :
(l.toArray.set i a) = (l.set i a).toArray := rfl
@@ -514,8 +539,8 @@ private theorem popWhile_toArray_aux (p : α → Bool) (l : List α) :
@[simp] theorem toArray_replicate (n : Nat) (v : α) : (List.replicate n v).toArray = mkArray n v := rfl
@[deprecated toArray_replicate (since := "2024-12-13")]
abbrev _root_.Array.mkArray_eq_toArray_replicate := @toArray_replicate
theorem _root_.Array.mkArray_eq_toArray_replicate : mkArray n v = (List.replicate n v).toArray := by
simp
@[simp] theorem flatMap_empty {β} (f : α Array β) : (#[] : Array α).flatMap f = #[] := rfl
@@ -633,4 +658,46 @@ private theorem insertIdx_loop_toArray (i : Nat) (l : List α) (j : Nat) (hj : j
· simp only [size_toArray, Nat.not_le] at h'
rw [List.insertIdx_of_length_lt (h := h')]
@[simp]
theorem replace_toArray [BEq α] [LawfulBEq α] (l : List α) (a b : α) :
l.toArray.replace a b = (l.replace a b).toArray := by
rw [Array.replace]
split <;> rename_i i h
· simp only [finIdxOf?_toArray, finIdxOf?_eq_none_iff] at h
rw [replace_of_not_mem]
simpa
· simp_all only [finIdxOf?_toArray, finIdxOf?_eq_some_iff, Fin.getElem_fin, set_toArray,
mk.injEq]
apply List.ext_getElem
· simp
· intro j h₁ h₂
rw [List.getElem_replace, List.getElem_set]
by_cases h₃ : j < i
· rw [if_neg (by omega), if_neg]
simp only [length_set] at h₁ h₃
simpa using h.2 j, by omega h₃
· by_cases h₃ : j = i
· rw [if_pos (by omega), if_pos, if_neg]
· simp only [mem_take_iff_getElem, not_exists]
intro k hk
simpa using h.2 k, by omega (by show k < i.1; omega)
· subst h₃
simpa using h.1
· rw [if_neg (by omega)]
split
· rw [if_pos]
· simp_all
· simp only [mem_take_iff_getElem]
simp only [length_set] at h₁
exact i, by omega, h.1
· rfl
@[simp] theorem leftpad_toArray (n : Nat) (a : α) (l : List α) :
Array.leftpad n a l.toArray = (leftpad n a l).toArray := by
simp [leftpad, Array.leftpad, toArray_replicate]
@[simp] theorem rightpad_toArray (n : Nat) (a : α) (l : List α) :
Array.rightpad n a l.toArray = (rightpad n a l).toArray := by
simp [rightpad, Array.rightpad, toArray_replicate]
end List

View File

@@ -6,8 +6,8 @@ Authors: Henrik Böving
prelude
import Init.Data.List.Basic
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
/--
Auxiliary definition for `List.toArray`.

View File

@@ -11,8 +11,8 @@ import Init.Data.Function
# Lemmas about `List.zip`, `List.zipWith`, `List.zipWithAll`, and `List.unzip`.
-/
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace List
@@ -186,7 +186,7 @@ theorem zipWith_eq_cons_iff {f : α → β → γ} {l₁ : List α} {l₂ : List
theorem zipWith_eq_append_iff {f : α β γ} {l₁ : List α} {l₂ : List β} :
zipWith f l₁ l₂ = l₁' ++ l₂'
w x y z, w.length = y.length l₁ = w ++ x l₂ = y ++ z l₁' = zipWith f w y l₂' = zipWith f x z := by
ws xs ys zs, ws.length = ys.length l₁ = ws ++ xs l₂ = ys ++ zs l₁' = zipWith f ws ys l₂' = zipWith f xs zs := by
induction l₁ generalizing l₂ l₁' with
| nil =>
simp
@@ -347,7 +347,7 @@ theorem zip_eq_cons_iff {l₁ : List α} {l₂ : List β} :
theorem zip_eq_append_iff {l₁ : List α} {l₂ : List β} :
zip l₁ l₂ = l₁' ++ l₂'
w x y z, w.length = y.length l₁ = w ++ x l₂ = y ++ z l₁' = zip w y l₂' = zip x z := by
ws xs ys zs, ws.length = ys.length l₁ = ws ++ xs l₂ = ys ++ zs l₁' = zip ws ys l₂' = zip xs zs := by
simp [zip_eq_zipWith, zipWith_eq_append_iff]
/-- See also `List.zip_replicate` in `Init.Data.List.TakeDrop` for a generalization with different lengths. -/

View File

@@ -6,6 +6,7 @@ Authors: Kim Morrison
prelude
import Init.Omega
import Init.Data.Nat.Lemmas
import Init.Data.Nat.Simproc
/-!
# Further lemmas about `Nat.div` and `Nat.mod`, with the convenience of having `omega` available.
@@ -62,4 +63,53 @@ theorem div_add_le_right {z : Nat} (h : 0 < z) (x y : Nat) :
x / (y + z) x / z :=
div_le_div_left (Nat.le_add_left z y) h
theorem succ_div_of_dvd {a b : Nat} (h : b a + 1) :
(a + 1) / b = a / b + 1 := by
replace h := mod_eq_zero_of_dvd h
cases b with
| zero => simp at h
| succ b =>
by_cases h' : b a
· rw [Nat.div_eq]
simp only [zero_lt_succ, Nat.add_le_add_iff_right, h', and_self, reduceIte,
Nat.reduceSubDiff, Nat.add_right_cancel_iff]
obtain _|k, h := Nat.dvd_of_mod_eq_zero h
· simp at h
· simp only [Nat.mul_add, Nat.add_mul, Nat.one_mul, Nat.mul_one, Nat.add_assoc,
Nat.add_right_cancel_iff] at h
subst h
rw [Nat.add_sub_cancel, Nat.add_one_mul, mul_div_right _ (zero_lt_succ _), Nat.add_comm,
Nat.add_mul_div_left _ _ (zero_lt_succ _), Nat.self_eq_add_left, div_eq_of_lt le.refl]
· simp only [Nat.not_le] at h'
replace h' : a + 1 < b + 1 := Nat.add_lt_add_right h' 1
rw [Nat.mod_eq_of_lt h'] at h
simp at h
theorem succ_div_of_mod_eq_zero {a b : Nat} (h : (a + 1) % b = 0) :
(a + 1) / b = a / b + 1 := by
rw [succ_div_of_dvd (by rwa [dvd_iff_mod_eq_zero])]
theorem succ_div_of_not_dvd {a b : Nat} (h : ¬ b a + 1) :
(a + 1) / b = a / b := by
replace h := mt dvd_of_mod_eq_zero h
cases b with
| zero => simp
| succ b =>
rw [eq_comm, Nat.div_eq_iff (by simp)]
constructor
· rw [Nat.div_mul_self_eq_mod_sub_self]
have : (a + 1) % (b + 1) < b + 1 := Nat.mod_lt _ (by simp)
omega
· rw [Nat.div_mul_self_eq_mod_sub_self]
omega
theorem succ_div_of_mod_ne_zero {a b : Nat} (h : (a + 1) % b 0) :
(a + 1) / b = a / b := by
rw [succ_div_of_not_dvd (by rwa [dvd_iff_mod_eq_zero])]
theorem succ_div {a b : Nat} : (a + 1) / b = a / b + if b a + 1 then 1 else 0 := by
split <;> rename_i h
· simp [succ_div_of_dvd h]
· simp [succ_div_of_not_dvd h]
end Nat

View File

@@ -1016,6 +1016,39 @@ theorem mul_add_mod (m x y : Nat) : (m * x + y) % m = y % m := by
· exact (m % 0).div_zero
· case succ n => exact Nat.div_eq_of_lt (m.mod_lt n.succ_pos)
theorem mod_eq_iff {a b c : Nat} :
a % b = c (b = 0 a = c) (c < b Exists fun k => a = b * k + c) :=
fun h =>
if w : b = 0 then
.inl w, by simpa [w] using h
else
.inr by subst h; exact Nat.mod_lt a (zero_lt_of_ne_zero w),
a / b, by subst h; exact (div_add_mod a b).symm,
by
rintro (rfl, rfl | w, h, rfl)
· simp_all
· rw [mul_add_mod, mod_eq_of_lt w]
theorem succ_mod_succ_eq_zero_iff {a b : Nat} :
(a + 1) % (b + 1) = 0 a % (b + 1) = b := by
symm
rw [mod_eq_iff, mod_eq_iff]
simp only [add_one_ne_zero, false_and, Nat.lt_add_one, true_and, false_or, and_self, zero_lt_succ,
Nat.add_zero]
constructor
· rintro k, rfl
refine k + 1, ?_
simp [Nat.add_mul, Nat.mul_add, Nat.add_assoc]
· rintro k, h
cases k with
| zero => simp at h
| succ k =>
refine k, ?_
simp only [Nat.mul_add, Nat.add_mul, Nat.one_mul, Nat.mul_one, Nat.add_assoc,
Nat.add_right_cancel_iff] at h
subst h
simp [Nat.add_mul]
/-! ### Decidability of predicates -/
instance decidableBallLT :

View File

@@ -431,19 +431,22 @@ attribute [local simp] Poly.denote_le_cancel_eq
theorem Expr.denote_toPoly_go (ctx : Context) (e : Expr) :
(toPoly.go k e p).denote ctx = k * e.denote ctx + p.denote ctx := by
induction k, e using Expr.toPoly.go.induct generalizing p with
| case1 k k' =>
simp only [toPoly.go]
by_cases h : k' == 0
· simp [h, eq_of_beq h]
· simp [h, Var.denote]
| case2 k i => simp [toPoly.go]
| case3 k a b iha ihb => simp [toPoly.go, iha, ihb]
| case4 k k' a ih
| case5 k a k' ih =>
| case1 k k' h =>
simp [toPoly.go, eq_of_beq h]
| case2 k k' h =>
simp [toPoly.go, h, Var.denote]
| case3 k i => simp [toPoly.go]
| case4 k a b iha ihb => simp [toPoly.go, iha, ihb]
| case5 k k' a h => simp [toPoly.go, h, eq_of_beq h]
| case6 k a k' h ih =>
simp only [toPoly.go, denote, mul_eq]
by_cases h : k' == 0
· simp [h, eq_of_beq h]
· simp [h, cond_false, ih, Nat.mul_assoc]
simp [h, cond_false, ih, Nat.mul_assoc]
| case7 k a k' h =>
simp only [toPoly.go, denote, mul_eq]
simp [h, eq_of_beq h]
| case8 k a k' h ih =>
simp only [toPoly.go, denote, mul_eq]
simp [h, cond_false, ih, Nat.mul_assoc]
theorem Expr.denote_toPoly (ctx : Context) (e : Expr) : e.toPoly.denote ctx = e.denote ctx := by
simp [toPoly, Expr.denote_toPoly_go]

View File

@@ -40,3 +40,20 @@ theorem neZero_iff {n : R} : NeZero n ↔ n ≠ 0 :=
instance {p : Prop} [Decidable p] {n m : Nat} [NeZero n] [NeZero m] :
NeZero (if p then n else m) := by
split <;> infer_instance
instance {n m : Nat} [h : NeZero n] : NeZero (n + m) where
out :=
match n, h, m with
| _ + 1, _, 0
| _ + 1, _, _ + 1 => fun h => nomatch h
instance {n m : Nat} [h : NeZero m] : NeZero (n + m) where
out :=
match m, h, n with
| _ + 1, _, 0 => fun h => nomatch h
| _ + 1, _, _ + 1 => fun h => nomatch h
instance {n m : Nat} [hn : NeZero n] [hm : NeZero m] : NeZero (n * m) where
out :=
match n, hn, m, hm with
| _ + 1, _, _ + 1, _ => fun h => nomatch h

View File

@@ -654,6 +654,11 @@ theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (o H)
Option.map g (pmap f o H) = pmap (fun a h => g (f a h)) o H := by
cases o <;> simp
theorem pmap_map (o : Option α) (f : α β) {p : β Prop} (g : b, p b γ) (H) :
pmap g (o.map f) H =
pmap (fun a h => g (f a) h) o (fun a m => H (f a) (mem_map_of_mem f m)) := by
cases o <;> simp
/-! ### pelim -/
@[simp] theorem pelim_none : pelim none b f = b := rfl

View File

@@ -7,6 +7,7 @@ prelude
import Init.Data.SInt.Basic
import Init.Data.SInt.Float
import Init.Data.SInt.Float32
import Init.Data.SInt.Lemmas
/-!
This module contains the definitions and basic theory about signed fixed width integer types.

View File

@@ -154,6 +154,10 @@ def Int8.shiftLeft (a b : Int8) : Int8 := ⟨⟨a.toBitVec <<< (b.toBitVec.smod
def Int8.shiftRight (a b : Int8) : Int8 := BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 8)
@[extern "lean_int8_complement"]
def Int8.complement (a : Int8) : Int8 := ~~~a.toBitVec
/-- Computes the absolute value of the signed integer. This function is equivalent to
`if a < 0 then -a else a`, so in particular `Int8.minValue` will be mapped to `Int8.minValue`. -/
@[extern "lean_int8_abs"]
def Int8.abs (a : Int8) : Int8 := a.toBitVec.abs
@[extern "lean_int8_dec_eq"]
def Int8.decEq (a b : Int8) : Decidable (a = b) :=
@@ -290,6 +294,10 @@ def Int16.shiftLeft (a b : Int16) : Int16 := ⟨⟨a.toBitVec <<< (b.toBitVec.sm
def Int16.shiftRight (a b : Int16) : Int16 := BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 16)
@[extern "lean_int16_complement"]
def Int16.complement (a : Int16) : Int16 := ~~~a.toBitVec
/-- Computes the absolute value of the signed integer. This function is equivalent to
`if a < 0 then -a else a`, so in particular `Int16.minValue` will be mapped to `Int16.minValue`. -/
@[extern "lean_int16_abs"]
def Int16.abs (a : Int16) : Int16 := a.toBitVec.abs
@[extern "lean_int16_dec_eq"]
def Int16.decEq (a b : Int16) : Decidable (a = b) :=
@@ -430,6 +438,10 @@ def Int32.shiftLeft (a b : Int32) : Int32 := ⟨⟨a.toBitVec <<< (b.toBitVec.sm
def Int32.shiftRight (a b : Int32) : Int32 := BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 32)
@[extern "lean_int32_complement"]
def Int32.complement (a : Int32) : Int32 := ~~~a.toBitVec
/-- Computes the absolute value of the signed integer. This function is equivalent to
`if a < 0 then -a else a`, so in particular `Int32.minValue` will be mapped to `Int32.minValue`. -/
@[extern "lean_int32_abs"]
def Int32.abs (a : Int32) : Int32 := a.toBitVec.abs
@[extern "lean_int32_dec_eq"]
def Int32.decEq (a b : Int32) : Decidable (a = b) :=
@@ -574,6 +586,10 @@ def Int64.shiftLeft (a b : Int64) : Int64 := ⟨⟨a.toBitVec <<< (b.toBitVec.sm
def Int64.shiftRight (a b : Int64) : Int64 := BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 64)
@[extern "lean_int64_complement"]
def Int64.complement (a : Int64) : Int64 := ~~~a.toBitVec
/-- Computes the absolute value of the signed integer. This function is equivalent to
`if a < 0 then -a else a`, so in particular `Int64.minValue` will be mapped to `Int64.minValue`. -/
@[extern "lean_int64_abs"]
def Int64.abs (a : Int64) : Int64 := a.toBitVec.abs
@[extern "lean_int64_dec_eq"]
def Int64.decEq (a b : Int64) : Decidable (a = b) :=
@@ -690,9 +706,8 @@ instance : Neg ISize where
/-- The maximum value an `ISize` may attain, that is, `2^(System.Platform.numBits - 1) - 1`. -/
abbrev ISize.maxValue : ISize := .ofInt (2 ^ (System.Platform.numBits - 1) - 1)
-- 9223372036854775807
/-- The minimum value an `ISize` may attain, that is, `-2^(System.Platform.numBits - 1)`. -/
abbrev ISize.minValue : ISize := .ofInt (2 ^ (System.Platform.numBits - 1))
abbrev ISize.minValue : ISize := .ofInt (-2 ^ (System.Platform.numBits - 1))
/-- Constructs an `ISize` from an `Int` which is known to be in bounds. -/
@[inline]
@@ -730,6 +745,10 @@ def ISize.shiftLeft (a b : ISize) : ISize := ⟨⟨a.toBitVec <<< (b.toBitVec.sm
def ISize.shiftRight (a b : ISize) : ISize := BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod System.Platform.numBits)
@[extern "lean_isize_complement"]
def ISize.complement (a : ISize) : ISize := ~~~a.toBitVec
/-- Computes the absolute value of the signed integer. This function is equivalent to
`if a < 0 then -a else a`, so in particular `ISize.minValue` will be mapped to `ISize.minValue`. -/
@[extern "lean_isize_abs"]
def ISize.abs (a : ISize) : ISize := a.toBitVec.abs
@[extern "lean_isize_dec_eq"]
def ISize.decEq (a b : ISize) : Decidable (a = b) :=

View File

@@ -0,0 +1,13 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Markus Himmel
-/
prelude
import Init.Data.SInt.Basic
@[simp] theorem UInt8.toBitVec_toInt8 (x : UInt8) : x.toInt8.toBitVec = x.toBitVec := rfl
@[simp] theorem UInt16.toBitVec_toInt16 (x : UInt16) : x.toInt16.toBitVec = x.toBitVec := rfl
@[simp] theorem UInt32.toBitVec_toInt32 (x : UInt32) : x.toInt32.toBitVec = x.toBitVec := rfl
@[simp] theorem UInt64.toBitVec_toInt64 (x : UInt64) : x.toInt64.toBitVec = x.toBitVec := rfl
@[simp] theorem USize.toBitVec_toISize (x : USize) : x.toISize.toBitVec = x.toBitVec := rfl

View File

@@ -295,11 +295,16 @@ def USize.mk (bitVec : BitVec System.Platform.numBits) : USize :=
def USize.ofNatCore (n : Nat) (h : n < USize.size) : USize :=
USize.ofNatLT n h
theorem usize_size_le : USize.size 18446744073709551616 := by
cases usize_size_eq <;> next h => rw [h]; decide
@[simp] theorem USize.le_size : 2 ^ 32 USize.size := by cases USize.size_eq <;> simp_all
@[simp] theorem USize.size_le : USize.size 2 ^ 64 := by cases USize.size_eq <;> simp_all
theorem le_usize_size : 4294967296 USize.size := by
cases usize_size_eq <;> next h => rw [h]; decide
@[deprecated USize.size_le (since := "2025-02-24")]
theorem usize_size_le : USize.size 18446744073709551616 :=
USize.size_le
@[deprecated USize.le_size (since := "2025-02-24")]
theorem le_usize_size : 4294967296 USize.size :=
USize.le_size
@[extern "lean_usize_mul"]
def USize.mul (a b : USize) : USize := a.toBitVec * b.toBitVec
@@ -326,7 +331,7 @@ This function is overridden with a native implementation.
-/
@[extern "lean_usize_of_nat"]
def USize.ofNat32 (n : @& Nat) (h : n < 4294967296) : USize :=
USize.ofNatLT n (Nat.lt_of_lt_of_le h le_usize_size)
USize.ofNatLT n (Nat.lt_of_lt_of_le h USize.le_size)
@[extern "lean_uint8_to_usize"]
def UInt8.toUSize (a : UInt8) : USize :=
USize.ofNat32 a.toBitVec.toNat (Nat.lt_trans a.toBitVec.isLt (by decide))
@@ -351,7 +356,7 @@ This function is overridden with a native implementation.
-/
@[extern "lean_usize_to_uint64"]
def USize.toUInt64 (a : USize) : UInt64 :=
UInt64.ofNatLT a.toBitVec.toNat (Nat.lt_of_lt_of_le a.toBitVec.isLt usize_size_le)
UInt64.ofNatLT a.toBitVec.toNat (Nat.lt_of_lt_of_le a.toBitVec.isLt USize.size_le)
instance : Mul USize := USize.mul
instance : Mod USize := USize.mod

View File

@@ -138,8 +138,16 @@ def UInt32.toUInt64 (a : UInt32) : UInt64 := ⟨⟨a.toNat, Nat.lt_trans a.toBit
instance UInt64.instOfNat : OfNat UInt64 n := UInt64.ofNat n
@[deprecated usize_size_pos (since := "2024-11-24")] theorem usize_size_gt_zero : USize.size > 0 :=
usize_size_pos
@[deprecated USize.size_eq (since := "2025-02-24")]
theorem usize_size_eq : USize.size = 4294967296 USize.size = 18446744073709551616 :=
USize.size_eq
@[deprecated USize.size_pos (since := "2025-02-24")]
theorem usize_size_pos : 0 < USize.size :=
USize.size_pos
@[deprecated USize.size_pos (since := "2024-11-24")] theorem usize_size_gt_zero : USize.size > 0 :=
USize.size_pos
/-- Converts a `USize` into the corresponding `Fin USize.size`. -/
def USize.toFin (x : USize) : Fin USize.size := x.toBitVec.toFin
@@ -155,7 +163,7 @@ def USize.ofNatTruncate (n : Nat) : USize :=
if h : n < USize.size then
USize.ofNatLT n h
else
USize.ofNatLT (USize.size - 1) (Nat.pred_lt (Nat.ne_zero_of_lt usize_size_pos))
USize.ofNatLT (USize.size - 1) (Nat.pred_lt (Nat.ne_zero_of_lt USize.size_pos))
abbrev Nat.toUSize := USize.ofNat
@[extern "lean_usize_to_nat"]
def USize.toNat (n : USize) : Nat := n.toBitVec.toNat

View File

@@ -25,11 +25,11 @@ namespace $typeName
@[simp, int_toBitVec] protected theorem toBitVec_shiftLeft (a b : $typeName) : (a <<< b).toBitVec = a.toBitVec <<< (b.toBitVec % $bits) := rfl
@[simp, int_toBitVec] protected theorem toBitVec_shiftRight (a b : $typeName) : (a >>> b).toBitVec = a.toBitVec >>> (b.toBitVec % $bits) := rfl
@[simp] protected theorem toNat_and (a b : $typeName) : (a &&& b).toNat = a.toNat &&& b.toNat := by simp [toNat]
@[simp] protected theorem toNat_or (a b : $typeName) : (a ||| b).toNat = a.toNat ||| b.toNat := by simp [toNat]
@[simp] protected theorem toNat_xor (a b : $typeName) : (a ^^^ b).toNat = a.toNat ^^^ b.toNat := by simp [toNat]
@[simp] protected theorem toNat_shiftLeft (a b : $typeName) : (a <<< b).toNat = a.toNat <<< (b.toNat % $bits) % 2 ^ $bits := by simp [toNat]
@[simp] protected theorem toNat_shiftRight (a b : $typeName) : (a >>> b).toNat = a.toNat >>> (b.toNat % $bits) := by simp [toNat]
@[simp] protected theorem toNat_and (a b : $typeName) : (a &&& b).toNat = a.toNat &&& b.toNat := by simp [toNat, -toNat_toBitVec]
@[simp] protected theorem toNat_or (a b : $typeName) : (a ||| b).toNat = a.toNat ||| b.toNat := by simp [toNat, -toNat_toBitVec]
@[simp] protected theorem toNat_xor (a b : $typeName) : (a ^^^ b).toNat = a.toNat ^^^ b.toNat := by simp [toNat, -toNat_toBitVec]
@[simp] protected theorem toNat_shiftLeft (a b : $typeName) : (a <<< b).toNat = a.toNat <<< (b.toNat % $bits) % 2 ^ $bits := by simp [toNat, -toNat_toBitVec]
@[simp] protected theorem toNat_shiftRight (a b : $typeName) : (a >>> b).toNat = a.toNat >>> (b.toNat % $bits) := by simp [toNat, -toNat_toBitVec]
open $typeName (toNat_and) in
@[deprecated toNat_and (since := "2024-11-28")]
@@ -37,7 +37,6 @@ protected theorem and_toNat (a b : $typeName) : (a &&& b).toNat = a.toNat &&& b.
end $typeName
)
declare_bitwise_uint_theorems UInt8 8
declare_bitwise_uint_theorems UInt16 16
declare_bitwise_uint_theorems UInt32 32

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