mirror of
https://github.com/leanprover/lean4.git
synced 2026-04-04 19:24:09 +00:00
Compare commits
4 Commits
instances_
...
int_norm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b410270dbc | ||
|
|
579316d10a | ||
|
|
fb6f9abedd | ||
|
|
1393e8e754 |
57
.github/workflows/check-stage0.yml
vendored
57
.github/workflows/check-stage0.yml
vendored
@@ -1,57 +0,0 @@
|
||||
name: Check for stage0 changes
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
check-stage0-on-queue:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
filter: blob:none
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Find base commit
|
||||
if: github.event_name == 'pull_request'
|
||||
run: echo "BASE=$(git merge-base origin/${{ github.base_ref }} HEAD)" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Identify stage0 changes
|
||||
run: |
|
||||
git diff "${BASE:-HEAD^}..HEAD" --name-only -- stage0 |
|
||||
grep -v -x -F $'stage0/src/stdlib_flags.h\nstage0/src/lean.mk.in' \
|
||||
> "$RUNNER_TEMP/stage0" || true
|
||||
if test -s "$RUNNER_TEMP/stage0"
|
||||
then
|
||||
echo "CHANGES=yes" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "CHANGES=no" >> "$GITHUB_ENV"
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- if: github.event_name == 'pull_request'
|
||||
name: Set label
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const { owner, repo, number: issue_number } = context.issue;
|
||||
if (process.env.CHANGES == 'yes') {
|
||||
await github.rest.issues.addLabels({ owner, repo, issue_number, labels: ['changes-stage0'] }).catch(() => {});
|
||||
} else {
|
||||
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: 'changes-stage0' }).catch(() => {});
|
||||
}
|
||||
|
||||
- if: env.CHANGES == 'yes'
|
||||
name: Report changes
|
||||
run: |
|
||||
echo "Found changes to stage0/, please do not merge using the merge queue." | tee "$GITHUB_STEP_SUMMARY"
|
||||
# shellcheck disable=SC2129
|
||||
echo '```' >> "$GITHUB_STEP_SUMMARY"
|
||||
cat "$RUNNER_TEMP/stage0" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo '```' >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- if: github.event_name == 'merge_group' && env.CHANGES == 'yes'
|
||||
name: Fail when on the merge queue
|
||||
run: exit 1
|
||||
26
.github/workflows/ci.yml
vendored
26
.github/workflows/ci.yml
vendored
@@ -110,7 +110,7 @@ jobs:
|
||||
},*/
|
||||
{
|
||||
"name": "macOS",
|
||||
"os": "macos-13",
|
||||
"os": "macos-latest",
|
||||
"release": true,
|
||||
"quick": false,
|
||||
"shell": "bash -euxo pipefail {0}",
|
||||
@@ -121,7 +121,7 @@ jobs:
|
||||
},
|
||||
{
|
||||
"name": "macOS aarch64",
|
||||
"os": "macos-13",
|
||||
"os": "macos-latest",
|
||||
"release": true,
|
||||
"quick": false,
|
||||
"cross": true,
|
||||
@@ -277,18 +277,18 @@ jobs:
|
||||
uses: cachix/install-nix-action@v18
|
||||
with:
|
||||
install_url: https://releases.nixos.org/nix/nix-2.12.0/install
|
||||
if: runner.os == 'Linux' && !matrix.cmultilib
|
||||
if: matrix.os == 'ubuntu-latest' && !matrix.cmultilib
|
||||
- name: Install MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: clang64
|
||||
# `:p` means prefix with appropriate msystem prefix
|
||||
pacboy: "make python cmake:p clang:p ccache:p gmp:p git zip unzip diffutils binutils tree zstd:p tar"
|
||||
if: runner.os == 'Windows'
|
||||
if: matrix.os == 'windows-2022'
|
||||
- name: Install Brew Packages
|
||||
run: |
|
||||
brew install ccache tree zstd coreutils gmp
|
||||
if: runner.os == 'macOS'
|
||||
if: matrix.os == 'macos-latest'
|
||||
- name: Setup emsdk
|
||||
uses: mymindstorm/setup-emsdk@v12
|
||||
with:
|
||||
@@ -312,13 +312,13 @@ jobs:
|
||||
run: |
|
||||
# open nix-shell once for initial setup
|
||||
true
|
||||
if: runner.os == 'Linux'
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
- name: Set up core dumps
|
||||
run: |
|
||||
mkdir -p $PWD/coredumps
|
||||
# store in current directory, for easy uploading together with binary
|
||||
echo $PWD/coredumps/%e.%p.%t | sudo tee /proc/sys/kernel/core_pattern
|
||||
if: runner.os == 'Linux'
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir build
|
||||
@@ -383,14 +383,8 @@ jobs:
|
||||
cd build/stage1
|
||||
ulimit -c unlimited # coredumps
|
||||
# exclude nonreproducible test
|
||||
ctest -j4 --progress --output-junit test-results.xml --output-on-failure ${{ matrix.CTEST_OPTIONS }} < /dev/null
|
||||
ctest -j4 --output-on-failure ${{ matrix.CTEST_OPTIONS }} < /dev/null
|
||||
if: (matrix.wasm || !matrix.cross) && needs.configure.outputs.quick == 'false'
|
||||
- name: Test Summary
|
||||
uses: test-summary/action@v2
|
||||
with:
|
||||
paths: build/stage1/test-results.xml
|
||||
# prefix `if` above with `always` so it's run even if tests failed
|
||||
if: always() && (matrix.wasm || !matrix.cross) && needs.configure.outputs.quick == 'false'
|
||||
- name: Check Test Binary
|
||||
run: ${{ matrix.binary-check }} tests/compiler/534.lean.out
|
||||
if: ${{ !matrix.cross && needs.configure.outputs.quick == 'false' }}
|
||||
@@ -423,7 +417,7 @@ jobs:
|
||||
- name: CCache stats
|
||||
run: ccache -s
|
||||
- name: Show stacktrace for coredumps
|
||||
if: ${{ failure() && runner.os == 'Linux' }}
|
||||
if: ${{ failure() && matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
for c in coredumps/*; do
|
||||
progbin="$(file $c | sed "s/.*execfn: '\([^']*\)'.*/\1/")"
|
||||
@@ -433,7 +427,7 @@ jobs:
|
||||
# shared libs
|
||||
#- name: Upload coredumps
|
||||
# uses: actions/upload-artifact@v3
|
||||
# if: ${{ failure() && runner.os == 'Linux' }}
|
||||
# if: ${{ failure() && matrix.os == 'ubuntu-latest' }}
|
||||
# with:
|
||||
# name: coredumps-${{ matrix.name }}
|
||||
# path: |
|
||||
|
||||
2
.github/workflows/copyright-header.yml
vendored
2
.github/workflows/copyright-header.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
|
||||
- name: Verify .lean files start with a copyright header.
|
||||
run: |
|
||||
FILES=$(find ./src -type d \( -path "./src/lake/examples" -o -path "./src/lake/tests" \) -prune -o -type f -name "*.lean" -exec perl -ne 'BEGIN { $/ = undef; } print "$ARGV\n" if !m{\A/-\nCopyright}; exit;' {} \;)
|
||||
FILES=$(find . -type d \( -path "./tests" -o -path "./doc" -o -path "./src/lake/examples" -o -path "./src/lake/tests" -o -path "./build" -o -path "./nix" \) -prune -o -type f -name "*.lean" -exec perl -ne 'BEGIN { $/ = undef; } print "$ARGV\n" if !m{\A/-\nCopyright}; exit;' {} \;)
|
||||
if [ -n "$FILES" ]; then
|
||||
echo "Found .lean files which do not have a copyright header:"
|
||||
echo "$FILES"
|
||||
|
||||
8
.github/workflows/nix-ci.yml
vendored
8
.github/workflows/nix-ci.yml
vendored
@@ -77,13 +77,7 @@ jobs:
|
||||
nix build $NIX_BUILD_ARGS .#cacheRoots -o push-build
|
||||
- name: Test
|
||||
run: |
|
||||
nix build --keep-failed $NIX_BUILD_ARGS .#test -o push-test || (ln -s /tmp/nix-build-*/source/src/build/ ./push-test; false)
|
||||
- name: Test Summary
|
||||
uses: test-summary/action@v2
|
||||
with:
|
||||
paths: push-test/test-results.xml
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
nix build $NIX_BUILD_ARGS .#test -o push-test
|
||||
- name: Build manual
|
||||
run: |
|
||||
nix build $NIX_BUILD_ARGS --update-input lean --no-write-lock-file ./doc#{lean-mdbook,leanInk,alectryon,test,inked} -o push-doc
|
||||
|
||||
4
.github/workflows/pr-release.yml
vendored
4
.github/workflows/pr-release.yml
vendored
@@ -149,9 +149,7 @@ jobs:
|
||||
echo "but 'git merge-base origin/master HEAD' reported: $MERGE_BASE_SHA"
|
||||
git -C lean4.git log -10 origin/master
|
||||
|
||||
git -C lean4.git fetch origin nightly-with-mathlib
|
||||
NIGHTLY_WITH_MATHLIB_SHA="$(git -C lean4.git rev-parse "origin/nightly-with-mathlib")"
|
||||
MESSAGE="- ❗ Std/Mathlib CI will not be attempted unless your PR branches off the \`nightly-with-mathlib\` branch. Try \`git rebase $MERGE_BASE_SHA --onto $NIGHTLY_WITH_MATHLIB_SHA\`."
|
||||
MESSAGE="- ❗ Std/Mathlib CI will not be attempted unless your PR branches off the \`nightly-with-mathlib\` branch. Try \`git rebase $MERGE_BASE_SHA --onto $NIGHTLY_SHA\`."
|
||||
fi
|
||||
|
||||
if [[ -n "$MESSAGE" ]]; then
|
||||
|
||||
@@ -78,10 +78,6 @@ add_custom_target(update-stage0
|
||||
COMMAND $(MAKE) -C stage1 update-stage0
|
||||
DEPENDS stage1)
|
||||
|
||||
add_custom_target(update-stage0-commit
|
||||
COMMAND $(MAKE) -C stage1 update-stage0-commit
|
||||
DEPENDS stage1)
|
||||
|
||||
add_custom_target(test
|
||||
COMMAND $(MAKE) -C stage1 test
|
||||
DEPENDS stage1)
|
||||
|
||||
26
CODEOWNERS
26
CODEOWNERS
@@ -6,6 +6,7 @@
|
||||
|
||||
/.github/ @Kha @semorrison
|
||||
/RELEASES.md @semorrison
|
||||
/src/Init/IO.lean @joehendrix
|
||||
/src/kernel/ @leodemoura
|
||||
/src/lake/ @tydeu
|
||||
/src/Lean/Compiler/ @leodemoura
|
||||
@@ -19,27 +20,4 @@
|
||||
/src/Lean/PrettyPrinter/Delaborator/ @kmill
|
||||
/src/Lean/Server/ @mhuisi
|
||||
/src/Lean/Widget/ @Vtec234
|
||||
/src/Init/Data/ @semorrison
|
||||
/src/Init/Data/Array/Lemmas.lean @digama0
|
||||
/src/Init/Data/List/Lemmas.lean @digama0
|
||||
/src/Init/Data/List/BasicAux.lean @digama0
|
||||
/src/Init/Data/Array/Subarray.lean @david-christiansen
|
||||
/src/Lean/Elab/Tactic/RCases.lean @digama0
|
||||
/src/Init/RCases.lean @digama0
|
||||
/src/Lean/Elab/Tactic/Ext.lean @digama0
|
||||
/src/Init/Ext.lean @digama0
|
||||
/src/Lean/Elab/Tactic/Simpa.lean @digama0
|
||||
/src/Lean/Elab/Tactic/NormCast.lean @digama0
|
||||
/src/Lean/Meta/Tactic/NormCast.lean @digama0
|
||||
/src/Lean/Meta/Tactic/TryThis.lean @digama0
|
||||
/src/Lean/Elab/Tactic/SimpTrace.lean @digama0
|
||||
/src/Lean/Elab/Tactic/NoMatch.lean @digama0
|
||||
/src/Lean/Elab/Tactic/ShowTerm.lean @digama0
|
||||
/src/Lean/Elab/Tactic/Repeat.lean @digama0
|
||||
/src/Lean/Meta/Tactic/Repeat.lean @digama0
|
||||
/src/Lean/Meta/CoeAttr.lean @digama0
|
||||
/src/Lean/Elab/GuardMsgs.lean @digama0
|
||||
/src/Lean/Elab/Tactic/Guard.lean @digama0
|
||||
/src/Init/Guard.lean @digama0
|
||||
/src/Lean/Server/CodeActions/ @digama0
|
||||
|
||||
/src/runtime/io.cpp @joehendrix
|
||||
|
||||
@@ -22,4 +22,4 @@ Please read our [Contribution Guidelines](CONTRIBUTING.md) first.
|
||||
|
||||
# Building from Source
|
||||
|
||||
See [Building Lean](https://lean-lang.org/lean4/doc/make/index.html) (documentation source: [doc/make/index.md](doc/make/index.md)).
|
||||
See [Building Lean](https://lean-lang.org/lean4/doc/make/index.html).
|
||||
|
||||
57
RELEASES.md
57
RELEASES.md
@@ -21,16 +21,17 @@ v4.8.0 (development in progress)
|
||||
|
||||
* Importing two different files containing proofs of the same theorem is no longer considered an error. This feature is particularly useful for theorems that are automatically generated on demand (e.g., equational theorems).
|
||||
|
||||
* Functional induction principles.
|
||||
* New command `derive_functional_induction`:
|
||||
|
||||
Derived from the definition of a (possibly mutually) recursive function, a **functional induction principle** is created that is tailored to proofs about that function.
|
||||
|
||||
For example from:
|
||||
Derived from the definition of a (possibly mutually) recursive function
|
||||
defined by well-founded recursion, a **functional induction principle** is
|
||||
tailored to proofs about that function. For example from:
|
||||
```
|
||||
def ackermann : Nat → Nat → Nat
|
||||
| 0, m => m + 1
|
||||
| n+1, 0 => ackermann n 1
|
||||
| n+1, m+1 => ackermann n (ackermann (n + 1) m)
|
||||
derive_functional_induction ackermann
|
||||
```
|
||||
we get
|
||||
```
|
||||
@@ -40,11 +41,6 @@ v4.8.0 (development in progress)
|
||||
(x x : Nat) : motive x x
|
||||
```
|
||||
|
||||
It can be used in the `induction` tactic using the `using` syntax:
|
||||
```
|
||||
induction n, m using ackermann.induct
|
||||
```
|
||||
|
||||
* The termination checker now recognizes more recursion patterns without an
|
||||
explicit `termination_by`. In particular the idiom of counting up to an upper
|
||||
bound, as in
|
||||
@@ -57,15 +53,6 @@ v4.8.0 (development in progress)
|
||||
```
|
||||
is recognized without having to say `termination_by arr.size - i`.
|
||||
|
||||
* Shorter instances names. There is a new algorithm for generating names for anonymous instances.
|
||||
Across Std and Mathlib, the median ratio between lengths of new names and of old names is about 72%.
|
||||
With the old algorithm, the longest name was 1660 characters, and now the longest name is 202 characters.
|
||||
The new algorithm's 95th percentile name length is 67 characters, versus 278 for the old algorithm.
|
||||
While the new algorithm produces names that are 1.2% less unique,
|
||||
it avoids cross-project collisions by adding a module-based suffix
|
||||
when it does not refer to declarations from the same "project" (modules that share the same root).
|
||||
PR [#3089](https://github.com/leanprover/lean4/pull/3089).
|
||||
|
||||
* Attribute `@[pp_using_anonymous_constructor]` to make structures pretty print like `⟨x, y, z⟩`
|
||||
rather than `{a := x, b := y, c := z}`.
|
||||
This attribute is applied to `Sigma`, `PSigma`, `PProd`, `Subtype`, `And`, and `Fin`.
|
||||
@@ -78,34 +65,6 @@ v4.8.0 (development in progress)
|
||||
to enable pretty printing function applications using generalized field notation (defaults to true).
|
||||
Field notation can be disabled on a function-by-function basis using the `@[pp_nodot]` attribute.
|
||||
|
||||
* Added options `pp.mvars` (default: true) and `pp.mvars.withType` (default: false).
|
||||
When `pp.mvars` is false, expression metavariables pretty print as `?_` and universe metavariables pretty print as `_`.
|
||||
When `pp.mvars.withType` is true, expression metavariables pretty print with a type ascription.
|
||||
These can be set when using `#guard_msgs` to make tests not depend on the particular names of metavariables.
|
||||
[#3798](https://github.com/leanprover/lean4/pull/3798) and
|
||||
[#3978](https://github.com/leanprover/lean4/pull/3978).
|
||||
|
||||
* Hovers for terms in `match` expressions in the Infoview now reliably show the correct term.
|
||||
|
||||
* Added `@[induction_eliminator]` and `@[cases_eliminator]` attributes to be able to define custom eliminators
|
||||
for the `induction` and `cases` tactics, replacing the `@[eliminator]` attribute.
|
||||
Gives custom eliminators for `Nat` so that `induction` and `cases` put goal states into terms of `0` and `n + 1`
|
||||
rather than `Nat.zero` and `Nat.succ n`.
|
||||
Added option `tactic.customEliminators` to control whether to use custom eliminators.
|
||||
Added a hack for `rcases`/`rintro`/`obtain` to use the custom eliminator for `Nat`.
|
||||
[#3629](https://github.com/leanprover/lean4/pull/3629),
|
||||
[#3655](https://github.com/leanprover/lean4/pull/3655), and
|
||||
[#3747](https://github.com/leanprover/lean4/pull/3747).
|
||||
|
||||
* The `#guard_msgs` command now has options to change whitespace normalization and sensitivity to message ordering.
|
||||
For example, `#guard_msgs (whitespace := lax) in cmd` collapses whitespace before checking messages,
|
||||
and `#guard_msgs (ordering := sorted) in cmd` sorts the messages in lexicographic order before checking.
|
||||
PR [#3883](https://github.com/leanprover/lean4/pull/3883).
|
||||
|
||||
* The `#guard_msgs` command now supports showing a diff between the expected and actual outputs. This feature is currently
|
||||
disabled by default, but can be enabled with `set_option guard_msgs.diff true`. Depending on user feedback, this option
|
||||
may default to `true` in a future version of Lean.
|
||||
|
||||
Breaking changes:
|
||||
|
||||
* Automatically generated equational theorems are now named using suffix `.eq_<idx>` instead of `._eq_<idx>`, and `.def` instead of `._unfold`. Example:
|
||||
@@ -135,12 +94,6 @@ fact.def :
|
||||
|
||||
* The coercion from `String` to `Name` was removed. Previously, it was `Name.mkSimple`, which does not separate strings at dots, but experience showed that this is not always the desired coercion. For the previous behavior, manually insert a call to `Name.mkSimple`.
|
||||
|
||||
* The `Subarray` fields `as`, `h₁` and `h₂` have been renamed to `array`, `start_le_stop`, and `stop_le_array_size`, respectively. This more closely follows standard Lean conventions. Deprecated aliases for the field projections were added; these will be removed in a future release.
|
||||
|
||||
* The change to the instance name algorithm (described above) can break projects that made use of the auto-generated names.
|
||||
|
||||
* `Option.toMonad` has been renamed to `Option.getM` and the unneeded `[Monad m]` instance argument has been removed.
|
||||
|
||||
v4.7.0
|
||||
---------
|
||||
|
||||
|
||||
@@ -75,25 +75,26 @@ The github repository will automatically update stage0 on `master` once
|
||||
|
||||
If you have write access to the lean4 repository, you can also also manually
|
||||
trigger that process, for example to be able to use new features in the compiler itself.
|
||||
You can do that on <https://github.com/leanprover/lean4/actions/workflows/update-stage0.yml>
|
||||
You can do that on <https://github.com/nomeata/lean4/actions/workflows/update-stage0.yml>
|
||||
or using Github CLI with
|
||||
```
|
||||
gh workflow run update-stage0.yml
|
||||
```
|
||||
|
||||
Leaving stage0 updates to the CI automation is preferable, but should you need
|
||||
to do it locally, you can use `make update-stage0-commit` in `build/release` to
|
||||
update `stage0` from `stage1` or `make -C stageN update-stage0-commit` to
|
||||
update from another stage.
|
||||
Leaving stage0 updates to the CI automation is preferrable, but should you need
|
||||
to do it locally, you can use `make update-stage0` in `build/release`, to
|
||||
update `stage0` from `stage1`, `make -C stageN update-stage0` to update from
|
||||
another stage, or `nix run .#update-stage0-commit` to update using nix.
|
||||
|
||||
This command will automatically stage the updated files and introduce a commit,
|
||||
so make sure to commit your work before that.
|
||||
|
||||
The CI should prevent PRs with changes to stage0 (besides `stdlib_flags.h`)
|
||||
from entering `master` through the (squashing!) merge queue, and label such PRs
|
||||
with the `changes-stage0` label. Such PRs should have a cleaned up history,
|
||||
with separate stage0 update commits; then coordinate with the admins to merge
|
||||
your PR using rebase merge, bypassing the merge queue.
|
||||
Updates to `stage0` should be their own commits in the Git history. So should
|
||||
you have to include the stage0 update in your PR (rather than using above
|
||||
automation after merging changes), commit your work before running `make
|
||||
update-stage0`, commit the updated `stage0` compiler code with the commit
|
||||
message:
|
||||
```
|
||||
chore: update stage0
|
||||
```
|
||||
and coordinate with the admins to not squash your PR.
|
||||
|
||||
## Further Bootstrapping Complications
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
||||
- Reconcile discrepancies in the `v4.6.0` section,
|
||||
usually via copy and paste and a commit to `releases/v4.6.0`.
|
||||
- `git tag v4.6.0`
|
||||
- `git push $REMOTE v4.6.0`, where `$REMOTE` is the upstream Lean repository (e.g., `origin`, `upstream`)
|
||||
- `git push origin v4.6.0`
|
||||
- Now wait, while CI runs.
|
||||
- You can monitor this at `https://github.com/leanprover/lean4/actions/workflows/ci.yml`,
|
||||
looking for the `v4.6.0` tag.
|
||||
@@ -34,76 +34,48 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
||||
(e.g. `v4.6.0-rc1`), and quickly sanity check.
|
||||
- Next, we will move a curated list of downstream repos to the latest stable release.
|
||||
- For each of the repositories listed below:
|
||||
- Make a PR to `master`/`main` changing the toolchain to `v4.6.0`
|
||||
- Update the toolchain file
|
||||
- In the Lakefile, if there are dependencies on specific version tags of dependencies that you've already pushed as part of this process, update them to the new tag.
|
||||
If they depend on `main` or `master`, don't change this; you've just updated the dependency, so it will work and be saved in the manifest
|
||||
- Run `lake update`
|
||||
- The PR title should be "chore: bump toolchain to v4.6.0".
|
||||
- Merge the PR once CI completes.
|
||||
- Create the tag `v4.6.0` from `master`/`main` and push it.
|
||||
- Merge the tag `v4.6.0` into the `stable` branch and push it.
|
||||
- Make a PR to `master`/`main` changing the toolchain to `v4.6.0`.
|
||||
The PR title should be "chore: bump toolchain to v4.6.0".
|
||||
Since the `v4.6.0` release should be functionally identical to the last release candidate,
|
||||
which the repository should already be on, this PR is a no-op besides changing the toolchain.
|
||||
- Once this is merged, create the tag `v4.6.0` from `master`/`main` and push it.
|
||||
- Merge the tag `v4.6.0` into the stable branch.
|
||||
- We do this for the repositories:
|
||||
- [lean4checker](https://github.com/leanprover/lean4checker)
|
||||
- No dependencies
|
||||
- Note: `lean4checker` uses a different version tagging scheme: use `toolchain/v4.6.0` rather than `v4.6.0`.
|
||||
- Toolchain bump PR
|
||||
- Create and push the tag
|
||||
- Merge the tag into `stable`
|
||||
- [Std](https://github.com/leanprover-community/std4)
|
||||
- No dependencies
|
||||
- Toolchain bump PR
|
||||
- Create and push the tag
|
||||
- Merge the tag into `stable`
|
||||
- `lean4checker` uses a different version tagging scheme: use `toolchain/v4.6.0` rather than `v4.6.0`.
|
||||
- [Std](https://github.com/leanprover-community/repl)
|
||||
- [ProofWidgets4](https://github.com/leanprover-community/ProofWidgets4)
|
||||
- Dependencies: `Std`
|
||||
- Note on versions and branches:
|
||||
- `ProofWidgets` uses a sequential version tagging scheme, e.g. `v0.0.29`,
|
||||
which does not refer to the toolchain being used.
|
||||
- Make a new release in this sequence after merging the toolchain bump PR.
|
||||
- `ProofWidgets` does not maintain a `stable` branch.
|
||||
- Toolchain bump PR
|
||||
- Create and push the tag, following the version convention of the repository
|
||||
- `ProofWidgets` uses a sequential version tagging scheme, e.g. `v0.0.29`,
|
||||
which does not refer to the toolchain being used.
|
||||
- Make a new release in this sequence after merging the toolchain bump PR.
|
||||
- `ProofWidgets` does not maintain a `stable` branch.
|
||||
- [Aesop](https://github.com/leanprover-community/aesop)
|
||||
- Dependencies: `Std`
|
||||
- Toolchain bump PR including updated Lake manifest
|
||||
- Create and push the tag
|
||||
- Merge the tag into `stable`
|
||||
- [doc-gen4](https://github.com/leanprover/doc-gen4)
|
||||
- Dependencies: exist, but they're not part of the release workflow
|
||||
- Toolchain bump PR including updated Lake manifest
|
||||
- Create and push the tag
|
||||
- There is no `stable` branch; skip this step
|
||||
- [import-graph](https://github.com/leanprover-community/import-graph)
|
||||
- Toolchain bump PR including updated Lake manifest
|
||||
- Create and push the tag
|
||||
- There is no `stable` branch; skip this step
|
||||
- [Mathlib](https://github.com/leanprover-community/mathlib4)
|
||||
- Dependencies: `Aesop`, `ProofWidgets4`, `lean4checker`, `Std`, `doc-gen4`, `import-graph`
|
||||
- Toolchain bump PR notes:
|
||||
- In addition to updating the `lean-toolchain` and `lakefile.lean`,
|
||||
in `.github/workflows/build.yml.in` in the `lean4checker` section update the line
|
||||
`git checkout toolchain/v4.6.0` to the appropriate tag,
|
||||
and then run `.github/workflows/mk_build_yml.sh`. Coordinate with
|
||||
a Mathlib maintainer to get this merged.
|
||||
- Push the PR branch to the main Mathlib repository rather than a fork, or CI may not work reliably
|
||||
- Create and push the tag
|
||||
- Create a new branch from the tag, push it, and open a pull request against `stable`.
|
||||
Coordinate with a Mathlib maintainer to get this merged.
|
||||
- In addition to updating the `lean-toolchain` and `lakefile.lean`,
|
||||
in `.github/workflows/build.yml.in` in the `lean4checker` section update the line
|
||||
`git checkout toolchain/v4.6.0` to the appropriate tag,
|
||||
and then run `.github/workflows/mk_build_yml.sh`.
|
||||
- [REPL](https://github.com/leanprover-community/repl)
|
||||
- Dependencies: `Mathlib` (for test code)
|
||||
- Note that there are two copies of `lean-toolchain`/`lakefile.lean`:
|
||||
in the root, and in `test/Mathlib/`. Edit both, and run `lake update` in both directories.
|
||||
- Toolchain bump PR including updated Lake manifest
|
||||
- Create and push the tag
|
||||
- Merge the tag into `stable`
|
||||
in the root, and in `test/Mathlib/`.
|
||||
- Note that there are dependencies between these packages:
|
||||
you should update the lakefile so that you are using the `v4.6.0` tag of upstream repositories
|
||||
(or the sequential tag for `ProofWidgets4`), and run `lake update` before committing.
|
||||
- This means that this process is sequential; each repository must have its bump PR merged,
|
||||
and the new tag pushed, before you can make the PR for the downstream repositories.
|
||||
- `lean4checker` has no dependencies
|
||||
- `Std` has no dependencies
|
||||
- `Aesop` depends on `Std`
|
||||
- `ProofWidgets4` depends on `Std`
|
||||
- `Mathlib` depends on `Aesop`, `ProofWidgets4`, and `lean4checker` (and transitively on `Std`)
|
||||
- `REPL` depends on `Mathlib` (this dependency is only for testing).
|
||||
- Merge the release announcement PR for the Lean website - it will be deployed automatically
|
||||
- Finally, make an announcement!
|
||||
This should go in https://leanprover.zulipchat.com/#narrow/stream/113486-announce, with topic `v4.6.0`.
|
||||
Please see previous announcements for suggested language.
|
||||
You will want a few bullet points for main topics from the release notes.
|
||||
Link to the blog post from the Zulip announcement.
|
||||
- Make sure that whoever is handling social media knows the release is out.
|
||||
Please also make sure that whoever is handling social media knows the release is out.
|
||||
|
||||
## Optimistic(?) time estimates:
|
||||
- Initial checks and push the tag: 30 minutes.
|
||||
|
||||
@@ -4,16 +4,16 @@ def ack : Nat → Nat → Nat
|
||||
| 0, y => y+1
|
||||
| x+1, 0 => ack x 1
|
||||
| x+1, y+1 => ack x (ack (x+1) y)
|
||||
termination_by x y => (x, y)
|
||||
termination_by ack x y => (x, y)
|
||||
|
||||
def sum (a : Array Int) : Int :=
|
||||
let rec go (i : Nat) :=
|
||||
if _ : i < a.size then
|
||||
if i < a.size then
|
||||
a[i] + go (i+1)
|
||||
else
|
||||
0
|
||||
termination_by a.size - i
|
||||
go 0
|
||||
termination_by go i => a.size - i
|
||||
|
||||
set_option pp.proofs true
|
||||
#print sum.go
|
||||
|
||||
@@ -4,42 +4,43 @@ open Lean Meta
|
||||
|
||||
def ctor (mvarId : MVarId) (idx : Nat) : MetaM (List MVarId) := do
|
||||
/- Set `MetaM` context using `mvarId` -/
|
||||
mvarId.withContext do
|
||||
withMVarContext mvarId do
|
||||
/- Fail if the metavariable is already assigned. -/
|
||||
mvarId.checkNotAssigned `ctor
|
||||
checkNotAssigned mvarId `ctor
|
||||
/- Retrieve the target type, instantiateMVars, and use `whnf`. -/
|
||||
let target ← mvarId.getType'
|
||||
let target ← getMVarType' mvarId
|
||||
let .const declName us := target.getAppFn
|
||||
| throwTacticEx `ctor mvarId "target is not an inductive datatype"
|
||||
let .inductInfo { ctors, .. } ← getConstInfo declName
|
||||
| throwTacticEx `ctor mvarId "target is not an inductive datatype"
|
||||
if idx = 0 then
|
||||
throwTacticEx `ctor mvarId "invalid index, it must be > 0"
|
||||
throwTacticEx `ctor mvarId "invalid index, it must be > 0"
|
||||
else if h : idx - 1 < ctors.length then
|
||||
mvarId.apply (.const ctors[idx - 1] us)
|
||||
apply mvarId (.const ctors[idx - 1] us)
|
||||
else
|
||||
throwTacticEx `ctor mvarId "invalid index, inductive datatype has only {ctors.length} contructors"
|
||||
throwTacticEx `ctor mvarId "invalid index, inductive datatype has only {ctors.length} contructors"
|
||||
|
||||
open Elab Tactic
|
||||
|
||||
elab "ctor" idx:num : tactic =>
|
||||
elab "ctor" idx:num : tactic =>
|
||||
liftMetaTactic (ctor · idx.getNat)
|
||||
|
||||
example (p : Prop) : p := by
|
||||
example (p : Prop) : p := by
|
||||
ctor 1 -- Error
|
||||
|
||||
example (h : q) : p ∨ q := by
|
||||
example (h : q) : p ∨ q := by
|
||||
ctor 0 -- Error
|
||||
exact h
|
||||
|
||||
example (h : q) : p ∨ q := by
|
||||
example (h : q) : p ∨ q := by
|
||||
ctor 3 -- Error
|
||||
exact h
|
||||
|
||||
example (h : q) : p ∨ q := by
|
||||
example (h : q) : p ∨ q := by
|
||||
ctor 2
|
||||
exact h
|
||||
|
||||
example (h : q) : p ∨ q := by
|
||||
example (h : q) : p ∨ q := by
|
||||
ctor 1
|
||||
exact h -- Error
|
||||
exact h -- Error
|
||||
|
||||
|
||||
@@ -5,15 +5,15 @@ open Lean Meta
|
||||
def ex1 (declName : Name) : MetaM Unit := do
|
||||
let info ← getConstInfo declName
|
||||
IO.println s!"{declName} : {← ppExpr info.type}"
|
||||
if let some val := info.value? then
|
||||
if let some val := info.value? then
|
||||
IO.println s!"{declName} : {← ppExpr val}"
|
||||
|
||||
|
||||
#eval ex1 ``Nat
|
||||
|
||||
def ex2 (declName : Name) : MetaM Unit := do
|
||||
let info ← getConstInfo declName
|
||||
trace[Meta.debug] "{declName} : {info.type}"
|
||||
if let some val := info.value? then
|
||||
if let some val := info.value? then
|
||||
trace[Meta.debug] "{declName} : {val}"
|
||||
|
||||
#eval ex2 ``Add.add
|
||||
@@ -30,9 +30,9 @@ def ex3 (declName : Name) : MetaM Unit := do
|
||||
trace[Meta.debug] "{x} : {← inferType x}"
|
||||
|
||||
def myMin [LT α] [DecidableRel (α := α) (·<·)] (a b : α) : α :=
|
||||
if a < b then
|
||||
if a < b then
|
||||
a
|
||||
else
|
||||
else
|
||||
b
|
||||
|
||||
set_option trace.Meta.debug true in
|
||||
@@ -40,7 +40,7 @@ set_option trace.Meta.debug true in
|
||||
|
||||
def ex4 : MetaM Unit := do
|
||||
let nat := mkConst ``Nat
|
||||
withLocalDeclD `a nat fun a =>
|
||||
withLocalDeclD `a nat fun a =>
|
||||
withLocalDeclD `b nat fun b => do
|
||||
let e ← mkAppM ``HAdd.hAdd #[a, b]
|
||||
trace[Meta.debug] "{e} : {← inferType e}"
|
||||
@@ -66,17 +66,15 @@ open Elab Term
|
||||
|
||||
def ex5 : TermElabM Unit := do
|
||||
let nat := Lean.mkConst ``Nat
|
||||
withLocalDeclD `a nat fun a => do
|
||||
withLocalDeclD `a nat fun a => do
|
||||
withLocalDeclD `b nat fun b => do
|
||||
let ab ← mkAppM ``HAdd.hAdd #[a, b]
|
||||
let abStx ← exprToSyntax ab
|
||||
let aStx ← exprToSyntax a
|
||||
let stx ← `(fun x => if x < 10 then $abStx + x else x + $aStx)
|
||||
let stx ← `(fun x => if x < 10 then $(← exprToSyntax ab) + x else x + $(← exprToSyntax a))
|
||||
let e ← elabTerm stx none
|
||||
trace[Meta.debug] "{e} : {← inferType e}"
|
||||
let e := mkApp e (mkNatLit 5)
|
||||
let e ← whnf e
|
||||
trace[Meta.debug] "{e}"
|
||||
|
||||
|
||||
set_option trace.Meta.debug true in
|
||||
#eval ex5
|
||||
|
||||
@@ -4,16 +4,16 @@ def ack : Nat → Nat → Nat
|
||||
| 0, y => y+1
|
||||
| x+1, 0 => ack x 1
|
||||
| x+1, y+1 => ack x (ack (x+1) y)
|
||||
termination_by x y => (x, y)
|
||||
termination_by ack x y => (x, y)
|
||||
|
||||
def sum (a : Array Int) : Int :=
|
||||
let rec go (i : Nat) :=
|
||||
if _ : i < a.size then
|
||||
if i < a.size then
|
||||
a[i] + go (i+1)
|
||||
else
|
||||
0
|
||||
termination_by a.size - i
|
||||
go 0
|
||||
termination_by go i => a.size - i
|
||||
|
||||
set_option pp.proofs true
|
||||
#print sum.go
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
src = inputs.mdBook;
|
||||
cargoDeps = drv.cargoDeps.overrideAttrs (_: {
|
||||
inherit src;
|
||||
outputHash = "sha256-CO3A9Kpp4sIvkT9X3p+GTidazk7Fn4jf0AP2PINN44A=";
|
||||
outputHash = "sha256-1YlPS6cqgxE4fjy9G8pWrpP27YrrbCDnfeyIsX81ZNw=";
|
||||
});
|
||||
doCheck = false;
|
||||
});
|
||||
|
||||
85
flake.lock
generated
85
flake.lock
generated
@@ -1,31 +1,12 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1673956053,
|
||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"lastModified": 1656928814,
|
||||
"narHash": "sha256-RIFfgBuKz6Hp89yRr7+NR5tzIAbn52h8vT6vXkYjZoM=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"rev": "7e2a3b3dfd9af950a856d66b0a7d01e3c18aa249",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -37,11 +18,11 @@
|
||||
"lean4-mode": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1709737301,
|
||||
"narHash": "sha256-uT9JN2kLNKJK9c/S/WxLjiHmwijq49EgLb+gJUSDpz0=",
|
||||
"lastModified": 1676498134,
|
||||
"narHash": "sha256-u3WvyKxOViZG53hkb8wd2/Og6muTecbh+NdflIgVeyk=",
|
||||
"owner": "leanprover",
|
||||
"repo": "lean4-mode",
|
||||
"rev": "f1f24c15134dee3754b82c9d9924866fe6bc6b9f",
|
||||
"rev": "2c6ef33f476fdf5eb5e4fa4fa023ba8b11372440",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -50,35 +31,34 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"libgit2": {
|
||||
"lowdown-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1697646580,
|
||||
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
|
||||
"owner": "libgit2",
|
||||
"repo": "libgit2",
|
||||
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
|
||||
"lastModified": 1633514407,
|
||||
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
|
||||
"owner": "kristapsdz",
|
||||
"repo": "lowdown",
|
||||
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "libgit2",
|
||||
"repo": "libgit2",
|
||||
"owner": "kristapsdz",
|
||||
"repo": "lowdown",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"libgit2": "libgit2",
|
||||
"lowdown-src": "lowdown-src",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-regression": "nixpkgs-regression"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1711102798,
|
||||
"narHash": "sha256-CXOIJr8byjolqG7eqCLa+Wfi7rah62VmLoqSXENaZnw=",
|
||||
"lastModified": 1657097207,
|
||||
"narHash": "sha256-SmeGmjWM3fEed3kQjqIAO8VpGmkC2sL1aPE7kKpK650=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nix",
|
||||
"rev": "a22328066416650471c3545b0b138669ea212ab4",
|
||||
"rev": "f6316b49a0c37172bca87ede6ea8144d7d89832f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -89,16 +69,16 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1709083642,
|
||||
"narHash": "sha256-7kkJQd4rZ+vFrzWu8sTRtta5D1kBG0LSRYAfhtmMlSo=",
|
||||
"lastModified": 1653988320,
|
||||
"narHash": "sha256-ZaqFFsSDipZ6KVqriwM34T739+KLYJvNmCWzErjAg7c=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b550fe4b4776908ac2a861124307045f8e717c8e",
|
||||
"rev": "2fa57ed190fd6c7c746319444f34b5917666e5c1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "release-23.11",
|
||||
"ref": "nixos-22.05-small",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
@@ -138,11 +118,11 @@
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1710889954,
|
||||
"narHash": "sha256-Pr6F5Pmd7JnNEMHHmspZ0qVqIBVxyZ13ik1pJtm2QXk=",
|
||||
"lastModified": 1686089707,
|
||||
"narHash": "sha256-LTNlJcru2qJ0XhlhG9Acp5KyjB774Pza3tRH0pKIb3o=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7872526e9c5332274ea5932a0c3270d6e4724f3b",
|
||||
"rev": "af21c31b2a1ec5d361ed8050edd0303c31306397",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -160,21 +140,6 @@
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"nixpkgs-old": "nixpkgs-old"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
||||
@@ -170,11 +170,10 @@ rec {
|
||||
ln -sf ${lean-all}/* .
|
||||
'';
|
||||
buildPhase = ''
|
||||
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)' -j$NIX_BUILD_CORES
|
||||
ctest --output-on-failure -E 'leancomptest_(doc_example|foreign)' -j$NIX_BUILD_CORES
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir $out
|
||||
mv test-results.xml $out
|
||||
touch $out
|
||||
'';
|
||||
};
|
||||
update-stage0 =
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import Lean.Util.Profiler
|
||||
|
||||
/-!
|
||||
|
||||
Usage:
|
||||
```sh
|
||||
lean --run ./script/collideProfiles.lean **/*.lean.json ... > merged.json
|
||||
```
|
||||
|
||||
Merges multiple `trace.profiler.output` profiles into a single one while deduplicating samples with
|
||||
the same stack. This is useful for building cumulative profiles of medium-to-large projects because
|
||||
Firefox Profiler cannot handle hundreds of tracks and the deduplication will also ensure that the
|
||||
profile is small enough for uploading.
|
||||
|
||||
As ordering of samples is not meaningful after this transformation, only "Call Tree" and "Flame
|
||||
Graph" are useful for such profiles.
|
||||
-/
|
||||
|
||||
open Lean
|
||||
|
||||
def main (args : List String) : IO Unit := do
|
||||
let profiles ← args.toArray.mapM fun path => do
|
||||
let json ← IO.FS.readFile ⟨path⟩
|
||||
let profile ← IO.ofExcept $ Json.parse json
|
||||
IO.ofExcept <| fromJson? profile
|
||||
-- NOTE: `collide` should not be interpreted
|
||||
let profile := Firefox.Profile.collide profiles
|
||||
IO.println <| Json.compress <| toJson profile
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# https://chat.openai.com/share/7469c7c3-aceb-4d80-aee5-62982e1f1538
|
||||
|
||||
# Output CSV Header
|
||||
echo '"Issue URL","Title","Days Since Creation","Days Since Last Update","Total Reactions","Assignee","Labels"'
|
||||
|
||||
# Get the current date in YYYY-MM-DD format
|
||||
today=$(date +%Y-%m-%d)
|
||||
|
||||
# Fetch only open issues (excluding PRs and closed issues) from the repository 'leanprover/lean4'
|
||||
issues=$(gh api repos/leanprover/lean4/issues --paginate --jq '.[] | select(.pull_request == null and .state == "open") | {url: .html_url, title: .title, created_at: (.created_at | split("T")[0]), updated_at: (.updated_at | split("T")[0]), number: .number, assignee: (.assignee.login // ""), labels: [.labels[].name] | join(",")}')
|
||||
|
||||
# Process each JSON object
|
||||
echo "$issues" | while IFS= read -r issue; do
|
||||
# Extract fields from JSON
|
||||
url=$(echo "$issue" | jq -r '.url')
|
||||
title=$(echo "$issue" | jq -r '.title')
|
||||
created_at=$(echo "$issue" | jq -r '.created_at')
|
||||
updated_at=$(echo "$issue" | jq -r '.updated_at')
|
||||
issue_number=$(echo "$issue" | jq -r '.number')
|
||||
assignee=$(echo "$issue" | jq -r '.assignee')
|
||||
labels=$(echo "$issue" | jq -r '.labels')
|
||||
|
||||
# Calculate days since creation and update using macOS compatible date calculation
|
||||
days_since_created=$(( ($(date -jf "%Y-%m-%d" "$today" +%s) - $(date -jf "%Y-%m-%d" "$created_at" +%s)) / 86400 ))
|
||||
days_since_updated=$(( ($(date -jf "%Y-%m-%d" "$today" +%s) - $(date -jf "%Y-%m-%d" "$updated_at" +%s)) / 86400 ))
|
||||
|
||||
# Fetch the total number of reactions for each issue
|
||||
reaction_data=$(gh api repos/leanprover/lean4/issues/$issue_number/reactions --paginate --jq 'length' 2>&1)
|
||||
if [[ $reaction_data == *"Not Found"* ]]; then
|
||||
total_reactions="Error fetching reactions"
|
||||
else
|
||||
total_reactions=$reaction_data
|
||||
fi
|
||||
|
||||
# Format output as CSV by escaping quotes and delimiting with commas
|
||||
echo "\"$url\",\"${title//\"/\"\"}\",\"$days_since_created\",\"$days_since_updated\",\"$total_reactions\",\"$assignee\",\"$labels\""
|
||||
done
|
||||
@@ -315,12 +315,6 @@ endif()
|
||||
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " ${LEAN_CXX_STDLIB}")
|
||||
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " ${LEAN_CXX_STDLIB}")
|
||||
|
||||
# in local builds, link executables and not just dynlibs against C++ stdlib as well,
|
||||
# which is required for e.g. asan
|
||||
if(NOT LEAN_STANDALONE)
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " ${LEAN_CXX_STDLIB}")
|
||||
endif()
|
||||
|
||||
# flags for user binaries = flags for toolchain binaries + Lake
|
||||
string(APPEND LEANC_STATIC_LINKER_FLAGS " ${TOOLCHAIN_STATIC_LINKER_FLAGS} -lLake")
|
||||
|
||||
@@ -594,10 +588,6 @@ if(PREV_STAGE)
|
||||
COMMAND bash -c 'CSRCS=${CMAKE_BINARY_DIR}/lib/temp script/update-stage0'
|
||||
DEPENDS make_stdlib
|
||||
WORKING_DIRECTORY "${LEAN_SOURCE_DIR}/..")
|
||||
|
||||
add_custom_target(update-stage0-commit
|
||||
COMMAND git commit -m "chore: update stage0"
|
||||
DEPENDS update-stage0)
|
||||
endif()
|
||||
|
||||
# use Bash version for building, use Lean version in bin/ for tests & distribution
|
||||
|
||||
@@ -33,4 +33,3 @@ import Init.SizeOfLemmas
|
||||
import Init.BinderPredicates
|
||||
import Init.Ext
|
||||
import Init.Omega
|
||||
import Init.MacroTrace
|
||||
|
||||
@@ -15,13 +15,6 @@ namespace Classical
|
||||
noncomputable def indefiniteDescription {α : Sort u} (p : α → Prop) (h : ∃ x, p x) : {x // p x} :=
|
||||
choice <| let ⟨x, px⟩ := h; ⟨⟨x, px⟩⟩
|
||||
|
||||
/--
|
||||
Given that there exists an element satisfying `p`, returns one such element.
|
||||
|
||||
This is a straightforward consequence of, and equivalent to, `Classical.choice`.
|
||||
|
||||
See also `choose_spec`, which asserts that the returned value has property `p`.
|
||||
-/
|
||||
noncomputable def choose {α : Sort u} {p : α → Prop} (h : ∃ x, p x) : α :=
|
||||
(indefiniteDescription p h).val
|
||||
|
||||
|
||||
@@ -20,29 +20,8 @@ def Functor.discard {f : Type u → Type v} {α : Type u} [Functor f] (x : f α)
|
||||
|
||||
export Functor (discard)
|
||||
|
||||
/--
|
||||
An `Alternative` functor is an `Applicative` functor that can "fail" or be "empty"
|
||||
and a binary operation `<|>` that “collects values” or finds the “left-most success”.
|
||||
|
||||
Important instances include
|
||||
* `Option`, where `failure := none` and `<|>` returns the left-most `some`.
|
||||
* Parser combinators typically provide an `Applicative` instance for error-handling and
|
||||
backtracking.
|
||||
|
||||
Error recovery and state can interact subtly. For example, the implementation of `Alternative` for `OptionT (StateT σ Id)` keeps modifications made to the state while recovering from failure, while `StateT σ (OptionT Id)` discards them.
|
||||
-/
|
||||
-- NB: List instance is in mathlib. Once upstreamed, add
|
||||
-- * `List`, where `failure` is the empty list and `<|>` concatenates.
|
||||
class Alternative (f : Type u → Type v) extends Applicative f : Type (max (u+1) v) where
|
||||
/--
|
||||
Produces an empty collection or recoverable failure. The `<|>` operator collects values or recovers
|
||||
from failures. See `Alternative` for more details.
|
||||
-/
|
||||
failure : {α : Type u} → f α
|
||||
/--
|
||||
Depending on the `Alternative` instance, collects values or recovers from `failure`s by
|
||||
returning the leftmost success. Can be written using the `<|>` operator syntax.
|
||||
-/
|
||||
orElse : {α : Type u} → f α → (Unit → f α) → f α
|
||||
|
||||
instance (f : Type u → Type v) (α : Type u) [Alternative f] : OrElse (f α) := ⟨Alternative.orElse⟩
|
||||
@@ -51,15 +30,9 @@ variable {f : Type u → Type v} [Alternative f] {α : Type u}
|
||||
|
||||
export Alternative (failure)
|
||||
|
||||
/--
|
||||
If the proposition `p` is true, does nothing, else fails (using `failure`).
|
||||
-/
|
||||
@[always_inline, inline] def guard {f : Type → Type v} [Alternative f] (p : Prop) [Decidable p] : f Unit :=
|
||||
if p then pure () else failure
|
||||
|
||||
/--
|
||||
Returns `some x` if `f` succeeds with value `x`, else returns `none`.
|
||||
-/
|
||||
@[always_inline, inline] def optional (x : f α) : f (Option α) :=
|
||||
some <$> x <|> pure none
|
||||
|
||||
|
||||
@@ -12,15 +12,6 @@ open Function
|
||||
@[simp] theorem monadLift_self [Monad m] (x : m α) : monadLift x = x :=
|
||||
rfl
|
||||
|
||||
/--
|
||||
The `Functor` typeclass only contains the operations of a functor.
|
||||
`LawfulFunctor` further asserts that these operations satisfy the laws of a functor,
|
||||
including the preservation of the identity and composition laws:
|
||||
```
|
||||
id <$> x = x
|
||||
(h ∘ g) <$> x = h <$> g <$> x
|
||||
```
|
||||
-/
|
||||
class LawfulFunctor (f : Type u → Type v) [Functor f] : Prop where
|
||||
map_const : (Functor.mapConst : α → f β → f α) = Functor.map ∘ const β
|
||||
id_map (x : f α) : id <$> x = x
|
||||
@@ -33,16 +24,6 @@ attribute [simp] id_map
|
||||
@[simp] theorem id_map' [Functor m] [LawfulFunctor m] (x : m α) : (fun a => a) <$> x = x :=
|
||||
id_map x
|
||||
|
||||
/--
|
||||
The `Applicative` typeclass only contains the operations of an applicative functor.
|
||||
`LawfulApplicative` further asserts that these operations satisfy the laws of an applicative functor:
|
||||
```
|
||||
pure id <*> v = v
|
||||
pure (·∘·) <*> u <*> v <*> w = u <*> (v <*> w)
|
||||
pure f <*> pure x = pure (f x)
|
||||
u <*> pure y = pure (· y) <*> u
|
||||
```
|
||||
-/
|
||||
class LawfulApplicative (f : Type u → Type v) [Applicative f] extends LawfulFunctor f : Prop where
|
||||
seqLeft_eq (x : f α) (y : f β) : x <* y = const β <$> x <*> y
|
||||
seqRight_eq (x : f α) (y : f β) : x *> y = const α id <$> x <*> y
|
||||
@@ -61,18 +42,6 @@ attribute [simp] map_pure seq_pure
|
||||
@[simp] theorem pure_id_seq [Applicative f] [LawfulApplicative f] (x : f α) : pure id <*> x = x := by
|
||||
simp [pure_seq]
|
||||
|
||||
/--
|
||||
The `Monad` typeclass only contains the operations of a monad.
|
||||
`LawfulMonad` further asserts that these operations satisfy the laws of a monad,
|
||||
including associativity and identity laws for `bind`:
|
||||
```
|
||||
pure x >>= f = f x
|
||||
x >>= pure = x
|
||||
x >>= f >>= g = x >>= (fun x => f x >>= g)
|
||||
```
|
||||
|
||||
`LawfulMonad.mk'` is an alternative constructor containing useful defaults for many fields.
|
||||
-/
|
||||
class LawfulMonad (m : Type u → Type v) [Monad m] extends LawfulApplicative m : Prop where
|
||||
bind_pure_comp (f : α → β) (x : m α) : x >>= (fun a => pure (f a)) = f <$> x
|
||||
bind_map {α β : Type u} (f : m (α → β)) (x : m α) : f >>= (. <$> x) = f <*> x
|
||||
|
||||
@@ -235,13 +235,13 @@ end StateT
|
||||
|
||||
instance : LawfulMonad (EStateM ε σ) := .mk'
|
||||
(id_map := fun x => funext <| fun s => by
|
||||
dsimp only [EStateM.instMonad, EStateM.map]
|
||||
dsimp only [EStateM.instMonadEStateM, EStateM.map]
|
||||
match x s with
|
||||
| .ok _ _ => rfl
|
||||
| .error _ _ => rfl)
|
||||
(pure_bind := fun _ _ => rfl)
|
||||
(bind_assoc := fun x _ _ => funext <| fun s => by
|
||||
dsimp only [EStateM.instMonad, EStateM.bind]
|
||||
dsimp only [EStateM.instMonadEStateM, EStateM.bind]
|
||||
match x s with
|
||||
| .ok _ _ => rfl
|
||||
| .error _ _ => rfl)
|
||||
|
||||
@@ -10,7 +10,7 @@ import Init.Control.Except
|
||||
|
||||
universe u v
|
||||
|
||||
instance : ToBool (Option α) := ⟨Option.isSome⟩
|
||||
instance : ToBool (Option α) := ⟨Option.toBool⟩
|
||||
|
||||
def OptionT (m : Type u → Type v) (α : Type u) : Type v :=
|
||||
m (Option α)
|
||||
|
||||
@@ -6,7 +6,7 @@ Authors: Leonardo de Moura
|
||||
Notation for operators defined at Prelude.lean
|
||||
-/
|
||||
prelude
|
||||
import Init.Tactics
|
||||
import Init.Meta
|
||||
|
||||
namespace Lean.Parser.Tactic.Conv
|
||||
|
||||
@@ -201,7 +201,7 @@ macro (name := anyGoals) tk:"any_goals " s:convSeq : conv =>
|
||||
with inaccessible names to the given names.
|
||||
* `case tag₁ | tag₂ => tac` is equivalent to `(case tag₁ => tac); (case tag₂ => tac)`.
|
||||
-/
|
||||
macro (name := case) tk:"case " args:sepBy1(caseArg, "|") arr:" => " s:convSeq : conv =>
|
||||
macro (name := case) tk:"case " args:sepBy1(caseArg, " | ") arr:" => " s:convSeq : conv =>
|
||||
`(conv| tactic' => case%$tk $args|* =>%$arr conv' => ($s); all_goals rfl)
|
||||
|
||||
/--
|
||||
@@ -210,7 +210,7 @@ has been solved after applying `tac`, nor admits the goal if `tac` failed.
|
||||
Recall that `case` closes the goal using `sorry` when `tac` fails, and
|
||||
the tactic execution is not interrupted.
|
||||
-/
|
||||
macro (name := case') tk:"case' " args:sepBy1(caseArg, "|") arr:" => " s:convSeq : conv =>
|
||||
macro (name := case') tk:"case' " args:sepBy1(caseArg, " | ") arr:" => " s:convSeq : conv =>
|
||||
`(conv| tactic' => case'%$tk $args|* =>%$arr conv' => $s)
|
||||
|
||||
/--
|
||||
|
||||
@@ -1308,6 +1308,7 @@ gen_injective_theorems% Fin
|
||||
gen_injective_theorems% Array
|
||||
gen_injective_theorems% Sum
|
||||
gen_injective_theorems% PSum
|
||||
gen_injective_theorems% Nat
|
||||
gen_injective_theorems% Option
|
||||
gen_injective_theorems% List
|
||||
gen_injective_theorems% Except
|
||||
@@ -1315,12 +1316,6 @@ gen_injective_theorems% EStateM.Result
|
||||
gen_injective_theorems% Lean.Name
|
||||
gen_injective_theorems% Lean.Syntax
|
||||
|
||||
theorem Nat.succ.inj {m n : Nat} : m.succ = n.succ → m = n :=
|
||||
fun x => Nat.noConfusion x id
|
||||
|
||||
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⟩
|
||||
|
||||
@@ -1601,7 +1596,7 @@ protected def mk' {α : Sort u} [s : Setoid α] (a : α) : Quotient s :=
|
||||
The analogue of `Quot.sound`: If `a` and `b` are related by the equivalence relation,
|
||||
then they have equal equivalence classes.
|
||||
-/
|
||||
theorem sound {α : Sort u} {s : Setoid α} {a b : α} : a ≈ b → Quotient.mk s a = Quotient.mk s b :=
|
||||
def sound {α : Sort u} {s : Setoid α} {a b : α} : a ≈ b → Quotient.mk s a = Quotient.mk s b :=
|
||||
Quot.sound
|
||||
|
||||
/--
|
||||
@@ -2040,8 +2035,4 @@ class LawfulCommIdentity (op : α → α → α) (o : outParam α) [hc : Commuta
|
||||
left_id a := Eq.trans (hc.comm o a) (right_id a)
|
||||
right_id a := Eq.trans (hc.comm a o) (left_id a)
|
||||
|
||||
instance : Commutative Or := ⟨fun _ _ => propext or_comm⟩
|
||||
instance : Commutative And := ⟨fun _ _ => propext and_comm⟩
|
||||
instance : Commutative Iff := ⟨fun _ _ => propext iff_comm⟩
|
||||
|
||||
end Std
|
||||
|
||||
@@ -14,7 +14,6 @@ import Init.Data.String
|
||||
import Init.Data.List
|
||||
import Init.Data.Int
|
||||
import Init.Data.Array
|
||||
import Init.Data.Array.Subarray.Split
|
||||
import Init.Data.ByteArray
|
||||
import Init.Data.FloatArray
|
||||
import Init.Data.Fin
|
||||
|
||||
@@ -10,7 +10,7 @@ import Init.Data.Fin.Basic
|
||||
import Init.Data.UInt.Basic
|
||||
import Init.Data.Repr
|
||||
import Init.Data.ToString.Basic
|
||||
import Init.GetElem
|
||||
import Init.Util
|
||||
universe u v w
|
||||
|
||||
namespace Array
|
||||
@@ -31,7 +31,6 @@ def ofFn {n} (f : Fin n → α) : Array α := go 0 (mkEmpty n) where
|
||||
go (i : Nat) (acc : Array α) : Array α :=
|
||||
if h : i < n then go (i+1) (acc.push (f ⟨i, h⟩)) else acc
|
||||
termination_by n - i
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
/-- The array `#[0, 1, ..., n - 1]`. -/
|
||||
def range (n : Nat) : Array Nat :=
|
||||
@@ -60,8 +59,6 @@ def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
|
||||
instance : GetElem (Array α) USize α fun xs i => i.toNat < xs.size where
|
||||
getElem xs i h := xs.uget i h
|
||||
|
||||
instance : LawfulGetElem (Array α) USize α fun xs i => i.toNat < xs.size where
|
||||
|
||||
def back [Inhabited α] (a : Array α) : α :=
|
||||
a.get! (a.size - 1)
|
||||
|
||||
@@ -307,7 +304,6 @@ def mapM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
|
||||
else
|
||||
pure r
|
||||
termination_by as.size - i
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
map 0 (mkEmpty as.size)
|
||||
|
||||
@[inline]
|
||||
@@ -380,7 +376,6 @@ def anyM {α : Type u} {m : Type → Type w} [Monad m] (p : α → m Bool) (as :
|
||||
else
|
||||
pure false
|
||||
termination_by stop - j
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
loop start
|
||||
if h : stop ≤ as.size then
|
||||
any stop h
|
||||
@@ -461,13 +456,24 @@ def findRev? {α : Type} (as : Array α) (p : α → Bool) : Option α :=
|
||||
|
||||
@[inline]
|
||||
def findIdx? {α : Type u} (as : Array α) (p : α → Bool) : Option Nat :=
|
||||
let rec loop (j : Nat) :=
|
||||
if h : j < as.size then
|
||||
if p as[j] then some j else loop (j + 1)
|
||||
else none
|
||||
termination_by as.size - j
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
loop 0
|
||||
let rec loop (i : Nat) (j : Nat) (inv : i + j = as.size) : Option Nat :=
|
||||
if hlt : j < as.size then
|
||||
match i, inv with
|
||||
| 0, inv => by
|
||||
apply False.elim
|
||||
rw [Nat.zero_add] at inv
|
||||
rw [inv] at hlt
|
||||
exact absurd hlt (Nat.lt_irrefl _)
|
||||
| i+1, inv =>
|
||||
if p as[j] then
|
||||
some j
|
||||
else
|
||||
have : i + (j+1) = as.size := by
|
||||
rw [← inv, Nat.add_comm j 1, Nat.add_assoc]
|
||||
loop i (j+1) this
|
||||
else
|
||||
none
|
||||
loop as.size 0 rfl
|
||||
|
||||
def getIdx? [BEq α] (a : Array α) (v : α) : Option Nat :=
|
||||
a.findIdx? fun a => a == v
|
||||
@@ -561,7 +567,6 @@ def isEqvAux (a b : Array α) (hsz : a.size = b.size) (p : α → α → Bool) (
|
||||
else
|
||||
true
|
||||
termination_by a.size - i
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
@[inline] def isEqv (a b : Array α) (p : α → α → Bool) : Bool :=
|
||||
if h : a.size = b.size then
|
||||
@@ -666,7 +671,6 @@ def indexOfAux [BEq α] (a : Array α) (v : α) (i : Nat) : Option (Fin a.size)
|
||||
else indexOfAux a v (i+1)
|
||||
else none
|
||||
termination_by a.size - i
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
def indexOf? [BEq α] (a : Array α) (v : α) : Option (Fin a.size) :=
|
||||
indexOfAux a v 0
|
||||
@@ -709,7 +713,6 @@ def popWhile (p : α → Bool) (as : Array α) : Array α :=
|
||||
else
|
||||
as
|
||||
termination_by as.size
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
def takeWhile (p : α → Bool) (as : Array α) : Array α :=
|
||||
let rec go (i : Nat) (r : Array α) : Array α :=
|
||||
@@ -722,7 +725,6 @@ def takeWhile (p : α → Bool) (as : Array α) : Array α :=
|
||||
else
|
||||
r
|
||||
termination_by as.size - i
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
go 0 #[]
|
||||
|
||||
/-- Remove the element at a given index from an array without bounds checks, using a `Fin` index.
|
||||
@@ -739,10 +741,11 @@ def feraseIdx (a : Array α) (i : Fin a.size) : Array α :=
|
||||
else
|
||||
a.pop
|
||||
termination_by a.size - i.val
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
derive_functional_induction feraseIdx
|
||||
|
||||
theorem size_feraseIdx (a : Array α) (i : Fin a.size) : (a.feraseIdx i).size = a.size - 1 := by
|
||||
induction a, i using Array.feraseIdx.induct with
|
||||
induction a, i using feraseIdx.induct with
|
||||
| @case1 a i h a' _ _ ih =>
|
||||
unfold feraseIdx
|
||||
simp [h, a', ih]
|
||||
@@ -772,7 +775,6 @@ def erase [BEq α] (as : Array α) (a : α) : Array α :=
|
||||
else
|
||||
as
|
||||
termination_by j.1
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
let j := as.size
|
||||
let as := as.push a
|
||||
loop as ⟨j, size_push .. ▸ j.lt_succ_self⟩
|
||||
@@ -826,7 +828,6 @@ def isPrefixOfAux [BEq α] (as bs : Array α) (hle : as.size ≤ bs.size) (i : N
|
||||
else
|
||||
true
|
||||
termination_by as.size - i
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
/-- Return true iff `as` is a prefix of `bs`.
|
||||
That is, `bs = as ++ t` for some `t : List α`.-/
|
||||
@@ -848,7 +849,6 @@ private def allDiffAux [BEq α] (as : Array α) (i : Nat) : Bool :=
|
||||
else
|
||||
true
|
||||
termination_by as.size - i
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
def allDiff [BEq α] (as : Array α) : Bool :=
|
||||
allDiffAux as 0
|
||||
@@ -864,7 +864,6 @@ def allDiff [BEq α] (as : Array α) : Bool :=
|
||||
else
|
||||
cs
|
||||
termination_by as.size - i
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
@[inline] def zipWith (as : Array α) (bs : Array β) (f : α → β → γ) : Array γ :=
|
||||
zipWithAux f as bs 0 #[]
|
||||
|
||||
@@ -48,7 +48,6 @@ where
|
||||
let b ← f as[i]
|
||||
go (i+1) ⟨acc.val.push b, by simp [acc.property]⟩ hlt
|
||||
termination_by as.size - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
|
||||
@[inline] private unsafe def mapMonoMImp [Monad m] (as : Array α) (f : α → m α) : m (Array α) :=
|
||||
go 0 as
|
||||
|
||||
@@ -21,8 +21,6 @@ theorem eq_of_isEqvAux [DecidableEq α] (a b : Array α) (hsz : a.size = b.size)
|
||||
subst heq
|
||||
exact absurd (Nat.lt_of_lt_of_le high low) (Nat.lt_irrefl j)
|
||||
termination_by a.size - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
|
||||
|
||||
theorem eq_of_isEqv [DecidableEq α] (a b : Array α) : Array.isEqv a b (fun x y => x = y) → a = b := by
|
||||
simp [Array.isEqv]
|
||||
@@ -39,7 +37,6 @@ theorem isEqvAux_self [DecidableEq α] (a : Array α) (i : Nat) : Array.isEqvAux
|
||||
case inl h => simp [h, isEqvAux_self a (i+1)]
|
||||
case inr h => simp [h]
|
||||
termination_by a.size - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
|
||||
theorem isEqv_self [DecidableEq α] (a : Array α) : Array.isEqv a a (fun x y => x = y) = true := by
|
||||
simp [isEqv, isEqvAux_self]
|
||||
|
||||
@@ -5,7 +5,6 @@ Authors: Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Nat.MinMax
|
||||
import Init.Data.Nat.Lemmas
|
||||
import Init.Data.List.Lemmas
|
||||
import Init.Data.Fin.Basic
|
||||
import Init.Data.Array.Mem
|
||||
@@ -131,7 +130,6 @@ where
|
||||
simp [aux (i+1), map_eq_pure_bind]; rfl
|
||||
· rw [List.drop_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
||||
termination_by arr.size - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
|
||||
@[simp] theorem map_data (f : α → β) (arr : Array α) : (arr.map f).data = arr.data.map f := by
|
||||
rw [map, mapM_eq_foldlM]
|
||||
@@ -189,8 +187,7 @@ theorem anyM_stop_le_start [Monad m] (p : α → m Bool) (as : Array α) (start
|
||||
theorem mem_def (a : α) (as : Array α) : a ∈ as ↔ a ∈ as.data :=
|
||||
⟨fun | .mk h => h, Array.Mem.mk⟩
|
||||
|
||||
/-! # get -/
|
||||
|
||||
/-- # get -/
|
||||
@[simp] theorem get_eq_getElem (a : Array α) (i : Fin _) : a.get i = a[i.1] := rfl
|
||||
|
||||
theorem getElem?_lt
|
||||
@@ -220,7 +217,7 @@ theorem get!_eq_getD [Inhabited α] (a : Array α) : a.get! n = a.getD n default
|
||||
@[simp] theorem get!_eq_getElem? [Inhabited α] (a : Array α) (i : Nat) : a.get! i = (a.get? i).getD default := by
|
||||
by_cases p : i < a.size <;> simp [getD_get?, get!_eq_getD, p]
|
||||
|
||||
/-! # set -/
|
||||
/-- # set -/
|
||||
|
||||
@[simp] theorem getElem_set_eq (a : Array α) (i : Fin a.size) (v : α) {j : Nat}
|
||||
(eq : i.val = j) (p : j < (a.set i v).size) :
|
||||
@@ -243,7 +240,7 @@ theorem getElem_set (a : Array α) (i : Fin a.size) (v : α) (j : Nat)
|
||||
(ne : i.val ≠ j) : (a.set i v)[j]? = a[j]? := by
|
||||
by_cases h : j < a.size <;> simp [getElem?_lt, getElem?_ge, Nat.ge_of_not_lt, ne, h]
|
||||
|
||||
/-! # setD -/
|
||||
/- # setD -/
|
||||
|
||||
@[simp] theorem set!_is_setD : @set! = @setD := rfl
|
||||
|
||||
@@ -269,44 +266,4 @@ theorem getElem?_setD_eq (a : Array α) {i : Nat} (p : i < a.size) (v : α) : (a
|
||||
by_cases h : i < a.size <;>
|
||||
simp [setD, Nat.not_lt_of_le, h, getD_get?]
|
||||
|
||||
/-! # ofFn -/
|
||||
|
||||
@[simp] theorem size_ofFn_go {n} (f : Fin n → α) (i acc) :
|
||||
(ofFn.go f i acc).size = acc.size + (n - i) := by
|
||||
if hin : i < n then
|
||||
unfold ofFn.go
|
||||
have : 1 + (n - (i + 1)) = n - i :=
|
||||
Nat.sub_sub .. ▸ Nat.add_sub_cancel' (Nat.le_sub_of_add_le (Nat.add_comm .. ▸ hin))
|
||||
rw [dif_pos hin, size_ofFn_go f (i+1), size_push, Nat.add_assoc, this]
|
||||
else
|
||||
have : n - i = 0 := Nat.sub_eq_zero_of_le (Nat.le_of_not_lt hin)
|
||||
unfold ofFn.go
|
||||
simp [hin, this]
|
||||
termination_by n - i
|
||||
|
||||
@[simp] theorem size_ofFn (f : Fin n → α) : (ofFn f).size = n := by simp [ofFn]
|
||||
|
||||
theorem getElem_ofFn_go (f : Fin n → α) (i) {acc k}
|
||||
(hki : k < n) (hin : i ≤ n) (hi : i = acc.size)
|
||||
(hacc : ∀ j, ∀ hj : j < acc.size, acc[j] = f ⟨j, Nat.lt_of_lt_of_le hj (hi ▸ hin)⟩) :
|
||||
haveI : acc.size + (n - acc.size) = n := Nat.add_sub_cancel' (hi ▸ hin)
|
||||
(ofFn.go f i acc)[k]'(by simp [*]) = f ⟨k, hki⟩ := by
|
||||
unfold ofFn.go
|
||||
if hin : i < n then
|
||||
have : 1 + (n - (i + 1)) = n - i :=
|
||||
Nat.sub_sub .. ▸ Nat.add_sub_cancel' (Nat.le_sub_of_add_le (Nat.add_comm .. ▸ hin))
|
||||
simp only [dif_pos hin]
|
||||
rw [getElem_ofFn_go f (i+1) _ hin (by simp [*]) (fun j hj => ?hacc)]
|
||||
cases (Nat.lt_or_eq_of_le <| Nat.le_of_lt_succ (by simpa using hj)) with
|
||||
| inl hj => simp [get_push, hj, hacc j hj]
|
||||
| inr hj => simp [get_push, *]
|
||||
else
|
||||
simp [hin, hacc k (Nat.lt_of_lt_of_le hki (Nat.le_of_not_lt (hi ▸ hin)))]
|
||||
termination_by n - i
|
||||
|
||||
@[simp] theorem getElem_ofFn (f : Fin n → α) (i : Nat) (h) :
|
||||
(ofFn f)[i] = f ⟨i, size_ofFn f ▸ h⟩ :=
|
||||
getElem_ofFn_go _ _ _ (by simp) (by simp) nofun
|
||||
|
||||
|
||||
end Array
|
||||
|
||||
@@ -27,20 +27,13 @@ theorem sizeOf_lt_of_mem [SizeOf α] {as : Array α} (h : a ∈ as) : sizeOf a <
|
||||
cases as with | _ as =>
|
||||
exact Nat.lt_trans (List.sizeOf_get ..) (by simp_arith)
|
||||
|
||||
@[simp] theorem sizeOf_getElem [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) :
|
||||
sizeOf (as[i]'h) < sizeOf as := sizeOf_get _ _
|
||||
|
||||
/-- This tactic, added to the `decreasing_trivial` toolbox, proves that
|
||||
`sizeOf arr[i] < sizeOf arr`, which is useful for well founded recursions
|
||||
over a nested inductive like `inductive T | mk : Array T → T`. -/
|
||||
macro "array_get_dec" : tactic =>
|
||||
`(tactic| first
|
||||
-- subsumed by simp
|
||||
-- | with_reducible apply sizeOf_get
|
||||
-- | with_reducible apply sizeOf_getElem
|
||||
| (with_reducible apply Nat.lt_trans (sizeOf_get ..)); simp_arith
|
||||
| (with_reducible apply Nat.lt_trans (sizeOf_getElem ..)); simp_arith
|
||||
)
|
||||
| apply sizeOf_get
|
||||
| apply Nat.lt_trans (sizeOf_get ..); simp_arith)
|
||||
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| array_get_dec)
|
||||
|
||||
@@ -50,10 +43,9 @@ provided that `a ∈ arr` which is useful for well founded recursions over a nes
|
||||
-- NB: This is analogue to tactic `sizeOf_list_dec`
|
||||
macro "array_mem_dec" : tactic =>
|
||||
`(tactic| first
|
||||
| with_reducible apply Array.sizeOf_lt_of_mem; assumption; done
|
||||
| with_reducible
|
||||
apply Nat.lt_trans (Array.sizeOf_lt_of_mem ?h)
|
||||
case' h => assumption
|
||||
| apply Array.sizeOf_lt_of_mem; assumption; done
|
||||
| apply Nat.lt_trans (Array.sizeOf_lt_of_mem ?h)
|
||||
case' h => assumption
|
||||
simp_arith)
|
||||
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| array_mem_dec)
|
||||
|
||||
@@ -27,7 +27,6 @@ def qpartition (as : Array α) (lt : α → α → Bool) (lo hi : Nat) : Nat ×
|
||||
let as := as.swap! i hi
|
||||
(i, as)
|
||||
termination_by hi - j
|
||||
decreasing_by all_goals simp_wf; decreasing_trivial_pre_omega
|
||||
loop as lo lo
|
||||
|
||||
@[inline] partial def qsort (as : Array α) (lt : α → α → Bool) (low := 0) (high := as.size - 1) : Array α :=
|
||||
|
||||
@@ -9,46 +9,29 @@ import Init.Data.Array.Basic
|
||||
universe u v w
|
||||
|
||||
structure Subarray (α : Type u) where
|
||||
array : Array α
|
||||
as : Array α
|
||||
start : Nat
|
||||
stop : Nat
|
||||
start_le_stop : start ≤ stop
|
||||
stop_le_array_size : stop ≤ array.size
|
||||
|
||||
@[deprecated Subarray.array]
|
||||
abbrev Subarray.as (s : Subarray α) : Array α := s.array
|
||||
|
||||
@[deprecated Subarray.start_le_stop]
|
||||
theorem Subarray.h₁ (s : Subarray α) : s.start ≤ s.stop := s.start_le_stop
|
||||
|
||||
@[deprecated Subarray.stop_le_array_size]
|
||||
theorem Subarray.h₂ (s : Subarray α) : s.stop ≤ s.as.size := s.stop_le_array_size
|
||||
h₁ : start ≤ stop
|
||||
h₂ : stop ≤ as.size
|
||||
|
||||
namespace Subarray
|
||||
|
||||
def size (s : Subarray α) : Nat :=
|
||||
s.stop - s.start
|
||||
|
||||
theorem size_le_array_size {s : Subarray α} : s.size ≤ s.array.size := by
|
||||
let {array, start, stop, start_le_stop, stop_le_array_size} := s
|
||||
simp [size]
|
||||
apply Nat.le_trans (Nat.sub_le stop start)
|
||||
assumption
|
||||
|
||||
def get (s : Subarray α) (i : Fin s.size) : α :=
|
||||
have : s.start + i.val < s.array.size := by
|
||||
apply Nat.lt_of_lt_of_le _ s.stop_le_array_size
|
||||
have : s.start + i.val < s.as.size := by
|
||||
apply Nat.lt_of_lt_of_le _ s.h₂
|
||||
have := i.isLt
|
||||
simp [size] at this
|
||||
rw [Nat.add_comm]
|
||||
exact Nat.add_lt_of_lt_sub this
|
||||
s.array[s.start + i.val]
|
||||
s.as[s.start + i.val]
|
||||
|
||||
instance : GetElem (Subarray α) Nat α fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
|
||||
instance : LawfulGetElem (Subarray α) Nat α fun xs i => i < xs.size where
|
||||
|
||||
@[inline] def getD (s : Subarray α) (i : Nat) (v₀ : α) : α :=
|
||||
if h : i < s.size then s.get ⟨i, h⟩ else v₀
|
||||
|
||||
@@ -57,7 +40,7 @@ abbrev get! [Inhabited α] (s : Subarray α) (i : Nat) : α :=
|
||||
|
||||
def popFront (s : Subarray α) : Subarray α :=
|
||||
if h : s.start < s.stop then
|
||||
{ s with start := s.start + 1, start_le_stop := Nat.le_of_lt_succ (Nat.add_lt_add_right h 1) }
|
||||
{ s with start := s.start + 1, h₁ := Nat.le_of_lt_succ (Nat.add_lt_add_right h 1) }
|
||||
else
|
||||
s
|
||||
|
||||
@@ -65,7 +48,7 @@ def popFront (s : Subarray α) : Subarray α :=
|
||||
let sz := USize.ofNat s.stop
|
||||
let rec @[specialize] loop (i : USize) (b : β) : m β := do
|
||||
if i < sz then
|
||||
let a := s.array.uget i lcProof
|
||||
let a := s.as.uget i lcProof
|
||||
match (← f a b) with
|
||||
| ForInStep.done b => pure b
|
||||
| ForInStep.yield b => loop (i+1) b
|
||||
@@ -83,27 +66,27 @@ instance : ForIn m (Subarray α) α where
|
||||
|
||||
@[inline]
|
||||
def foldlM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : β → α → m β) (init : β) (as : Subarray α) : m β :=
|
||||
as.array.foldlM f (init := init) (start := as.start) (stop := as.stop)
|
||||
as.as.foldlM f (init := init) (start := as.start) (stop := as.stop)
|
||||
|
||||
@[inline]
|
||||
def foldrM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → β → m β) (init : β) (as : Subarray α) : m β :=
|
||||
as.array.foldrM f (init := init) (start := as.stop) (stop := as.start)
|
||||
as.as.foldrM f (init := init) (start := as.stop) (stop := as.start)
|
||||
|
||||
@[inline]
|
||||
def anyM {α : Type u} {m : Type → Type w} [Monad m] (p : α → m Bool) (as : Subarray α) : m Bool :=
|
||||
as.array.anyM p (start := as.start) (stop := as.stop)
|
||||
as.as.anyM p (start := as.start) (stop := as.stop)
|
||||
|
||||
@[inline]
|
||||
def allM {α : Type u} {m : Type → Type w} [Monad m] (p : α → m Bool) (as : Subarray α) : m Bool :=
|
||||
as.array.allM p (start := as.start) (stop := as.stop)
|
||||
as.as.allM p (start := as.start) (stop := as.stop)
|
||||
|
||||
@[inline]
|
||||
def forM {α : Type u} {m : Type v → Type w} [Monad m] (f : α → m PUnit) (as : Subarray α) : m PUnit :=
|
||||
as.array.forM f (start := as.start) (stop := as.stop)
|
||||
as.as.forM f (start := as.start) (stop := as.stop)
|
||||
|
||||
@[inline]
|
||||
def forRevM {α : Type u} {m : Type v → Type w} [Monad m] (f : α → m PUnit) (as : Subarray α) : m PUnit :=
|
||||
as.array.forRevM f (start := as.stop) (stop := as.start)
|
||||
as.as.forRevM f (start := as.stop) (stop := as.start)
|
||||
|
||||
@[inline]
|
||||
def foldl {α : Type u} {β : Type v} (f : β → α → β) (init : β) (as : Subarray α) : β :=
|
||||
@@ -150,25 +133,15 @@ variable {α : Type u}
|
||||
|
||||
def toSubarray (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : Subarray α :=
|
||||
if h₂ : stop ≤ as.size then
|
||||
if h₁ : start ≤ stop then
|
||||
{ array := as, start := start, stop := stop,
|
||||
start_le_stop := h₁, stop_le_array_size := h₂ }
|
||||
else
|
||||
{ array := as, start := stop, stop := stop,
|
||||
start_le_stop := Nat.le_refl _, stop_le_array_size := h₂ }
|
||||
if h₁ : start ≤ stop then
|
||||
{ as := as, start := start, stop := stop, h₁ := h₁, h₂ := h₂ }
|
||||
else
|
||||
{ as := as, start := stop, stop := stop, h₁ := Nat.le_refl _, h₂ := h₂ }
|
||||
else
|
||||
if h₁ : start ≤ as.size then
|
||||
{ array := as,
|
||||
start := start,
|
||||
stop := as.size,
|
||||
start_le_stop := h₁,
|
||||
stop_le_array_size := Nat.le_refl _ }
|
||||
else
|
||||
{ array := as,
|
||||
start := as.size,
|
||||
stop := as.size,
|
||||
start_le_stop := Nat.le_refl _,
|
||||
stop_le_array_size := Nat.le_refl _ }
|
||||
if h₁ : start ≤ as.size then
|
||||
{ as := as, start := start, stop := as.size, h₁ := h₁, h₂ := Nat.le_refl _ }
|
||||
else
|
||||
{ as := as, start := as.size, stop := as.size, h₁ := Nat.le_refl _, h₂ := Nat.le_refl _ }
|
||||
|
||||
@[coe]
|
||||
def ofSubarray (s : Subarray α) : Array α := Id.run do
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: David Thrane Christiansen
|
||||
-/
|
||||
|
||||
prelude
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.Array.Subarray
|
||||
import Init.Omega
|
||||
|
||||
/-
|
||||
This module contains splitting operations on subarrays that crucially rely on `omega` for proof
|
||||
automation. Placing them in another module breaks an import cycle, because `omega` itself uses the
|
||||
array library.
|
||||
-/
|
||||
|
||||
namespace Subarray
|
||||
/--
|
||||
Splits a subarray into two parts.
|
||||
-/
|
||||
def split (s : Subarray α) (i : Fin s.size.succ) : (Subarray α × Subarray α) :=
|
||||
let ⟨i', isLt⟩ := i
|
||||
have := s.start_le_stop
|
||||
have := s.stop_le_array_size
|
||||
have : i' ≤ s.stop - s.start := Nat.lt_succ.mp isLt
|
||||
have : s.start + i' ≤ s.stop := by omega
|
||||
have : s.start + i' ≤ s.array.size := by omega
|
||||
have : s.start + i' ≤ s.stop := by
|
||||
simp only [size] at isLt
|
||||
omega
|
||||
let pre := {s with
|
||||
stop := s.start + i',
|
||||
start_le_stop := by omega,
|
||||
stop_le_array_size := by assumption
|
||||
}
|
||||
let post := {s with
|
||||
start := s.start + i'
|
||||
start_le_stop := by assumption
|
||||
}
|
||||
(pre, post)
|
||||
|
||||
/--
|
||||
Removes the first `i` elements of the subarray. If there are `i` or fewer elements, the resulting
|
||||
subarray is empty.
|
||||
-/
|
||||
def drop (arr : Subarray α) (i : Nat) : Subarray α where
|
||||
array := arr.array
|
||||
start := min (arr.start + i) arr.stop
|
||||
stop := arr.stop
|
||||
start_le_stop := by
|
||||
rw [Nat.min_def]
|
||||
split <;> simp only [Nat.le_refl, *]
|
||||
stop_le_array_size := arr.stop_le_array_size
|
||||
|
||||
/--
|
||||
Keeps only the first `i` elements of the subarray. If there are `i` or fewer elements, the resulting
|
||||
subarray is empty.
|
||||
-/
|
||||
def take (arr : Subarray α) (i : Nat) : Subarray α where
|
||||
array := arr.array
|
||||
start := arr.start
|
||||
stop := min (arr.start + i) arr.stop
|
||||
start_le_stop := by
|
||||
have := arr.start_le_stop
|
||||
rw [Nat.min_def]
|
||||
split <;> omega
|
||||
stop_le_array_size := by
|
||||
have := arr.stop_le_array_size
|
||||
rw [Nat.min_def]
|
||||
split <;> omega
|
||||
@@ -1,7 +1,7 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Joe Hendrix, Wojciech Nawrocki, Leonardo de Moura, Mario Carneiro, Alex Keizer, Harun Khan, Abdalrhman M Mohamed
|
||||
Authors: Joe Hendrix, Wojciech Nawrocki, Leonardo de Moura, Mario Carneiro, Alex Keizer
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Fin.Basic
|
||||
@@ -34,7 +34,7 @@ structure BitVec (w : Nat) where
|
||||
O(1), because we use `Fin` as the internal representation of a bitvector. -/
|
||||
toFin : Fin (2^w)
|
||||
|
||||
@[deprecated] protected abbrev Std.BitVec := _root_.BitVec
|
||||
@[deprecated] abbrev Std.BitVec := _root_.BitVec
|
||||
|
||||
-- We manually derive the `DecidableEq` instances for `BitVec` because
|
||||
-- we want to have builtin support for bit-vector literals, and we
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/-
|
||||
Copyright (c) 2023 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Joe Hendrix, Harun Khan, Alex Keizer, Abdalrhman M Mohamed,
|
||||
Authors: Joe Hendrix
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Bool
|
||||
@@ -103,13 +103,7 @@ theorem eq_of_getMsb_eq {x y : BitVec w}
|
||||
have q := pred ⟨w - 1 - i, q_lt⟩
|
||||
simpa [q_lt, Nat.sub_sub_self, r] using q
|
||||
|
||||
-- This cannot be a `@[simp]` lemma, as it would be tried at every term.
|
||||
theorem of_length_zero {x : BitVec 0} : x = 0#0 := by ext; simp
|
||||
|
||||
@[simp] theorem toNat_zero_length (x : BitVec 0) : x.toNat = 0 := by simp [of_length_zero]
|
||||
@[simp] theorem getLsb_zero_length (x : BitVec 0) : x.getLsb i = false := by simp [of_length_zero]
|
||||
@[simp] theorem getMsb_zero_length (x : BitVec 0) : x.getMsb i = false := by simp [of_length_zero]
|
||||
@[simp] theorem msb_zero_length (x : BitVec 0) : x.msb = false := by simp [BitVec.msb, of_length_zero]
|
||||
@[simp] theorem of_length_zero {x : BitVec 0} : x = 0#0 := by ext; simp
|
||||
|
||||
theorem eq_of_toFin_eq : ∀ {x y : BitVec w}, x.toFin = y.toFin → x = y
|
||||
| ⟨_, _⟩, ⟨_, _⟩, rfl => rfl
|
||||
@@ -342,7 +336,7 @@ theorem nat_eq_toNat (x : BitVec w) (y : Nat)
|
||||
@[simp] theorem getMsb_zeroExtend_add {x : BitVec w} (h : k ≤ i) :
|
||||
(x.zeroExtend (w + k)).getMsb i = x.getMsb (i - k) := by
|
||||
by_cases h : w = 0
|
||||
· subst h; simp [of_length_zero]
|
||||
· subst h; simp
|
||||
simp only [getMsb, getLsb_zeroExtend]
|
||||
by_cases h₁ : i < w + k <;> by_cases h₂ : i - k < w <;> by_cases h₃ : w + k - 1 - i < w + k
|
||||
<;> simp [h₁, h₂, h₃]
|
||||
@@ -734,7 +728,8 @@ theorem toNat_cons' {x : BitVec w} :
|
||||
rw [← BitVec.msb, msb_cons]
|
||||
|
||||
@[simp] theorem getMsb_cons_succ : (cons a x).getMsb (i + 1) = x.getMsb i := by
|
||||
simp [cons, Nat.le_add_left 1 i]
|
||||
simp [cons, cond_eq_if]
|
||||
omega
|
||||
|
||||
theorem truncate_succ (x : BitVec w) :
|
||||
truncate (i+1) x = cons (getLsb x i) (truncate i x) := by
|
||||
@@ -823,42 +818,24 @@ Definition of bitvector addition as a nat.
|
||||
.ofFin x + y = .ofFin (x + y.toFin) := rfl
|
||||
@[simp] theorem add_ofFin (x : BitVec n) (y : Fin (2^n)) :
|
||||
x + .ofFin y = .ofFin (x.toFin + y) := rfl
|
||||
|
||||
theorem ofNat_add {n} (x y : Nat) : (x + y)#n = x#n + y#n := by
|
||||
@[simp] theorem ofNat_add_ofNat {n} (x y : Nat) : x#n + y#n = (x + y)#n := by
|
||||
apply eq_of_toNat_eq ; simp [BitVec.ofNat]
|
||||
|
||||
theorem ofNat_add_ofNat {n} (x y : Nat) : x#n + y#n = (x + y)#n :=
|
||||
(ofNat_add x y).symm
|
||||
|
||||
protected theorem add_assoc (x y z : BitVec n) : x + y + z = x + (y + z) := by
|
||||
apply eq_of_toNat_eq ; simp [Nat.add_assoc]
|
||||
instance : Std.Associative (α := BitVec n) (· + ·) := ⟨BitVec.add_assoc⟩
|
||||
|
||||
protected theorem add_comm (x y : BitVec n) : x + y = y + x := by
|
||||
simp [add_def, Nat.add_comm]
|
||||
instance : Std.Commutative (α := BitVec n) (· + ·) := ⟨BitVec.add_comm⟩
|
||||
|
||||
@[simp] protected theorem add_zero (x : BitVec n) : x + 0#n = x := by simp [add_def]
|
||||
|
||||
@[simp] protected theorem zero_add (x : BitVec n) : 0#n + x = x := by simp [add_def]
|
||||
instance : Std.LawfulIdentity (α := BitVec n) (· + ·) 0#n where
|
||||
left_id := BitVec.zero_add
|
||||
right_id := BitVec.add_zero
|
||||
|
||||
theorem truncate_add (x y : BitVec w) (h : i ≤ w) :
|
||||
(x + y).truncate i = x.truncate i + y.truncate i := by
|
||||
have dvd : 2^i ∣ 2^w := Nat.pow_dvd_pow _ h
|
||||
simp [bv_toNat, h, Nat.mod_mod_of_dvd _ dvd]
|
||||
|
||||
@[simp, bv_toNat] theorem toInt_add (x y : BitVec w) :
|
||||
(x + y).toInt = (x.toInt + y.toInt).bmod (2^w) := by
|
||||
simp [toInt_eq_toNat_bmod]
|
||||
|
||||
theorem ofInt_add {n} (x y : Int) : BitVec.ofInt n (x + y) =
|
||||
BitVec.ofInt n x + BitVec.ofInt n y := by
|
||||
apply eq_of_toInt_eq
|
||||
simp
|
||||
|
||||
/-! ### sub/neg -/
|
||||
|
||||
theorem sub_def {n} (x y : BitVec n) : x - y = .ofNat n (x.toNat + (2^n - y.toNat)) := by rfl
|
||||
@@ -935,15 +912,6 @@ instance : Std.Associative (fun (x y : BitVec w) => x * y) := ⟨BitVec.mul_asso
|
||||
instance : Std.LawfulCommIdentity (fun (x y : BitVec w) => x * y) (1#w) where
|
||||
right_id := BitVec.mul_one
|
||||
|
||||
@[simp, bv_toNat] theorem toInt_mul (x y : BitVec w) :
|
||||
(x * y).toInt = (x.toInt * y.toInt).bmod (2^w) := by
|
||||
simp [toInt_eq_toNat_bmod]
|
||||
|
||||
theorem ofInt_mul {n} (x y : Int) : BitVec.ofInt n (x * y) =
|
||||
BitVec.ofInt n x * BitVec.ofInt n y := by
|
||||
apply eq_of_toInt_eq
|
||||
simp
|
||||
|
||||
/-! ### le and lt -/
|
||||
|
||||
@[bv_toNat] theorem le_def (x y : BitVec n) :
|
||||
|
||||
@@ -74,7 +74,6 @@ Added for confluence with `not_and_self` `and_not_self` on term
|
||||
@[simp] theorem eq_false_and_eq_true_self : ∀(b : Bool), (b = false ∧ b = true) ↔ False := by decide
|
||||
|
||||
theorem and_comm : ∀ (x y : Bool), (x && y) = (y && x) := by decide
|
||||
instance : Std.Commutative (· && ·) := ⟨and_comm⟩
|
||||
|
||||
theorem and_left_comm : ∀ (x y z : Bool), (x && (y && z)) = (y && (x && z)) := by decide
|
||||
theorem and_right_comm : ∀ (x y z : Bool), ((x && y) && z) = ((x && z) && y) := by decide
|
||||
@@ -121,7 +120,6 @@ Needed for confluence of term `(a || b) ↔ a` which reduces to `(a || b) = a` v
|
||||
@[simp] theorem iff_or_self : ∀(a b : Bool), (b = (a || b)) ↔ (a → b) := by decide
|
||||
|
||||
theorem or_comm : ∀ (x y : Bool), (x || y) = (y || x) := by decide
|
||||
instance : Std.Commutative (· || ·) := ⟨or_comm⟩
|
||||
|
||||
theorem or_left_comm : ∀ (x y z : Bool), (x || (y || z)) = (y || (x || z)) := by decide
|
||||
theorem or_right_comm : ∀ (x y z : Bool), ((x || y) || z) = ((x || z) || y) := by decide
|
||||
@@ -188,18 +186,12 @@ in false_eq and true_eq.
|
||||
@[simp] theorem true_beq : ∀b, (true == b) = b := by decide
|
||||
@[simp] theorem false_beq : ∀b, (false == b) = !b := by decide
|
||||
@[simp] theorem beq_true : ∀b, (b == true) = b := by decide
|
||||
instance : Std.LawfulIdentity (· == ·) true where
|
||||
left_id := true_beq
|
||||
right_id := beq_true
|
||||
@[simp] theorem beq_false : ∀b, (b == false) = !b := by decide
|
||||
|
||||
@[simp] theorem true_bne : ∀(b : Bool), (true != b) = !b := by decide
|
||||
@[simp] theorem false_bne : ∀(b : Bool), (false != b) = b := by decide
|
||||
@[simp] theorem bne_true : ∀(b : Bool), (b != true) = !b := by decide
|
||||
@[simp] theorem bne_false : ∀(b : Bool), (b != false) = b := by decide
|
||||
instance : Std.LawfulIdentity (· != ·) false where
|
||||
left_id := false_bne
|
||||
right_id := bne_false
|
||||
|
||||
@[simp] theorem not_beq_self : ∀ (x : Bool), ((!x) == x) = false := by decide
|
||||
@[simp] theorem beq_not_self : ∀ (x : Bool), (x == !x) = false := by decide
|
||||
@@ -222,19 +214,12 @@ due to `beq_iff_eq`.
|
||||
@[simp] theorem not_bne_not : ∀ (x y : Bool), ((!x) != (!y)) = (x != y) := by decide
|
||||
|
||||
@[simp] theorem bne_assoc : ∀ (x y z : Bool), ((x != y) != z) = (x != (y != z)) := by decide
|
||||
instance : Std.Associative (· != ·) := ⟨bne_assoc⟩
|
||||
|
||||
@[simp] theorem bne_left_inj : ∀ (x y z : Bool), (x != y) = (x != z) ↔ y = z := by decide
|
||||
@[simp] theorem bne_right_inj : ∀ (x y z : Bool), (x != z) = (y != z) ↔ x = y := by decide
|
||||
|
||||
/-! ### coercision related normal forms -/
|
||||
|
||||
theorem beq_eq_decide_eq [BEq α] [LawfulBEq α] [DecidableEq α] (a b : α) :
|
||||
(a == b) = decide (a = b) := by
|
||||
cases h : a == b
|
||||
· simp [ne_of_beq_false h]
|
||||
· simp [eq_of_beq h]
|
||||
|
||||
@[simp] theorem not_eq_not : ∀ {a b : Bool}, ¬a = !b ↔ a = b := by decide
|
||||
|
||||
@[simp] theorem not_not_eq : ∀ {a b : Bool}, ¬(!a) = b ↔ a = b := by decide
|
||||
@@ -245,11 +230,6 @@ theorem beq_eq_decide_eq [BEq α] [LawfulBEq α] [DecidableEq α] (a b : α) :
|
||||
@[simp] theorem coe_false_iff_true : ∀(a b : Bool), (a = false ↔ b) ↔ (!a) = b := by decide
|
||||
@[simp] theorem coe_false_iff_false : ∀(a b : Bool), (a = false ↔ b = false) ↔ (!a) = (!b) := by decide
|
||||
|
||||
/-! ### beq properties -/
|
||||
|
||||
theorem beq_comm {α} [BEq α] [LawfulBEq α] {a b : α} : (a == b) = (b == a) :=
|
||||
(Bool.coe_iff_coe (a == b) (b == a)).mp (by simp [@eq_comm α])
|
||||
|
||||
/-! ### xor -/
|
||||
|
||||
theorem false_xor : ∀ (x : Bool), xor false x = x := false_bne
|
||||
|
||||
@@ -52,13 +52,9 @@ def get : (a : @& ByteArray) → (@& Fin a.size) → UInt8
|
||||
instance : GetElem ByteArray Nat UInt8 fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
|
||||
instance : LawfulGetElem ByteArray Nat UInt8 fun xs i => i < xs.size where
|
||||
|
||||
instance : GetElem ByteArray USize UInt8 fun xs i => i.val < xs.size where
|
||||
getElem xs i h := xs.uget i h
|
||||
|
||||
instance : LawfulGetElem ByteArray USize UInt8 fun xs i => i.val < xs.size where
|
||||
|
||||
@[extern "lean_byte_array_set"]
|
||||
def set! : ByteArray → (@& Nat) → UInt8 → ByteArray
|
||||
| ⟨bs⟩, i, b => ⟨bs.set! i b⟩
|
||||
@@ -199,18 +195,6 @@ instance : ToString ByteArray := ⟨fun bs => bs.toList.toString⟩
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a little-endian `UInt64`. -/
|
||||
def ByteArray.toUInt64LE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 7).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 0).toUInt64
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a big-endian `UInt64`. -/
|
||||
def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 0).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x30 |||
|
||||
@@ -220,3 +204,15 @@ def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
|
||||
(bs.get! 5).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 7).toUInt64
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a big-endian `UInt64`. -/
|
||||
def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 7).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 0).toUInt64
|
||||
|
||||
@@ -4,7 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura, Robert Y. Lewis, Keeley Hoek, Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Nat.Div
|
||||
import Init.Data.Nat.Bitwise.Basic
|
||||
import Init.Coe
|
||||
|
||||
open Nat
|
||||
|
||||
@@ -13,40 +15,17 @@ namespace Fin
|
||||
instance coeToNat : CoeOut (Fin n) Nat :=
|
||||
⟨fun v => v.val⟩
|
||||
|
||||
/--
|
||||
From the empty type `Fin 0`, any desired result `α` can be derived. This is simlar to `Empty.elim`.
|
||||
-/
|
||||
def elim0.{u} {α : Sort u} : Fin 0 → α
|
||||
| ⟨_, h⟩ => absurd h (not_lt_zero _)
|
||||
|
||||
/--
|
||||
Returns the successor of the argument.
|
||||
|
||||
The bound in the result type is increased:
|
||||
```
|
||||
(2 : Fin 3).succ = (3 : Fin 4)
|
||||
```
|
||||
This differs from addition, which wraps around:
|
||||
```
|
||||
(2 : Fin 3) + 1 = (0 : Fin 3)
|
||||
```
|
||||
-/
|
||||
def succ : Fin n → Fin n.succ
|
||||
| ⟨i, h⟩ => ⟨i+1, Nat.succ_lt_succ h⟩
|
||||
|
||||
variable {n : Nat}
|
||||
|
||||
/--
|
||||
Returns `a` modulo `n + 1` as a `Fin n.succ`.
|
||||
-/
|
||||
protected def ofNat {n : Nat} (a : Nat) : Fin n.succ :=
|
||||
⟨a % (n+1), Nat.mod_lt _ (Nat.zero_lt_succ _)⟩
|
||||
|
||||
/--
|
||||
Returns `a` modulo `n` as a `Fin n`.
|
||||
|
||||
The assumption `n > 0` ensures that `Fin n` is nonempty.
|
||||
-/
|
||||
protected def ofNat' {n : Nat} (a : Nat) (h : n > 0) : Fin n :=
|
||||
⟨a % n, Nat.mod_lt _ h⟩
|
||||
|
||||
@@ -56,15 +35,12 @@ private theorem mlt {b : Nat} : {a : Nat} → a < n → b % n < n
|
||||
have : n > 0 := Nat.lt_trans (Nat.zero_lt_succ _) h;
|
||||
Nat.mod_lt _ this
|
||||
|
||||
/-- Addition modulo `n` -/
|
||||
protected def add : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a + b) % n, mlt h⟩
|
||||
|
||||
/-- Multiplication modulo `n` -/
|
||||
protected def mul : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a * b) % n, mlt h⟩
|
||||
|
||||
/-- Subtraction modulo `n` -/
|
||||
protected def sub : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a + (n - b)) % n, mlt h⟩
|
||||
|
||||
@@ -194,3 +170,9 @@ theorem val_add_one_le_of_lt {n : Nat} {a b : Fin n} (h : a < b) : (a : Nat) + 1
|
||||
theorem val_add_one_le_of_gt {n : Nat} {a b : Fin n} (h : a > b) : (b : Nat) + 1 ≤ (a : Nat) := h
|
||||
|
||||
end Fin
|
||||
|
||||
instance [GetElem cont Nat elem dom] : GetElem cont (Fin n) elem fun xs i => dom xs i where
|
||||
getElem xs i h := getElem xs i.1 h
|
||||
|
||||
macro_rules
|
||||
| `(tactic| get_elem_tactic_trivial) => `(tactic| apply Fin.val_lt_of_le; get_elem_tactic_trivial; done)
|
||||
|
||||
@@ -12,7 +12,6 @@ import Init.Data.Nat.Linear
|
||||
loop (x : α) (i : Nat) : α :=
|
||||
if h : i < n then loop (f x ⟨i, h⟩) (i+1) else x
|
||||
termination_by n - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
|
||||
/-- Folds over `Fin n` from the right: `foldr 3 f x = f 0 (f 1 (f 2 x))`. -/
|
||||
@[inline] def foldr (n) (f : Fin n → α → α) (init : α) : α := loop ⟨n, Nat.le_refl n⟩ init where
|
||||
|
||||
@@ -23,7 +23,6 @@ def hIterateFrom (P : Nat → Sort _) {n} (f : ∀(i : Fin n), P i.val → P (i.
|
||||
have p : i = n := (or_iff_left g).mp (Nat.eq_or_lt_of_le ubnd)
|
||||
_root_.cast (congrArg P p) a
|
||||
termination_by n - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
|
||||
/--
|
||||
`hIterate` is a heterogenous iterative operation that applies a
|
||||
|
||||
@@ -541,7 +541,7 @@ theorem pred_mk {n : Nat} (i : Nat) (h : i < n + 1) (w) : Fin.pred ⟨i, h⟩ w
|
||||
∀ {a b : Fin (n + 1)} {ha : a ≠ 0} {hb : b ≠ 0}, a.pred ha = b.pred hb ↔ a = b
|
||||
| ⟨0, _⟩, _, ha, _ => by simp only [mk_zero, ne_eq, not_true] at ha
|
||||
| ⟨i + 1, _⟩, ⟨0, _⟩, _, hb => by simp only [mk_zero, ne_eq, not_true] at hb
|
||||
| ⟨i + 1, hi⟩, ⟨j + 1, hj⟩, ha, hb => by simp [ext_iff, Nat.succ.injEq]
|
||||
| ⟨i + 1, hi⟩, ⟨j + 1, hj⟩, ha, hb => by simp [ext_iff]
|
||||
|
||||
@[simp] theorem pred_one {n : Nat} :
|
||||
Fin.pred (1 : Fin (n + 2)) (Ne.symm (Fin.ne_of_lt one_pos)) = 0 := rfl
|
||||
@@ -602,7 +602,6 @@ A version of `Fin.succRec` taking `i : Fin n` as the first argument. -/
|
||||
@Fin.succRecOn (n + 1) i.succ motive zero succ = succ n i (Fin.succRecOn i zero succ) := by
|
||||
cases i; rfl
|
||||
|
||||
|
||||
/-- Define `motive i` by induction on `i : Fin (n + 1)` via induction on the underlying `Nat` value.
|
||||
This function has two arguments: `zero` handles the base case on `motive 0`,
|
||||
and `succ` defines the inductive step using `motive i.castSucc`.
|
||||
@@ -611,12 +610,8 @@ and `succ` defines the inductive step using `motive i.castSucc`.
|
||||
@[elab_as_elim] def induction {motive : Fin (n + 1) → Sort _} (zero : motive 0)
|
||||
(succ : ∀ i : Fin n, motive (castSucc i) → motive i.succ) :
|
||||
∀ i : Fin (n + 1), motive i
|
||||
| ⟨i, hi⟩ => go i hi
|
||||
where
|
||||
-- Use a curried function so that this is structurally recursive
|
||||
go : ∀ (i : Nat) (hi : i < n + 1), motive ⟨i, hi⟩
|
||||
| 0, hi => by rwa [Fin.mk_zero]
|
||||
| i+1, hi => succ ⟨i, Nat.lt_of_succ_lt_succ hi⟩ (go i (Nat.lt_of_succ_lt hi))
|
||||
| ⟨0, hi⟩ => by rwa [Fin.mk_zero]
|
||||
| ⟨i+1, hi⟩ => succ ⟨i, Nat.lt_of_succ_lt_succ hi⟩ (induction zero succ ⟨i, Nat.lt_of_succ_lt hi⟩)
|
||||
|
||||
@[simp] theorem induction_zero {motive : Fin (n + 1) → Sort _} (zero : motive 0)
|
||||
(hs : ∀ i : Fin n, motive (castSucc i) → motive i.succ) :
|
||||
@@ -687,8 +682,7 @@ and `cast` defines the inductive step using `motive i.succ`, inducting downwards
|
||||
cast _ (reverseInduction last cast j.succ)
|
||||
termination_by n + 1 - i
|
||||
decreasing_by decreasing_with
|
||||
-- FIXME: we put the proof down here to avoid getting a dummy `have` in the definition
|
||||
try simp only [Nat.succ_sub_succ_eq_sub]
|
||||
simp [Nat.succ_sub_succ_eq_sub]
|
||||
exact Nat.add_sub_add_right .. ▸ Nat.sub_lt_sub_left i.2 (Nat.lt_succ_self i)
|
||||
|
||||
@[simp] theorem reverseInduction_last {n : Nat} {motive : Fin (n + 1) → Sort _} {zero succ} :
|
||||
@@ -798,20 +792,15 @@ protected theorem mul_one (k : Fin (n + 1)) : k * 1 = k := by
|
||||
|
||||
protected theorem mul_comm (a b : Fin n) : a * b = b * a :=
|
||||
ext <| by rw [mul_def, mul_def, Nat.mul_comm]
|
||||
instance : Std.Commutative (α := Fin n) (· * ·) := ⟨Fin.mul_comm⟩
|
||||
|
||||
protected theorem mul_assoc (a b c : Fin n) : a * b * c = a * (b * c) := by
|
||||
apply eq_of_val_eq
|
||||
simp only [val_mul]
|
||||
rw [← Nat.mod_eq_of_lt a.isLt, ← Nat.mod_eq_of_lt b.isLt, ← Nat.mod_eq_of_lt c.isLt]
|
||||
simp only [← Nat.mul_mod, Nat.mul_assoc]
|
||||
instance : Std.Associative (α := Fin n) (· * ·) := ⟨Fin.mul_assoc⟩
|
||||
|
||||
protected theorem one_mul (k : Fin (n + 1)) : (1 : Fin (n + 1)) * k = k := by
|
||||
rw [Fin.mul_comm, Fin.mul_one]
|
||||
instance : Std.LawfulIdentity (α := Fin (n + 1)) (· * ·) 1 where
|
||||
left_id := Fin.one_mul
|
||||
right_id := Fin.mul_one
|
||||
|
||||
protected theorem mul_zero (k : Fin (n + 1)) : k * 0 = 0 := by simp [ext_iff, mul_def]
|
||||
|
||||
|
||||
@@ -58,13 +58,9 @@ def get? (ds : FloatArray) (i : Nat) : Option Float :=
|
||||
instance : GetElem FloatArray Nat Float fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
|
||||
instance : LawfulGetElem FloatArray Nat Float fun xs i => i < xs.size where
|
||||
|
||||
instance : GetElem FloatArray USize Float fun xs i => i.val < xs.size where
|
||||
getElem xs i h := xs.uget i h
|
||||
|
||||
instance : LawfulGetElem FloatArray USize Float fun xs i => i.val < xs.size where
|
||||
|
||||
@[extern "lean_float_array_uset"]
|
||||
def uset : (a : FloatArray) → (i : USize) → Float → i.toNat < a.size → FloatArray
|
||||
| ⟨ds⟩, i, v, h => ⟨ds.uset i v h⟩
|
||||
|
||||
@@ -8,6 +8,7 @@ import Init.Data.Int.Basic
|
||||
import Init.Data.Int.Bitwise
|
||||
import Init.Data.Int.DivMod
|
||||
import Init.Data.Int.DivModLemmas
|
||||
import Init.Data.Int.DivModExt
|
||||
import Init.Data.Int.Gcd
|
||||
import Init.Data.Int.Lemmas
|
||||
import Init.Data.Int.Order
|
||||
|
||||
@@ -100,7 +100,7 @@ protected def neg (n : @& Int) : Int :=
|
||||
```
|
||||
-/
|
||||
@[default_instance mid]
|
||||
instance instNegInt : Neg Int where
|
||||
instance : Neg Int where
|
||||
neg := Int.neg
|
||||
|
||||
/-- Subtraction of two natural numbers. -/
|
||||
@@ -173,13 +173,13 @@ inductive NonNeg : Int → Prop where
|
||||
/-- Definition of `a ≤ b`, encoded as `b - a ≥ 0`. -/
|
||||
protected def le (a b : Int) : Prop := NonNeg (b - a)
|
||||
|
||||
instance instLEInt : LE Int where
|
||||
instance : LE Int where
|
||||
le := Int.le
|
||||
|
||||
/-- Definition of `a < b`, encoded as `a + 1 ≤ b`. -/
|
||||
protected def lt (a b : Int) : Prop := (a + 1) ≤ b
|
||||
|
||||
instance instLTInt : LT Int where
|
||||
instance : LT Int where
|
||||
lt := Int.lt
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
|
||||
83
src/Init/Data/Int/DivModExt.lean
Normal file
83
src/Init/Data/Int/DivModExt.lean
Normal file
@@ -0,0 +1,83 @@
|
||||
prelude
|
||||
import Init.Data.Int.DivModLemmas
|
||||
import Init.Data.Nat.Lemmas
|
||||
|
||||
namespace Int
|
||||
|
||||
theorem ediv_ofNat_negSucc (m n : Nat) : m / -[n+1] = -ofNat (m / Nat.succ n) := rfl
|
||||
theorem ediv_negSucc_zero (m : Nat) : -[m+1] / 0 = 0 := rfl
|
||||
theorem ediv_negSucc_succ (m n : Nat) : -[m+1] / (n + 1 : Nat) = -((m / (n + 1)) : Nat) + (-1) := by
|
||||
simp [HDiv.hDiv, Div.div, Int.ediv, Int.negSucc_coe', Int.sub_eq_add_neg]
|
||||
theorem ediv_negSucc_negSucc (m n : Nat) : -[m+1] / -[n+1] = ((m / (n + 1) + 1) : Nat) := rfl
|
||||
|
||||
theorem emod_ofNat (a : Nat) (b : Int) : Nat.cast a % b = Nat.cast (a % b.natAbs) := rfl
|
||||
theorem emod_negSucc (a : Nat) (b : Int) : -[a+1] % b = (b.natAbs : Int) - (a % b.natAbs + 1) := rfl
|
||||
|
||||
@[simp] theorem dvd_natCast_natCast (a b : Nat) : (a : Int) ∣ (b : Int) ↔ a ∣ b := by
|
||||
simp [Int.dvd_iff_mod_eq_zero, Nat.dvd_iff_mod_eq_zero, mod, Int.emod_ofNat,
|
||||
-emod_ofNat]
|
||||
apply Int.ofNat_inj
|
||||
|
||||
@[simp] theorem dvd_negSucc (a : Int) (b : Nat) : a ∣ -[b +1] ↔ a ∣ (b+1 : Nat) := by
|
||||
simp only [Int.dvd_def]
|
||||
apply Iff.intro
|
||||
· intro ⟨c, p⟩
|
||||
apply Exists.intro (-c)
|
||||
simp only [Int.mul_neg, ← p]
|
||||
rfl
|
||||
· intro ⟨c, p⟩
|
||||
apply Exists.intro (-c)
|
||||
simp only [Int.mul_neg, ← p]
|
||||
rfl
|
||||
|
||||
@[simp] theorem negSucc_dvd (a : Nat) (b : Int) : -[a +1] ∣ b ↔ (((a+1 : Nat) : Int) ∣ b) := by
|
||||
apply Iff.intro
|
||||
· intro ⟨c, p⟩
|
||||
apply Exists.intro (-c)
|
||||
match c with
|
||||
| .ofNat 0 =>
|
||||
simp_all
|
||||
| .ofNat (.succ c) =>
|
||||
simp_all [-natCast_add, Int.mul_neg]
|
||||
| -[c+1] =>
|
||||
simp_all [-natCast_add, Int.mul_neg]
|
||||
· intro ⟨c, p⟩
|
||||
apply Exists.intro (-c)
|
||||
match c with
|
||||
| .ofNat 0 =>
|
||||
simp_all
|
||||
| .ofNat (.succ c) =>
|
||||
simp_all [-natCast_add, Int.mul_neg]
|
||||
| -[c+1] =>
|
||||
simp_all [-natCast_add, Int.mul_neg]
|
||||
|
||||
theorem fdiv_eq_ediv' (a b : Int) : Int.fdiv a b = a / b + if b < 0 ∧ ¬(b ∣ a) then (-1) else 0 := by
|
||||
match a, b with
|
||||
| 0, b =>
|
||||
simp [Int.fdiv, Int.dvd_zero]
|
||||
| ofNat (Nat.succ m), ofNat n =>
|
||||
simp [Int.fdiv, Int.ofNat_not_neg]
|
||||
| ofNat (Nat.succ m), -[n+1] =>
|
||||
simp only [fdiv,Int.negSucc_lt_zero, true_and, Int.ofNat_eq_coe, ediv_ofNat_negSucc,
|
||||
Int.negSucc_dvd, Int.dvd_natCast_natCast, ite_not,
|
||||
Nat.succ_div, Nat.succ_eq_add_one]
|
||||
split <;> rename_i h
|
||||
· rw [Int.add_zero]; rfl
|
||||
· rw [← Int.neg_add]; rfl
|
||||
| -[_+1], 0 =>
|
||||
simp
|
||||
| -[m+1], ofNat (Nat.succ n) => rfl
|
||||
| -[m+1], -[n+1] =>
|
||||
simp only [Int.fdiv, Int.ediv_negSucc_negSucc, Nat.succ_div, Int.negSucc_lt_zero, true_and,
|
||||
Int.dvd_negSucc, Int.negSucc_dvd, Int.dvd_natCast_natCast]
|
||||
split <;> rename_i h
|
||||
· simp only [Int.add_zero]
|
||||
rfl
|
||||
· simp only [Int.natCast_add, Int.Nat.cast_ofNat_Int, Int.add_neg_cancel_right]
|
||||
rfl
|
||||
|
||||
theorem fmod_eq_emod' (a b : Int) : Int.fmod a b = a % b - b * ite (b < 0 ∧ ¬(b ∣ a)) (-1) 0 := by
|
||||
simp [fmod_def, emod_def, fdiv_eq_ediv', Int.sub_eq_add_neg, Int.mul_add, Int.neg_add,
|
||||
Int.add_assoc]
|
||||
|
||||
end Int
|
||||
@@ -8,7 +8,6 @@ prelude
|
||||
import Init.Data.Int.DivMod
|
||||
import Init.Data.Int.Order
|
||||
import Init.Data.Nat.Dvd
|
||||
import Init.RCases
|
||||
|
||||
/-!
|
||||
# Lemmas about integer division needed to bootstrap `omega`.
|
||||
@@ -23,55 +22,40 @@ namespace Int
|
||||
|
||||
protected theorem dvd_def (a b : Int) : (a ∣ b) = Exists (fun c => b = a * c) := rfl
|
||||
|
||||
protected theorem dvd_zero (n : Int) : n ∣ 0 := ⟨0, (Int.mul_zero _).symm⟩
|
||||
|
||||
protected theorem dvd_refl (n : Int) : n ∣ n := ⟨1, (Int.mul_one _).symm⟩
|
||||
|
||||
protected theorem one_dvd (n : Int) : 1 ∣ n := ⟨n, (Int.one_mul n).symm⟩
|
||||
|
||||
protected theorem dvd_trans : ∀ {a b c : Int}, a ∣ b → b ∣ c → a ∣ c
|
||||
| _, _, _, ⟨d, rfl⟩, ⟨e, rfl⟩ => Exists.intro (d * e) (by rw [Int.mul_assoc])
|
||||
|
||||
@[norm_cast] theorem ofNat_dvd {m n : Nat} : (↑m : Int) ∣ ↑n ↔ m ∣ n := by
|
||||
refine ⟨fun ⟨a, ae⟩ => ?_, fun ⟨k, e⟩ => ⟨k, by rw [e, Int.ofNat_mul]⟩⟩
|
||||
match Int.le_total a 0 with
|
||||
| .inl h =>
|
||||
have := ae.symm ▸ Int.mul_nonpos_of_nonneg_of_nonpos (ofNat_zero_le _) h
|
||||
rw [Nat.le_antisymm (ofNat_le.1 this) (Nat.zero_le _)]
|
||||
apply Nat.dvd_zero
|
||||
| .inr h => match a, eq_ofNat_of_zero_le h with
|
||||
| _, ⟨k, rfl⟩ => exact ⟨k, Int.ofNat.inj ae⟩
|
||||
|
||||
theorem dvd_antisymm {a b : Int} (H1 : 0 ≤ a) (H2 : 0 ≤ b) : a ∣ b → b ∣ a → a = b := by
|
||||
rw [← natAbs_of_nonneg H1, ← natAbs_of_nonneg H2]
|
||||
rw [ofNat_dvd, ofNat_dvd, ofNat_inj]
|
||||
apply Nat.dvd_antisymm
|
||||
protected theorem dvd_zero (n : Int) : n ∣ 0 := ⟨0, (Int.mul_zero _).symm⟩
|
||||
|
||||
@[simp] protected theorem zero_dvd {n : Int} : 0 ∣ n ↔ n = 0 :=
|
||||
Iff.intro (fun ⟨k, e⟩ => by rw [e, Int.zero_mul])
|
||||
(fun h => h.symm ▸ Int.dvd_refl _)
|
||||
|
||||
protected theorem one_dvd (n : Int) : 1 ∣ n := ⟨n, (Int.one_mul n).symm⟩
|
||||
|
||||
protected theorem dvd_trans : ∀ {a b c : Int}, a ∣ b → b ∣ c → a ∣ c
|
||||
| a, _, _, ⟨d, rfl⟩, ⟨e, rfl⟩ => Exists.intro (d * e) (Int.mul_assoc a d e)
|
||||
|
||||
protected theorem dvd_mul_left (a b : Int) : a ∣ b * a := ⟨_, Int.mul_comm ..⟩
|
||||
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 ..⟩
|
||||
|
||||
protected theorem neg_dvd {a b : Int} : -a ∣ b ↔ a ∣ b := by
|
||||
constructor <;> exact fun ⟨k, e⟩ =>
|
||||
⟨-k, by simp [e, Int.neg_mul, Int.mul_neg, Int.neg_neg]⟩
|
||||
|
||||
protected theorem dvd_neg {a b : Int} : a ∣ -b ↔ a ∣ b := by
|
||||
constructor <;> exact fun ⟨k, e⟩ =>
|
||||
⟨-k, by simp [← e, Int.neg_mul, Int.mul_neg, Int.neg_neg]⟩
|
||||
|
||||
@[simp] theorem natAbs_dvd_natAbs {a b : Int} : natAbs a ∣ natAbs b ↔ a ∣ b := by
|
||||
theorem natAbs_dvd_natAbs {a b : Int} : natAbs a ∣ natAbs b ↔ a ∣ b := by
|
||||
refine ⟨fun ⟨k, hk⟩ => ?_, fun ⟨k, hk⟩ => ⟨natAbs k, hk.symm ▸ natAbs_mul a k⟩⟩
|
||||
rw [← natAbs_ofNat k, ← natAbs_mul, natAbs_eq_natAbs_iff] at hk
|
||||
cases hk <;> subst b
|
||||
· apply Int.dvd_mul_right
|
||||
· rw [← Int.mul_neg]; apply Int.dvd_mul_right
|
||||
|
||||
protected theorem neg_dvd {a b : Int} : -a ∣ b ↔ a ∣ b := by
|
||||
simp [←natAbs_dvd_natAbs]
|
||||
|
||||
protected theorem dvd_neg {a b : Int} : a ∣ -b ↔ a ∣ b := by
|
||||
simp [←natAbs_dvd_natAbs]
|
||||
|
||||
@[norm_cast] theorem ofNat_dvd {m n : Nat} : (↑m : Int) ∣ ↑n ↔ m ∣ n := by
|
||||
simp [←natAbs_dvd_natAbs]
|
||||
|
||||
theorem ofNat_dvd_left {n : Nat} {z : Int} : (↑n : Int) ∣ z ↔ n ∣ z.natAbs := by
|
||||
rw [← natAbs_dvd_natAbs, natAbs_ofNat]
|
||||
simp [←natAbs_dvd_natAbs]
|
||||
|
||||
protected theorem dvd_add : ∀ {a b c : Int}, a ∣ b → a ∣ c → a ∣ b + c
|
||||
| _, _, _, ⟨d, rfl⟩, ⟨e, rfl⟩ => ⟨d + e, by rw [Int.mul_add]⟩
|
||||
@@ -79,15 +63,19 @@ protected theorem dvd_add : ∀ {a b c : Int}, a ∣ b → a ∣ c → a ∣ b +
|
||||
protected theorem dvd_sub : ∀ {a b c : Int}, a ∣ b → a ∣ c → a ∣ b - c
|
||||
| _, _, _, ⟨d, rfl⟩, ⟨e, rfl⟩ => ⟨d - e, by rw [Int.mul_sub]⟩
|
||||
|
||||
protected theorem dvd_add_left {a b c : Int} (H : a ∣ c) : a ∣ b + c ↔ a ∣ b :=
|
||||
⟨fun h => by have := Int.dvd_sub h H; rwa [Int.add_sub_cancel] at this, (Int.dvd_add · H)⟩
|
||||
protected theorem dvd_add_left {a b c : Int} (H : a ∣ c) : a ∣ b + c ↔ a ∣ b := by
|
||||
apply Iff.intro
|
||||
· intro h
|
||||
have := Int.dvd_sub h H
|
||||
rwa [Int.add_sub_cancel] at this
|
||||
· exact (Int.dvd_add · H)
|
||||
|
||||
protected theorem dvd_add_right {a b c : Int} (H : a ∣ b) : a ∣ b + c ↔ a ∣ c := by
|
||||
rw [Int.add_comm, Int.dvd_add_left H]
|
||||
|
||||
protected theorem dvd_iff_dvd_of_dvd_sub {a b c : Int} (H : a ∣ b - c) : a ∣ b ↔ a ∣ c :=
|
||||
⟨fun h => Int.sub_sub_self b c ▸ Int.dvd_sub h H,
|
||||
fun h => Int.sub_add_cancel b c ▸ Int.dvd_add H h⟩
|
||||
Iff.intro (fun h => Int.sub_sub_self b c ▸ Int.dvd_sub h H)
|
||||
(fun h => Int.sub_add_cancel b c ▸ Int.dvd_add H h)
|
||||
|
||||
protected theorem dvd_iff_dvd_of_dvd_add {a b c : Int} (H : a ∣ b + c) : a ∣ b ↔ a ∣ c := by
|
||||
rw [← Int.sub_neg] at H; rw [Int.dvd_iff_dvd_of_dvd_sub H, Int.dvd_neg]
|
||||
@@ -97,26 +85,25 @@ theorem le_of_dvd {a b : Int} (bpos : 0 < b) (H : a ∣ b) : a ≤ b :=
|
||||
| ofNat _, _, ⟨n, rfl⟩, H => ofNat_le.2 <| Nat.le_of_dvd n.succ_pos <| ofNat_dvd.1 H
|
||||
| -[_+1], _, ⟨_, rfl⟩, _ => Int.le_trans (Int.le_of_lt <| negSucc_lt_zero _) (ofNat_zero_le _)
|
||||
|
||||
theorem natAbs_dvd {a b : Int} : (a.natAbs : Int) ∣ b ↔ a ∣ b :=
|
||||
match natAbs_eq a with
|
||||
| .inl e => by rw [← e]
|
||||
| .inr e => by rw [← Int.neg_dvd, ← e]
|
||||
theorem dvd_antisymm {a b : Int} (H1 : 0 ≤ a) (H2 : 0 ≤ b) : a ∣ b → b ∣ a → a = b := by
|
||||
rw [← natAbs_of_nonneg H1, ← natAbs_of_nonneg H2]
|
||||
rw [ofNat_dvd, ofNat_dvd, ofNat_inj]
|
||||
apply Nat.dvd_antisymm
|
||||
|
||||
theorem dvd_natAbs {a b : Int} : a ∣ b.natAbs ↔ a ∣ b :=
|
||||
match natAbs_eq b with
|
||||
| .inl e => by rw [← e]
|
||||
| .inr e => by rw [← Int.dvd_neg, ← e]
|
||||
theorem dvd_natAbs {a b : Int} : a ∣ b.natAbs ↔ a ∣ b := by
|
||||
simp [←natAbs_dvd_natAbs]
|
||||
|
||||
theorem natAbs_dvd_self {a : Int} : (a.natAbs : Int) ∣ a := by
|
||||
rw [Int.natAbs_dvd]
|
||||
exact Int.dvd_refl a
|
||||
theorem natAbs_dvd {a b : Int} : (a.natAbs : Int) ∣ b ↔ a ∣ b := by
|
||||
simp [←natAbs_dvd_natAbs]
|
||||
|
||||
theorem dvd_natAbs_self {a : Int} : a ∣ (a.natAbs : Int) := by
|
||||
rw [Int.dvd_natAbs]
|
||||
exact Int.dvd_refl a
|
||||
simp [←natAbs_dvd_natAbs, Nat.dvd_refl]
|
||||
|
||||
theorem natAbs_dvd_self {a : Int} : (a.natAbs : Int) ∣ a := by
|
||||
simp [←natAbs_dvd_natAbs, Nat.dvd_refl]
|
||||
|
||||
theorem ofNat_dvd_right {n : Nat} {z : Int} : z ∣ (↑n : Int) ↔ z.natAbs ∣ n := by
|
||||
rw [← natAbs_dvd_natAbs, natAbs_ofNat]
|
||||
simp [←natAbs_dvd_natAbs]
|
||||
|
||||
theorem eq_one_of_dvd_one {a : Int} (H : 0 ≤ a) (H' : a ∣ 1) : a = 1 :=
|
||||
match a, eq_ofNat_of_zero_le H, H' with
|
||||
@@ -128,6 +115,8 @@ theorem eq_one_of_mul_eq_one_right {a b : Int} (H : 0 ≤ a) (H' : a * b = 1) :
|
||||
theorem eq_one_of_mul_eq_one_left {a b : Int} (H : 0 ≤ b) (H' : a * b = 1) : b = 1 :=
|
||||
eq_one_of_mul_eq_one_right H <| by rw [Int.mul_comm, H']
|
||||
|
||||
attribute [simp] natAbs_dvd_natAbs
|
||||
|
||||
/-! ### *div zero -/
|
||||
|
||||
@[simp] theorem zero_ediv : ∀ b : Int, 0 / b = 0
|
||||
@@ -153,19 +142,6 @@ theorem eq_one_of_mul_eq_one_left {a b : Int} (H : 0 ≤ b) (H' : a * b = 1) : b
|
||||
| succ _ => rfl
|
||||
| -[_+1] => rfl
|
||||
|
||||
/-! ### div equivalences -/
|
||||
|
||||
theorem div_eq_ediv : ∀ {a b : Int}, 0 ≤ a → 0 ≤ b → a.div b = a / b
|
||||
| 0, _, _, _ | _, 0, _, _ => by simp
|
||||
| succ _, succ _, _, _ => rfl
|
||||
|
||||
theorem fdiv_eq_ediv : ∀ (a : Int) {b : Int}, 0 ≤ b → fdiv a b = a / b
|
||||
| 0, _, _ | -[_+1], 0, _ => by simp
|
||||
| succ _, ofNat _, _ | -[_+1], succ _, _ => rfl
|
||||
|
||||
theorem fdiv_eq_div {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : fdiv a b = div a b :=
|
||||
div_eq_ediv Ha Hb ▸ fdiv_eq_ediv _ Hb
|
||||
|
||||
/-! ### mod zero -/
|
||||
|
||||
@[simp] theorem zero_emod (b : Int) : 0 % b = 0 := rfl
|
||||
@@ -194,6 +170,19 @@ theorem fdiv_eq_div {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : fdiv a b = div a
|
||||
|
||||
/-! ### mod definitiions -/
|
||||
|
||||
theorem emod_as_nat_mod (m n : Int) : (m % n) =
|
||||
(if m ≥ 0 then
|
||||
(((m.natAbs % n.natAbs) : Nat) : Int)
|
||||
else
|
||||
((n.natAbs : Int) - (((((m.natAbs - 1) % n.natAbs + 1) : Nat) : Int)))) := by
|
||||
cases m <;> cases n <;> (rename_i m n ; simp [HMod.hMod, Mod.mod, emod, ofNat_nonneg])
|
||||
· have p : (Nat.cast (Nat.succ m) : Int) - 1 = m := by simp [Nat.succ_eq_add_one]
|
||||
simp [p, Int.subNatNat_eq_coe, Nat.succ_eq_add_one]
|
||||
· have p : (Nat.cast (Nat.succ m) : Int) - 1 = m := by simp [Nat.succ_eq_add_one]
|
||||
have q : (Nat.cast n : Int) + 1 = Nat.cast (n + 1) := by rfl
|
||||
simp [p, Int.subNatNat_eq_coe, Nat.succ_eq_add_one, q, -Int.natCast_add]
|
||||
rfl
|
||||
|
||||
theorem emod_add_ediv : ∀ a b : Int, a % b + b * (a / b) = a
|
||||
| ofNat _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..
|
||||
| ofNat m, -[n+1] => by
|
||||
@@ -220,67 +209,6 @@ theorem ediv_add_emod' (a b : Int) : a / b * b + a % b = a := by
|
||||
theorem emod_def (a b : Int) : a % b = a - b * (a / b) := by
|
||||
rw [← Int.add_sub_cancel (a % b), emod_add_ediv]
|
||||
|
||||
theorem mod_add_div : ∀ a b : Int, mod a b + b * (a.div b) = a
|
||||
| ofNat _, ofNat _ => congrArg ofNat (Nat.mod_add_div ..)
|
||||
| ofNat m, -[n+1] => by
|
||||
show (m % succ n + -↑(succ n) * -↑(m / succ n) : Int) = m
|
||||
rw [Int.neg_mul_neg]; exact congrArg ofNat (Nat.mod_add_div ..)
|
||||
| -[_+1], 0 => rfl
|
||||
| -[m+1], ofNat n => by
|
||||
show -(↑((succ m) % n) : Int) + ↑n * -↑(succ m / n) = -↑(succ m)
|
||||
rw [Int.mul_neg, ← Int.neg_add]
|
||||
exact congrArg (-ofNat ·) (Nat.mod_add_div ..)
|
||||
| -[m+1], -[n+1] => by
|
||||
show -(↑(succ m % succ n) : Int) + -↑(succ n) * ↑(succ m / succ n) = -↑(succ m)
|
||||
rw [Int.neg_mul, ← Int.neg_add]
|
||||
exact congrArg (-ofNat ·) (Nat.mod_add_div ..)
|
||||
|
||||
theorem div_add_mod (a b : Int) : b * a.div b + mod a b = a := by
|
||||
rw [Int.add_comm]; apply mod_add_div ..
|
||||
|
||||
theorem mod_add_div' (m k : Int) : mod m k + m.div k * k = m := by
|
||||
rw [Int.mul_comm]; apply mod_add_div
|
||||
|
||||
theorem div_add_mod' (m k : Int) : m.div k * k + mod m k = m := by
|
||||
rw [Int.mul_comm]; apply div_add_mod
|
||||
|
||||
theorem mod_def (a b : Int) : mod a b = a - b * a.div b := by
|
||||
rw [← Int.add_sub_cancel (mod a b), mod_add_div]
|
||||
|
||||
theorem fmod_add_fdiv : ∀ a b : Int, a.fmod b + b * a.fdiv b = a
|
||||
| 0, ofNat _ | 0, -[_+1] => congrArg ofNat <| by simp
|
||||
| succ m, ofNat n => congrArg ofNat <| Nat.mod_add_div ..
|
||||
| succ m, -[n+1] => by
|
||||
show subNatNat (m % succ n) n + (↑(succ n * (m / succ n)) + n + 1) = (m + 1)
|
||||
rw [Int.add_comm _ n, ← Int.add_assoc, ← Int.add_assoc,
|
||||
Int.subNatNat_eq_coe, Int.sub_add_cancel]
|
||||
exact congrArg (ofNat · + 1) <| Nat.mod_add_div ..
|
||||
| -[_+1], 0 => by rw [fmod_zero]; rfl
|
||||
| -[m+1], succ n => by
|
||||
show subNatNat .. - (↑(succ n * (m / succ n)) + ↑(succ n)) = -↑(succ m)
|
||||
rw [Int.subNatNat_eq_coe, ← Int.sub_sub, ← Int.neg_sub, Int.sub_sub, Int.sub_sub_self]
|
||||
exact congrArg (-ofNat ·) <| Nat.succ_add .. ▸ Nat.mod_add_div .. ▸ rfl
|
||||
| -[m+1], -[n+1] => by
|
||||
show -(↑(succ m % succ n) : Int) + -↑(succ n * (succ m / succ n)) = -↑(succ m)
|
||||
rw [← Int.neg_add]; exact congrArg (-ofNat ·) <| Nat.mod_add_div ..
|
||||
|
||||
theorem fdiv_add_fmod (a b : Int) : b * a.fdiv b + a.fmod b = a := by
|
||||
rw [Int.add_comm]; exact fmod_add_fdiv ..
|
||||
|
||||
theorem fmod_def (a b : Int) : a.fmod b = a - b * a.fdiv b := by
|
||||
rw [← Int.add_sub_cancel (a.fmod b), fmod_add_fdiv]
|
||||
|
||||
/-! ### mod equivalences -/
|
||||
|
||||
theorem fmod_eq_emod (a : Int) {b : Int} (hb : 0 ≤ b) : fmod a b = a % b := by
|
||||
simp [fmod_def, emod_def, fdiv_eq_ediv _ hb]
|
||||
|
||||
theorem mod_eq_emod {a b : Int} (ha : 0 ≤ a) (hb : 0 ≤ b) : mod a b = a % b := by
|
||||
simp [emod_def, mod_def, div_eq_ediv ha hb]
|
||||
|
||||
theorem fmod_eq_mod {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : fmod a b = mod a b :=
|
||||
mod_eq_emod Ha Hb ▸ fmod_eq_emod _ Hb
|
||||
|
||||
/-! ### `/` ediv -/
|
||||
|
||||
@[simp] protected theorem ediv_neg : ∀ a b : Int, a / (-b) = -(a / b)
|
||||
@@ -305,6 +233,10 @@ theorem ediv_nonneg {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : 0 ≤ a / b :=
|
||||
theorem ediv_nonpos {a b : Int} (Ha : 0 ≤ a) (Hb : b ≤ 0) : a / b ≤ 0 :=
|
||||
Int.nonpos_of_neg_nonneg <| Int.ediv_neg .. ▸ Int.ediv_nonneg Ha (Int.neg_nonneg_of_nonpos Hb)
|
||||
|
||||
theorem emod_nonneg : ∀ (a : Int) {b : Int}, b ≠ 0 → 0 ≤ a % b
|
||||
| ofNat _, _, _ => ofNat_zero_le _
|
||||
| -[_+1], _, H => Int.sub_nonneg_of_le <| ofNat_le.2 <| Nat.mod_lt _ (natAbs_pos.2 H)
|
||||
|
||||
theorem add_mul_ediv_right (a b : Int) {c : Int} (H : c ≠ 0) : (a + b * c) / c = a / c + b :=
|
||||
suffices ∀ {{a b c : Int}}, 0 < c → (a + b * c).ediv c = a.ediv c + b from
|
||||
match Int.lt_trichotomy c 0 with
|
||||
@@ -335,19 +267,24 @@ theorem add_mul_ediv_right (a b : Int) {c : Int} (H : c ≠ 0) : (a + b * c) / c
|
||||
apply congrArg negSucc
|
||||
rw [Nat.mul_comm, Nat.sub_mul_div]; rwa [Nat.mul_comm]
|
||||
|
||||
theorem add_ediv_of_dvd_right {a b c : Int} (H : c ∣ b) : (a + b) / c = a / c + b / c :=
|
||||
if h : c = 0 then by simp [h] else by
|
||||
let ⟨k, hk⟩ := H
|
||||
rw [hk, Int.mul_comm c k, Int.add_mul_ediv_right _ _ h,
|
||||
← Int.zero_add (k * c), Int.add_mul_ediv_right _ _ h, Int.zero_ediv, Int.zero_add]
|
||||
|
||||
theorem add_ediv_of_dvd_left {a b c : Int} (H : c ∣ a) : (a + b) / c = a / c + b / c := by
|
||||
rw [Int.add_comm, Int.add_ediv_of_dvd_right H, Int.add_comm]
|
||||
theorem add_mul_ediv_left (a : Int) {b : Int}
|
||||
(c : Int) (H : b ≠ 0) : (a + b * c) / b = a / b + c :=
|
||||
Int.mul_comm .. ▸ Int.add_mul_ediv_right _ _ H
|
||||
|
||||
@[simp] theorem mul_ediv_cancel (a : Int) {b : Int} (H : b ≠ 0) : (a * b) / b = a := by
|
||||
have := Int.add_mul_ediv_right 0 a H
|
||||
rwa [Int.zero_add, Int.zero_ediv, Int.zero_add] at this
|
||||
|
||||
theorem add_ediv_of_dvd_right {a b c : Int} (H : c ∣ b) : (a + b) / c = a / c + b / c :=
|
||||
if z : c = 0 then by
|
||||
simp [z]
|
||||
else by
|
||||
let ⟨d, h⟩ := H
|
||||
simp [h, Int.mul_comm c _, Int.add_mul_ediv_right, z]
|
||||
|
||||
theorem add_ediv_of_dvd_left {a b c : Int} (H : c ∣ a) : (a + b) / c = a / c + b / c := by
|
||||
rw [Int.add_comm a b, Int.add_comm (a/c) _, Int.add_ediv_of_dvd_right H]
|
||||
|
||||
@[simp] theorem mul_ediv_cancel_left (b : Int) (H : a ≠ 0) : (a * b) / a = b :=
|
||||
Int.mul_comm .. ▸ Int.mul_ediv_cancel _ H
|
||||
|
||||
@@ -362,10 +299,6 @@ theorem ediv_eq_zero_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a / b = 0 :
|
||||
match a, b, eq_ofNat_of_zero_le H1, eq_succ_of_zero_lt (Int.lt_of_le_of_lt H1 H2) with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => congrArg Nat.cast <| Nat.div_eq_of_lt <| ofNat_lt.1 H2
|
||||
|
||||
theorem add_mul_ediv_left (a : Int) {b : Int}
|
||||
(c : Int) (H : b ≠ 0) : (a + b * c) / b = a / b + c :=
|
||||
Int.mul_comm .. ▸ Int.add_mul_ediv_right _ _ H
|
||||
|
||||
@[simp] theorem mul_ediv_mul_of_pos {a : Int}
|
||||
(b c : Int) (H : 0 < a) : (a * b) / (a * c) = b / c :=
|
||||
suffices ∀ (m k : Nat) (b : Int), (m.succ * b) / (m.succ * k) = b / k from
|
||||
@@ -414,11 +347,7 @@ theorem negSucc_emod (m : Nat) {b : Int} (bpos : 0 < b) : -[m+1] % b = b - 1 - m
|
||||
match b, eq_succ_of_zero_lt bpos with
|
||||
| _, ⟨n, rfl⟩ => rfl
|
||||
|
||||
theorem ofNat_mod_ofNat (m n : Nat) : (m % n : Int) = ↑(m % n) := rfl
|
||||
|
||||
theorem emod_nonneg : ∀ (a : Int) {b : Int}, b ≠ 0 → 0 ≤ a % b
|
||||
| ofNat _, _, _ => ofNat_zero_le _
|
||||
| -[_+1], _, H => Int.sub_nonneg_of_le <| ofNat_le.2 <| Nat.mod_lt _ (natAbs_pos.2 H)
|
||||
theorem ofNat_mod_ofNat (m n : Nat) : ↑m % (↑n : Int) = ↑(m % n) := rfl
|
||||
|
||||
theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < b :=
|
||||
match a, b, eq_succ_of_zero_lt H with
|
||||
@@ -440,11 +369,15 @@ theorem lt_mul_ediv_self_add {x k : Int} (h : 0 < k) : x < k * (x / k) + k :=
|
||||
rw [cz, Int.mul_zero, Int.add_zero]
|
||||
else by
|
||||
rw [Int.emod_def, Int.emod_def, Int.add_mul_ediv_right _ _ cz, Int.add_comm _ b,
|
||||
Int.mul_add, Int.mul_comm, ← Int.sub_sub, Int.add_sub_cancel]
|
||||
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]
|
||||
|
||||
theorem add_emod_of_dvd (a b c : Int) (p : c ∣ b) : (a + b) % c = a % c := by
|
||||
let ⟨d, eq⟩ := p
|
||||
simp only [eq, Int.add_mul_emod_self_left]
|
||||
|
||||
@[simp] theorem add_emod_self {a b : Int} : (a + b) % b = a % b := by
|
||||
have := add_mul_emod_self_left a b 1; rwa [Int.mul_one] at this
|
||||
|
||||
@@ -498,6 +431,11 @@ theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
|
||||
match k, h with
|
||||
| _, ⟨t, rfl⟩ => rw [Int.mul_assoc, add_mul_emod_self_left]
|
||||
|
||||
theorem emod_eq_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a % b = a :=
|
||||
have b0 := Int.le_trans H1 (Int.le_of_lt H2)
|
||||
match a, b, eq_ofNat_of_zero_le H1, eq_ofNat_of_zero_le b0 with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => congrArg ofNat <| Nat.mod_eq_of_lt (Int.ofNat_lt.1 H2)
|
||||
|
||||
@[simp] theorem emod_emod (a b : Int) : (a % b) % b = a % b := by
|
||||
conv => rhs; rw [← emod_add_ediv a b, add_mul_emod_self_left]
|
||||
|
||||
@@ -505,10 +443,6 @@ theorem sub_emod (a b n : Int) : (a - b) % n = (a % n - b % n) % n := by
|
||||
apply (emod_add_cancel_right b).mp
|
||||
rw [Int.sub_add_cancel, ← Int.add_emod_emod, Int.sub_add_cancel, emod_emod]
|
||||
|
||||
theorem emod_eq_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a % b = a :=
|
||||
have b0 := Int.le_trans H1 (Int.le_of_lt H2)
|
||||
match a, b, eq_ofNat_of_zero_le H1, eq_ofNat_of_zero_le b0 with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => congrArg ofNat <| Nat.mod_eq_of_lt (Int.ofNat_lt.1 H2)
|
||||
|
||||
@[simp] theorem emod_self_add_one {x : Int} (h : 0 ≤ x) : x % (x + 1) = x :=
|
||||
emod_eq_of_lt h (Int.lt_succ x)
|
||||
@@ -759,6 +693,34 @@ theorem ediv_eq_ediv_of_mul_eq_mul {a b c d : Int}
|
||||
|
||||
/-! ### div -/
|
||||
|
||||
|
||||
theorem mod_add_div : ∀ a b : Int, mod a b + b * (a.div b) = a
|
||||
| ofNat _, ofNat _ => congrArg ofNat (Nat.mod_add_div ..)
|
||||
| ofNat m, -[n+1] => by
|
||||
show (m % succ n + -↑(succ n) * -↑(m / succ n) : Int) = m
|
||||
rw [Int.neg_mul_neg]; exact congrArg ofNat (Nat.mod_add_div ..)
|
||||
| -[_+1], 0 => rfl
|
||||
| -[m+1], ofNat n => by
|
||||
show -(↑((succ m) % n) : Int) + ↑n * -↑(succ m / n) = -↑(succ m)
|
||||
rw [Int.mul_neg, ← Int.neg_add]
|
||||
exact congrArg (-ofNat ·) (Nat.mod_add_div ..)
|
||||
| -[m+1], -[n+1] => by
|
||||
show -(↑(succ m % succ n) : Int) + -↑(succ n) * ↑(succ m / succ n) = -↑(succ m)
|
||||
rw [Int.neg_mul, ← Int.neg_add]
|
||||
exact congrArg (-ofNat ·) (Nat.mod_add_div ..)
|
||||
|
||||
theorem div_add_mod (a b : Int) : b * a.div b + mod a b = a := by
|
||||
rw [Int.add_comm]; apply mod_add_div ..
|
||||
|
||||
theorem mod_add_div' (m k : Int) : mod m k + m.div k * k = m := by
|
||||
rw [Int.mul_comm]; apply mod_add_div
|
||||
|
||||
theorem div_add_mod' (m k : Int) : m.div k * k + mod m k = m := by
|
||||
rw [Int.mul_comm]; apply div_add_mod
|
||||
|
||||
theorem mod_def (a b : Int) : mod a b = a - b * a.div b := by
|
||||
rw [← Int.add_sub_cancel (mod a b), mod_add_div]
|
||||
|
||||
@[simp] protected theorem div_one : ∀ a : Int, a.div 1 = a
|
||||
| (n:Nat) => congrArg ofNat (Nat.div_one _)
|
||||
| -[n+1] => by simp [Int.div, neg_ofNat_succ]; rfl
|
||||
@@ -845,6 +807,10 @@ protected theorem eq_div_of_mul_eq_right {a b c : Int}
|
||||
(H1 : a ≠ 0) (H2 : a * b = c) : b = c.div a :=
|
||||
(Int.div_eq_of_eq_mul_right H1 H2.symm).symm
|
||||
|
||||
theorem div_eq_ediv : ∀ {a b : Int}, 0 ≤ a → 0 ≤ b → a.div b = a / b
|
||||
| 0, _, _, _ | _, 0, _, _ => by simp
|
||||
| succ _, succ _, _, _ => rfl
|
||||
|
||||
/-! ### (t-)mod -/
|
||||
|
||||
theorem ofNat_mod (m n : Nat) : (↑(m % n) : Int) = mod m n := rfl
|
||||
@@ -852,6 +818,11 @@ theorem ofNat_mod (m n : Nat) : (↑(m % n) : Int) = mod m n := rfl
|
||||
@[simp] theorem mod_one (a : Int) : mod a 1 = 0 := by
|
||||
simp [mod_def, Int.div_one, Int.one_mul, Int.sub_self]
|
||||
|
||||
/-! ### mod equivalences -/
|
||||
|
||||
theorem mod_eq_emod {a b : Int} (ha : 0 ≤ a) (hb : 0 ≤ b) : mod a b = a % b := by
|
||||
simp [emod_def, mod_def, div_eq_ediv ha hb]
|
||||
|
||||
theorem mod_eq_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : mod a b = a := by
|
||||
rw [mod_eq_emod H1 (Int.le_trans H1 (Int.le_of_lt H2)), emod_eq_of_lt H1 H2]
|
||||
|
||||
@@ -932,6 +903,36 @@ protected theorem sign_eq_div_abs (a : Int) : sign a = a.div (natAbs a) :=
|
||||
|
||||
/-! ### fdiv -/
|
||||
|
||||
theorem fmod_add_fdiv : ∀ a b : Int, a.fmod b + b * a.fdiv b = a
|
||||
| 0, ofNat _ | 0, -[_+1] => congrArg ofNat <| by simp
|
||||
| succ m, ofNat n => congrArg ofNat <| Nat.mod_add_div ..
|
||||
| succ m, -[n+1] => by
|
||||
show subNatNat (m % succ n) n + (↑(succ n * (m / succ n)) + n + 1) = (m + 1)
|
||||
rw [Int.add_comm _ n, ← Int.add_assoc, ← Int.add_assoc,
|
||||
Int.subNatNat_eq_coe, Int.sub_add_cancel]
|
||||
exact congrArg (ofNat · + 1) <| Nat.mod_add_div ..
|
||||
| -[_+1], 0 => by rw [fmod_zero]; rfl
|
||||
| -[m+1], succ n => by
|
||||
show subNatNat .. - (↑(succ n * (m / succ n)) + ↑(succ n)) = -↑(succ m)
|
||||
rw [Int.subNatNat_eq_coe, ← Int.sub_sub, ← Int.neg_sub, Int.sub_sub, Int.sub_sub_self]
|
||||
exact congrArg (-ofNat ·) <| Nat.succ_add .. ▸ Nat.mod_add_div .. ▸ rfl
|
||||
| -[m+1], -[n+1] => by
|
||||
show -(↑(succ m % succ n) : Int) + -↑(succ n * (succ m / succ n)) = -↑(succ m)
|
||||
rw [← Int.neg_add]; exact congrArg (-ofNat ·) <| Nat.mod_add_div ..
|
||||
|
||||
theorem fdiv_add_fmod (a b : Int) : b * a.fdiv b + a.fmod b = a := by
|
||||
rw [Int.add_comm]; exact fmod_add_fdiv ..
|
||||
|
||||
theorem fmod_def (a b : Int) : a.fmod b = a - b * a.fdiv b := by
|
||||
rw [← Int.add_sub_cancel (a.fmod b), fmod_add_fdiv]
|
||||
|
||||
theorem fdiv_eq_ediv : ∀ (a : Int) {b : Int}, 0 ≤ b → fdiv a b = a / b
|
||||
| 0, _, _ | -[_+1], 0, _ => by simp
|
||||
| succ _, ofNat _, _ | -[_+1], succ _, _ => rfl
|
||||
|
||||
theorem fdiv_eq_div {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : fdiv a b = div a b :=
|
||||
div_eq_ediv Ha Hb ▸ fdiv_eq_ediv _ Hb
|
||||
|
||||
theorem fdiv_nonneg {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : 0 ≤ a.fdiv b :=
|
||||
match a, b, eq_ofNat_of_zero_le Ha, eq_ofNat_of_zero_le Hb with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => ofNat_fdiv .. ▸ ofNat_zero_le _
|
||||
@@ -969,8 +970,13 @@ theorem lt_fdiv_add_one_mul_self (a : Int) {b : Int} (H : 0 < b) : a < (a.fdiv b
|
||||
|
||||
/-! ### fmod -/
|
||||
|
||||
theorem ofNat_fmod (m n : Nat) : ↑(m % n) = fmod m n := by
|
||||
cases m <;> simp [fmod, Nat.succ_eq_add_one]
|
||||
theorem fmod_eq_emod (a : Int) {b : Int} (hb : 0 ≤ b) : fmod a b = a % b := by
|
||||
simp [fmod_def, emod_def, fdiv_eq_ediv _ hb]
|
||||
|
||||
theorem fmod_eq_mod {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : fmod a b = mod a b :=
|
||||
mod_eq_emod Ha Hb ▸ fmod_eq_emod _ Hb
|
||||
|
||||
theorem ofNat_fmod (m n : Nat) : ↑(m % n) = fmod m n := by cases m <;> simp [fmod]
|
||||
|
||||
@[simp] theorem fmod_one (a : Int) : a.fmod 1 = 0 := by
|
||||
simp [fmod_def, Int.one_mul, Int.sub_self]
|
||||
@@ -999,7 +1005,7 @@ theorem fmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a.fmod b < b :=
|
||||
|
||||
/-! ### Theorems crossing div/mod versions -/
|
||||
|
||||
theorem div_eq_ediv_of_dvd {a b : Int} (h : b ∣ a) : a.div b = a / b := by
|
||||
theorem div_eq_ediv_of_dvd {a b : Int} (h : b ∣ a) : Int.div a b = a / b := by
|
||||
by_cases b0 : b = 0
|
||||
· simp [b0]
|
||||
· rw [Int.div_eq_iff_eq_mul_left b0 h, ← Int.ediv_eq_iff_eq_mul_left b0 h]
|
||||
@@ -1054,39 +1060,19 @@ theorem emod_add_bmod_congr (x : Int) (n : Nat) : Int.bmod (x%n + y) n = Int.bmo
|
||||
simp [Int.emod_def, Int.sub_eq_add_neg]
|
||||
rw [←Int.mul_neg, Int.add_right_comm, Int.bmod_add_mul_cancel]
|
||||
|
||||
@[simp]
|
||||
theorem emod_mul_bmod_congr (x : Int) (n : Nat) : Int.bmod (x%n * y) n = Int.bmod (x * y) n := by
|
||||
simp [Int.emod_def, Int.sub_eq_add_neg]
|
||||
rw [←Int.mul_neg, Int.add_mul, Int.mul_assoc, Int.bmod_add_mul_cancel]
|
||||
|
||||
@[simp]
|
||||
theorem bmod_add_bmod_congr : Int.bmod (Int.bmod x n + y) n = Int.bmod (x + y) n := by
|
||||
rw [bmod_def x n]
|
||||
split
|
||||
case inl p =>
|
||||
simp only [emod_add_bmod_congr]
|
||||
simp
|
||||
case inr p =>
|
||||
rw [Int.sub_eq_add_neg, Int.add_right_comm, ←Int.sub_eq_add_neg]
|
||||
simp
|
||||
|
||||
@[simp] theorem add_bmod_bmod : Int.bmod (x + Int.bmod y n) n = Int.bmod (x + y) n := by
|
||||
rw [Int.add_comm x, Int.bmod_add_bmod_congr, Int.add_comm y]
|
||||
|
||||
@[simp]
|
||||
theorem bmod_mul_bmod : Int.bmod (Int.bmod x n * y) n = Int.bmod (x * y) n := by
|
||||
rw [bmod_def x n]
|
||||
split
|
||||
case inl p =>
|
||||
simp
|
||||
case inr p =>
|
||||
rw [Int.sub_mul, Int.sub_eq_add_neg, ← Int.mul_neg]
|
||||
simp
|
||||
|
||||
@[simp] theorem mul_bmod_bmod : Int.bmod (x * Int.bmod y n) n = Int.bmod (x * y) n := by
|
||||
rw [Int.mul_comm x, bmod_mul_bmod, Int.mul_comm x]
|
||||
|
||||
theorem add_bmod (a b : Int) (n : Nat) : (a + b).bmod n = (a.bmod n + b.bmod n).bmod n := by
|
||||
simp
|
||||
theorem add_bmod_bmod : Int.bmod (x + Int.bmod y n) n = Int.bmod (x + y) n := by
|
||||
rw [Int.add_comm x, Int.bmod_add_bmod_congr, Int.add_comm y]
|
||||
|
||||
theorem emod_bmod {x : Int} {m : Nat} : bmod (x % m) m = bmod x m := by
|
||||
simp [bmod]
|
||||
@@ -1095,7 +1081,8 @@ theorem emod_bmod {x : Int} {m : Nat} : bmod (x % m) m = bmod x m := by
|
||||
rw [bmod, bmod_emod]
|
||||
rfl
|
||||
|
||||
@[simp] theorem bmod_zero : Int.bmod 0 m = 0 := by
|
||||
-- N.B. This is renamed from bmod_zero.
|
||||
@[simp] theorem zero_bmod : Int.bmod 0 m = 0 := by
|
||||
dsimp [bmod]
|
||||
simp only [zero_emod, Int.zero_sub, ite_eq_left_iff, Int.neg_eq_zero]
|
||||
intro h
|
||||
|
||||
@@ -6,7 +6,7 @@ Authors: Jeremy Avigad, Deniz Aydin, Floris van Doorn, Mario Carneiro
|
||||
prelude
|
||||
import Init.Data.Int.Basic
|
||||
import Init.Conv
|
||||
import Init.NotationExtra
|
||||
import Init.PropLemmas
|
||||
|
||||
namespace Int
|
||||
|
||||
@@ -137,16 +137,12 @@ protected theorem add_comm : ∀ a b : Int, a + b = b + a
|
||||
| ofNat _, -[_+1] => rfl
|
||||
| -[_+1], ofNat _ => rfl
|
||||
| -[_+1], -[_+1] => by simp [Nat.add_comm]
|
||||
instance : Std.Commutative (α := Int) (· + ·) := ⟨Int.add_comm⟩
|
||||
|
||||
@[simp] protected theorem add_zero : ∀ a : Int, a + 0 = a
|
||||
| ofNat _ => rfl
|
||||
| -[_+1] => rfl
|
||||
|
||||
@[simp] protected theorem zero_add (a : Int) : 0 + a = a := Int.add_comm .. ▸ a.add_zero
|
||||
instance : Std.LawfulIdentity (α := Int) (· + ·) 0 where
|
||||
left_id := Int.zero_add
|
||||
right_id := Int.add_zero
|
||||
|
||||
theorem ofNat_add_negSucc_of_lt (h : m < n.succ) : ofNat m + -[n+1] = -[n - m+1] :=
|
||||
show subNatNat .. = _ by simp [succ_sub (le_of_lt_succ h), subNatNat]
|
||||
@@ -200,7 +196,6 @@ where
|
||||
simp
|
||||
rw [Int.add_comm, subNatNat_add_negSucc]
|
||||
simp [Nat.add_comm, Nat.add_left_comm, Nat.add_assoc]
|
||||
instance : Std.Associative (α := Int) (· + ·) := ⟨Int.add_assoc⟩
|
||||
|
||||
protected theorem add_left_comm (a b c : Int) : a + (b + c) = b + (a + c) := by
|
||||
rw [← Int.add_assoc, Int.add_comm a, Int.add_assoc]
|
||||
@@ -356,7 +351,6 @@ protected theorem sub_right_inj (i j k : Int) : (i - k = j - k) ↔ i = j := by
|
||||
|
||||
protected theorem mul_comm (a b : Int) : a * b = b * a := by
|
||||
cases a <;> cases b <;> simp [Nat.mul_comm]
|
||||
instance : Std.Commutative (α := Int) (· * ·) := ⟨Int.mul_comm⟩
|
||||
|
||||
theorem ofNat_mul_negOfNat (m n : Nat) : (m : Nat) * negOfNat n = negOfNat (m * n) := by
|
||||
cases n <;> rfl
|
||||
@@ -375,7 +369,6 @@ attribute [local simp] ofNat_mul_negOfNat negOfNat_mul_ofNat
|
||||
|
||||
protected theorem mul_assoc (a b c : Int) : a * b * c = a * (b * c) := by
|
||||
cases a <;> cases b <;> cases c <;> simp [Nat.mul_assoc]
|
||||
instance : Std.Associative (α := Int) (· * ·) := ⟨Int.mul_assoc⟩
|
||||
|
||||
protected theorem mul_left_comm (a b c : Int) : a * (b * c) = b * (a * c) := by
|
||||
rw [← Int.mul_assoc, ← Int.mul_assoc, Int.mul_comm a]
|
||||
@@ -465,9 +458,6 @@ protected theorem sub_mul (a b c : Int) : (a - b) * c = a * c - b * c := by
|
||||
| -[n+1] => show -[1 * n +1] = -[n+1] by rw [Nat.one_mul]
|
||||
|
||||
@[simp] protected theorem mul_one (a : Int) : a * 1 = a := by rw [Int.mul_comm, Int.one_mul]
|
||||
instance : Std.LawfulIdentity (α := Int) (· * ·) 1 where
|
||||
left_id := Int.one_mul
|
||||
right_id := Int.mul_one
|
||||
|
||||
protected theorem mul_neg_one (a : Int) : a * -1 = -a := by rw [Int.mul_neg, Int.mul_one]
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Jeremy Avigad, Deniz Aydin, Floris van Doorn, Mario Carneiro
|
||||
prelude
|
||||
import Init.Data.Int.Lemmas
|
||||
import Init.ByCases
|
||||
import Init.RCases
|
||||
|
||||
/-!
|
||||
# Results about the order properties of the integers, and the integers as an ordered ring.
|
||||
@@ -127,9 +128,14 @@ protected theorem lt_iff_le_not_le {a b : Int} : a < b ↔ a ≤ b ∧ ¬b ≤ a
|
||||
· exact Int.le_antisymm h h'
|
||||
· subst h'; apply Int.le_refl
|
||||
|
||||
protected theorem lt_of_not_ge {a b : Int} (h : ¬a ≤ b) : b < a :=
|
||||
Int.lt_iff_le_not_le.2 ⟨(Int.le_total ..).resolve_right h, h⟩
|
||||
|
||||
protected theorem not_le_of_gt {a b : Int} (h : b < a) : ¬a ≤ b :=
|
||||
(Int.lt_iff_le_not_le.1 h).2
|
||||
|
||||
protected theorem not_le {a b : Int} : ¬a ≤ b ↔ b < a :=
|
||||
⟨fun h => Int.lt_iff_le_not_le.2 ⟨(Int.le_total ..).resolve_right h, h⟩,
|
||||
fun h => (Int.lt_iff_le_not_le.1 h).2⟩
|
||||
Iff.intro Int.lt_of_not_ge Int.not_le_of_gt
|
||||
|
||||
protected theorem not_lt {a b : Int} : ¬a < b ↔ b ≤ a :=
|
||||
by rw [← Int.not_le, Decidable.not_not]
|
||||
@@ -187,7 +193,6 @@ protected theorem min_comm (a b : Int) : min a b = min b a := by
|
||||
by_cases h₁ : a ≤ b <;> by_cases h₂ : b ≤ a <;> simp [h₁, h₂]
|
||||
· exact Int.le_antisymm h₁ h₂
|
||||
· cases not_or_intro h₁ h₂ <| Int.le_total ..
|
||||
instance : Std.Commutative (α := Int) min := ⟨Int.min_comm⟩
|
||||
|
||||
protected theorem min_le_right (a b : Int) : min a b ≤ b := by rw [Int.min_def]; split <;> simp [*]
|
||||
|
||||
@@ -207,7 +212,6 @@ protected theorem max_comm (a b : Int) : max a b = max b a := by
|
||||
by_cases h₁ : a ≤ b <;> by_cases h₂ : b ≤ a <;> simp [h₁, h₂]
|
||||
· exact Int.le_antisymm h₂ h₁
|
||||
· cases not_or_intro h₁ h₂ <| Int.le_total ..
|
||||
instance : Std.Commutative (α := Int) max := ⟨Int.max_comm⟩
|
||||
|
||||
protected theorem le_max_left (a b : Int) : a ≤ max a b := by rw [Int.max_def]; split <;> simp [*]
|
||||
|
||||
@@ -509,9 +513,6 @@ theorem mem_toNat' : ∀ (a : Int) (n : Nat), toNat' a = some n ↔ a = n
|
||||
|
||||
/-! ## Order properties of the integers -/
|
||||
|
||||
protected theorem lt_of_not_ge {a b : Int} : ¬a ≤ b → b < a := Int.not_le.mp
|
||||
protected theorem not_le_of_gt {a b : Int} : b < a → ¬a ≤ b := Int.not_le.mpr
|
||||
|
||||
protected theorem le_of_not_le {a b : Int} : ¬ a ≤ b → b ≤ a := (Int.le_total a b).resolve_left
|
||||
|
||||
@[simp] theorem negSucc_not_pos (n : Nat) : 0 < -[n+1] ↔ False := by
|
||||
@@ -586,7 +587,11 @@ theorem add_one_le_iff {a b : Int} : a + 1 ≤ b ↔ a < b := .rfl
|
||||
theorem lt_add_one_iff {a b : Int} : a < b + 1 ↔ a ≤ b := Int.add_le_add_iff_right _
|
||||
|
||||
@[simp] theorem succ_ofNat_pos (n : Nat) : 0 < (n : Int) + 1 :=
|
||||
lt_add_one_iff.2 (ofNat_zero_le _)
|
||||
lt_add_one_iff.mpr (ofNat_zero_le _)
|
||||
|
||||
theorem ofNat_not_neg (n : Nat) : (n : Int) < 0 ↔ False :=
|
||||
(iff_false _).mpr
|
||||
(Int.not_le_of_gt (lt_add_one_iff.mpr (ofNat_zero_le _)))
|
||||
|
||||
theorem le_add_one {a b : Int} (h : a ≤ b) : a ≤ b + 1 :=
|
||||
Int.le_of_lt (Int.lt_add_one_iff.2 h)
|
||||
@@ -1000,8 +1005,7 @@ theorem natAbs_add_le (a b : Int) : natAbs (a + b) ≤ natAbs a + natAbs b := by
|
||||
refine fun a b => subNatNat_elim a b.succ
|
||||
(fun m n i => n = b.succ → natAbs i ≤ (m + b).succ) ?_
|
||||
(fun i n (e : (n + i).succ = _) => ?_) rfl
|
||||
· intro i n h
|
||||
subst h
|
||||
· rintro i n rfl
|
||||
rw [Nat.add_comm _ i, Nat.add_assoc]
|
||||
exact Nat.le_add_right i (b.succ + b).succ
|
||||
· apply succ_le_succ
|
||||
|
||||
@@ -8,4 +8,3 @@ import Init.Data.List.Basic
|
||||
import Init.Data.List.BasicAux
|
||||
import Init.Data.List.Control
|
||||
import Init.Data.List.Lemmas
|
||||
import Init.Data.List.Impl
|
||||
|
||||
@@ -7,7 +7,6 @@ prelude
|
||||
import Init.SimpLemmas
|
||||
import Init.Data.Nat.Basic
|
||||
import Init.Data.Nat.Div
|
||||
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
open Decidable List
|
||||
|
||||
@@ -55,6 +54,15 @@ variable {α : Type u} {β : Type v} {γ : Type w}
|
||||
|
||||
namespace List
|
||||
|
||||
instance : GetElem (List α) Nat α fun as i => i < as.length where
|
||||
getElem as i h := as.get ⟨i, h⟩
|
||||
|
||||
@[simp] theorem cons_getElem_zero (a : α) (as : List α) (h : 0 < (a :: as).length) : getElem (a :: as) 0 h = a := by
|
||||
rfl
|
||||
|
||||
@[simp] theorem cons_getElem_succ (a : α) (as : List α) (i : Nat) (h : i + 1 < (a :: as).length) : getElem (a :: as) (i+1) h = getElem as i (Nat.lt_of_succ_lt_succ h) := by
|
||||
rfl
|
||||
|
||||
theorem length_add_eq_lengthTRAux (as : List α) (n : Nat) : as.length + n = as.lengthTRAux n := by
|
||||
induction as generalizing n with
|
||||
| nil => simp [length, lengthTRAux]
|
||||
@@ -127,9 +135,6 @@ instance : Append (List α) := ⟨List.append⟩
|
||||
| nil => rfl
|
||||
| cons a as ih =>
|
||||
simp_all [HAppend.hAppend, Append.append, List.append]
|
||||
instance : Std.LawfulIdentity (α := List α) (· ++ ·) [] where
|
||||
left_id := nil_append
|
||||
right_id := append_nil
|
||||
|
||||
@[simp] theorem cons_append (a : α) (as bs : List α) : (a::as) ++ bs = a::(as ++ bs) := rfl
|
||||
|
||||
@@ -139,7 +144,6 @@ theorem append_assoc (as bs cs : List α) : (as ++ bs) ++ cs = as ++ (bs ++ cs)
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih => simp [ih]
|
||||
instance : Std.Associative (α := List α) (· ++ ·) := ⟨append_assoc⟩
|
||||
|
||||
theorem append_cons (as : List α) (b : α) (bs : List α) : as ++ b :: bs = as ++ [b] ++ bs := by
|
||||
induction as with
|
||||
@@ -516,6 +520,11 @@ def drop : Nat → List α → List α
|
||||
@[simp] theorem drop_nil : ([] : List α).drop i = [] := by
|
||||
cases i <;> rfl
|
||||
|
||||
theorem get_drop_eq_drop (as : List α) (i : Nat) (h : i < as.length) : as[i] :: as.drop (i+1) = as.drop i :=
|
||||
match as, i with
|
||||
| _::_, 0 => rfl
|
||||
| _::_, i+1 => get_drop_eq_drop _ i _
|
||||
|
||||
/--
|
||||
`O(min n |xs|)`. Returns the first `n` elements of `xs`, or the whole list if `n` is too large.
|
||||
* `take 0 [a, b, c, d, e] = []`
|
||||
|
||||
@@ -5,7 +5,6 @@ Author: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Nat.Linear
|
||||
import Init.Ext
|
||||
|
||||
universe u
|
||||
|
||||
@@ -13,157 +12,63 @@ namespace List
|
||||
/-! The following functions can't be defined at `Init.Data.List.Basic`, because they depend on `Init.Util`,
|
||||
and `Init.Util` depends on `Init.Data.List.Basic`. -/
|
||||
|
||||
/--
|
||||
Returns the `i`-th element in the list (zero-based).
|
||||
|
||||
If the index is out of bounds (`i ≥ as.length`), this function panics when executed, and returns
|
||||
`default`. See `get?` and `getD` for safer alternatives.
|
||||
-/
|
||||
def get! [Inhabited α] : (as : List α) → (i : Nat) → α
|
||||
def get! [Inhabited α] : List α → Nat → α
|
||||
| a::_, 0 => a
|
||||
| _::as, n+1 => get! as n
|
||||
| _, _ => panic! "invalid index"
|
||||
|
||||
/--
|
||||
Returns the `i`-th element in the list (zero-based).
|
||||
|
||||
If the index is out of bounds (`i ≥ as.length`), this function returns `none`.
|
||||
Also see `get`, `getD` and `get!`.
|
||||
-/
|
||||
def get? : (as : List α) → (i : Nat) → Option α
|
||||
def get? : List α → Nat → Option α
|
||||
| a::_, 0 => some a
|
||||
| _::as, n+1 => get? as n
|
||||
| _, _ => none
|
||||
|
||||
/--
|
||||
Returns the `i`-th element in the list (zero-based).
|
||||
def getD (as : List α) (idx : Nat) (a₀ : α) : α :=
|
||||
(as.get? idx).getD a₀
|
||||
|
||||
If the index is out of bounds (`i ≥ as.length`), this function returns `fallback`.
|
||||
See also `get?` and `get!`.
|
||||
-/
|
||||
def getD (as : List α) (i : Nat) (fallback : α) : α :=
|
||||
(as.get? i).getD fallback
|
||||
|
||||
@[ext] theorem ext : ∀ {l₁ l₂ : List α}, (∀ n, l₁.get? n = l₂.get? n) → l₁ = l₂
|
||||
| [], [], _ => rfl
|
||||
| a :: l₁, [], h => nomatch h 0
|
||||
| [], a' :: l₂, h => nomatch h 0
|
||||
| a :: l₁, a' :: l₂, h => by
|
||||
have h0 : some a = some a' := h 0
|
||||
injection h0 with aa; simp only [aa, ext fun n => h (n+1)]
|
||||
|
||||
/--
|
||||
Returns the first element in the list.
|
||||
|
||||
If the list is empty, this function panics when executed, and returns `default`.
|
||||
See `head` and `headD` for safer alternatives.
|
||||
-/
|
||||
def head! [Inhabited α] : List α → α
|
||||
| [] => panic! "empty list"
|
||||
| a::_ => a
|
||||
|
||||
/--
|
||||
Returns the first element in the list.
|
||||
|
||||
If the list is empty, this function returns `none`.
|
||||
Also see `headD` and `head!`.
|
||||
-/
|
||||
def head? : List α → Option α
|
||||
| [] => none
|
||||
| a::_ => some a
|
||||
|
||||
/--
|
||||
Returns the first element in the list.
|
||||
|
||||
If the list is empty, this function returns `fallback`.
|
||||
Also see `head?` and `head!`.
|
||||
-/
|
||||
def headD : (as : List α) → (fallback : α) → α
|
||||
| [], fallback => fallback
|
||||
def headD : List α → α → α
|
||||
| [], a₀ => a₀
|
||||
| a::_, _ => a
|
||||
|
||||
/--
|
||||
Returns the first element of a non-empty list.
|
||||
-/
|
||||
def head : (as : List α) → as ≠ [] → α
|
||||
| a::_, _ => a
|
||||
|
||||
/--
|
||||
Drops the first element of the list.
|
||||
|
||||
If the list is empty, this function panics when executed, and returns the empty list.
|
||||
See `tail` and `tailD` for safer alternatives.
|
||||
-/
|
||||
def tail! : List α → List α
|
||||
| [] => panic! "empty list"
|
||||
| _::as => as
|
||||
|
||||
/--
|
||||
Drops the first element of the list.
|
||||
|
||||
If the list is empty, this function returns `none`.
|
||||
Also see `tailD` and `tail!`.
|
||||
-/
|
||||
def tail? : List α → Option (List α)
|
||||
| [] => none
|
||||
| _::as => some as
|
||||
|
||||
/--
|
||||
Drops the first element of the list.
|
||||
def tailD : List α → List α → List α
|
||||
| [], as₀ => as₀
|
||||
| _::as, _ => as
|
||||
|
||||
If the list is empty, this function returns `fallback`.
|
||||
Also see `head?` and `head!`.
|
||||
-/
|
||||
def tailD (list fallback : List α) : List α :=
|
||||
match list with
|
||||
| [] => fallback
|
||||
| _ :: tl => tl
|
||||
|
||||
/--
|
||||
Returns the last element of a non-empty list.
|
||||
-/
|
||||
def getLast : ∀ (as : List α), as ≠ [] → α
|
||||
| [], h => absurd rfl h
|
||||
| [a], _ => a
|
||||
| _::b::as, _ => getLast (b::as) (fun h => List.noConfusion h)
|
||||
|
||||
/--
|
||||
Returns the last element in the list.
|
||||
|
||||
If the list is empty, this function panics when executed, and returns `default`.
|
||||
See `getLast` and `getLastD` for safer alternatives.
|
||||
-/
|
||||
def getLast! [Inhabited α] : List α → α
|
||||
| [] => panic! "empty list"
|
||||
| a::as => getLast (a::as) (fun h => List.noConfusion h)
|
||||
|
||||
/--
|
||||
Returns the last element in the list.
|
||||
|
||||
If the list is empty, this function returns `none`.
|
||||
Also see `getLastD` and `getLast!`.
|
||||
-/
|
||||
def getLast? : List α → Option α
|
||||
| [] => none
|
||||
| a::as => some (getLast (a::as) (fun h => List.noConfusion h))
|
||||
|
||||
/--
|
||||
Returns the last element in the list.
|
||||
|
||||
If the list is empty, this function returns `fallback`.
|
||||
Also see `getLast?` and `getLast!`.
|
||||
-/
|
||||
def getLastD : (as : List α) → (fallback : α) → α
|
||||
def getLastD : List α → α → α
|
||||
| [], a₀ => a₀
|
||||
| a::as, _ => getLast (a::as) (fun h => List.noConfusion h)
|
||||
|
||||
/--
|
||||
`O(n)`. Rotates the elements of `xs` to the left such that the element at
|
||||
`xs[i]` rotates to `xs[(i - n) % l.length]`.
|
||||
* `rotateLeft [1, 2, 3, 4, 5] 3 = [4, 5, 1, 2, 3]`
|
||||
* `rotateLeft [1, 2, 3, 4, 5] 5 = [1, 2, 3, 4, 5]`
|
||||
* `rotateLeft [1, 2, 3, 4, 5] = [2, 3, 4, 5, 1]`
|
||||
-/
|
||||
def rotateLeft (xs : List α) (n : Nat := 1) : List α :=
|
||||
let len := xs.length
|
||||
if len ≤ 1 then
|
||||
@@ -174,13 +79,6 @@ def rotateLeft (xs : List α) (n : Nat := 1) : List α :=
|
||||
let e := xs.drop n
|
||||
e ++ b
|
||||
|
||||
/--
|
||||
`O(n)`. Rotates the elements of `xs` to the right such that the element at
|
||||
`xs[i]` rotates to `xs[(i + n) % l.length]`.
|
||||
* `rotateRight [1, 2, 3, 4, 5] 3 = [3, 4, 5, 1, 2]`
|
||||
* `rotateRight [1, 2, 3, 4, 5] 5 = [1, 2, 3, 4, 5]`
|
||||
* `rotateRight [1, 2, 3, 4, 5] = [5, 1, 2, 3, 4]`
|
||||
-/
|
||||
def rotateRight (xs : List α) (n : Nat := 1) : List α :=
|
||||
let len := xs.length
|
||||
if len ≤ 1 then
|
||||
@@ -226,10 +124,9 @@ theorem sizeOf_lt_of_mem [SizeOf α] {as : List α} (h : a ∈ as) : sizeOf a <
|
||||
over a nested inductive like `inductive T | mk : List T → T`. -/
|
||||
macro "sizeOf_list_dec" : tactic =>
|
||||
`(tactic| first
|
||||
| with_reducible apply sizeOf_lt_of_mem; assumption; done
|
||||
| with_reducible
|
||||
apply Nat.lt_trans (sizeOf_lt_of_mem ?h)
|
||||
case' h => assumption
|
||||
| apply sizeOf_lt_of_mem; assumption; done
|
||||
| apply Nat.lt_trans (sizeOf_lt_of_mem ?h)
|
||||
case' h => assumption
|
||||
simp_arith)
|
||||
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| sizeOf_list_dec)
|
||||
@@ -312,15 +209,6 @@ def mapMono (as : List α) (f : α → α) : List α :=
|
||||
Monadic generalization of `List.partition`.
|
||||
|
||||
This uses `Array.toList` and which isn't imported by `Init.Data.List.Basic`.
|
||||
```
|
||||
def posOrNeg (x : Int) : Except String Bool :=
|
||||
if x > 0 then pure true
|
||||
else if x < 0 then pure false
|
||||
else throw "Zero is not positive or negative"
|
||||
|
||||
partitionM posOrNeg [-1, 2, 3] = Except.ok ([2, 3], [-1])
|
||||
partitionM posOrNeg [0, 2, 3] = Except.error "Zero is not positive or negative"
|
||||
```
|
||||
-/
|
||||
@[inline] def partitionM [Monad m] (p : α → m Bool) (l : List α) : m (List α × List α) :=
|
||||
go l #[] #[]
|
||||
|
||||
@@ -40,13 +40,6 @@ Finally, we rarely use `mapM` with something that is not a `Monad`.
|
||||
Users that want to use `mapM` with `Applicative` should use `mapA` instead.
|
||||
-/
|
||||
|
||||
/--
|
||||
Applies the monadic action `f` on every element in the list, left-to-right, and returns the list of
|
||||
results.
|
||||
|
||||
See `List.forM` for the variant that discards the results.
|
||||
See `List.mapA` for the variant that works with `Applicative`.
|
||||
-/
|
||||
@[inline]
|
||||
def mapM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α → m β) (as : List α) : m (List β) :=
|
||||
let rec @[specialize] loop
|
||||
@@ -54,42 +47,17 @@ def mapM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α
|
||||
| a :: as, bs => do loop as ((← f a)::bs)
|
||||
loop as []
|
||||
|
||||
/--
|
||||
Applies the applicative action `f` on every element in the list, left-to-right, and returns the list of
|
||||
results.
|
||||
|
||||
NB: If `m` is also a `Monad`, then using `mapM` can be more efficient.
|
||||
|
||||
See `List.forA` for the variant that discards the results.
|
||||
See `List.mapM` for the variant that works with `Monad`.
|
||||
|
||||
**Warning**: this function is not tail-recursive, meaning that it may fail with a stack overflow on long lists.
|
||||
-/
|
||||
@[specialize]
|
||||
def mapA {m : Type u → Type v} [Applicative m] {α : Type w} {β : Type u} (f : α → m β) : List α → m (List β)
|
||||
| [] => pure []
|
||||
| a::as => List.cons <$> f a <*> mapA f as
|
||||
|
||||
/--
|
||||
Applies the monadic action `f` on every element in the list, left-to-right.
|
||||
|
||||
See `List.mapM` for the variant that collects results.
|
||||
See `List.forA` for the variant that works with `Applicative`.
|
||||
-/
|
||||
@[specialize]
|
||||
protected def forM {m : Type u → Type v} [Monad m] {α : Type w} (as : List α) (f : α → m PUnit) : m PUnit :=
|
||||
match as with
|
||||
| [] => pure ⟨⟩
|
||||
| a :: as => do f a; List.forM as f
|
||||
|
||||
/--
|
||||
Applies the applicative action `f` on every element in the list, left-to-right.
|
||||
|
||||
NB: If `m` is also a `Monad`, then using `forM` can be more efficient.
|
||||
|
||||
See `List.mapA` for the variant that collects results.
|
||||
See `List.forM` for the variant that works with `Monad`.
|
||||
-/
|
||||
@[specialize]
|
||||
def forA {m : Type u → Type v} [Applicative m] {α : Type w} (as : List α) (f : α → m PUnit) : m PUnit :=
|
||||
match as with
|
||||
@@ -103,27 +71,15 @@ def filterAuxM {m : Type → Type v} [Monad m] {α : Type} (f : α → m Bool) :
|
||||
let b ← f h
|
||||
filterAuxM f t (cond b (h :: acc) acc)
|
||||
|
||||
/--
|
||||
Applies the monadic predicate `p` on every element in the list, left-to-right, and returns those
|
||||
elements `x` for which `p x` returns `true`.
|
||||
-/
|
||||
@[inline]
|
||||
def filterM {m : Type → Type v} [Monad m] {α : Type} (p : α → m Bool) (as : List α) : m (List α) := do
|
||||
let as ← filterAuxM p as []
|
||||
def filterM {m : Type → Type v} [Monad m] {α : Type} (f : α → m Bool) (as : List α) : m (List α) := do
|
||||
let as ← filterAuxM f as []
|
||||
pure as.reverse
|
||||
|
||||
/--
|
||||
Applies the monadic predicate `p` on every element in the list, right-to-left, and returns those
|
||||
elements `x` for which `p x` returns `true`.
|
||||
-/
|
||||
@[inline]
|
||||
def filterRevM {m : Type → Type v} [Monad m] {α : Type} (p : α → m Bool) (as : List α) : m (List α) :=
|
||||
filterAuxM p as.reverse []
|
||||
def filterRevM {m : Type → Type v} [Monad m] {α : Type} (f : α → m Bool) (as : List α) : m (List α) :=
|
||||
filterAuxM f as.reverse []
|
||||
|
||||
/--
|
||||
Applies the monadic function `f` on every element `x` in the list, left-to-right, and returns those
|
||||
results `y` for which `f x` returns `some y`.
|
||||
-/
|
||||
@[inline]
|
||||
def filterMapM {m : Type u → Type v} [Monad m] {α β : Type u} (f : α → m (Option β)) (as : List α) : m (List β) :=
|
||||
let rec @[specialize] loop
|
||||
@@ -134,16 +90,6 @@ def filterMapM {m : Type u → Type v} [Monad m] {α β : Type u} (f : α → m
|
||||
| some b => loop as (b::bs)
|
||||
loop as.reverse []
|
||||
|
||||
/--
|
||||
Folds a monadic function over a list from left to right:
|
||||
```
|
||||
foldlM f x₀ [a, b, c] = do
|
||||
let x₁ ← f x₀ a
|
||||
let x₂ ← f x₁ b
|
||||
let x₃ ← f x₂ c
|
||||
pure x₃
|
||||
```
|
||||
-/
|
||||
@[specialize]
|
||||
protected def foldlM {m : Type u → Type v} [Monad m] {s : Type u} {α : Type w} : (f : s → α → m s) → (init : s) → List α → m s
|
||||
| _, s, [] => pure s
|
||||
@@ -151,26 +97,10 @@ protected def foldlM {m : Type u → Type v} [Monad m] {s : Type u} {α : Type w
|
||||
let s' ← f s a
|
||||
List.foldlM f s' as
|
||||
|
||||
/--
|
||||
Folds a monadic function over a list from right to left:
|
||||
```
|
||||
foldrM f x₀ [a, b, c] = do
|
||||
let x₁ ← f c x₀
|
||||
let x₂ ← f b x₁
|
||||
let x₃ ← f a x₂
|
||||
pure x₃
|
||||
```
|
||||
-/
|
||||
@[inline]
|
||||
def foldrM {m : Type u → Type v} [Monad m] {s : Type u} {α : Type w} (f : α → s → m s) (init : s) (l : List α) : m s :=
|
||||
l.reverse.foldlM (fun s a => f a s) init
|
||||
|
||||
/--
|
||||
Maps `f` over the list and collects the results with `<|>`.
|
||||
```
|
||||
firstM f [a, b, c] = f a <|> f b <|> f c <|> failure
|
||||
```
|
||||
-/
|
||||
@[specialize]
|
||||
def firstM {m : Type u → Type v} [Alternative m] {α : Type w} {β : Type u} (f : α → m β) : List α → m β
|
||||
| [] => failure
|
||||
|
||||
@@ -1,261 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
|
||||
/-!
|
||||
## Tail recursive implementations for `List` definitions.
|
||||
|
||||
Many of the proofs require theorems about `Array`,
|
||||
so these are in a separate file to minimize imports.
|
||||
-/
|
||||
|
||||
namespace List
|
||||
|
||||
/-- Tail recursive version of `erase`. -/
|
||||
@[inline] def setTR (l : List α) (n : Nat) (a : α) : List α := go l n #[] where
|
||||
/-- Auxiliary for `setTR`: `setTR.go l a xs n acc = acc.toList ++ set xs a`,
|
||||
unless `n ≥ l.length` in which case it returns `l` -/
|
||||
go : List α → Nat → Array α → List α
|
||||
| [], _, _ => l
|
||||
| _::xs, 0, acc => acc.toListAppend (a::xs)
|
||||
| x::xs, n+1, acc => go xs n (acc.push x)
|
||||
|
||||
@[csimp] theorem set_eq_setTR : @set = @setTR := by
|
||||
funext α l n a; simp [setTR]
|
||||
let rec go (acc) : ∀ xs n, l = acc.data ++ xs →
|
||||
setTR.go l a xs n acc = acc.data ++ xs.set n a
|
||||
| [], _ => fun h => by simp [setTR.go, set, h]
|
||||
| x::xs, 0 => by simp [setTR.go, set]
|
||||
| x::xs, n+1 => fun h => by simp [setTR.go, set]; rw [go _ xs]; {simp}; simp [h]
|
||||
exact (go #[] _ _ rfl).symm
|
||||
|
||||
/-- Tail recursive version of `erase`. -/
|
||||
@[inline] def eraseTR [BEq α] (l : List α) (a : α) : List α := go l #[] where
|
||||
/-- Auxiliary for `eraseTR`: `eraseTR.go l a xs acc = acc.toList ++ erase xs a`,
|
||||
unless `a` is not present in which case it returns `l` -/
|
||||
go : List α → Array α → List α
|
||||
| [], _ => l
|
||||
| x::xs, acc => bif x == a then acc.toListAppend xs else go xs (acc.push x)
|
||||
|
||||
@[csimp] theorem erase_eq_eraseTR : @List.erase = @eraseTR := by
|
||||
funext α _ l a; simp [eraseTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs → eraseTR.go l a xs acc = acc.data ++ xs.erase a from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs with intro acc h
|
||||
| nil => simp [List.erase, eraseTR.go, h]
|
||||
| cons x xs IH =>
|
||||
simp [List.erase, eraseTR.go]
|
||||
cases x == a <;> simp
|
||||
· rw [IH]; simp; simp; exact h
|
||||
|
||||
/-- Tail recursive version of `eraseIdx`. -/
|
||||
@[inline] def eraseIdxTR (l : List α) (n : Nat) : List α := go l n #[] where
|
||||
/-- Auxiliary for `eraseIdxTR`: `eraseIdxTR.go l n xs acc = acc.toList ++ eraseIdx xs a`,
|
||||
unless `a` is not present in which case it returns `l` -/
|
||||
go : List α → Nat → Array α → List α
|
||||
| [], _, _ => l
|
||||
| _::as, 0, acc => acc.toListAppend as
|
||||
| a::as, n+1, acc => go as n (acc.push a)
|
||||
|
||||
@[csimp] theorem eraseIdx_eq_eraseIdxTR : @eraseIdx = @eraseIdxTR := by
|
||||
funext α l n; simp [eraseIdxTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs → eraseIdxTR.go l xs n acc = acc.data ++ xs.eraseIdx n from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs generalizing n with intro acc h
|
||||
| nil => simp [eraseIdx, eraseIdxTR.go, h]
|
||||
| cons x xs IH =>
|
||||
match n with
|
||||
| 0 => simp [eraseIdx, eraseIdxTR.go]
|
||||
| n+1 =>
|
||||
simp [eraseIdx, eraseIdxTR.go]
|
||||
rw [IH]; simp; simp; exact h
|
||||
|
||||
/-- Tail recursive version of `bind`. -/
|
||||
@[inline] def bindTR (as : List α) (f : α → List β) : List β := go as #[] where
|
||||
/-- Auxiliary for `bind`: `bind.go f as = acc.toList ++ bind f as` -/
|
||||
@[specialize] go : List α → Array β → List β
|
||||
| [], acc => acc.toList
|
||||
| x::xs, acc => go xs (acc ++ f x)
|
||||
|
||||
@[csimp] theorem bind_eq_bindTR : @List.bind = @bindTR := by
|
||||
funext α β as f
|
||||
let rec go : ∀ as acc, bindTR.go f as acc = acc.data ++ as.bind f
|
||||
| [], acc => by simp [bindTR.go, bind]
|
||||
| x::xs, acc => by simp [bindTR.go, bind, go xs]
|
||||
exact (go as #[]).symm
|
||||
|
||||
/-- Tail recursive version of `join`. -/
|
||||
@[inline] def joinTR (l : List (List α)) : List α := bindTR l id
|
||||
|
||||
@[csimp] theorem join_eq_joinTR : @join = @joinTR := by
|
||||
funext α l; rw [← List.bind_id, List.bind_eq_bindTR]; rfl
|
||||
|
||||
/-- Tail recursive version of `filterMap`. -/
|
||||
@[inline] def filterMapTR (f : α → Option β) (l : List α) : List β := go l #[] where
|
||||
/-- Auxiliary for `filterMap`: `filterMap.go f l = acc.toList ++ filterMap f l` -/
|
||||
@[specialize] go : List α → Array β → List β
|
||||
| [], acc => acc.toList
|
||||
| a::as, acc => match f a with
|
||||
| none => go as acc
|
||||
| some b => go as (acc.push b)
|
||||
|
||||
@[csimp] theorem filterMap_eq_filterMapTR : @List.filterMap = @filterMapTR := by
|
||||
funext α β f l
|
||||
let rec go : ∀ as acc, filterMapTR.go f as acc = acc.data ++ as.filterMap f
|
||||
| [], acc => by simp [filterMapTR.go, filterMap]
|
||||
| a::as, acc => by simp [filterMapTR.go, filterMap, go as]; split <;> simp [*]
|
||||
exact (go l #[]).symm
|
||||
|
||||
/-- Tail recursive version of `replace`. -/
|
||||
@[inline] def replaceTR [BEq α] (l : List α) (b c : α) : List α := go l #[] where
|
||||
/-- Auxiliary for `replace`: `replace.go l b c xs acc = acc.toList ++ replace xs b c`,
|
||||
unless `b` is not found in `xs` in which case it returns `l`. -/
|
||||
@[specialize] go : List α → Array α → List α
|
||||
| [], _ => l
|
||||
| a::as, acc => bif a == b then acc.toListAppend (c::as) else go as (acc.push a)
|
||||
|
||||
@[csimp] theorem replace_eq_replaceTR : @List.replace = @replaceTR := by
|
||||
funext α _ l b c; simp [replaceTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs →
|
||||
replaceTR.go l b c xs acc = acc.data ++ xs.replace b c from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs with intro acc
|
||||
| nil => simp [replace, replaceTR.go]
|
||||
| cons x xs IH =>
|
||||
simp [replace, replaceTR.go]; split <;> simp [*]
|
||||
· intro h; rw [IH]; simp; simp; exact h
|
||||
|
||||
/-- Tail recursive version of `take`. -/
|
||||
@[inline] def takeTR (n : Nat) (l : List α) : List α := go l n #[] where
|
||||
/-- Auxiliary for `take`: `take.go l xs n acc = acc.toList ++ take n xs`,
|
||||
unless `n ≥ xs.length` in which case it returns `l`. -/
|
||||
@[specialize] go : List α → Nat → Array α → List α
|
||||
| [], _, _ => l
|
||||
| _::_, 0, acc => acc.toList
|
||||
| a::as, n+1, acc => go as n (acc.push a)
|
||||
|
||||
@[csimp] theorem take_eq_takeTR : @take = @takeTR := by
|
||||
funext α n l; simp [takeTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs → takeTR.go l xs n acc = acc.data ++ xs.take n from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs generalizing n with intro acc
|
||||
| nil => cases n <;> simp [take, takeTR.go]
|
||||
| cons x xs IH =>
|
||||
cases n with simp [take, takeTR.go]
|
||||
| succ n => intro h; rw [IH]; simp; simp; exact h
|
||||
|
||||
/-- Tail recursive version of `takeWhile`. -/
|
||||
@[inline] def takeWhileTR (p : α → Bool) (l : List α) : List α := go l #[] where
|
||||
/-- Auxiliary for `takeWhile`: `takeWhile.go p l xs acc = acc.toList ++ takeWhile p xs`,
|
||||
unless no element satisfying `p` is found in `xs` in which case it returns `l`. -/
|
||||
@[specialize] go : List α → Array α → List α
|
||||
| [], _ => l
|
||||
| a::as, acc => bif p a then go as (acc.push a) else acc.toList
|
||||
|
||||
@[csimp] theorem takeWhile_eq_takeWhileTR : @takeWhile = @takeWhileTR := by
|
||||
funext α p l; simp [takeWhileTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs →
|
||||
takeWhileTR.go p l xs acc = acc.data ++ xs.takeWhile p from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs with intro acc
|
||||
| nil => simp [takeWhile, takeWhileTR.go]
|
||||
| cons x xs IH =>
|
||||
simp [takeWhile, takeWhileTR.go]; split <;> simp [*]
|
||||
· intro h; rw [IH]; simp; simp; exact h
|
||||
|
||||
/-- Tail recursive version of `foldr`. -/
|
||||
@[specialize] def foldrTR (f : α → β → β) (init : β) (l : List α) : β := l.toArray.foldr f init
|
||||
|
||||
@[csimp] theorem foldr_eq_foldrTR : @foldr = @foldrTR := by
|
||||
funext α β f init l; simp [foldrTR, Array.foldr_eq_foldr_data, -Array.size_toArray]
|
||||
|
||||
/-- Tail recursive version of `zipWith`. -/
|
||||
@[inline] def zipWithTR (f : α → β → γ) (as : List α) (bs : List β) : List γ := go as bs #[] where
|
||||
/-- Auxiliary for `zipWith`: `zipWith.go f as bs acc = acc.toList ++ zipWith f as bs` -/
|
||||
go : List α → List β → Array γ → List γ
|
||||
| a::as, b::bs, acc => go as bs (acc.push (f a b))
|
||||
| _, _, acc => acc.toList
|
||||
|
||||
@[csimp] theorem zipWith_eq_zipWithTR : @zipWith = @zipWithTR := by
|
||||
funext α β γ f as bs
|
||||
let rec go : ∀ as bs acc, zipWithTR.go f as bs acc = acc.data ++ as.zipWith f bs
|
||||
| [], _, acc | _::_, [], acc => by simp [zipWithTR.go, zipWith]
|
||||
| a::as, b::bs, acc => by simp [zipWithTR.go, zipWith, go as bs]
|
||||
exact (go as bs #[]).symm
|
||||
|
||||
/-- Tail recursive version of `unzip`. -/
|
||||
def unzipTR (l : List (α × β)) : List α × List β :=
|
||||
l.foldr (fun (a, b) (al, bl) => (a::al, b::bl)) ([], [])
|
||||
|
||||
@[csimp] theorem unzip_eq_unzipTR : @unzip = @unzipTR := by
|
||||
funext α β l; simp [unzipTR]; induction l <;> simp [*]
|
||||
|
||||
/-- Tail recursive version of `enumFrom`. -/
|
||||
def enumFromTR (n : Nat) (l : List α) : List (Nat × α) :=
|
||||
let arr := l.toArray
|
||||
(arr.foldr (fun a (n, acc) => (n-1, (n-1, a) :: acc)) (n + arr.size, [])).2
|
||||
|
||||
@[csimp] theorem enumFrom_eq_enumFromTR : @enumFrom = @enumFromTR := by
|
||||
funext α n l; simp [enumFromTR, -Array.size_toArray]
|
||||
let f := fun (a : α) (n, acc) => (n-1, (n-1, a) :: acc)
|
||||
let rec go : ∀ l n, l.foldr f (n + l.length, []) = (n, enumFrom n l)
|
||||
| [], n => rfl
|
||||
| a::as, n => by
|
||||
rw [← show _ + as.length = n + (a::as).length from Nat.succ_add .., foldr, go as]
|
||||
simp [enumFrom, f]
|
||||
rw [Array.foldr_eq_foldr_data]
|
||||
simp [go]
|
||||
|
||||
theorem replicateTR_loop_eq : ∀ n, replicateTR.loop a n acc = replicate n a ++ acc
|
||||
| 0 => rfl
|
||||
| n+1 => by rw [← replicateTR_loop_replicate_eq _ 1 n, replicate, replicate,
|
||||
replicateTR.loop, replicateTR_loop_eq n, replicateTR_loop_eq n, append_assoc]; rfl
|
||||
|
||||
/-- Tail recursive version of `dropLast`. -/
|
||||
@[inline] def dropLastTR (l : List α) : List α := l.toArray.pop.toList
|
||||
|
||||
@[csimp] theorem dropLast_eq_dropLastTR : @dropLast = @dropLastTR := by
|
||||
funext α l; simp [dropLastTR]
|
||||
|
||||
/-- Tail recursive version of `intersperse`. -/
|
||||
def intersperseTR (sep : α) : List α → List α
|
||||
| [] => []
|
||||
| [x] => [x]
|
||||
| x::y::xs => x :: sep :: y :: xs.foldr (fun a r => sep :: a :: r) []
|
||||
|
||||
@[csimp] theorem intersperse_eq_intersperseTR : @intersperse = @intersperseTR := by
|
||||
funext α sep l; simp [intersperseTR]
|
||||
match l with
|
||||
| [] | [_] => rfl
|
||||
| x::y::xs => simp [intersperse]; induction xs generalizing y <;> simp [*]
|
||||
|
||||
/-- Tail recursive version of `intercalate`. -/
|
||||
def intercalateTR (sep : List α) : List (List α) → List α
|
||||
| [] => []
|
||||
| [x] => x
|
||||
| x::xs => go sep.toArray x xs #[]
|
||||
where
|
||||
/-- Auxiliary for `intercalateTR`:
|
||||
`intercalateTR.go sep x xs acc = acc.toList ++ intercalate sep.toList (x::xs)` -/
|
||||
go (sep : Array α) : List α → List (List α) → Array α → List α
|
||||
| x, [], acc => acc.toListAppend x
|
||||
| x, y::xs, acc => go sep y xs (acc ++ x ++ sep)
|
||||
|
||||
@[csimp] theorem intercalate_eq_intercalateTR : @intercalate = @intercalateTR := by
|
||||
funext α sep l; simp [intercalate, intercalateTR]
|
||||
match l with
|
||||
| [] => rfl
|
||||
| [_] => simp
|
||||
| x::y::xs =>
|
||||
let rec go {acc x} : ∀ xs,
|
||||
intercalateTR.go sep.toArray x xs acc = acc.data ++ join (intersperse sep (x::xs))
|
||||
| [] => by simp [intercalateTR.go]
|
||||
| _::_ => by simp [intercalateTR.go, go]
|
||||
simp [intersperse, go]
|
||||
|
||||
end List
|
||||
@@ -251,12 +251,12 @@ theorem get?_append_right : ∀ {l₁ l₂ : List α} {n : Nat}, l₁.length ≤
|
||||
| [], _, n, _ => rfl
|
||||
| a :: l, _, n+1, h₁ => by
|
||||
rw [cons_append]
|
||||
simp [Nat.succ_sub_succ_eq_sub, get?_append_right (Nat.lt_succ.1 h₁)]
|
||||
simp [succ_sub_succ_eq_sub, get?_append_right (Nat.lt_succ.1 h₁)]
|
||||
|
||||
theorem get?_reverse' : ∀ {l : List α} (i j), i + j + 1 = length l →
|
||||
get? l.reverse i = get? l j
|
||||
| [], _, _, _ => rfl
|
||||
| a::l, i, 0, h => by simp [Nat.succ.injEq] at h; simp [h, get?_append_right, Nat.succ.injEq]
|
||||
| a::l, i, 0, h => by simp at h; simp [h, get?_append_right]
|
||||
| a::l, i, j+1, h => by
|
||||
have := Nat.succ.inj h; simp at this ⊢
|
||||
rw [get?_append, get?_reverse' _ j this]
|
||||
@@ -274,19 +274,6 @@ theorem get?_reverse {l : List α} (i) (h : i < length l) :
|
||||
|
||||
@[simp] theorem getD_cons_succ : getD (x :: xs) (n + 1) d = getD xs n d := rfl
|
||||
|
||||
theorem ext_get {l₁ l₂ : List α} (hl : length l₁ = length l₂)
|
||||
(h : ∀ n h₁ h₂, get l₁ ⟨n, h₁⟩ = get l₂ ⟨n, h₂⟩) : l₁ = l₂ :=
|
||||
ext fun n =>
|
||||
if h₁ : n < length l₁ then by
|
||||
rw [get?_eq_get, get?_eq_get, h n h₁ (by rwa [← hl])]
|
||||
else by
|
||||
have h₁ := Nat.le_of_not_lt h₁
|
||||
rw [get?_len_le h₁, get?_len_le]; rwa [← hl]
|
||||
|
||||
@[simp] theorem get_map (f : α → β) {l n} :
|
||||
get (map f l) n = f (get l ⟨n, length_map l f ▸ n.2⟩) :=
|
||||
Option.some.inj <| by rw [← get?_eq_get, get?_map, get?_eq_get]; rfl
|
||||
|
||||
/-! ### take and drop -/
|
||||
|
||||
@[simp] theorem take_append_drop : ∀ (n : Nat) (l : List α), take n l ++ drop n l = l
|
||||
@@ -404,14 +391,6 @@ theorem foldr_eq_foldrM (f : α → β → β) (b) (l : List α) :
|
||||
|
||||
theorem foldr_self (l : List α) : l.foldr cons [] = l := by simp
|
||||
|
||||
theorem foldl_map (f : β₁ → β₂) (g : α → β₂ → α) (l : List β₁) (init : α) :
|
||||
(l.map f).foldl g init = l.foldl (fun x y => g x (f y)) init := by
|
||||
induction l generalizing init <;> simp [*]
|
||||
|
||||
theorem foldr_map (f : α₁ → α₂) (g : α₂ → β → β) (l : List α₁) (init : β) :
|
||||
(l.map f).foldr g init = l.foldr (fun x y => g (f x) y) init := by
|
||||
induction l generalizing init <;> simp [*]
|
||||
|
||||
/-! ### mapM -/
|
||||
|
||||
/-- Alternate (non-tail-recursive) form of mapM for proofs. -/
|
||||
@@ -734,5 +713,3 @@ theorem minimum?_eq_some_iff [Min α] [LE α] [anti : Antisymm ((· : α) ≤ ·
|
||||
| _ :: l, i + 1, j + 1 => by
|
||||
have g : i ≠ j := h ∘ congrArg (· + 1)
|
||||
simp [get_set_ne l g]
|
||||
|
||||
end List
|
||||
|
||||
@@ -19,4 +19,3 @@ import Init.Data.Nat.Lemmas
|
||||
import Init.Data.Nat.Mod
|
||||
import Init.Data.Nat.Lcm
|
||||
import Init.Data.Nat.Compare
|
||||
import Init.Data.Nat.Simproc
|
||||
|
||||
@@ -137,9 +137,6 @@ instance : LawfulBEq Nat where
|
||||
@[simp] protected theorem zero_add : ∀ (n : Nat), 0 + n = n
|
||||
| 0 => rfl
|
||||
| n+1 => congrArg succ (Nat.zero_add n)
|
||||
instance : Std.LawfulIdentity (α := Nat) (· + ·) 0 where
|
||||
left_id := Nat.zero_add
|
||||
right_id := Nat.add_zero
|
||||
|
||||
theorem succ_add : ∀ (n m : Nat), (succ n) + m = succ (n + m)
|
||||
| _, 0 => rfl
|
||||
@@ -163,12 +160,10 @@ protected theorem add_comm : ∀ (n m : Nat), n + m = m + n
|
||||
have : succ (n + m) = succ (m + n) := by apply congrArg; apply Nat.add_comm
|
||||
rw [succ_add m n]
|
||||
apply this
|
||||
instance : Std.Commutative (α := Nat) (· + ·) := ⟨Nat.add_comm⟩
|
||||
|
||||
protected theorem add_assoc : ∀ (n m k : Nat), (n + m) + k = n + (m + k)
|
||||
| _, _, 0 => rfl
|
||||
| n, m, succ k => congrArg succ (Nat.add_assoc n m k)
|
||||
instance : Std.Associative (α := Nat) (· + ·) := ⟨Nat.add_assoc⟩
|
||||
|
||||
protected theorem add_left_comm (n m k : Nat) : n + (m + k) = m + (n + k) := by
|
||||
rw [← Nat.add_assoc, Nat.add_comm n m, Nat.add_assoc]
|
||||
@@ -179,7 +174,7 @@ protected theorem add_right_comm (n m k : Nat) : (n + m) + k = (n + k) + m := by
|
||||
protected theorem add_left_cancel {n m k : Nat} : n + m = n + k → m = k := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp [succ_add, succ.injEq]; intro h; apply ih h
|
||||
| succ n ih => simp [succ_add]; intro h; apply ih h
|
||||
|
||||
protected theorem add_right_cancel {n m k : Nat} (h : n + m = k + m) : n = k := by
|
||||
rw [Nat.add_comm n m, Nat.add_comm k m] at h
|
||||
@@ -212,16 +207,12 @@ theorem succ_mul (n m : Nat) : (succ n) * m = (n * m) + m := by
|
||||
protected theorem mul_comm : ∀ (n m : Nat), n * m = m * n
|
||||
| n, 0 => (Nat.zero_mul n).symm ▸ (Nat.mul_zero n).symm ▸ rfl
|
||||
| n, succ m => (mul_succ n m).symm ▸ (succ_mul m n).symm ▸ (Nat.mul_comm n m).symm ▸ rfl
|
||||
instance : Std.Commutative (α := Nat) (· * ·) := ⟨Nat.mul_comm⟩
|
||||
|
||||
@[simp] protected theorem mul_one : ∀ (n : Nat), n * 1 = n :=
|
||||
Nat.zero_add
|
||||
|
||||
@[simp] protected theorem one_mul (n : Nat) : 1 * n = n :=
|
||||
Nat.mul_comm n 1 ▸ Nat.mul_one n
|
||||
instance : Std.LawfulIdentity (α := Nat) (· * ·) 1 where
|
||||
left_id := Nat.one_mul
|
||||
right_id := Nat.mul_one
|
||||
|
||||
protected theorem left_distrib (n m k : Nat) : n * (m + k) = n * m + n * k := by
|
||||
induction n with
|
||||
@@ -240,7 +231,6 @@ protected theorem add_mul (n m k : Nat) : (n + m) * k = n * k + m * k :=
|
||||
protected theorem mul_assoc : ∀ (n m k : Nat), (n * m) * k = n * (m * k)
|
||||
| n, m, 0 => rfl
|
||||
| n, m, succ k => by simp [mul_succ, Nat.mul_assoc n m k, Nat.left_distrib]
|
||||
instance : Std.Associative (α := Nat) (· * ·) := ⟨Nat.mul_assoc⟩
|
||||
|
||||
protected theorem mul_left_comm (n m k : Nat) : n * (m * k) = m * (n * k) := by
|
||||
rw [← Nat.mul_assoc, Nat.mul_comm n m, Nat.mul_assoc]
|
||||
@@ -584,7 +574,7 @@ 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 := ⟨succ.inj, congrArg _⟩
|
||||
|
||||
theorem succ_le_succ_iff : succ a ≤ succ b ↔ a ≤ b := ⟨le_of_succ_le_succ, succ_le_succ⟩
|
||||
|
||||
@@ -760,15 +750,26 @@ theorem sub_one_add_one_eq_of_pos : ∀ {n}, 0 < n → (n - 1) + 1 = n
|
||||
|
||||
/-! # sub theorems -/
|
||||
|
||||
theorem add_sub_self_left (a b : Nat) : (a + b) - a = b := by
|
||||
induction a with
|
||||
protected theorem add_sub_add_right (n k m : Nat) : (n + k) - (m + k) = n - m := by
|
||||
induction k with
|
||||
| zero => simp
|
||||
| succ a ih =>
|
||||
rw [Nat.succ_add, Nat.succ_sub_succ]
|
||||
apply ih
|
||||
| succ k ih => simp [← Nat.add_assoc, succ_sub_succ_eq_sub, ih]
|
||||
|
||||
theorem add_sub_self_right (a b : Nat) : (a + b) - b = a := by
|
||||
rw [Nat.add_comm]; apply add_sub_self_left
|
||||
protected theorem add_sub_add_left (k n m : Nat) : (k + n) - (k + m) = n - m := by
|
||||
rw [Nat.add_comm k n, Nat.add_comm k m, Nat.add_sub_add_right]
|
||||
|
||||
@[simp] protected theorem add_sub_cancel (a b : Nat) : a + b - b = a :=
|
||||
suffices a + b - (0 + b) = a by rw [Nat.zero_add] at this; assumption
|
||||
by rw [Nat.add_sub_add_right, Nat.sub_zero]
|
||||
|
||||
protected theorem add_sub_cancel_left (a b : Nat) : a + b - a = b := by
|
||||
rw [Nat.add_comm]; apply Nat.add_sub_cancel
|
||||
|
||||
@[deprecated Nat.add_sub_cancel]
|
||||
theorem add_sub_self_right : ∀(a b : Nat), (a + b) - b = a := Nat.add_sub_cancel
|
||||
|
||||
@[deprecated Nat.add_sub_cancel_left]
|
||||
theorem add_sub_self_left : ∀(a b : Nat), (a + b) - a = b := Nat.add_sub_cancel_left
|
||||
|
||||
theorem sub_le_succ_sub (a i : Nat) : a - i ≤ a.succ - i := by
|
||||
cases i with
|
||||
@@ -780,7 +781,7 @@ theorem zero_lt_sub_of_lt (h : i < a) : 0 < a - i := by
|
||||
| zero => contradiction
|
||||
| succ a ih =>
|
||||
match Nat.eq_or_lt_of_le h with
|
||||
| Or.inl h => injection h with h; subst h; rw [Nat.add_sub_self_left]; decide
|
||||
| Or.inl h => injection h with h; subst h; rw [Nat.add_sub_cancel_left]; decide
|
||||
| Or.inr h =>
|
||||
have : 0 < a - i := ih (Nat.lt_of_succ_lt_succ h)
|
||||
exact Nat.lt_of_lt_of_le this (Nat.sub_le_succ_sub _ _)
|
||||
@@ -809,22 +810,6 @@ theorem add_sub_of_le {a b : Nat} (h : a ≤ b) : a + (b - a) = b := by
|
||||
@[simp] protected theorem sub_add_cancel {n m : Nat} (h : m ≤ n) : n - m + m = n := by
|
||||
rw [Nat.add_comm, Nat.add_sub_of_le h]
|
||||
|
||||
protected theorem add_sub_add_right (n k m : Nat) : (n + k) - (m + k) = n - m := by
|
||||
induction k with
|
||||
| zero => simp
|
||||
| succ k ih => simp [← Nat.add_assoc, succ_sub_succ_eq_sub, ih]
|
||||
|
||||
protected theorem add_sub_add_left (k n m : Nat) : (k + n) - (k + m) = n - m := by
|
||||
rw [Nat.add_comm k n, Nat.add_comm k m, Nat.add_sub_add_right]
|
||||
|
||||
@[simp] protected theorem add_sub_cancel (n m : Nat) : n + m - m = n :=
|
||||
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 :=
|
||||
show n + m - (n + 0) = m from
|
||||
by rw [Nat.add_sub_add_left, Nat.sub_zero]
|
||||
|
||||
protected theorem add_sub_assoc {m k : Nat} (h : k ≤ m) (n : Nat) : n + m - k = n + (m - k) := by
|
||||
cases Nat.le.dest h
|
||||
rename_i l hl
|
||||
@@ -1011,7 +996,7 @@ theorem not_gt_eq (a b : Nat) : (¬ (a > b)) = (a ≤ b) :=
|
||||
funext fun α => funext fun f => funext fun n => funext fun init =>
|
||||
let rec go : ∀ m n, foldTR.loop f (m + n) m (fold f n init) = fold f (m + n) init
|
||||
| 0, n => by simp [foldTR.loop]
|
||||
| succ m, n => by rw [foldTR.loop, add_sub_self_left, succ_add]; exact go m (succ n)
|
||||
| succ m, n => by rw [foldTR.loop, Nat.add_sub_cancel_left, succ_add]; exact go m (succ n)
|
||||
(go n 0).symm
|
||||
|
||||
@[csimp] theorem any_eq_anyTR : @any = @anyTR :=
|
||||
@@ -1019,7 +1004,7 @@ theorem not_gt_eq (a b : Nat) : (¬ (a > b)) = (a ≤ b) :=
|
||||
let rec go : ∀ m n, (any f n || anyTR.loop f (m + n) m) = any f (m + n)
|
||||
| 0, n => by simp [anyTR.loop]
|
||||
| succ m, n => by
|
||||
rw [anyTR.loop, add_sub_self_left, ← Bool.or_assoc, succ_add]
|
||||
rw [anyTR.loop, Nat.add_sub_cancel_left, ← Bool.or_assoc, succ_add]
|
||||
exact go m (succ n)
|
||||
(go n 0).symm
|
||||
|
||||
@@ -1028,7 +1013,7 @@ theorem not_gt_eq (a b : Nat) : (¬ (a > b)) = (a ≤ b) :=
|
||||
let rec go : ∀ m n, (all f n && allTR.loop f (m + n) m) = all f (m + n)
|
||||
| 0, n => by simp [allTR.loop]
|
||||
| succ m, n => by
|
||||
rw [allTR.loop, add_sub_self_left, ← Bool.and_assoc, succ_add]
|
||||
rw [allTR.loop, Nat.add_sub_cancel_left, ← Bool.and_assoc, succ_add]
|
||||
exact go m (succ n)
|
||||
(go n 0).symm
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import Init.Data.Bool
|
||||
import Init.Data.Int.Pow
|
||||
import Init.Data.Nat.Bitwise.Basic
|
||||
import Init.Data.Nat.Lemmas
|
||||
import Init.Data.Nat.Simproc
|
||||
import Init.TacticsExtra
|
||||
import Init.Omega
|
||||
|
||||
@@ -280,7 +279,7 @@ theorem testBit_two_pow_sub_succ (h₂ : x < 2 ^ n) (i : Nat) :
|
||||
simp only [testBit_succ]
|
||||
match n with
|
||||
| 0 =>
|
||||
simp [decide_eq_false, succ_sub_succ_eq_sub]
|
||||
simp [succ_sub_succ_eq_sub, decide_eq_false]
|
||||
| n+1 =>
|
||||
rw [Nat.two_pow_succ_sub_succ_div_two, ih]
|
||||
· simp [Nat.succ_lt_succ_iff]
|
||||
|
||||
@@ -28,7 +28,7 @@ protected def div (x y : @& Nat) : Nat :=
|
||||
0
|
||||
decreasing_by apply div_rec_lemma; assumption
|
||||
|
||||
instance instDiv : Div Nat := ⟨Nat.div⟩
|
||||
instance : Div Nat := ⟨Nat.div⟩
|
||||
|
||||
theorem div_eq (x y : Nat) : x / y = if 0 < y ∧ y ≤ x then (x - y) / y + 1 else 0 := by
|
||||
show Nat.div x y = _
|
||||
@@ -90,7 +90,7 @@ protected def mod : @& Nat → @& Nat → Nat
|
||||
| 0, _ => 0
|
||||
| x@(_ + 1), y => Nat.modCore x y
|
||||
|
||||
instance instMod : Mod Nat := ⟨Nat.mod⟩
|
||||
instance : Mod Nat := ⟨Nat.mod⟩
|
||||
|
||||
protected theorem modCore_eq_mod (x y : Nat) : Nat.modCore x y = x % y := by
|
||||
cases x with
|
||||
@@ -379,5 +379,4 @@ theorem mul_div_le (m n : Nat) : n * (m / n) ≤ m := by
|
||||
| _, Or.inl rfl => rw [Nat.zero_mul]; exact m.zero_le
|
||||
| n, Or.inr h => rw [Nat.mul_comm, ← Nat.le_div_iff_mul_le h]; exact Nat.le_refl _
|
||||
|
||||
|
||||
end Nat
|
||||
|
||||
@@ -9,39 +9,59 @@ import Init.Meta
|
||||
|
||||
namespace Nat
|
||||
|
||||
protected theorem dvd_refl (a : Nat) : a ∣ a := ⟨1, by simp⟩
|
||||
protected theorem dvd_def (a b : Nat) : (a ∣ b) = Exists (fun c => b = a * c) := rfl
|
||||
|
||||
protected theorem dvd_zero (a : Nat) : a ∣ 0 := ⟨0, by simp⟩
|
||||
@[simp] protected theorem dvd_refl (a : Nat) : a ∣ a := ⟨1, by simp⟩
|
||||
|
||||
protected theorem dvd_mul_left (a b : Nat) : a ∣ b * a := ⟨b, Nat.mul_comm b a⟩
|
||||
protected theorem dvd_mul_right (a b : Nat) : a ∣ a * b := ⟨b, rfl⟩
|
||||
@[simp] protected theorem dvd_zero (a : Nat) : a ∣ 0 := ⟨0, by simp⟩
|
||||
|
||||
protected theorem eq_zero_of_zero_dvd {a : Nat} (h : 0 ∣ a) : a = 0 :=
|
||||
let ⟨c, H'⟩ := h; H'.trans c.zero_mul
|
||||
|
||||
@[simp] protected theorem zero_dvd {n : Nat} : 0 ∣ n ↔ n = 0 :=
|
||||
Iff.intro Nat.eq_zero_of_zero_dvd
|
||||
(fun h => h.symm ▸ Nat.dvd_refl 0)
|
||||
|
||||
@[simp] protected theorem one_dvd (n : Nat) : 1 ∣ n := ⟨n, n.one_mul.symm⟩
|
||||
|
||||
protected theorem dvd_trans {a b c : Nat} (h₁ : a ∣ b) (h₂ : b ∣ c) : a ∣ c :=
|
||||
match h₁, h₂ with
|
||||
| ⟨d, (h₃ : b = a * d)⟩, ⟨e, (h₄ : c = b * e)⟩ =>
|
||||
⟨d * e, show c = a * (d * e) by simp[h₃,h₄, Nat.mul_assoc]⟩
|
||||
|
||||
protected theorem eq_zero_of_zero_dvd {a : Nat} (h : 0 ∣ a) : a = 0 :=
|
||||
let ⟨c, H'⟩ := h; H'.trans c.zero_mul
|
||||
|
||||
@[simp] protected theorem zero_dvd {n : Nat} : 0 ∣ n ↔ n = 0 :=
|
||||
⟨Nat.eq_zero_of_zero_dvd, fun h => h.symm ▸ Nat.dvd_zero 0⟩
|
||||
protected theorem dvd_mul_left (a b : Nat) : a ∣ b * a := ⟨b, Nat.mul_comm b a⟩
|
||||
protected theorem dvd_mul_right (a b : Nat) : a ∣ a * b := ⟨b, rfl⟩
|
||||
|
||||
protected theorem dvd_add {a b c : Nat} (h₁ : a ∣ b) (h₂ : a ∣ c) : a ∣ b + c :=
|
||||
let ⟨d, hd⟩ := h₁; let ⟨e, he⟩ := h₂; ⟨d + e, by simp [Nat.left_distrib, hd, he]⟩
|
||||
|
||||
protected theorem dvd_add_iff_right {k m n : Nat} (h : k ∣ m) : k ∣ n ↔ k ∣ m + n :=
|
||||
⟨Nat.dvd_add h,
|
||||
match m, h with
|
||||
-- Note. This removes unnecessary condition
|
||||
protected theorem dvd_sub : ∀ {a b c : Nat}, a ∣ b → a ∣ c → a ∣ b - c
|
||||
| a, _, _, ⟨d, rfl⟩, ⟨e, rfl⟩ => ⟨d - e, by rw [Nat.mul_sub_left_distrib]⟩
|
||||
|
||||
protected theorem dvd_add_left {a b c : Nat} (h : a ∣ c) : a ∣ b + c ↔ a ∣ b :=
|
||||
Iff.intro
|
||||
(match c, h with
|
||||
| _, ⟨d, rfl⟩ => fun ⟨e, he⟩ =>
|
||||
⟨e - d, by rw [Nat.mul_sub_left_distrib, ← he, Nat.add_sub_cancel_left]⟩⟩
|
||||
⟨e - d, by rw [Nat.mul_sub_left_distrib, ← he, Nat.add_sub_cancel]⟩)
|
||||
(Nat.dvd_add · h)
|
||||
|
||||
protected theorem dvd_add_iff_left {k m n : Nat} (h : k ∣ n) : k ∣ m ↔ k ∣ m + n := by
|
||||
rw [Nat.add_comm]; exact Nat.dvd_add_iff_right h
|
||||
protected theorem dvd_add_right {a b c : Nat} (h : a ∣ b) : a ∣ b + c ↔ a ∣ c := by
|
||||
rw [Nat.add_comm]; exact Nat.dvd_add_left h
|
||||
|
||||
theorem dvd_mod_iff {k m n : Nat} (h: k ∣ n) : k ∣ m % n ↔ k ∣ m :=
|
||||
have := Nat.dvd_add_iff_left <| Nat.dvd_trans h <| Nat.dvd_mul_right n (m / n)
|
||||
by rwa [mod_add_div] at this
|
||||
/--
|
||||
This is replaced by (dvd_add_left _).symm for consistency with Int version.
|
||||
-/
|
||||
@[deprecated Nat.dvd_add_left]
|
||||
protected theorem dvd_add_iff_left {k m n : Nat} (h : k ∣ n) : k ∣ m ↔ k ∣ m + n :=
|
||||
(Nat.dvd_add_left h).symm
|
||||
|
||||
/--
|
||||
This is replaced by (dvd_add_right _).symm for consistency with Int version.
|
||||
-/
|
||||
@[deprecated Nat.dvd_add_right]
|
||||
protected theorem dvd_add_iff_right {k m n : Nat} (h : k ∣ m) : k ∣ n ↔ k ∣ m + n :=
|
||||
(Nat.dvd_add_right h).symm
|
||||
|
||||
theorem le_of_dvd {m n : Nat} (h : 0 < n) : m ∣ n → m ≤ n
|
||||
| ⟨k, e⟩ => by
|
||||
@@ -59,11 +79,13 @@ protected theorem dvd_antisymm : ∀ {m n : Nat}, m ∣ n → n ∣ m → m = n
|
||||
| 0, _, h₁, _ => (Nat.eq_zero_of_zero_dvd h₁).symm
|
||||
| _+1, _+1, h₁, h₂ => Nat.le_antisymm (le_of_dvd (succ_pos _) h₁) (le_of_dvd (succ_pos _) h₂)
|
||||
|
||||
theorem dvd_mod_iff {k m n : Nat} (h: k ∣ n) : k ∣ m % n ↔ k ∣ m :=
|
||||
have := (Nat.dvd_add_left <| Nat.dvd_trans h <| Nat.dvd_mul_right n (m / n)).symm
|
||||
by rwa [mod_add_div] at this
|
||||
|
||||
theorem pos_of_dvd_of_pos {m n : Nat} (H1 : m ∣ n) (H2 : 0 < n) : 0 < m :=
|
||||
Nat.pos_of_ne_zero fun m0 => Nat.ne_of_gt H2 <| Nat.eq_zero_of_zero_dvd (m0 ▸ H1)
|
||||
|
||||
@[simp] protected theorem one_dvd (n : Nat) : 1 ∣ n := ⟨n, n.one_mul.symm⟩
|
||||
|
||||
theorem eq_one_of_dvd_one {n : Nat} (H : n ∣ 1) : n = 1 := Nat.dvd_antisymm H n.one_dvd
|
||||
|
||||
theorem mod_eq_zero_of_dvd {m n : Nat} (H : m ∣ n) : n % m = 0 := by
|
||||
@@ -75,7 +97,7 @@ theorem dvd_of_mod_eq_zero {m n : Nat} (H : n % m = 0) : m ∣ n := by
|
||||
rwa [H, Nat.zero_add] at this
|
||||
|
||||
theorem dvd_iff_mod_eq_zero (m n : Nat) : m ∣ n ↔ n % m = 0 :=
|
||||
⟨mod_eq_zero_of_dvd, dvd_of_mod_eq_zero⟩
|
||||
Iff.intro mod_eq_zero_of_dvd dvd_of_mod_eq_zero
|
||||
|
||||
instance decidable_dvd : @DecidableRel Nat (·∣·) :=
|
||||
fun _ _ => decidable_of_decidable_of_iff (dvd_iff_mod_eq_zero _ _).symm
|
||||
@@ -106,9 +128,6 @@ protected theorem dvd_of_mul_dvd_mul_left
|
||||
protected theorem dvd_of_mul_dvd_mul_right (kpos : 0 < k) (H : m * k ∣ n * k) : m ∣ n := by
|
||||
rw [Nat.mul_comm m k, Nat.mul_comm n k] at H; exact Nat.dvd_of_mul_dvd_mul_left kpos H
|
||||
|
||||
theorem dvd_sub {k m n : Nat} (H : n ≤ m) (h₁ : k ∣ m) (h₂ : k ∣ n) : k ∣ m - n :=
|
||||
(Nat.dvd_add_iff_left h₂).2 <| by rwa [Nat.sub_add_cancel H]
|
||||
|
||||
protected theorem mul_dvd_mul {a b c d : Nat} : a ∣ b → c ∣ d → a * c ∣ b * d
|
||||
| ⟨e, he⟩, ⟨f, hf⟩ =>
|
||||
⟨e * f, by simp [he, hf, Nat.mul_assoc, Nat.mul_left_comm, Nat.mul_comm]⟩
|
||||
|
||||
@@ -10,24 +10,6 @@ import Init.RCases
|
||||
|
||||
namespace Nat
|
||||
|
||||
/--
|
||||
Computes the greatest common divisor of two natural numbers.
|
||||
|
||||
This reference implementation via the Euclidean algorithm
|
||||
is overridden in both the kernel and the compiler to efficiently
|
||||
evaluate using the "bignum" representation (see `Nat`).
|
||||
The definition provided here is the logical model
|
||||
(and it is soundness-critical that they coincide).
|
||||
|
||||
The GCD of two natural numbers is the largest natural number
|
||||
that divides both arguments.
|
||||
In particular, the GCD of a number and `0` is the number itself:
|
||||
```
|
||||
example : Nat.gcd 10 15 = 5 := rfl
|
||||
example : Nat.gcd 0 5 = 5 := rfl
|
||||
example : Nat.gcd 7 0 = 7 := rfl
|
||||
```
|
||||
-/
|
||||
@[extern "lean_nat_gcd"]
|
||||
def gcd (m n : @& Nat) : Nat :=
|
||||
if m = 0 then
|
||||
@@ -54,13 +36,9 @@ theorem gcd_succ (x y : Nat) : gcd (succ x) y = gcd (y % succ x) (succ x) :=
|
||||
-- `simp [gcd_succ]` produces an invalid term unless `gcd_succ` is proved with `id rfl` instead
|
||||
rw [gcd_succ]
|
||||
exact gcd_zero_left _
|
||||
instance : Std.LawfulIdentity gcd 0 where
|
||||
left_id := gcd_zero_left
|
||||
right_id := gcd_zero_right
|
||||
|
||||
@[simp] theorem gcd_self (n : Nat) : gcd n n = n := by
|
||||
cases n <;> simp [gcd_succ]
|
||||
instance : Std.IdempotentOp gcd := ⟨gcd_self⟩
|
||||
|
||||
theorem gcd_rec (m n : Nat) : gcd m n = gcd (n % m) m :=
|
||||
match m with
|
||||
@@ -101,7 +79,6 @@ theorem gcd_comm (m n : Nat) : gcd m n = gcd n m :=
|
||||
Nat.dvd_antisymm
|
||||
(dvd_gcd (gcd_dvd_right m n) (gcd_dvd_left m n))
|
||||
(dvd_gcd (gcd_dvd_right n m) (gcd_dvd_left n m))
|
||||
instance : Std.Commutative gcd := ⟨gcd_comm⟩
|
||||
|
||||
theorem gcd_eq_left_iff_dvd : m ∣ n ↔ gcd m n = m :=
|
||||
⟨fun h => by rw [gcd_rec, mod_eq_zero_of_dvd h, gcd_zero_left],
|
||||
|
||||
@@ -14,7 +14,6 @@ def lcm (m n : Nat) : Nat := m * n / gcd m n
|
||||
|
||||
theorem lcm_comm (m n : Nat) : lcm m n = lcm n m := by
|
||||
rw [lcm, lcm, Nat.mul_comm n m, gcd_comm n m]
|
||||
instance : Std.Commutative lcm := ⟨lcm_comm⟩
|
||||
|
||||
@[simp] theorem lcm_zero_left (m : Nat) : lcm 0 m = 0 := by simp [lcm]
|
||||
|
||||
@@ -23,15 +22,11 @@ instance : Std.Commutative lcm := ⟨lcm_comm⟩
|
||||
@[simp] theorem lcm_one_left (m : Nat) : lcm 1 m = m := by simp [lcm]
|
||||
|
||||
@[simp] theorem lcm_one_right (m : Nat) : lcm m 1 = m := by simp [lcm]
|
||||
instance : Std.LawfulIdentity lcm 1 where
|
||||
left_id := lcm_one_left
|
||||
right_id := lcm_one_right
|
||||
|
||||
@[simp] theorem lcm_self (m : Nat) : lcm m m = m := by
|
||||
match eq_zero_or_pos m with
|
||||
| .inl h => rw [h, lcm_zero_left]
|
||||
| .inr h => simp [lcm, Nat.mul_div_cancel _ h]
|
||||
instance : Std.IdempotentOp lcm := ⟨lcm_self⟩
|
||||
|
||||
theorem dvd_lcm_left (m n : Nat) : m ∣ lcm m n :=
|
||||
⟨n / gcd m n, by rw [← Nat.mul_div_assoc m (Nat.gcd_dvd_right m n)]; rfl⟩
|
||||
@@ -59,7 +54,6 @@ Nat.dvd_antisymm
|
||||
(Nat.dvd_trans (dvd_lcm_left m n) (dvd_lcm_left (lcm m n) k))
|
||||
(lcm_dvd (Nat.dvd_trans (dvd_lcm_right m n) (dvd_lcm_left (lcm m n) k))
|
||||
(dvd_lcm_right (lcm m n) k)))
|
||||
instance : Std.Associative lcm := ⟨lcm_assoc⟩
|
||||
|
||||
theorem lcm_ne_zero (hm : m ≠ 0) (hn : n ≠ 0) : lcm m n ≠ 0 := by
|
||||
intro h
|
||||
|
||||
@@ -88,7 +88,7 @@ protected theorem add_pos_right (m) (h : 0 < n) : 0 < m + n :=
|
||||
Nat.lt_of_lt_of_le h (Nat.le_add_left ..)
|
||||
|
||||
protected theorem add_self_ne_one : ∀ n, n + n ≠ 1
|
||||
| n+1, h => by rw [Nat.succ_add, Nat.succ.injEq] at h; contradiction
|
||||
| n+1, h => by rw [Nat.succ_add, Nat.succ_inj'] at h; contradiction
|
||||
|
||||
/-! ## sub -/
|
||||
|
||||
@@ -200,7 +200,6 @@ theorem succ_min_succ (x y) : min (succ x) (succ y) = succ (min x y) := by
|
||||
| inr h => rw [Nat.min_eq_right h, Nat.min_eq_right (Nat.succ_le_succ h)]
|
||||
|
||||
@[simp] protected theorem min_self (a : Nat) : min a a = a := Nat.min_eq_left (Nat.le_refl _)
|
||||
instance : Std.IdempotentOp (α := Nat) min := ⟨Nat.min_self⟩
|
||||
|
||||
@[simp] protected theorem zero_min (a) : min 0 a = 0 := Nat.min_eq_left (Nat.zero_le _)
|
||||
|
||||
@@ -211,7 +210,6 @@ protected theorem min_assoc : ∀ (a b c : Nat), min (min a b) c = min a (min b
|
||||
| _, 0, _ => by rw [Nat.zero_min, Nat.min_zero, Nat.zero_min]
|
||||
| _, _, 0 => by rw [Nat.min_zero, Nat.min_zero, Nat.min_zero]
|
||||
| _+1, _+1, _+1 => by simp only [Nat.succ_min_succ]; exact congrArg succ <| Nat.min_assoc ..
|
||||
instance : Std.Associative (α := Nat) min := ⟨Nat.min_assoc⟩
|
||||
|
||||
protected theorem sub_sub_eq_min : ∀ (a b : Nat), a - (a - b) = min a b
|
||||
| 0, _ => by rw [Nat.zero_sub, Nat.zero_min]
|
||||
@@ -251,21 +249,16 @@ protected theorem max_lt {a b c : Nat} : max a b < c ↔ a < c ∧ b < c := by
|
||||
rw [← Nat.succ_le, ← Nat.succ_max_succ a b]; exact Nat.max_le
|
||||
|
||||
@[simp] protected theorem max_self (a : Nat) : max a a = a := Nat.max_eq_right (Nat.le_refl _)
|
||||
instance : Std.IdempotentOp (α := Nat) max := ⟨Nat.max_self⟩
|
||||
|
||||
@[simp] protected theorem zero_max (a) : max 0 a = a := Nat.max_eq_right (Nat.zero_le _)
|
||||
|
||||
@[simp] protected theorem max_zero (a) : max a 0 = a := Nat.max_eq_left (Nat.zero_le _)
|
||||
instance : Std.LawfulIdentity (α := Nat) max 0 where
|
||||
left_id := Nat.zero_max
|
||||
right_id := Nat.max_zero
|
||||
|
||||
protected theorem max_assoc : ∀ (a b c : Nat), max (max a b) c = max a (max b c)
|
||||
| 0, _, _ => by rw [Nat.zero_max, Nat.zero_max]
|
||||
| _, 0, _ => by rw [Nat.zero_max, Nat.max_zero]
|
||||
| _, _, 0 => by rw [Nat.max_zero, Nat.max_zero]
|
||||
| _+1, _+1, _+1 => by simp only [Nat.succ_max_succ]; exact congrArg succ <| Nat.max_assoc ..
|
||||
instance : Std.Associative (α := Nat) max := ⟨Nat.max_assoc⟩
|
||||
|
||||
protected theorem sub_add_eq_max (a b : Nat) : a - b + b = max a b := by
|
||||
match Nat.le_total a b with
|
||||
@@ -837,3 +830,42 @@ instance decidableExistsLT [h : DecidablePred p] : DecidablePred fun n => ∃ m
|
||||
instance decidableExistsLE [DecidablePred p] : DecidablePred fun n => ∃ m : Nat, m ≤ n ∧ p m :=
|
||||
fun n => decidable_of_iff (∃ m, m < n + 1 ∧ p m)
|
||||
(exists_congr fun _ => and_congr_left' Nat.lt_succ_iff)
|
||||
|
||||
theorem dvd_sub_iff {a b : Nat} (h : a ≥ b) : b ∣ (a - b) ↔ b ∣ a := by
|
||||
apply Iff.intro
|
||||
· intro ⟨c, p⟩
|
||||
replace p := Nat.eq_add_of_sub_eq h p
|
||||
apply Exists.intro (c+1)
|
||||
simp [Nat.mul_add, p]
|
||||
· intro ⟨c, p⟩
|
||||
match c with
|
||||
| 0 =>
|
||||
simp_all
|
||||
| c + 1 =>
|
||||
apply Exists.intro c
|
||||
simp [p, Nat.mul_add]
|
||||
|
||||
theorem succ_div (a b : Nat) : (a + 1) / b = if b ∣ (a+1) then a / b + 1 else a / b := by
|
||||
match b with
|
||||
| 0 =>
|
||||
simp
|
||||
| b + 1 =>
|
||||
match Nat.lt_trichotomy (a+1) (b+1) with
|
||||
| Or.inl q =>
|
||||
have p : a < b + 1 := Nat.le_succ_of_le (Nat.le_of_succ_le_succ q)
|
||||
split
|
||||
· rename_i dvd
|
||||
replace dvd := Nat.mod_eq_zero_of_dvd dvd
|
||||
simp only [Nat.mod_eq_of_lt q] at dvd
|
||||
· rename_i dvd
|
||||
simp only [Nat.div_eq_of_lt, p, q]
|
||||
| Or.inr (Or.inl p) =>
|
||||
simp [←p, Nat.div_self, Nat.div_eq_of_lt]
|
||||
| Or.inr (Or.inr p) =>
|
||||
replace p : a ≥ b + 1 := Nat.le_of_succ_le_succ p
|
||||
have q : a + 1 ≥ b + 1 := Nat.le_succ_of_le p
|
||||
have r := succ_div (a - (b + 1)) (b + 1)
|
||||
simp only [←Nat.sub_add_comm p, Nat.dvd_sub_iff q] at r
|
||||
have b_pos : 0 < b + 1 := Nat.succ_le_succ (Nat.zero_le b)
|
||||
rw [Nat.div_eq_sub_div b_pos p, Nat.div_eq_sub_div b_pos q, r]
|
||||
split <;> simp
|
||||
|
||||
@@ -580,7 +580,7 @@ attribute [-simp] Nat.right_distrib Nat.left_distrib
|
||||
|
||||
theorem PolyCnstr.denote_mul (ctx : Context) (k : Nat) (c : PolyCnstr) : (c.mul (k+1)).denote ctx = c.denote ctx := by
|
||||
cases c; rename_i eq lhs rhs
|
||||
have : k ≠ 0 → k + 1 ≠ 1 := by intro h; match k with | 0 => contradiction | k+1 => simp [Nat.succ.injEq]
|
||||
have : k ≠ 0 → k + 1 ≠ 1 := by intro h; match k with | 0 => contradiction | k+1 => simp
|
||||
have : ¬ (k == 0) → (k + 1 == 1) = false := fun h => beq_false_of_ne (this (ne_of_beq_false (Bool.of_not_eq_true h)))
|
||||
have : ¬ ((k + 1 == 0) = true) := fun h => absurd (eq_of_beq h) (Nat.succ_ne_zero k)
|
||||
have : (1 == (0 : Nat)) = false := rfl
|
||||
|
||||
@@ -17,7 +17,6 @@ protected theorem min_comm (a b : Nat) : min a b = min b a := by
|
||||
| .inl h => simp [Nat.min_def, h, Nat.le_of_lt, Nat.not_le_of_lt]
|
||||
| .inr (.inl h) => simp [Nat.min_def, h]
|
||||
| .inr (.inr h) => simp [Nat.min_def, h, Nat.le_of_lt, Nat.not_le_of_lt]
|
||||
instance : Std.Commutative (α := Nat) min := ⟨Nat.min_comm⟩
|
||||
|
||||
protected theorem min_le_right (a b : Nat) : min a b ≤ b := by
|
||||
by_cases (a <= b) <;> simp [Nat.min_def, *]
|
||||
@@ -48,7 +47,6 @@ protected theorem max_comm (a b : Nat) : max a b = max b a := by
|
||||
by_cases h₁ : a ≤ b <;> by_cases h₂ : b ≤ a <;> simp [h₁, h₂]
|
||||
· exact Nat.le_antisymm h₂ h₁
|
||||
· cases not_or_intro h₁ h₂ <| Nat.le_total ..
|
||||
instance : Std.Commutative (α := Nat) max := ⟨Nat.max_comm⟩
|
||||
|
||||
protected theorem le_max_left ( a b : Nat) : a ≤ max a b := by
|
||||
by_cases (a <= b) <;> simp [Nat.max_def, *]
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2023 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Joe Hendrix
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Bool
|
||||
import Init.Data.Nat.Basic
|
||||
import Init.Data.Nat.Lemmas
|
||||
|
||||
/-!
|
||||
This contains lemmas used by the Nat simprocs for simplifying arithmetic
|
||||
addition offsets.
|
||||
-/
|
||||
namespace Nat.Simproc
|
||||
|
||||
/- Sub proofs -/
|
||||
|
||||
theorem sub_add_eq_comm (a b c : Nat) : a - (b + c) = a - c - b := by
|
||||
rw [Nat.add_comm b c]
|
||||
exact Nat.sub_add_eq a c b
|
||||
|
||||
theorem add_sub_add_le (a c : Nat) {b d : Nat} (h : b ≤ d) : a + b - (c + d) = a - (c + (d-b)) := by
|
||||
induction b generalizing a c d with
|
||||
| zero =>
|
||||
simp
|
||||
| succ b ind =>
|
||||
match d with
|
||||
| 0 =>
|
||||
contradiction
|
||||
| d + 1 =>
|
||||
have g := Nat.le_of_succ_le_succ h
|
||||
rw [Nat.add_succ a, Nat.add_succ c, Nat.succ_sub_succ, Nat.succ_sub_succ,
|
||||
ind _ _ g]
|
||||
|
||||
theorem add_sub_add_ge (a c : Nat) {b d : Nat} (h : b ≥ d) : a + b - (c + d) = a + (b - d) - c := by
|
||||
rw [Nat.add_comm c d, Nat.sub_add_eq, Nat.add_sub_assoc h a]
|
||||
|
||||
theorem add_sub_le (a : Nat) {b c : Nat} (h : b ≤ c) : a + b - c = a - (c - b) := by
|
||||
have p := add_sub_add_le a 0 h
|
||||
simp only [Nat.zero_add] at p
|
||||
exact p
|
||||
|
||||
/- Eq proofs -/
|
||||
|
||||
theorem add_eq_gt (a : Nat) {b c : Nat} (h : b > c) : (a + b = c) = False :=
|
||||
eq_false (Nat.ne_of_gt (Nat.lt_of_lt_of_le h (le_add_left b a)))
|
||||
|
||||
theorem eq_add_gt (a : Nat) {b c : Nat} (h : c > a) : (a = b + c) = False := by
|
||||
rw [@Eq.comm Nat a (b + c)]
|
||||
exact add_eq_gt b h
|
||||
|
||||
theorem add_eq_add_le (a c : Nat) {b d : Nat} (h : b ≤ d) : (a + b = c + d) = (a = c + (d - b)) := by
|
||||
have g : b ≤ c + d := Nat.le_trans h (le_add_left d c)
|
||||
rw [← Nat.add_sub_assoc h, @Eq.comm _ a, Nat.sub_eq_iff_eq_add g, @Eq.comm _ (a + b)]
|
||||
|
||||
theorem add_eq_add_ge (a c : Nat) {b d : Nat} (h : b ≥ d) : (a + b = c + d) = (a + (b - d) = c) := by
|
||||
rw [@Eq.comm _ (a + b) _, add_eq_add_le c a h, @Eq.comm _ _ c]
|
||||
|
||||
theorem add_eq_le (a : Nat) {b c : Nat} (h : b ≤ c) : (a + b = c) = (a = c - b) := by
|
||||
have r := add_eq_add_le a 0 h
|
||||
simp only [Nat.zero_add] at r
|
||||
exact r
|
||||
|
||||
theorem eq_add_le {a : Nat} (b : Nat) {c : Nat} (h : c ≤ a) : (a = b + c) = (b = a - c) := by
|
||||
rw [@Eq.comm Nat a (b + c)]
|
||||
exact add_eq_le b h
|
||||
|
||||
/- Lemmas for lifting Eq proofs to beq -/
|
||||
|
||||
theorem beqEqOfEqEq {a b c d : Nat} (p : (a = b) = (c = d)) : (a == b) = (c == d) := by
|
||||
simp only [Bool.beq_eq_decide_eq, p]
|
||||
|
||||
theorem beqFalseOfEqFalse {a b : Nat} (p : (a = b) = False) : (a == b) = false := by
|
||||
simp [Bool.beq_eq_decide_eq, p]
|
||||
|
||||
theorem bneEqOfEqEq {a b c d : Nat} (p : (a = b) = (c = d)) : (a != b) = (c != d) := by
|
||||
simp only [bne, beqEqOfEqEq p]
|
||||
|
||||
theorem bneTrueOfEqFalse {a b : Nat} (p : (a = b) = False) : (a != b) = true := by
|
||||
simp [bne, beqFalseOfEqFalse p]
|
||||
|
||||
/- le proofs -/
|
||||
|
||||
theorem add_le_add_le (a c : Nat) {b d : Nat} (h : b ≤ d) : (a + b ≤ c + d) = (a ≤ c + (d - b)) := by
|
||||
rw [← Nat.add_sub_assoc h, Nat.le_sub_iff_add_le]
|
||||
exact Nat.le_trans h (le_add_left d c)
|
||||
|
||||
theorem add_le_add_ge (a c : Nat) {b d : Nat} (h : b ≥ d) : (a + b ≤ c + d) = (a + (b - d) ≤ c) := by
|
||||
rw [← Nat.add_sub_assoc h, Nat.sub_le_iff_le_add]
|
||||
|
||||
theorem add_le_le (a : Nat) {b c : Nat} (h : b ≤ c) : (a + b ≤ c) = (a ≤ c - b) := by
|
||||
have r := add_le_add_le a 0 h
|
||||
simp only [Nat.zero_add] at r
|
||||
exact r
|
||||
|
||||
theorem add_le_gt (a : Nat) {b c : Nat} (h : b > c) : (a + b ≤ c) = False :=
|
||||
eq_false (Nat.not_le_of_gt (Nat.lt_of_lt_of_le h (le_add_left b a)))
|
||||
|
||||
theorem le_add_le (a : Nat) {b c : Nat} (h : a ≤ c) : (a ≤ b + c) = True :=
|
||||
eq_true (Nat.le_trans h (le_add_left c b))
|
||||
|
||||
theorem le_add_ge (a : Nat) {b c : Nat} (h : a ≥ c) : (a ≤ b + c) = (a - c ≤ b) := by
|
||||
have r := add_le_add_ge 0 b h
|
||||
simp only [Nat.zero_add] at r
|
||||
exact r
|
||||
|
||||
end Nat.Simproc
|
||||
@@ -13,36 +13,29 @@ namespace Option
|
||||
deriving instance DecidableEq for Option
|
||||
deriving instance BEq for Option
|
||||
|
||||
/-- Lifts an optional value to any `Alternative`, sending `none` to `failure`. -/
|
||||
def getM [Alternative m] : Option α → m α
|
||||
def toMonad [Monad m] [Alternative m] : Option α → m α
|
||||
| none => failure
|
||||
| some a => pure a
|
||||
|
||||
@[deprecated getM] def toMonad [Monad m] [Alternative m] : Option α → m α :=
|
||||
getM
|
||||
@[inline] def toBool : Option α → Bool
|
||||
| some _ => true
|
||||
| none => false
|
||||
|
||||
/-- Returns `true` on `some x` and `false` on `none`. -/
|
||||
@[inline] def isSome : Option α → Bool
|
||||
| some _ => true
|
||||
| none => false
|
||||
|
||||
@[deprecated isSome, inline] def toBool : Option α → Bool := isSome
|
||||
|
||||
/-- Returns `true` on `none` and `false` on `some x`. -/
|
||||
@[inline] def isNone : Option α → Bool
|
||||
| some _ => false
|
||||
| none => true
|
||||
|
||||
/--
|
||||
`x?.isEqSome y` is equivalent to `x? == some y`, but avoids an allocation.
|
||||
-/
|
||||
@[inline] def isEqSome [BEq α] : Option α → α → Bool
|
||||
| some a, b => a == b
|
||||
| none, _ => false
|
||||
|
||||
@[inline] protected def bind : Option α → (α → Option β) → Option β
|
||||
| none, _ => none
|
||||
| some a, f => f a
|
||||
| some a, b => b a
|
||||
|
||||
/-- Runs `f` on `o`'s value, if any, and returns its result, or else returns `none`. -/
|
||||
@[inline] protected def bindM [Monad m] (f : α → m (Option β)) (o : Option α) : m (Option β) := do
|
||||
@@ -51,10 +44,6 @@ def getM [Alternative m] : Option α → m α
|
||||
else
|
||||
return none
|
||||
|
||||
/--
|
||||
Runs a monadic function `f` on an optional value.
|
||||
If the optional value is `none` the function is not called.
|
||||
-/
|
||||
@[inline] protected def mapM [Monad m] (f : α → m β) (o : Option α) : m (Option β) := do
|
||||
if let some a := o then
|
||||
return some (← f a)
|
||||
@@ -64,24 +53,18 @@ If the optional value is `none` the function is not called.
|
||||
theorem map_id : (Option.map id : Option α → Option α) = id :=
|
||||
funext (fun o => match o with | none => rfl | some _ => rfl)
|
||||
|
||||
/-- Keeps an optional value only if it satisfies the predicate `p`. -/
|
||||
@[always_inline, inline] protected def filter (p : α → Bool) : Option α → Option α
|
||||
| some a => if p a then some a else none
|
||||
| none => none
|
||||
|
||||
/-- Checks that an optional value satisfies a predicate `p` or is `none`. -/
|
||||
@[always_inline, inline] protected def all (p : α → Bool) : Option α → Bool
|
||||
| some a => p a
|
||||
| none => true
|
||||
|
||||
/-- Checks that an optional value is not `none` and the value satisfies a predicate `p`. -/
|
||||
@[always_inline, inline] protected def any (p : α → Bool) : Option α → Bool
|
||||
| some a => p a
|
||||
| none => false
|
||||
|
||||
/--
|
||||
Implementation of `OrElse`'s `<|>` syntax for `Option`.
|
||||
-/
|
||||
@[always_inline, macro_inline] protected def orElse : Option α → (Unit → Option α) → Option α
|
||||
| some a, _ => some a
|
||||
| none, b => b ()
|
||||
|
||||
@@ -114,18 +114,7 @@ by `cmp₂` to break the tie.
|
||||
@[inline] def compareLex (cmp₁ cmp₂ : α → β → Ordering) (a : α) (b : β) : Ordering :=
|
||||
(cmp₁ a b).then (cmp₂ a b)
|
||||
|
||||
/--
|
||||
`Ord α` provides a computable total order on `α`, in terms of the
|
||||
`compare : α → α → Ordering` function.
|
||||
|
||||
Typically instances will be transitive, reflexive, and antisymmetric,
|
||||
but this is not enforced by the typeclass.
|
||||
|
||||
There is a derive handler, so appending `deriving Ord` to an inductive type or structure
|
||||
will attempt to create an `Ord` instance.
|
||||
-/
|
||||
class Ord (α : Type u) where
|
||||
/-- Compare two elements in `α` using the comparator contained in an `[Ord α]` instance. -/
|
||||
compare : α → α → Ordering
|
||||
|
||||
export Ord (compare)
|
||||
@@ -182,13 +171,15 @@ instance [Ord α] : Ord (Option α) where
|
||||
|
||||
/-- The lexicographic order on pairs. -/
|
||||
def lexOrd [Ord α] [Ord β] : Ord (α × β) where
|
||||
compare := compareLex (compareOn (·.1)) (compareOn (·.2))
|
||||
compare p1 p2 := match compare p1.1 p2.1 with
|
||||
| .eq => compare p1.2 p2.2
|
||||
| o => o
|
||||
|
||||
def ltOfOrd [Ord α] : LT α where
|
||||
lt a b := compare a b = Ordering.lt
|
||||
lt a b := compare a b == Ordering.lt
|
||||
|
||||
instance [Ord α] : DecidableRel (@LT.lt α ltOfOrd) :=
|
||||
inferInstanceAs (DecidableRel (fun a b => compare a b = Ordering.lt))
|
||||
inferInstanceAs (DecidableRel (fun a b => compare a b == Ordering.lt))
|
||||
|
||||
def leOfOrd [Ord α] : LE α where
|
||||
le a b := (compare a b).isLE
|
||||
|
||||
@@ -13,24 +13,11 @@ open Sum Subtype Nat
|
||||
|
||||
open Std
|
||||
|
||||
/--
|
||||
A typeclass that specifies the standard way of turning values of some type into `Format`.
|
||||
|
||||
When rendered this `Format` should be as close as possible to something that can be parsed as the
|
||||
input value.
|
||||
-/
|
||||
class Repr (α : Type u) where
|
||||
/--
|
||||
Turn a value of type `α` into `Format` at a given precedence. The precedence value can be used
|
||||
to avoid parentheses if they are not necessary.
|
||||
-/
|
||||
reprPrec : α → Nat → Format
|
||||
|
||||
export Repr (reprPrec)
|
||||
|
||||
/--
|
||||
Turn `a` into `Format` using its `Repr` instance. The precedence level is initially set to 0.
|
||||
-/
|
||||
abbrev repr [Repr α] (a : α) : Format :=
|
||||
reprPrec a 0
|
||||
|
||||
@@ -116,11 +103,6 @@ instance {p : α → Prop} [Repr α] : Repr (Subtype p) where
|
||||
|
||||
namespace Nat
|
||||
|
||||
/-
|
||||
We have pure functions for calculating the decimal representation of a `Nat` (`toDigits`), but also
|
||||
a fast variant that handles small numbers (`USize`) via C code (`lean_string_of_usize`).
|
||||
-/
|
||||
|
||||
def digitChar (n : Nat) : Char :=
|
||||
if n = 0 then '0' else
|
||||
if n = 1 then '1' else
|
||||
@@ -151,20 +133,6 @@ def toDigitsCore (base : Nat) : Nat → Nat → List Char → List Char
|
||||
def toDigits (base : Nat) (n : Nat) : List Char :=
|
||||
toDigitsCore base (n+1) n []
|
||||
|
||||
@[extern "lean_string_of_usize"]
|
||||
protected def _root_.USize.repr (n : @& USize) : String :=
|
||||
(toDigits 10 n.toNat).asString
|
||||
|
||||
/-- We statically allocate and memoize reprs for small natural numbers. -/
|
||||
private def reprArray : Array String := Id.run do
|
||||
List.range 128 |>.map (·.toUSize.repr) |> Array.mk
|
||||
|
||||
private def reprFast (n : Nat) : String :=
|
||||
if h : n < 128 then Nat.reprArray.get ⟨n, h⟩ else
|
||||
if h : n < USize.size then (USize.ofNatCore n h).repr
|
||||
else (toDigits 10 n).asString
|
||||
|
||||
@[implemented_by reprFast]
|
||||
protected def repr (n : Nat) : String :=
|
||||
(toDigits 10 n).asString
|
||||
|
||||
@@ -194,32 +162,6 @@ def toSuperDigits (n : Nat) : List Char :=
|
||||
def toSuperscriptString (n : Nat) : String :=
|
||||
(toSuperDigits n).asString
|
||||
|
||||
def subDigitChar (n : Nat) : Char :=
|
||||
if n = 0 then '₀' else
|
||||
if n = 1 then '₁' else
|
||||
if n = 2 then '₂' else
|
||||
if n = 3 then '₃' else
|
||||
if n = 4 then '₄' else
|
||||
if n = 5 then '₅' else
|
||||
if n = 6 then '₆' else
|
||||
if n = 7 then '₇' else
|
||||
if n = 8 then '₈' else
|
||||
if n = 9 then '₉' else
|
||||
'*'
|
||||
|
||||
partial def toSubDigitsAux : Nat → List Char → List Char
|
||||
| n, ds =>
|
||||
let d := subDigitChar <| n % 10;
|
||||
let n' := n / 10;
|
||||
if n' = 0 then d::ds
|
||||
else toSubDigitsAux n' (d::ds)
|
||||
|
||||
def toSubDigits (n : Nat) : List Char :=
|
||||
toSubDigitsAux n []
|
||||
|
||||
def toSubscriptString (n : Nat) : String :=
|
||||
(toSubDigits n).asString
|
||||
|
||||
end Nat
|
||||
|
||||
instance : Repr Nat where
|
||||
|
||||
@@ -94,8 +94,7 @@ instance : Stream (Subarray α) α where
|
||||
next? s :=
|
||||
if h : s.start < s.stop then
|
||||
have : s.start + 1 ≤ s.stop := Nat.succ_le_of_lt h
|
||||
some (s.as.get ⟨s.start, Nat.lt_of_lt_of_le h s.stop_le_array_size⟩,
|
||||
{ s with start := s.start + 1, start_le_stop := this })
|
||||
some (s.as.get ⟨s.start, Nat.lt_of_lt_of_le h s.h₂⟩, { s with start := s.start + 1, h₁ := this })
|
||||
else
|
||||
none
|
||||
|
||||
|
||||
@@ -44,16 +44,6 @@ def append : String → (@& String) → String
|
||||
def toList (s : String) : List Char :=
|
||||
s.data
|
||||
|
||||
/-- Returns true if `p` is a valid UTF-8 position in the string `s`, meaning that `p ≤ s.endPos`
|
||||
and `p` lies on a UTF-8 character boundary. This has an O(1) implementation in the runtime. -/
|
||||
@[extern "lean_string_is_valid_pos"]
|
||||
def Pos.isValid (s : @&String) (p : @& Pos) : Bool :=
|
||||
go s.data 0
|
||||
where
|
||||
go : List Char → Pos → Bool
|
||||
| [], i => i = p
|
||||
| c::cs, i => if i = p then true else go cs (i + c)
|
||||
|
||||
def utf8GetAux : List Char → Pos → Pos → Char
|
||||
| [], _, _ => default
|
||||
| c::cs, i, p => if i = p then c else utf8GetAux cs (i + c) p
|
||||
@@ -255,21 +245,12 @@ termination_by s.endPos.1 - i.1
|
||||
@[specialize] def split (s : String) (p : Char → Bool) : List String :=
|
||||
splitAux s p 0 0 []
|
||||
|
||||
/--
|
||||
Auxiliary for `splitOn`. Preconditions:
|
||||
* `sep` is not empty
|
||||
* `b <= i` are indexes into `s`
|
||||
* `j` is an index into `sep`, and not at the end
|
||||
|
||||
It represents the state where we have currently parsed some split parts into `r` (in reverse order),
|
||||
`b` is the beginning of the string / the end of the previous match of `sep`, and the first `j` bytes
|
||||
of `sep` match the bytes `i-j .. i` of `s`.
|
||||
-/
|
||||
def splitOnAux (s sep : String) (b : Pos) (i : Pos) (j : Pos) (r : List String) : List String :=
|
||||
if s.atEnd i then
|
||||
if h : s.atEnd i then
|
||||
let r := (s.extract b i)::r
|
||||
r.reverse
|
||||
else
|
||||
have := Nat.sub_lt_sub_left (Nat.gt_of_not_le (mt decide_eq_true h)) (lt_next s _)
|
||||
if s.get i == sep.get j then
|
||||
let i := s.next i
|
||||
let j := sep.next j
|
||||
@@ -278,42 +259,9 @@ def splitOnAux (s sep : String) (b : Pos) (i : Pos) (j : Pos) (r : List String)
|
||||
else
|
||||
splitOnAux s sep b i j r
|
||||
else
|
||||
splitOnAux s sep b (s.next (i - j)) 0 r
|
||||
termination_by (s.endPos.1 - (i - j).1, sep.endPos.1 - j.1)
|
||||
decreasing_by
|
||||
all_goals simp_wf
|
||||
focus
|
||||
rename_i h _ _
|
||||
left; exact Nat.sub_lt_sub_left
|
||||
(Nat.lt_of_le_of_lt (Nat.sub_le ..) (Nat.gt_of_not_le (mt decide_eq_true h)))
|
||||
(Nat.lt_of_le_of_lt (Nat.sub_le ..) (lt_next s _))
|
||||
focus
|
||||
rename_i i₀ j₀ _ eq h'
|
||||
rw [show (s.next i₀ - sep.next j₀).1 = (i₀ - j₀).1 by
|
||||
show (_ + csize _) - (_ + csize _) = _
|
||||
rw [(beq_iff_eq ..).1 eq, Nat.add_sub_add_right]; rfl]
|
||||
right; exact Nat.sub_lt_sub_left
|
||||
(Nat.lt_of_le_of_lt (Nat.le_add_right ..) (Nat.gt_of_not_le (mt decide_eq_true h')))
|
||||
(lt_next sep _)
|
||||
focus
|
||||
rename_i h _
|
||||
left; exact Nat.sub_lt_sub_left
|
||||
(Nat.lt_of_le_of_lt (Nat.sub_le ..) (Nat.gt_of_not_le (mt decide_eq_true h)))
|
||||
(lt_next s _)
|
||||
splitOnAux s sep b (s.next i) 0 r
|
||||
termination_by s.endPos.1 - i.1
|
||||
|
||||
/--
|
||||
Splits a string `s` on occurrences of the separator `sep`. When `sep` is empty, it returns `[s]`;
|
||||
when `sep` occurs in overlapping patterns, the first match is taken. There will always be exactly
|
||||
`n+1` elements in the returned list if there were `n` nonoverlapping matches of `sep` in the string.
|
||||
The default separator is `" "`. The separators are not included in the returned substrings.
|
||||
|
||||
```
|
||||
"here is some text ".splitOn = ["here", "is", "some", "text", ""]
|
||||
"here is some text ".splitOn "some" = ["here is ", " text "]
|
||||
"here is some text ".splitOn "" = ["here is some text "]
|
||||
"ababacabac".splitOn "aba" = ["", "bac", "c"]
|
||||
```
|
||||
-/
|
||||
def splitOn (s : String) (sep : String := " ") : List String :=
|
||||
if sep == "" then [s] else splitOnAux s sep 0 0 0 []
|
||||
|
||||
|
||||
@@ -17,132 +17,32 @@ def toNat! (s : String) : Nat :=
|
||||
else
|
||||
panic! "Nat expected"
|
||||
|
||||
def utf8DecodeChar? (a : ByteArray) (i : Nat) : Option Char := do
|
||||
let c ← a[i]?
|
||||
if c &&& 0x80 == 0 then
|
||||
some ⟨c.toUInt32, .inl (Nat.lt_trans c.1.2 (by decide))⟩
|
||||
else if c &&& 0xe0 == 0xc0 then
|
||||
let c1 ← a[i+1]?
|
||||
guard (c1 &&& 0xc0 == 0x80)
|
||||
let r := ((c &&& 0x1f).toUInt32 <<< 6) ||| (c1 &&& 0x3f).toUInt32
|
||||
guard (0x80 ≤ r)
|
||||
-- TODO: Prove h from the definition of r once we have the necessary lemmas
|
||||
if h : r < 0xd800 then some ⟨r, .inl h⟩ else none
|
||||
else if c &&& 0xf0 == 0xe0 then
|
||||
let c1 ← a[i+1]?
|
||||
let c2 ← a[i+2]?
|
||||
guard (c1 &&& 0xc0 == 0x80 && c2 &&& 0xc0 == 0x80)
|
||||
let r :=
|
||||
((c &&& 0x0f).toUInt32 <<< 12) |||
|
||||
((c1 &&& 0x3f).toUInt32 <<< 6) |||
|
||||
(c2 &&& 0x3f).toUInt32
|
||||
guard (0x800 ≤ r)
|
||||
-- TODO: Prove `r < 0x110000` from the definition of r once we have the necessary lemmas
|
||||
if h : r < 0xd800 ∨ 0xdfff < r ∧ r < 0x110000 then some ⟨r, h⟩ else none
|
||||
else if c &&& 0xf8 == 0xf0 then
|
||||
let c1 ← a[i+1]?
|
||||
let c2 ← a[i+2]?
|
||||
let c3 ← a[i+3]?
|
||||
guard (c1 &&& 0xc0 == 0x80 && c2 &&& 0xc0 == 0x80 && c3 &&& 0xc0 == 0x80)
|
||||
let r :=
|
||||
((c &&& 0x07).toUInt32 <<< 18) |||
|
||||
((c1 &&& 0x3f).toUInt32 <<< 12) |||
|
||||
((c2 &&& 0x3f).toUInt32 <<< 6) |||
|
||||
(c3 &&& 0x3f).toUInt32
|
||||
if h : 0x10000 ≤ r ∧ r < 0x110000 then
|
||||
some ⟨r, .inr ⟨Nat.lt_of_lt_of_le (by decide) h.1, h.2⟩⟩
|
||||
else none
|
||||
else
|
||||
none
|
||||
/--
|
||||
Convert a [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoded `ByteArray` string to `String`.
|
||||
The result is unspecified if `a` is not properly UTF-8 encoded.
|
||||
-/
|
||||
@[extern "lean_string_from_utf8_unchecked"]
|
||||
opaque fromUTF8Unchecked (a : @& ByteArray) : String
|
||||
|
||||
/-- Returns true if the given byte array consists of valid UTF-8. -/
|
||||
@[extern "lean_string_validate_utf8"]
|
||||
def validateUTF8 (a : @& ByteArray) : Bool :=
|
||||
(loop 0).isSome
|
||||
where
|
||||
loop (i : Nat) : Option Unit := do
|
||||
if i < a.size then
|
||||
let c ← utf8DecodeChar? a i
|
||||
loop (i + csize c)
|
||||
else pure ()
|
||||
termination_by a.size - i
|
||||
decreasing_by exact Nat.sub_lt_sub_left ‹_› (Nat.lt_add_of_pos_right (one_le_csize c))
|
||||
|
||||
/-- Converts a [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoded `ByteArray` string to `String`. -/
|
||||
@[extern "lean_string_from_utf8"]
|
||||
def fromUTF8 (a : @& ByteArray) (h : validateUTF8 a) : String :=
|
||||
loop 0 ""
|
||||
where
|
||||
loop (i : Nat) (acc : String) : String :=
|
||||
if i < a.size then
|
||||
let c := (utf8DecodeChar? a i).getD default
|
||||
loop (i + csize c) (acc.push c)
|
||||
else acc
|
||||
termination_by a.size - i
|
||||
decreasing_by exact Nat.sub_lt_sub_left ‹_› (Nat.lt_add_of_pos_right (one_le_csize c))
|
||||
|
||||
/-- Converts a [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoded `ByteArray` string to `String`,
|
||||
or returns `none` if `a` is not properly UTF-8 encoded. -/
|
||||
@[inline] def fromUTF8? (a : ByteArray) : Option String :=
|
||||
if h : validateUTF8 a then fromUTF8 a h else none
|
||||
|
||||
/-- Converts a [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoded `ByteArray` string to `String`,
|
||||
or panics if `a` is not properly UTF-8 encoded. -/
|
||||
@[inline] def fromUTF8! (a : ByteArray) : String :=
|
||||
if h : validateUTF8 a then fromUTF8 a h else panic! "invalid UTF-8 string"
|
||||
|
||||
def utf8EncodeChar (c : Char) : List UInt8 :=
|
||||
let v := c.val
|
||||
if v ≤ 0x7f then
|
||||
[v.toUInt8]
|
||||
else if v ≤ 0x7ff then
|
||||
[(v >>> 6).toUInt8 &&& 0x1f ||| 0xc0,
|
||||
v.toUInt8 &&& 0x3f ||| 0x80]
|
||||
else if v ≤ 0xffff then
|
||||
[(v >>> 12).toUInt8 &&& 0x0f ||| 0xe0,
|
||||
(v >>> 6).toUInt8 &&& 0x3f ||| 0x80,
|
||||
v.toUInt8 &&& 0x3f ||| 0x80]
|
||||
else
|
||||
[(v >>> 18).toUInt8 &&& 0x07 ||| 0xf0,
|
||||
(v >>> 12).toUInt8 &&& 0x3f ||| 0x80,
|
||||
(v >>> 6).toUInt8 &&& 0x3f ||| 0x80,
|
||||
v.toUInt8 &&& 0x3f ||| 0x80]
|
||||
|
||||
@[simp] theorem length_utf8EncodeChar (c : Char) : (utf8EncodeChar c).length = csize c := by
|
||||
simp [csize, utf8EncodeChar, Char.utf8Size]
|
||||
cases Decidable.em (c.val ≤ 0x7f) <;> simp [*]
|
||||
cases Decidable.em (c.val ≤ 0x7ff) <;> simp [*]
|
||||
cases Decidable.em (c.val ≤ 0xffff) <;> simp [*]
|
||||
|
||||
/-- Converts the given `String` to a [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoded byte array. -/
|
||||
/-- Convert the given `String` to a [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoded byte array. -/
|
||||
@[extern "lean_string_to_utf8"]
|
||||
def toUTF8 (a : @& String) : ByteArray :=
|
||||
⟨⟨a.data.bind utf8EncodeChar⟩⟩
|
||||
|
||||
@[simp] theorem size_toUTF8 (s : String) : s.toUTF8.size = s.utf8ByteSize := by
|
||||
simp [toUTF8, ByteArray.size, Array.size, utf8ByteSize, List.bind]
|
||||
induction s.data <;> simp [List.map, List.join, utf8ByteSize.go, Nat.add_comm, *]
|
||||
opaque toUTF8 (a : @& String) : ByteArray
|
||||
|
||||
/-- Accesses a byte in the UTF-8 encoding of the `String`. O(1) -/
|
||||
@[extern "lean_string_get_byte_fast"]
|
||||
def getUtf8Byte (s : @& String) (n : Nat) (h : n < s.utf8ByteSize) : UInt8 :=
|
||||
(toUTF8 s).get ⟨n, size_toUTF8 _ ▸ h⟩
|
||||
opaque getUtf8Byte (s : @& String) (n : Nat) (h : n < s.utf8ByteSize) : UInt8
|
||||
|
||||
theorem Iterator.sizeOf_next_lt_of_hasNext (i : String.Iterator) (h : i.hasNext) : sizeOf i.next < sizeOf i := by
|
||||
cases i; rename_i s pos; simp [Iterator.next, Iterator.sizeOf_eq]; simp [Iterator.hasNext] at h
|
||||
exact Nat.sub_lt_sub_left h (String.lt_next s pos)
|
||||
|
||||
macro_rules
|
||||
| `(tactic| decreasing_trivial) =>
|
||||
`(tactic| with_reducible apply String.Iterator.sizeOf_next_lt_of_hasNext; assumption)
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| apply String.Iterator.sizeOf_next_lt_of_hasNext; assumption)
|
||||
|
||||
theorem Iterator.sizeOf_next_lt_of_atEnd (i : String.Iterator) (h : ¬ i.atEnd = true) : sizeOf i.next < sizeOf i :=
|
||||
have h : i.hasNext := decide_eq_true <| Nat.gt_of_not_le <| mt decide_eq_true h
|
||||
sizeOf_next_lt_of_hasNext i h
|
||||
|
||||
macro_rules
|
||||
| `(tactic| decreasing_trivial) =>
|
||||
`(tactic| with_reducible apply String.Iterator.sizeOf_next_lt_of_atEnd; assumption)
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| apply String.Iterator.sizeOf_next_lt_of_atEnd; assumption)
|
||||
|
||||
namespace Iterator
|
||||
|
||||
@@ -162,40 +62,4 @@ namespace Iterator
|
||||
|
||||
end Iterator
|
||||
|
||||
private def findLeadingSpacesSize (s : String) : Nat :=
|
||||
let it := s.iter
|
||||
let it := it.find (· == '\n') |>.next
|
||||
consumeSpaces it 0 s.length
|
||||
where
|
||||
consumeSpaces (it : String.Iterator) (curr min : Nat) : Nat :=
|
||||
if it.atEnd then min
|
||||
else if it.curr == ' ' || it.curr == '\t' then consumeSpaces it.next (curr + 1) min
|
||||
else if it.curr == '\n' then findNextLine it.next min
|
||||
else findNextLine it.next (Nat.min curr min)
|
||||
findNextLine (it : String.Iterator) (min : Nat) : Nat :=
|
||||
if it.atEnd then min
|
||||
else if it.curr == '\n' then consumeSpaces it.next 0 min
|
||||
else findNextLine it.next min
|
||||
|
||||
private def removeNumLeadingSpaces (n : Nat) (s : String) : String :=
|
||||
consumeSpaces n s.iter ""
|
||||
where
|
||||
consumeSpaces (n : Nat) (it : String.Iterator) (r : String) : String :=
|
||||
match n with
|
||||
| 0 => saveLine it r
|
||||
| n+1 =>
|
||||
if it.atEnd then r
|
||||
else if it.curr == ' ' || it.curr == '\t' then consumeSpaces n it.next r
|
||||
else saveLine it r
|
||||
termination_by (it, 1)
|
||||
saveLine (it : String.Iterator) (r : String) : String :=
|
||||
if it.atEnd then r
|
||||
else if it.curr == '\n' then consumeSpaces n it.next (r.push '\n')
|
||||
else saveLine it.next (r.push it.curr)
|
||||
termination_by (it, 0)
|
||||
|
||||
def removeLeadingSpaces (s : String) : String :=
|
||||
let n := findLeadingSpacesSize s
|
||||
if n == 0 then s else removeNumLeadingSpaces n s
|
||||
|
||||
end String
|
||||
|
||||
@@ -103,7 +103,7 @@ def UInt16.shiftLeft (a b : UInt16) : UInt16 := ⟨a.val <<< (modn b 16).val⟩
|
||||
@[extern "lean_uint16_to_uint8"]
|
||||
def UInt16.toUInt8 (a : UInt16) : UInt8 := a.toNat.toUInt8
|
||||
@[extern "lean_uint8_to_uint16"]
|
||||
def UInt8.toUInt16 (a : UInt8) : UInt16 := ⟨a.val, Nat.lt_trans a.1.2 (by decide)⟩
|
||||
def UInt8.toUInt16 (a : UInt8) : UInt16 := a.toNat.toUInt16
|
||||
@[extern "lean_uint16_shift_right"]
|
||||
def UInt16.shiftRight (a b : UInt16) : UInt16 := ⟨a.val >>> (modn b 16).val⟩
|
||||
def UInt16.lt (a b : UInt16) : Prop := a.val < b.val
|
||||
@@ -186,9 +186,9 @@ def UInt32.toUInt8 (a : UInt32) : UInt8 := a.toNat.toUInt8
|
||||
@[extern "lean_uint32_to_uint16"]
|
||||
def UInt32.toUInt16 (a : UInt32) : UInt16 := a.toNat.toUInt16
|
||||
@[extern "lean_uint8_to_uint32"]
|
||||
def UInt8.toUInt32 (a : UInt8) : UInt32 := ⟨a.val, Nat.lt_trans a.1.2 (by decide)⟩
|
||||
def UInt8.toUInt32 (a : UInt8) : UInt32 := a.toNat.toUInt32
|
||||
@[extern "lean_uint16_to_uint32"]
|
||||
def UInt16.toUInt32 (a : UInt16) : UInt32 := ⟨a.val, Nat.lt_trans a.1.2 (by decide)⟩
|
||||
def UInt16.toUInt32 (a : UInt16) : UInt32 := a.toNat.toUInt32
|
||||
|
||||
instance UInt32.instOfNat : OfNat UInt32 n := ⟨UInt32.ofNat n⟩
|
||||
instance : Add UInt32 := ⟨UInt32.add⟩
|
||||
@@ -244,11 +244,11 @@ def UInt64.toUInt16 (a : UInt64) : UInt16 := a.toNat.toUInt16
|
||||
@[extern "lean_uint64_to_uint32"]
|
||||
def UInt64.toUInt32 (a : UInt64) : UInt32 := a.toNat.toUInt32
|
||||
@[extern "lean_uint8_to_uint64"]
|
||||
def UInt8.toUInt64 (a : UInt8) : UInt64 := ⟨a.val, Nat.lt_trans a.1.2 (by decide)⟩
|
||||
def UInt8.toUInt64 (a : UInt8) : UInt64 := a.toNat.toUInt64
|
||||
@[extern "lean_uint16_to_uint64"]
|
||||
def UInt16.toUInt64 (a : UInt16) : UInt64 := ⟨a.val, Nat.lt_trans a.1.2 (by decide)⟩
|
||||
def UInt16.toUInt64 (a : UInt16) : UInt64 := a.toNat.toUInt64
|
||||
@[extern "lean_uint32_to_uint64"]
|
||||
def UInt32.toUInt64 (a : UInt32) : UInt64 := ⟨a.val, Nat.lt_trans a.1.2 (by decide)⟩
|
||||
def UInt32.toUInt64 (a : UInt32) : UInt64 := a.toNat.toUInt64
|
||||
|
||||
instance UInt64.instOfNat : OfNat UInt64 n := ⟨UInt64.ofNat n⟩
|
||||
instance : Add UInt64 := ⟨UInt64.add⟩
|
||||
@@ -321,7 +321,7 @@ def USize.shiftLeft (a b : USize) : USize := ⟨a.val <<< (modn b System.Platfor
|
||||
@[extern "lean_usize_shift_right"]
|
||||
def USize.shiftRight (a b : USize) : USize := ⟨a.val >>> (modn b System.Platform.numBits).val⟩
|
||||
@[extern "lean_uint32_to_usize"]
|
||||
def UInt32.toUSize (a : UInt32) : USize := USize.ofNat32 a.val a.1.2
|
||||
def UInt32.toUSize (a : UInt32) : USize := a.toNat.toUSize
|
||||
@[extern "lean_usize_to_uint32"]
|
||||
def USize.toUInt32 (a : USize) : UInt32 := a.toNat.toUInt32
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Gabriel Ebner, Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.ToString.Macro
|
||||
import Init.TacticsExtra
|
||||
import Init.RCases
|
||||
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura, Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Util
|
||||
|
||||
@[never_extract]
|
||||
private def outOfBounds [Inhabited α] : α :=
|
||||
panic! "index out of bounds"
|
||||
|
||||
/--
|
||||
The class `GetElem coll idx elem valid` implements the `xs[i]` notation.
|
||||
Given `xs[i]` with `xs : coll` and `i : idx`, Lean looks for an instance of
|
||||
`GetElem coll idx elem valid` and uses this to infer the type of return
|
||||
value `elem` and side conditions `valid` required to ensure `xs[i]` yields
|
||||
a valid value of type `elem`.
|
||||
|
||||
For example, the instance for arrays looks like
|
||||
`GetElem (Array α) Nat α (fun xs i => i < xs.size)`.
|
||||
|
||||
The proof side-condition `valid xs i` is automatically dispatched by the
|
||||
`get_elem_tactic` tactic, which can be extended by adding more clauses to
|
||||
`get_elem_tactic_trivial`.
|
||||
-/
|
||||
class GetElem (coll : Type u) (idx : Type v) (elem : outParam (Type w))
|
||||
(valid : outParam (coll → idx → Prop)) where
|
||||
/--
|
||||
The syntax `arr[i]` gets the `i`'th element of the collection `arr`. If there
|
||||
are proof side conditions to the application, they will be automatically
|
||||
inferred by the `get_elem_tactic` tactic.
|
||||
|
||||
The actual behavior of this class is type-dependent, but here are some
|
||||
important implementations:
|
||||
* `arr[i] : α` where `arr : Array α` and `i : Nat` or `i : USize`: does array
|
||||
indexing with no bounds check and a proof side goal `i < arr.size`.
|
||||
* `l[i] : α` where `l : List α` and `i : Nat`: index into a list, with proof
|
||||
side goal `i < l.length`.
|
||||
* `stx[i] : Syntax` where `stx : Syntax` and `i : Nat`: get a syntax argument,
|
||||
no side goal (returns `.missing` out of range)
|
||||
|
||||
There are other variations on this syntax:
|
||||
* `arr[i]!` is syntax for `getElem! arr i` which should panic and return
|
||||
`default : α` if the index is not valid.
|
||||
* `arr[i]?` is syntax for `getElem?` which should return `none` if the index
|
||||
is not valid.
|
||||
* `arr[i]'h` is syntax for `getElem arr i h` with `h` an explicit proof the
|
||||
index is valid.
|
||||
-/
|
||||
getElem (xs : coll) (i : idx) (h : valid xs i) : elem
|
||||
|
||||
getElem? (xs : coll) (i : idx) [Decidable (valid xs i)] : Option elem :=
|
||||
if h : _ then some (getElem xs i h) else none
|
||||
|
||||
getElem! [Inhabited elem] (xs : coll) (i : idx) [Decidable (valid xs i)] : elem :=
|
||||
match getElem? xs i with | some e => e | none => outOfBounds
|
||||
|
||||
export GetElem (getElem getElem! getElem?)
|
||||
|
||||
@[inherit_doc getElem]
|
||||
syntax:max term noWs "[" withoutPosition(term) "]" : term
|
||||
macro_rules | `($x[$i]) => `(getElem $x $i (by get_elem_tactic))
|
||||
|
||||
@[inherit_doc getElem]
|
||||
syntax term noWs "[" withoutPosition(term) "]'" term:max : term
|
||||
macro_rules | `($x[$i]'$h) => `(getElem $x $i $h)
|
||||
|
||||
/--
|
||||
The syntax `arr[i]?` gets the `i`'th element of the collection `arr` or
|
||||
returns `none` if `i` is out of bounds.
|
||||
-/
|
||||
macro:max x:term noWs "[" i:term "]" noWs "?" : term => `(getElem? $x $i)
|
||||
|
||||
/--
|
||||
The syntax `arr[i]!` gets the `i`'th element of the collection `arr` and
|
||||
panics `i` is out of bounds.
|
||||
-/
|
||||
macro:max x:term noWs "[" i:term "]" noWs "!" : term => `(getElem! $x $i)
|
||||
|
||||
class LawfulGetElem (cont : Type u) (idx : Type v) (elem : outParam (Type w))
|
||||
(dom : outParam (cont → idx → Prop)) [ge : GetElem cont idx elem dom] : Prop where
|
||||
|
||||
getElem?_def (c : cont) (i : idx) [Decidable (dom c i)] :
|
||||
c[i]? = if h : dom c i then some (c[i]'h) else none := by intros; eq_refl
|
||||
getElem!_def [Inhabited elem] (c : cont) (i : idx) [Decidable (dom c i)] :
|
||||
c[i]! = match c[i]? with | some e => e | none => default := by intros; eq_refl
|
||||
|
||||
export LawfulGetElem (getElem?_def getElem!_def)
|
||||
|
||||
theorem getElem?_pos [GetElem cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
(c : cont) (i : idx) (h : dom c i) [Decidable (dom c i)] : c[i]? = some (c[i]'h) := by
|
||||
rw [getElem?_def]
|
||||
exact dif_pos h
|
||||
|
||||
theorem getElem?_neg [GetElem cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
(c : cont) (i : idx) (h : ¬dom c i) [Decidable (dom c i)] : c[i]? = none := by
|
||||
rw [getElem?_def]
|
||||
exact dif_neg h
|
||||
|
||||
theorem getElem!_pos [GetElem cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
[Inhabited elem] (c : cont) (i : idx) (h : dom c i) [Decidable (dom c i)] :
|
||||
c[i]! = c[i]'h := by
|
||||
simp only [getElem!_def, getElem?_def, h]
|
||||
|
||||
theorem getElem!_neg [GetElem cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
[Inhabited elem] (c : cont) (i : idx) (h : ¬dom c i) [Decidable (dom c i)] : c[i]! = default := by
|
||||
simp only [getElem!_def, getElem?_def, h]
|
||||
|
||||
namespace Fin
|
||||
|
||||
instance instGetElemFinVal [GetElem cont Nat elem dom] : GetElem cont (Fin n) elem fun xs i => dom xs i where
|
||||
getElem xs i h := getElem xs i.1 h
|
||||
getElem? xs i := getElem? xs i.val
|
||||
getElem! xs i := getElem! xs i.val
|
||||
|
||||
instance [GetElem cont Nat elem dom] [h : LawfulGetElem cont Nat elem dom] :
|
||||
LawfulGetElem cont (Fin n) elem fun xs i => dom xs i where
|
||||
|
||||
getElem?_def _c _i _d := h.getElem?_def ..
|
||||
getElem!_def _c _i _d := h.getElem!_def ..
|
||||
|
||||
@[simp] theorem getElem_fin [GetElem Cont Nat Elem Dom] (a : Cont) (i : Fin n) (h : Dom a i) :
|
||||
a[i] = a[i.1] := rfl
|
||||
|
||||
@[simp] theorem getElem?_fin [h : GetElem Cont Nat Elem Dom] (a : Cont) (i : Fin n)
|
||||
[Decidable (Dom a i)] : a[i]? = a[i.1]? := by rfl
|
||||
|
||||
@[simp] theorem getElem!_fin [GetElem Cont Nat Elem Dom] (a : Cont) (i : Fin n)
|
||||
[Decidable (Dom a i)] [Inhabited Elem] : a[i]! = a[i.1]! := rfl
|
||||
|
||||
macro_rules
|
||||
| `(tactic| get_elem_tactic_trivial) => `(tactic| apply Fin.val_lt_of_le; get_elem_tactic_trivial; done)
|
||||
|
||||
end Fin
|
||||
|
||||
namespace List
|
||||
|
||||
instance : GetElem (List α) Nat α fun as i => i < as.length where
|
||||
getElem as i h := as.get ⟨i, h⟩
|
||||
|
||||
instance : LawfulGetElem (List α) Nat α fun as i => i < as.length where
|
||||
|
||||
@[simp] theorem cons_getElem_zero (a : α) (as : List α) (h : 0 < (a :: as).length) : getElem (a :: as) 0 h = a := by
|
||||
rfl
|
||||
|
||||
@[simp] theorem cons_getElem_succ (a : α) (as : List α) (i : Nat) (h : i + 1 < (a :: as).length) : getElem (a :: as) (i+1) h = getElem as i (Nat.lt_of_succ_lt_succ h) := by
|
||||
rfl
|
||||
|
||||
theorem get_drop_eq_drop (as : List α) (i : Nat) (h : i < as.length) : as[i] :: as.drop (i+1) = as.drop i :=
|
||||
match as, i with
|
||||
| _::_, 0 => rfl
|
||||
| _::_, i+1 => get_drop_eq_drop _ i _
|
||||
|
||||
end List
|
||||
|
||||
namespace Array
|
||||
|
||||
instance : GetElem (Array α) Nat α fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
|
||||
instance : LawfulGetElem (Array α) Nat α fun xs i => i < xs.size where
|
||||
|
||||
end Array
|
||||
|
||||
namespace Lean.Syntax
|
||||
|
||||
instance : GetElem Syntax Nat Syntax fun _ _ => True where
|
||||
getElem stx i _ := stx.getArg i
|
||||
|
||||
instance : LawfulGetElem Syntax Nat Syntax fun _ _ => True where
|
||||
|
||||
end Lean.Syntax
|
||||
@@ -1,18 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
|
||||
Extra notation that depends on Init/Meta
|
||||
-/
|
||||
|
||||
prelude
|
||||
import Init.Data.ToString.Macro
|
||||
import Init.Meta
|
||||
|
||||
namespace Lean
|
||||
|
||||
macro "Macro.trace[" id:ident "]" s:interpolatedStr(term) : term =>
|
||||
`(Macro.trace $(quote id.getId.eraseMacroScopes) (s! $s))
|
||||
|
||||
end Lean
|
||||
@@ -9,6 +9,7 @@ prelude
|
||||
import Init.MetaTypes
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.Option.BasicAux
|
||||
import Init.Data.String.Extra
|
||||
|
||||
namespace Lean
|
||||
|
||||
@@ -104,6 +105,43 @@ def idBeginEscape := '«'
|
||||
def idEndEscape := '»'
|
||||
def isIdBeginEscape (c : Char) : Bool := c = idBeginEscape
|
||||
def isIdEndEscape (c : Char) : Bool := c = idEndEscape
|
||||
|
||||
private def findLeadingSpacesSize (s : String) : Nat :=
|
||||
let it := s.iter
|
||||
let it := it.find (· == '\n') |>.next
|
||||
consumeSpaces it 0 s.length
|
||||
where
|
||||
consumeSpaces (it : String.Iterator) (curr min : Nat) : Nat :=
|
||||
if it.atEnd then min
|
||||
else if it.curr == ' ' || it.curr == '\t' then consumeSpaces it.next (curr + 1) min
|
||||
else if it.curr == '\n' then findNextLine it.next min
|
||||
else findNextLine it.next (Nat.min curr min)
|
||||
findNextLine (it : String.Iterator) (min : Nat) : Nat :=
|
||||
if it.atEnd then min
|
||||
else if it.curr == '\n' then consumeSpaces it.next 0 min
|
||||
else findNextLine it.next min
|
||||
|
||||
private def removeNumLeadingSpaces (n : Nat) (s : String) : String :=
|
||||
consumeSpaces n s.iter ""
|
||||
where
|
||||
consumeSpaces (n : Nat) (it : String.Iterator) (r : String) : String :=
|
||||
match n with
|
||||
| 0 => saveLine it r
|
||||
| n+1 =>
|
||||
if it.atEnd then r
|
||||
else if it.curr == ' ' || it.curr == '\t' then consumeSpaces n it.next r
|
||||
else saveLine it r
|
||||
termination_by (it, 1)
|
||||
saveLine (it : String.Iterator) (r : String) : String :=
|
||||
if it.atEnd then r
|
||||
else if it.curr == '\n' then consumeSpaces n it.next (r.push '\n')
|
||||
else saveLine it.next (r.push it.curr)
|
||||
termination_by (it, 0)
|
||||
|
||||
def removeLeadingSpaces (s : String) : String :=
|
||||
let n := findLeadingSpacesSize s
|
||||
if n == 0 then s else removeNumLeadingSpaces n s
|
||||
|
||||
namespace Name
|
||||
|
||||
def getRoot : Name → Name
|
||||
@@ -1057,7 +1095,6 @@ where
|
||||
else
|
||||
Syntax.mkCApp (Name.mkStr2 "Array" ("mkArray" ++ toString xs.size)) args
|
||||
termination_by xs.size - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
|
||||
instance [Quote α `term] : Quote (Array α) `term where
|
||||
quote := quoteArray
|
||||
@@ -1195,6 +1232,14 @@ instance : Coe (Lean.Term) (Lean.TSyntax `Lean.Parser.Term.funBinder) where
|
||||
|
||||
end Lean.Syntax
|
||||
|
||||
set_option linter.unusedVariables.funArgs false in
|
||||
/--
|
||||
Gadget for automatic parameter support. This is similar to the `optParam` gadget, but it uses
|
||||
the given tactic.
|
||||
Like `optParam`, this gadget only affects elaboration.
|
||||
For example, the tactic will *not* be invoked during type class resolution. -/
|
||||
abbrev autoParam.{u} (α : Sort u) (tactic : Lean.Syntax) : Sort u := α
|
||||
|
||||
/-! # Helper functions for manipulating interpolated strings -/
|
||||
|
||||
namespace Lean.Syntax
|
||||
|
||||
@@ -68,106 +68,38 @@ namespace Simp
|
||||
|
||||
def defaultMaxSteps := 100000
|
||||
|
||||
/--
|
||||
The configuration for `simp`.
|
||||
Passed to `simp` using, for example, the `simp (config := {contextual := true})` syntax.
|
||||
|
||||
See also `Lean.Meta.Simp.neutralConfig`.
|
||||
-/
|
||||
structure Config where
|
||||
/--
|
||||
The maximum number of subexpressions to visit when performing simplification.
|
||||
The default is 100000.
|
||||
-/
|
||||
maxSteps : Nat := defaultMaxSteps
|
||||
/--
|
||||
When simp discharges side conditions for conditional lemmas, it can recursively apply simplification.
|
||||
The `maxDischargeDepth` (default: 2) is the maximum recursion depth when recursively applying simplification to side conditions.
|
||||
-/
|
||||
maxDischargeDepth : Nat := 2
|
||||
/--
|
||||
When `contextual` is true (default: `false`) and simplification encounters an implication `p → q`
|
||||
it includes `p` as an additional simp lemma when simplifying `q`.
|
||||
-/
|
||||
contextual : Bool := false
|
||||
/--
|
||||
When true (default: `true`) then the simplifier caches the result of simplifying each subexpression, if possible.
|
||||
-/
|
||||
memoize : Bool := true
|
||||
/--
|
||||
When `singlePass` is `true` (default: `false`), the simplifier runs through a single round of simplification,
|
||||
which consists of running pre-methods, recursing using congruence lemmas, and then running post-methods.
|
||||
Otherwise, when it is `false`, it iteratively applies this simplification procedure.
|
||||
-/
|
||||
singlePass : Bool := false
|
||||
/--
|
||||
When `true` (default: `true`), performs zeta reduction of let expressions.
|
||||
That is, `let x := v; e[x]` reduces to `e[v]`.
|
||||
See also `zetaDelta`.
|
||||
-/
|
||||
/-- `let x := v; e[x]` reduces to `e[v]`. -/
|
||||
zeta : Bool := true
|
||||
/--
|
||||
When `true` (default: `true`), performs beta reduction of applications of `fun` expressions.
|
||||
That is, `(fun x => e[x]) v` reduces to `e[v]`.
|
||||
-/
|
||||
beta : Bool := true
|
||||
/--
|
||||
TODO (currently unimplemented). When `true` (default: `true`), performs eta reduction for `fun` expressions.
|
||||
That is, `(fun x => f x)` reduces to `f`.
|
||||
-/
|
||||
eta : Bool := true
|
||||
/--
|
||||
Configures how to determine definitional equality between two structure instances.
|
||||
See documentation for `Lean.Meta.EtaStructMode`.
|
||||
-/
|
||||
etaStruct : EtaStructMode := .all
|
||||
/--
|
||||
When `true` (default: `true`), reduces `match` expressions applied to constructors.
|
||||
-/
|
||||
iota : Bool := true
|
||||
/--
|
||||
When `true` (default: `true`), reduces projections of structure constructors.
|
||||
-/
|
||||
proj : Bool := true
|
||||
/--
|
||||
When `true` (default: `false`), rewrites a proposition `p` to `True` or `False` by inferring
|
||||
a `Decidable p` instance and reducing it.
|
||||
-/
|
||||
decide : Bool := false
|
||||
/-- When `true` (default: `false`), simplifies simple arithmetic expressions. -/
|
||||
arith : Bool := false
|
||||
/--
|
||||
When `true` (default: `false`), unfolds definitions.
|
||||
This can be enabled using the `simp!` syntax.
|
||||
-/
|
||||
autoUnfold : Bool := false
|
||||
/--
|
||||
When `true` (default: `true`) then switches to `dsimp` on dependent arguments
|
||||
if there is no congruence theorem that would allow `simp` to visit them.
|
||||
When `dsimp` is `false`, then the argument is not visited.
|
||||
If `dsimp := true`, then switches to `dsimp` on dependent arguments where there is no congruence theorem that allows
|
||||
`simp` to visit them. If `dsimp := false`, then argument is not visited.
|
||||
-/
|
||||
dsimp : Bool := true
|
||||
/--
|
||||
If `failIfUnchanged` is `true` (default: `true`), then calls to `simp`, `dsimp`, or `simp_all`
|
||||
will fail if they do not make progress.
|
||||
-/
|
||||
/-- If `failIfUnchanged := true`, then calls to `simp`, `dsimp`, or `simp_all`
|
||||
will fail if they do not make progress. -/
|
||||
failIfUnchanged : Bool := true
|
||||
/--
|
||||
If `ground` is `true` (default: `false`), then ground terms are reduced.
|
||||
A term is ground when it does not contain free or meta variables.
|
||||
Reduction is interrupted at a function application `f ...` if `f` is marked to not be unfolded.
|
||||
Ground term reduction applies `@[seval]` lemmas.
|
||||
-/
|
||||
/-- If `ground := true`, then ground terms are reduced. A term is ground when
|
||||
it does not contain free or meta variables. Reduction is interrupted at a function application `f ...`
|
||||
if `f` is marked to not be unfolded. -/
|
||||
ground : Bool := false
|
||||
/--
|
||||
If `unfoldPartialApp` is `true` (default: `false`), then calls to `simp`, `dsimp`, or `simp_all`
|
||||
will unfold even partial applications of `f` when we request `f` to be unfolded.
|
||||
-/
|
||||
/-- If `unfoldPartialApp := true`, then calls to `simp`, `dsimp`, or `simp_all`
|
||||
will unfold even partial applications of `f` when we request `f` to be unfolded. -/
|
||||
unfoldPartialApp : Bool := false
|
||||
/--
|
||||
When `true` (default: `false`), local definitions are unfolded.
|
||||
That is, given a local context containing entry `x : t := e`, the free variable `x` reduces to `e`.
|
||||
-/
|
||||
/-- Given a local context containing entry `x : t := e`, free variable `x` reduces to `e`. -/
|
||||
zetaDelta : Bool := false
|
||||
deriving Inhabited, BEq
|
||||
|
||||
@@ -175,9 +107,6 @@ structure Config where
|
||||
structure ConfigCtx extends Config where
|
||||
contextual := true
|
||||
|
||||
/--
|
||||
A neutral configuration for `simp`, turning off all reductions and other built-in simplifications.
|
||||
-/
|
||||
def neutralConfig : Simp.Config := {
|
||||
zeta := false
|
||||
beta := false
|
||||
|
||||
@@ -296,7 +296,7 @@ macro_rules | `($x - $y) => `(binop% HSub.hSub $x $y)
|
||||
macro_rules | `($x * $y) => `(binop% HMul.hMul $x $y)
|
||||
macro_rules | `($x / $y) => `(binop% HDiv.hDiv $x $y)
|
||||
macro_rules | `($x % $y) => `(binop% HMod.hMod $x $y)
|
||||
-- exponentiation should be considered a right action (#2854)
|
||||
-- exponentiation should be considered a right action (#2220)
|
||||
macro_rules | `($x ^ $y) => `(rightact% HPow.hPow $x $y)
|
||||
macro_rules | `($x ++ $y) => `(binop% HAppend.hAppend $x $y)
|
||||
macro_rules | `(- $x) => `(unop% Neg.neg $x)
|
||||
@@ -492,12 +492,9 @@ The attribute `@[deprecated]` on a declaration indicates that the declaration
|
||||
is discouraged for use in new code, and/or should be migrated away from in
|
||||
existing code. It may be removed in a future version of the library.
|
||||
|
||||
* `@[deprecated myBetterDef]` means that `myBetterDef` is the suggested replacement.
|
||||
* `@[deprecated myBetterDef "use myBetterDef instead"]` allows customizing the deprecation message.
|
||||
* `@[deprecated (since := "2024-04-21")]` records when the deprecation was first applied.
|
||||
`@[deprecated myBetterDef]` means that `myBetterDef` is the suggested replacement.
|
||||
-/
|
||||
syntax (name := deprecated) "deprecated" (ppSpace ident)? (ppSpace str)?
|
||||
(" (" &"since" " := " str ")")? : attr
|
||||
syntax (name := deprecated) "deprecated" (ppSpace ident)? : attr
|
||||
|
||||
/--
|
||||
The `@[coe]` attribute on a function (which should also appear in a
|
||||
@@ -555,52 +552,15 @@ except that it doesn't print an empty diagnostic.
|
||||
-/
|
||||
syntax (name := runMeta) "run_meta " doSeq : command
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
syntax guardMsgsFilterSeverity := &"info" <|> &"warning" <|> &"error" <|> &"all"
|
||||
/-- Element that can be part of a `#guard_msgs` specification. -/
|
||||
syntax guardMsgsSpecElt := &"drop"? (&"info" <|> &"warning" <|> &"error" <|> &"all")
|
||||
|
||||
/--
|
||||
A message filter specification for `#guard_msgs`.
|
||||
- `info`, `warning`, `error`: capture messages with the given severity level.
|
||||
- `all`: capture all messages (the default).
|
||||
- `drop info`, `drop warning`, `drop error`: drop messages with the given severity level.
|
||||
- `drop all`: drop every message.
|
||||
These filters are processed in left-to-right order.
|
||||
-/
|
||||
syntax guardMsgsFilter := &"drop"? guardMsgsFilterSeverity
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
syntax guardMsgsWhitespaceArg := &"exact" <|> &"normalized" <|> &"lax"
|
||||
|
||||
/--
|
||||
Whitespace handling for `#guard_msgs`:
|
||||
- `whitespace := exact` requires an exact whitespace match.
|
||||
- `whitespace := normalized` converts all newline characters to a space before matching
|
||||
(the default). This allows breaking long lines.
|
||||
- `whitespace := lax` collapses whitespace to a single space before matching.
|
||||
In all cases, leading and trailing whitespace is trimmed before matching.
|
||||
-/
|
||||
syntax guardMsgsWhitespace := &"whitespace" " := " guardMsgsWhitespaceArg
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
syntax guardMsgsOrderingArg := &"exact" <|> &"sorted"
|
||||
|
||||
/--
|
||||
Message ordering for `#guard_msgs`:
|
||||
- `ordering := exact` uses the exact ordering of the messages (the default).
|
||||
- `ordering := sorted` sorts the messages in lexicographic order.
|
||||
This helps with testing commands that are non-deterministic in their ordering.
|
||||
-/
|
||||
syntax guardMsgsOrdering := &"ordering" " := " guardMsgsOrderingArg
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
syntax guardMsgsSpecElt := guardMsgsFilter <|> guardMsgsWhitespace <|> guardMsgsOrdering
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
/-- Specification for `#guard_msgs` command. -/
|
||||
syntax guardMsgsSpec := "(" guardMsgsSpecElt,* ")"
|
||||
|
||||
/--
|
||||
`/-- ... -/ #guard_msgs in cmd` captures the messages generated by the command `cmd`
|
||||
and checks that they match the contents of the docstring.
|
||||
`#guard_msgs` captures the messages generated by another command and checks that they
|
||||
match the contents of the docstring attached to the `#guard_msgs` command.
|
||||
|
||||
Basic example:
|
||||
```lean
|
||||
@@ -610,10 +570,10 @@ error: unknown identifier 'x'
|
||||
#guard_msgs in
|
||||
example : α := x
|
||||
```
|
||||
This checks that there is such an error and then consumes the message.
|
||||
This checks that there is such an error and then consumes the message entirely.
|
||||
|
||||
By default, the command captures all messages, but the filter condition can be adjusted.
|
||||
For example, we can select only warnings:
|
||||
By default, the command intercepts all messages, but there is a way to specify which types
|
||||
of messages to consider. For example, we can select only warnings:
|
||||
```lean
|
||||
/--
|
||||
warning: declaration uses 'sorry'
|
||||
@@ -626,37 +586,29 @@ or only errors
|
||||
#guard_msgs(error) in
|
||||
example : α := sorry
|
||||
```
|
||||
In the previous example, since warnings are not captured there is a warning on `sorry`.
|
||||
In this last example, since the message is not intercepted there is a warning on `sorry`.
|
||||
We can drop the warning completely with
|
||||
```lean
|
||||
#guard_msgs(error, drop warning) in
|
||||
example : α := sorry
|
||||
```
|
||||
|
||||
In general, `#guard_msgs` accepts a comma-separated list of configuration clauses in parentheses:
|
||||
Syntax description:
|
||||
```
|
||||
#guard_msgs (configElt,*) in cmd
|
||||
#guard_msgs (drop? info|warning|error|all,*)? in cmd
|
||||
```
|
||||
By default, the configuration list is `(all, whitespace := normalized, ordering := exact)`.
|
||||
|
||||
Message filters (processed in left-to-right order):
|
||||
- `info`, `warning`, `error`: capture messages with the given severity level.
|
||||
- `all`: capture all messages (the default).
|
||||
- `drop info`, `drop warning`, `drop error`: drop messages with the given severity level.
|
||||
- `drop all`: drop every message.
|
||||
If there is no specification, `#guard_msgs` intercepts all messages.
|
||||
Otherwise, if there is one, the specification is considered in left-to-right order, and the first
|
||||
that applies chooses the outcome of the message:
|
||||
- `info`, `warning`, `error`: intercept a message with the given severity level.
|
||||
- `all`: intercept any message (so `#guard_msgs in cmd` and `#guard_msgs (all) in cmd`
|
||||
are equivalent).
|
||||
- `drop info`, `drop warning`, `drop error`: intercept a message with the given severity
|
||||
level and then drop it. These messages are not checked.
|
||||
- `drop all`: intercept a message and drop it.
|
||||
|
||||
Whitespace handling (after trimming leading and trailing whitespace):
|
||||
- `whitespace := exact` requires an exact whitespace match.
|
||||
- `whitespace := normalized` converts all newline characters to a space before matching
|
||||
(the default). This allows breaking long lines.
|
||||
- `whitespace := lax` collapses whitespace to a single space before matching.
|
||||
|
||||
Message ordering:
|
||||
- `ordering := exact` uses the exact ordering of the messages (the default).
|
||||
- `ordering := sorted` sorts the messages in lexicographic order.
|
||||
This helps with testing commands that are non-deterministic in their ordering.
|
||||
|
||||
For example, `#guard_msgs (error, drop all) in cmd` means to check warnings and drop
|
||||
For example, `#guard_msgs (error, drop all) in cmd` means to check warnings and then drop
|
||||
everything else.
|
||||
-/
|
||||
syntax (name := guardMsgsCmd)
|
||||
|
||||
@@ -6,13 +6,15 @@ Authors: Leonardo de Moura
|
||||
Extra notation that depends on Init/Meta
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.ToString.Basic
|
||||
import Init.Data.Array.Subarray
|
||||
import Init.Conv
|
||||
import Init.Meta
|
||||
|
||||
import Init.Data.Array.Subarray
|
||||
import Init.Data.ToString
|
||||
import Init.Conv
|
||||
namespace Lean
|
||||
|
||||
macro "Macro.trace[" id:ident "]" s:interpolatedStr(term) : term =>
|
||||
`(Macro.trace $(quote id.getId.eraseMacroScopes) (s! $s))
|
||||
|
||||
-- Auxiliary parsers and functions for declaring notation with binders
|
||||
|
||||
syntax unbracketedExplicitBinders := (ppSpace binderIdent)+ (" : " term)?
|
||||
@@ -222,35 +224,35 @@ macro tk:"calc" steps:calcSteps : conv =>
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander Name.mkStr1] def unexpandMkStr1 : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $a:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit ("`" ++ a.getString)]
|
||||
| `($(_) $a:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit s!"`{a.getString}"]
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander Name.mkStr2] def unexpandMkStr2 : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $a1:str $a2:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit ("`" ++ a1.getString ++ "." ++ a2.getString)]
|
||||
| `($(_) $a1:str $a2:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit s!"`{a1.getString}.{a2.getString}"]
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander Name.mkStr3] def unexpandMkStr3 : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $a1:str $a2:str $a3:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit ("`" ++ a1.getString ++ "." ++ a2.getString ++ "." ++ a3.getString)]
|
||||
| `($(_) $a1:str $a2:str $a3:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit s!"`{a1.getString}.{a2.getString}.{a3.getString}"]
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander Name.mkStr4] def unexpandMkStr4 : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $a1:str $a2:str $a3:str $a4:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit ("`" ++ a1.getString ++ "." ++ a2.getString ++ "." ++ a3.getString ++ "." ++ a4.getString)]
|
||||
| `($(_) $a1:str $a2:str $a3:str $a4:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit s!"`{a1.getString}.{a2.getString}.{a3.getString}.{a4.getString}"]
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander Name.mkStr5] def unexpandMkStr5 : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $a1:str $a2:str $a3:str $a4:str $a5:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit ("`" ++ a1.getString ++ "." ++ a2.getString ++ "." ++ a3.getString ++ "." ++ a4.getString ++ "." ++ a5.getString)]
|
||||
| `($(_) $a1:str $a2:str $a3:str $a4:str $a5:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit s!"`{a1.getString}.{a2.getString}.{a3.getString}.{a4.getString}.{a5.getString}"]
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander Name.mkStr6] def unexpandMkStr6 : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $a1:str $a2:str $a3:str $a4:str $a5:str $a6:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit ("`" ++ a1.getString ++ "." ++ a2.getString ++ "." ++ a3.getString ++ "." ++ a4.getString ++ "." ++ a5.getString ++ "." ++ a6.getString)]
|
||||
| `($(_) $a1:str $a2:str $a3:str $a4:str $a5:str $a6:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit s!"`{a1.getString}.{a2.getString}.{a3.getString}.{a4.getString}.{a5.getString}.{a6.getString}"]
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander Name.mkStr7] def unexpandMkStr7 : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $a1:str $a2:str $a3:str $a4:str $a5:str $a6:str $a7:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit ("`" ++ a1.getString ++ "." ++ a2.getString ++ "." ++ a3.getString ++ "." ++ a4.getString ++ "." ++ a5.getString ++ "." ++ a6.getString ++ "." ++ a7.getString)]
|
||||
| `($(_) $a1:str $a2:str $a3:str $a4:str $a5:str $a6:str $a7:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit s!"`{a1.getString}.{a2.getString}.{a3.getString}.{a4.getString}.{a5.getString}.{a6.getString}.{a7.getString}"]
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander Name.mkStr8] def unexpandMkStr8 : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $a1:str $a2:str $a3:str $a4:str $a5:str $a6:str $a7:str $a8:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit ("`" ++ a1.getString ++ "." ++ a2.getString ++ "." ++ a3.getString ++ "." ++ a4.getString ++ "." ++ a5.getString ++ "." ++ a6.getString ++ "." ++ a7.getString ++ "." ++ a8.getString)]
|
||||
| `($(_) $a1:str $a2:str $a3:str $a4:str $a5:str $a6:str $a7:str $a8:str) => return mkNode `Lean.Parser.Term.quotedName #[Syntax.mkNameLit s!"`{a1.getString}.{a2.getString}.{a3.getString}.{a4.getString}.{a5.getString}.{a6.getString}.{a7.getString}.{a8.getString}"]
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander Array.empty] def unexpandArrayEmpty : Lean.PrettyPrinter.Unexpander
|
||||
|
||||
@@ -137,13 +137,11 @@ theorem add_le_iff_le_sub (a b c : Int) : a + b ≤ c ↔ a ≤ c - b := by
|
||||
lhs
|
||||
rw [← Int.add_zero c, ← Int.sub_self (-b), Int.sub_eq_add_neg, ← Int.add_assoc, Int.neg_neg,
|
||||
Int.add_le_add_iff_right]
|
||||
try rfl -- stage0 update TODO: Change this to rfl or remove
|
||||
|
||||
theorem le_add_iff_sub_le (a b c : Int) : a ≤ b + c ↔ a - c ≤ b := by
|
||||
conv =>
|
||||
lhs
|
||||
rw [← Int.neg_neg c, ← Int.sub_eq_add_neg, ← add_le_iff_le_sub]
|
||||
try rfl -- stage0 update TODO: Change this to rfl or remove
|
||||
|
||||
theorem add_le_zero_iff_le_neg (a b : Int) : a + b ≤ 0 ↔ a ≤ - b := by
|
||||
rw [add_le_iff_le_sub, Int.zero_sub]
|
||||
|
||||
@@ -307,7 +307,7 @@ theorem dvd_gcd (xs : IntList) (c : Nat) (w : ∀ {a : Int}, a ∈ xs → (c : I
|
||||
c ∣ xs.gcd := by
|
||||
simp only [Int.ofNat_dvd_left] at w
|
||||
induction xs with
|
||||
| nil => have := Nat.dvd_zero c; simp at this; exact this
|
||||
| nil => have := Nat.dvd_zero c; simp
|
||||
| cons x xs ih =>
|
||||
simp
|
||||
apply Nat.dvd_gcd
|
||||
|
||||
@@ -5,7 +5,6 @@ Authors: Scott Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Omega.Coeffs
|
||||
import Init.Data.ToString.Macro
|
||||
|
||||
/-!
|
||||
# Linear combinations
|
||||
|
||||
@@ -477,8 +477,6 @@ and `Prod.snd p` respectively. You can also write `p.fst` and `p.snd`.
|
||||
For more information: [Constructors with Arguments](https://lean-lang.org/theorem_proving_in_lean4/inductive_types.html?highlight=Prod#constructors-with-arguments)
|
||||
-/
|
||||
structure Prod (α : Type u) (β : Type v) where
|
||||
/-- Constructs a pair from two terms. -/
|
||||
mk ::
|
||||
/-- The first projection out of a pair. if `p : α × β` then `p.1 : α`. -/
|
||||
fst : α
|
||||
/-- The second projection out of a pair. if `p : α × β` then `p.2 : β`. -/
|
||||
@@ -1098,7 +1096,7 @@ class OfNat (α : Type u) (_ : Nat) where
|
||||
ofNat : α
|
||||
|
||||
@[default_instance 100] /- low prio -/
|
||||
instance instOfNatNat (n : Nat) : OfNat Nat n where
|
||||
instance (n : Nat) : OfNat Nat n where
|
||||
ofNat := n
|
||||
|
||||
/-- `LE α` is the typeclass which supports the notation `x ≤ y` where `x y : α`.-/
|
||||
@@ -1432,31 +1430,31 @@ class ShiftRight (α : Type u) where
|
||||
shiftRight : α → α → α
|
||||
|
||||
@[default_instance]
|
||||
instance instHAdd [Add α] : HAdd α α α where
|
||||
instance [Add α] : HAdd α α α where
|
||||
hAdd a b := Add.add a b
|
||||
|
||||
@[default_instance]
|
||||
instance instHSub [Sub α] : HSub α α α where
|
||||
instance [Sub α] : HSub α α α where
|
||||
hSub a b := Sub.sub a b
|
||||
|
||||
@[default_instance]
|
||||
instance instHMul [Mul α] : HMul α α α where
|
||||
instance [Mul α] : HMul α α α where
|
||||
hMul a b := Mul.mul a b
|
||||
|
||||
@[default_instance]
|
||||
instance instHDiv [Div α] : HDiv α α α where
|
||||
instance [Div α] : HDiv α α α where
|
||||
hDiv a b := Div.div a b
|
||||
|
||||
@[default_instance]
|
||||
instance instHMod [Mod α] : HMod α α α where
|
||||
instance [Mod α] : HMod α α α where
|
||||
hMod a b := Mod.mod a b
|
||||
|
||||
@[default_instance]
|
||||
instance instHPow [Pow α β] : HPow α β α where
|
||||
instance [Pow α β] : HPow α β α where
|
||||
hPow a b := Pow.pow a b
|
||||
|
||||
@[default_instance]
|
||||
instance instPowNat [NatPow α] : Pow α Nat where
|
||||
instance [NatPow α] : Pow α Nat where
|
||||
pow a n := NatPow.pow a n
|
||||
|
||||
@[default_instance]
|
||||
@@ -1523,7 +1521,7 @@ protected def Nat.add : (@& Nat) → (@& Nat) → Nat
|
||||
| a, Nat.zero => a
|
||||
| a, Nat.succ b => Nat.succ (Nat.add a b)
|
||||
|
||||
instance instAddNat : Add Nat where
|
||||
instance : Add Nat where
|
||||
add := Nat.add
|
||||
|
||||
/- We mark the following definitions as pattern to make sure they can be used in recursive equations,
|
||||
@@ -1543,7 +1541,7 @@ protected def Nat.mul : (@& Nat) → (@& Nat) → Nat
|
||||
| _, 0 => 0
|
||||
| a, Nat.succ b => Nat.add (Nat.mul a b) a
|
||||
|
||||
instance instMulNat : Mul Nat where
|
||||
instance : Mul Nat where
|
||||
mul := Nat.mul
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@@ -1559,7 +1557,7 @@ protected def Nat.pow (m : @& Nat) : (@& Nat) → Nat
|
||||
| 0 => 1
|
||||
| succ n => Nat.mul (Nat.pow m n) m
|
||||
|
||||
instance instNatPowNat : NatPow Nat := ⟨Nat.pow⟩
|
||||
instance : NatPow Nat := ⟨Nat.pow⟩
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/--
|
||||
@@ -1636,14 +1634,14 @@ protected inductive Nat.le (n : Nat) : Nat → Prop
|
||||
/-- If `n ≤ m`, then `n ≤ m + 1`. -/
|
||||
| step {m} : Nat.le n m → Nat.le n (succ m)
|
||||
|
||||
instance instLENat : LE Nat where
|
||||
instance : LE Nat where
|
||||
le := Nat.le
|
||||
|
||||
/-- The strict less than relation on natural numbers is defined as `n < m := n + 1 ≤ m`. -/
|
||||
protected def Nat.lt (n m : Nat) : Prop :=
|
||||
Nat.le (succ n) m
|
||||
|
||||
instance instLTNat : LT Nat where
|
||||
instance : LT Nat where
|
||||
lt := Nat.lt
|
||||
|
||||
theorem Nat.not_succ_le_zero : ∀ (n : Nat), LE.le (succ n) 0 → False
|
||||
@@ -1795,7 +1793,7 @@ protected def Nat.sub : (@& Nat) → (@& Nat) → Nat
|
||||
| a, 0 => a
|
||||
| a, succ b => pred (Nat.sub a b)
|
||||
|
||||
instance instSubNat : Sub Nat where
|
||||
instance : Sub Nat where
|
||||
sub := Nat.sub
|
||||
|
||||
/--
|
||||
@@ -1822,8 +1820,6 @@ It is the "canonical type with `n` elements".
|
||||
-/
|
||||
@[pp_using_anonymous_constructor]
|
||||
structure Fin (n : Nat) where
|
||||
/-- Creates a `Fin n` from `i : Nat` and a proof that `i < n`. -/
|
||||
mk ::
|
||||
/-- If `i : Fin n`, then `i.val : ℕ` is the described number. It can also be
|
||||
written as `i.1` or just `i` when the target type is known. -/
|
||||
val : Nat
|
||||
@@ -2547,6 +2543,43 @@ def panic {α : Type u} [Inhabited α] (msg : String) : α :=
|
||||
-- TODO: this be applied directly to `Inhabited`'s definition when we remove the above workaround
|
||||
attribute [nospecialize] Inhabited
|
||||
|
||||
/--
|
||||
The class `GetElem cont idx elem dom` implements the `xs[i]` notation.
|
||||
When you write this, given `xs : cont` and `i : idx`, Lean looks for an instance
|
||||
of `GetElem cont idx elem dom`. Here `elem` is the type of `xs[i]`, while
|
||||
`dom` is whatever proof side conditions are required to make this applicable.
|
||||
For example, the instance for arrays looks like
|
||||
`GetElem (Array α) Nat α (fun xs i => i < xs.size)`.
|
||||
|
||||
The proof side-condition `dom xs i` is automatically dispatched by the
|
||||
`get_elem_tactic` tactic, which can be extended by adding more clauses to
|
||||
`get_elem_tactic_trivial`.
|
||||
-/
|
||||
class GetElem (cont : Type u) (idx : Type v) (elem : outParam (Type w)) (dom : outParam (cont → idx → Prop)) where
|
||||
/--
|
||||
The syntax `arr[i]` gets the `i`'th element of the collection `arr`.
|
||||
If there are proof side conditions to the application, they will be automatically
|
||||
inferred by the `get_elem_tactic` tactic.
|
||||
|
||||
The actual behavior of this class is type-dependent,
|
||||
but here are some important implementations:
|
||||
* `arr[i] : α` where `arr : Array α` and `i : Nat` or `i : USize`:
|
||||
does array indexing with no bounds check and a proof side goal `i < arr.size`.
|
||||
* `l[i] : α` where `l : List α` and `i : Nat`: index into a list,
|
||||
with proof side goal `i < l.length`.
|
||||
* `stx[i] : Syntax` where `stx : Syntax` and `i : Nat`: get a syntax argument,
|
||||
no side goal (returns `.missing` out of range)
|
||||
|
||||
There are other variations on this syntax:
|
||||
* `arr[i]`: proves the proof side goal by `get_elem_tactic`
|
||||
* `arr[i]!`: panics if the side goal is false
|
||||
* `arr[i]?`: returns `none` if the side goal is false
|
||||
* `arr[i]'h`: uses `h` to prove the side goal
|
||||
-/
|
||||
getElem (xs : cont) (i : idx) (h : dom xs i) : elem
|
||||
|
||||
export GetElem (getElem)
|
||||
|
||||
/--
|
||||
`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array)
|
||||
with elements from `α`. This type has special support in the runtime.
|
||||
@@ -2604,6 +2637,9 @@ def Array.get {α : Type u} (a : @& Array α) (i : @& Fin a.size) : α :=
|
||||
def Array.get! {α : Type u} [Inhabited α] (a : @& Array α) (i : @& Nat) : α :=
|
||||
Array.getD a i default
|
||||
|
||||
instance : GetElem (Array α) Nat α fun xs i => LT.lt i xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
|
||||
/--
|
||||
Push an element onto the end of an array. This is amortized O(1) because
|
||||
`Array α` is internally a dynamic array.
|
||||
@@ -3361,7 +3397,7 @@ protected def seqRight (x : EStateM ε σ α) (y : Unit → EStateM ε σ β) :
|
||||
| Result.error e s => Result.error e s
|
||||
|
||||
@[always_inline]
|
||||
instance instMonad : Monad (EStateM ε σ) where
|
||||
instance : Monad (EStateM ε σ) where
|
||||
bind := EStateM.bind
|
||||
pure := EStateM.pure
|
||||
map := EStateM.map
|
||||
@@ -3871,6 +3907,9 @@ def getArg (stx : Syntax) (i : Nat) : Syntax :=
|
||||
| Syntax.node _ _ args => args.getD i Syntax.missing
|
||||
| _ => Syntax.missing
|
||||
|
||||
instance : GetElem Syntax Nat Syntax fun _ _ => True where
|
||||
getElem stx i _ := stx.getArg i
|
||||
|
||||
/-- Gets the list of arguments of the syntax node, or `#[]` if it's not a `node`. -/
|
||||
def getArgs (stx : Syntax) : Array Syntax :=
|
||||
match stx with
|
||||
@@ -4335,13 +4374,8 @@ def addMacroScope (mainModule : Name) (n : Name) (scp : MacroScope) : Name :=
|
||||
Name.mkNum (Name.mkStr (Name.appendCore (Name.mkStr n "_@") mainModule) "_hyg") scp
|
||||
|
||||
/--
|
||||
Appends two names `a` and `b`, propagating macro scopes from `a` or `b`, if any, to the result.
|
||||
Panics if both `a` and `b` have macro scopes.
|
||||
|
||||
This function is used for the `Append Name` instance.
|
||||
|
||||
See also `Lean.Name.appendCore`, which appends names without any consideration for macro scopes.
|
||||
Also consider `Lean.Name.eraseMacroScopes` to erase macro scopes before appending, if appropriate.
|
||||
Append two names that may have macro scopes. The macro scopes in `b` are always erased.
|
||||
If `a` has macro scopes, then they are propagated to the result of `append a b`.
|
||||
-/
|
||||
def Name.append (a b : Name) : Name :=
|
||||
match a.hasMacroScopes, b.hasMacroScopes with
|
||||
@@ -4372,7 +4406,7 @@ def defaultMaxRecDepth := 512
|
||||
|
||||
/-- The message to display on stack overflow. -/
|
||||
def maxRecDepthErrorMessage : String :=
|
||||
"maximum recursion depth has been reached\nuse `set_option maxRecDepth <num>` to increase limit\nuse `set_option diagnostics true` to get diagnostic information"
|
||||
"maximum recursion depth has been reached (use `set_option maxRecDepth <num>` to increase limit)"
|
||||
|
||||
namespace Syntax
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@ Authors: Mario Carneiro, Jacob von Raumer
|
||||
-/
|
||||
prelude
|
||||
import Init.Tactics
|
||||
import Init.Meta
|
||||
|
||||
import Init.NotationExtra
|
||||
|
||||
/-!
|
||||
# Recursive cases (`rcases`) tactic and related tactics
|
||||
@@ -128,7 +127,7 @@ the input expression). An `rcases` pattern has the following grammar:
|
||||
and so on.
|
||||
* A `@` before a tuple pattern as in `@⟨p1, p2, p3⟩` will bind all arguments in the constructor,
|
||||
while leaving the `@` off will only use the patterns on the explicit arguments.
|
||||
* An alternation pattern `p1 | p2 | p3`, which matches an inductive type with multiple constructors,
|
||||
* An alteration pattern `p1 | p2 | p3`, which matches an inductive type with multiple constructors,
|
||||
or a nested disjunction like `a ∨ b ∨ c`.
|
||||
|
||||
A pattern like `⟨a, b, c⟩ | ⟨d, e⟩` will do a split over the inductive datatype,
|
||||
|
||||
@@ -103,26 +103,18 @@ end SimprocHelperLemmas
|
||||
|
||||
@[simp] theorem and_true (p : Prop) : (p ∧ True) = p := propext ⟨(·.1), (⟨·, trivial⟩)⟩
|
||||
@[simp] theorem true_and (p : Prop) : (True ∧ p) = p := propext ⟨(·.2), (⟨trivial, ·⟩)⟩
|
||||
instance : Std.LawfulIdentity And True where
|
||||
left_id := true_and
|
||||
right_id := and_true
|
||||
@[simp] theorem and_false (p : Prop) : (p ∧ False) = False := eq_false (·.2)
|
||||
@[simp] theorem false_and (p : Prop) : (False ∧ p) = False := eq_false (·.1)
|
||||
@[simp] theorem and_self (p : Prop) : (p ∧ p) = p := propext ⟨(·.left), fun h => ⟨h, h⟩⟩
|
||||
instance : Std.IdempotentOp And := ⟨and_self⟩
|
||||
@[simp] theorem and_not_self : ¬(a ∧ ¬a) | ⟨ha, hn⟩ => absurd ha hn
|
||||
@[simp] theorem not_and_self : ¬(¬a ∧ a) := and_not_self ∘ And.symm
|
||||
@[simp] theorem and_imp : (a ∧ b → c) ↔ (a → b → c) := ⟨fun h ha hb => h ⟨ha, hb⟩, fun h ⟨ha, hb⟩ => h ha hb⟩
|
||||
@[simp] theorem not_and : ¬(a ∧ b) ↔ (a → ¬b) := and_imp
|
||||
@[simp] theorem or_self (p : Prop) : (p ∨ p) = p := propext ⟨fun | .inl h | .inr h => h, .inl⟩
|
||||
instance : Std.IdempotentOp Or := ⟨or_self⟩
|
||||
@[simp] theorem or_true (p : Prop) : (p ∨ True) = True := eq_true (.inr trivial)
|
||||
@[simp] theorem true_or (p : Prop) : (True ∨ p) = True := eq_true (.inl trivial)
|
||||
@[simp] theorem or_false (p : Prop) : (p ∨ False) = p := propext ⟨fun (.inl h) => h, .inl⟩
|
||||
@[simp] theorem false_or (p : Prop) : (False ∨ p) = p := propext ⟨fun (.inr h) => h, .inr⟩
|
||||
instance : Std.LawfulIdentity Or False where
|
||||
left_id := false_or
|
||||
right_id := or_false
|
||||
@[simp] theorem iff_self (p : Prop) : (p ↔ p) = True := eq_true .rfl
|
||||
@[simp] theorem iff_true (p : Prop) : (p ↔ True) = p := propext ⟨(·.2 trivial), fun h => ⟨fun _ => trivial, fun _ => h⟩⟩
|
||||
@[simp] theorem true_iff (p : Prop) : (True ↔ p) = p := propext ⟨(·.1 trivial), fun h => ⟨fun _ => h, fun _ => trivial⟩⟩
|
||||
@@ -148,7 +140,6 @@ theorem and_congr_left (h : c → (a ↔ b)) : a ∧ c ↔ b ∧ c :=
|
||||
theorem and_assoc : (a ∧ b) ∧ c ↔ a ∧ (b ∧ c) :=
|
||||
Iff.intro (fun ⟨⟨ha, hb⟩, hc⟩ => ⟨ha, hb, hc⟩)
|
||||
(fun ⟨ha, hb, hc⟩ => ⟨⟨ha, hb⟩, hc⟩)
|
||||
instance : Std.Associative And := ⟨fun _ _ _ => propext and_assoc⟩
|
||||
|
||||
@[simp] theorem and_self_left : a ∧ (a ∧ b) ↔ a ∧ b := by rw [←propext and_assoc, and_self]
|
||||
@[simp] theorem and_self_right : (a ∧ b) ∧ b ↔ a ∧ b := by rw [ propext and_assoc, and_self]
|
||||
@@ -176,7 +167,6 @@ theorem Or.imp_right (f : b → c) : a ∨ b → a ∨ c := .imp id f
|
||||
theorem or_assoc : (a ∨ b) ∨ c ↔ a ∨ (b ∨ c) :=
|
||||
Iff.intro (.rec (.imp_right .inl) (.inr ∘ .inr))
|
||||
(.rec (.inl ∘ .inl) (.imp_left .inr))
|
||||
instance : Std.Associative Or := ⟨fun _ _ _ => propext or_assoc⟩
|
||||
|
||||
@[simp] theorem or_self_left : a ∨ (a ∨ b) ↔ a ∨ b := by rw [←propext or_assoc, or_self]
|
||||
@[simp] theorem or_self_right : (a ∨ b) ∨ b ↔ a ∨ b := by rw [ propext or_assoc, or_self]
|
||||
@@ -197,12 +187,8 @@ theorem or_iff_left_of_imp (hb : b → a) : (a ∨ b) ↔ a := Iff.intro (Or.r
|
||||
@[simp] theorem Bool.or_false (b : Bool) : (b || false) = b := by cases b <;> rfl
|
||||
@[simp] theorem Bool.or_true (b : Bool) : (b || true) = true := by cases b <;> rfl
|
||||
@[simp] theorem Bool.false_or (b : Bool) : (false || b) = b := by cases b <;> rfl
|
||||
instance : Std.LawfulIdentity (· || ·) false where
|
||||
left_id := Bool.false_or
|
||||
right_id := Bool.or_false
|
||||
@[simp] theorem Bool.true_or (b : Bool) : (true || b) = true := by cases b <;> rfl
|
||||
@[simp] theorem Bool.or_self (b : Bool) : (b || b) = b := by cases b <;> rfl
|
||||
instance : Std.IdempotentOp (· || ·) := ⟨Bool.or_self⟩
|
||||
@[simp] theorem Bool.or_eq_true (a b : Bool) : ((a || b) = true) = (a = true ∨ b = true) := by
|
||||
cases a <;> cases b <;> decide
|
||||
|
||||
@@ -210,20 +196,14 @@ instance : Std.IdempotentOp (· || ·) := ⟨Bool.or_self⟩
|
||||
@[simp] theorem Bool.and_true (b : Bool) : (b && true) = b := by cases b <;> rfl
|
||||
@[simp] theorem Bool.false_and (b : Bool) : (false && b) = false := by cases b <;> rfl
|
||||
@[simp] theorem Bool.true_and (b : Bool) : (true && b) = b := by cases b <;> rfl
|
||||
instance : Std.LawfulIdentity (· && ·) true where
|
||||
left_id := Bool.true_and
|
||||
right_id := Bool.and_true
|
||||
@[simp] theorem Bool.and_self (b : Bool) : (b && b) = b := by cases b <;> rfl
|
||||
instance : Std.IdempotentOp (· && ·) := ⟨Bool.and_self⟩
|
||||
@[simp] theorem Bool.and_eq_true (a b : Bool) : ((a && b) = true) = (a = true ∧ b = true) := by
|
||||
cases a <;> cases b <;> decide
|
||||
|
||||
theorem Bool.and_assoc (a b c : Bool) : (a && b && c) = (a && (b && c)) := by
|
||||
cases a <;> cases b <;> cases c <;> decide
|
||||
instance : Std.Associative (· && ·) := ⟨Bool.and_assoc⟩
|
||||
theorem Bool.or_assoc (a b c : Bool) : (a || b || c) = (a || (b || c)) := by
|
||||
cases a <;> cases b <;> cases c <;> decide
|
||||
instance : Std.Associative (· || ·) := ⟨Bool.or_assoc⟩
|
||||
|
||||
@[simp] theorem Bool.not_not (b : Bool) : (!!b) = b := by cases b <;> rfl
|
||||
@[simp] theorem Bool.not_true : (!true) = false := by decide
|
||||
|
||||
@@ -11,23 +11,22 @@ namespace Lean.Parser
|
||||
A user-defined simplification procedure used by the `simp` tactic, and its variants.
|
||||
Here is an example.
|
||||
```lean
|
||||
theorem and_false_eq {p : Prop} (q : Prop) (h : p = False) : (p ∧ q) = False := by simp [*]
|
||||
|
||||
open Lean Meta Simp
|
||||
simproc ↓ shortCircuitAnd (And _ _) := fun e => do
|
||||
let_expr And p q := e | return .continue
|
||||
let r ← simp p
|
||||
let_expr False := r.expr | return .continue
|
||||
let proof ← mkAppM ``and_false_eq #[q, (← r.getProof)]
|
||||
return .done { expr := r.expr, proof? := some proof }
|
||||
simproc reduce_add (_ + _) := fun e => do
|
||||
unless (e.isAppOfArity ``HAdd.hAdd 6) do return none
|
||||
let some n ← getNatValue? (e.getArg! 4) | return none
|
||||
let some m ← getNatValue? (e.getArg! 5) | return none
|
||||
return some (.done { expr := mkNatLit (n+m) })
|
||||
```
|
||||
The `simp` tactic invokes `shortCircuitAnd` whenever it finds a term of the form `And _ _`.
|
||||
The `simp` tactic invokes `reduce_add` whenever it finds a term of the form `_ + _`.
|
||||
The simplification procedures are stored in an (imperfect) discrimination tree.
|
||||
The procedure should **not** assume the term `e` perfectly matches the given pattern.
|
||||
The body of a simplification procedure must have type `Simproc`, which is an alias for
|
||||
`Expr → SimpM Step`
|
||||
`Expr → SimpM (Option Step)`.
|
||||
You can instruct the simplifier to apply the procedure before its sub-expressions
|
||||
have been simplified by using the modifier `↓` before the procedure name.
|
||||
have been simplified by using the modifier `↓` before the procedure name. Example.
|
||||
```lean
|
||||
simproc ↓ reduce_add (_ + _) := fun e => ...
|
||||
```
|
||||
Simplification procedures can be also scoped or local.
|
||||
-/
|
||||
syntax (docComment)? attrKind "simproc " (Tactic.simpPre <|> Tactic.simpPost)? ("[" ident,* "]")? ident " (" term ")" " := " term : command
|
||||
|
||||
@@ -73,21 +73,7 @@ private def posOfLastSep (p : FilePath) : Option String.Pos :=
|
||||
p.toString.revFind pathSeparators.contains
|
||||
|
||||
def parent (p : FilePath) : Option FilePath :=
|
||||
let extractParentPath := FilePath.mk <$> p.toString.extract {} <$> posOfLastSep p
|
||||
if p.isAbsolute then
|
||||
let lengthOfRootDirectory := if pathSeparators.contains p.toString.front then 1 else 3
|
||||
if p.toString.length == lengthOfRootDirectory then
|
||||
-- `p` is a root directory
|
||||
none
|
||||
else if posOfLastSep p == String.Pos.mk (lengthOfRootDirectory - 1) then
|
||||
-- `p` is a direct child of the root
|
||||
some ⟨p.toString.extract 0 ⟨lengthOfRootDirectory⟩⟩
|
||||
else
|
||||
-- `p` is an absolute path with at least two subdirectories
|
||||
extractParentPath
|
||||
else
|
||||
-- `p` is a relative path
|
||||
extractParentPath
|
||||
FilePath.mk <$> p.toString.extract {} <$> posOfLastSep p
|
||||
|
||||
def fileName (p : FilePath) : Option String :=
|
||||
let lastPart := match posOfLastSep p with
|
||||
|
||||
@@ -311,8 +311,6 @@ Note that EOF does not actually close a stream, so further reads may block and r
|
||||
-/
|
||||
getLine : IO String
|
||||
putStr : String → IO Unit
|
||||
/-- Returns true if a stream refers to a Windows console or Unix terminal. -/
|
||||
isTty : BaseIO Bool
|
||||
deriving Inhabited
|
||||
|
||||
open FS
|
||||
@@ -362,9 +360,6 @@ Will succeed even if no lock has been acquired.
|
||||
-/
|
||||
@[extern "lean_io_prim_handle_unlock"] opaque unlock (h : @& Handle) : IO Unit
|
||||
|
||||
/-- Returns true if a handle refers to a Windows console or Unix terminal. -/
|
||||
@[extern "lean_io_prim_handle_is_tty"] opaque isTty (h : @& Handle) : BaseIO Bool
|
||||
|
||||
@[extern "lean_io_prim_handle_flush"] opaque flush (h : @& Handle) : IO Unit
|
||||
/-- Rewinds the read/write cursor to the beginning of the handle. -/
|
||||
@[extern "lean_io_prim_handle_rewind"] opaque rewind (h : @& Handle) : IO Unit
|
||||
@@ -748,41 +743,36 @@ namespace FS
|
||||
namespace Stream
|
||||
|
||||
@[export lean_stream_of_handle]
|
||||
def ofHandle (h : Handle) : Stream where
|
||||
flush := Handle.flush h
|
||||
read := Handle.read h
|
||||
write := Handle.write h
|
||||
getLine := Handle.getLine h
|
||||
putStr := Handle.putStr h
|
||||
isTty := Handle.isTty h
|
||||
def ofHandle (h : Handle) : Stream := {
|
||||
flush := Handle.flush h,
|
||||
read := Handle.read h,
|
||||
write := Handle.write h,
|
||||
getLine := Handle.getLine h,
|
||||
putStr := Handle.putStr h,
|
||||
}
|
||||
|
||||
structure Buffer where
|
||||
data : ByteArray := ByteArray.empty
|
||||
pos : Nat := 0
|
||||
|
||||
def ofBuffer (r : Ref Buffer) : Stream where
|
||||
flush := pure ()
|
||||
def ofBuffer (r : Ref Buffer) : Stream := {
|
||||
flush := pure (),
|
||||
read := fun n => r.modifyGet fun b =>
|
||||
let data := b.data.extract b.pos (b.pos + n.toNat)
|
||||
(data, { b with pos := b.pos + data.size })
|
||||
(data, { b with pos := b.pos + data.size }),
|
||||
write := fun data => r.modify fun b =>
|
||||
-- set `exact` to `false` so that repeatedly writing to the stream does not impose quadratic run time
|
||||
{ b with data := data.copySlice 0 b.data b.pos data.size false, pos := b.pos + data.size }
|
||||
getLine := do
|
||||
let buf ← r.modifyGet fun b =>
|
||||
let pos := match b.data.findIdx? (start := b.pos) fun u => u == 0 || u = '\n'.toNat.toUInt8 with
|
||||
-- include '\n', but not '\0'
|
||||
| some pos => if b.data.get! pos == 0 then pos else pos + 1
|
||||
| none => b.data.size
|
||||
(b.data.extract b.pos pos, { b with pos := pos })
|
||||
match String.fromUTF8? buf with
|
||||
| some str => pure str
|
||||
| none => throw (.userError "invalid UTF-8")
|
||||
{ b with data := data.copySlice 0 b.data b.pos data.size false, pos := b.pos + data.size },
|
||||
getLine := r.modifyGet fun b =>
|
||||
let pos := match b.data.findIdx? (start := b.pos) fun u => u == 0 || u = '\n'.toNat.toUInt8 with
|
||||
-- include '\n', but not '\0'
|
||||
| some pos => if b.data.get! pos == 0 then pos else pos + 1
|
||||
| none => b.data.size
|
||||
(String.fromUTF8Unchecked <| b.data.extract b.pos pos, { b with pos := pos }),
|
||||
putStr := fun s => r.modify fun b =>
|
||||
let data := s.toUTF8
|
||||
{ b with data := data.copySlice 0 b.data b.pos data.size false, pos := b.pos + data.size }
|
||||
isTty := pure false
|
||||
|
||||
{ b with data := data.copySlice 0 b.data b.pos data.size false, pos := b.pos + data.size },
|
||||
}
|
||||
end Stream
|
||||
|
||||
/-- Run action with `stdin` emptied and `stdout+stderr` captured into a `String`. -/
|
||||
@@ -795,7 +785,7 @@ def withIsolatedStreams [Monad m] [MonadFinally m] [MonadLiftT BaseIO m] (x : m
|
||||
(if isolateStderr then withStderr (Stream.ofBuffer bOut) else id) <|
|
||||
x
|
||||
let bOut ← liftM (m := BaseIO) bOut.get
|
||||
let out := String.fromUTF8! bOut.data
|
||||
let out := String.fromUTF8Unchecked bOut.data
|
||||
pure (out, r)
|
||||
|
||||
end FS
|
||||
@@ -812,7 +802,7 @@ class Eval (α : Type u) where
|
||||
-- We take `Unit → α` instead of `α` because ‵α` may contain effectful debugging primitives (e.g., `dbg_trace`)
|
||||
eval : (Unit → α) → (hideUnit : Bool := true) → IO Unit
|
||||
|
||||
instance instEval [ToString α] : Eval α where
|
||||
instance [ToString α] : Eval α where
|
||||
eval a _ := IO.println (toString (a ()))
|
||||
|
||||
instance [Repr α] : Eval α where
|
||||
|
||||
@@ -50,7 +50,7 @@ def decodeUri (uri : String) : String := Id.run do
|
||||
((decoded.push c).push h1, i + 2)
|
||||
else
|
||||
(decoded.push c, i + 1)
|
||||
return String.fromUTF8! decoded
|
||||
return String.fromUTF8Unchecked decoded
|
||||
where hexDigitToUInt8? (c : UInt8) : Option UInt8 :=
|
||||
if zero ≤ c ∧ c ≤ nine then some (c - zero)
|
||||
else if lettera ≤ c ∧ c ≤ letterf then some (c - lettera + 10)
|
||||
|
||||
@@ -354,9 +354,6 @@ macro:1 x:tactic tk:" <;> " y:tactic:2 : tactic => `(tactic|
|
||||
with_annotate_state $tk skip
|
||||
all_goals $y:tactic)
|
||||
|
||||
/-- `fail msg` is a tactic that always fails, and produces an error using the given message. -/
|
||||
syntax (name := fail) "fail" (ppSpace str)? : tactic
|
||||
|
||||
/-- `eq_refl` is equivalent to `exact rfl`, but has a few optimizations. -/
|
||||
syntax (name := eqRefl) "eq_refl" : tactic
|
||||
|
||||
@@ -368,18 +365,13 @@ for new reflexive relations.
|
||||
Remark: `rfl` is an extensible tactic. We later add `macro_rules` to try different
|
||||
reflexivity theorems (e.g., `Iff.rfl`).
|
||||
-/
|
||||
macro "rfl" : tactic => `(tactic| fail "The rfl tactic failed. Possible reasons:
|
||||
- The goal is not a reflexive relation (neither `=` nor a relation with a @[refl] lemma).
|
||||
- The arguments of the relation are not equal.
|
||||
Try using the reflexivitiy lemma for your relation explicitly, e.g. `exact Eq.rfl`.")
|
||||
macro "rfl" : tactic => `(tactic| eq_refl)
|
||||
|
||||
macro_rules | `(tactic| rfl) => `(tactic| eq_refl)
|
||||
macro_rules | `(tactic| rfl) => `(tactic| exact HEq.rfl)
|
||||
|
||||
/--
|
||||
This tactic applies to a goal whose target has the form `x ~ x`,
|
||||
where `~` is a reflexive relation other than `=`,
|
||||
that is, a relation which has a reflexive lemma tagged with the attribute @[refl].
|
||||
This tactic applies to a goal whose target has the form `x ~ x`, where `~` is a reflexive
|
||||
relation, that is, a relation which has a reflexive lemma tagged with the attribute [refl].
|
||||
-/
|
||||
syntax (name := applyRfl) "apply_rfl" : tactic
|
||||
|
||||
@@ -915,6 +907,9 @@ example : ∀ x : Nat, x = x := by unhygienic
|
||||
-/
|
||||
macro "unhygienic " t:tacticSeq : tactic => `(tactic| set_option tactic.hygienic false in $t)
|
||||
|
||||
/-- `fail msg` is a tactic that always fails, and produces an error using the given message. -/
|
||||
syntax (name := fail) "fail" (ppSpace str)? : tactic
|
||||
|
||||
/--
|
||||
`checkpoint tac` acts the same as `tac`, but it caches the input and output of `tac`,
|
||||
and if the file is re-elaborated and the input matches, the tactic is not re-run and
|
||||
@@ -1125,14 +1120,11 @@ normalizes `h` with `norm_cast` and tries to use that to close the goal. -/
|
||||
macro "assumption_mod_cast" : tactic => `(tactic| norm_cast0 at * <;> assumption)
|
||||
|
||||
/--
|
||||
The `norm_cast` family of tactics is used to normalize certain coercions (*casts*) in expressions.
|
||||
- `norm_cast` normalizes casts in the target.
|
||||
- `norm_cast at h` normalizes casts in hypothesis `h`.
|
||||
|
||||
The tactic is basically a version of `simp` with a specific set of lemmas to move casts
|
||||
The `norm_cast` family of tactics is used to normalize casts inside expressions.
|
||||
It is basically a `simp` tactic with a specific set of lemmas to move casts
|
||||
upwards in the expression.
|
||||
Therefore even in situations where non-terminal `simp` calls are discouraged (because of fragility),
|
||||
`norm_cast` is considered to be safe.
|
||||
`norm_cast` is considered safe.
|
||||
It also has special handling of numerals.
|
||||
|
||||
For instance, given an assumption
|
||||
@@ -1140,22 +1132,22 @@ For instance, given an assumption
|
||||
a b : ℤ
|
||||
h : ↑a + ↑b < (10 : ℚ)
|
||||
```
|
||||
|
||||
writing `norm_cast at h` will turn `h` into
|
||||
```lean
|
||||
h : a + b < 10
|
||||
```
|
||||
|
||||
There are also variants of basic tactics that use `norm_cast` to normalize expressions during
|
||||
their operation, to make them more flexible about the expressions they accept
|
||||
(we say that it is a tactic *modulo* the effects of `norm_cast`):
|
||||
- `exact_mod_cast` for `exact` and `apply_mod_cast` for `apply`.
|
||||
Writing `exact_mod_cast h` and `apply_mod_cast h` will normalize casts
|
||||
in the goal and `h` before using `exact h` or `apply h`.
|
||||
- `rw_mod_cast` for `rw`. It applies `norm_cast` between rewrites.
|
||||
- `assumption_mod_cast` for `assumption`.
|
||||
This is effectively `norm_cast at *; assumption`, but more efficient.
|
||||
It normalizes casts in the goal and, for every hypothesis `h` in the context,
|
||||
it will try to normalize casts in `h` and use `exact h`.
|
||||
There are also variants of `exact`, `apply`, `rw`, and `assumption` that
|
||||
work modulo `norm_cast` - in other words, they apply `norm_cast` to make
|
||||
them more flexible. They are called `exact_mod_cast`, `apply_mod_cast`,
|
||||
`rw_mod_cast`, and `assumption_mod_cast`, respectively.
|
||||
Writing `exact_mod_cast h` and `apply_mod_cast h` will normalize casts
|
||||
in the goal and `h` before using `exact h` or `apply h`.
|
||||
Writing `assumption_mod_cast` will normalize casts in the goal and, for
|
||||
every hypothesis `h` in the context, it will try to normalize casts in `h` and use
|
||||
`exact h`.
|
||||
`rw_mod_cast` acts like the `rw` tactic but it applies `norm_cast` between steps.
|
||||
|
||||
See also `push_cast`, which moves casts inwards rather than lifting them outwards.
|
||||
-/
|
||||
@@ -1163,37 +1155,22 @@ macro "norm_cast" loc:(location)? : tactic =>
|
||||
`(tactic| norm_cast0 $[$loc]? <;> try trivial)
|
||||
|
||||
/--
|
||||
`push_cast` rewrites the goal to move certain coercions (*casts*) inward, toward the leaf nodes.
|
||||
`push_cast` rewrites the goal to move casts inward, toward the leaf nodes.
|
||||
This uses `norm_cast` lemmas in the forward direction.
|
||||
For example, `↑(a + b)` will be written to `↑a + ↑b`.
|
||||
- `push_cast` moves casts inward in the goal.
|
||||
- `push_cast at h` moves casts inward in the hypothesis `h`.
|
||||
It can be used with extra simp lemmas with, for example, `push_cast [Int.add_zero]`.
|
||||
It is equivalent to `simp only with push_cast`.
|
||||
It can also be used at hypotheses with `push_cast at h`
|
||||
and with extra simp lemmas with `push_cast [int.add_zero]`.
|
||||
|
||||
Example:
|
||||
```lean
|
||||
example (a b : Nat)
|
||||
(h1 : ((a + b : Nat) : Int) = 10)
|
||||
(h2 : ((a + b + 0 : Nat) : Int) = 10) :
|
||||
((a + b : Nat) : Int) = 10 := by
|
||||
/-
|
||||
h1 : ↑(a + b) = 10
|
||||
h2 : ↑(a + b + 0) = 10
|
||||
⊢ ↑(a + b) = 10
|
||||
-/
|
||||
push_cast
|
||||
/- Now
|
||||
⊢ ↑a + ↑b = 10
|
||||
-/
|
||||
push_cast at h1
|
||||
push_cast [Int.add_zero] at h2
|
||||
/- Now
|
||||
h1 h2 : ↑a + ↑b = 10
|
||||
-/
|
||||
exact h1
|
||||
example (a b : ℕ) (h1 : ((a + b : ℕ) : ℤ) = 10) (h2 : ((a + b + 0 : ℕ) : ℤ) = 10) :
|
||||
((a + b : ℕ) : ℤ) = 10 :=
|
||||
begin
|
||||
push_cast,
|
||||
push_cast at h1,
|
||||
push_cast [int.add_zero] at h2,
|
||||
end
|
||||
```
|
||||
|
||||
See also `norm_cast`.
|
||||
-/
|
||||
syntax (name := pushCast) "push_cast" (config)? (discharger)? (&" only")?
|
||||
(" [" (simpStar <|> simpErase <|> simpLemma),* "]")? (location)? : tactic
|
||||
@@ -1540,16 +1517,16 @@ macro "get_elem_tactic" : tactic =>
|
||||
- Use `a[i]'h` notation instead, where `h` is a proof that index is valid"
|
||||
)
|
||||
|
||||
@[inherit_doc getElem]
|
||||
syntax:max term noWs "[" withoutPosition(term) "]" : term
|
||||
macro_rules | `($x[$i]) => `(getElem $x $i (by get_elem_tactic))
|
||||
|
||||
@[inherit_doc getElem]
|
||||
syntax term noWs "[" withoutPosition(term) "]'" term:max : term
|
||||
macro_rules | `($x[$i]'$h) => `(getElem $x $i $h)
|
||||
|
||||
/--
|
||||
Searches environment for definitions or theorems that can be substituted in
|
||||
for `exact?%` to solve the goal.
|
||||
for `exact?% to solve the goal.
|
||||
-/
|
||||
syntax (name := Lean.Parser.Syntax.exact?) "exact?%" : term
|
||||
|
||||
set_option linter.unusedVariables.funArgs false in
|
||||
/--
|
||||
Gadget for automatic parameter support. This is similar to the `optParam` gadget, but it uses
|
||||
the given tactic.
|
||||
Like `optParam`, this gadget only affects elaboration.
|
||||
For example, the tactic will *not* be invoked during type class resolution. -/
|
||||
abbrev autoParam.{u} (α : Sort u) (tactic : Lean.Syntax) : Sort u := α
|
||||
|
||||
@@ -73,6 +73,19 @@ def withPtrEq {α : Type u} (a b : α) (k : Unit → Bool) (h : a = b → k () =
|
||||
@[implemented_by withPtrAddrUnsafe]
|
||||
def withPtrAddr {α : Type u} {β : Type v} (a : α) (k : USize → β) (h : ∀ u₁ u₂, k u₁ = k u₂) : β := k 0
|
||||
|
||||
@[never_extract]
|
||||
private def outOfBounds [Inhabited α] : α :=
|
||||
panic! "index out of bounds"
|
||||
|
||||
@[inline] def getElem! [GetElem cont idx elem dom] [Inhabited elem] (xs : cont) (i : idx) [Decidable (dom xs i)] : elem :=
|
||||
if h : _ then getElem xs i h else outOfBounds
|
||||
|
||||
@[inline] def getElem? [GetElem cont idx elem dom] (xs : cont) (i : idx) [Decidable (dom xs i)] : Option elem :=
|
||||
if h : _ then some (getElem xs i h) else none
|
||||
|
||||
macro:max x:term noWs "[" i:term "]" noWs "?" : term => `(getElem? $x $i)
|
||||
macro:max x:term noWs "[" i:term "]" noWs "!" : term => `(getElem! $x $i)
|
||||
|
||||
/--
|
||||
Marks given value and its object graph closure as multi-threaded if currently
|
||||
marked single-threaded. This will make reference counter updates atomic and
|
||||
|
||||
@@ -9,18 +9,7 @@ import Init.Data.Nat.Basic
|
||||
|
||||
universe u v
|
||||
|
||||
/--
|
||||
`Acc` is the accessibility predicate. Given some relation `r` (e.g. `<`) and a value `x`,
|
||||
`Acc r x` means that `x` is accessible through `r`:
|
||||
|
||||
`x` is accessible if there exists no infinite sequence `... < y₂ < y₁ < y₀ < x`.
|
||||
-/
|
||||
inductive Acc {α : Sort u} (r : α → α → Prop) : α → Prop where
|
||||
/--
|
||||
A value is accessible if for all `y` such that `r y x`, `y` is also accessible.
|
||||
Note that if there exists no `y` such that `r y x`, then `x` is accessible. Such an `x` is called a
|
||||
_base case_.
|
||||
-/
|
||||
| intro (x : α) (h : (y : α) → r y x → Acc r y) : Acc r x
|
||||
|
||||
noncomputable abbrev Acc.ndrec.{u1, u2} {α : Sort u2} {r : α → α → Prop} {C : α → Sort u1}
|
||||
@@ -42,14 +31,6 @@ def inv {x y : α} (h₁ : Acc r x) (h₂ : r y x) : Acc r y :=
|
||||
|
||||
end Acc
|
||||
|
||||
/--
|
||||
A relation `r` is `WellFounded` if all elements of `α` are accessible within `r`.
|
||||
If a relation is `WellFounded`, it does not allow for an infinite descent along the relation.
|
||||
|
||||
If the arguments of the recursive calls in a function definition decrease according to
|
||||
a well founded relation, then the function terminates.
|
||||
Well-founded relations are sometimes called _Artinian_ or said to satisfy the “descending chain condition”.
|
||||
-/
|
||||
inductive WellFounded {α : Sort u} (r : α → α → Prop) : Prop where
|
||||
| intro (h : ∀ a, Acc r a) : WellFounded r
|
||||
|
||||
|
||||
@@ -25,16 +25,9 @@ syntax "decreasing_trivial" : tactic
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| (simp (config := { arith := true, failIfUnchanged := false })) <;> done)
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| omega)
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| assumption)
|
||||
|
||||
/--
|
||||
Variant of `decreasing_trivial` that does not use `omega`, intended to be used in core modules
|
||||
before `omega` is available.
|
||||
-/
|
||||
syntax "decreasing_trivial_pre_omega" : tactic
|
||||
macro_rules | `(tactic| decreasing_trivial_pre_omega) => `(tactic| apply Nat.sub_succ_lt_self; assumption) -- a - (i+1) < a - i if i < a
|
||||
macro_rules | `(tactic| decreasing_trivial_pre_omega) => `(tactic| apply Nat.pred_lt'; assumption) -- i-1 < i if j < i
|
||||
macro_rules | `(tactic| decreasing_trivial_pre_omega) => `(tactic| apply Nat.pred_lt; assumption) -- i-1 < i if i ≠ 0
|
||||
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| apply Nat.sub_succ_lt_self; assumption) -- a - (i+1) < a - i if i < a
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| apply Nat.pred_lt'; assumption) -- i-1 < i if j < i
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| apply Nat.pred_lt; assumption) -- i-1 < i if i ≠ 0
|
||||
|
||||
/-- Constructs a proof of decreasing along a well founded relation, by applying
|
||||
lexicographic order lemmas and using `ts` to solve the base case. If it fails,
|
||||
|
||||
@@ -183,6 +183,7 @@ structure ParametricAttribute (α : Type) where
|
||||
deriving Inhabited
|
||||
|
||||
structure ParametricAttributeImpl (α : Type) extends AttributeImplCore where
|
||||
/-- This is used as the target for go-to-definition queries for simple attributes -/
|
||||
getParam : Name → Syntax → AttrM α
|
||||
afterSet : Name → α → AttrM Unit := fun _ _ _ => pure ()
|
||||
afterImport : Array (Array (Name × α)) → ImportM Unit := fun _ => pure ()
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2024 Mario Carneiro. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Lean.Compiler.InitAttr
|
||||
import Lean.DocString
|
||||
|
||||
namespace Lean
|
||||
|
||||
def declareBuiltinDocStringAndRanges (declName : Name) : AttrM Unit := do
|
||||
if let some doc ← findDocString? (← getEnv) declName (includeBuiltin := false) then
|
||||
declareBuiltin (declName ++ `docString) (mkAppN (mkConst ``addBuiltinDocString) #[toExpr declName, toExpr doc])
|
||||
if let some declRanges ← findDeclarationRanges? declName then
|
||||
declareBuiltin (declName ++ `declRange) (mkAppN (mkConst ``addBuiltinDeclarationRanges) #[toExpr declName, toExpr declRanges])
|
||||
|
||||
builtin_initialize
|
||||
registerBuiltinAttribute {
|
||||
name := `builtin_doc
|
||||
descr := "make the docs and location of this declaration available as a builtin"
|
||||
add := fun decl stx _ => do
|
||||
Attribute.Builtin.ensureNoArgs stx
|
||||
declareBuiltinDocStringAndRanges decl
|
||||
}
|
||||
|
||||
end Lean
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user