mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-26 23:04:07 +00:00
Compare commits
270 Commits
grind_warn
...
grind_modu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c8cb61b5c | ||
|
|
ca4322ff09 | ||
|
|
d32f04ba21 | ||
|
|
0db795a1dc | ||
|
|
d9a73dd1e3 | ||
|
|
e9f6033467 | ||
|
|
0c9bb4b861 | ||
|
|
9b4911f8f6 | ||
|
|
f678b40660 | ||
|
|
890722f571 | ||
|
|
ef1ca99bff | ||
|
|
26fdc1e19a | ||
|
|
0b0d183c1d | ||
|
|
21f5263f2f | ||
|
|
02edc0bd92 | ||
|
|
45affb5e09 | ||
|
|
6a7111ed0e | ||
|
|
6b4c356c5b | ||
|
|
e3947cbe20 | ||
|
|
d6a43a660f | ||
|
|
b2330fee2b | ||
|
|
105879669e | ||
|
|
679df58329 | ||
|
|
d604c16c0e | ||
|
|
44891fe0c0 | ||
|
|
ee699518fa | ||
|
|
1b213835e6 | ||
|
|
22becc78f7 | ||
|
|
e083771b81 | ||
|
|
1a31aa3d2b | ||
|
|
86dc07c20d | ||
|
|
48365b6052 | ||
|
|
d4a5a2c632 | ||
|
|
8d34dfe914 | ||
|
|
a1cf67edc3 | ||
|
|
d0167f7002 | ||
|
|
90ef90b462 | ||
|
|
cab46ea3d1 | ||
|
|
24cafcd65d | ||
|
|
b75fbe7a40 | ||
|
|
cd729660ed | ||
|
|
f81236185c | ||
|
|
7fa1a8b114 | ||
|
|
8536fe5aa9 | ||
|
|
6b24eb474f | ||
|
|
de493d761d | ||
|
|
b68f3455d3 | ||
|
|
f88d35f6c9 | ||
|
|
89752e2242 | ||
|
|
b8fa6f17ee | ||
|
|
2d4bcf202f | ||
|
|
1b0d83e7fc | ||
|
|
2d52d44710 | ||
|
|
af5322c7ef | ||
|
|
3af9cc3f6f | ||
|
|
688b930bad | ||
|
|
04f9baf4d3 | ||
|
|
19301f83eb | ||
|
|
2e6c1a74e5 | ||
|
|
e4be2b2cad | ||
|
|
48a8dd4a56 | ||
|
|
a805e7e12c | ||
|
|
3c702f38ee | ||
|
|
fe90da5a8d | ||
|
|
fd926cc44e | ||
|
|
f5bab3c8ba | ||
|
|
973885d087 | ||
|
|
1aa59f5579 | ||
|
|
a4496a4a6b | ||
|
|
84fecdc042 | ||
|
|
81a4b0ca99 | ||
|
|
6f7dba167a | ||
|
|
0cc0de9e51 | ||
|
|
010468699f | ||
|
|
4a6004b8fa | ||
|
|
c6df4a4a89 | ||
|
|
ee4cbbeb14 | ||
|
|
0e968f010a | ||
|
|
b0d42e6ac9 | ||
|
|
df898a5c87 | ||
|
|
bdc9124228 | ||
|
|
aad98fe749 | ||
|
|
506d16a603 | ||
|
|
9e1d97c261 | ||
|
|
4c562fc1a3 | ||
|
|
415a58f9fb | ||
|
|
85ba133df0 | ||
|
|
3ee8d35031 | ||
|
|
45fbe4a73d | ||
|
|
287b173844 | ||
|
|
05c1ba291d | ||
|
|
15a065d14d | ||
|
|
35a753dc98 | ||
|
|
06d05d1f46 | ||
|
|
fe7e0859d5 | ||
|
|
76971a88ff | ||
|
|
ddfeca1b1b | ||
|
|
0ab29c7420 | ||
|
|
1ba1424ac3 | ||
|
|
c8dae31ba5 | ||
|
|
49cd03bc29 | ||
|
|
6e1451dbd8 | ||
|
|
6b3aed29b9 | ||
|
|
34fe6b460c | ||
|
|
62f9de5edf | ||
|
|
0c39a50337 | ||
|
|
535435955b | ||
|
|
93e35dc3da | ||
|
|
05e8c856fa | ||
|
|
2e991d3b10 | ||
|
|
f60f946e11 | ||
|
|
253c10c398 | ||
|
|
f8c743e37d | ||
|
|
f80274be6b | ||
|
|
d93cdde938 | ||
|
|
640337e0a0 | ||
|
|
55f9dfad7d | ||
|
|
b9a8dd8f0d | ||
|
|
f973e855e0 | ||
|
|
93e0ebf25c | ||
|
|
21fa5d10f4 | ||
|
|
0046b8b4bb | ||
|
|
639baaaa03 | ||
|
|
6f7ca5e5d3 | ||
|
|
5210cdf43f | ||
|
|
072e3e89e3 | ||
|
|
6e18afac8c | ||
|
|
a9145d3312 | ||
|
|
5801dff9ea | ||
|
|
54dce214d1 | ||
|
|
e5bb854748 | ||
|
|
e9df183e87 | ||
|
|
954957c456 | ||
|
|
dfc8e38a21 | ||
|
|
bf348ae60f | ||
|
|
4df4968538 | ||
|
|
ca05569cd5 | ||
|
|
a157abbbc9 | ||
|
|
5abf4bb651 | ||
|
|
7ea711e043 | ||
|
|
b853166575 | ||
|
|
0725349bbd | ||
|
|
264e451d3c | ||
|
|
5b5bb5174b | ||
|
|
14120a519c | ||
|
|
2875e8f277 | ||
|
|
9a0c1ab2d0 | ||
|
|
f15d531acb | ||
|
|
e0fcaf5e7d | ||
|
|
1b78d8f0a3 | ||
|
|
66772d77fc | ||
|
|
d64637e8c7 | ||
|
|
02fa9641fd | ||
|
|
4506173a27 | ||
|
|
20eea7372f | ||
|
|
79f6bb6f54 | ||
|
|
fc076c5acc | ||
|
|
44d3cfb3dc | ||
|
|
0985326b2e | ||
|
|
cbeef963a9 | ||
|
|
544f9912b7 | ||
|
|
361ca788a7 | ||
|
|
68a249d23d | ||
|
|
95c8f1f866 | ||
|
|
fa17ea2715 | ||
|
|
c970c74d66 | ||
|
|
479da83f57 | ||
|
|
feca9e8103 | ||
|
|
a041ffa702 | ||
|
|
5eafc080e1 | ||
|
|
8558b2d278 | ||
|
|
756f837f82 | ||
|
|
0b838ff2c9 | ||
|
|
ca43608aa0 | ||
|
|
ad471b46b8 | ||
|
|
e6b357e87a | ||
|
|
b676fb1164 | ||
|
|
ca68b84623 | ||
|
|
d6bc78dcb8 | ||
|
|
2104fd7da9 | ||
|
|
c801a9e8cf | ||
|
|
c9a6446041 | ||
|
|
a2f24fac65 | ||
|
|
eaec888dc3 | ||
|
|
69d8cca38a | ||
|
|
04a3968206 | ||
|
|
ae699a6b13 | ||
|
|
9257ef42ba | ||
|
|
63f899a407 | ||
|
|
690cf16aa5 | ||
|
|
aaf831cd93 | ||
|
|
472a0b4954 | ||
|
|
c04323a7d5 | ||
|
|
fac4905e89 | ||
|
|
65e55ac094 | ||
|
|
f23d24ec7c | ||
|
|
e332adf3d5 | ||
|
|
13f00ea8ed | ||
|
|
a14e542ecb | ||
|
|
6065f08528 | ||
|
|
d455b05619 | ||
|
|
d49b941ea9 | ||
|
|
478be16fc5 | ||
|
|
26c1ddf104 | ||
|
|
f759d5dbc1 | ||
|
|
ea09ffc8ce | ||
|
|
6d5ce9b87f | ||
|
|
24d4353ab2 | ||
|
|
822f9e0a80 | ||
|
|
09600f2ca4 | ||
|
|
42e472ff3f | ||
|
|
285d271505 | ||
|
|
dcba6dfa7e | ||
|
|
953a1eefbb | ||
|
|
d5331d4150 | ||
|
|
61ea403bfa | ||
|
|
d5e19f9b28 | ||
|
|
d8c7c9fdb5 | ||
|
|
ed1ca47199 | ||
|
|
885b8bcc60 | ||
|
|
31e05cd2bd | ||
|
|
7fb72a0081 | ||
|
|
f3e3ebba81 | ||
|
|
51b780cd9f | ||
|
|
25b0c5af34 | ||
|
|
6ab20e7f03 | ||
|
|
6846a5179b | ||
|
|
eb5399445a | ||
|
|
83c08880a6 | ||
|
|
172a02557e | ||
|
|
2d3501be61 | ||
|
|
d07ec9a19f | ||
|
|
ed860dfa23 | ||
|
|
09e8079ea3 | ||
|
|
b42a7780e2 | ||
|
|
4ee90bd82f | ||
|
|
12cd4ca742 | ||
|
|
713a46cd75 | ||
|
|
f236328bc3 | ||
|
|
6e06978961 | ||
|
|
8edcfbe776 | ||
|
|
1c60173b69 | ||
|
|
59579bfc3e | ||
|
|
7f22c0883b | ||
|
|
78b941019b | ||
|
|
ae728d84f0 | ||
|
|
3eab35ef22 | ||
|
|
c260435913 | ||
|
|
a5351b5c47 | ||
|
|
718d8acc76 | ||
|
|
e8c3c7b5eb | ||
|
|
8f575bf986 | ||
|
|
cf48c6004d | ||
|
|
d0dc5dfd3d | ||
|
|
af473b085a | ||
|
|
9e778f3a61 | ||
|
|
52855ce1c1 | ||
|
|
22000a703a | ||
|
|
f6f54955fe | ||
|
|
1459d17bfd | ||
|
|
77646f7149 | ||
|
|
1e83f62d31 | ||
|
|
df9ca20339 | ||
|
|
b60f97cc19 | ||
|
|
ab946fdf2c | ||
|
|
d9956a9d05 | ||
|
|
2713c846f1 | ||
|
|
3056848819 | ||
|
|
08c3f3c236 | ||
|
|
a01eda79e8 |
45
.github/workflows/build-template.yml
vendored
45
.github/workflows/build-template.yml
vendored
@@ -104,7 +104,7 @@ jobs:
|
||||
# NOTE: must be in sync with `save` below and with `restore-cache` in `update-stage0.yml`
|
||||
path: |
|
||||
.ccache
|
||||
${{ matrix.name == 'Linux Lake (cached)' && 'build/stage1/**/*.trace
|
||||
${{ matrix.name == 'Linux Lake' && 'build/stage1/**/*.trace
|
||||
build/stage1/**/*.olean*
|
||||
build/stage1/**/*.ilean
|
||||
build/stage1/**/*.ir
|
||||
@@ -166,6 +166,22 @@ jobs:
|
||||
# contortion to support empty OPTIONS with old macOS bash
|
||||
cmake .. --preset ${{ matrix.CMAKE_PRESET || 'release' }} -B . ${{ matrix.CMAKE_OPTIONS }} ${OPTIONS[@]+"${OPTIONS[@]}"} -DLEAN_INSTALL_PREFIX=$PWD/..
|
||||
time make $TARGET_STAGE -j$NPROC
|
||||
# Should be done as early as possible and in particular *before* "Check rebootstrap" which
|
||||
# changes the state of stage1/
|
||||
- name: Save Cache
|
||||
if: steps.restore-cache.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
# NOTE: must be in sync with `restore` above
|
||||
path: |
|
||||
.ccache
|
||||
${{ matrix.name == 'Linux Lake' && 'build/stage1/**/*.trace
|
||||
build/stage1/**/*.olean*
|
||||
build/stage1/**/*.ilean
|
||||
build/stage1/**/*.ir
|
||||
build/stage1/**/*.c
|
||||
build/stage1/**/*.c.o*' || '' }}
|
||||
key: ${{ steps.restore-cache.outputs.cache-primary-key }}
|
||||
- name: Install
|
||||
run: |
|
||||
make -C build/$TARGET_STAGE install
|
||||
@@ -205,7 +221,7 @@ jobs:
|
||||
id: test
|
||||
run: |
|
||||
ulimit -c unlimited # coredumps
|
||||
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/$TARGET_STAGE -j$NPROC --output-junit test-results.xml ${{ matrix.CTARGET_OPTIONS }}
|
||||
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/$TARGET_STAGE -j$NPROC --output-junit test-results.xml
|
||||
if: (matrix.wasm || !matrix.cross) && (inputs.check-level >= 1 || matrix.test)
|
||||
- name: Test Summary
|
||||
uses: test-summary/action@v2
|
||||
@@ -235,9 +251,13 @@ jobs:
|
||||
if: matrix.test-speedcenter
|
||||
- name: Check rebootstrap
|
||||
run: |
|
||||
set -e
|
||||
# clean rebuild in case of Makefile changes/Lake does not detect uncommited stage 0
|
||||
# changes yet
|
||||
make -C build update-stage0 && make -C build/stage1 clean-stdlib && make -C build -j$NPROC
|
||||
make -C build update-stage0
|
||||
make -C build/stage1 clean-stdlib
|
||||
time make -C build -j$NPROC
|
||||
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/stage1 -j$NPROC
|
||||
if: matrix.check-rebootstrap
|
||||
- name: CCache stats
|
||||
if: always()
|
||||
@@ -249,22 +269,3 @@ jobs:
|
||||
progbin="$(file $c | sed "s/.*execfn: '\([^']*\)'.*/\1/")"
|
||||
echo bt | $GDB/bin/gdb -q $progbin $c || true
|
||||
done
|
||||
- name: Save Cache
|
||||
if: always() && steps.restore-cache.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
# NOTE: must be in sync with `restore` above
|
||||
path: |
|
||||
.ccache
|
||||
${{ matrix.name == 'Linux Lake (cached)' && 'build/stage1/**/*.trace
|
||||
build/stage1/**/*.olean*
|
||||
build/stage1/**/*.ilean
|
||||
build/stage1/**/*.ir
|
||||
build/stage1/**/*.c
|
||||
build/stage1/**/*.c.o*' || '' }}
|
||||
key: ${{ steps.restore-cache.outputs.cache-primary-key }}
|
||||
- name: Upload Build Artifact
|
||||
if: always() && matrix.name == 'Linux Lake (cached)'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: build
|
||||
|
||||
26
.github/workflows/ci.yml
vendored
26
.github/workflows/ci.yml
vendored
@@ -181,7 +181,9 @@ jobs:
|
||||
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*",
|
||||
"binary-check": "ldd -v",
|
||||
// foreign code may be linked against more recent glibc
|
||||
"CTEST_OPTIONS": "-E 'foreign'"
|
||||
"CTEST_OPTIONS": "-E 'foreign'",
|
||||
// not compatible with `prepare-llvm` currently
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=OFF",
|
||||
},
|
||||
{
|
||||
"name": "Linux Lake",
|
||||
@@ -192,13 +194,7 @@ jobs:
|
||||
"check-stage3": level >= 2,
|
||||
// NOTE: `test-speedcenter` currently seems to be broken on `ubuntu-latest`
|
||||
"test-speedcenter": large && level >= 2,
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=ON",
|
||||
},
|
||||
{
|
||||
"name": "Linux Lake (cached)",
|
||||
"os": "ubuntu-latest",
|
||||
"check-level": (isPr || isPushToMaster) ? 0 : 2,
|
||||
"secondary": true,
|
||||
// made explicit until it can be assumed to have propagated to PRs
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=ON",
|
||||
},
|
||||
{
|
||||
@@ -228,7 +224,9 @@ jobs:
|
||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/19.1.2/lean-llvm-x86_64-apple-darwin.tar.zst",
|
||||
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm*",
|
||||
"binary-check": "otool -L",
|
||||
"tar": "gtar" // https://github.com/actions/runner-images/issues/2619
|
||||
"tar": "gtar", // https://github.com/actions/runner-images/issues/2619
|
||||
// not compatible with `prepare-llvm` currently
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=OFF",
|
||||
},
|
||||
{
|
||||
"name": "macOS aarch64",
|
||||
@@ -244,6 +242,8 @@ jobs:
|
||||
// See "Linux release" for release job levels; Grove is not a concern here
|
||||
"check-level": isPr ? 0 : 2,
|
||||
"secondary": isPr,
|
||||
// not compatible with `prepare-llvm` currently
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=OFF",
|
||||
},
|
||||
{
|
||||
"name": "Windows",
|
||||
@@ -256,7 +256,9 @@ jobs:
|
||||
"CTEST_OPTIONS": "--repeat until-pass:2",
|
||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/19.1.2/lean-llvm-x86_64-w64-windows-gnu.tar.zst",
|
||||
"prepare-llvm": "../script/prepare-llvm-mingw.sh lean-llvm*",
|
||||
"binary-check": "ldd"
|
||||
"binary-check": "ldd",
|
||||
// not compatible with `prepare-llvm` currently
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=OFF",
|
||||
},
|
||||
{
|
||||
"name": "Linux aarch64",
|
||||
@@ -266,7 +268,9 @@ jobs:
|
||||
"check-level": 2,
|
||||
"shell": "nix develop .#oldGlibcAArch -c bash -euxo pipefail {0}",
|
||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/19.1.2/lean-llvm-aarch64-linux-gnu.tar.zst",
|
||||
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*"
|
||||
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*",
|
||||
// not compatible with `prepare-llvm` currently
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=OFF",
|
||||
},
|
||||
// Started running out of memory building expensive modules, a 2GB heap is just not that much even before fragmentation
|
||||
//{
|
||||
|
||||
7
.github/workflows/update-stage0.yml
vendored
7
.github/workflows/update-stage0.yml
vendored
@@ -57,9 +57,14 @@ jobs:
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
# NOTE: must be in sync with `restore-cache` in `build-template.yml`
|
||||
# TODO: actually switch to USE_LAKE once it caches more; for now it just caches more often than any other build type so let's use its cache
|
||||
path: |
|
||||
.ccache
|
||||
build/stage1/**/*.trace
|
||||
build/stage1/**/*.olean*
|
||||
build/stage1/**/*.ilean
|
||||
build/stage1/**/*.ir
|
||||
build/stage1/**/*.c
|
||||
build/stage1/**/*.c.o*
|
||||
key: Linux Lake-build-v3-${{ github.sha }}
|
||||
# fall back to (latest) previous cache
|
||||
restore-keys: |
|
||||
|
||||
@@ -147,6 +147,10 @@ add_custom_target(test
|
||||
COMMAND $(MAKE) -C stage1 test
|
||||
DEPENDS stage1)
|
||||
|
||||
add_custom_target(clean-stdlib
|
||||
COMMAND $(MAKE) -C stage1 clean-stdlib
|
||||
DEPENDS stage1)
|
||||
|
||||
install(CODE "execute_process(COMMAND make -C stage1 install)")
|
||||
|
||||
add_custom_target(check-stage3
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Lean Build Bootstrapping
|
||||
|
||||
Since version 4, Lean is a partially bootstrapped program: most parts of the
|
||||
Lean is a bootstrapped program: the
|
||||
frontend and compiler are written in Lean itself and thus need to be built before
|
||||
building Lean itself - which is needed to again build those parts. This cycle is
|
||||
broken by using pre-built C files checked into the repository (which ultimately
|
||||
@@ -73,6 +73,11 @@ update the archived C source code of the stage 0 compiler in `stage0/src`.
|
||||
The github repository will automatically update stage0 on `master` once
|
||||
`src/stdlib_flags.h` and `stage0/src/stdlib_flags.h` are out of sync.
|
||||
|
||||
NOTE: A full rebuild of stage 1 will only be triggered when the *committed* contents of `stage0/` are changed.
|
||||
Thus if you change files in it manually instead of through `update-stage0-commit` (see below) or fetching updates from git, you either need to commit those changes first or run `make -C build/release clean-stdlib`.
|
||||
The same is true for further stages except that a rebuild of them is retriggered on any commited change, not just to a specific directory.
|
||||
Thus when debugging e.g. stage 2 failures, you can resume the build from these failures on but may want to explicitly call `clean-stdlib` to either observe changes from `.olean` files of modules that built successfully or to check that you did not break modules that built successfully at some prior point.
|
||||
|
||||
If you have write access to the lean4 repository, you can 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>
|
||||
@@ -82,13 +87,13 @@ 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
|
||||
to do it locally, you can use `make -C build/release update-stage0-commit` to
|
||||
update `stage0` from `stage1` or `make -C build/release/stageN update-stage0-commit` to
|
||||
update from another stage. This command will automatically stage the updated files
|
||||
and introduce a commit,so make sure to commit your work before that.
|
||||
and introduce a commit, so make sure to commit your work before that.
|
||||
|
||||
If you rebased the branch (either onto a newer version of `master`, or fixing
|
||||
up some commits prior to the stage0 update, recreate the stage0 update commits.
|
||||
up some commits prior to the stage0 update), recreate the stage0 update commits.
|
||||
The script `script/rebase-stage0.sh` can be used for that.
|
||||
|
||||
The CI should prevent PRs with changes to stage0 (besides `stdlib_flags.h`)
|
||||
|
||||
@@ -9,7 +9,7 @@ You should not edit the `stage0` directory except using the commands described i
|
||||
## Development Setup
|
||||
|
||||
You can use any of the [supported editors](../setup.md) for editing the Lean source code.
|
||||
If you set up `elan` as below, opening `src/` as a *workspace folder* should ensure that stage 0 (i.e. the stage that first compiles `src/`) will be used for files in that directory.
|
||||
Please see below for specific instructions for VS Code.
|
||||
|
||||
### Dev setup using elan
|
||||
|
||||
@@ -68,6 +68,10 @@ code lean.code-workspace
|
||||
```
|
||||
on the command line.
|
||||
|
||||
You can use the `Refresh File Dependencies` command as in other projects to rebuild modules from inside VS Code but be aware that this does not trigger any non-Lake build targets.
|
||||
In particular, after updating `stage0/` (or fetching an update to it), you will want to invoke `make` directly to rebuild `stage0/bin/lean` as described in [building Lean](../make/index.md).
|
||||
You should then run the `Restart Server` command to update all open files and the server watchdog process as well.
|
||||
|
||||
### `ccache`
|
||||
|
||||
Lean's build process uses [`ccache`](https://ccache.dev/) if it is
|
||||
|
||||
@@ -282,7 +282,7 @@ theorem BinTree.find_insert_of_ne (b : BinTree β) (ne : k ≠ k') (v : β)
|
||||
let ⟨t, h⟩ := b; simp
|
||||
induction t with simp
|
||||
| leaf =>
|
||||
intros le
|
||||
intro le
|
||||
exact Nat.lt_of_le_of_ne le ne
|
||||
| node left key value right ihl ihr =>
|
||||
let .node hl hr bl br := h
|
||||
|
||||
@@ -53,11 +53,6 @@ There are also two alternative presets that combine some of these options you ca
|
||||
Select the C/C++ compilers to use. Official Lean releases currently use Clang;
|
||||
see also `.github/workflows/ci.yml` for the CI config.
|
||||
|
||||
* `-DUSE_LAKE=ON`\
|
||||
Experimental option to build the core libraries using Lake instead of `lean.mk`. Caveats:
|
||||
* As native code compilation is still handled by cmake, changes to stage0/ (such as from `git pull`) are picked up only when invoking the build via `make`, not via `Refresh Dependencies` in the editor.
|
||||
* `USE_LAKE` is not yet compatible with `LAKE_ARTIFACT_CACHE`
|
||||
|
||||
Lean will automatically use [CCache](https://ccache.dev/) if available to avoid
|
||||
redundant builds, especially after stage 0 has been updated.
|
||||
|
||||
|
||||
12
flake.nix
12
flake.nix
@@ -18,14 +18,14 @@
|
||||
# An old nixpkgs for creating releases with an old glibc
|
||||
pkgsDist-old-aarch = import inputs.nixpkgs-old { localSystem.config = "aarch64-unknown-linux-gnu"; };
|
||||
|
||||
lean-packages = pkgs.callPackage (./nix/packages.nix) { src = ./.; };
|
||||
llvmPackages = pkgs.llvmPackages_15;
|
||||
|
||||
devShellWithDist = pkgsDist: pkgs.mkShell.override {
|
||||
stdenv = pkgs.overrideCC pkgs.stdenv lean-packages.llvmPackages.clang;
|
||||
stdenv = pkgs.overrideCC pkgs.stdenv llvmPackages.clang;
|
||||
} ({
|
||||
buildInputs = with pkgs; [
|
||||
cmake gmp libuv ccache pkg-config
|
||||
lean-packages.llvmPackages.llvm # llvm-symbolizer for asan/lsan
|
||||
llvmPackages.llvm # llvm-symbolizer for asan/lsan
|
||||
gdb
|
||||
tree # for CI
|
||||
];
|
||||
@@ -60,12 +60,6 @@
|
||||
GDB = pkgsDist.gdb;
|
||||
});
|
||||
in {
|
||||
packages.${system} = {
|
||||
# to be removed when Nix CI is not needed anymore
|
||||
inherit (lean-packages) cacheRoots test update-stage0-commit ciShell;
|
||||
deprecated = lean-packages;
|
||||
};
|
||||
|
||||
devShells.${system} = {
|
||||
# The default development shell for working on lean itself
|
||||
default = devShellWithDist pkgs;
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
set -eo pipefail
|
||||
|
||||
for pkg in $buildInputs; do
|
||||
export PATH=$PATH:$pkg/bin
|
||||
done
|
||||
|
||||
: ${outputs:=out}
|
||||
@@ -1,208 +0,0 @@
|
||||
{ src, debug ? false, stage0debug ? false, extraCMakeFlags ? [],
|
||||
stdenv, lib, cmake, pkg-config, gmp, libuv, cadical, git, gnumake, bash, buildLeanPackage, writeShellScriptBin, runCommand, symlinkJoin, lndir, perl, gnused, darwin, llvmPackages, linkFarmFromDrvs,
|
||||
... } @ args:
|
||||
with builtins;
|
||||
lib.warn "The Nix-based build is deprecated" rec {
|
||||
inherit stdenv;
|
||||
sourceByRegex = p: rs: lib.sourceByRegex p (map (r: "(/src/)?${r}") rs);
|
||||
buildCMake = args: stdenv.mkDerivation ({
|
||||
nativeBuildInputs = [ cmake pkg-config ];
|
||||
buildInputs = [ gmp libuv llvmPackages.llvm ];
|
||||
# https://github.com/NixOS/nixpkgs/issues/60919
|
||||
hardeningDisable = [ "all" ];
|
||||
dontStrip = (args.debug or debug);
|
||||
|
||||
postConfigure = ''
|
||||
patchShebangs .
|
||||
'';
|
||||
} // args // {
|
||||
src = args.realSrc or (sourceByRegex args.src [ "[a-z].*" "CMakeLists\.txt" ]);
|
||||
cmakeFlags = ["-DSMALL_ALLOCATOR=ON" "-DUSE_MIMALLOC=OFF"] ++ (args.cmakeFlags or [ "-DSTAGE=1" "-DPREV_STAGE=./faux-prev-stage" "-DUSE_GITHASH=OFF" "-DCADICAL=${cadical}/bin/cadical" ]) ++ (args.extraCMakeFlags or extraCMakeFlags) ++ lib.optional (args.debug or debug) [ "-DCMAKE_BUILD_TYPE=Debug" ];
|
||||
preConfigure = args.preConfigure or "" + ''
|
||||
# ignore absence of submodule
|
||||
sed -i 's!lake/Lake.lean!!' CMakeLists.txt
|
||||
'';
|
||||
});
|
||||
lean-bin-tools-unwrapped = buildCMake {
|
||||
name = "lean-bin-tools";
|
||||
outputs = [ "out" "leanc_src" ];
|
||||
realSrc = sourceByRegex (src + "/src") [ "CMakeLists\.txt" "[a-z].*" ".*\.in" "Leanc\.lean" ];
|
||||
dontBuild = true;
|
||||
installPhase = ''
|
||||
mkdir $out $leanc_src
|
||||
mv bin/ include/ share/ $out/
|
||||
mv leanc.sh $out/bin/leanc
|
||||
mv leanc/Leanc.lean $leanc_src/
|
||||
substituteInPlace $out/bin/leanc --replace '$root' "$out" --replace " sed " " ${gnused}/bin/sed "
|
||||
substituteInPlace $out/bin/leanmake --replace "make" "${gnumake}/bin/make"
|
||||
substituteInPlace $out/share/lean/lean.mk --replace "/usr/bin/env bash" "${bash}/bin/bash"
|
||||
'';
|
||||
};
|
||||
leancpp = buildCMake {
|
||||
name = "leancpp";
|
||||
src = src + "/src";
|
||||
buildFlags = [ "leancpp" "leanrt" "leanrt_initial-exec" "leanshell" "leanmain" ];
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
mv lib/ $out/
|
||||
mv runtime/libleanrt_initial-exec.a $out/lib
|
||||
'';
|
||||
};
|
||||
stage0 = args.stage0 or (buildCMake {
|
||||
name = "lean-stage0";
|
||||
realSrc = src + "/stage0/src";
|
||||
debug = stage0debug;
|
||||
cmakeFlags = [ "-DSTAGE=0" ];
|
||||
extraCMakeFlags = [];
|
||||
preConfigure = ''
|
||||
ln -s ${src + "/stage0/stdlib"} ../stdlib
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin $out/lib/lean
|
||||
mv bin/lean $out/bin/
|
||||
mv lib/lean/*.{so,dylib} $out/lib/lean
|
||||
'';
|
||||
meta.mainProgram = "lean";
|
||||
});
|
||||
stage = { stage, prevStage, self }:
|
||||
let
|
||||
desc = "stage${toString stage}";
|
||||
build = args: buildLeanPackage.override {
|
||||
lean = prevStage;
|
||||
leanc = lean-bin-tools-unwrapped;
|
||||
# use same stage for retrieving dependencies
|
||||
lean-leanDeps = stage0;
|
||||
lean-final = self;
|
||||
} ({
|
||||
src = src + "/src";
|
||||
roots = [ { mod = args.name; glob = "andSubmodules"; } ];
|
||||
fullSrc = src;
|
||||
srcPath = "$PWD/src:$PWD/src/lake";
|
||||
inherit debug;
|
||||
leanFlags = [ "-DwarningAsError=true" ];
|
||||
} // args);
|
||||
Init' = build { name = "Init"; deps = []; };
|
||||
Std' = build { name = "Std"; deps = [ Init' ]; };
|
||||
Lean' = build { name = "Lean"; deps = [ Std' ]; };
|
||||
attachSharedLib = sharedLib: pkg: pkg // {
|
||||
inherit sharedLib;
|
||||
mods = mapAttrs (_: m: m // { inherit sharedLib; propagatedLoadDynlibs = []; }) pkg.mods;
|
||||
};
|
||||
in (all: all // all.lean) rec {
|
||||
inherit (Lean) emacs-dev emacs-package vscode-dev vscode-package;
|
||||
Init = attachSharedLib leanshared Init';
|
||||
Std = attachSharedLib leanshared Std' // { allExternalDeps = [ Init ]; };
|
||||
Lean = attachSharedLib leanshared Lean' // { allExternalDeps = [ Std ]; };
|
||||
Lake = build {
|
||||
name = "Lake";
|
||||
sharedLibName = "Lake_shared";
|
||||
src = src + "/src/lake";
|
||||
deps = [ Init Lean ];
|
||||
};
|
||||
Lake-Main = build {
|
||||
name = "LakeMain";
|
||||
roots = [{ glob = "one"; mod = "LakeMain"; }];
|
||||
executableName = "lake";
|
||||
deps = [ Lake ];
|
||||
linkFlags = lib.optional stdenv.isLinux "-rdynamic";
|
||||
src = src + "/src/lake";
|
||||
};
|
||||
stdlib = [ Init Std Lean Lake ];
|
||||
modDepsFiles = symlinkJoin { name = "modDepsFiles"; paths = map (l: l.modDepsFile) (stdlib ++ [ Leanc ]); };
|
||||
depRoots = symlinkJoin { name = "depRoots"; paths = map (l: l.depRoots) stdlib; };
|
||||
iTree = symlinkJoin { name = "ileans"; paths = map (l: l.iTree) stdlib; };
|
||||
Leanc = build { name = "Leanc"; src = lean-bin-tools-unwrapped.leanc_src; deps = stdlib; roots = [ "Leanc" ]; };
|
||||
stdlibLinkFlags = "${lib.concatMapStringsSep " " (l: "-L${l.staticLib}") stdlib} -L${leancpp}/lib/lean";
|
||||
libInit_shared = runCommand "libInit_shared" { buildInputs = [ stdenv.cc ]; libName = "libInit_shared${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
|
||||
mkdir $out
|
||||
touch empty.c
|
||||
${stdenv.cc}/bin/cc -shared -o $out/$libName empty.c
|
||||
'';
|
||||
leanshared_1 = runCommand "leanshared_1" { buildInputs = [ stdenv.cc ]; libName = "leanshared_1${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
|
||||
mkdir $out
|
||||
touch empty.c
|
||||
${stdenv.cc}/bin/cc -shared -o $out/$libName empty.c
|
||||
'';
|
||||
leanshared = runCommand "leanshared" { buildInputs = [ stdenv.cc ]; libName = "libleanshared${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
|
||||
mkdir $out
|
||||
LEAN_CC=${stdenv.cc}/bin/cc ${lean-bin-tools-unwrapped}/bin/leanc -shared ${lib.optionalString stdenv.isLinux "-Wl,-Bsymbolic"} \
|
||||
-Wl,--whole-archive ${leancpp}/lib/temp/libleanshell.a -lInit -lStd -lLean -lleancpp ${leancpp}/lib/libleanrt_initial-exec.a -Wl,--no-whole-archive -lstdc++ \
|
||||
-lm ${stdlibLinkFlags} \
|
||||
$(${llvmPackages.libllvm.dev}/bin/llvm-config --ldflags --libs) \
|
||||
-o $out/$libName
|
||||
'';
|
||||
mods = foldl' (mods: pkg: mods // pkg.mods) {} stdlib;
|
||||
print-paths = Lean.makePrintPathsFor [] mods;
|
||||
leanc = writeShellScriptBin "leanc" ''
|
||||
LEAN_CC=${stdenv.cc}/bin/cc ${Leanc.executable}/bin/leanc -I${lean-bin-tools-unwrapped}/include ${stdlibLinkFlags} -L${libInit_shared} -L${leanshared_1} -L${leanshared} -L${Lake.sharedLib} "$@"
|
||||
'';
|
||||
lean = runCommand "lean" { buildInputs = lib.optional stdenv.isDarwin darwin.cctools; } ''
|
||||
mkdir -p $out/bin
|
||||
${leanc}/bin/leanc ${leancpp}/lib/temp/libleanmain.a ${libInit_shared}/* ${leanshared_1}/* ${leanshared}/* -o $out/bin/lean
|
||||
'';
|
||||
# derivation following the directory layout of the "basic" setup, mostly useful for running tests
|
||||
lean-all = stdenv.mkDerivation {
|
||||
name = "lean-${desc}";
|
||||
buildCommand = ''
|
||||
mkdir -p $out/bin $out/lib/lean
|
||||
ln -sf ${leancpp}/lib/lean/* ${lib.concatMapStringsSep " " (l: "${l.modRoot}/* ${l.staticLib}/*") (lib.reverseList stdlib)} ${libInit_shared}/* ${leanshared_1}/* ${leanshared}/* ${Lake.sharedLib}/* $out/lib/lean/
|
||||
# put everything in a single final derivation so `IO.appDir` references work
|
||||
cp ${lean}/bin/lean ${leanc}/bin/leanc ${Lake-Main.executable}/bin/lake $out/bin
|
||||
# NOTE: `lndir` will not override existing `bin/leanc`
|
||||
${lndir}/bin/lndir -silent ${lean-bin-tools-unwrapped} $out
|
||||
'';
|
||||
meta.mainProgram = "lean";
|
||||
};
|
||||
cacheRoots = linkFarmFromDrvs "cacheRoots" ([
|
||||
stage0 lean leanc lean-all iTree modDepsFiles depRoots Leanc.src
|
||||
] ++ map (lib: lib.oTree) stdlib);
|
||||
test = buildCMake {
|
||||
name = "lean-test-${desc}";
|
||||
realSrc = lib.sourceByRegex src [ "src.*" "tests.*" ];
|
||||
buildInputs = [ gmp libuv perl git cadical ];
|
||||
preConfigure = ''
|
||||
cd src
|
||||
'';
|
||||
extraCMakeFlags = [ "-DLLVM=OFF" ];
|
||||
postConfigure = ''
|
||||
patchShebangs ../../tests ../lake
|
||||
rm -r bin lib include share
|
||||
ln -sf ${lean-all}/* .
|
||||
'';
|
||||
buildPhase = ''
|
||||
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)|leanlaketest_reverse-ffi|leanruntest_timeIO' -j$NIX_BUILD_CORES
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir $out
|
||||
mv test-results.xml $out
|
||||
'';
|
||||
};
|
||||
update-stage0 =
|
||||
let cTree = symlinkJoin { name = "cs"; paths = map (lib: lib.cTree) (stdlib ++ [Lake-Main]); }; in
|
||||
writeShellScriptBin "update-stage0" ''
|
||||
CSRCS=${cTree} CP_C_PARAMS="--dereference --no-preserve=all" ${src + "/script/lib/update-stage0"}
|
||||
'';
|
||||
update-stage0-commit = writeShellScriptBin "update-stage0-commit" ''
|
||||
set -euo pipefail
|
||||
${update-stage0}/bin/update-stage0
|
||||
git commit -m "chore: update stage0"
|
||||
'';
|
||||
link-ilean = writeShellScriptBin "link-ilean" ''
|
||||
dest=''${1:-src}
|
||||
rm -rf $dest/build/lib || true
|
||||
mkdir -p $dest/build/lib
|
||||
ln -s ${iTree}/* $dest/build/lib
|
||||
'';
|
||||
benchmarks =
|
||||
let
|
||||
entries = attrNames (readDir (src + "/tests/bench"));
|
||||
leanFiles = map (n: elemAt n 0) (filter (n: n != null) (map (match "(.*)\.lean") entries));
|
||||
in lib.genAttrs leanFiles (n: (buildLeanPackage {
|
||||
name = n;
|
||||
src = filterSource (e: _: baseNameOf e == "${n}.lean") (src + "/tests/bench");
|
||||
}).executable);
|
||||
};
|
||||
stage1 = stage { stage = 1; prevStage = stage0; self = stage1; };
|
||||
stage2 = stage { stage = 2; prevStage = stage1; self = stage2; };
|
||||
stage3 = stage { stage = 3; prevStage = stage2; self = stage3; };
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
{ lean, lean-leanDeps ? lean, lean-final ? lean, leanc,
|
||||
stdenv, lib, coreutils, gnused, writeShellScriptBin, bash, substituteAll, symlinkJoin, linkFarmFromDrvs,
|
||||
runCommand, darwin, mkShell, ... }:
|
||||
let lean-final' = lean-final; in
|
||||
lib.makeOverridable (
|
||||
{ name, src, fullSrc ? src, srcPrefix ? "", srcPath ? "$PWD/${srcPrefix}",
|
||||
# Lean dependencies. Each entry should be an output of buildLeanPackage.
|
||||
deps ? [ lean.Init lean.Std lean.Lean ],
|
||||
# Static library dependencies. Each derivation `static` should contain a static library in the directory `${static}`.
|
||||
staticLibDeps ? [],
|
||||
# Whether to wrap static library inputs in a -Wl,--start-group [...] -Wl,--end-group to ensure dependencies are resolved.
|
||||
groupStaticLibs ? false,
|
||||
# Shared library dependencies included at interpretation with --load-dynlib and linked to. Each derivation `shared` should contain a
|
||||
# shared library at the path `${shared}/${shared.libName or shared.name}` and a name to link to like `-l${shared.linkName or shared.name}`.
|
||||
# These libs are also linked to in packages that depend on this one.
|
||||
nativeSharedLibs ? [],
|
||||
# Lean modules to include.
|
||||
# A set of Lean modules names as strings (`"Foo.Bar"`) or attrsets (`{ name = "Foo.Bar"; glob = "one" | "submodules" | "andSubmodules"; }`);
|
||||
# see Lake README for glob meanings. Dependencies of selected modules are always included.
|
||||
roots ? [ name ],
|
||||
# Output from `lean --deps-json` on package source files. Persist the corresponding output attribute to a file and pass it back in here to avoid IFD.
|
||||
# Must be refreshed on any change in `import`s or set of source file names.
|
||||
modDepsFile ? null,
|
||||
# Whether to compile each module into a native shared library that is loaded whenever the module is imported in order to accelerate evaluation
|
||||
precompileModules ? false,
|
||||
# Whether to compile the package into a native shared library that is loaded whenever *any* of the package's modules is imported into another package.
|
||||
# If `precompileModules` is also `true`, the latter only affects imports within the current package.
|
||||
precompilePackage ? precompileModules,
|
||||
# Lean plugin dependencies. Each derivation `plugin` should contain a plugin library at path `${plugin}/${plugin.name}`.
|
||||
pluginDeps ? [],
|
||||
# `overrideAttrs` for `buildMod`
|
||||
overrideBuildModAttrs ? null,
|
||||
debug ? false, leanFlags ? [], leancFlags ? [], linkFlags ? [], executableName ? lib.toLower name, libName ? name, sharedLibName ? libName,
|
||||
srcTarget ? "..#stage0", srcArgs ? "(\${args[*]})", lean-final ? lean-final' }@args:
|
||||
with builtins; let
|
||||
# "Init.Core" ~> "Init/Core"
|
||||
modToPath = mod: replaceStrings ["."] ["/"] mod;
|
||||
modToAbsPath = mod: "${src}/${modToPath mod}";
|
||||
# sanitize file name before copying to store, except when already in store
|
||||
copyToStoreSafe = base: suffix: if lib.isDerivation base then base + suffix else
|
||||
builtins.path { name = lib.strings.sanitizeDerivationName (baseNameOf suffix); path = base + suffix; };
|
||||
modToLean = mod: copyToStoreSafe src "/${modToPath mod}.lean";
|
||||
bareStdenv = ./bareStdenv;
|
||||
mkBareDerivation = args: derivation (args // {
|
||||
name = lib.strings.sanitizeDerivationName args.name;
|
||||
stdenv = bareStdenv;
|
||||
inherit (stdenv) system;
|
||||
buildInputs = (args.buildInputs or []) ++ [ coreutils ];
|
||||
builder = stdenv.shell;
|
||||
args = [ "-c" ''
|
||||
source $stdenv/setup
|
||||
set -u
|
||||
${args.buildCommand}
|
||||
'' ];
|
||||
}) // { overrideAttrs = f: mkBareDerivation (lib.fix (lib.extends f (_: args))); };
|
||||
runBareCommand = name: args: buildCommand: mkBareDerivation (args // { inherit name buildCommand; });
|
||||
runBareCommandLocal = name: args: buildCommand: runBareCommand name (args // {
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
}) buildCommand;
|
||||
mkSharedLib = name: args: runBareCommand "${name}-dynlib" {
|
||||
buildInputs = [ stdenv.cc ] ++ lib.optional stdenv.isDarwin darwin.cctools;
|
||||
libName = "${name}${stdenv.hostPlatform.extensions.sharedLibrary}";
|
||||
} ''
|
||||
mkdir -p $out
|
||||
${leanc}/bin/leanc -shared ${args} -o $out/$libName
|
||||
'';
|
||||
depRoot = name: deps: mkBareDerivation {
|
||||
name = "${name}-depRoot";
|
||||
inherit deps;
|
||||
depRoots = map (drv: drv.LEAN_PATH) deps;
|
||||
|
||||
passAsFile = [ "deps" "depRoots" ];
|
||||
buildCommand = ''
|
||||
mkdir -p $out
|
||||
for i in $(cat $depRootsPath); do
|
||||
cp -dru --no-preserve=mode $i/. $out
|
||||
done
|
||||
for i in $(cat $depsPath); do
|
||||
cp -drsu --no-preserve=mode $i/. $out
|
||||
done
|
||||
'';
|
||||
};
|
||||
srcRoot = src;
|
||||
|
||||
# A flattened list of Lean-module dependencies (`deps`)
|
||||
allExternalDeps = lib.unique (lib.foldr (dep: allExternalDeps: allExternalDeps ++ [ dep ] ++ dep.allExternalDeps) [] deps);
|
||||
allNativeSharedLibs =
|
||||
lib.unique (lib.flatten (nativeSharedLibs ++ (map (dep: dep.allNativeSharedLibs or []) allExternalDeps)));
|
||||
|
||||
# A flattened list of all static library dependencies: this and every dep module's explicitly provided `staticLibDeps`,
|
||||
# plus every dep module itself: `dep.staticLib`
|
||||
allStaticLibDeps =
|
||||
lib.unique (lib.flatten (staticLibDeps ++ (map (dep: [dep.staticLib] ++ dep.staticLibDeps or []) allExternalDeps)));
|
||||
|
||||
pathOfSharedLib = dep: dep.libPath or "${dep}/${dep.libName or dep.name}";
|
||||
|
||||
leanPluginFlags = lib.concatStringsSep " " (map (dep: "--plugin=${pathOfSharedLib dep}") pluginDeps);
|
||||
loadDynlibsOfDeps = deps: lib.unique (concatMap (d: d.propagatedLoadDynlibs) deps);
|
||||
|
||||
# submodules "Init" = ["Init.List.Basic", "Init.Core", ...]
|
||||
submodules = mod: let
|
||||
dir = readDir (modToAbsPath mod);
|
||||
f = p: t:
|
||||
if t == "directory" then
|
||||
submodules "${mod}.${p}"
|
||||
else
|
||||
let m = builtins.match "(.*)\.lean" p;
|
||||
in lib.optional (m != null) "${mod}.${head m}";
|
||||
in concatLists (lib.mapAttrsToList f dir);
|
||||
|
||||
# conservatively approximate list of source files matched by glob
|
||||
expandGlobAllApprox = g:
|
||||
if typeOf g == "string" then
|
||||
# we can't know the required files without parsing dependencies (which is what we want this
|
||||
# function for), so we approximate to the entire package.
|
||||
let root = (head (split "\\." g));
|
||||
in lib.optional (pathExists (src + "/${modToPath root}.lean")) root ++ lib.optionals (pathExists (modToAbsPath root)) (submodules root)
|
||||
else if g.glob == "one" then expandGlobAllApprox g.mod
|
||||
else if g.glob == "submodules" then submodules g.mod
|
||||
else if g.glob == "andSubmodules" then [g.mod] ++ submodules g.mod
|
||||
else throw "unknown glob kind '${g}'";
|
||||
# list of modules that could potentially be involved in the build
|
||||
candidateMods = lib.unique (concatMap expandGlobAllApprox roots);
|
||||
candidateFiles = map modToLean candidateMods;
|
||||
modDepsFile = args.modDepsFile or mkBareDerivation {
|
||||
name = "${name}-deps.json";
|
||||
candidateFiles = lib.concatStringsSep " " candidateFiles;
|
||||
passAsFile = [ "candidateFiles" ];
|
||||
buildCommand = ''
|
||||
mkdir $out
|
||||
${lean-leanDeps}/bin/lean --deps-json --stdin < $candidateFilesPath > $out/$name
|
||||
'';
|
||||
};
|
||||
modDeps = fromJSON (
|
||||
# the only possible references to store paths in the JSON should be inside errors, so no chance of missed dependencies from this
|
||||
unsafeDiscardStringContext (readFile "${modDepsFile}/${modDepsFile.name}"));
|
||||
# map from module name to list of imports
|
||||
modDepsMap = listToAttrs (lib.zipListsWith lib.nameValuePair candidateMods modDeps.imports);
|
||||
maybeOverrideAttrs = f: x: if f != null then x.overrideAttrs f else x;
|
||||
# build module (.olean and .c) given derivations of all (immediate) dependencies
|
||||
# TODO: make `rec` parts override-compatible?
|
||||
buildMod = mod: deps: maybeOverrideAttrs overrideBuildModAttrs (mkBareDerivation rec {
|
||||
name = "${mod}";
|
||||
LEAN_PATH = depRoot mod deps;
|
||||
LEAN_ABORT_ON_PANIC = "1";
|
||||
relpath = modToPath mod;
|
||||
buildInputs = [ lean ];
|
||||
leanPath = relpath + ".lean";
|
||||
# should be either single .lean file or directory directly containing .lean file plus dependencies
|
||||
src = copyToStoreSafe srcRoot ("/" + leanPath);
|
||||
outputs = [ "out" "ilean" "c" ];
|
||||
oleanPath = relpath + ".olean";
|
||||
ileanPath = relpath + ".ilean";
|
||||
cPath = relpath + ".c";
|
||||
inherit leanFlags leanPluginFlags;
|
||||
leanLoadDynlibFlags = map (p: "--load-dynlib=${pathOfSharedLib p}") (loadDynlibsOfDeps deps);
|
||||
buildCommand = ''
|
||||
dir=$(dirname $relpath)
|
||||
mkdir -p $dir $out/$dir $ilean/$dir $c/$dir
|
||||
if [ -d $src ]; then cp -r $src/. .; else cp $src $leanPath; fi
|
||||
lean -o $out/$oleanPath -i $out/$ileanPath -c $c/$cPath $leanPath $leanFlags $leanPluginFlags $leanLoadDynlibFlags
|
||||
'';
|
||||
}) // {
|
||||
inherit deps;
|
||||
propagatedLoadDynlibs = loadDynlibsOfDeps deps;
|
||||
};
|
||||
compileMod = mod: drv: mkBareDerivation {
|
||||
name = "${mod}-cc";
|
||||
buildInputs = [ leanc stdenv.cc ];
|
||||
hardeningDisable = [ "all" ];
|
||||
oPath = drv.relpath + ".o";
|
||||
inherit leancFlags;
|
||||
buildCommand = ''
|
||||
mkdir -p $out/$(dirname ${drv.relpath})
|
||||
# make local "copy" so `drv`'s Nix store path doesn't end up in ccache's hash
|
||||
ln -s ${drv.c}/${drv.cPath} src.c
|
||||
# on the other hand, a debug build is pretty fast anyway, so preserve the path for gdb
|
||||
leanc -c -o $out/$oPath $leancFlags -fPIC ${if debug then "${drv.c}/${drv.cPath} -g" else "src.c -O3 -DNDEBUG -DLEAN_EXPORTING"}
|
||||
'';
|
||||
};
|
||||
mkMod = mod: deps:
|
||||
let drv = buildMod mod deps;
|
||||
obj = compileMod mod drv;
|
||||
# this attribute will only be used if any dependent module is precompiled
|
||||
sharedLib = mkSharedLib mod "${obj}/${obj.oPath} ${lib.concatStringsSep " " (map (d: pathOfSharedLib d.sharedLib) deps)}";
|
||||
in drv // {
|
||||
inherit obj sharedLib;
|
||||
} // lib.optionalAttrs precompileModules {
|
||||
propagatedLoadDynlibs = [sharedLib];
|
||||
};
|
||||
externalModMap = lib.foldr (dep: depMap: depMap // dep.mods) {} allExternalDeps;
|
||||
# map from module name to derivation
|
||||
modCandidates = mapAttrs (mod: header:
|
||||
let
|
||||
deps = if header.errors == []
|
||||
then map (m: m.module) header.result.imports
|
||||
else abort "errors while parsing imports of ${mod}:\n${lib.concatStringsSep "\n" header.errors}";
|
||||
in mkMod mod (map (dep: if modDepsMap ? ${dep} then modCandidates.${dep} else externalModMap.${dep}) deps)) modDepsMap;
|
||||
expandGlob = g:
|
||||
if typeOf g == "string" then [g]
|
||||
else if g.glob == "one" then [g.mod]
|
||||
else if g.glob == "submodules" then submodules g.mod
|
||||
else if g.glob == "andSubmodules" then [g.mod] ++ submodules g.mod
|
||||
else throw "unknown glob kind '${g}'";
|
||||
# subset of `modCandidates` that is transitively reachable from `roots`
|
||||
mods' = listToAttrs (map (e: { name = e.key; value = modCandidates.${e.key}; }) (genericClosure {
|
||||
startSet = map (m: { key = m; }) (concatMap expandGlob roots);
|
||||
operator = e: if modDepsMap ? ${e.key} then map (m: { key = m.module; }) (filter (m: modCandidates ? ${m.module}) modDepsMap.${e.key}.result.imports) else [];
|
||||
}));
|
||||
allLinkFlags = lib.foldr (shared: acc: acc ++ [ "-L${shared}" "-l${shared.linkName or shared.name}" ]) linkFlags allNativeSharedLibs;
|
||||
|
||||
objects = mapAttrs (_: m: m.obj) mods';
|
||||
bintools = if stdenv.isDarwin then darwin.cctools else stdenv.cc.bintools.bintools;
|
||||
staticLib = runCommand "${name}-lib" { buildInputs = [ bintools ]; } ''
|
||||
mkdir -p $out
|
||||
ar Trcs $out/lib${libName}.a ${lib.concatStringsSep " " (map (drv: "${drv}/${drv.oPath}") (attrValues objects))};
|
||||
'';
|
||||
|
||||
staticLibLinkWrapper = libs: if groupStaticLibs && !stdenv.isDarwin
|
||||
then "-Wl,--start-group ${libs} -Wl,--end-group"
|
||||
else "${libs}";
|
||||
in rec {
|
||||
inherit name lean deps staticLibDeps allNativeSharedLibs allLinkFlags allExternalDeps src objects staticLib modDepsFile;
|
||||
mods = mapAttrs (_: m:
|
||||
m //
|
||||
# if neither precompilation option was set but a dependent module wants to be precompiled, default to precompiling this package whole
|
||||
lib.optionalAttrs (precompilePackage || !precompileModules) { inherit sharedLib; } //
|
||||
lib.optionalAttrs precompilePackage { propagatedLoadDynlibs = [sharedLib]; })
|
||||
mods';
|
||||
modRoot = depRoot name (attrValues mods);
|
||||
depRoots = linkFarmFromDrvs "depRoots" (map (m: m.LEAN_PATH) (attrValues mods));
|
||||
cTree = symlinkJoin { name = "${name}-cTree"; paths = map (mod: mod.c) (attrValues mods); };
|
||||
oTree = symlinkJoin { name = "${name}-oTree"; paths = (attrValues objects); };
|
||||
iTree = symlinkJoin { name = "${name}-iTree"; paths = map (mod: mod.ilean) (attrValues mods); };
|
||||
sharedLib = mkSharedLib "lib${sharedLibName}" ''
|
||||
${if stdenv.isDarwin then "-Wl,-force_load,${staticLib}/lib${libName}.a" else "-Wl,--whole-archive ${staticLib}/lib${libName}.a -Wl,--no-whole-archive"} \
|
||||
${lib.concatStringsSep " " (map (d: "${d.sharedLib}/*") deps)}'';
|
||||
executable = lib.makeOverridable ({ withSharedStdlib ? true }: let
|
||||
objPaths = map (drv: "${drv}/${drv.oPath}") (attrValues objects) ++ lib.optional withSharedStdlib "${lean-final.leanshared}/*";
|
||||
in runCommand executableName { buildInputs = [ stdenv.cc leanc ]; } ''
|
||||
mkdir -p $out/bin
|
||||
leanc ${staticLibLinkWrapper (lib.concatStringsSep " " (objPaths ++ map (d: "${d}/*.a") allStaticLibDeps))} \
|
||||
-o $out/bin/${executableName} \
|
||||
${lib.concatStringsSep " " allLinkFlags}
|
||||
'') {};
|
||||
})
|
||||
@@ -1,42 +0,0 @@
|
||||
#!@bash@/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
function pebkac() {
|
||||
echo 'This is just a simple Nix adapter for `lake print-paths|serve`.'
|
||||
exit 1
|
||||
}
|
||||
|
||||
[[ $# -gt 0 ]] || pebkac
|
||||
case $1 in
|
||||
--version)
|
||||
# minimum version for `lake serve` with fallback
|
||||
echo 3.1.0
|
||||
;;
|
||||
print-paths)
|
||||
shift
|
||||
deps="$@"
|
||||
root=.
|
||||
# fall back to initial package if not in package
|
||||
[[ ! -f "$root/flake.nix" ]] && root="@srcRoot@"
|
||||
target="$root#print-paths"
|
||||
args=()
|
||||
# HACK: use stage 0 instead of 1 inside Lean's own `src/`
|
||||
[[ -d Lean && -f ../flake.nix ]] && target="@srcTarget@print-paths" && args=@srcArgs@
|
||||
for dep in $deps; do
|
||||
target="$target.\"$dep\""
|
||||
done
|
||||
echo "Building dependencies..." >&2
|
||||
# -v only has "built ...", but "-vv" is a bit too verbose
|
||||
exec @nix@/bin/nix run "$target" ${args[*]} -v
|
||||
;;
|
||||
serve)
|
||||
shift
|
||||
[[ ${1:-} == "--" ]] && shift
|
||||
# `link-ilean` puts them there
|
||||
LEAN_PATH=${LEAN_PATH:+$LEAN_PATH:}$PWD/build/lib exec $(dirname $0)/lean --server "$@"
|
||||
;;
|
||||
*)
|
||||
pebkac
|
||||
;;
|
||||
esac
|
||||
@@ -1,28 +0,0 @@
|
||||
#!@bash@/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
root="."
|
||||
# find package root
|
||||
while [[ "$root" != / ]]; do
|
||||
[ -f "$root/flake.nix" ] && break
|
||||
root="$(realpath "$root/..")"
|
||||
done
|
||||
# fall back to initial package if not in package
|
||||
[[ ! -f "$root/flake.nix" ]] && root="@srcRoot@"
|
||||
|
||||
# use Lean w/ package unless in server mode (which has its own LEAN_PATH logic)
|
||||
target="$root#lean-package"
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--server | --worker | -v | --version)
|
||||
target="$root#lean"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
args=(-- "$@")
|
||||
# HACK: use stage 0 instead of 1 inside Lean's own `src/`
|
||||
[[ -d Lean && -f ../flake.nix ]] && target="@srcTarget@" && args=@srcArgs@
|
||||
|
||||
LEAN_SYSROOT="$(dirname "$0")/.." exec @nix@/bin/nix ${LEAN_NIX_ARGS:-} run "$target" ${args[*]}
|
||||
@@ -1,52 +0,0 @@
|
||||
{ src, pkgs, ... } @ args:
|
||||
with pkgs;
|
||||
let
|
||||
# https://github.com/NixOS/nixpkgs/issues/130963
|
||||
llvmPackages = if stdenv.isDarwin then llvmPackages_11 else llvmPackages_15;
|
||||
cc = (ccacheWrapper.override rec {
|
||||
cc = llvmPackages.clang;
|
||||
extraConfig = ''
|
||||
export CCACHE_DIR=/nix/var/cache/ccache
|
||||
export CCACHE_UMASK=007
|
||||
export CCACHE_BASE_DIR=$NIX_BUILD_TOP
|
||||
# https://github.com/NixOS/nixpkgs/issues/109033
|
||||
args=("$@")
|
||||
for ((i=0; i<"''${#args[@]}"; i++)); do
|
||||
case ''${args[i]} in
|
||||
-frandom-seed=*) unset args[i]; break;;
|
||||
esac
|
||||
done
|
||||
set -- "''${args[@]}"
|
||||
[ -d $CCACHE_DIR ] || exec ${cc}/bin/$(basename "$0") "$@"
|
||||
'';
|
||||
}).overrideAttrs (old: {
|
||||
# https://github.com/NixOS/nixpkgs/issues/119779
|
||||
installPhase = builtins.replaceStrings ["use_response_file_by_default=1"] ["use_response_file_by_default=0"] old.installPhase;
|
||||
});
|
||||
stdenv' = if stdenv.isLinux then useGoldLinker stdenv else stdenv;
|
||||
lean = callPackage (import ./bootstrap.nix) (args // {
|
||||
stdenv = overrideCC stdenv' cc;
|
||||
inherit src buildLeanPackage llvmPackages;
|
||||
});
|
||||
makeOverridableLeanPackage = f:
|
||||
let newF = origArgs: f origArgs // {
|
||||
overrideArgs = newArgs: makeOverridableLeanPackage f (origArgs // newArgs);
|
||||
};
|
||||
in lib.setFunctionArgs newF (lib.getFunctionArgs f) // {
|
||||
override = args: makeOverridableLeanPackage (f.override args);
|
||||
};
|
||||
buildLeanPackage = makeOverridableLeanPackage (callPackage (import ./buildLeanPackage.nix) (args // {
|
||||
inherit (lean) stdenv;
|
||||
lean = lean.stage1;
|
||||
inherit (lean.stage1) leanc;
|
||||
}));
|
||||
in {
|
||||
inherit cc buildLeanPackage llvmPackages;
|
||||
nixpkgs = pkgs;
|
||||
ciShell = writeShellScriptBin "ciShell" ''
|
||||
set -o pipefail
|
||||
export PATH=${moreutils}/bin:$PATH
|
||||
# prefix lines with cumulative and individual execution time
|
||||
"$@" |& ts -i "(%.S)]" | ts -s "[%M:%S"
|
||||
'';
|
||||
} // lean.stage1
|
||||
@@ -1 +0,0 @@
|
||||
#eval "Hello, world!"
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
description = "My Lean package";
|
||||
|
||||
inputs.lean.url = "github:leanprover/lean4";
|
||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||
|
||||
outputs = { self, lean, flake-utils }: flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
leanPkgs = lean.packages.${system};
|
||||
pkg = leanPkgs.buildLeanPackage {
|
||||
name = "MyPackage"; # must match the name of the top-level .lean file
|
||||
src = ./.;
|
||||
};
|
||||
in {
|
||||
packages = pkg // {
|
||||
inherit (leanPkgs) lean;
|
||||
};
|
||||
|
||||
defaultPackage = pkg.modRoot;
|
||||
});
|
||||
}
|
||||
101
script/AnalyzeGrindAnnotations.lean
Normal file
101
script/AnalyzeGrindAnnotations.lean
Normal file
@@ -0,0 +1,101 @@
|
||||
/-
|
||||
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
import Lean
|
||||
|
||||
namespace Lean.Meta.Grind.Analyzer
|
||||
|
||||
|
||||
/-!
|
||||
A simple E-matching annotation analyzer.
|
||||
For each theorem annotated as an E-matching candidate, it creates an artificial goal, executes `grind` and shows the
|
||||
number of instances created.
|
||||
For a theorem of the form `params -> type`, the artificial goal is of the form `params -> type -> False`.
|
||||
-/
|
||||
|
||||
/--
|
||||
`grind` configuration for the analyzer. We disable case-splits and lookahead,
|
||||
increase the number of generations, and limit the number of instances generated.
|
||||
-/
|
||||
def config : Grind.Config := {
|
||||
splits := 0
|
||||
lookahead := false
|
||||
mbtc := false
|
||||
ematch := 20
|
||||
instances := 100
|
||||
gen := 10
|
||||
}
|
||||
|
||||
structure Config where
|
||||
/-- Minimum number of instantiations to trigger summary report -/
|
||||
min : Nat := 10
|
||||
/-- Minimum number of instantiations to trigger detailed report -/
|
||||
detailed : Nat := 50
|
||||
|
||||
def mkParams : MetaM Params := do
|
||||
let params ← Grind.mkParams config
|
||||
let ematch ← getEMatchTheorems
|
||||
let casesTypes ← Grind.getCasesTypes
|
||||
return { params with ematch, casesTypes }
|
||||
|
||||
/-- Returns the total number of generated instances. -/
|
||||
private def sum (cs : PHashMap Origin Nat) : Nat := Id.run do
|
||||
let mut r := 0
|
||||
for (_, c) in cs do
|
||||
r := r + c
|
||||
return r
|
||||
|
||||
private def thmsToMessageData (thms : PHashMap Origin Nat) : MetaM MessageData := do
|
||||
let data := thms.toArray.filterMap fun (origin, c) =>
|
||||
match origin with
|
||||
| .decl declName => some (declName, c)
|
||||
| _ => none
|
||||
let data := data.qsort fun (d₁, c₁) (d₂, c₂) => if c₁ == c₂ then Name.lt d₁ d₂ else c₁ > c₂
|
||||
let data ← data.mapM fun (declName, counter) =>
|
||||
return .trace { cls := `thm } m!"{.ofConst (← mkConstWithLevelParams declName)} ↦ {counter}" #[]
|
||||
return .trace { cls := `thm } "instances" data
|
||||
|
||||
/--
|
||||
Analyzes theorem `declName`. That is, creates the artificial goal based on `declName` type,
|
||||
and invokes `grind` on it.
|
||||
-/
|
||||
def analyzeEMatchTheorem (declName : Name) (c : Config) : MetaM Unit := do
|
||||
let info ← getConstInfo declName
|
||||
let mvarId ← forallTelescope info.type fun _ type => do
|
||||
withLocalDeclD `h type fun _ => do
|
||||
return (← mkFreshExprMVar (mkConst ``False)).mvarId!
|
||||
let result ← Grind.main mvarId (← mkParams) (pure ())
|
||||
let thms := result.counters.thm
|
||||
let s := sum thms
|
||||
if s > c.min then
|
||||
IO.println s!"{declName} : {s}"
|
||||
if s > c.detailed then
|
||||
logInfo m!"{declName}\n{← thmsToMessageData thms}"
|
||||
|
||||
-- Not sure why this is failing: `down_pure` perhaps has an unnecessary universe parameter?
|
||||
run_meta analyzeEMatchTheorem ``Std.Do.SPred.down_pure {}
|
||||
|
||||
/-- Analyzes all theorems in the standard library marked as E-matching theorems. -/
|
||||
def analyzeEMatchTheorems (c : Config := {}) : MetaM Unit := do
|
||||
let origins := (← getEMatchTheorems).getOrigins
|
||||
let decls := origins.filterMap fun | .decl declName => some declName | _ => none
|
||||
for declName in decls.mergeSort Name.lt do
|
||||
try
|
||||
analyzeEMatchTheorem declName c
|
||||
catch e =>
|
||||
logError m!"{declName} failed with {e.toMessageData}"
|
||||
logInfo m!"Finished analyzing {decls.length} theorems"
|
||||
|
||||
/-- Macro for analyzing E-match theorems with unlimited heartbeats -/
|
||||
macro "#analyzeEMatchTheorems" : command => `(
|
||||
set_option maxHeartbeats 0 in
|
||||
run_meta analyzeEMatchTheorems
|
||||
)
|
||||
|
||||
#analyzeEMatchTheorems
|
||||
|
||||
-- -- We can analyze specific theorems using commands such as
|
||||
set_option trace.grind.ematch.instance true in
|
||||
run_meta analyzeEMatchTheorem ``List.filterMap_some {}
|
||||
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
set -euxo pipefail
|
||||
|
||||
cmake --preset release -DUSE_LAKE=ON 1>&2
|
||||
cmake --preset release 1>&2
|
||||
|
||||
# We benchmark against stage 2 to test new optimizations.
|
||||
# We benchmark against stage2/bin to test new optimizations.
|
||||
timeout -s KILL 1h time make -C build/release -j$(nproc) stage3 1>&2
|
||||
export PATH=$PWD/build/release/stage2/bin:$PATH
|
||||
|
||||
@@ -11,6 +11,86 @@ export PATH=$PWD/build/release/stage2/bin:$PATH
|
||||
# easier to configure them statically.
|
||||
cmake -B build/release/stage3 -S src -DLEAN_EXTRA_LAKEFILE_TOML='weakLeanArgs=["-Dprofiler=true", "-Dprofiler.threshold=9999999", "--stats"]' 1>&2
|
||||
|
||||
(
|
||||
cd tests/bench
|
||||
timeout -s KILL 1h time temci exec --config speedcenter.yaml --in speedcenter.exec.velcom.yaml 1>&2
|
||||
temci report run_output.yaml --reporter codespeed2
|
||||
)
|
||||
|
||||
if [ -d .git ]; then
|
||||
DIR="$(git rev-parse @)"
|
||||
BASE_URL="https://speed.lean-lang.org/lean4-out/$DIR"
|
||||
{
|
||||
cat <<'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Lakeprof Report</title>
|
||||
</head>
|
||||
<h1>Lakeprof Report</h1>
|
||||
<button type="button" id="btn_fetch">View build trace in Perfetto</button>
|
||||
<script type="text/javascript">
|
||||
const ORIGIN = 'https://ui.perfetto.dev';
|
||||
|
||||
const btnFetch = document.getElementById('btn_fetch');
|
||||
|
||||
async function fetchAndOpen(traceUrl) {
|
||||
const resp = await fetch(traceUrl);
|
||||
// Error checking is left as an exercise to the reader.
|
||||
const blob = await resp.blob();
|
||||
const arrayBuffer = await blob.arrayBuffer();
|
||||
openTrace(arrayBuffer, traceUrl);
|
||||
}
|
||||
|
||||
function openTrace(arrayBuffer, traceUrl) {
|
||||
const win = window.open(ORIGIN);
|
||||
if (!win) {
|
||||
btnFetch.style.background = '#f3ca63';
|
||||
btnFetch.onclick = () => openTrace(arrayBuffer);
|
||||
btnFetch.innerText = 'Popups blocked, click here to open the trace file';
|
||||
return;
|
||||
}
|
||||
|
||||
const timer = setInterval(() => win.postMessage('PING', ORIGIN), 50);
|
||||
|
||||
const onMessageHandler = (evt) => {
|
||||
if (evt.data !== 'PONG') return;
|
||||
|
||||
// We got a PONG, the UI is ready.
|
||||
window.clearInterval(timer);
|
||||
window.removeEventListener('message', onMessageHandler);
|
||||
|
||||
const reopenUrl = new URL(location.href);
|
||||
reopenUrl.hash = `#reopen=${traceUrl}`;
|
||||
win.postMessage({
|
||||
perfetto: {
|
||||
buffer: arrayBuffer,
|
||||
title: 'Lake Build Trace',
|
||||
url: reopenUrl.toString(),
|
||||
}}, ORIGIN);
|
||||
};
|
||||
|
||||
window.addEventListener('message', onMessageHandler);
|
||||
}
|
||||
|
||||
// This is triggered when following the link from the Perfetto UI's sidebar.
|
||||
if (location.hash.startsWith('#reopen=')) {
|
||||
const traceUrl = location.hash.substr(8);
|
||||
fetchAndOpen(traceUrl);
|
||||
}
|
||||
EOF
|
||||
cat <<EOF
|
||||
btnFetch.onclick = () => fetchAndOpen("$BASE_URL/lakeprof.trace_event");
|
||||
</script>
|
||||
EOF
|
||||
echo "<pre><code>"
|
||||
(cd src; lakeprof report -prc)
|
||||
echo "</code></pre>"
|
||||
echo "</body></html>"
|
||||
} | tee index.html
|
||||
|
||||
curl -T index.html $BASE_URL/index.html
|
||||
curl -T src/lakeprof.log $BASE_URL/lakeprof.log
|
||||
curl -T src/lakeprof.trace_event $BASE_URL/lakeprof.trace_event
|
||||
fi
|
||||
|
||||
@@ -28,13 +28,6 @@ repositories:
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: doc-gen4
|
||||
url: https://github.com/leanprover/doc-gen4
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: [lean4-cli]
|
||||
|
||||
- name: verso
|
||||
url: https://github.com/leanprover/verso
|
||||
toolchain-tag: true
|
||||
@@ -42,6 +35,28 @@ repositories:
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: plausible
|
||||
url: https://github.com/leanprover-community/plausible
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: import-graph
|
||||
url: https://github.com/leanprover-community/import-graph
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies:
|
||||
- lean4-cli
|
||||
|
||||
- name: doc-gen4
|
||||
url: https://github.com/leanprover/doc-gen4
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: [lean4-cli]
|
||||
|
||||
- name: reference-manual
|
||||
url: https://github.com/leanprover/reference-manual
|
||||
toolchain-tag: true
|
||||
@@ -65,22 +80,6 @@ repositories:
|
||||
dependencies:
|
||||
- batteries
|
||||
|
||||
- name: import-graph
|
||||
url: https://github.com/leanprover-community/import-graph
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies:
|
||||
- lean4-cli
|
||||
- batteries
|
||||
|
||||
- name: plausible
|
||||
url: https://github.com/leanprover-community/plausible
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: mathlib4
|
||||
url: https://github.com/leanprover-community/mathlib4
|
||||
toolchain-tag: true
|
||||
|
||||
@@ -10,7 +10,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 23)
|
||||
set(LEAN_VERSION_MINOR 24)
|
||||
set(LEAN_VERSION_PATCH 0)
|
||||
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
|
||||
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
|
||||
@@ -81,7 +81,7 @@ option(USE_MIMALLOC "use mimalloc" ON)
|
||||
|
||||
# development-specific options
|
||||
option(CHECK_OLEAN_VERSION "Only load .olean files compiled with the current version of Lean" OFF)
|
||||
option(USE_LAKE "Use Lake instead of lean.mk for building core libs from language server" OFF)
|
||||
option(USE_LAKE "Use Lake instead of lean.mk for building core libs from language server" ON)
|
||||
|
||||
set(LEAN_EXTRA_MAKE_OPTS "" CACHE STRING "extra options to lean --make")
|
||||
set(LEANC_CC ${CMAKE_C_COMPILER} CACHE STRING "C compiler to use in `leanc`")
|
||||
@@ -684,12 +684,17 @@ if (LLVM AND ${STAGE} GREATER 0)
|
||||
set(EXTRA_LEANMAKE_OPTS "LLVM=1")
|
||||
endif()
|
||||
|
||||
set(STDLIBS Init Std Lean Leanc)
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
list(APPEND STDLIBS Lake)
|
||||
endif()
|
||||
|
||||
add_custom_target(make_stdlib ALL
|
||||
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
||||
# The actual rule is in a separate makefile because we want to prefix it with '+' to use the Make job server
|
||||
# for a parallelized nested build, but CMake doesn't let us do that.
|
||||
# We use `lean` from the previous stage, but `leanc`, headers, etc. from the current stage
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Init Std Lean Leanc
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make ${STDLIBS}
|
||||
VERBATIM)
|
||||
|
||||
# if we have LLVM enabled, then build `lean.h.bc` which has the LLVM bitcode
|
||||
@@ -733,14 +738,9 @@ else()
|
||||
endif()
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
add_custom_target(lake_lib
|
||||
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
||||
DEPENDS leanshared
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Lake
|
||||
VERBATIM)
|
||||
add_custom_target(lake_shared
|
||||
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
||||
DEPENDS lake_lib
|
||||
DEPENDS leanshared
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make libLake_shared
|
||||
VERBATIM)
|
||||
add_custom_target(lake ALL
|
||||
|
||||
@@ -29,6 +29,29 @@ theorem id_def {α : Sort u} (a : α) : id a = a := rfl
|
||||
|
||||
attribute [grind] id
|
||||
|
||||
/--
|
||||
A helper gadget for instructing the kernel to eagerly reduce terms.
|
||||
|
||||
When the gadget wraps the argument of an application, then when checking that
|
||||
the expected and inferred type of the argument match, the kernel will evaluate terms more eagerly.
|
||||
It is often used to wrap `Eq.refl true` proof terms as `eagerReduce (Eq.refl true)`
|
||||
when using proof by reflection.
|
||||
As an example, consider the theorem:
|
||||
```
|
||||
theorem eq_norm (ctx : Context) (p₁ p₂ : Poly) (h : (p₁.norm == p₂) = true) :
|
||||
p₁.denote ctx = 0 → p₂.denote ctx = 0
|
||||
```
|
||||
The argument `h : (p₁.norm == p₂) = true` is a candidate for `eagerReduce`.
|
||||
When applying this theorem, we would write:
|
||||
|
||||
```
|
||||
eq_norm ctx p q (eagerReduce (Eq.refl true)) h
|
||||
```
|
||||
to instruct the kernel to use eager reduction when establishing that `(p.norm == q) = true` is
|
||||
definitionally equal to `true = true`.
|
||||
-/
|
||||
@[expose] def eagerReduce {α : Sort u} (a : α) : α := a
|
||||
|
||||
/--
|
||||
`flip f a b` is `f b a`. It is useful for "point-free" programming,
|
||||
since it can sometimes be used to avoid introducing variables.
|
||||
@@ -2499,12 +2522,17 @@ class Antisymm (r : α → α → Prop) : Prop where
|
||||
/-- An antisymmetric relation `r` satisfies `r a b → r b a → a = b`. -/
|
||||
antisymm (a b : α) : r a b → r b a → a = b
|
||||
|
||||
/-- `Asymm X r` means that the binary relation `r` on `X` is asymmetric, that is,
|
||||
/-- `Asymm r` means that the binary relation `r` is asymmetric, that is,
|
||||
`r a b → ¬ r b a`. -/
|
||||
class Asymm (r : α → α → Prop) : Prop where
|
||||
/-- An asymmetric relation satisfies `r a b → ¬ r b a`. -/
|
||||
asymm : ∀ a b, r a b → ¬r b a
|
||||
|
||||
/-- `Symm r` means that the binary relation `r` is symmetric, that is, `r a b → r b a`. -/
|
||||
class Symm (r : α → α → Prop) : Prop where
|
||||
/-- A symmetric relation satisfies `r a b → r b a`. -/
|
||||
symm : ∀ a b, r a b → r b a
|
||||
|
||||
/-- `Total X r` means that the binary relation `r` on `X` is total, that is, that for any
|
||||
`x y : X` we have `r x y` or `r y x`. -/
|
||||
class Total (r : α → α → Prop) : Prop where
|
||||
|
||||
@@ -25,7 +25,7 @@ public import Init.Data.SInt
|
||||
public import Init.Data.Float
|
||||
public import Init.Data.Float32
|
||||
public import Init.Data.Option
|
||||
public import Init.Data.Ord
|
||||
public import Init.Data.OrdRoot
|
||||
public import Init.Data.Random
|
||||
public import Init.Data.ToString
|
||||
public import Init.Data.Range
|
||||
@@ -49,5 +49,7 @@ public import Init.Data.Vector
|
||||
public import Init.Data.Iterators
|
||||
public import Init.Data.Range.Polymorphic
|
||||
public import Init.Data.Slice
|
||||
public import Init.Data.Order
|
||||
public import Init.Data.Rat
|
||||
|
||||
public section
|
||||
|
||||
@@ -163,7 +163,7 @@ representation of arrays. While this is not provable, `Array.usize` always retur
|
||||
the array since the implementation only supports arrays of size less than `USize.size`.
|
||||
-/
|
||||
@[extern "lean_array_size", simp]
|
||||
def usize (a : @& Array α) : USize := a.size.toUSize
|
||||
def usize (xs : @& Array α) : USize := xs.size.toUSize
|
||||
|
||||
/--
|
||||
Low-level indexing operator which is as fast as a C array read.
|
||||
@@ -171,8 +171,8 @@ Low-level indexing operator which is as fast as a C array read.
|
||||
This avoids overhead due to unboxing a `Nat` used as an index.
|
||||
-/
|
||||
@[extern "lean_array_uget", simp, expose]
|
||||
def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
|
||||
a[i.toNat]
|
||||
def uget (xs : @& Array α) (i : USize) (h : i.toNat < xs.size) : α :=
|
||||
xs[i.toNat]
|
||||
|
||||
/--
|
||||
Low-level modification operator which is as fast as a C array write. The modification is performed
|
||||
@@ -1165,7 +1165,7 @@ Examples:
|
||||
def zipIdx (xs : Array α) (start := 0) : Array (α × Nat) :=
|
||||
xs.mapIdx fun i a => (a, start + i)
|
||||
|
||||
@[deprecated zipIdx (since := "2025-01-21")] abbrev zipWithIndex := @zipIdx
|
||||
|
||||
|
||||
/--
|
||||
Returns the first element of the array for which the predicate `p` returns `true`, or `none` if no
|
||||
@@ -1285,7 +1285,7 @@ def findFinIdx? {α : Type u} (p : α → Bool) (as : Array α) : Option (Fin as
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
loop 0
|
||||
|
||||
theorem findIdx?_loop_eq_map_findFinIdx?_loop_val {xs : Array α} {p : α → Bool} {j} :
|
||||
private theorem findIdx?_loop_eq_map_findFinIdx?_loop_val {xs : Array α} {p : α → Bool} {j} :
|
||||
findIdx?.loop p xs j = (findFinIdx?.loop p xs j).map (·.val) := by
|
||||
unfold findIdx?.loop
|
||||
unfold findFinIdx?.loop
|
||||
@@ -1322,8 +1322,7 @@ def idxOfAux [BEq α] (xs : Array α) (v : α) (i : Nat) : Option (Fin xs.size)
|
||||
else none
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
@[deprecated idxOfAux (since := "2025-01-29")]
|
||||
abbrev indexOfAux := @idxOfAux
|
||||
|
||||
|
||||
/--
|
||||
Returns the index of the first element equal to `a`, or the size of the array if no element is equal
|
||||
@@ -1338,8 +1337,7 @@ Examples:
|
||||
def finIdxOf? [BEq α] (xs : Array α) (v : α) : Option (Fin xs.size) :=
|
||||
idxOfAux xs v 0
|
||||
|
||||
@[deprecated "`Array.indexOf?` has been deprecated, use `idxOf?` or `finIdxOf?` instead." (since := "2025-01-29")]
|
||||
abbrev indexOf? := @finIdxOf?
|
||||
|
||||
|
||||
/--
|
||||
Returns the index of the first element equal to `a`, or the size of the array if no element is equal
|
||||
|
||||
@@ -34,8 +34,8 @@ the index is in bounds. This is because the tactic itself needs to look up value
|
||||
arrays.
|
||||
-/
|
||||
@[deprecated "Use indexing notation `as[i]` instead" (since := "2025-02-17")]
|
||||
def get {α : Type u} (a : @& Array α) (i : @& Nat) (h : LT.lt i a.size) : α :=
|
||||
a.toList.get ⟨i, h⟩
|
||||
def get {α : Type u} (xs : @& Array α) (i : @& Nat) (h : LT.lt i xs.size) : α :=
|
||||
xs.toList.get ⟨i, h⟩
|
||||
|
||||
/--
|
||||
Use the indexing notation `a[i]!` instead.
|
||||
@@ -43,8 +43,8 @@ Use the indexing notation `a[i]!` instead.
|
||||
Access an element from an array, or panic if the index is out of bounds.
|
||||
-/
|
||||
@[deprecated "Use indexing notation `as[i]!` instead" (since := "2025-02-17"), expose]
|
||||
def get! {α : Type u} [Inhabited α] (a : @& Array α) (i : @& Nat) : α :=
|
||||
Array.getD a i default
|
||||
def get! {α : Type u} [Inhabited α] (xs : @& Array α) (i : @& Nat) : α :=
|
||||
Array.getD xs i default
|
||||
|
||||
theorem foldlM_toList.aux [Monad m]
|
||||
{f : β → α → m β} {xs : Array α} {i j} (H : xs.size ≤ i + j) {b} :
|
||||
@@ -123,15 +123,9 @@ abbrev pop_toList := @Array.toList_pop
|
||||
@[simp, grind =] theorem append_empty {xs : Array α} : xs ++ #[] = xs := by
|
||||
apply ext'; simp only [toList_append, List.append_nil]
|
||||
|
||||
@[deprecated append_empty (since := "2025-01-13")]
|
||||
abbrev append_nil := @append_empty
|
||||
|
||||
@[simp, grind =] theorem empty_append {xs : Array α} : #[] ++ xs = xs := by
|
||||
apply ext'; simp only [toList_append, List.nil_append]
|
||||
|
||||
@[deprecated empty_append (since := "2025-01-13")]
|
||||
abbrev nil_append := @empty_append
|
||||
|
||||
@[simp, grind _=_] theorem append_assoc {xs ys zs : Array α} : xs ++ ys ++ zs = xs ++ (ys ++ zs) := by
|
||||
apply ext'; simp only [toList_append, List.append_assoc]
|
||||
|
||||
@@ -142,7 +136,6 @@ abbrev nil_append := @empty_append
|
||||
rw [← appendList_eq_append]; unfold Array.appendList
|
||||
induction l generalizing xs <;> simp [*]
|
||||
|
||||
@[deprecated toList_appendList (since := "2024-12-11")]
|
||||
abbrev appendList_toList := @toList_appendList
|
||||
|
||||
|
||||
end Array
|
||||
|
||||
@@ -8,19 +8,20 @@ module
|
||||
prelude
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.List.Range
|
||||
public import all Init.Data.List.Control
|
||||
public import Init.Data.List.Nat.TakeDrop
|
||||
public import Init.Data.List.Nat.Modify
|
||||
public import Init.Data.List.Nat.Basic
|
||||
public import Init.Data.List.Monadic
|
||||
public import Init.Data.List.OfFn
|
||||
public import all Init.Data.Array.Bootstrap
|
||||
public import Init.Data.Array.Mem
|
||||
public import Init.Data.Array.DecidableEq
|
||||
public import Init.Data.Array.Lex.Basic
|
||||
public import Init.Data.Range.Lemmas
|
||||
public import Init.TacticsExtra
|
||||
public import Init.Data.List.ToArray
|
||||
import all Init.Data.List.Control
|
||||
import all Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Bootstrap
|
||||
|
||||
public section
|
||||
|
||||
@@ -311,7 +312,7 @@ theorem eq_push_pop_back!_of_size_ne_zero [Inhabited α] {xs : Array α} (h : xs
|
||||
xs = xs.pop.push xs.back! := by
|
||||
apply ext
|
||||
· simp [Nat.sub_add_cancel (Nat.zero_lt_of_ne_zero h)]
|
||||
· intros i h h'
|
||||
· intro i h h'
|
||||
if hlt : i < xs.pop.size then
|
||||
rw [getElem_push_lt (h:=hlt), getElem_pop]
|
||||
else
|
||||
@@ -837,15 +838,10 @@ theorem mem_of_contains_eq_true [BEq α] [LawfulBEq α] {a : α} {as : Array α}
|
||||
cases as
|
||||
simp
|
||||
|
||||
@[deprecated mem_of_contains_eq_true (since := "2024-12-12")]
|
||||
abbrev mem_of_elem_eq_true := @mem_of_contains_eq_true
|
||||
|
||||
theorem contains_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : Array α} (h : a ∈ as) : as.contains a = true := by
|
||||
theorem contains_eq_true_of_mem [BEq α] [ReflBEq α] {a : α} {as : Array α} (h : a ∈ as) :
|
||||
as.contains a = true := by
|
||||
cases as
|
||||
simpa using h
|
||||
|
||||
@[deprecated contains_eq_true_of_mem (since := "2024-12-12")]
|
||||
abbrev elem_eq_true_of_mem := @contains_eq_true_of_mem
|
||||
simpa using List.elem_eq_true_of_mem (Array.mem_toList_iff.mpr h)
|
||||
|
||||
@[simp] theorem elem_eq_contains [BEq α] {a : α} {xs : Array α} :
|
||||
elem a xs = xs.contains a := by
|
||||
@@ -904,15 +900,9 @@ theorem all_push {xs : Array α} {a : α} {p : α → Bool} :
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[deprecated getElem_set_self (since := "2024-12-11")]
|
||||
abbrev getElem_set_eq := @getElem_set_self
|
||||
|
||||
@[simp] theorem getElem?_set_self {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} :
|
||||
(xs.set i v)[i]? = some v := by simp [h]
|
||||
|
||||
@[deprecated getElem?_set_self (since := "2024-12-11")]
|
||||
abbrev getElem?_set_eq := @getElem?_set_self
|
||||
|
||||
@[simp] theorem getElem_set_ne {xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat}
|
||||
(pj : j < xs.size) (h : i ≠ j) :
|
||||
(xs.set i v)[j]'(by simp [*]) = xs[j] := by
|
||||
@@ -1003,9 +993,6 @@ grind_pattern mem_or_eq_of_mem_set => a ∈ xs.set i b
|
||||
theorem setIfInBounds_def (xs : Array α) (i : Nat) (a : α) :
|
||||
xs.setIfInBounds i a = if h : i < xs.size then xs.set i a else xs := rfl
|
||||
|
||||
@[deprecated set!_eq_setIfInBounds (since := "2024-12-12")]
|
||||
abbrev set!_is_setIfInBounds := @set!_eq_setIfInBounds
|
||||
|
||||
@[simp, grind] theorem size_setIfInBounds {xs : Array α} {i : Nat} {a : α} :
|
||||
(xs.setIfInBounds i a).size = xs.size := by
|
||||
if h : i < xs.size then
|
||||
@@ -1027,9 +1014,6 @@ abbrev set!_is_setIfInBounds := @set!_eq_setIfInBounds
|
||||
simp at h
|
||||
simp only [setIfInBounds, h, ↓reduceDIte, getElem_set_self]
|
||||
|
||||
@[deprecated getElem_setIfInBounds_self (since := "2024-12-11")]
|
||||
abbrev getElem_setIfInBounds_eq := @getElem_setIfInBounds_self
|
||||
|
||||
@[simp] theorem getElem_setIfInBounds_ne {xs : Array α} {i : Nat} {a : α} {j : Nat}
|
||||
(hj : j < xs.size) (h : i ≠ j) :
|
||||
(xs.setIfInBounds i a)[j]'(by simpa using hj) = xs[j] := by
|
||||
@@ -1049,9 +1033,6 @@ theorem getElem?_setIfInBounds_self_of_lt {xs : Array α} {i : Nat} {a : α} (h
|
||||
(xs.setIfInBounds i a)[i]? = some a := by
|
||||
simp [h]
|
||||
|
||||
@[deprecated getElem?_setIfInBounds_self (since := "2024-12-11")]
|
||||
abbrev getElem?_setIfInBounds_eq := @getElem?_setIfInBounds_self
|
||||
|
||||
@[simp] theorem getElem?_setIfInBounds_ne {xs : Array α} {i j : Nat} (h : i ≠ j) {a : α} :
|
||||
(xs.setIfInBounds i a)[j]? = xs[j]? := by
|
||||
simp [getElem?_setIfInBounds, h]
|
||||
@@ -1377,23 +1358,6 @@ theorem mapM_eq_mapM_toList [Monad m] [LawfulMonad m] {f : α → m β} {xs : Ar
|
||||
toList <$> xs.mapM f = xs.toList.mapM f := by
|
||||
simp [mapM_eq_mapM_toList]
|
||||
|
||||
@[deprecated "Use `mapM_eq_foldlM` instead" (since := "2025-01-08")]
|
||||
theorem mapM_map_eq_foldl {as : Array α} {f : α → β} {i : Nat} :
|
||||
mapM.map (m := Id) (pure <| f ·) as i b = pure (as.foldl (start := i) (fun acc a => acc.push (f a)) b) := by
|
||||
unfold mapM.map
|
||||
split <;> rename_i h
|
||||
· ext : 1
|
||||
dsimp [foldl, foldlM]
|
||||
rw [mapM_map_eq_foldl, dif_pos (by omega), foldlM.loop, dif_pos h]
|
||||
-- Calling `split` here gives a bad goal.
|
||||
have : size as - i = Nat.succ (size as - i - 1) := by omega
|
||||
rw [this]
|
||||
simp [foldl, foldlM, Nat.sub_add_eq]
|
||||
· dsimp [foldl, foldlM]
|
||||
rw [dif_pos (by omega), foldlM.loop, dif_neg h]
|
||||
rfl
|
||||
termination_by as.size - i
|
||||
|
||||
/--
|
||||
Use this as `induction ass using array₂_induction` on a hypothesis of the form `ass : Array (Array α)`.
|
||||
The hypothesis `ass` will be replaced with a hypothesis `ass : List (List α)`,
|
||||
@@ -2930,14 +2894,14 @@ theorem getElem_extract_loop_ge_aux {xs ys : Array α} {size start : Nat} (hge :
|
||||
exact Nat.sub_lt_left_of_lt_add hge h
|
||||
|
||||
theorem getElem_extract_loop_ge {xs ys : Array α} {size start : Nat} (hge : i ≥ ys.size)
|
||||
(h : i < (extract.loop xs size start ys).size)
|
||||
(h' := getElem_extract_loop_ge_aux hge h) :
|
||||
(extract.loop xs size start ys)[i] = xs[start + i - ys.size] := by
|
||||
(h : i < (extract.loop xs size start ys).size) :
|
||||
(extract.loop xs size start ys)[i] = xs[start + i - ys.size]'(getElem_extract_loop_ge_aux hge h) := by
|
||||
induction size using Nat.recAux generalizing start ys with
|
||||
| zero =>
|
||||
rw [size_extract_loop, Nat.zero_min, Nat.add_zero] at h
|
||||
omega
|
||||
| succ size ih =>
|
||||
have h' : start + i - ys.size < xs.size := getElem_extract_loop_ge_aux hge h
|
||||
have : start < xs.size := by
|
||||
apply Nat.lt_of_le_of_lt (Nat.le_add_right start (i - ys.size))
|
||||
rwa [← Nat.add_sub_assoc hge]
|
||||
@@ -2991,7 +2955,7 @@ theorem getElem?_extract {xs : Array α} {start stop : Nat} :
|
||||
apply List.ext_getElem
|
||||
· simp only [length_toList, size_extract, List.length_take, List.length_drop]
|
||||
omega
|
||||
· intros n h₁ h₂
|
||||
· intro n h₁ h₂
|
||||
simp
|
||||
|
||||
@[simp] theorem extract_size {xs : Array α} : xs.extract 0 xs.size = xs := by
|
||||
@@ -2999,9 +2963,6 @@ theorem getElem?_extract {xs : Array α} {start stop : Nat} :
|
||||
· rw [size_extract, Nat.min_self, Nat.sub_zero]
|
||||
· intros; rw [getElem_extract]; congr; rw [Nat.zero_add]
|
||||
|
||||
@[deprecated extract_size (since := "2025-01-19")]
|
||||
abbrev extract_all := @extract_size
|
||||
|
||||
theorem extract_empty_of_stop_le_start {xs : Array α} {start stop : Nat} (h : stop ≤ start) :
|
||||
xs.extract start stop = #[] := by
|
||||
simp only [extract, Nat.sub_eq, emptyWithCapacity_eq]
|
||||
@@ -3036,14 +2997,14 @@ theorem take_size {xs : Array α} : xs.take xs.size = xs := by
|
||||
|
||||
/-! ### shrink -/
|
||||
|
||||
@[simp] theorem size_shrink_loop {xs : Array α} {n : Nat} : (shrink.loop n xs).size = xs.size - n := by
|
||||
@[simp] private theorem size_shrink_loop {xs : Array α} {n : Nat} : (shrink.loop n xs).size = xs.size - n := by
|
||||
induction n generalizing xs with
|
||||
| zero => simp [shrink.loop]
|
||||
| succ n ih =>
|
||||
simp [shrink.loop, ih]
|
||||
omega
|
||||
|
||||
@[simp] theorem getElem_shrink_loop {xs : Array α} {n i : Nat} (h : i < (shrink.loop n xs).size) :
|
||||
@[simp] private theorem getElem_shrink_loop {xs : Array α} {n i : Nat} (h : i < (shrink.loop n xs).size) :
|
||||
(shrink.loop n xs)[i] = xs[i]'(by simp at h; omega) := by
|
||||
induction n generalizing xs i with
|
||||
| zero => simp [shrink.loop]
|
||||
@@ -4319,7 +4280,7 @@ Examples:
|
||||
|
||||
/-! ### Preliminaries about `ofFn` -/
|
||||
|
||||
@[simp] theorem size_ofFn_go {n} {f : Fin n → α} {i acc h} :
|
||||
@[simp] private theorem size_ofFn_go {n} {f : Fin n → α} {i acc h} :
|
||||
(ofFn.go f acc i h).size = acc.size + i := by
|
||||
induction i generalizing acc with
|
||||
| zero => simp [ofFn.go]
|
||||
@@ -4329,7 +4290,7 @@ Examples:
|
||||
@[simp] theorem size_ofFn {n : Nat} {f : Fin n → α} : (ofFn f).size = n := by simp [ofFn]
|
||||
|
||||
-- Recall `ofFn.go f acc i h = acc ++ #[f (n - i), ..., f(n - 1)]`
|
||||
theorem getElem_ofFn_go {f : Fin n → α} {acc i k} (h : i ≤ n) (w₁ : k < acc.size + i) :
|
||||
private theorem getElem_ofFn_go {f : Fin n → α} {acc i k} (h : i ≤ n) (w₁ : k < acc.size + i) :
|
||||
(ofFn.go f acc i h)[k]'(by simpa using w₁) =
|
||||
if w₂ : k < acc.size then acc[k] else f ⟨n - i + k - acc.size, by omega⟩ := by
|
||||
induction i generalizing acc k with
|
||||
@@ -4734,27 +4695,10 @@ end List
|
||||
/-! ### Deprecations -/
|
||||
namespace Array
|
||||
|
||||
@[deprecated size_toArray (since := "2024-12-11")]
|
||||
theorem size_mk (as : List α) : (Array.mk as).size = as.length := by simp
|
||||
|
||||
@[deprecated getElem?_eq_getElem (since := "2024-12-11")]
|
||||
theorem getElem?_lt
|
||||
(xs : Array α) {i : Nat} (h : i < xs.size) : xs[i]? = some xs[i] := dif_pos h
|
||||
|
||||
@[deprecated getElem?_eq_none (since := "2024-12-11")]
|
||||
theorem getElem?_ge
|
||||
(xs : Array α) {i : Nat} (h : i ≥ xs.size) : xs[i]? = none := dif_neg (Nat.not_lt_of_le h)
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "`get?` is deprecated" (since := "2025-02-12"), simp]
|
||||
theorem get?_eq_getElem? (xs : Array α) (i : Nat) : xs.get? i = xs[i]? := rfl
|
||||
|
||||
@[deprecated getElem?_eq_none (since := "2024-12-11")]
|
||||
theorem getElem?_len_le (xs : Array α) {i : Nat} (h : xs.size ≤ i) : xs[i]? = none := by
|
||||
simp [h]
|
||||
|
||||
@[deprecated getD_getElem? (since := "2024-12-11")] abbrev getD_get? := @getD_getElem?
|
||||
|
||||
@[deprecated getD_eq_getD_getElem? (since := "2025-02-12")] abbrev getD_eq_get? := @getD_eq_getD_getElem?
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@@ -4779,64 +4723,9 @@ theorem get?_eq_get?_toList (xs : Array α) (i : Nat) : xs.get? i = xs.toList.ge
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated get!_eq_getD_getElem? (since := "2025-02-12")] abbrev get!_eq_get? := @get!_eq_getD_getElem?
|
||||
|
||||
@[deprecated getElem_set_self (since := "2025-01-17")]
|
||||
theorem get_set_eq (xs : Array α) (i : Nat) (v : α) (h : i < xs.size) :
|
||||
(xs.set i v h)[i]'(by simp [h]) = v := by
|
||||
simp only [set, ← getElem_toList, List.getElem_set_self]
|
||||
|
||||
@[deprecated Array.getElem_toList (since := "2024-12-08")]
|
||||
theorem getElem_eq_getElem_toList {xs : Array α} (h : i < xs.size) : xs[i] = xs.toList[i] := rfl
|
||||
|
||||
@[deprecated Array.getElem?_toList (since := "2024-12-08")]
|
||||
theorem getElem?_eq_getElem?_toList (xs : Array α) (i : Nat) : xs[i]? = xs.toList[i]? := by
|
||||
rw [getElem?_def]
|
||||
split <;> simp_all
|
||||
|
||||
@[deprecated LawfulGetElem.getElem?_def (since := "2024-12-08")]
|
||||
theorem getElem?_eq {xs : Array α} {i : Nat} :
|
||||
xs[i]? = if h : i < xs.size then some xs[i] else none := by
|
||||
rw [getElem?_def]
|
||||
|
||||
/-! ### map -/
|
||||
|
||||
@[deprecated "Use `toList_map` or `List.map_toArray` to characterize `Array.map`." (since := "2025-01-06")]
|
||||
theorem map_induction (xs : Array α) (f : α → β) (motive : Nat → Prop) (h0 : motive 0)
|
||||
(p : Fin xs.size → β → Prop) (hs : ∀ i, motive i.1 → p i (f xs[i]) ∧ motive (i+1)) :
|
||||
motive xs.size ∧
|
||||
∃ eq : (xs.map f).size = xs.size, ∀ i h, p ⟨i, h⟩ ((xs.map f)[i]) := by
|
||||
have t := foldl_induction (as := xs) (β := Array β)
|
||||
(motive := fun i xs => motive i ∧ xs.size = i ∧ ∀ i h2, p i xs[i.1])
|
||||
(init := #[]) (f := fun acc a => acc.push (f a)) ?_ ?_
|
||||
obtain ⟨m, eq, w⟩ := t
|
||||
· refine ⟨m, by simp, ?_⟩
|
||||
intro i h
|
||||
simp only [eq] at w
|
||||
specialize w ⟨i, h⟩ h
|
||||
simpa using w
|
||||
· exact ⟨h0, rfl, nofun⟩
|
||||
· intro i bs ⟨m, ⟨eq, w⟩⟩
|
||||
refine ⟨?_, ?_, ?_⟩
|
||||
· exact (hs _ m).2
|
||||
· simp_all
|
||||
· intro j h
|
||||
simp at h ⊢
|
||||
by_cases h' : j < size bs
|
||||
· rw [getElem_push]
|
||||
simp_all
|
||||
· rw [getElem_push, dif_neg h']
|
||||
simp only [show j = i by omega]
|
||||
exact (hs _ m).1
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `toList_map` or `List.map_toArray` to characterize `Array.map`." (since := "2025-01-06")]
|
||||
theorem map_spec (xs : Array α) (f : α → β) (p : Fin xs.size → β → Prop)
|
||||
(hs : ∀ i, p i (f xs[i])) :
|
||||
∃ eq : (xs.map f).size = xs.size, ∀ i h, p ⟨i, h⟩ ((xs.map f)[i]) := by
|
||||
simpa using map_induction xs f (fun _ => True) trivial p (by simp_all)
|
||||
|
||||
/-! ### set -/
|
||||
|
||||
@[deprecated getElem?_set_eq (since := "2025-02-27")] abbrev get?_set_eq := @getElem?_set_self
|
||||
@[deprecated getElem?_set_self (since := "2025-02-27")] abbrev get?_set_eq := @getElem?_set_self
|
||||
@[deprecated getElem?_set_ne (since := "2025-02-27")] abbrev get?_set_ne := @getElem?_set_ne
|
||||
@[deprecated getElem?_set (since := "2025-02-27")] abbrev get?_set := @getElem?_set
|
||||
@[deprecated get_set (since := "2025-02-27")] abbrev get_set := @getElem_set
|
||||
|
||||
@@ -12,9 +12,12 @@ public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.List.Lex
|
||||
import Init.Data.Range.Polymorphic.Lemmas
|
||||
import Init.Data.Range.Polymorphic.NatLemmas
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
@@ -28,8 +31,8 @@ namespace Array
|
||||
@[simp] theorem lt_toList [LT α] {xs ys : Array α} : xs.toList < ys.toList ↔ xs < ys := Iff.rfl
|
||||
@[simp] theorem le_toList [LT α] {xs ys : Array α} : xs.toList ≤ ys.toList ↔ xs ≤ ys := Iff.rfl
|
||||
|
||||
grind_pattern _root_.List.lt_toArray => l₁.toArray < l₂.toArray
|
||||
grind_pattern _root_.List.le_toArray => l₁.toArray ≤ l₂.toArray
|
||||
grind_pattern _root_.List.lt_toArray => l₁.toArray < l₂.toArray
|
||||
grind_pattern _root_.List.le_toArray => l₁.toArray ≤ l₂.toArray
|
||||
grind_pattern lt_toList => xs.toList < ys.toList
|
||||
grind_pattern le_toList => xs.toList ≤ ys.toList
|
||||
|
||||
@@ -100,6 +103,14 @@ theorem singleton_lex_singleton [BEq α] {lt : α → α → Bool} : #[a].lex #[
|
||||
xs.toList.lex ys.toList lt = xs.lex ys lt := by
|
||||
cases xs <;> cases ys <;> simp
|
||||
|
||||
instance [LT α] [LE α] [LawfulOrderLT α] [IsLinearOrder α] : IsLinearOrder (Array α) := by
|
||||
apply IsLinearOrder.of_le
|
||||
· constructor
|
||||
intro _ _ hab hba
|
||||
simpa using Std.le_antisymm (α := List α) hab hba
|
||||
· constructor; exact Std.le_trans (α := List α)
|
||||
· constructor; exact fun _ _ => Std.le_total (α := List α)
|
||||
|
||||
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α → α → Prop)] (xs : Array α) : ¬ xs < xs :=
|
||||
List.lt_irrefl xs.toList
|
||||
|
||||
@@ -131,27 +142,35 @@ instance [LT α] [Trans (· < · : α → α → Prop) (· < ·) (· < ·)] :
|
||||
Trans (· < · : Array α → Array α → Prop) (· < ·) (· < ·) where
|
||||
trans h₁ h₂ := Array.lt_trans h₁ h₂
|
||||
|
||||
protected theorem lt_of_le_of_lt [LT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
protected theorem lt_of_le_of_lt [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α]
|
||||
{xs ys zs : Array α} (h₁ : xs ≤ ys) (h₂ : ys < zs) : xs < zs :=
|
||||
Std.lt_of_le_of_lt (α := List α) h₁ h₂
|
||||
|
||||
@[deprecated Array.lt_of_le_of_lt (since := "2025-08-01")]
|
||||
protected theorem lt_of_le_of_lt' [LT α]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[i₃ : Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{xs ys zs : Array α} (h₁ : xs ≤ ys) (h₂ : ys < zs) : xs < zs :=
|
||||
List.lt_of_le_of_lt h₁ h₂
|
||||
letI := LE.ofLT α
|
||||
haveI : IsLinearOrder α := IsLinearOrder.of_lt
|
||||
Array.lt_of_le_of_lt h₁ h₂
|
||||
|
||||
protected theorem le_trans [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
protected theorem le_trans [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α]
|
||||
{xs ys zs : Array α} (h₁ : xs ≤ ys) (h₂ : ys ≤ zs) : xs ≤ zs :=
|
||||
fun h₃ => h₁ (Array.lt_of_le_of_lt h₂ h₃)
|
||||
|
||||
instance [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)] :
|
||||
@[deprecated Array.le_trans (since := "2025-08-01")]
|
||||
protected theorem le_trans' [LT α]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[i₃ : Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{xs ys zs : Array α} (h₁ : xs ≤ ys) (h₂ : ys ≤ zs) : xs ≤ zs :=
|
||||
letI := LE.ofLT α
|
||||
haveI : IsLinearOrder α := IsLinearOrder.of_lt
|
||||
Array.le_trans h₁ h₂
|
||||
|
||||
instance [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α] :
|
||||
Trans (· ≤ · : Array α → Array α → Prop) (· ≤ ·) (· ≤ ·) where
|
||||
trans h₁ h₂ := Array.le_trans h₁ h₂
|
||||
|
||||
@@ -165,7 +184,7 @@ instance [LT α]
|
||||
asymm _ _ := Array.lt_asymm
|
||||
|
||||
protected theorem le_total [LT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)] (xs ys : Array α) : xs ≤ ys ∨ ys ≤ xs :=
|
||||
[i : Std.Asymm (· < · : α → α → Prop)] (xs ys : Array α) : xs ≤ ys ∨ ys ≤ xs :=
|
||||
List.le_total xs.toList ys.toList
|
||||
|
||||
@[simp] protected theorem not_lt [LT α]
|
||||
@@ -175,19 +194,22 @@ protected theorem le_total [LT α]
|
||||
{xs ys : Array α} : ¬ ys ≤ xs ↔ xs < ys := Classical.not_not
|
||||
|
||||
protected theorem le_of_lt [LT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)]
|
||||
[i : Std.Asymm (· < · : α → α → Prop)]
|
||||
{xs ys : Array α} (h : xs < ys) : xs ≤ ys :=
|
||||
List.le_of_lt h
|
||||
|
||||
protected theorem le_iff_lt_or_eq [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Total (¬ · < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
{xs ys : Array α} : xs ≤ ys ↔ xs < ys ∨ xs = ys := by
|
||||
simpa using List.le_iff_lt_or_eq (l₁ := xs.toList) (l₂ := ys.toList)
|
||||
|
||||
instance [LT α]
|
||||
[Std.Total (¬ · < · : α → α → Prop)] :
|
||||
protected theorem le_antisymm [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α]
|
||||
{xs ys : Array α} : xs ≤ ys → ys ≤ xs → xs = ys := by
|
||||
simpa using List.le_antisymm (as := xs.toList) (bs := ys.toList)
|
||||
|
||||
instance [LT α] [Std.Asymm (· < · : α → α → Prop)] :
|
||||
Std.Total (· ≤ · : Array α → Array α → Prop) where
|
||||
total := Array.le_total
|
||||
|
||||
@@ -266,7 +288,6 @@ protected theorem lt_iff_exists [LT α] {xs ys : Array α} :
|
||||
simp [List.lt_iff_exists]
|
||||
|
||||
protected theorem le_iff_exists [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)] {xs ys : Array α} :
|
||||
xs ≤ ys ↔
|
||||
@@ -286,7 +307,6 @@ theorem append_left_lt [LT α] {xs ys zs : Array α} (h : ys < zs) :
|
||||
simpa using List.append_left_lt h
|
||||
|
||||
theorem append_left_le [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{xs ys zs : Array α} (h : ys ≤ zs) :
|
||||
@@ -310,10 +330,8 @@ protected theorem map_lt [LT α] [LT β]
|
||||
simpa using List.map_lt w h
|
||||
|
||||
protected theorem map_le [LT α] [LT β]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Irrefl (· < · : β → β → Prop)]
|
||||
[Std.Asymm (· < · : β → β → Prop)]
|
||||
[Std.Antisymm (¬ · < · : β → β → Prop)]
|
||||
{xs ys : Array α} {f : α → β} (w : ∀ x y, x < y → f x < f y) (h : xs ≤ ys) :
|
||||
|
||||
@@ -60,7 +60,7 @@ theorem mapFinIdx_spec {xs : Array α} {f : (i : Nat) → α → (h : i < xs.siz
|
||||
@[simp, grind =] theorem size_zipIdx {xs : Array α} {k : Nat} : (xs.zipIdx k).size = xs.size :=
|
||||
Array.size_mapFinIdx
|
||||
|
||||
@[deprecated size_zipIdx (since := "2025-01-21")] abbrev size_zipWithIndex := @size_zipIdx
|
||||
|
||||
|
||||
@[simp, grind =] theorem getElem_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {i : Nat}
|
||||
(h : i < (xs.mapFinIdx f).size) :
|
||||
@@ -132,23 +132,20 @@ namespace Array
|
||||
(xs.zipIdx k)[i] = (xs[i]'(by simp_all), k + i) := by
|
||||
simp [zipIdx]
|
||||
|
||||
@[deprecated getElem_zipIdx (since := "2025-01-21")]
|
||||
abbrev getElem_zipWithIndex := @getElem_zipIdx
|
||||
|
||||
|
||||
@[simp, grind =] theorem zipIdx_toArray {l : List α} {k : Nat} :
|
||||
l.toArray.zipIdx k = (l.zipIdx k).toArray := by
|
||||
ext i hi₁ hi₂ <;> simp
|
||||
|
||||
@[deprecated zipIdx_toArray (since := "2025-01-21")]
|
||||
abbrev zipWithIndex_toArray := @zipIdx_toArray
|
||||
|
||||
|
||||
@[simp, grind =] theorem toList_zipIdx {xs : Array α} {k : Nat} :
|
||||
(xs.zipIdx k).toList = xs.toList.zipIdx k := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[deprecated toList_zipIdx (since := "2025-01-21")]
|
||||
abbrev toList_zipWithIndex := @toList_zipIdx
|
||||
|
||||
|
||||
theorem mk_mem_zipIdx_iff_le_and_getElem?_sub {k i : Nat} {x : α} {xs : Array α} :
|
||||
(x, i) ∈ xs.zipIdx k ↔ k ≤ i ∧ xs[i - k]? = some x := by
|
||||
@@ -173,11 +170,7 @@ theorem mem_zipIdx_iff_getElem? {x : α × Nat} {xs : Array α} :
|
||||
x ∈ xs.zipIdx ↔ xs[x.2]? = some x.1 := by
|
||||
rw [mk_mem_zipIdx_iff_getElem?]
|
||||
|
||||
@[deprecated mk_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
abbrev mk_mem_zipWithIndex_iff_getElem? := @mk_mem_zipIdx_iff_getElem?
|
||||
|
||||
@[deprecated mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
abbrev mem_zipWithIndex_iff_getElem? := @mem_zipIdx_iff_getElem?
|
||||
|
||||
/-! ### mapFinIdx -/
|
||||
|
||||
@@ -222,8 +215,7 @@ theorem mapFinIdx_eq_zipIdx_map {xs : Array α} {f : (i : Nat) → α → (h : i
|
||||
f i x (by simp [mk_mem_zipIdx_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1) := by
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated mapFinIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapFinIdx_eq_zipWithIndex_map := @mapFinIdx_eq_zipIdx_map
|
||||
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_eq_empty_iff {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
@@ -332,8 +324,7 @@ theorem mapIdx_eq_zipIdx_map {xs : Array α} {f : Nat → α → β} :
|
||||
xs.mapIdx f = xs.zipIdx.map fun ⟨a, i⟩ => f i a := by
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapIdx_eq_zipWithIndex_map := @mapIdx_eq_zipIdx_map
|
||||
|
||||
|
||||
@[grind =]
|
||||
theorem mapIdx_append {xs ys : Array α} :
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Vector.Basic
|
||||
public import Init.Data.Ord
|
||||
public import Init.Data.Ord.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -23,11 +23,14 @@ class PartialEquivBEq (α) [BEq α] : Prop where
|
||||
/-- Transitivity for `BEq`. If `a == b` and `b == c` then `a == c`. -/
|
||||
trans : (a : α) == b → b == c → a == c
|
||||
|
||||
instance [BEq α] [PartialEquivBEq α] : Std.Symm (α := α) (· == ·) where
|
||||
symm _ _ h := PartialEquivBEq.symm h
|
||||
|
||||
/-- `EquivBEq` says that the `BEq` implementation is an equivalence relation. -/
|
||||
class EquivBEq (α) [BEq α] : Prop extends PartialEquivBEq α, ReflBEq α
|
||||
|
||||
theorem BEq.symm [BEq α] [PartialEquivBEq α] {a b : α} : a == b → b == a :=
|
||||
PartialEquivBEq.symm
|
||||
theorem BEq.symm [BEq α] [Std.Symm (α := α) (· == ·)] {a b : α} : a == b → b == a :=
|
||||
Std.Symm.symm a b (r := (· == ·))
|
||||
|
||||
theorem BEq.comm [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = (b == a) :=
|
||||
Bool.eq_iff_iff.2 ⟨BEq.symm, BEq.symm⟩
|
||||
|
||||
@@ -338,11 +338,11 @@ theorem add_eq_or_of_and_eq_zero {w : Nat} (x y : BitVec w)
|
||||
· rfl
|
||||
· simp only [adcb, atLeastTwo, Bool.and_false, Bool.or_false, bne_false,
|
||||
Prod.mk.injEq, and_eq_false_imp]
|
||||
intros i
|
||||
intro i
|
||||
replace h : (x &&& y).getLsbD i = (0#w).getLsbD i := by rw [h]
|
||||
simp only [getLsbD_and, getLsbD_zero, and_eq_false_imp] at h
|
||||
constructor
|
||||
· intros hx
|
||||
· intro hx
|
||||
simp_all
|
||||
· by_cases hx : x.getLsbD i <;> simp_all
|
||||
|
||||
@@ -1666,7 +1666,7 @@ private theorem neg_udiv_eq_intMin_iff_eq_intMin_eq_one_of_msb_eq_true
|
||||
{x y : BitVec w} (hx : x.msb = true) (hy : y.msb = false) :
|
||||
-x / y = intMin w ↔ (x = intMin w ∧ y = 1#w) := by
|
||||
constructor
|
||||
· intros h
|
||||
· intro h
|
||||
rcases w with _ | w; decide +revert
|
||||
have : (-x / y).msb = true := by simp [h, msb_intMin]
|
||||
rw [msb_udiv] at this
|
||||
@@ -1742,7 +1742,7 @@ theorem msb_sdiv_eq_decide {x y : BitVec w} :
|
||||
Bool.and_self, ne_zero_of_msb_true, decide_false, Bool.and_true, Bool.true_and, Bool.not_true,
|
||||
Bool.false_and, Bool.or_false, bool_to_prop]
|
||||
have : x / -y ≠ intMin (w + 1) := by
|
||||
intros h
|
||||
intro h
|
||||
have : (x / -y).msb = (intMin (w + 1)).msb := by simp only [h]
|
||||
simp only [msb_udiv, msb_intMin, show 0 < w + 1 by omega, decide_true, and_eq_true, beq_iff_eq] at this
|
||||
obtain ⟨hcontra, _⟩ := this
|
||||
@@ -1871,7 +1871,7 @@ theorem toInt_dvd_toInt_iff {x y : BitVec w} :
|
||||
y.toInt ∣ x.toInt ↔ (if x.msb then -x else x) % (if y.msb then -y else y) = 0#w := by
|
||||
constructor
|
||||
<;> by_cases hxmsb : x.msb <;> by_cases hymsb: y.msb
|
||||
<;> intros h
|
||||
<;> intro h
|
||||
<;> simp only [hxmsb, hymsb, reduceIte, false_eq_true, toNat_eq, toNat_umod, toNat_ofNat,
|
||||
zero_mod, toInt_eq_neg_toNat_neg_of_msb_true, Int.dvd_neg, Int.neg_dvd,
|
||||
toInt_eq_toNat_of_msb] at h
|
||||
@@ -2141,7 +2141,7 @@ theorem add_shiftLeft_eq_or_shiftLeft {x y : BitVec w} :
|
||||
ext i hi
|
||||
simp only [shiftLeft_eq', getElem_and, getElem_shiftLeft, getElem_zero, and_eq_false_imp,
|
||||
not_eq_eq_eq_not, Bool.not_true, decide_eq_false_iff_not, Nat.not_lt]
|
||||
intros hxi hxval
|
||||
intro hxi hxval
|
||||
have : 2^i ≤ x.toNat := two_pow_le_toNat_of_getElem_eq_true hi hxi
|
||||
have : i < 2^i := by exact Nat.lt_two_pow_self
|
||||
omega
|
||||
|
||||
@@ -19,9 +19,12 @@ public import Init.Data.Int.LemmasAux
|
||||
public import Init.Data.Int.Pow
|
||||
public import Init.Data.Int.LemmasAux
|
||||
public import Init.Data.BitVec.Bootstrap
|
||||
public import Init.Data.Order.Factories
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
namespace BitVec
|
||||
@@ -238,11 +241,11 @@ theorem eq_of_getLsbD_eq_iff {w : Nat} {x y : BitVec w} :
|
||||
x = y ↔ ∀ (i : Nat), i < w → x.getLsbD i = y.getLsbD i := by
|
||||
have iff := @BitVec.eq_of_getElem_eq_iff w x y
|
||||
constructor
|
||||
· intros heq i lt
|
||||
· intro heq i lt
|
||||
have hext := iff.mp heq i lt
|
||||
simp only [← getLsbD_eq_getElem] at hext
|
||||
exact hext
|
||||
· intros heq
|
||||
· intro heq
|
||||
exact iff.mpr heq
|
||||
|
||||
theorem eq_of_getMsbD_eq {x y : BitVec w}
|
||||
@@ -818,14 +821,14 @@ its most significant bit is true.
|
||||
theorem slt_zero_iff_msb_cond {x : BitVec w} : x.slt 0#w ↔ x.msb = true := by
|
||||
have := toInt_eq_msb_cond x
|
||||
constructor
|
||||
· intros h
|
||||
· intro h
|
||||
apply Classical.byContradiction
|
||||
intros hmsb
|
||||
intro hmsb
|
||||
simp only [Bool.not_eq_true] at hmsb
|
||||
simp only [hmsb, Bool.false_eq_true, ↓reduceIte] at this
|
||||
simp only [BitVec.slt, toInt_zero, decide_eq_true_eq] at h
|
||||
omega /- Can't have `x.toInt` which is equal to `x.toNat` be strictly less than zero -/
|
||||
· intros h
|
||||
· intro h
|
||||
simp only [h, ↓reduceIte] at this
|
||||
simp only [BitVec.slt, this, toInt_zero, decide_eq_true_eq]
|
||||
omega
|
||||
@@ -2094,7 +2097,7 @@ theorem toInt_ushiftRight_of_lt {x : BitVec w} {n : Nat} (hn : 0 < n) :
|
||||
(x >>> n).toInt = x.toNat >>> n := by
|
||||
rw [toInt_eq_toNat_cond]
|
||||
simp only [toNat_ushiftRight, ite_eq_left_iff, Nat.not_lt]
|
||||
intros h
|
||||
intro h
|
||||
by_cases hn : n ≤ w
|
||||
· have h1 := Nat.mul_lt_mul_of_pos_left (toNat_ushiftRight_lt x n hn) Nat.two_pos
|
||||
simp only [toNat_ushiftRight, Nat.zero_lt_succ, Nat.mul_lt_mul_left] at h1
|
||||
@@ -2232,7 +2235,7 @@ theorem getLsbD_sshiftRight (x : BitVec w) (s i : Nat) :
|
||||
omega
|
||||
· simp only [hi, decide_false, Bool.not_false, Bool.true_and, Bool.eq_and_self,
|
||||
decide_eq_true_eq]
|
||||
intros hlsb
|
||||
intro hlsb
|
||||
apply BitVec.lt_of_getLsbD hlsb
|
||||
· by_cases hi : i ≥ w
|
||||
· simp [hi]
|
||||
@@ -2286,7 +2289,7 @@ theorem msb_sshiftRight {n : Nat} {x : BitVec w} :
|
||||
· simp [hw₀]
|
||||
· simp only [show ¬(w ≤ w - 1) by omega, decide_false, Bool.not_false, Bool.true_and,
|
||||
ite_eq_right_iff]
|
||||
intros h
|
||||
intro h
|
||||
simp [show n = 0 by omega]
|
||||
|
||||
@[simp] theorem sshiftRight_zero {x : BitVec w} : x.sshiftRight 0 = x := by
|
||||
@@ -2774,7 +2777,7 @@ theorem toInt_append {x : BitVec n} {y : BitVec m} :
|
||||
(x ++ 0#m).toInt = (2 ^ m) * x.toInt := by
|
||||
simp only [toInt_append, beq_iff_eq, toInt_zero, toNat_ofNat, Nat.zero_mod, Int.cast_ofNat_Int, Int.add_zero,
|
||||
ite_eq_right_iff]
|
||||
intros h
|
||||
intro h
|
||||
subst h
|
||||
simp [BitVec.eq_nil x]
|
||||
|
||||
@@ -2958,7 +2961,7 @@ theorem extractLsb'_append_extractLsb'_eq_extractLsb' {x : BitVec w} (h : start
|
||||
ext i h
|
||||
simp only [getElem_append, getElem_extractLsb', dite_eq_ite, getElem_cast, ite_eq_left_iff,
|
||||
Nat.not_lt]
|
||||
intros hi
|
||||
intro hi
|
||||
congr 1
|
||||
omega
|
||||
|
||||
@@ -2985,7 +2988,7 @@ theorem signExtend_eq_append_extractLsb' {w v : Nat} {x : BitVec w} :
|
||||
· simp only [hx, signExtend_eq_setWidth_of_msb_false, getElem_setWidth, Bool.false_eq_true,
|
||||
↓reduceIte, getElem_append, getElem_extractLsb', Nat.zero_add, getElem_zero, dite_eq_ite,
|
||||
Bool.if_false_right, Bool.eq_and_self, decide_eq_true_eq]
|
||||
intros hi
|
||||
intro hi
|
||||
have hw : i < w := lt_of_getLsbD hi
|
||||
omega
|
||||
· simp [signExtend_eq_not_setWidth_not_of_msb_true hx, getElem_append, Nat.lt_min, hi]
|
||||
@@ -3033,7 +3036,7 @@ theorem extractLsb'_append_eq_ite {v w} {xhi : BitVec v} {xlo : BitVec w} {start
|
||||
· simp only [hlen, ↓reduceDIte]
|
||||
ext i hi
|
||||
simp only [getElem_extractLsb', getLsbD_append, ite_eq_left_iff, Nat.not_lt]
|
||||
intros hcontra
|
||||
intro hcontra
|
||||
omega
|
||||
· simp only [hlen, ↓reduceDIte]
|
||||
ext i hi
|
||||
@@ -3480,7 +3483,7 @@ theorem toInt_sub_toInt_lt_twoPow_iff {x y : BitVec w} :
|
||||
have := two_mul_toInt_lt (x := y)
|
||||
simp only [Nat.add_one_sub_one]
|
||||
constructor
|
||||
· intros h
|
||||
· intro h
|
||||
rw_mod_cast [← Int.add_bmod_right, Int.bmod_eq_of_le]
|
||||
<;> omega
|
||||
· have := Int.bmod_neg_iff (x := x.toInt - y.toInt) (m := 2 ^ (w + 1))
|
||||
@@ -3496,7 +3499,7 @@ theorem twoPow_le_toInt_sub_toInt_iff {x y : BitVec w} :
|
||||
have := le_two_mul_toInt (x := y); have := two_mul_toInt_lt (x := y)
|
||||
simp only [Nat.add_one_sub_one]
|
||||
constructor
|
||||
· intros h
|
||||
· intro h
|
||||
simp only [show 0 ≤ x.toInt by omega, show y.toInt < 0 by omega, _root_.true_and]
|
||||
rw_mod_cast [← Int.sub_bmod_right, Int.bmod_eq_of_le (by omega) (by omega)]
|
||||
omega
|
||||
@@ -4015,6 +4018,16 @@ protected theorem ne_of_lt {x y : BitVec n} : x < y → x ≠ y := by
|
||||
simp only [lt_def, ne_eq, toNat_eq]
|
||||
apply Nat.ne_of_lt
|
||||
|
||||
instance instIsLinearOrder : IsLinearOrder (BitVec n) := by
|
||||
apply IsLinearOrder.of_le
|
||||
case le_antisymm => constructor; apply BitVec.le_antisymm
|
||||
case le_trans => constructor; apply BitVec.le_trans
|
||||
case le_total => constructor; apply BitVec.le_total
|
||||
|
||||
instance instLawfulOrderLT : LawfulOrderLT (BitVec n) := by
|
||||
apply LawfulOrderLT.of_le
|
||||
simpa using fun _ _ => BitVec.lt_asymm
|
||||
|
||||
protected theorem umod_lt (x : BitVec n) {y : BitVec n} : 0 < y → x % y < y := by
|
||||
simp only [ofNat_eq_ofNat, lt_def, toNat_ofNat, Nat.zero_mod]
|
||||
apply Nat.mod_lt
|
||||
@@ -5842,13 +5855,8 @@ set_option linter.missingDocs false
|
||||
@[deprecated toFin_uShiftRight (since := "2025-02-18")]
|
||||
abbrev toFin_uShiftRight := @toFin_ushiftRight
|
||||
|
||||
@[deprecated signExtend_eq_setWidth_of_msb_false (since := "2024-12-08")]
|
||||
abbrev signExtend_eq_not_setWidth_not_of_msb_false := @signExtend_eq_setWidth_of_msb_false
|
||||
|
||||
@[deprecated replicate_zero (since := "2025-01-08")]
|
||||
abbrev replicate_zero_eq := @replicate_zero
|
||||
|
||||
@[deprecated replicate_succ (since := "2025-01-08")]
|
||||
abbrev replicate_succ_eq := @replicate_succ
|
||||
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -699,13 +699,13 @@ but may be used locally.
|
||||
|
||||
/-! ### Proof by reflection support -/
|
||||
|
||||
protected noncomputable def Bool.and' (a b : Bool) : Bool :=
|
||||
@[expose] protected noncomputable def Bool.and' (a b : Bool) : Bool :=
|
||||
Bool.rec false b a
|
||||
|
||||
protected noncomputable def Bool.or' (a b : Bool) : Bool :=
|
||||
@[expose] protected noncomputable def Bool.or' (a b : Bool) : Bool :=
|
||||
Bool.rec b true a
|
||||
|
||||
protected noncomputable def Bool.not' (a : Bool) : Bool :=
|
||||
@[expose] protected noncomputable def Bool.not' (a : Bool) : Bool :=
|
||||
Bool.rec true false a
|
||||
|
||||
@[simp] theorem Bool.and'_eq_and (a b : Bool) : a.and' b = a.and b := by
|
||||
|
||||
@@ -8,5 +8,6 @@ module
|
||||
prelude
|
||||
public import Init.Data.Char.Basic
|
||||
public import Init.Data.Char.Lemmas
|
||||
public import Init.Data.Char.Order
|
||||
|
||||
public section
|
||||
|
||||
@@ -61,6 +61,7 @@ instance leTotal : Std.Total (· ≤ · : Char → Char → Prop) where
|
||||
total := Char.le_total
|
||||
|
||||
-- This instance is useful while setting up instances for `String`.
|
||||
@[deprecated ltAsymm (since := "2025-08-01")]
|
||||
def notLTTotal : Std.Total (¬ · < · : Char → Char → Prop) where
|
||||
total := fun x y => by simpa using Char.le_total y x
|
||||
|
||||
|
||||
27
src/Init/Data/Char/Order.lean
Normal file
27
src/Init/Data/Char/Order.lean
Normal file
@@ -0,0 +1,27 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Char.Basic
|
||||
import Init.Data.Char.Lemmas
|
||||
public import Init.Data.Order.Factories
|
||||
|
||||
open Std
|
||||
|
||||
namespace Char
|
||||
|
||||
public instance instIsLinearOrder : IsLinearOrder Char := by
|
||||
apply IsLinearOrder.of_le
|
||||
case le_antisymm => constructor; apply Char.le_antisymm
|
||||
case le_trans => constructor; apply Char.le_trans
|
||||
case le_total => constructor; apply Char.le_total
|
||||
|
||||
public instance : LawfulOrderLT Char where
|
||||
lt_iff a b := by
|
||||
simp [← Char.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
end Char
|
||||
@@ -107,14 +107,14 @@ Fin.foldrM n f xₙ = do
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldlM_loop_lt [Monad m] (f : α → Fin n → m α) (x) (h : i < n) :
|
||||
private theorem foldlM_loop_lt [Monad m] (f : α → Fin n → m α) (x) (h : i < n) :
|
||||
foldlM.loop n f x i = f x ⟨i, h⟩ >>= (foldlM.loop n f . (i+1)) := by
|
||||
rw [foldlM.loop, dif_pos h]
|
||||
|
||||
theorem foldlM_loop_eq [Monad m] (f : α → Fin n → m α) (x) : foldlM.loop n f x n = pure x := by
|
||||
private theorem foldlM_loop_eq [Monad m] (f : α → Fin n → m α) (x) : foldlM.loop n f x n = pure x := by
|
||||
rw [foldlM.loop, dif_neg (Nat.lt_irrefl _)]
|
||||
|
||||
theorem foldlM_loop [Monad m] (f : α → Fin (n+1) → m α) (x) (h : i < n+1) :
|
||||
private theorem foldlM_loop [Monad m] (f : α → Fin (n+1) → m α) (x) (h : i < n+1) :
|
||||
foldlM.loop (n+1) f x i = f x ⟨i, h⟩ >>= (foldlM.loop n (fun x j => f x j.succ) . i) := by
|
||||
if h' : i < n then
|
||||
rw [foldlM_loop_lt _ _ h]
|
||||
@@ -170,15 +170,15 @@ theorem foldlM_add [Monad m] [LawfulMonad m] (f : α → Fin (n + k) → m α) :
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldrM_loop_zero [Monad m] (f : Fin n → α → m α) (x) :
|
||||
private theorem foldrM_loop_zero [Monad m] (f : Fin n → α → m α) (x) :
|
||||
foldrM.loop n f ⟨0, Nat.zero_le _⟩ x = pure x := by
|
||||
rw [foldrM.loop]
|
||||
|
||||
theorem foldrM_loop_succ [Monad m] (f : Fin n → α → m α) (x) (h : i < n) :
|
||||
private theorem foldrM_loop_succ [Monad m] (f : Fin n → α → m α) (x) (h : i < n) :
|
||||
foldrM.loop n f ⟨i+1, h⟩ x = f ⟨i, h⟩ x >>= foldrM.loop n f ⟨i, Nat.le_of_lt h⟩ := by
|
||||
rw [foldrM.loop]
|
||||
|
||||
theorem foldrM_loop [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x) (h : i+1 ≤ n+1) :
|
||||
private theorem foldrM_loop [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x) (h : i+1 ≤ n+1) :
|
||||
foldrM.loop (n+1) f ⟨i+1, h⟩ x =
|
||||
foldrM.loop n (fun j => f j.succ) ⟨i, Nat.le_of_succ_le_succ h⟩ x >>= f 0 := by
|
||||
induction i generalizing x with
|
||||
@@ -228,14 +228,14 @@ theorem foldrM_add [Monad m] [LawfulMonad m] (f : Fin (n + k) → α → m α) :
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldl_loop_lt (f : α → Fin n → α) (x) (h : i < n) :
|
||||
private theorem foldl_loop_lt (f : α → Fin n → α) (x) (h : i < n) :
|
||||
foldl.loop n f x i = foldl.loop n f (f x ⟨i, h⟩) (i+1) := by
|
||||
rw [foldl.loop, dif_pos h]
|
||||
|
||||
theorem foldl_loop_eq (f : α → Fin n → α) (x) : foldl.loop n f x n = x := by
|
||||
private theorem foldl_loop_eq (f : α → Fin n → α) (x) : foldl.loop n f x n = x := by
|
||||
rw [foldl.loop, dif_neg (Nat.lt_irrefl _)]
|
||||
|
||||
theorem foldl_loop (f : α → Fin (n+1) → α) (x) (h : i < n+1) :
|
||||
private theorem foldl_loop (f : α → Fin (n+1) → α) (x) (h : i < n+1) :
|
||||
foldl.loop (n+1) f x i = foldl.loop n (fun x j => f x j.succ) (f x ⟨i, h⟩) i := by
|
||||
if h' : i < n then
|
||||
rw [foldl_loop_lt _ _ h]
|
||||
@@ -285,15 +285,15 @@ theorem foldlM_pure [Monad m] [LawfulMonad m] {n} {f : α → Fin n → α} :
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldr_loop_zero (f : Fin n → α → α) (x) :
|
||||
private theorem foldr_loop_zero (f : Fin n → α → α) (x) :
|
||||
foldr.loop n f 0 (Nat.zero_le _) x = x := by
|
||||
rw [foldr.loop]
|
||||
|
||||
theorem foldr_loop_succ (f : Fin n → α → α) (x) (h : i < n) :
|
||||
private theorem foldr_loop_succ (f : Fin n → α → α) (x) (h : i < n) :
|
||||
foldr.loop n f (i+1) h x = foldr.loop n f i (Nat.le_of_lt h) (f ⟨i, h⟩ x) := by
|
||||
rw [foldr.loop]
|
||||
|
||||
theorem foldr_loop (f : Fin (n+1) → α → α) (x) (h : i+1 ≤ n+1) :
|
||||
private theorem foldr_loop (f : Fin (n+1) → α → α) (x) (h : i+1 ≤ n+1) :
|
||||
foldr.loop (n+1) f (i+1) h x =
|
||||
f 0 (foldr.loop n (fun j => f j.succ) i (Nat.le_of_succ_le_succ h) x) := by
|
||||
induction i generalizing x with
|
||||
|
||||
@@ -12,9 +12,13 @@ public import Init.Ext
|
||||
public import Init.ByCases
|
||||
public import Init.Conv
|
||||
public import Init.Omega
|
||||
public import Init.Data.Order.Factories
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
|
||||
namespace Fin
|
||||
|
||||
@[simp] theorem ofNat_zero (n : Nat) [NeZero n] : Fin.ofNat n 0 = 0 := rfl
|
||||
@@ -251,6 +255,16 @@ protected theorem le_antisymm_iff {x y : Fin n} : x = y ↔ x ≤ y ∧ y ≤ x
|
||||
protected theorem le_antisymm {x y : Fin n} (h1 : x ≤ y) (h2 : y ≤ x) : x = y :=
|
||||
Fin.le_antisymm_iff.2 ⟨h1, h2⟩
|
||||
|
||||
instance instIsLinearOrder : IsLinearOrder (Fin n) := by
|
||||
apply IsLinearOrder.of_le
|
||||
case le_antisymm => constructor; apply Fin.le_antisymm
|
||||
case le_total => constructor; apply Fin.le_total
|
||||
case le_trans => constructor; apply Fin.le_trans
|
||||
|
||||
instance : LawfulOrderLT (Fin n) where
|
||||
lt_iff := by
|
||||
simp [← Fin.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
@[simp, grind =] theorem val_rev (i : Fin n) : rev i = n - (i + 1) := rfl
|
||||
|
||||
@[simp] theorem rev_rev (i : Fin n) : rev (rev i) = i := Fin.ext <| by
|
||||
@@ -938,7 +952,7 @@ For the induction:
|
||||
(reverseInduction zero succ (Fin.last n) : motive (Fin.last n)) = zero := by
|
||||
rw [reverseInduction, reverseInduction.go]; simp
|
||||
|
||||
@[simp] theorem reverseInduction_castSucc_aux {n : Nat} {motive : Fin (n + 1) → Sort _} {succ}
|
||||
private theorem reverseInduction_castSucc_aux {n : Nat} {motive : Fin (n + 1) → Sort _} {succ}
|
||||
(i : Fin n) (j : Nat) (h) (h2 : i.1 < j) (zero : motive ⟨j, h⟩) :
|
||||
reverseInduction.go (motive := motive) succ i.castSucc j h (Nat.le_of_lt h2) zero =
|
||||
succ i (reverseInduction.go succ i.succ j h h2 zero) := by
|
||||
|
||||
@@ -314,7 +314,7 @@ Examples:
|
||||
* `(0 : Int).natAbs = 0`
|
||||
* `((-11 : Int).natAbs = 11`
|
||||
-/
|
||||
@[extern "lean_nat_abs"]
|
||||
@[extern "lean_nat_abs", expose]
|
||||
def natAbs (m : @& Int) : Nat :=
|
||||
match m with
|
||||
| ofNat m => m
|
||||
@@ -405,11 +405,25 @@ instance : Min Int := minOfLe
|
||||
instance : Max Int := maxOfLe
|
||||
|
||||
/-- Equality predicate for kernel reduction. -/
|
||||
protected noncomputable def beq' (a b : Int) : Bool :=
|
||||
@[expose] protected noncomputable def beq' (a b : Int) : Bool :=
|
||||
Int.rec
|
||||
(fun a => Int.rec (fun b => Nat.beq a b) (fun _ => false) b)
|
||||
(fun a => Int.rec (fun _ => false) (fun b => Nat.beq a b) b) a
|
||||
|
||||
/-- `x ≤ y` for kernel reduction. -/
|
||||
@[expose] protected noncomputable def ble' (a b : Int) : Bool :=
|
||||
Int.rec
|
||||
(fun a => Int.rec (fun b => Nat.ble a b) (fun _ => false) b)
|
||||
(fun a => Int.rec (fun _ => true) (fun b => Nat.ble b a) b)
|
||||
a
|
||||
|
||||
/-- `x < y` for kernel reduction. -/
|
||||
@[expose] protected noncomputable def blt' (a b : Int) : Bool :=
|
||||
Int.rec
|
||||
(fun a => Int.rec (fun b => Nat.blt a b) (fun _ => false) b)
|
||||
(fun a => Int.rec (fun _ => true) (fun b => Nat.blt b a) b)
|
||||
a
|
||||
|
||||
end Int
|
||||
|
||||
/--
|
||||
|
||||
@@ -6,7 +6,7 @@ Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro, Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Ord
|
||||
public import all Init.Data.Ord.Basic
|
||||
public import Init.Data.Int.Order
|
||||
|
||||
public section
|
||||
|
||||
@@ -956,6 +956,12 @@ theorem neg_mul_ediv_cancel_left (a b : Int) (h : a ≠ 0) : -(a * b) / a = -b :
|
||||
@[simp] theorem emod_one (a : Int) : a % 1 = 0 := by
|
||||
simp [emod_def, Int.one_mul, Int.sub_self]
|
||||
|
||||
theorem ediv_minus_one (a : Int) : a / (-1) = -a := by
|
||||
simp
|
||||
|
||||
theorem emod_minus_one (a : Int) : a % (-1) = 0 := by
|
||||
simp
|
||||
|
||||
@[deprecated sub_emod_right (since := "2025-04-11")]
|
||||
theorem emod_sub_cancel (x y : Int) : (x - y) % y = x % y :=
|
||||
sub_emod_right ..
|
||||
|
||||
@@ -361,10 +361,10 @@ theorem negSucc_coe' (n : Nat) : -[n+1] = -↑n - 1 := by
|
||||
|
||||
protected theorem subNatNat_eq_coe {m n : Nat} : subNatNat m n = ↑m - ↑n := by
|
||||
apply subNatNat_elim m n fun m n i => i = m - n
|
||||
· intros i n
|
||||
· intro i n
|
||||
rw [Int.natCast_add, Int.sub_eq_add_neg, Int.add_assoc, Int.add_left_comm,
|
||||
Int.add_right_neg, Int.add_zero]
|
||||
· intros i n
|
||||
· intro i n
|
||||
simp only [negSucc_eq, natCast_add, ofNat_one, Int.sub_eq_add_neg, Int.neg_add, ← Int.add_assoc]
|
||||
rw [Int.add_neg_eq_sub (a := n), ← ofNat_sub, Nat.sub_self, ofNat_zero, Int.zero_add]
|
||||
apply Nat.le_refl
|
||||
|
||||
@@ -69,6 +69,18 @@ theorem natCast_succ_pos (n : Nat) : 0 < (n.succ : Int) := natCast_pos.2 n.succ_
|
||||
|
||||
@[simp, norm_cast] theorem cast_id {n : Int} : Int.cast n = n := rfl
|
||||
|
||||
@[simp] theorem ble'_eq_true (a b : Int) : (Int.ble' a b = true) = (a ≤ b) := by
|
||||
cases a <;> cases b <;> simp [Int.ble'] <;> omega
|
||||
|
||||
@[simp] theorem blt'_eq_true (a b : Int) : (Int.blt' a b = true) = (a < b) := by
|
||||
cases a <;> cases b <;> simp [Int.blt'] <;> omega
|
||||
|
||||
@[simp] theorem ble'_eq_false (a b : Int) : (Int.ble' a b = false) = ¬(a ≤ b) := by
|
||||
simp [← Bool.not_eq_true]
|
||||
|
||||
@[simp] theorem blt'_eq_false (a b : Int) : (Int.blt' a b = false) = ¬ (a < b) := by
|
||||
simp [← Bool.not_eq_true]
|
||||
|
||||
/-! ### toNat -/
|
||||
|
||||
@[simp] theorem toNat_sub' (a : Int) (b : Nat) : (a - b).toNat = a.toNat - b := by
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,9 +8,13 @@ module
|
||||
prelude
|
||||
public import Init.Data.Int.Lemmas
|
||||
public import Init.ByCases
|
||||
public import Init.Data.Order.Factories
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
|
||||
/-!
|
||||
# Results about the order properties of the integers, and the integers as an ordered ring.
|
||||
-/
|
||||
@@ -1415,4 +1419,14 @@ theorem natAbs_eq_iff_mul_eq_zero : natAbs a = n ↔ (a - n) * (a + n) = 0 := by
|
||||
@[deprecated natAbs_eq_iff_mul_eq_zero (since := "2025-03-11")]
|
||||
abbrev eq_natAbs_iff_mul_eq_zero := @natAbs_eq_iff_mul_eq_zero
|
||||
|
||||
instance instIsLinearOrder : IsLinearOrder Int := by
|
||||
apply IsLinearOrder.of_le
|
||||
case le_antisymm => constructor; apply Int.le_antisymm
|
||||
case le_total => constructor; apply Int.le_total
|
||||
case le_trans => constructor; apply Int.le_trans
|
||||
|
||||
instance : LawfulOrderLT Int where
|
||||
lt_iff := by
|
||||
simp [← Int.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
end Int
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Lawful.Basic
|
||||
public import Init.Data.Subtype
|
||||
public import Init.Data.Subtype.Basic
|
||||
public import Init.PropLemmas
|
||||
|
||||
public section
|
||||
|
||||
@@ -8,7 +8,7 @@ module
|
||||
prelude
|
||||
public import all Init.Data.List.Lemmas -- for dsimping with `getElem?_cons_succ`
|
||||
public import Init.Data.List.Count
|
||||
public import Init.Data.Subtype
|
||||
public import Init.Data.Subtype.Basic
|
||||
public import Init.BinderNameHint
|
||||
|
||||
public section
|
||||
@@ -123,7 +123,7 @@ theorem attachWith_congr {l₁ l₂ : List α} (w : l₁ = l₂) {P : α → Pro
|
||||
⟨x, mem_cons_self⟩ :: xs.attach.map fun ⟨y, h⟩ => ⟨y, mem_cons_of_mem x h⟩ := by
|
||||
simp only [attach, attachWith, pmap, map_pmap, cons.injEq, true_and]
|
||||
apply pmap_congr_left
|
||||
intros a _ m' _
|
||||
intro a _ m' _
|
||||
rfl
|
||||
|
||||
@[simp, grind =]
|
||||
|
||||
@@ -242,8 +242,7 @@ instance instLT [LT α] : LT (List α) := ⟨List.lt⟩
|
||||
instance decidableLT [DecidableEq α] [LT α] [DecidableLT α] (l₁ l₂ : List α) :
|
||||
Decidable (l₁ < l₂) := decidableLex (· < ·) l₁ l₂
|
||||
|
||||
@[deprecated decidableLT (since := "2024-12-13"), inherit_doc decidableLT]
|
||||
abbrev hasDecidableLt := @decidableLT
|
||||
|
||||
|
||||
/--
|
||||
Non-strict ordering of lists with respect to a strict ordering of their elements.
|
||||
@@ -1722,14 +1721,8 @@ Examples:
|
||||
-/
|
||||
def idxOf [BEq α] (a : α) : List α → Nat := findIdx (· == a)
|
||||
|
||||
/-- Returns the index of the first element equal to `a`, or the length of the list otherwise. -/
|
||||
@[deprecated idxOf (since := "2025-01-29")] abbrev indexOf := @idxOf
|
||||
|
||||
@[simp] theorem idxOf_nil [BEq α] : ([] : List α).idxOf x = 0 := rfl
|
||||
|
||||
@[deprecated idxOf_nil (since := "2025-01-29")]
|
||||
theorem indexOf_nil [BEq α] : ([] : List α).idxOf x = 0 := rfl
|
||||
|
||||
/-! ### findIdx? -/
|
||||
|
||||
/--
|
||||
@@ -1760,10 +1753,6 @@ Examples:
|
||||
-/
|
||||
@[inline] def idxOf? [BEq α] (a : α) : List α → Option Nat := findIdx? (· == a)
|
||||
|
||||
/-- Return the index of the first occurrence of `a` in the list. -/
|
||||
@[deprecated idxOf? (since := "2025-01-29")]
|
||||
abbrev indexOf? := @idxOf?
|
||||
|
||||
/-! ### findFinIdx? -/
|
||||
|
||||
/--
|
||||
@@ -2119,21 +2108,10 @@ def range' : (start len : Nat) → (step : Nat := 1) → List Nat
|
||||
| _, 0, _ => []
|
||||
| s, n+1, step => s :: range' (s+step) n step
|
||||
|
||||
/-! ### iota -/
|
||||
|
||||
/--
|
||||
`O(n)`. `iota n` is the numbers from `1` to `n` inclusive, in decreasing order.
|
||||
* `iota 5 = [5, 4, 3, 2, 1]`
|
||||
-/
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
def iota : Nat → List Nat
|
||||
| 0 => []
|
||||
| m@(n+1) => m :: iota n
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[simp] theorem iota_zero : iota 0 = [] := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[simp] theorem iota_succ : iota (i+1) = (i+1) :: iota i := rfl
|
||||
@[simp, grind =] theorem range'_zero : range' s 0 step = [] := rfl
|
||||
@[simp, grind =] theorem range'_one {s step : Nat} : range' s 1 step = [s] := rfl
|
||||
-- The following theorem is intentionally not a simp lemma.
|
||||
theorem range'_succ : range' s (n + 1) step = s :: range' (s + step) n step := rfl
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@@ -2153,38 +2131,6 @@ def zipIdx : (l : List α) → (n : Nat := 0) → List (α × Nat)
|
||||
@[simp] theorem zipIdx_nil : ([] : List α).zipIdx i = [] := rfl
|
||||
@[simp] theorem zipIdx_cons : (a::as).zipIdx i = (a, i) :: as.zipIdx (i+1) := rfl
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
/--
|
||||
`O(|l|)`. `enumFrom n l` is like `enum` but it allows you to specify the initial index.
|
||||
* `enumFrom 5 [a, b, c] = [(5, a), (6, b), (7, c)]`
|
||||
-/
|
||||
@[deprecated "Use `zipIdx` instead; note the signature change." (since := "2025-01-21")]
|
||||
def enumFrom : Nat → List α → List (Nat × α)
|
||||
| _, [] => nil
|
||||
| n, x :: xs => (n, x) :: enumFrom (n + 1) xs
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated zipIdx_nil (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_nil : ([] : List α).enumFrom i = [] := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated zipIdx_cons (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_cons : (a::as).enumFrom i = (i, a) :: as.enumFrom (i+1) := rfl
|
||||
|
||||
/-! ### enum -/
|
||||
|
||||
set_option linter.deprecated false in
|
||||
/--
|
||||
`O(|l|)`. `enum l` pairs up each element with its index in the list.
|
||||
* `enum [a, b, c] = [(0, a), (1, b), (2, c)]`
|
||||
-/
|
||||
@[deprecated "Use `zipIdx` instead; note the signature change." (since := "2025-01-21")]
|
||||
def enum : List α → List (Nat × α) := enumFrom 0
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated zipIdx_nil (since := "2025-01-21"), simp]
|
||||
theorem enum_nil : ([] : List α).enum = [] := rfl
|
||||
|
||||
/-! ## Minima and maxima -/
|
||||
|
||||
/-! ### min? -/
|
||||
@@ -2604,25 +2550,6 @@ Examples:
|
||||
exact go s n (m + 1)
|
||||
exact (go s n 0).symm
|
||||
|
||||
/-! ### iota -/
|
||||
|
||||
/-- Tail-recursive version of `List.iota`. -/
|
||||
@[deprecated "Use `List.range' 1 n` instead of `iota n`." (since := "2025-01-20")]
|
||||
def iotaTR (n : Nat) : List Nat :=
|
||||
let rec go : Nat → List Nat → List Nat
|
||||
| 0, r => r.reverse
|
||||
| m@(n+1), r => go n (m::r)
|
||||
go n []
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[csimp]
|
||||
theorem iota_eq_iotaTR : @iota = @iotaTR :=
|
||||
have aux (n : Nat) (r : List Nat) : iotaTR.go n r = r.reverse ++ iota n := by
|
||||
induction n generalizing r with
|
||||
| zero => simp [iota, iotaTR.go]
|
||||
| succ n ih => simp [iota, iotaTR.go, ih, append_assoc]
|
||||
funext fun n => by simp [iotaTR, aux]
|
||||
|
||||
/-! ## Other list operations -/
|
||||
|
||||
/-! ### intersperse -/
|
||||
|
||||
@@ -57,15 +57,9 @@ theorem eraseP_of_forall_not {l : List α} (h : ∀ a, a ∈ l → ¬p a) : l.er
|
||||
rintro x h' rfl
|
||||
simp_all
|
||||
|
||||
@[deprecated eraseP_eq_nil_iff (since := "2025-01-30")]
|
||||
abbrev eraseP_eq_nil := @eraseP_eq_nil_iff
|
||||
|
||||
theorem eraseP_ne_nil_iff {xs : List α} {p : α → Bool} : xs.eraseP p ≠ [] ↔ xs ≠ [] ∧ ∀ x, p x → xs ≠ [x] := by
|
||||
simp
|
||||
|
||||
@[deprecated eraseP_ne_nil_iff (since := "2025-01-30")]
|
||||
abbrev eraseP_ne_nil := @eraseP_ne_nil_iff
|
||||
|
||||
theorem exists_of_eraseP : ∀ {l : List α} {a} (_ : a ∈ l) (_ : p a),
|
||||
∃ a l₁ l₂, (∀ b ∈ l₁, ¬p b) ∧ p a ∧ l = l₁ ++ a :: l₂ ∧ l.eraseP p = l₁ ++ l₂
|
||||
| b :: l, _, al, pa =>
|
||||
@@ -352,17 +346,11 @@ theorem erase_eq_eraseP [LawfulBEq α] (a : α) : ∀ (l : List α), l.erase a =
|
||||
rw [erase_eq_eraseP]
|
||||
simp
|
||||
|
||||
@[deprecated erase_eq_nil_iff (since := "2025-01-30")]
|
||||
abbrev erase_eq_nil := @erase_eq_nil_iff
|
||||
|
||||
theorem erase_ne_nil_iff [LawfulBEq α] {xs : List α} {a : α} :
|
||||
xs.erase a ≠ [] ↔ xs ≠ [] ∧ xs ≠ [a] := by
|
||||
rw [erase_eq_eraseP]
|
||||
simp
|
||||
|
||||
@[deprecated erase_ne_nil_iff (since := "2025-01-30")]
|
||||
abbrev erase_ne_nil := @erase_ne_nil_iff
|
||||
|
||||
theorem exists_erase_eq [LawfulBEq α] {a : α} {l : List α} (h : a ∈ l) :
|
||||
∃ l₁ l₂, a ∉ l₁ ∧ l = l₁ ++ a :: l₂ ∧ l.erase a = l₁ ++ l₂ := by
|
||||
let ⟨_, l₁, l₂, h₁, e, h₂, h₃⟩ := exists_of_eraseP h (beq_self_eq_true _)
|
||||
@@ -439,7 +427,7 @@ theorem erase_append_left [LawfulBEq α] {l₁ : List α} (l₂) (h : a ∈ l₁
|
||||
theorem erase_append_right [LawfulBEq α] {a : α} {l₁ : List α} (l₂ : List α) (h : a ∉ l₁) :
|
||||
(l₁ ++ l₂).erase a = (l₁ ++ l₂.erase a) := by
|
||||
rw [erase_eq_eraseP, erase_eq_eraseP, eraseP_append_right]
|
||||
intros b h' h''; rw [eq_of_beq h''] at h; exact h h'
|
||||
intro b h' h''; rw [eq_of_beq h''] at h; exact h h'
|
||||
|
||||
@[grind =]
|
||||
theorem erase_append [LawfulBEq α] {a : α} {l₁ l₂ : List α} :
|
||||
@@ -582,8 +570,7 @@ theorem eraseIdx_eq_take_drop_succ :
|
||||
| a::l, 0
|
||||
| a::l, i + 1 => simp
|
||||
|
||||
@[deprecated eraseIdx_eq_nil_iff (since := "2025-01-30")]
|
||||
abbrev eraseIdx_eq_nil := @eraseIdx_eq_nil_iff
|
||||
|
||||
|
||||
theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2 ≤ l.length ∨ (l.length = 1 ∧ i ≠ 0) := by
|
||||
match l with
|
||||
@@ -591,8 +578,7 @@ theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2
|
||||
| [a]
|
||||
| a::b::l => simp
|
||||
|
||||
@[deprecated eraseIdx_ne_nil_iff (since := "2025-01-30")]
|
||||
abbrev eraseIdx_ne_nil := @eraseIdx_ne_nil_iff
|
||||
|
||||
|
||||
@[grind]
|
||||
theorem eraseIdx_sublist : ∀ (l : List α) (k : Nat), eraseIdx l k <+ l
|
||||
@@ -700,7 +686,6 @@ theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α]
|
||||
rw [eq_comm, eraseIdx_eq_self]
|
||||
exact Nat.le_of_eq (idxOf_eq_length h).symm
|
||||
|
||||
@[deprecated erase_eq_eraseIdx_of_idxOf (since := "2025-01-29")]
|
||||
abbrev erase_eq_eraseIdx_of_indexOf := @erase_eq_eraseIdx_of_idxOf
|
||||
|
||||
|
||||
end List
|
||||
|
||||
@@ -1098,15 +1098,9 @@ theorem idxOf_cons [BEq α] :
|
||||
dsimp [idxOf]
|
||||
simp [findIdx_cons]
|
||||
|
||||
@[deprecated idxOf_cons (since := "2025-01-29")]
|
||||
abbrev indexOf_cons := @idxOf_cons
|
||||
|
||||
@[simp] theorem idxOf_cons_self [BEq α] [ReflBEq α] {l : List α} : (a :: l).idxOf a = 0 := by
|
||||
simp [idxOf_cons]
|
||||
|
||||
@[deprecated idxOf_cons_self (since := "2025-01-29")]
|
||||
abbrev indexOf_cons_self := @idxOf_cons_self
|
||||
|
||||
@[grind =]
|
||||
theorem idxOf_append [BEq α] [LawfulBEq α] {l₁ l₂ : List α} {a : α} :
|
||||
(l₁ ++ l₂).idxOf a = if a ∈ l₁ then l₁.idxOf a else l₂.idxOf a + l₁.length := by
|
||||
@@ -1117,8 +1111,7 @@ theorem idxOf_append [BEq α] [LawfulBEq α] {l₁ l₂ : List α} {a : α} :
|
||||
· rw [if_neg]
|
||||
simpa using h
|
||||
|
||||
@[deprecated idxOf_append (since := "2025-01-29")]
|
||||
abbrev indexOf_append := @idxOf_append
|
||||
|
||||
|
||||
theorem idxOf_eq_length [BEq α] [LawfulBEq α] {l : List α} (h : a ∉ l) : l.idxOf a = l.length := by
|
||||
induction l with
|
||||
@@ -1128,8 +1121,7 @@ theorem idxOf_eq_length [BEq α] [LawfulBEq α] {l : List α} (h : a ∉ l) : l.
|
||||
simp only [idxOf_cons, cond_eq_if, beq_iff_eq]
|
||||
split <;> simp_all
|
||||
|
||||
@[deprecated idxOf_eq_length (since := "2025-01-29")]
|
||||
abbrev indexOf_eq_length := @idxOf_eq_length
|
||||
|
||||
|
||||
theorem idxOf_lt_length_of_mem [BEq α] [EquivBEq α] {l : List α} (h : a ∈ l) : l.idxOf a < l.length := by
|
||||
induction l with
|
||||
@@ -1159,8 +1151,7 @@ theorem idxOf_lt_length_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
|
||||
grind_pattern idxOf_lt_length_iff => l.idxOf a, l.length
|
||||
|
||||
@[deprecated idxOf_lt_length_of_mem (since := "2025-01-29")]
|
||||
abbrev indexOf_lt_length := @idxOf_lt_length_of_mem
|
||||
|
||||
|
||||
/-! ### finIdxOf?
|
||||
|
||||
@@ -1231,8 +1222,7 @@ The lemmas below should be made consistent with those for `findIdx?` (and proved
|
||||
· rintro w x h rfl
|
||||
contradiction
|
||||
|
||||
@[deprecated idxOf?_eq_none_iff (since := "2025-01-29")]
|
||||
abbrev indexOf?_eq_none_iff := @idxOf?_eq_none_iff
|
||||
|
||||
|
||||
@[simp, grind =]
|
||||
theorem isSome_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
@@ -1251,9 +1241,9 @@ theorem isNone_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
/-! ### lookup -/
|
||||
|
||||
section lookup
|
||||
variable [BEq α] [LawfulBEq α]
|
||||
variable [BEq α]
|
||||
|
||||
@[simp] theorem lookup_cons_self {k : α} : ((k,b) :: es).lookup k = some b := by
|
||||
@[simp] theorem lookup_cons_self [ReflBEq α] {k : α} : ((k,b) :: es).lookup k = some b := by
|
||||
simp [lookup_cons]
|
||||
|
||||
@[simp] theorem lookup_singleton {a b : α} : [(a,b)].lookup c = if c == a then some b else none := by
|
||||
@@ -1272,13 +1262,13 @@ theorem lookup_eq_findSome? {l : List (α × β)} {k : α} :
|
||||
|
||||
@[simp, grind =] theorem lookup_eq_none_iff {l : List (α × β)} {k : α} :
|
||||
l.lookup k = none ↔ ∀ p ∈ l, k != p.1 := by
|
||||
simp [lookup_eq_findSome?]
|
||||
simp [lookup_eq_findSome?, bne]
|
||||
|
||||
@[simp] theorem lookup_isSome_iff {l : List (α × β)} {k : α} :
|
||||
(l.lookup k).isSome ↔ ∃ p ∈ l, k == p.1 := by
|
||||
simp [lookup_eq_findSome?]
|
||||
|
||||
theorem lookup_eq_some_iff {l : List (α × β)} {k : α} {b : β} :
|
||||
theorem lookup_eq_some_iff [LawfulBEq α] {l : List (α × β)} {k : α} {b : β} :
|
||||
l.lookup k = some b ↔ ∃ l₁ l₂, l = l₁ ++ (k, b) :: l₂ ∧ ∀ p ∈ l₁, k != p.1 := by
|
||||
simp only [lookup_eq_findSome?, findSome?_eq_some_iff]
|
||||
constructor
|
||||
@@ -1308,11 +1298,11 @@ theorem lookup_replicate_of_pos {k : α} (h : 0 < n) :
|
||||
(replicate n (a, b)).lookup k = if k == a then some b else none := by
|
||||
simp [lookup_replicate, Nat.ne_of_gt h]
|
||||
|
||||
theorem lookup_replicate_self {a : α} :
|
||||
theorem lookup_replicate_self [ReflBEq α] {a : α} :
|
||||
(replicate n (a, b)).lookup a = if n = 0 then none else some b := by
|
||||
simp [lookup_replicate]
|
||||
|
||||
@[simp] theorem lookup_replicate_self_of_pos {a : α} (h : 0 < n) :
|
||||
@[simp] theorem lookup_replicate_self_of_pos [ReflBEq α] {a : α} (h : 0 < n) :
|
||||
(replicate n (a, b)).lookup a = some b := by
|
||||
simp [lookup_replicate_self, Nat.ne_of_gt h]
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ Example:
|
||||
[10, 14, 14]
|
||||
```
|
||||
-/
|
||||
@[inline] def filterMapTR (f : α → Option β) (l : List α) : List β := go l #[] where
|
||||
@[inline, expose] 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
|
||||
@@ -367,7 +367,7 @@ def modifyTR (l : List α) (i : Nat) (f : α → α) : List α := go l i #[] whe
|
||||
| a :: l, 0, acc => acc.toListAppend (f a :: l)
|
||||
| a :: l, i+1, acc => go l i (acc.push a)
|
||||
|
||||
theorem modifyTR_go_eq : ∀ l i, modifyTR.go f l i acc = acc.toList ++ modify l i f
|
||||
private theorem modifyTR_go_eq : ∀ l i, modifyTR.go f l i acc = acc.toList ++ modify l i f
|
||||
| [], i => by cases i <;> simp [modifyTR.go, modify]
|
||||
| a :: l, 0 => by simp [modifyTR.go, modify]
|
||||
| a :: l, i+1 => by simp [modifyTR.go, modify, modifyTR_go_eq l]
|
||||
@@ -399,7 +399,7 @@ Examples:
|
||||
| _, [], acc => acc.toList
|
||||
| n+1, a :: l, acc => go n l (acc.push a)
|
||||
|
||||
theorem insertIdxTR_go_eq : ∀ i l, insertIdxTR.go a i l acc = acc.toList ++ insertIdx l i a
|
||||
private theorem insertIdxTR_go_eq : ∀ i l, insertIdxTR.go a i l acc = acc.toList ++ insertIdx l i a
|
||||
| 0, l | _+1, [] => by simp [insertIdxTR.go, insertIdx]
|
||||
| n+1, a :: l => by simp [insertIdxTR.go, insertIdx, insertIdxTR_go_eq n l]
|
||||
|
||||
@@ -564,24 +564,7 @@ def zipIdxTR (l : List α) (n : Nat := 0) : List (α × Nat) :=
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
/-- Tail recursive version of `List.enumFrom`. -/
|
||||
@[deprecated zipIdxTR (since := "2025-01-21")]
|
||||
def enumFromTR (n : Nat) (l : List α) : List (Nat × α) :=
|
||||
let as := l.toArray
|
||||
(as.foldr (fun a (n, acc) => (n-1, (n-1, a) :: acc)) (n + as.size, [])).2
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated zipIdx_eq_zipIdxTR (since := "2025-01-21"), csimp]
|
||||
theorem enumFrom_eq_enumFromTR : @enumFrom = @enumFromTR := by
|
||||
funext α n l; simp only [enumFromTR]
|
||||
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_toList]
|
||||
simp +zetaDelta [go]
|
||||
|
||||
/-! ## Other list operations -/
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ See also
|
||||
|
||||
Further results, which first require developing further automation around `Nat`, appear in
|
||||
* `Init.Data.List.Nat.Basic`: miscellaneous lemmas
|
||||
* `Init.Data.List.Nat.Range`: `List.range` and `List.enum`
|
||||
* `Init.Data.List.Nat.Range`: `List.range`, `List.range'` and `List.enum`
|
||||
* `Init.Data.List.Nat.TakeDrop`: `List.take` and `List.drop`
|
||||
|
||||
Also
|
||||
@@ -1084,6 +1084,12 @@ theorem getLast?_tail {l : List α} : (tail l).getLast? = if l.length = 1 then n
|
||||
rw [if_neg]
|
||||
rintro ⟨⟩
|
||||
|
||||
@[simp, grind =]
|
||||
theorem cons_head_tail (h : l ≠ []) : l.head h :: l.tail = l := by
|
||||
induction l with
|
||||
| nil => contradiction
|
||||
| cons ih => simp_all
|
||||
|
||||
/-! ## Basic operations -/
|
||||
|
||||
/-! ### map -/
|
||||
@@ -1586,9 +1592,7 @@ theorem filterMap_eq_cons_iff {l} {b} {bs} :
|
||||
theorem not_mem_append {a : α} {s t : List α} (h₁ : a ∉ s) (h₂ : a ∉ t) : a ∉ s ++ t :=
|
||||
mt mem_append.1 $ not_or.mpr ⟨h₁, h₂⟩
|
||||
|
||||
@[deprecated mem_append (since := "2025-01-13")]
|
||||
theorem mem_append_eq {a : α} {s t : List α} : (a ∈ s ++ t) = (a ∈ s ∨ a ∈ t) :=
|
||||
propext mem_append
|
||||
|
||||
|
||||
/--
|
||||
See also `eq_append_cons_of_mem`, which proves a stronger version
|
||||
@@ -1698,7 +1702,7 @@ theorem getLast_concat {a : α} : ∀ {l : List α}, getLast (l ++ [a]) (by simp
|
||||
@[simp] theorem append_eq_nil_iff : p ++ q = [] ↔ p = [] ∧ q = [] := by
|
||||
cases p <;> simp
|
||||
|
||||
@[deprecated append_eq_nil_iff (since := "2025-01-13")] abbrev append_eq_nil := @append_eq_nil_iff
|
||||
|
||||
|
||||
theorem nil_eq_append_iff : [] = a ++ b ↔ a = [] ∧ b = [] := by
|
||||
simp
|
||||
@@ -1853,6 +1857,10 @@ theorem append_eq_map_iff {f : α → β} :
|
||||
theorem sum_append_nat {l₁ l₂ : List Nat} : (l₁ ++ l₂).sum = l₁.sum + l₂.sum := by
|
||||
induction l₁ generalizing l₂ <;> simp_all [Nat.add_assoc]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_reverse_nat (xs : List Nat) : xs.reverse.sum = xs.sum := by
|
||||
induction xs <;> simp_all [Nat.add_comm]
|
||||
|
||||
/-! ### concat
|
||||
|
||||
Note that `concat_eq_append` is a `@[simp]` lemma, so `concat` should usually not appear in goals.
|
||||
@@ -2268,8 +2276,7 @@ theorem map_const' {l : List α} {b : β} : map (fun _ => b) l = replicate l.len
|
||||
simp only [mem_append, mem_replicate, ne_eq]
|
||||
rintro (⟨-, rfl⟩ | ⟨_, rfl⟩) <;> rfl
|
||||
|
||||
@[deprecated replicate_append_replicate (since := "2025-01-16")]
|
||||
abbrev append_replicate_replicate := @replicate_append_replicate
|
||||
|
||||
|
||||
theorem append_eq_replicate_iff {l₁ l₂ : List α} {a : α} :
|
||||
l₁ ++ l₂ = replicate n a ↔
|
||||
@@ -2657,8 +2664,6 @@ theorem foldl_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
· simp
|
||||
· simp [*]
|
||||
|
||||
@[deprecated foldl_map_hom (since := "2025-01-20")] abbrev foldl_map' := @foldl_map_hom
|
||||
|
||||
theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {l : List α}
|
||||
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
|
||||
(l.map g).foldr f' (g a) = g (l.foldr f a) := by
|
||||
@@ -2666,8 +2671,6 @@ theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
· simp
|
||||
· simp [*]
|
||||
|
||||
@[deprecated foldr_map_hom (since := "2025-01-20")] abbrev foldr_map' := @foldr_map_hom
|
||||
|
||||
@[simp] theorem foldrM_append [Monad m] [LawfulMonad m] {f : α → β → m β} {b : β} {l l' : List α} :
|
||||
(l ++ l').foldrM f b = l'.foldrM f b >>= l.foldrM f := by
|
||||
induction l <;> simp [*]
|
||||
@@ -3735,12 +3738,6 @@ theorem mem_iff_get? {a} {l : List α} : a ∈ l ↔ ∃ n, l.get? n = some a :=
|
||||
|
||||
/-! ### Deprecations -/
|
||||
|
||||
@[deprecated _root_.isSome_getElem? (since := "2024-12-09")]
|
||||
theorem isSome_getElem? {l : List α} {i : Nat} : l[i]?.isSome ↔ i < l.length := by
|
||||
simp
|
||||
|
||||
@[deprecated _root_.isNone_getElem? (since := "2024-12-09")]
|
||||
theorem isNone_getElem? {l : List α} {i : Nat} : l[i]?.isNone ↔ l.length ≤ i := by
|
||||
simp
|
||||
|
||||
end List
|
||||
|
||||
@@ -8,9 +8,13 @@ module
|
||||
prelude
|
||||
public import Init.Data.List.Lemmas
|
||||
public import Init.Data.List.Nat.TakeDrop
|
||||
public import Init.Data.Order.Factories
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
@@ -18,6 +22,11 @@ namespace List
|
||||
|
||||
/-! ### Lexicographic ordering -/
|
||||
|
||||
instance [LT α] [Std.Asymm (α := List α) (· < ·)] : LawfulOrderLT (List α) where
|
||||
lt_iff := by
|
||||
simp only [LE.le, List.le, Classical.not_not, iff_and_self]
|
||||
apply Std.Asymm.asymm
|
||||
|
||||
@[simp] theorem lex_lt [LT α] {l₁ l₂ : List α} : Lex (· < ·) l₁ l₂ ↔ l₁ < l₂ := Iff.rfl
|
||||
@[simp] theorem not_lex_lt [LT α] {l₁ l₂ : List α} : ¬ Lex (· < ·) l₁ l₂ ↔ l₂ ≤ l₁ := Iff.rfl
|
||||
|
||||
@@ -79,7 +88,6 @@ theorem not_cons_lex_cons_iff [DecidableEq α] [DecidableRel r] {a b} {l₁ l₂
|
||||
rw [cons_lex_cons_iff, not_or, Decidable.not_and_iff_or_not, and_or_left]
|
||||
|
||||
theorem cons_le_cons_iff [LT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{a b} {l₁ l₂ : List α} :
|
||||
@@ -101,19 +109,22 @@ theorem cons_le_cons_iff [LT α]
|
||||
exact ⟨i₂.antisymm _ _ h₃ h₁, h₂⟩
|
||||
· rintro (h | ⟨h₁, h₂⟩)
|
||||
· left
|
||||
exact ⟨i₁.asymm _ _ h, fun w => i₀.irrefl _ (w ▸ h)⟩
|
||||
exact ⟨i₁.asymm _ _ h, fun w => Irrefl.irrefl _ (w ▸ h)⟩
|
||||
· right
|
||||
exact ⟨fun w => i₀.irrefl _ (h₁ ▸ w), h₂⟩
|
||||
exact ⟨fun w => Irrefl.irrefl _ (h₁ ▸ w), h₂⟩
|
||||
|
||||
theorem not_lt_of_cons_le_cons [LT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{a b : α} {l₁ l₂ : List α} (h : a :: l₁ ≤ b :: l₂) : ¬ b < a := by
|
||||
rw [cons_le_cons_iff] at h
|
||||
rcases h with h | ⟨rfl, h⟩
|
||||
· exact i₁.asymm _ _ h
|
||||
· exact i₀.irrefl _
|
||||
· exact Irrefl.irrefl _
|
||||
|
||||
theorem left_le_left_of_cons_le_cons [LT α] [LE α] [IsLinearOrder α]
|
||||
[LawfulOrderLT α] {a b : α} {l₁ l₂ : List α} (h : a :: l₁ ≤ b :: l₂) : a ≤ b := by
|
||||
simpa [not_lt] using not_lt_of_cons_le_cons h
|
||||
|
||||
theorem le_of_cons_le_cons [LT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
@@ -163,14 +174,9 @@ instance [LT α] [Trans (· < · : α → α → Prop) (· < ·) (· < ·)] :
|
||||
Trans (· < · : List α → List α → Prop) (· < ·) (· < ·) where
|
||||
trans h₁ h₂ := List.lt_trans h₁ h₂
|
||||
|
||||
@[deprecated List.le_antisymm (since := "2024-12-13")]
|
||||
protected abbrev lt_antisymm := @List.le_antisymm
|
||||
|
||||
protected theorem lt_of_le_of_lt [LT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[i₃ : Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
|
||||
protected theorem lt_of_le_of_lt [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α]
|
||||
{l₁ l₂ l₃ : List α} (h₁ : l₁ ≤ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ := by
|
||||
induction h₂ generalizing l₁ with
|
||||
| nil => simp_all
|
||||
@@ -180,11 +186,8 @@ protected theorem lt_of_le_of_lt [LT α]
|
||||
| nil => simp_all
|
||||
| cons c l₁ =>
|
||||
apply Lex.rel
|
||||
replace h₁ := not_lt_of_cons_le_cons h₁
|
||||
apply Classical.byContradiction
|
||||
intro h₂
|
||||
have := i₃.trans h₁ h₂
|
||||
contradiction
|
||||
replace h₁ := left_le_left_of_cons_le_cons h₁
|
||||
exact lt_of_le_of_lt h₁ hab
|
||||
| cons w₃ ih =>
|
||||
rename_i a as bs
|
||||
cases l₁ with
|
||||
@@ -194,21 +197,34 @@ protected theorem lt_of_le_of_lt [LT α]
|
||||
by_cases w₅ : a = c
|
||||
· subst w₅
|
||||
exact Lex.cons (ih (le_of_cons_le_cons h₁))
|
||||
· exact Lex.rel (Classical.byContradiction fun w₆ => w₅ (i₂.antisymm _ _ w₄ w₆))
|
||||
· simp only [not_lt] at w₄
|
||||
exact Lex.rel (lt_of_le_of_ne w₄ (w₅.imp Eq.symm))
|
||||
|
||||
protected theorem le_trans [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
@[deprecated List.lt_of_le_of_lt (since := "2025-08-01")]
|
||||
protected theorem lt_of_le_of_lt' [LT α]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{l₁ l₂ l₃ : List α} (h₁ : l₁ ≤ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
|
||||
letI : LE α := .ofLT α
|
||||
haveI : IsLinearOrder α := IsLinearOrder.of_lt
|
||||
List.lt_of_le_of_lt h₁ h₂
|
||||
|
||||
protected theorem le_trans [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α]
|
||||
{l₁ l₂ l₃ : List α} (h₁ : l₁ ≤ l₂) (h₂ : l₂ ≤ l₃) : l₁ ≤ l₃ :=
|
||||
fun h₃ => h₁ (List.lt_of_le_of_lt h₂ h₃)
|
||||
|
||||
@[deprecated List.le_trans (since := "2025-08-01")]
|
||||
protected theorem le_trans' [LT α]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{l₁ l₂ l₃ : List α} (h₁ : l₁ ≤ l₂) (h₂ : l₂ ≤ l₃) : l₁ ≤ l₃ :=
|
||||
fun h₃ => h₁ (List.lt_of_le_of_lt h₂ h₃)
|
||||
letI := LE.ofLT α
|
||||
haveI : IsLinearOrder α := IsLinearOrder.of_lt
|
||||
List.le_trans h₁ h₂
|
||||
|
||||
instance [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)] :
|
||||
instance [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α] :
|
||||
Trans (· ≤ · : List α → List α → Prop) (· ≤ ·) (· ≤ ·) where
|
||||
trans h₁ h₂ := List.le_trans h₁ h₂
|
||||
|
||||
@@ -248,14 +264,21 @@ theorem not_lex_total {r : α → α → Prop}
|
||||
obtain (_ | _) := not_lex_total h l₁ l₂ <;> contradiction
|
||||
|
||||
protected theorem le_total [LT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)] (l₁ l₂ : List α) : l₁ ≤ l₂ ∨ l₂ ≤ l₁ :=
|
||||
not_lex_total i.total l₂ l₁
|
||||
[i : Std.Asymm (· < · : α → α → Prop)] (l₁ l₂ : List α) : l₁ ≤ l₂ ∨ l₂ ≤ l₁ :=
|
||||
not_lex_total i.total_not.total l₂ l₁
|
||||
|
||||
instance [LT α]
|
||||
[Std.Total (¬ · < · : α → α → Prop)] :
|
||||
protected theorem le_total_of_asymm [LT α]
|
||||
[i : Std.Asymm (· < · : α → α → Prop)] (l₁ l₂ : List α) : l₁ ≤ l₂ ∨ l₂ ≤ l₁ :=
|
||||
List.le_total l₁ l₂
|
||||
|
||||
instance [LT α] [Std.Asymm (· < · : α → α → Prop)] :
|
||||
Std.Total (· ≤ · : List α → List α → Prop) where
|
||||
total := List.le_total
|
||||
|
||||
@[no_expose]
|
||||
instance instIsLinearOrder [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α] :
|
||||
IsLinearOrder (List α) := IsLinearOrder.of_le
|
||||
|
||||
@[simp] protected theorem not_lt [LT α]
|
||||
{l₁ l₂ : List α} : ¬ l₁ < l₂ ↔ l₂ ≤ l₁ := Iff.rfl
|
||||
|
||||
@@ -263,7 +286,7 @@ instance [LT α]
|
||||
{l₁ l₂ : List α} : ¬ l₂ ≤ l₁ ↔ l₁ < l₂ := Classical.not_not
|
||||
|
||||
protected theorem le_of_lt [LT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)]
|
||||
[i : Std.Asymm (· < · : α → α → Prop)]
|
||||
{l₁ l₂ : List α} (h : l₁ < l₂) : l₁ ≤ l₂ := by
|
||||
obtain (h' | h') := List.le_total l₁ l₂
|
||||
· exact h'
|
||||
@@ -273,7 +296,7 @@ protected theorem le_of_lt [LT α]
|
||||
protected theorem le_iff_lt_or_eq [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Total (¬ · < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
{l₁ l₂ : List α} : l₁ ≤ l₂ ↔ l₁ < l₂ ∨ l₁ = l₂ := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -457,7 +480,6 @@ protected theorem lt_iff_exists [LT α] {l₁ l₂ : List α} :
|
||||
simp
|
||||
|
||||
protected theorem le_iff_exists [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)] {l₁ l₂ : List α} :
|
||||
l₁ ≤ l₂ ↔
|
||||
@@ -481,7 +503,6 @@ theorem append_left_lt [LT α] {l₁ l₂ l₃ : List α} (h : l₂ < l₃) :
|
||||
| cons a l₁ ih => simp [cons_lt_cons_iff, ih]
|
||||
|
||||
theorem append_left_le [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{l₁ l₂ l₃ : List α} (h : l₂ ≤ l₃) :
|
||||
@@ -515,10 +536,8 @@ protected theorem map_lt [LT α] [LT β]
|
||||
simp [cons_lt_cons_iff, w, h]
|
||||
|
||||
protected theorem map_le [LT α] [LT β]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Irrefl (· < · : β → β → Prop)]
|
||||
[Std.Asymm (· < · : β → β → Prop)]
|
||||
[Std.Antisymm (¬ · < · : β → β → Prop)]
|
||||
{l₁ l₂ : List α} {f : α → β} (w : ∀ x y, x < y → f x < f y) (h : l₁ ≤ l₂) :
|
||||
|
||||
@@ -61,7 +61,7 @@ proof that the index is valid.
|
||||
`List.mapIdxM` is a variant that does not provide the function with evidence that the index is
|
||||
valid.
|
||||
-/
|
||||
@[inline] def mapFinIdxM [Monad m] (as : List α) (f : (i : Nat) → α → (h : i < as.length) → m β) : m (List β) :=
|
||||
@[inline, expose] def mapFinIdxM [Monad m] (as : List α) (f : (i : Nat) → α → (h : i < as.length) → m β) : m (List β) :=
|
||||
go as #[] (by simp)
|
||||
where
|
||||
/-- Auxiliary for `mapFinIdxM`:
|
||||
@@ -78,7 +78,7 @@ found, returning the list of results.
|
||||
`List.mapFinIdxM` is a variant that additionally provides the function with a proof that the index
|
||||
is valid.
|
||||
-/
|
||||
@[inline] def mapIdxM [Monad m] (f : Nat → α → m β) (as : List α) : m (List β) := go as #[] where
|
||||
@[inline, expose] def mapIdxM [Monad m] (f : Nat → α → m β) (as : List α) : m (List β) := go as #[] where
|
||||
/-- Auxiliary for `mapIdxM`:
|
||||
`mapIdxM.go [a₀, a₁, ...] acc = acc.toList ++ [f acc.size a₀, f (acc.size + 1) a₁, ...]` -/
|
||||
@[specialize] go : List α → Array β → m (List β)
|
||||
@@ -182,8 +182,7 @@ theorem mapFinIdx_eq_zipIdx_map {l : List α} {f : (i : Nat) → α → (h : i <
|
||||
f i x (by rw [mk_mem_zipIdx_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1) := by
|
||||
apply ext_getElem <;> simp
|
||||
|
||||
@[deprecated mapFinIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapFinIdx_eq_zipWithIndex_map := @mapFinIdx_eq_zipIdx_map
|
||||
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_eq_nil_iff {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
@@ -220,7 +219,7 @@ theorem mapFinIdx_eq_cons_iff {l : List α} {b : β} {f : (i : Nat) → α → (
|
||||
cases l with
|
||||
| nil => simp
|
||||
| cons x l' =>
|
||||
simp only [mapFinIdx_cons, cons.injEq,
|
||||
simp only [mapFinIdx_cons, cons.injEq,
|
||||
]
|
||||
constructor
|
||||
· rintro ⟨rfl, rfl⟩
|
||||
@@ -384,8 +383,7 @@ theorem mapIdx_eq_zipIdx_map {l : List α} {f : Nat → α → β} :
|
||||
simp only [getElem?_mapIdx, Option.map, getElem?_map, getElem?_zipIdx]
|
||||
split <;> simp
|
||||
|
||||
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapIdx_eq_enum_map := @mapIdx_eq_zipIdx_map
|
||||
|
||||
|
||||
@[simp, grind =]
|
||||
theorem mapIdx_cons {l : List α} {a : α} :
|
||||
|
||||
@@ -8,9 +8,14 @@ module
|
||||
prelude
|
||||
public import Init.Data.List.Lemmas
|
||||
public import Init.Data.List.Pairwise
|
||||
public import Init.Data.Order.Factories
|
||||
public import Init.Data.Subtype.Order
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
|
||||
/-!
|
||||
# Lemmas about `List.min?` and `List.max?.
|
||||
-/
|
||||
@@ -55,7 +60,7 @@ theorem min?_eq_head? {α : Type u} [Min α] {l : List α}
|
||||
have hx : min x y = x := rel_of_pairwise_cons h mem_cons_self
|
||||
rw [foldl_cons, ih _ (hx.symm ▸ h.sublist (by simp)), hx]
|
||||
|
||||
theorem min?_mem [Min α] (min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b) :
|
||||
theorem min?_mem [Min α] [MinEqOr α] :
|
||||
{xs : List α} → xs.min? = some a → a ∈ xs := by
|
||||
intro xs
|
||||
match xs with
|
||||
@@ -72,13 +77,10 @@ theorem min?_mem [Min α] (min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b
|
||||
have p := ind _ eq
|
||||
cases p with
|
||||
| inl p =>
|
||||
cases min_eq_or x y with | _ q => simp [p, q]
|
||||
cases MinEqOr.min_eq_or x y with | _ q => simp [p, q]
|
||||
| inr p => simp [p, mem_cons]
|
||||
|
||||
-- See also `Init.Data.List.Nat.Basic` for specialisations of the next two results to `Nat`.
|
||||
|
||||
theorem le_min?_iff [Min α] [LE α]
|
||||
(le_min_iff : ∀ a b c : α, a ≤ min b c ↔ a ≤ b ∧ a ≤ c) :
|
||||
theorem le_min?_iff [Min α] [LE α] [LawfulOrderInf α] :
|
||||
{xs : List α} → xs.min? = some a → ∀ {x}, x ≤ a ↔ ∀ b, b ∈ xs → x ≤ b
|
||||
| nil => by simp
|
||||
| cons x xs => by
|
||||
@@ -93,34 +95,64 @@ theorem le_min?_iff [Min α] [LE α]
|
||||
simp at eq
|
||||
simp [ih _ eq, le_min_iff, and_assoc]
|
||||
|
||||
-- This could be refactored by designing appropriate typeclasses to replace `le_refl`, `min_eq_or`,
|
||||
-- and `le_min_iff`.
|
||||
theorem min?_eq_some_iff [Min α] [LE α]
|
||||
(le_refl : ∀ a : α, a ≤ a)
|
||||
(min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b)
|
||||
(le_min_iff : ∀ a b c : α, a ≤ min b c ↔ a ≤ b ∧ a ≤ c) {xs : List α}
|
||||
(anti : ∀ a b, a ∈ xs → b ∈ xs → a ≤ b → b ≤ a → a = b := by
|
||||
exact fun a b _ _ => Std.Antisymm.antisymm a b) :
|
||||
theorem min?_eq_some_iff [Min α] [LE α] {xs : List α} [IsLinearOrder α] [LawfulOrderMin α] :
|
||||
xs.min? = some a ↔ a ∈ xs ∧ ∀ b, b ∈ xs → a ≤ b := by
|
||||
refine ⟨fun h => ⟨min?_mem min_eq_or h, (le_min?_iff le_min_iff h).1 (le_refl _)⟩, ?_⟩
|
||||
refine ⟨fun h => ⟨min?_mem h, (le_min?_iff h).1 (le_refl _)⟩, ?_⟩
|
||||
intro ⟨h₁, h₂⟩
|
||||
cases xs with
|
||||
| nil => simp at h₁
|
||||
| cons x xs =>
|
||||
exact congrArg some <| anti _ _ (min?_mem min_eq_or rfl) h₁
|
||||
((le_min?_iff le_min_iff (xs := x::xs) rfl).1 (le_refl _) _ h₁)
|
||||
(h₂ _ (min?_mem min_eq_or (xs := x::xs) rfl))
|
||||
rw [List.min?]
|
||||
exact congrArg some <| le_antisymm
|
||||
((le_min?_iff (xs := x :: xs) rfl).1 (le_refl _) _ h₁)
|
||||
(h₂ _ (min?_mem (xs := x :: xs) rfl))
|
||||
|
||||
theorem min?_replicate [Min α] {n : Nat} {a : α} (w : min a a = a) :
|
||||
private theorem min?_attach [Min α] [MinEqOr α] {xs : List α} :
|
||||
xs.attach.min? = (xs.min?.pmap (fun m hm => ⟨m, min?_mem hm⟩) (fun _ => id)) := by
|
||||
cases xs with
|
||||
| nil => simp
|
||||
| cons x xs =>
|
||||
simp only [min?, attach_cons, Option.some.injEq, Option.pmap_some]
|
||||
rw [foldl_map]
|
||||
simp only [Subtype.ext_iff]
|
||||
rw [← foldl_attach (l := xs)]
|
||||
apply Eq.trans (foldl_hom (f := Subtype.val) ?_).symm
|
||||
· rfl
|
||||
· intros; rfl
|
||||
|
||||
theorem min?_eq_min?_attach [Min α] [MinEqOr α] {xs : List α} :
|
||||
xs.min? = (xs.attach.min?.map Subtype.val) := by
|
||||
simp [min?_attach, Option.map_pmap]
|
||||
|
||||
theorem min?_eq_some_iff_subtype [Min α] [LE α] {xs : List α}
|
||||
[MinEqOr α] [IsLinearOrder (Subtype (· ∈ xs))] [LawfulOrderMin (Subtype (· ∈ xs))] :
|
||||
xs.min? = some a ↔ a ∈ xs ∧ ∀ b, b ∈ xs → a ≤ b := by
|
||||
have := fun a => min?_eq_some_iff (xs := xs.attach) (a := a)
|
||||
rw [min?_eq_min?_attach]
|
||||
simp [min?_eq_some_iff]
|
||||
constructor
|
||||
· rintro ⟨ha, h⟩
|
||||
exact ⟨ha, h⟩
|
||||
· rintro ⟨ha, h⟩
|
||||
exact ⟨ha, h⟩
|
||||
|
||||
theorem min?_replicate [Min α] [Std.IdempotentOp (min : α → α → α)] {n : Nat} {a : α} :
|
||||
(replicate n a).min? = if n = 0 then none else some a := by
|
||||
induction n with
|
||||
| zero => rfl
|
||||
| succ n ih => cases n <;> simp_all [replicate_succ, min?_cons']
|
||||
| succ n ih => cases n <;> simp_all [replicate_succ, min?_cons', Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp] theorem min?_replicate_of_pos [Min α] {n : Nat} {a : α} (w : min a a = a) (h : 0 < n) :
|
||||
@[simp] theorem min?_replicate_of_pos [Min α] [MinEqOr α] {n : Nat} {a : α} (h : 0 < n) :
|
||||
(replicate n a).min? = some a := by
|
||||
simp [min?_replicate, Nat.ne_of_gt h, w]
|
||||
simp [min?_replicate, Nat.ne_of_gt h]
|
||||
|
||||
/--
|
||||
This lemma is also applicable given the following instances:
|
||||
|
||||
```
|
||||
[LE α] [Min α] [IsLinearOrder α] [LawfulOrderMin α]
|
||||
```
|
||||
-/
|
||||
theorem foldl_min [Min α] [Std.IdempotentOp (min : α → α → α)] [Std.Associative (min : α → α → α)]
|
||||
{l : List α} {a : α} : l.foldl (init := a) min = min a (l.min?.getD a) := by
|
||||
cases l <;> simp [min?, foldl_assoc, Std.IdempotentOp.idempotent]
|
||||
@@ -144,54 +176,124 @@ theorem isSome_max?_of_mem {l : List α} [Max α] {a : α} (h : a ∈ l) :
|
||||
l.max?.isSome := by
|
||||
cases l <;> simp_all [max?_cons']
|
||||
|
||||
theorem max?_mem [Max α] (min_eq_or : ∀ a b : α, max a b = a ∨ max a b = b) :
|
||||
{xs : List α} → xs.max? = some a → a ∈ xs
|
||||
| nil => by simp
|
||||
| cons x xs => by
|
||||
rw [max?]; rintro ⟨⟩
|
||||
induction xs generalizing x with simp at *
|
||||
| cons y xs ih =>
|
||||
rcases ih (max x y) with h | h <;> simp [h]
|
||||
simp [← or_assoc, min_eq_or x y]
|
||||
|
||||
-- See also `Init.Data.List.Nat.Basic` for specialisations of the next two results to `Nat`.
|
||||
|
||||
theorem max?_le_iff [Max α] [LE α]
|
||||
(max_le_iff : ∀ a b c : α, max b c ≤ a ↔ b ≤ a ∧ c ≤ a) :
|
||||
{xs : List α} → xs.max? = some a → ∀ {x}, a ≤ x ↔ ∀ b ∈ xs, b ≤ x
|
||||
| nil => by simp
|
||||
| cons x xs => by
|
||||
rw [max?]; rintro ⟨⟩ y
|
||||
induction xs generalizing x with
|
||||
theorem max?_eq_head? {α : Type u} [Max α] {l : List α}
|
||||
(h : l.Pairwise (fun a b => max a b = a)) : l.max? = l.head? := by
|
||||
cases l with
|
||||
| nil => rfl
|
||||
| cons x l =>
|
||||
rw [head?_cons, max?_cons', Option.some.injEq]
|
||||
induction l generalizing x with
|
||||
| nil => simp
|
||||
| cons y xs ih => simp [ih, max_le_iff, and_assoc]
|
||||
| cons y l ih =>
|
||||
have hx : max x y = x := rel_of_pairwise_cons h mem_cons_self
|
||||
rw [foldl_cons, ih _ (hx.symm ▸ h.sublist (by simp)), hx]
|
||||
|
||||
-- This could be refactored by designing appropriate typeclasses to replace `le_refl`, `max_eq_or`,
|
||||
-- and `le_min_iff`.
|
||||
theorem max?_eq_some_iff [Max α] [LE α] [anti : Std.Antisymm (· ≤ · : α → α → Prop)]
|
||||
(le_refl : ∀ a : α, a ≤ a)
|
||||
(max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b)
|
||||
(max_le_iff : ∀ a b c : α, max b c ≤ a ↔ b ≤ a ∧ c ≤ a) {xs : List α} :
|
||||
xs.max? = some a ↔ a ∈ xs ∧ ∀ b ∈ xs, b ≤ a := by
|
||||
refine ⟨fun h => ⟨max?_mem max_eq_or h, (max?_le_iff max_le_iff h).1 (le_refl _)⟩, ?_⟩
|
||||
theorem max?_mem [Max α] [MaxEqOr α] :
|
||||
{xs : List α} → xs.max? = some a → a ∈ xs := by
|
||||
intro xs
|
||||
match xs with
|
||||
| nil => simp
|
||||
| x :: xs =>
|
||||
simp only [max?_cons', Option.some.injEq, mem_cons]
|
||||
intro eq
|
||||
induction xs generalizing x with
|
||||
| nil =>
|
||||
simp at eq
|
||||
simp [eq]
|
||||
| cons y xs ind =>
|
||||
simp at eq
|
||||
have p := ind _ eq
|
||||
cases p with
|
||||
| inl p =>
|
||||
cases MaxEqOr.max_eq_or x y with | _ q => simp [p, q]
|
||||
| inr p => simp [p, mem_cons]
|
||||
|
||||
theorem max?_le_iff [Max α] [LE α] [LawfulOrderSup α] :
|
||||
{xs : List α} → xs.max? = some a → ∀ {x}, a ≤ x ↔ ∀ b, b ∈ xs → b ≤ x
|
||||
| nil => by simp
|
||||
| cons x xs => by
|
||||
rw [max?]
|
||||
intro eq y
|
||||
simp only [Option.some.injEq] at eq
|
||||
induction xs generalizing x with
|
||||
| nil =>
|
||||
simp at eq
|
||||
simp [eq]
|
||||
| cons z xs ih =>
|
||||
simp at eq
|
||||
simp [ih _ eq, max_le_iff, and_assoc]
|
||||
|
||||
theorem max?_eq_some_iff [Max α] [LE α] {xs : List α} [IsLinearOrder (α)]
|
||||
[LawfulOrderMax α] : xs.max? = some a ↔ a ∈ xs ∧ ∀ b, b ∈ xs → b ≤ a := by
|
||||
refine ⟨fun h => ⟨max?_mem h, (max?_le_iff h).1 (le_refl _)⟩, ?_⟩
|
||||
intro ⟨h₁, h₂⟩
|
||||
cases xs with
|
||||
| nil => simp at h₁
|
||||
| cons x xs =>
|
||||
exact congrArg some <| anti.1 _ _
|
||||
(h₂ _ (max?_mem max_eq_or (xs := x::xs) rfl))
|
||||
((max?_le_iff max_le_iff (xs := x::xs) rfl).1 (le_refl _) _ h₁)
|
||||
rw [List.max?]
|
||||
exact congrArg some <| le_antisymm
|
||||
(h₂ _ (max?_mem (xs := x :: xs) rfl))
|
||||
((max?_le_iff (xs := x :: xs) rfl).1 (le_refl _) _ h₁)
|
||||
|
||||
theorem max?_replicate [Max α] {n : Nat} {a : α} (w : max a a = a) :
|
||||
private theorem max?_attach [Max α] [MaxEqOr α] {xs : List α} :
|
||||
xs.attach.max? = (xs.max?.pmap (fun m hm => ⟨m, max?_mem hm⟩) (fun _ => id)) := by
|
||||
cases xs with
|
||||
| nil => simp
|
||||
| cons x xs =>
|
||||
simp only [max?, attach_cons, Option.some.injEq, Option.pmap_some]
|
||||
rw [foldl_map]
|
||||
simp only [Subtype.ext_iff]
|
||||
rw [← foldl_attach (l := xs)]
|
||||
apply Eq.trans (foldl_hom (f := Subtype.val) ?_).symm
|
||||
· rfl
|
||||
· intros; rfl
|
||||
|
||||
theorem max?_eq_max?_attach [Max α] [MaxEqOr α] {xs : List α} :
|
||||
xs.max? = (xs.attach.max?.map Subtype.val) := by
|
||||
simp [max?_attach, Option.map_pmap]
|
||||
|
||||
theorem max?_eq_some_iff_subtype [Max α] [LE α] {xs : List α}
|
||||
[MaxEqOr α] [IsLinearOrder (Subtype (· ∈ xs))]
|
||||
[LawfulOrderMax (Subtype (· ∈ xs))] :
|
||||
xs.max? = some a ↔ a ∈ xs ∧ ∀ b, b ∈ xs → b ≤ a := by
|
||||
have := fun a => max?_eq_some_iff (xs := xs.attach) (a := a)
|
||||
rw [max?_eq_max?_attach]
|
||||
simp [max?_eq_some_iff]
|
||||
constructor
|
||||
· rintro ⟨ha, h⟩
|
||||
exact ⟨ha, h⟩
|
||||
· rintro ⟨ha, h⟩
|
||||
exact ⟨ha, h⟩
|
||||
|
||||
@[deprecated max?_eq_some_iff (since := "2025-08-01")]
|
||||
theorem max?_eq_some_iff_legacy [Max α] [LE α] [anti : Std.Antisymm (· ≤ · : α → α → Prop)]
|
||||
(le_refl : ∀ a : α, a ≤ a)
|
||||
(max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b)
|
||||
(max_le_iff : ∀ a b c : α, max b c ≤ a ↔ b ≤ a ∧ c ≤ a) {xs : List α} :
|
||||
xs.max? = some a ↔ a ∈ xs ∧ ∀ b ∈ xs, b ≤ a := by
|
||||
haveI : MaxEqOr α := ⟨max_eq_or⟩
|
||||
haveI : LawfulOrderMax α := .of_le (fun _ _ _ => max_le_iff _ _ _) max_eq_or
|
||||
haveI : Refl (α := α) (· ≤ ·) := ⟨le_refl⟩
|
||||
haveI : IsLinearOrder α := .of_refl_of_antisymm_of_lawfulOrderMax
|
||||
apply max?_eq_some_iff
|
||||
|
||||
theorem max?_replicate [Max α] [Std.IdempotentOp (max : α → α → α)] {n : Nat} {a : α} :
|
||||
(replicate n a).max? = if n = 0 then none else some a := by
|
||||
induction n with
|
||||
| zero => rfl
|
||||
| succ n ih => cases n <;> simp_all [replicate_succ, max?_cons']
|
||||
| succ n ih => cases n <;> simp_all [replicate_succ, max?_cons', Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp] theorem max?_replicate_of_pos [Max α] {n : Nat} {a : α} (w : max a a = a) (h : 0 < n) :
|
||||
@[simp] theorem max?_replicate_of_pos [Max α] [MaxEqOr α] {n : Nat} {a : α} (h : 0 < n) :
|
||||
(replicate n a).max? = some a := by
|
||||
simp [max?_replicate, Nat.ne_of_gt h, w]
|
||||
simp [max?_replicate, Nat.ne_of_gt h]
|
||||
|
||||
/--
|
||||
This lemma is also applicable given the following instances:
|
||||
|
||||
```
|
||||
[LE α] [Min α] [IsLinearOrder α] [LawfulOrderMax α]
|
||||
```
|
||||
-/
|
||||
theorem foldl_max [Max α] [Std.IdempotentOp (max : α → α → α)] [Std.Associative (max : α → α → α)]
|
||||
{l : List α} {a : α} : l.foldl (init := a) max = max a (l.max?.getD a) := by
|
||||
cases l <;> simp [max?, foldl_assoc, Std.IdempotentOp.idempotent]
|
||||
|
||||
@@ -261,13 +261,7 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] {p : α → Bool} {g : α → β
|
||||
|
||||
/-! ### forM -/
|
||||
|
||||
@[deprecated forM_nil (since := "2025-01-31")]
|
||||
theorem forM_nil' [Monad m] : ([] : List α).forM f = (pure .unit : m PUnit) := rfl
|
||||
|
||||
@[deprecated forM_cons (since := "2025-01-31")]
|
||||
theorem forM_cons' [Monad m] :
|
||||
(a::as).forM f = (f a >>= fun _ => as.forM f : m PUnit) :=
|
||||
List.forM_cons
|
||||
|
||||
@[simp, grind =] theorem forM_append [Monad m] [LawfulMonad m] {l₁ l₂ : List α} {f : α → m PUnit} :
|
||||
forM (l₁ ++ l₂) f = (do forM l₁ f; forM l₂ f) := by
|
||||
|
||||
@@ -10,6 +10,7 @@ public import Init.Data.List.Count
|
||||
public import Init.Data.List.Find
|
||||
public import Init.Data.List.MinMax
|
||||
public import Init.Data.Nat.Lemmas
|
||||
import Init.Data.Nat.Order
|
||||
|
||||
public section
|
||||
|
||||
@@ -210,12 +211,10 @@ theorem mem_eraseIdx_iff_getElem? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃
|
||||
/-! ### min? -/
|
||||
|
||||
-- A specialization of `min?_eq_some_iff` to Nat.
|
||||
@[deprecated min?_eq_some_iff (since := "2025-08-08")]
|
||||
theorem min?_eq_some_iff' {xs : List Nat} :
|
||||
xs.min? = some a ↔ (a ∈ xs ∧ ∀ b ∈ xs, a ≤ b) :=
|
||||
min?_eq_some_iff
|
||||
(le_refl := Nat.le_refl)
|
||||
(min_eq_or := fun _ _ => Nat.min_def .. ▸ by split <;> simp)
|
||||
(le_min_iff := fun _ _ _ => Nat.le_min)
|
||||
xs.min? = some a ↔ (a ∈ xs ∧ ∀ b ∈ xs, a ≤ b) := by
|
||||
exact min?_eq_some_iff
|
||||
|
||||
theorem min?_get_le_of_mem {l : List Nat} {a : Nat} (h : a ∈ l) :
|
||||
l.min?.get (isSome_min?_of_mem h) ≤ a := by
|
||||
@@ -237,12 +236,10 @@ theorem min?_getD_le_of_mem {l : List Nat} {a k : Nat} (h : a ∈ l) : l.min?.ge
|
||||
/-! ### max? -/
|
||||
|
||||
-- A specialization of `max?_eq_some_iff` to Nat.
|
||||
@[deprecated max?_eq_some_iff (since := "2025-08-08")]
|
||||
theorem max?_eq_some_iff' {xs : List Nat} :
|
||||
xs.max? = some a ↔ (a ∈ xs ∧ ∀ b ∈ xs, b ≤ a) :=
|
||||
max?_eq_some_iff
|
||||
(le_refl := Nat.le_refl)
|
||||
(max_eq_or := fun _ _ => Nat.max_def .. ▸ by split <;> simp)
|
||||
(max_le_iff := fun _ _ _ => Nat.max_le)
|
||||
|
||||
theorem le_max?_get_of_mem {l : List Nat} {a : Nat} (h : a ∈ l) :
|
||||
a ≤ l.max?.get (isSome_max?_of_mem h) := by
|
||||
|
||||
@@ -61,10 +61,10 @@ theorem pairwise_iff_getElem {l : List α} : Pairwise R l ↔
|
||||
∀ (i j : Nat) (_hi : i < l.length) (_hj : j < l.length) (_hij : i < j), R l[i] l[j] := by
|
||||
rw [pairwise_iff_forall_sublist]
|
||||
constructor <;> intro h
|
||||
· intros i j hi hj h'
|
||||
· intro i j hi hj h'
|
||||
apply h
|
||||
simpa [h'] using map_getElem_sublist (is := [⟨i, hi⟩, ⟨j, hj⟩])
|
||||
· intros a b h'
|
||||
· intro a b h'
|
||||
have ⟨is, h', hij⟩ := sublist_eq_map_getElem h'
|
||||
rcases is with ⟨⟩ | ⟨a', ⟨⟩ | ⟨b', ⟨⟩⟩⟩ <;> simp at h'
|
||||
rcases h' with ⟨rfl, rfl⟩
|
||||
|
||||
@@ -58,7 +58,7 @@ theorem pairwise_lt_range' {s n} (step := 1) (pos : 0 < step := by simp) :
|
||||
| s, n + 1, step, pos => by
|
||||
simp only [range'_succ, pairwise_cons]
|
||||
constructor
|
||||
· intros n m
|
||||
· intro n m
|
||||
rw [mem_range'] at m
|
||||
omega
|
||||
· exact pairwise_lt_range' (s := s + step) step pos
|
||||
@@ -70,7 +70,7 @@ theorem pairwise_le_range' {s n} (step := 1) :
|
||||
| s, n + 1, step => by
|
||||
simp only [range'_succ, pairwise_cons]
|
||||
constructor
|
||||
· intros n m
|
||||
· intro n m
|
||||
rw [mem_range'] at m
|
||||
omega
|
||||
· exact pairwise_le_range' (s := s + step) step
|
||||
@@ -90,31 +90,27 @@ theorem map_sub_range' {a s : Nat} (h : a ≤ s) (n : Nat) :
|
||||
rintro rfl
|
||||
omega
|
||||
|
||||
@[deprecated range'_eq_singleton_iff (since := "2025-01-29")]
|
||||
abbrev range'_eq_singleton := @range'_eq_singleton_iff
|
||||
|
||||
theorem range'_eq_append_iff : range' s n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs = range' s k ∧ ys = range' (s + k) (n - k) := by
|
||||
theorem range'_eq_append_iff : range' s n step = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs = range' s k step ∧ ys = range' (s + k * step) (n - k) step := by
|
||||
induction n generalizing s xs ys with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp only [range'_succ]
|
||||
rw [cons_eq_append_iff]
|
||||
have add_mul' (k n m : Nat) : (n + m) * k = m * k + n * k := by rw [Nat.add_mul]; omega
|
||||
constructor
|
||||
· rintro (⟨rfl, rfl⟩ | ⟨_, rfl, h⟩)
|
||||
· exact ⟨0, by simp [range'_succ]⟩
|
||||
· simp only [ih] at h
|
||||
obtain ⟨k, h, rfl, rfl⟩ := h
|
||||
refine ⟨k + 1, ?_⟩
|
||||
simp_all [range'_succ]
|
||||
omega
|
||||
simp_all [range'_succ, Nat.add_assoc]
|
||||
· rintro ⟨k, h, rfl, rfl⟩
|
||||
cases k with
|
||||
| zero => simp [range'_succ]
|
||||
| succ k =>
|
||||
simp only [range'_succ, reduceCtorEq, false_and, cons.injEq, true_and, ih, range'_inj, exists_eq_left', or_true, and_true, false_or]
|
||||
simp only [range'_succ, reduceCtorEq, false_and, cons.injEq, true_and, ih, exists_eq_left', false_or]
|
||||
refine ⟨k, ?_⟩
|
||||
simp_all
|
||||
omega
|
||||
simp_all [Nat.add_assoc]
|
||||
|
||||
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range' s n).find? p = some i ↔ p i ∧ i ∈ range' s n ∧ ∀ j, s ≤ j → j < i → !p j := by
|
||||
@@ -181,6 +177,46 @@ theorem count_range_1' {a s n} :
|
||||
specialize h (a - s)
|
||||
omega
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_range' : (range' start n step).sum = n * start + n * (n - 1) * step / 2 := by
|
||||
induction n generalizing start with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp_all only [List.range'_succ, List.sum_cons, Nat.mul_add, ← Nat.add_assoc,
|
||||
Nat.add_mul, Nat.one_mul, Nat.add_one_sub_one]
|
||||
have : n * step + n * (n - 1) * step / 2 = (n * n * step + n * step) / 2 := by
|
||||
apply Nat.eq_div_of_mul_eq_left (by omega)
|
||||
rw [Nat.add_mul, Nat.div_mul_cancel]
|
||||
· calc n * step * 2 + n * (n - 1) * step
|
||||
_ = n * step * 2 + n * step * (n - 1) := by simp [Nat.mul_comm, Nat.mul_assoc]
|
||||
_ = n * step + n * step * n := by cases n <;> simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm]
|
||||
_ = n * n * step + n * step := by simp [Nat.mul_comm, Nat.add_comm, Nat.mul_left_comm]
|
||||
· have : 2 ∣ n ∨ 2 ∣ (n - 1) := by omega
|
||||
apply Nat.dvd_mul_right_of_dvd
|
||||
apply Nat.dvd_mul.mpr
|
||||
cases this with
|
||||
| inl h => exists 2, 1; omega
|
||||
| inr h => exists 1, 2; omega
|
||||
omega
|
||||
|
||||
@[simp, grind =]
|
||||
theorem drop_range' : (List.range' start n step).drop k = List.range' (start + k * step) (n - k) step := by
|
||||
induction k generalizing start n with
|
||||
| zero => simp
|
||||
| succ => cases n <;> simp [*, List.range'_succ, Nat.add_mul, ← Nat.add_assoc, Nat.add_right_comm]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem take_range'_of_length_le (h : n ≤ k) : (List.range' start n step).take k = List.range' start n step := by
|
||||
induction n generalizing start k with
|
||||
| zero => simp
|
||||
| succ n ih => cases k <;> simp_all [List.range'_succ]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem take_range'_of_length_ge (h : n ≥ k) : (List.range' start n step).take k = List.range' start k step := by
|
||||
induction k generalizing start n with
|
||||
| zero => simp
|
||||
| succ k ih => cases n <;> simp_all [List.range'_succ]
|
||||
|
||||
/-! ### range -/
|
||||
|
||||
theorem reverse_range' : ∀ {s n : Nat}, reverse (range' s n) = map (s + n - 1 - ·) (range n)
|
||||
@@ -230,152 +266,6 @@ theorem count_range {a n} :
|
||||
rw [range_eq_range', count_range_1']
|
||||
simp
|
||||
|
||||
/-! ### iota -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem iota_eq_reverse_range' : ∀ n : Nat, iota n = reverse (range' 1 n)
|
||||
| 0 => rfl
|
||||
| n + 1 => by simp [iota, range'_concat, iota_eq_reverse_range' n, reverse_append, Nat.add_comm]
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem length_iota (n : Nat) : length (iota n) = n := by simp [iota_eq_reverse_range']
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem iota_eq_nil {n : Nat} : iota n = [] ↔ n = 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem iota_ne_nil {n : Nat} : iota n ≠ [] ↔ n ≠ 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem mem_iota {m n : Nat} : m ∈ iota n ↔ 0 < m ∧ m ≤ n := by
|
||||
simp [iota_eq_reverse_range', Nat.add_comm, Nat.lt_succ]
|
||||
omega
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem iota_inj : iota n = iota n' ↔ n = n' := by
|
||||
constructor
|
||||
· intro h
|
||||
have h' := congrArg List.length h
|
||||
simp at h'
|
||||
exact h'
|
||||
· rintro rfl
|
||||
simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem iota_eq_cons_iff : iota n = a :: xs ↔ n = a ∧ 0 < n ∧ xs = iota (n - 1) := by
|
||||
simp [iota_eq_reverse_range']
|
||||
simp [range'_eq_append_iff, reverse_eq_iff]
|
||||
constructor
|
||||
· rintro ⟨k, h, rfl, h'⟩
|
||||
rw [eq_comm, range'_eq_singleton] at h'
|
||||
simp only [reverse_inj, range'_inj, or_true, and_true]
|
||||
omega
|
||||
· rintro ⟨rfl, h, rfl⟩
|
||||
refine ⟨n - 1, by simp, rfl, ?_⟩
|
||||
rw [eq_comm, range'_eq_singleton]
|
||||
omega
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem iota_eq_append_iff : iota n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs = (range' (k + 1) (n - k)).reverse ∧ ys = iota k := by
|
||||
simp only [iota_eq_reverse_range']
|
||||
rw [reverse_eq_append_iff]
|
||||
rw [range'_eq_append_iff]
|
||||
simp only [reverse_eq_iff]
|
||||
constructor
|
||||
· rintro ⟨k, h, rfl, rfl⟩
|
||||
simp; omega
|
||||
· rintro ⟨k, h, rfl, rfl⟩
|
||||
exact ⟨k, by simp; omega⟩
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem pairwise_gt_iota (n : Nat) : Pairwise (· > ·) (iota n) := by
|
||||
simpa only [iota_eq_reverse_range', pairwise_reverse] using pairwise_lt_range'
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem nodup_iota (n : Nat) : Nodup (iota n) :=
|
||||
(pairwise_gt_iota n).imp Nat.ne_of_gt
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem head?_iota (n : Nat) : (iota n).head? = if n = 0 then none else some n := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem head_iota (n : Nat) (h) : (iota n).head h = n := by
|
||||
cases n with
|
||||
| zero => simp at h
|
||||
| succ n => simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem tail_iota (n : Nat) : (iota n).tail = iota (n - 1) := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem reverse_iota : reverse (iota n) = range' 1 n := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
rw [iota_succ, reverse_cons, ih, range'_1_concat, Nat.add_comm]
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem getLast?_iota (n : Nat) : (iota n).getLast? = if n = 0 then none else some 1 := by
|
||||
rw [getLast?_eq_head?_reverse]
|
||||
simp [head?_range']
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem getLast_iota (n : Nat) (h) : (iota n).getLast h = 1 := by
|
||||
rw [getLast_eq_head_reverse]
|
||||
simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem find?_iota_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
(iota n).find? p = none ↔ ∀ i, 0 < i → i ≤ n → !p i := by
|
||||
simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem find?_iota_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(iota n).find? p = some i ↔ p i ∧ i ∈ iota n ∧ ∀ j, i < j → j ≤ n → !p j := by
|
||||
rw [find?_eq_some_iff_append]
|
||||
simp only [iota_eq_reverse_range', reverse_eq_append_iff, reverse_cons, append_assoc, cons_append,
|
||||
nil_append, Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, mem_reverse, mem_range'_1,
|
||||
and_congr_right_iff]
|
||||
intro h
|
||||
constructor
|
||||
· rintro ⟨as, ⟨xs, h⟩, h'⟩
|
||||
constructor
|
||||
· replace h : i ∈ range' 1 n := by
|
||||
rw [h]
|
||||
exact mem_append_cons_self
|
||||
simpa using h
|
||||
· rw [range'_eq_append_iff] at h
|
||||
simp [reverse_eq_iff] at h
|
||||
obtain ⟨k, h₁, rfl, h₂⟩ := h
|
||||
rw [eq_comm, range'_eq_cons_iff, reverse_eq_iff] at h₂
|
||||
obtain ⟨rfl, -, rfl⟩ := h₂
|
||||
intro j j₁ j₂
|
||||
apply h'
|
||||
simp; omega
|
||||
· rintro ⟨⟨i₁, i₂⟩, h⟩
|
||||
refine ⟨(range' (i+1) (n-i)).reverse, ⟨(range' 1 (i-1)).reverse, ?_⟩, ?_⟩
|
||||
· simp [← range'_succ]
|
||||
rw [range'_eq_append_iff]
|
||||
refine ⟨i-1, ?_⟩
|
||||
constructor
|
||||
· omega
|
||||
· simp
|
||||
omega
|
||||
· simp
|
||||
intros a a₁ a₂
|
||||
apply h
|
||||
· omega
|
||||
· omega
|
||||
|
||||
end
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@[simp, grind =]
|
||||
@@ -504,245 +394,10 @@ theorem zipIdx_eq_append_iff {l : List α} {k : Nat} :
|
||||
simp only [length_range'] at h
|
||||
obtain rfl := h
|
||||
refine ⟨ws, xs, rfl, ?_⟩
|
||||
simp only [zipIdx_eq_zip_range', length_append, true_and]
|
||||
congr
|
||||
omega
|
||||
simp [zipIdx_eq_zip_range', length_append]
|
||||
· rintro ⟨l₁', l₂', rfl, rfl, rfl⟩
|
||||
simp only [zipIdx_eq_zip_range']
|
||||
refine ⟨l₁', l₂', range' k l₁'.length, range' (k + l₁'.length) l₂'.length, ?_⟩
|
||||
simp
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated zipIdx_singleton (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_singleton (x : α) (n : Nat) : enumFrom n [x] = [(n, x)] :=
|
||||
rfl
|
||||
|
||||
@[deprecated head?_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem head?_enumFrom (n : Nat) (l : List α) :
|
||||
(enumFrom n l).head? = l.head?.map fun a => (n, a) := by
|
||||
simp [head?_eq_getElem?]
|
||||
|
||||
@[deprecated getLast?_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getLast?_enumFrom (n : Nat) (l : List α) :
|
||||
(enumFrom n l).getLast? = l.getLast?.map fun a => (n + l.length - 1, a) := by
|
||||
simp [getLast?_eq_getElem?]
|
||||
cases l <;> simp
|
||||
|
||||
@[deprecated mk_add_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
theorem mk_add_mem_enumFrom_iff_getElem? {n i : Nat} {x : α} {l : List α} :
|
||||
(n + i, x) ∈ enumFrom n l ↔ l[i]? = some x := by
|
||||
simp [mem_iff_get?]
|
||||
|
||||
@[deprecated mk_mem_zipIdx_iff_le_and_getElem?_sub (since := "2025-01-21")]
|
||||
theorem mk_mem_enumFrom_iff_le_and_getElem?_sub {n i : Nat} {x : α} {l : List α} :
|
||||
(i, x) ∈ enumFrom n l ↔ n ≤ i ∧ l[i - n]? = some x := by
|
||||
if h : n ≤ i then
|
||||
rcases Nat.exists_eq_add_of_le h with ⟨i, rfl⟩
|
||||
simp [mk_add_mem_enumFrom_iff_getElem?, Nat.add_sub_cancel_left]
|
||||
else
|
||||
have : ∀ k, n + k ≠ i := by rintro k rfl; simp at h
|
||||
simp [h, mem_iff_get?, this]
|
||||
|
||||
@[deprecated le_snd_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem le_fst_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x ∈ enumFrom n l) :
|
||||
n ≤ x.1 :=
|
||||
(mk_mem_enumFrom_iff_le_and_getElem?_sub.1 h).1
|
||||
|
||||
@[deprecated snd_lt_add_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem fst_lt_add_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x ∈ enumFrom n l) :
|
||||
x.1 < n + length l := by
|
||||
rcases mem_iff_get.1 h with ⟨i, rfl⟩
|
||||
simpa using i.isLt
|
||||
|
||||
@[deprecated map_zipIdx (since := "2025-01-21")]
|
||||
theorem map_enumFrom (f : α → β) (n : Nat) (l : List α) :
|
||||
map (Prod.map id f) (enumFrom n l) = enumFrom n (map f l) := by
|
||||
induction l generalizing n <;> simp_all
|
||||
|
||||
@[deprecated fst_mem_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem snd_mem_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x ∈ enumFrom n l) : x.2 ∈ l :=
|
||||
enumFrom_map_snd n l ▸ mem_map_of_mem h
|
||||
|
||||
@[deprecated fst_eq_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem snd_eq_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x ∈ enumFrom n l) :
|
||||
x.2 = l[x.1 - n]'(by have := le_fst_of_mem_enumFrom h; have := fst_lt_add_of_mem_enumFrom h; omega) := by
|
||||
induction l generalizing n with
|
||||
| nil => cases h
|
||||
| cons hd tl ih =>
|
||||
cases h with
|
||||
| head _ => simp
|
||||
| tail h m =>
|
||||
specialize ih m
|
||||
have : x.1 - n = x.1 - (n + 1) + 1 := by
|
||||
have := le_fst_of_mem_enumFrom m
|
||||
omega
|
||||
simp [this, ih]
|
||||
|
||||
@[deprecated mem_zipIdx (since := "2025-01-21")]
|
||||
theorem mem_enumFrom {x : α} {i j : Nat} {xs : List α} (h : (i, x) ∈ xs.enumFrom j) :
|
||||
j ≤ i ∧ i < j + xs.length ∧
|
||||
x = xs[i - j]'(by have := le_fst_of_mem_enumFrom h; have := fst_lt_add_of_mem_enumFrom h; omega) :=
|
||||
⟨le_fst_of_mem_enumFrom h, fst_lt_add_of_mem_enumFrom h, snd_eq_of_mem_enumFrom h⟩
|
||||
|
||||
@[deprecated zipIdx_map (since := "2025-01-21")]
|
||||
theorem enumFrom_map (n : Nat) (l : List α) (f : α → β) :
|
||||
enumFrom n (l.map f) = (enumFrom n l).map (Prod.map id f) := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons hd tl IH =>
|
||||
rw [map_cons, enumFrom_cons', enumFrom_cons', map_cons, map_map, IH, map_map]
|
||||
rfl
|
||||
|
||||
@[deprecated zipIdx_append (since := "2025-01-21")]
|
||||
theorem enumFrom_append (xs ys : List α) (n : Nat) :
|
||||
enumFrom n (xs ++ ys) = enumFrom n xs ++ enumFrom (n + xs.length) ys := by
|
||||
induction xs generalizing ys n with
|
||||
| nil => simp
|
||||
| cons x xs IH =>
|
||||
rw [cons_append, enumFrom_cons, IH, ← cons_append, ← enumFrom_cons, length, Nat.add_right_comm,
|
||||
Nat.add_assoc]
|
||||
|
||||
@[deprecated zipIdx_eq_cons_iff (since := "2025-01-21")]
|
||||
theorem enumFrom_eq_cons_iff {l : List α} {n : Nat} :
|
||||
l.enumFrom n = x :: l' ↔ ∃ a as, l = a :: as ∧ x = (n, a) ∧ l' = enumFrom (n + 1) as := by
|
||||
rw [enumFrom_eq_zip_range', zip_eq_cons_iff]
|
||||
constructor
|
||||
· rintro ⟨l₁, l₂, h, rfl, rfl⟩
|
||||
rw [range'_eq_cons_iff] at h
|
||||
obtain ⟨rfl, -, rfl⟩ := h
|
||||
exact ⟨x.2, l₂, by simp [enumFrom_eq_zip_range']⟩
|
||||
· rintro ⟨a, as, rfl, rfl, rfl⟩
|
||||
refine ⟨range' (n+1) as.length, as, ?_⟩
|
||||
simp [enumFrom_eq_zip_range', range'_succ]
|
||||
|
||||
@[deprecated zipIdx_eq_append_iff (since := "2025-01-21")]
|
||||
theorem enumFrom_eq_append_iff {l : List α} {n : Nat} :
|
||||
l.enumFrom n = l₁ ++ l₂ ↔
|
||||
∃ l₁' l₂', l = l₁' ++ l₂' ∧ l₁ = l₁'.enumFrom n ∧ l₂ = l₂'.enumFrom (n + l₁'.length) := by
|
||||
rw [enumFrom_eq_zip_range', zip_eq_append_iff]
|
||||
constructor
|
||||
· rintro ⟨ws, xs, ys, zs, h, h', rfl, rfl, rfl⟩
|
||||
rw [range'_eq_append_iff] at h'
|
||||
obtain ⟨k, -, rfl, rfl⟩ := h'
|
||||
simp only [length_range'] at h
|
||||
obtain rfl := h
|
||||
refine ⟨ys, zs, rfl, ?_⟩
|
||||
simp only [enumFrom_eq_zip_range', length_append, true_and]
|
||||
congr
|
||||
omega
|
||||
· rintro ⟨l₁', l₂', rfl, rfl, rfl⟩
|
||||
simp only [enumFrom_eq_zip_range']
|
||||
refine ⟨range' n l₁'.length, range' (n + l₁'.length) l₂'.length, l₁', l₂', ?_⟩
|
||||
simp
|
||||
|
||||
end
|
||||
|
||||
/-! ### enum -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated zipIdx_eq_nil_iff (since := "2025-01-21"), simp]
|
||||
theorem enum_eq_nil_iff {l : List α} : List.enum l = [] ↔ l = [] := enumFrom_eq_nil
|
||||
|
||||
@[deprecated zipIdx_singleton (since := "2025-01-21"), simp]
|
||||
theorem enum_singleton (x : α) : enum [x] = [(0, x)] := rfl
|
||||
|
||||
@[deprecated length_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem enum_length : (enum l).length = l.length :=
|
||||
enumFrom_length
|
||||
|
||||
@[deprecated getElem?_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getElem?_enum (l : List α) (i : Nat) : (enum l)[i]? = l[i]?.map fun a => (i, a) := by
|
||||
rw [enum, getElem?_enumFrom, Nat.zero_add]
|
||||
|
||||
@[deprecated getElem_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getElem_enum (l : List α) (i : Nat) (h : i < l.enum.length) :
|
||||
l.enum[i] = (i, l[i]'(by simpa [enum_length] using h)) := by
|
||||
simp [enum]
|
||||
|
||||
@[deprecated head?_zipIdx (since := "2025-01-21"), simp] theorem head?_enum (l : List α) :
|
||||
l.enum.head? = l.head?.map fun a => (0, a) := by
|
||||
simp [head?_eq_getElem?]
|
||||
|
||||
@[deprecated getLast?_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getLast?_enum (l : List α) :
|
||||
l.enum.getLast? = l.getLast?.map fun a => (l.length - 1, a) := by
|
||||
simp [getLast?_eq_getElem?]
|
||||
|
||||
@[deprecated tail_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem tail_enum (l : List α) : (enum l).tail = enumFrom 1 l.tail := by
|
||||
simp [enum]
|
||||
|
||||
@[deprecated mk_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
theorem mk_mem_enum_iff_getElem? {i : Nat} {x : α} {l : List α} : (i, x) ∈ enum l ↔ l[i]? = some x := by
|
||||
simp [enum, mk_mem_enumFrom_iff_le_and_getElem?_sub]
|
||||
|
||||
@[deprecated mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
theorem mem_enum_iff_getElem? {x : Nat × α} {l : List α} : x ∈ enum l ↔ l[x.1]? = some x.2 :=
|
||||
mk_mem_enum_iff_getElem?
|
||||
|
||||
@[deprecated snd_lt_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem fst_lt_of_mem_enum {x : Nat × α} {l : List α} (h : x ∈ enum l) : x.1 < length l := by
|
||||
simpa using fst_lt_add_of_mem_enumFrom h
|
||||
|
||||
@[deprecated fst_mem_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem snd_mem_of_mem_enum {x : Nat × α} {l : List α} (h : x ∈ enum l) : x.2 ∈ l :=
|
||||
snd_mem_of_mem_enumFrom h
|
||||
|
||||
@[deprecated fst_eq_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem snd_eq_of_mem_enum {x : Nat × α} {l : List α} (h : x ∈ enum l) :
|
||||
x.2 = l[x.1]'(fst_lt_of_mem_enum h) :=
|
||||
snd_eq_of_mem_enumFrom h
|
||||
|
||||
@[deprecated mem_zipIdx (since := "2025-01-21")]
|
||||
theorem mem_enum {x : α} {i : Nat} {xs : List α} (h : (i, x) ∈ xs.enum) :
|
||||
i < xs.length ∧ x = xs[i]'(fst_lt_of_mem_enum h) :=
|
||||
by simpa using mem_enumFrom h
|
||||
|
||||
@[deprecated map_zipIdx (since := "2025-01-21")]
|
||||
theorem map_enum (f : α → β) (l : List α) : map (Prod.map id f) (enum l) = enum (map f l) :=
|
||||
map_enumFrom f 0 l
|
||||
|
||||
@[deprecated zipIdx_map_snd (since := "2025-01-21"), simp]
|
||||
theorem enum_map_fst (l : List α) : map Prod.fst (enum l) = range l.length := by
|
||||
simp only [enum, enumFrom_map_fst, range_eq_range']
|
||||
|
||||
@[deprecated zipIdx_map_fst (since := "2025-01-21"), simp]
|
||||
theorem enum_map_snd (l : List α) : map Prod.snd (enum l) = l :=
|
||||
enumFrom_map_snd _ _
|
||||
|
||||
@[deprecated zipIdx_map (since := "2025-01-21")]
|
||||
theorem enum_map (l : List α) (f : α → β) : (l.map f).enum = l.enum.map (Prod.map id f) :=
|
||||
enumFrom_map _ _ _
|
||||
|
||||
@[deprecated zipIdx_append (since := "2025-01-21")]
|
||||
theorem enum_append (xs ys : List α) : enum (xs ++ ys) = enum xs ++ enumFrom xs.length ys := by
|
||||
simp [enum, enumFrom_append]
|
||||
|
||||
@[deprecated zipIdx_eq_zip_range' (since := "2025-01-21")]
|
||||
theorem enum_eq_zip_range (l : List α) : l.enum = (range l.length).zip l :=
|
||||
zip_of_prod (enum_map_fst _) (enum_map_snd _)
|
||||
|
||||
@[deprecated unzip_zipIdx_eq_prod (since := "2025-01-21"), simp]
|
||||
theorem unzip_enum_eq_prod (l : List α) : l.enum.unzip = (range l.length, l) := by
|
||||
simp only [enum_eq_zip_range, unzip_zip, length_range]
|
||||
|
||||
@[deprecated zipIdx_eq_cons_iff (since := "2025-01-21")]
|
||||
theorem enum_eq_cons_iff {l : List α} :
|
||||
l.enum = x :: l' ↔ ∃ a as, l = a :: as ∧ x = (0, a) ∧ l' = enumFrom 1 as := by
|
||||
rw [enum, enumFrom_eq_cons_iff]
|
||||
|
||||
@[deprecated zipIdx_eq_append_iff (since := "2025-01-21")]
|
||||
theorem enum_eq_append_iff {l : List α} :
|
||||
l.enum = l₁ ++ l₂ ↔
|
||||
∃ l₁' l₂', l = l₁' ++ l₂' ∧ l₁ = l₁'.enum ∧ l₂ = l₂'.enumFrom l₁'.length := by
|
||||
simp [enum, enumFrom_eq_append_iff]
|
||||
|
||||
end
|
||||
|
||||
end List
|
||||
|
||||
@@ -29,34 +29,31 @@ open Nat
|
||||
|
||||
/-! ### range' -/
|
||||
|
||||
theorem range'_succ {s n step} : range' s (n + 1) step = s :: range' (s + step) n step := by
|
||||
simp [range']
|
||||
|
||||
@[simp] theorem length_range' {s step} : ∀ {n : Nat}, length (range' s n step) = n
|
||||
@[simp, grind =] theorem length_range' {s step} : ∀ {n : Nat}, length (range' s n step) = n
|
||||
| 0 => rfl
|
||||
| _ + 1 => congrArg succ length_range'
|
||||
|
||||
@[simp] theorem range'_eq_nil_iff : range' s n step = [] ↔ n = 0 := by
|
||||
@[simp, grind =] theorem range'_eq_nil_iff : range' s n step = [] ↔ n = 0 := by
|
||||
rw [← length_eq_zero_iff, length_range']
|
||||
|
||||
@[deprecated range'_eq_nil_iff (since := "2025-01-29")] abbrev range'_eq_nil := @range'_eq_nil_iff
|
||||
|
||||
theorem range'_ne_nil_iff (s : Nat) {n step : Nat} : range' s n step ≠ [] ↔ n ≠ 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated range'_ne_nil_iff (since := "2025-01-29")] abbrev range'_ne_nil := @range'_ne_nil_iff
|
||||
theorem range'_eq_cons_iff : range' s n step = a :: xs ↔ s = a ∧ 0 < n ∧ xs = range' (a + step) (n - 1) step := by
|
||||
induction n generalizing s with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp only [range'_succ]
|
||||
simp only [cons.injEq, and_congr_right_iff]
|
||||
rintro rfl
|
||||
simp [eq_comm]
|
||||
|
||||
@[simp] theorem range'_zero : range' s 0 step = [] := by
|
||||
simp
|
||||
|
||||
@[simp] theorem range'_one {s step : Nat} : range' s 1 step = [s] := rfl
|
||||
|
||||
@[simp] theorem tail_range' : (range' s n step).tail = range' (s + step) (n - 1) step := by
|
||||
@[simp, grind =] theorem tail_range' : (range' s n step).tail = range' (s + step) (n - 1) step := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n => simp [range'_succ]
|
||||
|
||||
@[simp] theorem range'_inj : range' s n = range' s' n' ↔ n = n' ∧ (n = 0 ∨ s = s') := by
|
||||
@[simp, grind =] theorem range'_inj : range' s n = range' s' n' ↔ n = n' ∧ (n = 0 ∨ s = s') := by
|
||||
constructor
|
||||
· intro h
|
||||
have h' := congrArg List.length h
|
||||
@@ -85,14 +82,14 @@ theorem getElem?_range' {s step} :
|
||||
exact (getElem?_range' (s := s + step) (by exact succ_lt_succ_iff.mp h)).trans <| by
|
||||
simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm]
|
||||
|
||||
@[simp] theorem getElem_range' {n m step} {i} (H : i < (range' n m step).length) :
|
||||
@[simp, grind =] theorem getElem_range' {n m step} {i} (H : i < (range' n m step).length) :
|
||||
(range' n m step)[i] = n + step * i :=
|
||||
(getElem?_eq_some_iff.1 <| getElem?_range' (by simpa using H)).2
|
||||
|
||||
theorem head?_range' : (range' s n).head? = if n = 0 then none else some s := by
|
||||
induction n <;> simp_all [range'_succ]
|
||||
|
||||
@[simp] theorem head_range' (h) : (range' s n).head h = s := by
|
||||
@[simp, grind =] theorem head_range' (h) : (range' s n).head h = s := by
|
||||
repeat simp_all [head?_range', head_eq_iff_head?_eq_some]
|
||||
|
||||
theorem map_add_range' {a} : ∀ s n step, map (a + ·) (range' s n step) = range' (a + s) n step
|
||||
@@ -111,7 +108,7 @@ theorem range'_append : ∀ {s m n step : Nat},
|
||||
simpa [range', Nat.mul_succ, Nat.add_assoc, Nat.add_comm]
|
||||
using range'_append (s := s + step)
|
||||
|
||||
@[simp] theorem range'_append_1 {s m n : Nat} :
|
||||
@[simp, grind =] theorem range'_append_1 {s m n : Nat} :
|
||||
range' s m ++ range' (s + m) n = range' s (m + n) := by simpa using range'_append (step := 1)
|
||||
|
||||
theorem range'_sublist_right {s m n : Nat} : range' s m step <+ range' s n step ↔ m ≤ n :=
|
||||
@@ -133,15 +130,6 @@ theorem range'_concat {s n : Nat} : range' s (n + 1) step = range' s n step ++ [
|
||||
theorem range'_1_concat {s n : Nat} : range' s (n + 1) = range' s n ++ [s + n] := by
|
||||
simp [range'_concat]
|
||||
|
||||
theorem range'_eq_cons_iff : range' s n = a :: xs ↔ s = a ∧ 0 < n ∧ xs = range' (a + 1) (n - 1) := by
|
||||
induction n generalizing s with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp only [range'_succ]
|
||||
simp only [cons.injEq, and_congr_right_iff]
|
||||
rintro rfl
|
||||
simp [eq_comm]
|
||||
|
||||
/-! ### range -/
|
||||
|
||||
@[simp, grind =] theorem range_one : range 1 = [0] := rfl
|
||||
@@ -156,7 +144,7 @@ theorem range_eq_range' {n : Nat} : range n = range' 0 n :=
|
||||
theorem getElem?_range {i n : Nat} (h : i < n) : (range n)[i]? = some i := by
|
||||
simp [range_eq_range', getElem?_range' h]
|
||||
|
||||
@[simp] theorem getElem_range (h : j < (range n).length) : (range n)[j] = j := by
|
||||
@[simp, grind =] theorem getElem_range (h : j < (range n).length) : (range n)[j] = j := by
|
||||
simp [range_eq_range']
|
||||
|
||||
theorem range_succ_eq_map {n : Nat} : range (n + 1) = 0 :: map succ (range n) := by
|
||||
@@ -166,23 +154,23 @@ theorem range_succ_eq_map {n : Nat} : range (n + 1) = 0 :: map succ (range n) :=
|
||||
theorem range'_eq_map_range {s n : Nat} : range' s n = map (s + ·) (range n) := by
|
||||
rw [range_eq_range', map_add_range']; rfl
|
||||
|
||||
@[simp] theorem length_range {n : Nat} : (range n).length = n := by
|
||||
@[simp, grind =] theorem length_range {n : Nat} : (range n).length = n := by
|
||||
simp only [range_eq_range', length_range']
|
||||
|
||||
@[simp] theorem range_eq_nil {n : Nat} : range n = [] ↔ n = 0 := by
|
||||
@[simp, grind =] theorem range_eq_nil {n : Nat} : range n = [] ↔ n = 0 := by
|
||||
rw [← length_eq_zero_iff, length_range]
|
||||
|
||||
theorem range_ne_nil {n : Nat} : range n ≠ [] ↔ n ≠ 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[simp] theorem tail_range : (range n).tail = range' 1 (n - 1) := by
|
||||
@[simp, grind =] theorem tail_range : (range n).tail = range' 1 (n - 1) := by
|
||||
rw [range_eq_range', tail_range']
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem range_sublist {m n : Nat} : range m <+ range n ↔ m ≤ n := by
|
||||
simp only [range_eq_range', range'_sublist_right]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem range_subset {m n : Nat} : range m ⊆ range n ↔ m ≤ n := by
|
||||
simp only [range_eq_range', range'_subset_right, lt_succ_self]
|
||||
|
||||
@@ -200,7 +188,7 @@ theorem head?_range {n : Nat} : (range n).head? = if n = 0 then none else some 0
|
||||
simp only [range_succ, head?_append, ih]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem head_range {n : Nat} (h) : (range n).head h = 0 := by
|
||||
@[simp, grind =] theorem head_range {n : Nat} (h) : (range n).head h = 0 := by
|
||||
cases n with
|
||||
| zero => simp at h
|
||||
| succ n => simp [head?_range, head_eq_iff_head?_eq_some]
|
||||
@@ -212,7 +200,7 @@ theorem getLast?_range {n : Nat} : (range n).getLast? = if n = 0 then none else
|
||||
simp only [range_succ, getLast?_append, ih]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem getLast_range {n : Nat} (h) : (range n).getLast h = n - 1 := by
|
||||
@[simp, grind =] theorem getLast_range {n : Nat} (h) : (range n).getLast h = n - 1 := by
|
||||
cases n with
|
||||
| zero => simp at h
|
||||
| succ n => simp [getLast?_range, getLast_eq_iff_getLast?_eq_some]
|
||||
@@ -295,107 +283,4 @@ theorem zipIdx_eq_map_add {l : List α} {i : Nat} :
|
||||
| nil => rfl
|
||||
| cons _ _ ih => simp [ih (i := i + 1), zipIdx_succ, Nat.add_assoc, Nat.add_comm 1]
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated zipIdx_eq_nil_iff (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_eq_nil {n : Nat} {l : List α} : List.enumFrom n l = [] ↔ l = [] := by
|
||||
cases l <;> simp
|
||||
|
||||
@[deprecated length_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_length : ∀ {n} {l : List α}, (enumFrom n l).length = l.length
|
||||
| _, [] => rfl
|
||||
| _, _ :: _ => congrArg Nat.succ enumFrom_length
|
||||
|
||||
@[deprecated getElem?_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getElem?_enumFrom :
|
||||
∀ i (l : List α) j, (enumFrom i l)[j]? = l[j]?.map fun a => (i + j, a)
|
||||
| _, [], _ => rfl
|
||||
| _, _ :: _, 0 => by simp
|
||||
| n, _ :: l, m + 1 => by
|
||||
simp only [enumFrom_cons, getElem?_cons_succ]
|
||||
exact (getElem?_enumFrom (n + 1) l m).trans <| by rw [Nat.add_right_comm]; rfl
|
||||
|
||||
@[deprecated getElem_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getElem_enumFrom (l : List α) (n) (i : Nat) (h : i < (l.enumFrom n).length) :
|
||||
(l.enumFrom n)[i] = (n + i, l[i]'(by simpa [enumFrom_length] using h)) := by
|
||||
simp only [enumFrom_length] at h
|
||||
rw [getElem_eq_getElem?_get]
|
||||
simp only [getElem?_enumFrom, getElem?_eq_getElem h]
|
||||
simp
|
||||
|
||||
@[deprecated tail_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem tail_enumFrom (l : List α) (n : Nat) : (enumFrom n l).tail = enumFrom (n + 1) l.tail := by
|
||||
induction l generalizing n with
|
||||
| nil => simp
|
||||
| cons _ l ih => simp [enumFrom_cons]
|
||||
|
||||
@[deprecated map_snd_add_zipIdx_eq_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem map_fst_add_enumFrom_eq_enumFrom (l : List α) (n k : Nat) :
|
||||
map (Prod.map (· + n) id) (enumFrom k l) = enumFrom (n + k) l :=
|
||||
ext_getElem? fun i ↦ by simp [Nat.add_comm, Nat.add_left_comm]; rfl
|
||||
|
||||
@[deprecated map_snd_add_zipIdx_eq_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem map_fst_add_enum_eq_enumFrom (l : List α) (n : Nat) :
|
||||
map (Prod.map (· + n) id) (enum l) = enumFrom n l :=
|
||||
map_fst_add_enumFrom_eq_enumFrom l _ _
|
||||
|
||||
@[deprecated zipIdx_cons' (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_cons' (n : Nat) (x : α) (xs : List α) :
|
||||
enumFrom n (x :: xs) = (n, x) :: (enumFrom n xs).map (Prod.map (· + 1) id) := by
|
||||
rw [enumFrom_cons, Nat.add_comm, ← map_fst_add_enumFrom_eq_enumFrom]
|
||||
|
||||
@[deprecated zipIdx_map_snd (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_map_fst (n) :
|
||||
∀ (l : List α), map Prod.fst (enumFrom n l) = range' n l.length
|
||||
| [] => rfl
|
||||
| _ :: _ => congrArg (cons _) (enumFrom_map_fst _ _)
|
||||
|
||||
@[deprecated zipIdx_map_fst (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_map_snd : ∀ (n) (l : List α), map Prod.snd (enumFrom n l) = l
|
||||
| _, [] => rfl
|
||||
| _, _ :: _ => congrArg (cons _) (enumFrom_map_snd _ _)
|
||||
|
||||
@[deprecated zipIdx_eq_zip_range' (since := "2025-01-21")]
|
||||
theorem enumFrom_eq_zip_range' (l : List α) {n : Nat} : l.enumFrom n = (range' n l.length).zip l :=
|
||||
zip_of_prod (enumFrom_map_fst _ _) (enumFrom_map_snd _ _)
|
||||
|
||||
@[deprecated unzip_zipIdx_eq_prod (since := "2025-01-21"), simp]
|
||||
theorem unzip_enumFrom_eq_prod (l : List α) {n : Nat} :
|
||||
(l.enumFrom n).unzip = (range' n l.length, l) := by
|
||||
simp only [enumFrom_eq_zip_range', unzip_zip, length_range']
|
||||
|
||||
end
|
||||
|
||||
/-! ### enum -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated zipIdx_cons (since := "2025-01-21")]
|
||||
theorem enum_cons : (a::as).enum = (0, a) :: as.enumFrom 1 := rfl
|
||||
|
||||
@[deprecated zipIdx_cons (since := "2025-01-21")]
|
||||
theorem enum_cons' (x : α) (xs : List α) :
|
||||
enum (x :: xs) = (0, x) :: (enum xs).map (Prod.map (· + 1) id) :=
|
||||
enumFrom_cons' _ _ _
|
||||
|
||||
@[deprecated "These are now both `l.zipIdx 0`" (since := "2025-01-21")]
|
||||
theorem enum_eq_enumFrom {l : List α} : l.enum = l.enumFrom 0 := rfl
|
||||
|
||||
@[deprecated "Use the reverse direction of `map_snd_add_zipIdx_eq_zipIdx` instead" (since := "2025-01-21")]
|
||||
theorem enumFrom_eq_map_enum (l : List α) (n : Nat) :
|
||||
enumFrom n l = (enum l).map (Prod.map (· + n) id) := by
|
||||
induction l generalizing n with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [enumFrom_cons, ih, enum_cons, map_cons, Prod.map_apply, Nat.zero_add, id_eq, map_map,
|
||||
cons.injEq, map_inj_left, Function.comp_apply, Prod.forall, Prod.mk.injEq, and_true, true_and]
|
||||
intro a b _
|
||||
exact (succ_add a n).symm
|
||||
|
||||
end
|
||||
|
||||
end List
|
||||
|
||||
@@ -57,7 +57,7 @@ where go : List α → List α → List α → List α
|
||||
else
|
||||
go (x :: xs) ys (y :: acc)
|
||||
|
||||
theorem mergeTR_go_eq : mergeTR.go le l₁ l₂ acc = acc.reverse ++ merge l₁ l₂ le := by
|
||||
private theorem mergeTR_go_eq : mergeTR.go le l₁ l₂ acc = acc.reverse ++ merge l₁ l₂ le := by
|
||||
induction l₁ generalizing l₂ acc with
|
||||
| nil => simp [mergeTR.go, reverseAux_eq]
|
||||
| cons x l₁ ih₁ =>
|
||||
@@ -84,7 +84,7 @@ def splitRevAt (n : Nat) (l : List α) : List α × List α := go l n [] where
|
||||
| x :: xs, n+1, acc => go xs n (x :: acc)
|
||||
| xs, _, acc => (acc, xs)
|
||||
|
||||
theorem splitRevAt_go (xs : List α) (i : Nat) (acc : List α) :
|
||||
private theorem splitRevAt_go (xs : List α) (i : Nat) (acc : List α) :
|
||||
splitRevAt.go xs i acc = ((take i xs).reverse ++ acc, drop i xs) := by
|
||||
induction xs generalizing i acc with
|
||||
| nil => simp [splitRevAt.go]
|
||||
@@ -172,7 +172,7 @@ theorem splitRevInTwo_snd (l : { l : List α // l.length = n }) :
|
||||
(splitRevInTwo l).2 = ⟨(splitInTwo l).2.1, by simp; omega⟩ := by
|
||||
simp only [splitRevInTwo, splitRevAt_eq, reverse_take, splitInTwo_snd]
|
||||
|
||||
theorem mergeSortTR_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → mergeSortTR.run le l = mergeSort l.1 le
|
||||
private theorem mergeSortTR_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → mergeSortTR.run le l = mergeSort l.1 le
|
||||
| 0, ⟨[], _⟩
|
||||
| 1, ⟨[a], _⟩ => by simp [mergeSortTR.run]
|
||||
| n+2, ⟨a :: b :: l, h⟩ => by
|
||||
@@ -189,7 +189,7 @@ theorem mergeSort_eq_mergeSortTR : @mergeSort = @mergeSortTR := by
|
||||
-- This mutual block is unfortunately quite slow to elaborate.
|
||||
set_option maxHeartbeats 400000 in
|
||||
mutual
|
||||
theorem mergeSortTR₂_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → mergeSortTR₂.run le l = mergeSort l.1 le
|
||||
private theorem mergeSortTR₂_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → mergeSortTR₂.run le l = mergeSort l.1 le
|
||||
| 0, ⟨[], _⟩
|
||||
| 1, ⟨[a], _⟩ => by simp [mergeSortTR₂.run]
|
||||
| n+2, ⟨a :: b :: l, h⟩ => by
|
||||
@@ -201,7 +201,7 @@ theorem mergeSortTR₂_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.
|
||||
rw [reverse_reverse]
|
||||
termination_by n => n
|
||||
|
||||
theorem mergeSortTR₂_run'_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → (w : l' = l.1.reverse) → mergeSortTR₂.run' le l = mergeSort l' le
|
||||
private theorem mergeSortTR₂_run'_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → (w : l' = l.1.reverse) → mergeSortTR₂.run' le l = mergeSort l' le
|
||||
| 0, ⟨[], _⟩, w
|
||||
| 1, ⟨[a], _⟩, w => by simp_all [mergeSortTR₂.run']
|
||||
| n+2, ⟨a :: b :: l, h⟩, w => by
|
||||
|
||||
@@ -352,14 +352,14 @@ where go : ∀ (i : Nat) (l : List α),
|
||||
rw [merge_stable]
|
||||
· rw [go, go]
|
||||
· simp only [mem_mergeSort, Prod.forall]
|
||||
intros j x k y mx my
|
||||
intro j x k y mx my
|
||||
have := mem_zipIdx mx
|
||||
have := mem_zipIdx my
|
||||
simp_all
|
||||
omega
|
||||
termination_by _ l => l.length
|
||||
|
||||
@[deprecated mergeSort_zipIdx (since := "2025-01-21")] abbrev mergeSort_enum := @mergeSort_zipIdx
|
||||
|
||||
|
||||
theorem mergeSort_cons {le : α → α → Bool}
|
||||
(trans : ∀ (a b c : α), le a b → le b c → le a c)
|
||||
|
||||
@@ -68,9 +68,9 @@ theorem take_of_length_le {l : List α} (h : l.length ≤ i) : take i l = l := b
|
||||
theorem lt_length_of_take_ne_self {l : List α} {i} (h : l.take i ≠ l) : i < l.length :=
|
||||
gt_of_not_le (mt take_of_length_le h)
|
||||
|
||||
@[simp] theorem drop_length {l : List α} : l.drop l.length = [] := drop_of_length_le (Nat.le_refl _)
|
||||
@[simp, grind =] theorem drop_length {l : List α} : l.drop l.length = [] := drop_of_length_le (Nat.le_refl _)
|
||||
|
||||
@[simp] theorem take_length {l : List α} : l.take l.length = l := take_of_length_le (Nat.le_refl _)
|
||||
@[simp, grind =] theorem take_length {l : List α} : l.take l.length = l := take_of_length_le (Nat.le_refl _)
|
||||
|
||||
@[simp]
|
||||
theorem getElem_cons_drop : ∀ {l : List α} {i : Nat} (h : i < l.length),
|
||||
|
||||
@@ -222,11 +222,11 @@ theorem forM_toArray [Monad m] (l : List α) (f : α → m PUnit) :
|
||||
congr
|
||||
ext1 (_|_) <;> simp [ih]
|
||||
|
||||
theorem findSomeRevM?_find_toArray [Monad m] [LawfulMonad m] (f : α → m (Option β)) (l : List α)
|
||||
private theorem findSomeRevM?_find_toArray [Monad m] [LawfulMonad m] (f : α → m (Option β)) (l : List α)
|
||||
(i : Nat) (h) :
|
||||
findSomeRevM?.find f l.toArray i h = (l.take i).reverse.findSomeM? f := by
|
||||
induction i generalizing l with
|
||||
| zero => simp [Array.findSomeRevM?.find.eq_def]
|
||||
| zero => simp [Array.findSomeRevM?.find]
|
||||
| succ i ih =>
|
||||
rw [size_toArray] at h
|
||||
rw [Array.findSomeRevM?.find, take_succ, getElem?_eq_getElem (by omega)]
|
||||
@@ -437,7 +437,7 @@ theorem zipWithMAux_toArray_zero {m : Type u → Type v} [Monad m] [LawfulMonad
|
||||
Array.zip as.toArray bs.toArray = (List.zip as bs).toArray := by
|
||||
simp [Array.zip, zipWith_toArray, zip]
|
||||
|
||||
theorem zipWithAll_go_toArray (as : List α) (bs : List β) (f : Option α → Option β → γ) (i : Nat) (xs : Array γ) :
|
||||
private theorem zipWithAll_go_toArray (as : List α) (bs : List β) (f : Option α → Option β → γ) (i : Nat) (xs : Array γ) :
|
||||
zipWithAll.go f as.toArray bs.toArray i xs = xs ++ (List.zipWithAll f (as.drop i) (bs.drop i)).toArray := by
|
||||
unfold zipWithAll.go
|
||||
split <;> rename_i h
|
||||
@@ -489,7 +489,7 @@ theorem zipWithAll_go_toArray (as : List α) (bs : List β) (f : Option α → O
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
theorem takeWhile_go_succ (p : α → Bool) (a : α) (l : List α) (i : Nat) :
|
||||
private theorem takeWhile_go_succ (p : α → Bool) (a : α) (l : List α) (i : Nat) :
|
||||
takeWhile.go p (a :: l).toArray (i+1) r = takeWhile.go p l.toArray i r := by
|
||||
rw [takeWhile.go, takeWhile.go]
|
||||
simp only [size_toArray, length_cons, Nat.add_lt_add_iff_right,
|
||||
@@ -498,7 +498,7 @@ theorem takeWhile_go_succ (p : α → Bool) (a : α) (l : List α) (i : Nat) :
|
||||
rw [takeWhile_go_succ]
|
||||
rfl
|
||||
|
||||
theorem takeWhile_go_toArray (p : α → Bool) (l : List α) (i : Nat) :
|
||||
private theorem takeWhile_go_toArray (p : α → Bool) (l : List α) (i : Nat) :
|
||||
Array.takeWhile.go p l.toArray i r = r ++ (takeWhile p (l.drop i)).toArray := by
|
||||
induction l generalizing i r with
|
||||
| nil => simp [takeWhile.go]
|
||||
|
||||
@@ -42,7 +42,7 @@ theorem zipWith_self {f : α → α → δ} : ∀ {l : List α}, zipWith f l l =
|
||||
| [] => rfl
|
||||
| _ :: _ => congrArg _ zipWith_self
|
||||
|
||||
@[deprecated zipWith_self (since := "2025-01-29")] abbrev zipWith_same := @zipWith_self
|
||||
|
||||
|
||||
/--
|
||||
See also `getElem?_zipWith'` for a variant
|
||||
|
||||
@@ -10,7 +10,9 @@ public import Init.Data.Nat.Basic
|
||||
public import Init.Data.Nat.Div
|
||||
public import Init.Data.Nat.Dvd
|
||||
public import Init.Data.Nat.Gcd
|
||||
public import Init.Data.Nat.Coprime
|
||||
public import Init.Data.Nat.MinMax
|
||||
public import Init.Data.Nat.Order
|
||||
public import Init.Data.Nat.Bitwise
|
||||
public import Init.Data.Nat.Control
|
||||
public import Init.Data.Nat.Log2
|
||||
@@ -23,5 +25,6 @@ public import Init.Data.Nat.Lcm
|
||||
public import Init.Data.Nat.Compare
|
||||
public import Init.Data.Nat.Simproc
|
||||
public import Init.Data.Nat.Fold
|
||||
public import Init.Data.Nat.Order
|
||||
|
||||
public section
|
||||
|
||||
@@ -583,22 +583,20 @@ protected theorem or_assoc (x y z : Nat) : (x ||| y) ||| z = x ||| (y ||| z) :=
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.or_assoc]
|
||||
|
||||
@[grind _=_]
|
||||
@[grind =]
|
||||
theorem and_or_distrib_left (x y z : Nat) : x &&& (y ||| z) = (x &&& y) ||| (x &&& z) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.and_or_distrib_left]
|
||||
|
||||
@[grind _=_]
|
||||
@[grind =]
|
||||
theorem and_distrib_right (x y z : Nat) : (x ||| y) &&& z = (x &&& z) ||| (y &&& z) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.and_or_distrib_right]
|
||||
|
||||
@[grind _=_]
|
||||
theorem or_and_distrib_left (x y z : Nat) : x ||| (y &&& z) = (x ||| y) &&& (x ||| z) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.or_and_distrib_left]
|
||||
|
||||
@[grind _=_]
|
||||
theorem or_and_distrib_right (x y z : Nat) : (x &&& y) ||| z = (x ||| z) &&& (y ||| z) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.or_and_distrib_right]
|
||||
@@ -674,12 +672,12 @@ instance : Std.LawfulCommIdentity (α := Nat) (· ^^^ ·) 0 where
|
||||
theorem xor_lt_two_pow {x y n : Nat} (left : x < 2^n) (right : y < 2^n) : x ^^^ y < 2^n :=
|
||||
bitwise_lt_two_pow left right
|
||||
|
||||
@[grind _=_]
|
||||
@[grind =]
|
||||
theorem and_xor_distrib_right {a b c : Nat} : (a ^^^ b) &&& c = (a &&& c) ^^^ (b &&& c) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.and_xor_distrib_right]
|
||||
|
||||
@[grind _=_]
|
||||
@[grind =]
|
||||
theorem and_xor_distrib_left {a b c : Nat} : a &&& (b ^^^ c) = (a &&& b) ^^^ (a &&& c) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.and_xor_distrib_left]
|
||||
|
||||
@@ -6,7 +6,7 @@ Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Ord
|
||||
public import all Init.Data.Ord.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
194
src/Init/Data/Nat/Coprime.lean
Normal file
194
src/Init/Data/Nat/Coprime.lean
Normal file
@@ -0,0 +1,194 @@
|
||||
/-
|
||||
Copyright (c) 2014 Jeremy Avigad. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
|
||||
public import Init.Data.Nat.Gcd
|
||||
|
||||
public section
|
||||
|
||||
/-!
|
||||
# Definitions and properties of `coprime`
|
||||
-/
|
||||
|
||||
namespace Nat
|
||||
|
||||
/-!
|
||||
### `coprime`
|
||||
-/
|
||||
|
||||
/-- `m` and `n` are coprime, or relatively prime, if their `gcd` is 1. -/
|
||||
@[reducible, expose] def Coprime (m n : Nat) : Prop := gcd m n = 1
|
||||
|
||||
-- if we don't inline this, then the compiler computes the GCD even if it already has it
|
||||
@[inline] instance (m n : Nat) : Decidable (Coprime m n) := inferInstanceAs (Decidable (_ = 1))
|
||||
|
||||
theorem coprime_iff_gcd_eq_one : Coprime m n ↔ gcd m n = 1 := .rfl
|
||||
|
||||
theorem Coprime.gcd_eq_one : Coprime m n → gcd m n = 1 := id
|
||||
|
||||
theorem Coprime.symm : Coprime n m → Coprime m n := (gcd_comm m n).trans
|
||||
|
||||
theorem coprime_comm : Coprime n m ↔ Coprime m n := ⟨Coprime.symm, Coprime.symm⟩
|
||||
|
||||
theorem Coprime.dvd_of_dvd_mul_right (H1 : Coprime k n) (H2 : k ∣ m * n) : k ∣ m := by
|
||||
have t := dvd_gcd (Nat.dvd_mul_left k m) H2
|
||||
rwa [gcd_mul_left, H1.gcd_eq_one, Nat.mul_one] at t
|
||||
|
||||
theorem Coprime.dvd_of_dvd_mul_left (H1 : Coprime k m) (H2 : k ∣ m * n) : k ∣ n :=
|
||||
H1.dvd_of_dvd_mul_right (by rwa [Nat.mul_comm])
|
||||
|
||||
theorem Coprime.gcd_mul_left_cancel (m : Nat) (H : Coprime k n) : gcd (k * m) n = gcd m n :=
|
||||
have H1 : Coprime (gcd (k * m) n) k := by
|
||||
rw [Coprime, Nat.gcd_assoc, H.symm.gcd_eq_one, gcd_one_right]
|
||||
Nat.dvd_antisymm
|
||||
(dvd_gcd (H1.dvd_of_dvd_mul_left (gcd_dvd_left _ _)) (gcd_dvd_right _ _))
|
||||
(gcd_dvd_gcd_mul_left_left _ _ _)
|
||||
|
||||
theorem Coprime.gcd_mul_right_cancel (m : Nat) (H : Coprime k n) : gcd (m * k) n = gcd m n := by
|
||||
rw [Nat.mul_comm m k, H.gcd_mul_left_cancel m]
|
||||
|
||||
theorem Coprime.gcd_mul_left_cancel_right (n : Nat)
|
||||
(H : Coprime k m) : gcd m (k * n) = gcd m n := by
|
||||
rw [gcd_comm m n, gcd_comm m (k * n), H.gcd_mul_left_cancel n]
|
||||
|
||||
theorem Coprime.gcd_mul_right_cancel_right (n : Nat)
|
||||
(H : Coprime k m) : gcd m (n * k) = gcd m n := by
|
||||
rw [Nat.mul_comm n k, H.gcd_mul_left_cancel_right n]
|
||||
|
||||
theorem coprime_div_gcd_div_gcd
|
||||
(H : 0 < gcd m n) : Coprime (m / gcd m n) (n / gcd m n) := by
|
||||
rw [coprime_iff_gcd_eq_one, gcd_div (gcd_dvd_left m n) (gcd_dvd_right m n), Nat.div_self H]
|
||||
|
||||
theorem not_coprime_of_dvd_of_dvd (dgt1 : 1 < d) (Hm : d ∣ m) (Hn : d ∣ n) : ¬ Coprime m n :=
|
||||
fun co => Nat.not_le_of_gt dgt1 <| Nat.le_of_dvd Nat.zero_lt_one <| by
|
||||
rw [← co.gcd_eq_one]; exact dvd_gcd Hm Hn
|
||||
|
||||
theorem exists_coprime (m n : Nat) :
|
||||
∃ m' n', Coprime m' n' ∧ m = m' * gcd m n ∧ n = n' * gcd m n := by
|
||||
cases eq_zero_or_pos (gcd m n) with
|
||||
| inl h0 =>
|
||||
rw [gcd_eq_zero_iff] at h0
|
||||
refine ⟨1, 1, gcd_one_left 1, ?_⟩
|
||||
simp [h0]
|
||||
| inr hpos =>
|
||||
exact ⟨_, _, coprime_div_gcd_div_gcd hpos,
|
||||
(Nat.div_mul_cancel (gcd_dvd_left m n)).symm,
|
||||
(Nat.div_mul_cancel (gcd_dvd_right m n)).symm⟩
|
||||
|
||||
theorem exists_coprime' (H : 0 < gcd m n) :
|
||||
∃ g m' n', 0 < g ∧ Coprime m' n' ∧ m = m' * g ∧ n = n' * g :=
|
||||
let ⟨m', n', h⟩ := exists_coprime m n; ⟨_, m', n', H, h⟩
|
||||
|
||||
theorem Coprime.mul_left (H1 : Coprime m k) (H2 : Coprime n k) : Coprime (m * n) k :=
|
||||
(H1.gcd_mul_left_cancel n).trans H2
|
||||
|
||||
theorem Coprime.mul_right (H1 : Coprime k m) (H2 : Coprime k n) : Coprime k (m * n) :=
|
||||
(H1.symm.mul_left H2.symm).symm
|
||||
|
||||
theorem Coprime.coprime_dvd_left (H1 : m ∣ k) (H2 : Coprime k n) : Coprime m n := by
|
||||
apply eq_one_of_dvd_one
|
||||
rw [Coprime] at H2
|
||||
have := Nat.gcd_dvd_gcd_of_dvd_left n H1
|
||||
rwa [← H2]
|
||||
|
||||
theorem Coprime.coprime_dvd_right (H1 : n ∣ m) (H2 : Coprime k m) : Coprime k n :=
|
||||
(H2.symm.coprime_dvd_left H1).symm
|
||||
|
||||
theorem Coprime.coprime_mul_left (H : Coprime (k * m) n) : Coprime m n :=
|
||||
H.coprime_dvd_left (Nat.dvd_mul_left _ _)
|
||||
|
||||
theorem Coprime.coprime_mul_right (H : Coprime (m * k) n) : Coprime m n :=
|
||||
H.coprime_dvd_left (Nat.dvd_mul_right _ _)
|
||||
|
||||
theorem Coprime.coprime_mul_left_right (H : Coprime m (k * n)) : Coprime m n :=
|
||||
H.coprime_dvd_right (Nat.dvd_mul_left _ _)
|
||||
|
||||
theorem Coprime.coprime_mul_right_right (H : Coprime m (n * k)) : Coprime m n :=
|
||||
H.coprime_dvd_right (Nat.dvd_mul_right _ _)
|
||||
|
||||
theorem Coprime.coprime_div_left (cmn : Coprime m n) (dvd : a ∣ m) : Coprime (m / a) n := by
|
||||
match eq_zero_or_pos a with
|
||||
| .inl h0 =>
|
||||
rw [h0] at dvd
|
||||
rw [Nat.eq_zero_of_zero_dvd dvd] at cmn ⊢
|
||||
simp; assumption
|
||||
| .inr hpos =>
|
||||
let ⟨k, hk⟩ := dvd
|
||||
rw [hk, Nat.mul_div_cancel_left _ hpos]
|
||||
rw [hk] at cmn
|
||||
exact cmn.coprime_mul_left
|
||||
|
||||
theorem Coprime.coprime_div_right (cmn : Coprime m n) (dvd : a ∣ n) : Coprime m (n / a) :=
|
||||
(cmn.symm.coprime_div_left dvd).symm
|
||||
|
||||
theorem coprime_mul_iff_left : Coprime (m * n) k ↔ Coprime m k ∧ Coprime n k :=
|
||||
⟨fun h => ⟨h.coprime_mul_right, h.coprime_mul_left⟩,
|
||||
fun ⟨h, _⟩ => by rwa [coprime_iff_gcd_eq_one, h.gcd_mul_left_cancel n]⟩
|
||||
|
||||
theorem coprime_mul_iff_right : Coprime k (m * n) ↔ Coprime k m ∧ Coprime k n := by
|
||||
rw [@coprime_comm k, @coprime_comm k, @coprime_comm k, coprime_mul_iff_left]
|
||||
|
||||
theorem Coprime.gcd_left (k : Nat) (hmn : Coprime m n) : Coprime (gcd k m) n :=
|
||||
hmn.coprime_dvd_left <| gcd_dvd_right k m
|
||||
|
||||
theorem Coprime.gcd_right (k : Nat) (hmn : Coprime m n) : Coprime m (gcd k n) :=
|
||||
hmn.coprime_dvd_right <| gcd_dvd_right k n
|
||||
|
||||
theorem Coprime.gcd_both (k l : Nat) (hmn : Coprime m n) : Coprime (gcd k m) (gcd l n) :=
|
||||
(hmn.gcd_left k).gcd_right l
|
||||
|
||||
theorem Coprime.mul_dvd_of_dvd_of_dvd (hmn : Coprime m n) (hm : m ∣ a) (hn : n ∣ a) : m * n ∣ a :=
|
||||
let ⟨_, hk⟩ := hm
|
||||
hk.symm ▸ Nat.mul_dvd_mul_left _ (hmn.symm.dvd_of_dvd_mul_left (hk ▸ hn))
|
||||
|
||||
@[simp] theorem coprime_zero_left (n : Nat) : Coprime 0 n ↔ n = 1 := by simp [Coprime]
|
||||
|
||||
@[simp] theorem coprime_zero_right (n : Nat) : Coprime n 0 ↔ n = 1 := by simp [Coprime]
|
||||
|
||||
theorem coprime_one_left : ∀ n, Coprime 1 n := gcd_one_left
|
||||
|
||||
theorem coprime_one_right : ∀ n, Coprime n 1 := gcd_one_right
|
||||
|
||||
@[simp] theorem coprime_one_left_eq_true (n) : Coprime 1 n = True := eq_true (coprime_one_left _)
|
||||
|
||||
@[simp] theorem coprime_one_right_eq_true (n) : Coprime n 1 = True := eq_true (coprime_one_right _)
|
||||
|
||||
@[simp] theorem coprime_self (n : Nat) : Coprime n n ↔ n = 1 := by simp [Coprime]
|
||||
|
||||
theorem Coprime.pow_left (n : Nat) (H1 : Coprime m k) : Coprime (m ^ n) k := by
|
||||
induction n with
|
||||
| zero => exact coprime_one_left _
|
||||
| succ n ih => have hm := H1.mul_left ih; rwa [Nat.pow_succ, Nat.mul_comm]
|
||||
|
||||
theorem Coprime.pow_right (n : Nat) (H1 : Coprime k m) : Coprime k (m ^ n) :=
|
||||
(H1.symm.pow_left n).symm
|
||||
|
||||
theorem Coprime.pow {k l : Nat} (m n : Nat) (H1 : Coprime k l) : Coprime (k ^ m) (l ^ n) :=
|
||||
(H1.pow_left _).pow_right _
|
||||
|
||||
theorem Coprime.eq_one_of_dvd {k m : Nat} (H : Coprime k m) (d : k ∣ m) : k = 1 := by
|
||||
rw [← H.gcd_eq_one, gcd_eq_left d]
|
||||
|
||||
theorem Coprime.gcd_mul (k : Nat) (h : Coprime m n) : gcd k (m * n) = gcd k m * gcd k n :=
|
||||
Nat.dvd_antisymm
|
||||
(gcd_mul_right_dvd_mul_gcd k m n)
|
||||
((h.gcd_both k k).mul_dvd_of_dvd_of_dvd
|
||||
(gcd_dvd_gcd_mul_right_right ..)
|
||||
(gcd_dvd_gcd_mul_left_right ..))
|
||||
|
||||
theorem Coprime.mul_gcd (h : Coprime m n) (k : Nat) : gcd (m * n) k = gcd m k * gcd n k := by
|
||||
rw [gcd_comm, h.gcd_mul, gcd_comm k, gcd_comm k]
|
||||
|
||||
theorem gcd_mul_gcd_of_coprime_of_mul_eq_mul
|
||||
(cop : Coprime c d) (h : a * b = c * d) : a.gcd c * b.gcd c = c := by
|
||||
apply Nat.dvd_antisymm
|
||||
· apply ((cop.gcd_left _).mul_left (cop.gcd_left _)).dvd_of_dvd_mul_right
|
||||
rw [← h]
|
||||
apply Nat.mul_dvd_mul (gcd_dvd ..).1 (gcd_dvd ..).1
|
||||
· rw [gcd_comm a, gcd_comm b]
|
||||
refine Nat.dvd_trans ?_ (gcd_mul_right_dvd_mul_gcd ..)
|
||||
rw [h, gcd_mul_right_right d c]; apply Nat.dvd_refl
|
||||
@@ -128,7 +128,7 @@ theorem fold_congr {α : Type u} {n m : Nat} (w : n = m)
|
||||
subst m
|
||||
rfl
|
||||
|
||||
theorem foldTR_loop_congr {α : Type u} {n m : Nat} (w : n = m)
|
||||
private theorem foldTR_loop_congr {α : Type u} {n m : Nat} (w : n = m)
|
||||
(f : (i : Nat) → i < n → α → α) (j : Nat) (h : j ≤ n) (init : α) :
|
||||
foldTR.loop n f j h init = foldTR.loop m (fun i h => f i (by omega)) j (by omega) init := by
|
||||
subst m
|
||||
@@ -154,7 +154,7 @@ theorem any_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) : a
|
||||
subst m
|
||||
rfl
|
||||
|
||||
theorem anyTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) (j : Nat) (h : j ≤ n) :
|
||||
private theorem anyTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) (j : Nat) (h : j ≤ n) :
|
||||
anyTR.loop n f j h = anyTR.loop m (fun i h => f i (by omega)) j (by omega) := by
|
||||
subst m
|
||||
rfl
|
||||
@@ -179,7 +179,7 @@ theorem all_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) : a
|
||||
subst m
|
||||
rfl
|
||||
|
||||
theorem allTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) (j : Nat) (h : j ≤ n) : allTR.loop n f j h = allTR.loop m (fun i h => f i (by omega)) j (by omega) := by
|
||||
private theorem allTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) (j : Nat) (h : j ≤ n) : allTR.loop n f j h = allTR.loop m (fun i h => f i (by omega)) j (by omega) := by
|
||||
subst m
|
||||
rfl
|
||||
|
||||
|
||||
@@ -1164,7 +1164,7 @@ protected theorem pow_le_pow_iff_right {a n m : Nat} (h : 1 < a) :
|
||||
a ^ n ≤ a ^ m ↔ n ≤ m := by
|
||||
constructor
|
||||
· apply Decidable.by_contra
|
||||
intros w
|
||||
intro w
|
||||
simp at w
|
||||
apply Nat.lt_irrefl (a ^ n)
|
||||
exact Nat.lt_of_le_of_lt w.1 (Nat.pow_lt_pow_of_lt h w.2)
|
||||
@@ -1177,7 +1177,7 @@ protected theorem pow_lt_pow_iff_right {a n m : Nat} (h : 1 < a) :
|
||||
a ^ n < a ^ m ↔ n < m := by
|
||||
constructor
|
||||
· apply Decidable.by_contra
|
||||
intros w
|
||||
intro w
|
||||
simp at w
|
||||
apply Nat.lt_irrefl (a ^ n)
|
||||
exact Nat.lt_of_lt_of_le w.1 (Nat.pow_le_pow_of_le h w.2)
|
||||
|
||||
41
src/Init/Data/Nat/Order.lean
Normal file
41
src/Init/Data/Nat/Order.lean
Normal file
@@ -0,0 +1,41 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Nat.Basic
|
||||
import Init.Data.Nat.MinMax
|
||||
public import Init.Data.Order.Factories
|
||||
|
||||
open Std
|
||||
|
||||
namespace Nat
|
||||
|
||||
public instance instIsLinearOrder : IsLinearOrder Nat := by
|
||||
apply IsLinearOrder.of_le
|
||||
· constructor; apply Nat.le_antisymm
|
||||
· constructor; apply Nat.le_trans
|
||||
· constructor; apply Nat.le_total
|
||||
|
||||
public instance : LawfulOrderLT Nat := by
|
||||
apply LawfulOrderLT.of_le
|
||||
simp [Nat.lt_iff_le_and_ne]
|
||||
|
||||
public instance : LawfulOrderMin Nat := by
|
||||
apply LawfulOrderMin.of_le
|
||||
· apply Nat.le_min
|
||||
· intro a b
|
||||
simp only [Nat.min_def]
|
||||
split <;> simp
|
||||
|
||||
public instance : LawfulOrderMax Nat := by
|
||||
apply LawfulOrderMax.of_le
|
||||
· apply Nat.max_le
|
||||
· intro a b
|
||||
simp only [Nat.max_def]
|
||||
split <;> simp
|
||||
|
||||
end Nat
|
||||
@@ -58,9 +58,9 @@ theorem getD_of_ne_none {x : Option α} (hx : x ≠ none) (y : α) : some (x.get
|
||||
theorem getD_eq_iff {o : Option α} {a b} : o.getD a = b ↔ (o = some b ∨ o = none ∧ a = b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem get!_none [Inhabited α] : (none : Option α).get! = default := rfl
|
||||
@[simp, grind =] theorem get!_none [Inhabited α] : (none : Option α).get! = default := rfl
|
||||
|
||||
@[simp, grind] theorem get!_some [Inhabited α] {a : α} : (some a).get! = a := rfl
|
||||
@[simp, grind =] theorem get!_some [Inhabited α] {a : α} : (some a).get! = a := rfl
|
||||
|
||||
theorem get_eq_get! [Inhabited α] : (o : Option α) → {h : o.isSome} → o.get h = o.get!
|
||||
| some _, _ => rfl
|
||||
@@ -120,7 +120,7 @@ theorem isSome_of_eq_some {x : Option α} {y : α} (h : x = some y) : x.isSome :
|
||||
@[simp] theorem isNone_eq_false_iff : isNone a = false ↔ a.isSome = true := by
|
||||
cases a <;> simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem not_isSome (a : Option α) : (!a.isSome) = a.isNone := by
|
||||
cases a <;> simp
|
||||
|
||||
@@ -129,7 +129,7 @@ theorem not_comp_isSome : (! ·) ∘ @Option.isSome α = Option.isNone := by
|
||||
funext
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem not_isNone (a : Option α) : (!a.isNone) = a.isSome := by
|
||||
cases a <;> simp
|
||||
|
||||
@@ -191,11 +191,15 @@ theorem forall_ne_none {p : Option α → Prop} : (∀ x (_ : x ≠ none), p x)
|
||||
@[deprecated forall_ne_none (since := "2025-04-04")]
|
||||
abbrev ball_ne_none := @forall_ne_none
|
||||
|
||||
@[simp, grind] theorem pure_def : pure = @some α := rfl
|
||||
@[simp] theorem pure_def : pure = @some α := rfl
|
||||
|
||||
@[simp, grind] theorem bind_eq_bind : bind = @Option.bind α β := rfl
|
||||
@[grind =] theorem pure_apply : pure x = some x := rfl
|
||||
|
||||
@[simp, grind] theorem bind_fun_some (x : Option α) : x.bind some = x := by cases x <;> rfl
|
||||
@[simp] theorem bind_eq_bind : bind = @Option.bind α β := rfl
|
||||
|
||||
@[grind =] theorem bind_apply : bind x f = Option.bind x f := rfl
|
||||
|
||||
@[simp, grind =] theorem bind_fun_some (x : Option α) : x.bind some = x := by cases x <;> rfl
|
||||
|
||||
@[simp] theorem bind_fun_none (x : Option α) : x.bind (fun _ => none (α := β)) = none := by
|
||||
cases x <;> rfl
|
||||
@@ -216,7 +220,7 @@ theorem bind_eq_none' {o : Option α} {f : α → Option β} :
|
||||
o.bind f = none ↔ ∀ b a, o = some a → f a ≠ some b := by
|
||||
cases o <;> simp [eq_none_iff_forall_ne_some]
|
||||
|
||||
@[grind] theorem mem_bind_iff {o : Option α} {f : α → Option β} :
|
||||
@[grind =] theorem mem_bind_iff {o : Option α} {f : α → Option β} :
|
||||
b ∈ o.bind f ↔ ∃ a, a ∈ o ∧ b ∈ f a := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -224,7 +228,7 @@ theorem bind_comm {f : α → β → Option γ} (a : Option α) (b : Option β)
|
||||
(a.bind fun x => b.bind (f x)) = b.bind fun y => a.bind fun x => f x y := by
|
||||
cases a <;> cases b <;> rfl
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem bind_assoc (x : Option α) (f : α → Option β) (g : β → Option γ) :
|
||||
(x.bind f).bind g = x.bind fun y => (f y).bind g := by cases x <;> rfl
|
||||
|
||||
@@ -232,12 +236,12 @@ theorem bind_congr {α β} {o : Option α} {f g : α → Option β} :
|
||||
(h : ∀ a, o = some a → f a = g a) → o.bind f = o.bind g := by
|
||||
cases o <;> simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem isSome_bind {α β : Type _} (x : Option α) (f : α → Option β) :
|
||||
(x.bind f).isSome = x.any (fun x => (f x).isSome) := by
|
||||
cases x <;> rfl
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem isNone_bind {α β : Type _} (x : Option α) (f : α → Option β) :
|
||||
(x.bind f).isNone = x.all (fun x => (f x).isNone) := by
|
||||
cases x <;> rfl
|
||||
@@ -250,7 +254,7 @@ theorem isSome_apply_of_isSome_bind {α β : Type _} {x : Option α} {f : α →
|
||||
(h : (x.bind f).isSome) : (f (x.get (isSome_of_isSome_bind h))).isSome := by
|
||||
cases x <;> trivial
|
||||
|
||||
@[simp, grind] theorem get_bind {α β : Type _} {x : Option α} {f : α → Option β} (h : (x.bind f).isSome) :
|
||||
@[simp, grind =] theorem get_bind {α β : Type _} {x : Option α} {f : α → Option β} (h : (x.bind f).isSome) :
|
||||
(x.bind f).get h = (f (x.get (isSome_of_isSome_bind h))).get
|
||||
(isSome_apply_of_isSome_bind h) := by
|
||||
cases x <;> trivial
|
||||
@@ -263,7 +267,7 @@ theorem isSome_apply_of_isSome_bind {α β : Type _} {x : Option α} {f : α →
|
||||
(o.bind f).all p = o.all (Option.all p ∘ f) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[grind] theorem bind_id_eq_join {x : Option (Option α)} : x.bind id = x.join := rfl
|
||||
@[grind =] theorem bind_id_eq_join {x : Option (Option α)} : x.bind id = x.join := rfl
|
||||
|
||||
theorem join_eq_some_iff : x.join = some a ↔ x = some (some a) := by
|
||||
simp [← bind_id_eq_join, bind_eq_some_iff]
|
||||
@@ -287,7 +291,9 @@ theorem bind_join {f : α → Option β} {o : Option (Option α)} :
|
||||
o.join.bind f = o.bind (·.bind f) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem map_eq_map : Functor.map f = Option.map f := rfl
|
||||
@[simp] theorem map_eq_map : Functor.map f = Option.map f := rfl
|
||||
|
||||
@[grind =] theorem map_apply : Functor.map f x = Option.map f x := rfl
|
||||
|
||||
@[deprecated map_none (since := "2025-04-10")]
|
||||
abbrev map_none' := @map_none
|
||||
@@ -313,13 +319,13 @@ abbrev map_eq_none := @map_eq_none_iff
|
||||
@[deprecated map_eq_none_iff (since := "2025-04-10")]
|
||||
abbrev map_eq_none' := @map_eq_none_iff
|
||||
|
||||
@[simp, grind] theorem isSome_map {x : Option α} : (x.map f).isSome = x.isSome := by
|
||||
@[simp, grind =] theorem isSome_map {x : Option α} : (x.map f).isSome = x.isSome := by
|
||||
cases x <;> simp
|
||||
|
||||
@[deprecated isSome_map (since := "2025-04-10")]
|
||||
abbrev isSome_map' := @isSome_map
|
||||
|
||||
@[simp, grind] theorem isNone_map {x : Option α} : (x.map f).isNone = x.isNone := by
|
||||
@[simp, grind =] theorem isNone_map {x : Option α} : (x.map f).isNone = x.isNone := by
|
||||
cases x <;> simp
|
||||
|
||||
theorem map_eq_bind {x : Option α} : x.map f = x.bind (some ∘ f) := by
|
||||
@@ -329,28 +335,32 @@ theorem map_congr {x : Option α} (h : ∀ a, x = some a → f a = g a) :
|
||||
x.map f = x.map g := by
|
||||
cases x <;> simp only [map_none, map_some, h]
|
||||
|
||||
@[simp, grind] theorem map_id_fun {α : Type u} : Option.map (id : α → α) = id := by
|
||||
@[simp] theorem map_id_fun {α : Type u} : Option.map (id : α → α) = id := by
|
||||
funext; simp [map_id]
|
||||
|
||||
@[grind =] theorem map_id_apply {α : Type u} {x : Option α} : Option.map (id : α → α) x = x := by simp
|
||||
|
||||
theorem map_id' {x : Option α} : (x.map fun a => a) = x := congrFun map_id x
|
||||
|
||||
@[simp, grind] theorem map_id_fun' {α : Type u} : Option.map (fun (a : α) => a) = id := by
|
||||
@[simp] theorem map_id_fun' {α : Type u} : Option.map (fun (a : α) => a) = id := by
|
||||
funext; simp [map_id']
|
||||
|
||||
@[simp, grind] theorem get_map {f : α → β} {o : Option α} {h : (o.map f).isSome} :
|
||||
theorem map_id_apply' {α : Type u} {x : Option α} : Option.map (fun (a : α) => a) x = x := by simp
|
||||
|
||||
@[simp, grind =] theorem get_map {f : α → β} {o : Option α} {h : (o.map f).isSome} :
|
||||
(o.map f).get h = f (o.get (by simpa using h)) := by
|
||||
cases o with
|
||||
| none => simp at h
|
||||
| some a => simp
|
||||
|
||||
@[simp, grind _=_] theorem map_map (h : β → γ) (g : α → β) (x : Option α) :
|
||||
@[simp] theorem map_map (h : β → γ) (g : α → β) (x : Option α) :
|
||||
(x.map g).map h = x.map (h ∘ g) := by
|
||||
cases x <;> simp only [map_none, map_some, ·∘·]
|
||||
|
||||
theorem comp_map (h : β → γ) (g : α → β) (x : Option α) : x.map (h ∘ g) = (x.map g).map h :=
|
||||
(map_map ..).symm
|
||||
|
||||
@[simp, grind _=_] theorem map_comp_map (f : α → β) (g : β → γ) :
|
||||
@[simp] theorem map_comp_map (f : α → β) (g : β → γ) :
|
||||
Option.map g ∘ Option.map f = Option.map (g ∘ f) := by funext x; simp
|
||||
|
||||
theorem mem_map_of_mem (g : α → β) (h : a ∈ x) : g a ∈ Option.map g x := h.symm ▸ map_some ..
|
||||
@@ -372,9 +382,9 @@ theorem map_inj_right {f : α → β} {o o' : Option α} (w : ∀ x y, f x = f y
|
||||
(if h : c then some (a h) else none).map f = if h : c then some (f (a h)) else none := by
|
||||
split <;> rfl
|
||||
|
||||
@[simp, grind] theorem filter_none (p : α → Bool) : none.filter p = none := rfl
|
||||
@[simp, grind =] theorem filter_none (p : α → Bool) : none.filter p = none := rfl
|
||||
|
||||
@[grind] theorem filter_some : Option.filter p (some a) = if p a then some a else none := rfl
|
||||
@[grind =] theorem filter_some : Option.filter p (some a) = if p a then some a else none := rfl
|
||||
|
||||
theorem filter_some_pos (h : p a) : Option.filter p (some a) = some a := by
|
||||
rw [filter_some, if_pos h]
|
||||
@@ -417,12 +427,12 @@ theorem filter_some_eq_some : Option.filter p (some a) = some a ↔ p a := by si
|
||||
|
||||
theorem filter_some_eq_none : Option.filter p (some a) = none ↔ ¬p a := by simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem mem_filter_iff {p : α → Bool} {a : α} {o : Option α} :
|
||||
a ∈ o.filter p ↔ a ∈ o ∧ p a := by
|
||||
simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem bind_guard (x : Option α) (p : α → Bool) :
|
||||
x.bind (Option.guard p) = x.filter p := by
|
||||
cases x <;> rfl
|
||||
@@ -457,7 +467,7 @@ theorem filter_eq_bind (x : Option α) (p : α → Bool) :
|
||||
| false => by simp [filter_some_neg h, h]
|
||||
| true => by simp [filter_some_pos h, h]
|
||||
|
||||
@[simp, grind] theorem isSome_filter : Option.isSome (Option.filter p o) = Option.any p o :=
|
||||
@[simp, grind =] theorem isSome_filter : Option.isSome (Option.filter p o) = Option.any p o :=
|
||||
match o with
|
||||
| none => rfl
|
||||
| some a =>
|
||||
@@ -536,12 +546,12 @@ theorem get_of_any_eq_true (p : α → Bool) (x : Option α) (h : x.any p = true
|
||||
p (x.get (isSome_of_any h)) :=
|
||||
any_eq_true_iff_get p x |>.1 h |>.2
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem any_map {α β : Type _} {x : Option α} {f : α → β} {p : β → Bool} :
|
||||
(x.map f).any p = x.any (fun a => p (f a)) := by
|
||||
cases x <;> rfl
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem all_map {α β : Type _} {x : Option α} {f : α → β} {p : β → Bool} :
|
||||
(x.map f).all p = x.all (fun a => p (f a)) := by
|
||||
cases x <;> rfl
|
||||
@@ -549,13 +559,13 @@ theorem all_map {α β : Type _} {x : Option α} {f : α → β} {p : β → Boo
|
||||
theorem bind_map_comm {α β} {x : Option (Option α)} {f : α → β} :
|
||||
x.bind (Option.map f) = (x.map (Option.map f)).bind id := by cases x <;> simp
|
||||
|
||||
@[grind] theorem bind_map {f : α → β} {g : β → Option γ} {x : Option α} :
|
||||
@[grind =] theorem bind_map {f : α → β} {g : β → Option γ} {x : Option α} :
|
||||
(x.map f).bind g = x.bind (g ∘ f) := by cases x <;> simp
|
||||
|
||||
@[simp, grind] theorem map_bind {f : α → Option β} {g : β → γ} {x : Option α} :
|
||||
@[simp, grind =] theorem map_bind {f : α → Option β} {g : β → γ} {x : Option α} :
|
||||
(x.bind f).map g = x.bind (Option.map g ∘ f) := by cases x <;> simp
|
||||
|
||||
@[grind] theorem join_map_eq_map_join {f : α → β} {x : Option (Option α)} :
|
||||
@[grind =] theorem join_map_eq_map_join {f : α → β} {x : Option (Option α)} :
|
||||
(x.map (Option.map f)).join = x.join.map f := by cases x <;> simp
|
||||
|
||||
@[grind _=_] theorem join_join {x : Option (Option (Option α))} : x.join.join = (x.map join).join := by
|
||||
@@ -652,10 +662,11 @@ theorem get_none_eq_iff_true {h} : (none : Option α).get h = a ↔ True := by
|
||||
simp only [guard]
|
||||
split <;> simp
|
||||
|
||||
@[grind]
|
||||
theorem guard_def (p : α → Bool) :
|
||||
Option.guard p = fun x => if p x then some x else none := rfl
|
||||
|
||||
@[grind =] theorem guard_apply : Option.guard p x = if p x then some x else none := rfl
|
||||
|
||||
@[deprecated guard_def (since := "2025-05-15")]
|
||||
theorem guard_eq_map (p : α → Bool) :
|
||||
Option.guard p = fun x => Option.map (fun _ => x) (if p x then some x else none) := by
|
||||
@@ -704,13 +715,13 @@ theorem merge_eq_or_eq {f : α → α → α} (h : ∀ a b, f a b = a ∨ f a b
|
||||
| none, some _ => .inr rfl
|
||||
| some a, some b => by have := h a b; simp [merge] at this ⊢; exact this
|
||||
|
||||
@[simp, grind] theorem merge_none_left {f} {b : Option α} : merge f none b = b := by
|
||||
@[simp, grind =] theorem merge_none_left {f} {b : Option α} : merge f none b = b := by
|
||||
cases b <;> rfl
|
||||
|
||||
@[simp, grind] theorem merge_none_right {f} {a : Option α} : merge f a none = a := by
|
||||
@[simp, grind =] theorem merge_none_right {f} {a : Option α} : merge f a none = a := by
|
||||
cases a <;> rfl
|
||||
|
||||
@[simp, grind] theorem merge_some_some {f} {a b : α} :
|
||||
@[simp, grind =] theorem merge_some_some {f} {a b : α} :
|
||||
merge f (some a) (some b) = some (f a b) := rfl
|
||||
|
||||
@[deprecated merge_eq_or_eq (since := "2025-04-04")]
|
||||
@@ -784,9 +795,9 @@ theorem get_merge {o o' : Option α} {f : α → α → α} {i : α} [Std.Lawful
|
||||
(o.merge f o').get h = f (o.getD i) (o'.getD i) := by
|
||||
cases o <;> cases o' <;> simp [Std.LawfulLeftIdentity.left_id, Std.LawfulRightIdentity.right_id]
|
||||
|
||||
@[simp, grind] theorem elim_none (x : β) (f : α → β) : none.elim x f = x := rfl
|
||||
@[simp, grind =] theorem elim_none (x : β) (f : α → β) : none.elim x f = x := rfl
|
||||
|
||||
@[simp, grind] theorem elim_some (x : β) (f : α → β) (a : α) : (some a).elim x f = f a := rfl
|
||||
@[simp, grind =] theorem elim_some (x : β) (f : α → β) (a : α) : (some a).elim x f = f a := rfl
|
||||
|
||||
@[grind =] theorem elim_filter {o : Option α} {b : β} :
|
||||
Option.elim (Option.filter p o) b f = Option.elim o b (fun a => if p a then f a else b) :=
|
||||
@@ -804,7 +815,8 @@ theorem get_merge {o o' : Option α} {f : α → α → α} {i : α} [Std.Lawful
|
||||
theorem elim_guard : (guard p a).elim b f = if p a then f a else b := by
|
||||
cases h : p a <;> simp [*, guard]
|
||||
|
||||
@[simp, grind] theorem getD_map (f : α → β) (x : α) (o : Option α) :
|
||||
-- I don't see how to construct a good grind pattern to instantiate this.
|
||||
@[simp] theorem getD_map (f : α → β) (x : α) (o : Option α) :
|
||||
(o.map f).getD (f x) = f (getD o x) := by cases o <;> rfl
|
||||
|
||||
section choice
|
||||
@@ -867,37 +879,37 @@ theorem get!_choice [Inhabited α] : (choice α).get! = (choice α).get isSome_c
|
||||
|
||||
end choice
|
||||
|
||||
@[simp, grind] theorem toList_some (a : α) : (some a).toList = [a] := rfl
|
||||
@[simp, grind] theorem toList_none (α : Type _) : (none : Option α).toList = [] := rfl
|
||||
@[simp, grind =] theorem toList_some (a : α) : (some a).toList = [a] := rfl
|
||||
@[simp, grind =] theorem toList_none (α : Type _) : (none : Option α).toList = [] := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_some (a : α) : (some a).toArray = #[a] := rfl
|
||||
@[simp, grind] theorem toArray_none (α : Type _) : (none : Option α).toArray = #[] := rfl
|
||||
@[simp, grind =] theorem toArray_some (a : α) : (some a).toArray = #[a] := rfl
|
||||
@[simp, grind =] theorem toArray_none (α : Type _) : (none : Option α).toArray = #[] := rfl
|
||||
|
||||
-- See `Init.Data.Option.List` for lemmas about `toList`.
|
||||
|
||||
@[simp, grind] theorem some_or : (some a).or o = some a := rfl
|
||||
@[simp, grind] theorem none_or : none.or o = o := rfl
|
||||
@[simp, grind =] theorem some_or : (some a).or o = some a := rfl
|
||||
@[simp, grind =] theorem none_or : none.or o = o := rfl
|
||||
|
||||
theorem or_eq_right_of_none {o o' : Option α} (h : o = none) : o.or o' = o' := by
|
||||
cases h; simp
|
||||
|
||||
@[simp, grind] theorem or_some {o : Option α} : o.or (some a) = some (o.getD a) := by
|
||||
@[simp, grind =] theorem or_some {o : Option α} : o.or (some a) = some (o.getD a) := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[deprecated or_some (since := "2025-05-03")]
|
||||
abbrev or_some' := @or_some
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem or_none : or o none = o := by
|
||||
cases o <;> rfl
|
||||
|
||||
theorem or_eq_bif : or o o' = bif o.isSome then o else o' := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp, grind] theorem isSome_or : (or o o').isSome = (o.isSome || o'.isSome) := by
|
||||
@[simp, grind =] theorem isSome_or : (or o o').isSome = (o.isSome || o'.isSome) := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp, grind] theorem isNone_or : (or o o').isNone = (o.isNone && o'.isNone) := by
|
||||
@[simp, grind =] theorem isNone_or : (or o o').isNone = (o.isNone && o'.isNone) := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp] theorem or_eq_none_iff : or o o' = none ↔ o = none ∧ o' = none := by
|
||||
@@ -912,7 +924,7 @@ abbrev or_eq_none := @or_eq_none_iff
|
||||
@[deprecated or_eq_some_iff (since := "2025-04-10")]
|
||||
abbrev or_eq_some := @or_eq_some_iff
|
||||
|
||||
@[grind] theorem or_assoc : or (or o₁ o₂) o₃ = or o₁ (or o₂ o₃) := by
|
||||
@[grind _=_] theorem or_assoc : or (or o₁ o₂) o₃ = or o₁ (or o₂ o₃) := by
|
||||
cases o₁ <;> cases o₂ <;> rfl
|
||||
instance : Std.Associative (or (α := α)) := ⟨@or_assoc _⟩
|
||||
|
||||
@@ -923,7 +935,7 @@ instance : Std.LawfulIdentity (or (α := α)) none where
|
||||
left_id := @none_or _
|
||||
right_id := @or_none _
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem or_self : or o o = o := by
|
||||
cases o <;> rfl
|
||||
instance : Std.IdempotentOp (or (α := α)) := ⟨@or_self _⟩
|
||||
@@ -962,13 +974,15 @@ theorem guard_or_guard : (guard p a).or (guard q a) = guard (fun x => p x || q x
|
||||
/-! ### `orElse` -/
|
||||
|
||||
/-- The `simp` normal form of `o <|> o'` is `o.or o'` via `orElse_eq_orElse` and `orElse_eq_or`. -/
|
||||
@[simp, grind] theorem orElse_eq_orElse : HOrElse.hOrElse = @Option.orElse α := rfl
|
||||
@[simp] theorem orElse_eq_orElse : HOrElse.hOrElse = @Option.orElse α := rfl
|
||||
|
||||
@[grind =] theorem orElse_apply : HOrElse.hOrElse o o' = Option.orElse o o' := rfl
|
||||
|
||||
theorem or_eq_orElse : or o o' = o.orElse (fun _ => o') := by
|
||||
cases o <;> rfl
|
||||
|
||||
/-- The `simp` normal form of `o.orElse f` is o.or (f ())`. -/
|
||||
@[simp, grind] theorem orElse_eq_or {o : Option α} {f} : o.orElse f = o.or (f ()) := by
|
||||
@[simp, grind =] theorem orElse_eq_or {o : Option α} {f} : o.orElse f = o.or (f ()) := by
|
||||
simp [or_eq_orElse]
|
||||
|
||||
@[deprecated or_some (since := "2025-05-03")]
|
||||
@@ -1001,13 +1015,13 @@ section beq
|
||||
|
||||
variable [BEq α]
|
||||
|
||||
@[simp, grind] theorem none_beq_none : ((none : Option α) == none) = true := rfl
|
||||
@[simp, grind] theorem none_beq_some (a : α) : ((none : Option α) == some a) = false := rfl
|
||||
@[simp, grind] theorem some_beq_none (a : α) : ((some a : Option α) == none) = false := rfl
|
||||
@[simp, grind] theorem some_beq_some {a b : α} : (some a == some b) = (a == b) := rfl
|
||||
@[simp, grind =] theorem none_beq_none : ((none : Option α) == none) = true := rfl
|
||||
@[simp, grind =] theorem none_beq_some (a : α) : ((none : Option α) == some a) = false := rfl
|
||||
@[simp, grind =] theorem some_beq_none (a : α) : ((some a : Option α) == none) = false := rfl
|
||||
@[simp, grind =] theorem some_beq_some {a b : α} : (some a == some b) = (a == b) := rfl
|
||||
|
||||
/-- We simplify away `isEqSome` in terms of `==`. -/
|
||||
@[simp, grind] theorem isEqSome_eq_beq_some {o : Option α} : isEqSome o y = (o == some y) := by
|
||||
@[simp, grind =] theorem isEqSome_eq_beq_some {o : Option α} : isEqSome o y = (o == some y) := by
|
||||
cases o <;> simp [isEqSome]
|
||||
|
||||
@[simp] theorem reflBEq_iff : ReflBEq (Option α) ↔ ReflBEq α := by
|
||||
@@ -1128,12 +1142,15 @@ theorem mem_ite_none_right {x : α} {_ : Decidable p} {l : Option α} :
|
||||
@[simp] theorem isSome_dite {p : Prop} {_ : Decidable p} {b : p → β} :
|
||||
(if h : p then some (b h) else none).isSome = true ↔ p := by
|
||||
split <;> simpa
|
||||
|
||||
@[simp] theorem isSome_ite {p : Prop} {_ : Decidable p} :
|
||||
(if p then some b else none).isSome = true ↔ p := by
|
||||
split <;> simpa
|
||||
|
||||
@[simp] theorem isSome_dite' {p : Prop} {_ : Decidable p} {b : ¬ p → β} :
|
||||
(if h : p then none else some (b h)).isSome = true ↔ ¬ p := by
|
||||
split <;> simpa
|
||||
|
||||
@[simp] theorem isSome_ite' {p : Prop} {_ : Decidable p} :
|
||||
(if p then none else some b).isSome = true ↔ ¬ p := by
|
||||
split <;> simpa
|
||||
@@ -1145,9 +1162,11 @@ theorem mem_ite_none_right {x : α} {_ : Decidable p} {l : Option α} :
|
||||
· exfalso
|
||||
simp at w
|
||||
contradiction
|
||||
|
||||
@[simp] theorem get_ite {p : Prop} {_ : Decidable p} (h) :
|
||||
(if p then some b else none).get h = b := by
|
||||
simpa using get_dite (p := p) (fun _ => b) (by simpa using h)
|
||||
|
||||
@[simp] theorem get_dite' {p : Prop} {_ : Decidable p} (b : ¬ p → β) (w) :
|
||||
(if h : p then none else some (b h)).get w = b (by simpa using w) := by
|
||||
split
|
||||
@@ -1155,13 +1174,14 @@ theorem mem_ite_none_right {x : α} {_ : Decidable p} {l : Option α} :
|
||||
simp at w
|
||||
contradiction
|
||||
· simp
|
||||
|
||||
@[simp] theorem get_ite' {p : Prop} {_ : Decidable p} (h) :
|
||||
(if p then none else some b).get h = b := by
|
||||
simpa using get_dite' (p := p) (fun _ => b) (by simpa using h)
|
||||
|
||||
end ite
|
||||
|
||||
@[simp, grind] theorem get_filter {α : Type _} {x : Option α} {f : α → Bool} (h : (x.filter f).isSome) :
|
||||
@[simp, grind =] theorem get_filter {α : Type _} {x : Option α} {f : α → Bool} (h : (x.filter f).isSome) :
|
||||
(x.filter f).get h = x.get (isSome_of_isSome_filter f x h) := by
|
||||
cases x
|
||||
· contradiction
|
||||
@@ -1176,16 +1196,16 @@ end ite
|
||||
@[grind = gen] theorem pbind_none' (h : x = none) : pbind x f = none := by subst h; rfl
|
||||
@[grind = gen] theorem pbind_some' (h : x = some a) : pbind x f = f a h := by subst h; rfl
|
||||
|
||||
@[simp, grind] theorem map_pbind {o : Option α} {f : (a : α) → o = some a → Option β}
|
||||
@[simp, grind =] theorem map_pbind {o : Option α} {f : (a : α) → o = some a → Option β}
|
||||
{g : β → γ} : (o.pbind f).map g = o.pbind (fun a h => (f a h).map g) := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp, grind] theorem pbind_map {α β γ : Type _} (o : Option α)
|
||||
@[simp, grind =] theorem pbind_map {α β γ : Type _} (o : Option α)
|
||||
(f : α → β) (g : (x : β) → o.map f = some x → Option γ) :
|
||||
(o.map f).pbind g = o.pbind (fun x h => g (f x) (h ▸ rfl)) := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp, grind] theorem pbind_eq_bind {α β : Type _} (o : Option α)
|
||||
@[simp] theorem pbind_eq_bind {α β : Type _} (o : Option α)
|
||||
(f : α → Option β) : o.pbind (fun x _ => f x) = o.bind f := by
|
||||
cases o <;> rfl
|
||||
|
||||
@@ -1253,11 +1273,11 @@ theorem get_pbind {o : Option α} {f : (a : α) → o = some a → Option β} {h
|
||||
pmap f o h = none ↔ o = none := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem isSome_pmap {p : α → Prop} {f : ∀ (a : α), p a → β} {o : Option α} {h} :
|
||||
@[simp, grind =] theorem isSome_pmap {p : α → Prop} {f : ∀ (a : α), p a → β} {o : Option α} {h} :
|
||||
(pmap f o h).isSome = o.isSome := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem isNone_pmap {p : α → Prop} {f : ∀ (a : α), p a → β} {o : Option α} {h} :
|
||||
@[simp, grind =] theorem isNone_pmap {p : α → Prop} {f : ∀ (a : α), p a → β} {o : Option α} {h} :
|
||||
(pmap f o h).isNone = o.isNone := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -1279,11 +1299,11 @@ theorem pmap_eq_map (p : α → Prop) (f : α → β) (o : Option α) (H) :
|
||||
@pmap _ _ p (fun a _ => f a) o H = Option.map f o := by
|
||||
cases o <;> simp
|
||||
|
||||
@[grind] theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (o H) :
|
||||
@[grind =] theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (o H) :
|
||||
Option.map g (pmap f o H) = pmap (fun a h => g (f a h)) o H := by
|
||||
cases o <;> simp
|
||||
|
||||
@[grind] theorem pmap_map (o : Option α) (f : α → β) {p : β → Prop} (g : ∀ b, p b → γ) (H) :
|
||||
@[grind =] theorem pmap_map (o : Option α) (f : α → β) {p : β → Prop} (g : ∀ b, p b → γ) (H) :
|
||||
pmap g (o.map f) H =
|
||||
pmap (fun a h => g (f a) h) o (fun a m => H (f a) (map_eq_some_iff.2 ⟨_, m, rfl⟩)) := by
|
||||
cases o <;> simp
|
||||
@@ -1340,7 +1360,7 @@ theorem get_pmap {p : α → Bool} {f : (x : α) → p x → β} {o : Option α}
|
||||
@[simp] theorem pelim_eq_elim : pelim o b (fun a _ => f a) = o.elim b f := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem elim_pmap {p : α → Prop} (f : (a : α) → p a → β) (o : Option α)
|
||||
@[simp, grind =] theorem elim_pmap {p : α → Prop} (f : (a : α) → p a → β) (o : Option α)
|
||||
(H : ∀ (a : α), o = some a → p a) (g : γ) (g' : β → γ) :
|
||||
(o.pmap f H).elim g g' =
|
||||
o.pelim g (fun a h => g' (f a (H a h))) := by
|
||||
@@ -1387,11 +1407,11 @@ theorem pfilter_congr {α : Type u} {o o' : Option α} (ho : o = o')
|
||||
congr; funext a ha
|
||||
exact hf a ha
|
||||
|
||||
@[simp, grind] theorem pfilter_none {α : Type _} {p : (a : α) → none = some a → Bool} :
|
||||
@[simp, grind =] theorem pfilter_none {α : Type _} {p : (a : α) → none = some a → Bool} :
|
||||
none.pfilter p = none := by
|
||||
rfl
|
||||
|
||||
@[simp, grind] theorem pfilter_some {α : Type _} {x : α} {p : (a : α) → some x = some a → Bool} :
|
||||
@[simp, grind =] theorem pfilter_some {α : Type _} {x : α} {p : (a : α) → some x = some a → Bool} :
|
||||
(some x).pfilter p = if p x rfl then some x else none := by
|
||||
simp only [pfilter, cond_eq_if]
|
||||
|
||||
@@ -1416,7 +1436,7 @@ theorem isNone_pfilter_iff {o : Option α} {p : (a : α) → o = some a → Bool
|
||||
Bool.not_eq_true, some.injEq]
|
||||
exact ⟨fun h _ h' => h' ▸ h, fun h => h _ rfl⟩
|
||||
|
||||
@[simp, grind] theorem get_pfilter {α : Type _} {o : Option α} {p : (a : α) → o = some a → Bool}
|
||||
@[simp, grind =] theorem get_pfilter {α : Type _} {o : Option α} {p : (a : α) → o = some a → Bool}
|
||||
(h : (o.pfilter p).isSome) :
|
||||
(o.pfilter p).get h = o.get (isSome_of_isSome_pfilter h) := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -96,7 +96,7 @@ Ordering.lt
|
||||
| a => a
|
||||
|
||||
/-- Version of `Ordering.then'` for proof by reflection. -/
|
||||
noncomputable def then' (a b : Ordering) : Ordering :=
|
||||
@[expose] noncomputable def then' (a b : Ordering) : Ordering :=
|
||||
Ordering.rec a b a a
|
||||
|
||||
/--
|
||||
@@ -204,6 +204,7 @@ instance [DecidablePred p] : Decidable (∃ o : Ordering, p o) :=
|
||||
theorem eq_eq_of_isLE_of_isLE_swap : ∀ {o : Ordering}, o.isLE → o.swap.isLE → o = .eq := by decide
|
||||
theorem eq_eq_of_isGE_of_isGE_swap : ∀ {o : Ordering}, o.isGE → o.swap.isGE → o = .eq := by decide
|
||||
theorem eq_eq_of_isLE_of_isGE : ∀ {o : Ordering}, o.isLE → o.isGE → o = .eq := by decide
|
||||
theorem eq_eq_iff_isLE_and_isGE : ∀ {o : Ordering}, o = .eq ↔ o.isLE ∧ o.isGE := by decide
|
||||
theorem eq_swap_iff_eq_eq : ∀ {o : Ordering}, o = o.swap ↔ o = .eq := by decide
|
||||
theorem eq_eq_of_eq_swap : ∀ {o : Ordering}, o = o.swap → o = .eq := eq_swap_iff_eq_eq.mp
|
||||
|
||||
@@ -6,7 +6,7 @@ Authors: Markus Himmel, Paul Reichert, Robin Arnez
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Std.Classes.Ord.Basic
|
||||
public import Init.Data.Order.Ord
|
||||
public import Init.Data.BitVec.Lemmas
|
||||
|
||||
public section
|
||||
@@ -6,7 +6,7 @@ Authors: Markus Himmel, Paul Reichert, Robin Arnez
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Std.Classes.Ord.Basic
|
||||
public import Init.Data.Order.Ord
|
||||
public import Init.Data.SInt.Lemmas
|
||||
|
||||
public section
|
||||
@@ -6,7 +6,7 @@ Authors: Markus Himmel, Paul Reichert, Robin Arnez
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Std.Classes.Ord.Basic
|
||||
public import Init.Data.Order.Ord
|
||||
public import Init.Data.String.Lemmas
|
||||
|
||||
public section
|
||||
@@ -6,7 +6,7 @@ Authors: Markus Himmel, Paul Reichert, Robin Arnez
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Std.Classes.Ord.Basic
|
||||
public import Init.Data.Order.Ord
|
||||
public import Init.Data.UInt.Lemmas
|
||||
|
||||
public section
|
||||
@@ -6,7 +6,7 @@ Authors: Markus Himmel, Paul Reichert, Robin Arnez
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Std.Classes.Ord.Basic
|
||||
public import Init.Data.Order.Ord
|
||||
public import Init.Data.Vector.Lemmas
|
||||
|
||||
public section
|
||||
14
src/Init/Data/OrdRoot.lean
Normal file
14
src/Init/Data/OrdRoot.lean
Normal file
@@ -0,0 +1,14 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Ord.Basic
|
||||
public import Init.Data.Ord.BitVec
|
||||
public import Init.Data.Ord.SInt
|
||||
public import Init.Data.Ord.String
|
||||
public import Init.Data.Ord.UInt
|
||||
public import Init.Data.Ord.Vector
|
||||
16
src/Init/Data/Order.lean
Normal file
16
src/Init/Data/Order.lean
Normal file
@@ -0,0 +1,16 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Order.Ord
|
||||
public import Init.Data.Order.Classes
|
||||
public import Init.Data.Order.ClassesExtra
|
||||
public import Init.Data.Order.Lemmas
|
||||
public import Init.Data.Order.LemmasExtra
|
||||
public import Init.Data.Order.Factories
|
||||
public import Init.Data.Order.FactoriesExtra
|
||||
public import Init.Data.Order.PackageFactories
|
||||
194
src/Init/Data/Order/Classes.lean
Normal file
194
src/Init/Data/Order/Classes.lean
Normal file
@@ -0,0 +1,194 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Core
|
||||
|
||||
namespace Std
|
||||
|
||||
/-!
|
||||
# Order-related typeclasses
|
||||
|
||||
This module provides the typeclasses used to state that basic operations on some type `α`
|
||||
reflect a certain well-behaved order structure on `α`.
|
||||
|
||||
The basic operations are provided by the typeclasses `LE α`, `LT α`, `BEq α`, `Ord α`, `Min α` and
|
||||
`Max α`.
|
||||
All of them describe at least some way to compare elements in `α`. Usually, any subset of them
|
||||
is available and one can/must show that these comparisons are well-behaved in some sense.
|
||||
|
||||
For example, one could merely require that the available operations reflect a preorder
|
||||
(where the less-or-equal relation only needs to be reflexive and transitive). Alternatively,
|
||||
one could require a full linear order (additionally requiring antisymmetry and totality of the
|
||||
less-or-equal relation).
|
||||
|
||||
There are many ways to characterize, say, linear orders:
|
||||
|
||||
* `(· ≤ ·)` is reflexive, transitive, antisymmetric and total.
|
||||
* `(· ≤ ·)` is antisymmetric, `a < b ↔ ¬ b ≤ a` and `(· < ·)` is irreflexive, transitive and asymmetric.
|
||||
* `min a b` is either `a` or `b`, is symmetric and satisfies the
|
||||
following property: `min c (min a b) = c` if and only if `min c a = c` and `min c b = c`.
|
||||
|
||||
It is desirable that lemmas about linear orders state this hypothesis in a canonical way.
|
||||
Therefore, the classes defining preorders, partial orders, linear preorders and linear orders
|
||||
are all formulated purely in terms of `LE`. For other operations, there are
|
||||
classes for compatibility of `LE` with other operations. Hence, a lemma may look like:
|
||||
|
||||
```lean
|
||||
theorem lt_trans {α : Type u} [LE α] [LT α]
|
||||
[IsPreorder α] -- The order on `α` induced by `LE α` is, among other things, transitive.
|
||||
[LawfulOrderLT α] -- `<` is the less-than relation induced by `LE α`.
|
||||
{a b : α} : a < b → b < c → a < c := by
|
||||
sorry
|
||||
```
|
||||
-/
|
||||
|
||||
/--
|
||||
This typeclass states that the order structure on `α`, represented by an `LE α` instance,
|
||||
is a preorder. In other words, the less-or-equal relation is reflexive and transitive.
|
||||
-/
|
||||
public class IsPreorder (α : Type u) [LE α] where
|
||||
le_refl : ∀ a : α, a ≤ a
|
||||
le_trans : ∀ a b c : α, a ≤ b → b ≤ c → a ≤ c
|
||||
|
||||
/--
|
||||
This typeclass states that the order structure on `α`, represented by an `LE α` instance,
|
||||
is a partial order.
|
||||
In other words, the less-or-equal relation is reflexive, transitive and antisymmetric.
|
||||
-/
|
||||
public class IsPartialOrder (α : Type u) [LE α] extends IsPreorder α where
|
||||
le_antisymm : ∀ a b : α, a ≤ b → b ≤ a → a = b
|
||||
|
||||
/--
|
||||
This typeclass states that the order structure on `α`, represented by an `LE α` instance,
|
||||
is a linear preorder.
|
||||
In other words, the less-or-equal relation is reflexive, transitive and total.
|
||||
-/
|
||||
public class IsLinearPreorder (α : Type u) [LE α] extends IsPreorder α where
|
||||
le_total : ∀ a b : α, a ≤ b ∨ b ≤ a
|
||||
|
||||
/--
|
||||
This typeclass states that the order structure on `α`, represented by an `LE α` instance,
|
||||
is a linear order.
|
||||
In other words, the less-or-equal relation is reflexive, transitive, antisymmetric and total.
|
||||
-/
|
||||
public class IsLinearOrder (α : Type u) [LE α] extends IsPartialOrder α, IsLinearPreorder α
|
||||
|
||||
section LT
|
||||
|
||||
/--
|
||||
This typeclass states that the synthesized `LT α` instance is compatible with the `LE α`
|
||||
instance. This means that `LT.lt a b` holds if and only if `a` is less or equal to `b` according
|
||||
to the `LE α` instance, but `b` is not less or equal to `a`.
|
||||
|
||||
`LawfulOrderLT α` automatically entails that `LT α` is asymmetric: `a < b` and `b < a` can never
|
||||
be true simultaneously.
|
||||
|
||||
`LT α` does not uniquely determine the `LE α`: There can be only one compatible order data
|
||||
instance that is total, but there can be others that are not total.
|
||||
-/
|
||||
public class LawfulOrderLT (α : Type u) [LT α] [LE α] where
|
||||
lt_iff : ∀ a b : α, a < b ↔ a ≤ b ∧ ¬ b ≤ a
|
||||
|
||||
end LT
|
||||
|
||||
section BEq
|
||||
|
||||
public class LawfulOrderBEq (α : Type u) [BEq α] [LE α] where
|
||||
beq_iff_le_and_ge : ∀ a b : α, a == b ↔ a ≤ b ∧ b ≤ a
|
||||
|
||||
end BEq
|
||||
|
||||
section Min
|
||||
|
||||
/--
|
||||
This typeclass states that `Min.min a b` returns one of its arguments, either `a` or `b`.
|
||||
-/
|
||||
public class MinEqOr (α : Type u) [Min α] where
|
||||
min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b
|
||||
|
||||
/--
|
||||
If both `a` and `b` satisfy some property `P`, then so does `min a b`, because it is equal to
|
||||
either `a` or `b`.
|
||||
-/
|
||||
public def MinEqOr.elim {α : Type u} [Min α] [MinEqOr α] {P : α → Prop} {a b : α} (ha : P a) (hb : P b) :
|
||||
P (min a b) := by
|
||||
cases MinEqOr.min_eq_or a b <;> rename_i h
|
||||
case inl => exact h.symm ▸ ha
|
||||
case inr => exact h.symm ▸ hb
|
||||
|
||||
/--
|
||||
This typeclass states that being less or equal to `min a b` is equivalent to being less or
|
||||
equal to both `a` and `b`..
|
||||
-/
|
||||
public class LawfulOrderInf (α : Type u) [Min α] [LE α] where
|
||||
le_min_iff : ∀ a b c : α, a ≤ (min b c) ↔ a ≤ b ∧ a ≤ c
|
||||
|
||||
/--
|
||||
This typeclass bundles `MinEqOr α` and `LawfulOrderInf α`. It characterizes when a `Min α`
|
||||
instance reasonably computes minima in some type `α` that has an `LE α` instance.
|
||||
|
||||
As long as `α` is a preorder (see `IsPreorder α`), this typeclass implies that the order on
|
||||
`α` is total and that `Min.min a b` returns either `a` or `b`, whichever is less or equal to
|
||||
the other.
|
||||
-/
|
||||
public class LawfulOrderMin (α : Type u) [Min α] [LE α] extends MinEqOr α, LawfulOrderInf α
|
||||
|
||||
/--
|
||||
This typeclass states that `min a b = if a ≤ b then a else b` (for any `DecidableLE α` instance).
|
||||
-/
|
||||
public class LawfulOrderLeftLeaningMin (α : Type u) [Min α] [LE α] where
|
||||
min_eq_left : ∀ a b : α, a ≤ b → min a b = a
|
||||
min_eq_right : ∀ a b : α, ¬ a ≤ b → min a b = b
|
||||
|
||||
end Min
|
||||
|
||||
section Max
|
||||
|
||||
/--
|
||||
This typeclass states that `Max.max a b` returns one of its arguments, either `a` or `b`.
|
||||
-/
|
||||
public class MaxEqOr (α : Type u) [Max α] where
|
||||
max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b
|
||||
|
||||
/--
|
||||
If both `a` and `b` satisfy some property `P`, then so does `max a b`, because it is equal to
|
||||
either `a` or `b`.
|
||||
-/
|
||||
public def MaxEqOr.elim {α : Type u} [Max α] [MaxEqOr α] {P : α → Prop} {a b : α} (ha : P a) (hb : P b) :
|
||||
P (max a b) := by
|
||||
cases MaxEqOr.max_eq_or a b <;> rename_i h
|
||||
case inl => exact h.symm ▸ ha
|
||||
case inr => exact h.symm ▸ hb
|
||||
|
||||
/--
|
||||
This typeclass states that being less or equal to `Max.max a b` is equivalent to being less or
|
||||
equal to both `a` and `b`.
|
||||
-/
|
||||
public class LawfulOrderSup (α : Type u) [Max α] [LE α] where
|
||||
max_le_iff : ∀ a b c : α, (max a b) ≤ c ↔ a ≤ c ∧ b ≤ c
|
||||
|
||||
/--
|
||||
This typeclass bundles `MaxEqOr α` and `LawfulOrderSup α`. It characterizes when a `Max α`
|
||||
instance reasonably computes maxima in some type `α` that has an `LE α` instance.
|
||||
|
||||
As long as `α` is a preorder (see `IsPreorder α`), this typeclass implies that the order on
|
||||
`α` is total and that `Min.min a b` returns either `a` or `b`, whichever is greater or equal to
|
||||
the other.
|
||||
-/
|
||||
public class LawfulOrderMax (α : Type u) [Max α] [LE α] extends MaxEqOr α, LawfulOrderSup α
|
||||
|
||||
/--
|
||||
This typeclass states that `max a b = if b ≤ a then a else b` (for any `DecidableLE α` instance).
|
||||
-/
|
||||
public class LawfulOrderLeftLeaningMax (α : Type u) [Max α] [LE α] where
|
||||
max_eq_left : ∀ a b : α, b ≤ a → max a b = a
|
||||
max_eq_right : ∀ a b : α, ¬ b ≤ a → max a b = b
|
||||
|
||||
end Max
|
||||
|
||||
end Std
|
||||
39
src/Init/Data/Order/ClassesExtra.lean
Normal file
39
src/Init/Data/Order/ClassesExtra.lean
Normal file
@@ -0,0 +1,39 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Order.Classes
|
||||
public import Init.Data.Ord.Basic
|
||||
|
||||
namespace Std
|
||||
|
||||
/--
|
||||
This typeclass states that the synthesized `Ord α` instance is compatible with the `LE α`
|
||||
instance. This means that according to `compare`, the following are equivalent:
|
||||
|
||||
* `a` is less than or equal to `b` according to `compare`.
|
||||
* `b` is greater than or equal to `b` according to `compare`.
|
||||
* `a ≤ b` holds.
|
||||
|
||||
`LawfulOrderOrd α` automatically entails that `Ord α` is oriented (see `OrientedOrd α`)
|
||||
and that `LE α` is total.
|
||||
|
||||
`Ord α` and `LE α` mutually determine each other in the presence of `LawfulOrderOrd α`.
|
||||
-/
|
||||
public class LawfulOrderOrd (α : Type u) [Ord α] [LE α] where
|
||||
isLE_compare : ∀ a b : α, (compare a b).isLE ↔ a ≤ b
|
||||
isGE_compare : ∀ a b : α, (compare a b).isGE ↔ b ≤ a
|
||||
|
||||
public theorem LawfulOrderOrd.isLE_compare_eq_false {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α] {a b : α} :
|
||||
(compare a b).isLE = false ↔ ¬ a ≤ b := by
|
||||
simp [← isLE_compare]
|
||||
|
||||
public theorem LawfulOrderOrd.isGE_compare_eq_false {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α] {a b : α} :
|
||||
(compare a b).isGE = false ↔ ¬ b ≤ a := by
|
||||
simp [← isGE_compare]
|
||||
|
||||
end Std
|
||||
240
src/Init/Data/Order/Factories.lean
Normal file
240
src/Init/Data/Order/Factories.lean
Normal file
@@ -0,0 +1,240 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Order.Classes
|
||||
import Init.Classical
|
||||
|
||||
namespace Std
|
||||
|
||||
/-!
|
||||
This module provides utilities for the creation of order-related typeclass instances.
|
||||
-/
|
||||
|
||||
section OfLE
|
||||
|
||||
/--
|
||||
This instance is only publicly defined in `Init.Data.Order.Lemmas`.
|
||||
-/
|
||||
instance {r : α → α → Prop} [Total r] : Refl r where
|
||||
refl a := by simpa using Total.total a a
|
||||
|
||||
/--
|
||||
If an `LE α` instance is reflexive and transitive, then it represents a preorder.
|
||||
-/
|
||||
public theorem IsPreorder.of_le {α : Type u} [LE α]
|
||||
(le_refl : Std.Refl (α := α) (· ≤ ·) := by exact inferInstance)
|
||||
(le_trans : Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·) := by exact inferInstance) :
|
||||
IsPreorder α where
|
||||
le_refl := le_refl.refl
|
||||
le_trans _ _ _ := le_trans.trans
|
||||
|
||||
/--
|
||||
If an `LE α` instance is transitive and total, then it represents a linear preorder.
|
||||
-/
|
||||
public theorem IsLinearPreorder.of_le {α : Type u} [LE α]
|
||||
(le_trans : Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·) := by exact inferInstance)
|
||||
(le_total : Total (α := α) (· ≤ ·) := by exact inferInstance) :
|
||||
IsLinearPreorder α where
|
||||
toIsPreorder := .of_le
|
||||
le_total := le_total.total
|
||||
|
||||
/--
|
||||
If an `LE α` is reflexive, antisymmetric and transitive, then it represents a partial order.
|
||||
-/
|
||||
public theorem IsPartialOrder.of_le {α : Type u} [LE α]
|
||||
(le_refl : Std.Refl (α := α) (· ≤ ·) := by exact inferInstance)
|
||||
(le_antisymm : Std.Antisymm (α := α) (· ≤ ·) := by exact inferInstance)
|
||||
(le_trans : Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·) := by exact inferInstance) :
|
||||
IsPartialOrder α where
|
||||
toIsPreorder := .of_le
|
||||
le_antisymm := le_antisymm.antisymm
|
||||
|
||||
/--
|
||||
If an `LE α` instance is antisymmetric, transitive and total, then it represents a linear order.
|
||||
-/
|
||||
public theorem IsLinearOrder.of_le {α : Type u} [LE α]
|
||||
(le_antisymm : Std.Antisymm (α := α) (· ≤ ·) := by exact inferInstance)
|
||||
(le_trans : Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·) := by exact inferInstance)
|
||||
(le_total : Total (α := α) (· ≤ ·) := by exact inferInstance) :
|
||||
IsLinearOrder α where
|
||||
toIsLinearPreorder := .of_le
|
||||
le_antisymm := le_antisymm.antisymm
|
||||
|
||||
/--
|
||||
This lemma derives a `LawfulOrderLT α` instance from a property involving an `LE α` instance.
|
||||
-/
|
||||
public theorem LawfulOrderLT.of_le {α : Type u} [LT α] [LE α]
|
||||
(lt_iff : ∀ a b : α, a < b ↔ a ≤ b ∧ ¬ b ≤ a) : LawfulOrderLT α where
|
||||
lt_iff := lt_iff
|
||||
|
||||
/--
|
||||
This lemma derives a `LawfulOrderBEq α` instance from a property involving an `LE α` instance.
|
||||
-/
|
||||
public theorem LawfulOrderBEq.of_le {α : Type u} [BEq α] [LE α]
|
||||
(beq_iff : ∀ a b : α, a == b ↔ a ≤ b ∧ b ≤ a) : LawfulOrderBEq α where
|
||||
beq_iff_le_and_ge := by simp [beq_iff]
|
||||
|
||||
/--
|
||||
This lemma characterizes in terms of `LE α` when a `Min α` instance "behaves like an infimum
|
||||
operator".
|
||||
-/
|
||||
public theorem LawfulOrderInf.of_le {α : Type u} [Min α] [LE α]
|
||||
(le_min_iff : ∀ a b c : α, a ≤ min b c ↔ a ≤ b ∧ a ≤ c) : LawfulOrderInf α where
|
||||
le_min_iff := le_min_iff
|
||||
|
||||
/--
|
||||
Returns a `LawfulOrderMin α` instance given certain properties.
|
||||
|
||||
This lemma derives a `LawfulOrderMin α` instance from two properties involving `LE α` and `Min α`
|
||||
instances.
|
||||
|
||||
The produced instance entails `LawfulOrderInf α` and `MinEqOr α`.
|
||||
-/
|
||||
public theorem LawfulOrderMin.of_le {α : Type u} [Min α] [LE α]
|
||||
(le_min_iff : ∀ a b c : α, a ≤ min b c ↔ a ≤ b ∧ a ≤ c)
|
||||
(min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b) : LawfulOrderMin α where
|
||||
toLawfulOrderInf := .of_le le_min_iff
|
||||
toMinEqOr := ⟨min_eq_or⟩
|
||||
|
||||
/--
|
||||
This lemma characterizes in terms of `LE α` when a `Max α` instance "behaves like a supremum
|
||||
operator".
|
||||
-/
|
||||
public def LawfulOrderSup.of_le {α : Type u} [Max α] [LE α]
|
||||
(max_le_iff : ∀ a b c : α, max a b ≤ c ↔ a ≤ c ∧ b ≤ c) : LawfulOrderSup α where
|
||||
max_le_iff := max_le_iff
|
||||
|
||||
/--
|
||||
Returns a `LawfulOrderMax α` instance given certain properties.
|
||||
|
||||
This lemma derives a `LawfulOrderMax α` instance from two properties involving `LE α` and `Max α`
|
||||
instances.
|
||||
|
||||
The produced instance entails `LawfulOrderSup α` and `MaxEqOr α`.
|
||||
-/
|
||||
public def LawfulOrderMax.of_le {α : Type u} [Max α] [LE α]
|
||||
(max_le_iff : ∀ a b c : α, max a b ≤ c ↔ a ≤ c ∧ b ≤ c)
|
||||
(max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b) : LawfulOrderMax α where
|
||||
toLawfulOrderSup := .of_le max_le_iff
|
||||
toMaxEqOr := ⟨max_eq_or⟩
|
||||
|
||||
end OfLE
|
||||
|
||||
section OfLT
|
||||
|
||||
/--
|
||||
Creates a *total* `LE α` instance from an `LT α` instance.
|
||||
|
||||
This only makes sense for asymmetric `LT α` instances (see `Std.Asymm`).
|
||||
-/
|
||||
public def LE.ofLT (α : Type u) [LT α] : LE α where
|
||||
le a b := ¬ b < a
|
||||
|
||||
/--
|
||||
The `LE α` instance obtained from an asymmetric `LT α` instance is compatible with said
|
||||
`LT α` instance.
|
||||
-/
|
||||
public instance LawfulOrderLT.of_lt {α : Type u} [LT α] [i : Asymm (α := α) (· < ·)] :
|
||||
haveI := LE.ofLT α
|
||||
LawfulOrderLT α :=
|
||||
letI := LE.ofLT α
|
||||
{ lt_iff a b := by simpa [LE.ofLT, Classical.not_not] using i.asymm a b }
|
||||
|
||||
/--
|
||||
If an `LT α` instance is asymmetric and its negation is transitive, then `LE.ofLT α` represents a
|
||||
linear preorder.
|
||||
-/
|
||||
public theorem IsLinearPreorder.of_lt {α : Type u} [LT α]
|
||||
(lt_asymm : Asymm (α := α) (· < ·) := by exact inferInstance)
|
||||
(not_lt_trans : Trans (α := α) (¬ · < ·) (¬ · < ·) (¬ · < ·) := by exact inferInstance) :
|
||||
haveI := LE.ofLT α
|
||||
IsLinearPreorder α :=
|
||||
letI := LE.ofLT α
|
||||
{ le_trans := by simpa [LE.ofLT] using fun a b c hab hbc => not_lt_trans.trans hbc hab
|
||||
le_total a b := by
|
||||
apply Or.symm
|
||||
open Classical in simpa [LE.ofLT, Decidable.imp_iff_not_or] using lt_asymm.asymm a b
|
||||
le_refl a := by
|
||||
open Classical in simpa [LE.ofLT] using lt_asymm.asymm a a }
|
||||
|
||||
/--
|
||||
If an `LT α` instance is asymmetric and its negation is transitive and antisymmetric, then
|
||||
`LE.ofLT α` represents a linear order.
|
||||
-/
|
||||
public theorem IsLinearOrder.of_lt {α : Type u} [LT α]
|
||||
(lt_asymm : Asymm (α := α) (· < ·) := by exact inferInstance)
|
||||
(not_lt_trans : Trans (α := α) (¬ · < ·) (¬ · < ·) (¬ · < ·) := by exact inferInstance)
|
||||
(not_lt_antisymm : Antisymm (α := α) (¬ · < ·) := by exact inferInstance) :
|
||||
haveI := LE.ofLT α
|
||||
IsLinearOrder α :=
|
||||
letI := LE.ofLT α
|
||||
haveI : IsLinearPreorder α := .of_lt
|
||||
{ le_antisymm := by
|
||||
simpa [LE.ofLT] using fun a b hab hba => not_lt_antisymm.antisymm a b hba hab }
|
||||
|
||||
/--
|
||||
This lemma characterizes in terms of `LT α` when a `Min α` instance
|
||||
"behaves like an infimum operator" with respect to `LE.ofLT α`.
|
||||
-/
|
||||
public theorem LawfulOrderInf.of_lt {α : Type u} [Min α] [LT α]
|
||||
(min_lt_iff : ∀ a b c : α, min b c < a ↔ b < a ∨ c < a) :
|
||||
haveI := LE.ofLT α
|
||||
LawfulOrderInf α :=
|
||||
letI := LE.ofLT α
|
||||
{ le_min_iff a b c := by
|
||||
open Classical in
|
||||
simp only [LE.ofLT, ← Decidable.not_iff_not (a := ¬ min b c < a)]
|
||||
simpa [Decidable.imp_iff_not_or] using min_lt_iff a b c }
|
||||
|
||||
/--
|
||||
Derives a `LawfulOrderMin α` instance for `LE.ofLT` from two properties involving
|
||||
`LT α` and `Min α` instances.
|
||||
|
||||
The produced instance entails `LawfulOrderInf α` and `MinEqOr α`.
|
||||
-/
|
||||
public theorem LawfulOrderMin.of_lt {α : Type u} [Min α] [LT α]
|
||||
(min_lt_iff : ∀ a b c : α, min b c < a ↔ b < a ∨ c < a)
|
||||
(min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b) :
|
||||
haveI := LE.ofLT α
|
||||
LawfulOrderMin α :=
|
||||
letI := LE.ofLT α
|
||||
{ toLawfulOrderInf := .of_lt min_lt_iff
|
||||
toMinEqOr := ⟨min_eq_or⟩ }
|
||||
|
||||
/--
|
||||
This lemma characterizes in terms of `LT α` when a `Max α` instance
|
||||
"behaves like an supremum operator" with respect to `LE.ofLT α`.
|
||||
-/
|
||||
public def LawfulOrderSup.of_lt {α : Type u} [Max α] [LT α]
|
||||
(lt_max_iff : ∀ a b c : α, c < max a b ↔ c < a ∨ c < b) :
|
||||
haveI := LE.ofLT α
|
||||
LawfulOrderSup α :=
|
||||
letI := LE.ofLT α
|
||||
{ max_le_iff a b c := by
|
||||
open Classical in
|
||||
simp only [LE.ofLT, ← Decidable.not_iff_not ( a := ¬ c < max a b)]
|
||||
simpa [Decidable.imp_iff_not_or] using lt_max_iff a b c }
|
||||
|
||||
/--
|
||||
Derives a `LawfulOrderMax α` instance for `LE.ofLT` from two properties involving `LT α` and
|
||||
`Max α` instances.
|
||||
|
||||
The produced instance entails `LawfulOrderSup α` and `MaxEqOr α`.
|
||||
-/
|
||||
public def LawfulOrderMax.of_lt {α : Type u} [Max α] [LT α]
|
||||
(lt_max_iff : ∀ a b c : α, c < max a b ↔ c < a ∨ c < b)
|
||||
(max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b) :
|
||||
haveI := LE.ofLT α
|
||||
LawfulOrderMax α :=
|
||||
letI := LE.ofLT α
|
||||
{ toLawfulOrderSup := .of_lt lt_max_iff
|
||||
toMaxEqOr := ⟨max_eq_or⟩ }
|
||||
|
||||
end OfLT
|
||||
|
||||
end Std
|
||||
122
src/Init/Data/Order/FactoriesExtra.lean
Normal file
122
src/Init/Data/Order/FactoriesExtra.lean
Normal file
@@ -0,0 +1,122 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Order.ClassesExtra
|
||||
public import Init.Data.Order.Ord
|
||||
|
||||
namespace Std
|
||||
|
||||
/--
|
||||
Creates an `LE α` instance from an `Ord α` instance.
|
||||
|
||||
`OrientedOrd α` must be satisfied so that the resulting `LE α` instance faithfully represents
|
||||
the `Ord α` instance.
|
||||
-/
|
||||
@[inline, expose]
|
||||
public def _root_.LE.ofOrd (α : Type u) [Ord α] : LE α where
|
||||
le a b := (compare a b).isLE
|
||||
|
||||
/--
|
||||
Creates an `DecidableLE α` instance using a well-behaved `Ord α` instance.
|
||||
-/
|
||||
@[inline, expose]
|
||||
public def _root_.DecidableLE.ofOrd (α : Type u) [LE α] [Ord α] [LawfulOrderOrd α] :
|
||||
DecidableLE α :=
|
||||
fun a b => match h : (compare a b).isLE with
|
||||
| true => isTrue (by simpa only [LawfulOrderOrd.isLE_compare] using h)
|
||||
| false => isFalse (by simpa only [LawfulOrderOrd.isLE_compare_eq_false] using h)
|
||||
|
||||
/--
|
||||
Creates an `LT α` instance from an `Ord α` instance.
|
||||
|
||||
`OrientedOrd α` must be satisfied so that the resulting `LT α` instance faithfully represents
|
||||
the `Ord α` instance.
|
||||
-/
|
||||
@[inline, expose]
|
||||
public def _root_.LT.ofOrd (α : Type u) [Ord α] :
|
||||
LT α where
|
||||
lt a b := compare a b = .lt
|
||||
|
||||
public theorem isLE_compare {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α]
|
||||
{a b : α} : (compare a b).isLE ↔ a ≤ b := by
|
||||
simp [← LawfulOrderOrd.isLE_compare]
|
||||
|
||||
public theorem isGE_compare {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α]
|
||||
{a b : α} : (compare a b).isGE ↔ b ≤ a := by
|
||||
simp [← LawfulOrderOrd.isGE_compare]
|
||||
|
||||
-- We need to define `compare_eq_lt` and `compare_eq_gt` here instead of in `LemmasExtra.lean`
|
||||
-- because they are needed for `DecidableLT.ofOrd`.
|
||||
public theorem compare_eq_lt {α : Type u} [Ord α] [LT α] [LE α] [LawfulOrderOrd α] [LawfulOrderLT α]
|
||||
{a b : α} : compare a b = .lt ↔ a < b := by
|
||||
rw [LawfulOrderLT.lt_iff, ← LawfulOrderOrd.isLE_compare, ← LawfulOrderOrd.isGE_compare]
|
||||
cases compare a b <;> simp
|
||||
|
||||
public theorem compare_eq_gt {α : Type u} [Ord α] [LT α] [LE α] [LawfulOrderOrd α] [LawfulOrderLT α]
|
||||
{a b : α} : compare a b = .gt ↔ b < a := by
|
||||
rw [LawfulOrderLT.lt_iff, ← LawfulOrderOrd.isGE_compare, ← LawfulOrderOrd.isLE_compare]
|
||||
cases compare a b <;> simp
|
||||
|
||||
public theorem compare_eq_eq {α : Type u} [Ord α] [BEq α] [LE α] [LawfulOrderOrd α] [LawfulOrderBEq α]
|
||||
{a b : α} : compare a b = .eq ↔ a == b := by
|
||||
open Classical.Order in
|
||||
rw [LawfulOrderBEq.beq_iff_le_and_ge, ← isLE_compare, ← isGE_compare]
|
||||
cases compare a b <;> simp
|
||||
|
||||
/--
|
||||
Creates a `DecidableLT α` instance using a well-behaved `Ord α` instance.
|
||||
-/
|
||||
@[inline, expose]
|
||||
public def _root_.DecidableLT.ofOrd (α : Type u) [LE α] [LT α] [Ord α] [LawfulOrderOrd α]
|
||||
[LawfulOrderLT α] :
|
||||
DecidableLT α :=
|
||||
fun a b => if h : compare a b = .lt then
|
||||
isTrue (by simpa only [compare_eq_lt] using h)
|
||||
else
|
||||
isFalse (by simpa only [compare_eq_lt] using h)
|
||||
|
||||
/--
|
||||
Creates a `BEq α` instance from an `Ord α` instance. -/
|
||||
@[inline, expose]
|
||||
public def _root_.BEq.ofOrd (α : Type u) [Ord α] :
|
||||
BEq α where
|
||||
beq a b := compare a b = .eq
|
||||
|
||||
/--
|
||||
The `LE α` instance obtained from an `Ord α` instance is compatible with said `Ord α`
|
||||
instance if `compare` is oriented, i.e., `compare a b = .lt ↔ compare b a = .gt`.
|
||||
-/
|
||||
public instance instLawfulOrderOrd_ofOrd (α : Type u) [Ord α] [OrientedOrd α] :
|
||||
haveI := LE.ofOrd α
|
||||
LawfulOrderOrd α :=
|
||||
letI := LE.ofOrd α
|
||||
{ isLE_compare := by simp [LE.ofOrd]
|
||||
isGE_compare := by simp [LE.ofOrd, OrientedCmp.isGE_eq_isLE] }
|
||||
|
||||
attribute [local instance] LT.ofOrd in
|
||||
/--
|
||||
The `LT α` instance obtained from an `Ord α` instance is compatible with the `LE α` instance
|
||||
instance if `Ord α` is compatible with it.
|
||||
-/
|
||||
public instance instLawfulOrderLT_ofOrd {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α] :
|
||||
LawfulOrderLT α where
|
||||
lt_iff {a b} := by
|
||||
simp +contextual [LT.lt, ← Std.isLE_compare (a := a), ← Std.isGE_compare (a := a)]
|
||||
|
||||
attribute [local instance] BEq.ofOrd in
|
||||
/--
|
||||
The `BEq α` instance obtained from an `Ord α` instance is compatible with the `LE α` instance
|
||||
instance if `Ord α` is compatible with it.
|
||||
-/
|
||||
public instance instLawfulOrderBEq_ofOrd {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α] :
|
||||
LawfulOrderBEq α where
|
||||
beq_iff_le_and_ge {a b} := by
|
||||
simp +contextual [BEq.beq, ← Std.isLE_compare (a := a), ← Std.isGE_compare (a := a),
|
||||
Ordering.eq_eq_iff_isLE_and_isGE]
|
||||
|
||||
end Std
|
||||
406
src/Init/Data/Order/Lemmas.lean
Normal file
406
src/Init/Data/Order/Lemmas.lean
Normal file
@@ -0,0 +1,406 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Order.Classes
|
||||
public import Init.Data.Order.Factories
|
||||
import Init.SimpLemmas
|
||||
public import Init.Classical
|
||||
public import Init.Data.BEq
|
||||
|
||||
namespace Std
|
||||
|
||||
/-!
|
||||
This module provides typeclass instances and lemmas about order-related typeclasses.
|
||||
-/
|
||||
|
||||
section AxiomaticInstances
|
||||
|
||||
public instance (r : α → α → Prop) [Asymm r] : Irrefl r where
|
||||
irrefl a h := Asymm.asymm a a h h
|
||||
|
||||
public instance {r : α → α → Prop} [Total r] : Refl r where
|
||||
refl a := by simpa using Total.total a a
|
||||
|
||||
public instance Total.asymm_of_total_not {r : α → α → Prop} [i : Total (¬ r · ·)] : Asymm r where
|
||||
asymm a b h := by cases i.total a b <;> trivial
|
||||
|
||||
public theorem Asymm.total_not {r : α → α → Prop} [i : Asymm r] : Total (¬ r · ·) where
|
||||
total a b := by
|
||||
apply Classical.byCases (p := r a b) <;> intro hab
|
||||
· exact Or.inr <| i.asymm a b hab
|
||||
· exact Or.inl hab
|
||||
|
||||
public instance {α : Type u} [LE α] [IsPartialOrder α] :
|
||||
Antisymm (α := α) (· ≤ ·) where
|
||||
antisymm := IsPartialOrder.le_antisymm
|
||||
|
||||
public instance {α : Type u} [LE α] [IsPreorder α] :
|
||||
Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·) where
|
||||
trans := IsPreorder.le_trans _ _ _
|
||||
|
||||
public instance {α : Type u} [LE α] [IsPreorder α] :
|
||||
Refl (α := α) (· ≤ ·) where
|
||||
refl := IsPreorder.le_refl
|
||||
|
||||
public instance {α : Type u} [LE α] [IsLinearPreorder α] :
|
||||
Total (α := α) (· ≤ ·) where
|
||||
total := IsLinearPreorder.le_total
|
||||
|
||||
end AxiomaticInstances
|
||||
|
||||
section LE
|
||||
|
||||
public theorem le_refl {α : Type u} [LE α] [Refl (α := α) (· ≤ ·)] (a : α) : a ≤ a := by
|
||||
simp [Refl.refl]
|
||||
|
||||
public theorem le_antisymm {α : Type u} [LE α] [Std.Antisymm (α := α) (· ≤ ·)] {a b : α}
|
||||
(hab : a ≤ b) (hba : b ≤ a) : a = b :=
|
||||
Antisymm.antisymm _ _ hab hba
|
||||
|
||||
public theorem le_antisymm_iff {α : Type u} [LE α] [Antisymm (α := α) (· ≤ ·)]
|
||||
[Refl (α := α) (· ≤ ·)] {a b : α} : a ≤ b ∧ b ≤ a ↔ a = b :=
|
||||
⟨fun | ⟨hab, hba⟩ => le_antisymm hab hba, by simp +contextual [le_refl]⟩
|
||||
|
||||
public theorem le_trans {α : Type u} [LE α] [Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·)] {a b c : α}
|
||||
(hab : a ≤ b) (hbc : b ≤ c) : a ≤ c :=
|
||||
Trans.trans hab hbc
|
||||
|
||||
public theorem le_total {α : Type u} [LE α] [Std.Total (α := α) (· ≤ ·)] {a b : α} :
|
||||
a ≤ b ∨ b ≤ a :=
|
||||
Std.Total.total a b
|
||||
|
||||
public theorem le_of_not_ge {α : Type u} [LE α] [Std.Total (α := α) (· ≤ ·)] {a b : α} :
|
||||
¬ b ≤ a → a ≤ b := by
|
||||
intro h
|
||||
simpa [h] using Std.Total.total a b (r := (· ≤ ·))
|
||||
|
||||
end LE
|
||||
|
||||
section LT
|
||||
|
||||
public theorem lt_iff_le_and_not_ge {α : Type u} [LT α] [LE α] [LawfulOrderLT α] {a b : α} :
|
||||
a < b ↔ a ≤ b ∧ ¬ b ≤ a :=
|
||||
LawfulOrderLT.lt_iff a b
|
||||
|
||||
public theorem not_lt {α : Type u} [LT α] [LE α] [Std.Total (α := α) (· ≤ ·)] [LawfulOrderLT α]
|
||||
{a b : α} : ¬ a < b ↔ b ≤ a := by
|
||||
simp [lt_iff_le_and_not_ge, Classical.not_not, Std.Total.total]
|
||||
|
||||
public theorem not_gt_of_lt {α : Type u} [LT α] [i : Std.Asymm (α := α) (· < ·)] {a b : α}
|
||||
(h : a < b) : ¬ b < a :=
|
||||
i.asymm a b h
|
||||
|
||||
public instance {α : Type u} [LT α] [LE α] [LawfulOrderLT α] :
|
||||
Std.Asymm (α := α) (· < ·) where
|
||||
asymm a b := by
|
||||
simp only [LawfulOrderLT.lt_iff]
|
||||
intro h h'
|
||||
exact h.2.elim h'.1
|
||||
|
||||
public instance {α : Type u} [LT α] [LE α] [IsPreorder α] [LawfulOrderLT α] :
|
||||
Std.Irrefl (α := α) (· < ·) := inferInstance
|
||||
|
||||
public instance {α : Type u} [LT α] [LE α] [Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·) ]
|
||||
[LawfulOrderLT α] : Trans (α := α) (· < ·) (· < ·) (· < ·) where
|
||||
trans {a b c} hab hbc := by
|
||||
simp only [lt_iff_le_and_not_ge] at hab hbc ⊢
|
||||
apply And.intro
|
||||
· exact le_trans hab.1 hbc.1
|
||||
· intro hca
|
||||
exact hab.2.elim (le_trans hbc.1 hca)
|
||||
|
||||
public instance {α : Type u} {_ : LT α} [LE α] [LawfulOrderLT α]
|
||||
[Total (α := α) (· ≤ ·)] [Antisymm (α := α) (· ≤ ·)] :
|
||||
Antisymm (α := α) (¬ · < ·) where
|
||||
antisymm a b hab hba := by
|
||||
simp only [not_lt] at hab hba
|
||||
exact Antisymm.antisymm (r := (· ≤ ·)) a b hba hab
|
||||
|
||||
public instance {α : Type u} {_ : LT α} [LE α] [LawfulOrderLT α]
|
||||
[Total (α := α) (· ≤ ·)] [Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·)] :
|
||||
Trans (α := α) (¬ · < ·) (¬ · < ·) (¬ · < ·) where
|
||||
trans {a b c} hab hbc := by
|
||||
simp only [not_lt] at hab hbc ⊢
|
||||
exact le_trans hbc hab
|
||||
|
||||
public instance {α : Type u} {_ : LT α} [LE α] [LawfulOrderLT α] [Total (α := α) (· ≤ ·)] :
|
||||
Total (α := α) (¬ · < ·) where
|
||||
total a b := by simp [not_lt, Std.Total.total]
|
||||
|
||||
public theorem lt_of_le_of_lt {α : Type u} [LE α] [LT α]
|
||||
[Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·)] [LawfulOrderLT α] {a b c : α} (hab : a ≤ b)
|
||||
(hbc : b < c) : a < c := by
|
||||
simp only [lt_iff_le_and_not_ge] at hbc ⊢
|
||||
apply And.intro
|
||||
· exact le_trans hab hbc.1
|
||||
· intro hca
|
||||
exact hbc.2.elim (le_trans hca hab)
|
||||
|
||||
public theorem lt_of_le_of_ne {α : Type u} [LE α] [LT α]
|
||||
[Std.Antisymm (α := α) (· ≤ ·)] [LawfulOrderLT α] {a b : α}
|
||||
(hle : a ≤ b) (hne : a ≠ b) : a < b := by
|
||||
apply Classical.byContradiction
|
||||
simp only [lt_iff_le_and_not_ge, hle, true_and, Classical.not_not, imp_false]
|
||||
intro hge
|
||||
exact hne.elim <| Std.Antisymm.antisymm a b hle hge
|
||||
|
||||
end LT
|
||||
end Std
|
||||
|
||||
namespace Classical.Order
|
||||
open Std
|
||||
|
||||
public scoped instance instLT {α : Type u} [LE α] :
|
||||
LT α where
|
||||
lt a b := a ≤ b ∧ ¬ b ≤ a
|
||||
|
||||
public instance instLawfulOrderLT {α : Type u} [LE α] :
|
||||
LawfulOrderLT α where
|
||||
lt_iff _ _ := Iff.rfl
|
||||
|
||||
end Classical.Order
|
||||
|
||||
namespace Std
|
||||
section BEq
|
||||
|
||||
public theorem beq_iff_le_and_ge {α : Type u} [BEq α] [LE α] [LawfulOrderBEq α]
|
||||
{a b : α} : a == b ↔ a ≤ b ∧ b ≤ a := by
|
||||
simp [LawfulOrderBEq.beq_iff_le_and_ge]
|
||||
|
||||
public instance {α : Type u} [BEq α] [LE α] [LawfulOrderBEq α] :
|
||||
Symm (α := α) (· == ·) where
|
||||
symm := by simp_all [beq_iff_le_and_ge]
|
||||
|
||||
public instance {α : Type u} [BEq α] [LE α] [LawfulOrderBEq α] [IsPreorder α] : EquivBEq α where
|
||||
rfl := by simp [beq_iff_le_and_ge, le_refl]
|
||||
symm := Symm.symm (r := (· == ·)) _ _
|
||||
trans hab hbc := by
|
||||
simp only [beq_iff_le_and_ge] at hab hbc ⊢
|
||||
exact ⟨le_trans hab.1 hbc.1, le_trans hbc.2 hab.2⟩
|
||||
|
||||
public instance {α : Type u} [BEq α] [LE α] [LawfulOrderBEq α] [IsPartialOrder α] :
|
||||
LawfulBEq α where
|
||||
eq_of_beq := by
|
||||
simp only [beq_iff_le_and_ge, and_imp]
|
||||
apply le_antisymm
|
||||
|
||||
end BEq
|
||||
end Std
|
||||
|
||||
namespace Classical.Order
|
||||
open Std
|
||||
|
||||
public noncomputable scoped instance instBEq {α : Type u} [LE α] : BEq α where
|
||||
beq a b := a ≤ b ∧ b ≤ a
|
||||
|
||||
public instance instLawfulOrderBEq {α : Type u} [LE α] :
|
||||
LawfulOrderBEq α where
|
||||
beq_iff_le_and_ge a b := by simp [BEq.beq]
|
||||
|
||||
end Classical.Order
|
||||
|
||||
namespace Std
|
||||
section Min
|
||||
|
||||
public theorem min_self {α : Type u} [Min α] [Std.IdempotentOp (min : α → α → α)] {a : α} :
|
||||
min a a = a :=
|
||||
Std.IdempotentOp.idempotent a
|
||||
|
||||
public theorem le_min_iff {α : Type u} [Min α] [LE α]
|
||||
[LawfulOrderInf α] {a b c : α} :
|
||||
a ≤ min b c ↔ a ≤ b ∧ a ≤ c :=
|
||||
LawfulOrderInf.le_min_iff a b c
|
||||
|
||||
public theorem min_le_left {α : Type u} [Min α] [LE α] [Refl (α := α) (· ≤ ·)] [LawfulOrderInf α]
|
||||
{a b : α} : min a b ≤ a :=
|
||||
le_min_iff.mp (le_refl _) |>.1
|
||||
|
||||
public theorem min_le_right {α : Type u} [Min α] [LE α] [Refl (α := α) (· ≤ ·)] [LawfulOrderInf α]
|
||||
{a b : α} : min a b ≤ b :=
|
||||
le_min_iff.mp (le_refl _) |>.2
|
||||
|
||||
public theorem min_le {α : Type u} [Min α] [LE α] [IsPreorder α] [LawfulOrderMin α] {a b c : α} :
|
||||
min a b ≤ c ↔ a ≤ c ∨ b ≤ c := by
|
||||
cases MinEqOr.min_eq_or a b <;> rename_i h
|
||||
· simpa [h] using le_trans (h ▸ min_le_right (a := a) (b := b))
|
||||
· simpa [h] using le_trans (h ▸ min_le_left (a := a) (b := b))
|
||||
|
||||
public theorem min_eq_or {α : Type u} [Min α] [MinEqOr α] {a b : α} :
|
||||
min a b = a ∨ min a b = b :=
|
||||
MinEqOr.min_eq_or a b
|
||||
|
||||
public instance {α : Type u} [LE α] [Min α] [IsLinearOrder α] [LawfulOrderInf α] :
|
||||
MinEqOr α where
|
||||
min_eq_or a b := by
|
||||
cases le_total (a := a) (b := b)
|
||||
· apply Or.inl
|
||||
apply le_antisymm
|
||||
· apply min_le_left
|
||||
· rw [le_min_iff]
|
||||
exact ⟨le_refl a, ‹_›⟩
|
||||
· apply Or.inr
|
||||
apply le_antisymm
|
||||
· apply min_le_right
|
||||
· rw [le_min_iff]
|
||||
exact ⟨‹_›, le_refl b⟩
|
||||
|
||||
/--
|
||||
If a `Min α` instance satisfies typical properties in terms of a reflexive and antisymmetric `LE α`
|
||||
instance, then the `LE α` instance represents a linear order.
|
||||
-/
|
||||
public theorem IsLinearOrder.of_refl_of_antisymm_of_lawfulOrderMin {α : Type u} [LE α]
|
||||
[LE α] [Min α] [Refl (α := α) (· ≤ ·)] [Antisymm (α := α) (· ≤ ·)] [LawfulOrderMin α] :
|
||||
IsLinearOrder α := by
|
||||
apply IsLinearOrder.of_le
|
||||
· infer_instance
|
||||
· constructor
|
||||
intro a b c hab hbc
|
||||
have : b = min b c := by
|
||||
apply le_antisymm
|
||||
· rw [le_min_iff]
|
||||
exact ⟨le_refl b, hbc⟩
|
||||
· apply min_le_left
|
||||
rw [this, le_min_iff] at hab
|
||||
exact hab.2
|
||||
· constructor
|
||||
intro a b
|
||||
cases min_eq_or (a := a) (b := b) <;> rename_i h
|
||||
· exact Or.inl (h ▸ min_le_right)
|
||||
· exact Or.inr (h ▸ min_le_left)
|
||||
|
||||
public instance {α : Type u} [Min α] [MinEqOr α] :
|
||||
Std.IdempotentOp (min : α → α → α) where
|
||||
idempotent a := by cases MinEqOr.min_eq_or a a <;> assumption
|
||||
|
||||
public instance {α : Type u} [LE α] [Min α] [IsLinearOrder α] [LawfulOrderMin α] :
|
||||
Std.Associative (min : α → α → α) where
|
||||
assoc a b c := by apply le_antisymm <;> simp [min_le, le_min_iff, le_refl]
|
||||
|
||||
public theorem min_eq_if {α : Type u} [LE α] [DecidableLE α] {_ : Min α}
|
||||
[LawfulOrderLeftLeaningMin α] {a b : α} :
|
||||
min a b = if a ≤ b then a else b := by
|
||||
split <;> rename_i h
|
||||
· simp [LawfulOrderLeftLeaningMin.min_eq_left _ _ h]
|
||||
· simp [LawfulOrderLeftLeaningMin.min_eq_right _ _ h]
|
||||
|
||||
public theorem max_eq_if {α : Type u} [LE α] [DecidableLE α] {_ : Max α}
|
||||
[LawfulOrderLeftLeaningMax α] {a b : α} :
|
||||
max a b = if b ≤ a then a else b := by
|
||||
split <;> rename_i h
|
||||
· simp [LawfulOrderLeftLeaningMax.max_eq_left _ _ h]
|
||||
· simp [LawfulOrderLeftLeaningMax.max_eq_right _ _ h]
|
||||
|
||||
public instance {α : Type u} [LE α] [Min α] [IsLinearOrder α] [LawfulOrderInf α] :
|
||||
LawfulOrderLeftLeaningMin α where
|
||||
min_eq_left a b hab := by
|
||||
apply le_antisymm
|
||||
· apply min_le_left
|
||||
· simp [le_min_iff, le_refl, hab]
|
||||
min_eq_right a b hab := by
|
||||
apply le_antisymm
|
||||
· apply min_le_right
|
||||
· simp [le_min_iff, le_refl, le_of_not_ge hab]
|
||||
|
||||
end Min
|
||||
|
||||
section Max
|
||||
|
||||
public theorem max_self {α : Type u} [Max α] [Std.IdempotentOp (max : α → α → α)] {a : α} :
|
||||
max a a = a :=
|
||||
Std.IdempotentOp.idempotent a
|
||||
|
||||
public theorem max_le_iff {α : Type u} [Max α] [LE α] [LawfulOrderSup α] {a b c : α} :
|
||||
max a b ≤ c ↔ a ≤ c ∧ b ≤ c :=
|
||||
LawfulOrderSup.max_le_iff a b c
|
||||
|
||||
public theorem left_le_max {α : Type u} [Max α] [LE α] [Refl (α := α) (· ≤ ·)] [LawfulOrderSup α]
|
||||
{a b : α} : a ≤ max a b :=
|
||||
max_le_iff.mp (le_refl _) |>.1
|
||||
|
||||
public theorem right_le_max {α : Type u} [Max α] [LE α] [Refl (α := α) (· ≤ ·)]
|
||||
[LawfulOrderSup α] {a b : α} : b ≤ max a b :=
|
||||
max_le_iff.mp (le_refl _) |>.2
|
||||
|
||||
public theorem le_max {α : Type u} [Max α] [LE α] [IsPreorder α] [LawfulOrderMax α] {a b c : α} :
|
||||
a ≤ max b c ↔ a ≤ b ∨ a ≤ c := by
|
||||
cases MaxEqOr.max_eq_or b c <;> rename_i h
|
||||
· simpa [h] using (le_trans · (h ▸ right_le_max))
|
||||
· simpa [h] using (le_trans · (h ▸ left_le_max))
|
||||
|
||||
public theorem max_eq_or {α : Type u} [Max α] [MaxEqOr α] {a b : α} :
|
||||
max a b = a ∨ max a b = b :=
|
||||
MaxEqOr.max_eq_or a b
|
||||
|
||||
public instance {α : Type u} [LE α] [Max α] [IsLinearOrder α] [LawfulOrderSup α] :
|
||||
MaxEqOr α where
|
||||
max_eq_or a b := by
|
||||
cases le_total (a := a) (b := b)
|
||||
· apply Or.inr
|
||||
apply le_antisymm
|
||||
· rw [max_le_iff]
|
||||
exact ⟨‹_›, le_refl b⟩
|
||||
· apply right_le_max
|
||||
· apply Or.inl
|
||||
apply le_antisymm
|
||||
· rw [max_le_iff]
|
||||
exact ⟨le_refl a, ‹_›⟩
|
||||
· apply left_le_max
|
||||
|
||||
/--
|
||||
If a `Max α` instance satisfies typical properties in terms of a reflexive and antisymmetric `LE α`
|
||||
instance, then the `LE α` instance represents a linear order.
|
||||
-/
|
||||
public theorem IsLinearOrder.of_refl_of_antisymm_of_lawfulOrderMax {α : Type u} [LE α] [Max α]
|
||||
[Refl (α := α) (· ≤ ·)] [Antisymm (α := α) (· ≤ ·)] [LawfulOrderMax α] :
|
||||
IsLinearOrder α := by
|
||||
apply IsLinearOrder.of_le
|
||||
· infer_instance
|
||||
· constructor
|
||||
intro a b c hab hbc
|
||||
have : b = max a b := by
|
||||
apply le_antisymm
|
||||
· exact right_le_max
|
||||
· rw [max_le_iff]
|
||||
exact ⟨hab, le_refl b⟩
|
||||
rw [this, max_le_iff] at hbc
|
||||
exact hbc.1
|
||||
· constructor
|
||||
intro a b
|
||||
cases max_eq_or (a := a) (b := b) <;> rename_i h
|
||||
· exact Or.inr (h ▸ right_le_max)
|
||||
· exact Or.inl (h ▸ left_le_max)
|
||||
|
||||
public instance {α : Type u} [Max α] [MaxEqOr α] {P : α → Prop} : Max (Subtype P) where
|
||||
max a b := ⟨Max.max a.val b.val, MaxEqOr.elim a.property b.property⟩
|
||||
|
||||
public instance {α : Type u} [Max α] [MaxEqOr α] :
|
||||
Std.IdempotentOp (max : α → α → α) where
|
||||
idempotent a := by cases MaxEqOr.max_eq_or a a <;> assumption
|
||||
|
||||
public instance {α : Type u} [LE α] [Max α] [IsLinearOrder α] [LawfulOrderMax α] :
|
||||
Std.Associative (max : α → α → α) where
|
||||
assoc a b c := by
|
||||
apply le_antisymm
|
||||
all_goals
|
||||
simp only [max_le_iff]
|
||||
simp [le_max, le_refl]
|
||||
|
||||
public instance {α : Type u} [LE α] [Max α] [IsLinearOrder α] [LawfulOrderSup α] :
|
||||
LawfulOrderLeftLeaningMax α where
|
||||
max_eq_left a b hab := by
|
||||
apply le_antisymm
|
||||
· simp [max_le_iff, le_refl, hab]
|
||||
· apply left_le_max
|
||||
max_eq_right a b hab := by
|
||||
apply le_antisymm
|
||||
· simp [max_le_iff, le_refl, le_of_not_ge hab]
|
||||
· apply right_le_max
|
||||
|
||||
end Max
|
||||
|
||||
end Std
|
||||
180
src/Init/Data/Order/LemmasExtra.lean
Normal file
180
src/Init/Data/Order/LemmasExtra.lean
Normal file
@@ -0,0 +1,180 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.Order.Lemmas
|
||||
public import Init.Data.Order.FactoriesExtra
|
||||
public import Init.Data.Order.Ord
|
||||
|
||||
namespace Std
|
||||
|
||||
public instance {α : Type u} [LE α] [Ord α] [LawfulOrderOrd α] : OrientedOrd α where
|
||||
eq_swap := by
|
||||
open Classical.Order in
|
||||
intro a b
|
||||
apply Eq.symm
|
||||
cases h : compare a b
|
||||
· rw [compare_eq_lt] at h
|
||||
simpa [Ordering.swap_eq_lt, compare_eq_gt] using h
|
||||
· rw [compare_eq_eq] at h
|
||||
simpa [Ordering.swap_eq_eq, compare_eq_eq] using BEq.symm h
|
||||
· rw [compare_eq_gt] at h
|
||||
simpa [Ordering.swap_eq_gt, compare_eq_lt] using h
|
||||
|
||||
public instance {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α] [IsPreorder α] : TransOrd α where
|
||||
isLE_trans := by
|
||||
simp only [isLE_compare]
|
||||
apply le_trans
|
||||
|
||||
public instance {α : Type u} [Ord α] [BEq α] [LE α] [LawfulOrderOrd α] [LawfulOrderBEq α] :
|
||||
LawfulBEqOrd α where
|
||||
compare_eq_iff_beq := by
|
||||
simp [Ordering.eq_eq_iff_isLE_and_isGE, isLE_compare, isGE_compare, beq_iff_le_and_ge]
|
||||
|
||||
public instance {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α] [IsPartialOrder α] : LawfulEqOrd α where
|
||||
eq_of_compare {a b} := by
|
||||
intro h
|
||||
apply le_antisymm
|
||||
· simp [← isLE_compare, h]
|
||||
· simp [← isGE_compare, h]
|
||||
|
||||
public instance [Ord α] [LE α] [LawfulOrderOrd α] :
|
||||
Total (α := α) (· ≤ ·) where
|
||||
total a b := by
|
||||
rw [← isLE_compare, ← isGE_compare]
|
||||
cases compare a b <;> simp
|
||||
|
||||
public instance {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α] [Antisymm (α := α) (· ≤ ·)] :
|
||||
LawfulEqOrd α where
|
||||
eq_of_compare := by
|
||||
open Classical.Order in
|
||||
simp [Ordering.eq_eq_iff_isLE_and_isGE, isLE_compare, isGE_compare, le_antisymm_iff]
|
||||
|
||||
public instance {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α] [LawfulEqOrd α] :
|
||||
Antisymm (α := α) (· ≤ ·) where
|
||||
antisymm a b := by
|
||||
simp [← and_imp, ← isLE_compare (a := a), ← isGE_compare (a := a),
|
||||
← Ordering.eq_eq_iff_isLE_and_isGE]
|
||||
|
||||
public theorem compare_eq_eq_iff_eq {α : Type u} [Ord α] [LawfulEqOrd α] {a b : α} :
|
||||
compare a b = .eq ↔ a = b :=
|
||||
LawfulEqOrd.compare_eq_iff_eq
|
||||
|
||||
public theorem IsLinearPreorder.of_ord {α : Type u} [LE α] [Ord α] [LawfulOrderOrd α]
|
||||
[TransOrd α] : IsLinearPreorder α where
|
||||
le_refl a := by simp [← isLE_compare]
|
||||
le_trans a b c := by simpa [← isLE_compare] using TransOrd.isLE_trans
|
||||
le_total a b := Total.total a b
|
||||
|
||||
public theorem IsLinearOrder.of_ord {α : Type u} [LE α] [Ord α] [LawfulOrderOrd α]
|
||||
[TransOrd α] [LawfulEqOrd α] : IsLinearOrder α where
|
||||
toIsLinearPreorder := .of_ord
|
||||
le_antisymm a b hab hba := by
|
||||
apply LawfulEqOrd.eq_of_compare
|
||||
rw [← isLE_compare] at hab
|
||||
rw [← isGE_compare] at hba
|
||||
rw [Ordering.eq_eq_iff_isLE_and_isGE, hab, hba, and_self]
|
||||
|
||||
/--
|
||||
This lemma derives a `LawfulOrderLT α` instance from a property involving an `Ord α` instance.
|
||||
-/
|
||||
public instance LawfulOrderLT.of_ord (α : Type u) [Ord α] [LT α] [LE α] [LawfulOrderOrd α]
|
||||
(lt_iff_compare_eq_lt : ∀ a b : α, a < b ↔ compare a b = .lt) :
|
||||
LawfulOrderLT α where
|
||||
lt_iff a b := by
|
||||
simp +contextual [lt_iff_compare_eq_lt, ← isLE_compare (a := a), ← isGE_compare (a := a)]
|
||||
|
||||
/--
|
||||
This lemma derives a `LawfulOrderBEq α` instance from a property involving an `Ord α` instance.
|
||||
-/
|
||||
public instance LawfulOrderBEq.of_ord (α : Type u) [Ord α] [BEq α] [LE α] [LawfulOrderOrd α]
|
||||
(beq_iff_compare_eq_eq : ∀ a b : α, a == b ↔ compare a b = .eq) :
|
||||
LawfulOrderBEq α where
|
||||
beq_iff_le_and_ge := by
|
||||
simp [beq_iff_compare_eq_eq, Ordering.eq_eq_iff_isLE_and_isGE, isLE_compare, isGE_compare]
|
||||
|
||||
/--
|
||||
This lemma derives a `LawfulOrderInf α` instance from a property involving an `Ord α` instance.
|
||||
-/
|
||||
public instance LawfulOrderInf.of_ord (α : Type u) [Ord α] [Min α] [LE α] [LawfulOrderOrd α]
|
||||
(compare_min_isLE_iff : ∀ a b c : α,
|
||||
(compare a (min b c)).isLE ↔ (compare a b).isLE ∧ (compare a c).isLE) :
|
||||
LawfulOrderInf α where
|
||||
le_min_iff := by simpa [isLE_compare] using compare_min_isLE_iff
|
||||
|
||||
/--
|
||||
This lemma derives a `LawfulOrderMin α` instance from a property involving an `Ord α` instance.
|
||||
-/
|
||||
public instance LawfulOrderMin.of_ord (α : Type u) [Ord α] [Min α] [LE α] [LawfulOrderOrd α]
|
||||
(compare_min_isLE_iff : ∀ a b c : α,
|
||||
(compare a (min b c)).isLE ↔ (compare a b).isLE ∧ (compare a c).isLE)
|
||||
(min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b) :
|
||||
LawfulOrderMin α where
|
||||
toLawfulOrderInf := .of_ord α compare_min_isLE_iff
|
||||
min_eq_or := min_eq_or
|
||||
|
||||
/--
|
||||
This lemma derives a `LawfulOrderSup α` instance from a property involving an `Ord α` instance.
|
||||
-/
|
||||
public instance LawfulOrderSup.of_ord (α : Type u) [Ord α] [Max α] [LE α] [LawfulOrderOrd α]
|
||||
(compare_max_isLE_iff : ∀ a b c : α,
|
||||
(compare (max a b) c).isLE ↔ (compare a c).isLE ∧ (compare b c).isLE) :
|
||||
LawfulOrderSup α where
|
||||
max_le_iff := by simpa [isLE_compare] using compare_max_isLE_iff
|
||||
|
||||
/--
|
||||
This lemma derives a `LawfulOrderMax α` instance from a property involving an `Ord α` instance.
|
||||
-/
|
||||
public instance LawfulOrderMax.of_ord (α : Type u) [Ord α] [Max α] [LE α] [LawfulOrderOrd α]
|
||||
(compare_max_isLE_iff : ∀ a b c : α,
|
||||
(compare (max a b) c).isLE ↔ (compare a c).isLE ∧ (compare b c).isLE)
|
||||
(max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b) :
|
||||
LawfulOrderMax α where
|
||||
toLawfulOrderSup := .of_ord α compare_max_isLE_iff
|
||||
max_eq_or := max_eq_or
|
||||
|
||||
public theorem min_eq_if_isLE_compare {α : Type u} [Ord α] [LE α] {_ : Min α}
|
||||
[LawfulOrderOrd α] [LawfulOrderLeftLeaningMin α] {a b : α} :
|
||||
min a b = if (compare a b).isLE then a else b := by
|
||||
open Classical in simp [min_eq_if, isLE_compare]
|
||||
|
||||
public theorem max_eq_if_isGE_compare {α : Type u} [Ord α] [LE α] {_ : Max α}
|
||||
[LawfulOrderOrd α] [LawfulOrderLeftLeaningMax α]
|
||||
{a b : α} : max a b = if (compare a b).isGE then a else b := by
|
||||
open Classical in simp [max_eq_if, isGE_compare]
|
||||
|
||||
end Std
|
||||
|
||||
namespace Classical.Order
|
||||
open Std
|
||||
|
||||
/--
|
||||
Derives an `Ord α` instance from an `LE α` instance. Because all elements are comparable with
|
||||
`compare`, the resulting `Ord α` instance only makes sense if `LE α` is total.
|
||||
-/
|
||||
public noncomputable scoped instance instOrd {α : Type u} [LE α] :
|
||||
Ord α where
|
||||
compare a b := if a ≤ b then if b ≤ a then .eq else .lt else .gt
|
||||
|
||||
public instance instLawfulOrderOrd {α : Type u} [LE α]
|
||||
[Total (α := α) (· ≤ ·)] :
|
||||
LawfulOrderOrd α where
|
||||
isLE_compare a b := by
|
||||
simp only [compare]
|
||||
by_cases a ≤ b <;> rename_i h
|
||||
· simp only [h, ↓reduceIte, iff_true]
|
||||
split <;> simp
|
||||
· simp [h]
|
||||
isGE_compare a b := by
|
||||
simp only [compare]
|
||||
cases Total.total (r := (· ≤ ·)) a b <;> rename_i h
|
||||
· simp only [h, ↓reduceIte]
|
||||
split <;> simp [*]
|
||||
· simp only [h, ↓reduceIte, iff_true]
|
||||
split <;> simp
|
||||
|
||||
end Classical.Order
|
||||
@@ -6,7 +6,7 @@ Authors: Markus Himmel, Paul Reichert, Robin Arnez
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Ord
|
||||
public import Init.Data.Ord.Basic
|
||||
|
||||
public section
|
||||
|
||||
@@ -610,22 +610,20 @@ instance {α β} {f : α → β} [Ord β] [TransOrd β] :
|
||||
TransCmp (compareOn f) where
|
||||
isLE_trans := TransOrd.isLE_trans (α := β)
|
||||
|
||||
attribute [instance] lexOrd in
|
||||
attribute [local instance] lexOrd
|
||||
|
||||
instance {α β} [Ord α] [Ord β] [ReflOrd α] [ReflOrd β] :
|
||||
ReflOrd (α × β) :=
|
||||
inferInstanceAs <| ReflCmp (compareLex _ _)
|
||||
|
||||
attribute [instance] lexOrd in
|
||||
instance {α β} [Ord α] [Ord β] [OrientedOrd α] [OrientedOrd β] :
|
||||
OrientedOrd (α × β) :=
|
||||
inferInstanceAs <| OrientedCmp (compareLex _ _)
|
||||
|
||||
attribute [instance] lexOrd in
|
||||
instance {α β} [Ord α] [Ord β] [TransOrd α] [TransOrd β] :
|
||||
TransOrd (α × β) :=
|
||||
inferInstanceAs <| TransCmp (compareLex _ _)
|
||||
|
||||
attribute [instance] lexOrd in
|
||||
instance {α β} [Ord α] [Ord β] [LawfulEqOrd α] [LawfulEqOrd β] : LawfulEqOrd (α × β) where
|
||||
eq_of_compare {a b} h := by
|
||||
simp only [lexOrd, compareLex_eq_eq, compareOn] at h
|
||||
857
src/Init/Data/Order/PackageFactories.lean
Normal file
857
src/Init/Data/Order/PackageFactories.lean
Normal file
@@ -0,0 +1,857 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Order.FactoriesExtra
|
||||
public import Init.Data.Order.LemmasExtra
|
||||
|
||||
namespace Std
|
||||
|
||||
/-!
|
||||
## Instance packages and factories for them
|
||||
|
||||
Instance packages are classes with the sole purpose to bundle together multiple smaller classes.
|
||||
They should not be used as hypotheses, but they make it more convenient to define multiple instances
|
||||
at once.
|
||||
-/
|
||||
|
||||
section Preorder
|
||||
|
||||
/--
|
||||
This class entails `LE α`, `LT α` and `BEq α` instances as well as proofs that these operations
|
||||
represent the same preorder structure on `α`.
|
||||
-/
|
||||
public class PreorderPackage (α : Type u) extends
|
||||
LE α, LT α, BEq α, LawfulOrderLT α, LawfulOrderBEq α, IsPreorder α where
|
||||
decidableLE : DecidableLE α
|
||||
decidableLT : DecidableLT α
|
||||
|
||||
public instance [PreorderPackage α] : DecidableLE α := PreorderPackage.decidableLE
|
||||
public instance [PreorderPackage α] : DecidableLT α := PreorderPackage.decidableLT
|
||||
|
||||
namespace FactoryInstances
|
||||
|
||||
public scoped instance beqOfDecidableLE {α : Type u} [LE α] [DecidableLE α] :
|
||||
BEq α where
|
||||
beq a b := a ≤ b ∧ b ≤ a
|
||||
|
||||
public instance instLawfulOrderBEqOfDecidableLE {α : Type u} [LE α] [DecidableLE α] :
|
||||
LawfulOrderBEq α where
|
||||
beq_iff_le_and_ge := by simp [BEq.beq]
|
||||
|
||||
/-- If `LT` can be characterized in terms of a decidable `LE`, then `LT` is decidable either. -/
|
||||
@[expose]
|
||||
public def decidableLTOfLE {α : Type u} [LE α] {_ : LT α} [DecidableLE α] [LawfulOrderLT α] :
|
||||
DecidableLT α :=
|
||||
fun a b =>
|
||||
haveI := iff_iff_eq.mp <| LawfulOrderLT.lt_iff a b
|
||||
if h : a ≤ b ∧ ¬ b ≤ a then .isTrue (this ▸ h) else .isFalse (this ▸ h)
|
||||
|
||||
end FactoryInstances
|
||||
|
||||
/--
|
||||
This structure contains all the data needed to create a `PreorderPackage α` instance. Its fields
|
||||
are automatically provided if possible. For the detailed rules how the fields are inferred, see
|
||||
`PreorderPackage.ofLE`.
|
||||
-/
|
||||
public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
le : LE α := by infer_instance
|
||||
decidableLE : DecidableLE α := by infer_instance
|
||||
lt :
|
||||
let := le
|
||||
LT α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact Classical.Order.instLT
|
||||
beq :
|
||||
let := le; let := decidableLE
|
||||
BEq α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.beqOfDecidableLE
|
||||
lt_iff :
|
||||
let := le; let := lt
|
||||
∀ a b : α, a < b ↔ a ≤ b ∧ ¬ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulOrderLT.lt_iff
|
||||
| fail "Failed to automatically prove that the `LE` and `LT` instances are compatible. \
|
||||
Please ensure that a `LawfulOrderLT` instance can be synthesized or \
|
||||
manually provide the field `lt_iff`."
|
||||
decidableLT :
|
||||
let := le; let := decidableLE; let := lt; haveI := lt_iff
|
||||
have := lt_iff
|
||||
DecidableLT α := by
|
||||
extract_lets
|
||||
haveI := @LawfulOrderLT.mk (lt_iff := by assumption) ..
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.decidableLTOfLE
|
||||
| fail "Failed to automatically derive that `LT` is decidable. \
|
||||
Please ensure that a `DecidableLT` instance can be synthesized or \
|
||||
manually provide the field `decidableLT`."
|
||||
beq_iff_le_and_ge :
|
||||
let := le; let := decidableLE; let := beq
|
||||
∀ a b : α, a == b ↔ a ≤ b ∧ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulOrderBEq.beq_iff_le_and_ge
|
||||
| fail "Failed to automatically prove that the `LE` and `BEq` instances are compatible. \
|
||||
Please ensure that a `LawfulOrderBEq` instance can be synthesized or \
|
||||
manually provide the field `beq_iff_le_and_ge`."
|
||||
le_refl :
|
||||
let := le
|
||||
∀ a : α, a ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact Std.Refl.refl (r := (· ≤ ·))
|
||||
| fail "Failed to automatically prove that the `LE` instance is reflexive. \
|
||||
Please ensure that a `Refl` instance can be synthesized or \
|
||||
manually provide the field `le_refl`."
|
||||
le_trans :
|
||||
let := le
|
||||
∀ a b c : α, a ≤ b → b ≤ c → a ≤ c := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun _ _ _ hab hbc => Trans.trans (r := (· ≤ ·)) (s := (· ≤ ·)) (t := (· ≤ ·)) hab hbc
|
||||
| fail "Failed to automatically prove that the `LE` instance is transitive. \
|
||||
Please ensure that a `Trans` instance can be synthesized or \
|
||||
manually provide the field `le_trans`."
|
||||
|
||||
/--
|
||||
Use this factory to conveniently define a preorder on a type `α` and all the associated operations
|
||||
and instances given an `LE α` instance.
|
||||
|
||||
Creates a `PreorderPackage α` instance. Such an instance entails `LE α`, `LT α` and
|
||||
`BEq α` instances as well as an `IsPreorder α` instance and `LawfulOrder*` instances proving the
|
||||
compatibility of the operations with the preorder.
|
||||
|
||||
In the presence of `LE α`, `DecidableLE α`, `Refl (· ≤ ·)` and `Trans (· ≤ ·) (· ≤ ·) (· ≤ ·)`
|
||||
instances, no arguments are required and the factory can be used as in this example:
|
||||
|
||||
```lean
|
||||
public instance : PreorderPackage X := .ofLE X
|
||||
```
|
||||
|
||||
If not all of these instances are available via typeclass synthesis, it is necessary to explicitly
|
||||
provide some arguments:
|
||||
|
||||
```lean
|
||||
public instance : PreorderPackage X := .ofLE X {
|
||||
le_refl := sorry
|
||||
le_trans := sorry }
|
||||
```
|
||||
|
||||
It is also possible to do all of this by hand, without resorting to `PreorderPackage`. This can
|
||||
be useful if, say, one wants to avoid specifying an `LT α` instance, which is not possible with
|
||||
`PreorderPackage`.
|
||||
|
||||
**How the arguments are filled**
|
||||
|
||||
Lean tries to fill all of the fields of the `args : Packages.PreorderOfLEArgs α` parameter
|
||||
automatically. If it fails, it is necessary to provide some of the fields manually.
|
||||
|
||||
* For the data-carrying typeclasses `LE`, `LT` and `BEq`, existing instances are always preferred.
|
||||
If no existing instances can be synthesized, it is attempted to derive an instance from the `LE`
|
||||
instance.
|
||||
* Some proof obligations can be filled automatically if the data-carrying typeclasses have been
|
||||
derived from the `LE` instance. For example: If the `beq` field is omitted and no `BEq α` instance
|
||||
can be synthesized, it is derived from the `LE α` instance. In this case, `beq_iff_le_and_ge` can
|
||||
be omitted because Lean can infer that `BEq α` and `LE α` are compatible.
|
||||
* Other proof obligations, namely `le_refl` and `le_trans`, can be omitted if `Refl` and `Trans`
|
||||
instances can be synthesized.
|
||||
-/
|
||||
@[expose]
|
||||
public def PreorderPackage.ofLE (α : Type u)
|
||||
(args : Packages.PreorderOfLEArgs α := by exact {}) : PreorderPackage α where
|
||||
toLE := args.le
|
||||
decidableLE := args.decidableLE
|
||||
toLT := args.lt
|
||||
toBEq := args.beq
|
||||
toLawfulOrderLT := @LawfulOrderLT.mk (lt_iff := args.lt_iff)
|
||||
decidableLT := args.decidableLT
|
||||
toLawfulOrderBEq := @LawfulOrderBEq.mk (beq_iff_le_and_ge := args.beq_iff_le_and_ge)
|
||||
le_refl := args.le_refl
|
||||
le_trans := args.le_trans
|
||||
|
||||
end Preorder
|
||||
|
||||
section PartialOrder
|
||||
|
||||
/--
|
||||
This class entails `LE α`, `LT α` and `BEq α` instances as well as proofs that these operations
|
||||
represent the same partial order structure on `α`.
|
||||
-/
|
||||
public class PartialOrderPackage (α : Type u) extends
|
||||
PreorderPackage α, IsPartialOrder α
|
||||
|
||||
/--
|
||||
This structure contains all the data needed to create a `PartialOrderPakckage α` instance. Its
|
||||
fields are automatically provided if possible. For the detailed rules how the fields are inferred,
|
||||
see `PartialOrderPackage.ofLE`.
|
||||
-/
|
||||
public structure Packages.PartialOrderOfLEArgs (α : Type u) extends Packages.PreorderOfLEArgs α where
|
||||
le_antisymm :
|
||||
let := le
|
||||
∀ a b : α, a ≤ b → b ≤ a → a = b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact Antisymm.antisymm
|
||||
| fail "Failed to automatically prove that the `LE` instance is antisymmetric. \
|
||||
Please ensure that a `Antisymm` instance can be synthesized or \
|
||||
manually provide the field `le_antisymm`."
|
||||
|
||||
/-
|
||||
Use this factory to conveniently define a partial order on a type `α` and all the associated
|
||||
operations and instances given an `LE α` instance.
|
||||
|
||||
Creates a `PartialOrderPackage α` instance. Such an instance entails `LE α`, `LT α` and
|
||||
`BEq α` instances as well as an `IsPartialOrder α` instance and `LawfulOrder*` instances proving the
|
||||
compatibility of the operations with the preorder.
|
||||
|
||||
In the presence of `LE α`, `DecidableLE α`, `Refl (· ≤ ·)`, `Trans (· ≤ ·) (· ≤ ·) (· ≤ ·)`
|
||||
and `Antisymm (· ≤ ·)` instances, no arguments are required and the factory can be used as in this
|
||||
example:
|
||||
|
||||
```lean
|
||||
public instance : PartialOrderPackage X := .ofLE X
|
||||
```
|
||||
|
||||
If not all of these instances are available via typeclass synthesis, it is necessary to explicitly
|
||||
provide some arguments:
|
||||
|
||||
```lean
|
||||
public instance : PartialOrderPackage X := .ofLE X {
|
||||
le_refl := sorry
|
||||
le_trans := sorry
|
||||
le_antisymm := sorry }
|
||||
```
|
||||
|
||||
It is also possible to do all of this by hand, without resorting to `PartialOrderPackage`. This can
|
||||
be useful if, say, one wants to avoid specifying an `LT α` instance, which is not possible with
|
||||
`PartialOrderPackage`.
|
||||
|
||||
**How the arguments are filled**
|
||||
|
||||
Lean tries to fill all of the fields of the `args : Packages.PartialOrderOfLEArgs α` parameter
|
||||
automatically. If it fails, it is necessary to provide some of the fields manually.
|
||||
|
||||
* For the data-carrying typeclasses `LE`, `LT` and `BEq`, existing instances are always preferred.
|
||||
If no existing instances can be synthesized, it is attempted to derive an instance from the `LE`
|
||||
instance.
|
||||
* Some proof obligations can be filled automatically if the data-carrying typeclasses have been
|
||||
derived from the `LE` instance. For example: If the `beq` field is omitted and no `BEq α` instance
|
||||
can be synthesized, it is derived from the `LE α` instance. In this case, `beq_iff_le_and_ge` can be
|
||||
omitted because Lean can infer that `BEq α` and `LE α` are compatible.
|
||||
* Other proof obligations, namely `le_refl`, `le_trans` and `le_antisymm`, can be omitted if `Refl`,
|
||||
`Trans` and `Antisymm` instances can be synthesized.
|
||||
-/
|
||||
@[expose]
|
||||
public def PartialOrderPackage.ofLE (α : Type u)
|
||||
(args : Packages.PartialOrderOfLEArgs α := by exact {}) : PartialOrderPackage α where
|
||||
toPreorderPackage := .ofLE α args.toPreorderOfLEArgs
|
||||
le_antisymm := args.le_antisymm
|
||||
|
||||
end PartialOrder
|
||||
|
||||
namespace FactoryInstances
|
||||
|
||||
public scoped instance instOrdOfDecidableLE {α : Type u} [LE α] [DecidableLE α] :
|
||||
Ord α where
|
||||
compare a b := if a ≤ b then if b ≤ a then .eq else .lt else .gt
|
||||
|
||||
theorem isLE_compare {α : Type u} [LE α] [DecidableLE α] {a b : α} :
|
||||
(compare a b).isLE ↔ a ≤ b := by
|
||||
simp only [compare]
|
||||
split
|
||||
· split <;> simp_all
|
||||
· simp_all
|
||||
|
||||
theorem isGE_compare {α : Type u} [LE α] [DecidableLE α]
|
||||
(le_total : ∀ a b : α, a ≤ b ∨ b ≤ a) {a b : α} :
|
||||
(compare a b).isGE ↔ b ≤ a := by
|
||||
simp only [compare]
|
||||
split
|
||||
· split <;> simp_all
|
||||
· specialize le_total a b
|
||||
simp_all
|
||||
|
||||
public instance instLawfulOrderOrdOfDecidableLE {α : Type u} [LE α] [DecidableLE α]
|
||||
[Total (α := α) (· ≤ ·)] :
|
||||
LawfulOrderOrd α where
|
||||
isLE_compare _ _ := by exact isLE_compare
|
||||
isGE_compare _ _ := by exact isGE_compare (le_total := Total.total)
|
||||
|
||||
end FactoryInstances
|
||||
|
||||
/--
|
||||
This class entails `LE α`, `LT α`, `BEq α` and `Ord α` instances as well as proofs that these
|
||||
operations represent the same linear preorder structure on `α`.
|
||||
-/
|
||||
public class LinearPreorderPackage (α : Type u) extends
|
||||
PreorderPackage α, Ord α, LawfulOrderOrd α, IsLinearPreorder α
|
||||
|
||||
/--
|
||||
This structure contains all the data needed to create a `LinearPreorderPackage α` instance. Its fields
|
||||
are automatically provided if possible. For the detailed rules how the fields are inferred, see
|
||||
`LinearPreorderPackage.ofLE`.
|
||||
-/
|
||||
public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
|
||||
PreorderOfLEArgs α where
|
||||
ord :
|
||||
let := le; let := decidableLE
|
||||
Ord α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.instOrdOfDecidableLE
|
||||
le_total :
|
||||
∀ a b : α, a ≤ b ∨ b ≤ a := by
|
||||
first
|
||||
| exact Total.total
|
||||
| fail "Failed to automatically prove that the `LE` instance is total. \
|
||||
Please ensure that a `Total` instance can be synthesized or \
|
||||
manually provide the field `le_total`."
|
||||
le_refl a := (by simpa using le_total a a)
|
||||
isLE_compare :
|
||||
let := le; let := decidableLE; let := ord
|
||||
∀ a b : α, (compare a b).isLE ↔ a ≤ b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulOrderOrd.isLE_compare
|
||||
| fail "Failed to automatically prove that `(compare a b).isLE` is equivalent to `a ≤ b`. \
|
||||
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
|
||||
manually provide the field `isLE_compare`."
|
||||
isGE_compare :
|
||||
let := le; let := decidableLE; have := le_total; let := ord
|
||||
∀ a b : α, (compare a b).isGE ↔ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulOrderOrd.isGE_compare
|
||||
| fail "Failed to automatically prove that `(compare a b).isGE` is equivalent to `b ≤ a`. \
|
||||
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
|
||||
manually provide the field `isGE_compare`."
|
||||
|
||||
/--
|
||||
Use this factory to conveniently define a linear preorder on a type `α` and all the associated
|
||||
operations and instances given an `LE α` instance.
|
||||
|
||||
Creates a `LinearPreorderPackage α` instance. Such an instance entails `LE α`, `LT α`, `BEq α` and
|
||||
`Ord α` instances as well as an `IsLinearPreorder α` instance and `LawfulOrder*` instances proving
|
||||
the compatibility of the operations with the linear preorder.
|
||||
|
||||
In the presence of `LE α`, `DecidableLE α`, `Total (· ≤ ·)` and `Trans (· ≤ ·) (· ≤ ·) (· ≤ ·)`
|
||||
instances, no arguments are required and the factory can be used as in this example:
|
||||
|
||||
```lean
|
||||
public instance : LinearPreorderPackage X := .ofLE X
|
||||
```
|
||||
|
||||
If not all of these instances are available via typeclass synthesis, it is necessary to explicitly
|
||||
provide some arguments:
|
||||
|
||||
```lean
|
||||
public instance : LinearPreorderPackage X := .ofLE X {
|
||||
le_total := sorry
|
||||
le_trans := sorry }
|
||||
```
|
||||
|
||||
It is also possible to do all of this by hand, without resorting to `LinearPreorderPackage`. This
|
||||
can be useful if, say, one wants to avoid specifying an `LT α` instance, which is not possible with
|
||||
`LinearPreorderPackage`.
|
||||
|
||||
**How the arguments are filled**
|
||||
|
||||
Lean tries to fill all of the fields of the `args : Packages.LinearPreorderOfLEArgs α` parameter
|
||||
automatically. If it fails, it is necessary to provide some of the fields manually.
|
||||
|
||||
* For the data-carrying typeclasses `LE`, `LT`, `BEq` and `Ord`, existing instances are always
|
||||
preferred. If no existing instances can be synthesized, it is attempted to derive an instance from
|
||||
the `LE` instance.
|
||||
* Some proof obligations can be filled automatically if the data-carrying typeclasses have been
|
||||
derived from the `LE` instance. For example: If the `beq` field is omitted and no `BEq α` instance
|
||||
can be synthesized, it is derived from the `LE α` instance. In this case, `beq_iff_le_and_ge` can be
|
||||
omitted because Lean can infer that `BEq α` and `LE α` are compatible.
|
||||
* Other proof obligations, namely `le_total` and `le_trans`, can be omitted if `Total` and `Trans`
|
||||
instances can be synthesized.
|
||||
-/
|
||||
@[expose]
|
||||
public def LinearPreorderPackage.ofLE (α : Type u)
|
||||
(args : Packages.LinearPreorderOfLEArgs α := by exact {}) : LinearPreorderPackage α where
|
||||
toPreorderPackage := .ofLE α args.toPreorderOfLEArgs
|
||||
toOrd := letI := args.le; args.ord
|
||||
le_total := args.le_total
|
||||
isLE_compare := args.isLE_compare
|
||||
isGE_compare := args.isGE_compare
|
||||
|
||||
namespace FactoryInstances
|
||||
|
||||
public scoped instance instMinOfDecidableLE {α : Type u} [LE α] [DecidableLE α] : Min α where
|
||||
min a b := if a ≤ b then a else b
|
||||
|
||||
public scoped instance instMaxOfDecidableLE {α : Type u} [LE α] [DecidableLE α] : Max α where
|
||||
max a b := if b ≤ a then a else b
|
||||
|
||||
public instance instLawfulOrderLeftLeaningMinOfDecidableLE {α : Type u} [LE α] [DecidableLE α] :
|
||||
LawfulOrderLeftLeaningMin α where
|
||||
min_eq_left a b := by simp +contextual [min]
|
||||
min_eq_right a b := by simp +contextual [min]
|
||||
|
||||
public instance instLawfulOrderLeftLeaningMaxOfDecidableLE {α : Type u} [LE α] [DecidableLE α] :
|
||||
LawfulOrderLeftLeaningMax α where
|
||||
max_eq_left a b := by simp +contextual [max]
|
||||
max_eq_right a b := by simp +contextual [max]
|
||||
|
||||
end FactoryInstances
|
||||
|
||||
/--
|
||||
This class entails `LE α`, `LT α`, `BEq α`, `Ord α`, `Min α` and `Max α` instances as well as proofs
|
||||
that these operations represent the same linear order structure on `α`.
|
||||
-/
|
||||
public class LinearOrderPackage (α : Type u) extends
|
||||
LinearPreorderPackage α, PartialOrderPackage α, Min α, Max α,
|
||||
LawfulOrderMin α, LawfulOrderMax α, IsLinearOrder α
|
||||
|
||||
/--
|
||||
This structure contains all the data needed to create a `LinearOrderPackage α` instance. Its fields
|
||||
are automatically provided if possible. For the detailed rules how the fields are inferred, see
|
||||
`LinearOrderPackage.ofLE`.
|
||||
-/
|
||||
public structure Packages.LinearOrderOfLEArgs (α : Type u) extends
|
||||
LinearPreorderOfLEArgs α, PartialOrderOfLEArgs α where
|
||||
min :
|
||||
let := le; let := decidableLE
|
||||
Min α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.instMinOfDecidableLE
|
||||
max :
|
||||
let := le; let := decidableLE
|
||||
Max α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.instMaxOfDecidableLE
|
||||
min_eq :
|
||||
let := le; let := decidableLE; let := min
|
||||
∀ a b : α, Min.min a b = if a ≤ b then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => Std.min_eq_if (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `min` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
|
||||
manually provide the field `min_eq`."
|
||||
max_eq :
|
||||
let := le; let := decidableLE; let := max
|
||||
∀ a b : α, Max.max a b = if b ≤ a then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => Std.max_eq_if (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `max` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMax` instance can be synthesized or \
|
||||
manually provide the field `max_eq`."
|
||||
|
||||
public theorem IsLinearPreorder.lawfulOrderMin_of_min_eq {α : Type u} [LE α]
|
||||
[DecidableLE α] [Min α] [IsLinearPreorder α]
|
||||
(min_eq : ∀ a b : α, min a b = if a ≤ b then a else b) :
|
||||
LawfulOrderMin α where
|
||||
min_eq_or a b := by
|
||||
rw [min_eq]
|
||||
split <;> simp
|
||||
le_min_iff a b c := by
|
||||
simp only [min_eq]
|
||||
split <;> rename_i hbc
|
||||
· simp only [iff_self_and]
|
||||
exact fun hab => le_trans hab hbc
|
||||
· simp only [iff_and_self]
|
||||
exact fun hac => le_trans hac (by simpa [hbc] using Std.le_total (a := b) (b := c))
|
||||
|
||||
public theorem IsLinearPreorder.lawfulOrderMax_of_max_eq {α : Type u} [LE α]
|
||||
[DecidableLE α] [Max α] [IsLinearPreorder α]
|
||||
(max_eq : ∀ a b : α, max a b = if b ≤ a then a else b) :
|
||||
LawfulOrderMax α where
|
||||
max_eq_or a b := by
|
||||
rw [max_eq]
|
||||
split <;> simp
|
||||
max_le_iff a b c := by
|
||||
simp only [max_eq]
|
||||
split <;> rename_i hab
|
||||
· simp only [iff_self_and]
|
||||
exact fun hbc => le_trans hab hbc
|
||||
· simp only [iff_and_self]
|
||||
exact fun hac => le_trans (by simpa [hab] using Std.le_total (a := a) (b := b)) hac
|
||||
|
||||
/--
|
||||
Use this factory to conveniently define a linear order on a type `α` and all the associated
|
||||
operations and instances given an `LE α` instance.
|
||||
|
||||
Creates a `LinearOrderPackage α` instance. Such an instance entails `LE α`, `LT α`, `BEq α`,
|
||||
`Ord α`, `Min α` and `Max α` instances as well as an `IsLinearOrder α` instance and `LawfulOrder*`
|
||||
instances proving the compatibility of the operations with the linear order.
|
||||
|
||||
In the presence of `LE α`, `DecidableLE α`, `Total (· ≤ ·)`, `Trans (· ≤ ·) (· ≤ ·) (· ≤ ·)` and
|
||||
`Antisymm (· ≤ ·)` instances, no arguments are required and the factory can be used as in this
|
||||
example:
|
||||
|
||||
```lean
|
||||
public instance : LinearOrderPackage X := .ofLE X
|
||||
```
|
||||
|
||||
If not all of these instances are available via typeclass synthesis, it is necessary to explicitly
|
||||
provide some arguments:
|
||||
|
||||
```lean
|
||||
public instance : LinearOrderPackage X := .ofLE X {
|
||||
le_total := sorry
|
||||
le_trans := sorry
|
||||
le_antisymm := sorry }
|
||||
```
|
||||
|
||||
It is also possible to do all of this by hand, without resorting to `LinearOrderPackage`. This
|
||||
can be useful if, say, one wants to avoid specifying an `LT α` instance, which is not possible with
|
||||
`LinearOrderPackage`.
|
||||
|
||||
**How the arguments are filled**
|
||||
|
||||
Lean tries to fill all of the fields of the `args : Packages.LinearOrderOfLEArgs α` parameter
|
||||
automatically. If it fails, it is necessary to provide some of the fields manually.
|
||||
|
||||
* For the data-carrying typeclasses `LE`, `LT`, `BEq`, `Ord`, `Min` and `Max`, existing instances
|
||||
are always preferred. If no existing instances can be synthesized, it is attempted to derive an
|
||||
instance from the `LE` instance.
|
||||
* Some proof obligations can be filled automatically if the data-carrying typeclasses have been
|
||||
derived from the `LE` instance. For example: If the `beq` field is omitted and no `BEq α` instance
|
||||
can be synthesized, it is derived from the `LE α` instance. In this case, `beq_iff_le_and_ge` can be
|
||||
omitted because Lean can infer that `BEq α` and `LE α` are compatible.
|
||||
* Other proof obligations, namely `le_total`, `le_trans` and `le_antisymm`, can be omitted if
|
||||
`Total`, `Trans` and `Antisymm` instances can be synthesized.
|
||||
-/
|
||||
@[expose]
|
||||
public def LinearOrderPackage.ofLE (α : Type u)
|
||||
(args : Packages.LinearOrderOfLEArgs α := by exact {}) : LinearOrderPackage α where
|
||||
toLinearPreorderPackage := .ofLE α args.toLinearPreorderOfLEArgs
|
||||
le_antisymm := (PartialOrderPackage.ofLE α args.toPartialOrderOfLEArgs).le_antisymm
|
||||
toMin := args.min
|
||||
toMax := args.max
|
||||
toLawfulOrderMin :=
|
||||
letI := LinearPreorderPackage.ofLE α args.toLinearPreorderOfLEArgs
|
||||
letI := args.decidableLE; letI := args.min
|
||||
IsLinearPreorder.lawfulOrderMin_of_min_eq args.min_eq
|
||||
toLawfulOrderMax :=
|
||||
letI := LinearPreorderPackage.ofLE α args.toLinearPreorderOfLEArgs
|
||||
letI := args.decidableLE; letI := args.max
|
||||
IsLinearPreorder.lawfulOrderMax_of_max_eq args.max_eq
|
||||
|
||||
section LinearPreorder
|
||||
|
||||
namespace FactoryInstances
|
||||
|
||||
attribute [scoped instance] LE.ofOrd
|
||||
attribute [scoped instance] LT.ofOrd
|
||||
attribute [scoped instance] BEq.ofOrd
|
||||
|
||||
public theorem _root_.Std.OrientedCmp.of_gt_iff_lt {α : Type u} {cmp : α → α → Ordering}
|
||||
(h : ∀ a b : α, cmp a b = .gt ↔ cmp b a = .lt) : OrientedCmp cmp where
|
||||
eq_swap {a b} := by
|
||||
cases h' : cmp a b
|
||||
· apply Eq.symm
|
||||
simp [h, h']
|
||||
· cases h'' : cmp b a
|
||||
· simp [← h, h'] at h''
|
||||
· simp
|
||||
· simp [h, h'] at h''
|
||||
· apply Eq.symm
|
||||
simp [← h, h']
|
||||
|
||||
end FactoryInstances
|
||||
|
||||
/--
|
||||
This structure contains all the data needed to create a `LinearPreorderPackage α` instance.
|
||||
Its fields are automatically provided if possible. For the detailed rules how the fields are
|
||||
inferred, see `LinearPreorderPackage.ofOrd`.
|
||||
-/
|
||||
public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
ord : Ord α := by infer_instance
|
||||
transOrd : TransOrd α := by infer_instance
|
||||
le :
|
||||
let := ord
|
||||
LE α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact LE.ofOrd _
|
||||
lawful_le :
|
||||
let := ord; let := transOrd; let := le
|
||||
LawfulOrderOrd α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| fail "Failed to automatically derive a `LawfulOrderOrd` instance. \
|
||||
Please ensure that the instance can be synthesized or \
|
||||
manually provide the field `lawful_le`."
|
||||
decidableLE :
|
||||
let := ord; let := le; have := lawful_le
|
||||
DecidableLE α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact DecidableLE.ofOrd _
|
||||
| fail "Failed to automatically derive that `LE` is decidable.\
|
||||
Please ensure that a `DecidableLE` instance can be synthesized or \
|
||||
manually provide the field `decidableLE`."
|
||||
lt :
|
||||
let := ord
|
||||
LT α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact LT.ofOrd _
|
||||
lt_iff :
|
||||
let := ord; let := le; have := lawful_le; let := lt
|
||||
∀ a b : α, a < b ↔ compare a b = .lt := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun _ _ => Std.compare_eq_lt.symm
|
||||
| fail "Failed to automatically derive that `LT` and `Ord` are compatible. \
|
||||
Please ensure that a `LawfulOrderLT` instance can be synthesized or \
|
||||
manually provide the field `lt_iff`."
|
||||
decidableLT :
|
||||
let := ord; let := lt; let := le; have := lawful_le; have := lt_iff
|
||||
DecidableLT α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact DecidableLT.ofOrd _
|
||||
| fail "Failed to automatically derive that `LT` is decidable. \
|
||||
Please ensure that a `DecidableLT` instance can be synthesized or \
|
||||
manually provide the field `decidableLT`."
|
||||
beq :
|
||||
let := ord; BEq α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact BEq.ofOrd _
|
||||
beq_iff :
|
||||
let := ord; let := le; have := lawful_le; let := beq
|
||||
∀ a b : α, a == b ↔ compare a b = .eq := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun _ _ => Std.compare_eq_eq.symm
|
||||
| fail "Failed to automatically derive that `BEq` and `Ord` are compatible. \
|
||||
Please ensure that a `LawfulOrderBEq` instance can be synthesized or \
|
||||
manually provide the field `beq_iff`."
|
||||
|
||||
/--
|
||||
Use this factory to conveniently define a linear preorder on a type `α` and all the associated
|
||||
operations and instances given an `Ord α` instance.
|
||||
|
||||
Creates a `LinearPreorderPackage α` instance. Such an instance entails `LE α`, `LT α`, `BEq α` and
|
||||
`Ord α` instances as well as an `IsLinearPreorder α` instance and `LawfulOrder*` instances proving
|
||||
the compatibility of the operations with the linear preorder.
|
||||
|
||||
In the presence of `Ord α` and `TransOrd α` instances, no arguments are required and the factory can
|
||||
be used as in this example:
|
||||
|
||||
```lean
|
||||
public instance : LinearPreorderPackage X := .ofOrd X
|
||||
```
|
||||
|
||||
If not all of these instances are available via typeclass synthesis, it is necessary to explicitly
|
||||
provide some arguments:
|
||||
|
||||
```lean
|
||||
public instance : LinearPreorderPackage X := .ofOrd X {
|
||||
ord := sorry
|
||||
transOrd := sorry }
|
||||
```
|
||||
|
||||
It is also possible to do all of this by hand, without resorting to `LinearPreorderPackage`. This
|
||||
can be useful if, say, one wants to avoid specifying an `LT α` instance, which is not possible with
|
||||
`LinearPreorderPackage`.
|
||||
|
||||
**How the arguments are filled**
|
||||
|
||||
Lean tries to fill all of the fields of the `args : Packages.LinearPreorderOfOrdArgs α` parameter
|
||||
automatically. If it fails, it is necessary to provide some of the fields manually.
|
||||
|
||||
* For the data-carrying typeclasses `LE`, `LT`, `BEq` and `Ord`, existing instances are always
|
||||
preferred. If no existing instances can be synthesized, it is attempted to derive an instance from
|
||||
the `Ord` instance.
|
||||
* Some proof obligations can be filled automatically if the data-carrying typeclasses have been
|
||||
derived from the `Ord` instance. For example: If the `beq` field is omitted and no `BEq α` instance
|
||||
can be synthesized, it is derived from the `Ord α` instance. In this case, `beq_iff`
|
||||
can be omitted because Lean can infer that `BEq α` and `Ord α` are compatible.
|
||||
* Other proof obligations, for example `transOrd`, can be omitted if a matching instance can be
|
||||
synthesized.
|
||||
-/
|
||||
@[expose]
|
||||
public def LinearPreorderPackage.ofOrd (α : Type u)
|
||||
(args : Packages.LinearPreorderOfOrdArgs α := by exact {}) : LinearPreorderPackage α :=
|
||||
letI := args.ord
|
||||
haveI := args.transOrd
|
||||
letI := args.le
|
||||
haveI := args.lawful_le
|
||||
{ toOrd := args.ord
|
||||
toLE := args.le
|
||||
toLT := args.lt
|
||||
toBEq := args.beq
|
||||
toLawfulOrderOrd := args.lawful_le
|
||||
lt_iff a b := by
|
||||
cases h : compare a b
|
||||
all_goals simp [h, ← args.lawful_le.isLE_compare a _, ← args.lawful_le.isGE_compare a _,
|
||||
args.lt_iff]
|
||||
beq_iff_le_and_ge a b := by
|
||||
simp [args.beq_iff, Ordering.eq_eq_iff_isLE_and_isGE, isLE_compare,
|
||||
isGE_compare]
|
||||
decidableLE := args.decidableLE
|
||||
decidableLT := args.decidableLT
|
||||
le_refl a := by simp [← isLE_compare]
|
||||
le_total a b := by cases h : compare a b <;> simp [h, ← isLE_compare (a := a), ← isGE_compare (a := a)]
|
||||
le_trans a b c := by simpa [← isLE_compare] using TransOrd.isLE_trans }
|
||||
|
||||
end LinearPreorder
|
||||
|
||||
section LinearOrder
|
||||
|
||||
namespace FactoryInstances
|
||||
|
||||
public scoped instance instMinOfOrd {α : Type u} [Ord α] :
|
||||
Min α where
|
||||
min a b := if (compare a b).isLE then a else b
|
||||
|
||||
public scoped instance instMaxOfOrd {α : Type u} [Ord α] :
|
||||
Max α where
|
||||
max a b := if (compare b a).isLE then a else b
|
||||
|
||||
public instance instLawfulOrderLeftLeaningMinOfOrd {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α] :
|
||||
LawfulOrderLeftLeaningMin α where
|
||||
min_eq_left a b := by simp +contextual only [← Std.isLE_compare, min, ↑reduceIte, implies_true]
|
||||
min_eq_right a b := by
|
||||
simp +contextual only [← Std.isLE_compare, min, Bool.false_eq_true, ↑reduceIte, implies_true]
|
||||
|
||||
public instance instLawfulOrderLeftLeaningMaxOfOrd {α : Type u} [Ord α] [LE α] [LawfulOrderOrd α] :
|
||||
LawfulOrderLeftLeaningMax α where
|
||||
max_eq_left a b := by simp +contextual only [← Std.isLE_compare, max, ↑reduceIte, implies_true]
|
||||
max_eq_right a b := by
|
||||
simp +contextual only [← Std.isLE_compare, max, Bool.false_eq_true, ↑reduceIte, implies_true]
|
||||
|
||||
end FactoryInstances
|
||||
|
||||
/--
|
||||
This structure contains all the data needed to create a `LinearOrderPackage α` instance.
|
||||
Its fields are automatically provided if possible. For the detailed rules how the fields are
|
||||
inferred, see `LinearOrderPackage.ofOrd`.
|
||||
-/
|
||||
public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
|
||||
LinearPreorderOfOrdArgs α where
|
||||
eq_of_compare :
|
||||
let := ord; let := le
|
||||
∀ a b : α, compare a b = .eq → a = b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact LawfulEqOrd.eq_of_compare
|
||||
| fail "Failed to derive a `LawfulEqOrd` instance. \
|
||||
Please make sure that it can be synthesized or \
|
||||
manually provide the field `eq_of_compare`."
|
||||
min :
|
||||
let := ord
|
||||
Min α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.instMinOfOrd
|
||||
max :
|
||||
let := ord
|
||||
Max α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact FactoryInstances.instMaxOfOrd
|
||||
min_eq :
|
||||
let := ord; let := le; let := min; have := lawful_le
|
||||
∀ a b : α, Min.min a b = if (compare a b).isLE then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => Std.min_eq_if_isLE_compare (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `min` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
|
||||
manuelly provide the field `min_eq`."
|
||||
max_eq :
|
||||
let := ord; let := le; let := max; have := lawful_le
|
||||
∀ a b : α, Max.max a b = if (compare a b).isGE then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => Std.max_eq_if_isGE_compare (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `max` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMax` instance can be synthesized or \
|
||||
manually provide the field `max_eq`."
|
||||
|
||||
/--
|
||||
Use this factory to conveniently define a linear order on a type `α` and all the associated
|
||||
operations and instances given an `Ord α` instance.
|
||||
|
||||
Creates a `LinearOrderPackage α` instance. Such an instance entails `LE α`, `LT α`, `BEq α`,
|
||||
`Ord α`, `Min α` and `Max α` instances as well as an `IsLinearOrder α` instance and `LawfulOrder*`
|
||||
instances proving the compatibility of the operations with the linear order.
|
||||
|
||||
In the presence of `Ord α`, `TransOrd α` and `LawfulEqOrd α` instances, no arguments are required
|
||||
and the factory can be used as in this
|
||||
example:
|
||||
|
||||
```lean
|
||||
public instance : LinearOrderPackage X := .ofLE X
|
||||
```
|
||||
|
||||
If not all of these instances are available via typeclass synthesis, it is necessary to explicitly
|
||||
provide some arguments:
|
||||
|
||||
```lean
|
||||
public instance : LinearOrderPackage X := .ofLE X {
|
||||
transOrd := sorry
|
||||
eq_of_compare := sorry }
|
||||
```
|
||||
|
||||
It is also possible to do all of this by hand, without resorting to `LinearOrderPackage`. This
|
||||
can be useful if, say, one wants to avoid specifying an `LT α` instance, which is not possible with
|
||||
`LinearOrderPackage`.
|
||||
|
||||
**How the arguments are filled**
|
||||
|
||||
Lean tries to fill all of the fields of the `args : Packages.LinearOrderOfLEArgs α` parameter
|
||||
automatically. If it fails, it is necessary to provide some of the fields manually.
|
||||
|
||||
* For the data-carrying typeclasses `LE`, `LT`, `BEq`, `Ord`, `Min` and `Max`, existing instances
|
||||
are always preferred. If no existing instances can be synthesized, it is attempted to derive an
|
||||
instance from the `Ord` instance.
|
||||
* Some proof obligations can be filled automatically if the data-carrying typeclasses have been
|
||||
derived from the `Ord` instance. For example: If the `beq` field is omitted and no `BEq α` instance
|
||||
can be synthesized, it is derived from the `LE α` instance. In this case, `beq_iff`
|
||||
can be omitted because Lean can infer that `BEq α` and `Ord α` are compatible.
|
||||
* Other proof obligations, such as `transOrd`, can be omitted if matching instances can be
|
||||
synthesized.
|
||||
-/
|
||||
@[expose]
|
||||
public def LinearOrderPackage.ofOrd (α : Type u)
|
||||
(args : Packages.LinearOrderOfOrdArgs α := by exact {}) : LinearOrderPackage α :=
|
||||
letI := LinearPreorderPackage.ofOrd α args.toLinearPreorderOfOrdArgs
|
||||
haveI : LawfulEqOrd α := ⟨args.eq_of_compare _ _⟩
|
||||
letI : Min α := args.min
|
||||
letI : Max α := args.max
|
||||
{ toMin := args.min
|
||||
toMax := args.max,
|
||||
le_antisymm := Antisymm.antisymm
|
||||
toLawfulOrderMin := IsLinearPreorder.lawfulOrderMin_of_min_eq
|
||||
(by simpa [isLE_compare] using args.min_eq)
|
||||
toLawfulOrderMax := IsLinearPreorder.lawfulOrderMax_of_max_eq
|
||||
(by simpa [isGE_compare] using args.max_eq) }
|
||||
|
||||
end LinearOrder
|
||||
|
||||
end Std
|
||||
@@ -36,7 +36,14 @@ structure StdGen where
|
||||
s1 : Nat
|
||||
s2 : Nat
|
||||
|
||||
instance : Inhabited StdGen := ⟨{ s1 := 0, s2 := 0 }⟩
|
||||
/-- Returns a standard number generator. -/
|
||||
def mkStdGen (s : Nat := 0) : StdGen :=
|
||||
let q := s / 2147483562
|
||||
let s1 := s % 2147483562
|
||||
let s2 := q % 2147483398
|
||||
⟨s1 + 1, s2 + 1⟩
|
||||
|
||||
instance : Inhabited StdGen := ⟨mkStdGen⟩
|
||||
|
||||
/-- The range of values returned by `StdGen` -/
|
||||
def stdRange := (1, 2147483562)
|
||||
@@ -77,13 +84,6 @@ instance : RandomGen StdGen := {
|
||||
split := stdSplit
|
||||
}
|
||||
|
||||
/-- Returns a standard number generator. -/
|
||||
def mkStdGen (s : Nat := 0) : StdGen :=
|
||||
let q := s / 2147483562
|
||||
let s1 := s % 2147483562
|
||||
let s2 := q % 2147483398
|
||||
⟨s1 + 1, s2 + 1⟩
|
||||
|
||||
/--
|
||||
Auxiliary function for randomNatVal.
|
||||
Generate random values until we exceed the target magnitude.
|
||||
|
||||
@@ -12,6 +12,7 @@ public import Init.Data.Range.Polymorphic.Stream
|
||||
public import Init.Data.Range.Polymorphic.Lemmas
|
||||
public import Init.Data.Range.Polymorphic.Nat
|
||||
public import Init.Data.Range.Polymorphic.NatLemmas
|
||||
public import Init.Data.Range.Polymorphic.GetElemTactic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -60,6 +60,11 @@ def isEmpty {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α] (r : PRange ⟨sl, su⟩ α) : Bool :=
|
||||
(BoundedUpwardEnumerable.init? r.lower).all (! SupportsUpperBound.IsSatisfied r.upper ·)
|
||||
|
||||
theorem mem_iff_isSatisfied [SupportsLowerBound sl α] [SupportsUpperBound su α]
|
||||
{x : α} {r : Std.PRange ⟨sl, su⟩ α} :
|
||||
x ∈ r ↔ SupportsLowerBound.IsSatisfied r.lower x ∧ SupportsUpperBound.IsSatisfied r.upper x := by
|
||||
simp [Membership.mem]
|
||||
|
||||
theorem le_upper_of_mem {sl α} [LE α] [DecidableLE α] [SupportsLowerBound sl α]
|
||||
{a : α} {r : PRange ⟨sl, .closed⟩ α} (h : a ∈ r) : a ≤ r.upper :=
|
||||
h.2
|
||||
@@ -84,6 +89,11 @@ macro_rules
|
||||
| `(tactic| get_elem_tactic_extensible) =>
|
||||
`(tactic|
|
||||
first
|
||||
-- This is a relatively rigid check. See `Init.Data.Range.Polymorphic.GetElemTactic`
|
||||
-- for a second one that is more flexible.
|
||||
-- Note: This one is not *strictly* inferior. This one is better able to look under
|
||||
-- reducible terms. The other tactic needs special handling for `Vector.size` to work
|
||||
-- around that fact that `omega` does not reduce terms.
|
||||
| apply Std.PRange.Internal.get_elem_helper_upper_open ‹_› (by trivial)
|
||||
| done)
|
||||
|
||||
|
||||
34
src/Init/Data/Range/Polymorphic/GetElemTactic.lean
Normal file
34
src/Init/Data/Range/Polymorphic/GetElemTactic.lean
Normal file
@@ -0,0 +1,34 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Range.Polymorphic.Basic
|
||||
public import Init.Data.Vector.Basic
|
||||
|
||||
public section
|
||||
|
||||
/-!
|
||||
This module contains an advanced `GetElem` tactic extension for polymorphic ranges.
|
||||
While `Init.Data.Range.Polymorphic.Basic` already defines one, it only works in very
|
||||
basic cases where the open upper bound of the range is exactly the size of the collection.
|
||||
|
||||
This tactic is using `omega` to be more powerful, but it needs special handling for `Vector`,
|
||||
which is impossible in `Init.Data.Range.Polymorphic.Basic` for bootstrapping reasons.
|
||||
-/
|
||||
|
||||
macro_rules
|
||||
| `(tactic| get_elem_tactic_extensible) =>
|
||||
`(tactic|
|
||||
first
|
||||
| rw [Std.PRange.mem_iff_isSatisfied] at *
|
||||
dsimp +zetaDelta only [Std.PRange.SupportsLowerBound.IsSatisfied, Std.PRange.SupportsUpperBound.IsSatisfied,
|
||||
-- `Vector.size` needs to be unfolded because for `xs : Vector α n`, one needs to prove
|
||||
-- `i < n` instead of `i < xs.size`. Although `Vector.size` is reducible, this is
|
||||
-- not enough for `omega`.
|
||||
Vector.size] at *
|
||||
omega
|
||||
| done)
|
||||
@@ -441,7 +441,7 @@ instance RangeIterator.instIteratorLoop {su} [UpwardEnumerable α] [SupportsUppe
|
||||
(f : (out : α) → UpwardEnumerable.LE least out → SupportsUpperBound.IsSatisfied upperBound out → (c : γ) → n (Subtype (fun s : ForInStep γ => Pl out c s)))
|
||||
(next : α) (hl : UpwardEnumerable.LE least next) (hu : SupportsUpperBound.IsSatisfied upperBound next) : n γ := do
|
||||
match ← f next hl hu acc with
|
||||
| ⟨.yield acc', h⟩ =>
|
||||
| ⟨.yield acc', _⟩ =>
|
||||
match hs : UpwardEnumerable.succ? next with
|
||||
| some next' =>
|
||||
if hu : SupportsUpperBound.IsSatisfied upperBound next' then
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Std.Classes.Ord
|
||||
|
||||
public section
|
||||
public import Init.Data.Rat.Basic
|
||||
public import Init.Data.Rat.Lemmas
|
||||
295
src/Init/Data/Rat/Basic.lean
Normal file
295
src/Init/Data/Rat/Basic.lean
Normal file
@@ -0,0 +1,295 @@
|
||||
/-
|
||||
Copyright (c) 2022 Mario Carneiro. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mario Carneiro
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Nat.Coprime
|
||||
public import Init.Data.Hashable
|
||||
public import Init.Data.OfScientific
|
||||
|
||||
@[expose] public section
|
||||
|
||||
/-! # Basics for the Rational Numbers -/
|
||||
|
||||
/--
|
||||
Rational numbers, implemented as a pair of integers `num / den` such that the
|
||||
denominator is positive and the numerator and denominator are coprime.
|
||||
-/
|
||||
-- `Rat` is not tagged with the `ext` attribute, since this is more often than not undesirable
|
||||
structure Rat where
|
||||
/-- Constructs a rational number from components.
|
||||
We rename the constructor to `mk'` to avoid a clash with the smart constructor. -/
|
||||
mk' ::
|
||||
/-- The numerator of the rational number is an integer. -/
|
||||
num : Int
|
||||
/-- The denominator of the rational number is a natural number. -/
|
||||
den : Nat := 1
|
||||
/-- The denominator is nonzero. -/
|
||||
den_nz : den ≠ 0 := by decide
|
||||
/-- The numerator and denominator are coprime: it is in "reduced form". -/
|
||||
reduced : num.natAbs.Coprime den := by decide
|
||||
deriving DecidableEq, Hashable
|
||||
|
||||
instance : Inhabited Rat := ⟨{ num := 0 }⟩
|
||||
|
||||
instance : ToString Rat where
|
||||
toString a := if a.den = 1 then toString a.num else s!"{a.num}/{a.den}"
|
||||
|
||||
instance : Repr Rat where
|
||||
reprPrec a _ := if a.den = 1 then repr a.num else s!"({a.num} : Rat)/{a.den}"
|
||||
|
||||
theorem Rat.den_pos (self : Rat) : 0 < self.den := Nat.pos_of_ne_zero self.den_nz
|
||||
|
||||
/--
|
||||
Auxiliary definition for `Rat.normalize`. Constructs `num / den` as a rational number,
|
||||
dividing both `num` and `den` by `g` (which is the gcd of the two) if it is not 1.
|
||||
-/
|
||||
@[inline] def Rat.maybeNormalize (num : Int) (den g : Nat)
|
||||
(dvd_num : ↑g ∣ num) (dvd_den : g ∣ den) (den_nz : den / g ≠ 0)
|
||||
(reduced : (num / g).natAbs.Coprime (den / g)) : Rat :=
|
||||
if hg : g = 1 then
|
||||
{ num, den
|
||||
den_nz := by simp [hg] at den_nz; exact den_nz
|
||||
reduced := by simp [hg] at reduced; exact reduced }
|
||||
else { num := num.divExact g dvd_num, den := den.divExact g dvd_den, den_nz, reduced }
|
||||
|
||||
theorem Rat.normalize.dvd_num {num : Int} {den g : Nat}
|
||||
(e : g = num.natAbs.gcd den) : ↑g ∣ num := by
|
||||
rw [e, ← Int.dvd_natAbs, Int.ofNat_dvd]
|
||||
exact Nat.gcd_dvd_left num.natAbs den
|
||||
|
||||
theorem Rat.normalize.dvd_den {num : Int} {den g : Nat}
|
||||
(e : g = num.natAbs.gcd den) : g ∣ den :=
|
||||
e ▸ Nat.gcd_dvd_right ..
|
||||
|
||||
theorem Rat.normalize.den_nz {num : Int} {den g : Nat} (den_nz : den ≠ 0)
|
||||
(e : g = num.natAbs.gcd den) : den / g ≠ 0 :=
|
||||
e ▸ Nat.ne_of_gt (Nat.div_gcd_pos_of_pos_right _ (Nat.pos_of_ne_zero den_nz))
|
||||
|
||||
theorem Rat.normalize.reduced {num : Int} {den g : Nat} (den_nz : den ≠ 0)
|
||||
(e : g = num.natAbs.gcd den) : (num / g).natAbs.Coprime (den / g) :=
|
||||
have : Int.natAbs (num / ↑g) = num.natAbs / g := by
|
||||
rw [Int.natAbs_ediv_of_dvd (dvd_num e), Int.natAbs_natCast]
|
||||
this ▸ e ▸ Nat.coprime_div_gcd_div_gcd (Nat.gcd_pos_of_pos_right _ (Nat.pos_of_ne_zero den_nz))
|
||||
|
||||
/--
|
||||
Construct a normalized `Rat` from a numerator and nonzero denominator.
|
||||
This is a "smart constructor" that divides the numerator and denominator by
|
||||
the gcd to ensure that the resulting rational number is normalized.
|
||||
-/
|
||||
@[inline] def Rat.normalize (num : Int) (den : Nat := 1) (den_nz : den ≠ 0 := by decide) : Rat :=
|
||||
Rat.maybeNormalize num den (num.natAbs.gcd den)
|
||||
(normalize.dvd_num rfl) (normalize.dvd_den rfl)
|
||||
(normalize.den_nz den_nz rfl) (normalize.reduced den_nz rfl)
|
||||
|
||||
/--
|
||||
Construct a rational number from a numerator and denominator.
|
||||
This is a "smart constructor" that divides the numerator and denominator by
|
||||
the gcd to ensure that the resulting rational number is normalized, and returns
|
||||
zero if `den` is zero.
|
||||
-/
|
||||
def mkRat (num : Int) (den : Nat) : Rat :=
|
||||
if den_nz : den = 0 then { num := 0 } else Rat.normalize num den den_nz
|
||||
|
||||
namespace Rat
|
||||
|
||||
/-- Embedding of `Int` in the rational numbers. -/
|
||||
def ofInt (num : Int) : Rat := { num, reduced := Nat.coprime_one_right _ }
|
||||
|
||||
instance : NatCast Rat where
|
||||
natCast n := ofInt n
|
||||
instance : IntCast Rat := ⟨ofInt⟩
|
||||
|
||||
instance : OfNat Rat n := ⟨n⟩
|
||||
|
||||
/-- Is this rational number integral? -/
|
||||
@[inline] protected def isInt (a : Rat) : Bool := a.den == 1
|
||||
|
||||
/-- Form the quotient `n / d` where `n d : Int`. -/
|
||||
def divInt : Int → Int → Rat
|
||||
| n, .ofNat d => inline (mkRat n d)
|
||||
| n, .negSucc d => normalize (-n) d.succ nofun
|
||||
|
||||
@[inherit_doc] scoped infixl:70 " /. " => Rat.divInt
|
||||
|
||||
/-- Implements "scientific notation" `123.4e-5` for rational numbers. (This definition is
|
||||
`@[irreducible]` because you don't want to unfold it. Use `Rat.ofScientific_def`,
|
||||
`Rat.ofScientific_true_def`, or `Rat.ofScientific_false_def` instead.) -/
|
||||
@[irreducible] protected def ofScientific (m : Nat) (s : Bool) (e : Nat) : Rat :=
|
||||
if s then
|
||||
Rat.normalize m (10 ^ e) <| Nat.ne_of_gt <| Nat.pow_pos (by decide)
|
||||
else
|
||||
(m * 10 ^ e : Nat)
|
||||
|
||||
instance : OfScientific Rat where
|
||||
ofScientific m s e := Rat.ofScientific (OfNat.ofNat m) s (OfNat.ofNat e)
|
||||
|
||||
/-- Rational number strictly less than relation, as a `Bool`. -/
|
||||
protected def blt (a b : Rat) : Bool :=
|
||||
if a.num < 0 && 0 ≤ b.num then
|
||||
true
|
||||
else if a.num = 0 then
|
||||
0 < b.num
|
||||
else if 0 < a.num && b.num ≤ 0 then
|
||||
false
|
||||
else
|
||||
-- `a` and `b` must have the same sign
|
||||
a.num * b.den < b.num * a.den
|
||||
|
||||
instance : LT Rat := ⟨(·.blt ·)⟩
|
||||
|
||||
instance (a b : Rat) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (_ = true))
|
||||
|
||||
instance : LE Rat := ⟨fun a b => b.blt a = false⟩
|
||||
|
||||
instance (a b : Rat) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (_ = false))
|
||||
|
||||
/-- Multiplication of rational numbers. (This definition is `@[irreducible]` because you don't
|
||||
want to unfold it. Use `Rat.mul_def` instead.) -/
|
||||
@[irreducible] protected def mul (a b : Rat) : Rat :=
|
||||
let g1 := Nat.gcd a.num.natAbs b.den
|
||||
let g2 := Nat.gcd b.num.natAbs a.den
|
||||
{ num := a.num.divExact g1 (normalize.dvd_num rfl) * b.num.divExact g2 (normalize.dvd_num rfl)
|
||||
den := a.den.divExact g2 (normalize.dvd_den rfl) * b.den.divExact g1 (normalize.dvd_den rfl)
|
||||
den_nz := Nat.ne_of_gt <| Nat.mul_pos
|
||||
(Nat.div_gcd_pos_of_pos_right _ a.den_pos) (Nat.div_gcd_pos_of_pos_right _ b.den_pos)
|
||||
reduced := by
|
||||
simp only [Int.divExact_eq_tdiv, Int.natAbs_mul, Int.natAbs_tdiv, Nat.coprime_mul_iff_left]
|
||||
refine ⟨Nat.coprime_mul_iff_right.2 ⟨?_, ?_⟩, Nat.coprime_mul_iff_right.2 ⟨?_, ?_⟩⟩
|
||||
· exact a.reduced.coprime_div_left (Nat.gcd_dvd_left ..)
|
||||
|>.coprime_div_right (Nat.gcd_dvd_right ..)
|
||||
· exact Nat.coprime_div_gcd_div_gcd (Nat.gcd_pos_of_pos_right _ b.den_pos)
|
||||
· exact Nat.coprime_div_gcd_div_gcd (Nat.gcd_pos_of_pos_right _ a.den_pos)
|
||||
· exact b.reduced.coprime_div_left (Nat.gcd_dvd_left ..)
|
||||
|>.coprime_div_right (Nat.gcd_dvd_right ..) }
|
||||
|
||||
instance : Mul Rat := ⟨Rat.mul⟩
|
||||
|
||||
/--
|
||||
The inverse of a rational number. Note: `inv 0 = 0`. (This definition is `@[irreducible]`
|
||||
because you don't want to unfold it. Use `Rat.inv_def` instead.)
|
||||
-/
|
||||
@[irreducible] protected def inv (a : Rat) : Rat :=
|
||||
if h : a.num < 0 then
|
||||
{ num := -a.den, den := a.num.natAbs
|
||||
den_nz := Nat.ne_of_gt (Int.natAbs_pos.2 (Int.ne_of_lt h))
|
||||
reduced := Int.natAbs_neg a.den ▸ a.reduced.symm }
|
||||
else if h : a.num > 0 then
|
||||
{ num := a.den, den := a.num.natAbs
|
||||
den_nz := Nat.ne_of_gt (Int.natAbs_pos.2 (Int.ne_of_gt h))
|
||||
reduced := a.reduced.symm }
|
||||
else
|
||||
a
|
||||
|
||||
/-- Division of rational numbers. Note: `div a 0 = 0`. -/
|
||||
protected def div : Rat → Rat → Rat := (· * ·.inv)
|
||||
|
||||
/-- Division of rational numbers. Note: `div a 0 = 0`. Written with a separate function `Rat.div`
|
||||
as a wrapper so that the definition is not unfolded at `.instance` transparency. -/
|
||||
instance : Div Rat := ⟨Rat.div⟩
|
||||
|
||||
theorem add.aux (a b : Rat) {g ad bd} (hg : g = a.den.gcd b.den)
|
||||
(had : ad = a.den / g) (hbd : bd = b.den / g) :
|
||||
let den := ad * b.den; let num := a.num * bd + b.num * ad
|
||||
num.natAbs.gcd g = num.natAbs.gcd den := by
|
||||
intro den num
|
||||
have ae : ad * g = a.den := had ▸ Nat.div_mul_cancel (hg ▸ Nat.gcd_dvd_left ..)
|
||||
have be : bd * g = b.den := hbd ▸ Nat.div_mul_cancel (hg ▸ Nat.gcd_dvd_right ..)
|
||||
have hden : den = ad * bd * g := by rw [Nat.mul_assoc, be]
|
||||
rw [hden, Nat.Coprime.gcd_mul_left_cancel_right]
|
||||
have cop : ad.Coprime bd := had ▸ hbd ▸ hg ▸
|
||||
Nat.coprime_div_gcd_div_gcd (Nat.gcd_pos_of_pos_left _ a.den_pos)
|
||||
have H1 (d : Nat) :
|
||||
d.gcd num.natAbs ∣ a.num.natAbs * bd ↔ d.gcd num.natAbs ∣ b.num.natAbs * ad := by
|
||||
have := d.gcd_dvd_right num.natAbs
|
||||
rw [← Int.ofNat_dvd, Int.dvd_natAbs] at this
|
||||
have := Int.dvd_iff_dvd_of_dvd_add this
|
||||
rwa [← Int.dvd_natAbs, Int.ofNat_dvd, Int.natAbs_mul,
|
||||
← Int.dvd_natAbs, Int.ofNat_dvd, Int.natAbs_mul] at this
|
||||
apply Nat.Coprime.mul_left
|
||||
· have := (H1 ad).2 <| Nat.dvd_trans (Nat.gcd_dvd_left ..) (Nat.dvd_mul_left ..)
|
||||
have := (cop.coprime_dvd_left <| Nat.gcd_dvd_left ..).dvd_of_dvd_mul_right this
|
||||
exact Nat.eq_one_of_dvd_one <| a.reduced.gcd_eq_one ▸ Nat.dvd_gcd this <|
|
||||
Nat.dvd_trans (Nat.gcd_dvd_left ..) (ae ▸ Nat.dvd_mul_right ..)
|
||||
· have := (H1 bd).1 <| Nat.dvd_trans (Nat.gcd_dvd_left ..) (Nat.dvd_mul_left ..)
|
||||
have := (cop.symm.coprime_dvd_left <| Nat.gcd_dvd_left ..).dvd_of_dvd_mul_right this
|
||||
exact Nat.eq_one_of_dvd_one <| b.reduced.gcd_eq_one ▸ Nat.dvd_gcd this <|
|
||||
Nat.dvd_trans (Nat.gcd_dvd_left ..) (be ▸ Nat.dvd_mul_right ..)
|
||||
|
||||
/--
|
||||
Addition of rational numbers. (This definition is `@[irreducible]` because you don't want to
|
||||
unfold it. Use `Rat.add_def` instead.)
|
||||
-/
|
||||
@[irreducible] protected def add (a b : Rat) : Rat :=
|
||||
let g := a.den.gcd b.den
|
||||
if hg : g = 1 then
|
||||
have den_nz := Nat.ne_of_gt <| Nat.mul_pos a.den_pos b.den_pos
|
||||
have reduced := add.aux a b hg.symm (Nat.div_one _).symm (Nat.div_one _).symm
|
||||
|>.symm.trans (Nat.gcd_one_right _)
|
||||
{ num := a.num * b.den + b.num * a.den, den := a.den * b.den, den_nz, reduced }
|
||||
else
|
||||
let den := (a.den / g) * b.den
|
||||
let num := a.num * ↑(b.den / g) + b.num * ↑(a.den / g)
|
||||
let g1 := num.natAbs.gcd g
|
||||
have den_nz := Nat.ne_of_gt <| Nat.mul_pos (Nat.div_gcd_pos_of_pos_left _ a.den_pos) b.den_pos
|
||||
have e : g1 = num.natAbs.gcd den := add.aux a b rfl rfl rfl
|
||||
Rat.maybeNormalize num den g1 (normalize.dvd_num e) (normalize.dvd_den e)
|
||||
(normalize.den_nz den_nz e) (normalize.reduced den_nz e)
|
||||
|
||||
instance : Add Rat := ⟨Rat.add⟩
|
||||
|
||||
/-- Negation of rational numbers. -/
|
||||
protected def neg (a : Rat) : Rat :=
|
||||
{ a with num := -a.num, reduced := by rw [Int.natAbs_neg]; exact a.reduced }
|
||||
|
||||
instance : Neg Rat := ⟨Rat.neg⟩
|
||||
|
||||
theorem sub.aux (a b : Rat) {g ad bd} (hg : g = a.den.gcd b.den)
|
||||
(had : ad = a.den / g) (hbd : bd = b.den / g) :
|
||||
let den := ad * b.den; let num := a.num * bd - b.num * ad
|
||||
num.natAbs.gcd g = num.natAbs.gcd den := by
|
||||
have := add.aux a (-b) hg had hbd
|
||||
simp only [show (-b).num = -b.num from rfl, Int.neg_mul] at this
|
||||
exact this
|
||||
|
||||
/-- Subtraction of rational numbers. (This definition is `@[irreducible]` because you don't want to
|
||||
unfold it. Use `Rat.sub_def` instead.)
|
||||
-/
|
||||
@[irreducible] protected def sub (a b : Rat) : Rat :=
|
||||
let g := a.den.gcd b.den
|
||||
if hg : g = 1 then
|
||||
have den_nz := Nat.ne_of_gt <| Nat.mul_pos a.den_pos b.den_pos
|
||||
have reduced := sub.aux a b hg.symm (Nat.div_one _).symm (Nat.div_one _).symm
|
||||
|>.symm.trans (Nat.gcd_one_right _)
|
||||
{ num := a.num * b.den - b.num * a.den, den := a.den * b.den, den_nz, reduced }
|
||||
else
|
||||
let den := (a.den / g) * b.den
|
||||
let num := a.num * ↑(b.den / g) - b.num * ↑(a.den / g)
|
||||
let g1 := num.natAbs.gcd g
|
||||
have den_nz := Nat.ne_of_gt <| Nat.mul_pos (Nat.div_gcd_pos_of_pos_left _ a.den_pos) b.den_pos
|
||||
have e : g1 = num.natAbs.gcd den := sub.aux a b rfl rfl rfl
|
||||
Rat.maybeNormalize num den g1 (normalize.dvd_num e) (normalize.dvd_den e)
|
||||
(normalize.den_nz den_nz e) (normalize.reduced den_nz e)
|
||||
|
||||
instance : Sub Rat := ⟨Rat.sub⟩
|
||||
|
||||
/-- The floor of a rational number `a` is the largest integer less than or equal to `a`. -/
|
||||
protected def floor (a : Rat) : Int :=
|
||||
if a.den = 1 then
|
||||
a.num
|
||||
else
|
||||
a.num / a.den
|
||||
|
||||
/-- The ceiling of a rational number `a` is the smallest integer greater than or equal to `a`. -/
|
||||
protected def ceil (a : Rat) : Int :=
|
||||
if a.den = 1 then
|
||||
a.num
|
||||
else
|
||||
a.num / a.den + 1
|
||||
|
||||
end Rat
|
||||
388
src/Init/Data/Rat/Lemmas.lean
Normal file
388
src/Init/Data/Rat/Lemmas.lean
Normal file
@@ -0,0 +1,388 @@
|
||||
/-
|
||||
Copyright (c) 2022 Mario Carneiro. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mario Carneiro
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
|
||||
public import Init.Data.Rat.Basic
|
||||
|
||||
@[expose] public section
|
||||
|
||||
/-! # Additional lemmas about the Rational Numbers -/
|
||||
|
||||
namespace Rat
|
||||
|
||||
-- This is not marked as an `@[ext]` lemma as this is rarely useful for rational numbers.
|
||||
theorem ext : {p q : Rat} → p.num = q.num → p.den = q.den → p = q
|
||||
| ⟨_,_,_,_⟩, ⟨_,_,_,_⟩, rfl, rfl => rfl
|
||||
|
||||
@[simp] theorem mk_den_one {r : Int} :
|
||||
⟨r, 1, Nat.one_ne_zero, (Nat.coprime_one_right _)⟩ = (r : Rat) := rfl
|
||||
|
||||
@[simp] theorem zero_num : (0 : Rat).num = 0 := rfl
|
||||
@[simp] theorem zero_den : (0 : Rat).den = 1 := rfl
|
||||
@[simp] theorem one_num : (1 : Rat).num = 1 := rfl
|
||||
@[simp] theorem one_den : (1 : Rat).den = 1 := rfl
|
||||
|
||||
@[simp] theorem maybeNormalize_eq {num den g} (dvd_num dvd_den den_nz reduced) :
|
||||
maybeNormalize num den g dvd_num dvd_den den_nz reduced =
|
||||
{ num := num.divExact g dvd_num, den := den / g, den_nz, reduced } := by
|
||||
unfold maybeNormalize; split
|
||||
· subst g; simp
|
||||
· rfl
|
||||
|
||||
theorem normalize_eq {num den} (den_nz) : normalize num den den_nz =
|
||||
{ num := num / num.natAbs.gcd den
|
||||
den := den / num.natAbs.gcd den
|
||||
den_nz := normalize.den_nz den_nz rfl
|
||||
reduced := normalize.reduced den_nz rfl } := by
|
||||
simp only [normalize, maybeNormalize_eq, Int.divExact_eq_ediv]
|
||||
|
||||
@[simp] theorem normalize_zero (nz) : normalize 0 d nz = 0 := by
|
||||
simp [normalize, Int.natAbs_zero, Nat.div_self (Nat.pos_of_ne_zero nz)]; rfl
|
||||
|
||||
theorem mk_eq_normalize (num den nz c) : ⟨num, den, nz, c⟩ = normalize num den nz := by
|
||||
simp [normalize_eq, c.gcd_eq_one]
|
||||
|
||||
theorem normalize_self (r : Rat) : normalize r.num r.den r.den_nz = r := (mk_eq_normalize ..).symm
|
||||
|
||||
theorem normalize_mul_left {a : Nat} (d0 : d ≠ 0) (a0 : a ≠ 0) :
|
||||
normalize (↑a * n) (a * d) (Nat.mul_ne_zero a0 d0) = normalize n d d0 := by
|
||||
simp [normalize_eq, Int.natAbs_mul, Nat.gcd_mul_left,
|
||||
Nat.mul_div_mul_left _ _ (Nat.pos_of_ne_zero a0), Int.natCast_mul,
|
||||
Int.mul_ediv_mul_of_pos _ _ (Int.natCast_pos.2 <| Nat.pos_of_ne_zero a0)]
|
||||
|
||||
theorem normalize_mul_right {a : Nat} (d0 : d ≠ 0) (a0 : a ≠ 0) :
|
||||
normalize (n * a) (d * a) (Nat.mul_ne_zero d0 a0) = normalize n d d0 := by
|
||||
rw [← normalize_mul_left (d0 := d0) a0]
|
||||
congr 1
|
||||
· apply Int.mul_comm
|
||||
· apply Nat.mul_comm
|
||||
|
||||
theorem normalize_eq_iff (z₁ : d₁ ≠ 0) (z₂ : d₂ ≠ 0) :
|
||||
normalize n₁ d₁ z₁ = normalize n₂ d₂ z₂ ↔ n₁ * d₂ = n₂ * d₁ := by
|
||||
constructor <;> intro h
|
||||
· simp only [normalize_eq, mk'.injEq] at h
|
||||
have hn₁ := Int.ofNat_dvd_left.2 <| Nat.gcd_dvd_left n₁.natAbs d₁
|
||||
have hn₂ := Int.ofNat_dvd_left.2 <| Nat.gcd_dvd_left n₂.natAbs d₂
|
||||
have hd₁ := Int.ofNat_dvd.2 <| Nat.gcd_dvd_right n₁.natAbs d₁
|
||||
have hd₂ := Int.ofNat_dvd.2 <| Nat.gcd_dvd_right n₂.natAbs d₂
|
||||
rw [← Int.ediv_mul_cancel (Int.dvd_trans hd₂ (Int.dvd_mul_left ..)),
|
||||
Int.mul_ediv_assoc _ hd₂, ← Int.natCast_ediv, ← h.2, Int.natCast_ediv,
|
||||
← Int.mul_ediv_assoc _ hd₁, Int.mul_ediv_assoc' _ hn₁,
|
||||
Int.mul_right_comm, h.1, Int.ediv_mul_cancel hn₂]
|
||||
· rw [← normalize_mul_right _ z₂, ← normalize_mul_left z₂ z₁, Int.mul_comm d₁, h]
|
||||
|
||||
theorem maybeNormalize_eq_normalize {num : Int} {den g : Nat} (dvd_num dvd_den den_nz reduced)
|
||||
(hn : ↑g ∣ num) (hd : g ∣ den) :
|
||||
maybeNormalize num den g dvd_num dvd_den den_nz reduced =
|
||||
normalize num den (mt (by simp [·]) den_nz) := by
|
||||
simp only [maybeNormalize_eq, mk_eq_normalize, Int.divExact_eq_ediv]
|
||||
have : g ≠ 0 := mt (by simp [·]) den_nz
|
||||
rw [← normalize_mul_right _ this, Int.ediv_mul_cancel hn]
|
||||
congr 1; exact Nat.div_mul_cancel hd
|
||||
|
||||
@[simp] theorem normalize_eq_zero (d0 : d ≠ 0) : normalize n d d0 = 0 ↔ n = 0 := by
|
||||
have' := normalize_eq_iff d0 Nat.one_ne_zero
|
||||
rw [normalize_zero (d := 1)] at this; rw [this]; simp
|
||||
|
||||
theorem normalize_num_den' (num den nz) : ∃ d : Nat, d ≠ 0 ∧
|
||||
num = (normalize num den nz).num * d ∧ den = (normalize num den nz).den * d := by
|
||||
refine ⟨num.natAbs.gcd den, Nat.gcd_ne_zero_right nz, ?_⟩
|
||||
simp [normalize_eq, Int.ediv_mul_cancel (Int.ofNat_dvd_left.2 <| Nat.gcd_dvd_left ..),
|
||||
Nat.div_mul_cancel (Nat.gcd_dvd_right ..)]
|
||||
|
||||
theorem normalize_num_den (h : normalize n d z = ⟨n', d', z', c⟩) :
|
||||
∃ m : Nat, m ≠ 0 ∧ n = n' * m ∧ d = d' * m := by
|
||||
have := normalize_num_den' n d z; rwa [h] at this
|
||||
|
||||
theorem normalize_eq_mkRat {num den} (den_nz) : normalize num den den_nz = mkRat num den := by
|
||||
simp [mkRat, den_nz]
|
||||
|
||||
theorem mkRat_num_den (z : d ≠ 0) (h : mkRat n d = ⟨n', d', z', c⟩) :
|
||||
∃ m : Nat, m ≠ 0 ∧ n = n' * m ∧ d = d' * m :=
|
||||
normalize_num_den ((normalize_eq_mkRat z).symm ▸ h)
|
||||
|
||||
theorem mkRat_def (n d) : mkRat n d = if d0 : d = 0 then 0 else normalize n d d0 := rfl
|
||||
|
||||
theorem mkRat_self (a : Rat) : mkRat a.num a.den = a := by
|
||||
rw [← normalize_eq_mkRat a.den_nz, normalize_self]
|
||||
|
||||
theorem mk_eq_mkRat (num den nz c) : ⟨num, den, nz, c⟩ = mkRat num den := by
|
||||
simp [mk_eq_normalize, normalize_eq_mkRat]
|
||||
|
||||
@[simp] theorem zero_mkRat (n) : mkRat 0 n = 0 := by simp [mkRat_def]
|
||||
|
||||
@[simp] theorem mkRat_zero (n) : mkRat n 0 = 0 := by simp [mkRat_def]
|
||||
|
||||
theorem mkRat_eq_zero (d0 : d ≠ 0) : mkRat n d = 0 ↔ n = 0 := by simp [mkRat_def, d0]
|
||||
|
||||
theorem mkRat_ne_zero (d0 : d ≠ 0) : mkRat n d ≠ 0 ↔ n ≠ 0 := not_congr (mkRat_eq_zero d0)
|
||||
|
||||
theorem mkRat_mul_left {a : Nat} (a0 : a ≠ 0) : mkRat (↑a * n) (a * d) = mkRat n d := by
|
||||
if d0 : d = 0 then simp [d0] else
|
||||
rw [← normalize_eq_mkRat d0, ← normalize_mul_left d0 a0, normalize_eq_mkRat]
|
||||
|
||||
theorem mkRat_mul_right {a : Nat} (a0 : a ≠ 0) : mkRat (n * a) (d * a) = mkRat n d := by
|
||||
rw [← mkRat_mul_left (d := d) a0]
|
||||
congr 1
|
||||
· apply Int.mul_comm
|
||||
· apply Nat.mul_comm
|
||||
|
||||
theorem mkRat_eq_iff (z₁ : d₁ ≠ 0) (z₂ : d₂ ≠ 0) :
|
||||
mkRat n₁ d₁ = mkRat n₂ d₂ ↔ n₁ * d₂ = n₂ * d₁ := by
|
||||
rw [← normalize_eq_mkRat z₁, ← normalize_eq_mkRat z₂, normalize_eq_iff]
|
||||
|
||||
@[simp] theorem divInt_ofNat (num den) : num /. (den : Nat) = mkRat num den := by
|
||||
simp [divInt]
|
||||
|
||||
theorem mk_eq_divInt (num den nz c) : ⟨num, den, nz, c⟩ = num /. (den : Nat) := by
|
||||
simp [mk_eq_mkRat]
|
||||
|
||||
theorem divInt_self (a : Rat) : a.num /. a.den = a := by rw [divInt_ofNat, mkRat_self]
|
||||
|
||||
@[simp] theorem zero_divInt (n) : 0 /. n = 0 := by cases n <;> simp [divInt]
|
||||
|
||||
@[simp] theorem divInt_zero (n) : n /. 0 = 0 := mkRat_zero n
|
||||
|
||||
theorem neg_divInt_neg (num den) : -num /. -den = num /. den := by
|
||||
match den with
|
||||
| Nat.succ n =>
|
||||
simp only [divInt, Int.neg_ofNat_succ]
|
||||
simp [normalize_eq_mkRat, Int.neg_neg]
|
||||
| 0 => rfl
|
||||
| Int.negSucc n =>
|
||||
simp only [divInt, Int.neg_negSucc]
|
||||
simp [normalize_eq_mkRat]
|
||||
|
||||
theorem divInt_neg' (num den) : num /. -den = -num /. den := by rw [← neg_divInt_neg, Int.neg_neg]
|
||||
|
||||
theorem divInt_eq_iff (z₁ : d₁ ≠ 0) (z₂ : d₂ ≠ 0) :
|
||||
n₁ /. d₁ = n₂ /. d₂ ↔ n₁ * d₂ = n₂ * d₁ := by
|
||||
rcases Int.eq_nat_or_neg d₁ with ⟨_, rfl | rfl⟩ <;>
|
||||
rcases Int.eq_nat_or_neg d₂ with ⟨_, rfl | rfl⟩ <;>
|
||||
simp_all [divInt_neg', Int.neg_eq_zero,
|
||||
mkRat_eq_iff, Int.neg_mul, Int.mul_neg, Int.eq_neg_comm, eq_comm]
|
||||
|
||||
theorem divInt_mul_left {a : Int} (a0 : a ≠ 0) : (a * n) /. (a * d) = n /. d := by
|
||||
if d0 : d = 0 then simp [d0] else
|
||||
simp [divInt_eq_iff (Int.mul_ne_zero a0 d0) d0, Int.mul_assoc, Int.mul_left_comm]
|
||||
|
||||
theorem divInt_mul_right {a : Int} (a0 : a ≠ 0) : (n * a) /. (d * a) = n /. d := by
|
||||
simp [← divInt_mul_left (d := d) a0, Int.mul_comm]
|
||||
|
||||
theorem divInt_num_den (z : d ≠ 0) (h : n /. d = ⟨n', d', z', c⟩) :
|
||||
∃ m, m ≠ 0 ∧ n = n' * m ∧ d = d' * m := by
|
||||
rcases Int.eq_nat_or_neg d with ⟨_, rfl | rfl⟩ <;>
|
||||
simp_all [divInt_neg', Int.neg_eq_zero]
|
||||
· have ⟨m, h₁, h₂⟩ := mkRat_num_den z h; exists m
|
||||
simp [Int.natCast_mul, h₁, h₂]
|
||||
· have ⟨m, h₁, h₂⟩ := mkRat_num_den z h; exists -m
|
||||
rw [← Int.neg_inj, Int.neg_neg] at h₂
|
||||
simp [Int.natCast_mul, h₁, h₂, Int.mul_neg, Int.neg_eq_zero]
|
||||
|
||||
@[simp] theorem ofInt_ofNat : ofInt (OfNat.ofNat n) = OfNat.ofNat n := rfl
|
||||
|
||||
@[simp] theorem ofInt_num : (ofInt n : Rat).num = n := rfl
|
||||
@[simp] theorem ofInt_den : (ofInt n : Rat).den = 1 := rfl
|
||||
|
||||
@[simp] theorem ofNat_num : (OfNat.ofNat n : Rat).num = OfNat.ofNat n := rfl
|
||||
@[simp] theorem ofNat_den : (OfNat.ofNat n : Rat).den = 1 := rfl
|
||||
|
||||
theorem add_def (a b : Rat) :
|
||||
a + b = normalize (a.num * b.den + b.num * a.den) (a.den * b.den)
|
||||
(Nat.mul_ne_zero a.den_nz b.den_nz) := by
|
||||
show Rat.add .. = _; delta Rat.add; dsimp only; split
|
||||
· exact (normalize_self _).symm
|
||||
· have : a.den.gcd b.den ≠ 0 := Nat.gcd_ne_zero_left a.den_nz
|
||||
rw [maybeNormalize_eq_normalize _ _ _ _
|
||||
(Int.ofNat_dvd_left.2 <| Nat.gcd_dvd_left ..)
|
||||
(Nat.dvd_trans (Nat.gcd_dvd_right ..) <|
|
||||
Nat.dvd_trans (Nat.gcd_dvd_right ..) (Nat.dvd_mul_left ..)),
|
||||
← normalize_mul_right _ this]; congr 1
|
||||
· simp only [Int.add_mul, Int.mul_assoc, Int.ofNat_mul_ofNat,
|
||||
Nat.div_mul_cancel (Nat.gcd_dvd_left ..), Nat.div_mul_cancel (Nat.gcd_dvd_right ..)]
|
||||
· rw [Nat.mul_right_comm, Nat.div_mul_cancel (Nat.gcd_dvd_left ..)]
|
||||
|
||||
theorem add_def' (a b : Rat) : a + b = mkRat (a.num * b.den + b.num * a.den) (a.den * b.den) := by
|
||||
rw [add_def, normalize_eq_mkRat]
|
||||
|
||||
theorem normalize_add_normalize (n₁ n₂) {d₁ d₂} (z₁ z₂) :
|
||||
normalize n₁ d₁ z₁ + normalize n₂ d₂ z₂ =
|
||||
normalize (n₁ * d₂ + n₂ * d₁) (d₁ * d₂) (Nat.mul_ne_zero z₁ z₂) := by
|
||||
cases e₁ : normalize n₁ d₁ z₁; rcases normalize_num_den e₁ with ⟨g₁, zg₁, rfl, rfl⟩
|
||||
cases e₂ : normalize n₂ d₂ z₂; rcases normalize_num_den e₂ with ⟨g₂, zg₂, rfl, rfl⟩
|
||||
simp only [add_def]; rw [← normalize_mul_right _ (Nat.mul_ne_zero zg₁ zg₂)]; congr 1
|
||||
· rw [Int.add_mul]; simp [Int.natCast_mul, Int.mul_assoc, Int.mul_left_comm, Int.mul_comm]
|
||||
· simp [Nat.mul_left_comm, Nat.mul_comm]
|
||||
|
||||
theorem mkRat_add_mkRat (n₁ n₂ : Int) {d₁ d₂} (z₁ : d₁ ≠ 0) (z₂ : d₂ ≠ 0) :
|
||||
mkRat n₁ d₁ + mkRat n₂ d₂ = mkRat (n₁ * d₂ + n₂ * d₁) (d₁ * d₂) := by
|
||||
rw [← normalize_eq_mkRat z₁, ← normalize_eq_mkRat z₂, normalize_add_normalize, normalize_eq_mkRat]
|
||||
|
||||
theorem divInt_add_divInt (n₁ n₂ : Int) {d₁ d₂} (z₁ : d₁ ≠ 0) (z₂ : d₂ ≠ 0) :
|
||||
n₁ /. d₁ + n₂ /. d₂ = (n₁ * d₂ + n₂ * d₁) /. (d₁ * d₂) := by
|
||||
rcases Int.eq_nat_or_neg d₁ with ⟨_, rfl | rfl⟩ <;>
|
||||
rcases Int.eq_nat_or_neg d₂ with ⟨_, rfl | rfl⟩ <;>
|
||||
simp_all [← Int.natCast_mul, Int.neg_eq_zero, divInt_neg', Int.mul_neg,
|
||||
Int.neg_add, Int.neg_mul, mkRat_add_mkRat]
|
||||
|
||||
@[simp] theorem neg_num (a : Rat) : (-a).num = -a.num := rfl
|
||||
@[simp] theorem neg_den (a : Rat) : (-a).den = a.den := rfl
|
||||
|
||||
theorem neg_normalize (n d z) : -normalize n d z = normalize (-n) d z := by
|
||||
simp only [normalize, maybeNormalize_eq, Int.divExact_eq_tdiv, Int.natAbs_neg, Int.neg_tdiv]
|
||||
rfl
|
||||
|
||||
theorem neg_mkRat (n d) : -mkRat n d = mkRat (-n) d := by
|
||||
if z : d = 0 then simp [z]; rfl else simp [← normalize_eq_mkRat z, neg_normalize]
|
||||
|
||||
theorem neg_divInt (n d) : -(n /. d) = -n /. d := by
|
||||
rcases Int.eq_nat_or_neg d with ⟨_, rfl | rfl⟩ <;> simp [divInt_neg', neg_mkRat]
|
||||
|
||||
theorem sub_def (a b : Rat) :
|
||||
a - b = normalize (a.num * b.den - b.num * a.den) (a.den * b.den)
|
||||
(Nat.mul_ne_zero a.den_nz b.den_nz) := by
|
||||
show Rat.sub .. = _; delta Rat.sub; dsimp only; split
|
||||
· exact (normalize_self _).symm
|
||||
· have : a.den.gcd b.den ≠ 0 := Nat.gcd_ne_zero_left a.den_nz
|
||||
rw [maybeNormalize_eq_normalize _ _ _ _
|
||||
(Int.ofNat_dvd_left.2 <| Nat.gcd_dvd_left ..)
|
||||
(Nat.dvd_trans (Nat.gcd_dvd_right ..) <|
|
||||
Nat.dvd_trans (Nat.gcd_dvd_right ..) (Nat.dvd_mul_left ..)),
|
||||
← normalize_mul_right _ this]; congr 1
|
||||
· simp only [Int.sub_mul, Int.mul_assoc, ← Int.natCast_mul,
|
||||
Nat.div_mul_cancel (Nat.gcd_dvd_left ..), Nat.div_mul_cancel (Nat.gcd_dvd_right ..)]
|
||||
· rw [Nat.mul_right_comm, Nat.div_mul_cancel (Nat.gcd_dvd_left ..)]
|
||||
|
||||
theorem sub_def' (a b : Rat) : a - b = mkRat (a.num * b.den - b.num * a.den) (a.den * b.den) := by
|
||||
rw [sub_def, normalize_eq_mkRat]
|
||||
|
||||
protected theorem sub_eq_add_neg (a b : Rat) : a - b = a + -b := by
|
||||
simp [add_def, sub_def, Int.neg_mul, Int.sub_eq_add_neg]
|
||||
|
||||
theorem divInt_sub_divInt (n₁ n₂ : Int) {d₁ d₂} (z₁ : d₁ ≠ 0) (z₂ : d₂ ≠ 0) :
|
||||
n₁ /. d₁ - n₂ /. d₂ = (n₁ * d₂ - n₂ * d₁) /. (d₁ * d₂) := by
|
||||
simp only [Rat.sub_eq_add_neg, neg_divInt,
|
||||
divInt_add_divInt _ _ z₁ z₂, Int.neg_mul, Int.sub_eq_add_neg]
|
||||
|
||||
theorem mul_def (a b : Rat) :
|
||||
a * b = normalize (a.num * b.num) (a.den * b.den) (Nat.mul_ne_zero a.den_nz b.den_nz) := by
|
||||
show Rat.mul .. = _; delta Rat.mul; dsimp only
|
||||
have H1 : a.num.natAbs.gcd b.den ≠ 0 := Nat.gcd_ne_zero_right b.den_nz
|
||||
have H2 : b.num.natAbs.gcd a.den ≠ 0 := Nat.gcd_ne_zero_right a.den_nz
|
||||
simp only [Int.divExact_eq_tdiv, Nat.divExact_eq_div]
|
||||
rw [mk_eq_normalize, ← normalize_mul_right _ (Nat.mul_ne_zero H1 H2)]; congr 1
|
||||
· rw [Int.natCast_mul, ← Int.mul_assoc, Int.mul_right_comm (Int.tdiv ..),
|
||||
Int.tdiv_mul_cancel (Int.ofNat_dvd_left.2 <| Nat.gcd_dvd_left ..), Int.mul_assoc,
|
||||
Int.tdiv_mul_cancel (Int.ofNat_dvd_left.2 <| Nat.gcd_dvd_left ..)]
|
||||
· rw [← Nat.mul_assoc, Nat.mul_right_comm, Nat.mul_right_comm (_/_),
|
||||
Nat.div_mul_cancel (Nat.gcd_dvd_right ..), Nat.mul_assoc,
|
||||
Nat.div_mul_cancel (Nat.gcd_dvd_right ..)]
|
||||
|
||||
theorem mul_def' (a b : Rat) : a * b = mkRat (a.num * b.num) (a.den * b.den) := by
|
||||
rw [mul_def, normalize_eq_mkRat]
|
||||
|
||||
protected theorem mul_comm (a b : Rat) : a * b = b * a := by
|
||||
simp [mul_def, normalize_eq_mkRat, Int.mul_comm, Nat.mul_comm]
|
||||
|
||||
@[simp] protected theorem zero_mul (a : Rat) : 0 * a = 0 := by simp [mul_def]
|
||||
@[simp] protected theorem mul_zero (a : Rat) : a * 0 = 0 := by simp [mul_def]
|
||||
@[simp] protected theorem one_mul (a : Rat) : 1 * a = a := by simp [mul_def, normalize_self]
|
||||
@[simp] protected theorem mul_one (a : Rat) : a * 1 = a := by simp [mul_def, normalize_self]
|
||||
|
||||
theorem normalize_mul_normalize (n₁ n₂) {d₁ d₂} (z₁ z₂) :
|
||||
normalize n₁ d₁ z₁ * normalize n₂ d₂ z₂ =
|
||||
normalize (n₁ * n₂) (d₁ * d₂) (Nat.mul_ne_zero z₁ z₂) := by
|
||||
cases e₁ : normalize n₁ d₁ z₁; rcases normalize_num_den e₁ with ⟨g₁, zg₁, rfl, rfl⟩
|
||||
cases e₂ : normalize n₂ d₂ z₂; rcases normalize_num_den e₂ with ⟨g₂, zg₂, rfl, rfl⟩
|
||||
simp only [mul_def]; rw [← normalize_mul_right _ (Nat.mul_ne_zero zg₁ zg₂)]; congr 1
|
||||
· simp [Int.natCast_mul, Int.mul_assoc, Int.mul_left_comm]
|
||||
· simp [Nat.mul_left_comm, Nat.mul_comm]
|
||||
|
||||
theorem mkRat_mul_mkRat (n₁ n₂ : Int) (d₁ d₂) :
|
||||
mkRat n₁ d₁ * mkRat n₂ d₂ = mkRat (n₁ * n₂) (d₁ * d₂) := by
|
||||
if z₁ : d₁ = 0 then simp [z₁] else if z₂ : d₂ = 0 then simp [z₂] else
|
||||
rw [← normalize_eq_mkRat z₁, ← normalize_eq_mkRat z₂, normalize_mul_normalize, normalize_eq_mkRat]
|
||||
|
||||
theorem divInt_mul_divInt (n₁ n₂ : Int) {d₁ d₂} (z₁ : d₁ ≠ 0) (z₂ : d₂ ≠ 0) :
|
||||
(n₁ /. d₁) * (n₂ /. d₂) = (n₁ * n₂) /. (d₁ * d₂) := by
|
||||
rcases Int.eq_nat_or_neg d₁ with ⟨_, rfl | rfl⟩ <;>
|
||||
rcases Int.eq_nat_or_neg d₂ with ⟨_, rfl | rfl⟩ <;>
|
||||
simp_all [← Int.natCast_mul, divInt_neg', Int.mul_neg, Int.neg_mul, mkRat_mul_mkRat]
|
||||
|
||||
theorem inv_def (a : Rat) : a.inv = (a.den : Int) /. a.num := by
|
||||
unfold Rat.inv; split
|
||||
· next h => rw [mk_eq_divInt, ← Int.natAbs_neg,
|
||||
Int.natAbs_of_nonneg (Int.le_of_lt <| Int.neg_pos_of_neg h), neg_divInt_neg]
|
||||
split
|
||||
· next h => rw [mk_eq_divInt, Int.natAbs_of_nonneg (Int.le_of_lt h)]
|
||||
· next h₁ h₂ =>
|
||||
apply (divInt_self _).symm.trans
|
||||
simp [Int.le_antisymm (Int.not_lt.1 h₂) (Int.not_lt.1 h₁)]
|
||||
|
||||
@[simp] protected theorem inv_zero : (0 : Rat).inv = 0 := by unfold Rat.inv; rfl
|
||||
|
||||
@[simp] theorem inv_divInt (n d : Int) : (n /. d).inv = d /. n := by
|
||||
if z : d = 0 then simp [z] else
|
||||
cases e : n /. d; rcases divInt_num_den z e with ⟨g, zg, rfl, rfl⟩
|
||||
simp [inv_def, divInt_mul_right zg]
|
||||
|
||||
theorem div_def (a b : Rat) : a / b = a * b.inv := rfl
|
||||
|
||||
/-! ### `ofScientific` -/
|
||||
|
||||
theorem ofScientific_true_def : Rat.ofScientific m true e = mkRat m (10 ^ e) := by
|
||||
unfold Rat.ofScientific; rw [normalize_eq_mkRat]; rfl
|
||||
|
||||
theorem ofScientific_false_def : Rat.ofScientific m false e = (m * 10 ^ e : Nat) := by
|
||||
unfold Rat.ofScientific; rfl
|
||||
|
||||
theorem ofScientific_def : Rat.ofScientific m s e =
|
||||
if s then mkRat m (10 ^ e) else (m * 10 ^ e : Nat) := by
|
||||
cases s; exact ofScientific_false_def; exact ofScientific_true_def
|
||||
|
||||
/-- `Rat.ofScientific` applied to numeric literals is the same as a scientific literal. -/
|
||||
@[simp]
|
||||
theorem ofScientific_ofNat_ofNat :
|
||||
Rat.ofScientific (no_index (OfNat.ofNat m)) s (no_index (OfNat.ofNat e))
|
||||
= OfScientific.ofScientific m s e := rfl
|
||||
|
||||
/-! ### `intCast` -/
|
||||
|
||||
@[simp] theorem intCast_den (a : Int) : (a : Rat).den = 1 := rfl
|
||||
|
||||
@[simp] theorem intCast_num (a : Int) : (a : Rat).num = a := rfl
|
||||
|
||||
/-!
|
||||
The following lemmas are later subsumed by e.g. `Int.cast_add` and `Int.cast_mul` in Mathlib
|
||||
but it is convenient to have these earlier, for users who only need `Int` and `Rat`.
|
||||
-/
|
||||
|
||||
@[simp, norm_cast] theorem intCast_inj {a b : Int} : (a : Rat) = (b : Rat) ↔ a = b := by
|
||||
constructor
|
||||
· rintro ⟨⟩; rfl
|
||||
· simp_all
|
||||
|
||||
theorem intCast_zero : ((0 : Int) : Rat) = (0 : Rat) := rfl
|
||||
|
||||
theorem intCast_one : ((1 : Int) : Rat) = (1 : Rat) := rfl
|
||||
|
||||
@[simp, norm_cast] theorem intCast_add (a b : Int) :
|
||||
((a + b : Int) : Rat) = (a : Rat) + (b : Rat) := by
|
||||
rw [add_def]
|
||||
simp [normalize_eq]
|
||||
|
||||
@[simp, norm_cast] theorem intCast_neg (a : Int) : ((-a : Int) : Rat) = -(a : Rat) := rfl
|
||||
|
||||
@[simp, norm_cast] theorem intCast_sub (a b : Int) :
|
||||
((a - b : Int) : Rat) = (a : Rat) - (b : Rat) := by
|
||||
rw [sub_def]
|
||||
simp [normalize_eq]
|
||||
|
||||
@[simp, norm_cast] theorem intCast_mul (a b : Int) :
|
||||
((a * b : Int) : Rat) = (a : Rat) * (b : Rat) := by
|
||||
rw [mul_def]
|
||||
simp [normalize_eq]
|
||||
@@ -15,9 +15,12 @@ public import Init.Data.Int.LemmasAux
|
||||
public import all Init.Data.UInt.Basic
|
||||
public import Init.Data.UInt.Lemmas
|
||||
public import Init.System.Platform
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
|
||||
open Lean in
|
||||
set_option hygiene false in
|
||||
macro "declare_int_theorems" typeName:ident _bits:term:arg : command => do
|
||||
@@ -85,11 +88,11 @@ theorem Int64.toInt_inj {x y : Int64} : x.toInt = y.toInt ↔ x = y := ⟨Int64.
|
||||
theorem ISize.toInt.inj {x y : ISize} (h : x.toInt = y.toInt) : x = y := ISize.toBitVec.inj (BitVec.eq_of_toInt_eq h)
|
||||
theorem ISize.toInt_inj {x y : ISize} : x.toInt = y.toInt ↔ x = y := ⟨ISize.toInt.inj, fun h => h ▸ rfl⟩
|
||||
|
||||
@[simp] theorem Int8.toBitVec_neg (x : Int8) : (-x).toBitVec = -x.toBitVec := (rfl)
|
||||
@[simp] theorem Int16.toBitVec_neg (x : Int16) : (-x).toBitVec = -x.toBitVec := (rfl)
|
||||
@[simp] theorem Int32.toBitVec_neg (x : Int32) : (-x).toBitVec = -x.toBitVec := (rfl)
|
||||
@[simp] theorem Int64.toBitVec_neg (x : Int64) : (-x).toBitVec = -x.toBitVec := (rfl)
|
||||
@[simp] theorem ISize.toBitVec_neg (x : ISize) : (-x).toBitVec = -x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int8.toBitVec_neg (x : Int8) : (-x).toBitVec = -x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int16.toBitVec_neg (x : Int16) : (-x).toBitVec = -x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int32.toBitVec_neg (x : Int32) : (-x).toBitVec = -x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int64.toBitVec_neg (x : Int64) : (-x).toBitVec = -x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem ISize.toBitVec_neg (x : ISize) : (-x).toBitVec = -x.toBitVec := (rfl)
|
||||
|
||||
@[simp] theorem Int8.toBitVec_zero : toBitVec 0 = 0#8 := (rfl)
|
||||
@[simp] theorem Int16.toBitVec_zero : toBitVec 0 = 0#16 := (rfl)
|
||||
@@ -103,11 +106,11 @@ theorem Int32.toBitVec_one : (1 : Int32).toBitVec = 1#32 := (rfl)
|
||||
theorem Int64.toBitVec_one : (1 : Int64).toBitVec = 1#64 := (rfl)
|
||||
theorem ISize.toBitVec_one : (1 : ISize).toBitVec = 1#System.Platform.numBits := (rfl)
|
||||
|
||||
@[simp] theorem Int8.toBitVec_ofInt (i : Int) : (ofInt i).toBitVec = BitVec.ofInt _ i := (rfl)
|
||||
@[simp] theorem Int16.toBitVec_ofInt (i : Int) : (ofInt i).toBitVec = BitVec.ofInt _ i := (rfl)
|
||||
@[simp] theorem Int32.toBitVec_ofInt (i : Int) : (ofInt i).toBitVec = BitVec.ofInt _ i := (rfl)
|
||||
@[simp] theorem Int64.toBitVec_ofInt (i : Int) : (ofInt i).toBitVec = BitVec.ofInt _ i := (rfl)
|
||||
@[simp] theorem ISize.toBitVec_ofInt (i : Int) : (ofInt i).toBitVec = BitVec.ofInt _ i := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int8.toBitVec_ofInt (i : Int) : (ofInt i).toBitVec = BitVec.ofInt _ i := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int16.toBitVec_ofInt (i : Int) : (ofInt i).toBitVec = BitVec.ofInt _ i := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int32.toBitVec_ofInt (i : Int) : (ofInt i).toBitVec = BitVec.ofInt _ i := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int64.toBitVec_ofInt (i : Int) : (ofInt i).toBitVec = BitVec.ofInt _ i := (rfl)
|
||||
@[simp, int_toBitVec] theorem ISize.toBitVec_ofInt (i : Int) : (ofInt i).toBitVec = BitVec.ofInt _ i := (rfl)
|
||||
|
||||
@[simp] protected theorem Int8.neg_zero : -(0 : Int8) = 0 := (rfl)
|
||||
@[simp] protected theorem Int16.neg_zero : -(0 : Int16) = 0 := (rfl)
|
||||
@@ -271,11 +274,11 @@ theorem ISize.toInt_maxValue : ISize.maxValue.toInt = 2 ^ (System.Platform.numBi
|
||||
rw [toNatClampNeg, toInt_minValue]
|
||||
cases System.Platform.numBits_eq <;> simp_all
|
||||
|
||||
@[simp] theorem UInt8.toBitVec_toInt8 (x : UInt8) : x.toInt8.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp] theorem UInt16.toBitVec_toInt16 (x : UInt16) : x.toInt16.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp] theorem UInt32.toBitVec_toInt32 (x : UInt32) : x.toInt32.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp] theorem UInt64.toBitVec_toInt64 (x : UInt64) : x.toInt64.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp] theorem USize.toBitVec_toISize (x : USize) : x.toISize.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem UInt8.toBitVec_toInt8 (x : UInt8) : x.toInt8.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem UInt16.toBitVec_toInt16 (x : UInt16) : x.toInt16.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem UInt32.toBitVec_toInt32 (x : UInt32) : x.toInt32.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem UInt64.toBitVec_toInt64 (x : UInt64) : x.toInt64.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem USize.toBitVec_toISize (x : USize) : x.toISize.toBitVec = x.toBitVec := (rfl)
|
||||
|
||||
@[simp] theorem Int8.ofBitVec_uInt8ToBitVec (x : UInt8) : Int8.ofBitVec x.toBitVec = x.toInt8 := (rfl)
|
||||
@[simp] theorem Int16.ofBitVec_uInt16ToBitVec (x : UInt16) : Int16.ofBitVec x.toBitVec = x.toInt16 := (rfl)
|
||||
@@ -301,30 +304,30 @@ theorem ISize.toInt_maxValue : ISize.maxValue.toInt = 2 ^ (System.Platform.numBi
|
||||
@[simp] theorem Int64.toInt_toBitVec (x : Int64) : x.toBitVec.toInt = x.toInt := (rfl)
|
||||
@[simp] theorem ISize.toInt_toBitVec (x : ISize) : x.toBitVec.toInt = x.toInt := (rfl)
|
||||
|
||||
@[simp] theorem Int8.toBitVec_toInt16 (x : Int8) : x.toInt16.toBitVec = x.toBitVec.signExtend 16 := (rfl)
|
||||
@[simp] theorem Int8.toBitVec_toInt32 (x : Int8) : x.toInt32.toBitVec = x.toBitVec.signExtend 32 := (rfl)
|
||||
@[simp] theorem Int8.toBitVec_toInt64 (x : Int8) : x.toInt64.toBitVec = x.toBitVec.signExtend 64 := (rfl)
|
||||
@[simp] theorem Int8.toBitVec_toISize (x : Int8) : x.toISize.toBitVec = x.toBitVec.signExtend System.Platform.numBits := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int8.toBitVec_toInt16 (x : Int8) : x.toInt16.toBitVec = x.toBitVec.signExtend 16 := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int8.toBitVec_toInt32 (x : Int8) : x.toInt32.toBitVec = x.toBitVec.signExtend 32 := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int8.toBitVec_toInt64 (x : Int8) : x.toInt64.toBitVec = x.toBitVec.signExtend 64 := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int8.toBitVec_toISize (x : Int8) : x.toISize.toBitVec = x.toBitVec.signExtend System.Platform.numBits := (rfl)
|
||||
|
||||
@[simp] theorem Int16.toBitVec_toInt8 (x : Int16) : x.toInt8.toBitVec = x.toBitVec.signExtend 8 := (rfl)
|
||||
@[simp] theorem Int16.toBitVec_toInt32 (x : Int16) : x.toInt32.toBitVec = x.toBitVec.signExtend 32 := (rfl)
|
||||
@[simp] theorem Int16.toBitVec_toInt64 (x : Int16) : x.toInt64.toBitVec = x.toBitVec.signExtend 64 := (rfl)
|
||||
@[simp] theorem Int16.toBitVec_toISize (x : Int16) : x.toISize.toBitVec = x.toBitVec.signExtend System.Platform.numBits := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int16.toBitVec_toInt8 (x : Int16) : x.toInt8.toBitVec = x.toBitVec.signExtend 8 := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int16.toBitVec_toInt32 (x : Int16) : x.toInt32.toBitVec = x.toBitVec.signExtend 32 := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int16.toBitVec_toInt64 (x : Int16) : x.toInt64.toBitVec = x.toBitVec.signExtend 64 := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int16.toBitVec_toISize (x : Int16) : x.toISize.toBitVec = x.toBitVec.signExtend System.Platform.numBits := (rfl)
|
||||
|
||||
@[simp] theorem Int32.toBitVec_toInt8 (x : Int32) : x.toInt8.toBitVec = x.toBitVec.signExtend 8 := (rfl)
|
||||
@[simp] theorem Int32.toBitVec_toInt16 (x : Int32) : x.toInt16.toBitVec = x.toBitVec.signExtend 16 := (rfl)
|
||||
@[simp] theorem Int32.toBitVec_toInt64 (x : Int32) : x.toInt64.toBitVec = x.toBitVec.signExtend 64 := (rfl)
|
||||
@[simp] theorem Int32.toBitVec_toISize (x : Int32) : x.toISize.toBitVec = x.toBitVec.signExtend System.Platform.numBits := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int32.toBitVec_toInt8 (x : Int32) : x.toInt8.toBitVec = x.toBitVec.signExtend 8 := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int32.toBitVec_toInt16 (x : Int32) : x.toInt16.toBitVec = x.toBitVec.signExtend 16 := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int32.toBitVec_toInt64 (x : Int32) : x.toInt64.toBitVec = x.toBitVec.signExtend 64 := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int32.toBitVec_toISize (x : Int32) : x.toISize.toBitVec = x.toBitVec.signExtend System.Platform.numBits := (rfl)
|
||||
|
||||
@[simp] theorem Int64.toBitVec_toInt8 (x : Int64) : x.toInt8.toBitVec = x.toBitVec.signExtend 8 := (rfl)
|
||||
@[simp] theorem Int64.toBitVec_toInt16 (x : Int64) : x.toInt16.toBitVec = x.toBitVec.signExtend 16 := (rfl)
|
||||
@[simp] theorem Int64.toBitVec_toInt32 (x : Int64) : x.toInt32.toBitVec = x.toBitVec.signExtend 32 := (rfl)
|
||||
@[simp] theorem Int64.toBitVec_toISize (x : Int64) : x.toISize.toBitVec = x.toBitVec.signExtend System.Platform.numBits := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int64.toBitVec_toInt8 (x : Int64) : x.toInt8.toBitVec = x.toBitVec.signExtend 8 := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int64.toBitVec_toInt16 (x : Int64) : x.toInt16.toBitVec = x.toBitVec.signExtend 16 := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int64.toBitVec_toInt32 (x : Int64) : x.toInt32.toBitVec = x.toBitVec.signExtend 32 := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int64.toBitVec_toISize (x : Int64) : x.toISize.toBitVec = x.toBitVec.signExtend System.Platform.numBits := (rfl)
|
||||
|
||||
@[simp] theorem ISize.toBitVec_toInt8 (x : ISize) : x.toInt8.toBitVec = x.toBitVec.signExtend 8 := (rfl)
|
||||
@[simp] theorem ISize.toBitVec_toInt16 (x : ISize) : x.toInt16.toBitVec = x.toBitVec.signExtend 16 := (rfl)
|
||||
@[simp] theorem ISize.toBitVec_toInt32 (x : ISize) : x.toInt32.toBitVec = x.toBitVec.signExtend 32 := (rfl)
|
||||
@[simp] theorem ISize.toBitVec_toInt64 (x : ISize) : x.toInt64.toBitVec = x.toBitVec.signExtend 64 := (rfl)
|
||||
@[simp, int_toBitVec] theorem ISize.toBitVec_toInt8 (x : ISize) : x.toInt8.toBitVec = x.toBitVec.signExtend 8 := (rfl)
|
||||
@[simp, int_toBitVec] theorem ISize.toBitVec_toInt16 (x : ISize) : x.toInt16.toBitVec = x.toBitVec.signExtend 16 := (rfl)
|
||||
@[simp, int_toBitVec] theorem ISize.toBitVec_toInt32 (x : ISize) : x.toInt32.toBitVec = x.toBitVec.signExtend 32 := (rfl)
|
||||
@[simp, int_toBitVec] theorem ISize.toBitVec_toInt64 (x : ISize) : x.toInt64.toBitVec = x.toBitVec.signExtend 64 := (rfl)
|
||||
|
||||
theorem Int8.toInt_lt (x : Int8) : x.toInt < 2 ^ 7 := Int.lt_of_mul_lt_mul_left BitVec.two_mul_toInt_lt (by decide)
|
||||
theorem Int8.le_toInt (x : Int8) : -2 ^ 7 ≤ x.toInt := Int.le_of_mul_le_mul_left BitVec.le_two_mul_toInt (by decide)
|
||||
@@ -507,11 +510,11 @@ theorem Int32.toFin_toBitVec (x : Int32) : x.toBitVec.toFin = x.toUInt32.toFin :
|
||||
theorem Int64.toFin_toBitVec (x : Int64) : x.toBitVec.toFin = x.toUInt64.toFin := (rfl)
|
||||
theorem ISize.toFin_toBitVec (x : ISize) : x.toBitVec.toFin = x.toUSize.toFin := (rfl)
|
||||
|
||||
@[simp] theorem Int8.toBitVec_toUInt8 (x : Int8) : x.toUInt8.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp] theorem Int16.toBitVec_toUInt16 (x : Int16) : x.toUInt16.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp] theorem Int32.toBitVec_toUInt32 (x : Int32) : x.toUInt32.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp] theorem Int64.toBitVec_toUInt64 (x : Int64) : x.toUInt64.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp] theorem ISize.toBitVec_toUSize (x : ISize) : x.toUSize.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int8.toBitVec_toUInt8 (x : Int8) : x.toUInt8.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int16.toBitVec_toUInt16 (x : Int16) : x.toUInt16.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int32.toBitVec_toUInt32 (x : Int32) : x.toUInt32.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int64.toBitVec_toUInt64 (x : Int64) : x.toUInt64.toBitVec = x.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] theorem ISize.toBitVec_toUSize (x : ISize) : x.toUSize.toBitVec = x.toBitVec := (rfl)
|
||||
|
||||
@[simp] theorem UInt8.ofBitVec_int8ToBitVec (x : Int8) : UInt8.ofBitVec x.toBitVec = x.toUInt8 := (rfl)
|
||||
@[simp] theorem UInt16.ofBitVec_int16ToBitVec (x : Int16) : UInt16.ofBitVec x.toBitVec = x.toUInt16 := (rfl)
|
||||
@@ -1001,11 +1004,11 @@ theorem USize.toISize_ofNatLT {n : Nat} (hn) : (USize.ofNatLT n hn).toISize = IS
|
||||
@[simp] theorem UInt64.toInt64_ofBitVec (b) : (UInt64.ofBitVec b).toInt64 = Int64.ofBitVec b := (rfl)
|
||||
@[simp] theorem USize.toISize_ofBitVec (b) : (USize.ofBitVec b).toISize = ISize.ofBitVec b := (rfl)
|
||||
|
||||
@[simp] theorem Int8.toBitVec_ofBitVec (b) : (Int8.ofBitVec b).toBitVec = b := (rfl)
|
||||
@[simp] theorem Int16.toBitVec_ofBitVec (b) : (Int16.ofBitVec b).toBitVec = b := (rfl)
|
||||
@[simp] theorem Int32.toBitVec_ofBitVec (b) : (Int32.ofBitVec b).toBitVec = b := (rfl)
|
||||
@[simp] theorem Int64.toBitVec_ofBitVec (b) : (Int64.ofBitVec b).toBitVec = b := (rfl)
|
||||
@[simp] theorem ISize.toBitVec_ofBitVec (b) : (ISize.ofBitVec b).toBitVec = b := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int8.toBitVec_ofBitVec (b) : (Int8.ofBitVec b).toBitVec = b := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int16.toBitVec_ofBitVec (b) : (Int16.ofBitVec b).toBitVec = b := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int32.toBitVec_ofBitVec (b) : (Int32.ofBitVec b).toBitVec = b := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int64.toBitVec_ofBitVec (b) : (Int64.ofBitVec b).toBitVec = b := (rfl)
|
||||
@[simp, int_toBitVec] theorem ISize.toBitVec_ofBitVec (b) : (ISize.ofBitVec b).toBitVec = b := (rfl)
|
||||
|
||||
theorem Int8.toBitVec_ofIntTruncate {n : Int} (h₁ : Int8.minValue.toInt ≤ n) (h₂ : n ≤ Int8.maxValue.toInt) :
|
||||
(Int8.ofIntTruncate n).toBitVec = BitVec.ofInt _ n := by
|
||||
@@ -1281,11 +1284,11 @@ theorem Int64.toISize_ofIntTruncate {n : Int} (h₁ : -2 ^ 63 ≤ n) (h₂ : n <
|
||||
(Int64.ofIntTruncate n).toISize = ISize.ofInt n := by
|
||||
rw [← ofIntLE_eq_ofIntTruncate (h₁ := h₁) (h₂ := Int.le_of_lt_add_one h₂), toISize_ofIntLE]
|
||||
|
||||
@[simp] theorem Int8.toBitVec_minValue : minValue.toBitVec = BitVec.intMin _ := (rfl)
|
||||
@[simp] theorem Int16.toBitVec_minValue : minValue.toBitVec = BitVec.intMin _ := (rfl)
|
||||
@[simp] theorem Int32.toBitVec_minValue : minValue.toBitVec = BitVec.intMin _ := (rfl)
|
||||
@[simp] theorem Int64.toBitVec_minValue : minValue.toBitVec = BitVec.intMin _ := (rfl)
|
||||
@[simp] theorem ISize.toBitVec_minValue : minValue.toBitVec = BitVec.intMin _ :=
|
||||
@[simp, int_toBitVec] theorem Int8.toBitVec_minValue : minValue.toBitVec = BitVec.intMin _ := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int16.toBitVec_minValue : minValue.toBitVec = BitVec.intMin _ := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int32.toBitVec_minValue : minValue.toBitVec = BitVec.intMin _ := (rfl)
|
||||
@[simp, int_toBitVec] theorem Int64.toBitVec_minValue : minValue.toBitVec = BitVec.intMin _ := (rfl)
|
||||
@[simp, int_toBitVec] theorem ISize.toBitVec_minValue : minValue.toBitVec = BitVec.intMin _ :=
|
||||
BitVec.eq_of_toInt_eq (by rw [toInt_toBitVec, toInt_minValue,
|
||||
BitVec.toInt_intMin_of_pos (by cases System.Platform.numBits_eq <;> simp_all)])
|
||||
|
||||
@@ -3025,6 +3028,56 @@ protected theorem Int64.lt_asymm {a b : Int64} : a < b → ¬b < a :=
|
||||
protected theorem ISize.lt_asymm {a b : ISize} : a < b → ¬b < a :=
|
||||
fun hab hba => ISize.lt_irrefl (ISize.lt_trans hab hba)
|
||||
|
||||
instance Int8.instIsLinearOrder : IsLinearOrder Int8 := by
|
||||
apply IsLinearOrder.of_le
|
||||
case le_antisymm => constructor; apply Int8.le_antisymm
|
||||
case le_total => constructor; apply Int8.le_total
|
||||
case le_trans => constructor; apply Int8.le_trans
|
||||
|
||||
instance : LawfulOrderLT Int8 where
|
||||
lt_iff := by
|
||||
simp [← Int8.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
instance Int16.instIsLinearOrder : IsLinearOrder Int16 := by
|
||||
apply IsLinearOrder.of_le
|
||||
case le_antisymm => constructor; apply Int16.le_antisymm
|
||||
case le_total => constructor; apply Int16.le_total
|
||||
case le_trans => constructor; apply Int16.le_trans
|
||||
|
||||
instance : LawfulOrderLT Int16 where
|
||||
lt_iff := by
|
||||
simp [← Int16.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
instance Int32.instIsLinearOrder : IsLinearOrder Int32 := by
|
||||
apply IsLinearOrder.of_le
|
||||
case le_antisymm => constructor; apply Int32.le_antisymm
|
||||
case le_total => constructor; apply Int32.le_total
|
||||
case le_trans => constructor; apply Int32.le_trans
|
||||
|
||||
instance : LawfulOrderLT Int32 where
|
||||
lt_iff := by
|
||||
simp [← Int32.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
instance Int64.instIsLinearOrder : IsLinearOrder Int64 := by
|
||||
apply IsLinearOrder.of_le
|
||||
case le_antisymm => constructor; apply Int64.le_antisymm
|
||||
case le_total => constructor; apply Int64.le_total
|
||||
case le_trans => constructor; apply Int64.le_trans
|
||||
|
||||
instance : LawfulOrderLT Int64 where
|
||||
lt_iff := by
|
||||
simp [← Int64.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
instance ISize.instIsLinearOrder : IsLinearOrder ISize := by
|
||||
apply IsLinearOrder.of_le
|
||||
case le_antisymm => constructor; apply ISize.le_antisymm
|
||||
case le_total => constructor; apply ISize.le_total
|
||||
case le_trans => constructor; apply ISize.le_trans
|
||||
|
||||
instance : LawfulOrderLT ISize where
|
||||
lt_iff := by
|
||||
simp [← ISize.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
protected theorem Int8.add_neg_eq_sub {a b : Int8} : a + -b = a - b := Int8.toBitVec_inj.1 BitVec.add_neg_eq_sub
|
||||
protected theorem Int16.add_neg_eq_sub {a b : Int16} : a + -b = a - b := Int16.toBitVec_inj.1 BitVec.add_neg_eq_sub
|
||||
protected theorem Int32.add_neg_eq_sub {a b : Int32} : a + -b = a - b := Int32.toBitVec_inj.1 BitVec.add_neg_eq_sub
|
||||
|
||||
@@ -108,9 +108,17 @@ Examples:
|
||||
* `#["red", "green", "blue"].toSubarray.popFront.foldl (· + ·.length) 0 = 9`
|
||||
-/
|
||||
@[inline]
|
||||
def foldl {α : Type u} {β : Type v} (f : β → α → β) (init : β) (as : Subarray α) : β :=
|
||||
def Subarray.foldl {α : Type u} {β : Type v} (f : β → α → β) (init : β) (as : Subarray α) : β :=
|
||||
Slice.foldl f (init := init) as
|
||||
|
||||
/--
|
||||
The implementation of `ForIn.forIn` for `Subarray`, which allows it to be used with `for` loops in
|
||||
`do`-notation.
|
||||
-/
|
||||
@[inline]
|
||||
def Subarray.forIn {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (s : Subarray α) (b : β) (f : α → β → m (ForInStep β)) : m β :=
|
||||
ForIn.forIn s b f
|
||||
|
||||
namespace Array
|
||||
|
||||
/--
|
||||
|
||||
@@ -26,6 +26,33 @@ def List.asString (s : List Char) : String :=
|
||||
|
||||
namespace String
|
||||
|
||||
instance : HAdd String.Pos String.Pos String.Pos where
|
||||
hAdd p₁ p₂ := { byteIdx := p₁.byteIdx + p₂.byteIdx }
|
||||
|
||||
instance : HSub String.Pos String.Pos String.Pos where
|
||||
hSub p₁ p₂ := { byteIdx := p₁.byteIdx - p₂.byteIdx }
|
||||
|
||||
instance : HAdd String.Pos Char String.Pos where
|
||||
hAdd p c := { byteIdx := p.byteIdx + c.utf8Size }
|
||||
|
||||
instance : HAdd String.Pos String String.Pos where
|
||||
hAdd p s := { byteIdx := p.byteIdx + s.utf8ByteSize }
|
||||
|
||||
instance : LE String.Pos where
|
||||
le p₁ p₂ := p₁.byteIdx ≤ p₂.byteIdx
|
||||
|
||||
instance : LT String.Pos where
|
||||
lt p₁ p₂ := p₁.byteIdx < p₂.byteIdx
|
||||
|
||||
instance (p₁ p₂ : String.Pos) : Decidable (LE.le p₁ p₂) :=
|
||||
inferInstanceAs (Decidable (p₁.byteIdx ≤ p₂.byteIdx))
|
||||
|
||||
instance (p₁ p₂ : String.Pos) : Decidable (LT.lt p₁ p₂) :=
|
||||
inferInstanceAs (Decidable (p₁.byteIdx < p₂.byteIdx))
|
||||
|
||||
instance : Min String.Pos := minOfLe
|
||||
instance : Max String.Pos := maxOfLe
|
||||
|
||||
instance : OfNat String.Pos (nat_lit 0) where
|
||||
ofNat := {}
|
||||
|
||||
@@ -36,7 +63,7 @@ instance : LT String :=
|
||||
instance decidableLT (s₁ s₂ : @& String) : Decidable (s₁ < s₂) :=
|
||||
List.decidableLT s₁.data s₂.data
|
||||
|
||||
@[deprecated decidableLT (since := "2024-12-13")] abbrev decLt := @decidableLT
|
||||
|
||||
|
||||
/--
|
||||
Non-strict inequality on strings, typically used via the `≤` operator.
|
||||
@@ -485,6 +512,7 @@ Examples:
|
||||
* `"tea".firstDiffPos "teas" = ⟨3⟩`
|
||||
* `"teas".firstDiffPos "tea" = ⟨3⟩`
|
||||
-/
|
||||
@[expose]
|
||||
def firstDiffPos (a b : String) : Pos :=
|
||||
let stopPos := a.endPos.min b.endPos
|
||||
let rec loop (i : Pos) : Pos :=
|
||||
@@ -511,7 +539,7 @@ Examples:
|
||||
* `"red green blue".extract ⟨4⟩ ⟨100⟩ = "green blue"`
|
||||
* `"L∃∀N".extract ⟨2⟩ ⟨100⟩ = "green blue"`
|
||||
-/
|
||||
@[extern "lean_string_utf8_extract"]
|
||||
@[extern "lean_string_utf8_extract", expose]
|
||||
def extract : (@& String) → (@& Pos) → (@& Pos) → String
|
||||
| ⟨s⟩, b, e => if b.byteIdx ≥ e.byteIdx then "" else ⟨go₁ s 0 b e⟩
|
||||
where
|
||||
@@ -652,7 +680,7 @@ Use `String.intercalate` to place a separator string between the strings in a li
|
||||
|
||||
Examples:
|
||||
* `String.join ["gr", "ee", "n"] = "green"`
|
||||
* `String.join ["b", "", "l", "", "ue"] = "red"`
|
||||
* `String.join ["b", "", "l", "", "ue"] = "blue"`
|
||||
* `String.join [] = ""`
|
||||
-/
|
||||
@[inline] def join (l : List String) : String :=
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user