mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-22 04:44:07 +00:00
Compare commits
197 Commits
expose_fil
...
dyadic_pre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a61b025fe | ||
|
|
584ed5f33e | ||
|
|
1523ed1cdb | ||
|
|
facc356a0a | ||
|
|
c4b3f303bb | ||
|
|
1448493489 | ||
|
|
f7a251b75f | ||
|
|
5aa706435a | ||
|
|
a581433d8b | ||
|
|
6683d1eb91 | ||
|
|
504d71f268 | ||
|
|
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 |
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 committed 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,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euxo pipefail
|
||||
|
||||
cmake --preset release -DUSE_LAKE=ON 1>&2
|
||||
cmake --preset release 1>&2
|
||||
|
||||
# We benchmark against stage2/bin to test new optimizations.
|
||||
timeout -s KILL 1h time make -C build/release -j$(nproc) stage3 1>&2
|
||||
|
||||
@@ -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`")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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} :
|
||||
|
||||
@@ -312,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
|
||||
@@ -838,9 +838,10 @@ theorem mem_of_contains_eq_true [BEq α] [LawfulBEq α] {a : α} {as : Array α}
|
||||
cases as
|
||||
simp
|
||||
|
||||
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
|
||||
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
|
||||
@@ -2893,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]
|
||||
@@ -2954,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
|
||||
|
||||
@@ -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) :
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -50,4 +50,21 @@ protected def shiftRight : Int → Nat → Int
|
||||
|
||||
instance : HShiftRight Int Nat Int := ⟨.shiftRight⟩
|
||||
|
||||
/--
|
||||
Bitwise left shift, usually accessed via the `<<<` operator.
|
||||
|
||||
Examples:
|
||||
* `1 <<< 2 = 4`
|
||||
* `1 <<< 3 = 8`
|
||||
* `0 <<< 3 = 0`
|
||||
* `0xf1 <<< 4 = 0xf10`
|
||||
* `(-1) <<< 3 = -8`
|
||||
-/
|
||||
@[expose]
|
||||
protected def shiftLeft : Int → Nat → Int
|
||||
| Int.ofNat n, s => Int.ofNat (n <<< s)
|
||||
| Int.negSucc n, s => Int.negSucc (((n + 1) <<< s) - 1)
|
||||
|
||||
instance : HShiftLeft Int Nat Int := ⟨.shiftLeft⟩
|
||||
|
||||
end Int
|
||||
|
||||
@@ -37,11 +37,11 @@ theorem shiftRight_eq_div_pow (m : Int) (n : Nat) :
|
||||
· rw [negSucc_ediv _ (by norm_cast; exact Nat.pow_pos (Nat.zero_lt_two))]
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem zero_shiftRight (n : Nat) : (0 : Int) >>> n = 0 := by
|
||||
simp [Int.shiftRight_eq_div_pow]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem shiftRight_zero (n : Int) : n >>> 0 = n := by
|
||||
simp [Int.shiftRight_eq_div_pow]
|
||||
|
||||
@@ -88,4 +88,32 @@ theorem shiftRight_le_of_nonpos {n : Int} {s : Nat} (h : n ≤ 0) : (n >>> s)
|
||||
have rl : n / 2 ^ s ≤ 0 := Int.ediv_nonpos_of_nonpos_of_neg (by omega) (by norm_cast at *; omega)
|
||||
norm_cast at *
|
||||
|
||||
@[simp, grind =]
|
||||
theorem shiftLeft_zero (n : Int) : n <<< 0 = n := by
|
||||
change Int.shiftLeft _ _ = _
|
||||
match n with
|
||||
| Int.ofNat n
|
||||
| Int.negSucc n => simp [Int.shiftLeft]
|
||||
|
||||
theorem shiftLeft_succ (m : Int) (n : Nat) : m <<< (n + 1) = (m <<< n) * 2 := by
|
||||
change Int.shiftLeft _ _ = Int.shiftLeft _ _ * 2
|
||||
match m with
|
||||
| (m : Nat) =>
|
||||
dsimp [Int.shiftLeft]
|
||||
rw [Nat.shiftLeft_succ, Nat.mul_comm, natCast_mul, ofNat_two]
|
||||
| Int.negSucc m =>
|
||||
dsimp [Int.shiftLeft]
|
||||
rw [Nat.shiftLeft_succ, Nat.mul_comm, Int.negSucc_eq]
|
||||
have := Nat.le_shiftLeft (a := m + 1) (b := n)
|
||||
omega
|
||||
|
||||
theorem shiftLeft_eq (a : Int) (b : Nat) : a <<< b = a * 2 ^ b := by
|
||||
induction b with
|
||||
| zero => simp
|
||||
| succ b ih =>
|
||||
rw [shiftLeft_succ, ih, Int.pow_succ, Int.mul_assoc]
|
||||
|
||||
theorem shiftLeft_eq' (a : Int) (b : Nat) : a <<< b = a * (2 ^ b : Nat) := by
|
||||
simp [shiftLeft_eq]
|
||||
|
||||
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
|
||||
|
||||
@@ -1280,7 +1280,7 @@ noncomputable def diseq_eq_subst_cert (x : Var) (p₁ : Poly) (p₂ : Poly) (p
|
||||
theorem eq_diseq_subst (ctx : Context) (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
|
||||
: diseq_eq_subst_cert x p₁ p₂ p₃ → p₁.denote' ctx = 0 → p₂.denote' ctx ≠ 0 → p₃.denote' ctx ≠ 0 := by
|
||||
simp [diseq_eq_subst_cert]
|
||||
intros _ _; subst p₃
|
||||
intro _ _; subst p₃
|
||||
intro h₁ h₂
|
||||
simp [*]
|
||||
|
||||
@@ -2121,6 +2121,81 @@ theorem not_le_of_le (ctx : Context) (p₁ p₂ : Poly) : not_le_of_le_cert p₁
|
||||
have := not_le_of_le' ctx p₁ p₂ h 0 h₁; simp at this
|
||||
simp [*]
|
||||
|
||||
theorem natCast_sub (x y : Nat)
|
||||
: (NatCast.natCast (x - y) : Int)
|
||||
=
|
||||
if (NatCast.natCast y : Int) + (-1)*NatCast.natCast x ≤ 0 then
|
||||
(NatCast.natCast x : Int) + -1*NatCast.natCast y
|
||||
else
|
||||
(0 : Int) := by
|
||||
change (↑(x - y) : Int) = if (↑y : Int) + (-1)*↑x ≤ 0 then (↑x : Int) + (-1)*↑y else 0
|
||||
rw [Int.neg_mul, ← Int.sub_eq_add_neg, Int.one_mul]
|
||||
rw [Int.neg_mul, ← Int.sub_eq_add_neg, Int.one_mul]
|
||||
split
|
||||
next h =>
|
||||
replace h := Int.le_of_sub_nonpos h
|
||||
rw [Int.ofNat_le] at h
|
||||
rw [Int.ofNat_sub h]
|
||||
next h =>
|
||||
have : ¬ (↑y : Int) ≤ ↑x := by
|
||||
intro h
|
||||
replace h := Int.sub_nonpos_of_le h
|
||||
contradiction
|
||||
rw [Int.ofNat_le] at this
|
||||
rw [Lean.Omega.Int.ofNat_sub_eq_zero this]
|
||||
|
||||
/-! Helper theorem for linearizing nonlinear terms -/
|
||||
|
||||
@[expose] noncomputable def var_eq_cert (x : Var) (k : Int) (p : Poly) : Bool :=
|
||||
Poly.rec (fun _ => false)
|
||||
(fun k₁ x' p' _ => Poly.rec (fun k₂ => k₁ != 0 && x == x' && k == -k₂/k₁) (fun _ _ _ _ => false) p')
|
||||
p
|
||||
|
||||
theorem var_eq (ctx : Context) (x : Var) (k : Int) (p : Poly) : var_eq_cert x k p → p.denote' ctx = 0 → x.denote ctx = k := by
|
||||
simp [var_eq_cert]; cases p <;> simp; next k₁ x' p' =>
|
||||
cases p' <;> simp; next k₂ =>
|
||||
intro h₁ _ _; subst x' k; intro h₂
|
||||
replace h₂ := Int.neg_eq_of_add_eq_zero h₂
|
||||
rw [Int.neg_eq_comm] at h₂
|
||||
rw [← h₂]; clear h₂; simp; rw [Int.mul_comm, Int.mul_ediv_cancel]
|
||||
assumption
|
||||
|
||||
@[expose] noncomputable def of_var_eq_mul_cert (x : Var) (k : Int) (y : Var) (p : Poly) : Bool :=
|
||||
p.beq' (.add 1 x (.add (-k) y (.num 0)))
|
||||
|
||||
theorem of_var_eq_mul (ctx : Context) (x : Var) (k : Int) (y : Var) (p : Poly) : of_var_eq_mul_cert x k y p → x.denote ctx = k * y.denote ctx → p.denote' ctx = 0 := by
|
||||
simp [of_var_eq_mul_cert]; intro _ h; subst p; simp [h]
|
||||
rw [Int.neg_mul, ← Int.sub_eq_add_neg, Int.sub_self]
|
||||
|
||||
@[expose] noncomputable def of_var_eq_var_cert (x : Var) (y : Var) (p : Poly) : Bool :=
|
||||
p.beq' (.add 1 x (.add (-1) y (.num 0)))
|
||||
|
||||
theorem of_var_eq_var (ctx : Context) (x : Var) (y : Var) (p : Poly) : of_var_eq_var_cert x y p → x.denote ctx = y.denote ctx → p.denote' ctx = 0 := by
|
||||
simp [of_var_eq_var_cert]; intro _ h; subst p; simp [h]
|
||||
rw [← Int.sub_eq_add_neg, Int.sub_self]
|
||||
|
||||
@[expose] noncomputable def of_var_eq_cert (x : Var) (k : Int) (p : Poly) : Bool :=
|
||||
p.beq' (.add 1 x (.num (-k)))
|
||||
|
||||
theorem of_var_eq (ctx : Context) (x : Var) (k : Int) (p : Poly) : of_var_eq_cert x k p → x.denote ctx = k → p.denote' ctx = 0 := by
|
||||
simp [of_var_eq_cert]; intro _ h; subst p; simp [h]
|
||||
rw [← Int.sub_eq_add_neg, Int.sub_self]
|
||||
|
||||
theorem eq_one_mul (a : Int) : a = 1*a := by simp
|
||||
theorem mul_eq_kk (a b k₁ k₂ k : Int) (h₁ : a = k₁) (h₂ : b = k₂) (h₃ : k₁*k₂ == k) : a*b = k := by simp_all
|
||||
theorem mul_eq_kkx (a b k₁ k₂ c k : Int) (h₁ : a = k₁) (h₂ : b = k₂*c) (h₃ : k₁*k₂ == k) : a*b = k*c := by
|
||||
simp at h₃; rw [h₁, h₂, ← Int.mul_assoc, h₃]
|
||||
theorem mul_eq_kxk (a b k₁ c k₂ k : Int) (h₁ : a = k₁*c) (h₂ : b = k₂) (h₃ : k₁*k₂ == k) : a*b = k*c := by
|
||||
simp at h₃; rw [h₁, h₂, Int.mul_comm, ← Int.mul_assoc, Int.mul_comm k₂, h₃]
|
||||
theorem mul_eq_zero_left (a b : Int) (h : a = 0) : a*b = 0 := by simp [*]
|
||||
theorem mul_eq_zero_right (a b : Int) (h : b = 0) : a*b = 0 := by simp [*]
|
||||
|
||||
theorem div_eq (a b k : Int) (h : b = k) : a / b = a / k := by simp [*]
|
||||
theorem mod_eq (a b k : Int) (h : b = k) : a % b = a % k := by simp [*]
|
||||
|
||||
theorem div_eq' (a b b' k : Int) (h₁ : b = b') (h₂ : k == a/b') : a / b = k := by simp_all
|
||||
theorem mod_eq' (a b b' k : Int) (h₁ : b = b') (h₂ : k == a%b') : a % b = k := by simp_all
|
||||
|
||||
end Int.Linear
|
||||
|
||||
theorem Int.not_le_eq (a b : Int) : (¬a ≤ b) = (b + 1 ≤ a) := by
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -21,6 +21,11 @@ protected theorem pow_succ (b : Int) (e : Nat) : b ^ (e+1) = (b ^ e) * b := rfl
|
||||
protected theorem pow_succ' (b : Int) (e : Nat) : b ^ (e+1) = b * (b ^ e) := by
|
||||
rw [Int.mul_comm, Int.pow_succ]
|
||||
|
||||
protected theorem pow_add (a : Int) (m n : Nat) : a ^ (m + n) = a ^ m * a ^ n := by
|
||||
induction n with
|
||||
| zero => rw [Nat.add_zero, Int.pow_zero, Int.mul_one]
|
||||
| succ _ ih => rw [Nat.add_succ, Int.pow_succ, Int.pow_succ, ih, Int.mul_assoc]
|
||||
|
||||
protected theorem zero_pow {n : Nat} (h : n ≠ 0) : (0 : Int) ^ n = 0 := by
|
||||
match n, h with
|
||||
| n + 1, _ => simp [Int.pow_succ]
|
||||
|
||||
@@ -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 =]
|
||||
|
||||
@@ -2108,6 +2108,11 @@ def range' : (start len : Nat) → (step : Nat := 1) → List Nat
|
||||
| _, 0, _ => []
|
||||
| s, n+1, step => s :: range' (s+step) n step
|
||||
|
||||
@[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 -/
|
||||
|
||||
/--
|
||||
|
||||
@@ -427,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 α} :
|
||||
|
||||
@@ -1241,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
|
||||
@@ -1262,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
|
||||
@@ -1298,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]
|
||||
|
||||
|
||||
@@ -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 -/
|
||||
@@ -1851,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.
|
||||
|
||||
@@ -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)]
|
||||
@@ -165,11 +176,7 @@ instance [LT α] [Trans (· < · : α → α → Prop) (· < ·) (· < ·)] :
|
||||
|
||||
|
||||
|
||||
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
|
||||
@@ -179,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
|
||||
@@ -193,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₂
|
||||
|
||||
@@ -247,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
|
||||
|
||||
@@ -262,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'
|
||||
@@ -272,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
|
||||
@@ -456,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₂ ↔
|
||||
@@ -480,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₃) :
|
||||
@@ -514,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 β)
|
||||
|
||||
@@ -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_max_le_iff (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]
|
||||
|
||||
@@ -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,28 +90,27 @@ theorem map_sub_range' {a s : Nat} (h : a ≤ s) (n : Nat) :
|
||||
rintro rfl
|
||||
omega
|
||||
|
||||
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
|
||||
@@ -178,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)
|
||||
@@ -355,9 +394,7 @@ 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, ?_⟩
|
||||
|
||||
@@ -29,30 +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']
|
||||
|
||||
theorem range'_ne_nil_iff (s : Nat) {n step : Nat} : range' s n step ≠ [] ↔ n ≠ 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[simp] theorem range'_zero : range' s 0 step = [] := by
|
||||
simp
|
||||
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'_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
|
||||
@@ -81,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
|
||||
@@ -107,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 :=
|
||||
@@ -129,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
|
||||
@@ -152,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
|
||||
@@ -162,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]
|
||||
|
||||
@@ -196,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]
|
||||
@@ -208,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]
|
||||
|
||||
@@ -352,7 +352,7 @@ 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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -1331,6 +1331,25 @@ theorem le_log2 (h : n ≠ 0) : k ≤ n.log2 ↔ 2 ^ k ≤ n := by
|
||||
theorem log2_lt (h : n ≠ 0) : n.log2 < k ↔ n < 2 ^ k := by
|
||||
rw [← Nat.not_le, ← Nat.not_le, le_log2 h]
|
||||
|
||||
theorem log2_eq_iff (h : n ≠ 0) : n.log2 = k ↔ 2 ^ k ≤ n ∧ n < 2 ^ (k + 1) := by
|
||||
constructor
|
||||
· intro w
|
||||
exact ⟨(le_log2 h).mp (Nat.le_of_eq w.symm), (log2_lt h).mp (by subst w; apply lt_succ_self)⟩
|
||||
· intro w
|
||||
apply Nat.le_antisymm
|
||||
· apply Nat.le_of_lt_add_one
|
||||
exact (log2_lt h).mpr w.2
|
||||
· exact (le_log2 h).mpr w.1
|
||||
|
||||
theorem log2_two_mul (h : n ≠ 0) : (2 * n).log2 = n.log2 + 1 := by
|
||||
obtain ⟨h₁, h₂⟩ := (log2_eq_iff h).mp rfl
|
||||
rw [log2_eq_iff (Nat.mul_ne_zero (by decide) h)]
|
||||
constructor
|
||||
· rw [Nat.pow_succ, Nat.mul_comm]
|
||||
exact mul_le_mul_left 2 h₁
|
||||
· rw [Nat.pow_succ, Nat.mul_comm]
|
||||
rwa [Nat.mul_lt_mul_right (by decide)]
|
||||
|
||||
@[simp]
|
||||
theorem log2_two_pow : (2 ^ n).log2 = n := by
|
||||
apply Nat.eq_of_le_of_lt_succ <;> simp [le_log2, log2_lt, NeZero.ne, Nat.pow_lt_pow_iff_right]
|
||||
|
||||
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_min_iff
|
||||
· apply Nat.le_min
|
||||
· intro a b
|
||||
simp only [Nat.min_def]
|
||||
split <;> simp
|
||||
|
||||
public instance : LawfulOrderMax Nat := by
|
||||
apply LawfulOrderMax.of_max_le_iff
|
||||
· 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
|
||||
|
||||
@@ -1,824 +1,14 @@
|
||||
/-
|
||||
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Dany Fabian, Sebastian Ullrich
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.SInt.Basic
|
||||
public import all Init.Data.Vector.Basic
|
||||
|
||||
public section
|
||||
|
||||
/--
|
||||
The result of a comparison according to a total order.
|
||||
|
||||
The relationship between the compared items may be:
|
||||
* `Ordering.lt`: less than
|
||||
* `Ordering.eq`: equal
|
||||
* `Ordering.gt`: greater than
|
||||
-/
|
||||
inductive Ordering where
|
||||
/-- Less than. -/
|
||||
| lt
|
||||
/-- Equal. -/
|
||||
| eq
|
||||
/-- Greater than. -/
|
||||
| gt
|
||||
deriving Inhabited, DecidableEq, Repr
|
||||
|
||||
namespace Ordering
|
||||
|
||||
/--
|
||||
Swaps less-than and greater-than ordering results.
|
||||
|
||||
Examples:
|
||||
* `Ordering.lt.swap = Ordering.gt`
|
||||
* `Ordering.eq.swap = Ordering.eq`
|
||||
* `Ordering.gt.swap = Ordering.lt`
|
||||
-/
|
||||
@[inline, expose]
|
||||
def swap : Ordering → Ordering
|
||||
| .lt => .gt
|
||||
| .eq => .eq
|
||||
| .gt => .lt
|
||||
|
||||
/--
|
||||
If `a` and `b` are `Ordering`, then `a.then b` returns `a` unless it is `.eq`, in which case it
|
||||
returns `b`. Additionally, it has “short-circuiting” behavior similar to boolean `&&`: if `a` is not
|
||||
`.eq` then the expression for `b` is not evaluated.
|
||||
|
||||
This is a useful primitive for constructing lexicographic comparator functions. The `deriving Ord`
|
||||
syntax on a structure uses the `Ord` instance to compare each field in order, combining the results
|
||||
equivalently to `Ordering.then`.
|
||||
|
||||
Use `compareLex` to lexicographically combine two comparison functions.
|
||||
|
||||
Examples:
|
||||
```lean example
|
||||
structure Person where
|
||||
name : String
|
||||
age : Nat
|
||||
|
||||
-- Sort people first by name (in ascending order), and people with the same name by age (in
|
||||
-- descending order)
|
||||
instance : Ord Person where
|
||||
compare a b := (compare a.name b.name).then (compare b.age a.age)
|
||||
```
|
||||
|
||||
```lean example
|
||||
#eval Ord.compare (⟨"Gert", 33⟩ : Person) ⟨"Dana", 50⟩
|
||||
```
|
||||
```output
|
||||
Ordering.gt
|
||||
```
|
||||
|
||||
```lean example
|
||||
#eval Ord.compare (⟨"Gert", 33⟩ : Person) ⟨"Gert", 50⟩
|
||||
```
|
||||
```output
|
||||
Ordering.gt
|
||||
```
|
||||
|
||||
```lean example
|
||||
#eval Ord.compare (⟨"Gert", 33⟩ : Person) ⟨"Gert", 20⟩
|
||||
```
|
||||
```output
|
||||
Ordering.lt
|
||||
```
|
||||
-/
|
||||
@[macro_inline, expose] def «then» (a b : Ordering) : Ordering :=
|
||||
match a with
|
||||
| .eq => b
|
||||
| a => a
|
||||
|
||||
/-- Version of `Ordering.then'` for proof by reflection. -/
|
||||
noncomputable def then' (a b : Ordering) : Ordering :=
|
||||
Ordering.rec a b a a
|
||||
|
||||
/--
|
||||
Checks whether the ordering is `eq`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def isEq : Ordering → Bool
|
||||
| eq => true
|
||||
| _ => false
|
||||
|
||||
/--
|
||||
Checks whether the ordering is not `eq`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def isNe : Ordering → Bool
|
||||
| eq => false
|
||||
| _ => true
|
||||
|
||||
/--
|
||||
Checks whether the ordering is `lt` or `eq`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def isLE : Ordering → Bool
|
||||
| gt => false
|
||||
| _ => true
|
||||
|
||||
/--
|
||||
Checks whether the ordering is `lt`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def isLT : Ordering → Bool
|
||||
| lt => true
|
||||
| _ => false
|
||||
|
||||
/--
|
||||
Checks whether the ordering is `gt`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def isGT : Ordering → Bool
|
||||
| gt => true
|
||||
| _ => false
|
||||
|
||||
/--
|
||||
Checks whether the ordering is `gt` or `eq`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def isGE : Ordering → Bool
|
||||
| lt => false
|
||||
| _ => true
|
||||
|
||||
section Lemmas
|
||||
|
||||
protected theorem «forall» {p : Ordering → Prop} : (∀ o, p o) ↔ p .lt ∧ p .eq ∧ p .gt := by
|
||||
constructor
|
||||
· intro h
|
||||
exact ⟨h _, h _, h _⟩
|
||||
· rintro ⟨h₁, h₂, h₃⟩ (_ | _ | _) <;> assumption
|
||||
|
||||
protected theorem «exists» {p : Ordering → Prop} : (∃ o, p o) ↔ p .lt ∨ p .eq ∨ p .gt := by
|
||||
constructor
|
||||
· rintro ⟨(_ | _ | _), h⟩
|
||||
· exact .inl h
|
||||
· exact .inr (.inl h)
|
||||
· exact .inr (.inr h)
|
||||
· rintro (h | h | h) <;> exact ⟨_, h⟩
|
||||
|
||||
instance [DecidablePred p] : Decidable (∀ o : Ordering, p o) :=
|
||||
decidable_of_decidable_of_iff Ordering.«forall».symm
|
||||
|
||||
instance [DecidablePred p] : Decidable (∃ o : Ordering, p o) :=
|
||||
decidable_of_decidable_of_iff Ordering.«exists».symm
|
||||
|
||||
@[simp] theorem isLT_lt : lt.isLT := rfl
|
||||
@[simp] theorem isLE_lt : lt.isLE := rfl
|
||||
@[simp] theorem isEq_lt : lt.isEq = false := rfl
|
||||
@[simp] theorem isNe_lt : lt.isNe = true := rfl
|
||||
@[simp] theorem isGE_lt : lt.isGE = false := rfl
|
||||
@[simp] theorem isGT_lt : lt.isGT = false := rfl
|
||||
|
||||
@[simp] theorem isLT_eq : eq.isLT = false := rfl
|
||||
@[simp] theorem isLE_eq : eq.isLE := rfl
|
||||
@[simp] theorem isEq_eq : eq.isEq := rfl
|
||||
@[simp] theorem isNe_eq : eq.isNe = false := rfl
|
||||
@[simp] theorem isGE_eq : eq.isGE := rfl
|
||||
@[simp] theorem isGT_eq : eq.isGT = false := rfl
|
||||
|
||||
@[simp] theorem isLT_gt : gt.isLT = false := rfl
|
||||
@[simp] theorem isLE_gt : gt.isLE = false := rfl
|
||||
@[simp] theorem isEq_gt : gt.isEq = false := rfl
|
||||
@[simp] theorem isNe_gt : gt.isNe = true := rfl
|
||||
@[simp] theorem isGE_gt : gt.isGE := rfl
|
||||
@[simp] theorem isGT_gt : gt.isGT := rfl
|
||||
|
||||
@[simp] theorem lt_beq_eq : (lt == eq) = false := rfl
|
||||
@[simp] theorem lt_beq_gt : (lt == gt) = false := rfl
|
||||
@[simp] theorem eq_beq_lt : (eq == lt) = false := rfl
|
||||
@[simp] theorem eq_beq_gt : (eq == gt) = false := rfl
|
||||
@[simp] theorem gt_beq_lt : (gt == lt) = false := rfl
|
||||
@[simp] theorem gt_beq_eq : (gt == eq) = false := rfl
|
||||
|
||||
@[simp] theorem swap_lt : lt.swap = .gt := rfl
|
||||
@[simp] theorem swap_eq : eq.swap = .eq := rfl
|
||||
@[simp] theorem swap_gt : gt.swap = .lt := rfl
|
||||
|
||||
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_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
|
||||
|
||||
@[simp] theorem isLE_eq_false : ∀ {o : Ordering}, o.isLE = false ↔ o = .gt := by decide
|
||||
@[simp] theorem isGE_eq_false : ∀ {o : Ordering}, o.isGE = false ↔ o = .lt := by decide
|
||||
@[simp] theorem isNe_eq_false : ∀ {o : Ordering}, o.isNe = false ↔ o = .eq := by decide
|
||||
@[simp] theorem isEq_eq_false : ∀ {o : Ordering}, o.isEq = false ↔ ¬o = .eq := by decide
|
||||
|
||||
@[simp] theorem swap_eq_gt : ∀ {o : Ordering}, o.swap = .gt ↔ o = .lt := by decide
|
||||
@[simp] theorem swap_eq_lt : ∀ {o : Ordering}, o.swap = .lt ↔ o = .gt := by decide
|
||||
@[simp] theorem swap_eq_eq : ∀ {o : Ordering}, o.swap = .eq ↔ o = .eq := by decide
|
||||
|
||||
@[simp] theorem isLT_swap : ∀ {o : Ordering}, o.swap.isLT = o.isGT := by decide
|
||||
@[simp] theorem isLE_swap : ∀ {o : Ordering}, o.swap.isLE = o.isGE := by decide
|
||||
@[simp] theorem isEq_swap : ∀ {o : Ordering}, o.swap.isEq = o.isEq := by decide
|
||||
@[simp] theorem isNe_swap : ∀ {o : Ordering}, o.swap.isNe = o.isNe := by decide
|
||||
@[simp] theorem isGE_swap : ∀ {o : Ordering}, o.swap.isGE = o.isLE := by decide
|
||||
@[simp] theorem isGT_swap : ∀ {o : Ordering}, o.swap.isGT = o.isLT := by decide
|
||||
|
||||
theorem isLE_of_eq_lt : ∀ {o : Ordering}, o = .lt → o.isLE := by decide
|
||||
theorem isLE_of_eq_eq : ∀ {o : Ordering}, o = .eq → o.isLE := by decide
|
||||
theorem isGE_of_eq_gt : ∀ {o : Ordering}, o = .gt → o.isGE := by decide
|
||||
theorem isGE_of_eq_eq : ∀ {o : Ordering}, o = .eq → o.isGE := by decide
|
||||
|
||||
theorem ne_eq_of_eq_lt : ∀ {o : Ordering}, o = .lt → o ≠ .eq := by decide
|
||||
theorem ne_eq_of_eq_gt : ∀ {o : Ordering}, o = .gt → o ≠ .eq := by decide
|
||||
|
||||
@[simp] theorem isLT_iff_eq_lt : ∀ {o : Ordering}, o.isLT ↔ o = .lt := by decide
|
||||
@[simp] theorem isGT_iff_eq_gt : ∀ {o : Ordering}, o.isGT ↔ o = .gt := by decide
|
||||
@[simp] theorem isEq_iff_eq_eq : ∀ {o : Ordering}, o.isEq ↔ o = .eq := by decide
|
||||
@[simp] theorem isNe_iff_ne_eq : ∀ {o : Ordering}, o.isNe ↔ ¬o = .eq := by decide
|
||||
|
||||
theorem isLE_iff_ne_gt : ∀ {o : Ordering}, o.isLE ↔ ¬o = .gt := by decide
|
||||
theorem isGE_iff_ne_lt : ∀ {o : Ordering}, o.isGE ↔ ¬o = .lt := by decide
|
||||
theorem isLE_iff_eq_lt_or_eq_eq : ∀ {o : Ordering}, o.isLE ↔ o = .lt ∨ o = .eq := by decide
|
||||
theorem isGE_iff_eq_gt_or_eq_eq : ∀ {o : Ordering}, o.isGE ↔ o = .gt ∨ o = .eq := by decide
|
||||
|
||||
theorem isLT_eq_beq_lt : ∀ {o : Ordering}, o.isLT = (o == .lt) := by decide
|
||||
theorem isLE_eq_not_beq_gt : ∀ {o : Ordering}, o.isLE = (!o == .gt) := by decide
|
||||
theorem isLE_eq_isLT_or_isEq : ∀ {o : Ordering}, o.isLE = (o.isLT || o.isEq) := by decide
|
||||
theorem isGT_eq_beq_gt : ∀ {o : Ordering}, o.isGT = (o == .gt) := by decide
|
||||
theorem isGE_eq_not_beq_lt : ∀ {o : Ordering}, o.isGE = (!o == .lt) := by decide
|
||||
theorem isGE_eq_isGT_or_isEq : ∀ {o : Ordering}, o.isGE = (o.isGT || o.isEq) := by decide
|
||||
theorem isEq_eq_beq_eq : ∀ {o : Ordering}, o.isEq = (o == .eq) := by decide
|
||||
theorem isNe_eq_not_beq_eq : ∀ {o : Ordering}, o.isNe = (!o == .eq) := by decide
|
||||
theorem isNe_eq_isLT_or_isGT : ∀ {o : Ordering}, o.isNe = (o.isLT || o.isGT) := by decide
|
||||
|
||||
@[simp] theorem not_isLT_eq_isGE : ∀ {o : Ordering}, (!o.isLT) = o.isGE := by decide
|
||||
@[simp] theorem not_isLE_eq_isGT : ∀ {o : Ordering}, (!o.isLE) = o.isGT := by decide
|
||||
@[simp] theorem not_isGT_eq_isLE : ∀ {o : Ordering}, (!o.isGT) = o.isLE := by decide
|
||||
@[simp] theorem not_isGE_eq_isLT : ∀ {o : Ordering}, (!o.isGE) = o.isLT := by decide
|
||||
@[simp] theorem not_isNe_eq_isEq : ∀ {o : Ordering}, (!o.isNe) = o.isEq := by decide
|
||||
theorem not_isEq_eq_isNe : ∀ {o : Ordering}, (!o.isEq) = o.isNe := by decide
|
||||
|
||||
theorem ne_lt_iff_isGE : ∀ {o : Ordering}, ¬o = .lt ↔ o.isGE := by decide
|
||||
theorem ne_gt_iff_isLE : ∀ {o : Ordering}, ¬o = .gt ↔ o.isLE := by decide
|
||||
|
||||
@[simp] theorem swap_swap : ∀ {o : Ordering}, o.swap.swap = o := by decide
|
||||
@[simp] theorem swap_inj : ∀ {o₁ o₂ : Ordering}, o₁.swap = o₂.swap ↔ o₁ = o₂ := by decide
|
||||
|
||||
theorem swap_then : ∀ (o₁ o₂ : Ordering), (o₁.then o₂).swap = o₁.swap.then o₂.swap := by decide
|
||||
|
||||
theorem then_eq_lt : ∀ {o₁ o₂ : Ordering}, o₁.then o₂ = lt ↔ o₁ = lt ∨ o₁ = eq ∧ o₂ = lt := by decide
|
||||
theorem then_eq_gt : ∀ {o₁ o₂ : Ordering}, o₁.then o₂ = gt ↔ o₁ = gt ∨ o₁ = eq ∧ o₂ = gt := by decide
|
||||
@[simp] theorem then_eq_eq : ∀ {o₁ o₂ : Ordering}, o₁.then o₂ = eq ↔ o₁ = eq ∧ o₂ = eq := by decide
|
||||
|
||||
theorem isLT_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isLT = (o₁.isLT || o₁.isEq && o₂.isLT) := by decide
|
||||
theorem isEq_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isEq = (o₁.isEq && o₂.isEq) := by decide
|
||||
theorem isNe_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isNe = (o₁.isNe || o₂.isNe) := by decide
|
||||
theorem isGT_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isGT = (o₁.isGT || o₁.isEq && o₂.isGT) := by decide
|
||||
|
||||
@[simp] theorem lt_then {o : Ordering} : lt.then o = lt := rfl
|
||||
@[simp] theorem gt_then {o : Ordering} : gt.then o = gt := rfl
|
||||
@[simp] theorem eq_then {o : Ordering} : eq.then o = o := rfl
|
||||
|
||||
@[simp] theorem then_eq : ∀ {o : Ordering}, o.then eq = o := by decide
|
||||
@[simp] theorem then_self : ∀ {o : Ordering}, o.then o = o := by decide
|
||||
theorem then_assoc : ∀ (o₁ o₂ o₃ : Ordering), (o₁.then o₂).then o₃ = o₁.then (o₂.then o₃) := by decide
|
||||
|
||||
theorem isLE_then_iff_or : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isLE ↔ o₁ = lt ∨ (o₁ = eq ∧ o₂.isLE) := by decide
|
||||
theorem isLE_then_iff_and : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isLE ↔ o₁.isLE ∧ (o₁ = lt ∨ o₂.isLE) := by decide
|
||||
theorem isLE_left_of_isLE_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isLE → o₁.isLE := by decide
|
||||
theorem isGE_left_of_isGE_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isGE → o₁.isGE := by decide
|
||||
|
||||
instance : Std.Associative Ordering.then := ⟨then_assoc⟩
|
||||
instance : Std.IdempotentOp Ordering.then := ⟨fun _ => then_self⟩
|
||||
|
||||
instance : Std.LawfulIdentity Ordering.then eq where
|
||||
left_id _ := eq_then
|
||||
right_id _ := then_eq
|
||||
|
||||
theorem then'_eq_then (a b : Ordering) : a.then' b = a.then b := by
|
||||
cases a <;> simp [Ordering.then', Ordering.then]
|
||||
|
||||
end Lemmas
|
||||
|
||||
end Ordering
|
||||
|
||||
/--
|
||||
Uses decidable less-than and equality relations to find an `Ordering`.
|
||||
|
||||
In particular, if `x < y` then the result is `Ordering.lt`. If `x = y` then the result is
|
||||
`Ordering.eq`. Otherwise, it is `Ordering.gt`.
|
||||
|
||||
`compareOfLessAndBEq` uses `BEq` instead of `DecidableEq`.
|
||||
-/
|
||||
@[inline, expose] def compareOfLessAndEq {α} (x y : α) [LT α] [Decidable (x < y)] [DecidableEq α] : Ordering :=
|
||||
if x < y then Ordering.lt
|
||||
else if x = y then Ordering.eq
|
||||
else Ordering.gt
|
||||
|
||||
/--
|
||||
Uses a decidable less-than relation and Boolean equality to find an `Ordering`.
|
||||
|
||||
In particular, if `x < y` then the result is `Ordering.lt`. If `x == y` then the result is
|
||||
`Ordering.eq`. Otherwise, it is `Ordering.gt`.
|
||||
|
||||
`compareOfLessAndEq` uses `DecidableEq` instead of `BEq`.
|
||||
-/
|
||||
@[inline] def compareOfLessAndBEq {α} (x y : α) [LT α] [Decidable (x < y)] [BEq α] : Ordering :=
|
||||
if x < y then .lt
|
||||
else if x == y then .eq
|
||||
else .gt
|
||||
|
||||
/--
|
||||
Compares `a` and `b` lexicographically by `cmp₁` and `cmp₂`.
|
||||
|
||||
`a` and `b` are first compared by `cmp₁`. If this returns `Ordering.eq`, `a` and `b` are compared
|
||||
by `cmp₂` to break the tie.
|
||||
|
||||
To lexicographically combine two `Ordering`s, use `Ordering.then`.
|
||||
-/
|
||||
@[inline, expose] def compareLex (cmp₁ cmp₂ : α → β → Ordering) (a : α) (b : β) : Ordering :=
|
||||
(cmp₁ a b).then (cmp₂ a b)
|
||||
|
||||
section Lemmas
|
||||
|
||||
@[simp]
|
||||
theorem compareLex_eq_eq {α} {cmp₁ cmp₂} {a b : α} :
|
||||
compareLex cmp₁ cmp₂ a b = .eq ↔ cmp₁ a b = .eq ∧ cmp₂ a b = .eq := by
|
||||
simp [compareLex]
|
||||
|
||||
theorem compareOfLessAndEq_eq_swap_of_lt_iff_not_gt_and_ne {α : Type u} [LT α] [DecidableLT α] [DecidableEq α]
|
||||
(h : ∀ x y : α, x < y ↔ ¬ y < x ∧ x ≠ y) {x y : α} :
|
||||
compareOfLessAndEq x y = (compareOfLessAndEq y x).swap := by
|
||||
simp only [compareOfLessAndEq]
|
||||
split
|
||||
· rename_i h'
|
||||
rw [h] at h'
|
||||
simp only [h'.1, h'.2.symm, ↓reduceIte, Ordering.swap_gt]
|
||||
· split
|
||||
· rename_i h'
|
||||
have : ¬ y < y := Not.imp (·.2 rfl) <| (h y y).mp
|
||||
simp only [h', this, ↓reduceIte, Ordering.swap_eq]
|
||||
· rename_i h' h''
|
||||
replace h' := (h y x).mpr ⟨h', Ne.symm h''⟩
|
||||
simp only [h', ↓reduceIte, Ordering.swap_lt]
|
||||
|
||||
theorem lt_iff_not_gt_and_ne_of_antisymm_of_total_of_not_le
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableEq α]
|
||||
(antisymm : ∀ {x y : α}, x ≤ y → y ≤ x → x = y)
|
||||
(total : ∀ (x y : α), x ≤ y ∨ y ≤ x) (not_le : ∀ {x y : α}, ¬ x ≤ y ↔ y < x) (x y : α) :
|
||||
x < y ↔ ¬ y < x ∧ x ≠ y := by
|
||||
simp only [← not_le, Classical.not_not]
|
||||
constructor
|
||||
· intro h
|
||||
have refl := by cases total y y <;> assumption
|
||||
exact ⟨(total _ _).resolve_left h, fun h' => (h' ▸ h) refl⟩
|
||||
· intro ⟨h₁, h₂⟩ h₃
|
||||
exact h₂ (antisymm h₁ h₃)
|
||||
|
||||
theorem compareOfLessAndEq_eq_swap
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableEq α]
|
||||
(antisymm : ∀ {x y : α}, x ≤ y → y ≤ x → x = y)
|
||||
(total : ∀ (x y : α), x ≤ y ∨ y ≤ x) (not_le : ∀ {x y : α}, ¬ x ≤ y ↔ y < x) {x y : α} :
|
||||
compareOfLessAndEq x y = (compareOfLessAndEq y x).swap := by
|
||||
apply compareOfLessAndEq_eq_swap_of_lt_iff_not_gt_and_ne
|
||||
exact lt_iff_not_gt_and_ne_of_antisymm_of_total_of_not_le antisymm total not_le
|
||||
|
||||
@[simp]
|
||||
theorem compareOfLessAndEq_eq_lt
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableEq α] {x y : α} :
|
||||
compareOfLessAndEq x y = .lt ↔ x < y := by
|
||||
rw [compareOfLessAndEq]
|
||||
repeat' split <;> simp_all
|
||||
|
||||
theorem compareOfLessAndEq_eq_eq
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableLE α] [DecidableEq α]
|
||||
(refl : ∀ (x : α), x ≤ x) (not_le : ∀ {x y : α}, ¬ x ≤ y ↔ y < x) {x y : α} :
|
||||
compareOfLessAndEq x y = .eq ↔ x = y := by
|
||||
rw [compareOfLessAndEq]
|
||||
repeat' split <;> try (simp_all; done)
|
||||
simp only [reduceCtorEq, false_iff]
|
||||
rintro rfl
|
||||
rename_i hlt
|
||||
simp [← not_le] at hlt
|
||||
exact hlt (refl x)
|
||||
|
||||
theorem compareOfLessAndEq_eq_gt_of_lt_iff_not_gt_and_ne
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableEq α] {x y : α}
|
||||
(h : ∀ x y : α, x < y ↔ ¬ y < x ∧ x ≠ y) :
|
||||
compareOfLessAndEq x y = .gt ↔ y < x := by
|
||||
rw [compareOfLessAndEq_eq_swap_of_lt_iff_not_gt_and_ne h, Ordering.swap_eq_gt]
|
||||
exact compareOfLessAndEq_eq_lt
|
||||
|
||||
theorem compareOfLessAndEq_eq_gt
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableEq α]
|
||||
(antisymm : ∀ {x y : α}, x ≤ y → y ≤ x → x = y)
|
||||
(total : ∀ (x y : α), x ≤ y ∨ y ≤ x) (not_le : ∀ {x y : α}, ¬ x ≤ y ↔ y < x) (x y : α) :
|
||||
compareOfLessAndEq x y = .gt ↔ y < x := by
|
||||
apply compareOfLessAndEq_eq_gt_of_lt_iff_not_gt_and_ne
|
||||
exact lt_iff_not_gt_and_ne_of_antisymm_of_total_of_not_le antisymm total not_le
|
||||
|
||||
theorem isLE_compareOfLessAndEq
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableLE α] [DecidableEq α]
|
||||
(antisymm : ∀ {x y : α}, x ≤ y → y ≤ x → x = y)
|
||||
(not_le : ∀ {x y : α}, ¬ x ≤ y ↔ y < x) (total : ∀ (x y : α), x ≤ y ∨ y ≤ x) {x y : α} :
|
||||
(compareOfLessAndEq x y).isLE ↔ x ≤ y := by
|
||||
have refl (a : α) := by cases total a a <;> assumption
|
||||
rw [Ordering.isLE_iff_eq_lt_or_eq_eq, compareOfLessAndEq_eq_lt,
|
||||
compareOfLessAndEq_eq_eq refl not_le]
|
||||
constructor
|
||||
· rintro (h | rfl)
|
||||
· rw [← not_le] at h
|
||||
exact total _ _ |>.resolve_left h
|
||||
· exact refl x
|
||||
· intro hle
|
||||
by_cases hge : x ≥ y
|
||||
· exact Or.inr <| antisymm hle hge
|
||||
· exact Or.inl <| not_le.mp hge
|
||||
|
||||
end Lemmas
|
||||
|
||||
/--
|
||||
`Ord α` provides a computable total order on `α`, in terms of the
|
||||
`compare : α → α → Ordering` function.
|
||||
|
||||
Typically instances will be transitive, reflexive, and antisymmetric,
|
||||
but this is not enforced by the typeclass.
|
||||
|
||||
There is a derive handler, so appending `deriving Ord` to an inductive type or structure
|
||||
will attempt to create an `Ord` instance.
|
||||
-/
|
||||
@[ext]
|
||||
class Ord (α : Type u) where
|
||||
/-- Compare two elements in `α` using the comparator contained in an `[Ord α]` instance. -/
|
||||
compare : α → α → Ordering
|
||||
|
||||
export Ord (compare)
|
||||
|
||||
/--
|
||||
Compares two values by comparing the results of applying a function.
|
||||
|
||||
In particular, `x` is compared to `y` by comparing `f x` and `f y`.
|
||||
|
||||
Examples:
|
||||
* `compareOn (·.length) "apple" "banana" = .lt`
|
||||
* `compareOn (· % 3) 5 6 = .gt`
|
||||
* `compareOn (·.foldl max 0) [1, 2, 3] [3, 2, 1] = .eq`
|
||||
-/
|
||||
@[inline, expose] def compareOn [ord : Ord β] (f : α → β) (x y : α) : Ordering :=
|
||||
compare (f x) (f y)
|
||||
|
||||
instance : Ord Nat where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Int where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Bool where
|
||||
compare
|
||||
| false, true => Ordering.lt
|
||||
| true, false => Ordering.gt
|
||||
| _, _ => Ordering.eq
|
||||
|
||||
instance : Ord String where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance (n : Nat) : Ord (Fin n) where
|
||||
compare x y := compare x.val y.val
|
||||
|
||||
instance : Ord UInt8 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord UInt16 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord UInt32 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord UInt64 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord USize where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Char where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Int8 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Int16 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Int32 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Int64 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord ISize where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance {n} : Ord (BitVec n) where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance [Ord α] : Ord (Option α) where
|
||||
compare
|
||||
| none, none => .eq
|
||||
| none, some _ => .lt
|
||||
| some _, none => .gt
|
||||
| some x, some y => compare x y
|
||||
|
||||
instance : Ord Ordering where
|
||||
compare := compareOn (·.toCtorIdx)
|
||||
|
||||
namespace List
|
||||
|
||||
@[specialize, expose]
|
||||
protected def compareLex {α} (cmp : α → α → Ordering) :
|
||||
List α → List α → Ordering
|
||||
| [], [] => .eq
|
||||
| [], _ => .lt
|
||||
| _, [] => .gt
|
||||
| x :: xs, y :: ys => match cmp x y with
|
||||
| .lt => .lt
|
||||
| .eq => xs.compareLex cmp ys
|
||||
| .gt => .gt
|
||||
|
||||
instance {α} [Ord α] : Ord (List α) where
|
||||
compare := List.compareLex compare
|
||||
|
||||
protected theorem compare_eq_compareLex {α} [Ord α] :
|
||||
compare (α := List α) = List.compareLex compare := rfl
|
||||
|
||||
protected theorem compareLex_cons_cons {α} {cmp} {x y : α} {xs ys : List α} :
|
||||
(x :: xs).compareLex cmp (y :: ys) = (cmp x y).then (xs.compareLex cmp ys) := by
|
||||
rw [List.compareLex]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp]
|
||||
protected theorem compare_cons_cons {α} [Ord α] {x y : α} {xs ys : List α} :
|
||||
compare (x :: xs) (y :: ys) = (compare x y).then (compare xs ys) :=
|
||||
List.compareLex_cons_cons
|
||||
|
||||
protected theorem compareLex_nil_cons {α} {cmp} {x : α} {xs : List α} :
|
||||
[].compareLex cmp (x :: xs) = .lt :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
protected theorem compare_nil_cons {α} [Ord α] {x : α} {xs : List α} :
|
||||
compare [] (x :: xs) = .lt :=
|
||||
rfl
|
||||
|
||||
protected theorem compareLex_cons_nil {α} {cmp} {x : α} {xs : List α} :
|
||||
(x :: xs).compareLex cmp [] = .gt :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
protected theorem compare_cons_nil {α} [Ord α] {x : α} {xs : List α} :
|
||||
compare (x :: xs) [] = .gt :=
|
||||
rfl
|
||||
|
||||
protected theorem compareLex_nil_nil {α} {cmp} :
|
||||
[].compareLex (α := α) cmp [] = .eq :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
protected theorem compare_nil_nil {α} [Ord α] :
|
||||
compare (α := List α) [] [] = .eq :=
|
||||
rfl
|
||||
|
||||
protected theorem isLE_compareLex_nil_left {α} {cmp} {xs : List α} :
|
||||
(List.compareLex (cmp := cmp) [] xs).isLE := by
|
||||
cases xs <;> simp [List.compareLex_nil_nil, List.compareLex_nil_cons]
|
||||
|
||||
protected theorem isLE_compare_nil_left {α} [Ord α] {xs : List α} :
|
||||
(compare [] xs).isLE :=
|
||||
List.isLE_compareLex_nil_left
|
||||
|
||||
protected theorem isLE_compareLex_nil_right {α} {cmp} {xs : List α} :
|
||||
(List.compareLex (cmp := cmp) xs []).isLE ↔ xs = [] := by
|
||||
cases xs <;> simp [List.compareLex_nil_nil, List.compareLex_cons_nil]
|
||||
|
||||
@[simp]
|
||||
protected theorem isLE_compare_nil_right {α} [Ord α] {xs : List α} :
|
||||
(compare xs []).isLE ↔ xs = [] :=
|
||||
List.isLE_compareLex_nil_right
|
||||
|
||||
protected theorem isGE_compareLex_nil_left {α} {cmp} {xs : List α} :
|
||||
(List.compareLex (cmp := cmp) [] xs).isGE ↔ xs = [] := by
|
||||
cases xs <;> simp [List.compareLex_nil_nil, List.compareLex_nil_cons]
|
||||
|
||||
@[simp]
|
||||
protected theorem isGE_compare_nil_left {α} [Ord α] {xs : List α} :
|
||||
(compare [] xs).isGE ↔ xs = [] :=
|
||||
List.isGE_compareLex_nil_left
|
||||
|
||||
protected theorem isGE_compareLex_nil_right {α} {cmp} {xs : List α} :
|
||||
(List.compareLex (cmp := cmp) xs []).isGE := by
|
||||
cases xs <;> simp [List.compareLex_nil_nil, List.compareLex_cons_nil]
|
||||
|
||||
protected theorem isGE_compare_nil_right {α} [Ord α] {xs : List α} :
|
||||
(compare xs []).isGE :=
|
||||
List.isGE_compareLex_nil_right
|
||||
|
||||
protected theorem compareLex_nil_left_eq_eq {α} {cmp} {xs : List α} :
|
||||
List.compareLex cmp [] xs = .eq ↔ xs = [] := by
|
||||
cases xs <;> simp [List.compareLex_nil_nil, List.compareLex_nil_cons]
|
||||
|
||||
@[simp]
|
||||
protected theorem compare_nil_left_eq_eq {α} [Ord α] {xs : List α} :
|
||||
compare [] xs = .eq ↔ xs = [] :=
|
||||
List.compareLex_nil_left_eq_eq
|
||||
|
||||
protected theorem compareLex_nil_right_eq_eq {α} {cmp} {xs : List α} :
|
||||
xs.compareLex cmp [] = .eq ↔ xs = [] := by
|
||||
cases xs <;> simp [List.compareLex_nil_nil, List.compareLex_cons_nil]
|
||||
|
||||
@[simp]
|
||||
protected theorem compare_nil_right_eq_eq {α} [Ord α] {xs : List α} :
|
||||
compare xs [] = .eq ↔ xs = [] :=
|
||||
List.compareLex_nil_right_eq_eq
|
||||
|
||||
end List
|
||||
|
||||
namespace Array
|
||||
|
||||
@[specialize]
|
||||
protected def compareLex {α} (cmp : α → α → Ordering) (a₁ a₂ : Array α) : Ordering :=
|
||||
go 0
|
||||
where go i :=
|
||||
if h₁ : a₁.size <= i then
|
||||
if a₂.size <= i then .eq else .lt
|
||||
else
|
||||
if h₂ : a₂.size <= i then
|
||||
.gt
|
||||
else match cmp a₁[i] a₂[i] with
|
||||
| .lt => .lt
|
||||
| .eq => go (i + 1)
|
||||
| .gt => .gt
|
||||
termination_by a₁.size - i
|
||||
|
||||
instance {α} [Ord α] : Ord (Array α) where
|
||||
compare := Array.compareLex compare
|
||||
|
||||
protected theorem compare_eq_compareLex {α} [Ord α] :
|
||||
compare (α := Array α) = Array.compareLex compare := rfl
|
||||
|
||||
private theorem compareLex.go_succ {α} {cmp} {x₁ x₂} {a₁ a₂ : List α} {i} :
|
||||
compareLex.go cmp (x₁ :: a₁).toArray (x₂ :: a₂).toArray (i + 1) =
|
||||
compareLex.go cmp a₁.toArray a₂.toArray i := by
|
||||
induction i using Array.compareLex.go.induct cmp a₁.toArray a₂.toArray
|
||||
all_goals try
|
||||
conv => congr <;> rw [compareLex.go]
|
||||
simp
|
||||
repeat' split <;> (try simp_all; done)
|
||||
|
||||
protected theorem _root_.List.compareLex_eq_compareLex_toArray {α} {cmp} {l₁ l₂ : List α} :
|
||||
List.compareLex cmp l₁ l₂ = Array.compareLex cmp l₁.toArray l₂.toArray := by
|
||||
simp only [Array.compareLex]
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil =>
|
||||
cases l₂
|
||||
· simp [Array.compareLex.go, List.compareLex_nil_nil]
|
||||
· simp [Array.compareLex.go, List.compareLex_nil_cons]
|
||||
| cons x xs ih =>
|
||||
cases l₂
|
||||
· simp [Array.compareLex.go, List.compareLex_cons_nil]
|
||||
· rw [Array.compareLex.go, List.compareLex_cons_cons]
|
||||
simp only [List.size_toArray, List.length_cons, Nat.le_zero_eq, Nat.add_one_ne_zero,
|
||||
↓reduceDIte, List.getElem_toArray, List.getElem_cons_zero, Nat.zero_add]
|
||||
split <;> simp_all [compareLex.go_succ]
|
||||
|
||||
protected theorem _root_.List.compare_eq_compare_toArray {α} [Ord α] {l₁ l₂ : List α} :
|
||||
compare l₁ l₂ = compare l₁.toArray l₂.toArray :=
|
||||
List.compareLex_eq_compareLex_toArray
|
||||
|
||||
protected theorem compareLex_eq_compareLex_toList {α} {cmp} {a₁ a₂ : Array α} :
|
||||
Array.compareLex cmp a₁ a₂ = List.compareLex cmp a₁.toList a₂.toList := by
|
||||
rw [List.compareLex_eq_compareLex_toArray]
|
||||
|
||||
protected theorem compare_eq_compare_toList {α} [Ord α] {a₁ a₂ : Array α} :
|
||||
compare a₁ a₂ = compare a₁.toList a₂.toList :=
|
||||
Array.compareLex_eq_compareLex_toList
|
||||
|
||||
end Array
|
||||
|
||||
namespace Vector
|
||||
|
||||
@[expose]
|
||||
protected def compareLex {α n} (cmp : α → α → Ordering) (a b : Vector α n) : Ordering :=
|
||||
Array.compareLex cmp a.toArray b.toArray
|
||||
|
||||
instance {α n} [Ord α] : Ord (Vector α n) where
|
||||
compare := Vector.compareLex compare
|
||||
|
||||
protected theorem compareLex_eq_compareLex_toArray {α n cmp} {a b : Vector α n} :
|
||||
Vector.compareLex cmp a b = Array.compareLex cmp a.toArray b.toArray :=
|
||||
rfl
|
||||
|
||||
protected theorem compareLex_eq_compareLex_toList {α n cmp} {a b : Vector α n} :
|
||||
Vector.compareLex cmp a b = List.compareLex cmp a.toList b.toList :=
|
||||
Array.compareLex_eq_compareLex_toList
|
||||
|
||||
protected theorem compare_eq_compare_toArray {α n} [Ord α] {a b : Vector α n} :
|
||||
compare a b = compare a.toArray b.toArray :=
|
||||
rfl
|
||||
|
||||
protected theorem compare_eq_compare_toList {α n} [Ord α] {a b : Vector α n} :
|
||||
compare a b = compare a.toList b.toList :=
|
||||
Array.compare_eq_compare_toList
|
||||
|
||||
end Vector
|
||||
|
||||
/-- The lexicographic order on pairs. -/
|
||||
@[expose] def lexOrd [Ord α] [Ord β] : Ord (α × β) where
|
||||
compare := compareLex (compareOn (·.1)) (compareOn (·.2))
|
||||
|
||||
/--
|
||||
Constructs an `BEq` instance from an `Ord` instance that asserts that the result of `compare` is
|
||||
`Ordering.eq`.
|
||||
-/
|
||||
@[expose] def beqOfOrd [Ord α] : BEq α where
|
||||
beq a b := (compare a b).isEq
|
||||
|
||||
/--
|
||||
Constructs an `LT` instance from an `Ord` instance that asserts that the result of `compare` is
|
||||
`Ordering.lt`.
|
||||
-/
|
||||
@[expose] def ltOfOrd [Ord α] : LT α where
|
||||
lt a b := compare a b = Ordering.lt
|
||||
|
||||
@[inline]
|
||||
instance [Ord α] : DecidableRel (@LT.lt α ltOfOrd) := fun a b =>
|
||||
decidable_of_bool (compare a b).isLT Ordering.isLT_iff_eq_lt
|
||||
|
||||
/--
|
||||
Constructs an `LT` instance from an `Ord` instance that asserts that the result of `compare`
|
||||
satisfies `Ordering.isLE`.
|
||||
-/
|
||||
@[expose] def leOfOrd [Ord α] : LE α where
|
||||
le a b := (compare a b).isLE
|
||||
|
||||
@[inline]
|
||||
instance [Ord α] : DecidableRel (@LE.le α leOfOrd) := fun _ _ => instDecidableEqBool ..
|
||||
|
||||
namespace Ord
|
||||
|
||||
/--
|
||||
Constructs a `BEq` instance from an `Ord` instance.
|
||||
-/
|
||||
@[expose] protected abbrev toBEq (ord : Ord α) : BEq α :=
|
||||
beqOfOrd
|
||||
|
||||
/--
|
||||
Constructs an `LT` instance from an `Ord` instance.
|
||||
-/
|
||||
@[expose] protected abbrev toLT (ord : Ord α) : LT α :=
|
||||
ltOfOrd
|
||||
|
||||
/--
|
||||
Constructs an `LE` instance from an `Ord` instance.
|
||||
-/
|
||||
@[expose] protected abbrev toLE (ord : Ord α) : LE α :=
|
||||
leOfOrd
|
||||
|
||||
/--
|
||||
Inverts the order of an `Ord` instance.
|
||||
|
||||
The result is an `Ord α` instance that returns `Ordering.lt` when `ord` would return `Ordering.gt`
|
||||
and that returns `Ordering.gt` when `ord` would return `Ordering.lt`.
|
||||
-/
|
||||
@[expose] protected def opposite (ord : Ord α) : Ord α where
|
||||
compare x y := ord.compare y x
|
||||
|
||||
/--
|
||||
Constructs an `Ord` instance that compares values according to the results of `f`.
|
||||
|
||||
In particular, `ord.on f` compares `x` and `y` by comparing `f x` and `f y` according to `ord`.
|
||||
|
||||
The function `compareOn` can be used to perform this comparison without constructing an intermediate
|
||||
`Ord` instance.
|
||||
-/
|
||||
@[expose] protected def on (_ : Ord β) (f : α → β) : Ord α where
|
||||
compare := compareOn f
|
||||
|
||||
/--
|
||||
Constructs the lexicographic order on products `α × β` from orders for `α` and `β`.
|
||||
-/
|
||||
@[expose] protected abbrev lex (_ : Ord α) (_ : Ord β) : Ord (α × β) :=
|
||||
lexOrd
|
||||
|
||||
/--
|
||||
Constructs an `Ord` instance from two existing instances by combining them lexicographically.
|
||||
|
||||
The resulting instance compares elements first by `ord₁` and then, if this returns `Ordering.eq`, by
|
||||
`ord₂`.
|
||||
|
||||
The function `compareLex` can be used to perform this comparison without constructing an
|
||||
intermediate `Ord` instance. `Ordering.then` can be used to lexicographically combine the results of
|
||||
comparisons.
|
||||
-/
|
||||
@[expose] protected def lex' (ord₁ ord₂ : Ord α) : Ord α where
|
||||
compare := compareLex ord₁.compare ord₂.compare
|
||||
|
||||
end Ord
|
||||
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
|
||||
|
||||
825
src/Init/Data/Ord/Basic.lean
Normal file
825
src/Init/Data/Ord/Basic.lean
Normal file
@@ -0,0 +1,825 @@
|
||||
/-
|
||||
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Dany Fabian, Sebastian Ullrich
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.SInt.Basic
|
||||
public import all Init.Data.Vector.Basic
|
||||
|
||||
public section
|
||||
|
||||
/--
|
||||
The result of a comparison according to a total order.
|
||||
|
||||
The relationship between the compared items may be:
|
||||
* `Ordering.lt`: less than
|
||||
* `Ordering.eq`: equal
|
||||
* `Ordering.gt`: greater than
|
||||
-/
|
||||
inductive Ordering where
|
||||
/-- Less than. -/
|
||||
| lt
|
||||
/-- Equal. -/
|
||||
| eq
|
||||
/-- Greater than. -/
|
||||
| gt
|
||||
deriving Inhabited, DecidableEq, Repr
|
||||
|
||||
namespace Ordering
|
||||
|
||||
/--
|
||||
Swaps less-than and greater-than ordering results.
|
||||
|
||||
Examples:
|
||||
* `Ordering.lt.swap = Ordering.gt`
|
||||
* `Ordering.eq.swap = Ordering.eq`
|
||||
* `Ordering.gt.swap = Ordering.lt`
|
||||
-/
|
||||
@[inline, expose]
|
||||
def swap : Ordering → Ordering
|
||||
| .lt => .gt
|
||||
| .eq => .eq
|
||||
| .gt => .lt
|
||||
|
||||
/--
|
||||
If `a` and `b` are `Ordering`, then `a.then b` returns `a` unless it is `.eq`, in which case it
|
||||
returns `b`. Additionally, it has “short-circuiting” behavior similar to boolean `&&`: if `a` is not
|
||||
`.eq` then the expression for `b` is not evaluated.
|
||||
|
||||
This is a useful primitive for constructing lexicographic comparator functions. The `deriving Ord`
|
||||
syntax on a structure uses the `Ord` instance to compare each field in order, combining the results
|
||||
equivalently to `Ordering.then`.
|
||||
|
||||
Use `compareLex` to lexicographically combine two comparison functions.
|
||||
|
||||
Examples:
|
||||
```lean example
|
||||
structure Person where
|
||||
name : String
|
||||
age : Nat
|
||||
|
||||
-- Sort people first by name (in ascending order), and people with the same name by age (in
|
||||
-- descending order)
|
||||
instance : Ord Person where
|
||||
compare a b := (compare a.name b.name).then (compare b.age a.age)
|
||||
```
|
||||
|
||||
```lean example
|
||||
#eval Ord.compare (⟨"Gert", 33⟩ : Person) ⟨"Dana", 50⟩
|
||||
```
|
||||
```output
|
||||
Ordering.gt
|
||||
```
|
||||
|
||||
```lean example
|
||||
#eval Ord.compare (⟨"Gert", 33⟩ : Person) ⟨"Gert", 50⟩
|
||||
```
|
||||
```output
|
||||
Ordering.gt
|
||||
```
|
||||
|
||||
```lean example
|
||||
#eval Ord.compare (⟨"Gert", 33⟩ : Person) ⟨"Gert", 20⟩
|
||||
```
|
||||
```output
|
||||
Ordering.lt
|
||||
```
|
||||
-/
|
||||
@[macro_inline, expose] def «then» (a b : Ordering) : Ordering :=
|
||||
match a with
|
||||
| .eq => b
|
||||
| a => a
|
||||
|
||||
/-- Version of `Ordering.then'` for proof by reflection. -/
|
||||
@[expose] noncomputable def then' (a b : Ordering) : Ordering :=
|
||||
Ordering.rec a b a a
|
||||
|
||||
/--
|
||||
Checks whether the ordering is `eq`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def isEq : Ordering → Bool
|
||||
| eq => true
|
||||
| _ => false
|
||||
|
||||
/--
|
||||
Checks whether the ordering is not `eq`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def isNe : Ordering → Bool
|
||||
| eq => false
|
||||
| _ => true
|
||||
|
||||
/--
|
||||
Checks whether the ordering is `lt` or `eq`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def isLE : Ordering → Bool
|
||||
| gt => false
|
||||
| _ => true
|
||||
|
||||
/--
|
||||
Checks whether the ordering is `lt`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def isLT : Ordering → Bool
|
||||
| lt => true
|
||||
| _ => false
|
||||
|
||||
/--
|
||||
Checks whether the ordering is `gt`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def isGT : Ordering → Bool
|
||||
| gt => true
|
||||
| _ => false
|
||||
|
||||
/--
|
||||
Checks whether the ordering is `gt` or `eq`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def isGE : Ordering → Bool
|
||||
| lt => false
|
||||
| _ => true
|
||||
|
||||
section Lemmas
|
||||
|
||||
protected theorem «forall» {p : Ordering → Prop} : (∀ o, p o) ↔ p .lt ∧ p .eq ∧ p .gt := by
|
||||
constructor
|
||||
· intro h
|
||||
exact ⟨h _, h _, h _⟩
|
||||
· rintro ⟨h₁, h₂, h₃⟩ (_ | _ | _) <;> assumption
|
||||
|
||||
protected theorem «exists» {p : Ordering → Prop} : (∃ o, p o) ↔ p .lt ∨ p .eq ∨ p .gt := by
|
||||
constructor
|
||||
· rintro ⟨(_ | _ | _), h⟩
|
||||
· exact .inl h
|
||||
· exact .inr (.inl h)
|
||||
· exact .inr (.inr h)
|
||||
· rintro (h | h | h) <;> exact ⟨_, h⟩
|
||||
|
||||
instance [DecidablePred p] : Decidable (∀ o : Ordering, p o) :=
|
||||
decidable_of_decidable_of_iff Ordering.«forall».symm
|
||||
|
||||
instance [DecidablePred p] : Decidable (∃ o : Ordering, p o) :=
|
||||
decidable_of_decidable_of_iff Ordering.«exists».symm
|
||||
|
||||
@[simp] theorem isLT_lt : lt.isLT := rfl
|
||||
@[simp] theorem isLE_lt : lt.isLE := rfl
|
||||
@[simp] theorem isEq_lt : lt.isEq = false := rfl
|
||||
@[simp] theorem isNe_lt : lt.isNe = true := rfl
|
||||
@[simp] theorem isGE_lt : lt.isGE = false := rfl
|
||||
@[simp] theorem isGT_lt : lt.isGT = false := rfl
|
||||
|
||||
@[simp] theorem isLT_eq : eq.isLT = false := rfl
|
||||
@[simp] theorem isLE_eq : eq.isLE := rfl
|
||||
@[simp] theorem isEq_eq : eq.isEq := rfl
|
||||
@[simp] theorem isNe_eq : eq.isNe = false := rfl
|
||||
@[simp] theorem isGE_eq : eq.isGE := rfl
|
||||
@[simp] theorem isGT_eq : eq.isGT = false := rfl
|
||||
|
||||
@[simp] theorem isLT_gt : gt.isLT = false := rfl
|
||||
@[simp] theorem isLE_gt : gt.isLE = false := rfl
|
||||
@[simp] theorem isEq_gt : gt.isEq = false := rfl
|
||||
@[simp] theorem isNe_gt : gt.isNe = true := rfl
|
||||
@[simp] theorem isGE_gt : gt.isGE := rfl
|
||||
@[simp] theorem isGT_gt : gt.isGT := rfl
|
||||
|
||||
@[simp] theorem lt_beq_eq : (lt == eq) = false := rfl
|
||||
@[simp] theorem lt_beq_gt : (lt == gt) = false := rfl
|
||||
@[simp] theorem eq_beq_lt : (eq == lt) = false := rfl
|
||||
@[simp] theorem eq_beq_gt : (eq == gt) = false := rfl
|
||||
@[simp] theorem gt_beq_lt : (gt == lt) = false := rfl
|
||||
@[simp] theorem gt_beq_eq : (gt == eq) = false := rfl
|
||||
|
||||
@[simp] theorem swap_lt : lt.swap = .gt := rfl
|
||||
@[simp] theorem swap_eq : eq.swap = .eq := rfl
|
||||
@[simp] theorem swap_gt : gt.swap = .lt := rfl
|
||||
|
||||
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
|
||||
|
||||
@[simp] theorem isLE_eq_false : ∀ {o : Ordering}, o.isLE = false ↔ o = .gt := by decide
|
||||
@[simp] theorem isGE_eq_false : ∀ {o : Ordering}, o.isGE = false ↔ o = .lt := by decide
|
||||
@[simp] theorem isNe_eq_false : ∀ {o : Ordering}, o.isNe = false ↔ o = .eq := by decide
|
||||
@[simp] theorem isEq_eq_false : ∀ {o : Ordering}, o.isEq = false ↔ ¬o = .eq := by decide
|
||||
|
||||
@[simp] theorem swap_eq_gt : ∀ {o : Ordering}, o.swap = .gt ↔ o = .lt := by decide
|
||||
@[simp] theorem swap_eq_lt : ∀ {o : Ordering}, o.swap = .lt ↔ o = .gt := by decide
|
||||
@[simp] theorem swap_eq_eq : ∀ {o : Ordering}, o.swap = .eq ↔ o = .eq := by decide
|
||||
|
||||
@[simp] theorem isLT_swap : ∀ {o : Ordering}, o.swap.isLT = o.isGT := by decide
|
||||
@[simp] theorem isLE_swap : ∀ {o : Ordering}, o.swap.isLE = o.isGE := by decide
|
||||
@[simp] theorem isEq_swap : ∀ {o : Ordering}, o.swap.isEq = o.isEq := by decide
|
||||
@[simp] theorem isNe_swap : ∀ {o : Ordering}, o.swap.isNe = o.isNe := by decide
|
||||
@[simp] theorem isGE_swap : ∀ {o : Ordering}, o.swap.isGE = o.isLE := by decide
|
||||
@[simp] theorem isGT_swap : ∀ {o : Ordering}, o.swap.isGT = o.isLT := by decide
|
||||
|
||||
theorem isLE_of_eq_lt : ∀ {o : Ordering}, o = .lt → o.isLE := by decide
|
||||
theorem isLE_of_eq_eq : ∀ {o : Ordering}, o = .eq → o.isLE := by decide
|
||||
theorem isGE_of_eq_gt : ∀ {o : Ordering}, o = .gt → o.isGE := by decide
|
||||
theorem isGE_of_eq_eq : ∀ {o : Ordering}, o = .eq → o.isGE := by decide
|
||||
|
||||
theorem ne_eq_of_eq_lt : ∀ {o : Ordering}, o = .lt → o ≠ .eq := by decide
|
||||
theorem ne_eq_of_eq_gt : ∀ {o : Ordering}, o = .gt → o ≠ .eq := by decide
|
||||
|
||||
@[simp] theorem isLT_iff_eq_lt : ∀ {o : Ordering}, o.isLT ↔ o = .lt := by decide
|
||||
@[simp] theorem isGT_iff_eq_gt : ∀ {o : Ordering}, o.isGT ↔ o = .gt := by decide
|
||||
@[simp] theorem isEq_iff_eq_eq : ∀ {o : Ordering}, o.isEq ↔ o = .eq := by decide
|
||||
@[simp] theorem isNe_iff_ne_eq : ∀ {o : Ordering}, o.isNe ↔ ¬o = .eq := by decide
|
||||
|
||||
theorem isLE_iff_ne_gt : ∀ {o : Ordering}, o.isLE ↔ ¬o = .gt := by decide
|
||||
theorem isGE_iff_ne_lt : ∀ {o : Ordering}, o.isGE ↔ ¬o = .lt := by decide
|
||||
theorem isLE_iff_eq_lt_or_eq_eq : ∀ {o : Ordering}, o.isLE ↔ o = .lt ∨ o = .eq := by decide
|
||||
theorem isGE_iff_eq_gt_or_eq_eq : ∀ {o : Ordering}, o.isGE ↔ o = .gt ∨ o = .eq := by decide
|
||||
|
||||
theorem isLT_eq_beq_lt : ∀ {o : Ordering}, o.isLT = (o == .lt) := by decide
|
||||
theorem isLE_eq_not_beq_gt : ∀ {o : Ordering}, o.isLE = (!o == .gt) := by decide
|
||||
theorem isLE_eq_isLT_or_isEq : ∀ {o : Ordering}, o.isLE = (o.isLT || o.isEq) := by decide
|
||||
theorem isGT_eq_beq_gt : ∀ {o : Ordering}, o.isGT = (o == .gt) := by decide
|
||||
theorem isGE_eq_not_beq_lt : ∀ {o : Ordering}, o.isGE = (!o == .lt) := by decide
|
||||
theorem isGE_eq_isGT_or_isEq : ∀ {o : Ordering}, o.isGE = (o.isGT || o.isEq) := by decide
|
||||
theorem isEq_eq_beq_eq : ∀ {o : Ordering}, o.isEq = (o == .eq) := by decide
|
||||
theorem isNe_eq_not_beq_eq : ∀ {o : Ordering}, o.isNe = (!o == .eq) := by decide
|
||||
theorem isNe_eq_isLT_or_isGT : ∀ {o : Ordering}, o.isNe = (o.isLT || o.isGT) := by decide
|
||||
|
||||
@[simp] theorem not_isLT_eq_isGE : ∀ {o : Ordering}, (!o.isLT) = o.isGE := by decide
|
||||
@[simp] theorem not_isLE_eq_isGT : ∀ {o : Ordering}, (!o.isLE) = o.isGT := by decide
|
||||
@[simp] theorem not_isGT_eq_isLE : ∀ {o : Ordering}, (!o.isGT) = o.isLE := by decide
|
||||
@[simp] theorem not_isGE_eq_isLT : ∀ {o : Ordering}, (!o.isGE) = o.isLT := by decide
|
||||
@[simp] theorem not_isNe_eq_isEq : ∀ {o : Ordering}, (!o.isNe) = o.isEq := by decide
|
||||
theorem not_isEq_eq_isNe : ∀ {o : Ordering}, (!o.isEq) = o.isNe := by decide
|
||||
|
||||
theorem ne_lt_iff_isGE : ∀ {o : Ordering}, ¬o = .lt ↔ o.isGE := by decide
|
||||
theorem ne_gt_iff_isLE : ∀ {o : Ordering}, ¬o = .gt ↔ o.isLE := by decide
|
||||
|
||||
@[simp] theorem swap_swap : ∀ {o : Ordering}, o.swap.swap = o := by decide
|
||||
@[simp] theorem swap_inj : ∀ {o₁ o₂ : Ordering}, o₁.swap = o₂.swap ↔ o₁ = o₂ := by decide
|
||||
|
||||
theorem swap_then : ∀ (o₁ o₂ : Ordering), (o₁.then o₂).swap = o₁.swap.then o₂.swap := by decide
|
||||
|
||||
theorem then_eq_lt : ∀ {o₁ o₂ : Ordering}, o₁.then o₂ = lt ↔ o₁ = lt ∨ o₁ = eq ∧ o₂ = lt := by decide
|
||||
theorem then_eq_gt : ∀ {o₁ o₂ : Ordering}, o₁.then o₂ = gt ↔ o₁ = gt ∨ o₁ = eq ∧ o₂ = gt := by decide
|
||||
@[simp] theorem then_eq_eq : ∀ {o₁ o₂ : Ordering}, o₁.then o₂ = eq ↔ o₁ = eq ∧ o₂ = eq := by decide
|
||||
|
||||
theorem isLT_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isLT = (o₁.isLT || o₁.isEq && o₂.isLT) := by decide
|
||||
theorem isEq_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isEq = (o₁.isEq && o₂.isEq) := by decide
|
||||
theorem isNe_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isNe = (o₁.isNe || o₂.isNe) := by decide
|
||||
theorem isGT_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isGT = (o₁.isGT || o₁.isEq && o₂.isGT) := by decide
|
||||
|
||||
@[simp] theorem lt_then {o : Ordering} : lt.then o = lt := rfl
|
||||
@[simp] theorem gt_then {o : Ordering} : gt.then o = gt := rfl
|
||||
@[simp] theorem eq_then {o : Ordering} : eq.then o = o := rfl
|
||||
|
||||
@[simp] theorem then_eq : ∀ {o : Ordering}, o.then eq = o := by decide
|
||||
@[simp] theorem then_self : ∀ {o : Ordering}, o.then o = o := by decide
|
||||
theorem then_assoc : ∀ (o₁ o₂ o₃ : Ordering), (o₁.then o₂).then o₃ = o₁.then (o₂.then o₃) := by decide
|
||||
|
||||
theorem isLE_then_iff_or : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isLE ↔ o₁ = lt ∨ (o₁ = eq ∧ o₂.isLE) := by decide
|
||||
theorem isLE_then_iff_and : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isLE ↔ o₁.isLE ∧ (o₁ = lt ∨ o₂.isLE) := by decide
|
||||
theorem isLE_left_of_isLE_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isLE → o₁.isLE := by decide
|
||||
theorem isGE_left_of_isGE_then : ∀ {o₁ o₂ : Ordering}, (o₁.then o₂).isGE → o₁.isGE := by decide
|
||||
|
||||
instance : Std.Associative Ordering.then := ⟨then_assoc⟩
|
||||
instance : Std.IdempotentOp Ordering.then := ⟨fun _ => then_self⟩
|
||||
|
||||
instance : Std.LawfulIdentity Ordering.then eq where
|
||||
left_id _ := eq_then
|
||||
right_id _ := then_eq
|
||||
|
||||
theorem then'_eq_then (a b : Ordering) : a.then' b = a.then b := by
|
||||
cases a <;> simp [Ordering.then', Ordering.then]
|
||||
|
||||
end Lemmas
|
||||
|
||||
end Ordering
|
||||
|
||||
/--
|
||||
Uses decidable less-than and equality relations to find an `Ordering`.
|
||||
|
||||
In particular, if `x < y` then the result is `Ordering.lt`. If `x = y` then the result is
|
||||
`Ordering.eq`. Otherwise, it is `Ordering.gt`.
|
||||
|
||||
`compareOfLessAndBEq` uses `BEq` instead of `DecidableEq`.
|
||||
-/
|
||||
@[inline, expose] def compareOfLessAndEq {α} (x y : α) [LT α] [Decidable (x < y)] [DecidableEq α] : Ordering :=
|
||||
if x < y then Ordering.lt
|
||||
else if x = y then Ordering.eq
|
||||
else Ordering.gt
|
||||
|
||||
/--
|
||||
Uses a decidable less-than relation and Boolean equality to find an `Ordering`.
|
||||
|
||||
In particular, if `x < y` then the result is `Ordering.lt`. If `x == y` then the result is
|
||||
`Ordering.eq`. Otherwise, it is `Ordering.gt`.
|
||||
|
||||
`compareOfLessAndEq` uses `DecidableEq` instead of `BEq`.
|
||||
-/
|
||||
@[inline] def compareOfLessAndBEq {α} (x y : α) [LT α] [Decidable (x < y)] [BEq α] : Ordering :=
|
||||
if x < y then .lt
|
||||
else if x == y then .eq
|
||||
else .gt
|
||||
|
||||
/--
|
||||
Compares `a` and `b` lexicographically by `cmp₁` and `cmp₂`.
|
||||
|
||||
`a` and `b` are first compared by `cmp₁`. If this returns `Ordering.eq`, `a` and `b` are compared
|
||||
by `cmp₂` to break the tie.
|
||||
|
||||
To lexicographically combine two `Ordering`s, use `Ordering.then`.
|
||||
-/
|
||||
@[inline, expose] def compareLex (cmp₁ cmp₂ : α → β → Ordering) (a : α) (b : β) : Ordering :=
|
||||
(cmp₁ a b).then (cmp₂ a b)
|
||||
|
||||
section Lemmas
|
||||
|
||||
@[simp]
|
||||
theorem compareLex_eq_eq {α} {cmp₁ cmp₂} {a b : α} :
|
||||
compareLex cmp₁ cmp₂ a b = .eq ↔ cmp₁ a b = .eq ∧ cmp₂ a b = .eq := by
|
||||
simp [compareLex]
|
||||
|
||||
theorem compareOfLessAndEq_eq_swap_of_lt_iff_not_gt_and_ne {α : Type u} [LT α] [DecidableLT α] [DecidableEq α]
|
||||
(h : ∀ x y : α, x < y ↔ ¬ y < x ∧ x ≠ y) {x y : α} :
|
||||
compareOfLessAndEq x y = (compareOfLessAndEq y x).swap := by
|
||||
simp only [compareOfLessAndEq]
|
||||
split
|
||||
· rename_i h'
|
||||
rw [h] at h'
|
||||
simp only [h'.1, h'.2.symm, ↓reduceIte, Ordering.swap_gt]
|
||||
· split
|
||||
· rename_i h'
|
||||
have : ¬ y < y := Not.imp (·.2 rfl) <| (h y y).mp
|
||||
simp only [h', this, ↓reduceIte, Ordering.swap_eq]
|
||||
· rename_i h' h''
|
||||
replace h' := (h y x).mpr ⟨h', Ne.symm h''⟩
|
||||
simp only [h', ↓reduceIte, Ordering.swap_lt]
|
||||
|
||||
theorem lt_iff_not_gt_and_ne_of_antisymm_of_total_of_not_le
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableEq α]
|
||||
(antisymm : ∀ {x y : α}, x ≤ y → y ≤ x → x = y)
|
||||
(total : ∀ (x y : α), x ≤ y ∨ y ≤ x) (not_le : ∀ {x y : α}, ¬ x ≤ y ↔ y < x) (x y : α) :
|
||||
x < y ↔ ¬ y < x ∧ x ≠ y := by
|
||||
simp only [← not_le, Classical.not_not]
|
||||
constructor
|
||||
· intro h
|
||||
have refl := by cases total y y <;> assumption
|
||||
exact ⟨(total _ _).resolve_left h, fun h' => (h' ▸ h) refl⟩
|
||||
· intro ⟨h₁, h₂⟩ h₃
|
||||
exact h₂ (antisymm h₁ h₃)
|
||||
|
||||
theorem compareOfLessAndEq_eq_swap
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableEq α]
|
||||
(antisymm : ∀ {x y : α}, x ≤ y → y ≤ x → x = y)
|
||||
(total : ∀ (x y : α), x ≤ y ∨ y ≤ x) (not_le : ∀ {x y : α}, ¬ x ≤ y ↔ y < x) {x y : α} :
|
||||
compareOfLessAndEq x y = (compareOfLessAndEq y x).swap := by
|
||||
apply compareOfLessAndEq_eq_swap_of_lt_iff_not_gt_and_ne
|
||||
exact lt_iff_not_gt_and_ne_of_antisymm_of_total_of_not_le antisymm total not_le
|
||||
|
||||
@[simp]
|
||||
theorem compareOfLessAndEq_eq_lt
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableEq α] {x y : α} :
|
||||
compareOfLessAndEq x y = .lt ↔ x < y := by
|
||||
rw [compareOfLessAndEq]
|
||||
repeat' split <;> simp_all
|
||||
|
||||
theorem compareOfLessAndEq_eq_eq
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableLE α] [DecidableEq α]
|
||||
(refl : ∀ (x : α), x ≤ x) (not_le : ∀ {x y : α}, ¬ x ≤ y ↔ y < x) {x y : α} :
|
||||
compareOfLessAndEq x y = .eq ↔ x = y := by
|
||||
rw [compareOfLessAndEq]
|
||||
repeat' split <;> try (simp_all; done)
|
||||
simp only [reduceCtorEq, false_iff]
|
||||
rintro rfl
|
||||
rename_i hlt
|
||||
simp [← not_le] at hlt
|
||||
exact hlt (refl x)
|
||||
|
||||
theorem compareOfLessAndEq_eq_gt_of_lt_iff_not_gt_and_ne
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableEq α] {x y : α}
|
||||
(h : ∀ x y : α, x < y ↔ ¬ y < x ∧ x ≠ y) :
|
||||
compareOfLessAndEq x y = .gt ↔ y < x := by
|
||||
rw [compareOfLessAndEq_eq_swap_of_lt_iff_not_gt_and_ne h, Ordering.swap_eq_gt]
|
||||
exact compareOfLessAndEq_eq_lt
|
||||
|
||||
theorem compareOfLessAndEq_eq_gt
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableEq α]
|
||||
(antisymm : ∀ {x y : α}, x ≤ y → y ≤ x → x = y)
|
||||
(total : ∀ (x y : α), x ≤ y ∨ y ≤ x) (not_le : ∀ {x y : α}, ¬ x ≤ y ↔ y < x) (x y : α) :
|
||||
compareOfLessAndEq x y = .gt ↔ y < x := by
|
||||
apply compareOfLessAndEq_eq_gt_of_lt_iff_not_gt_and_ne
|
||||
exact lt_iff_not_gt_and_ne_of_antisymm_of_total_of_not_le antisymm total not_le
|
||||
|
||||
theorem isLE_compareOfLessAndEq
|
||||
{α : Type u} [LT α] [LE α] [DecidableLT α] [DecidableLE α] [DecidableEq α]
|
||||
(antisymm : ∀ {x y : α}, x ≤ y → y ≤ x → x = y)
|
||||
(not_le : ∀ {x y : α}, ¬ x ≤ y ↔ y < x) (total : ∀ (x y : α), x ≤ y ∨ y ≤ x) {x y : α} :
|
||||
(compareOfLessAndEq x y).isLE ↔ x ≤ y := by
|
||||
have refl (a : α) := by cases total a a <;> assumption
|
||||
rw [Ordering.isLE_iff_eq_lt_or_eq_eq, compareOfLessAndEq_eq_lt,
|
||||
compareOfLessAndEq_eq_eq refl not_le]
|
||||
constructor
|
||||
· rintro (h | rfl)
|
||||
· rw [← not_le] at h
|
||||
exact total _ _ |>.resolve_left h
|
||||
· exact refl x
|
||||
· intro hle
|
||||
by_cases hge : x ≥ y
|
||||
· exact Or.inr <| antisymm hle hge
|
||||
· exact Or.inl <| not_le.mp hge
|
||||
|
||||
end Lemmas
|
||||
|
||||
/--
|
||||
`Ord α` provides a computable total order on `α`, in terms of the
|
||||
`compare : α → α → Ordering` function.
|
||||
|
||||
Typically instances will be transitive, reflexive, and antisymmetric,
|
||||
but this is not enforced by the typeclass.
|
||||
|
||||
There is a derive handler, so appending `deriving Ord` to an inductive type or structure
|
||||
will attempt to create an `Ord` instance.
|
||||
-/
|
||||
@[ext]
|
||||
class Ord (α : Type u) where
|
||||
/-- Compare two elements in `α` using the comparator contained in an `[Ord α]` instance. -/
|
||||
compare : α → α → Ordering
|
||||
|
||||
export Ord (compare)
|
||||
|
||||
/--
|
||||
Compares two values by comparing the results of applying a function.
|
||||
|
||||
In particular, `x` is compared to `y` by comparing `f x` and `f y`.
|
||||
|
||||
Examples:
|
||||
* `compareOn (·.length) "apple" "banana" = .lt`
|
||||
* `compareOn (· % 3) 5 6 = .gt`
|
||||
* `compareOn (·.foldl max 0) [1, 2, 3] [3, 2, 1] = .eq`
|
||||
-/
|
||||
@[inline, expose] def compareOn [ord : Ord β] (f : α → β) (x y : α) : Ordering :=
|
||||
compare (f x) (f y)
|
||||
|
||||
instance : Ord Nat where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Int where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Bool where
|
||||
compare
|
||||
| false, true => Ordering.lt
|
||||
| true, false => Ordering.gt
|
||||
| _, _ => Ordering.eq
|
||||
|
||||
instance : Ord String where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance (n : Nat) : Ord (Fin n) where
|
||||
compare x y := compare x.val y.val
|
||||
|
||||
instance : Ord UInt8 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord UInt16 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord UInt32 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord UInt64 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord USize where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Char where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Int8 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Int16 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Int32 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord Int64 where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance : Ord ISize where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance {n} : Ord (BitVec n) where
|
||||
compare x y := compareOfLessAndEq x y
|
||||
|
||||
instance [Ord α] : Ord (Option α) where
|
||||
compare
|
||||
| none, none => .eq
|
||||
| none, some _ => .lt
|
||||
| some _, none => .gt
|
||||
| some x, some y => compare x y
|
||||
|
||||
instance : Ord Ordering where
|
||||
compare := compareOn (·.toCtorIdx)
|
||||
|
||||
namespace List
|
||||
|
||||
@[specialize, expose]
|
||||
protected def compareLex {α} (cmp : α → α → Ordering) :
|
||||
List α → List α → Ordering
|
||||
| [], [] => .eq
|
||||
| [], _ => .lt
|
||||
| _, [] => .gt
|
||||
| x :: xs, y :: ys => match cmp x y with
|
||||
| .lt => .lt
|
||||
| .eq => xs.compareLex cmp ys
|
||||
| .gt => .gt
|
||||
|
||||
instance {α} [Ord α] : Ord (List α) where
|
||||
compare := List.compareLex compare
|
||||
|
||||
protected theorem compare_eq_compareLex {α} [Ord α] :
|
||||
compare (α := List α) = List.compareLex compare := rfl
|
||||
|
||||
protected theorem compareLex_cons_cons {α} {cmp} {x y : α} {xs ys : List α} :
|
||||
(x :: xs).compareLex cmp (y :: ys) = (cmp x y).then (xs.compareLex cmp ys) := by
|
||||
rw [List.compareLex]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp]
|
||||
protected theorem compare_cons_cons {α} [Ord α] {x y : α} {xs ys : List α} :
|
||||
compare (x :: xs) (y :: ys) = (compare x y).then (compare xs ys) :=
|
||||
List.compareLex_cons_cons
|
||||
|
||||
protected theorem compareLex_nil_cons {α} {cmp} {x : α} {xs : List α} :
|
||||
[].compareLex cmp (x :: xs) = .lt :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
protected theorem compare_nil_cons {α} [Ord α] {x : α} {xs : List α} :
|
||||
compare [] (x :: xs) = .lt :=
|
||||
rfl
|
||||
|
||||
protected theorem compareLex_cons_nil {α} {cmp} {x : α} {xs : List α} :
|
||||
(x :: xs).compareLex cmp [] = .gt :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
protected theorem compare_cons_nil {α} [Ord α] {x : α} {xs : List α} :
|
||||
compare (x :: xs) [] = .gt :=
|
||||
rfl
|
||||
|
||||
protected theorem compareLex_nil_nil {α} {cmp} :
|
||||
[].compareLex (α := α) cmp [] = .eq :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
protected theorem compare_nil_nil {α} [Ord α] :
|
||||
compare (α := List α) [] [] = .eq :=
|
||||
rfl
|
||||
|
||||
protected theorem isLE_compareLex_nil_left {α} {cmp} {xs : List α} :
|
||||
(List.compareLex (cmp := cmp) [] xs).isLE := by
|
||||
cases xs <;> simp [List.compareLex_nil_nil, List.compareLex_nil_cons]
|
||||
|
||||
protected theorem isLE_compare_nil_left {α} [Ord α] {xs : List α} :
|
||||
(compare [] xs).isLE :=
|
||||
List.isLE_compareLex_nil_left
|
||||
|
||||
protected theorem isLE_compareLex_nil_right {α} {cmp} {xs : List α} :
|
||||
(List.compareLex (cmp := cmp) xs []).isLE ↔ xs = [] := by
|
||||
cases xs <;> simp [List.compareLex_nil_nil, List.compareLex_cons_nil]
|
||||
|
||||
@[simp]
|
||||
protected theorem isLE_compare_nil_right {α} [Ord α] {xs : List α} :
|
||||
(compare xs []).isLE ↔ xs = [] :=
|
||||
List.isLE_compareLex_nil_right
|
||||
|
||||
protected theorem isGE_compareLex_nil_left {α} {cmp} {xs : List α} :
|
||||
(List.compareLex (cmp := cmp) [] xs).isGE ↔ xs = [] := by
|
||||
cases xs <;> simp [List.compareLex_nil_nil, List.compareLex_nil_cons]
|
||||
|
||||
@[simp]
|
||||
protected theorem isGE_compare_nil_left {α} [Ord α] {xs : List α} :
|
||||
(compare [] xs).isGE ↔ xs = [] :=
|
||||
List.isGE_compareLex_nil_left
|
||||
|
||||
protected theorem isGE_compareLex_nil_right {α} {cmp} {xs : List α} :
|
||||
(List.compareLex (cmp := cmp) xs []).isGE := by
|
||||
cases xs <;> simp [List.compareLex_nil_nil, List.compareLex_cons_nil]
|
||||
|
||||
protected theorem isGE_compare_nil_right {α} [Ord α] {xs : List α} :
|
||||
(compare xs []).isGE :=
|
||||
List.isGE_compareLex_nil_right
|
||||
|
||||
protected theorem compareLex_nil_left_eq_eq {α} {cmp} {xs : List α} :
|
||||
List.compareLex cmp [] xs = .eq ↔ xs = [] := by
|
||||
cases xs <;> simp [List.compareLex_nil_nil, List.compareLex_nil_cons]
|
||||
|
||||
@[simp]
|
||||
protected theorem compare_nil_left_eq_eq {α} [Ord α] {xs : List α} :
|
||||
compare [] xs = .eq ↔ xs = [] :=
|
||||
List.compareLex_nil_left_eq_eq
|
||||
|
||||
protected theorem compareLex_nil_right_eq_eq {α} {cmp} {xs : List α} :
|
||||
xs.compareLex cmp [] = .eq ↔ xs = [] := by
|
||||
cases xs <;> simp [List.compareLex_nil_nil, List.compareLex_cons_nil]
|
||||
|
||||
@[simp]
|
||||
protected theorem compare_nil_right_eq_eq {α} [Ord α] {xs : List α} :
|
||||
compare xs [] = .eq ↔ xs = [] :=
|
||||
List.compareLex_nil_right_eq_eq
|
||||
|
||||
end List
|
||||
|
||||
namespace Array
|
||||
|
||||
@[specialize]
|
||||
protected def compareLex {α} (cmp : α → α → Ordering) (a₁ a₂ : Array α) : Ordering :=
|
||||
go 0
|
||||
where go i :=
|
||||
if h₁ : a₁.size <= i then
|
||||
if a₂.size <= i then .eq else .lt
|
||||
else
|
||||
if h₂ : a₂.size <= i then
|
||||
.gt
|
||||
else match cmp a₁[i] a₂[i] with
|
||||
| .lt => .lt
|
||||
| .eq => go (i + 1)
|
||||
| .gt => .gt
|
||||
termination_by a₁.size - i
|
||||
|
||||
instance {α} [Ord α] : Ord (Array α) where
|
||||
compare := Array.compareLex compare
|
||||
|
||||
protected theorem compare_eq_compareLex {α} [Ord α] :
|
||||
compare (α := Array α) = Array.compareLex compare := rfl
|
||||
|
||||
private theorem compareLex.go_succ {α} {cmp} {x₁ x₂} {a₁ a₂ : List α} {i} :
|
||||
compareLex.go cmp (x₁ :: a₁).toArray (x₂ :: a₂).toArray (i + 1) =
|
||||
compareLex.go cmp a₁.toArray a₂.toArray i := by
|
||||
induction i using Array.compareLex.go.induct cmp a₁.toArray a₂.toArray
|
||||
all_goals try
|
||||
conv => congr <;> rw [compareLex.go]
|
||||
simp
|
||||
repeat' split <;> (try simp_all; done)
|
||||
|
||||
protected theorem _root_.List.compareLex_eq_compareLex_toArray {α} {cmp} {l₁ l₂ : List α} :
|
||||
List.compareLex cmp l₁ l₂ = Array.compareLex cmp l₁.toArray l₂.toArray := by
|
||||
simp only [Array.compareLex]
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil =>
|
||||
cases l₂
|
||||
· simp [Array.compareLex.go, List.compareLex_nil_nil]
|
||||
· simp [Array.compareLex.go, List.compareLex_nil_cons]
|
||||
| cons x xs ih =>
|
||||
cases l₂
|
||||
· simp [Array.compareLex.go, List.compareLex_cons_nil]
|
||||
· rw [Array.compareLex.go, List.compareLex_cons_cons]
|
||||
simp only [List.size_toArray, List.length_cons, Nat.le_zero_eq, Nat.add_one_ne_zero,
|
||||
↓reduceDIte, List.getElem_toArray, List.getElem_cons_zero, Nat.zero_add]
|
||||
split <;> simp_all [compareLex.go_succ]
|
||||
|
||||
protected theorem _root_.List.compare_eq_compare_toArray {α} [Ord α] {l₁ l₂ : List α} :
|
||||
compare l₁ l₂ = compare l₁.toArray l₂.toArray :=
|
||||
List.compareLex_eq_compareLex_toArray
|
||||
|
||||
protected theorem compareLex_eq_compareLex_toList {α} {cmp} {a₁ a₂ : Array α} :
|
||||
Array.compareLex cmp a₁ a₂ = List.compareLex cmp a₁.toList a₂.toList := by
|
||||
rw [List.compareLex_eq_compareLex_toArray]
|
||||
|
||||
protected theorem compare_eq_compare_toList {α} [Ord α] {a₁ a₂ : Array α} :
|
||||
compare a₁ a₂ = compare a₁.toList a₂.toList :=
|
||||
Array.compareLex_eq_compareLex_toList
|
||||
|
||||
end Array
|
||||
|
||||
namespace Vector
|
||||
|
||||
@[expose]
|
||||
protected def compareLex {α n} (cmp : α → α → Ordering) (a b : Vector α n) : Ordering :=
|
||||
Array.compareLex cmp a.toArray b.toArray
|
||||
|
||||
instance {α n} [Ord α] : Ord (Vector α n) where
|
||||
compare := Vector.compareLex compare
|
||||
|
||||
protected theorem compareLex_eq_compareLex_toArray {α n cmp} {a b : Vector α n} :
|
||||
Vector.compareLex cmp a b = Array.compareLex cmp a.toArray b.toArray :=
|
||||
rfl
|
||||
|
||||
protected theorem compareLex_eq_compareLex_toList {α n cmp} {a b : Vector α n} :
|
||||
Vector.compareLex cmp a b = List.compareLex cmp a.toList b.toList :=
|
||||
Array.compareLex_eq_compareLex_toList
|
||||
|
||||
protected theorem compare_eq_compare_toArray {α n} [Ord α] {a b : Vector α n} :
|
||||
compare a b = compare a.toArray b.toArray :=
|
||||
rfl
|
||||
|
||||
protected theorem compare_eq_compare_toList {α n} [Ord α] {a b : Vector α n} :
|
||||
compare a b = compare a.toList b.toList :=
|
||||
Array.compare_eq_compare_toList
|
||||
|
||||
end Vector
|
||||
|
||||
/-- The lexicographic order on pairs. -/
|
||||
@[expose] def lexOrd [Ord α] [Ord β] : Ord (α × β) where
|
||||
compare := compareLex (compareOn (·.1)) (compareOn (·.2))
|
||||
|
||||
/--
|
||||
Constructs an `BEq` instance from an `Ord` instance that asserts that the result of `compare` is
|
||||
`Ordering.eq`.
|
||||
-/
|
||||
@[expose] def beqOfOrd [Ord α] : BEq α where
|
||||
beq a b := (compare a b).isEq
|
||||
|
||||
/--
|
||||
Constructs an `LT` instance from an `Ord` instance that asserts that the result of `compare` is
|
||||
`Ordering.lt`.
|
||||
-/
|
||||
@[expose] def ltOfOrd [Ord α] : LT α where
|
||||
lt a b := compare a b = Ordering.lt
|
||||
|
||||
@[inline]
|
||||
instance [Ord α] : DecidableRel (@LT.lt α ltOfOrd) := fun a b =>
|
||||
decidable_of_bool (compare a b).isLT Ordering.isLT_iff_eq_lt
|
||||
|
||||
/--
|
||||
Constructs an `LT` instance from an `Ord` instance that asserts that the result of `compare`
|
||||
satisfies `Ordering.isLE`.
|
||||
-/
|
||||
@[expose] def leOfOrd [Ord α] : LE α where
|
||||
le a b := (compare a b).isLE
|
||||
|
||||
@[inline]
|
||||
instance [Ord α] : DecidableRel (@LE.le α leOfOrd) := fun _ _ => instDecidableEqBool ..
|
||||
|
||||
namespace Ord
|
||||
|
||||
/--
|
||||
Constructs a `BEq` instance from an `Ord` instance.
|
||||
-/
|
||||
@[expose] protected abbrev toBEq (ord : Ord α) : BEq α :=
|
||||
beqOfOrd
|
||||
|
||||
/--
|
||||
Constructs an `LT` instance from an `Ord` instance.
|
||||
-/
|
||||
@[expose] protected abbrev toLT (ord : Ord α) : LT α :=
|
||||
ltOfOrd
|
||||
|
||||
/--
|
||||
Constructs an `LE` instance from an `Ord` instance.
|
||||
-/
|
||||
@[expose] protected abbrev toLE (ord : Ord α) : LE α :=
|
||||
leOfOrd
|
||||
|
||||
/--
|
||||
Inverts the order of an `Ord` instance.
|
||||
|
||||
The result is an `Ord α` instance that returns `Ordering.lt` when `ord` would return `Ordering.gt`
|
||||
and that returns `Ordering.gt` when `ord` would return `Ordering.lt`.
|
||||
-/
|
||||
@[expose] protected def opposite (ord : Ord α) : Ord α where
|
||||
compare x y := ord.compare y x
|
||||
|
||||
/--
|
||||
Constructs an `Ord` instance that compares values according to the results of `f`.
|
||||
|
||||
In particular, `ord.on f` compares `x` and `y` by comparing `f x` and `f y` according to `ord`.
|
||||
|
||||
The function `compareOn` can be used to perform this comparison without constructing an intermediate
|
||||
`Ord` instance.
|
||||
-/
|
||||
@[expose] protected def on (_ : Ord β) (f : α → β) : Ord α where
|
||||
compare := compareOn f
|
||||
|
||||
/--
|
||||
Constructs the lexicographic order on products `α × β` from orders for `α` and `β`.
|
||||
-/
|
||||
@[expose] protected abbrev lex (_ : Ord α) (_ : Ord β) : Ord (α × β) :=
|
||||
lexOrd
|
||||
|
||||
/--
|
||||
Constructs an `Ord` instance from two existing instances by combining them lexicographically.
|
||||
|
||||
The resulting instance compares elements first by `ord₁` and then, if this returns `Ordering.eq`, by
|
||||
`ord₂`.
|
||||
|
||||
The function `compareLex` can be used to perform this comparison without constructing an
|
||||
intermediate `Ord` instance. `Ordering.then` can be used to lexicographically combine the results of
|
||||
comparisons.
|
||||
-/
|
||||
@[expose] protected def lex' (ord₁ ord₂ : Ord α) : Ord α where
|
||||
compare := compareLex ord₁.compare ord₂.compare
|
||||
|
||||
end Ord
|
||||
@@ -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
|
||||
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
|
||||
305
src/Init/Data/Order/Factories.lean
Normal file
305
src/Init/Data/Order/Factories.lean
Normal file
@@ -0,0 +1,305 @@
|
||||
/-
|
||||
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
|
||||
|
||||
/--
|
||||
Creates a `Min α` instance from `LE α` and `DecidableLE α` so that `min a b` is either `a` or `b`,
|
||||
preferring `a` over `b` when in doubt.
|
||||
|
||||
Has a `LawfulOrderLeftLeaningMin α` instance.
|
||||
-/
|
||||
@[inline]
|
||||
public def _root_.Min.leftLeaningOfLE (α : Type u) [LE α] [DecidableLE α] : Min α where
|
||||
min a b := if a ≤ b then a else b
|
||||
|
||||
/--
|
||||
Creates a `Max α` instance from `LE α` and `DecidableLE α` so that `max a b` is either `a` or `b`,
|
||||
preferring `a` over `b` when in doubt.
|
||||
|
||||
Has a `LawfulOrderLeftLeaningMax α` instance.
|
||||
-/
|
||||
@[inline]
|
||||
public def _root_.Max.leftLeaningOfLE (α : Type u) [LE α] [DecidableLE α] : Max α where
|
||||
max a b := if b ≤ a then a else b
|
||||
|
||||
/--
|
||||
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_min_iff {α : Type u} [Min α] [LE α]
|
||||
(le_min_iff : ∀ a b c : α, a ≤ min b c ↔ a ≤ b ∧ a ≤ c := by exact LawfulOrderInf.le_min_iff)
|
||||
(min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b := by exact MinEqOr.min_eq_or) :
|
||||
LawfulOrderMin α where
|
||||
toLawfulOrderInf := .of_le le_min_iff
|
||||
toMinEqOr := ⟨min_eq_or⟩
|
||||
|
||||
/--
|
||||
Returns a `LawfulOrderMin α` instance given that `max a b` returns either `a` or `b` and that
|
||||
it is less than or equal to both of them. The `≤` relation needs to be transitive.
|
||||
|
||||
The produced instance entails `LawfulOrderInf α` and `MinEqOr α`.
|
||||
-/
|
||||
public theorem LawfulOrderMin.of_min_le {α : Type u} [Min α] [LE α]
|
||||
[i : Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·)]
|
||||
(min_le_left : ∀ a b : α, min a b ≤ a) (min_le_right : ∀ a b : α, min a b ≤ b)
|
||||
(min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b := by exact MinEqOr.min_eq_or) :
|
||||
LawfulOrderMin α := by
|
||||
apply LawfulOrderMin.of_le_min_iff
|
||||
· simp [autoParam]
|
||||
intro a b c
|
||||
constructor
|
||||
· intro h
|
||||
exact ⟨i.trans h (min_le_left b c), i.trans h (min_le_right b c)⟩
|
||||
· intro h
|
||||
cases min_eq_or b c <;> simp [*]
|
||||
· exact 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_max_le_iff {α : Type u} [Max α] [LE α]
|
||||
(max_le_iff : ∀ a b c : α, max a b ≤ c ↔ a ≤ c ∧ b ≤ c := by exact LawfulOrderInf.le_min_iff)
|
||||
(max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b := by exact MaxEqOr.max_eq_or) :
|
||||
LawfulOrderMax α where
|
||||
toLawfulOrderSup := .of_le max_le_iff
|
||||
toMaxEqOr := ⟨max_eq_or⟩
|
||||
|
||||
/--
|
||||
Returns a `LawfulOrderMax α` instance given that `max a b` returns either `a` or `b` and that
|
||||
it is larger than or equal to both of them. The `≤` relation needs to be transitive.
|
||||
|
||||
The produced instance entails `LawfulOrderSup α` and `MaxEqOr α`.
|
||||
-/
|
||||
public theorem LawfulOrderMax.of_le_max {α : Type u} [Max α] [LE α]
|
||||
[i : Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·)]
|
||||
(left_le_max : ∀ a b : α, a ≤ max a b) (right_le_max : ∀ a b : α, b ≤ max a b)
|
||||
(max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b := by exact MaxEqOr.max_eq_or) :
|
||||
LawfulOrderMax α := by
|
||||
apply LawfulOrderMax.of_max_le_iff
|
||||
· simp [autoParam]
|
||||
intro a b c
|
||||
constructor
|
||||
· intro h
|
||||
exact ⟨i.trans (left_le_max a b) h, i.trans (right_le_max a b) h⟩
|
||||
· intro h
|
||||
cases max_eq_or a b <;> simp [*]
|
||||
· exact 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`).
|
||||
-/
|
||||
@[inline]
|
||||
public def _root_.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
|
||||
502
src/Init/Data/Order/Lemmas.lean
Normal file
502
src/Init/Data/Order/Lemmas.lean
Normal file
@@ -0,0 +1,502 @@
|
||||
/-
|
||||
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 all 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 theorem le_of_lt {α : Type u} [LT α] [LE α] [LawfulOrderLT α] {a b : α} (h : a < b) :
|
||||
a ≤ b := by
|
||||
simp only [LawfulOrderLT.lt_iff] at h
|
||||
exact h.1
|
||||
|
||||
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_lt_of_le {α : 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 hab ⊢
|
||||
apply And.intro
|
||||
· exact le_trans hab.1 hbc
|
||||
· intro hca
|
||||
exact hab.2.elim (le_trans hbc hca)
|
||||
|
||||
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]
|
||||
|
||||
public theorem LawfulOrderLeftLeaningMin.of_eq {α : Type u} [LE α] [Min α] [DecidableLE α]
|
||||
(min_eq : ∀ a b : α, min a b = if a ≤ b then a else b) : LawfulOrderLeftLeaningMin α where
|
||||
min_eq_left a b := by simp +contextual [min_eq]
|
||||
min_eq_right a b := by simp +contextual [min_eq]
|
||||
|
||||
attribute [local instance] Min.leftLeaningOfLE
|
||||
public instance [LE α] [DecidableLE α] : LawfulOrderLeftLeaningMin α :=
|
||||
.of_eq (fun a b => by simp [min])
|
||||
|
||||
public instance {α : Type u} [LE α] [Min α] [LawfulOrderLeftLeaningMin α] :
|
||||
MinEqOr α where
|
||||
min_eq_or a b := by
|
||||
open scoped Classical in
|
||||
suffices min_eq : min a b = if a ≤ b then a else b by
|
||||
rw [min_eq]
|
||||
split <;> simp
|
||||
split <;> simp [*, LawfulOrderLeftLeaningMin.min_eq_left, LawfulOrderLeftLeaningMin.min_eq_right]
|
||||
|
||||
public instance {α : Type u} [LE α] [Min α] [IsLinearPreorder α] [LawfulOrderLeftLeaningMin α] :
|
||||
LawfulOrderMin α where
|
||||
toMinEqOr := inferInstance
|
||||
le_min_iff a b c := by
|
||||
open scoped Classical in
|
||||
suffices min_eq : min b c = if b ≤ c then b else c by
|
||||
rw [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))
|
||||
split <;> simp [*, LawfulOrderLeftLeaningMin.min_eq_left, LawfulOrderLeftLeaningMin.min_eq_right]
|
||||
|
||||
end Min
|
||||
end Std
|
||||
|
||||
namespace Classical.Order
|
||||
open Std
|
||||
|
||||
public noncomputable scoped instance instMin {α : Type u} [LE α] : Min α :=
|
||||
.leftLeaningOfLE α
|
||||
|
||||
end Classical.Order
|
||||
|
||||
namespace Std
|
||||
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
|
||||
|
||||
public theorem LawfulOrderLeftLeaningMax.of_eq {α : Type u} [LE α] [Max α] [DecidableLE α]
|
||||
(min_eq : ∀ a b : α, max a b = if b ≤ a then a else b) : LawfulOrderLeftLeaningMax α where
|
||||
max_eq_left a b := by simp +contextual [min_eq]
|
||||
max_eq_right a b := by simp +contextual [min_eq]
|
||||
|
||||
attribute [local instance] Max.leftLeaningOfLE
|
||||
public instance [LE α] [DecidableLE α] : LawfulOrderLeftLeaningMax α :=
|
||||
.of_eq (fun a b => by simp [max])
|
||||
|
||||
public instance {α : Type u} [LE α] [Max α] [LawfulOrderLeftLeaningMax α] :
|
||||
MaxEqOr α where
|
||||
max_eq_or a b := by
|
||||
open scoped Classical in
|
||||
suffices min_eq : max a b = if b ≤ a then a else b by
|
||||
rw [min_eq]
|
||||
split <;> simp
|
||||
split <;> simp [*, LawfulOrderLeftLeaningMax.max_eq_left, LawfulOrderLeftLeaningMax.max_eq_right]
|
||||
|
||||
public instance {α : Type u} [LE α] [Max α] [IsLinearPreorder α] [LawfulOrderLeftLeaningMax α] :
|
||||
LawfulOrderMax α where
|
||||
toMaxEqOr := inferInstance
|
||||
max_le_iff a b c := by
|
||||
open scoped Classical in
|
||||
suffices max_eq : max a b = if b ≤ a then a else b by
|
||||
rw [max_eq]
|
||||
split <;> rename_i hba
|
||||
· simp only [iff_self_and]
|
||||
exact fun hac => le_trans hba hac
|
||||
· simp only [iff_and_self]
|
||||
exact fun hbc => le_trans (by simpa [hba] using Std.le_total (a := b) (b := a)) hbc
|
||||
split <;> simp [*, LawfulOrderLeftLeaningMax.max_eq_left, LawfulOrderLeftLeaningMax.max_eq_right]
|
||||
|
||||
end Max
|
||||
end Std
|
||||
|
||||
namespace Classical.Order
|
||||
open Std
|
||||
|
||||
public noncomputable scoped instance instMax {α : Type u} [LE α] : Max α :=
|
||||
.leftLeaningOfLE α
|
||||
|
||||
end Classical.Order
|
||||
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
|
||||
|
||||
811
src/Init/Data/Order/PackageFactories.lean
Normal file
811
src/Init/Data/Order/PackageFactories.lean
Normal file
@@ -0,0 +1,811 @@
|
||||
/-
|
||||
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
|
||||
|
||||
/--
|
||||
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 Min.leftLeaningOfLE _
|
||||
max :
|
||||
let := le; let := decidableLE
|
||||
Max α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact Max.leftLeaningOfLE _
|
||||
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`."
|
||||
|
||||
/--
|
||||
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 := by
|
||||
letI := LinearPreorderPackage.ofLE α args.toLinearPreorderOfLEArgs
|
||||
letI := args.decidableLE; letI := args.min
|
||||
haveI : LawfulOrderLeftLeaningMin α := .of_eq args.min_eq
|
||||
infer_instance
|
||||
toLawfulOrderMax := by
|
||||
letI := LinearPreorderPackage.ofLE α args.toLinearPreorderOfLEArgs
|
||||
letI := args.decidableLE; letI := args.max
|
||||
haveI : LawfulOrderLeftLeaningMax α := .of_eq args.max_eq
|
||||
infer_instance
|
||||
|
||||
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 _
|
||||
lawfulOrderOrd :
|
||||
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 `lawfulOrderOrd`."
|
||||
decidableLE :
|
||||
let := ord; let := le; have := lawfulOrderOrd
|
||||
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 := lawfulOrderOrd; 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 := lawfulOrderOrd; 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 := lawfulOrderOrd; 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.lawfulOrderOrd
|
||||
{ toOrd := args.ord
|
||||
toLE := args.le
|
||||
toLT := args.lt
|
||||
toBEq := args.beq
|
||||
toLawfulOrderOrd := args.lawfulOrderOrd
|
||||
lt_iff a b := by
|
||||
cases h : compare a b
|
||||
all_goals simp [h, ← args.lawfulOrderOrd.isLE_compare a _, ← args.lawfulOrderOrd.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 := lawfulOrderOrd
|
||||
∀ 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 \
|
||||
manually provide the field `min_eq`."
|
||||
max_eq :
|
||||
let := ord; let := le; let := max; have := lawfulOrderOrd
|
||||
∀ 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 := by
|
||||
haveI : LawfulOrderLeftLeaningMin α := .of_eq (by simpa [isLE_compare] using args.min_eq)
|
||||
infer_instance
|
||||
toLawfulOrderMax := by
|
||||
haveI : LawfulOrderLeftLeaningMax α := .of_eq (by simpa [isGE_compare] using args.max_eq)
|
||||
infer_instance }
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -26,10 +26,9 @@ class RangeSize (shape : BoundShape) (α : Type u) where
|
||||
This typeclass ensures that a `RangeSize` instance returns the correct size for all ranges.
|
||||
-/
|
||||
class LawfulRangeSize (su : BoundShape) (α : Type u) [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [RangeSize su α]
|
||||
[LawfulUpwardEnumerable α] [HasFiniteRanges su α] where
|
||||
[SupportsUpperBound su α] [RangeSize su α] where
|
||||
/-- If the smallest value in the range is beyond the upper bound, the size is zero. -/
|
||||
size_eq_zero_of_not_satisfied (upperBound : Bound su α) (init : α)
|
||||
size_eq_zero_of_not_isSatisfied (upperBound : Bound su α) (init : α)
|
||||
(h : ¬ SupportsUpperBound.IsSatisfied upperBound init) :
|
||||
RangeSize.size upperBound init = 0
|
||||
/--
|
||||
@@ -43,11 +42,38 @@ class LawfulRangeSize (su : BoundShape) (α : Type u) [UpwardEnumerable α]
|
||||
/--
|
||||
If the smallest value in the range satisfies the upper bound and has a successor, the size is
|
||||
one larger than the size of the range starting at the successor. -/
|
||||
size_eq_succ_of_succ?_eq_some (upperBound : Bound su α) (init : α)
|
||||
size_eq_succ_of_succ?_eq_some (upperBound : Bound su α) (init a : α)
|
||||
(h : SupportsUpperBound.IsSatisfied upperBound init)
|
||||
(h' : UpwardEnumerable.succ? init = some a) :
|
||||
RangeSize.size upperBound init = RangeSize.size upperBound a + 1
|
||||
|
||||
theorem LawfulRangeSize.size_eq_zero_iff_not_isSatisfied {su : BoundShape} {α : Type u}
|
||||
[UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α] [LawfulRangeSize su α]
|
||||
{bound : Bound su α} {init : α} :
|
||||
RangeSize.size bound init = 0 ↔ ¬ SupportsUpperBound.IsSatisfied bound init := by
|
||||
match h : decide (SupportsUpperBound.IsSatisfied bound init) with
|
||||
| true =>
|
||||
simp only [decide_eq_true_eq] at h
|
||||
match hs : UpwardEnumerable.succ? init with
|
||||
| none => simp [h, LawfulRangeSize.size_eq_one_of_succ?_eq_none (h := h) (h' := hs)]
|
||||
| some b => simp [h, LawfulRangeSize.size_eq_succ_of_succ?_eq_some (h := h) (h' := hs)]
|
||||
| false =>
|
||||
simp only [decide_eq_false_iff_not] at h
|
||||
simp [h, LawfulRangeSize.size_eq_zero_of_not_isSatisfied]
|
||||
|
||||
theorem LawfulRangeSize.size_pos_iff_isSatisfied {su : BoundShape} {α : Type u}
|
||||
[UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α] [LawfulRangeSize su α]
|
||||
{bound : Bound su α} {init : α} :
|
||||
0 < RangeSize.size bound init ↔ SupportsUpperBound.IsSatisfied bound init := by
|
||||
have := size_eq_zero_iff_not_isSatisfied (bound := bound) (init := init)
|
||||
match h : decide (SupportsUpperBound.IsSatisfied bound init) with
|
||||
| true =>
|
||||
simp only [decide_eq_true_eq] at h
|
||||
simp_all [Nat.pos_iff_ne_zero]
|
||||
| false =>
|
||||
simp only [decide_eq_false_iff_not] at h
|
||||
simp_all
|
||||
|
||||
/--
|
||||
Checks whether the range contains any value.
|
||||
|
||||
@@ -60,6 +86,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 +115,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)
|
||||
178
src/Init/Data/Range/Polymorphic/Instances.lean
Normal file
178
src/Init/Data/Range/Polymorphic/Instances.lean
Normal file
@@ -0,0 +1,178 @@
|
||||
/-
|
||||
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.Range.Polymorphic.Basic
|
||||
import Init.Data.Nat.Lemmas
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
/-!
|
||||
This module provides instances that reduce the amount of code necessary to make a type compatible
|
||||
with the polymorphic ranges. For an example of the required work, take a look at
|
||||
`Init.Data.Range.Polymorphic.Nat`.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.PRange
|
||||
|
||||
instance [LE α] [LT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLE α] [LawfulOrderLT α] : LawfulUpwardEnumerableLT α where
|
||||
lt_iff a b := by
|
||||
simp only [LawfulOrderLT.lt_iff, LawfulUpwardEnumerableLE.le_iff]
|
||||
constructor
|
||||
· intro h
|
||||
obtain ⟨n, hn⟩ := h.1
|
||||
cases n
|
||||
· apply h.2.elim
|
||||
refine ⟨0, ?_⟩
|
||||
simpa [UpwardEnumerable.succMany?_zero] using hn.symm
|
||||
exact ⟨_, hn⟩
|
||||
· intro h
|
||||
constructor
|
||||
· match h with | ⟨_, hn⟩ => exact ⟨_, hn⟩
|
||||
· exact UpwardEnumerable.not_ge_of_lt h
|
||||
|
||||
instance [LE α] [DecidableLE α] [UpwardEnumerable α] [LawfulUpwardEnumerableLE α] :
|
||||
LawfulUpwardEnumerableLowerBound .closed α where
|
||||
isSatisfied_iff a l := by
|
||||
simp [SupportsLowerBound.IsSatisfied, BoundedUpwardEnumerable.init?,
|
||||
LawfulUpwardEnumerableLE.le_iff]
|
||||
|
||||
instance [LE α] [DecidableLE α] [UpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·)]:
|
||||
LawfulUpwardEnumerableUpperBound .closed α where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, ← LawfulUpwardEnumerableLE.le_iff] at hub hab ⊢
|
||||
exact Trans.trans hab hub
|
||||
|
||||
instance [LT α] [DecidableLT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLT α] :
|
||||
LawfulUpwardEnumerableLowerBound .open α where
|
||||
isSatisfied_iff a l := by
|
||||
simp only [SupportsLowerBound.IsSatisfied, BoundedUpwardEnumerable.init?,
|
||||
LawfulUpwardEnumerableLT.lt_iff]
|
||||
constructor
|
||||
· rintro ⟨n, hn⟩
|
||||
simp only [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
cases h : UpwardEnumerable.succ? l
|
||||
· simp [h] at hn
|
||||
· exact ⟨_, rfl, n, by simpa [h] using hn⟩
|
||||
· rintro ⟨init, hi, n, hn⟩
|
||||
exact ⟨n, by simpa [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, hi] using hn⟩
|
||||
|
||||
instance [LT α] [DecidableLT α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLT α] :
|
||||
LawfulUpwardEnumerableUpperBound .open α where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, LawfulUpwardEnumerableLT.lt_iff] at hub ⊢
|
||||
exact UpwardEnumerable.lt_of_le_of_lt hab hub
|
||||
|
||||
instance [UpwardEnumerable α] [Least? α] [LawfulUpwardEnumerableLeast? α] :
|
||||
LawfulUpwardEnumerableLowerBound .unbounded α where
|
||||
isSatisfied_iff a l := by
|
||||
simpa [SupportsLowerBound.IsSatisfied, BoundedUpwardEnumerable.init?] using
|
||||
LawfulUpwardEnumerableLeast?.eq_succMany?_least? a
|
||||
|
||||
instance [LE α] [Total (α := α) (· ≤ ·)] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLE α] :
|
||||
LinearlyUpwardEnumerable α where
|
||||
eq_of_succ?_eq a b hab := by
|
||||
cases Total.total (α := α) (r := (· ≤ ·)) a b <;> rename_i h <;>
|
||||
simp only [LawfulUpwardEnumerableLE.le_iff] at h
|
||||
· obtain ⟨n, hn⟩ := h
|
||||
cases n
|
||||
· simpa [UpwardEnumerable.succMany?_zero] using hn
|
||||
· exfalso
|
||||
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, hab,
|
||||
← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
exact UpwardEnumerable.lt_irrefl ⟨_, hn⟩
|
||||
· obtain ⟨n, hn⟩ := h
|
||||
cases n
|
||||
· simpa [UpwardEnumerable.succMany?_zero] using hn.symm
|
||||
· exfalso
|
||||
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, hab.symm,
|
||||
← LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
exact UpwardEnumerable.lt_irrefl ⟨_, hn⟩
|
||||
|
||||
instance [UpwardEnumerable α] : LawfulUpwardEnumerableUpperBound .unbounded α where
|
||||
isSatisfied_of_le _ _ _ _ _ := .intro
|
||||
|
||||
/--
|
||||
Creates a `RangeSize .open α` from a `RangeSize .closed α` instance. If the latter is lawful
|
||||
and certain other conditions hold, then the former is also lawful by
|
||||
`LawfulRangeSize.open_of_closed`.
|
||||
-/
|
||||
@[inline]
|
||||
abbrev RangeSize.openOfClosed [RangeSize .closed α] : RangeSize .open α where
|
||||
size bound a := RangeSize.size (shape := .closed) bound a - 1
|
||||
|
||||
attribute [local instance] RangeSize.openOfClosed in
|
||||
instance LawfulRangeSize.open_of_closed [UpwardEnumerable α] [LE α] [DecidableLE α]
|
||||
[LT α] [DecidableLT α] [LawfulOrderLT α] [IsPartialOrder α]
|
||||
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[RangeSize .closed α] [LawfulRangeSize .closed α] :
|
||||
LawfulRangeSize .open α where
|
||||
size_eq_zero_of_not_isSatisfied bound a h := by
|
||||
simp only [SupportsUpperBound.IsSatisfied] at h
|
||||
simp only [RangeSize.size]
|
||||
by_cases h' : a ≤ bound
|
||||
· match hs : UpwardEnumerable.succ? a with
|
||||
| none => rw [LawfulRangeSize.size_eq_one_of_succ?_eq_none (h := h') (h' := by omega)]
|
||||
| some b =>
|
||||
rw [LawfulRangeSize.size_eq_succ_of_succ?_eq_some (h := h') (h' := hs)]
|
||||
have : ¬ b ≤ bound := by
|
||||
intro hb
|
||||
have : a < b := by
|
||||
rw [LawfulUpwardEnumerableLT.lt_iff]
|
||||
exact ⟨0, by simpa [UpwardEnumerable.succMany?_one] using hs⟩
|
||||
exact h (lt_of_lt_of_le this hb)
|
||||
rw [LawfulRangeSize.size_eq_zero_of_not_isSatisfied (h := this)]
|
||||
· suffices RangeSize.size (shape := .closed) bound a = 0 by omega
|
||||
exact LawfulRangeSize.size_eq_zero_of_not_isSatisfied _ _ h'
|
||||
size_eq_one_of_succ?_eq_none bound a h h' := by
|
||||
exfalso
|
||||
simp only [SupportsUpperBound.IsSatisfied, LawfulUpwardEnumerableLT.lt_iff] at h
|
||||
obtain ⟨n, hn⟩ := h
|
||||
simp [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, h'] at hn
|
||||
size_eq_succ_of_succ?_eq_some bound a a' h h' := by
|
||||
simp only [SupportsUpperBound.IsSatisfied] at h
|
||||
simp only [RangeSize.size, Nat.pred_eq_succ_iff]
|
||||
rw [LawfulRangeSize.size_eq_succ_of_succ?_eq_some (h := le_of_lt h) (h' := h')]
|
||||
rw [← Nat.sub_add_comm]
|
||||
· omega
|
||||
· simp only [Nat.succ_le_iff, LawfulRangeSize.size_pos_iff_isSatisfied,
|
||||
SupportsUpperBound.IsSatisfied]
|
||||
rw [LawfulUpwardEnumerableLE.le_iff]
|
||||
rw [LawfulUpwardEnumerableLT.lt_iff] at h
|
||||
refine ⟨h.choose, ?_⟩
|
||||
simpa [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?, h'] using h.choose_spec
|
||||
|
||||
instance LawfulRangeSize.instHasFiniteRanges [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[RangeSize su α] [SupportsUpperBound su α] [LawfulRangeSize su α] : HasFiniteRanges su α where
|
||||
finite init bound := by
|
||||
refine ⟨RangeSize.size bound init, ?_⟩
|
||||
generalize hn : RangeSize.size bound init = n
|
||||
induction n generalizing init with
|
||||
| zero =>
|
||||
simp only [LawfulRangeSize.size_eq_zero_iff_not_isSatisfied] at hn
|
||||
simp [UpwardEnumerable.succMany?_zero, hn]
|
||||
| succ =>
|
||||
rename_i n ih
|
||||
rw [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?]
|
||||
match hs : UpwardEnumerable.succ? init with
|
||||
| none => simp
|
||||
| some a =>
|
||||
simp only [Option.bind_some]
|
||||
apply ih
|
||||
have : SupportsUpperBound.IsSatisfied bound init :=
|
||||
LawfulRangeSize.size_pos_iff_isSatisfied.mp (by omega)
|
||||
rw [LawfulRangeSize.size_eq_succ_of_succ?_eq_some (h := this) (h' := hs)] at hn
|
||||
omega
|
||||
|
||||
end Std.PRange
|
||||
@@ -376,7 +376,7 @@ instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
|
||||
cases hn : UpwardEnumerable.succ? next
|
||||
· have := LawfulRangeSize.size_eq_one_of_succ?_eq_none _ _ h hn
|
||||
simp [*] at this
|
||||
· have := LawfulRangeSize.size_eq_succ_of_succ?_eq_some _ _ h hn
|
||||
· have := LawfulRangeSize.size_eq_succ_of_succ?_eq_some _ _ _ h hn
|
||||
simp [*] at this
|
||||
· simp [h]
|
||||
· rename_i ih
|
||||
@@ -389,11 +389,11 @@ instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize su α]
|
||||
simp only [RangeIterator.step, Array.size_empty]
|
||||
simp_all [LawfulRangeSize.size_eq_one_of_succ?_eq_none _ _ h' hn]
|
||||
· rename_i next'
|
||||
have := LawfulRangeSize.size_eq_succ_of_succ?_eq_some _ _ h' hn
|
||||
have := LawfulRangeSize.size_eq_succ_of_succ?_eq_some _ _ _ h' hn
|
||||
simp only [this, Nat.add_right_cancel_iff] at h
|
||||
specialize ih (it := ⟨⟨some next', it.internalState.upperBound⟩⟩) next' rfl h
|
||||
rw [ih, Nat.add_comm]
|
||||
· have := LawfulRangeSize.size_eq_zero_of_not_satisfied _ _ h'
|
||||
· have := LawfulRangeSize.size_eq_zero_of_not_isSatisfied _ _ h'
|
||||
simp [*] at this
|
||||
|
||||
theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
|
||||
@@ -6,12 +6,18 @@ Authors: Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Range.Polymorphic.Basic
|
||||
import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Nat.Order
|
||||
public import Init.Data.Range.Polymorphic.Instances
|
||||
public import Init.Data.Order.Classes
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.PRange
|
||||
open Std
|
||||
|
||||
-- induce LawfulUpwardEnumerable from antisymmetry and transitivity?
|
||||
|
||||
instance : UpwardEnumerable Nat where
|
||||
succ? n := some (n + 1)
|
||||
@@ -20,6 +26,10 @@ instance : UpwardEnumerable Nat where
|
||||
instance : Least? Nat where
|
||||
least? := some 0
|
||||
|
||||
instance : LawfulUpwardEnumerableLeast? Nat where
|
||||
eq_succMany?_least? a := by
|
||||
simpa [Least?.least?] using ⟨a, by simp [UpwardEnumerable.succMany?]⟩
|
||||
|
||||
instance : LawfulUpwardEnumerableLE Nat where
|
||||
le_iff a b := by
|
||||
constructor
|
||||
@@ -30,101 +40,24 @@ instance : LawfulUpwardEnumerableLE Nat where
|
||||
rw [← hn]
|
||||
exact Nat.le_add_right _ _
|
||||
|
||||
instance : LawfulUpwardEnumerableLT Nat where
|
||||
lt_iff a b := by
|
||||
constructor
|
||||
· intro h
|
||||
refine ⟨b - a - 1, ?_⟩
|
||||
simp [UpwardEnumerable.succMany?]
|
||||
rw [Nat.sub_add_cancel, Nat.add_sub_cancel']
|
||||
· exact Nat.le_of_lt h
|
||||
· rwa [Nat.lt_iff_add_one_le, ← Nat.le_sub_iff_add_le'] at h
|
||||
exact Nat.le_trans (Nat.le_succ _) h
|
||||
· rintro ⟨n, hn⟩
|
||||
simp only [UpwardEnumerable.succMany?, Option.some.injEq] at hn
|
||||
rw [← hn]
|
||||
apply Nat.lt_add_of_pos_right
|
||||
apply Nat.zero_lt_succ
|
||||
|
||||
instance : LawfulUpwardEnumerable Nat where
|
||||
succMany?_zero := by simp [UpwardEnumerable.succMany?]
|
||||
succMany?_succ := by simp [UpwardEnumerable.succMany?, UpwardEnumerable.succ?, Nat.add_assoc]
|
||||
ne_of_lt a b hlt := by
|
||||
rw [← LawfulUpwardEnumerableLT.lt_iff] at hlt
|
||||
exact Nat.ne_of_lt hlt
|
||||
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed Nat where
|
||||
isSatisfied_iff a l := by
|
||||
simp [← LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
|
||||
SupportsLowerBound.IsSatisfied]
|
||||
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed Nat where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
rw [← LawfulUpwardEnumerableLE.le_iff] at hab
|
||||
exact Nat.le_trans hab hub
|
||||
|
||||
instance : LawfulUpwardEnumerableLowerBound .open Nat where
|
||||
isSatisfied_iff a l := by
|
||||
simp [← LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
|
||||
SupportsLowerBound.IsSatisfied, UpwardEnumerable.succ?, Nat.lt_iff_add_one_le]
|
||||
|
||||
instance : LawfulUpwardEnumerableUpperBound .open Nat where
|
||||
isSatisfied_of_le u a b hub hab := by
|
||||
rw [← LawfulUpwardEnumerableLE.le_iff] at hab
|
||||
exact Nat.lt_of_le_of_lt hab hub
|
||||
|
||||
instance : LawfulUpwardEnumerableLowerBound .unbounded Nat where
|
||||
isSatisfied_iff a l := by
|
||||
simp [← LawfulUpwardEnumerableLE.le_iff, BoundedUpwardEnumerable.init?,
|
||||
SupportsLowerBound.IsSatisfied, Least?.least?]
|
||||
|
||||
instance : LawfulUpwardEnumerableUpperBound .unbounded Nat where
|
||||
isSatisfied_of_le _ _ _ _ _ := .intro
|
||||
|
||||
instance : LinearlyUpwardEnumerable Nat where
|
||||
eq_of_succ?_eq a b := by simp [UpwardEnumerable.succ?]
|
||||
have hn := hlt.choose_spec
|
||||
simp only [UpwardEnumerable.succMany?, Option.some.injEq] at hn
|
||||
omega
|
||||
|
||||
instance : InfinitelyUpwardEnumerable Nat where
|
||||
isSome_succ? a := by simp [UpwardEnumerable.succ?]
|
||||
|
||||
private def rangeRev (k : Nat) :=
|
||||
match k with
|
||||
| 0 => []
|
||||
| k + 1 => k :: rangeRev k
|
||||
|
||||
private theorem mem_rangeRev {k l : Nat} (h : l < k) : l ∈ rangeRev k := by
|
||||
induction k
|
||||
case zero => cases h
|
||||
case succ k ih =>
|
||||
rw [rangeRev]
|
||||
by_cases hl : l = k
|
||||
· simp [hl]
|
||||
· apply List.mem_cons_of_mem
|
||||
exact ih (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ h) hl)
|
||||
|
||||
@[no_expose]
|
||||
instance : HasFiniteRanges .closed Nat where
|
||||
mem_of_satisfiesUpperBound upperBound := by
|
||||
refine ⟨rangeRev (upperBound + 1), fun a h => ?_⟩
|
||||
simp only [SupportsUpperBound.IsSatisfied] at h
|
||||
exact mem_rangeRev (Nat.lt_succ_of_le h)
|
||||
|
||||
@[no_expose]
|
||||
instance : HasFiniteRanges .open Nat where
|
||||
mem_of_satisfiesUpperBound upperBound := by
|
||||
refine ⟨rangeRev (upperBound + 1), fun a h => ?_⟩
|
||||
simp only [SupportsUpperBound.IsSatisfied] at h
|
||||
apply mem_rangeRev
|
||||
exact Nat.lt_succ_of_lt h
|
||||
|
||||
instance : RangeSize .closed Nat where
|
||||
size bound a := bound + 1 - a
|
||||
|
||||
instance : RangeSize .open Nat where
|
||||
size bound a := bound - a
|
||||
instance : RangeSize .open Nat := .openOfClosed
|
||||
|
||||
instance : LawfulRangeSize .closed Nat where
|
||||
size_eq_zero_of_not_satisfied upperBound init hu := by
|
||||
size_eq_zero_of_not_isSatisfied upperBound init hu := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, RangeSize.size] at hu ⊢
|
||||
omega
|
||||
size_eq_one_of_succ?_eq_none upperBound init hu h := by
|
||||
@@ -135,17 +68,10 @@ instance : LawfulRangeSize .closed Nat where
|
||||
Option.some.injEq] at hu h ⊢
|
||||
omega
|
||||
|
||||
instance : LawfulRangeSize .open Nat where
|
||||
size_eq_zero_of_not_satisfied upperBound init hu := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, RangeSize.size] at hu ⊢
|
||||
omega
|
||||
size_eq_one_of_succ?_eq_none upperBound init hu h := by
|
||||
simp only [UpwardEnumerable.succ?] at h
|
||||
cases h
|
||||
size_eq_succ_of_succ?_eq_some upperBound init hu h := by
|
||||
simp only [SupportsUpperBound.IsSatisfied, RangeSize.size, UpwardEnumerable.succ?,
|
||||
Option.some.injEq] at hu h ⊢
|
||||
omega
|
||||
/-!
|
||||
The following instances are used for the implementation of array slices a.k.a. `Subarray`.
|
||||
See also `Init.Data.Slice.Array`.
|
||||
-/
|
||||
|
||||
instance : ClosedOpenIntersection ⟨.open, .open⟩ Nat where
|
||||
intersection r s := PRange.mk (max (r.lower + 1) s.lower) (min r.upper s.upper)
|
||||
|
||||
@@ -175,9 +175,9 @@ instance {sl su α a} [SupportsLowerBound sl α] [SupportsUpperBound su α] (r :
|
||||
This typeclass ensures that ranges with the given shape of upper bounds are always finite.
|
||||
This is a prerequisite for many functions and instances, such as `PRange.toList` or `ForIn'`.
|
||||
-/
|
||||
class HasFiniteRanges (shape α) [SupportsUpperBound shape α] : Prop where
|
||||
mem_of_satisfiesUpperBound (u : Bound shape α) :
|
||||
∃ enumeration : List α, (a : α) → SupportsUpperBound.IsSatisfied u a → a ∈ enumeration
|
||||
class HasFiniteRanges (shape α) [UpwardEnumerable α] [SupportsUpperBound shape α] : Prop where
|
||||
finite (init : α) (u : Bound shape α) :
|
||||
∃ n, (UpwardEnumerable.succMany? n init).elim True (¬ SupportsUpperBound.IsSatisfied u ·)
|
||||
|
||||
/--
|
||||
This typeclass will usually be used together with `UpwardEnumerable α`. It provides the starting
|
||||
|
||||
@@ -232,36 +232,49 @@ private def List.length_filter_strict_mono {l : List α} {P Q : α → Bool} {a
|
||||
private def RangeIterator.instFinitenessRelation [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
[LawfulUpwardEnumerable α] [HasFiniteRanges su α] :
|
||||
FinitenessRelation (RangeIterator su α) Id where
|
||||
rel :=
|
||||
open Classical in
|
||||
InvImage WellFoundedRelation.rel
|
||||
(fun it => (HasFiniteRanges.mem_of_satisfiesUpperBound it.internalState.upperBound).choose
|
||||
|>.filter (∃ a, it.internalState.next = some a ∧ UpwardEnumerable.LE a ·)
|
||||
|>.length)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation {it it'} h := by
|
||||
simp_wf
|
||||
rw [Monadic.isPlausibleSuccessorOf_iff] at h
|
||||
obtain ⟨a, hn, hu, hn', hu'⟩ := h
|
||||
rw [hu']
|
||||
apply List.length_filter_strict_mono (a := a)
|
||||
· intro u h
|
||||
simp only [decide_eq_true_eq] at ⊢ h
|
||||
obtain ⟨a', ha', hle⟩ := h
|
||||
refine ⟨a, hn, UpwardEnumerable.le_trans ⟨1, ?_⟩ hle⟩
|
||||
rw [ha'] at hn'
|
||||
rw [UpwardEnumerable.succMany?_succ, LawfulUpwardEnumerable.succMany?_zero,
|
||||
Option.bind_some, hn']
|
||||
· exact (HasFiniteRanges.mem_of_satisfiesUpperBound _).choose_spec _ hu
|
||||
· intro h
|
||||
simp only [decide_eq_true_eq] at h
|
||||
obtain ⟨x, hx, h⟩ := h
|
||||
rw [hx] at hn'
|
||||
have hlt : UpwardEnumerable.LT a x :=
|
||||
⟨0, by simp [UpwardEnumerable.succMany?_succ, UpwardEnumerable.succMany?_zero, hn']⟩
|
||||
exact UpwardEnumerable.not_gt_of_le h hlt
|
||||
· simp only [decide_eq_true_eq]
|
||||
exact ⟨a, hn, UpwardEnumerable.le_refl _⟩
|
||||
rel it' it := it'.IsPlausibleSuccessorOf it
|
||||
wf := by
|
||||
constructor
|
||||
intro it
|
||||
have hnone : ∀ bound, Acc (fun it' it : IterM (α := RangeIterator su α) Id α => it'.IsPlausibleSuccessorOf it)
|
||||
⟨⟨none, bound⟩⟩ := by
|
||||
intro bound
|
||||
constructor
|
||||
intro it' ⟨step, hs₁, hs₂⟩
|
||||
simp only [IterM.IsPlausibleStep, Iterator.IsPlausibleStep, Monadic.step] at hs₂
|
||||
simp [hs₂, IterStep.successor] at hs₁
|
||||
simp only [IterM.IsPlausibleSuccessorOf, IterM.IsPlausibleStep, Iterator.IsPlausibleStep,
|
||||
Monadic.step, exists_eq_right] at hnone ⊢
|
||||
match it with
|
||||
| ⟨⟨none, _⟩⟩ => apply hnone
|
||||
| ⟨⟨some init, bound⟩⟩ =>
|
||||
obtain ⟨n, hn⟩ := HasFiniteRanges.finite init bound
|
||||
induction n generalizing init with
|
||||
| zero =>
|
||||
simp only [UpwardEnumerable.succMany?_zero, Option.elim_some] at hn
|
||||
constructor
|
||||
simp [hn, IterStep.successor]
|
||||
| succ n ih =>
|
||||
constructor
|
||||
rintro it'
|
||||
simp only [LawfulUpwardEnumerable.succMany?_succ_eq_succ?_bind_succMany?] at hn
|
||||
match hs : UpwardEnumerable.succ? init with
|
||||
| none =>
|
||||
simp only [hs]
|
||||
intro h
|
||||
split at h
|
||||
· cases h
|
||||
apply hnone
|
||||
· cases h
|
||||
| some a =>
|
||||
intro h
|
||||
simp only [hs] at h hn
|
||||
specialize ih _ hn
|
||||
split at h
|
||||
· cases h
|
||||
exact ih
|
||||
· cases h
|
||||
subrelation := id
|
||||
|
||||
@[no_expose]
|
||||
instance RangeIterator.instFinite {su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
@@ -441,7 +454,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
|
||||
|
||||
@@ -129,6 +129,10 @@ theorem UpwardEnumerable.le_refl {α : Type u} [UpwardEnumerable α] [LawfulUpwa
|
||||
(a : α) : UpwardEnumerable.LE a a :=
|
||||
⟨0, LawfulUpwardEnumerable.succMany?_zero a⟩
|
||||
|
||||
theorem UpwardEnumerable.lt_irrefl {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a : α} : ¬ UpwardEnumerable.LT a a :=
|
||||
fun h => LawfulUpwardEnumerable.ne_of_lt a a h rfl
|
||||
|
||||
theorem UpwardEnumerable.le_trans {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b c : α} (hab : UpwardEnumerable.LE a b) (hbc : UpwardEnumerable.LE b c) :
|
||||
UpwardEnumerable.LE a c := by
|
||||
@@ -145,6 +149,12 @@ theorem UpwardEnumerable.lt_of_lt_of_le {α : Type u} [UpwardEnumerable α] [Law
|
||||
refine ⟨hab.choose + hbc.choose, ?_⟩
|
||||
rw [Nat.add_right_comm, succMany?_add, hab.choose_spec, Option.bind_some, hbc.choose_spec]
|
||||
|
||||
theorem UpwardEnumerable.lt_of_le_of_lt {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b c : α} (hab : UpwardEnumerable.LE a b) (hbc : UpwardEnumerable.LT b c) :
|
||||
UpwardEnumerable.LT a c := by
|
||||
refine ⟨hab.choose + hbc.choose, ?_⟩
|
||||
rw [Nat.add_assoc, succMany?_add, hab.choose_spec, Option.bind_some, hbc.choose_spec]
|
||||
|
||||
theorem UpwardEnumerable.not_gt_of_le {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b : α} :
|
||||
UpwardEnumerable.LE a b → ¬ UpwardEnumerable.LT b a := by
|
||||
@@ -154,6 +164,11 @@ theorem UpwardEnumerable.not_gt_of_le {α : Type u} [UpwardEnumerable α] [Lawfu
|
||||
rw [Nat.add_assoc, UpwardEnumerable.succMany?_add, hle, Option.bind_some, hgt]
|
||||
exact LawfulUpwardEnumerable.ne_of_lt _ _ this rfl
|
||||
|
||||
theorem UpwardEnumerable.not_ge_of_lt {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b : α} :
|
||||
UpwardEnumerable.LT a b → ¬ UpwardEnumerable.LE b a :=
|
||||
flip not_gt_of_le
|
||||
|
||||
theorem UpwardEnumerable.not_gt_of_lt {α : Type u} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{a b : α} (h : UpwardEnumerable.LT a b) : ¬ UpwardEnumerable.LT b a :=
|
||||
not_gt_of_le (le_of_lt h)
|
||||
|
||||
@@ -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
|
||||
391
src/Init/Data/Rat/Lemmas.lean
Normal file
391
src/Init/Data/Rat/Lemmas.lean
Normal file
@@ -0,0 +1,391 @@
|
||||
/-
|
||||
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 add_zero (a : Rat) : a + 0 = a := by simp [add_def', mkRat_self]
|
||||
theorem zero_add (a : Rat) : 0 + a = a := by simp [add_def', mkRat_self]
|
||||
|
||||
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
|
||||
@@ -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
|
||||
|
||||
@@ -17,6 +17,7 @@ public import all Init.Data.Range.Polymorphic.Basic
|
||||
public import Init.Data.Range.Polymorphic.Nat
|
||||
public import Init.Data.Range.Polymorphic.Iterators
|
||||
public import Init.Data.Slice.Operations
|
||||
import Init.Omega
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -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 := {}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,11 +6,15 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Char.Order
|
||||
public import Init.Data.Char.Lemmas
|
||||
public import Init.Data.List.Lex
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
|
||||
namespace String
|
||||
|
||||
protected theorem data_eq_of_eq {a b : String} (h : a = b) : a.data = b.data :=
|
||||
@@ -34,4 +38,14 @@ protected theorem ne_of_lt {a b : String} (h : a < b) : a ≠ b := by
|
||||
have := String.lt_irrefl a
|
||||
intro h; subst h; contradiction
|
||||
|
||||
instance instIsLinearOrder : IsLinearOrder String := by
|
||||
apply IsLinearOrder.of_le
|
||||
case le_antisymm => constructor; apply String.le_antisymm
|
||||
case le_trans => constructor; apply String.le_trans
|
||||
case le_total => constructor; apply String.le_total
|
||||
|
||||
instance : LawfulOrderLT String where
|
||||
lt_iff a b := by
|
||||
simp [← String.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
end String
|
||||
|
||||
@@ -1,32 +1,11 @@
|
||||
/-
|
||||
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Johannes Hölzl
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Ext
|
||||
public import Init.Core
|
||||
|
||||
public section
|
||||
|
||||
namespace Subtype
|
||||
|
||||
universe u
|
||||
variable {α : Sort u} {p q : α → Prop}
|
||||
|
||||
@[ext]
|
||||
protected theorem ext : ∀ {a1 a2 : { x // p x }}, (a1 : α) = (a2 : α) → a1 = a2
|
||||
| ⟨_, _⟩, ⟨_, _⟩, rfl => rfl
|
||||
|
||||
@[simp]
|
||||
protected theorem «forall» {q : { a // p a } → Prop} : (∀ x, q x) ↔ ∀ a b, q ⟨a, b⟩ :=
|
||||
⟨fun h a b ↦ h ⟨a, b⟩, fun h ⟨a, b⟩ ↦ h a b⟩
|
||||
|
||||
@[simp]
|
||||
protected theorem «exists» {q : { a // p a } → Prop} :
|
||||
(Exists fun x => q x) ↔ Exists fun a => Exists fun b => q ⟨a, b⟩ :=
|
||||
⟨fun ⟨⟨a, b⟩, h⟩ ↦ ⟨a, b, h⟩, fun ⟨a, b, h⟩ ↦ ⟨⟨a, b⟩, h⟩⟩
|
||||
|
||||
end Subtype
|
||||
public import Init.Data.Subtype.Basic
|
||||
public import Init.Data.Subtype.Order
|
||||
public import Init.Data.Subtype.OrderExtra
|
||||
|
||||
32
src/Init/Data/Subtype/Basic.lean
Normal file
32
src/Init/Data/Subtype/Basic.lean
Normal file
@@ -0,0 +1,32 @@
|
||||
/-
|
||||
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Johannes Hölzl
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Ext
|
||||
public import Init.Core
|
||||
|
||||
public section
|
||||
|
||||
namespace Subtype
|
||||
|
||||
universe u
|
||||
variable {α : Sort u} {p q : α → Prop}
|
||||
|
||||
@[ext]
|
||||
protected theorem ext : ∀ {a1 a2 : { x // p x }}, (a1 : α) = (a2 : α) → a1 = a2
|
||||
| ⟨_, _⟩, ⟨_, _⟩, rfl => rfl
|
||||
|
||||
@[simp]
|
||||
protected theorem «forall» {q : { a // p a } → Prop} : (∀ x, q x) ↔ ∀ a b, q ⟨a, b⟩ :=
|
||||
⟨fun h a b ↦ h ⟨a, b⟩, fun h ⟨a, b⟩ ↦ h a b⟩
|
||||
|
||||
@[simp]
|
||||
protected theorem «exists» {q : { a // p a } → Prop} :
|
||||
(Exists fun x => q x) ↔ Exists fun a => Exists fun b => q ⟨a, b⟩ :=
|
||||
⟨fun ⟨⟨a, b⟩, h⟩ ↦ ⟨a, b, h⟩, fun ⟨a, b, h⟩ ↦ ⟨⟨a, b⟩, h⟩⟩
|
||||
|
||||
end Subtype
|
||||
92
src/Init/Data/Subtype/Order.lean
Normal file
92
src/Init/Data/Subtype/Order.lean
Normal file
@@ -0,0 +1,92 @@
|
||||
/-
|
||||
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.SimpLemmas
|
||||
public import Init.Data.Order.Classes
|
||||
public import Init.Data.Order.Lemmas
|
||||
import Init.Data.Order.Factories
|
||||
import Init.Data.Subtype.Basic
|
||||
|
||||
namespace Subtype
|
||||
open Std
|
||||
|
||||
public instance instLE {α : Type u} [LE α] {P : α → Prop} : LE (Subtype P) where
|
||||
le a b := a.val ≤ b.val
|
||||
|
||||
public instance instLT {α : Type u} [LT α] {P : α → Prop} : LT (Subtype P) where
|
||||
lt a b := a.val < b.val
|
||||
|
||||
public instance instLawfulOrderLT {α : Type u} [LT α] [LE α] [LawfulOrderLT α]
|
||||
{P : α → Prop} : LawfulOrderLT (Subtype P) where
|
||||
lt_iff a b := by simp [LT.lt, LE.le, LawfulOrderLT.lt_iff]
|
||||
|
||||
public instance instMin {α : Type u} [Min α] [MinEqOr α] {P : α → Prop} : Min (Subtype P) where
|
||||
min a b := ⟨Min.min a.val b.val, MinEqOr.elim a.property b.property⟩
|
||||
|
||||
public instance instMax {α : Type u} [Max α] [MaxEqOr α] {P : α → Prop} : Max (Subtype P) where
|
||||
max a b := ⟨max a.val b.val, MaxEqOr.elim a.property b.property⟩
|
||||
|
||||
public instance instReflLE {α : Type u} [LE α] [i : Refl (α := α) (· ≤ ·)] {P : α → Prop} :
|
||||
Refl (α := Subtype P) (· ≤ ·) where
|
||||
refl a := i.refl a.val
|
||||
|
||||
public instance instAntisymmLE {α : Type u} [LE α] [i : Antisymm (α := α) (· ≤ ·)] {P : α → Prop} :
|
||||
Antisymm (α := Subtype P) (· ≤ ·) where
|
||||
antisymm a b hab hba := private Subtype.ext <| i.antisymm a.val b.val hab hba
|
||||
|
||||
public instance instTotalLE {α : Type u} [LE α] [i : Total (α := α) (· ≤ ·)] {P : α → Prop} :
|
||||
Total (α := Subtype P) (· ≤ ·) where
|
||||
total a b := i.total a.val b.val
|
||||
|
||||
public instance instTransLE {α : Type u} [LE α] [i : Trans (α := α) (· ≤ ·) (· ≤ ·) (· ≤ ·)]
|
||||
{P : α → Prop} :
|
||||
Trans (α := Subtype P) (· ≤ ·) (· ≤ ·) (· ≤ ·) where
|
||||
trans := i.trans
|
||||
|
||||
public instance instMinEqOr {α : Type u} [Min α] [MinEqOr α] {P : α → Prop} :
|
||||
MinEqOr (Subtype P) where
|
||||
min_eq_or a b := by
|
||||
cases min_eq_or (a := a.val) (b := b.val) <;> rename_i h
|
||||
· exact Or.inl <| Subtype.ext h
|
||||
· exact Or.inr <| Subtype.ext h
|
||||
|
||||
public instance instLawfulOrderMin {α : Type u} [LE α] [Min α] [LawfulOrderMin α] {P : α → Prop} :
|
||||
LawfulOrderMin (Subtype P) where
|
||||
le_min_iff _ _ _ := by
|
||||
exact le_min_iff (α := α)
|
||||
|
||||
public instance instMaxEqOr {α : Type u} [Max α] [MaxEqOr α] {P : α → Prop} :
|
||||
MaxEqOr (Subtype P) where
|
||||
max_eq_or a b := by
|
||||
cases max_eq_or (a := a.val) (b := b.val) <;> rename_i h
|
||||
· exact Or.inl <| Subtype.ext h
|
||||
· exact Or.inr <| Subtype.ext h
|
||||
|
||||
public instance instLawfulOrderMax {α : Type u} [LE α] [Max α] [LawfulOrderMax α] {P : α → Prop} :
|
||||
LawfulOrderMax (Subtype P) where
|
||||
max_le_iff _ _ _ := by
|
||||
open Classical.Order in
|
||||
exact max_le_iff (α := α)
|
||||
|
||||
public instance instIsPreorder {α : Type u} [LE α] [IsPreorder α] {P : α → Prop} :
|
||||
IsPreorder (Subtype P) :=
|
||||
IsPreorder.of_le
|
||||
|
||||
public instance instIsLinearPreorder {α : Type u} [LE α] [IsLinearPreorder α] {P : α → Prop} :
|
||||
IsLinearPreorder (Subtype P) :=
|
||||
IsLinearPreorder.of_le
|
||||
|
||||
public instance instIsPartialOrder {α : Type u} [LE α] [IsPartialOrder α] {P : α → Prop} :
|
||||
IsPartialOrder (Subtype P) :=
|
||||
IsPartialOrder.of_le
|
||||
|
||||
public instance instIsLinearOrder {α : Type u} [LE α] [IsLinearOrder α] {P : α → Prop} :
|
||||
IsLinearOrder (Subtype P) :=
|
||||
IsLinearOrder.of_le
|
||||
|
||||
end Subtype
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user