Compare commits

...

96 Commits

Author SHA1 Message Date
Leonardo de Moura
f20f69ef74 chore: fix tests 2025-04-17 17:38:10 -07:00
Leonardo de Moura
c8da6a878d chore: allow RArray to be universe polymorphic 2025-04-17 17:35:38 -07:00
Cameron Zwarich
d981fa0faf fix: make implemented_by of casesOn work correctly with hash consing (#8010)
This PR fixes caseOn expressions with an implemented_by to work
correctly with hash consing, even when the elaborator produces terms
that reconstruct the discriminant rather than just reusing a variable.
2025-04-17 23:32:59 +00:00
Cameron Zwarich
7b292090ce fix: restrict lifting outside of cases expressions on Decidable (#8009)
This PR restricts lifting outside of cases expressions on values of a
Decidable type, since we can't correctly represent the dependency on the
erased proposition in the later stages of the compiler.
2025-04-17 23:01:56 +00:00
Cameron Zwarich
f0033cd15e fix: consider params to be ground variables in specialization (#8008)
This PR changes specialization in the new code generator to consider
callee params to be ground variables, which improves the specialization
of polymorphic functions.
2025-04-17 22:34:16 +00:00
Cameron Zwarich
7bbcfdf712 fix: modify eager lambda lifting heuristics to match the old compiler (#8007)
This PR changes eager lambda lifting heuristics in the new compiler to
match the old compiler, which ensures that inlining/specializing monadic
code does not accidentally create mutual tail recursion that the code
generator can't handle.
2025-04-17 21:46:51 +00:00
Cameron Zwarich
130e2d93a5 fix: change inlining heuristics to match old code generator (#8006)
This PR changes the inlining heuristics of the new code generator to
match the old one, which ensures that monadic folds get sufficiently
inlined for their tail recursion to be exposed to the code generator.
2025-04-17 20:47:40 +00:00
Mac Malone
5b16ea98f5 fix: lake: extern_lib linking (#7987)
This PR fixes a bug in #7967 that broke external library linking.

This is slipped through because the FFI example no longer uses
`extern_lib`. As such, a separate `extern_lib` test has been added.
2025-04-17 19:33:22 +00:00
Rob23oba
acfc9c50d5 feat: hash map lemmas for filter, map and filterMap (#7400)
This PR adds lemmas for the `filter`, `map` and `filterMap` functions of
the hash map.

---------

Co-authored-by: jt0202 <johannes.tantow@gmail.com>
Co-authored-by: Johannes Tantow <44068763+jt0202@users.noreply.github.com>
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
2025-04-17 10:15:52 +00:00
Markus Himmel
5af99cc840 chore: fix typo in simp docstring (#7998)
This PR fixes a typo in the `simp` hover.
2025-04-17 08:46:41 +00:00
Joachim Breitner
85f5a81f17 feat: FunInd: consume all type annotaions (#7997)
This PR removes all type annotations (optional paramters, auto
parameters, out params, semi-out params, not just optional parameters as
before) from the type of functional induction principles.
2025-04-17 07:52:17 +00:00
Cameron Zwarich
a81169bbe4 fix: don't eliminate fun decls in CSE in the base phase (#7996)
This PR disables CSE of local function declarations in the base phase of
the new compiler. This was introducing sharing between lambdas to bind
calls w/ `do` notation, which caused them to later no longer be inlined.
2025-04-17 04:57:21 +00:00
Kim Morrison
fdc62faa0f feat: reproduce Array.Perm API for Vector.Perm (#7994)
This PR reproduces the `Array.Perm` API for `Vector`. Both are still
significantly less developed than the API for `List.Perm`.
2025-04-17 02:39:48 +00:00
Leonardo de Moura
eaf46dfab1 feat: add Expr.toPoly (#7992)
This PR add a function for converting `CommRing` expressions into
multivariate polynomials.

Co-authored-by: Leonardo de Moura <leonardodemoura@Leonardos-MacBook-Pro.local>
2025-04-17 01:48:03 +00:00
Cameron Zwarich
d52b8e3cc1 fix: use lcAny in more cases of type erasure (#7990)
This PR adopts lcAny in more cases of type erasure in the new code
generator.
2025-04-16 22:53:18 +00:00
Kim Morrison
2a5373258f chore: add grind non-determinism repro (#7978)
This PR adds a repro for a non-determinism problem in `grind`.
2025-04-16 22:36:22 +00:00
Leonardo de Moura
d71e9cb96b feat: CommRing.Poly functions and theorems (#7989)
This PR adds functions and theorems for `CommRing` multivariate
polynomials.
2025-04-16 22:09:50 +00:00
Leonardo de Moura
a3a11ffaf9 feat: revlex and grevlex monomial orders (#7986)
This PR implements reverse lexicographical and graded reverse
lexicographical orders for `CommRing` monomials.
2025-04-16 18:03:53 +00:00
Markus Himmel
9d57ed83a9 chore: upstream Int lemmas from mathlib (#7983)
This PR upstreams many of the results from `Mathlib/Data/Int/Init.lean`.

Notably, we upstream the `simp` tag on `Int.natCast_pow`. While this is
desirable as a `simp` lemma, it is non-confluent with other good `simp`
lemmas like `Int.emod_bmod_congr`, and this will need to be addressed in
the future.
2025-04-16 17:45:08 +00:00
Rob23oba
7cca594a4a chore: adjust BEq classes (#7855)
This PR moves `ReflBEq` to `Init.Core` and changes `LawfulBEq` to extend
`ReflBEq`.

**BREAKING CHANGES:**
- The `refl` field of `ReflBEq` has been renamed to `rfl` to match
`LawfulBEq`
- `LawfulBEq` extends `ReflBEq`, so in particular `LawfulBEq.rfl` is no
longer valid
2025-04-16 13:24:23 +00:00
Kim Morrison
eed8a4828b chore: updates to List API before installing grind attributes (#7982) 2025-04-16 08:06:53 +00:00
Kim Morrison
4bea52c48e chore: failing grind test (#7981)
`propagateForallPropDown` is assuming the domain is a `Prop`
2025-04-16 07:24:53 +00:00
Markus Himmel
5a34ffb9b0 chore: upstream Nat material from mathlib (#7971)
This PR upstreams much of the material from `Mathlib/Data/Nat/Init.lean`
and `Mathlib/Data/Nat/Basic.lean`.
2025-04-16 06:55:32 +00:00
Leonardo de Moura
020b8834c3 feat: monomials for CommRing (#7980)
This PR adds a simple type for representing monomials in a `CommRing`.
This is going to be used in `grind`.
2025-04-16 02:39:31 +00:00
Mac Malone
7423e570f4 chore: lake: temporarily disable tests in tests (#7979)
These tests are currently flaky in `merge-ci` and nightly releases, so
they are being temporarily disabled. Whatever the issue is will be
debugged in a separate PR.
2025-04-16 02:29:53 +00:00
Mac Malone
b51115dac5 feat: IO.Process.SpawnArgs.inheritEnv (#6081)
This PR adds an `inheritEnv` field to `IO.Process.SpawnArgs`. If
`false`, the spawned process does not inherit its parent's environment.

For example, Lake will make use of this to ensure that build processes
do not use environment variables that Lake is not properly tracking with
its traces.
2025-04-16 00:25:32 +00:00
Mac Malone
46769b64c9 chore: lake: bootstrap Lean include directory (#7967)
This PR adds a `bootstrap` option to Lake which is used to identify the
core Lean package. This enables Lake to use the current stage's include
directory rather than the Lean toolchains when compiling Lean with Lean
in core.

**Breaking change:** The Lean library directory is no longer part of
`getLeanLinkSharedFlags`. FFI users should provide this option
separately when linking to Lean (e.g.. via `s!"-L{(←
getLeanLibDir).toString}"`). See the FFI example for a demonstration.
2025-04-15 23:15:53 +00:00
Mac Malone
7d26c7c4f3 feat: lake: build by source path (#7909)
This PR adds Lake support for building modules given their source file
path. This is made use of in both the CLI and the sever.

As a target specifier, `lake build Foo/Bar.lean` will now look for a
module in the workspace whose source file is `Foo/Bar.lean` and build
it. Facets are support via `lake build Foo/Bar.lean:o`. As such, `:` is
an illegal character in such file names (which is reasonable considering
its use in search paths like `PATH` on Linux).

In the server, `lake setup-file Foo/Bar.lean` will now try to lookup a
module for the source and and build its dependencies, ignoring the
imports specified. This allows Lake to return more specific
configuration for the module requested (e.g., library-specific dynlibs
and plugins). If the path cannot be found in the workspace, Lake will
fallback to its previous behavior.

Finally, like `setup-file`, `lake lean Foo/Bar.lean` will try to lookup
a module for the source path and use its more specific configuration if
possible.

Closes #2756.
2025-04-15 23:12:36 +00:00
Kyle Miller
dd84829282 feat: allow omission of => ?_ in induction/cases tactics (#7830)
This PR modifies the syntax of `induction`, `cases`, and other tactics
that use `Lean.Parser.Tactic.inductionAlts`. If a case omits `=> ...`
then it is assumed to be `=> ?_`. Example:
```lean
example (p : Nat × Nat) : p.1 = p.1 := by
  cases p with | _ p1 p2
  /-
  case mk
  p1 p2 : Nat
  ⊢ (p1, p2).fst = (p1, p2).fst
  -/
```
This works with multiple cases as well. Example:
```lean
example (n : Nat) : n + 1 = 1 + n := by
  induction n with | zero | succ n ih
  /-
  case zero
  ⊢ 0 + 1 = 1 + 0
  
  case succ
  n : Nat
  ih : n + 1 = 1 + n
  ⊢ n + 1 + 1 = 1 + (n + 1)
  -/
```
The `induction n with | zero | succ n ih` is short for `induction n with
| zero | succ n ih => ?_`, which is short for `induction n with | zero
=> ?_ | succ n ih => ?_`. Note that a consequence of parsing is that
only the last alternative can omit `=>`. Any `=>`-free alternatives
before an alternative with `=>` will be a part of that alternative.

Rationale:
- In the future we may require `tacticSeq` to be indented. For
one-constructor types, this lets the rest of the tactic sequence not
need indentation.
- This is a semi-structured alternative to the `cases'`/`induction'`
tactics in mathlib.
2025-04-15 22:03:46 +00:00
Mac Malone
17d3daca8a feat: lake: track trace inputs & related fixes (#7906)
This PR changes Lake build traces to track their mixed inputs. The
tracked inputs are saved as part of the `.trace` file, which can
significantly assist in debugging trace issues. In addition, this PR
tweaks some existing Lake traces. Most significant, module olean traces
no longer incorporate their module's source trace.
2025-04-15 19:23:02 +00:00
Henrik Böving
712bb070f9 feat: make bv_decide work on simp normal forms of shifts (#7976)
This PR ensure that `bv_decide` can handle the simp normal form of a
shift.

Consider:
```lean
theorem test1 (b s : BitVec 5) (hb : b = 0) (hs : s ≠ 0)
  : b <<< s = 0 := by
  bv_decide
```
This works out, however:
```lean
theorem test2 (b s : BitVec 5) (hb : b = 0) (hs : s ≠ 0)
  : b <<< s = 0 := by
  simp
  bv_decide
```
this fails because the `simp` normal form adds `toNat` to the right hand
argument of the `<<<` and `bv_decide` cannot deal with shifts by
non-constant `Nat`.

Discovered by @spdskatr
2025-04-15 17:26:19 +00:00
Kim Morrison
525fd2697c fix: reduce priorities of CommRing parent projections (#7975)
This PR reduces the priority of the parent projections of
`Lean.Grind.CommRing`, to avoid these being used in typeclass inference
in Mathlib.
2025-04-15 13:45:53 +00:00
Markus Himmel
c82159e09b feat: Int.bmod lemmas (#7933)
This PR adds lemmas about `Int.bmod` to achieve parity between
`Int.bmod` and `Int.emod`/`Int.fmod`/`Int.tmod`. Furthermore, it adds
missing lemmas for `emod`/`fmod`/`tmod` and performs cleanup on names
and statements for all four operations, also with a view towards
increasing consistency with the corresponding `Nat.mod` lemmas.
2025-04-15 12:26:49 +00:00
Kim Morrison
c3996aadb8 feat: Array.count_erase lemma (#7939)
This PR adds `Array.count_erase` and specializations.
2025-04-15 04:02:29 +00:00
Eric Wieser
bb2f51a230 feat: link Lake.EStateT with EStateM (#7963)
This PR adds helper functions to convert between `Lake.EStateT` and
`EStateM`.

In the longer run the two types could just be merged.
2025-04-15 01:05:47 +00:00
Mac Malone
d5027c1a29 chore: lake: rm unused import in DSL.DeclUtil (#7964) 2025-04-15 00:01:02 +00:00
Henrik Böving
bfb02be281 fix: bv_decide default match with as many arms as constructors (#7961)
This PR fixes a bug in bv_decide where if it was presented with a match
on an enum with as many arms as constructors but the last arm being a
default match it would (wrongly) give up on the match.
2025-04-14 14:58:13 +00:00
Sebastian Ullrich
0076ba03d4 fix: race condition in IO.getTaskState (#7945)
This PR fixes a potential race between `IO.getTaskState` and the task in
question finishing, resulting in undefined behavior.

All task state must be accessed under the respective lock.
2025-04-14 14:08:36 +00:00
Henrik Böving
8e9da7a1bc feat: wait on dedicated tasks after main is finished (#7958)
This PR ensures that after `main` is finished we still wait on dedicated
tasks instead of exiting forcefully. If users wish to violently kill
their dedicated tasks at the end of main instead they can run
`IO.Process.exit` at the end of `main` instead.
2025-04-14 11:53:54 +00:00
Henrik Böving
ac738a8e81 perf: use mimalloc in compactor hashmaps (#7929)
This PR changes the compactor hashmap to use mimalloc which speeds up
olean serialization.
2025-04-14 09:11:34 +00:00
Lean stage0 autoupdater
689acab1d3 chore: update stage0 2025-04-14 07:03:16 +00:00
Kyle Miller
de25524dd6 feat: preparation for #7830 (#7955)
This PR adds the tactic implementation for #7830, before changing the
syntax after a stage0 update. It will allow optional RHSs in induction
cases.
2025-04-14 06:22:04 +00:00
Kyle Miller
48a9bfb73d doc: add docstrings to mkFreshUserName etc (#7947)
This PR adds some docstrings to clarify the functions of
`Lean.mkFreshId`, `Lean.Core.mkFreshUserName`,
`Lean.Elab.Term.mkFreshBinderName`, and
`Lean.Meta.mkFreshBinderNameForTactic`.
2025-04-14 04:17:45 +00:00
Kyle Miller
7c9519e60c fix: make sure all_goals restores state on failure (#7950)
This PR modifies `all_goals` so that in recovery mode it commits changes
to the state only for those goals for which the tactic succeeds (while
preserving the new message log state). Before, we were trusting that
failing tactics left things in a reasonable state, but now we roll back
and admit the goal. The changes also fixes a bug where we were rolling
back only the metacontext state and not the tactic state, leading to an
inconsistent state (a goal list with metavariables not in the
metacontext). Closes #7883

Alternatively we could stop on the first error, however it is helpful to
see what the tactic did to each goal while interactively writing a
tactic script. There is some non-monotonicity here though since tactics
can solve for metavariables that appear in successive goals, and
conceivably a later goal succeeds only if a previous one does. Given
that the non-monotonicity is limited to recovery mode (which is for
example the RHS and not the LHS of the `<;>` combinator), we think this
is acceptable.

Another justification for the change to roll back the state on each
failure is that we need to admit goals in the failing cases. When a
tactic throws an error, we cannot assume the goal list is meaningful.
Rolling back lets us admit just the goal the tactic started with,
without needing to try to work out which new metavariables should be
admitted in the error state, allowing the tactic to continue trying the
tactic on the next goal.
2025-04-14 04:16:28 +00:00
Leonardo de Moura
4e1dbe1ae8 chore: add [grind ext] funext (#7951)
Co-authored-by: Kim Morrison <kim@tqft.net>
2025-04-14 02:52:44 +00:00
Kim Morrison
a0b63deb04 feat: updates to List/Array.Perm API (#7953)
This PR generalizes some typeclass hypotheses in the `List.Perm` API
(away from `DecidableEq`), and reproduces `List.Perm.mem_iff` for
`Array`, and fixes a mistake in the statement of `Array.Perm.extract`.
2025-04-14 01:17:02 +00:00
Lean stage0 autoupdater
c5e20c980c chore: update stage0 2025-04-13 23:32:03 +00:00
Leonardo de Moura
cd5b495573 feat: add [grind ext] attribute (#7949)
This PR adds the attribute `[grind ext]`. It is used to select which
`[ext]` theorems should be used by `grind`. The option `grind +extAll`
instructs `grind` to use all `[ext]` theorems available in the
environment.
After update stage0, we need to add the builtin `[grind ext]`
annotations to key theorems such as `funext`.
2025-04-13 22:08:36 +00:00
Leonardo de Moura
2337b95676 feat: improve case split heuristics in grind (#7946)
This PR improves the case split heuristics in `grind`.
2025-04-13 17:57:56 +00:00
Sebastian Ullrich
973f521c46 chore: fix cmake install exclude patterns (#7941) 2025-04-13 12:32:55 +00:00
Sebastian Ullrich
069456ea9c chore: disable flaky test 2025-04-13 13:18:05 +02:00
Kim Morrison
aa2cae8801 feat: List/Array/Vector.count_replace lemmas (#7938)
This PR adds lemmas about `List/Array/Vector.countP/count` interacting
with `replace`. (Specializing to `_self` and `_ne` lemmas doesn't seem
useful, as there will still be an `if` on the RHS.)
2025-04-13 03:10:19 +00:00
Leonardo de Moura
f513c35742 feat: lookahead in grind (#7937)
This PR implements a lookahead feature to reduce the size of the search
space in `grind`. It is currently effective only for arithmetic atoms.
2025-04-13 03:01:47 +00:00
Kim Morrison
d7cc0fd754 chore: add grind annotations for Nat/Int.min/max (#7934) 2025-04-13 01:48:17 +00:00
Kim Morrison
5f8847151d chore: generalize List.Perm.take (#7936)
Thanks @b-mehta for these generalizations.

---------

Co-authored-by: Bhavik Mehta <bhavikmehta8@gmail.com>
2025-04-13 01:45:48 +00:00
Kim Morrison
8bc9c4f154 chore: cleanup 'if normalization' grind example (#7935) 2025-04-13 01:09:38 +00:00
Henrik Böving
dd7ca772d8 refactor: more complete channel implementation for Std.Channel (#7819)
This PR extends `Std.Channel` to provide a full sync and async API, as
well as unbounded, zero sized and bounded channels.

A few notes on the implementation:
- the bounded channel is inspired by [Go channels on
steroids](https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub)
though currently doesn't do any of the lock-free optimizations
- @mhuisi convinced me that having a non-closable channel may be a good
idea as this alleviates the need for error handling which is very
annoying when working with `Task`. This does complicate the API a little
bit and I'm not quite sure whether this is a choice we want users to
give. An alternative to this would be to just write `send!` that panics
on sending to a closed channel (receiving from a closed channel is not
an error), this is for example the behavior that golang goes with.
2025-04-12 21:02:24 +00:00
Lean stage0 autoupdater
85a0232e87 chore: update stage0 2025-04-12 11:07:22 +00:00
Sebastian Ullrich
8ea6465e6d chore: CI: disable Linux 32bit (#7924)
A 2GB heap is just not that much even before fragmentation
2025-04-12 09:29:13 +00:00
Leonardo de Moura
38ed4346c2 chore: improve grind.clear_aux_decls error message (#7931)
cc @kim-em
2025-04-12 02:39:51 +00:00
Leonardo de Moura
2657f4e62c chore: move test to correct directory (#7932) 2025-04-11 19:46:47 -07:00
Leonardo de Moura
d4767a08b0 chore: another grind fixed test (#7930)
cc @kim-em
2025-04-11 19:43:35 -07:00
Leonardo de Moura
f562e72e59 chore: move test (#7921)
This test is easy for `grind`, we just need to annotate `Nat.min_def`.
2025-04-12 01:40:54 +00:00
Leonardo de Moura
5a6d45817d fix: nontermination in grind (#7928)
This PR fixes a nontermination issue in `grind`.
2025-04-11 21:06:07 +00:00
Leonardo de Moura
264095be7f fix: missing propagation and split filter in grind (#7926)
This PR fixes two issues that were preventing `grind` to solve
`getElem?_eq_some_iff`.
1. Missing propagation rule for `Exists p = False`
2. Missing conditions at `isCongrToPrevSplit` a filter for discarding
unnecessary case-splits.
2025-04-11 19:26:50 +00:00
Sebastian Ullrich
0669a04704 chore: CI: limit CCACHE_SIZE to 400MB (#7922) 2025-04-11 17:09:16 +00:00
Sebastian Ullrich
5cd352588c perf: use mimalloc with important C++ hash maps (#7868)
`unordered_map`/`unordered_set` does an allocation per insert, use
mimalloc for them for important hash maps
2025-04-11 16:23:33 +00:00
Henrik Böving
e9cc776f22 perf: bv_decide DecidableEq fast path using hash comparison (#7920)
This PR introduces a fast path based on comparing the (cached) hash
value to the `DecidableEq` instance of the core expression data type in
`bv_decide`'s bitblaster.

As we use a good hash function ™️ this should allow us to short
circuit to "not equal" quicker (if appropriate) than currently as we
will often not have to traverse all the way down to the actual conflict.
This in turn should speed up traversing of bucket chains during hash
collisions.
2025-04-11 15:00:41 +00:00
Lean stage0 autoupdater
e79fef15df chore: update stage0 2025-04-11 14:12:34 +00:00
Sebastian Ullrich
c672934f11 chore: add "Init size" benchmark (#7918) 2025-04-11 13:15:27 +00:00
Sebastian Ullrich
582877d2d3 feat: environment extension data can be split into .olean.server (#7914)
This PR adds a function hook `PersistentEnvExtension.saveEntriesFn` that
can be used to store server-only metadata such as position information
and docstrings that should not affect (re)builds.
2025-04-11 13:06:19 +00:00
Marc Huisinga
39ce3d14f4 test: make test deterministic (#7916) 2025-04-11 11:16:16 +00:00
Kim Morrison
32758aa712 feat: lemmas about permutations (#7912)
This PR adds `List.Perm.take/drop`, and `Array.Perm.extract`,
restricting permutations to sublist / subarrays when they are constant
elsewhere.
2025-04-11 08:13:58 +00:00
Kim Morrison
0f6e35dc63 feat: missing List/Array/Vector lemmas about isSome_idxOf? and relatives (#7913)
This PR adds some missing `List/Array/Vector lemmas` about
`isSome_idxOf?`, `isSome_finIdxOf?`, `isSome_findFinIdx?,
`isSome_findIdx?` and the corresponding `isNone` versions.
2025-04-11 07:45:46 +00:00
Kim Morrison
2528188dde chore: add failing grind test (#7910)
Adds a currently failing test, for a `grind` improvement.
2025-04-11 03:22:56 +00:00
Leonardo de Moura
1cdadfd47a chore: cleanup grind cutsat trace messages (#7908) 2025-04-11 00:52:18 +00:00
Kyle Miller
e07c59c831 fix: eliminate panic when inductive has autoparam parameter with underdetermined type (#7905)
This PR fixes an issue introduced bug #6125 where an `inductive` or
`structure` with an autoimplicit parameter with a type that has a
metavariable would lead to a panic. Closes #7788.

This was due to switching from `Term.addAutoBoundImplicits'` to
`Term.addAutoBoundImplicits` and not properly handling metavariables in
the parameters list. To fix this, now the inductive type headers record
the abstracted type and the number of parameters, rather than record the
parameters, the type, the local context, and the local instances. A
benefit to this over `Term.addAutoBoundImplicits'` is that the type's
parameters do not appear twice in the local context.
2025-04-11 00:19:53 +00:00
Leonardo de Moura
cbd38ceadd fix: mbtc and cast issue in grind (#7907)
This PR fixes two bugs in `grind`. 
1. Model-based theory combination was creating type incorrect terms.
2. `Nat.cast` vs `NatCast.natCast` issue during normalization.
2025-04-10 22:46:56 +00:00
Kyle Miller
c46f1e941c fix: sorry in Infoview shouldn't show module name (#7813)
This PR fixes an issue where `let n : Nat := sorry` in the Infoview
pretty prints as ``n : ℕ := sorry `«Foo:17:17»``. This was caused by
top-level expressions being pretty printed with the same rules as
Infoview hovers. Closes #6715. Refactors `Lean.Widget.ppExprTagged`; now
it takes a delaborator, and downstream users should configure their own
pretty printer option overrides if necessary if they used the `explicit`
argument (see `Lean.Widget.makePopup.ppExprForPopup` for an example).
Breaking change: `ppExprTagged` does not set `pp.proofs` on the root
expression.
2025-04-10 21:47:07 +00:00
Markus Himmel
cf3b257ccd chore: Option cleanup (#7897)
This PR cleans up the `Option` development, upstreaming some results
from mathlib in the process.

Notable changes:
- the name `<op>_eq_some_iff` is preferred over `<op>_eq_some`
- the `simp` normal form for `<$>` is `Option.map`, for `>>=` is
`Option.bind` and for `<|>` is `Option.orElse` (for the former two, this
was already true before this PR). All further lemmas about these
operations are now stated only in terms of
`Option.map`/`Option.bind`/`Option.orElse`. Previously, in some cases
both versions were available, with a prime used to disambiguate (the
primed version was usually the "non-ascii-art" version). Now, there are
no lemmas about the ascii-art versions besides the ones turning them
into the non-ascii-art operations, and there is only one version of
every lemma, about the non-ascii-art operation, and named without a
prime.
2025-04-10 18:53:30 +00:00
Kyle Miller
09ab15dc6d fix: remove infinite loop in withFnRefWhenTagAppFns (#7904)
This PR fixes an oversight in `withFnRefWhenTagAppFns` that causes an
infinite loop when the expression is a constant. This affected pretty
printing of zero-field structures when `pp.tagAppFns` was true (used by
docgen and verso). Closes #7898.
2025-04-10 17:16:29 +00:00
Sebastian Ullrich
e631efd817 feat: introduce Elab.inServer option (#7902)
This PR introduces a dedicated option for checking whether elaborators
are running in the language server.
2025-04-10 14:51:37 +00:00
Sebastian Graf
d2f4ce0158 fix: Add Inhabited instance for OptionT (#7901)
This PR adds `instance [Pure f] : Inhabited (OptionT f α)`, so that
`Inhabited (OptionT Id Empty)` synthesizes.

Co-authored-by: Sebastian Graf <sg@lean-fro.org>
2025-04-10 14:49:03 +00:00
Sebastian Ullrich
69536808ca feat: read/writeModuleDataParts API for serialization with cross-file sharing (#7854)
This PR introduces fundamental API to distribute module data across
multiple files in preparation for the module system.
2025-04-10 13:32:24 +00:00
Markus Himmel
3d5dd15de4 chore: move bmod results from LemmasAux.lean to DivMod/Lemmas.lean (#7899)
This PR shuffles some results about integers around to make sure that
all material that currently exists about `Int.bmod` is located in
`DivMod/Lemmas.lean` and not downstream of that.
2025-04-10 12:07:11 +00:00
Lean stage0 autoupdater
91c245663b chore: update stage0 2025-04-10 12:26:07 +00:00
Sebastian Ullrich
1421b6145e fix: cancellation of synchronous part of previous elaboration (#7882)
This PR fixes a regression where elaboration of a previous document
version is not cancelled on changes to the document.

Done by removing the default from `SnapshotTask.cancelTk?` and
consistently passing the current thread's token for synchronous
elaboration steps.
2025-04-10 11:43:41 +00:00
Kim Morrison
bffa642ad6 feat: Lean.Grind.IsCharP (#7870)
This PR adds a mixin typeclass for `Lean.Grind.CommRing` recording the
characteristic of the ring, and constructs instances for `Int`, `IntX`,
`UIntX`, and `BitVec`.
2025-04-10 08:36:42 +00:00
Kim Morrison
deef1c2739 feat: BitVec.pow and Pow (BitVec w) Nat (#7893)
This PR adds `BitVec.pow` and `Pow (BitVec w) Nat`. The implementation
is the naive one, and should later be replaced by an `@[extern]`. This
is tracked at https://github.com/leanprover/lean4/issues/7887.
2025-04-10 05:21:30 +00:00
Kim Morrison
acf42bd30b chore: add simp lemma Int.cast x = x for x : Int (#7891)
This PR adds the rfl simp lemma `Int.cast x = x` for `x : Int`.
2025-04-10 02:35:06 +00:00
Leonardo de Moura
4947215325 feat: improve funext support in grind (#7892)
This PR improves the support for `funext` in `grind`. We will push
another PR to minimize the number of case-splits later.
2025-04-10 01:57:27 +00:00
Kim Morrison
6e7209dfa3 chore: add Int.dvd_iff_bmod_eq_zero (#7890)
This PR adds missing lemmas about `Int.bmod`, parallel to lemmas about
the other `mod` variants.
2025-04-10 01:36:42 +00:00
Kim Morrison
97a00b3881 chore: variant of Int.toNat_sub (#7889)
This PR adds `Int.toNat_sub''` a variant of `Int.toNat_sub` taking
inequality hypotheses, rather than expecting the arguments to be casts
of natural numbers. This is parallel to the existing `toNat_add` and
`toNat_mul`.
2025-04-10 01:34:48 +00:00
Kim Morrison
d758b4c862 chore: Fin.ofNat'_mul, analogous to existing add lemmas (#7888)
This PR adds `Fin.ofNat'_mul` and `Fin.mul_ofNat'`, parallel to the
existing lemmas about `add`.
2025-04-10 01:32:47 +00:00
Kim Morrison
61d7716ad8 feat: UIntX.pow and Pow UIntX Nat instances (#7886)
This PR adds `UIntX.pow` and `Pow UIntX Nat` instances, and similarly
for signed fixed-width integers. These are currently only the naive
implementation, and will need to be subsequently replaced via
`@[extern]` with fast implementations (tracked at #7887).
2025-04-10 00:27:48 +00:00
Kim Morrison
05f16ed279 feat: UIntX.ofInt (#7880)
This PR adds the functions `UIntX.ofInt`, and basic lemmas.
2025-04-09 23:50:29 +00:00
765 changed files with 12959 additions and 2861 deletions

View File

@@ -46,7 +46,7 @@ jobs:
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_COMPRESS: true
# current cache limit
CCACHE_MAXSIZE: 600M
CCACHE_MAXSIZE: 400M
# squelch error message about missing nixpkgs channel
NIX_BUILD_SHELL: bash
LSAN_OPTIONS: max_leaks=10

View File

@@ -256,17 +256,18 @@ jobs:
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-linux-gnu.tar.zst",
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*"
},
{
"name": "Linux 32bit",
"os": "ubuntu-latest",
// Use 32bit on stage0 and stage1 to keep oleans compatible
"CMAKE_OPTIONS": "-DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DLEAN_EXTRA_CXX_FLAGS='-m32' -DLEANC_OPTS='-m32' -DMMAP=OFF -DLEAN_INSTALL_SUFFIX=-linux_x86 -DCMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DSTAGE0_CMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DPKG_CONFIG_EXECUTABLE=/usr/bin/i386-linux-gnu-pkg-config",
"cmultilib": true,
"release": true,
"check-level": 2,
"cross": true,
"shell": "bash -euxo pipefail {0}"
}
// Started running out of memory building expensive modules, a 2GB heap is just not that much even before fragmentation
//{
// "name": "Linux 32bit",
// "os": "ubuntu-latest",
// // Use 32bit on stage0 and stage1 to keep oleans compatible
// "CMAKE_OPTIONS": "-DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DLEAN_EXTRA_CXX_FLAGS='-m32' -DLEANC_OPTS='-m32' -DMMAP=OFF -DLEAN_INSTALL_SUFFIX=-linux_x86 -DCMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DSTAGE0_CMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DPKG_CONFIG_EXECUTABLE=/usr/bin/i386-linux-gnu-pkg-config",
// "cmultilib": true,
// "release": true,
// "check-level": 2,
// "cross": true,
// "shell": "bash -euxo pipefail {0}"
//}
// {
// "name": "Web Assembly",
// "os": "ubuntu-latest",

View File

@@ -108,6 +108,7 @@ ExternalProject_add(stage2
INSTALL_COMMAND ""
DEPENDS stage1
EXCLUDE_FROM_ALL ON
STEP_TARGETS configure
)
ExternalProject_add(stage3
SOURCE_DIR "${LEAN_SOURCE_DIR}"

View File

@@ -780,12 +780,11 @@ add_custom_target(clean-olean
DEPENDS clean-stdlib)
install(DIRECTORY "${CMAKE_BINARY_DIR}/lib/" DESTINATION lib
PATTERN temp
PATTERN "*.export"
PATTERN "*.hash"
PATTERN "*.trace"
PATTERN "*.rsp"
EXCLUDE)
PATTERN temp EXCLUDE
PATTERN "*.export" EXCLUDE
PATTERN "*.hash" EXCLUDE
PATTERN "*.trace" EXCLUDE
PATTERN "*.rsp" EXCLUDE)
# symlink source into expected installation location for go-to-definition, if file system allows it
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/src)

View File

@@ -59,6 +59,9 @@ instance : Monad (OptionT m) where
pure := OptionT.pure
bind := OptionT.bind
instance {m : Type u Type v} [Pure m] : Inhabited (OptionT m α) where
default := pure (f:=m) default
/--
Recovers from failures. Typically used via the `<|>` operator.
-/

View File

@@ -738,6 +738,20 @@ Unlike `x ≠ y` (which is notation for `Ne x y`), this is `Bool` valued instead
recommended_spelling "bne" for "!=" in [bne, «term_!=_»]
/-- `ReflBEq α` says that the `BEq` implementation is reflexive. -/
class ReflBEq (α) [BEq α] : Prop where
/-- `==` is reflexive, that is, `(a == a) = true`. -/
protected rfl {a : α} : a == a
@[simp] theorem BEq.rfl [BEq α] [ReflBEq α] {a : α} : a == a := ReflBEq.rfl
theorem BEq.refl [BEq α] [ReflBEq α] (a : α) : a == a := BEq.rfl
theorem beq_of_eq [BEq α] [ReflBEq α] {a b : α} : a = b a == b
| rfl => BEq.rfl
theorem not_eq_of_beq_eq_false [BEq α] [ReflBEq α] {a b : α} (h : (a == b) = false) : ¬a = b := by
intro h'; subst h'; have : true = false := BEq.rfl.symm.trans h; contradiction
/--
A Boolean equality test coincides with propositional equality.
@@ -745,11 +759,9 @@ In other words:
* `a == b` implies `a = b`.
* `a == a` is true.
-/
class LawfulBEq (α : Type u) [BEq α] : Prop where
class LawfulBEq (α : Type u) [BEq α] : Prop extends ReflBEq α where
/-- If `a == b` evaluates to `true`, then `a` and `b` are equal in the logic. -/
eq_of_beq : {a b : α} a == b a = b
/-- `==` is reflexive, that is, `(a == a) = true`. -/
protected rfl : {a : α} a == a
export LawfulBEq (eq_of_beq)
@@ -761,6 +773,15 @@ instance [DecidableEq α] : LawfulBEq α where
eq_of_beq := of_decide_eq_true
rfl := of_decide_eq_self_eq_true _
/--
Non-instance for `DecidableEq` from `LawfulBEq`.
To use this, add `attribute [local instance 5] instDecidableEqOfLawfulBEq` at the top of a file.
-/
def instDecidableEqOfLawfulBEq [BEq α] [LawfulBEq α] : DecidableEq α := fun x y =>
match h : x == y with
| false => .isFalse (not_eq_of_beq_eq_false h)
| true => .isTrue (eq_of_beq h)
instance : LawfulBEq Char := inferInstance
instance : LawfulBEq String := inferInstance
@@ -855,8 +876,8 @@ theorem Bool.of_not_eq_false : {b : Bool} → ¬ (b = false) → b = true
| true, _ => rfl
| false, h => absurd rfl h
theorem ne_of_beq_false [BEq α] [LawfulBEq α] {a b : α} (h : (a == b) = false) : a b := by
intro h'; subst h'; have : true = false := Eq.trans LawfulBEq.rfl.symm h; contradiction
theorem ne_of_beq_false [BEq α] [ReflBEq α] {a b : α} (h : (a == b) = false) : a b :=
not_eq_of_beq_eq_false h
theorem beq_false_of_ne [BEq α] [LawfulBEq α] {a b : α} (h : a b) : (a == b) = false :=
have : ¬ (a == b) = true := by
@@ -1296,6 +1317,15 @@ theorem eta (a : {x // p x}) (h : p (val a)) : mk (val a) h = a := by
cases a
exact rfl
instance {α : Type u} {p : α Prop} [BEq α] : BEq {x : α // p x} :=
fun x y => x.1 == y.1
instance {α : Type u} {p : α Prop} [BEq α] [ReflBEq α] : ReflBEq {x : α // p x} where
rfl {x} := BEq.refl x.1
instance {α : Type u} {p : α Prop} [BEq α] [LawfulBEq α] : LawfulBEq {x : α // p x} where
eq_of_beq h := Subtype.eq (eq_of_beq h)
instance {α : Type u} {p : α Prop} [DecidableEq α] : DecidableEq {x : α // p x} :=
fun a, h₁ b, h₂ =>
if h : a = b then isTrue (by subst h; exact rfl)
@@ -1564,7 +1594,7 @@ theorem Nat.succ.injEq (u v : Nat) : (u.succ = v.succ) = (u = v) :=
Eq.propIntro Nat.succ.inj (congrArg Nat.succ)
@[simp] theorem beq_iff_eq [BEq α] [LawfulBEq α] {a b : α} : a == b a = b :=
eq_of_beq, by intro h; subst h; exact LawfulBEq.rfl
eq_of_beq, beq_of_eq
/-! # Prop lemmas -/

View File

@@ -34,7 +34,6 @@ import Init.Data.Stream
import Init.Data.Prod
import Init.Data.AC
import Init.Data.Queue
import Init.Data.Channel
import Init.Data.Sum
import Init.Data.BEq
import Init.Data.Subtype

View File

@@ -525,7 +525,7 @@ theorem countP_attachWith {p : α → Prop} {q : α → Bool} {xs : Array α} {H
simp
@[simp]
theorem count_attach [DecidableEq α] {xs : Array α} {a : {x // x xs}} :
theorem count_attach [BEq α] {xs : Array α} {a : {x // x xs}} :
xs.attach.count a = xs.count a := by
rcases xs with xs
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.count_toArray]
@@ -534,7 +534,7 @@ theorem count_attach [DecidableEq α] {xs : Array α} {a : {x // x ∈ xs}} :
rw [List.countP_pmap, List.countP_attach (p := (fun x => x == a.1)), List.count]
@[simp]
theorem count_attachWith [DecidableEq α] {p : α Prop} {xs : Array α} (H : a xs, p a) {a : {x // p x}} :
theorem count_attachWith [BEq α] {p : α Prop} {xs : Array α} (H : a xs, p a) {a : {x // p x}} :
(xs.attachWith p H).count a = xs.count a := by
cases xs
simp

View File

@@ -257,8 +257,8 @@ theorem filter_beq {xs : Array α} (a : α) : xs.filter (· == a) = replicate (c
rcases xs with xs
simp [List.filter_beq]
theorem filter_eq {α} [DecidableEq α] {xs : Array α} (a : α) : xs.filter (· = a) = replicate (count a xs) a :=
filter_beq a
theorem filter_eq {α} [BEq α] [LawfulBEq α] [DecidableEq α] {xs : Array α} (a : α) : xs.filter (· = a) = replicate (count a xs) a :=
funext (Bool.beq_eq_decide_eq · a) filter_beq a
theorem replicate_count_eq_of_count_eq_size {xs : Array α} (h : count a xs = xs.size) :
replicate (count a xs) a = xs := by
@@ -273,7 +273,7 @@ abbrev mkArray_count_eq_of_count_eq_size := @replicate_count_eq_of_count_eq_size
rcases xs with xs
simp [List.count_filter, h]
theorem count_le_count_map [DecidableEq β] {xs : Array α} {f : α β} {x : α} :
theorem count_le_count_map [BEq β] [LawfulBEq β] {xs : Array α} {f : α β} {x : α} :
count x xs count (f x) (map f xs) := by
rcases xs with xs
simp [List.count_le_count_map, countP_map]
@@ -288,15 +288,25 @@ theorem count_flatMap {α} [BEq β] {xs : Array α} {f : α → Array β} {x :
rcases xs with xs
simp [List.count_flatMap, countP_flatMap, Function.comp_def]
-- FIXME these theorems can be restored once `List.erase` and `Array.erase` have been related.
theorem countP_replace {a b : α} {xs : Array α} {p : α Bool} :
(xs.replace a b).countP p =
if xs.contains a then xs.countP p + (if p b then 1 else 0) - (if p a then 1 else 0) else xs.countP p := by
rcases xs with xs
simp [List.countP_replace]
-- theorem count_erase (a b : α) (l : Array α) : count a (l.erase b) = count a l - if b == a then 1 else 0 := by
-- sorry
theorem count_replace {a b c : α} {xs : Array α} :
(xs.replace a b).count c =
if xs.contains a then xs.count c + (if b == c then 1 else 0) - (if a == c then 1 else 0) else xs.count c := by
simp [count_eq_countP, countP_replace]
-- @[simp] theorem count_erase_self (a : α) (l : Array α) :
-- count a (l.erase a) = count a l - 1 := by rw [count_erase, if_pos (by simp)]
theorem count_erase (a b : α) (xs : Array α) : count a (xs.erase b) = count a xs - if b == a then 1 else 0 := by
rcases xs with l
simp [List.count_erase]
-- @[simp] theorem count_erase_of_ne (ab : a ≠ b) (l : Array α) : count a (l.erase b) = count a l := by
-- rw [count_erase, if_neg (by simpa using ab.symm), Nat.sub_zero]
@[simp] theorem count_erase_self (a : α) (xs : Array α) :
count a (xs.erase a) = count a xs - 1 := by rw [count_erase, if_pos (by simp)]
@[simp] theorem count_erase_of_ne (ab : a b) (xs : Array α) : count a (xs.erase b) = count a xs := by
rw [count_erase, if_neg (by simpa using ab.symm), Nat.sub_zero]
end count

View File

@@ -114,8 +114,10 @@ end List
namespace Array
instance [BEq α] [LawfulBEq α] : LawfulBEq (Array α) where
instance [BEq α] [ReflBEq α] : ReflBEq (Array α) where
rfl := by simp [BEq.beq, isEqv_self_beq]
instance [BEq α] [LawfulBEq α] : LawfulBEq (Array α) where
eq_of_beq := by
rintro _ _ h
simpa using h

View File

@@ -59,7 +59,7 @@ theorem exists_or_eq_self_of_eraseP (p) (xs : Array α) :
@[simp] theorem size_eraseP_of_mem {xs : Array α} (al : a xs) (pa : p a) :
(xs.eraseP p).size = xs.size - 1 := by
let _, ys, zs, _, _, e₁, e₂ := exists_of_eraseP al pa
rw [e₂]; simp [size_append, e₁]; omega
rw [e₂]; simp [size_append, e₁]
theorem size_eraseP {xs : Array α} : (xs.eraseP p).size = if xs.any p then xs.size - 1 else xs.size := by
split <;> rename_i h

View File

@@ -446,11 +446,13 @@ theorem findIdx?_eq_none_iff {xs : Array α} {p : α → Bool} :
rcases xs with xs
simp
@[simp]
theorem findIdx?_isSome {xs : Array α} {p : α Bool} :
(xs.findIdx? p).isSome = xs.any p := by
rcases xs with xs
simp [List.findIdx?_isSome]
@[simp]
theorem findIdx?_isNone {xs : Array α} {p : α Bool} :
(xs.findIdx? p).isNone = xs.all (¬p ·) := by
rcases xs with xs
@@ -591,6 +593,18 @@ theorem findFinIdx?_eq_some_iff {xs : Array α} {p : α → Bool} {i : Fin xs.si
· rintro h, w
exact i, i.2, h, fun j hji => w j, by omega hji, rfl
@[simp]
theorem isSome_findFinIdx? {xs : Array α} {p : α Bool} :
(xs.findFinIdx? p).isSome = xs.any p := by
rcases xs with xs
simp
@[simp]
theorem isNone_findFinIdx? {xs : Array α} {p : α Bool} :
(xs.findFinIdx? p).isNone = xs.all (fun x => ¬ p x) := by
rcases xs with xs
simp
@[simp] theorem findFinIdx?_subtype {p : α Prop} {xs : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
xs.findFinIdx? f = (xs.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
@@ -636,6 +650,20 @@ The lemmas below should be made consistent with those for `findIdx?` (and proved
rcases xs with xs
simp [List.idxOf?_eq_none_iff]
@[simp]
theorem isSome_idxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
(xs.idxOf? a).isSome a xs := by
rcases xs with xs
simp
@[simp]
theorem isNone_idxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
(xs.idxOf? a).isNone = ¬ a xs := by
rcases xs with xs
simp
/-! ### finIdxOf?
The verification API for `finIdxOf?` is still incomplete.
@@ -658,4 +686,16 @@ theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : Array α} {a : α} :
rcases xs with xs
simp [List.finIdxOf?_eq_some_iff]
@[simp]
theorem isSome_finIdxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
(xs.finIdxOf? a).isSome a xs := by
rcases xs with xs
simp
@[simp]
theorem isNone_finIdxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
(xs.finIdxOf? a).isNone = ¬ a xs := by
rcases xs with xs
simp
end Array

View File

@@ -135,6 +135,9 @@ theorem getElem?_eq_none {xs : Array α} (h : xs.size ≤ i) : xs[i]? = none :=
theorem getElem?_eq_some_iff {xs : Array α} : xs[i]? = some b h : i < xs.size, xs[i] = b := by
simp [getElem?_def]
theorem getElem_of_getElem? {xs : Array α} : xs[i]? = some a h : i < xs.size, xs[i] = a :=
getElem?_eq_some_iff.mp
theorem some_eq_getElem?_iff {xs : Array α} : some b = xs[i]? h : i < xs.size, xs[i] = b := by
rw [eq_comm, getElem?_eq_some_iff]
@@ -826,9 +829,6 @@ theorem contains_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : Array α}
@[deprecated contains_eq_true_of_mem (since := "2024-12-12")]
abbrev elem_eq_true_of_mem := @contains_eq_true_of_mem
instance [BEq α] [LawfulBEq α] (a : α) (as : Array α) : Decidable (a as) :=
decidable_of_decidable_of_iff (Iff.intro mem_of_contains_eq_true contains_eq_true_of_mem)
@[simp] theorem elem_eq_contains [BEq α] {a : α} {xs : Array α} :
elem a xs = xs.contains a := by
simp [elem]
@@ -839,6 +839,9 @@ theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
xs.contains a = true a xs := mem_of_contains_eq_true, contains_eq_true_of_mem
instance [BEq α] [LawfulBEq α] (a : α) (as : Array α) : Decidable (a as) :=
decidable_of_decidable_of_iff elem_iff
theorem elem_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
elem a xs = decide (a xs) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
@@ -1091,33 +1094,23 @@ private theorem beq_of_beq_singleton [BEq α] {a b : α} : #[a] == #[b] → a ==
apply beq_of_beq_singleton
simp
· intro h
constructor
apply Array.isEqv_self_beq
infer_instance
@[simp] theorem lawfulBEq_iff [BEq α] : LawfulBEq (Array α) LawfulBEq α := by
constructor
· intro h
have : ReflBEq α := reflBEq_iff.mp inferInstance
constructor
· intro a b h
apply singleton_inj.1
apply eq_of_beq
simpa [instBEq, isEqv, isEqvAux]
· intro a
apply beq_of_beq_singleton
simp
intro a b h
apply singleton_inj.1
apply eq_of_beq
simpa [instBEq, isEqv, isEqvAux]
· intro h
constructor
· intro xs ys h
obtain hs, hi := isEqv_iff_rel.mp h
ext i h₁ h₂
· exact hs
· simpa using hi _ h₁
· intro xs
apply Array.isEqv_self_beq
infer_instance
/-! ### isEqv -/
@[simp] theorem isEqv_eq [DecidableEq α] {xs ys : Array α} : xs.isEqv ys (· == ·) = (xs = ys) := by
@[simp] theorem isEqv_eq [BEq α] [LawfulBEq α] {xs ys : Array α} : xs.isEqv ys (· == ·) = (xs = ys) := by
cases xs
cases ys
simp
@@ -3035,7 +3028,7 @@ theorem foldrM_start_stop {m} [Monad m] {xs : Array α} {f : α → β → m β}
simp
| succ i ih =>
unfold foldrM.fold
simp only [beq_iff_eq, Nat.add_right_eq_self, Nat.add_one_ne_zero, reduceIte, Nat.add_eq,
simp only [beq_iff_eq, Nat.add_eq_left, Nat.add_one_ne_zero, reduceIte, Nat.add_eq,
getElem_extract]
congr
funext b
@@ -3777,14 +3770,8 @@ variable [LawfulBEq α]
theorem getElem?_replace {xs : Array α} {i : Nat} :
(xs.replace a b)[i]? = if xs[i]? == some a then if a xs.take i then some a else some b else xs[i]? := by
rcases xs with xs
simp only [List.replace_toArray, List.getElem?_toArray, List.getElem?_replace, beq_iff_eq,
take_eq_extract, List.extract_toArray, List.extract_eq_drop_take, Nat.sub_zero, List.drop_zero,
mem_toArray]
split <;> rename_i h
· rw (occs := [2]) [if_pos]
simpa using h
· rw [if_neg]
simpa using h
simp only [List.replace_toArray, List.getElem?_toArray, List.getElem?_replace, take_eq_extract,
List.extract_toArray, List.extract_eq_drop_take, Nat.sub_zero, List.drop_zero, mem_toArray]
theorem getElem?_replace_of_ne {xs : Array α} {i : Nat} (h : xs[i]? some a) :
(xs.replace a b)[i]? = xs[i]? := by
@@ -4276,11 +4263,9 @@ theorem getElem?_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size]? = some
/-! ### contains -/
theorem contains_def [DecidableEq α] {a : α} {xs : Array α} : xs.contains a a xs := by
rw [mem_def, contains, any_toList, List.any_eq_true]; simp [and_comm]
instance [DecidableEq α] (a : α) (xs : Array α) : Decidable (a xs) :=
decidable_of_iff _ contains_def
@[deprecated contains_iff (since := "2025-04-07")]
abbrev contains_def [DecidableEq α] {a : α} {xs : Array α} : xs.contains a a xs :=
contains_iff
/-! ### isPrefixOf -/

View File

@@ -150,13 +150,13 @@ instance [DecidableEq α] [LT α] [DecidableLT α]
Std.Total (· · : Array α Array α Prop) where
total := Array.le_total
@[simp] theorem lex_eq_true_iff_lt [DecidableEq α] [LT α] [DecidableLT α]
@[simp] theorem lex_eq_true_iff_lt [BEq α] [LawfulBEq α] [LT α] [DecidableLT α]
{xs ys : Array α} : lex xs ys = true xs < ys := by
cases xs
cases ys
simp
@[simp] theorem lex_eq_false_iff_ge [DecidableEq α] [LT α] [DecidableLT α]
@[simp] theorem lex_eq_false_iff_ge [BEq α] [LawfulBEq α] [LT α] [DecidableLT α]
{xs ys : Array α} : lex xs ys = false ys xs := by
cases xs
cases ys

View File

@@ -34,7 +34,7 @@ theorem perm_iff_toList_perm {as bs : Array α} : as ~ bs ↔ as.toList ~ bs.toL
cases xs
simp
protected theorem Perm.rfl {xs : List α} : xs ~ xs := .refl _
protected theorem Perm.rfl {xs : Array α} : xs ~ xs := .refl _
theorem Perm.of_eq {xs ys : Array α} (h : xs = ys) : xs ~ ys := h .rfl
@@ -53,6 +53,17 @@ instance : Trans (Perm (α := α)) (Perm (α := α)) (Perm (α := α)) where
theorem perm_comm {xs ys : Array α} : xs ~ ys ys ~ xs := Perm.symm, Perm.symm
theorem Perm.length_eq {xs ys : Array α} (p : xs ~ ys) : xs.size = ys.size := by
cases xs; cases ys
simp only [perm_toArray] at p
simpa using p.length_eq
theorem Perm.mem_iff {a : α} {xs ys : Array α} (p : xs ~ ys) : a xs a ys := by
rcases xs with xs
rcases ys with ys
simp at p
simpa using p.mem_iff
theorem Perm.push (x y : α) {xs ys : Array α} (p : xs ~ ys) :
(xs.push x).push y ~ (ys.push y).push x := by
cases xs; cases ys
@@ -65,4 +76,20 @@ theorem swap_perm {xs : Array α} {i j : Nat} (h₁ : i < xs.size) (h₂ : j < x
simp only [swap, perm_iff_toList_perm, toList_set]
apply set_set_perm
namespace Perm
set_option linter.indexVariables false in
theorem extract {xs ys : Array α} (h : xs ~ ys) {lo hi : Nat}
(wlo : i, i < lo xs[i]? = ys[i]?) (whi : i, hi i xs[i]? = ys[i]?) :
(xs.extract lo hi) ~ (ys.extract lo hi) := by
rcases xs with xs
rcases ys with ys
simp_all only [perm_toArray, List.getElem?_toArray, List.extract_toArray,
List.extract_eq_drop_take]
apply List.Perm.take_of_getElem? (w := fun i h => by simpa using whi (lo + i) (by omega))
apply List.Perm.drop_of_getElem? (w := wlo)
exact h
end Perm
end Array

View File

@@ -19,21 +19,9 @@ class PartialEquivBEq (α) [BEq α] : Prop where
/-- Transitivity for `BEq`. If `a == b` and `b == c` then `a == c`. -/
trans : (a : α) == b b == c a == c
/-- `ReflBEq α` says that the `BEq` implementation is reflexive. -/
class ReflBEq (α) [BEq α] : Prop where
/-- Reflexivity for `BEq`. -/
refl : (a : α) == a
/-- `EquivBEq` says that the `BEq` implementation is an equivalence relation. -/
class EquivBEq (α) [BEq α] : Prop extends PartialEquivBEq α, ReflBEq α
@[simp]
theorem BEq.refl [BEq α] [ReflBEq α] {a : α} : a == a :=
ReflBEq.refl
theorem beq_of_eq [BEq α] [ReflBEq α] {a b : α} : a = b a == b
| rfl => BEq.refl
theorem BEq.symm [BEq α] [PartialEquivBEq α] {a b : α} : a == b b == a :=
PartialEquivBEq.symm
@@ -66,6 +54,5 @@ theorem BEq.neq_of_beq_of_neq [BEq α] [PartialEquivBEq α] {a b c : α} :
fun h₁ h₂ => Bool.eq_false_iff.2 fun h₃ => Bool.eq_false_iff.1 h₂ (BEq.trans (BEq.symm h₁) h₃)
instance (priority := low) [BEq α] [LawfulBEq α] : EquivBEq α where
refl := LawfulBEq.rfl
symm h := beq_iff_eq.2 <| Eq.symm <| beq_iff_eq.1 h
trans hab hbc := beq_iff_eq.2 <| (beq_iff_eq.1 hab).trans <| beq_iff_eq.1 hbc

View File

@@ -227,6 +227,20 @@ SMT-LIB name: `bvmul`.
protected def mul (x y : BitVec n) : BitVec n := BitVec.ofNat n (x.toNat * y.toNat)
instance : Mul (BitVec n) := .mul
/--
Raises a bitvector to a natural number power. Usually accessed via the `^` operator.
Note that this is currently an inefficient implementation,
and should be replaced via an `@[extern]` with a native implementation.
See https://github.com/leanprover/lean4/issues/7887.
-/
protected def pow (x : BitVec n) (y : Nat) : BitVec n :=
match y with
| 0 => 1
| y + 1 => x.pow y * x
instance : Pow (BitVec n) Nat where
pow x y := x.pow y
/--
Unsigned division of bitvectors using the Lean convention where division by zero returns zero.
Usually accessed via the `/` operator.

View File

@@ -566,7 +566,7 @@ theorem ult_eq_msb_of_msb_neq {x y : BitVec w} (h : x.msb ≠ y.msb) :
theorem slt_eq_not_ult_of_msb_neq {x y : BitVec w} (h : x.msb y.msb) :
x.slt y = !x.ult y := by
simp only [BitVec.slt, toInt_eq_msb_cond, Bool.eq_not_of_ne h, ult_eq_msb_of_msb_neq h]
cases y.msb <;> (simp; omega)
cases y.msb <;> (simp [-Int.natCast_pow]; omega)
theorem slt_eq_ult {x y : BitVec w} :
x.slt y = (x.msb != y.msb).xor (x.ult y) := by
@@ -1332,7 +1332,7 @@ theorem saddOverflow_eq {w : Nat} (x y : BitVec w) :
simp only [ decide_or, msb_eq_toInt, decide_beq_decide, toInt_add, decide_not, decide_and,
decide_eq_decide]
rw_mod_cast [Int.bmod_neg_iff (by omega) (by omega)]
simp
simp only [Nat.add_one_sub_one, ge_iff_le]
omega
theorem usubOverflow_eq {w : Nat} (x y : BitVec w) :
@@ -1456,7 +1456,6 @@ theorem udiv_intMin_of_msb_false {x : BitVec w} (h : x.msb = false) :
have wpos : 0 < w := by omega
have := Nat.two_pow_pos (w-1)
simp [toNat_eq, wpos]
rw [Nat.div_eq_zero_iff_lt (by omega)]
exact toNat_lt_of_msb_false h
theorem sdiv_intMin {x : BitVec w} :
@@ -1571,7 +1570,8 @@ theorem intMin_udiv_eq_intMin_iff (x : BitVec w) :
· intro h
rw [ toInt_inj, toInt_eq_msb_cond] at h
have : (intMin w / x).msb = false := by simp [msb_udiv, msb_intMin, wpos, hx]
simp [this, wpos, toInt_intMin] at h
simp only [this, false_eq_true, reduceIte, toNat_udiv, toNat_intMin, wpos,
Nat.two_pow_pred_mod_two_pow, Int.natCast_ediv, toInt_intMin] at h
omega
· intro h
subst h
@@ -1612,11 +1612,11 @@ theorem toInt_sdiv_of_ne_or_ne (a b : BitVec w) (h : a ≠ intMin w b ≠ -1
Nat.two_pow_pred_mod_two_pow, Int.neg_tdiv, Int.neg_neg]
rw [Int.tdiv_self (by omega)]
· by_cases ha_nonneg : 0 a.toInt
· simp [Int.tdiv_eq_zero_of_lt ha_nonneg (by norm_cast at *), ha_intMin]
· simp [Int.tdiv_eq_zero_of_lt ha_nonneg (by norm_cast at *), ha_intMin, -Int.natCast_pow]
· simp only [ne_eq, toInt_inj, toInt_intMin, wpos, Nat.two_pow_pred_mod_two_pow] at h
rw [ Int.neg_tdiv, Int.tdiv_eq_zero_of_lt (by omega)]
· simp [ha_intMin]
· simp [wpos, toInt_ne, toInt_intMin] at ha_intMin
· simp [wpos, toInt_ne, toInt_intMin, -Int.natCast_pow] at ha_intMin
omega
· by_cases ha : a.msb <;> by_cases hb : b.msb

View File

@@ -68,6 +68,9 @@ theorem getElem?_eq_some_iff {l : BitVec w} : l[n]? = some a ↔ ∃ h : n < w,
· simp_all
· simp; omega
theorem getElem_of_getElem? {l : BitVec w} : l[n]? = some a h : n < w, l[n] = a :=
getElem?_eq_some_iff.mp
set_option linter.missingDocs false in
@[deprecated getElem?_eq_some_iff (since := "2025-02-17")]
abbrev getElem?_eq_some := @getElem?_eq_some_iff
@@ -449,7 +452,7 @@ theorem getLsbD_ofNat (n : Nat) (x : Nat) (i : Nat) :
@[simp] theorem sub_add_bmod_cancel {x y : BitVec w} :
((((2 ^ w : Nat) - y.toNat) : Int) + x.toNat).bmod (2 ^ w) =
((x.toNat : Int) - y.toNat).bmod (2 ^ w) := by
rw [Int.sub_eq_add_neg, Int.add_assoc, Int.add_comm, Int.bmod_add_cancel, Int.add_comm,
rw [Int.sub_eq_add_neg, Int.add_assoc, Int.add_comm, Int.add_bmod_right, Int.add_comm,
Int.sub_eq_add_neg]
private theorem lt_two_pow_of_le {x m n : Nat} (lt : x < 2 ^ m) (le : m n) : x < 2 ^ n :=
@@ -655,20 +658,19 @@ theorem toInt_ne {x y : BitVec n} : x.toInt ≠ y.toInt ↔ x ≠ y := by
unfold BitVec.ofInt
simp
theorem toInt_ofNat {n : Nat} (x : Nat) :
(BitVec.ofNat n x).toInt = (x : Int).bmod (2^n) := by
simp [toInt_eq_toNat_bmod]
theorem toInt_ofNat {n : Nat} (x : Nat) : (BitVec.ofNat n x).toInt = (x : Int).bmod (2^n) := by
simp [toInt_eq_toNat_bmod, -Int.natCast_pow]
@[simp] theorem toInt_ofInt {n : Nat} (i : Int) :
(BitVec.ofInt n i).toInt = i.bmod (2^n) := by
have _ := Nat.two_pow_pos n
have p : 0 i % (2^n : Nat) := by omega
simp [toInt_eq_toNat_bmod, Int.toNat_of_nonneg p]
simp [toInt_eq_toNat_bmod, Int.toNat_of_nonneg p, -Int.natCast_pow]
theorem toInt_ofInt_eq_self {w : Nat} (hw : 0 < w) {n : Int}
(h : -2 ^ (w - 1) n) (h' : n < 2 ^ (w - 1)) : (BitVec.ofInt w n).toInt = n := by
have hw : w = (w - 1) + 1 := by omega
rw [toInt_ofInt, Int.bmod_eq_self_of_le] <;> (rw [hw]; simp [Int.natCast_pow]; omega)
rw [toInt_ofInt, Int.bmod_eq_of_le] <;> (rw [hw]; simp [Int.natCast_pow]; omega)
@[simp] theorem ofInt_natCast (w n : Nat) :
BitVec.ofInt w (n : Int) = BitVec.ofNat w n := rfl
@@ -676,16 +678,13 @@ theorem toInt_ofInt_eq_self {w : Nat} (hw : 0 < w) {n : Int}
@[simp] theorem ofInt_ofNat (w n : Nat) :
BitVec.ofInt w (no_index (OfNat.ofNat n)) = BitVec.ofNat w (OfNat.ofNat n) := rfl
@[simp] theorem ofInt_toInt {x : BitVec w} : BitVec.ofInt w x.toInt = x := by
by_cases h : 2 * x.toNat < 2^w <;> ext <;> simp [getLsbD_eq_getElem, getLsbD, h, BitVec.toInt]
theorem toInt_neg_iff {w : Nat} {x : BitVec w} :
BitVec.toInt x < 0 2 ^ w 2 * x.toNat := by
simp [toInt_eq_toNat_cond]; omega
simp only [toInt_eq_toNat_cond]; omega
theorem toInt_pos_iff {w : Nat} {x : BitVec w} :
0 BitVec.toInt x 2 * x.toNat < 2 ^ w := by
simp [toInt_eq_toNat_cond]; omega
simp only [toInt_eq_toNat_cond]; omega
theorem eq_zero_or_eq_one (a : BitVec 1) : a = 0#1 a = 1#1 := by
obtain a, ha := a
@@ -777,6 +776,12 @@ theorem le_toInt {w : Nat} (x : BitVec w) : -2 ^ (w - 1) ≤ x.toInt := by
rw [(show w = w - 1 + 1 by omega), Int.pow_succ] at this
omega
@[simp] theorem ofInt_toInt {x : BitVec w} : BitVec.ofInt w x.toInt = x := by
apply eq_of_toInt_eq
rw [toInt_ofInt, Int.bmod_eq_of_le_mul_two]
· simpa [Int.mul_comm _ 2] using le_two_mul_toInt
· simpa [Int.mul_comm _ 2] using two_mul_toInt_lt
/-! ### sle/slt -/
/--
@@ -795,7 +800,7 @@ theorem slt_zero_iff_msb_cond {x : BitVec w} : x.slt 0#w ↔ x.msb = true := by
omega /- Can't have `x.toInt` which is equal to `x.toNat` be strictly less than zero -/
· intros h
simp only [h, reduceIte] at this
simp [BitVec.slt, this]
simp only [BitVec.slt, this, toInt_zero, decide_eq_true_eq]
omega
theorem slt_zero_eq_msb {w : Nat} {x : BitVec w} : x.slt 0#w = x.msb := by
@@ -866,7 +871,7 @@ theorem zeroExtend_eq_setWidth {v : Nat} {x : BitVec w} :
@[simp] theorem toInt_setWidth (x : BitVec w) :
(x.setWidth v).toInt = Int.bmod x.toNat (2^v) := by
simp [toInt_eq_toNat_bmod, toNat_setWidth, Int.emod_bmod]
simp [toInt_eq_toNat_bmod, toNat_setWidth, Int.emod_bmod, -Int.natCast_pow]
@[simp] theorem toFin_setWidth {x : BitVec w} :
(x.setWidth v).toFin = Fin.ofNat' (2^v) x.toNat := by
@@ -1059,7 +1064,7 @@ and the second `setWidth` is a non-trivial extension.
theorem toInt_setWidth' {m n : Nat} (p : m n) {x : BitVec m} :
(setWidth' p x).toInt = if m = n then x.toInt else x.toNat := by
split
case isTrue h => simp [h, toInt_eq_toNat_bmod]
case isTrue h => simp [h, toInt_eq_toNat_bmod, -Int.natCast_pow]
case isFalse h => rw [toInt_setWidth'_of_lt (by omega)]
@[simp] theorem toFin_setWidth' {m n : Nat} (p : m n) (x : BitVec m) :
@@ -1267,7 +1272,7 @@ theorem extractLsb'_eq_zero {x : BitVec w} {start : Nat} :
· subst h
simp
· have : 1 < 2 ^ w := by simp [h]
simp [BitVec.toInt]
simp [BitVec.toInt, -Int.natCast_pow]
omega
@[simp] theorem toFin_allOnes : (allOnes w).toFin = Fin.ofNat' (2^w) (2^w - 1) := by
@@ -1627,7 +1632,8 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
@[simp] theorem toInt_not {x : BitVec w} :
(~~~x).toInt = Int.bmod (2^w - 1 - x.toNat) (2^w) := by
rw_mod_cast [BitVec.toInt, BitVec.toNat_not, Int.bmod_def]
simp [show ((2^w : Nat) : Int) - 1 - x.toNat = ((2^w - 1 - x.toNat) : Nat) by omega]
simp [show ((2^w : Nat) : Int) - 1 - x.toNat = ((2^w - 1 - x.toNat) : Nat) by omega,
-Int.natCast_pow]
rw_mod_cast [Nat.mod_eq_of_lt (by omega)]
omega
@@ -1803,7 +1809,7 @@ theorem not_xor_right {x y : BitVec w} : ~~~ (x ^^^ y) = x ^^^ ~~~ y := by
@[simp] theorem toInt_shiftLeft {x : BitVec w} :
(x <<< n).toInt = (x.toNat <<< n : Int).bmod (2^w) := by
rw [toInt_eq_toNat_bmod, toNat_shiftLeft, Nat.shiftLeft_eq]
simp
simp [-Int.natCast_pow]
@[simp] theorem toFin_shiftLeft {n : Nat} (x : BitVec w) :
(x <<< n).toFin = Fin.ofNat' (2^w) (x.toNat <<< n) := rfl
@@ -2032,7 +2038,6 @@ theorem toInt_ushiftRight_of_lt {x : BitVec w} {n : Nat} (hn : 0 < n) :
have : 2^w 2^n := Nat.pow_le_pow_of_le (by decide) (by omega)
omega
simp [this] at h
omega
/--
Unsigned shift right by at least one bit makes the interpretations of the bitvector as an `Int` or `Nat` agree,
@@ -2137,8 +2142,8 @@ theorem sshiftRight_eq_of_msb_true {x : BitVec w} {s : Nat} (h : x.msb = true) :
simp only [hxbound, reduceIte, toNat_ofInt, toNat_not, toNat_ushiftRight]
rw [ Int.subNatNat_eq_coe, Int.subNatNat_of_lt (by omega),
Nat.pred_eq_sub_one, Int.negSucc_shiftRight,
Int.emod_negSucc, Int.natAbs_ofNat, Nat.succ_eq_add_one,
Int.subNatNat_of_le (by omega), Int.toNat_ofNat, Nat.mod_eq_of_lt,
Int.emod_negSucc, Int.natAbs_natCast, Nat.succ_eq_add_one,
Int.subNatNat_of_le (by omega), Int.toNat_natCast, Nat.mod_eq_of_lt,
Nat.sub_right_comm]
omega
· rw [Nat.shiftRight_eq_div_pow]
@@ -2334,7 +2339,7 @@ theorem toInt_sshiftRight {x : BitVec w} {n : Nat} :
have := @toInt_shiftRight_lt w x n
have := @le_toInt_shiftRight w x n
norm_cast at *
exact Int.bmod_eq_self_of_le (by omega) (by omega)
exact Int.bmod_eq_of_le (by omega) (by omega)
/-! ### sshiftRight reductions from BitVec to Nat -/
@@ -2427,9 +2432,9 @@ theorem signExtend_eq_not_setWidth_not_of_msb_true {x : BitVec w} {v : Nat} (hms
toNat_setWidth, hmsb, reduceIte]
norm_cast
rw [Int.ofNat_sub_ofNat_of_lt, Int.negSucc_emod]
simp only [Int.natAbs_ofNat, Nat.succ_eq_add_one]
simp only [Int.natAbs_natCast, Nat.succ_eq_add_one]
rw [Int.subNatNat_of_le]
· rw [Int.toNat_ofNat, Nat.add_comm, Nat.sub_add_eq]
· rw [Int.toNat_natCast, Nat.add_comm, Nat.sub_add_eq]
· apply Nat.le_trans
· apply Nat.succ_le_of_lt
apply Nat.mod_lt
@@ -2539,7 +2544,7 @@ where
simp only [this, toNat_setWidth, Int.natCast_add, Int.ofNat_emod, Int.natCast_mul]
by_cases h : x.msb
<;> norm_cast
<;> simp [h, Nat.mod_eq_of_lt (Nat.lt_of_lt_of_le x.isLt H)]
<;> simp [h, Nat.mod_eq_of_lt (Nat.lt_of_lt_of_le x.isLt H), -Int.natCast_pow]
omega
/--
@@ -3314,7 +3319,7 @@ theorem setWidth_add (x y : BitVec w) (h : i ≤ w) :
@[simp, bitvec_to_nat] theorem toInt_add (x y : BitVec w) :
(x + y).toInt = (x.toInt + y.toInt).bmod (2^w) := by
simp [toInt_eq_toNat_bmod]
simp [toInt_eq_toNat_bmod, -Int.natCast_pow]
theorem ofInt_add {n} (x y : Int) : BitVec.ofInt n (x + y) =
BitVec.ofInt n x + BitVec.ofInt n y := by
@@ -3344,7 +3349,7 @@ theorem sub_def {n} (x y : BitVec n) : x - y = .ofNat n ((2^n - y.toNat) + x.toN
@[simp, bitvec_to_nat] theorem toInt_sub {x y : BitVec w} :
(x - y).toInt = (x.toInt - y.toInt).bmod (2 ^ w) := by
simp [toInt_eq_toNat_bmod, @Int.ofNat_sub y.toNat (2 ^ w) (by omega)]
simp [toInt_eq_toNat_bmod, @Int.ofNat_sub y.toNat (2 ^ w) (by omega), -Int.natCast_pow]
theorem toInt_sub_toInt_lt_twoPow_iff {x y : BitVec w} :
(x.toInt - y.toInt < - 2 ^ (w - 1))
@@ -3356,7 +3361,7 @@ theorem toInt_sub_toInt_lt_twoPow_iff {x y : BitVec w} :
simp only [Nat.add_one_sub_one]
constructor
· intros h
rw_mod_cast [ Int.bmod_add_cancel, Int.bmod_eq_self_of_le]
rw_mod_cast [ Int.add_bmod_right, Int.bmod_eq_of_le]
<;> omega
· have := Int.bmod_neg_iff (x := x.toInt - y.toInt) (m := 2 ^ (w + 1))
push_cast at this
@@ -3373,7 +3378,7 @@ theorem twoPow_le_toInt_sub_toInt_iff {x y : BitVec w} :
constructor
· intros h
simp only [show 0 x.toInt by omega, show y.toInt < 0 by omega, _root_.true_and]
rw_mod_cast [ Int.bmod_sub_cancel, Int.bmod_eq_self_of_le (by omega) (by omega)]
rw_mod_cast [ Int.sub_bmod_right, Int.bmod_eq_of_le (by omega) (by omega)]
omega
· have := Int.bmod_neg_iff (x := x.toInt - y.toInt) (m := 2 ^ (w + 1))
push_cast at this
@@ -3653,6 +3658,13 @@ theorem mul_def {n} {x y : BitVec n} : x * y = (ofFin <| x.toFin * y.toFin) := b
@[simp, bitvec_to_nat] theorem toNat_mul (x y : BitVec n) : (x * y).toNat = (x.toNat * y.toNat) % 2 ^ n := rfl
@[simp] theorem toFin_mul (x y : BitVec n) : (x * y).toFin = (x.toFin * y.toFin) := rfl
theorem ofNat_mul {n} (x y : Nat) : BitVec.ofNat n (x * y) = BitVec.ofNat n x * BitVec.ofNat n y := by
apply eq_of_toNat_eq
simp [BitVec.ofNat, Fin.ofNat'_mul]
theorem ofNat_mul_ofNat {n} (x y : Nat) : BitVec.ofNat n x * BitVec.ofNat n y = BitVec.ofNat n (x * y) :=
(ofNat_mul x y).symm
protected theorem mul_comm (x y : BitVec w) : x * y = y * x := by
apply eq_of_toFin_eq; simpa using Fin.mul_comm ..
instance : Std.Commutative (fun (x y : BitVec w) => x * y) := BitVec.mul_comm
@@ -3700,7 +3712,7 @@ theorem two_mul {x : BitVec w} : 2#w * x = x + x := by rw [BitVec.mul_comm, mul_
@[simp, bitvec_to_nat] theorem toInt_mul (x y : BitVec w) :
(x * y).toInt = (x.toInt * y.toInt).bmod (2^w) := by
simp [toInt_eq_toNat_bmod]
simp [toInt_eq_toNat_bmod, -Int.natCast_pow]
theorem ofInt_mul {n} (x y : Int) : BitVec.ofInt n (x * y) =
BitVec.ofInt n x * BitVec.ofInt n y := by
@@ -3746,6 +3758,22 @@ theorem setWidth_mul (x y : BitVec w) (h : i ≤ w) :
have dvd : 2^i 2^w := Nat.pow_dvd_pow _ h
simp [bitvec_to_nat, h, Nat.mod_mod_of_dvd _ dvd]
/-! ### pow -/
@[simp]
protected theorem pow_zero {x : BitVec w} : x ^ 0 = 1#w := rfl
protected theorem pow_succ {x : BitVec w} : x ^ (n + 1) = x ^ n * x := rfl
@[simp]
protected theorem pow_one {x : BitVec w} : x ^ 1 = x := by simp [BitVec.pow_succ]
protected theorem pow_add {x : BitVec w} {n m : Nat}: x ^ (n + m) = (x ^ n) * (x ^ m):= by
induction m with
| zero => simp
| succ m ih =>
rw [ Nat.add_assoc, BitVec.pow_succ, ih, BitVec.mul_assoc, BitVec.pow_succ]
/-! ### le and lt -/
@[bitvec_to_nat] theorem le_def {x y : BitVec n} :
@@ -3958,7 +3986,6 @@ then `x / y` is nonnegative, thus `toInt` and `toNat` coincide.
theorem toInt_udiv_of_msb {x : BitVec w} (h : x.msb = false) (y : BitVec w) :
(x / y).toInt = x.toNat / y.toNat := by
simp [toInt_eq_msb_cond, msb_udiv_eq_false_of h]
norm_cast
/-! ### umod -/
@@ -4891,7 +4918,6 @@ theorem intMin_eq_zero_iff {w : Nat} : intMin w = 0#w ↔ w = 0 := by
· constructor
· have := Nat.two_pow_pos (w - 1)
simp [toNat_eq, show 0 < w by omega]
omega
· simp [h]
/--
@@ -5129,7 +5155,7 @@ theorem two_pow_le_toInt_mul_toInt_iff {x y : BitVec w} :
toInt_intMax, Nat.add_one_sub_one]
push_cast
rw [ Nat.two_pow_pred_add_two_pow_pred (by omega),
Int.bmod_eq_self_of_le_mul_two (by rw [ Nat.mul_two]; push_cast; omega)
Int.bmod_eq_of_le_mul_two (by rw [ Nat.mul_two]; push_cast; omega)
(by rw [ Nat.mul_two]; push_cast; omega)]
omega
@@ -5146,14 +5172,14 @@ theorem toInt_mul_toInt_lt_neg_two_pow_iff {x y : BitVec w} :
simp only [toInt_twoPow, show ¬w + 1 w by omega, reduceIte]
push_cast
rw [ Nat.two_pow_pred_add_two_pow_pred (by omega),
Int.bmod_eq_self_of_le_mul_two (by rw [ Nat.mul_two]; push_cast; omega)
Int.bmod_eq_of_le_mul_two (by rw [ Nat.mul_two]; push_cast; omega)
(by rw [ Nat.mul_two]; push_cast; omega)]
/-! ### neg -/
theorem msb_eq_toInt {x : BitVec w}:
x.msb = decide (x.toInt < 0) := by
by_cases h : x.msb <;> simp [h, toInt_eq_msb_cond] <;> omega
by_cases h : x.msb <;> simp [h, toInt_eq_msb_cond, -Int.natCast_pow] <;> omega
theorem msb_eq_toNat {x : BitVec w}:
x.msb = decide (x.toNat 2 ^ (w - 1)) := by

View File

@@ -690,9 +690,5 @@ def boolRelToRel : Coe (αα → Bool) (αα → Prop) where
/-! ### subtypes -/
@[simp] theorem Subtype.beq_iff {α : Type u} [DecidableEq α] {p : α Prop} {x y : {a : α // p a}} :
(x == y) = (x.1 == y.1) := by
cases x
cases y
rw [Bool.eq_iff_iff]
simp [beq_iff_eq]
@[simp] theorem Subtype.beq_iff {α : Type u} [BEq α] {p : α Prop} {x y : {a : α // p a}} :
(x == y) = (x.1 == y.1) := rfl

View File

@@ -1,149 +0,0 @@
/-
Copyright (c) 2022 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Gabriel Ebner
-/
prelude
import Init.Data.Queue
import Init.System.Promise
import Init.System.Mutex
set_option linter.deprecated false
namespace IO
/--
Internal state of an `Channel`.
We maintain the invariant that at all times either `consumers` or `values` is empty.
-/
@[deprecated "Use Std.Channel.State from Std.Sync.Channel instead" (since := "2024-12-02")]
structure Channel.State (α : Type) where
values : Std.Queue α :=
consumers : Std.Queue (Promise (Option α)) :=
closed := false
deriving Inhabited
/--
FIFO channel with unbounded buffer, where `recv?` returns a `Task`.
A channel can be closed. Once it is closed, all `send`s are ignored, and
`recv?` returns `none` once the queue is empty.
-/
@[deprecated "Use Std.Channel from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel (α : Type) : Type := Mutex (Channel.State α)
instance : Nonempty (Channel α) :=
inferInstanceAs (Nonempty (Mutex _))
/-- Creates a new `Channel`. -/
@[deprecated "Use Std.Channel.new from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.new : BaseIO (Channel α) :=
Mutex.new {}
/--
Sends a message on an `Channel`.
This function does not block.
-/
@[deprecated "Use Std.Channel.send from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.send (ch : Channel α) (v : α) : BaseIO Unit :=
ch.atomically do
let st get
if st.closed then return
if let some (consumer, consumers) := st.consumers.dequeue? then
consumer.resolve (some v)
set { st with consumers }
else
set { st with values := st.values.enqueue v }
/--
Closes an `Channel`.
-/
@[deprecated "Use Std.Channel.close from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.close (ch : Channel α) : BaseIO Unit :=
ch.atomically do
let st get
for consumer in st.consumers.toArray do consumer.resolve none
set { st with closed := true, consumers := }
/--
Receives a message, without blocking.
The returned task waits for the message.
Every message is only received once.
Returns `none` if the channel is closed and the queue is empty.
-/
@[deprecated "Use Std.Channel.recv? from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.recv? (ch : Channel α) : BaseIO (Task (Option α)) :=
ch.atomically do
let st get
if let some (a, values) := st.values.dequeue? then
set { st with values }
return .pure a
else if !st.closed then
let promise Promise.new
set { st with consumers := st.consumers.enqueue promise }
return promise.result
else
return .pure none
/--
`ch.forAsync f` calls `f` for every messages received on `ch`.
Note that if this function is called twice, each `forAsync` only gets half the messages.
-/
@[deprecated "Use Std.Channel.forAsync from Std.Sync.Channel instead" (since := "2024-12-02")]
partial def Channel.forAsync (f : α BaseIO Unit) (ch : Channel α)
(prio : Task.Priority := .default) : BaseIO (Task Unit) := do
BaseIO.bindTask (prio := prio) ( ch.recv?) fun
| none => return .pure ()
| some v => do f v; ch.forAsync f prio
/--
Receives all currently queued messages from the channel.
Those messages are dequeued and will not be returned by `recv?`.
-/
@[deprecated "Use Std.Channel.recvAllCurrent from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.recvAllCurrent (ch : Channel α) : BaseIO (Array α) :=
ch.atomically do
modifyGet fun st => (st.values.toArray, { st with values := })
/-- Type tag for synchronous (blocking) operations on a `Channel`. -/
@[deprecated "Use Std.Channel.Sync from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.Sync := Channel
/--
Accesses synchronous (blocking) version of channel operations.
For example, `ch.sync.recv?` blocks until the next message,
and `for msg in ch.sync do ...` iterates synchronously over the channel.
These functions should only be used in dedicated threads.
-/
@[deprecated "Use Std.Channel.sync from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.sync (ch : Channel α) : Channel.Sync α := ch
/--
Synchronously receives a message from the channel.
Every message is only received once.
Returns `none` if the channel is closed and the queue is empty.
-/
@[deprecated "Use Std.Channel.Sync.recv? from Std.Sync.Channel instead" (since := "2024-12-02")]
def Channel.Sync.recv? (ch : Channel.Sync α) : BaseIO (Option α) := do
IO.wait ( Channel.recv? ch)
@[deprecated "Use Std.Channel.Sync.forIn from Std.Sync.Channel instead" (since := "2024-12-02")]
private partial def Channel.Sync.forIn [Monad m] [MonadLiftT BaseIO m]
(ch : Channel.Sync α) (f : α β m (ForInStep β)) : β m β := fun b => do
match ch.recv? with
| some a =>
match f a b with
| .done b => pure b
| .yield b => ch.forIn f b
| none => pure b
/-- `for msg in ch.sync do ...` receives all messages in the channel until it is closed. -/
instance [MonadLiftT BaseIO m] : ForIn m (Channel.Sync α) α where
forIn ch b f := ch.forIn f b

View File

@@ -976,6 +976,16 @@ theorem coe_sub_iff_lt {a b : Fin n} : (↑(a - b) : Nat) = n + a - b ↔ a < b
/-! ### mul -/
theorem ofNat'_mul [NeZero n] (x : Nat) (y : Fin n) :
Fin.ofNat' n x * y = Fin.ofNat' n (x * y.val) := by
apply Fin.eq_of_val_eq
simp [Fin.ofNat', Fin.mul_def]
theorem mul_ofNat' [NeZero n] (x : Fin n) (y : Nat) :
x * Fin.ofNat' n y = Fin.ofNat' n (x.val * y) := by
apply Fin.eq_of_val_eq
simp [Fin.ofNat', Fin.mul_def]
theorem val_mul {n : Nat} : a b : Fin n, (a * b).val = a.val * b.val % n
| _, _, _, _ => rfl

View File

@@ -6,6 +6,7 @@ Authors: Leonardo de Moura
prelude
import Init.Data.Int.Basic
import Init.Data.Int.Bitwise
import Init.Data.Int.Compare
import Init.Data.Int.DivMod
import Init.Data.Int.Gcd
import Init.Data.Int.Lemmas

View File

@@ -420,6 +420,8 @@ instance : IntCast Int where intCast n := n
protected def Int.cast {R : Type u} [IntCast R] : Int R :=
IntCast.intCast
@[simp] theorem Int.cast_eq (x : Int) : Int.cast x = x := rfl
-- see the notes about coercions into arbitrary types in the module doc-string
instance [IntCast R] : CoeTail Int R where coe := Int.cast

View File

@@ -28,7 +28,7 @@ theorem shiftRight_eq_div_pow (m : Int) (n : Nat) :
m >>> n = m / ((2 ^ n) : Nat) := by
simp only [shiftRight_eq, Int.shiftRight, Nat.shiftRight_eq_div_pow]
split
· simp; norm_cast
· simp
· rw [negSucc_ediv _ (by norm_cast; exact Nat.pow_pos (Nat.zero_lt_two))]
rfl

View File

@@ -18,9 +18,6 @@ namespace Int
protected theorem lt_or_eq_of_le {n m : Int} (h : n m) : n < m n = m := by
omega
protected theorem le_iff_lt_or_eq {n m : Int} : n m n < m n = m :=
Int.lt_or_eq_of_le, fun | .inl h => Int.le_of_lt h | .inr rfl => Int.le_refl _
theorem compare_eq_ite_lt (a b : Int) :
compare a b = if a < b then .lt else if b < a then .gt else .eq := by
simp only [compare, compareOfLessAndEq]

View File

@@ -45,9 +45,9 @@ protected theorem dvd_trans : ∀ {a b c : Int}, a b → b c → a c
Iff.intro (fun k, e => by rw [e, Int.zero_mul])
(fun h => h.symm Int.dvd_refl _)
protected theorem dvd_mul_right (a b : Int) : a a * b := _, rfl
@[simp] protected theorem dvd_mul_right (a b : Int) : a a * b := _, rfl
protected theorem dvd_mul_left (a b : Int) : b a * b := _, Int.mul_comm ..
@[simp] protected theorem dvd_mul_left (a b : Int) : b a * b := _, Int.mul_comm ..
@[simp] protected theorem neg_dvd {a b : Int} : -a b a b := by
constructor <;> exact fun k, e =>
@@ -59,13 +59,13 @@ protected theorem dvd_mul_left (a b : Int) : b a * b := ⟨_, Int.mul_comm .
@[simp] theorem natAbs_dvd_natAbs {a b : Int} : natAbs a natAbs b a b := by
refine fun k, hk => ?_, fun k, hk => natAbs k, hk.symm natAbs_mul a k
rw [ natAbs_ofNat k, natAbs_mul, natAbs_eq_natAbs_iff] at hk
rw [ natAbs_natCast k, natAbs_mul, natAbs_eq_natAbs_iff] at hk
cases hk <;> subst b
· apply Int.dvd_mul_right
· rw [ Int.mul_neg]; apply Int.dvd_mul_right
theorem ofNat_dvd_left {n : Nat} {z : Int} : (n : Int) z n z.natAbs := by
rw [ natAbs_dvd_natAbs, natAbs_ofNat]
rw [ natAbs_dvd_natAbs, natAbs_natCast]
/-! ### ediv zero -/
@@ -156,7 +156,7 @@ theorem add_mul_ediv_right (a b : Int) {c : Int} (H : c ≠ 0) : (a + b * c) / c
show ediv ((n * succ k) + -((m : Int) + 1)) (succ k) = n + -((m / succ k) + 1 : Int)
rw [H h, H ((Nat.le_div_iff_mul_le k.succ_pos).2 h)]
apply congrArg negSucc
rw [Nat.mul_comm, Nat.sub_mul_div]; rwa [Nat.mul_comm]
rw [Nat.mul_comm, Nat.sub_mul_div_of_le]; rwa [Nat.mul_comm]
theorem add_mul_ediv_left (a : Int) {b : Int}
(c : Int) (H : b 0) : (a + b * c) / b = a / b + c :=
@@ -198,7 +198,7 @@ theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < b :=
| ofNat _, _, _, rfl => ofNat_lt.2 (Nat.mod_lt _ (Nat.succ_pos _))
| -[_+1], _, _, rfl => Int.sub_lt_self _ (ofNat_lt.2 <| Nat.succ_pos _)
@[simp] theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
@[simp] theorem add_mul_emod_self_right (a b c : Int) : (a + b * c) % c = a % c :=
if cz : c = 0 then by
rw [cz, Int.mul_zero, Int.add_zero]
else by
@@ -206,7 +206,17 @@ theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < b :=
Int.mul_add, Int.mul_comm, Int.sub_sub, Int.add_sub_cancel]
@[simp] theorem add_mul_emod_self_left (a b c : Int) : (a + b * c) % b = a % b := by
rw [Int.mul_comm, Int.add_mul_emod_self]
rw [Int.mul_comm, add_mul_emod_self_right]
@[simp] theorem mul_add_emod_self_right (a b c : Int) : (a * b + c) % b = c % b := by
rw [Int.add_comm, add_mul_emod_self_right]
@[simp] theorem mul_add_emod_self_left (a b c : Int) : (a * b + c) % a = c % a := by
rw [Int.add_comm, add_mul_emod_self_left]
@[deprecated add_mul_emod_self_right (since := "2025-04-11")]
theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
add_mul_emod_self_right ..
@[simp] theorem emod_add_emod (m n k : Int) : (m % n + k) % n = (m + k) % n := by
have := (add_mul_emod_self_left (m % n + k) n (m / n)).symm
@@ -229,7 +239,7 @@ theorem emod_add_cancel_right {m n k : Int} (i) : (m + i) % n = (k + i) % n ↔
add_emod_eq_add_emod_right _
@[simp] theorem mul_emod_left (a b : Int) : (a * b) % b = 0 := by
rw [ Int.zero_add (a * b), Int.add_mul_emod_self, Int.zero_emod]
rw [ Int.zero_add (a * b), add_mul_emod_self_right, Int.zero_emod]
@[simp] theorem mul_emod_right (a b : Int) : (a * b) % a = 0 := by
rw [Int.mul_comm, mul_emod_left]
@@ -238,7 +248,7 @@ theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
conv => lhs; rw [
emod_add_ediv a n, emod_add_ediv' b n, Int.add_mul, Int.mul_add, Int.mul_add,
Int.mul_assoc, Int.mul_assoc, Int.mul_add n _ _, add_mul_emod_self_left,
Int.mul_assoc, add_mul_emod_self]
Int.mul_assoc, add_mul_emod_self_right]
@[simp] theorem emod_self {a : Int} : a % a = 0 := by
have := mul_emod_left 1 a; rwa [Int.one_mul] at this
@@ -324,10 +334,10 @@ theorem lt_mul_ediv_self_add {x k : Int} (h : 0 < k) : x < k * (x / k) + k :=
split <;> simp [Int.sub_emod]
theorem bmod_def (x : Int) (m : Nat) : bmod x m =
if (x % m) < (m + 1) / 2 then
x % m
else
(x % m) - m :=
if (x % m) < (m + 1) / 2 then
x % m
else
(x % m) - m :=
rfl
end Int

File diff suppressed because it is too large Load Diff

View File

@@ -135,7 +135,7 @@ theorem natAbs_div_gcd_pos_of_ne_zero_right (a : Int) (h : b ≠ 0) : 0 < b.natA
Nat.div_gcd_pos_of_pos_right _ (natAbs_pos.2 h)
theorem ediv_gcd_ne_zero_of_ne_zero_left (b : Int) (h : a 0) : a / gcd a b 0 := by
rw [ natAbs_pos, natAbs_ediv_of_dvd (gcd_dvd_left _ _), natAbs_ofNat]
rw [ natAbs_pos, natAbs_ediv_of_dvd (gcd_dvd_left _ _), natAbs_natCast]
exact natAbs_div_gcd_pos_of_ne_zero_left _ h
theorem ediv_gcd_ne_zero_if_ne_zero_right (a : Int) (h : b 0) : b / gcd a b 0 := by
@@ -393,12 +393,12 @@ theorem pow_gcd_pow_of_gcd_eq_one {n m : Int} {k l : Nat} (h : gcd n m = 1) : gc
theorem gcd_ediv_gcd_ediv_gcd_of_ne_zero_left {n m : Int} (h : n 0) :
gcd (n / gcd n m) (m / gcd n m) = 1 := by
rw [gcd_ediv (gcd_dvd_left _ _) (gcd_dvd_right _ _), natAbs_ofNat,
rw [gcd_ediv (gcd_dvd_left _ _) (gcd_dvd_right _ _), natAbs_natCast,
Nat.div_self (gcd_pos_of_ne_zero_left _ h)]
theorem gcd_ediv_gcd_ediv_gcd_of_ne_zero_right {n m : Int} (h : m 0) :
gcd (n / gcd n m) (m / gcd n m) = 1 := by
rw [gcd_ediv (gcd_dvd_left _ _) (gcd_dvd_right _ _), natAbs_ofNat,
rw [gcd_ediv (gcd_dvd_left _ _) (gcd_dvd_right _ _), natAbs_natCast,
Nat.div_self (gcd_pos_of_ne_zero_right _ h)]
theorem gcd_ediv_gcd_ediv_gcd {i j : Int} (h : 0 < gcd i j) : gcd (i / gcd i j) (j / gcd i j) = 1 :=

View File

@@ -377,6 +377,11 @@ theorem toNat_of_nonpos : ∀ {z : Int}, z ≤ 0 → z.toNat = 0
@[simp] theorem negSucc_add_one_eq_neg_ofNat_iff {a b : Nat} : -[a+1] + 1 = - (b : Int) a = b := by
rw [eq_comm, neg_ofNat_eq_negSucc_add_one_iff, eq_comm]
protected theorem sub_eq_iff_eq_add {b a c : Int} : a - b = c a = c + b := by
refine fun h => ?_, fun h => ?_ <;> subst h <;> simp
protected theorem sub_eq_iff_eq_add' {b a c : Int} : a - b = c a = b + c := by
rw [Int.sub_eq_iff_eq_add, Int.add_comm]
/- ## add/sub injectivity -/
@[simp] protected theorem add_left_inj {i j : Int} (k : Int) : (i + k = j + k) i = j := by
@@ -561,7 +566,11 @@ theorem eq_one_of_mul_eq_self_left {a b : Int} (Hpos : a ≠ 0) (H : b * a = a)
theorem eq_one_of_mul_eq_self_right {a b : Int} (Hpos : b 0) (H : b * a = b) : a = 1 :=
Int.eq_of_mul_eq_mul_left Hpos <| by rw [Int.mul_one, H]
/-! NatCast lemmas -/
protected theorem two_mul (n : Int) : 2 * n = n + n := calc
2 * n = (1 + 1) * n := rfl
_ = n + n := by simp only [Int.add_mul, Int.one_mul]
/-! ## NatCast lemmas -/
/-!
The following lemmas are later subsumed by e.g. `Nat.cast_add` and `Nat.cast_mul` in Mathlib
@@ -572,10 +581,8 @@ protected theorem natCast_zero : ((0 : Nat) : Int) = (0 : Int) := rfl
protected theorem natCast_one : ((1 : Nat) : Int) = (1 : Int) := rfl
@[simp] protected theorem natCast_add (a b : Nat) : ((a + b : Nat) : Int) = (a : Int) + (b : Int) := by
-- Note this only works because of local simp attributes in this file,
-- so it still makes sense to tag the lemmas with `@[simp]`.
simp
@[simp, norm_cast] protected theorem natCast_add (a b : Nat) : ((a + b : Nat) : Int) = (a : Int) + (b : Int) := by
rfl
protected theorem natCast_succ (n : Nat) : ((n + 1 : Nat) : Int) = (n : Int) + 1 := rfl

View File

@@ -5,6 +5,7 @@ Authors: Kim Morrison
-/
prelude
import Init.Data.Int.Order
import Init.Data.Int.Pow
import Init.Data.Int.DivMod.Lemmas
import Init.Omega
@@ -19,9 +20,6 @@ namespace Int
@[simp] theorem natCast_le_zero : {n : Nat} (n : Int) 0 n = 0 := by omega
protected theorem sub_eq_iff_eq_add {b a c : Int} : a - b = c a = c + b := by omega
protected theorem sub_eq_iff_eq_add' {b a c : Int} : a - b = c a = b + c := by omega
@[simp] protected theorem neg_nonpos_iff (i : Int) : -i 0 0 i := by omega
@[simp] theorem zero_le_ofNat (n : Nat) : 0 ((no_index (OfNat.ofNat n)) : Int) :=
@@ -42,6 +40,39 @@ protected theorem sub_eq_iff_eq_add' {b a c : Int} : a - b = c ↔ a = b + c :=
theorem neg_lt_self_iff {n : Int} : -n < n 0 < n := by
omega
protected theorem ofNat_add_out (m n : Nat) : m + n = ((m + n) : Int) := rfl
protected theorem ofNat_mul_out (m n : Nat) : m * n = ((m * n) : Int) := rfl
protected theorem ofNat_add_one_out (n : Nat) : n + (1 : Int) = (Nat.succ n) := rfl
@[simp] theorem ofNat_eq_natCast (n : Nat) : Int.ofNat n = n := rfl
@[norm_cast] theorem natCast_inj {m n : Nat} : (m : Int) = (n : Int) m = n := ofNat_inj
@[simp, norm_cast] theorem natAbs_cast (n : Nat) : natAbs n = n := rfl
@[norm_cast]
protected theorem natCast_sub {n m : Nat} : n m ((m - n) : Int) = m - n := ofNat_sub
@[simp high] theorem natCast_eq_zero {n : Nat} : (n : Int) = 0 n = 0 := by omega
theorem natCast_ne_zero {n : Nat} : (n : Int) 0 n 0 := by omega
theorem natCast_ne_zero_iff_pos {n : Nat} : (n : Int) 0 0 < n := by omega
@[simp high] theorem natCast_pos {n : Nat} : (0 : Int) < n 0 < n := by omega
theorem natCast_succ_pos (n : Nat) : 0 < (n.succ : Int) := natCast_pos.2 n.succ_pos
@[simp high] theorem natCast_nonpos_iff {n : Nat} : (n : Int) 0 n = 0 := by omega
theorem natCast_nonneg (n : Nat) : 0 (n : Int) := ofNat_le.2 (Nat.zero_le _)
@[simp] theorem sign_natCast_add_one (n : Nat) : sign (n + 1) = 1 := rfl
@[simp, norm_cast] theorem cast_id {n : Int} : Int.cast n = n := rfl
/-! ### toNat -/
@[simp] theorem toNat_sub' (a : Int) (b : Nat) : (a - b).toNat = a.toNat - b := by
@@ -72,24 +103,27 @@ theorem neg_lt_self_iff {n : Int} : -n < n ↔ 0 < n := by
@[simp] theorem toNat_le {m : Int} {n : Nat} : m.toNat n m n := by omega
@[simp] theorem toNat_lt' {m : Int} {n : Nat} (hn : 0 < n) : m.toNat < n m < n := by omega
@[simp] theorem lt_toNat {m : Nat} {n : Int} : m < toNat n m < n := by omega
theorem lt_of_toNat_lt {a b : Int} (h : toNat a < toNat b) : a < b := by omega
theorem toNat_sub_of_le {a b : Int} (h : b a) : (toNat (a - b) : Int) = a - b := by omega
theorem pos_iff_toNat_pos {n : Int} : 0 < n 0 < n.toNat := by
omega
theorem ofNat_toNat_eq_self {a : Int} : a.toNat = a 0 a := by omega
theorem eq_ofNat_toNat {a : Int} : a = a.toNat 0 a := by omega
theorem natCast_toNat_eq_self {a : Int} : a.toNat = a 0 a := by omega
@[deprecated natCast_toNat_eq_self (since := "2025-04-16")]
theorem ofNat_toNat_eq_self {a : Int} : a.toNat = a 0 a := natCast_toNat_eq_self
theorem eq_natCast_toNat {a : Int} : a = a.toNat 0 a := by omega
@[deprecated eq_natCast_toNat (since := "2025-04-16")]
theorem eq_ofNat_toNat {a : Int} : a = a.toNat 0 a := eq_natCast_toNat
theorem toNat_le_toNat {n m : Int} (h : n m) : n.toNat m.toNat := by omega
theorem toNat_lt_toNat {n m : Int} (hn : 0 < m) : n.toNat < m.toNat n < m := by omega
/-! ### natAbs -/
theorem eq_zero_of_dvd_of_natAbs_lt_natAbs {d n : Int} (h : d n) (h₁ : n.natAbs < d.natAbs) :
n = 0 := by
obtain a, rfl := h
rw [natAbs_mul] at h₁
suffices ¬ 0 < a.natAbs by simp [Int.natAbs_eq_zero.1 (Nat.eq_zero_of_not_pos this)]
exact fun h => Nat.lt_irrefl _ (Nat.lt_of_le_of_lt (Nat.le_mul_of_pos_right d.natAbs h) h₁)
/-! ### min and max -/
@[simp] protected theorem min_assoc : (a b c : Int), min (min a b) c = min a (min b c) := by omega
@@ -128,32 +162,7 @@ protected theorem sub_min_sub_left (a b c : Int) : min (a - b) (a - c) = a - max
protected theorem sub_max_sub_left (a b c : Int) : max (a - b) (a - c) = a - min b c := by omega
/-! ### bmod -/
theorem bmod_neg_iff {m : Nat} {x : Int} (h2 : -m x) (h1 : x < m) :
(x.bmod m) < 0 (-(m / 2) x x < 0) ((m + 1) / 2 x) := by
simp only [Int.bmod_def]
by_cases xpos : 0 x
· rw [Int.emod_eq_of_lt xpos (by omega)]; omega
· rw [Int.add_emod_self.symm, Int.emod_eq_of_lt (by omega) (by omega)]; omega
theorem bmod_eq_self_of_le {n : Int} {m : Nat} (hn' : -(m / 2) n) (hn : n < (m + 1) / 2) :
n.bmod m = n := by
rw [ Int.sub_eq_zero]
have := le_bmod (x := n) (m := m) (by omega)
have := bmod_lt (x := n) (m := m) (by omega)
apply eq_zero_of_dvd_of_natAbs_lt_natAbs Int.dvd_bmod_sub_self
omega
theorem bmod_bmod_of_dvd {a : Int} {n m : Nat} (hnm : n m) :
(a.bmod m).bmod n = a.bmod n := by
rw [ Int.sub_eq_iff_eq_add.2 (bmod_add_bdiv a m).symm]
obtain k, rfl := hnm
simp [Int.mul_assoc]
theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y x * 2) (hlt : x * 2 < y) :
x.bmod y = x := by
apply bmod_eq_self_of_le (by omega) (by omega)
/-! ## mul -/
theorem mul_le_mul_of_natAbs_le {x y : Int} {s t : Nat} (hx : x.natAbs s) (hy : y.natAbs t) :
x * y s * t := by
@@ -206,4 +215,9 @@ theorem neg_mul_le_mul {x y : Int} {s t : Nat} (lbx : -s ≤ x) (ubx : x < s) (l
norm_cast
omega
/-! ## pow -/
theorem natAbs_pow_two (a : Int) : (natAbs a : Int) ^ 2 = a ^ 2 := by
simp [Int.pow_succ]
end Int

View File

@@ -191,9 +191,9 @@ theorem cmod_nonpos (a : Int) {b : Int} (h : b ≠ 0) : cmod a b ≤ 0 := by
theorem cmod_eq_zero_iff_emod_eq_zero (a b : Int) : cmod a b = 0 a%b = 0 := by
unfold cmod
have := @Int.emod_eq_emod_iff_emod_sub_eq_zero b b a
simp at this
simp [Int.neg_emod_eq_sub_emod, this, Eq.comm]
have := @Int.emod_eq_emod_iff_emod_sub_eq_zero b b a
simp only [emod_self, sub_emod_left] at this
rw [Int.neg_eq_zero, this, Eq.comm]
private abbrev div_mul_cancel_of_mod_zero :=
@Int.ediv_mul_cancel_of_emod_eq_zero
@@ -435,7 +435,7 @@ def norm_eq_coeff_cert (lhs rhs : Expr) (p : Poly) (k : Int) : Bool :=
theorem norm_eq_coeff (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int)
: norm_eq_coeff_cert lhs rhs p k (lhs.denote ctx = rhs.denote ctx) = (p.denote' ctx = 0) := by
simp [norm_eq_coeff_cert]
rw [norm_eq ctx lhs rhs (lhs.sub rhs).norm BEq.refl, Poly.denote'_eq_denote]
rw [norm_eq ctx lhs rhs (lhs.sub rhs).norm BEq.rfl, Poly.denote'_eq_denote]
apply norm_eq_coeff'
private theorem mul_le_zero_iff (a k : Int) (h₁ : k > 0) : k * a 0 a 0 := by
@@ -454,7 +454,7 @@ private theorem norm_le_coeff' (ctx : Context) (p p' : Poly) (k : Int) : p = p'.
theorem norm_le_coeff (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int)
: norm_eq_coeff_cert lhs rhs p k (lhs.denote ctx rhs.denote ctx) = (p.denote' ctx 0) := by
simp [norm_eq_coeff_cert]
rw [norm_le ctx lhs rhs (lhs.sub rhs).norm BEq.refl, Poly.denote'_eq_denote]
rw [norm_le ctx lhs rhs (lhs.sub rhs).norm BEq.rfl, Poly.denote'_eq_denote]
apply norm_le_coeff'
private theorem mul_add_cmod_le_iff {a k b : Int} (h : k > 0) : a*k + cmod b k 0 a 0 := by
@@ -499,7 +499,7 @@ def norm_le_coeff_tight_cert (lhs rhs : Expr) (p : Poly) (k : Int) : Bool :=
theorem norm_le_coeff_tight (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int)
: norm_le_coeff_tight_cert lhs rhs p k (lhs.denote ctx rhs.denote ctx) = (p.denote' ctx 0) := by
simp [norm_le_coeff_tight_cert]
rw [norm_le ctx lhs rhs (lhs.sub rhs).norm BEq.refl, Poly.denote'_eq_denote]
rw [norm_le ctx lhs rhs (lhs.sub rhs).norm BEq.rfl, Poly.denote'_eq_denote]
apply eq_of_norm_eq_of_divCoeffs
def Poly.isUnsatEq (p : Poly) : Bool :=
@@ -665,7 +665,7 @@ theorem norm_dvd (ctx : Context) (k : Int) (e : Expr) (p : Poly) : e.norm == p
simp; intro h; simp [ h]
theorem dvd_eq_false (ctx : Context) (k : Int) (e : Expr) (h : e.norm.isUnsatDvd k) : (k e.denote ctx) = False := by
rw [norm_dvd ctx k e e.norm BEq.refl]
rw [norm_dvd ctx k e e.norm BEq.rfl]
apply dvd_eq_false' ctx k e.norm h
def dvd_coeff_cert (k₁ : Int) (p₁ : Poly) (k₂ : Int) (p₂ : Poly) (k : Int) : Bool :=

View File

@@ -84,6 +84,11 @@ theorem ofNat_succ_pos (n : Nat) : 0 < (succ n : Int) := ofNat_lt.2 <| Nat.succ_
@[simp] protected theorem le_refl (a : Int) : a a :=
le.intro _ (Int.add_zero a)
protected theorem le_rfl {a : Int} : a a := a.le_refl
protected theorem le_of_eq {a b : Int} (hab : a = b) : a b := by rw [hab]; exact Int.le_rfl
protected theorem ge_of_eq {a b : Int} (hab : a = b) : b a := Int.le_of_eq hab.symm
protected theorem le_trans {a b c : Int} (h₁ : a b) (h₂ : b c) : a c :=
let n, hn := le.dest h₁; let m, hm := le.dest h₂
le.intro (n + m) <| by rw [ hm, hn, Int.add_assoc, ofNat_add]
@@ -94,6 +99,9 @@ protected theorem le_antisymm {a b : Int} (h₁ : a ≤ b) (h₂ : b ≤ a) : a
have := Int.ofNat.inj <| Int.add_left_cancel <| this.trans (Int.add_zero _).symm
rw [ hn, Nat.eq_zero_of_add_eq_zero_left this, ofNat_zero, Int.add_zero a]
protected theorem le_antisymm_iff {a b : Int} : a = b a b b a :=
fun h Int.le_of_eq h, Int.ge_of_eq h, fun h Int.le_antisymm h.1 h.2
@[simp] protected theorem lt_irrefl (a : Int) : ¬a < a := fun H =>
let n, hn := lt.dest H
have : (a+Nat.succ n) = a+0 := by
@@ -119,6 +127,12 @@ protected theorem lt_succ (a : Int) : a < a + 1 := Int.le_refl _
protected theorem zero_lt_one : (0 : Int) < 1 := _
protected theorem one_pos : 0 < (1 : Int) := Int.zero_lt_one
protected theorem one_ne_zero : (1 : Int) 0 := by decide
protected theorem one_nonneg : 0 (1 : Int) := Int.le_of_lt Int.zero_lt_one
protected theorem lt_iff_le_not_le {a b : Int} : a < b a b ¬b a := by
rw [Int.lt_iff_le_and_ne]
constructor <;> refine fun h, h' => h, h'.imp fun h' => ?_
@@ -137,6 +151,10 @@ protected theorem not_le_of_gt {a b : Int} (h : b < a) : ¬a ≤ b :=
@[simp] protected theorem not_lt {a b : Int} : ¬a < b b a :=
by rw [ Int.not_le, Decidable.not_not]
protected theorem lt_asymm {a b : Int} : a < b ¬ b < a := by rw [Int.not_lt]; exact Int.le_of_lt
protected theorem lt_or_le (a b : Int) : a < b b a := by rw [ Int.not_lt]; exact Decidable.em _
protected theorem le_of_not_gt {a b : Int} (h : ¬ a > b) : a b :=
Int.not_lt.mp h
@@ -161,12 +179,23 @@ protected theorem ne_iff_lt_or_gt {a b : Int} : a ≠ b ↔ a < b b < a := b
protected theorem lt_or_gt_of_ne {a b : Int} : a b a < b b < a:= Int.ne_iff_lt_or_gt.mp
protected theorem lt_or_lt_of_ne {a b : Int} : a b a < b b < a := Int.lt_or_gt_of_ne
protected theorem eq_iff_le_and_ge {x y : Int} : x = y x y y x := by
constructor
· simp_all
· intro h₁, h₂
exact Int.le_antisymm h₁ h₂
protected theorem le_iff_eq_or_lt {a b : Int} : a b a = b a < b :=
match Int.lt_trichotomy a b with
| Or.inl h => by simp [h, Int.le_of_lt]
| Or.inr (Or.inl h) => by simp [h]
| Or.inr (Or.inr h) => by simp [h, Int.not_le_of_gt, Int.ne_of_gt, Int.le_of_lt]
protected theorem le_iff_lt_or_eq {a b : Int} : a b a < b a = b := by
rw [Int.le_iff_eq_or_lt, or_comm]
protected theorem lt_of_le_of_lt {a b c : Int} (h₁ : a b) (h₂ : b < c) : a < c :=
Int.not_le.1 fun h => Int.not_le.2 h₂ (Int.le_trans h h₁)
@@ -283,9 +312,8 @@ protected theorem neg_lt_neg {a b : Int} (h : a < b) : -b < -a := by
@[simp] protected theorem zero_lt_neg_iff {a : Int} : 0 < -a a < 0 := by
rw [ Int.neg_zero, Int.neg_lt_neg_iff, Int.neg_zero]
protected theorem neg_neg_of_pos {a : Int} (h : 0 < a) : -a < 0 := by
have : -a < -0 := Int.neg_lt_neg h
rwa [Int.neg_zero] at this
protected theorem neg_neg_of_pos {a : Int} (h : 0 < a) : -a < 0 :=
Int.neg_lt_zero_iff.2 h
protected theorem neg_pos_of_neg {a : Int} (h : a < 0) : 0 < -a := by
have : -0 < -a := Int.neg_lt_neg h
@@ -329,9 +357,9 @@ protected theorem le_iff_lt_add_one {a b : Int} : a ≤ b ↔ a < b + 1 := by
/- ### min and max -/
protected theorem min_def (n m : Int) : min n m = if n m then n else m := rfl
@[grind =] protected theorem min_def (n m : Int) : min n m = if n m then n else m := rfl
protected theorem max_def (n m : Int) : max n m = if n m then m else n := rfl
@[grind =] protected theorem max_def (n m : Int) : max n m = if n m then m else n := rfl
@[simp] protected theorem neg_min_neg (a b : Int) : min (-a) (-b) = -max a b := by
rw [Int.min_def, Int.max_def]
@@ -507,7 +535,17 @@ protected theorem mul_le_mul_of_nonpos_left {a b c : Int}
/- ## natAbs -/
@[simp, norm_cast] theorem natAbs_ofNat (n : Nat) : natAbs n = n := rfl
@[simp, norm_cast] theorem natAbs_natCast (n : Nat) : natAbs n = n := rfl
@[deprecated natAbs_natCast (since := "2025-04-16")]
theorem natAbs_ofNat (n : Nat) : natAbs n = n := natAbs_natCast n
/-
TODO: rename `natAbs_ofNat'` to `natAbs_ofNat` once the current deprecated alias
`natAbs_ofNat := natAbs_natCast` is removed
-/
@[simp] theorem natAbs_ofNat' (n : Nat) : natAbs (ofNat n) = n := rfl
@[simp] theorem natAbs_negSucc (n : Nat) : natAbs -[n+1] = n.succ := rfl
@[simp] theorem natAbs_zero : natAbs (0 : Int) = (0 : Nat) := rfl
@[simp] theorem natAbs_one : natAbs (1 : Int) = (1 : Nat) := rfl
@@ -518,7 +556,8 @@ protected theorem mul_le_mul_of_nonpos_left {a b c : Int}
| -[_+1] => absurd H (succ_ne_zero _),
fun e => e rfl
theorem natAbs_pos : 0 < natAbs a a 0 := by rw [Nat.pos_iff_ne_zero, Ne, natAbs_eq_zero]
@[simp] theorem natAbs_pos : 0 < natAbs a a 0 := by
rw [Nat.pos_iff_ne_zero, Ne, natAbs_eq_zero]
@[simp] theorem natAbs_neg : (a : Int), natAbs (-a) = natAbs a
| 0 => rfl
@@ -562,6 +601,16 @@ theorem natAbs_sub_of_nonneg_of_le {a b : Int} (h₁ : 0 ≤ b) (h₂ : b ≤ a)
· rwa [ Int.ofNat_le, natAbs_of_nonneg h₁, natAbs_of_nonneg (Int.le_trans h₁ h₂)]
· exact Int.sub_nonneg_of_le h₂
theorem eq_zero_of_dvd_of_natAbs_lt_natAbs {d n : Int} (h : d n) (h₁ : n.natAbs < d.natAbs) :
n = 0 := by
let a, ha := h
subst ha
rw [natAbs_mul] at h₁
suffices ¬ 0 < a.natAbs by simp [Int.natAbs_eq_zero.1 (Nat.eq_zero_of_not_pos this)]
refine fun h => Nat.lt_irrefl _ (Nat.lt_of_le_of_lt ?_ h₁)
rw (occs := [1]) [ Nat.mul_one d.natAbs]
exact Nat.mul_le_mul (Nat.le_refl _) h
/-! ### toNat -/
theorem toNat_eq_max : a : Int, (toNat a : Int) = max a 0
@@ -575,12 +624,18 @@ theorem toNat_eq_max : ∀ a : Int, (toNat a : Int) = max a 0
theorem toNat_of_nonneg {a : Int} (h : 0 a) : (toNat a : Int) = a := by
rw [toNat_eq_max, Int.max_eq_left h]
@[simp] theorem toNat_ofNat (n : Nat) : toNat n = n := rfl
@[simp] theorem toNat_natCast (n : Nat) : toNat n = n := rfl
@[deprecated toNat_natCast (since := "2025-04-16")]
theorem toNat_ofNat (n : Nat) : toNat n = n := toNat_natCast n
@[simp] theorem toNat_negSucc (n : Nat) : (Int.negSucc n).toNat = 0 := by
simp [toNat]
@[simp] theorem toNat_ofNat_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := rfl
@[simp] theorem toNat_natCast_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := rfl
@[deprecated toNat_natCast_add_one (since := "2025-04-16")]
theorem toNat_ofNat_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := toNat_natCast_add_one
@[simp] theorem ofNat_toNat (a : Int) : (a.toNat : Int) = max a 0 := by
match a with
@@ -599,6 +654,18 @@ theorem toNat_add {a b : Int} (ha : 0 ≤ a) (hb : 0 ≤ b) : (a + b).toNat = a.
match a, b, eq_ofNat_of_zero_le ha, eq_ofNat_of_zero_le hb with
| _, _, _, rfl, _, rfl => rfl
theorem toNat_mul {a b : Int} (ha : 0 a) (hb : 0 b) : (a * b).toNat = a.toNat * b.toNat :=
match a, b, eq_ofNat_of_zero_le ha, eq_ofNat_of_zero_le hb with
| _, _, _, rfl, _, rfl => rfl
/--
Variant of `Int.toNat_sub` taking non-negativity hypotheses,
rather than expecting the arguments to be casts of natural numbers.
-/
theorem toNat_sub'' {a b : Int} (ha : 0 a) (hb : 0 b) : (a - b).toNat = a.toNat - b.toNat :=
match a, b, eq_ofNat_of_zero_le ha, eq_ofNat_of_zero_le hb with
| _, _, _, rfl, _, rfl => toNat_sub _ _
theorem toNat_add_nat {a : Int} (ha : 0 a) (n : Nat) : (a + n).toNat = a.toNat + n :=
match a, eq_ofNat_of_zero_le ha with | _, _, rfl => rfl
@@ -746,6 +813,16 @@ protected theorem neg_lt_of_neg_lt {a b : Int} (h : -a < b) : -b < a := by
have h := Int.neg_lt_neg h
rwa [Int.neg_neg] at h
@[simp high]
protected theorem neg_pos : 0 < -a a < 0 := Int.neg_of_neg_pos, Int.neg_pos_of_neg
@[simp high]
protected theorem neg_nonneg : 0 -a a 0 :=
Int.nonpos_of_neg_nonneg, Int.neg_nonneg_of_nonpos
@[simp high]
protected theorem neg_neg_iff_pos : -a < 0 0 < a := Int.pos_of_neg_neg, Int.neg_neg_of_pos
protected theorem sub_nonpos_of_le {a b : Int} (h : a b) : a - b 0 := by
have h := Int.add_le_add_right h (-b)
rwa [Int.add_right_neg] at h
@@ -758,6 +835,14 @@ protected theorem sub_neg_of_lt {a b : Int} (h : a < b) : a - b < 0 := by
have h := Int.add_lt_add_right h (-b)
rwa [Int.add_right_neg] at h
@[simp high]
protected theorem sub_pos {a b : Int} : 0 < a - b b < a :=
Int.lt_of_sub_pos, Int.sub_pos_of_lt
@[simp high]
protected theorem sub_nonneg {a b : Int} : 0 a - b b a :=
Int.le_of_sub_nonneg, Int.sub_nonneg_of_le
protected theorem lt_of_sub_neg {a b : Int} (h : a - b < 0) : a < b := by
have h := Int.add_lt_add_right h b
rwa [Int.sub_add_cancel, Int.zero_add] at h
@@ -998,6 +1083,33 @@ theorem le_sub_one_of_lt {a b : Int} (H : a < b) : a ≤ b - 1 := Int.le_sub_rig
theorem lt_of_le_sub_one {a b : Int} (H : a b - 1) : a < b := Int.add_le_of_le_sub_right H
theorem le_add_one_iff {m n : Int} : m n + 1 m n m = n + 1 := by
rw [Int.le_iff_lt_or_eq, Int.le_iff_lt_add_one]
theorem sub_one_lt_iff {m n : Int} : m - 1 < n m n :=
le_of_sub_one_lt, sub_one_lt_of_le
theorem le_sub_one_iff {m n : Int} : m n - 1 m < n :=
lt_of_le_sub_one, le_sub_one_of_lt
protected theorem add_le_iff_le_sub {a b c : Int} : a + b c a c - b :=
Int.le_sub_right_of_add_le, Int.add_le_of_le_sub_right
protected theorem le_add_iff_sub_le {a b c : Int} : a b + c a - c b :=
Int.sub_right_le_of_le_add, Int.le_add_of_sub_right_le
protected theorem add_le_zero_iff_le_neg {a b : Int} : a + b 0 a -b := by
rw [Int.add_le_iff_le_sub, Int.zero_sub]
protected theorem add_le_zero_iff_le_neg' {a b : Int} : a + b 0 b -a := by
rw [Int.add_comm, Int.add_le_zero_iff_le_neg]
protected theorem add_nonnneg_iff_neg_le {a b : Int} : 0 a + b -b a := by
rw [Int.le_add_iff_sub_le, Int.zero_sub]
protected theorem add_nonnneg_iff_neg_le' {a b : Int} : 0 a + b -a b := by
rw [Int.add_comm, Int.add_nonnneg_iff_neg_le]
/- ### Order properties and multiplication -/
protected theorem mul_lt_mul {a b c d : Int}
@@ -1073,13 +1185,21 @@ theorem sign_neg_one : sign (-1) = -1 := rfl
theorem natAbs_sign (z : Int) : z.sign.natAbs = if z = 0 then 0 else 1 :=
match z with | 0 | succ _ | -[_+1] => rfl
theorem natAbs_sign_of_nonzero {z : Int} (hz : z 0) : z.sign.natAbs = 1 := by
theorem natAbs_sign_of_ne_zero {z : Int} (hz : z 0) : z.sign.natAbs = 1 := by
rw [Int.natAbs_sign, if_neg hz]
theorem sign_ofNat_of_nonzero {n : Nat} (hn : n 0) : Int.sign n = 1 :=
@[deprecated natAbs_sign_of_ne_zero (since := "2025-04-16")]
theorem natAbs_sign_of_nonzero {z : Int} (hz : z 0) : z.sign.natAbs = 1 :=
natAbs_sign_of_ne_zero hz
theorem sign_natCast_of_ne_zero {n : Nat} (hn : n 0) : Int.sign n = 1 :=
match n, Nat.exists_eq_succ_of_ne_zero hn with
| _, n, rfl => Int.sign_of_add_one n
@[deprecated sign_natCast_of_ne_zero (since := "2025-04-16")]
theorem sign_ofNat_of_nonzero {n : Nat} (hn : n 0) : Int.sign n = 1 :=
sign_natCast_of_ne_zero hn
@[simp] theorem sign_neg (z : Int) : Int.sign (-z) = -Int.sign z := by
match z with | 0 | succ _ | -[_+1] => rfl
@@ -1161,7 +1281,7 @@ theorem neg_of_sign_eq_neg_one : ∀ {a : Int}, sign a = -1 → a < 0
@[deprecated mul_sign_self (since := "2025-02-24")] abbrev mul_sign := @mul_sign_self
@[simp] theorem sign_mul_self : sign i * i = natAbs i := by
@[simp] theorem sign_mul_self (i : Int) : sign i * i = natAbs i := by
rw [Int.mul_comm, mul_sign_self]
theorem sign_trichotomy (a : Int) : sign a = 1 sign a = 0 sign a = -1 := by
@@ -1187,15 +1307,15 @@ theorem natAbs_mul_natAbs_eq {a b : Int} {c : Nat}
rw [ Int.ofNat_mul, natAbs_mul_self]
theorem natAbs_eq_iff {a : Int} {n : Nat} : a.natAbs = n a = n a = -n := by
rw [ Int.natAbs_eq_natAbs_iff, Int.natAbs_ofNat]
rw [ Int.natAbs_eq_natAbs_iff, Int.natAbs_natCast]
theorem natAbs_add_le (a b : Int) : natAbs (a + b) natAbs a + natAbs b := by
suffices a b : Nat, natAbs (subNatNat a b.succ) (a + b).succ by
match a, b with
| (a:Nat), (b:Nat) => rw [ ofNat_add, natAbs_ofNat]; apply Nat.le_refl
| (a:Nat), -[b+1] => rw [natAbs_ofNat, natAbs_negSucc]; apply this
| (a:Nat), (b:Nat) => rw [ ofNat_add, natAbs_natCast]; apply Nat.le_refl
| (a:Nat), -[b+1] => rw [natAbs_natCast, natAbs_negSucc]; apply this
| -[a+1], (b:Nat) =>
rw [natAbs_negSucc, natAbs_ofNat, Nat.succ_add, Nat.add_comm a b]; apply this
rw [natAbs_negSucc, natAbs_natCast, Nat.succ_add, Nat.add_comm a b]; apply this
| -[a+1], -[b+1] => rw [natAbs_negSucc, succ_add]; apply Nat.le_refl
refine fun a b => subNatNat_elim a b.succ
(fun m n i => n = b.succ natAbs i (m + b).succ) ?_
@@ -1211,6 +1331,15 @@ theorem natAbs_add_le (a b : Int) : natAbs (a + b) ≤ natAbs a + natAbs b := by
theorem natAbs_sub_le (a b : Int) : natAbs (a - b) natAbs a + natAbs b := by
rw [ Int.natAbs_neg b]; apply natAbs_add_le
theorem natAbs_add_of_nonneg : {a b : Int}, 0 a 0 b natAbs (a + b) = natAbs a + natAbs b
| ofNat _, ofNat _, _, _ => rfl
theorem natAbs_add_of_nonpos {a b : Int} (ha : a 0) (hb : b 0) :
natAbs (a + b) = natAbs a + natAbs b := by
rw [ Int.neg_neg a, Int.neg_neg b, Int.neg_add, natAbs_neg,
natAbs_add_of_nonneg (Int.neg_nonneg_of_nonpos ha) (Int.neg_nonneg_of_nonpos hb),
natAbs_neg (-a), natAbs_neg (-b)]
@[deprecated negSucc_eq (since := "2025-03-11")]
theorem negSucc_eq' (m : Nat) : -[m+1] = -m - 1 := by simp only [negSucc_eq, Int.neg_add]; rfl

View File

@@ -36,7 +36,7 @@ abbrev pow_le_pow_of_le_right := @Nat.pow_le_pow_right
@[deprecated Nat.pow_pos (since := "2025-02-17")]
abbrev pos_pow_of_pos := @Nat.pow_pos
@[norm_cast]
@[simp, norm_cast]
protected theorem natCast_pow (b n : Nat) : ((b^n : Nat) : Int) = (b : Int) ^ n := by
match n with
| 0 => rfl
@@ -54,7 +54,7 @@ protected theorem two_pow_pred_sub_two_pow' {w : Nat} (h : 0 < w) :
(2 : Int) ^ (w - 1) - (2 : Int) ^ w = - (2 : Int) ^ (w - 1) := by
norm_cast
rw [ Nat.two_pow_pred_add_two_pow_pred h]
simp [h]
simp [h, -Int.natCast_pow]
theorem pow_lt_pow_of_lt {a : Int} {b c : Nat} (ha : 1 < a) (hbc : b < c):
a ^ b < a ^ c := by
@@ -63,7 +63,7 @@ theorem pow_lt_pow_of_lt {a : Int} {b c : Nat} (ha : 1 < a) (hbc : b < c):
simp only [Int.ofNat_lt]
omega
theorem natAbs_pow (n : Int) : (k : Nat) (n ^ k).natAbs = n.natAbs ^ k
@[simp] theorem natAbs_pow (n : Int) : (k : Nat) (n ^ k).natAbs = n.natAbs ^ k
| 0 => rfl
| k + 1 => by rw [Int.pow_succ, natAbs_mul, natAbs_pow, Nat.pow_succ]

View File

@@ -477,7 +477,7 @@ theorem attach_filterMap {l : List α} {f : α → Option β} :
· simp only [h]
rfl
rw [ih]
simp only [map_filterMap, Option.map_pbind, Option.map_some']
simp only [map_filterMap, Option.map_pbind, Option.map_some]
rfl
· simp only [Option.pbind_eq_some_iff] at h
obtain a, h, w := h
@@ -640,12 +640,12 @@ theorem countP_attachWith {p : α → Prop} {q : α → Bool} {l : List α} (H :
simp only [ Function.comp_apply (g := Subtype.val), countP_map, attachWith_map_subtype_val]
@[simp]
theorem count_attach [DecidableEq α] {l : List α} {a : {x // x l}} :
theorem count_attach [BEq α] {l : List α} {a : {x // x l}} :
l.attach.count a = l.count a :=
Eq.trans (countP_congr fun _ _ => by simp [Subtype.ext_iff]) <| countP_attach
@[simp]
theorem count_attachWith [DecidableEq α] {p : α Prop} {l : List α} (H : a l, p a) {a : {x // p x}} :
theorem count_attachWith [BEq α] {p : α Prop} {l : List α} (H : a l, p a) {a : {x // p x}} :
(l.attachWith p H).count a = l.count a :=
Eq.trans (countP_congr fun _ _ => by simp [Subtype.ext_iff]) <| countP_attachWith _

View File

@@ -131,6 +131,12 @@ theorem beq_cons₂ [BEq α] {a b : α} {as bs : List α} : List.beq (a::as) (b:
instance [BEq α] : BEq (List α) := List.beq
instance [BEq α] [ReflBEq α] : ReflBEq (List α) where
rfl {as} := by
induction as with
| nil => rfl
| cons a as ih => simp [BEq.beq, List.beq]; exact ih
instance [BEq α] [LawfulBEq α] : LawfulBEq (List α) where
eq_of_beq {as bs} := by
induction as generalizing bs with
@@ -142,10 +148,6 @@ instance [BEq α] [LawfulBEq α] : LawfulBEq (List α) where
simp [show (a::as == b::bs) = (a == b && as == bs) from rfl, -and_imp]
intro h₁, h₂
exact h₁, ih h₂
rfl {as} := by
induction as with
| nil => rfl
| cons a as ih => simp [BEq.beq, List.beq, LawfulBEq.rfl]; exact ih
/--
Returns `true` if `as` and `bs` have the same length and they are pairwise related by `eqv`.
@@ -900,10 +902,10 @@ theorem mem_of_elem_eq_true [BEq α] [LawfulBEq α] {a : α} {as : List α} : el
next h => intros; simp [BEq.beq] at h; subst h; apply Mem.head
next _ => intro h; exact Mem.tail _ (mem_of_elem_eq_true h)
theorem elem_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : List α} (h : a as) : elem a as = true := by
theorem elem_eq_true_of_mem [BEq α] [ReflBEq α] {a : α} {as : List α} (h : a as) : elem a as = true := by
induction h with
| head _ => simp [elem]
| tail _ _ ih => simp [elem]; split; rfl; assumption
| tail _ _ ih => simp only [elem]; split; rfl; assumption
instance [BEq α] [LawfulBEq α] (a : α) (as : List α) : Decidable (a as) :=
decidable_of_decidable_of_iff (Iff.intro mem_of_elem_eq_true elem_eq_true_of_mem)

View File

@@ -298,8 +298,8 @@ theorem filter_beq {l : List α} (a : α) : l.filter (· == a) = replicate (coun
simp only [count, countP_eq_length_filter, eq_replicate_iff, mem_filter, beq_iff_eq]
exact trivial, fun _ h => h.2
theorem filter_eq {α} [DecidableEq α] {l : List α} (a : α) : l.filter (· = a) = replicate (count a l) a :=
filter_beq a
theorem filter_eq [DecidableEq α] {l : List α} (a : α) : l.filter (· = a) = replicate (count a l) a :=
funext (Bool.beq_eq_decide_eq · a) filter_beq a
theorem le_count_iff_replicate_sublist {l : List α} : n count a l replicate n a <+ l := by
refine fun h => ?_, fun h => ?_
@@ -314,7 +314,7 @@ theorem replicate_count_eq_of_count_eq_length {l : List α} (h : count a l = len
rw [count, countP_filter]; congr; funext b
simp; rintro rfl; exact h
theorem count_le_count_map [DecidableEq β] {l : List α} {f : α β} {x : α} :
theorem count_le_count_map {β} [BEq β] [LawfulBEq β] {l : List α} {f : α β} {x : α} :
count x l count (f x) (map f l) := by
rw [count, count, countP_map]
apply countP_mono_left; simp +contextual

View File

@@ -88,7 +88,7 @@ theorem exists_or_eq_self_of_eraseP (p) (l : List α) :
@[simp] theorem length_eraseP_of_mem (al : a l) (pa : p a) :
length (l.eraseP p) = length l - 1 := by
let _, l₁, l₂, _, _, e₁, e₂ := exists_of_eraseP al pa
rw [e₂]; simp [length_append, e₁]; rfl
rw [e₂]; simp [length_append, e₁]
theorem length_eraseP {l : List α} : (l.eraseP p).length = if l.any p then l.length - 1 else l.length := by
split <;> rename_i h
@@ -542,7 +542,7 @@ theorem eraseIdx_eq_take_drop_succ :
match l, i with
| [], _
| a::l, 0
| a::l, i + 1 => simp [Nat.succ_inj']
| a::l, i + 1 => simp [Nat.succ_inj]
@[deprecated eraseIdx_eq_nil_iff (since := "2025-01-30")]
abbrev eraseIdx_eq_nil := @eraseIdx_eq_nil_iff
@@ -551,7 +551,7 @@ theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2
match l with
| []
| [a]
| a::b::l => simp [Nat.succ_inj']
| a::b::l => simp [Nat.succ_inj]
@[deprecated eraseIdx_ne_nil_iff (since := "2025-01-30")]
abbrev eraseIdx_ne_nil := @eraseIdx_ne_nil_iff

View File

@@ -95,10 +95,10 @@ theorem findSome?_eq_some_iff {f : α → Option β} {l : List α} {b : β} :
| cons x xs ih =>
simp [guard, findSome?, find?]
split <;> rename_i h
· simp only [Option.guard_eq_some] at h
· simp only [Option.guard_eq_some_iff] at h
obtain rfl, h := h
simp [h]
· simp only [Option.guard_eq_none] at h
· simp only [Option.guard_eq_none_iff] at h
simp [ih, h]
theorem find?_eq_findSome?_guard {l : List α} : find? p l = findSome? (Option.guard fun x => p x) l :=
@@ -700,6 +700,7 @@ theorem findIdx?_eq_none_iff {xs : List α} {p : α → Bool} :
simp only [findIdx?_cons]
split <;> simp_all [cond_eq_if]
@[simp]
theorem findIdx?_isSome {xs : List α} {p : α Bool} :
(xs.findIdx? p).isSome = xs.any p := by
induction xs with
@@ -708,6 +709,7 @@ theorem findIdx?_isSome {xs : List α} {p : α → Bool} :
simp only [findIdx?_cons]
split <;> simp_all
@[simp]
theorem findIdx?_isNone {xs : List α} {p : α Bool} :
(xs.findIdx? p).isNone = xs.all (¬p ·) := by
induction xs with
@@ -768,7 +770,7 @@ theorem findIdx?_eq_some_iff_getElem {xs : List α} {p : α → Bool} {i : Nat}
not_and, Classical.not_forall, Bool.not_eq_false]
intros
refine 0, zero_lt_succ i, _
· simp only [Option.map_eq_some', ih, Bool.not_eq_true, length_cons]
· simp only [Option.map_eq_some_iff, ih, Bool.not_eq_true, length_cons]
constructor
· rintro a, h, h₁, h₂, rfl
refine Nat.succ_lt_succ_iff.mpr h, by simpa, fun j hj => ?_
@@ -790,7 +792,7 @@ theorem of_findIdx?_eq_some {xs : List α} {p : α → Bool} (w : xs.findIdx? p
| nil => simp_all
| cons x xs ih =>
simp_all only [findIdx?_cons, Nat.zero_add]
split at w <;> cases i <;> simp_all [succ_inj']
split at w <;> cases i <;> simp_all [succ_inj]
@[deprecated of_findIdx?_eq_some (since := "2025-02-02")]
abbrev findIdx?_of_eq_some := @of_findIdx?_eq_some
@@ -824,7 +826,7 @@ abbrev findIdx?_of_eq_none := @of_findIdx?_eq_none
(xs ++ ys : List α).findIdx? p =
(xs.findIdx? p).or ((ys.findIdx? p).map fun i => i + xs.length) := by
induction xs with simp
| cons _ _ _ => split <;> simp_all [Option.map_or', Option.map_map]; rfl
| cons _ _ _ => split <;> simp_all [Option.map_or, Option.map_map]; rfl
theorem findIdx?_flatten {l : List (List α)} {p : α Bool} :
l.flatten.findIdx? p =
@@ -984,6 +986,24 @@ theorem findFinIdx?_eq_some_iff {xs : List α} {p : α → Bool} {i : Fin xs.len
· rintro h, w
exact i, i.2, h, fun j hji => w j, by omega hji, rfl
@[simp]
theorem isSome_findFinIdx? {l : List α} {p : α Bool} :
(l.findFinIdx? p).isSome = l.any p := by
induction l with
| nil => simp
| cons x xs ih =>
simp only [findFinIdx?_cons]
split <;> simp_all
@[simp]
theorem isNone_findFinIdx? {l : List α} {p : α Bool} :
(l.findFinIdx? p).isNone = l.all (fun x => ¬ p x) := by
induction l with
| nil => simp
| cons x xs ih =>
simp only [findFinIdx?_cons]
split <;> simp_all
@[simp] theorem findFinIdx?_subtype {p : α Prop} {l : List { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findFinIdx? f = (l.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
@@ -1084,6 +1104,24 @@ theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : List α} {a : α} :
l.finIdxOf? a = some i l[i] = a j (_ : j < i), ¬l[j] = a := by
simp only [finIdxOf?, findFinIdx?_eq_some_iff, beq_iff_eq]
@[simp]
theorem isSome_finIdxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
(l.finIdxOf? a).isSome a l := by
induction l with
| nil => simp
| cons x xs ih =>
simp only [finIdxOf?_cons]
split <;> simp_all [@eq_comm _ x a]
@[simp]
theorem isNone_finIdxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
(l.finIdxOf? a).isNone = ¬ a l := by
induction l with
| nil => simp
| cons x xs ih =>
simp only [finIdxOf?_cons]
split <;> simp_all [@eq_comm _ x a]
/-! ### idxOf?
The verification API for `idxOf?` is still incomplete.
@@ -1109,6 +1147,25 @@ theorem idxOf?_cons [BEq α] {a : α} {xs : List α} {b : α} :
@[deprecated idxOf?_eq_none_iff (since := "2025-01-29")]
abbrev indexOf?_eq_none_iff := @idxOf?_eq_none_iff
@[simp]
theorem isSome_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
(l.idxOf? a).isSome a l := by
induction l with
| nil => simp
| cons x xs ih =>
simp only [idxOf?_cons]
split <;> simp_all [@eq_comm _ x a]
@[simp]
theorem isNone_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
(l.idxOf? a).isNone = ¬ a l := by
induction l with
| nil => simp
| cons x xs ih =>
simp only [idxOf?_cons]
split <;> simp_all [@eq_comm _ x a]
/-! ### lookup -/
section lookup

View File

@@ -105,7 +105,7 @@ abbrev length_eq_zero := @length_eq_zero_iff
theorem eq_nil_iff_length_eq_zero : l = [] length l = 0 :=
length_eq_zero_iff.symm
@[grind] theorem length_pos_of_mem {a : α} : {l : List α}, a l 0 < length l
@[grind ] theorem length_pos_of_mem {a : α} : {l : List α}, a l 0 < length l
| _::_, _ => Nat.zero_lt_succ _
theorem exists_mem_of_length_pos : {l : List α}, 0 < length l a, a l
@@ -185,7 +185,7 @@ theorem singleton_inj {α : Type _} {a b : α} : [a] = [b] ↔ a = b := by
We simplify `l.get i` to `l[i.1]'i.2` and `l.get? i` to `l[i]?`.
-/
@[simp, grind]
@[simp, grind =]
theorem get_eq_getElem {l : List α} {i : Fin l.length} : l.get i = l[i.1]'i.2 := rfl
set_option linter.deprecated false in
@@ -225,7 +225,7 @@ theorem get?_eq_getElem? {l : List α} {i : Nat} : l.get? i = l[i]? := by
We simplify `l[i]!` to `(l[i]?).getD default`.
-/
@[simp, grind]
@[simp, grind =]
theorem getElem!_eq_getElem?_getD [Inhabited α] {l : List α} {i : Nat} :
l[i]! = (l[i]?).getD (default : α) := by
simp only [getElem!_def]
@@ -235,16 +235,16 @@ theorem getElem!_eq_getElem?_getD [Inhabited α] {l : List α} {i : Nat} :
/-! ### getElem? and getElem -/
@[simp, grind] theorem getElem?_nil {i : Nat} : ([] : List α)[i]? = none := rfl
@[simp, grind =] theorem getElem?_nil {i : Nat} : ([] : List α)[i]? = none := rfl
theorem getElem_cons {l : List α} (w : i < (a :: l).length) :
(a :: l)[i] =
if h : i = 0 then a else l[i-1]'(match i, h with | i+1, _ => succ_lt_succ_iff.mp w) := by
cases i <;> simp
@[grind] theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := rfl
@[grind =] theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := rfl
@[simp, grind] theorem getElem?_cons_succ {l : List α} : (a::l)[i+1]? = l[i]? := rfl
@[simp, grind =] theorem getElem?_cons_succ {l : List α} : (a::l)[i+1]? = l[i]? := rfl
theorem getElem?_cons : (a :: l)[i]? = if i = 0 then some a else l[i-1]? := by
cases i <;> simp [getElem?_cons_zero]
@@ -259,6 +259,9 @@ theorem getElem?_eq_some_iff {l : List α} : l[i]? = some a ↔ ∃ h : i < l.le
· match i, h with
| i + 1, h => simp [getElem?_eq_some_iff, Nat.succ_lt_succ_iff]
theorem getElem_of_getElem? {l : List α} : l[i]? = some a h : i < l.length, l[i] = a :=
getElem?_eq_some_iff.mp
theorem some_eq_getElem?_iff {l : List α} : some a = l[i]? h : i < l.length, l[i] = a := by
rw [eq_comm, getElem?_eq_some_iff]
@@ -337,7 +340,7 @@ We simplify away `getD`, replacing `getD l n a` with `(l[n]?).getD a`.
Because of this, there is only minimal API for `getD`.
-/
@[simp, grind]
@[simp, grind =]
theorem getD_eq_getElem?_getD {l : List α} {i : Nat} {a : α} : getD l i a = (l[i]?).getD a := by
simp [getD]
@@ -701,7 +704,7 @@ theorem set_comm (a b : α) : ∀ {i j : Nat} {l : List α}, i ≠ j →
| _+1, 0, _ :: _, _ => by simp [set]
| 0, _+1, _ :: _, _ => by simp [set]
| _+1, _+1, _ :: t, h =>
congrArg _ <| set_comm a b fun h' => h <| Nat.succ_inj'.mpr h'
congrArg _ <| set_comm a b fun h' => h <| Nat.succ_inj.mpr h'
@[simp]
theorem set_set (a : α) {b : α} : {l : List α} {i : Nat}, (l.set i a).set i b = l.set i b
@@ -711,8 +714,8 @@ theorem set_set (a : α) {b : α} : ∀ {l : List α} {i : Nat}, (l.set i a).set
theorem mem_set {l : List α} {i : Nat} (h : i < l.length) (a : α) :
a l.set i a := by
simp [mem_iff_getElem]
exact i, (by simpa using h), by simp
simp only [mem_iff_getElem]
exact i, by simpa using h, by simp
theorem mem_or_eq_of_mem_set : {l : List α} {i : Nat} {a b : α}, a l.set i b a l a = b
| _ :: _, 0, _, _, h => ((mem_cons ..).1 h).symm.imp_left (.tail _)
@@ -774,37 +777,24 @@ theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l
simpa only [List.instBEq, List.beq, Bool.and_true]
simp
· intro h
constructor
intro l
induction l with
| nil => simp only [List.instBEq, List.beq]
| cons _ _ ih =>
simp [List.instBEq, List.beq]
exact ih
infer_instance
@[simp] theorem lawfulBEq_iff [BEq α] : LawfulBEq (List α) LawfulBEq α := by
constructor
· intro h
have : ReflBEq α := reflBEq_iff.mp inferInstance
constructor
· intro a b h
apply singleton_inj.1
apply eq_of_beq
simp only [List.instBEq, List.beq]
simpa
· intro a
suffices ([a] == [a]) = true by
simpa only [List.instBEq, List.beq, Bool.and_true]
simp
intro a b h
apply singleton_inj.1
apply eq_of_beq
simp only [List.instBEq, List.beq]
simpa
· intro h
constructor
· intro _ _ h
simpa using h
· intro _
simp
infer_instance
/-! ### isEqv -/
@[simp] theorem isEqv_eq [DecidableEq α] {l₁ l₂ : List α} : l₁.isEqv l₂ (· == ·) = (l₁ = l₂) := by
@[simp] theorem isEqv_eq [BEq α] [LawfulBEq α] {l₁ l₂ : List α} : l₁.isEqv l₂ (· == ·) = (l₁ = l₂) := by
induction l₁ generalizing l₂ with
| nil => cases l₂ <;> simp
| cons a l₁ ih =>
@@ -827,9 +817,15 @@ theorem getElem_length_sub_one_eq_getLast {l : List α} (h : l.length - 1 < l.le
l[l.length - 1] = getLast l (by cases l; simp at h; simp) := by
rw [ getLast_eq_getElem]
@[simp] theorem getLast_cons_cons {a : α} {l : List α} :
getLast (a :: b :: l) (by simp) = getLast (b :: l) (by simp) := by
rfl
theorem getLast_cons {a : α} {l : List α} : (h : l nil),
getLast (a :: l) (cons_ne_nil a l) = getLast l h := by
induction l <;> intros; {contradiction}; rfl
induction l <;> intros
· contradiction
· rfl
theorem getLast_eq_getLastD {a l} (h) : @getLast α (a::l) h = getLastD l a := by
cases l <;> rfl
@@ -1296,7 +1292,7 @@ abbrev filter_length_eq_length := @length_filter_eq_length_iff
@[simp] theorem mem_filter : x filter p as x as p x := by
induction as with
| nil => simp [filter]
| nil => simp
| cons a as ih =>
by_cases h : p a
· simp_all [or_and_left]
@@ -1362,12 +1358,9 @@ theorem filter_eq_cons_iff {l} {a} {as} :
split at h <;> rename_i w
· simp only [cons.injEq] at h
obtain rfl, rfl := h
refine [], l, ?_
simp [w]
· specialize ih h
obtain l₁, l₂, rfl, w₁, w₂, w₃ := ih
refine x :: l₁, l₂, ?_
simp_all
exact [], l, by simp [w]
· obtain l₁, l₂, rfl, w₁, w₂, w₃ := ih h
exact x :: l₁, l₂, by simp_all
· rintro l₁, l₂, rfl, h₁, h, h₂
simp [h₂, filter_cons, filter_eq_nil_iff.mpr h₁, h]
@@ -2046,7 +2039,7 @@ theorem eq_iff_flatten_eq : ∀ {L L' : List (List α)},
| _, [] => by simp_all
| [], _ :: _ => by simp_all
| _ :: _, _ :: _ => by
simp
simp only [cons.injEq, flatten_cons, map_cons]
rw [eq_iff_flatten_eq]
constructor
· rintro rfl, h₁, h₂
@@ -2154,7 +2147,7 @@ theorem replicate_succ' : replicate (n + 1) a = replicate n a ++ [a] := by
| 0 => by simp
| n+1 => by simp [replicate_succ, mem_replicate, Nat.succ_ne_zero]
@[deprecated mem_replicate (since := "2024-09-05")]
@[simp]
theorem contains_replicate [BEq α] {n : Nat} {a b : α} :
(replicate n b).contains a = (a == b && !n == 0) := by
induction n with
@@ -2165,9 +2158,9 @@ theorem contains_replicate [BEq α] {n : Nat} {a b : α} :
@[deprecated mem_replicate (since := "2024-09-05")]
theorem decide_mem_replicate [BEq α] [LawfulBEq α] {a b : α} :
{n}, decide (b replicate n a) = ((¬ n == 0) && b == a)
| 0 => by simp
| n+1 => by simp [replicate_succ, decide_mem_replicate, Nat.succ_ne_zero]
{n}, decide (b replicate n a) = ((¬ n == 0) && b == a) := by
have : DecidableEq α := instDecidableEqOfLawfulBEq
simp [Bool.beq_eq_decide_eq]
theorem eq_of_mem_replicate {a b : α} {n} (h : b replicate n a) : b = a := (mem_replicate.1 h).2
@@ -2709,12 +2702,12 @@ theorem foldr_assoc {op : ααα} [ha : Std.Associative op] :
-- The argument `f : α₁ → α₂` is intentionally explicit, as it is sometimes not found by unification.
theorem foldl_hom (f : α₁ α₂) {g₁ : α₁ β α₁} {g₂ : α₂ β α₂} {l : List β} {init : α₁}
(H : x y, g₂ (f x) y = f (g₁ x y)) : l.foldl g₂ (f init) = f (l.foldl g₁ init) := by
induction l generalizing init <;> simp [*, H]
induction l generalizing init <;> simp [*]
-- The argument `f : β₁ → β₂` is intentionally explicit, as it is sometimes not found by unification.
theorem foldr_hom (f : β₁ β₂) {g₁ : α β₁ β₁} {g₂ : α β₂ β₂} {l : List α} {init : β₁}
(H : x y, g₂ x (f y) = f (g₁ x y)) : l.foldr g₂ (f init) = f (l.foldr g₁ init) := by
induction l <;> simp [*, H]
induction l <;> simp [*]
/--
A reasoning principle for proving propositions about the result of `List.foldl` by establishing an
@@ -3260,6 +3253,10 @@ theorem eq_or_mem_of_mem_insert {l : List α} (h : a ∈ l.insert b) : a = b
@[simp] theorem length_insert_of_not_mem {l : List α} (h : a l) :
length (l.insert a) = length l + 1 := by rw [insert_of_not_mem h]; rfl
theorem length_insert {l : List α} :
(l.insert a).length = l.length + if a l then 0 else 1 := by
split <;> simp_all
theorem length_le_length_insert {l : List α} {a : α} : l.length (l.insert a).length := by
by_cases h : a l
· rw [length_insert_of_mem h]

View File

@@ -281,7 +281,7 @@ protected theorem le_iff_lt_or_eq [DecidableEq α] [LT α] [DecidableLT α]
· exact List.le_of_lt h
· exact List.le_refl l₁
theorem lex_eq_decide_lex [DecidableEq α] (lt : α α Bool) :
theorem lex_eq_decide_lex [BEq α] [LawfulBEq α] [DecidableEq α] (lt : α α Bool) :
lex l₁ l₂ lt = decide (Lex (fun x y => lt x y) l₁ l₂) := by
induction l₁ generalizing l₂ with
| nil =>
@@ -295,21 +295,22 @@ theorem lex_eq_decide_lex [DecidableEq α] (lt : αα → Bool) :
simp [lex, ih, cons_lex_cons_iff, Bool.beq_eq_decide_eq]
/-- Variant of `lex_eq_true_iff` using an arbitrary comparator. -/
@[simp] theorem lex_eq_true_iff_lex [DecidableEq α] (lt : α α Bool) :
@[simp] theorem lex_eq_true_iff_lex [BEq α] [LawfulBEq α] (lt : α α Bool) :
lex l₁ l₂ lt = true Lex (fun x y => lt x y) l₁ l₂ := by
have : DecidableEq α := instDecidableEqOfLawfulBEq
simp [lex_eq_decide_lex]
/-- Variant of `lex_eq_false_iff` using an arbitrary comparator. -/
@[simp] theorem lex_eq_false_iff_not_lex [DecidableEq α] (lt : α α Bool) :
@[simp] theorem lex_eq_false_iff_not_lex [BEq α] [LawfulBEq α] (lt : α α Bool) :
lex l₁ l₂ lt = false ¬ Lex (fun x y => lt x y) l₁ l₂ := by
simp [Bool.eq_false_iff, lex_eq_true_iff_lex]
@[simp] theorem lex_eq_true_iff_lt [DecidableEq α] [LT α] [DecidableLT α]
@[simp] theorem lex_eq_true_iff_lt [BEq α] [LawfulBEq α] [LT α] [DecidableLT α]
{l₁ l₂ : List α} : lex l₁ l₂ = true l₁ < l₂ := by
simp only [lex_eq_true_iff_lex, decide_eq_true_eq]
exact Iff.rfl
@[simp] theorem lex_eq_false_iff_ge [DecidableEq α] [LT α] [DecidableLT α]
@[simp] theorem lex_eq_false_iff_ge [BEq α] [LawfulBEq α] [LT α] [DecidableLT α]
{l₁ l₂ : List α} : lex l₁ l₂ = false l₂ l₁ := by
simp only [lex_eq_false_iff_not_lex, decide_eq_true_eq]
exact Iff.rfl

View File

@@ -339,7 +339,7 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {acc : Array β} {i : Nat},
if h : i < acc.size then some acc[i] else Option.map (f i) l[i - acc.size]?
| [], acc, i => by
simp only [mapIdx.go, Array.toListImpl_eq, getElem?_def, Array.length_toList,
Array.getElem_toList, length_nil, Nat.not_lt_zero, reduceDIte, Option.map_none']
Array.getElem_toList, length_nil, Nat.not_lt_zero, reduceDIte, Option.map_none]
| a :: l, acc, i => by
rw [mapIdx.go, getElem?_mapIdx_go]
simp only [Array.size_push]

View File

@@ -118,7 +118,7 @@ theorem mem_eraseIdx_iff_getElem {x : α} :
| a::l, 0 => by simp [mem_iff_getElem, Nat.succ_lt_succ_iff]
| a::l, k+1 => by
rw [ Nat.or_exists_add_one]
simp [mem_eraseIdx_iff_getElem, @eq_comm _ a, succ_inj', Nat.succ_lt_succ_iff]
simp [mem_eraseIdx_iff_getElem, @eq_comm _ a, succ_inj, Nat.succ_lt_succ_iff]
theorem mem_eraseIdx_iff_getElem? {x : α} {l} {k} : x eraseIdx l k i k, l[i]? = some x := by
simp only [mem_eraseIdx_iff_getElem, getElem_eq_iff, exists_and_left]

View File

@@ -31,6 +31,33 @@ theorem count_set [BEq α] {a b : α} {l : List α} {i : Nat} (h : i < l.length)
(l.set i a).count b = l.count b - (if l[i] == b then 1 else 0) + (if a == b then 1 else 0) := by
simp [count_eq_countP, countP_set, h]
theorem countP_replace [BEq α] [LawfulBEq α] {a b : α} {l : List α} {p : α Bool} :
(l.replace a b).countP p =
if l.contains a then l.countP p + (if p b then 1 else 0) - (if p a then 1 else 0) else l.countP p := by
induction l with
| nil => simp
| cons x l ih =>
simp [replace_cons]
split <;> rename_i h
· simp at h
simp [h, ih, countP_cons]
omega
· simp only [beq_eq_false_iff_ne, ne_eq] at h
simp only [countP_cons, ih, contains_eq_mem, decide_eq_true_eq, mem_cons, h, false_or]
split <;> rename_i h'
· by_cases h'' : p a
· have : countP p l > 0 := countP_pos_iff.mpr a, h', h''
simp [h'']
omega
· simp [h'']
omega
· omega
theorem count_replace [BEq α] [LawfulBEq α] {a b c : α} {l : List α} :
(l.replace a b).count c =
if l.contains a then l.count c + (if b == c then 1 else 0) - (if a == c then 1 else 0) else l.count c := by
simp [count_eq_countP, countP_replace]
/--
The number of elements satisfying a predicate in a sublist is at least the number of elements satisfying the predicate in the list,
minus the difference in the lengths.

View File

@@ -54,4 +54,23 @@ theorem set_set_perm {as : List α} {i j : Nat} (h₁ : i < as.length) (h₂ : j
subst t
apply set_set_perm' _ _ (by omega)
namespace Perm
/-- Variant of `List.Perm.take` specifying the the permutation is constant after `i` elementwise. -/
theorem take_of_getElem? {l₁ l₂ : List α} (h : l₁ ~ l₂) {i : Nat} (w : j, i j l₁[j]? = l₂[j]?) :
l₁.take i ~ l₂.take i := by
refine h.take (Perm.of_eq ?_)
ext1 j
simpa using w (i + j) (by omega)
/-- Variant of `List.Perm.drop` specifying the the permutation is constant before `i` elementwise. -/
theorem drop_of_getElem? {l₁ l₂ : List α} (h : l₁ ~ l₂) {i : Nat} (w : j, j < i l₁[j]? = l₂[j]?) :
l₁.drop i ~ l₂.drop i := by
refine h.drop (Perm.of_eq ?_)
ext1
simp only [getElem?_take]
split <;> simp_all
end Perm
end List

View File

@@ -40,7 +40,6 @@ theorem getLast?_range' {n : Nat} : (range' s n).getLast? = if n = 0 then none e
simp [h]
· rw [if_neg h]
simp
omega
@[simp] theorem getLast_range' {n : Nat} (h) : (range' s n).getLast h = s + n - 1 := by
cases n with
@@ -358,7 +357,7 @@ theorem zipIdx_singleton {x : α} {k : Nat} : zipIdx [x] k = [(x, k)] :=
@[simp] theorem getLast?_zipIdx {l : List α} {k : Nat} :
(zipIdx l k).getLast? = l.getLast?.map fun a => (a, k + l.length - 1) := by
simp [getLast?_eq_getElem?]
cases l <;> simp; omega
cases l <;> simp
theorem mk_add_mem_zipIdx_iff_getElem? {k i : Nat} {x : α} {l : List α} :
(x, k + i) zipIdx l k l[i]? = some x := by
@@ -497,7 +496,7 @@ theorem head?_enumFrom (n : Nat) (l : List α) :
theorem getLast?_enumFrom (n : Nat) (l : List α) :
(enumFrom n l).getLast? = l.getLast?.map fun a => (n + l.length - 1, a) := by
simp [getLast?_eq_getElem?]
cases l <;> simp; omega
cases l <;> simp
@[deprecated mk_add_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
theorem mk_add_mem_enumFrom_iff_getElem? {n i : Nat} {x : α} {l : List α} :

View File

@@ -532,7 +532,7 @@ theorem dropWhile_eq_drop_findIdx_not {xs : List α} {p : α → Bool} :
| zero => simp
| succ n =>
suffices 1 < m m - (m - (n + 1) % m) + min (m - (n + 1) % m) m = m by
simpa [rotateRight]
simp [rotateRight]
intro h
have : (n + 1) % m < m := Nat.mod_lt _ (by omega)
rw [Nat.min_eq_left (by omega)]

View File

@@ -6,6 +6,7 @@ Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
prelude
import Init.Data.List.Pairwise
import Init.Data.List.Erase
import Init.Data.List.Find
/-!
# List Permutations
@@ -178,7 +179,7 @@ theorem Perm.singleton_eq (h : [a] ~ l) : [a] = l := singleton_perm.mp h
theorem singleton_perm_singleton {a b : α} : [a] ~ [b] a = b := by simp
theorem perm_cons_erase [DecidableEq α] {a : α} {l : List α} (h : a l) : l ~ a :: l.erase a :=
theorem perm_cons_erase [BEq α] [LawfulBEq α] {a : α} {l : List α} (h : a l) : l ~ a :: l.erase a :=
let _, _, _, e₁, e₂ := exists_erase_eq h
e₂ e₁ perm_middle
@@ -201,6 +202,9 @@ theorem Perm.pmap {p : α → Prop} (f : ∀ a, p a → β) {l₁ l₂ : List α
| swap x y => simp [swap]
| trans _p₁ p₂ IH₁ IH₂ => exact IH₁.trans (IH₂ (H₁ := fun a m => H₂ a (p₂.subset m)))
theorem Perm.unattach {α : Type u} {p : α Prop} {l₁ l₂ : List { x // p x }} (h : l₁ ~ l₂) :
l₁.unattach.Perm l₂.unattach := h.map _
theorem Perm.filter (p : α Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) :
filter p l₁ ~ filter p l₂ := by rw [ filterMap_eq_filter]; apply s.filterMap
@@ -268,7 +272,7 @@ theorem countP_eq_countP_filter_add (l : List α) (p q : α → Bool) :
l.countP p = (l.filter q).countP p + (l.filter fun a => !q a).countP p :=
countP_append .. Perm.countP_eq _ (filter_append_perm _ _).symm
theorem Perm.count_eq [DecidableEq α] {l₁ l₂ : List α} (p : l₁ ~ l₂) (a) :
theorem Perm.count_eq [BEq α] {l₁ l₂ : List α} (p : l₁ ~ l₂) (a) :
count a l₁ = count a l₂ := p.countP_eq _
/-
@@ -369,9 +373,9 @@ theorem perm_append_right_iff {l₁ l₂ : List α} (l) : l₁ ++ l ~ l₂ ++ l
refine fun p => ?_, .append_right _
exact (perm_append_left_iff _).1 <| perm_append_comm.trans <| p.trans perm_append_comm
section DecidableEq
section LawfulBEq
variable [DecidableEq α]
variable [BEq α] [LawfulBEq α]
theorem Perm.erase (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.erase a ~ l₂.erase a :=
if h₁ : a l₁ then
@@ -401,14 +405,14 @@ theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l
refine ((IH fun b => ?_).cons a).trans (perm_cons_erase this).symm
specialize H b
rw [(perm_cons_erase this).count_eq] at H
by_cases h : b = a <;> simpa [h, count_cons, Nat.succ_inj'] using H
by_cases h : b = a <;> simpa [h, count_cons, Nat.succ_inj] using H
theorem isPerm_iff : {l₁ l₂ : List α}, l₁.isPerm l₂ l₁ ~ l₂
| [], [] => by simp [isPerm, isEmpty]
| [], _ :: _ => by simp [isPerm, isEmpty, Perm.nil_eq]
| a :: l₁, l₂ => by simp [isPerm, isPerm_iff, cons_perm_iff_perm_erase]
instance decidablePerm (l₁ l₂ : List α) : Decidable (l₁ ~ l₂) := decidable_of_iff _ isPerm_iff
instance decidablePerm {α} [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ ~ l₂) := decidable_of_iff _ isPerm_iff
protected theorem Perm.insert (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) :
l₁.insert a ~ l₂.insert a := by
@@ -425,7 +429,7 @@ theorem perm_insert_swap (x y : α) (l : List α) :
simp [List.insert, xl, yl, xy, Ne.symm xy]
constructor
end DecidableEq
end LawfulBEq
theorem Perm.pairwise_iff {R : α α Prop} (S : {x y}, R x y R y x) :
{l₁ l₂ : List α} (_p : l₁ ~ l₂), Pairwise R l₁ Pairwise R l₂ :=
@@ -536,4 +540,22 @@ theorem perm_insertIdx {α} (x : α) (l : List α) {i} (h : i ≤ l.length) :
simp only [insertIdx, modifyTailIdx]
refine .trans (.cons _ (ih (Nat.le_of_succ_le_succ h))) (.swap ..)
namespace Perm
theorem take {l₁ l₂ : List α} (h : l₁ ~ l₂) {n : Nat} (w : l₁.drop n ~ l₂.drop n) :
l₁.take n ~ l₂.take n := by
classical
rw [perm_iff_count] at h w
rw [ take_append_drop n l₁, take_append_drop n l₂] at h
simpa only [count_append, w, Nat.add_right_cancel_iff] using h
theorem drop {l₁ l₂ : List α} (h : l₁ ~ l₂) {n : Nat} (w : l₁.take n ~ l₂.take n) :
l₁.drop n ~ l₂.drop n := by
classical
rw [perm_iff_count] at h w
rw [ take_append_drop n l₁, take_append_drop n l₂] at h
simpa only [count_append, w, Nat.add_left_cancel_iff] using h
end Perm
end List

View File

@@ -69,7 +69,7 @@ theorem mem_range' : ∀ {n}, m ∈ range' s n step ↔ ∃ i < n, m = s + step
| 0 => by simp [range', Nat.not_lt_zero]
| n + 1 => by
have h (i) : i n i = 0 j, i = succ j j < n := by
cases i <;> simp [Nat.succ_le, Nat.succ_inj']
cases i <;> simp [Nat.succ_le, Nat.succ_inj]
simp [range', mem_range', Nat.lt_succ, h]; simp only [ exists_and_right, and_assoc]
rw [exists_comm]; simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm]

View File

@@ -220,7 +220,7 @@ theorem zipWith_eq_append_iff {f : α → β → γ} {l₁ : List α} {l₂ : Li
· simp_all
· obtain (rfl, rfl | _, rfl, rfl) := h₃
· simp_all
· simp_all [zipWith_append, Nat.succ_inj']
· simp_all [zipWith_append, Nat.succ_inj]
/-- See also `List.zipWith_replicate` in `Init.Data.List.TakeDrop` for a generalization with different lengths. -/
@[simp] theorem zipWith_replicate' {a : α} {b : β} {n : Nat} :

View File

@@ -6,6 +6,7 @@ Authors: Floris van Doorn, Leonardo de Moura
prelude
import Init.SimpLemmas
import Init.Data.NeZero
import Init.Grind.Tactics
set_option linter.missingDocs true -- keep it documented
universe u
@@ -545,6 +546,10 @@ protected theorem le_of_add_le_add_right {a b c : Nat} : a + b ≤ c + b → a
/-! ### le/lt -/
attribute [simp] not_lt_zero
example : (default : Nat) = 0 := rfl
protected theorem lt_asymm {a b : Nat} (h : a < b) : ¬ b < a := Nat.not_lt.2 (Nat.le_of_lt h)
/-- Alias for `Nat.lt_asymm`. -/
protected abbrev not_lt_of_gt := @Nat.lt_asymm
@@ -617,7 +622,7 @@ protected theorem eq_zero_of_not_pos (h : ¬0 < n) : n = 0 :=
attribute [simp] zero_lt_succ
theorem succ_ne_self (n) : succ n n := Nat.ne_of_gt (lt_succ_self n)
@[simp] theorem succ_ne_self (n) : succ n n := Nat.ne_of_gt (lt_succ_self n)
theorem add_one_ne_self (n) : n + 1 n := Nat.ne_of_gt (lt_succ_self n)
@@ -640,13 +645,20 @@ theorem eq_zero_or_eq_succ_pred : ∀ n, n = 0 n = succ (pred n)
| 0 => .inl rfl
| _+1 => .inr rfl
theorem succ_inj' : succ a = succ b a = b := (Nat.succ.injEq a b).to_iff
theorem succ_inj : succ a = succ b a = b := (Nat.succ.injEq a b).to_iff
@[deprecated succ_inj (since := "2025-04-14")]
theorem succ_inj' : succ a = succ b a = b := succ_inj
theorem succ_le_succ_iff : succ a succ b a b := le_of_succ_le_succ, succ_le_succ
theorem succ_lt_succ_iff : succ a < succ b a < b := lt_of_succ_lt_succ, succ_lt_succ
theorem add_one_inj : a + 1 = b + 1 a = b := succ_inj'
theorem succ_ne_succ_iff : succ a succ b a b := by simp [Nat.succ.injEq]
theorem succ_succ_ne_one (a : Nat) : succ (succ a) 1 := nofun
theorem add_one_inj : a + 1 = b + 1 a = b := succ_inj
theorem ne_add_one (n : Nat) : n n + 1 := fun h => by cases h
@@ -656,6 +668,10 @@ theorem add_one_le_add_one_iff : a + 1 ≤ b + 1 ↔ a ≤ b := succ_le_succ_iff
theorem add_one_lt_add_one_iff : a + 1 < b + 1 a < b := succ_lt_succ_iff
theorem add_one_ne_add_one_iff : a + 1 b + 1 a b := succ_ne_succ_iff
theorem add_one_add_one_ne_one : a + 1 + 1 1 := nofun
theorem pred_inj : {a b}, 0 < a 0 < b pred a = pred b a = b
| _+1, _+1, _, _ => congrArg _
@@ -713,16 +729,18 @@ theorem exists_eq_add_one_of_ne_zero : ∀ {n}, n ≠ 0 → Exists fun k => n =
theorem ctor_eq_zero : Nat.zero = 0 :=
rfl
protected theorem one_ne_zero : 1 (0 : Nat) :=
@[simp] protected theorem one_ne_zero : 1 (0 : Nat) :=
fun h => Nat.noConfusion h
protected theorem zero_ne_one : 0 (1 : Nat) :=
@[simp] protected theorem zero_ne_one : 0 (1 : Nat) :=
fun h => Nat.noConfusion h
theorem succ_ne_zero (n : Nat) : succ n 0 := by simp
@[simp] theorem succ_ne_zero (n : Nat) : succ n 0 := by simp
instance instNeZeroSucc {n : Nat} : NeZero (n + 1) := succ_ne_zero n
@[simp] theorem default_eq_zero : default = 0 := rfl
/-! # mul + order -/
theorem mul_le_mul_left {n m : Nat} (k : Nat) (h : n m) : k * n k * m :=
@@ -867,7 +885,7 @@ Examples:
-/
protected abbrev min (n m : Nat) := min n m
protected theorem min_def {n m : Nat} : min n m = if n m then n else m := rfl
@[grind =] protected theorem min_def {n m : Nat} : min n m = if n m then n else m := rfl
instance : Max Nat := maxOfLe
@@ -884,7 +902,7 @@ Examples:
-/
protected abbrev max (n m : Nat) := max n m
protected theorem max_def {n m : Nat} : max n m = if n m then m else n := rfl
@[grind =] protected theorem max_def {n m : Nat} : max n m = if n m then m else n := rfl
/-! # Auxiliary theorems for well-founded recursion -/
@@ -1002,7 +1020,7 @@ protected theorem add_sub_add_left (k n m : Nat) : (k + n) - (k + m) = n - m :=
suffices n + m - (0 + m) = n by rw [Nat.zero_add] at this; assumption
by rw [Nat.add_sub_add_right, Nat.sub_zero]
protected theorem add_sub_cancel_left (n m : Nat) : n + m - n = m :=
@[simp] protected theorem add_sub_cancel_left (n m : Nat) : n + m - n = m :=
show n + m - (n + 0) = m from
by rw [Nat.add_sub_add_left, Nat.sub_zero]
@@ -1053,7 +1071,7 @@ protected theorem sub_self_add (n m : Nat) : n - (n + m) = 0 := by
show (n + 0) - (n + m) = 0
rw [Nat.add_sub_add_left, Nat.zero_sub]
protected theorem sub_eq_zero_of_le {n m : Nat} (h : n m) : n - m = 0 := by
@[simp] protected theorem sub_eq_zero_of_le {n m : Nat} (h : n m) : n - m = 0 := by
match le.dest h with
| k, hk => rw [ hk, Nat.sub_self_add]

View File

@@ -473,7 +473,8 @@ Nat.le_antisymm
(le_of_lt_succ ((Nat.div_lt_iff_lt_mul npos).2 hi))
((Nat.le_div_iff_mul_le npos).2 lo)
theorem sub_mul_div (x n p : Nat) (h₁ : n*p x) : (x - n*p) / n = x / n - p := by
/-- See also `sub_mul_div` for a strictly more general version. -/
theorem sub_mul_div_of_le (x n p : Nat) (h₁ : n*p x) : (x - n*p) / n = x / n - p := by
match eq_zero_or_pos n with
| .inl h₀ => rw [h₀, Nat.div_zero, Nat.div_zero, Nat.zero_sub]
| .inr h₀ => induction p with
@@ -551,7 +552,7 @@ protected theorem div_le_of_le_mul {m n : Nat} : ∀ {k}, m ≤ k * n → m / k
@[simp] theorem mul_div_left (m : Nat) {n : Nat} (H : 0 < n) : m * n / n = m := by
rw [Nat.mul_comm, mul_div_right _ H]
protected theorem div_self (H : 0 < n) : n / n = 1 := by
@[simp] protected theorem div_self (H : 0 < n) : n / n = 1 := by
let t := add_div_right 0 H
rwa [Nat.zero_add, Nat.zero_div] at t

View File

@@ -84,6 +84,10 @@ theorem div_le_div_left (hcb : c ≤ b) (hc : 0 < c) : a / b ≤ a / c :=
(Nat.le_div_iff_mul_le hc).2 <|
Nat.le_trans (Nat.mul_le_mul_left _ hcb) (Nat.div_mul_le_self a b)
protected theorem div_le_div {a b c d : Nat} (h1 : a b) (h2 : d c) (h3 : d 0) : a / c b / d :=
calc a / c b / c := Nat.div_le_div_right h1
_ b / d := Nat.div_le_div_left h2 (Nat.pos_of_ne_zero h3)
theorem div_add_le_right {z : Nat} (h : 0 < z) (x y : Nat) :
x / (y + z) x / z :=
div_le_div_left (Nat.le_add_left z y) h
@@ -104,7 +108,7 @@ theorem succ_div_of_dvd {a b : Nat} (h : b a + 1) :
Nat.add_right_cancel_iff] at h
subst h
rw [Nat.add_sub_cancel, Nat.add_one_mul, mul_div_right _ (zero_lt_succ _), Nat.add_comm,
Nat.add_mul_div_left _ _ (zero_lt_succ _), Nat.self_eq_add_left, div_eq_of_lt le.refl]
Nat.add_mul_div_left _ _ (zero_lt_succ _), Nat.right_eq_add, div_eq_of_lt le.refl]
· simp only [Nat.not_le] at h'
replace h' : a + 1 < b + 1 := Nat.add_lt_add_right h' 1
rw [Nat.mod_eq_of_lt h'] at h

View File

@@ -1,21 +1,22 @@
/-
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Copyright (c) 2014 Floris van Doorn (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro, Floris van Doorn
-/
prelude
import Init.Data.Nat.MinMax
import Init.Data.Nat.Log2
import Init.Data.Nat.Power2
import Init.Data.Nat.Mod
import Init.Omega
/-! # Basic lemmas about natural numbers
/-! # Basic theorems about natural numbers
The primary purpose of the lemmas in this file is to assist with reasoning
The primary purpose of the theorems in this file is to assist with reasoning
about sizes of objects, array indices and such.
This file was upstreamed from Std,
and later these lemmas should be organised into other files more systematically.
The content of this file was upstreamed from Batteries and mathlib,
and later these theorems should be organised into other files more systematically.
-/
namespace Nat
@@ -100,13 +101,94 @@ theorem exists_lt_succ_left {p : Nat → Prop} :
( m, m < n + 1 p m) p 0 ( m, m < n p (m + 1)) := by
simpa using exists_lt_succ_left' (p := fun m _ => p m)
/-! ## succ/pred -/
protected theorem sub_one (n) : n - 1 = pred n := rfl
theorem one_add (n) : 1 + n = succ n := Nat.add_comm ..
theorem succ_ne_succ : succ m succ n m n :=
mt (congrArg Nat.succ ·), mt succ.inj
theorem one_lt_succ_succ (n : Nat) : 1 < n.succ.succ := succ_lt_succ <| succ_pos _
theorem not_succ_lt_self : ¬ succ n < n := Nat.not_lt_of_ge n.le_succ
theorem succ_le_iff : succ m n m < n := lt_of_succ_le, succ_le_of_lt
theorem le_succ_iff {m n : Nat} : m n.succ m n m = n.succ := by
refine fun hmn (Nat.lt_or_eq_of_le hmn).imp_left le_of_lt_succ, ?_
rintro (hmn | rfl)
· exact le_succ_of_le hmn
· exact Nat.le_refl _
theorem lt_iff_le_pred : {n}, 0 < n (m < n m n - 1) | _ + 1, _ => Nat.lt_succ_iff
-- TODO: state LHS using `- 1` instead?
theorem le_of_pred_lt : {m}, pred m < n m n
| 0 => Nat.le_of_lt
| _ + 1 => id
theorem lt_iff_add_one_le : m < n m + 1 n := by rw [succ_le_iff]
theorem lt_one_add_iff : m < 1 + n m n := by simp only [Nat.add_comm, Nat.lt_succ_iff]
theorem one_add_le_iff : 1 + m n m < n := by simp only [Nat.add_comm, add_one_le_iff]
theorem one_le_iff_ne_zero : 1 n n 0 := Nat.pos_iff_ne_zero
theorem one_lt_iff_ne_zero_and_ne_one : {n : Nat}, 1 < n n 0 n 1
| 0 => by decide
| 1 => by decide
| n + 2 => by omega
theorem le_one_iff_eq_zero_or_eq_one : {n : Nat}, n 1 n = 0 n = 1 := by simp [le_succ_iff]
theorem one_le_of_lt (h : a < b) : 1 b := Nat.lt_of_le_of_lt (Nat.zero_le _) h
theorem pred_one_add (n : Nat) : pred (1 + n) = n := by rw [Nat.add_comm, add_one, Nat.pred_succ]
theorem pred_eq_self_iff : n.pred = n n = 0 := by cases n <;> simp [(Nat.succ_ne_self _).symm]
theorem pred_eq_of_eq_succ {m n : Nat} (H : m = n.succ) : m.pred = n := by simp [H]
@[simp] theorem pred_eq_succ_iff : n - 1 = m + 1 n = m + 2 := by
cases n <;> constructor <;> rintro <;> rfl
@[simp] theorem add_succ_sub_one (m n : Nat) : m + succ n - 1 = m + n := rfl
@[simp]
theorem succ_add_sub_one (n m : Nat) : succ m + n - 1 = m + n := by rw [succ_add, Nat.add_one_sub_one]
theorem pred_sub (n m : Nat) : pred n - m = pred (n - m) := by
rw [ Nat.sub_one, Nat.sub_sub, one_add, sub_succ]
theorem self_add_sub_one : n, n + (n - 1) = 2 * n - 1
| 0 => rfl
| n + 1 => by rw [Nat.two_mul]; exact (add_succ_sub_one (Nat.succ _) _).symm
theorem sub_one_add_self (n : Nat) : (n - 1) + n = 2 * n - 1 := Nat.add_comm _ n self_add_sub_one n
theorem self_add_pred (n : Nat) : n + pred n = (2 * n).pred := self_add_sub_one n
theorem pred_add_self (n : Nat) : pred n + n = (2 * n).pred := sub_one_add_self n
theorem pred_le_iff : pred m n m succ n :=
le_succ_of_pred_le, by
cases m
· exact fun _ zero_le n
· exact le_of_succ_le_succ
theorem lt_of_lt_pred (h : m < n - 1) : m < n := by omega
theorem le_add_pred_of_pos (a : Nat) (hb : b 0) : a b + (a - 1) := by omega
theorem lt_pred_iff : a < pred b succ a < b := by simp; omega
/-! ## add -/
protected theorem add_add_add_comm (a b c d : Nat) : (a + b) + (c + d) = (a + c) + (b + d) := by
rw [Nat.add_assoc, Nat.add_assoc, Nat.add_left_comm b]
theorem one_add (n) : 1 + n = succ n := Nat.add_comm ..
theorem succ_eq_one_add (n) : succ n = 1 + n := (one_add _).symm
theorem succ_add_eq_add_succ (a b) : succ a + b = a + succ b := Nat.succ_add ..
@@ -114,19 +196,31 @@ theorem succ_add_eq_add_succ (a b) : succ a + b = a + succ b := Nat.succ_add ..
protected theorem eq_zero_of_add_eq_zero_right (h : n + m = 0) : n = 0 :=
(Nat.eq_zero_of_add_eq_zero h).1
@[simp] protected theorem add_eq_zero_iff : n + m = 0 n = 0 m = 0 :=
protected theorem add_eq_zero_iff : n + m = 0 n = 0 m = 0 :=
Nat.eq_zero_of_add_eq_zero, fun h₁, h₂ => h₂.symm h₁
@[simp] protected theorem add_left_cancel_iff {n : Nat} : n + m = n + k m = k :=
@[simp high] protected theorem add_left_cancel_iff {n : Nat} : n + m = n + k m = k :=
Nat.add_left_cancel, fun | rfl => rfl
@[simp] protected theorem add_right_cancel_iff {n : Nat} : m + n = k + n m = k :=
@[simp high] protected theorem add_right_cancel_iff {n : Nat} : m + n = k + n m = k :=
Nat.add_right_cancel, fun | rfl => rfl
@[simp] protected theorem add_left_eq_self {a b : Nat} : a + b = b a = 0 := by omega
@[simp] protected theorem add_right_eq_self {a b : Nat} : a + b = a b = 0 := by omega
@[simp] protected theorem self_eq_add_right {a b : Nat} : a = a + b b = 0 := by omega
@[simp] protected theorem self_eq_add_left {a b : Nat} : a = b + a b = 0 := by omega
protected theorem add_left_inj {n : Nat} : m + n = k + n m = k := Nat.add_right_cancel_iff
protected theorem add_right_inj {n : Nat} : n + m = n + k m = k := Nat.add_left_cancel_iff
@[simp high] protected theorem add_eq_left {a b : Nat} : a + b = a b = 0 := by omega
@[simp high] protected theorem add_eq_right {a b : Nat} : a + b = b a = 0 := by omega
@[simp high] protected theorem left_eq_add {a b : Nat} : a = a + b b = 0 := by omega
@[simp high] protected theorem right_eq_add {a b : Nat} : b = a + b a = 0 := by omega
@[deprecated Nat.add_eq_right (since := "2025-04-15")]
protected theorem add_left_eq_self {a b : Nat} : a + b = b a = 0 := Nat.add_eq_right
@[deprecated Nat.add_eq_left (since := "2025-04-15")]
protected theorem add_right_eq_self {a b : Nat} : a + b = a b = 0 := Nat.add_eq_left
@[deprecated Nat.left_eq_add (since := "2025-04-15")]
protected theorem self_eq_add_right {a b : Nat} : a = a + b b = 0 := Nat.left_eq_add
@[deprecated Nat.right_eq_add (since := "2025-04-15")]
protected theorem self_eq_add_left {a b : Nat} : a = b + a b = 0 := Nat.right_eq_add
protected theorem lt_of_add_lt_add_right : {n : Nat}, k + n < m + n k < m
| 0, h => h
@@ -173,9 +267,28 @@ protected theorem add_self_ne_one : ∀ n, n + n ≠ 1
theorem le_iff_lt_add_one : x y x < y + 1 := by
omega
/-! ## sub -/
@[simp high] protected theorem add_eq_zero : m + n = 0 m = 0 n = 0 := by omega
protected theorem sub_one (n) : n - 1 = pred n := rfl
theorem add_pos_iff_pos_or_pos : 0 < m + n 0 < m 0 < n := by omega
theorem add_eq_one_iff : m + n = 1 m = 0 n = 1 m = 1 n = 0 := by omega
theorem add_eq_two_iff : m + n = 2 m = 0 n = 2 m = 1 n = 1 m = 2 n = 0 := by
omega
theorem add_eq_three_iff :
m + n = 3 m = 0 n = 3 m = 1 n = 2 m = 2 n = 1 m = 3 n = 0 := by
omega
theorem le_add_one_iff : m n + 1 m n m = n + 1 := by omega
theorem le_and_le_add_one_iff : n m m n + 1 m = n m = n + 1 := by omega
theorem add_succ_lt_add (hab : a < b) (hcd : c < d) : a + c + 1 < b + d := by omega
theorem le_or_le_of_add_eq_add_pred (h : a + c = b + d - 1) : b a d c := by omega
/-! ## sub -/
protected theorem one_sub : n, 1 - n = if n = 0 then 1 else 0
| 0 => rfl
@@ -213,7 +326,7 @@ protected theorem sub_eq_zero_iff_le : n - m = 0 ↔ n ≤ m :=
protected theorem sub_pos_iff_lt : 0 < n - m m < n :=
Nat.lt_of_sub_pos, Nat.sub_pos_of_lt
protected theorem sub_le_iff_le_add {a b c : Nat} : a - b c a c + b :=
@[simp] protected theorem sub_le_iff_le_add {a b c : Nat} : a - b c a c + b :=
Nat.le_add_of_sub_le, sub_le_of_le_add
protected theorem sub_le_iff_le_add' {a b c : Nat} : a - b c a b + c := by
@@ -274,6 +387,25 @@ protected theorem exists_eq_add_of_le' (h : m ≤ n) : ∃ k : Nat, n = k + m :=
protected theorem exists_eq_add_of_lt (h : m < n) : k : Nat, n = m + k + 1 :=
n - (m + 1), by rw [Nat.add_right_comm, add_sub_of_le h]
/-- A version of `Nat.sub_succ` in the form `_ - 1` instead of `Nat.pred _`. -/
theorem sub_succ' (m n : Nat) : m - n.succ = m - n - 1 := rfl
protected theorem sub_eq_of_eq_add' {a b c : Nat} (h : a = b + c) : a - b = c := by omega
protected theorem eq_sub_of_add_eq {a b c : Nat} (h : c + b = a) : c = a - b := by omega
protected theorem eq_sub_of_add_eq' {a b c : Nat} (h : b + c = a) : c = a - b := by omega
protected theorem lt_sub_iff_add_lt {a b c : Nat} : a < c - b a + b < c := add_lt_of_lt_sub, lt_sub_of_add_lt
protected theorem lt_sub_iff_add_lt' {a b c : Nat} : a < c - b b + a < c := by omega
protected theorem sub_lt_iff_lt_add {a b c : Nat} (hba : b a) : a - b < c a < c + b := by omega
protected theorem sub_lt_iff_lt_add' {a b c : Nat} (hba : b a) : a - b < c a < b + c := by omega
-- TODO: variants
protected theorem sub_sub_sub_cancel_right {a b c : Nat} (h : c b) : a - c - (b - c) = a - b := by omega
protected theorem add_sub_sub_cancel {a b c : Nat} (h : c a) : a + b - (a - c) = b + c := by omega
protected theorem sub_add_sub_cancel {a b c : Nat} (hab : b a) (hcb : c b) : a - b + (b - c) = a - c := by omega
protected theorem sub_lt_sub_iff_right {a b c : Nat} (h : c a) : a - c < b - c a < b := by omega
/-! ### min/max -/
theorem succ_min_succ (x y) : min (succ x) (succ y) = succ (min x y) := by
@@ -417,6 +549,24 @@ protected theorem sub_min_sub_left (a b c : Nat) : min (a - b) (a - c) = a - max
protected theorem sub_max_sub_left (a b c : Nat) : max (a - b) (a - c) = a - min b c := by
omega
protected theorem min_left_comm (a b c : Nat) : min a (min b c) = min b (min a c) := by
rw [ Nat.min_assoc, Nat.min_assoc, b.min_comm]
protected theorem max_left_comm (a b c : Nat) : max a (max b c) = max b (max a c) := by
rw [ Nat.max_assoc, Nat.max_assoc, b.max_comm]
protected theorem min_right_comm (a b c : Nat) : min (min a b) c = min (min a c) b := by
rw [Nat.min_assoc, Nat.min_assoc, b.min_comm]
protected theorem max_right_comm (a b c : Nat) : max (max a b) c = max (max a c) b := by
rw [Nat.max_assoc, Nat.max_assoc, b.max_comm]
@[simp] theorem min_eq_zero_iff : min m n = 0 m = 0 n = 0 := by omega
@[simp] theorem max_eq_zero_iff : max m n = 0 m = 0 n = 0 := by omega
theorem add_eq_max_iff : m + n = max m n m = 0 n = 0 := by omega
theorem add_eq_min_iff : m + n = min m n m = 0 n = 0 := by omega
/-! ### mul -/
protected theorem mul_right_comm (n m k : Nat) : n * m * k = n * k * m := by
@@ -538,6 +688,101 @@ protected theorem mul_dvd_mul_iff_left {a b c : Nat} (h : 0 < a) : a * b a *
protected theorem mul_dvd_mul_iff_right {a b c : Nat} (h : 0 < c) : a * c b * c a b := by
rw [Nat.mul_comm _ c, Nat.mul_comm _ c, Nat.mul_dvd_mul_iff_left h]
protected theorem zero_eq_mul : 0 = m * n m = 0 n = 0 := by rw [eq_comm, Nat.mul_eq_zero]
-- TODO: Replace `Nat.mul_right_cancel_iff` with `Nat.mul_left_inj`
protected theorem mul_left_inj (ha : a 0) : b * a = c * a b = c :=
Nat.mul_right_cancel_iff (Nat.pos_iff_ne_zero.2 ha)
-- TODO: Replace `Nat.mul_left_cancel_iff` with `Nat.mul_right_inj`
protected theorem mul_right_inj (ha : a 0) : a * b = a * c b = c :=
Nat.mul_left_cancel_iff (Nat.pos_iff_ne_zero.2 ha)
protected theorem mul_ne_mul_left (ha : a 0) : b * a c * a b c :=
not_congr (Nat.mul_left_inj ha)
protected theorem mul_ne_mul_right (ha : a 0) : a * b a * c b c :=
not_congr (Nat.mul_right_inj ha)
theorem mul_eq_left (ha : a 0) : a * b = a b = 1 := by simpa using Nat.mul_right_inj ha (c := 1)
theorem mul_eq_right (hb : b 0) : a * b = b a = 1 := by simpa using Nat.mul_left_inj hb (c := 1)
/-- The product of two natural numbers is greater than 1 if and only if
at least one of them is greater than 1 and both are positive. -/
theorem one_lt_mul_iff : 1 < m * n 0 < m 0 < n (1 < m 1 < n) := by
constructor <;> intro h
· refine Decidable.by_contra (fun h' => ?_)
simp only [Nat.le_zero, Decidable.not_and_iff_not_or_not, not_or, Nat.not_lt] at h'
obtain rfl | rfl | h' := h'
· simp at h
· simp at h
· exact Nat.not_lt_of_le (Nat.mul_le_mul h'.1 h'.2) h
· obtain hm | hn := h.2.2
· exact Nat.mul_lt_mul_of_lt_of_le' hm h.2.1 Nat.zero_lt_one
· exact Nat.mul_lt_mul_of_le_of_lt h.1 hn h.1
theorem eq_one_of_mul_eq_one_right (H : m * n = 1) : m = 1 := eq_one_of_dvd_one n, H.symm
theorem eq_one_of_mul_eq_one_left (H : m * n = 1) : n = 1 :=
eq_one_of_mul_eq_one_right (n := m) (by rwa [Nat.mul_comm])
@[simp] protected theorem lt_mul_iff_one_lt_left (hb : 0 < b) : b < a * b 1 < a := by
simpa using Nat.mul_lt_mul_right (b := 1) hb
@[simp] protected theorem lt_mul_iff_one_lt_right (ha : 0 < a) : a < a * b 1 < b := by
simpa using Nat.mul_lt_mul_left (b := 1) ha
theorem eq_zero_of_two_mul_le (h : 2 * n n) : n = 0 := by omega
theorem eq_zero_of_mul_le (hb : 2 n) (h : n * m m) : m = 0 :=
eq_zero_of_two_mul_le <| Nat.le_trans (Nat.mul_le_mul_right _ hb) h
theorem succ_mul_pos (m : Nat) (hn : 0 < n) : 0 < succ m * n := Nat.mul_pos m.succ_pos hn
theorem mul_self_le_mul_self {m n : Nat} (h : m n) : m * m n * n := Nat.mul_le_mul h h
-- This name is consistent with mathlib's top level definitions for groups with zero, where there
-- are `mul_lt_mul`, `mul_lt_mul'` and `mul_lt_mul''`, all with different sets of hypotheses.
theorem mul_lt_mul'' {a b c d : Nat} (hac : a < c) (hbd : b < d) : a * b < c * d :=
Nat.mul_lt_mul_of_lt_of_le hac (Nat.le_of_lt hbd) <| by omega
protected theorem lt_iff_lt_of_mul_eq_mul (ha : a 0) (hbd : a = b * d) (hce : a = c * e) :
c < b d < e where
mp hcb := Nat.lt_of_not_le fun hed Nat.not_lt_of_le (Nat.le_of_eq <| hbd.symm.trans hce) <|
Nat.mul_lt_mul_of_lt_of_le hcb hed <| by simp [hbd, Nat.mul_eq_zero] at ha; omega
mpr hde := Nat.lt_of_not_le fun hbc Nat.not_lt_of_le (Nat.le_of_eq <| hce.symm.trans hbd) <|
Nat.mul_lt_mul_of_le_of_lt hbc hde <| by simp [hce, Nat.mul_eq_zero] at ha; omega
theorem mul_self_lt_mul_self {m n : Nat} (h : m < n) : m * m < n * n := mul_lt_mul'' h h
theorem mul_self_le_mul_self_iff {m n : Nat} : m * m n * n m n :=
fun h => Nat.le_of_not_lt fun h' => Nat.not_le_of_gt (mul_self_lt_mul_self h') h,
mul_self_le_mul_self
theorem mul_self_lt_mul_self_iff {m n : Nat} : m * m < n * n m < n := by
simp only [ Nat.not_le, mul_self_le_mul_self_iff]
theorem le_mul_self : n : Nat, n n * n
| 0 => Nat.le_refl _
| n + 1 => by simp [Nat.mul_add]
theorem mul_self_inj {m n : Nat} : m * m = n * n m = n := by
simp [Nat.le_antisymm_iff, mul_self_le_mul_self_iff]
@[simp] theorem lt_mul_self_iff : {n : Nat}, n < n * n 1 < n
| 0 => by simp
| n + 1 => Nat.lt_mul_iff_one_lt_left n.succ_pos
theorem add_sub_one_le_mul (ha : a 0) (hb : b 0) : a + b - 1 a * b := by
cases a
· cases ha rfl
· rw [succ_add, Nat.add_one_sub_one, succ_mul]
exact Nat.add_le_add_right (Nat.le_mul_of_pos_right _ <| Nat.pos_iff_ne_zero.2 hb) _
protected theorem add_le_mul {a : Nat} (ha : 2 a) : {b : Nat} (_ : 2 b), a + b a * b
| 2, _ => by omega
| b + 3, _ => by have := Nat.add_le_mul ha (Nat.le_add_left _ b); rw [mul_succ]; omega
/-! ### div/mod -/
theorem mod_two_eq_zero_or_one (n : Nat) : n % 2 = 0 n % 2 = 1 :=
@@ -629,6 +874,203 @@ theorem div_eq_self {m n : Nat} : m / n = m ↔ m = 0 n = 1 := by
· exact hn
· exact False.elim (absurd h (Nat.ne_of_lt (Nat.div_lt_self hm hn)))
@[simp] protected theorem div_eq_zero_iff : a / b = 0 b = 0 a < b where
mp h := by
rw [ mod_add_div a b, h, Nat.mul_zero, Nat.add_zero, Decidable.or_iff_not_imp_left]
exact mod_lt _ Nat.pos_iff_ne_zero.2
mpr := by
obtain rfl | hb := Decidable.em (b = 0)
· simp
simp only [hb, false_or]
rw [ Nat.mul_right_inj hb, Nat.add_left_cancel_iff, mod_add_div]
simp +contextual [mod_eq_of_lt]
protected theorem div_ne_zero_iff : a / b 0 b 0 b a := by simp
@[simp] protected theorem div_pos_iff : 0 < a / b 0 < b b a := by
simp [Nat.pos_iff_ne_zero]
theorem lt_mul_of_div_lt (h : a / c < b) (hc : 0 < c) : a < b * c :=
Nat.lt_of_not_ge <| Nat.not_le_of_gt h (Nat.le_div_iff_mul_le hc).2
theorem mul_div_le_mul_div_assoc (a b c : Nat) : a * (b / c) a * b / c :=
if hc0 : c = 0 then by simp [hc0] else
(Nat.le_div_iff_mul_le (Nat.pos_of_ne_zero hc0)).2
(by rw [Nat.mul_assoc]; exact Nat.mul_le_mul_left _ (Nat.div_mul_le_self _ _))
protected theorem eq_mul_of_div_eq_right {a b c : Nat} (H1 : b a) (H2 : a / b = c) :
a = b * c := by
rw [ H2, Nat.mul_div_cancel' H1]
protected theorem eq_mul_of_div_eq_left {a b c : Nat} (H1 : b a) (H2 : a / b = c) : a = c * b := by
rw [Nat.mul_comm, Nat.eq_mul_of_div_eq_right H1 H2]
protected theorem mul_div_cancel_left' {a b : Nat} (Hd : a b) : a * (b / a) = b := by
rw [Nat.mul_comm, Nat.div_mul_cancel Hd]
theorem lt_div_mul_add {a b : Nat} (hb : 0 < b) : a < a / b * b + b := by
rw [ Nat.succ_mul, Nat.div_lt_iff_lt_mul hb]; exact Nat.lt_succ_self _
@[simp]
protected theorem div_left_inj {a b d : Nat} (hda : d a) (hdb : d b) :
a / d = b / d a = b := by
refine fun h ?_, congrArg fun b b / d
rw [ Nat.mul_div_cancel' hda, Nat.mul_div_cancel' hdb, h]
theorem div_le_iff_le_mul_add_pred (hb : 0 < b) : a / b c a b * c + (b - 1) := by
rw [ Nat.lt_succ_iff, div_lt_iff_lt_mul hb, succ_mul, Nat.mul_comm]
cases hb <;> exact Nat.lt_succ_iff
theorem one_le_div_iff {a b : Nat} (hb : 0 < b) : 1 a / b b a := by
rw [le_div_iff_mul_le hb, Nat.one_mul]
theorem div_lt_one_iff (hb : 0 < b) : a / b < 1 a < b := by
simp only [ Nat.not_le, one_le_div_iff hb]
protected theorem div_le_div_right {a b c : Nat} (h : a b) : a / c b / c :=
(c.eq_zero_or_pos.elim fun hc by simp [hc]) fun hc
(le_div_iff_mul_le hc).2 <| Nat.le_trans (Nat.div_mul_le_self _ _) h
theorem lt_of_div_lt_div {a b c : Nat} (h : a / c < b / c) : a < b :=
Nat.lt_of_not_le fun hab Nat.not_le_of_lt h <| Nat.div_le_div_right hab
theorem sub_mul_div (a b c : Nat) : (a - b * c) / b = a / b - c := by
obtain h | h := Nat.le_total (b * c) a
· rw [Nat.sub_mul_div_of_le _ _ _ h]
· rw [Nat.sub_eq_zero_of_le h, Nat.zero_div]
by_cases hn : b = 0
· simp only [hn, Nat.div_zero, zero_le, Nat.sub_eq_zero_of_le]
· have h2 : a / b (b * c) / b := Nat.div_le_div_right h
rw [Nat.mul_div_cancel_left _ (zero_lt_of_ne_zero hn)] at h2
rw [Nat.sub_eq_zero_of_le h2]
theorem mul_sub_div_of_dvd {b c : Nat} (hc : c 0) (hcb : c b) (a : Nat) : (c * a - b) / c = a - b / c := by
obtain _, hx := hcb
simp only [hx, Nat.mul_sub_left_distrib, Nat.mul_div_right, zero_lt_of_ne_zero hc]
theorem mul_add_mul_div_of_dvd (hb : b 0) (hd : d 0) (hba : b a) (hdc : d c) :
(a * d + b * c) / (b * d) = a / b + c / d := by
obtain n, hn := hba
obtain _, hm := hdc
rw [hn, hm, Nat.mul_assoc b n d, Nat.mul_comm n d, Nat.mul_assoc, Nat.mul_assoc,
Nat.mul_add,
Nat.mul_div_right _ (zero_lt_of_ne_zero hb),
Nat.mul_div_right _ (zero_lt_of_ne_zero hd),
Nat.mul_div_right _ (zero_lt_of_ne_zero <| Nat.mul_ne_zero hb hd)]
theorem mul_sub_mul_div_of_dvd (hb : b 0) (hd : d 0) (hba : b a) (hdc : d c) :
(a * d - b * c) / (b * d) = a / b - c / d := by
obtain n, hn := hba
obtain m, hm := hdc
rw [hn, hm]
rw [Nat.mul_assoc,Nat.mul_comm n d, Nat.mul_assoc, Nat.mul_assoc, Nat.mul_sub_left_distrib,
Nat.mul_div_right _ (zero_lt_of_ne_zero hb), Nat.mul_div_right _ (zero_lt_of_ne_zero hd),
Nat.mul_div_right _ (zero_lt_of_ne_zero <| Nat.mul_ne_zero hb hd)]
protected theorem div_mul_right_comm {a b : Nat} (hba : b a) (c : Nat) : a / b * c = a * c / b := by
rw [Nat.mul_comm, Nat.mul_div_assoc _ hba, Nat.mul_comm]
protected theorem mul_div_right_comm {a b : Nat} (hba : b a) (c : Nat) : a * c / b = a / b * c :=
(Nat.div_mul_right_comm hba _).symm
protected theorem div_eq_iff_eq_mul_right {a b c : Nat} (H : 0 < b) (H' : b a) :
a / b = c a = b * c :=
Nat.eq_mul_of_div_eq_right H', Nat.div_eq_of_eq_mul_right H
protected theorem div_eq_iff_eq_mul_left {a b c : Nat} (H : 0 < b) (H' : b a) :
a / b = c a = c * b := by
rw [Nat.mul_comm]; exact Nat.div_eq_iff_eq_mul_right H H'
theorem eq_div_iff_mul_eq_left (hc : c 0) (hcb : c b) : a = b / c b = a * c := by
rw [eq_comm, Nat.div_eq_iff_eq_mul_left (zero_lt_of_ne_zero hc) hcb]
theorem div_mul_div_comm {a b c d : Nat} : b a d c (a / b) * (c / d) = (a * c) / (b * d) := by
rintro x, rfl y, rfl
obtain rfl | hb := b.eq_zero_or_pos
· simp
obtain rfl | hd := d.eq_zero_or_pos
· simp
rw [Nat.mul_div_cancel_left _ hb, Nat.mul_div_cancel_left _ hd, Nat.mul_assoc b,
Nat.mul_left_comm x, Nat.mul_assoc b, Nat.mul_div_cancel_left _ (Nat.mul_pos hb hd)]
protected theorem mul_div_mul_comm {a b c d : Nat} (hba : b a) (hdc : d c) : a * c / (b * d) = a / b * (c / d) :=
(div_mul_div_comm hba hdc).symm
theorem eq_zero_of_le_div (hn : 2 n) (h : m m / n) : m = 0 :=
eq_zero_of_mul_le hn <| by
rw [Nat.mul_comm]; exact (Nat.le_div_iff_mul_le (Nat.lt_of_lt_of_le (by decide) hn)).1 h
theorem div_mul_div_le_div (a b c : Nat) : a / c * b / a b / c := by
obtain rfl | ha := Nat.eq_zero_or_pos a
· simp
· calc
a / c * b / a b * a / c / a :=
Nat.div_le_div_right (by rw [Nat.mul_comm]; exact mul_div_le_mul_div_assoc _ _ _)
_ = b / c := by rw [Nat.div_div_eq_div_mul, Nat.mul_comm b, Nat.mul_comm c,
Nat.mul_div_mul_left _ _ ha]
theorem eq_zero_of_le_div_two (h : n n / 2) : n = 0 := eq_zero_of_le_div (Nat.le_refl _) h
theorem le_div_two_of_div_two_lt_sub (h : a / 2 < a - b) : b a / 2 := by
omega
theorem div_two_le_of_sub_le_div_two (h : a - b a / 2) : a / 2 b := by
omega
protected theorem div_le_div_of_mul_le_mul (hd : d 0) (hdc : d c) (h : a * d c * b) :
a / b c / d :=
Nat.div_le_of_le_mul <| by
rwa [ Nat.mul_div_assoc _ hdc, Nat.le_div_iff_mul_le (Nat.pos_iff_ne_zero.2 hd), b.mul_comm]
theorem div_eq_sub_mod_div {m n : Nat} : m / n = (m - m % n) / n := by
obtain rfl | hn := n.eq_zero_or_pos
· rw [Nat.div_zero, Nat.div_zero]
· have : m - m % n = n * (m / n) := by
rw [Nat.sub_eq_iff_eq_add (Nat.mod_le _ _), Nat.add_comm, mod_add_div]
rw [this, mul_div_right _ hn]
protected theorem eq_div_of_mul_eq_left (hc : c 0) (h : a * c = b) : a = b / c := by
rw [ h, Nat.mul_div_cancel _ (Nat.pos_iff_ne_zero.2 hc)]
protected theorem eq_div_of_mul_eq_right (hc : c 0) (h : c * a = b) : a = b / c := by
rw [ h, Nat.mul_div_cancel_left _ (Nat.pos_iff_ne_zero.2 hc)]
protected theorem mul_le_of_le_div (k x y : Nat) (h : x y / k) : x * k y := by
if hk : k = 0 then
rw [hk, Nat.mul_zero]; exact zero_le _
else
rwa [ le_div_iff_mul_le (Nat.pos_iff_ne_zero.2 hk)]
theorem div_le_iff_le_mul_of_dvd (hb : b 0) (hba : b a) : a / b c a c * b := by
obtain _, hx := hba
simp only [hx]
rw [Nat.mul_div_right _ (zero_lt_of_ne_zero hb), Nat.mul_comm]
exact mul_le_mul_right b, fun h Nat.le_of_mul_le_mul_right h (zero_lt_of_ne_zero hb)
protected theorem div_lt_div_right (ha : a 0) : a b a c (b / a < c / a b < c) := by
rintro d, rfl e, rfl; simp [Nat.mul_div_cancel, Nat.pos_iff_ne_zero.2 ha]
protected theorem div_lt_div_left (ha : a 0) (hba : b a) (hca : c a) :
a / b < a / c c < b := by
obtain d, hd := hba
obtain e, he := hca
rw [Nat.div_eq_of_eq_mul_right _ hd, Nat.div_eq_of_eq_mul_right _ he,
Nat.lt_iff_lt_of_mul_eq_mul ha hd he] <;>
rw [Nat.pos_iff_ne_zero] <;> rintro rfl <;> simp at * <;> contradiction
theorem lt_div_iff_mul_lt_of_dvd (hc : c 0) (hcb : c b) : a < b / c a * c < b := by
simp [ Nat.div_lt_div_right _ _ hcb, hc, Nat.pos_iff_ne_zero, Nat.dvd_mul_left]
protected theorem div_mul_div_le (a b c d : Nat) :
(a / b) * (c / d) (a * c) / (b * d) := by
if hb : b = 0 then simp [hb] else
if hd : d = 0 then simp [hd] else
have hbd : b * d 0 := Nat.mul_ne_zero hb hd
rw [le_div_iff_mul_le (Nat.pos_of_ne_zero hbd)]
refine Nat.le_trans (m := ((a / b) * b) * ((c / d) * d)) ?_ ?_
· apply Nat.le_of_eq; simp only [Nat.mul_assoc, Nat.mul_left_comm]
· apply Nat.mul_le_mul <;> apply div_mul_le_self
/-! ### pow -/
theorem pow_succ' {m n : Nat} : m ^ n.succ = m * m ^ n := by
@@ -802,6 +1244,74 @@ theorem le_pow {a b : Nat} (h : 0 < b) : a ≤ a ^ b := by
rw [(show b = b - 1 + 1 by omega), Nat.pow_succ]
exact Nat.le_mul_of_pos_left _ (Nat.pow_pos ha)
protected theorem pow_lt_pow_right (ha : 1 < a) (h : m < n) : a ^ m < a ^ n :=
(Nat.pow_lt_pow_iff_right ha).2 h
protected theorem pow_le_pow_iff_left {a b n : Nat} (hn : n 0) : a ^ n b ^ n a b where
mp := by simpa only [ Nat.not_le, Decidable.not_imp_not] using (Nat.pow_lt_pow_left · hn)
mpr h := Nat.pow_le_pow_left h _
protected theorem pow_lt_pow_iff_left {a b n : Nat} (hn : n 0) : a ^ n < b ^ n a < b := by
simp only [ Nat.not_le, Nat.pow_le_pow_iff_left hn]
@[simp high] protected theorem pow_eq_zero {a : Nat} : {n : Nat}, a ^ n = 0 a = 0 n 0
| 0 => by simp
| n + 1 => by rw [Nat.pow_succ, mul_eq_zero, Nat.pow_eq_zero]; omega
theorem le_self_pow (hn : n 0) : a : Nat, a a ^ n
| 0 => zero_le _
| a + 1 => by simpa using Nat.pow_le_pow_right a.succ_pos (Nat.one_le_iff_ne_zero.2 hn)
theorem one_le_pow (n m : Nat) (h : 0 < m) : 1 m ^ n := by simpa using Nat.pow_le_pow_left h n
theorem one_lt_pow (hn : n 0) (ha : 1 < a) : 1 < a ^ n := by simpa using Nat.pow_lt_pow_left ha hn
theorem two_pow_succ (n : Nat) : 2 ^ (n + 1) = 2 ^ n + 2 ^ n := by simp [Nat.pow_succ, Nat.mul_two]
theorem one_lt_pow' (n m : Nat) : 1 < (m + 2) ^ (n + 1) :=
one_lt_pow n.succ_ne_zero (Nat.lt_of_sub_eq_succ rfl)
@[simp] theorem one_lt_pow_iff {n : Nat} (hn : n 0) : {a}, 1 < a ^ n 1 < a
| 0 => by simp [Nat.zero_pow (Nat.pos_of_ne_zero hn)]
| 1 => by simp
| a + 2 => by simp [one_lt_pow hn]
theorem one_lt_two_pow' (n : Nat) : 1 < 2 ^ (n + 1) := one_lt_pow n.succ_ne_zero (by decide)
theorem mul_lt_mul_pow_succ (ha : 0 < a) (hb : 1 < b) : n * b < a * b ^ (n + 1) := by
rw [Nat.pow_succ, Nat.mul_assoc, Nat.mul_lt_mul_right (Nat.lt_trans Nat.zero_lt_one hb)]
exact Nat.lt_of_le_of_lt (Nat.le_mul_of_pos_left _ ha)
((Nat.mul_lt_mul_left ha).2 <| Nat.lt_pow_self hb)
theorem pow_two_sub_pow_two (a b : Nat) : a ^ 2 - b ^ 2 = (a + b) * (a - b) := by
simpa [Nat.pow_succ] using Nat.mul_self_sub_mul_self_eq a b
protected theorem pow_pos_iff : 0 < a ^ n 0 < a n = 0 := by
simp [Nat.pos_iff_ne_zero, Decidable.imp_iff_not_or]
theorem pow_self_pos : 0 < n ^ n := by simp [Nat.pow_pos_iff, n.eq_zero_or_pos.symm]
theorem pow_self_mul_pow_self_le : m ^ m * n ^ n (m + n) ^ (m + n) := by
rw [Nat.pow_add]
exact Nat.mul_le_mul (Nat.pow_le_pow_left (le_add_right ..) _)
(Nat.pow_le_pow_left (le_add_left ..) _)
protected theorem pow_right_inj (ha : 1 < a) : a ^ m = a ^ n m = n := by
simp [Nat.le_antisymm_iff, Nat.pow_le_pow_iff_right ha]
@[simp] protected theorem pow_eq_one : a ^ n = 1 a = 1 n = 0 := by
obtain rfl | hn := Decidable.em (n = 0)
· simp
· simpa [hn] using Nat.pow_left_inj hn (b := 1)
/-- For `a > 1`, `a ^ b = a` iff `b = 1`. -/
theorem pow_eq_self_iff {a b : Nat} (ha : 1 < a) : a ^ b = a b = 1 := by
rw [ Nat.pow_right_inj (m := b) ha, Nat.pow_one]
@[simp] protected theorem pow_le_one_iff (hn : n 0) : a ^ n 1 a 1 := by
rw [ Nat.not_lt, one_lt_pow_iff hn, Nat.not_lt]
/-! ### log2 -/
@[simp]
@@ -835,19 +1345,7 @@ theorem lt_log2_self : n < 2 ^ (n.log2 + 1) :=
| 0 => by simp
| n+1 => (log2_lt n.succ_ne_zero).1 (Nat.le_refl _)
/-! ### dvd -/
protected theorem eq_mul_of_div_eq_right {a b c : Nat} (H1 : b a) (H2 : a / b = c) :
a = b * c := by
rw [ H2, Nat.mul_div_cancel' H1]
protected theorem div_eq_iff_eq_mul_right {a b c : Nat} (H : 0 < b) (H' : b a) :
a / b = c a = b * c :=
Nat.eq_mul_of_div_eq_right H', Nat.div_eq_of_eq_mul_right H
protected theorem div_eq_iff_eq_mul_left {a b c : Nat} (H : 0 < b) (H' : b a) :
a / b = c a = c * b := by
rw [Nat.mul_comm]; exact Nat.div_eq_iff_eq_mul_right H H'
/-! ### mod, dvd -/
theorem pow_dvd_pow_iff_pow_le_pow {k l : Nat} :
{x : Nat}, 0 < x (x ^ k x ^ l x ^ k x ^ l)
@@ -903,48 +1401,151 @@ protected theorem div_pow {a b c : Nat} (h : a b) : (b / a) ^ c = b ^ c / a
rw [Nat.pow_succ (b / a), Nat.pow_succ a, Nat.mul_comm _ a, Nat.mul_assoc, Nat.mul_assoc _ a,
Nat.div_mul_cancel h, Nat.mul_comm b, Nat.mul_assoc, ih, Nat.pow_succ]
/-! ### shiftLeft and shiftRight -/
@[simp] theorem mod_two_not_eq_one : ¬n % 2 = 1 n % 2 = 0 := by
cases mod_two_eq_zero_or_one n <;> simp [*]
@[simp] theorem shiftLeft_zero : n <<< 0 = n := rfl
@[simp] theorem mod_two_not_eq_zero : ¬n % 2 = 0 n % 2 = 1 := by
cases mod_two_eq_zero_or_one n <;> simp [*]
/-- Shiftleft on successor with multiple moved inside. -/
theorem shiftLeft_succ_inside (m n : Nat) : m <<< (n+1) = (2*m) <<< n := rfl
theorem mod_two_ne_one : n % 2 1 n % 2 = 0 := mod_two_not_eq_one
theorem mod_two_ne_zero : n % 2 0 n % 2 = 1 := mod_two_not_eq_zero
/-- Shiftleft on successor with multiple moved to outside. -/
theorem shiftLeft_succ : (m n), m <<< (n + 1) = 2 * (m <<< n)
| _, 0 => rfl
| _, k + 1 => by
rw [shiftLeft_succ_inside _ (k+1)]
rw [shiftLeft_succ _ k, shiftLeft_succ_inside]
/-- Variant of `Nat.lt_div_iff_mul_lt` that assumes `d n`. -/
protected theorem lt_div_iff_mul_lt' (hdn : d n) (a : Nat) : a < n / d d * a < n := by
obtain rfl | hd := d.eq_zero_or_pos
· simp [Nat.zero_dvd.1 hdn]
· rw [ Nat.mul_lt_mul_left hd, Nat.eq_mul_of_div_eq_right hdn rfl]
/-- Shiftright on successor with division moved inside. -/
theorem shiftRight_succ_inside : m n, m >>> (n+1) = (m/2) >>> n
| _, 0 => rfl
| _, k + 1 => by
rw [shiftRight_succ _ (k+1)]
rw [shiftRight_succ_inside _ k, shiftRight_succ]
theorem mul_div_eq_iff_dvd {n d : Nat} : d * (n / d) = n d n :=
calc
d * (n / d) = n d * (n / d) = d * (n / d) + (n % d) := by rw [div_add_mod]
_ d n := by rw [eq_comm, Nat.add_eq_left, dvd_iff_mod_eq_zero]
@[simp] theorem zero_shiftLeft : n, 0 <<< n = 0
| 0 => by simp [shiftLeft]
| n + 1 => by simp [shiftLeft, zero_shiftLeft n, shiftLeft_succ]
theorem mul_div_lt_iff_not_dvd {n d : Nat} : d * (n / d) < n ¬ d n := by
simp [Nat.lt_iff_le_and_ne, mul_div_eq_iff_dvd, mul_div_le]
@[simp] theorem zero_shiftRight : n, 0 >>> n = 0
| 0 => by simp [shiftRight]
| n + 1 => by simp [shiftRight, zero_shiftRight n, shiftRight_succ]
theorem div_eq_iff_eq_of_dvd_dvd (hn : n 0) (ha : a n) (hb : b n) : n / a = n / b a = b := by
constructor <;> intro h
· rw [ Nat.mul_right_inj hn]
apply Nat.eq_mul_of_div_eq_left (Nat.dvd_trans hb (Nat.dvd_mul_right _ _))
rw [eq_comm, Nat.mul_comm, Nat.mul_div_assoc _ hb]
exact Nat.eq_mul_of_div_eq_right ha h
· rw [h]
theorem shiftLeft_add (m n : Nat) : k, m <<< (n + k) = (m <<< n) <<< k
| 0 => rfl
| k + 1 => by simp [ Nat.add_assoc, shiftLeft_add _ _ k, shiftLeft_succ]
theorem le_iff_ne_zero_of_dvd (ha : a 0) (hab : a b) : a b b 0 where
mp := by rw [ Nat.pos_iff_ne_zero] at ha ; exact Nat.lt_of_lt_of_le ha
mpr hb := Nat.le_of_dvd (Nat.pos_iff_ne_zero.2 hb) hab
@[simp] theorem shiftLeft_shiftRight (x n : Nat) : x <<< n >>> n = x := by
rw [Nat.shiftLeft_eq, Nat.shiftRight_eq_div_pow, Nat.mul_div_cancel _ (Nat.two_pow_pos _)]
theorem div_ne_zero_iff_of_dvd (hba : b a) : a / b 0 a 0 b 0 := by
obtain rfl | hb := Decidable.em (b = 0) <;>
simp [Nat.div_ne_zero_iff, Nat.le_iff_ne_zero_of_dvd, *]
theorem pow_mod (a b n : Nat) : a ^ b % n = (a % n) ^ b % n := by
induction b with
| zero => rfl
| succ b ih => simp [Nat.pow_succ, Nat.mul_mod, ih]
theorem lt_of_pow_dvd_right (hb : b 0) (ha : 2 a) (h : a ^ n b) : n < b := by
rw [ Nat.pow_lt_pow_iff_right (succ_le_iff.1 ha)]
exact Nat.lt_of_le_of_lt (le_of_dvd (Nat.pos_iff_ne_zero.2 hb) h) (Nat.lt_pow_self ha)
theorem div_dvd_of_dvd {n m : Nat} (h : n m) : m / n m := n, (Nat.div_mul_cancel h).symm
protected theorem div_div_self (h : n m) (hm : m 0) : m / (m / n) = n := by
rcases h with _, rfl
rw [Nat.mul_ne_zero_iff] at hm
rw [mul_div_right _ (Nat.pos_of_ne_zero hm.1), mul_div_left _ (Nat.pos_of_ne_zero hm.2)]
theorem not_dvd_of_pos_of_lt (h1 : 0 < n) (h2 : n < m) : ¬m n := by
rintro k, rfl
rcases Nat.eq_zero_or_pos k with (rfl | hk)
· exact Nat.lt_irrefl 0 h1
· exact Nat.not_lt.2 (Nat.le_mul_of_pos_right _ hk) h2
theorem eq_of_dvd_of_lt_two_mul (ha : a 0) (hdvd : b a) (hlt : a < 2 * b) : a = b := by
obtain _ | _ | c, rfl := hdvd
· simp at ha
· exact Nat.mul_one _
· rw [Nat.mul_comm] at hlt
cases Nat.not_le_of_lt hlt (Nat.mul_le_mul_right _ (by omega))
theorem mod_eq_iff_lt (hn : n 0) : m % n = m m < n :=
fun h by rw [ h]; exact mod_lt _ <| Nat.pos_iff_ne_zero.2 hn, mod_eq_of_lt
@[simp]
theorem mod_succ_eq_iff_lt {m n : Nat} : m % n.succ = m m < n.succ :=
mod_eq_iff_lt (succ_ne_zero _)
@[simp] theorem mod_succ (n : Nat) : n % n.succ = n := mod_eq_of_lt n.lt_succ_self
theorem mod_add_div' (a b : Nat) : a % b + a / b * b = a := by rw [Nat.mul_comm]; exact mod_add_div _ _
theorem div_add_mod' (a b : Nat) : a / b * b + a % b = a := by rw [Nat.mul_comm]; exact div_add_mod _ _
/-- See also `Nat.divModEquiv` for a similar statement as an `Equiv`. -/
protected theorem div_mod_unique (h : 0 < b) :
a / b = d a % b = c c + b * d = a c < b :=
fun e₁, e₂ e₁ e₂ mod_add_div _ _, mod_lt _ h, fun h₁, h₂ h₁ by
rw [add_mul_div_left _ _ h, add_mul_mod_self_left]; simp [div_eq_of_lt, mod_eq_of_lt, h₂]
/-- If `m` and `n` are equal mod `k`, `m - n` is zero mod `k`. -/
theorem sub_mod_eq_zero_of_mod_eq (h : m % k = n % k) : (m - n) % k = 0 := by
rw [ Nat.mod_add_div m k, Nat.mod_add_div n k, h, Nat.sub_sub,
Nat.add_sub_cancel_left, k.mul_sub, Nat.mul_mod_right]
@[simp] theorem one_mod (n : Nat) : 1 % (n + 2) = 1 :=
Nat.mod_eq_of_lt (Nat.add_lt_add_right n.succ_pos 1)
theorem one_mod_eq_one : {n : Nat}, 1 % n = 1 n 1
| 0 | 1 | n + 2 => by simp; try omega
theorem dvd_sub_mod (k : Nat) : n k - k % n :=
k / n, Nat.sub_eq_of_eq_add (Nat.div_add_mod k n).symm
theorem add_mod_eq_ite {m n : Nat} :
(m + n) % k = if k m % k + n % k then m % k + n % k - k else m % k + n % k := by
cases k with
| zero => simp
| succ k =>
rw [Nat.add_mod]
by_cases h : k + 1 m % (k + 1) + n % (k + 1)
· rw [if_pos h, Nat.mod_eq_sub_mod h, Nat.mod_eq_of_lt]
exact (Nat.sub_lt_iff_lt_add h).mpr (Nat.add_lt_add (m.mod_lt (zero_lt_succ _))
(n.mod_lt (zero_lt_succ _)))
· rw [if_neg h]
exact Nat.mod_eq_of_lt (Nat.lt_of_not_ge h)
-- TODO: Replace `Nat.dvd_add_iff_left`
protected theorem dvd_add_left {a b c : Nat} (h : a c) : a b + c a b := (Nat.dvd_add_iff_left h).symm
protected theorem dvd_add_right {a b c : Nat} (h : a b) : a b + c a c := (Nat.dvd_add_iff_right h).symm
theorem add_mod_eq_add_mod_right (c : Nat) (H : a % d = b % d) : (a + c) % d = (b + c) % d := by
rw [ mod_add_mod, mod_add_mod b, H]
theorem add_mod_eq_add_mod_left (c : Nat) (H : a % d = b % d) : (c + a) % d = (c + b) % d := by
rw [Nat.add_comm, add_mod_eq_add_mod_right _ H, Nat.add_comm]
theorem mul_dvd_of_dvd_div {a b c : Nat} (hcb : c b) (h : a b / c) : c * a b :=
have d, hd := h
d, by simpa [Nat.mul_comm, Nat.mul_left_comm] using Nat.eq_mul_of_div_eq_left hcb hd
theorem eq_of_dvd_of_div_eq_one (hab : a b) (h : b / a = 1) : a = b := by
rw [ Nat.div_mul_cancel hab, h, Nat.one_mul]
theorem eq_zero_of_dvd_of_div_eq_zero (hab : a b) (h : b / a = 0) : b = 0 := by
rw [ Nat.div_mul_cancel hab, h, Nat.zero_mul]
theorem lt_mul_div_succ (a : Nat) (hb : 0 < b) : a < b * (a / b + 1) := by
rw [Nat.mul_comm, Nat.div_lt_iff_lt_mul hb]
exact lt_succ_self _
theorem mul_add_div {m : Nat} (m_pos : m > 0) (x y : Nat) : (m * x + y) / m = x + y / m := by
match x with
| 0 => simp
| x + 1 =>
rw [Nat.mul_succ, Nat.add_assoc _ m, mul_add_div m_pos x (m+y), div_eq]
simp +arith [m_pos]; rw [Nat.add_comm, Nat.add_sub_cancel]
simp +arith [m_pos]
theorem mul_add_mod (m x y : Nat) : (m * x + y) % m = y % m := by
match x with
@@ -952,6 +1553,13 @@ theorem mul_add_mod (m x y : Nat) : (m * x + y) % m = y % m := by
| x + 1 =>
simp [Nat.mul_succ, Nat.add_assoc _ m, mul_add_mod _ x]
-- TODO: make naming and statements consistent across all variations of `mod`, `gcd` etc. across
-- `Nat` and `Int`.
theorem mul_add_mod' (a b c : Nat) : (a * b + c) % b = c % b := by rw [Nat.mul_comm, Nat.mul_add_mod]
theorem mul_add_mod_of_lt {a b c : Nat} (h : c < b) : (a * b + c) % b = c := by
rw [Nat.mul_add_mod', Nat.mod_eq_of_lt h]
@[simp] theorem mod_div_self (m n : Nat) : m % n / n = 0 := by
cases n
· exact (m % 0).div_zero
@@ -1009,6 +1617,113 @@ theorem succ_mod_succ_eq_zero_iff {a b : Nat} :
subst h
simp [Nat.add_mul]
theorem dvd_iff_div_mul_eq (n d : Nat) : d n n / d * d = n :=
fun h => Nat.div_mul_cancel h, fun h => by rw [ h]; exact Nat.dvd_mul_left _ _
theorem dvd_iff_le_div_mul (n d : Nat) : d n n n / d * d :=
((dvd_iff_div_mul_eq _ _).trans Nat.le_antisymm_iff).trans (and_iff_right (div_mul_le_self n d))
theorem dvd_iff_dvd_dvd (n d : Nat) : d n k : Nat, k d k n :=
fun h _ hkd => Nat.dvd_trans hkd h, fun h => h _ (Nat.dvd_refl _)
theorem dvd_div_of_mul_dvd {a b c : Nat} (h : a * b c) : b c / a :=
if ha : a = 0 then by simp [ha]
else
have ha : 0 < a := Nat.pos_of_ne_zero ha
have h1 : d, c = a * b * d := h
let d, hd := h1
have h2 : c / a = b * d := Nat.div_eq_of_eq_mul_right ha (by simpa [Nat.mul_assoc] using hd)
show d, c / a = b * d from d, h2
@[simp] theorem dvd_div_iff_mul_dvd {a b c : Nat} (hbc : c b) : a b / c c * a b :=
fun h => mul_dvd_of_dvd_div hbc h, fun h => dvd_div_of_mul_dvd h
theorem dvd_mul_of_div_dvd {a b c : Nat} (h : b a) (hdiv : a / b c) : a b * c := by
obtain e, rfl := hdiv
rw [ Nat.mul_assoc, Nat.mul_comm _ (a / b), Nat.div_mul_cancel h]
exact Nat.dvd_mul_right a e
@[simp] theorem div_div_div_eq_div {a b c : Nat} (dvd : b a) (dvd2 : a c) : c / (a / b) / b = c / a :=
match a, b, c with
| 0, _, _ => by simp
| a + 1, 0, _ => by simp at dvd
| a + 1, c + 1, _ => by
have a_split : a + 1 0 := succ_ne_zero a
have c_split : c + 1 0 := succ_ne_zero c
rcases dvd2 with k, rfl
rcases dvd with k2, pr
have k2_nonzero : k2 0 := fun k2_zero => by simp [k2_zero] at pr
rw [Nat.mul_div_cancel_left k (Nat.pos_of_ne_zero a_split), pr,
Nat.mul_div_cancel_left k2 (Nat.pos_of_ne_zero c_split), Nat.mul_comm ((c + 1) * k2) k,
Nat.mul_assoc k (c + 1) k2, Nat.mul_div_cancel _ (Nat.pos_of_ne_zero k2_nonzero),
Nat.mul_div_cancel _ (Nat.pos_of_ne_zero c_split)]
/-- If a small natural number is divisible by a larger natural number,
the small number is zero. -/
theorem eq_zero_of_dvd_of_lt (w : a b) (h : b < a) : b = 0 :=
Nat.eq_zero_of_dvd_of_div_eq_zero w (by simp [h])
theorem le_of_lt_add_of_dvd {a b : Nat} (h : a < b + n) : n a n b a b := by
rintro a, rfl b, rfl
rw [ mul_succ] at h
exact Nat.mul_le_mul_left _ (Nat.lt_succ_iff.1 <| Nat.lt_of_mul_lt_mul_left h)
/-- `m` is not divisible by `n` if it is between `n * k` and `n * (k + 1)` for some `k`. -/
theorem not_dvd_of_lt_of_lt_mul_succ (h1 : n * k < m) (h2 : m < n * (k + 1)) : ¬n m := by
rintro d, rfl
have := Nat.lt_of_mul_lt_mul_left h1
have := Nat.lt_of_mul_lt_mul_left h2
omega
/-- `n` is not divisible by `a` iff it is between `a * k` and `a * (k + 1)` for some `k`. -/
theorem not_dvd_iff_lt_mul_succ (n : Nat) {a : Nat} (ha : 0 < a) :
¬a n ( k : Nat, a * k < n n < a * (k + 1)) := by
refine Iff.symm
fun k, hk1, hk2 => not_dvd_of_lt_of_lt_mul_succ hk1 hk2, fun han =>
n / a, Nat.lt_of_le_of_ne (mul_div_le n a) ?_, lt_mul_div_succ _ ha
exact mt (n / a, Eq.symm ·) han
theorem div_lt_div_of_lt_of_dvd {a b d : Nat} (hdb : d b) (h : a < b) : a / d < b / d := by
rw [Nat.lt_div_iff_mul_lt' hdb]
exact Nat.lt_of_le_of_lt (mul_div_le a d) h
/-! ### shiftLeft and shiftRight -/
@[simp] theorem shiftLeft_zero : n <<< 0 = n := rfl
/-- Shiftleft on successor with multiple moved inside. -/
theorem shiftLeft_succ_inside (m n : Nat) : m <<< (n+1) = (2*m) <<< n := rfl
/-- Shiftleft on successor with multiple moved to outside. -/
theorem shiftLeft_succ : (m n), m <<< (n + 1) = 2 * (m <<< n)
| _, 0 => rfl
| _, k + 1 => by
rw [shiftLeft_succ_inside _ (k+1)]
rw [shiftLeft_succ _ k, shiftLeft_succ_inside]
/-- Shiftright on successor with division moved inside. -/
theorem shiftRight_succ_inside : m n, m >>> (n+1) = (m/2) >>> n
| _, 0 => rfl
| _, k + 1 => by
rw [shiftRight_succ _ (k+1)]
rw [shiftRight_succ_inside _ k, shiftRight_succ]
@[simp] theorem zero_shiftLeft : n, 0 <<< n = 0
| 0 => by simp [shiftLeft]
| n + 1 => by simp [shiftLeft, zero_shiftLeft n, shiftLeft_succ]
@[simp] theorem zero_shiftRight : n, 0 >>> n = 0
| 0 => by simp [shiftRight]
| n + 1 => by simp [shiftRight, zero_shiftRight n, shiftRight_succ]
theorem shiftLeft_add (m n : Nat) : k, m <<< (n + k) = (m <<< n) <<< k
| 0 => rfl
| k + 1 => by simp [ Nat.add_assoc, shiftLeft_add _ _ k, shiftLeft_succ]
@[simp] theorem shiftLeft_shiftRight (x n : Nat) : x <<< n >>> n = x := by
rw [Nat.shiftLeft_eq, Nat.shiftRight_eq_div_pow, Nat.mul_div_cancel _ (Nat.two_pow_pos _)]
/-! ### Decidability of predicates -/
instance decidableBallLT :

View File

@@ -146,7 +146,7 @@ instance : LawfulBEq PolyCnstr where
rfl {a} := by
cases a; rename_i eq lhs rhs
show (eq == eq && (lhs == lhs && rhs == rhs)) = true
simp [LawfulBEq.rfl]
simp
structure ExprCnstr where
eq : Bool

View File

@@ -52,8 +52,8 @@ protected theorem min_le_right (a b : Nat) : min a b ≤ b := by
protected theorem min_le_left (a b : Nat) : min a b a :=
Nat.min_comm .. Nat.min_le_right ..
protected theorem min_eq_left {a b : Nat} (h : a b) : min a b = a := if_pos h
protected theorem min_eq_right {a b : Nat} (h : b a) : min a b = b :=
@[simp] protected theorem min_eq_left {a b : Nat} (h : a b) : min a b = a := if_pos h
@[simp] protected theorem min_eq_right {a b : Nat} (h : b a) : min a b = b :=
Nat.min_comm .. Nat.min_eq_left h
protected theorem le_min_of_le_of_le {a b c : Nat} : a b a c a min b c := by
@@ -111,9 +111,9 @@ protected theorem le_max_left (a b : Nat) : a ≤ max a b := by
protected theorem le_max_right (a b : Nat) : b max a b :=
Nat.max_comm .. Nat.le_max_left ..
protected theorem max_eq_right {a b : Nat} (h : a b) : max a b = b := if_pos h
@[simp] protected theorem max_eq_right {a b : Nat} (h : a b) : max a b = b := if_pos h
protected theorem max_eq_left {a b : Nat} (h : b a) : max a b = a :=
@[simp] protected theorem max_eq_left {a b : Nat} (h : b a) : max a b = a :=
Nat.max_comm .. Nat.max_eq_right h
protected theorem max_le_of_le_of_le {a b c : Nat} : a c b c max a b c := by

View File

@@ -141,11 +141,11 @@ theorem toList_attach (o : Option α) :
cases o <;> simp
theorem attach_map {o : Option α} (f : α β) :
(o.map f).attach = o.attach.map (fun x, h => f x, map_eq_some.2 _, h, rfl) := by
(o.map f).attach = o.attach.map (fun x, h => f x, map_eq_some_iff.2 _, h, rfl) := by
cases o <;> simp
theorem attachWith_map {o : Option α} (f : α β) {P : β Prop} {H : (b : β), o.map f = some b P b} :
(o.map f).attachWith P H = (o.attachWith (P f) (fun _ h => H _ (map_eq_some.2 _, h, rfl))).map
(o.map f).attachWith P H = (o.attachWith (P f) (fun _ h => H _ (map_eq_some_iff.2 _, h, rfl))).map
fun x, h => f x, h := by
cases o <;> simp
@@ -174,7 +174,7 @@ theorem map_attach_eq_attachWith {o : Option α} {p : α → Prop} (f : ∀ a, o
theorem attach_bind {o : Option α} {f : α Option β} :
(o.bind f).attach =
o.attach.bind fun x, h => (f x).attach.map fun y, h' => y, bind_eq_some.2 _, h, h' := by
o.attach.bind fun x, h => (f x).attach.map fun y, h' => y, bind_eq_some_iff.2 _, h, h' := by
cases o <;> simp
theorem bind_attach {o : Option α} {f : {x // o = some x} Option β} :
@@ -262,7 +262,7 @@ and simplifies these to the function directly taking the value.
@[simp] theorem bind_subtype {p : α Prop} {o : Option { x // p x }}
{f : { x // p x } Option β} {g : α Option β} (hf : x h, f x, h = g x) :
(o.bind f) = o.unattach.bind g := by
o.bind f = o.unattach.bind g := by
cases o <;> simp [hf]
@[simp] theorem unattach_filter {p : α Prop} {o : Option { x // p x }}

View File

@@ -231,13 +231,12 @@ def merge (fn : ααα) : Option α → Option α → Option α
@[simp] theorem getD_none : getD none a = a := rfl
@[simp] theorem getD_some : getD (some a) b = a := rfl
@[simp] theorem map_none' (f : α β) : none.map f = none := rfl
@[simp] theorem map_some' (a) (f : α β) : (some a).map f = some (f a) := rfl
@[simp] theorem map_none (f : α β) : none.map f = none := rfl
@[simp] theorem map_some (a) (f : α β) : (some a).map f = some (f a) := rfl
@[simp] theorem none_bind (f : α Option β) : none.bind f = none := rfl
@[simp] theorem some_bind (a) (f : α Option β) : (some a).bind f = f a := rfl
/--
A case analysis function for `Option`.
@@ -387,11 +386,13 @@ This is the monadic analogue of `Option.getD`.
| some a => pure a
| none => y
instance (α) [BEq α] [LawfulBEq α] : LawfulBEq (Option α) where
instance (α) [BEq α] [ReflBEq α] : ReflBEq (Option α) where
rfl {x} :=
match x with
| some _ => LawfulBEq.rfl (α := α)
| some _ => BEq.rfl (α := α)
| none => rfl
instance (α) [BEq α] [LawfulBEq α] : LawfulBEq (Option α) where
eq_of_beq {x y h} := by
match x, y with
| some x, some y => rw [LawfulBEq.eq_of_beq (α := α) h]

View File

@@ -39,18 +39,24 @@ This is not an instance because it is not definitionally equal to the standard i
Try to use the Boolean comparisons `Option.isNone` or `Option.isSome` instead.
-/
@[inline] def decidable_eq_none {o : Option α} : Decidable (o = none) :=
@[inline] def decidableEqNone {o : Option α} : Decidable (o = none) :=
decidable_of_decidable_of_iff isNone_iff_eq_none
instance {p : α Prop} [DecidablePred p] : o : Option α, Decidable ( a, a o p a)
| none => isTrue nofun
| some a =>
if h : p a then isTrue fun _ e => some_inj.1 e h
else isFalse <| mt (· _ rfl) h
@[deprecated decidableEqNone (since := "2025-04-10"), inline]
def decidable_eq_none {o : Option α} : Decidable (o = none) :=
decidableEqNone
instance {p : α Prop} [DecidablePred p] : o : Option α, Decidable (Exists fun a => a o p a)
| none => isFalse nofun
| some a => if h : p a then isTrue _, rfl, h else isFalse fun _, rfl, hn => h hn
instance decidableForallMem {p : α Prop} [DecidablePred p] :
o : Option α, Decidable ( a, a o p a)
| none => isTrue nofun
| some a =>
if h : p a then isTrue fun _ e => some_inj.1 e h
else isFalse <| mt (· _ rfl) h
instance decidableExistsMem {p : α Prop} [DecidablePred p] :
o : Option α, Decidable (Exists fun a => a o p a)
| none => isFalse nofun
| some a => if h : p a then isTrue _, rfl, h else isFalse fun _, rfl, hn => h hn
/--
Given an optional value and a function that can be applied when the value is `some`, returns the

View File

@@ -17,6 +17,8 @@ theorem mem_iff {a : α} {b : Option α} : a ∈ b ↔ b = some a := .rfl
theorem mem_some {a b : α} : a some b b = a := by simp
theorem mem_some_iff {a b : α} : a some b b = a := mem_some
theorem mem_some_self (a : α) : a some a := rfl
theorem some_ne_none (x : α) : some x none := nofun
@@ -29,6 +31,9 @@ protected theorem «exists» {p : Option α → Prop} :
fun | none, hx => .inl hx | some x, hx => .inr x, hx,
fun | .inl h => _, h | .inr _, hx => _, hx
theorem eq_none_or_eq_some (a : Option α) : a = none x, a = some x :=
Option.exists.mp exists_eq'
theorem get_mem : {o : Option α} (h : isSome o), o.get h o
| some _, _ => rfl
@@ -88,6 +93,9 @@ set_option Elab.async false
theorem eq_none_iff_forall_ne_some : o = none a, o some a := by
cases o <;> simp
theorem eq_none_iff_forall_some_ne : o = none a, some a o := by
cases o <;> simp
theorem eq_none_iff_forall_not_mem : o = none a, a o :=
eq_none_iff_forall_ne_some
@@ -102,9 +110,30 @@ theorem isSome_of_mem {x : Option α} {y : α} (h : y ∈ x) : x.isSome := by
theorem isSome_of_eq_some {x : Option α} {y : α} (h : x = some y) : x.isSome := by
cases x <;> trivial
@[simp] theorem not_isSome : isSome a = false a.isNone = true := by
@[simp] theorem isSome_eq_false_iff : isSome a = false a.isNone = true := by
cases a <;> simp
@[simp] theorem isNone_eq_false_iff : isNone a = false a.isSome = true := by
cases a <;> simp
@[simp]
theorem not_isSome (a : Option α) : (!a.isSome) = a.isNone := by
cases a <;> simp
@[simp]
theorem not_comp_isSome : (! ·) @Option.isSome α = Option.isNone := by
funext
simp
@[simp]
theorem not_isNone (a : Option α) : (!a.isNone) = a.isSome := by
cases a <;> simp
@[simp]
theorem not_comp_isNone : (!·) @Option.isNone α = Option.isSome := by
funext x
simp
theorem eq_some_iff_get_eq : o = some a h : o.isSome, o.get h = a := by
cases o <;> simp
@@ -146,17 +175,25 @@ abbrev ball_ne_none := @forall_ne_none
@[simp] theorem bind_eq_bind : bind = @Option.bind α β := rfl
@[simp] theorem orElse_eq_orElse : HOrElse.hOrElse = @Option.orElse α := rfl
@[simp] theorem bind_some (x : Option α) : x.bind some = x := by cases x <;> rfl
@[simp] theorem bind_none (x : Option α) : x.bind (fun _ => none (α := β)) = none := by
cases x <;> rfl
theorem bind_eq_some : x.bind f = some b a, x = some a f a = some b := by
theorem bind_eq_some_iff : x.bind f = some b a, x = some a f a = some b := by
cases x <;> simp
@[simp] theorem bind_eq_none {o : Option α} {f : α Option β} :
@[deprecated bind_eq_some_iff (since := "2025-04-10")]
abbrev bind_eq_some := @bind_eq_some_iff
@[simp] theorem bind_eq_none_iff {o : Option α} {f : α Option β} :
o.bind f = none a, o = some a f a = none := by cases o <;> simp
@[deprecated bind_eq_none_iff (since := "2025-04-10")]
abbrev bind_eq_none := @bind_eq_none_iff
theorem bind_eq_none' {o : Option α} {f : α Option β} :
o.bind f = none b a, o = some a f a some b := by
cases o <;> simp [eq_none_iff_forall_ne_some]
@@ -193,50 +230,67 @@ theorem isSome_apply_of_isSome_bind {α β : Type _} {x : Option α} {f : α
(isSome_apply_of_isSome_bind h) := by
cases x <;> trivial
theorem join_eq_some : x.join = some a x = some (some a) := by
simp [bind_eq_some]
theorem join_eq_some_iff : x.join = some a x = some (some a) := by
simp [bind_eq_some_iff]
@[deprecated join_eq_some_iff (since := "2025-04-10")]
abbrev join_eq_some := @join_eq_some_iff
theorem join_ne_none : x.join none z, x = some (some z) := by
simp only [ne_none_iff_exists', join_eq_some, iff_self]
simp only [ne_none_iff_exists', join_eq_some_iff, iff_self]
theorem join_ne_none' : ¬x.join = none z, x = some (some z) :=
join_ne_none
theorem join_eq_none : o.join = none o = none o = some none :=
theorem join_eq_none_iff : o.join = none o = none o = some none :=
match o with | none | some none | some (some _) => by simp
@[deprecated join_eq_none_iff (since := "2025-04-10")]
abbrev join_eq_none := @join_eq_none_iff
theorem bind_id_eq_join {x : Option (Option α)} : x.bind id = x.join := rfl
@[simp] theorem map_eq_map : Functor.map f = Option.map f := rfl
theorem map_none : f <$> none = none := rfl
@[deprecated map_none (since := "2025-04-10")]
abbrev map_none' := @map_none
theorem map_some : f <$> some a = some (f a) := rfl
@[deprecated map_some (since := "2025-04-10")]
abbrev map_some' := @map_some
@[simp] theorem map_eq_some' : x.map f = some b a, x = some a f a = b := by cases x <;> simp
theorem map_eq_some : f <$> x = some b a, x = some a f a = b := map_eq_some'
@[simp] theorem map_eq_none' : x.map f = none x = none := by
cases x <;> simp [map_none', map_some', eq_self_iff_true]
theorem isSome_map {x : Option α} : (f <$> x).isSome = x.isSome := by
@[simp] theorem map_eq_some_iff : x.map f = some b a, x = some a f a = b := by
cases x <;> simp
@[simp] theorem isSome_map' {x : Option α} : (x.map f).isSome = x.isSome := by
@[deprecated map_eq_some_iff (since := "2025-04-10")]
abbrev map_eq_some := @map_eq_some_iff
@[deprecated map_eq_some_iff (since := "2025-04-10")]
abbrev map_eq_some' := @map_eq_some_iff
@[simp] theorem map_eq_none_iff : x.map f = none x = none := by
cases x <;> simp [map_none, map_some, eq_self_iff_true]
@[deprecated map_eq_none_iff (since := "2025-04-10")]
abbrev map_eq_none := @map_eq_none_iff
@[deprecated map_eq_none_iff (since := "2025-04-10")]
abbrev map_eq_none' := @map_eq_none_iff
@[simp] theorem isSome_map {x : Option α} : (x.map f).isSome = x.isSome := by
cases x <;> simp
@[simp] theorem isNone_map' {x : Option α} : (x.map f).isNone = x.isNone := by
cases x <;> simp
@[deprecated isSome_map (since := "2025-04-10")]
abbrev isSome_map' := @isSome_map
theorem map_eq_none : f <$> x = none x = none := map_eq_none'
@[simp] theorem isNone_map {x : Option α} : (x.map f).isNone = x.isNone := by
cases x <;> simp
theorem map_eq_bind {x : Option α} : x.map f = x.bind (some f) := by
cases x <;> simp [Option.bind]
theorem map_congr {x : Option α} (h : a, x = some a f a = g a) :
x.map f = x.map g := by
cases x <;> simp only [map_none', map_some', h]
cases x <;> simp only [map_none, map_some, h]
@[simp] theorem map_id_fun {α : Type u} : Option.map (id : α α) = id := by
funext; simp [map_id]
@@ -254,7 +308,7 @@ theorem get_map {f : α → β} {o : Option α} {h : (o.map f).isSome} :
@[simp] theorem map_map (h : β γ) (g : α β) (x : Option α) :
(x.map g).map h = x.map (h g) := by
cases x <;> simp only [map_none', map_some', ··]
cases x <;> simp only [map_none, map_some, ··]
theorem comp_map (h : β γ) (g : α β) (x : Option α) : x.map (h g) = (x.map g).map h :=
(map_map ..).symm
@@ -262,7 +316,7 @@ theorem comp_map (h : β → γ) (g : α → β) (x : Option α) : x.map (h ∘
@[simp] theorem map_comp_map (f : α β) (g : β γ) :
Option.map g Option.map f = Option.map (g f) := by funext x; simp
theorem mem_map_of_mem (g : α β) (h : a x) : g a Option.map g x := h.symm map_some' ..
theorem mem_map_of_mem (g : α β) (h : a x) : g a Option.map g x := h.symm map_some ..
theorem map_inj_right {f : α β} {o o' : Option α} (w : x y, f x = f y x = y) :
o.map f = o'.map f o = o' := by
@@ -292,11 +346,14 @@ theorem isSome_of_isSome_filter (p : α → Bool) (o : Option α) (h : (o.filter
@[deprecated isSome_of_isSome_filter (since := "2025-03-18")]
abbrev isSome_filter_of_isSome := @isSome_of_isSome_filter
@[simp] theorem filter_eq_none {o : Option α} {p : α Bool} :
@[simp] theorem filter_eq_none_iff {o : Option α} {p : α Bool} :
o.filter p = none a, o = some a ¬ p a := by
cases o <;> simp [filter_some]
@[simp] theorem filter_eq_some {o : Option α} {p : α Bool} :
@[deprecated filter_eq_none_iff (since := "2025-04-10")]
abbrev filter_eq_none := @filter_eq_none_iff
@[simp] theorem filter_eq_some_iff {o : Option α} {p : α Bool} :
o.filter p = some a o = some a p a := by
cases o with
| none => simp
@@ -310,6 +367,9 @@ abbrev isSome_filter_of_isSome := @isSome_of_isSome_filter
rintro rfl
simpa using h
@[deprecated filter_eq_some_iff (since := "2025-04-10")]
abbrev filter_eq_some := @filter_eq_some_iff
theorem mem_filter_iff {p : α Bool} {a : α} {o : Option α} :
a o.filter p a o p a := by
simp
@@ -383,29 +443,43 @@ theorem join_join {x : Option (Option (Option α))} : x.join.join = (x.map join)
cases x <;> simp
theorem mem_of_mem_join {a : α} {x : Option (Option α)} (h : a x.join) : some a x :=
h.symm join_eq_some.1 h
h.symm join_eq_some_iff.1 h
@[simp] theorem some_orElse (a : α) (x : Option α) : (some a <|> x) = some a := rfl
@[simp] theorem some_orElse (a : α) (f) : (some a).orElse f = some a := rfl
@[simp] theorem none_orElse (x : Option α) : (none <|> x) = x := rfl
@[simp] theorem none_orElse (f : Unit Option α) : none.orElse f = f () := rfl
@[simp] theorem orElse_none (x : Option α) : (x <|> none) = x := by cases x <;> rfl
@[simp] theorem orElse_none (x : Option α) : x.orElse (fun _ => none) = x := by cases x <;> rfl
theorem map_orElse {x y : Option α} : (x <|> y).map f = (x.map f <|> y.map f) := by
theorem orElse_eq_some_iff (o : Option α) (f) (x : α) :
(o.orElse f) = some x o = some x o = none f () = some x := by
cases o <;> simp
theorem orElse_eq_none_iff (o : Option α) (f) : (o.orElse f) = none o = none f () = none := by
cases o <;> simp
theorem map_orElse {x : Option α} {y} :
(x.orElse y).map f = (x.map f).orElse (fun _ => (y ()).map f) := by
cases x <;> simp
@[simp] theorem guard_eq_some [DecidablePred p] : guard p a = some b a = b p a :=
@[simp] theorem guard_eq_some_iff [DecidablePred p] : guard p a = some b a = b p a :=
if h : p a then by simp [Option.guard, h] else by simp [Option.guard, h]
@[deprecated guard_eq_some_iff (since := "2025-04-10")]
abbrev guard_eq_some := @guard_eq_some_iff
@[simp] theorem isSome_guard [DecidablePred p] : (Option.guard p a).isSome p a :=
if h : p a then by simp [Option.guard, h] else by simp [Option.guard, h]
@[deprecated isSome_guard (since := "2025-03-18")]
abbrev guard_isSome := @isSome_guard
@[simp] theorem guard_eq_none [DecidablePred p] : Option.guard p a = none ¬ p a :=
@[simp] theorem guard_eq_none_iff [DecidablePred p] : Option.guard p a = none ¬ p a :=
if h : p a then by simp [Option.guard, h] else by simp [Option.guard, h]
@[deprecated guard_eq_none_iff (since := "2025-04-10")]
abbrev guard_eq_none := @guard_eq_none_iff
@[simp] theorem guard_pos [DecidablePred p] (h : p a) : Option.guard p a = some a := by
simp [Option.guard, h]
@@ -475,6 +549,22 @@ theorem liftOrGet_none_right {f} {a : Option α} : merge f a none = a :=
theorem liftOrGet_some_some {f} {a b : α} : merge f (some a) (some b) = f a b :=
merge_some_some
instance commutative_merge (f : α α α) [Std.Commutative f] :
Std.Commutative (merge f) :=
fun a b by cases a <;> cases b <;> simp [merge, Std.Commutative.comm]
instance associative_merge (f : α α α) [Std.Associative f] :
Std.Associative (merge f) :=
fun a b c by cases a <;> cases b <;> cases c <;> simp [merge, Std.Associative.assoc]
instance idempotentOp_merge (f : α α α) [Std.IdempotentOp f] :
Std.IdempotentOp (merge f) :=
fun a by cases a <;> simp [merge, Std.IdempotentOp.idempotent]
instance lawfulIdentity_merge (f : α α α) : Std.LawfulIdentity (merge f) none where
left_id a := by cases a <;> simp [merge]
right_id a := by cases a <;> simp [merge]
@[simp] theorem elim_none (x : β) (f : α β) : none.elim x f = x := rfl
@[simp] theorem elim_some (x : β) (f : α β) (a : α) : (some a).elim x f = f a := rfl
@@ -535,12 +625,18 @@ theorem or_eq_bif : or o o' = bif o.isSome then o else o' := by
@[simp] theorem isNone_or : (or o o').isNone = (o.isNone && o'.isNone) := by
cases o <;> rfl
@[simp] theorem or_eq_none : or o o' = none o = none o' = none := by
@[simp] theorem or_eq_none_iff : or o o' = none o = none o' = none := by
cases o <;> simp
@[simp] theorem or_eq_some : or o o' = some a o = some a (o = none o' = some a) := by
@[deprecated or_eq_none_iff (since := "2025-04-10")]
abbrev or_eq_none := @or_eq_none_iff
@[simp] theorem or_eq_some_iff : or o o' = some a o = some a (o = none o' = some a) := by
cases o <;> simp
@[deprecated or_eq_some_iff (since := "2025-04-10")]
abbrev or_eq_some := @or_eq_some_iff
theorem or_assoc : or (or o₁ o₂) o₃ = or o₁ (or o₂ o₃) := by
cases o₁ <;> cases o₂ <;> rfl
instance : Std.Associative (or (α := α)) := @or_assoc _
@@ -564,11 +660,11 @@ instance : Std.IdempotentOp (or (α := α)) := ⟨@or_self _⟩
theorem or_eq_orElse : or o o' = o.orElse (fun _ => o') := by
cases o <;> rfl
theorem map_or : f <$> or o o' = (f <$> o).or (f <$> o') := by
theorem map_or : (or o o').map f = (o.map f).or (o'.map f) := by
cases o <;> rfl
theorem map_or' : (or o o').map f = (o.map f).or (o'.map f) := by
cases o <;> rfl
@[deprecated map_or (since := "2025-04-10")]
abbrev map_or' := @map_or
theorem or_of_isSome {o o' : Option α} (h : o.isSome) : o.or o' = o := by
match o, h with
@@ -598,27 +694,19 @@ variable [BEq α]
simpa only [some_beq_some]
simp
· intro h
constructor
· rintro (_ | a) <;> simp
infer_instance
@[simp] theorem lawfulBEq_iff : LawfulBEq (Option α) LawfulBEq α := by
constructor
· intro h
have : ReflBEq α := reflBEq_iff.mp inferInstance
constructor
· intro a b h
apply Option.some.inj
apply eq_of_beq
simpa
· intro a
suffices (some a == some a) = true by
simpa only [some_beq_some]
simp
intro a b h
apply Option.some.inj
apply eq_of_beq
simpa
· intro h
constructor
· intro a b h
simpa using h
· intro a
simp
infer_instance
end beq
@@ -804,7 +892,7 @@ theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (o H)
theorem pmap_map (o : Option α) (f : α β) {p : β Prop} (g : b, p b γ) (H) :
pmap g (o.map f) H =
pmap (fun a h => g (f a) h) o (fun a m => H (f a) (map_eq_some.2 _, m, rfl)) := by
pmap (fun a h => g (f a) h) o (fun a m => H (f a) (map_eq_some_iff.2 _, m, rfl)) := by
cases o <;> simp
theorem pmap_pred_congr {α : Type u}

View File

@@ -9,11 +9,13 @@ import Init.NotationExtra
namespace Prod
instance [BEq α] [BEq β] [ReflBEq α] [ReflBEq β] : ReflBEq (α × β) where
rfl {a} := by cases a; simp [BEq.beq]
instance [BEq α] [BEq β] [LawfulBEq α] [LawfulBEq β] : LawfulBEq (α × β) where
eq_of_beq {a b} (h : a.1 == b.1 && a.2 == b.2) := by
cases a; cases b
refine congr (congrArg _ (eq_of_beq ?_)) (eq_of_beq ?_) <;> simp_all
rfl {a} := by cases a; simp [BEq.beq, LawfulBEq.rfl]
@[simp]
protected theorem «forall» {p : α × β Prop} : ( x, p x) a b, p (a, b) :=

View File

@@ -239,6 +239,17 @@ Examples:
@[extern "lean_int8_div"]
protected def Int8.div (a b : Int8) : Int8 := BitVec.sdiv a.toBitVec b.toBitVec
/--
The power operation, raising an 8-bit signed integer to a natural number power,
wrapping around on overflow. Usually accessed via the `^` operator.
This function is currently *not* overridden at runtime with an efficient implementation,
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
-/
protected def Int8.pow (x : Int8) (n : Nat) : Int8 :=
match n with
| 0 => 1
| n + 1 => Int8.mul (Int8.pow x n) x
/--
The modulo operator for 8-bit signed integers, which computes the remainder when dividing one
integer by another with the T-rounding convention used by `Int8.div`. Usually accessed via the `%`
operator.
@@ -366,6 +377,7 @@ instance : Inhabited Int8 where
instance : Add Int8 := Int8.add
instance : Sub Int8 := Int8.sub
instance : Mul Int8 := Int8.mul
instance : Pow Int8 Nat := Int8.pow
instance : Mod Int8 := Int8.mod
instance : Div Int8 := Int8.div
instance : LT Int8 := Int8.lt
@@ -598,6 +610,17 @@ Examples:
@[extern "lean_int16_div"]
protected def Int16.div (a b : Int16) : Int16 := BitVec.sdiv a.toBitVec b.toBitVec
/--
The power operation, raising a 16-bit signed integer to a natural number power,
wrapping around on overflow. Usually accessed via the `^` operator.
This function is currently *not* overridden at runtime with an efficient implementation,
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
-/
protected def Int16.pow (x : Int16) (n : Nat) : Int16 :=
match n with
| 0 => 1
| n + 1 => Int16.mul (Int16.pow x n) x
/--
The modulo operator for 16-bit signed integers, which computes the remainder when dividing one
integer by another with the T-rounding convention used by `Int16.div`. Usually accessed via the `%`
operator.
@@ -725,6 +748,7 @@ instance : Inhabited Int16 where
instance : Add Int16 := Int16.add
instance : Sub Int16 := Int16.sub
instance : Mul Int16 := Int16.mul
instance : Pow Int16 Nat := Int16.pow
instance : Mod Int16 := Int16.mod
instance : Div Int16 := Int16.div
instance : LT Int16 := Int16.lt
@@ -973,6 +997,17 @@ Examples:
@[extern "lean_int32_div"]
protected def Int32.div (a b : Int32) : Int32 := BitVec.sdiv a.toBitVec b.toBitVec
/--
The power operation, raising a 32-bit signed integer to a natural number power,
wrapping around on overflow. Usually accessed via the `^` operator.
This function is currently *not* overridden at runtime with an efficient implementation,
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
-/
protected def Int32.pow (x : Int32) (n : Nat) : Int32 :=
match n with
| 0 => 1
| n + 1 => Int32.mul (Int32.pow x n) x
/--
The modulo operator for 32-bit signed integers, which computes the remainder when dividing one
integer by another with the T-rounding convention used by `Int32.div`. Usually accessed via the `%`
operator.
@@ -1100,6 +1135,7 @@ instance : Inhabited Int32 where
instance : Add Int32 := Int32.add
instance : Sub Int32 := Int32.sub
instance : Mul Int32 := Int32.mul
instance : Pow Int32 Nat := Int32.pow
instance : Mod Int32 := Int32.mod
instance : Div Int32 := Int32.div
instance : LT Int32 := Int32.lt
@@ -1368,6 +1404,17 @@ Examples:
@[extern "lean_int64_div"]
protected def Int64.div (a b : Int64) : Int64 := BitVec.sdiv a.toBitVec b.toBitVec
/--
The power operation, raising a 64-bit signed integer to a natural number power,
wrapping around on overflow. Usually accessed via the `^` operator.
This function is currently *not* overridden at runtime with an efficient implementation,
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
-/
protected def Int64.pow (x : Int64) (n : Nat) : Int64 :=
match n with
| 0 => 1
| n + 1 => Int64.mul (Int64.pow x n) x
/--
The modulo operator for 64-bit signed integers, which computes the remainder when dividing one
integer by another with the T-rounding convention used by `Int64.div`. Usually accessed via the `%`
operator.
@@ -1495,6 +1542,7 @@ instance : Inhabited Int64 where
instance : Add Int64 := Int64.add
instance : Sub Int64 := Int64.sub
instance : Mul Int64 := Int64.mul
instance : Pow Int64 Nat := Int64.pow
instance : Mod Int64 := Int64.mod
instance : Div Int64 := Int64.div
instance : LT Int64 := Int64.lt
@@ -1746,6 +1794,17 @@ Examples:
@[extern "lean_isize_div"]
protected def ISize.div (a b : ISize) : ISize := BitVec.sdiv a.toBitVec b.toBitVec
/--
The power operation, raising a word-sized signed integer to a natural number power,
wrapping around on overflow. Usually accessed via the `^` operator.
This function is currently *not* overridden at runtime with an efficient implementation,
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
-/
protected def ISize.pow (x : ISize) (n : Nat) : ISize :=
match n with
| 0 => 1
| n + 1 => ISize.mul (ISize.pow x n) x
/--
The modulo operator for word-sized signed integers, which computes the remainder when dividing one
integer by another with the T-rounding convention used by `ISize.div`. Usually accessed via the `%`
operator.
@@ -1875,6 +1934,7 @@ instance : Inhabited ISize where
instance : Add ISize := ISize.add
instance : Sub ISize := ISize.sub
instance : Mul ISize := ISize.mul
instance : Pow ISize Nat := ISize.pow
instance : Mod ISize := ISize.mod
instance : Div ISize := ISize.div
instance : LT ISize := ISize.lt

View File

@@ -183,18 +183,18 @@ theorem ISize.neg_ofNat {n : Nat} : -ofNat n = ofInt (-n) := by
rw [ neg_ofInt, ofInt_eq_ofNat]
theorem Int8.toNatClampNeg_ofNat_of_lt {n : Nat} (h : n < 2 ^ 7) : toNatClampNeg (ofNat n) = n := by
rw [toNatClampNeg, ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_ofNat]
rw [toNatClampNeg, ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_natCast]
theorem Int16.toNatClampNeg_ofNat_of_lt {n : Nat} (h : n < 2 ^ 15) : toNatClampNeg (ofNat n) = n := by
rw [toNatClampNeg, ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_ofNat]
rw [toNatClampNeg, ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_natCast]
theorem Int32.toNatClampNeg_ofNat_of_lt {n : Nat} (h : n < 2 ^ 31) : toNatClampNeg (ofNat n) = n := by
rw [toNatClampNeg, ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_ofNat]
rw [toNatClampNeg, ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_natCast]
theorem Int64.toNatClampNeg_ofNat_of_lt {n : Nat} (h : n < 2 ^ 63) : toNatClampNeg (ofNat n) = n := by
rw [toNatClampNeg, ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_ofNat]
rw [toNatClampNeg, ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_natCast]
theorem ISize.toNatClampNeg_ofNat_of_lt {n : Nat} (h : n < 2 ^ 31) : toNatClampNeg (ofNat n) = n := by
rw [toNatClampNeg, ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_ofNat]
rw [toNatClampNeg, ofInt_eq_ofNat, toInt_ofInt_of_le (by omega) (by omega), Int.toNat_natCast]
theorem ISize.toNatClampNeg_ofNat_of_lt_two_pow_numBits {n : Nat} (h : n < 2 ^ (System.Platform.numBits - 1)) :
toNatClampNeg (ofNat n) = n := by
rw [toNatClampNeg, ofInt_eq_ofNat, toInt_ofInt_of_two_pow_numBits_le, Int.toNat_ofNat]
rw [toNatClampNeg, ofInt_eq_ofNat, toInt_ofInt_of_two_pow_numBits_le, Int.toNat_natCast]
· cases System.Platform.numBits_eq <;> simp_all <;> omega
· cases System.Platform.numBits_eq <;> simp_all <;> omega
@@ -537,41 +537,41 @@ theorem ISize.toFin_toBitVec (x : ISize) : x.toBitVec.toFin = x.toUSize.toFin :=
@[simp] theorem Int64.toBitVec_ofIntLE (x : Int) (h₁ h₂) : (Int64.ofIntLE x h₁ h₂).toBitVec = BitVec.ofInt 64 x := rfl
@[simp] theorem ISize.toBitVec_ofIntLE (x : Int) (h₁ h₂) : (ISize.ofIntLE x h₁ h₂).toBitVec = BitVec.ofInt System.Platform.numBits x := rfl
@[simp] theorem Int8.toInt_bmod (x : Int8) : x.toInt.bmod 256 = x.toInt := Int.bmod_eq_self_of_le x.le_toInt x.toInt_lt
@[simp] theorem Int16.toInt_bmod (x : Int16) : x.toInt.bmod 65536 = x.toInt := Int.bmod_eq_self_of_le x.le_toInt x.toInt_lt
@[simp] theorem Int32.toInt_bmod (x : Int32) : x.toInt.bmod 4294967296 = x.toInt := Int.bmod_eq_self_of_le x.le_toInt x.toInt_lt
@[simp] theorem Int64.toInt_bmod (x : Int64) : x.toInt.bmod 18446744073709551616 = x.toInt := Int.bmod_eq_self_of_le x.le_toInt x.toInt_lt
@[simp] theorem Int8.toInt_bmod (x : Int8) : x.toInt.bmod 256 = x.toInt := Int.bmod_eq_of_le x.le_toInt x.toInt_lt
@[simp] theorem Int16.toInt_bmod (x : Int16) : x.toInt.bmod 65536 = x.toInt := Int.bmod_eq_of_le x.le_toInt x.toInt_lt
@[simp] theorem Int32.toInt_bmod (x : Int32) : x.toInt.bmod 4294967296 = x.toInt := Int.bmod_eq_of_le x.le_toInt x.toInt_lt
@[simp] theorem Int64.toInt_bmod (x : Int64) : x.toInt.bmod 18446744073709551616 = x.toInt := Int.bmod_eq_of_le x.le_toInt x.toInt_lt
@[simp] theorem ISize.toInt_bmod_two_pow_numBits (x : ISize) : x.toInt.bmod (2 ^ System.Platform.numBits) = x.toInt := by
refine Int.bmod_eq_self_of_le ?_ ?_
refine Int.bmod_eq_of_le ?_ ?_
· have := x.two_pow_numBits_le_toInt
cases System.Platform.numBits_eq <;> simp_all
· have := x.toInt_lt_two_pow_numBits
cases System.Platform.numBits_eq <;> simp_all
@[simp] theorem Int8.toInt_bmod_65536 (x : Int8) : x.toInt.bmod 65536 = x.toInt :=
Int.bmod_eq_self_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
Int.bmod_eq_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
@[simp] theorem Int8.toInt_bmod_4294967296 (x : Int8) : x.toInt.bmod 4294967296 = x.toInt :=
Int.bmod_eq_self_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
Int.bmod_eq_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
@[simp] theorem Int16.toInt_bmod_4294967296 (x : Int16) : x.toInt.bmod 4294967296 = x.toInt :=
Int.bmod_eq_self_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
Int.bmod_eq_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
@[simp] theorem Int8.toInt_bmod_18446744073709551616 (x : Int8) : x.toInt.bmod 18446744073709551616 = x.toInt :=
Int.bmod_eq_self_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
Int.bmod_eq_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
@[simp] theorem Int16.toInt_bmod_18446744073709551616 (x : Int16) : x.toInt.bmod 18446744073709551616 = x.toInt :=
Int.bmod_eq_self_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
Int.bmod_eq_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
@[simp] theorem Int32.toInt_bmod_18446744073709551616 (x : Int32) : x.toInt.bmod 18446744073709551616 = x.toInt :=
Int.bmod_eq_self_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
Int.bmod_eq_of_le (Int.le_trans (by decide) x.le_toInt) (Int.lt_of_lt_of_le x.toInt_lt (by decide))
@[simp] theorem ISize.toInt_bmod_18446744073709551616 (x : ISize) : x.toInt.bmod 18446744073709551616 = x.toInt :=
Int.bmod_eq_self_of_le x.le_toInt x.toInt_lt
Int.bmod_eq_of_le x.le_toInt x.toInt_lt
@[simp] theorem Int8.toInt_bmod_two_pow_numBits (x : Int8) : x.toInt.bmod (2 ^ System.Platform.numBits) = x.toInt := by
refine Int.bmod_eq_self_of_le (Int.le_trans ?_ x.iSizeMinValue_le_toInt)
refine Int.bmod_eq_of_le (Int.le_trans ?_ x.iSizeMinValue_le_toInt)
(Int.lt_of_le_sub_one (Int.le_trans x.toInt_le_iSizeMaxValue ?_))
all_goals cases System.Platform.numBits_eq <;> simp_all [ISize.toInt_minValue, ISize.toInt_maxValue]
@[simp] theorem Int16.toInt_bmod_two_pow_numBits (x : Int16) : x.toInt.bmod (2 ^ System.Platform.numBits) = x.toInt := by
refine Int.bmod_eq_self_of_le (Int.le_trans ?_ x.iSizeMinValue_le_toInt)
refine Int.bmod_eq_of_le (Int.le_trans ?_ x.iSizeMinValue_le_toInt)
(Int.lt_of_le_sub_one (Int.le_trans x.toInt_le_iSizeMaxValue ?_))
all_goals cases System.Platform.numBits_eq <;> simp_all [ISize.toInt_minValue, ISize.toInt_maxValue]
@[simp] theorem Int32.toInt_bmod_two_pow_numBits (x : Int32) : x.toInt.bmod (2 ^ System.Platform.numBits) = x.toInt := by
refine Int.bmod_eq_self_of_le (Int.le_trans ?_ x.iSizeMinValue_le_toInt)
refine Int.bmod_eq_of_le (Int.le_trans ?_ x.iSizeMinValue_le_toInt)
(Int.lt_of_le_sub_one (Int.le_trans x.toInt_le_iSizeMaxValue ?_))
all_goals cases System.Platform.numBits_eq <;> simp_all [ISize.toInt_minValue, ISize.toInt_maxValue]
@@ -2066,7 +2066,7 @@ theorem ISize.toInt_maxValue_add_one : maxValue.toInt + 1 = 2 ^ (System.Platform
theorem Int8.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt a) (ha₂ : a maxValue.toInt)
(hb₁ : minValue.toInt b) (hb₂ : b maxValue.toInt) : Int8.ofInt (a.tdiv b) = Int8.ofInt a / Int8.ofInt b := by
rw [Int8.ofInt_eq_iff_bmod_eq_toInt, toInt_div, toInt_ofInt, toInt_ofInt,
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
· exact hb₁
· exact Int.lt_of_le_sub_one hb₂
· exact ha₁
@@ -2074,7 +2074,7 @@ theorem Int8.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
theorem Int16.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt a) (ha₂ : a maxValue.toInt)
(hb₁ : minValue.toInt b) (hb₂ : b maxValue.toInt) : Int16.ofInt (a.tdiv b) = Int16.ofInt a / Int16.ofInt b := by
rw [Int16.ofInt_eq_iff_bmod_eq_toInt, toInt_div, toInt_ofInt, toInt_ofInt,
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
· exact hb₁
· exact Int.lt_of_le_sub_one hb₂
· exact ha₁
@@ -2082,7 +2082,7 @@ theorem Int16.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
theorem Int32.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt a) (ha₂ : a maxValue.toInt)
(hb₁ : minValue.toInt b) (hb₂ : b maxValue.toInt) : Int32.ofInt (a.tdiv b) = Int32.ofInt a / Int32.ofInt b := by
rw [Int32.ofInt_eq_iff_bmod_eq_toInt, toInt_div, toInt_ofInt, toInt_ofInt,
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
· exact hb₁
· exact Int.lt_of_le_sub_one hb₂
· exact ha₁
@@ -2090,7 +2090,7 @@ theorem Int32.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
theorem Int64.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt a) (ha₂ : a maxValue.toInt)
(hb₁ : minValue.toInt b) (hb₂ : b maxValue.toInt) : Int64.ofInt (a.tdiv b) = Int64.ofInt a / Int64.ofInt b := by
rw [Int64.ofInt_eq_iff_bmod_eq_toInt, toInt_div, toInt_ofInt, toInt_ofInt,
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
· exact hb₁
· exact Int.lt_of_le_sub_one hb₂
· exact ha₁
@@ -2098,7 +2098,7 @@ theorem Int64.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
theorem ISize.ofInt_tdiv {a b : Int} (ha₁ : minValue.toInt a) (ha₂ : a maxValue.toInt)
(hb₁ : minValue.toInt b) (hb₂ : b maxValue.toInt) : ISize.ofInt (a.tdiv b) = ISize.ofInt a / ISize.ofInt b := by
rw [ISize.ofInt_eq_iff_bmod_eq_toInt, toInt_div, toInt_ofInt, toInt_ofInt,
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
· exact le_of_eq_of_le (by cases System.Platform.numBits_eq <;> simp_all [size, toInt_ofInt, toInt_neg]) hb₁
· refine Int.lt_of_le_sub_one (le_of_le_of_eq hb₂ ?_)
cases System.Platform.numBits_eq <;> simp_all [size, toInt_ofInt]
@@ -2625,6 +2625,17 @@ instance : Std.LawfulCommIdentity (α := ISize) (· * ·) 1 where
@[simp] theorem Int64.zero_mul {a : Int64} : 0 * a = 0 := Int64.toBitVec_inj.1 BitVec.zero_mul
@[simp] theorem ISize.zero_mul {a : ISize} : 0 * a = 0 := ISize.toBitVec_inj.1 BitVec.zero_mul
@[simp] protected theorem Int8.pow_zero (x : Int8) : x ^ 0 = 1 := rfl
protected theorem Int8.pow_succ (x : Int8) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
@[simp] protected theorem Int16.pow_zero (x : Int16) : x ^ 0 = 1 := rfl
protected theorem Int16.pow_succ (x : Int16) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
@[simp] protected theorem Int32.pow_zero (x : Int32) : x ^ 0 = 1 := rfl
protected theorem Int32.pow_succ (x : Int32) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
@[simp] protected theorem Int64.pow_zero (x : Int64) : x ^ 0 = 1 := rfl
protected theorem Int64.pow_succ (x : Int64) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
@[simp] protected theorem ISize.pow_zero (x : ISize) : x ^ 0 = 1 := rfl
protected theorem ISize.pow_succ (x : ISize) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
protected theorem Int8.mul_add {a b c : Int8} : a * (b + c) = a * b + a * c :=
Int8.toBitVec_inj.1 BitVec.mul_add
protected theorem Int16.mul_add {a b c : Int16} : a * (b + c) = a * b + a * c :=
@@ -2910,7 +2921,7 @@ protected theorem ISize.div_self {a : ISize} : a / a = if a = 0 then 0 else 1 :=
simp [ ISize.toInt_inj]
split
· simp_all
· rw [Int.tdiv_self, Int.bmod_eq_self_of_le]
· rw [Int.tdiv_self, Int.bmod_eq_of_le]
· simp
· cases System.Platform.numBits_eq <;> simp_all
· cases System.Platform.numBits_eq <;> simp_all
@@ -3065,15 +3076,15 @@ protected theorem Int64.lt_or_eq_of_le {a b : Int64} : a ≤ b → a < b a =
protected theorem ISize.lt_or_eq_of_le {a b : ISize} : a b a < b a = b := ISize.le_iff_lt_or_eq.mp
theorem Int8.toInt_eq_toNatClampNeg {a : Int8} (ha : 0 a) : a.toInt = a.toNatClampNeg := by
simpa only [ toNat_toInt, Int.eq_ofNat_toNat, le_iff_toInt_le] using ha
simpa only [ toNat_toInt, Int.eq_natCast_toNat, le_iff_toInt_le] using ha
theorem Int16.toInt_eq_toNatClampNeg {a : Int16} (ha : 0 a) : a.toInt = a.toNatClampNeg := by
simpa only [ toNat_toInt, Int.eq_ofNat_toNat, le_iff_toInt_le] using ha
simpa only [ toNat_toInt, Int.eq_natCast_toNat, le_iff_toInt_le] using ha
theorem Int32.toInt_eq_toNatClampNeg {a : Int32} (ha : 0 a) : a.toInt = a.toNatClampNeg := by
simpa only [ toNat_toInt, Int.eq_ofNat_toNat, le_iff_toInt_le] using ha
simpa only [ toNat_toInt, Int.eq_natCast_toNat, le_iff_toInt_le] using ha
theorem Int64.toInt_eq_toNatClampNeg {a : Int64} (ha : 0 a) : a.toInt = a.toNatClampNeg := by
simpa only [ toNat_toInt, Int.eq_ofNat_toNat, le_iff_toInt_le] using ha
simpa only [ toNat_toInt, Int.eq_natCast_toNat, le_iff_toInt_le] using ha
theorem ISize.toInt_eq_toNatClampNeg {a : ISize} (ha : 0 a) : a.toInt = a.toNatClampNeg := by
simpa only [ toNat_toInt, Int.eq_ofNat_toNat, le_iff_toInt_le, toInt_zero] using ha
simpa only [ toNat_toInt, Int.eq_natCast_toNat, le_iff_toInt_le, toInt_zero] using ha
@[simp] theorem UInt8.toInt8_add (a b : UInt8) : (a + b).toInt8 = a.toInt8 + b.toInt8 := rfl
@[simp] theorem UInt16.toInt16_add (a b : UInt16) : (a + b).toInt16 = a.toInt16 + b.toInt16 := rfl
@@ -3311,7 +3322,7 @@ protected theorem ISize.ne_of_lt {a b : ISize} : a < b → a ≠ b := by
theorem Int8.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt a) (ha₂ : a maxValue.toInt)
(hb₁ : minValue.toInt b) (hb₂ : b maxValue.toInt) : Int8.ofInt (a.tmod b) = Int8.ofInt a % Int8.ofInt b := by
rw [Int8.ofInt_eq_iff_bmod_eq_toInt, toInt_bmod_size, toInt_mod, toInt_ofInt, toInt_ofInt,
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
· exact hb₁
· exact Int.lt_of_le_sub_one hb₂
· exact ha₁
@@ -3319,7 +3330,7 @@ theorem Int8.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
theorem Int16.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt a) (ha₂ : a maxValue.toInt)
(hb₁ : minValue.toInt b) (hb₂ : b maxValue.toInt) : Int16.ofInt (a.tmod b) = Int16.ofInt a % Int16.ofInt b := by
rw [Int16.ofInt_eq_iff_bmod_eq_toInt, toInt_bmod_size, toInt_mod, toInt_ofInt, toInt_ofInt,
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
· exact hb₁
· exact Int.lt_of_le_sub_one hb₂
· exact ha₁
@@ -3327,7 +3338,7 @@ theorem Int16.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
theorem Int32.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt a) (ha₂ : a maxValue.toInt)
(hb₁ : minValue.toInt b) (hb₂ : b maxValue.toInt) : Int32.ofInt (a.tmod b) = Int32.ofInt a % Int32.ofInt b := by
rw [Int32.ofInt_eq_iff_bmod_eq_toInt, toInt_bmod_size, toInt_mod, toInt_ofInt, toInt_ofInt,
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
· exact hb₁
· exact Int.lt_of_le_sub_one hb₂
· exact ha₁
@@ -3335,7 +3346,7 @@ theorem Int32.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
theorem Int64.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt a) (ha₂ : a maxValue.toInt)
(hb₁ : minValue.toInt b) (hb₂ : b maxValue.toInt) : Int64.ofInt (a.tmod b) = Int64.ofInt a % Int64.ofInt b := by
rw [Int64.ofInt_eq_iff_bmod_eq_toInt, toInt_bmod_size, toInt_mod, toInt_ofInt, toInt_ofInt,
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
· exact hb₁
· exact Int.lt_of_le_sub_one hb₂
· exact ha₁
@@ -3343,7 +3354,7 @@ theorem Int64.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt ≤ a) (ha₂ : a
theorem ISize.ofInt_tmod {a b : Int} (ha₁ : minValue.toInt a) (ha₂ : a maxValue.toInt)
(hb₁ : minValue.toInt b) (hb₂ : b maxValue.toInt) : ISize.ofInt (a.tmod b) = ISize.ofInt a % ISize.ofInt b := by
rw [ISize.ofInt_eq_iff_bmod_eq_toInt, toInt_bmod_size, toInt_mod, toInt_ofInt, toInt_ofInt,
Int.bmod_eq_self_of_le (n := a), Int.bmod_eq_self_of_le (n := b)]
Int.bmod_eq_of_le (n := a), Int.bmod_eq_of_le (n := b)]
· exact le_of_eq_of_le (by cases System.Platform.numBits_eq <;> simp_all [size, toInt_ofInt, toInt_neg]) hb₁
· refine Int.lt_of_le_sub_one (le_of_le_of_eq hb₂ ?_)
cases System.Platform.numBits_eq <;> simp_all [size, toInt_ofInt]

View File

@@ -20,6 +20,9 @@ def UInt8.mk (bitVec : BitVec 8) : UInt8 :=
def UInt8.ofNatCore (n : Nat) (h : n < UInt8.size) : UInt8 :=
UInt8.ofNatLT n h
/-- Converts an `Int` to a `UInt8` by taking the (non-negative remainder of the division by `2 ^ 8`. -/
def UInt8.ofInt (x : Int) : UInt8 := ofNat (x % 2 ^ 8).toNat
/--
Adds two 8-bit unsigned integers, wrapping around on overflow. Usually accessed via the `+`
operator.
@@ -55,6 +58,17 @@ This function is overridden at runtime with an efficient implementation.
@[extern "lean_uint8_div"]
protected def UInt8.div (a b : UInt8) : UInt8 := BitVec.udiv a.toBitVec b.toBitVec
/--
The power operation, raising an 8-bit unsigned integer to a natural number power,
wrapping around on overflow. Usually accessed via the `^` operator.
This function is currently *not* overridden at runtime with an efficient implementation,
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
-/
protected def UInt8.pow (x : UInt8) (n : Nat) : UInt8 :=
match n with
| 0 => 1
| n + 1 => UInt8.mul (UInt8.pow x n) x
/--
The modulo operator for 8-bit unsigned integers, which computes the remainder when dividing one
integer by another. Usually accessed via the `%` operator.
@@ -129,6 +143,7 @@ protected def UInt8.le (a b : UInt8) : Prop := a.toBitVec ≤ b.toBitVec
instance : Add UInt8 := UInt8.add
instance : Sub UInt8 := UInt8.sub
instance : Mul UInt8 := UInt8.mul
instance : Pow UInt8 Nat := UInt8.pow
instance : Mod UInt8 := UInt8.mod
set_option linter.deprecated false in
@@ -217,6 +232,9 @@ def UInt16.mk (bitVec : BitVec 16) : UInt16 :=
def UInt16.ofNatCore (n : Nat) (h : n < UInt16.size) : UInt16 :=
UInt16.ofNatLT n h
/-- Converts an `Int` to a `UInt16` by taking the (non-negative remainder of the division by `2 ^ 16`. -/
def UInt16.ofInt (x : Int) : UInt16 := ofNat (x % 2 ^ 16).toNat
/--
Adds two 16-bit unsigned integers, wrapping around on overflow. Usually accessed via the `+`
operator.
@@ -252,6 +270,17 @@ This function is overridden at runtime with an efficient implementation.
@[extern "lean_uint16_div"]
protected def UInt16.div (a b : UInt16) : UInt16 := BitVec.udiv a.toBitVec b.toBitVec
/--
The power operation, raising a 16-bit unsigned integer to a natural number power,
wrapping around on overflow. Usually accessed via the `^` operator.
This function is currently *not* overridden at runtime with an efficient implementation,
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
-/
protected def UInt16.pow (x : UInt16) (n : Nat) : UInt16 :=
match n with
| 0 => 1
| n + 1 => UInt16.mul (UInt16.pow x n) x
/--
The modulo operator for 16-bit unsigned integers, which computes the remainder when dividing one
integer by another. Usually accessed via the `%` operator.
@@ -289,7 +318,7 @@ This function is overridden at runtime with an efficient implementation.
@[extern "lean_uint16_lor"]
protected def UInt16.lor (a b : UInt16) : UInt16 := a.toBitVec ||| b.toBitVec
/--
Bitwise exclusive or for 8-bit unsigned integers. Usually accessed via the `^^^` operator.
Bitwise exclusive or for 16-bit unsigned integers. Usually accessed via the `^^^` operator.
Each bit of the resulting integer is set if exactly one of the corresponding bits of both input
integers are set.
@@ -326,6 +355,7 @@ protected def UInt16.le (a b : UInt16) : Prop := a.toBitVec ≤ b.toBitVec
instance : Add UInt16 := UInt16.add
instance : Sub UInt16 := UInt16.sub
instance : Mul UInt16 := UInt16.mul
instance : Pow UInt16 Nat := UInt16.pow
instance : Mod UInt16 := UInt16.mod
set_option linter.deprecated false in
@@ -416,6 +446,9 @@ def UInt32.mk (bitVec : BitVec 32) : UInt32 :=
def UInt32.ofNatCore (n : Nat) (h : n < UInt32.size) : UInt32 :=
UInt32.ofNatLT n h
/-- Converts an `Int` to a `UInt32` by taking the (non-negative remainder of the division by `2 ^ 32`. -/
def UInt32.ofInt (x : Int) : UInt32 := ofNat (x % 2 ^ 32).toNat
/--
Adds two 32-bit unsigned integers, wrapping around on overflow. Usually accessed via the `+`
operator.
@@ -451,6 +484,17 @@ This function is overridden at runtime with an efficient implementation.
@[extern "lean_uint32_div"]
protected def UInt32.div (a b : UInt32) : UInt32 := BitVec.udiv a.toBitVec b.toBitVec
/--
The power operation, raising a 32-bit unsigned integer to a natural number power,
wrapping around on overflow. Usually accessed via the `^` operator.
This function is currently *not* overridden at runtime with an efficient implementation,
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
-/
protected def UInt32.pow (x : UInt32) (n : Nat) : UInt32 :=
match n with
| 0 => 1
| n + 1 => UInt32.mul (UInt32.pow x n) x
/--
The modulo operator for 32-bit unsigned integers, which computes the remainder when dividing one
integer by another. Usually accessed via the `%` operator.
@@ -525,6 +569,7 @@ protected def UInt32.le (a b : UInt32) : Prop := a.toBitVec ≤ b.toBitVec
instance : Add UInt32 := UInt32.add
instance : Sub UInt32 := UInt32.sub
instance : Mul UInt32 := UInt32.mul
instance : Pow UInt32 Nat := UInt32.pow
instance : Mod UInt32 := UInt32.mod
set_option linter.deprecated false in
@@ -577,6 +622,9 @@ def UInt64.mk (bitVec : BitVec 64) : UInt64 :=
def UInt64.ofNatCore (n : Nat) (h : n < UInt64.size) : UInt64 :=
UInt64.ofNatLT n h
/-- Converts an `Int` to a `UInt64` by taking the (non-negative remainder of the division by `2 ^ 64`. -/
def UInt64.ofInt (x : Int) : UInt64 := ofNat (x % 2 ^ 64).toNat
/--
Adds two 64-bit unsigned integers, wrapping around on overflow. Usually accessed via the `+`
operator.
@@ -612,6 +660,17 @@ This function is overridden at runtime with an efficient implementation.
@[extern "lean_uint64_div"]
protected def UInt64.div (a b : UInt64) : UInt64 := BitVec.udiv a.toBitVec b.toBitVec
/--
The power operation, raising a 64-bit unsigned integer to a natural number power,
wrapping around on overflow. Usually accessed via the `^` operator.
This function is currently *not* overridden at runtime with an efficient implementation,
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
-/
protected def UInt64.pow (x : UInt64) (n : Nat) : UInt64 :=
match n with
| 0 => 1
| n + 1 => UInt64.mul (UInt64.pow x n) x
/--
The modulo operator for 64-bit unsigned integers, which computes the remainder when dividing one
integer by another. Usually accessed via the `%` operator.
@@ -686,6 +745,7 @@ protected def UInt64.le (a b : UInt64) : Prop := a.toBitVec ≤ b.toBitVec
instance : Add UInt64 := UInt64.add
instance : Sub UInt64 := UInt64.sub
instance : Mul UInt64 := UInt64.mul
instance : Pow UInt64 Nat := UInt64.pow
instance : Mod UInt64 := UInt64.mod
set_option linter.deprecated false in
@@ -706,7 +766,7 @@ This function is overridden at runtime with an efficient implementation.
@[extern "lean_uint64_complement"]
protected def UInt64.complement (a : UInt64) : UInt64 := ~~~a.toBitVec
/--
Negation of 32-bit unsigned integers, computed modulo `UInt64.size`.
Negation of 64-bit unsigned integers, computed modulo `UInt64.size`.
`UInt64.neg a` is equivalent to `18_446_744_073_709_551_615 - a + 1`.
@@ -774,6 +834,9 @@ def USize.mk (bitVec : BitVec System.Platform.numBits) : USize :=
def USize.ofNatCore (n : Nat) (h : n < USize.size) : USize :=
USize.ofNatLT n h
/-- Converts an `Int` to a `USize` by taking the (non-negative remainder of the division by `2 ^ numBits`. -/
def USize.ofInt (x : Int) : USize := ofNat (x % 2 ^ System.Platform.numBits).toNat
@[simp] theorem USize.le_size : 2 ^ 32 USize.size := by cases USize.size_eq <;> simp_all
@[simp] theorem USize.size_le : USize.size 2 ^ 64 := by cases USize.size_eq <;> simp_all
@@ -804,6 +867,17 @@ This function is overridden at runtime with an efficient implementation.
@[extern "lean_usize_div"]
protected def USize.div (a b : USize) : USize := a.toBitVec / b.toBitVec
/--
The power operation, raising a word-sized unsigned integer to a natural number power,
wrapping around on overflow. Usually accessed via the `^` operator.
This function is currently *not* overridden at runtime with an efficient implementation,
and should be used with caution. See https://github.com/leanprover/lean4/issues/7887.
-/
protected def USize.pow (x : USize) (n : Nat) : USize :=
match n with
| 0 => 1
| n + 1 => USize.mul (USize.pow x n) x
/--
The modulo operator for word-sized unsigned integers, which computes the remainder when dividing one
integer by another. Usually accessed via the `%` operator.
@@ -937,6 +1011,7 @@ def USize.toUInt64 (a : USize) : UInt64 :=
UInt64.ofNatLT a.toBitVec.toNat (Nat.lt_of_lt_of_le a.toBitVec.isLt USize.size_le)
instance : Mul USize := USize.mul
instance : Pow USize Nat := USize.pow
instance : Mod USize := USize.mod
set_option linter.deprecated false in

View File

@@ -286,6 +286,17 @@ declare_uint_theorems USize System.Platform.numBits
theorem USize.toNat_ofNat_of_lt_32 {n : Nat} (h : n < 4294967296) : toNat (ofNat n) = n :=
toNat_ofNat_of_lt (Nat.lt_of_lt_of_le h USize.le_size)
theorem UInt8.ofNat_mod_size : ofNat (x % 2 ^ 8) = ofNat x := by
simp [ofNat, BitVec.ofNat, Fin.ofNat']
theorem UInt16.ofNat_mod_size : ofNat (x % 2 ^ 16) = ofNat x := by
simp [ofNat, BitVec.ofNat, Fin.ofNat']
theorem UInt32.ofNat_mod_size : ofNat (x % 2 ^ 32) = ofNat x := by
simp [ofNat, BitVec.ofNat, Fin.ofNat']
theorem UInt64.ofNat_mod_size : ofNat (x % 2 ^ 64) = ofNat x := by
simp [ofNat, BitVec.ofNat, Fin.ofNat']
theorem USize.ofNat_mod_size : ofNat (x % 2 ^ System.Platform.numBits) = ofNat x := by
simp [ofNat, BitVec.ofNat, Fin.ofNat']
theorem UInt8.lt_ofNat_iff {n : UInt8} {m : Nat} (h : m < size) : n < ofNat m n.toNat < m := by
rw [lt_iff_toNat_lt, toNat_ofNat_of_lt' h]
theorem UInt8.ofNat_lt_iff {n : UInt8} {m : Nat} (h : m < size) : ofNat m < n m < n.toNat := by
@@ -1655,7 +1666,7 @@ theorem USize.toUInt32_eq (a b : USize) : a.toUInt32 = b.toUInt32 ↔ a % 429496
simp [ UInt32.toNat_inj, USize.toNat_inj, USize.toNat_ofNat]
have := Nat.mod_eq_of_lt a.toNat_lt_two_pow_numBits
have := Nat.mod_eq_of_lt b.toNat_lt_two_pow_numBits
cases System.Platform.numBits_eq <;> simp_all
cases System.Platform.numBits_eq <;> simp_all [Nat.mod_eq_of_lt]
theorem UInt8.toUInt16_eq_mod_256_iff (a : UInt8) (b : UInt16) : a.toUInt16 = b % 256 a = b.toUInt8 := by
simp [ UInt8.toNat_inj, UInt16.toNat_inj]
@@ -1678,7 +1689,7 @@ theorem UInt32.toUInt64_eq_mod_4294967296_iff (a : UInt32) (b : UInt64) : a.toUI
theorem UInt32.toUSize_eq_mod_4294967296_iff (a : UInt32) (b : USize) : a.toUSize = b % 4294967296 a = b.toUInt32 := by
simp [ UInt32.toNat_inj, USize.toNat_inj, USize.toNat_ofNat]
have := Nat.mod_eq_of_lt b.toNat_lt_two_pow_numBits
cases System.Platform.numBits_eq <;> simp_all
cases System.Platform.numBits_eq <;> simp_all [Nat.mod_eq_of_lt]
theorem USize.toUInt64_eq_mod_usizeSize_iff (a : USize) (b : UInt64) : a.toUInt64 = b % UInt64.ofNat USize.size a = b.toUSize := by
simp [ USize.toNat_inj, UInt64.toNat_inj, USize.size_eq_two_pow]
@@ -2081,6 +2092,23 @@ theorem USize.ofNat_eq_iff_mod_eq_toNat (a : Nat) (b : USize) : USize.ofNat a =
USize.ofNatLT (a % b) (Nat.mod_lt_of_lt ha) = USize.ofNatLT a ha % USize.ofNatLT b hb := by
simp [USize.ofNatLT_eq_ofNat, USize.ofNat_mod ha hb]
@[simp] theorem UInt8.ofInt_one : ofInt 1 = 1 := rfl
@[simp] theorem UInt8.ofInt_neg_one : ofInt (-1) = -1 := rfl
@[simp] theorem UInt16.ofInt_one : ofInt 1 = 1 := rfl
@[simp] theorem UInt16.ofInt_neg_one : ofInt (-1) = -1 := rfl
@[simp] theorem UInt32.ofInt_one : ofInt 1 = 1 := rfl
@[simp] theorem UInt32.ofInt_neg_one : ofInt (-1) = -1 := rfl
@[simp] theorem UInt64.ofInt_one : ofInt 1 = 1 := rfl
@[simp] theorem UInt64.ofInt_neg_one : ofInt (-1) = -1 := rfl
@[simp] theorem USize.ofInt_one : ofInt 1 = 1 := by
rcases System.Platform.numBits_eq with h | h <;>
· apply USize.toNat_inj.mp
simp_all [USize.ofInt, USize.ofNat, size, toNat]
@[simp] theorem USize.ofInt_neg_one : ofInt (-1) = -1 := by
rcases System.Platform.numBits_eq with h | h <;>
· apply USize.toNat_inj.mp
simp_all [USize.ofInt, USize.ofNat, size, toNat]
@[simp] theorem UInt8.ofNat_add (a b : Nat) : UInt8.ofNat (a + b) = UInt8.ofNat a + UInt8.ofNat b := by
simp [UInt8.ofNat_eq_iff_mod_eq_toNat]
@[simp] theorem UInt16.ofNat_add (a b : Nat) : UInt16.ofNat (a + b) = UInt16.ofNat a + UInt16.ofNat b := by
@@ -2092,6 +2120,70 @@ theorem USize.ofNat_eq_iff_mod_eq_toNat (a : Nat) (b : USize) : USize.ofNat a =
@[simp] theorem USize.ofNat_add (a b : Nat) : USize.ofNat (a + b) = USize.ofNat a + USize.ofNat b := by
simp [USize.ofNat_eq_iff_mod_eq_toNat]
@[simp] theorem UInt8.ofInt_add (x y : Int) : ofInt (x + y) = ofInt x + ofInt y := by
dsimp only [UInt8.ofInt]
rw [Int.add_emod]
have h₁ : 0 x % 2 ^ 8 := Int.emod_nonneg _ (by decide)
have h₂ : 0 y % 2 ^ 8 := Int.emod_nonneg _ (by decide)
have h₃ : 0 x % 2 ^ 8 + y % 2 ^ 8 := Int.add_nonneg h₁ h₂
rw [Int.toNat_emod h₃ (by decide), Int.toNat_add h₁ h₂]
have : (2 ^ 8 : Int).toNat = 2 ^ 8 := rfl
rw [this, UInt8.ofNat_mod_size, UInt8.ofNat_add]
@[simp] theorem UInt16.ofInt_add (x y : Int) : UInt16.ofInt (x + y) = UInt16.ofInt x + UInt16.ofInt y := by
dsimp only [UInt16.ofInt]
rw [Int.add_emod]
have h₁ : 0 x % 2 ^ 16 := Int.emod_nonneg _ (by decide)
have h₂ : 0 y % 2 ^ 16 := Int.emod_nonneg _ (by decide)
have h₃ : 0 x % 2 ^ 16 + y % 2 ^ 16 := Int.add_nonneg h₁ h₂
rw [Int.toNat_emod h₃ (by decide), Int.toNat_add h₁ h₂]
have : (2 ^ 16 : Int).toNat = 2 ^ 16 := rfl
rw [this, UInt16.ofNat_mod_size, UInt16.ofNat_add]
@[simp] theorem UInt32.ofInt_add (x y : Int) : UInt32.ofInt (x + y) = UInt32.ofInt x + UInt32.ofInt y := by
dsimp only [UInt32.ofInt]
rw [Int.add_emod]
have h₁ : 0 x % 2 ^ 32 := Int.emod_nonneg _ (by decide)
have h₂ : 0 y % 2 ^ 32 := Int.emod_nonneg _ (by decide)
have h₃ : 0 x % 2 ^ 32 + y % 2 ^ 32 := Int.add_nonneg h₁ h₂
rw [Int.toNat_emod h₃ (by decide), Int.toNat_add h₁ h₂]
have : (2 ^ 32 : Int).toNat = 2 ^ 32 := rfl
rw [this, UInt32.ofNat_mod_size, UInt32.ofNat_add]
@[simp] theorem UInt64.ofInt_add (x y : Int) : UInt64.ofInt (x + y) = UInt64.ofInt x + UInt64.ofInt y := by
dsimp only [UInt64.ofInt]
rw [Int.add_emod]
have h₁ : 0 x % 2 ^ 64 := Int.emod_nonneg _ (by decide)
have h₂ : 0 y % 2 ^ 64 := Int.emod_nonneg _ (by decide)
have h₃ : 0 x % 2 ^ 64 + y % 2 ^ 64 := Int.add_nonneg h₁ h₂
rw [Int.toNat_emod h₃ (by decide), Int.toNat_add h₁ h₂]
have : (2 ^ 64 : Int).toNat = 2 ^ 64 := rfl
rw [this, UInt64.ofNat_mod_size, UInt64.ofNat_add]
namespace System.Platform
theorem two_pow_numBits_nonneg : 0 (2 ^ System.Platform.numBits : Int) := by
rcases System.Platform.numBits_eq with h | h <;>
· rw [h]
decide
theorem two_pow_numBits_ne_zero : (2 ^ System.Platform.numBits : Int) 0 := by
rcases System.Platform.numBits_eq with h | h <;>
· rw [h]
decide
end System.Platform
open System.Platform in
@[simp] theorem USize.ofInt_add (x y : Int) : USize.ofInt (x + y) = USize.ofInt x + USize.ofInt y := by
dsimp only [USize.ofInt]
rw [Int.add_emod]
have h₁ : 0 x % 2 ^ numBits := Int.emod_nonneg _ two_pow_numBits_ne_zero
have h₂ : 0 y % 2 ^ numBits := Int.emod_nonneg _ two_pow_numBits_ne_zero
have h₃ : 0 x % 2 ^ numBits + y % 2 ^ numBits := Int.add_nonneg h₁ h₂
rw [Int.toNat_emod h₃ two_pow_numBits_nonneg, Int.toNat_add h₁ h₂]
have : (2 ^ numBits : Int).toNat = 2 ^ numBits := by
rcases System.Platform.numBits_eq with h | h <;>
· rw [h]
decide
rw [this, USize.ofNat_mod_size, USize.ofNat_add]
@[simp] theorem UInt8.ofNatLT_add {a b : Nat} (hab : a + b < 2 ^ 8) :
UInt8.ofNatLT (a + b) hab = UInt8.ofNatLT a (Nat.lt_of_add_right_lt hab) + UInt8.ofNatLT b (Nat.lt_of_add_left_lt hab) := by
simp [UInt8.ofNatLT_eq_ofNat]
@@ -2176,6 +2268,56 @@ theorem USize.ofNatLT_sub {a b : Nat} (ha : a < 2 ^ System.Platform.numBits) (ha
@[simp] theorem USize.ofNat_mul (a b : Nat) : USize.ofNat (a * b) = USize.ofNat a * USize.ofNat b := by
simp [USize.ofNat_eq_iff_mod_eq_toNat]
@[simp] theorem UInt8.ofInt_mul (x y : Int) : ofInt (x * y) = ofInt x * ofInt y := by
dsimp only [UInt8.ofInt]
rw [Int.mul_emod]
have h₁ : 0 x % 2 ^ 8 := Int.emod_nonneg _ (by decide)
have h₂ : 0 y % 2 ^ 8 := Int.emod_nonneg _ (by decide)
have h₃ : 0 (x % 2 ^ 8) * (y % 2 ^ 8) := Int.mul_nonneg h₁ h₂
rw [Int.toNat_emod h₃ (by decide), Int.toNat_mul h₁ h₂]
have : (2 ^ 8 : Int).toNat = 2 ^ 8 := rfl
rw [this, UInt8.ofNat_mod_size, UInt8.ofNat_mul]
@[simp] theorem UInt16.ofInt_mul (x y : Int) : ofInt (x * y) = ofInt x * ofInt y := by
dsimp only [UInt16.ofInt]
rw [Int.mul_emod]
have h₁ : 0 x % 2 ^ 16 := Int.emod_nonneg _ (by decide)
have h₂ : 0 y % 2 ^ 16 := Int.emod_nonneg _ (by decide)
have h₃ : 0 (x % 2 ^ 16) * (y % 2 ^ 16) := Int.mul_nonneg h₁ h₂
rw [Int.toNat_emod h₃ (by decide), Int.toNat_mul h₁ h₂]
have : (2 ^ 16 : Int).toNat = 2 ^ 16 := rfl
rw [this, UInt16.ofNat_mod_size, UInt16.ofNat_mul]
@[simp] theorem UInt32.ofInt_mul (x y : Int) : ofInt (x * y) = ofInt x * ofInt y := by
dsimp only [UInt32.ofInt]
rw [Int.mul_emod]
have h₁ : 0 x % 2 ^ 32 := Int.emod_nonneg _ (by decide)
have h₂ : 0 y % 2 ^ 32 := Int.emod_nonneg _ (by decide)
have h₃ : 0 (x % 2 ^ 32) * (y % 2 ^ 32) := Int.mul_nonneg h₁ h₂
rw [Int.toNat_emod h₃ (by decide), Int.toNat_mul h₁ h₂]
have : (2 ^ 32 : Int).toNat = 2 ^ 32 := rfl
rw [this, UInt32.ofNat_mod_size, UInt32.ofNat_mul]
@[simp] theorem UInt64.ofInt_mul (x y : Int) : ofInt (x * y) = ofInt x * ofInt y := by
dsimp only [UInt64.ofInt]
rw [Int.mul_emod]
have h₁ : 0 x % 2 ^ 64 := Int.emod_nonneg _ (by decide)
have h₂ : 0 y % 2 ^ 64 := Int.emod_nonneg _ (by decide)
have h₃ : 0 (x % 2 ^ 64) * (y % 2 ^ 64) := Int.mul_nonneg h₁ h₂
rw [Int.toNat_emod h₃ (by decide), Int.toNat_mul h₁ h₂]
have : (2 ^ 64 : Int).toNat = 2 ^ 64 := rfl
rw [this, UInt64.ofNat_mod_size, UInt64.ofNat_mul]
open System.Platform in
@[simp] theorem USize.ofInt_mul (x y : Int) : ofInt (x * y) = ofInt x * ofInt y := by
dsimp only [USize.ofInt]
rw [Int.mul_emod]
have h₁ : 0 x % 2 ^ numBits := Int.emod_nonneg _ two_pow_numBits_ne_zero
have h₂ : 0 y % 2 ^ numBits := Int.emod_nonneg _ two_pow_numBits_ne_zero
have h₃ : 0 (x % 2 ^ numBits) * (y % 2 ^ numBits) := Int.mul_nonneg h₁ h₂
rw [Int.toNat_emod h₃ two_pow_numBits_nonneg, Int.toNat_mul h₁ h₂]
have : (2 ^ numBits : Int).toNat = 2 ^ numBits := by
rcases System.Platform.numBits_eq with h | h <;>
· rw [h]
decide
rw [this, USize.ofNat_mod_size, USize.ofNat_mul]
@[simp] theorem UInt8.ofNatLT_mul {a b : Nat} (ha : a < 2 ^ 8) (hb : b < 2 ^ 8) (hab : a * b < 2 ^ 8) :
UInt8.ofNatLT (a * b) hab = UInt8.ofNatLT a ha * UInt8.ofNatLT b hb := by
simp [UInt8.ofNatLT_eq_ofNat]
@@ -2467,6 +2609,17 @@ protected theorem USize.neg_add {a b : USize} : - (a + b) = -a - b := USize.toBi
@[simp] protected theorem USize.neg_sub {a b : USize} : -(a - b) = b - a := by
rw [USize.sub_eq_add_neg, USize.neg_add, USize.sub_neg, USize.add_comm, USize.sub_eq_add_neg]
@[simp] protected theorem UInt8.ofInt_neg (x : Int) : ofInt (-x) = -ofInt x := by
rw [Int.neg_eq_neg_one_mul, ofInt_mul, ofInt_neg_one, UInt8.neg_eq_neg_one_mul]
@[simp] protected theorem UInt16.ofInt_neg (x : Int) : ofInt (-x) = -ofInt x := by
rw [Int.neg_eq_neg_one_mul, ofInt_mul, ofInt_neg_one, UInt16.neg_eq_neg_one_mul]
@[simp] protected theorem UInt32.ofInt_neg (x : Int) : ofInt (-x) = -ofInt x := by
rw [Int.neg_eq_neg_one_mul, ofInt_mul, ofInt_neg_one, UInt32.neg_eq_neg_one_mul]
@[simp] protected theorem UInt64.ofInt_neg (x : Int) : ofInt (-x) = -ofInt x := by
rw [Int.neg_eq_neg_one_mul, ofInt_mul, ofInt_neg_one, UInt64.neg_eq_neg_one_mul]
@[simp] protected theorem USize.ofInt_neg (x : Int) : ofInt (-x) = -ofInt x := by
rw [Int.neg_eq_neg_one_mul, ofInt_mul, ofInt_neg_one, USize.neg_eq_neg_one_mul]
@[simp] protected theorem UInt8.add_left_inj {a b : UInt8} (c : UInt8) : (a + c = b + c) a = b := by
simp [ UInt8.toBitVec_inj]
@[simp] protected theorem UInt16.add_left_inj {a b : UInt16} (c : UInt16) : (a + c = b + c) a = b := by
@@ -2614,6 +2767,17 @@ instance : Std.LawfulCommIdentity (α := USize) (· * ·) 1 where
@[simp] theorem UInt64.zero_mul {a : UInt64} : 0 * a = 0 := UInt64.toBitVec_inj.1 BitVec.zero_mul
@[simp] theorem USize.zero_mul {a : USize} : 0 * a = 0 := USize.toBitVec_inj.1 BitVec.zero_mul
@[simp] protected theorem UInt8.pow_zero (x : UInt8) : x ^ 0 = 1 := rfl
protected theorem UInt8.pow_succ (x : UInt8) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
@[simp] protected theorem UInt16.pow_zero (x : UInt16) : x ^ 0 = 1 := rfl
protected theorem UInt16.pow_succ (x : UInt16) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
@[simp] protected theorem UInt32.pow_zero (x : UInt32) : x ^ 0 = 1 := rfl
protected theorem UInt32.pow_succ (x : UInt32) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
@[simp] protected theorem UInt64.pow_zero (x : UInt64) : x ^ 0 = 1 := rfl
protected theorem UInt64.pow_succ (x : UInt64) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
@[simp] protected theorem USize.pow_zero (x : USize) : x ^ 0 = 1 := rfl
protected theorem USize.pow_succ (x : USize) (n : Nat) : x ^ (n + 1) = x ^ n * x := rfl
protected theorem UInt8.mul_add {a b c : UInt8} : a * (b + c) = a * b + a * c :=
UInt8.toBitVec_inj.1 BitVec.mul_add
protected theorem UInt16.mul_add {a b c : UInt16} : a * (b + c) = a * b + a * c :=

View File

@@ -18,3 +18,4 @@ import Init.Data.Vector.Monadic
import Init.Data.Vector.InsertIdx
import Init.Data.Vector.FinRange
import Init.Data.Vector.Extract
import Init.Data.Vector.Perm

View File

@@ -432,13 +432,13 @@ theorem countP_attachWith {p : α → Prop} {q : α → Bool} {xs : Vector α n}
simp
@[simp]
theorem count_attach [DecidableEq α] {xs : Vector α n} {a : {x // x xs}} :
theorem count_attach [BEq α] {xs : Vector α n} {a : {x // x xs}} :
xs.attach.count a = xs.count a := by
rcases xs with xs, rfl
simp
@[simp]
theorem count_attachWith [DecidableEq α] {p : α Prop} {xs : Vector α n} (H : a xs, p a) {a : {x // p x}} :
theorem count_attachWith [BEq α] {p : α Prop} {xs : Vector α n} (H : a xs, p a) {a : {x // p x}} :
(xs.attachWith p H).count a = xs.count a := by
cases xs
simp

View File

@@ -229,7 +229,7 @@ theorem count_replicate {a b : α} {n : Nat} : count a (replicate n b) = if b ==
@[deprecated count_replicate (since := "2025-03-18")]
abbrev count_mkVector := @count_replicate
theorem count_le_count_map [DecidableEq β] {xs : Vector α n} {f : α β} {x : α} :
theorem count_le_count_map [BEq β] [LawfulBEq β] {xs : Vector α n} {f : α β} {x : α} :
count x xs count (f x) (map f xs) := by
rcases xs with xs, rfl
simp [Array.count_le_count_map]
@@ -239,4 +239,15 @@ theorem count_flatMap {α} [BEq β] {xs : Vector α n} {f : α → Vector β m}
rcases xs with xs, rfl
simp [Array.count_flatMap, Function.comp_def]
theorem countP_replace {a b : α} {xs : Vector α n} {p : α Bool} :
(xs.replace a b).countP p =
if xs.contains a then xs.countP p + (if p b then 1 else 0) - (if p a then 1 else 0) else xs.countP p := by
rcases xs with xs, rfl
simp [Array.countP_replace]
theorem count_replace {a b c : α} {xs : Vector α n} :
(xs.replace a b).count c =
if xs.contains a then xs.count c + (if b == c then 1 else 0) - (if a == c then 1 else 0) else xs.count c := by
simp [count_eq_countP, countP_replace]
end count

View File

@@ -62,8 +62,10 @@ theorem beq_eq_decide [BEq α] (xs ys : Vector α n) :
@[simp] theorem beq_toList [BEq α] (xs ys : Vector α n) : (xs.toList == ys.toList) = (xs == ys) := by
simp [beq_eq_decide, List.beq_eq_decide]
instance [BEq α] [LawfulBEq α] : LawfulBEq (Vector α n) where
instance [BEq α] [ReflBEq α] : ReflBEq (Vector α n) where
rfl := by simp [BEq.beq, isEqv_self_beq]
instance [BEq α] [LawfulBEq α] : LawfulBEq (Vector α n) where
eq_of_beq := by
rintro xs, rfl ys, h h'
simpa using h'

View File

@@ -294,6 +294,18 @@ theorem find?_eq_some_iff_getElem {xs : Vector α n} {p : α → Bool} {b : α}
subst w
simp
@[simp]
theorem isSome_findFinIdx? {xs : Vector α n} {p : α Bool} :
(xs.findFinIdx? p).isSome = xs.any p := by
rcases xs with xs, rfl
simp
@[simp]
theorem isNone_findFinIdx? {xs : Vector α n} {p : α Bool} :
(xs.findFinIdx? p).isNone = xs.all (fun x => ¬ p x) := by
rcases xs with xs, rfl
simp
@[simp] theorem findFinIdx?_subtype {p : α Prop} {xs : Vector { x // p x } n}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
xs.findFinIdx? f = xs.unattach.findFinIdx? g := by

View File

@@ -824,6 +824,9 @@ theorem getElem?_eq_none {xs : Vector α n} (h : n ≤ i) : xs[i]? = none := by
theorem getElem?_eq_some_iff {xs : Vector α n} : xs[i]? = some b h : i < n, xs[i] = b := by
simp [getElem?_def]
theorem getElem_of_getElem? {xs : Vector α n} : xs[i]? = some a h : i < n, xs[i] = a :=
getElem?_eq_some_iff.mp
theorem some_eq_getElem?_iff {xs : Vector α n} : some b = xs[i]? h : i < n, xs[i] = b := by
rw [eq_comm, getElem?_eq_some_iff]
@@ -1179,20 +1182,20 @@ theorem all_bne' [BEq α] [PartialEquivBEq α] {xs : Vector α n} :
theorem mem_of_contains_eq_true [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
as.contains a = true a as := by
rcases as with as, rfl
simp [Array.mem_of_contains_eq_true]
simp
theorem contains_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} (h : a as) :
as.contains a = true := by
rcases as with as, rfl
simp only [mem_mk] at h
simp [Array.contains_eq_true_of_mem, h]
instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a as) :=
decidable_of_decidable_of_iff (Iff.intro mem_of_contains_eq_true contains_eq_true_of_mem)
simp [h]
theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
as.contains a = true a as := mem_of_contains_eq_true, contains_eq_true_of_mem
instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a as) :=
decidable_of_decidable_of_iff contains_iff
@[simp] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
as.contains a = decide (a as) := by
rw [Bool.eq_iff_iff, contains_iff, decide_eq_true_iff]
@@ -1348,36 +1351,31 @@ abbrev mkVector_beq_mkVector := @replicate_beq_replicate
· intro h
constructor
rintro xs, h
simpa using Array.isEqv_self_beq ..
simp
@[simp] theorem lawfulBEq_iff [BEq α] [NeZero n] : LawfulBEq (Vector α n) LawfulBEq α := by
match n, NeZero.ne n with
| n + 1, _ =>
constructor
· intro h
have : ReflBEq α := reflBEq_iff.mp h.toReflBEq
constructor
· intro a b h
have := replicate_inj (n := n+1) (a := a) (b := b)
simp only [Nat.add_one_ne_zero, false_or] at this
rw [ this]
apply eq_of_beq
rw [replicate_beq_replicate]
simpa
· intro a
suffices (replicate (n + 1) a == replicate (n + 1) a) = true by
rw [replicate_beq_replicate] at this
simpa
simp
intro a b h
have := replicate_inj (n := n+1) (a := a) (b := b)
simp only [Nat.add_one_ne_zero, false_or] at this
rw [ this]
apply eq_of_beq
rw [replicate_beq_replicate]
simpa
· intro h
have : ReflBEq (Vector α (n + 1)) := reflBEq_iff.mpr inferInstance
constructor
· rintro as, ha bs, hb h
simp_all
· rintro as, ha
simp
rintro as, ha bs, hb h
simp_all
/-! ### isEqv -/
@[simp] theorem isEqv_eq [DecidableEq α] {xs ys : Vector α n} : xs.isEqv ys (· == ·) = (xs = ys) := by
@[simp] theorem isEqv_eq [BEq α] [LawfulBEq α] {xs ys : Vector α n} : xs.isEqv ys (· == ·) = (xs = ys) := by
cases xs
cases ys
simp
@@ -1511,7 +1509,7 @@ theorem map_eq_iff {f : α → β} {as : Vector α n} {bs : Vector β n} :
if h : i < as.size then
simpa [h, h'] using w i h
else
rw [getElem?_neg, getElem?_neg, Option.map_none'] <;> omega
rw [getElem?_neg, getElem?_neg, Option.map_none] <;> omega
@[simp] theorem map_set {f : α β} {xs : Vector α n} {i : Nat} {h : i < n} {a : α} :
(xs.set i a).map f = (xs.map f).set i (f a) (by simpa using h) := by
@@ -1717,12 +1715,12 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
constructor
· rintro (as, rfl, rfl | cs, rfl, rfl)
· rw [dif_pos (by simp)]
exact as.toVector.cast (by simp; omega), by simp
exact as.toVector.cast (by simp), by simp
· split <;> rename_i h
· have hc : cs.size = 0 := by simp at h; omega
simp at hc
exact #v[].cast (by simp; omega), by simp_all
· exact cs.toVector.cast (by simp; omega), by simp
exact #v[].cast (by simp), by simp_all
· exact cs.toVector.cast (by simp), by simp
· split <;> rename_i h
· rintro as, hc, rfl
left
@@ -2677,12 +2675,7 @@ variable [LawfulBEq α]
theorem getElem?_replace {xs : Vector α n} {i : Nat} :
(xs.replace a b)[i]? = if xs[i]? == some a then if a xs.take i then some a else some b else xs[i]? := by
rcases xs with xs, rfl
simp [Array.getElem?_replace]
split <;> rename_i h
· rw (occs := [2]) [if_pos]
simpa using h
· rw [if_neg]
simpa using h
simp [Array.getElem?_replace, -beq_iff_eq]
theorem getElem?_replace_of_ne {xs : Vector α n} {i : Nat} (h : xs[i]? some a) :
(xs.replace a b)[i]? = xs[i]? := by

View File

@@ -148,13 +148,13 @@ protected theorem le_iff_lt_or_eq [DecidableEq α] [LT α] [DecidableLT α]
{xs ys : Vector α n} : xs ys xs < ys xs = ys := by
simpa using Array.le_iff_lt_or_eq (xs := xs.toArray) (ys := ys.toArray)
@[simp] theorem lex_eq_true_iff_lt [DecidableEq α] [LT α] [DecidableLT α]
@[simp] theorem lex_eq_true_iff_lt [BEq α] [LawfulBEq α] [LT α] [DecidableLT α]
{xs ys : Vector α n} : lex xs ys = true xs < ys := by
cases xs
cases ys
simp
@[simp] theorem lex_eq_false_iff_ge [DecidableEq α] [LT α] [DecidableLT α]
@[simp] theorem lex_eq_false_iff_ge [BEq α] [LawfulBEq α] [LT α] [DecidableLT α]
{xs ys : Vector α n} : lex xs ys = false ys xs := by
cases xs
cases ys

View File

@@ -0,0 +1,104 @@
/-
Copyright (c) 2024 Lean FRO. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Array.Perm
import Init.Data.Vector.Lemmas
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Vector
open List Array
/--
`Perm as bs` asserts that `as` and `bs` are permutations of each other.
This is a wrapper around `List.Perm`, and for now has much less API.
For more complicated verification, use `perm_iff_toList_perm` and the `List` API.
-/
def Perm (as bs : Vector α n) : Prop :=
as.toArray ~ bs.toArray
@[inherit_doc] scoped infixl:50 " ~ " => Perm
theorem perm_iff_toList_perm {as bs : Vector α n} : as ~ bs as.toList ~ bs.toList := Iff.rfl
theorem perm_iff_toArray_perm {as bs : Vector α n} : as ~ bs as.toArray ~ bs.toArray := Iff.rfl
@[simp] theorem perm_mk (as bs : Array α) (ha : as.size = n) (hb : bs.size = n) :
mk as ha ~ mk bs hb as ~ bs := by
simp [perm_iff_toArray_perm, ha, hb]
theorem toArray_perm_iff (xs : Vector α n) (ys : Array α) : xs.toArray ~ ys h, xs ~ Vector.mk ys h := by
constructor
· intro h
refine by simp [ h.length_eq], h
· intro h, p
exact p
theorem perm_toArray_iff (xs : Array α) (ys : Vector α n) : xs ~ ys.toArray h, Vector.mk xs h ~ ys := by
constructor
· intro h
refine by simp [h.length_eq], h
· intro h, p
exact p
@[simp, refl] protected theorem Perm.refl (xs : Vector α n) : xs ~ xs := by
cases xs
simp
protected theorem Perm.rfl {xs : List α} : xs ~ xs := .refl _
theorem Perm.of_eq {xs ys : Vector α n} (h : xs = ys) : xs ~ ys := h .rfl
protected theorem Perm.symm {xs ys : Vector α n} (h : xs ~ ys) : ys ~ xs := by
cases xs; cases ys
simp only [perm_mk] at h
simpa using h.symm
protected theorem Perm.trans {xs ys zs : Vector α n} (h₁ : xs ~ ys) (h₂ : ys ~ zs) : xs ~ zs := by
cases xs; cases ys; cases zs
simp only [perm_mk] at h₁ h₂
simpa using h₁.trans h₂
instance : Trans (Perm (α := α) (n := n)) (Perm (α := α) (n := n)) (Perm (α := α) (n := n)) where
trans h₁ h₂ := Perm.trans h₁ h₂
theorem perm_comm {xs ys : Vector α n} : xs ~ ys ys ~ xs := Perm.symm, Perm.symm
theorem Perm.mem_iff {a : α} {xs ys : Vector α n} (p : xs ~ ys) : a xs a ys := by
rcases xs with xs
rcases ys with ys
simp at p
simpa using p.mem_iff
theorem Perm.push (x y : α) {xs ys : Vector α n} (p : xs ~ ys) :
(xs.push x).push y ~ (ys.push y).push x := by
rcases xs with xs, rfl
rcases ys with ys, h
simp only [perm_mk] at p
simp only [push_mk, List.append_assoc, singleton_append, perm_toArray]
simpa using Array.Perm.push x y p
theorem swap_perm {xs : Vector α n} {i j : Nat} (h₁ : i < n) (h₂ : j < n) :
xs.swap i j ~ xs := by
rcases xs with xs, rfl
simp only [swap, perm_iff_toList_perm, toList_set]
apply set_set_perm
namespace Perm
set_option linter.indexVariables false in
theorem extract {xs ys : Vector α n} (h : xs ~ ys) {lo hi : Nat}
(wlo : i, i < lo xs[i]? = ys[i]?) (whi : i, hi i xs[i]? = ys[i]?) :
(xs.extract lo hi) ~ (ys.extract lo hi) := by
rcases xs with xs, rfl
rcases ys with ys, h
exact Array.Perm.extract h (by simpa using wlo) (by simpa using whi)
end Perm
end Vector

View File

@@ -101,9 +101,8 @@ theorem range'_eq_append_iff : range' s (n + m) = xs ++ ys ↔ xs = range' s n
simp_all
subst w
simp_all
omega
· rintro h₁, h₂
exact n, by omega, by simp_all; omega
exact n, by omega, by simp_all
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat Bool} :
(range' s n).find? p = some i p i i range' s n j, s j j < i !p j := by

View File

@@ -13,3 +13,4 @@ import Init.Grind.Util
import Init.Grind.Offset
import Init.Grind.PP
import Init.Grind.CommRing
import Init.Grind.Ext

View File

@@ -5,14 +5,31 @@ Authors: Kim Morrison
-/
prelude
import Init.Data.Zero
import Init.Data.Int.DivMod.Lemmas
import Init.Data.Int.Pow
import Init.TacticsExtra
/-!
# A monolithic commutative ring typeclass for internal use in `grind`.
The `Lean.Grind.CommRing` class will be used to convert expressions into the internal representation via polynomials,
with coefficients expressed via `OfNat` and `Neg`.
The `IsCharP α p` typeclass expresses that the ring has characteristic `p`,
i.e. that a coefficient `OfNat.ofNat x : α` is zero if and only if `x % p = 0` (in `Nat`).
See
```
theorem ofNat_ext_iff {x y : Nat} : OfNat.ofNat (α := α) x = OfNat.ofNat (α := α) y ↔ x % p = y % p
theorem ofNat_emod (x : Nat) : OfNat.ofNat (α := α) (x % p) = OfNat.ofNat x
theorem ofNat_eq_iff_of_lt {x y : Nat} (h₁ : x < p) (h₂ : y < p) :
OfNat.ofNat (α := α) x = OfNat.ofNat (α := α) y ↔ x = y
```
-/
namespace Lean.Grind
class CommRing (α : Type u) extends Add α, Zero α, Mul α, One α, Neg α where
class CommRing (α : Type u) extends Add α, Mul α, Neg α, Sub α, HPow α Nat α where
[ofNat : n, OfNat α n]
add_assoc : a b c : α, a + b + c = a + (b + c)
add_comm : a b : α, a + b = b + a
add_zero : a : α, a + 0 = a
@@ -22,17 +39,46 @@ class CommRing (α : Type u) extends Add α, Zero α, Mul α, One α, Neg α whe
mul_one : a : α, a * 1 = a
left_distrib : a b c : α, a * (b + c) = a * b + a * c
zero_mul : a : α, 0 * a = 0
sub_eq_add_neg : a b : α, a - b = a + -b
pow_zero : a : α, a ^ 0 = 1
pow_succ : a : α, n : Nat, a ^ (n + 1) = (a ^ n) * a
ofNat_succ : a : Nat, OfNat.ofNat (α := α) (a + 1) = OfNat.ofNat a + 1 := by intros; rfl
-- We reduce the priority of these parent instances,
-- so that in downstream libraries with their own `CommRing` class,
-- the path `CommRing -> Add` is found before `CommRing -> Lean.Grind.CommRing -> Add`.
-- (And similarly for the other parents.)
attribute [instance 100] CommRing.toAdd CommRing.toMul CommRing.toNeg CommRing.toSub CommRing.toHPow
-- This is a low-priority instance, to avoid conflicts with existing `OfNat` instances.
attribute [instance 100] CommRing.ofNat
namespace CommRing
variable {α : Type u} [CommRing α]
instance : NatCast α where
natCast n := OfNat.ofNat n
theorem natCast_zero : ((0 : Nat) : α) = 0 := rfl
theorem ofNat_eq_natCast (n : Nat) : OfNat.ofNat n = (n : α) := rfl
theorem ofNat_add (a b : Nat) : OfNat.ofNat (α := α) (a + b) = OfNat.ofNat a + OfNat.ofNat b := by
induction b with
| zero => simp [Nat.add_zero, add_zero]
| succ b ih => rw [Nat.add_succ, ofNat_succ, ih, ofNat_succ b, add_assoc]
theorem natCast_succ (n : Nat) : ((n + 1 : Nat) : α) = ((n : α) + 1) := ofNat_add _ _
theorem zero_add (a : α) : 0 + a = a := by
rw [add_comm, add_zero]
theorem add_neg_cancel (a : α) : a + -a = 0 := by
rw [add_comm, neg_add_cancel]
theorem add_left_comm (a b c : α) : a + (b + c) = b + (a + c) := by
rw [ add_assoc, add_assoc, add_comm a]
theorem one_mul (a : α) : 1 * a = a := by
rw [mul_comm, mul_one]
@@ -42,6 +88,217 @@ theorem right_distrib (a b c : α) : (a + b) * c = a * c + b * c := by
theorem mul_zero (a : α) : a * 0 = 0 := by
rw [mul_comm, zero_mul]
theorem mul_left_comm (a b c : α) : a * (b * c) = b * (a * c) := by
rw [ mul_assoc, mul_assoc, mul_comm a]
theorem ofNat_mul (a b : Nat) : OfNat.ofNat (α := α) (a * b) = OfNat.ofNat a * OfNat.ofNat b := by
induction b with
| zero => simp [Nat.mul_zero, mul_zero]
| succ a ih => rw [Nat.mul_succ, ofNat_add, ih, ofNat_add, left_distrib, mul_one]
theorem add_left_inj {a b : α} (c : α) : a + c = b + c a = b :=
fun h => by simpa [add_assoc, add_neg_cancel, add_zero] using (congrArg (· + -c) h),
fun g => congrArg (· + c) g
theorem add_right_inj (a b c : α) : a + b = a + c b = c := by
rw [add_comm a b, add_comm a c, add_left_inj]
theorem neg_zero : (-0 : α) = 0 := by
rw [ add_left_inj 0, neg_add_cancel, add_zero]
theorem neg_neg (a : α) : -(-a) = a := by
rw [ add_left_inj (-a), neg_add_cancel, add_neg_cancel]
theorem neg_eq_zero (a : α) : -a = 0 a = 0 :=
fun h => by
replace h := congrArg (-·) h
simpa [neg_neg, neg_zero] using h,
fun h => by rw [h, neg_zero]
theorem neg_add (a b : α) : -(a + b) = -a + -b := by
rw [ add_left_inj (a + b), neg_add_cancel, add_assoc (-a), add_comm a b, add_assoc (-b),
neg_add_cancel, zero_add, neg_add_cancel]
theorem neg_sub (a b : α) : -(a - b) = b - a := by
rw [sub_eq_add_neg, neg_add, neg_neg, sub_eq_add_neg, add_comm]
theorem sub_self (a : α) : a - a = 0 := by
rw [sub_eq_add_neg, add_neg_cancel]
instance : IntCast α where
intCast n := match n with
| Int.ofNat n => OfNat.ofNat n
| Int.negSucc n => -OfNat.ofNat (n + 1)
theorem intCast_zero : ((0 : Int) : α) = 0 := rfl
theorem intCast_one : ((1 : Int) : α) = 1 := rfl
theorem intCast_neg_one : ((-1 : Int) : α) = -1 := rfl
theorem intCast_ofNat (n : Nat) : ((n : Int) : α) = (n : α) := rfl
theorem intCast_ofNat_add_one (n : Nat) : ((n + 1 : Int) : α) = (n : α) + 1 := ofNat_add _ _
theorem intCast_negSucc (n : Nat) : ((-(n + 1) : Int) : α) = -((n : α) + 1) := congrArg (- ·) (ofNat_add _ _)
theorem intCast_neg (x : Int) : ((-x : Int) : α) = - (x : α) :=
match x with
| (0 : Nat) => neg_zero.symm
| (n + 1 : Nat) => by
rw [Int.natCast_add, Int.cast_ofNat_Int, intCast_negSucc, intCast_ofNat_add_one]
| -((n : Nat) + 1) => by
rw [Int.neg_neg, intCast_ofNat_add_one, intCast_negSucc, neg_neg]
theorem intCast_nat_add {x y : Nat} : ((x + y : Int) : α) = ((x : α) + (y : α)) := ofNat_add _ _
theorem intCast_nat_sub {x y : Nat} (h : x y) : (((x - y : Nat) : Int) : α) = ((x : α) - (y : α)) := by
induction x with
| zero =>
have : y = 0 := by omega
simp [this, intCast_zero, natCast_zero, sub_eq_add_neg, zero_add, neg_zero]
| succ x ih =>
by_cases h : x + 1 = y
· simp [h, intCast_zero, sub_self]
· have : ((x + 1 - y : Nat) : Int) = (x - y : Nat) + 1 := by omega
rw [this, intCast_ofNat_add_one]
specialize ih (by omega)
rw [intCast_ofNat] at ih
rw [ih, natCast_succ, sub_eq_add_neg, sub_eq_add_neg, add_assoc, add_comm _ 1, add_assoc]
theorem intCast_add (x y : Int) : ((x + y : Int) : α) = ((x : α) + (y : α)) :=
match x, y with
| (x : Nat), (y : Nat) => ofNat_add _ _
| (x : Nat), (-(y + 1 : Nat)) => by
by_cases h : x y + 1
· have : (x + -(y+1 : Nat) : Int) = ((x - (y + 1) : Nat) : Int) := by omega
rw [this, intCast_neg, intCast_nat_sub h, intCast_ofNat, intCast_ofNat, sub_eq_add_neg]
· have : (x + -(y+1 : Nat) : Int) = (-(y + 1 - x : Nat) : Int) := by omega
rw [this, intCast_neg, intCast_nat_sub (by omega), intCast_ofNat, intCast_neg, intCast_ofNat,
neg_sub, sub_eq_add_neg]
| (-(x + 1 : Nat)), (y : Nat) => by
by_cases h : y x+ 1
· have : (-(x+1 : Nat) + y : Int) = ((y - (x + 1) : Nat) : Int) := by omega
rw [this, intCast_neg, intCast_nat_sub h, intCast_ofNat, intCast_ofNat, sub_eq_add_neg, add_comm]
· have : (-(x+1 : Nat) + y : Int) = (-(x + 1 - y : Nat) : Int) := by omega
rw [this, intCast_neg, intCast_nat_sub (by omega), intCast_ofNat, intCast_neg, intCast_ofNat,
neg_sub, sub_eq_add_neg, add_comm]
| (-(x + 1 : Nat)), (-(y + 1 : Nat)) => by
rw [ Int.neg_add, intCast_neg, intCast_nat_add, neg_add, intCast_neg, intCast_neg, intCast_ofNat, intCast_ofNat]
theorem intCast_sub (x y : Int) : ((x - y : Int) : α) = ((x : α) - (y : α)) := by
rw [Int.sub_eq_add_neg, intCast_add, intCast_neg, sub_eq_add_neg]
theorem neg_eq_neg_one_mul (a : α) : -a = (-1) * a := by
rw [ add_left_inj a, neg_add_cancel]
conv => rhs; arg 2; rw [ one_mul a]
rw [ right_distrib, intCast_neg_one, intCast_one (α := α)]
simp [ intCast_add, intCast_zero, zero_mul]
theorem neg_mul (a b : α) : (-a) * b = -(a * b) := by
rw [neg_eq_neg_one_mul a, neg_eq_neg_one_mul (a * b), mul_assoc]
theorem mul_neg (a b : α) : a * (-b) = -(a * b) := by
rw [mul_comm, neg_mul, mul_comm]
theorem intCast_nat_mul (x y : Nat) : ((x * y : Int) : α) = ((x : α) * (y : α)) := ofNat_mul _ _
theorem intCast_mul (x y : Int) : ((x * y : Int) : α) = ((x : α) * (y : α)) :=
match x, y with
| (x : Nat), (y : Nat) => ofNat_mul _ _
| (x : Nat), (-(y + 1 : Nat)) => by
rw [Int.mul_neg, intCast_neg, intCast_nat_mul, intCast_neg, mul_neg, intCast_ofNat, intCast_ofNat]
| (-(x + 1 : Nat)), (y : Nat) => by
rw [Int.neg_mul, intCast_neg, intCast_nat_mul, intCast_neg, neg_mul, intCast_ofNat, intCast_ofNat]
| (-(x + 1 : Nat)), (-(y + 1 : Nat)) => by
rw [Int.neg_mul_neg, intCast_neg, intCast_neg, neg_mul, mul_neg, neg_neg, intCast_nat_mul,
intCast_ofNat, intCast_ofNat]
theorem intCast_pow (x : Int) (k : Nat) : ((x ^ k : Int) : α) = (x : α) ^ k := by
induction k
next => simp [pow_zero, Int.pow_zero, intCast_one]
next k ih => simp [pow_succ, Int.pow_succ, intCast_mul, *]
theorem pow_add (a : α) (k₁ k₂ : Nat) : a ^ (k₁ + k₂) = a^k₁ * a^k₂ := by
induction k₂
next => simp [pow_zero, mul_one]
next k₂ ih => rw [Nat.add_succ, pow_succ, pow_succ, ih, mul_assoc]
end CommRing
open CommRing
class IsCharP (α : Type u) [CommRing α] (p : Nat) where
ofNat_eq_zero_iff (p) : (x : Nat), OfNat.ofNat (α := α) x = 0 x % p = 0
namespace IsCharP
variable (p) {α : Type u} [CommRing α] [IsCharP α p]
theorem natCast_eq_zero_iff (x : Nat) : (x : α) = 0 x % p = 0 :=
ofNat_eq_zero_iff p x
theorem intCast_eq_zero_iff (x : Int) : (x : α) = 0 x % p = 0 :=
match x with
| (x : Nat) => by
have := ofNat_eq_zero_iff (α := α) p (x := x)
rw [Int.ofNat_mod_ofNat]
norm_cast
| -(x + 1 : Nat) => by
rw [Int.neg_emod, Int.ofNat_mod_ofNat, intCast_neg, intCast_ofNat, neg_eq_zero]
have := ofNat_eq_zero_iff (α := α) p (x := x + 1)
rw [ofNat_eq_natCast] at this
rw [this]
simp only [Int.ofNat_dvd]
simp only [ Nat.dvd_iff_mod_eq_zero, Int.natAbs_natCast, Int.natCast_add,
Int.cast_ofNat_Int, ite_eq_left_iff]
by_cases h : p x + 1
· simp [h]
· simp only [h, not_false_eq_true, Int.natCast_add, Int.cast_ofNat_Int,
forall_const, false_iff, ne_eq]
by_cases w : p = 0
· simp [w]
omega
· have : ((x + 1) % p) < p := Nat.mod_lt _ (by omega)
omega
theorem intCast_ext_iff {x y : Int} : (x : α) = (y : α) x % p = y % p := by
constructor
· intro h
replace h : ((x - y : Int) : α) = 0 := by rw [intCast_sub, h, sub_self]
exact Int.emod_eq_emod_iff_emod_sub_eq_zero.mpr ((intCast_eq_zero_iff p _).mp h)
· intro h
have : ((x - y : Int) : α) = 0 :=
(intCast_eq_zero_iff p _).mpr (by rw [Int.sub_emod, h, Int.sub_self, Int.zero_emod])
replace this := congrArg (· + (y : α)) this
simpa [intCast_sub, zero_add, sub_eq_add_neg, add_assoc, neg_add_cancel, add_zero] using this
theorem ofNat_ext_iff {x y : Nat} : OfNat.ofNat (α := α) x = OfNat.ofNat (α := α) y x % p = y % p := by
have := intCast_ext_iff (α := α) p (x := x) (y := y)
simp only [intCast_ofNat, Int.ofNat_emod] at this
simp only [ofNat_eq_natCast]
norm_cast at this
theorem ofNat_ext {x y : Nat} (h : x % p = y % p) : OfNat.ofNat (α := α) x = OfNat.ofNat (α := α) y := (ofNat_ext_iff p).mpr h
theorem natCast_ext {x y : Nat} (h : x % p = y % p) : (x : α) = (y : α) := ofNat_ext _ h
theorem natCast_ext_iff {x y : Nat} : (x : α) = (y : α) x % p = y % p :=
ofNat_ext_iff p
theorem intCast_emod (x : Int) : ((x % p : Int) : α) = (x : α) := by
rw [intCast_ext_iff p, Int.emod_emod]
theorem natCast_emod (x : Nat) : ((x % p : Nat) : α) = (x : α) := by
simp only [ intCast_ofNat]
rw [Int.ofNat_emod, intCast_emod]
theorem ofNat_emod (x : Nat) : OfNat.ofNat (α := α) (x % p) = OfNat.ofNat x :=
natCast_emod _ _
theorem ofNat_eq_zero_iff_of_lt {x : Nat} (h : x < p) : OfNat.ofNat (α := α) x = 0 x = 0 := by
rw [ofNat_eq_zero_iff p, Nat.mod_eq_of_lt h]
theorem ofNat_eq_iff_of_lt {x y : Nat} (h₁ : x < p) (h₂ : y < p) :
OfNat.ofNat (α := α) x = OfNat.ofNat (α := α) y x = y := by
rw [ofNat_ext_iff p, Nat.mod_eq_of_lt h₁, Nat.mod_eq_of_lt h₂]
theorem natCast_eq_zero_iff_of_lt {x : Nat} (h : x < p) : (x : α) = 0 x = 0 := by
rw [natCast_eq_zero_iff p, Nat.mod_eq_of_lt h]
theorem natCast_eq_iff_of_lt {x y : Nat} (h₁ : x < p) (h₂ : y < p) :
(x : α) = (y : α) x = y := by
rw [natCast_ext_iff p, Nat.mod_eq_of_lt h₁, Nat.mod_eq_of_lt h₂]
end IsCharP
end Lean.Grind

View File

@@ -19,5 +19,12 @@ instance : CommRing (BitVec w) where
mul_one := BitVec.mul_one
left_distrib _ _ _ := BitVec.mul_add
zero_mul _ := BitVec.zero_mul
sub_eq_add_neg := BitVec.sub_eq_add_neg
pow_zero _ := BitVec.pow_zero
pow_succ _ _ := BitVec.pow_succ
ofNat_succ x := BitVec.ofNat_add x 1
instance : IsCharP (BitVec w) (2 ^ w) where
ofNat_eq_zero_iff {x} := by simp [BitVec.ofInt, BitVec.toNat_eq]
end Lean.Grind

View File

@@ -19,5 +19,12 @@ instance : CommRing Int where
mul_one := Int.mul_one
left_distrib := Int.mul_add
zero_mul := Int.zero_mul
pow_zero _ := rfl
pow_succ _ _ := rfl
ofNat_succ _ := rfl
sub_eq_add_neg _ _ := Int.sub_eq_add_neg
instance : IsCharP Int 0 where
ofNat_eq_zero_iff {x} := by erw [Int.ofNat_eq_zero]; simp
end Lean.Grind

View File

@@ -9,6 +9,9 @@ import Init.Data.SInt.Lemmas
namespace Lean.Grind
instance : IntCast Int8 where
intCast x := Int8.ofInt x
instance : CommRing Int8 where
add_assoc := Int8.add_assoc
add_comm := Int8.add_comm
@@ -19,6 +22,20 @@ instance : CommRing Int8 where
mul_one := Int8.mul_one
left_distrib _ _ _ := Int8.mul_add
zero_mul _ := Int8.zero_mul
sub_eq_add_neg := Int8.sub_eq_add_neg
pow_zero := Int8.pow_zero
pow_succ := Int8.pow_succ
ofNat_succ x := Int8.ofNat_add x 1
instance : IsCharP Int8 (2 ^ 8) where
ofNat_eq_zero_iff {x} := by
have : OfNat.ofNat x = Int8.ofInt x := rfl
rw [this]
simp [Int8.ofInt_eq_iff_bmod_eq_toInt,
Int.dvd_iff_bmod_eq_zero, Nat.dvd_iff_mod_eq_zero, Int.ofNat_dvd_right]
instance : IntCast Int16 where
intCast x := Int16.ofInt x
instance : CommRing Int16 where
add_assoc := Int16.add_assoc
@@ -30,6 +47,20 @@ instance : CommRing Int16 where
mul_one := Int16.mul_one
left_distrib _ _ _ := Int16.mul_add
zero_mul _ := Int16.zero_mul
sub_eq_add_neg := Int16.sub_eq_add_neg
pow_zero := Int16.pow_zero
pow_succ := Int16.pow_succ
ofNat_succ x := Int16.ofNat_add x 1
instance : IsCharP Int16 (2 ^ 16) where
ofNat_eq_zero_iff {x} := by
have : OfNat.ofNat x = Int16.ofInt x := rfl
rw [this]
simp [Int16.ofInt_eq_iff_bmod_eq_toInt,
Int.dvd_iff_bmod_eq_zero, Nat.dvd_iff_mod_eq_zero, Int.ofNat_dvd_right]
instance : IntCast Int32 where
intCast x := Int32.ofInt x
instance : CommRing Int32 where
add_assoc := Int32.add_assoc
@@ -41,6 +72,20 @@ instance : CommRing Int32 where
mul_one := Int32.mul_one
left_distrib _ _ _ := Int32.mul_add
zero_mul _ := Int32.zero_mul
sub_eq_add_neg := Int32.sub_eq_add_neg
pow_zero := Int32.pow_zero
pow_succ := Int32.pow_succ
ofNat_succ x := Int32.ofNat_add x 1
instance : IsCharP Int32 (2 ^ 32) where
ofNat_eq_zero_iff {x} := by
have : OfNat.ofNat x = Int32.ofInt x := rfl
rw [this]
simp [Int32.ofInt_eq_iff_bmod_eq_toInt,
Int.dvd_iff_bmod_eq_zero, Nat.dvd_iff_mod_eq_zero, Int.ofNat_dvd_right]
instance : IntCast Int64 where
intCast x := Int64.ofInt x
instance : CommRing Int64 where
add_assoc := Int64.add_assoc
@@ -52,6 +97,20 @@ instance : CommRing Int64 where
mul_one := Int64.mul_one
left_distrib _ _ _ := Int64.mul_add
zero_mul _ := Int64.zero_mul
sub_eq_add_neg := Int64.sub_eq_add_neg
pow_zero := Int64.pow_zero
pow_succ := Int64.pow_succ
ofNat_succ x := Int64.ofNat_add x 1
instance : IsCharP Int64 (2 ^ 64) where
ofNat_eq_zero_iff {x} := by
have : OfNat.ofNat x = Int64.ofInt x := rfl
rw [this]
simp [Int64.ofInt_eq_iff_bmod_eq_toInt,
Int.dvd_iff_bmod_eq_zero, Nat.dvd_iff_mod_eq_zero, Int.ofNat_dvd_right]
instance : IntCast ISize where
intCast x := ISize.ofInt x
instance : CommRing ISize where
add_assoc := ISize.add_assoc
@@ -63,5 +122,18 @@ instance : CommRing ISize where
mul_one := ISize.mul_one
left_distrib _ _ _ := ISize.mul_add
zero_mul _ := ISize.zero_mul
sub_eq_add_neg := ISize.sub_eq_add_neg
pow_zero := ISize.pow_zero
pow_succ := ISize.pow_succ
ofNat_succ x := ISize.ofNat_add x 1
open System.Platform (numBits)
instance : IsCharP ISize (2 ^ numBits) where
ofNat_eq_zero_iff {x} := by
have : OfNat.ofNat x = ISize.ofInt x := rfl
rw [this]
simp [ISize.ofInt_eq_iff_bmod_eq_toInt,
Int.dvd_iff_bmod_eq_zero, Nat.dvd_iff_mod_eq_zero, Int.ofNat_dvd_right]
end Lean.Grind

View File

@@ -0,0 +1,503 @@
/-
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Init.Data.Nat.Lemmas
import Init.Data.Ord
import Init.Grind.CommRing.Basic
namespace Lean.Grind
namespace CommRing
abbrev Var := Nat
inductive Expr where
| num (v : Int)
| var (i : Var)
| neg (a : Expr)
| add (a b : Expr)
| sub (a b : Expr)
| mul (a b : Expr)
| pow (a : Expr) (k : Nat)
deriving Inhabited, BEq
-- TODO: add support for universes to Lean.RArray
inductive RArray (α : Type u) : Type u where
| leaf : α RArray α
| branch : Nat RArray α RArray α RArray α
def RArray.get (a : RArray α) (n : Nat) : α :=
match a with
| .leaf x => x
| .branch p l r => if n < p then l.get n else r.get n
abbrev Context (α : Type u) := RArray α
def Var.denote (ctx : Context α) (v : Var) : α :=
ctx.get v
def Expr.denote [CommRing α] (ctx : Context α) : Expr α
| .add a b => denote ctx a + denote ctx b
| .sub a b => denote ctx a - denote ctx b
| .mul a b => denote ctx a * denote ctx b
| .neg a => -denote ctx a
| .num k => k
| .var v => v.denote ctx
| .pow a k => denote ctx a ^ k
structure Power where
x : Var
k : Nat
deriving BEq, Repr
def Power.varLt (p₁ p₂ : Power) : Bool :=
p₁.x.blt p₂.x
def Power.denote [CommRing α] (ctx : Context α) : Power α
| {x, k} =>
match k with
| 0 => 1
| 1 => x.denote ctx
| k => x.denote ctx ^ k
inductive Mon where
| leaf (p : Power)
| cons (p : Power) (m : Mon)
deriving BEq, Repr
def Mon.denote [CommRing α] (ctx : Context α) : Mon α
| .leaf p => p.denote ctx
| .cons p m => p.denote ctx * denote ctx m
def Mon.denote' [CommRing α] (ctx : Context α) : Mon α
| .leaf p => p.denote ctx
| .cons p m => go (p.denote ctx) m
where
go (acc : α) : Mon α
| .leaf p => acc * p.denote ctx
| .cons p m => go (acc * p.denote ctx) m
def Mon.ofVar (x : Var) : Mon :=
.leaf { x, k := 1 }
def Mon.concat (m₁ m₂ : Mon) : Mon :=
match m₁ with
| .leaf p => .cons p m₂
| .cons p m₁ => .cons p (concat m₁ m₂)
def Mon.mulPow (p : Power) (m : Mon) : Mon :=
match m with
| .leaf p' =>
bif p.varLt p' then
.cons p m
else bif p'.varLt p then
.cons p' (.leaf p)
else
.leaf { x := p.x, k := p.k + p'.k }
| .cons p' m =>
bif p.varLt p' then
.cons p (.cons p' m)
else bif p'.varLt p then
.cons p' (mulPow p m)
else
.cons { x := p.x, k := p.k + p'.k } m
def Mon.length : Mon Nat
| .leaf _ => 1
| .cons _ m => 1 + length m
def hugeFuel := 1000000
def Mon.mul (m₁ m₂ : Mon) : Mon :=
-- We could use `m₁.length + m₂.length` to avoid hugeFuel
go hugeFuel m₁ m₂
where
go (fuel : Nat) (m₁ m₂ : Mon) : Mon :=
match fuel with
| 0 => concat m₁ m₂
| fuel + 1 =>
match m₁, m₂ with
| m₁, .leaf p => m₁.mulPow p
| .leaf p, m₂ => m₂.mulPow p
| .cons p₁ m₁, .cons p₂ m₂ =>
bif p₁.varLt p₂ then
.cons p₁ (go fuel m₁ (.cons p₂ m₂))
else bif p₂.varLt p₁ then
.cons p₂ (go fuel (.cons p₁ m₁) m₂)
else
.cons { x := p₁.x, k := p₁.k + p₂.k } (go fuel m₁ m₂)
def Mon.degree : Mon Nat
| .leaf p => p.k
| .cons p m => p.k + degree m
def Var.revlex (x y : Var) : Ordering :=
bif x.blt y then .gt
else bif y.blt x then .lt
else .eq
def powerRevlex (k₁ k₂ : Nat) : Ordering :=
bif k₁.blt k₂ then .gt
else bif k₂.blt k₁ then .lt
else .eq
def Power.revlex (p₁ p₂ : Power) : Ordering :=
p₁.x.revlex p₂.x |>.then (powerRevlex p₁.k p₂.k)
def Mon.revlexWF (m₁ m₂ : Mon) : Ordering :=
match m₁, m₂ with
| .leaf p₁, .leaf p₂ => p₁.revlex p₂
| .leaf p₁, .cons p₂ m₂ =>
bif p₁.x.ble p₂.x then
.gt
else
revlexWF (.leaf p₁) m₂ |>.then .gt
| .cons p₁ m₁, .leaf p₂ =>
bif p₂.x.ble p₁.x then
.lt
else
revlexWF m₁ (.leaf p₂) |>.then .lt
| .cons p₁ m₁, .cons p₂ m₂ =>
bif p₁.x == p₂.x then
revlexWF m₁ m₂ |>.then (powerRevlex p₁.k p₂.k)
else bif p₁.x.blt p₂.x then
revlexWF m₁ (.cons p₂ m₂) |>.then .gt
else
revlexWF (.cons p₁ m₁) m₂ |>.then .lt
def Mon.revlexFuel (fuel : Nat) (m₁ m₂ : Mon) : Ordering :=
match fuel with
| 0 =>
-- This branch is not reachable in practice, but we add it here
-- to ensure we can prove helper theorems
revlexWF m₁ m₂
| fuel + 1 =>
match m₁, m₂ with
| .leaf p₁, .leaf p₂ => p₁.revlex p₂
| .leaf p₁, .cons p₂ m₂ =>
bif p₁.x.ble p₂.x then
.gt
else
revlexFuel fuel (.leaf p₁) m₂ |>.then .gt
| .cons p₁ m₁, .leaf p₂ =>
bif p₂.x.ble p₁.x then
.lt
else
revlexFuel fuel m₁ (.leaf p₂) |>.then .lt
| .cons p₁ m₁, .cons p₂ m₂ =>
bif p₁.x == p₂.x then
revlexFuel fuel m₁ m₂ |>.then (powerRevlex p₁.k p₂.k)
else bif p₁.x.blt p₂.x then
revlexFuel fuel m₁ (.cons p₂ m₂) |>.then .gt
else
revlexFuel fuel (.cons p₁ m₁) m₂ |>.then .lt
def Mon.revlex (m₁ m₂ : Mon) : Ordering :=
revlexFuel hugeFuel m₁ m₂
def Mon.grevlex (m₁ m₂ : Mon) : Ordering :=
compare m₁.degree m₂.degree |>.then (revlex m₁ m₂)
inductive Poly where
| num (k : Int)
| add (k : Int) (v : Mon) (p : Poly)
deriving BEq
def Poly.denote [CommRing α] (ctx : Context α) (p : Poly) : α :=
match p with
| .num k => Int.cast k
| .add k m p => Int.cast k * m.denote ctx + denote ctx p
def Poly.ofMon (m : Mon) : Poly :=
.add 1 m (.num 0)
def Poly.ofVar (x : Var) : Poly :=
ofMon (Mon.ofVar x)
def Poly.addConst (p : Poly) (k : Int) : Poly :=
match p with
| .num k' => .num (k' + k)
| .add k' m p => .add k' m (addConst p k)
def Poly.insert (k : Int) (m : Mon) (p : Poly) : Poly :=
match p with
| .num k' => .add k m (.num k')
| .add k' m' p =>
match m.grevlex m' with
| .eq =>
let k'' := k + k'
bif k'' == 0 then
p
else
.add k'' m p
| .lt => .add k m (.add k' m' p)
| .gt => .add k' m' (insert k m p)
def Poly.concat (p₁ p₂ : Poly) : Poly :=
match p₁ with
| .num k₁ => p₂.addConst k₁
| .add k m p₁ => .add k m (concat p₁ p₂)
def Poly.mulConst (k : Int) (p : Poly) : Poly :=
bif k == 0 then
.num 0
else
go p
where
go : Poly Poly
| .num k' => .num (k*k')
| .add k' m p => .add (k*k') m (go p)
def Poly.mulMon (k : Int) (m : Mon) (p : Poly) : Poly :=
bif k == 0 then
.num 0
else
go p
where
go : Poly Poly
| .num k' => .add (k*k') m (.num 0)
| .add k' m' p => .add (k*k') (m.mul m') (go p)
def Poly.combine (p₁ p₂ : Poly) : Poly :=
go hugeFuel p₁ p₂
where
go (fuel : Nat) (p₁ p₂ : Poly) : Poly :=
match fuel with
| 0 => p₁.concat p₂
| fuel + 1 => match p₁, p₂ with
| .num k₁, .num k₂ => .num (k₁ + k₂)
| .num k₁, .add k₂ m₂ p₂ => addConst (.add k₂ m₂ p₂) k₁
| .add k₁ m₁ p₁, .num k₂ => addConst (.add k₁ m₁ p₁) k₂
| .add k₁ m₁ p₁, .add k₂ m₂ p₂ =>
match m₁.grevlex m₂ with
| .eq =>
let k := k₁ + k₂
bif k == 0 then
go fuel p₁ p₂
else
.add k m₁ (go fuel p₁ p₂)
| .lt => .add k₁ m₁ (go fuel p₁ (.add k₂ m₂ p₂))
| .gt => .add k₂ m₂ (go fuel (.add k₁ m₁ p₁) p₂)
def Poly.mul (p₁ : Poly) (p₂ : Poly) : Poly :=
go p₁ (.num 0)
where
go (p₁ : Poly) (acc : Poly) : Poly :=
match p₁ with
| .num k => acc.combine (p₂.mulConst k)
| .add k m p₁ => go p₁ (acc.combine (p₂.mulMon k m))
-- TODO: optimize
def Poly.pow (p : Poly) (k : Nat) : Poly :=
match k with
| 0 => .num 1
| 1 => p
| k+1 => p.mul (pow p k)
def Expr.toPoly : Expr Poly
| .num n => .num n
| .var x => Poly.ofVar x
| .add a b => a.toPoly.combine b.toPoly
| .mul a b => a.toPoly.mul b.toPoly
| .neg a => a.toPoly.mulConst (-1)
| .sub a b => a.toPoly.combine (b.toPoly.mulConst (-1))
| .pow a k =>
match a with
| .num n => .num (n^k)
| .var x => Poly.ofMon (.leaf {x, k})
| _ => a.toPoly.pow k
theorem Power.denote_eq [CommRing α] (ctx : Context α) (p : Power)
: p.denote ctx = p.x.denote ctx ^ p.k := by
cases p <;> simp [Power.denote] <;> split <;> simp [pow_zero, pow_succ, one_mul]
theorem Mon.denote'_go_eq_denote [CommRing α] (ctx : Context α) (a : α) (m : Mon)
: denote'.go ctx a m = a * denote ctx m := by
induction m generalizing a <;> simp [Mon.denote, Mon.denote'.go]
next p' m ih =>
simp [Mon.denote] at ih
rw [ih, mul_assoc]
theorem Mon.denote'_eq_denote [CommRing α] (ctx : Context α) (m : Mon)
: denote' ctx m = denote ctx m := by
cases m <;> simp [Mon.denote, Mon.denote']
next p m => apply denote'_go_eq_denote
theorem Mon.denote_ofVar [CommRing α] (ctx : Context α) (x : Var)
: denote ctx (ofVar x) = x.denote ctx := by
simp [denote, ofVar, Power.denote_eq, pow_succ, pow_zero, one_mul]
theorem Mon.denote_concat [CommRing α] (ctx : Context α) (m₁ m₂ : Mon)
: denote ctx (concat m₁ m₂) = m₁.denote ctx * m₂.denote ctx := by
induction m₁ <;> simp [concat, denote, *]
next p₁ m₁ ih => rw [mul_assoc]
private theorem le_of_blt_false {a b : Nat} : a.blt b = false b a := by
intro h; apply Nat.le_of_not_gt; show ¬a < b
rw [ Nat.blt_eq, h]; simp
private theorem eq_of_blt_false {a b : Nat} : a.blt b = false b.blt a = false a = b := by
intro h₁ h₂
replace h₁ := le_of_blt_false h₁
replace h₂ := le_of_blt_false h₂
exact Nat.le_antisymm h₂ h₁
theorem Mon.denote_mulPow [CommRing α] (ctx : Context α) (p : Power) (m : Mon)
: denote ctx (mulPow p m) = p.denote ctx * m.denote ctx := by
fun_induction mulPow <;> simp [mulPow, *]
next => simp [denote]
next => simp [denote]; rw [mul_comm]
next p' h₁ h₂ =>
have := eq_of_blt_false h₁ h₂
simp [denote, Power.denote_eq, this, pow_add]
next => simp [denote]
next => simp [denote, mul_assoc, mul_comm, mul_left_comm, *]
next h₁ h₂ =>
have := eq_of_blt_false h₁ h₂
simp [denote, Power.denote_eq, pow_add, this, mul_assoc]
theorem Mon.denote_mul [CommRing α] (ctx : Context α) (m₁ m₂ : Mon)
: denote ctx (mul m₁ m₂) = m₁.denote ctx * m₂.denote ctx := by
unfold mul
generalize hugeFuel = fuel
fun_induction mul.go <;> simp [mul.go, denote, denote_concat, denote_mulPow, *]
next => rw [mul_comm]
next => simp [mul_assoc]
next => simp [mul_assoc, mul_left_comm, mul_comm]
next h₁ h₂ _ =>
have := eq_of_blt_false h₁ h₂
simp [Power.denote_eq, pow_add, mul_assoc, mul_left_comm, mul_comm, this]
theorem Var.eq_of_revlex {x₁ x₂ : Var} : x₁.revlex x₂ = .eq x₁ = x₂ := by
simp [revlex, cond_eq_if] <;> split <;> simp
next h₁ => intro h₂; exact Nat.le_antisymm h₂ (Nat.ge_of_not_lt h₁)
theorem eq_of_powerRevlex {k₁ k₂ : Nat} : powerRevlex k₁ k₂ = .eq k₁ = k₂ := by
simp [powerRevlex, cond_eq_if] <;> split <;> simp
next h₁ => intro h₂; exact Nat.le_antisymm h₂ (Nat.ge_of_not_lt h₁)
theorem Power.eq_of_revlex (p₁ p₂ : Power) : p₁.revlex p₂ = .eq p₁ = p₂ := by
cases p₁; cases p₂; simp [revlex, Ordering.then]; split
next h₁ => intro h₂; simp [Var.eq_of_revlex h₁, eq_of_powerRevlex h₂]
next h₁ => intro h₂; simp [h₂] at h₁
private theorem then_gt (o : Ordering) : ¬ o.then .gt = .eq := by
cases o <;> simp [Ordering.then]
private theorem then_lt (o : Ordering) : ¬ o.then .lt = .eq := by
cases o <;> simp [Ordering.then]
private theorem then_eq (o₁ o₂ : Ordering) : o₁.then o₂ = .eq o₁ = .eq o₂ = .eq := by
cases o₁ <;> cases o₂ <;> simp [Ordering.then]
theorem Mon.eq_of_revlexWF {m₁ m₂ : Mon} : m₁.revlexWF m₂ = .eq m₁ = m₂ := by
fun_induction revlexWF <;> simp [revlexWF, *, then_gt, then_lt, then_eq]
next => apply Power.eq_of_revlex
next p₁ m₁ p₂ m₂ h ih =>
cases p₁; cases p₂; intro h₁ h₂; simp [ih h₁, h]
simp at h h₂
simp [h, eq_of_powerRevlex h₂]
theorem Mon.eq_of_revlexFuel {fuel : Nat} {m₁ m₂ : Mon} : revlexFuel fuel m₁ m₂ = .eq m₁ = m₂ := by
fun_induction revlexFuel <;> simp [revlexFuel, *, then_gt, then_lt, then_eq]
next => apply eq_of_revlexWF
next => apply Power.eq_of_revlex
next p₁ m₁ p₂ m₂ h ih =>
cases p₁; cases p₂; intro h₁ h₂; simp [ih h₁, h]
simp at h h₂
simp [h, eq_of_powerRevlex h₂]
theorem Mon.eq_of_revlex {m₁ m₂ : Mon} : revlex m₁ m₂ = .eq m₁ = m₂ := by
apply eq_of_revlexFuel
theorem Mon.eq_of_grevlex {m₁ m₂ : Mon} : grevlex m₁ m₂ = .eq m₁ = m₂ := by
simp [grevlex, then_eq]; intro; apply eq_of_revlex
theorem Poly.denote_ofMon [CommRing α] (ctx : Context α) (m : Mon)
: denote ctx (ofMon m) = m.denote ctx := by
simp [ofMon, denote, intCast_one, intCast_zero, one_mul, add_zero]
theorem Poly.denote_ofVar [CommRing α] (ctx : Context α) (x : Var)
: denote ctx (ofVar x) = x.denote ctx := by
simp [ofVar, denote_ofMon, Mon.denote_ofVar]
theorem Poly.denote_addConst [CommRing α] (ctx : Context α) (p : Poly) (k : Int) : (addConst p k).denote ctx = p.denote ctx + k := by
fun_induction addConst <;> simp [addConst, denote, *]
next => rw [intCast_add]
next => simp [add_comm, add_left_comm, add_assoc]
theorem Poly.denote_insert [CommRing α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
: (insert k m p).denote ctx = k * m.denote ctx + p.denote ctx := by
fun_induction insert <;> simp_all +zetaDelta [insert, denote, cond_eq_if]
next h₁ _ h₂ =>
rw [ add_assoc, Mon.eq_of_grevlex h₁, right_distrib, intCast_add, h₂, intCast_zero, zero_mul, zero_add]
next h₁ _ _ =>
rw [intCast_add, right_distrib, add_assoc, Mon.eq_of_grevlex h₁]
next =>
rw [add_left_comm]
theorem Poly.denote_concat [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
: (concat p₁ p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
fun_induction concat <;> simp [concat, *, denote_addConst, denote]
next => rw [add_comm]
next => rw [add_assoc]
theorem Poly.denote_mulConst [CommRing α] (ctx : Context α) (k : Int) (p : Poly)
: (mulConst k p).denote ctx = k * p.denote ctx := by
simp [mulConst, cond_eq_if] <;> split
next => simp [denote, *, intCast_zero, zero_mul]
next =>
fun_induction mulConst.go <;> simp [mulConst.go, denote, *]
next => rw [intCast_mul]
next => rw [intCast_mul, left_distrib, mul_assoc]
theorem Poly.denote_mulMon [CommRing α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
: (mulMon k m p).denote ctx = k * m.denote ctx * p.denote ctx := by
simp [mulMon, cond_eq_if] <;> split
next => simp [denote, *, intCast_zero, zero_mul]
next =>
fun_induction mulMon.go <;> simp [mulMon.go, denote, *]
next => simp [intCast_mul, intCast_zero, add_zero, mul_comm, mul_left_comm, mul_assoc]
next => simp [Mon.denote_mul, intCast_mul, left_distrib, mul_comm, mul_left_comm, mul_assoc]
theorem Poly.denote_combine [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
: (combine p₁ p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
unfold combine; generalize hugeFuel = fuel
fun_induction combine.go
<;> simp [combine.go, *, denote_concat, denote_addConst, denote, intCast_add, cond_eq_if, add_comm, add_left_comm, add_assoc]
next hg _ h _ =>
simp +zetaDelta at h; simp [*]
rw [ add_assoc, Mon.eq_of_grevlex hg, right_distrib, intCast_add, h, intCast_zero, zero_mul, zero_add]
next hg _ h _ =>
simp +zetaDelta at h; simp [*, denote, intCast_add]
rw [right_distrib, Mon.eq_of_grevlex hg, add_assoc]
theorem Poly.denote_mul_go [CommRing α] (ctx : Context α) (p₁ p₂ acc : Poly)
: (mul.go p₂ p₁ acc).denote ctx = acc.denote ctx + p₁.denote ctx * p₂.denote ctx := by
fun_induction mul.go
<;> simp [mul.go, denote_combine, denote_mulConst, denote, *, right_distrib, denote_mulMon, add_assoc]
theorem Poly.denote_mul [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
: (mul p₁ p₂).denote ctx = p₁.denote ctx * p₂.denote ctx := by
simp [mul, denote_mul_go, denote, intCast_zero, zero_add]
theorem Poly.denote_pow [CommRing α] (ctx : Context α) (p : Poly) (k : Nat)
: (pow p k).denote ctx = p.denote ctx ^ k := by
fun_induction pow <;> simp [pow, denote, intCast_one, pow_zero]
next => simp [pow_succ, pow_zero, one_mul]
next => simp [denote_mul, *, pow_succ, mul_comm]
theorem Expr.denote_toPoly [CommRing α] (ctx : Context α) (e : Expr)
: e.toPoly.denote ctx = e.denote ctx := by
fun_induction toPoly
<;> simp [toPoly, denote, Poly.denote, Poly.denote_ofVar, Poly.denote_combine,
Poly.denote_mul, Poly.denote_mulConst, Poly.denote_pow, *]
next => rw [intCast_neg, neg_mul, intCast_one, one_mul]
next => rw [intCast_neg, neg_mul, intCast_one, one_mul, sub_eq_add_neg]
next => rw [intCast_pow]
next => simp [Poly.denote_ofMon, Mon.denote, Power.denote_eq]
end CommRing
end Lean.Grind

View File

@@ -7,6 +7,53 @@ prelude
import Init.Grind.CommRing.Basic
import Init.Data.UInt.Lemmas
namespace UInt8
/-- Variant of `UInt8.ofNat_mod_size` replacing `2 ^ 8` with `256`.-/
theorem ofNat_mod_size' : ofNat (x % 256) = ofNat x := ofNat_mod_size
instance : IntCast UInt8 where
intCast x := UInt8.ofInt x
end UInt8
namespace UInt16
/-- Variant of `UInt16.ofNat_mod_size` replacing `2 ^ 16` with `65536`.-/
theorem ofNat_mod_size' : ofNat (x % 65536) = ofNat x := ofNat_mod_size
instance : IntCast UInt16 where
intCast x := UInt16.ofInt x
end UInt16
namespace UInt32
/-- Variant of `UInt32.ofNat_mod_size` replacing `2 ^ 32` with `4294967296`.-/
theorem ofNat_mod_size' : ofNat (x % 4294967296) = ofNat x := ofNat_mod_size
instance : IntCast UInt32 where
intCast x := UInt32.ofInt x
end UInt32
namespace UInt64
/-- Variant of `UInt64.ofNat_mod_size` replacing `2 ^ 64` with `18446744073709551616`.-/
theorem ofNat_mod_size' : ofNat (x % 18446744073709551616) = ofNat x := ofNat_mod_size
instance : IntCast UInt64 where
intCast x := UInt64.ofInt x
end UInt64
namespace USize
instance : IntCast USize where
intCast x := USize.ofInt x
end USize
namespace Lean.Grind
instance : CommRing UInt8 where
@@ -19,6 +66,15 @@ instance : CommRing UInt8 where
mul_one := UInt8.mul_one
left_distrib _ _ _ := UInt8.mul_add
zero_mul _ := UInt8.zero_mul
sub_eq_add_neg := UInt8.sub_eq_add_neg
pow_zero := UInt8.pow_zero
pow_succ := UInt8.pow_succ
ofNat_succ x := UInt8.ofNat_add x 1
instance : IsCharP UInt8 (2 ^ 8) where
ofNat_eq_zero_iff {x} := by
have : OfNat.ofNat x = UInt8.ofNat x := rfl
simp [this, UInt8.ofNat_eq_iff_mod_eq_toNat]
instance : CommRing UInt16 where
add_assoc := UInt16.add_assoc
@@ -30,6 +86,15 @@ instance : CommRing UInt16 where
mul_one := UInt16.mul_one
left_distrib _ _ _ := UInt16.mul_add
zero_mul _ := UInt16.zero_mul
sub_eq_add_neg := UInt16.sub_eq_add_neg
pow_zero := UInt16.pow_zero
pow_succ := UInt16.pow_succ
ofNat_succ x := UInt16.ofNat_add x 1
instance : IsCharP UInt16 (2 ^ 16) where
ofNat_eq_zero_iff {x} := by
have : OfNat.ofNat x = UInt16.ofNat x := rfl
simp [this, UInt16.ofNat_eq_iff_mod_eq_toNat]
instance : CommRing UInt32 where
add_assoc := UInt32.add_assoc
@@ -41,6 +106,15 @@ instance : CommRing UInt32 where
mul_one := UInt32.mul_one
left_distrib _ _ _ := UInt32.mul_add
zero_mul _ := UInt32.zero_mul
sub_eq_add_neg := UInt32.sub_eq_add_neg
pow_zero := UInt32.pow_zero
pow_succ := UInt32.pow_succ
ofNat_succ x := UInt32.ofNat_add x 1
instance : IsCharP UInt32 (2 ^ 32) where
ofNat_eq_zero_iff {x} := by
have : OfNat.ofNat x = UInt32.ofNat x := rfl
simp [this, UInt32.ofNat_eq_iff_mod_eq_toNat]
instance : CommRing UInt64 where
add_assoc := UInt64.add_assoc
@@ -52,6 +126,15 @@ instance : CommRing UInt64 where
mul_one := UInt64.mul_one
left_distrib _ _ _ := UInt64.mul_add
zero_mul _ := UInt64.zero_mul
sub_eq_add_neg := UInt64.sub_eq_add_neg
pow_zero := UInt64.pow_zero
pow_succ := UInt64.pow_succ
ofNat_succ x := UInt64.ofNat_add x 1
instance : IsCharP UInt64 (2 ^ 64) where
ofNat_eq_zero_iff {x} := by
have : OfNat.ofNat x = UInt64.ofNat x := rfl
simp [this, UInt64.ofNat_eq_iff_mod_eq_toNat]
instance : CommRing USize where
add_assoc := USize.add_assoc
@@ -63,5 +146,16 @@ instance : CommRing USize where
mul_one := USize.mul_one
left_distrib _ _ _ := USize.mul_add
zero_mul _ := USize.zero_mul
sub_eq_add_neg := USize.sub_eq_add_neg
pow_zero := USize.pow_zero
pow_succ := USize.pow_succ
ofNat_succ x := USize.ofNat_add x 1
open System.Platform
instance : IsCharP USize (2 ^ numBits) where
ofNat_eq_zero_iff {x} := by
have : OfNat.ofNat x = USize.ofNat x := rfl
simp [this, USize.ofNat_eq_iff_mod_eq_toNat]
end Lean.Grind

10
src/Init/Grind/Ext.lean Normal file
View File

@@ -0,0 +1,10 @@
/-
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Init.Ext
import Init.Grind.Tactics
attribute [grind ext] funext

View File

@@ -165,4 +165,9 @@ theorem of_decide_eq_false {p : Prop} {_ : Decidable p} : decide p = false → p
theorem decide_eq_true {p : Prop} {_ : Decidable p} : p = True decide p = true := by simp
theorem decide_eq_false {p : Prop} {_ : Decidable p} : p = False decide p = false := by simp
/-! Lookahead -/
theorem of_lookahead (p : Prop) (h : (¬ p) False) : p = True := by
simp at h; simp [h]
end Lean.Grind

View File

@@ -74,11 +74,11 @@ theorem bne_eq_decide_not_eq {_ : BEq α} [LawfulBEq α] [DecidableEq α] (a b :
theorem xor_eq (a b : Bool) : (a ^^ b) = (a != b) := by
rfl
theorem natCast_div (a b : Nat) : ((a / b) : Int) = a / b := by
rfl
theorem natCast_mod (a b : Nat) : ((a % b) : Int) = a % b := by
rfl
theorem natCast_eq [NatCast α] (a : Nat) : (Nat.cast a : α) = (NatCast.natCast a : α) := rfl
theorem natCast_div (a b : Nat) : (NatCast.natCast (a / b) : Int) = (NatCast.natCast a) / (NatCast.natCast b) := rfl
theorem natCast_mod (a b : Nat) : (NatCast.natCast (a % b) : Int) = (NatCast.natCast a) % (NatCast.natCast b) := rfl
theorem natCast_add (a b : Nat) : (NatCast.natCast (a + b : Nat) : Int) = (NatCast.natCast a : Int) + (NatCast.natCast b : Int) := rfl
theorem natCast_mul (a b : Nat) : (NatCast.natCast (a * b : Nat) : Int) = (NatCast.natCast a : Int) * (NatCast.natCast b : Int) := rfl
theorem Nat.pow_one (a : Nat) : a ^ 1 = a := by
simp
@@ -153,8 +153,10 @@ init_grind_norm
Int.emod_neg Int.ediv_neg
Int.ediv_zero Int.emod_zero
Int.ediv_one Int.emod_one
Int.natCast_add Int.natCast_mul Int.natCast_pow
Int.natCast_zero natCast_div natCast_mod
natCast_eq natCast_div natCast_mod
natCast_add natCast_mul
Int.pow_zero Int.pow_one
-- GT GE
ge_eq gt_eq

View File

@@ -25,7 +25,8 @@ syntax grindUsr := &"usr "
syntax grindCases := &"cases "
syntax grindCasesEager := atomic(&"cases" &"eager ")
syntax grindIntro := &"intro "
syntax grindMod := grindEqBoth <|> grindEqRhs <|> grindEq <|> grindEqBwd <|> grindBwd <|> grindFwd <|> grindRL <|> grindLR <|> grindUsr <|> grindCasesEager <|> grindCases <|> grindIntro
syntax grindExt := &"ext "
syntax grindMod := grindEqBoth <|> grindEqRhs <|> grindEq <|> grindEqBwd <|> grindBwd <|> grindFwd <|> grindRL <|> grindLR <|> grindUsr <|> grindCasesEager <|> grindCases <|> grindIntro <|> grindExt
syntax (name := grind) "grind" (grindMod)? : attr
end Attr
end Lean.Parser
@@ -68,8 +69,17 @@ structure Config where
failures : Nat := 1
/-- Maximum number of heartbeats (in thousands) the canonicalizer can spend per definitional equality test. -/
canonHeartbeats : Nat := 1000
/-- If `ext` is `true`, `grind` uses extensionality theorems available in the environment. -/
/-- If `ext` is `true`, `grind` uses extensionality theorems that have been marked with `[grind ext]`. -/
ext : Bool := true
/-- If `extAll` is `true`, `grind` uses any extensionality theorems available in the environment. -/
extAll : Bool := false
/--
If `funext` is `true`, `grind` creates new opportunities for applying function extensionality by case-splitting
on equalities between lambda expressions.
-/
funext : Bool := true
/-- TODO -/
lookahead : Bool := true
/-- If `verbose` is `false`, additional diagnostics information is not collected. -/
verbose : Bool := true
/-- If `clean` is `true`, `grind` uses `expose_names` and only generates accessible names. -/

View File

@@ -275,6 +275,14 @@ class MonadNameGenerator (m : Type → Type) where
export MonadNameGenerator (getNGen setNGen)
/--
Creates a globally unique `Name`, without any semantic interpretation.
The names are not intended to be user-visible.
With the default name generator, names use `_uniq` as a base and have a numeric suffix.
This is used for example by `Lean.mkFreshFVarId`, `Lean.mkFreshMVarId`, and `Lean.mkFreshLMVarId`.
To create fresh user-visible identifiers, use functions such as `Lean.Core.mkFreshUserName` instead.
-/
def mkFreshId {m : Type Type} [Monad m] [MonadNameGenerator m] : m Name := do
let ngen getNGen
let r := ngen.curr

View File

@@ -286,7 +286,7 @@ theorem gcd_cons_div_right : gcd (x::xs) gcd xs := by
apply Nat.gcd_dvd_right
theorem gcd_cons_div_right' : (gcd (x::xs) : Int) (gcd xs : Int) := by
rw [Int.ofNat_dvd_left, Int.natAbs_ofNat]
rw [Int.ofNat_dvd_left, Int.natAbs_natCast]
exact gcd_cons_div_right
theorem gcd_dvd (xs : IntList) {a : Int} (m : a xs) : (xs.gcd : Int) a := by

View File

@@ -1003,7 +1003,7 @@ class BEq (α : Type u) where
open BEq (beq)
instance [DecidableEq α] : BEq α where
instance (priority := 500) [DecidableEq α] : BEq α where
beq a b := decide (Eq a b)

View File

@@ -287,8 +287,8 @@ theorem not_decide_eq_true [h : Decidable p] : ((!decide p) = true) = ¬ p := by
@[simp] theorem cond_true (a b : α) : cond true a b = a := rfl
@[simp] theorem cond_false (a b : α) : cond false a b = b := rfl
@[simp] theorem beq_self_eq_true [BEq α] [LawfulBEq α] (a : α) : (a == a) = true := LawfulBEq.rfl
theorem beq_self_eq_true' [DecidableEq α] (a : α) : (a == a) = true := by simp
theorem beq_self_eq_true [BEq α] [ReflBEq α] (a : α) : (a == a) = true := BEq.rfl
theorem beq_self_eq_true' [DecidableEq α] (a : α) : (a == a) = true := BEq.rfl
@[simp] theorem bne_self_eq_false [BEq α] [LawfulBEq α] (a : α) : (a != a) = false := by simp [bne]
theorem bne_self_eq_false' [DecidableEq α] (a : α) : (a != a) = false := by simp

View File

@@ -1355,6 +1355,8 @@ structure SpawnArgs extends StdioConfig where
and `some` sets the variable to the new value, adding it if necessary. Variables are processed from left to right.
-/
env : Array (String × Option String) := #[]
/-- Inherit environment variables from the spawning process. -/
inheritEnv : Bool := true
/--
Starts the child process in a new session and process group using `setsid`. Currently a no-op on
non-POSIX platforms.

View File

@@ -819,12 +819,12 @@ The left hand side of an induction arm, `| foo a b c` or `| @foo a b c`
where `foo` is a constructor of the inductive type and `a b c` are the arguments
to the constructor.
-/
syntax inductionAltLHS := "| " (("@"? ident) <|> hole) (ident <|> hole)*
syntax inductionAltLHS := withPosition("| " (("@"? ident) <|> hole) (colGt (ident <|> hole))*)
/--
In induction alternative, which can have 1 or more cases on the left
and `_`, `?_`, or a tactic sequence after the `=>`.
-/
syntax inductionAlt := ppDedent(ppLine) inductionAltLHS+ " => " (hole <|> syntheticHole <|> tacticSeq)
syntax inductionAlt := ppDedent(ppLine) inductionAltLHS+ (" => " (hole <|> syntheticHole <|> tacticSeq))?
/--
After `with`, there is an optional tactic that runs on all branches, and
then a list of alternatives.
@@ -1752,7 +1752,7 @@ attribute @[simp ←] and_assoc
```
When multiple simp theorems are applicable, the simplifier uses the one with highest priority.
The equational theorems of function are applied at very low priority (100 and below).
The equational theorems of functions are applied at very low priority (100 and below).
If there are several with the same priority, it is uses the "most recent one". Example:
```lean
@[simp high] theorem cond_true (a b : α) : cond true a b = a := rfl

View File

@@ -17,9 +17,16 @@ private opaque getLeancExtraFlags : Unit → String
private def flagsStringToArray (s : String) : Array String :=
s.splitOn.toArray |>.filter (· "")
/--
Return C compiler flags for including Lean's headers.
Unlike `getCFlags`, this does not contain the Lean include directory.
-/
def getCFlags' : Array String :=
flagsStringToArray (getLeancExtraFlags ())
/-- Return C compiler flags for including Lean's headers. -/
def getCFlags (leanSysroot : FilePath) : Array String :=
#["-I", (leanSysroot / "include").toString] ++ flagsStringToArray (getLeancExtraFlags ())
#["-I", (leanSysroot / "include").toString] ++ getCFlags'
@[extern "lean_get_leanc_internal_flags"]
private opaque getLeancInternalFlags : Unit String
@@ -31,9 +38,16 @@ def getInternalCFlags (leanSysroot : FilePath) : Array String :=
@[extern "lean_get_linker_flags"]
private opaque getBuiltinLinkerFlags (linkStatic : Bool) : String
/--
Return linker flags for linking against Lean's libraries.
Unlike `getLinkerFlags`, this does not contain the Lean library directory.
-/
def getLinkerFlags' (linkStatic := true) : Array String :=
flagsStringToArray (getBuiltinLinkerFlags linkStatic)
/-- Return linker flags for linking against Lean's libraries. -/
def getLinkerFlags (leanSysroot : FilePath) (linkStatic := true) : Array String :=
#["-L", (leanSysroot / "lib" / "lean").toString] ++ flagsStringToArray (getBuiltinLinkerFlags linkStatic)
#["-L", (leanSysroot / "lib" / "lean").toString] ++ getLinkerFlags' linkStatic
@[extern "lean_get_internal_linker_flags"]
private opaque getBuiltinInternalLinkerFlags : Unit String

View File

@@ -44,7 +44,7 @@ def replaceFun (decl : FunDecl) (fvarId : FVarId) : M Unit := do
eraseFunDecl decl
addFVarSubst decl.fvarId fvarId
partial def _root_.Lean.Compiler.LCNF.Code.cse (code : Code) : CompilerM Code :=
partial def _root_.Lean.Compiler.LCNF.Code.cse (shouldElimFunDecls : Bool) (code : Code) : CompilerM Code :=
go code |>.run' {}
where
goFunDecl (decl : FunDecl) : M FunDecl := do
@@ -67,14 +67,18 @@ where
addEntry key decl.fvarId
return code.updateLet! decl ( go k)
| .fun decl k =>
let decl goFunDecl decl
let value := decl.toExpr
match ( get).map.find? value with
| some fvarId' =>
replaceFun decl fvarId'
go k
| none =>
addEntry value decl.fvarId
if shouldElimFunDecls then
let decl goFunDecl decl
let value := decl.toExpr
match ( get).map.find? value with
| some fvarId' =>
replaceFun decl fvarId'
go k
| none =>
addEntry value decl.fvarId
return code.updateFun! decl ( go k)
else
let decl goFunDecl decl
return code.updateFun! decl ( go k)
| .jp decl k =>
let decl goFunDecl decl
@@ -101,12 +105,12 @@ end CSE
/--
Common sub-expression elimination
-/
def Decl.cse (decl : Decl) : CompilerM Decl := do
let value decl.value.mapCodeM (·.cse)
def Decl.cse (shouldElimFunDecls : Bool) (decl : Decl) : CompilerM Decl := do
let value decl.value.mapCodeM (·.cse shouldElimFunDecls)
return { decl with value }
def cse (phase : Phase := .base) (occurrence := 0) : Pass :=
.mkPerDeclaration `cse Decl.cse phase occurrence
def cse (phase : Phase := .base) (shouldElimFunDecls := false) (occurrence := 0) : Pass :=
.mkPerDeclaration `cse (Decl.cse shouldElimFunDecls) phase occurrence
builtin_initialize
registerTraceClass `Compiler.cse (inherited := true)

View File

@@ -142,7 +142,7 @@ mutual
fType := instantiateRevRangeArgs fType j i args |>.headBeta
match fType with
| .forallE _ _ b _ => j := i; fType := b
| _ => return erasedExpr
| _ => return anyExpr
return instantiateRevRangeArgs fType j args.size args |>.headBeta
partial def inferAppType (e : Expr) : InferTypeM Expr := do
@@ -157,7 +157,7 @@ mutual
fType := fType.instantiateRevRange j i args |>.headBeta
match fType with
| .forallE _ _ b _ => j := i; fType := b
| _ => return erasedExpr
| _ => return anyExpr
return fType.instantiateRevRange j args.size args |>.headBeta
partial def inferProjType (structName : Name) (idx : Nat) (s : FVarId) : InferTypeM Expr := do
@@ -167,6 +167,8 @@ mutual
if structType.isErased then
/- TODO: after we erase universe variables, we can just extract a better type using just `structName` and `idx`. -/
return erasedExpr
else if structType.isAny then
return anyExpr
else
matchConstStructure structType.getAppFn failed fun structVal structLvls ctorVal =>
let structTypeArgs := structType.getAppArgs
@@ -179,7 +181,7 @@ mutual
| .forallE _ _ body _ =>
if body.hasLooseBVars then
-- This can happen when one of the fields is a type or type former.
ctorType := body.instantiate1 erasedExpr
ctorType := body.instantiate1 anyExpr
else
ctorType := body
| _ =>

View File

@@ -178,16 +178,8 @@ def eagerLambdaLifting : Pass where
name := `eagerLambdaLifting
run := fun decls => do
decls.foldlM (init := #[]) fun decls decl => do
if ( Meta.isInstance decl.name) then
/-
Recall that we lambda lift local functions in instances to control code blowup, and make sure they are cheap to inline.
It is not worth to lift tiny ones. TODO: evaluate whether we should add a compiler option to control the min size.
Recall that when performing eager lambda lifting in instances, we progatate the `[inline]` annotations to the new auxiliary functions.
Note: we have tried `if decl.inlineable then return decls.push decl`, but it didn't help in our preliminary experiments.
-/
return decls ++ ( decl.lambdaLifting (liftInstParamOnly := false) (suffix := `_elam) (inheritInlineAttrs := true) (minSize := 3))
if decl.inlineAttr || ( Meta.isInstance decl.name) then
return decls.push decl
else
return decls ++ ( decl.lambdaLifting (liftInstParamOnly := true) (suffix := `_elam))

View File

@@ -85,7 +85,11 @@ partial def toMonoType (type : Expr) : CoreM Expr := do
where
visitApp (f : Expr) (args : Array Expr) : CoreM Expr := do
match f with
| .const ``lcErased _ => return erasedExpr
| .const ``lcErased _ =>
if args.all (·.isErased) then
return erasedExpr
else
return anyExpr
| .const ``lcAny _ => return anyExpr
| .const ``Decidable _ => return mkConst ``Bool
| .const declName us =>
@@ -101,7 +105,7 @@ where
if d matches .const ``lcErased _ | .sort _ then
result := mkApp result ( toMonoType arg)
else
result := mkApp result erasedExpr
result := mkApp result anyExpr
type := b.instantiate1 arg
return result
| _ => return anyExpr

View File

@@ -46,7 +46,7 @@ def builtinPassManager : PassManager := {
passes := #[
init,
pullInstances,
cse,
cse (shouldElimFunDecls := false),
simp,
floatLetIn,
findJoinPoints,
@@ -61,7 +61,7 @@ def builtinPassManager : PassManager := {
eagerLambdaLifting,
specialize,
simp (occurrence := 2),
cse (occurrence := 1),
cse (shouldElimFunDecls := false) (occurrence := 1),
saveBase, -- End of base phase
toMono,
simp (occurrence := 3) (phase := .mono),

View File

@@ -69,9 +69,14 @@ mutual
partial def pullDecls (code : Code) : PullM Code := do
match code with
| .cases c =>
withCheckpoint do
let alts c.alts.mapMonoM pullAlt
return code.updateAlts! alts
-- At the present time, we can't correctly enforce the dependencies required for lifting
-- out of a cases expression on Decidable, so we disable this optimization.
if c.typeName == ``Decidable then
return code
else
withCheckpoint do
let alts c.alts.mapMonoM pullAlt
return code.updateAlts! alts
| .let decl k =>
if ( shouldPull decl) then
pullDecls k

View File

@@ -42,30 +42,13 @@ def Decl.simp? (decl : Decl) : SimpM (Option Decl) := do
partial def Decl.simp (decl : Decl) (config : Config) : CompilerM Decl := do
let mut config := config
if ( isTemplateLike decl) then
let mut inlineDefs := config.inlineDefs
/-
At the base phase, we don't inline definitions occurring in instances.
Reason: we eagerly lambda lift local functions occurring at instances before saving their code at the end of the base
phase. The goal is to make them cheap to inline in actual code. By inlining definitions we would be just generating extra
work for the lambda lifter.
There is an exception: inlineable instances. This is important for auxiliary instances such as
```
@[always_inline]
instance : Monad TermElabM := let i := inferInstanceAs (Monad TermElabM); { pure := i.pure, bind := i.bind }
```
by keeping `inlineDefs := true`, we can pre-compute the `pure` and `bind` methods for `TermElabM`.
-/
if ( inBasePhase <&&> Meta.isInstance decl.name) then
unless decl.inlineable do
inlineDefs := false
/-
We do not eta-expand or inline partial applications in template like code.
Recall we don't want to generate code for them.
Remark: by eta-expanding partial applications in instances, we also make the simplifier
work harder when inlining instance projections.
-/
config := { config with etaPoly := false, inlinePartial := false, inlineDefs }
config := { config with etaPoly := false, inlinePartial := false }
go decl config
where
go (decl : Decl) (config : Config) : CompilerM Decl := do

View File

@@ -261,6 +261,9 @@ def getRemainingArgs (paramsInfo : Array SpecParamInfo) (args : Array Arg) : Arr
result := result.push arg
return result ++ args[paramsInfo.size:]
def paramsToVarSet (params : Array Param) : FVarIdSet :=
params.foldl (fun r p => r.insert p.fvarId) {}
mutual
/--
Try to specialize the function application in the given let-declaration.
@@ -295,7 +298,8 @@ mutual
specDecl.saveBase
let specDecl specDecl.simp {}
let specDecl specDecl.simp { etaPoly := true, inlinePartial := true, implementedBy := true }
let value withReader (fun _ => { declName := specDecl.name }) do
let ground := paramsToVarSet specDecl.params
let value withReader (fun _ => { declName := specDecl.name, ground }) do
withParams specDecl.params <| specDecl.value.mapCodeM visitCode
let specDecl := { specDecl with value }
modify fun s => { s with decls := s.decls.push specDecl }
@@ -337,7 +341,8 @@ def main (decl : Decl) : SpecializeM Decl := do
end Specialize
partial def Decl.specialize (decl : Decl) : CompilerM (Array Decl) := do
let (decl, s) Specialize.main decl |>.run { declName := decl.name } |>.run {}
let ground := Specialize.paramsToVarSet decl.params
let (decl, s) Specialize.main decl |>.run { declName := decl.name, ground } |>.run {}
return s.decls.push decl
def specialize : Pass where

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