mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-23 13:24:11 +00:00
Compare commits
388 Commits
fix_qsort
...
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 | ||
|
|
9257ef42ba | ||
|
|
63f899a407 | ||
|
|
690cf16aa5 | ||
|
|
aaf831cd93 | ||
|
|
472a0b4954 | ||
|
|
c04323a7d5 | ||
|
|
fac4905e89 | ||
|
|
65e55ac094 | ||
|
|
f23d24ec7c | ||
|
|
e332adf3d5 | ||
|
|
13f00ea8ed | ||
|
|
a14e542ecb | ||
|
|
6065f08528 | ||
|
|
d455b05619 | ||
|
|
d49b941ea9 | ||
|
|
478be16fc5 | ||
|
|
26c1ddf104 | ||
|
|
f759d5dbc1 | ||
|
|
ea09ffc8ce | ||
|
|
6d5ce9b87f | ||
|
|
24d4353ab2 | ||
|
|
822f9e0a80 | ||
|
|
09600f2ca4 | ||
|
|
42e472ff3f | ||
|
|
285d271505 | ||
|
|
dcba6dfa7e | ||
|
|
953a1eefbb | ||
|
|
d5331d4150 | ||
|
|
61ea403bfa | ||
|
|
d5e19f9b28 | ||
|
|
d8c7c9fdb5 | ||
|
|
ed1ca47199 | ||
|
|
885b8bcc60 | ||
|
|
31e05cd2bd | ||
|
|
7fb72a0081 | ||
|
|
f3e3ebba81 | ||
|
|
51b780cd9f | ||
|
|
25b0c5af34 | ||
|
|
6ab20e7f03 | ||
|
|
6846a5179b | ||
|
|
eb5399445a | ||
|
|
83c08880a6 | ||
|
|
172a02557e | ||
|
|
2d3501be61 | ||
|
|
d07ec9a19f | ||
|
|
ed860dfa23 | ||
|
|
09e8079ea3 | ||
|
|
b42a7780e2 | ||
|
|
4ee90bd82f | ||
|
|
12cd4ca742 | ||
|
|
713a46cd75 | ||
|
|
f236328bc3 | ||
|
|
6e06978961 | ||
|
|
8edcfbe776 | ||
|
|
1c60173b69 | ||
|
|
59579bfc3e | ||
|
|
7f22c0883b | ||
|
|
78b941019b | ||
|
|
ae728d84f0 | ||
|
|
3eab35ef22 | ||
|
|
c260435913 | ||
|
|
a5351b5c47 | ||
|
|
718d8acc76 | ||
|
|
e8c3c7b5eb | ||
|
|
8f575bf986 | ||
|
|
cf48c6004d | ||
|
|
d0dc5dfd3d | ||
|
|
af473b085a | ||
|
|
9e778f3a61 | ||
|
|
52855ce1c1 | ||
|
|
22000a703a | ||
|
|
f6f54955fe | ||
|
|
1459d17bfd | ||
|
|
77646f7149 | ||
|
|
1e83f62d31 | ||
|
|
df9ca20339 | ||
|
|
b60f97cc19 | ||
|
|
ab946fdf2c | ||
|
|
d9956a9d05 | ||
|
|
2713c846f1 | ||
|
|
3056848819 | ||
|
|
08c3f3c236 | ||
|
|
a01eda79e8 | ||
|
|
f6e19f1f93 | ||
|
|
bad582ed45 | ||
|
|
18e1cdb7bb | ||
|
|
aa3e50ee76 | ||
|
|
eb6cede35d | ||
|
|
f8cdb03352 | ||
|
|
08ff19d973 | ||
|
|
2ea6b5068c | ||
|
|
4cd917aa65 | ||
|
|
417031fc17 | ||
|
|
416a8372cd | ||
|
|
6eaf406305 | ||
|
|
009bcf1a27 | ||
|
|
335c5ca5c8 | ||
|
|
5b18ea1545 | ||
|
|
d817fb0ef3 | ||
|
|
37bf79b0e2 | ||
|
|
7cdd65d5fb | ||
|
|
1901e2ecfd | ||
|
|
76051ab1fe | ||
|
|
062ac89c34 | ||
|
|
0c686e09db | ||
|
|
4575799f8e | ||
|
|
271c8ab9cb | ||
|
|
ee1854a607 | ||
|
|
9b186297c7 | ||
|
|
c8ef2fae1a | ||
|
|
0aba471758 | ||
|
|
467d905709 | ||
|
|
62f14514da | ||
|
|
5ece18cede | ||
|
|
33eac4497b | ||
|
|
fa449aab14 | ||
|
|
5f20213876 | ||
|
|
28f64e57ae | ||
|
|
5e7c4557f8 | ||
|
|
c517f8fc9e | ||
|
|
3a3c816a27 | ||
|
|
b8e801ecad | ||
|
|
7f17970551 | ||
|
|
0f1fb8bafe | ||
|
|
7931e19572 | ||
|
|
285f0e329f | ||
|
|
9006af4a96 | ||
|
|
5f17e3bf15 | ||
|
|
366b4b2810 | ||
|
|
e3517f1c86 | ||
|
|
fa1da03d50 | ||
|
|
5c2ae7b414 | ||
|
|
6ae31ea2d6 | ||
|
|
edade0cea8 | ||
|
|
969136b0d6 | ||
|
|
1726a61e88 | ||
|
|
9399b2ee36 | ||
|
|
e53f944c83 | ||
|
|
dbfeb9e2da | ||
|
|
ab87a6f797 | ||
|
|
475bd65c90 | ||
|
|
0fe7cc8794 | ||
|
|
2cdb547af0 | ||
|
|
fd25fd70f1 | ||
|
|
8a58037df9 | ||
|
|
e38f0c6990 | ||
|
|
557592aa97 | ||
|
|
e5600afddc | ||
|
|
87dae299b8 | ||
|
|
7034310a3b | ||
|
|
d7e7bd16a6 | ||
|
|
bdd1918cd8 | ||
|
|
30ba416fe3 | ||
|
|
95e753c6b4 | ||
|
|
5d54b0b13f | ||
|
|
d2153064ec | ||
|
|
4d295d85b6 | ||
|
|
8ce0e045a8 | ||
|
|
2be6c75c2b | ||
|
|
af84f76f31 | ||
|
|
dd45a21257 | ||
|
|
8177de88cd | ||
|
|
99dac6aec0 | ||
|
|
30afb0dbec | ||
|
|
309a3c364f | ||
|
|
fcbd1037fd | ||
|
|
aa769e7677 | ||
|
|
737105fd78 | ||
|
|
1285a3c9a7 | ||
|
|
17a477393c | ||
|
|
437b4a4f9b | ||
|
|
eddc3b421e | ||
|
|
98569c7cf0 | ||
|
|
7f39e56a79 | ||
|
|
bc5526cacb | ||
|
|
6300329057 | ||
|
|
15f0cd9527 | ||
|
|
b437232ab6 | ||
|
|
3ff069911e | ||
|
|
e74a97d5a8 | ||
|
|
7f4d673d33 | ||
|
|
81fe5243d3 | ||
|
|
3f19182afc | ||
|
|
ff1d3138bf | ||
|
|
0071bea64e | ||
|
|
5244ac3bb5 | ||
|
|
26be599e65 | ||
|
|
671057eecf | ||
|
|
0ab69a32cb | ||
|
|
6995f280b4 | ||
|
|
73422d52fd |
42
.github/workflows/build-template.yml
vendored
42
.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
|
||||
@@ -199,13 +215,13 @@ jobs:
|
||||
path: pack/*
|
||||
- name: Lean stats
|
||||
run: |
|
||||
build/stage1/bin/lean --stats src/Lean.lean
|
||||
build/stage1/bin/lean --stats src/Lean.lean -Dexperimental.module=true
|
||||
if: ${{ !matrix.cross }}
|
||||
- name: Test
|
||||
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,17 +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 }}
|
||||
|
||||
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
|
||||
|
||||
@@ -48,3 +48,7 @@
|
||||
/src/Std/Do @sgraf812
|
||||
/src/Std/Tactic/Do @sgraf812
|
||||
/src/Lean/Elab/Tactic/Do @sgraf812
|
||||
/src/Init/Data/Range/Polymorphic @datokrat
|
||||
/src/Init/Data/Slice @datokrat
|
||||
/src/Init/Data/Iterators @datokrat
|
||||
/src/Std/Data/Iterators @datokrat
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -44,12 +44,12 @@ Useful CMake Configuration Settings
|
||||
Pass these along with the `cmake --preset release` command.
|
||||
There are also two alternative presets that combine some of these options you can use instead of `release`: `debug` and `sandebug` (sanitize + debug).
|
||||
|
||||
* `-D CMAKE_BUILD_TYPE=`\
|
||||
* `-DCMAKE_BUILD_TYPE=`\
|
||||
Select the build type. Valid values are `RELEASE` (default), `DEBUG`,
|
||||
`RELWITHDEBINFO`, and `MINSIZEREL`.
|
||||
|
||||
* `-D CMAKE_C_COMPILER=`\
|
||||
`-D CMAKE_CXX_COMPILER=`\
|
||||
* `-DCMAKE_C_COMPILER=`\
|
||||
`-DCMAKE_CXX_COMPILER=`\
|
||||
Select the C/C++ compilers to use. Official Lean releases currently use Clang;
|
||||
see also `.github/workflows/ci.yml` for the CI config.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Install Packages on OS X 14.5
|
||||
# Install Packages on OS X
|
||||
|
||||
We assume that you are using [homebrew][homebrew] as a package manager.
|
||||
|
||||
@@ -6,23 +6,23 @@ We assume that you are using [homebrew][homebrew] as a package manager.
|
||||
|
||||
## Compilers
|
||||
|
||||
You need a C++11-compatible compiler to build Lean. As of November
|
||||
2014, you have three options:
|
||||
You need a C++14-compatible compiler to build Lean. As of July
|
||||
2025, you have three options:
|
||||
|
||||
- clang++-3.5 (shipped with OSX, Apple LLVM version 6.0)
|
||||
- gcc-4.9.1 (homebrew)
|
||||
- clang++-3.5 (homebrew)
|
||||
- clang++ shipped with OSX (at time of writing v17.0.0)
|
||||
- clang++ via homebrew (at time of writing, v20.1.8)
|
||||
- gcc via homebrew (at time of writing, v15.1.0)
|
||||
|
||||
We recommend to use Apple's clang++ because it is pre-shipped with OS
|
||||
X and requires no further installation.
|
||||
|
||||
To install gcc-4.9.1 via homebrew, please execute:
|
||||
To install gcc via homebrew, please execute:
|
||||
```bash
|
||||
brew install gcc
|
||||
```
|
||||
To install clang++-3.5 via homebrew, please execute:
|
||||
To install clang via homebrew, please execute:
|
||||
```bash
|
||||
brew install llvm
|
||||
brew install llvm lld
|
||||
```
|
||||
To use compilers other than the default one (Apple's clang++), you
|
||||
need to use `-DCMAKE_CXX_COMPILER` option to specify the compiler
|
||||
|
||||
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,16 +1,96 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
set -euxo pipefail
|
||||
|
||||
cmake --preset release -DUSE_LAKE=ON 1>&2
|
||||
cmake --preset release 1>&2
|
||||
|
||||
# We benchmark against stage 2 to test new optimizations.
|
||||
timeout -s KILL 1h time make -C build/release -j$(nproc) stage2 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
|
||||
export PATH=$PWD/build/release/stage2/bin:$PATH
|
||||
|
||||
# The extra opts used to be passed to the Makefile during benchmarking only but with Lake it is
|
||||
# easier to configure them statically.
|
||||
cmake -B build/release/stage2 -S src -DLEAN_EXTRA_LAKEFILE_TOML='weakLeanArgs=["-Dprofiler=true", "-Dprofiler.threshold=9999999", "--stats"]' 1>&2
|
||||
cmake -B build/release/stage3 -S src -DLEAN_EXTRA_LAKEFILE_TOML='weakLeanArgs=["-Dprofiler=true", "-Dprofiler.threshold=9999999", "--stats"]' 1>&2
|
||||
|
||||
(
|
||||
cd tests/bench
|
||||
timeout -s KILL 1h time temci exec --config speedcenter.yaml --in speedcenter.exec.velcom.yaml 1>&2
|
||||
temci report run_output.yaml --reporter codespeed2
|
||||
)
|
||||
|
||||
if [ -d .git ]; then
|
||||
DIR="$(git rev-parse @)"
|
||||
BASE_URL="https://speed.lean-lang.org/lean4-out/$DIR"
|
||||
{
|
||||
cat <<'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Lakeprof Report</title>
|
||||
</head>
|
||||
<h1>Lakeprof Report</h1>
|
||||
<button type="button" id="btn_fetch">View build trace in Perfetto</button>
|
||||
<script type="text/javascript">
|
||||
const ORIGIN = 'https://ui.perfetto.dev';
|
||||
|
||||
const btnFetch = document.getElementById('btn_fetch');
|
||||
|
||||
async function fetchAndOpen(traceUrl) {
|
||||
const resp = await fetch(traceUrl);
|
||||
// Error checking is left as an exercise to the reader.
|
||||
const blob = await resp.blob();
|
||||
const arrayBuffer = await blob.arrayBuffer();
|
||||
openTrace(arrayBuffer, traceUrl);
|
||||
}
|
||||
|
||||
function openTrace(arrayBuffer, traceUrl) {
|
||||
const win = window.open(ORIGIN);
|
||||
if (!win) {
|
||||
btnFetch.style.background = '#f3ca63';
|
||||
btnFetch.onclick = () => openTrace(arrayBuffer);
|
||||
btnFetch.innerText = 'Popups blocked, click here to open the trace file';
|
||||
return;
|
||||
}
|
||||
|
||||
const timer = setInterval(() => win.postMessage('PING', ORIGIN), 50);
|
||||
|
||||
const onMessageHandler = (evt) => {
|
||||
if (evt.data !== 'PONG') return;
|
||||
|
||||
// We got a PONG, the UI is ready.
|
||||
window.clearInterval(timer);
|
||||
window.removeEventListener('message', onMessageHandler);
|
||||
|
||||
const reopenUrl = new URL(location.href);
|
||||
reopenUrl.hash = `#reopen=${traceUrl}`;
|
||||
win.postMessage({
|
||||
perfetto: {
|
||||
buffer: arrayBuffer,
|
||||
title: 'Lake Build Trace',
|
||||
url: reopenUrl.toString(),
|
||||
}}, ORIGIN);
|
||||
};
|
||||
|
||||
window.addEventListener('message', onMessageHandler);
|
||||
}
|
||||
|
||||
// This is triggered when following the link from the Perfetto UI's sidebar.
|
||||
if (location.hash.startsWith('#reopen=')) {
|
||||
const traceUrl = location.hash.substr(8);
|
||||
fetchAndOpen(traceUrl);
|
||||
}
|
||||
EOF
|
||||
cat <<EOF
|
||||
btnFetch.onclick = () => fetchAndOpen("$BASE_URL/lakeprof.trace_event");
|
||||
</script>
|
||||
EOF
|
||||
echo "<pre><code>"
|
||||
(cd src; lakeprof report -prc)
|
||||
echo "</code></pre>"
|
||||
echo "</body></html>"
|
||||
} | tee index.html
|
||||
|
||||
curl -T index.html $BASE_URL/index.html
|
||||
curl -T src/lakeprof.log $BASE_URL/lakeprof.log
|
||||
curl -T src/lakeprof.trace_event $BASE_URL/lakeprof.trace_event
|
||||
fi
|
||||
|
||||
@@ -28,13 +28,6 @@ repositories:
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: doc-gen4
|
||||
url: https://github.com/leanprover/doc-gen4
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: [lean4-cli]
|
||||
|
||||
- name: verso
|
||||
url: https://github.com/leanprover/verso
|
||||
toolchain-tag: true
|
||||
@@ -42,6 +35,28 @@ repositories:
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: plausible
|
||||
url: https://github.com/leanprover-community/plausible
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: import-graph
|
||||
url: https://github.com/leanprover-community/import-graph
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies:
|
||||
- lean4-cli
|
||||
|
||||
- name: doc-gen4
|
||||
url: https://github.com/leanprover/doc-gen4
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: [lean4-cli]
|
||||
|
||||
- name: reference-manual
|
||||
url: https://github.com/leanprover/reference-manual
|
||||
toolchain-tag: true
|
||||
@@ -65,22 +80,6 @@ repositories:
|
||||
dependencies:
|
||||
- batteries
|
||||
|
||||
- name: import-graph
|
||||
url: https://github.com/leanprover-community/import-graph
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies:
|
||||
- lean4-cli
|
||||
- batteries
|
||||
|
||||
- name: plausible
|
||||
url: https://github.com/leanprover-community/plausible
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: mathlib4
|
||||
url: https://github.com/leanprover-community/mathlib4
|
||||
toolchain-tag: true
|
||||
|
||||
@@ -10,7 +10,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 23)
|
||||
set(LEAN_VERSION_MINOR 24)
|
||||
set(LEAN_VERSION_PATCH 0)
|
||||
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
|
||||
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
|
||||
@@ -81,7 +81,7 @@ option(USE_MIMALLOC "use mimalloc" ON)
|
||||
|
||||
# development-specific options
|
||||
option(CHECK_OLEAN_VERSION "Only load .olean files compiled with the current version of Lean" OFF)
|
||||
option(USE_LAKE "Use Lake instead of lean.mk for building core libs from language server" OFF)
|
||||
option(USE_LAKE "Use Lake instead of lean.mk for building core libs from language server" ON)
|
||||
|
||||
set(LEAN_EXTRA_MAKE_OPTS "" CACHE STRING "extra options to lean --make")
|
||||
set(LEANC_CC ${CMAKE_C_COMPILER} CACHE STRING "C compiler to use in `leanc`")
|
||||
@@ -684,12 +684,17 @@ if (LLVM AND ${STAGE} GREATER 0)
|
||||
set(EXTRA_LEANMAKE_OPTS "LLVM=1")
|
||||
endif()
|
||||
|
||||
set(STDLIBS Init Std Lean Leanc)
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
list(APPEND STDLIBS Lake)
|
||||
endif()
|
||||
|
||||
add_custom_target(make_stdlib ALL
|
||||
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
||||
# The actual rule is in a separate makefile because we want to prefix it with '+' to use the Make job server
|
||||
# for a parallelized nested build, but CMake doesn't let us do that.
|
||||
# We use `lean` from the previous stage, but `leanc`, headers, etc. from the current stage
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Init Std Lean Leanc
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make ${STDLIBS}
|
||||
VERBATIM)
|
||||
|
||||
# if we have LLVM enabled, then build `lean.h.bc` which has the LLVM bitcode
|
||||
@@ -733,14 +738,9 @@ else()
|
||||
endif()
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
add_custom_target(lake_lib
|
||||
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
||||
DEPENDS leanshared
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Lake
|
||||
VERBATIM)
|
||||
add_custom_target(lake_shared
|
||||
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
||||
DEPENDS lake_lib
|
||||
DEPENDS leanshared
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make libLake_shared
|
||||
VERBATIM)
|
||||
add_custom_target(lake ALL
|
||||
|
||||
@@ -9,7 +9,7 @@ prelude
|
||||
public import Init.Core
|
||||
public import Init.BinderNameHint
|
||||
|
||||
public section
|
||||
@[expose] public section
|
||||
|
||||
universe u v w
|
||||
|
||||
|
||||
@@ -187,6 +187,9 @@ match [a, b] with
|
||||
simplifies to `a`. -/
|
||||
syntax (name := simpMatch) "simp_match" : conv
|
||||
|
||||
/-- Removes one or more hypotheses from the local context. -/
|
||||
syntax (name := clear) "clear" (ppSpace colGt term:max)+ : conv
|
||||
|
||||
/-- Executes the given tactic block without converting `conv` goal into a regular goal. -/
|
||||
syntax (name := nestedTacticCore) "tactic'" " => " tacticSeq : conv
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -1536,38 +1559,13 @@ end Setoid
|
||||
/-! # Propositional extensionality -/
|
||||
|
||||
/--
|
||||
The axiom of **propositional extensionality**. It asserts that if propositions
|
||||
`a` and `b` are logically equivalent (i.e. we can prove `a` from `b` and vice versa),
|
||||
then `a` and `b` are *equal*, meaning that we can replace `a` with `b` in all
|
||||
contexts.
|
||||
The [axiom](lean-manual://section/axioms) of **propositional extensionality**. It asserts that if
|
||||
propositions `a` and `b` are logically equivalent (that is, if `a` can be proved from `b` and vice
|
||||
versa), then `a` and `b` are *equal*, meaning `a` can be replaced with `b` in all contexts.
|
||||
|
||||
For simple expressions like `a ∧ c ∨ d → e` we can prove that because all the logical
|
||||
connectives respect logical equivalence, we can replace `a` with `b` in this expression
|
||||
without using `propext`. However, for higher order expressions like `P a` where
|
||||
`P : Prop → Prop` is unknown, or indeed for `a = b` itself, we cannot replace `a` with `b`
|
||||
without an axiom which says exactly this.
|
||||
|
||||
This is a relatively uncontroversial axiom, which is intuitionistically valid.
|
||||
It does however block computation when using `#reduce` to reduce proofs directly
|
||||
(which is not recommended), meaning that canonicity,
|
||||
the property that all closed terms of type `Nat` normalize to numerals,
|
||||
fails to hold when this (or any) axiom is used:
|
||||
```
|
||||
set_option pp.proofs true
|
||||
|
||||
def foo : Nat := by
|
||||
have : (True → True) ↔ True := ⟨λ _ => trivial, λ _ _ => trivial⟩
|
||||
have := propext this ▸ (2 : Nat)
|
||||
exact this
|
||||
|
||||
#reduce foo
|
||||
-- propext { mp := fun x x => True.intro, mpr := fun x => True.intro } ▸ 2
|
||||
|
||||
#eval foo -- 2
|
||||
```
|
||||
`#eval` can evaluate it to a numeral because the compiler erases casts and
|
||||
does not evaluate proofs, so `propext`, whose return type is a proposition,
|
||||
can never block it.
|
||||
The standard logical connectives provably respect propositional extensionality. However, an axiom is
|
||||
needed for higher order expressions like `P a` where `P : Prop → Prop` is unknown, as well as for
|
||||
equality. Propositional extensionality is intuitionistically valid.
|
||||
-/
|
||||
axiom propext {a b : Prop} : (a ↔ b) → a = b
|
||||
|
||||
@@ -1598,6 +1596,7 @@ gen_injective_theorems% MProd
|
||||
gen_injective_theorems% NonScalar
|
||||
gen_injective_theorems% Option
|
||||
gen_injective_theorems% PLift
|
||||
gen_injective_theorems% PULift
|
||||
gen_injective_theorems% PNonScalar
|
||||
gen_injective_theorems% PProd
|
||||
gen_injective_theorems% Prod
|
||||
@@ -2523,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
|
||||
@@ -2542,3 +2546,7 @@ class Irrefl (r : α → α → Prop) : Prop where
|
||||
irrefl : ∀ a, ¬r a a
|
||||
|
||||
end Std
|
||||
|
||||
/-- Deprecated alias for `XorOp`. -/
|
||||
@[deprecated XorOp (since := "2025-07-30")]
|
||||
abbrev Xor := XorOp
|
||||
|
||||
@@ -49,5 +49,7 @@ public import Init.Data.Vector
|
||||
public import Init.Data.Iterators
|
||||
public import Init.Data.Range.Polymorphic
|
||||
public import Init.Data.Slice
|
||||
public import Init.Data.Order
|
||||
public import Init.Data.Rat
|
||||
|
||||
public section
|
||||
|
||||
@@ -163,7 +163,7 @@ representation of arrays. While this is not provable, `Array.usize` always retur
|
||||
the array since the implementation only supports arrays of size less than `USize.size`.
|
||||
-/
|
||||
@[extern "lean_array_size", simp]
|
||||
def usize (a : @& Array α) : USize := a.size.toUSize
|
||||
def usize (xs : @& Array α) : USize := xs.size.toUSize
|
||||
|
||||
/--
|
||||
Low-level indexing operator which is as fast as a C array read.
|
||||
@@ -171,8 +171,8 @@ Low-level indexing operator which is as fast as a C array read.
|
||||
This avoids overhead due to unboxing a `Nat` used as an index.
|
||||
-/
|
||||
@[extern "lean_array_uget", simp, expose]
|
||||
def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
|
||||
a[i.toNat]
|
||||
def uget (xs : @& Array α) (i : USize) (h : i.toNat < xs.size) : α :=
|
||||
xs[i.toNat]
|
||||
|
||||
/--
|
||||
Low-level modification operator which is as fast as a C array write. The modification is performed
|
||||
@@ -1165,7 +1165,7 @@ Examples:
|
||||
def zipIdx (xs : Array α) (start := 0) : Array (α × Nat) :=
|
||||
xs.mapIdx fun i a => (a, start + i)
|
||||
|
||||
@[deprecated zipIdx (since := "2025-01-21")] abbrev zipWithIndex := @zipIdx
|
||||
|
||||
|
||||
/--
|
||||
Returns the first element of the array for which the predicate `p` returns `true`, or `none` if no
|
||||
@@ -1285,7 +1285,7 @@ def findFinIdx? {α : Type u} (p : α → Bool) (as : Array α) : Option (Fin as
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
loop 0
|
||||
|
||||
theorem findIdx?_loop_eq_map_findFinIdx?_loop_val {xs : Array α} {p : α → Bool} {j} :
|
||||
private theorem findIdx?_loop_eq_map_findFinIdx?_loop_val {xs : Array α} {p : α → Bool} {j} :
|
||||
findIdx?.loop p xs j = (findFinIdx?.loop p xs j).map (·.val) := by
|
||||
unfold findIdx?.loop
|
||||
unfold findFinIdx?.loop
|
||||
@@ -1322,8 +1322,7 @@ def idxOfAux [BEq α] (xs : Array α) (v : α) (i : Nat) : Option (Fin xs.size)
|
||||
else none
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
@[deprecated idxOfAux (since := "2025-01-29")]
|
||||
abbrev indexOfAux := @idxOfAux
|
||||
|
||||
|
||||
/--
|
||||
Returns the index of the first element equal to `a`, or the size of the array if no element is equal
|
||||
@@ -1338,8 +1337,7 @@ Examples:
|
||||
def finIdxOf? [BEq α] (xs : Array α) (v : α) : Option (Fin xs.size) :=
|
||||
idxOfAux xs v 0
|
||||
|
||||
@[deprecated "`Array.indexOf?` has been deprecated, use `idxOf?` or `finIdxOf?` instead." (since := "2025-01-29")]
|
||||
abbrev indexOf? := @finIdxOf?
|
||||
|
||||
|
||||
/--
|
||||
Returns the index of the first element equal to `a`, or the size of the array if no element is equal
|
||||
@@ -1956,16 +1954,16 @@ def isPrefixOf [BEq α] (as bs : Array α) : Bool :=
|
||||
false
|
||||
|
||||
@[semireducible, specialize] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
def zipWithAux (as : Array α) (bs : Array β) (f : α → β → γ) (i : Nat) (cs : Array γ) : Array γ :=
|
||||
def zipWithMAux {m : Type v → Type w} [Monad m] (as : Array α) (bs : Array β) (f : α → β → m γ) (i : Nat) (cs : Array γ) : m (Array γ) := do
|
||||
if h : i < as.size then
|
||||
let a := as[i]
|
||||
if h : i < bs.size then
|
||||
let b := bs[i]
|
||||
zipWithAux as bs f (i+1) <| cs.push <| f a b
|
||||
zipWithMAux as bs f (i+1) <| cs.push (← f a b)
|
||||
else
|
||||
cs
|
||||
return cs
|
||||
else
|
||||
cs
|
||||
return cs
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
/--
|
||||
@@ -1979,7 +1977,7 @@ Examples:
|
||||
* `#[x₁, x₂, x₃].zipWith f #[y₁, y₂, y₃, y₄] = #[f x₁ y₁, f x₂ y₂, f x₃ y₃]`
|
||||
-/
|
||||
@[inline] def zipWith (f : α → β → γ) (as : Array α) (bs : Array β) : Array γ :=
|
||||
zipWithAux as bs f 0 #[]
|
||||
Id.run (zipWithMAux as bs (pure <| f · ·) 0 #[])
|
||||
|
||||
/--
|
||||
Combines two arrays into an array of pairs in which the first and second components are the
|
||||
@@ -2016,6 +2014,13 @@ where go (as : Array α) (bs : Array β) (i : Nat) (cs : Array γ) :=
|
||||
termination_by max as.size bs.size - i
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
/--
|
||||
Applies a monadic function to the corresponding elements of two arrays, left-to-right, stopping at
|
||||
the end of the shorter array. `zipWithM f as bs` is equivalent to `mapM id (zipWith f as bs)`.
|
||||
-/
|
||||
@[inline] def zipWithM {m : Type v → Type w} [Monad m] (f : α → β → m γ) (as : Array α) (bs : Array β) : m (Array γ) :=
|
||||
zipWithMAux as bs f 0 #[]
|
||||
|
||||
/--
|
||||
Separates an array of pairs into two arrays that contain the respective first and second components.
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ the index is in bounds. This is because the tactic itself needs to look up value
|
||||
arrays.
|
||||
-/
|
||||
@[deprecated "Use indexing notation `as[i]` instead" (since := "2025-02-17")]
|
||||
def get {α : Type u} (a : @& Array α) (i : @& Nat) (h : LT.lt i a.size) : α :=
|
||||
a.toList.get ⟨i, h⟩
|
||||
def get {α : Type u} (xs : @& Array α) (i : @& Nat) (h : LT.lt i xs.size) : α :=
|
||||
xs.toList.get ⟨i, h⟩
|
||||
|
||||
/--
|
||||
Use the indexing notation `a[i]!` instead.
|
||||
@@ -43,8 +43,8 @@ Use the indexing notation `a[i]!` instead.
|
||||
Access an element from an array, or panic if the index is out of bounds.
|
||||
-/
|
||||
@[deprecated "Use indexing notation `as[i]!` instead" (since := "2025-02-17"), expose]
|
||||
def get! {α : Type u} [Inhabited α] (a : @& Array α) (i : @& Nat) : α :=
|
||||
Array.getD a i default
|
||||
def get! {α : Type u} [Inhabited α] (xs : @& Array α) (i : @& Nat) : α :=
|
||||
Array.getD xs i default
|
||||
|
||||
theorem foldlM_toList.aux [Monad m]
|
||||
{f : β → α → m β} {xs : Array α} {i j} (H : xs.size ≤ i + j) {b} :
|
||||
@@ -123,15 +123,9 @@ abbrev pop_toList := @Array.toList_pop
|
||||
@[simp, grind =] theorem append_empty {xs : Array α} : xs ++ #[] = xs := by
|
||||
apply ext'; simp only [toList_append, List.append_nil]
|
||||
|
||||
@[deprecated append_empty (since := "2025-01-13")]
|
||||
abbrev append_nil := @append_empty
|
||||
|
||||
@[simp, grind =] theorem empty_append {xs : Array α} : #[] ++ xs = xs := by
|
||||
apply ext'; simp only [toList_append, List.nil_append]
|
||||
|
||||
@[deprecated empty_append (since := "2025-01-13")]
|
||||
abbrev nil_append := @empty_append
|
||||
|
||||
@[simp, grind _=_] theorem append_assoc {xs ys zs : Array α} : xs ++ ys ++ zs = xs ++ (ys ++ zs) := by
|
||||
apply ext'; simp only [toList_append, List.append_assoc]
|
||||
|
||||
@@ -142,7 +136,6 @@ abbrev nil_append := @empty_append
|
||||
rw [← appendList_eq_append]; unfold Array.appendList
|
||||
induction l generalizing xs <;> simp [*]
|
||||
|
||||
@[deprecated toList_appendList (since := "2024-12-11")]
|
||||
abbrev appendList_toList := @toList_appendList
|
||||
|
||||
|
||||
end Array
|
||||
|
||||
@@ -8,19 +8,20 @@ module
|
||||
prelude
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.List.Range
|
||||
public import all Init.Data.List.Control
|
||||
public import Init.Data.List.Nat.TakeDrop
|
||||
public import Init.Data.List.Nat.Modify
|
||||
public import Init.Data.List.Nat.Basic
|
||||
public import Init.Data.List.Monadic
|
||||
public import Init.Data.List.OfFn
|
||||
public import all Init.Data.Array.Bootstrap
|
||||
public import Init.Data.Array.Mem
|
||||
public import Init.Data.Array.DecidableEq
|
||||
public import Init.Data.Array.Lex.Basic
|
||||
public import Init.Data.Range.Lemmas
|
||||
public import Init.TacticsExtra
|
||||
public import Init.Data.List.ToArray
|
||||
import all Init.Data.List.Control
|
||||
import all Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Bootstrap
|
||||
|
||||
public section
|
||||
|
||||
@@ -311,7 +312,7 @@ theorem eq_push_pop_back!_of_size_ne_zero [Inhabited α] {xs : Array α} (h : xs
|
||||
xs = xs.pop.push xs.back! := by
|
||||
apply ext
|
||||
· simp [Nat.sub_add_cancel (Nat.zero_lt_of_ne_zero h)]
|
||||
· intros i h h'
|
||||
· intro i h h'
|
||||
if hlt : i < xs.pop.size then
|
||||
rw [getElem_push_lt (h:=hlt), getElem_pop]
|
||||
else
|
||||
@@ -837,15 +838,10 @@ theorem mem_of_contains_eq_true [BEq α] [LawfulBEq α] {a : α} {as : Array α}
|
||||
cases as
|
||||
simp
|
||||
|
||||
@[deprecated mem_of_contains_eq_true (since := "2024-12-12")]
|
||||
abbrev mem_of_elem_eq_true := @mem_of_contains_eq_true
|
||||
|
||||
theorem contains_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : Array α} (h : a ∈ as) : as.contains a = true := by
|
||||
theorem contains_eq_true_of_mem [BEq α] [ReflBEq α] {a : α} {as : Array α} (h : a ∈ as) :
|
||||
as.contains a = true := by
|
||||
cases as
|
||||
simpa using h
|
||||
|
||||
@[deprecated contains_eq_true_of_mem (since := "2024-12-12")]
|
||||
abbrev elem_eq_true_of_mem := @contains_eq_true_of_mem
|
||||
simpa using List.elem_eq_true_of_mem (Array.mem_toList_iff.mpr h)
|
||||
|
||||
@[simp] theorem elem_eq_contains [BEq α] {a : α} {xs : Array α} :
|
||||
elem a xs = xs.contains a := by
|
||||
@@ -904,15 +900,9 @@ theorem all_push {xs : Array α} {a : α} {p : α → Bool} :
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[deprecated getElem_set_self (since := "2024-12-11")]
|
||||
abbrev getElem_set_eq := @getElem_set_self
|
||||
|
||||
@[simp] theorem getElem?_set_self {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} :
|
||||
(xs.set i v)[i]? = some v := by simp [h]
|
||||
|
||||
@[deprecated getElem?_set_self (since := "2024-12-11")]
|
||||
abbrev getElem?_set_eq := @getElem?_set_self
|
||||
|
||||
@[simp] theorem getElem_set_ne {xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat}
|
||||
(pj : j < xs.size) (h : i ≠ j) :
|
||||
(xs.set i v)[j]'(by simp [*]) = xs[j] := by
|
||||
@@ -1003,9 +993,6 @@ grind_pattern mem_or_eq_of_mem_set => a ∈ xs.set i b
|
||||
theorem setIfInBounds_def (xs : Array α) (i : Nat) (a : α) :
|
||||
xs.setIfInBounds i a = if h : i < xs.size then xs.set i a else xs := rfl
|
||||
|
||||
@[deprecated set!_eq_setIfInBounds (since := "2024-12-12")]
|
||||
abbrev set!_is_setIfInBounds := @set!_eq_setIfInBounds
|
||||
|
||||
@[simp, grind] theorem size_setIfInBounds {xs : Array α} {i : Nat} {a : α} :
|
||||
(xs.setIfInBounds i a).size = xs.size := by
|
||||
if h : i < xs.size then
|
||||
@@ -1027,9 +1014,6 @@ abbrev set!_is_setIfInBounds := @set!_eq_setIfInBounds
|
||||
simp at h
|
||||
simp only [setIfInBounds, h, ↓reduceDIte, getElem_set_self]
|
||||
|
||||
@[deprecated getElem_setIfInBounds_self (since := "2024-12-11")]
|
||||
abbrev getElem_setIfInBounds_eq := @getElem_setIfInBounds_self
|
||||
|
||||
@[simp] theorem getElem_setIfInBounds_ne {xs : Array α} {i : Nat} {a : α} {j : Nat}
|
||||
(hj : j < xs.size) (h : i ≠ j) :
|
||||
(xs.setIfInBounds i a)[j]'(by simpa using hj) = xs[j] := by
|
||||
@@ -1049,9 +1033,6 @@ theorem getElem?_setIfInBounds_self_of_lt {xs : Array α} {i : Nat} {a : α} (h
|
||||
(xs.setIfInBounds i a)[i]? = some a := by
|
||||
simp [h]
|
||||
|
||||
@[deprecated getElem?_setIfInBounds_self (since := "2024-12-11")]
|
||||
abbrev getElem?_setIfInBounds_eq := @getElem?_setIfInBounds_self
|
||||
|
||||
@[simp] theorem getElem?_setIfInBounds_ne {xs : Array α} {i j : Nat} (h : i ≠ j) {a : α} :
|
||||
(xs.setIfInBounds i a)[j]? = xs[j]? := by
|
||||
simp [getElem?_setIfInBounds, h]
|
||||
@@ -1377,23 +1358,6 @@ theorem mapM_eq_mapM_toList [Monad m] [LawfulMonad m] {f : α → m β} {xs : Ar
|
||||
toList <$> xs.mapM f = xs.toList.mapM f := by
|
||||
simp [mapM_eq_mapM_toList]
|
||||
|
||||
@[deprecated "Use `mapM_eq_foldlM` instead" (since := "2025-01-08")]
|
||||
theorem mapM_map_eq_foldl {as : Array α} {f : α → β} {i : Nat} :
|
||||
mapM.map (m := Id) (pure <| f ·) as i b = pure (as.foldl (start := i) (fun acc a => acc.push (f a)) b) := by
|
||||
unfold mapM.map
|
||||
split <;> rename_i h
|
||||
· ext : 1
|
||||
dsimp [foldl, foldlM]
|
||||
rw [mapM_map_eq_foldl, dif_pos (by omega), foldlM.loop, dif_pos h]
|
||||
-- Calling `split` here gives a bad goal.
|
||||
have : size as - i = Nat.succ (size as - i - 1) := by omega
|
||||
rw [this]
|
||||
simp [foldl, foldlM, Nat.sub_add_eq]
|
||||
· dsimp [foldl, foldlM]
|
||||
rw [dif_pos (by omega), foldlM.loop, dif_neg h]
|
||||
rfl
|
||||
termination_by as.size - i
|
||||
|
||||
/--
|
||||
Use this as `induction ass using array₂_induction` on a hypothesis of the form `ass : Array (Array α)`.
|
||||
The hypothesis `ass` will be replaced with a hypothesis `ass : List (List α)`,
|
||||
@@ -1676,12 +1640,12 @@ theorem filterMap_eq_map' {f : α → β} (w : stop = as.size) :
|
||||
filterMap (fun x => some (f x)) as 0 stop = map f as :=
|
||||
filterMap_eq_map w
|
||||
|
||||
@[simp] theorem filterMap_some_fun : filterMap (some : α → Option α) = id := by
|
||||
theorem filterMap_some_fun : filterMap (some : α → Option α) = id := by
|
||||
funext xs
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[grind] theorem filterMap_some {xs : Array α} : filterMap some xs = xs := by
|
||||
@[simp, grind] theorem filterMap_some {xs : Array α} : filterMap some xs = xs := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@@ -2930,14 +2894,14 @@ theorem getElem_extract_loop_ge_aux {xs ys : Array α} {size start : Nat} (hge :
|
||||
exact Nat.sub_lt_left_of_lt_add hge h
|
||||
|
||||
theorem getElem_extract_loop_ge {xs ys : Array α} {size start : Nat} (hge : i ≥ ys.size)
|
||||
(h : i < (extract.loop xs size start ys).size)
|
||||
(h' := getElem_extract_loop_ge_aux hge h) :
|
||||
(extract.loop xs size start ys)[i] = xs[start + i - ys.size] := by
|
||||
(h : i < (extract.loop xs size start ys).size) :
|
||||
(extract.loop xs size start ys)[i] = xs[start + i - ys.size]'(getElem_extract_loop_ge_aux hge h) := by
|
||||
induction size using Nat.recAux generalizing start ys with
|
||||
| zero =>
|
||||
rw [size_extract_loop, Nat.zero_min, Nat.add_zero] at h
|
||||
omega
|
||||
| succ size ih =>
|
||||
have h' : start + i - ys.size < xs.size := getElem_extract_loop_ge_aux hge h
|
||||
have : start < xs.size := by
|
||||
apply Nat.lt_of_le_of_lt (Nat.le_add_right start (i - ys.size))
|
||||
rwa [← Nat.add_sub_assoc hge]
|
||||
@@ -2991,7 +2955,7 @@ theorem getElem?_extract {xs : Array α} {start stop : Nat} :
|
||||
apply List.ext_getElem
|
||||
· simp only [length_toList, size_extract, List.length_take, List.length_drop]
|
||||
omega
|
||||
· intros n h₁ h₂
|
||||
· intro n h₁ h₂
|
||||
simp
|
||||
|
||||
@[simp] theorem extract_size {xs : Array α} : xs.extract 0 xs.size = xs := by
|
||||
@@ -2999,9 +2963,6 @@ theorem getElem?_extract {xs : Array α} {start stop : Nat} :
|
||||
· rw [size_extract, Nat.min_self, Nat.sub_zero]
|
||||
· intros; rw [getElem_extract]; congr; rw [Nat.zero_add]
|
||||
|
||||
@[deprecated extract_size (since := "2025-01-19")]
|
||||
abbrev extract_all := @extract_size
|
||||
|
||||
theorem extract_empty_of_stop_le_start {xs : Array α} {start stop : Nat} (h : stop ≤ start) :
|
||||
xs.extract start stop = #[] := by
|
||||
simp only [extract, Nat.sub_eq, emptyWithCapacity_eq]
|
||||
@@ -3036,14 +2997,14 @@ theorem take_size {xs : Array α} : xs.take xs.size = xs := by
|
||||
|
||||
/-! ### shrink -/
|
||||
|
||||
@[simp] theorem size_shrink_loop {xs : Array α} {n : Nat} : (shrink.loop n xs).size = xs.size - n := by
|
||||
@[simp] private theorem size_shrink_loop {xs : Array α} {n : Nat} : (shrink.loop n xs).size = xs.size - n := by
|
||||
induction n generalizing xs with
|
||||
| zero => simp [shrink.loop]
|
||||
| succ n ih =>
|
||||
simp [shrink.loop, ih]
|
||||
omega
|
||||
|
||||
@[simp] theorem getElem_shrink_loop {xs : Array α} {n i : Nat} (h : i < (shrink.loop n xs).size) :
|
||||
@[simp] private theorem getElem_shrink_loop {xs : Array α} {n i : Nat} (h : i < (shrink.loop n xs).size) :
|
||||
(shrink.loop n xs)[i] = xs[i]'(by simp at h; omega) := by
|
||||
induction n generalizing xs i with
|
||||
| zero => simp [shrink.loop]
|
||||
@@ -3312,11 +3273,11 @@ theorem foldl_induction
|
||||
let rec go {i j b} (h₁ : j ≤ as.size) (h₂ : as.size ≤ i + j) (H : motive j b) :
|
||||
(motive as.size) (foldlM.loop (m := Id) f as as.size (Nat.le_refl _) i j b) := by
|
||||
unfold foldlM.loop; split
|
||||
· next hj =>
|
||||
next hj =>
|
||||
split
|
||||
· cases Nat.not_le_of_gt (by simp [hj]) h₂
|
||||
· exact go hj (by rwa [Nat.succ_add] at h₂) (hf ⟨j, hj⟩ b H)
|
||||
· next hj => exact Nat.le_antisymm h₁ (Nat.ge_of_not_lt hj) ▸ H
|
||||
next hj => exact Nat.le_antisymm h₁ (Nat.ge_of_not_lt hj) ▸ H
|
||||
simpa [foldl, foldlM] using go (Nat.zero_le _) (Nat.le_refl _) h0
|
||||
|
||||
theorem foldr_induction
|
||||
@@ -3326,13 +3287,13 @@ theorem foldr_induction
|
||||
let rec go {i b} (hi : i ≤ as.size) (H : motive i b) :
|
||||
(motive 0) (foldrM.fold (m := Id) f as 0 i hi b) := by
|
||||
unfold foldrM.fold; simp; split
|
||||
· next hi => exact (hi ▸ H)
|
||||
· next hi =>
|
||||
next hi => exact (hi ▸ H)
|
||||
next hi =>
|
||||
split; {simp at hi}
|
||||
· next i hi' =>
|
||||
next i hi' =>
|
||||
exact go _ (hf ⟨i, hi'⟩ b H)
|
||||
simp [foldr, foldrM]; split; {exact go _ h0}
|
||||
· next h => exact (Nat.eq_zero_of_not_pos h ▸ h0)
|
||||
next h => exact (Nat.eq_zero_of_not_pos h ▸ h0)
|
||||
|
||||
@[congr]
|
||||
theorem foldl_congr {as bs : Array α} (h₀ : as = bs) {f g : β → α → β} (h₁ : f = g)
|
||||
@@ -4319,7 +4280,7 @@ Examples:
|
||||
|
||||
/-! ### Preliminaries about `ofFn` -/
|
||||
|
||||
@[simp] theorem size_ofFn_go {n} {f : Fin n → α} {i acc h} :
|
||||
@[simp] private theorem size_ofFn_go {n} {f : Fin n → α} {i acc h} :
|
||||
(ofFn.go f acc i h).size = acc.size + i := by
|
||||
induction i generalizing acc with
|
||||
| zero => simp [ofFn.go]
|
||||
@@ -4329,7 +4290,7 @@ Examples:
|
||||
@[simp] theorem size_ofFn {n : Nat} {f : Fin n → α} : (ofFn f).size = n := by simp [ofFn]
|
||||
|
||||
-- Recall `ofFn.go f acc i h = acc ++ #[f (n - i), ..., f(n - 1)]`
|
||||
theorem getElem_ofFn_go {f : Fin n → α} {acc i k} (h : i ≤ n) (w₁ : k < acc.size + i) :
|
||||
private theorem getElem_ofFn_go {f : Fin n → α} {acc i k} (h : i ≤ n) (w₁ : k < acc.size + i) :
|
||||
(ofFn.go f acc i h)[k]'(by simpa using w₁) =
|
||||
if w₂ : k < acc.size then acc[k] else f ⟨n - i + k - acc.size, by omega⟩ := by
|
||||
induction i generalizing acc k with
|
||||
@@ -4413,10 +4374,17 @@ theorem getElem?_range {n : Nat} {i : Nat} : (Array.range n)[i]? = if i < n then
|
||||
|
||||
-- Without further algebraic hypotheses, there's no useful `sum_push` lemma.
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_eq_sum_toList [Add α] [Zero α] {as : Array α} : as.toList.sum = as.sum := by
|
||||
cases as
|
||||
simp [Array.sum, List.sum]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_append_nat {as₁ as₂ : Array Nat} : (as₁ ++ as₂).sum = as₁.sum + as₂.sum := by
|
||||
cases as₁
|
||||
cases as₂
|
||||
simp [List.sum_append_nat]
|
||||
|
||||
theorem foldl_toList_eq_flatMap {l : List α} {acc : Array β}
|
||||
{F : Array β → α → Array β} {G : α → List β}
|
||||
(H : ∀ acc a, (F acc a).toList = acc.toList ++ G a) :
|
||||
@@ -4727,27 +4695,10 @@ end List
|
||||
/-! ### Deprecations -/
|
||||
namespace Array
|
||||
|
||||
@[deprecated size_toArray (since := "2024-12-11")]
|
||||
theorem size_mk (as : List α) : (Array.mk as).size = as.length := by simp
|
||||
|
||||
@[deprecated getElem?_eq_getElem (since := "2024-12-11")]
|
||||
theorem getElem?_lt
|
||||
(xs : Array α) {i : Nat} (h : i < xs.size) : xs[i]? = some xs[i] := dif_pos h
|
||||
|
||||
@[deprecated getElem?_eq_none (since := "2024-12-11")]
|
||||
theorem getElem?_ge
|
||||
(xs : Array α) {i : Nat} (h : i ≥ xs.size) : xs[i]? = none := dif_neg (Nat.not_lt_of_le h)
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "`get?` is deprecated" (since := "2025-02-12"), simp]
|
||||
theorem get?_eq_getElem? (xs : Array α) (i : Nat) : xs.get? i = xs[i]? := rfl
|
||||
|
||||
@[deprecated getElem?_eq_none (since := "2024-12-11")]
|
||||
theorem getElem?_len_le (xs : Array α) {i : Nat} (h : xs.size ≤ i) : xs[i]? = none := by
|
||||
simp [h]
|
||||
|
||||
@[deprecated getD_getElem? (since := "2024-12-11")] abbrev getD_get? := @getD_getElem?
|
||||
|
||||
@[deprecated getD_eq_getD_getElem? (since := "2025-02-12")] abbrev getD_eq_get? := @getD_eq_getD_getElem?
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@@ -4772,64 +4723,9 @@ theorem get?_eq_get?_toList (xs : Array α) (i : Nat) : xs.get? i = xs.toList.ge
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated get!_eq_getD_getElem? (since := "2025-02-12")] abbrev get!_eq_get? := @get!_eq_getD_getElem?
|
||||
|
||||
@[deprecated getElem_set_self (since := "2025-01-17")]
|
||||
theorem get_set_eq (xs : Array α) (i : Nat) (v : α) (h : i < xs.size) :
|
||||
(xs.set i v h)[i]'(by simp [h]) = v := by
|
||||
simp only [set, ← getElem_toList, List.getElem_set_self]
|
||||
|
||||
@[deprecated Array.getElem_toList (since := "2024-12-08")]
|
||||
theorem getElem_eq_getElem_toList {xs : Array α} (h : i < xs.size) : xs[i] = xs.toList[i] := rfl
|
||||
|
||||
@[deprecated Array.getElem?_toList (since := "2024-12-08")]
|
||||
theorem getElem?_eq_getElem?_toList (xs : Array α) (i : Nat) : xs[i]? = xs.toList[i]? := by
|
||||
rw [getElem?_def]
|
||||
split <;> simp_all
|
||||
|
||||
@[deprecated LawfulGetElem.getElem?_def (since := "2024-12-08")]
|
||||
theorem getElem?_eq {xs : Array α} {i : Nat} :
|
||||
xs[i]? = if h : i < xs.size then some xs[i] else none := by
|
||||
rw [getElem?_def]
|
||||
|
||||
/-! ### map -/
|
||||
|
||||
@[deprecated "Use `toList_map` or `List.map_toArray` to characterize `Array.map`." (since := "2025-01-06")]
|
||||
theorem map_induction (xs : Array α) (f : α → β) (motive : Nat → Prop) (h0 : motive 0)
|
||||
(p : Fin xs.size → β → Prop) (hs : ∀ i, motive i.1 → p i (f xs[i]) ∧ motive (i+1)) :
|
||||
motive xs.size ∧
|
||||
∃ eq : (xs.map f).size = xs.size, ∀ i h, p ⟨i, h⟩ ((xs.map f)[i]) := by
|
||||
have t := foldl_induction (as := xs) (β := Array β)
|
||||
(motive := fun i xs => motive i ∧ xs.size = i ∧ ∀ i h2, p i xs[i.1])
|
||||
(init := #[]) (f := fun acc a => acc.push (f a)) ?_ ?_
|
||||
obtain ⟨m, eq, w⟩ := t
|
||||
· refine ⟨m, by simp, ?_⟩
|
||||
intro i h
|
||||
simp only [eq] at w
|
||||
specialize w ⟨i, h⟩ h
|
||||
simpa using w
|
||||
· exact ⟨h0, rfl, nofun⟩
|
||||
· intro i bs ⟨m, ⟨eq, w⟩⟩
|
||||
refine ⟨?_, ?_, ?_⟩
|
||||
· exact (hs _ m).2
|
||||
· simp_all
|
||||
· intro j h
|
||||
simp at h ⊢
|
||||
by_cases h' : j < size bs
|
||||
· rw [getElem_push]
|
||||
simp_all
|
||||
· rw [getElem_push, dif_neg h']
|
||||
simp only [show j = i by omega]
|
||||
exact (hs _ m).1
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `toList_map` or `List.map_toArray` to characterize `Array.map`." (since := "2025-01-06")]
|
||||
theorem map_spec (xs : Array α) (f : α → β) (p : Fin xs.size → β → Prop)
|
||||
(hs : ∀ i, p i (f xs[i])) :
|
||||
∃ eq : (xs.map f).size = xs.size, ∀ i h, p ⟨i, h⟩ ((xs.map f)[i]) := by
|
||||
simpa using map_induction xs f (fun _ => True) trivial p (by simp_all)
|
||||
|
||||
/-! ### set -/
|
||||
|
||||
@[deprecated getElem?_set_eq (since := "2025-02-27")] abbrev get?_set_eq := @getElem?_set_self
|
||||
@[deprecated getElem?_set_self (since := "2025-02-27")] abbrev get?_set_eq := @getElem?_set_self
|
||||
@[deprecated getElem?_set_ne (since := "2025-02-27")] abbrev get?_set_ne := @getElem?_set_ne
|
||||
@[deprecated getElem?_set (since := "2025-02-27")] abbrev get?_set := @getElem?_set
|
||||
@[deprecated get_set (since := "2025-02-27")] abbrev get_set := @getElem_set
|
||||
|
||||
@@ -12,9 +12,12 @@ public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.List.Lex
|
||||
import Init.Data.Range.Polymorphic.Lemmas
|
||||
import Init.Data.Range.Polymorphic.NatLemmas
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
@@ -28,8 +31,8 @@ namespace Array
|
||||
@[simp] theorem lt_toList [LT α] {xs ys : Array α} : xs.toList < ys.toList ↔ xs < ys := Iff.rfl
|
||||
@[simp] theorem le_toList [LT α] {xs ys : Array α} : xs.toList ≤ ys.toList ↔ xs ≤ ys := Iff.rfl
|
||||
|
||||
grind_pattern _root_.List.lt_toArray => l₁.toArray < l₂.toArray
|
||||
grind_pattern _root_.List.le_toArray => l₁.toArray ≤ l₂.toArray
|
||||
grind_pattern _root_.List.lt_toArray => l₁.toArray < l₂.toArray
|
||||
grind_pattern _root_.List.le_toArray => l₁.toArray ≤ l₂.toArray
|
||||
grind_pattern lt_toList => xs.toList < ys.toList
|
||||
grind_pattern le_toList => xs.toList ≤ ys.toList
|
||||
|
||||
@@ -100,6 +103,14 @@ theorem singleton_lex_singleton [BEq α] {lt : α → α → Bool} : #[a].lex #[
|
||||
xs.toList.lex ys.toList lt = xs.lex ys lt := by
|
||||
cases xs <;> cases ys <;> simp
|
||||
|
||||
instance [LT α] [LE α] [LawfulOrderLT α] [IsLinearOrder α] : IsLinearOrder (Array α) := by
|
||||
apply IsLinearOrder.of_le
|
||||
· constructor
|
||||
intro _ _ hab hba
|
||||
simpa using Std.le_antisymm (α := List α) hab hba
|
||||
· constructor; exact Std.le_trans (α := List α)
|
||||
· constructor; exact fun _ _ => Std.le_total (α := List α)
|
||||
|
||||
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α → α → Prop)] (xs : Array α) : ¬ xs < xs :=
|
||||
List.lt_irrefl xs.toList
|
||||
|
||||
@@ -131,27 +142,35 @@ instance [LT α] [Trans (· < · : α → α → Prop) (· < ·) (· < ·)] :
|
||||
Trans (· < · : Array α → Array α → Prop) (· < ·) (· < ·) where
|
||||
trans h₁ h₂ := Array.lt_trans h₁ h₂
|
||||
|
||||
protected theorem lt_of_le_of_lt [LT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
protected theorem lt_of_le_of_lt [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α]
|
||||
{xs ys zs : Array α} (h₁ : xs ≤ ys) (h₂ : ys < zs) : xs < zs :=
|
||||
Std.lt_of_le_of_lt (α := List α) h₁ h₂
|
||||
|
||||
@[deprecated Array.lt_of_le_of_lt (since := "2025-08-01")]
|
||||
protected theorem lt_of_le_of_lt' [LT α]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[i₃ : Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{xs ys zs : Array α} (h₁ : xs ≤ ys) (h₂ : ys < zs) : xs < zs :=
|
||||
List.lt_of_le_of_lt h₁ h₂
|
||||
letI := LE.ofLT α
|
||||
haveI : IsLinearOrder α := IsLinearOrder.of_lt
|
||||
Array.lt_of_le_of_lt h₁ h₂
|
||||
|
||||
protected theorem le_trans [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
protected theorem le_trans [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α]
|
||||
{xs ys zs : Array α} (h₁ : xs ≤ ys) (h₂ : ys ≤ zs) : xs ≤ zs :=
|
||||
fun h₃ => h₁ (Array.lt_of_le_of_lt h₂ h₃)
|
||||
|
||||
instance [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)] :
|
||||
@[deprecated Array.le_trans (since := "2025-08-01")]
|
||||
protected theorem le_trans' [LT α]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[i₃ : Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{xs ys zs : Array α} (h₁ : xs ≤ ys) (h₂ : ys ≤ zs) : xs ≤ zs :=
|
||||
letI := LE.ofLT α
|
||||
haveI : IsLinearOrder α := IsLinearOrder.of_lt
|
||||
Array.le_trans h₁ h₂
|
||||
|
||||
instance [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α] :
|
||||
Trans (· ≤ · : Array α → Array α → Prop) (· ≤ ·) (· ≤ ·) where
|
||||
trans h₁ h₂ := Array.le_trans h₁ h₂
|
||||
|
||||
@@ -165,7 +184,7 @@ instance [LT α]
|
||||
asymm _ _ := Array.lt_asymm
|
||||
|
||||
protected theorem le_total [LT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)] (xs ys : Array α) : xs ≤ ys ∨ ys ≤ xs :=
|
||||
[i : Std.Asymm (· < · : α → α → Prop)] (xs ys : Array α) : xs ≤ ys ∨ ys ≤ xs :=
|
||||
List.le_total xs.toList ys.toList
|
||||
|
||||
@[simp] protected theorem not_lt [LT α]
|
||||
@@ -175,19 +194,22 @@ protected theorem le_total [LT α]
|
||||
{xs ys : Array α} : ¬ ys ≤ xs ↔ xs < ys := Classical.not_not
|
||||
|
||||
protected theorem le_of_lt [LT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)]
|
||||
[i : Std.Asymm (· < · : α → α → Prop)]
|
||||
{xs ys : Array α} (h : xs < ys) : xs ≤ ys :=
|
||||
List.le_of_lt h
|
||||
|
||||
protected theorem le_iff_lt_or_eq [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Total (¬ · < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
{xs ys : Array α} : xs ≤ ys ↔ xs < ys ∨ xs = ys := by
|
||||
simpa using List.le_iff_lt_or_eq (l₁ := xs.toList) (l₂ := ys.toList)
|
||||
|
||||
instance [LT α]
|
||||
[Std.Total (¬ · < · : α → α → Prop)] :
|
||||
protected theorem le_antisymm [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α]
|
||||
{xs ys : Array α} : xs ≤ ys → ys ≤ xs → xs = ys := by
|
||||
simpa using List.le_antisymm (as := xs.toList) (bs := ys.toList)
|
||||
|
||||
instance [LT α] [Std.Asymm (· < · : α → α → Prop)] :
|
||||
Std.Total (· ≤ · : Array α → Array α → Prop) where
|
||||
total := Array.le_total
|
||||
|
||||
@@ -266,7 +288,6 @@ protected theorem lt_iff_exists [LT α] {xs ys : Array α} :
|
||||
simp [List.lt_iff_exists]
|
||||
|
||||
protected theorem le_iff_exists [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)] {xs ys : Array α} :
|
||||
xs ≤ ys ↔
|
||||
@@ -286,7 +307,6 @@ theorem append_left_lt [LT α] {xs ys zs : Array α} (h : ys < zs) :
|
||||
simpa using List.append_left_lt h
|
||||
|
||||
theorem append_left_le [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{xs ys zs : Array α} (h : ys ≤ zs) :
|
||||
@@ -310,10 +330,8 @@ protected theorem map_lt [LT α] [LT β]
|
||||
simpa using List.map_lt w h
|
||||
|
||||
protected theorem map_le [LT α] [LT β]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Irrefl (· < · : β → β → Prop)]
|
||||
[Std.Asymm (· < · : β → β → Prop)]
|
||||
[Std.Antisymm (¬ · < · : β → β → Prop)]
|
||||
{xs ys : Array α} {f : α → β} (w : ∀ x y, x < y → f x < f y) (h : xs ≤ ys) :
|
||||
|
||||
@@ -60,7 +60,7 @@ theorem mapFinIdx_spec {xs : Array α} {f : (i : Nat) → α → (h : i < xs.siz
|
||||
@[simp, grind =] theorem size_zipIdx {xs : Array α} {k : Nat} : (xs.zipIdx k).size = xs.size :=
|
||||
Array.size_mapFinIdx
|
||||
|
||||
@[deprecated size_zipIdx (since := "2025-01-21")] abbrev size_zipWithIndex := @size_zipIdx
|
||||
|
||||
|
||||
@[simp, grind =] theorem getElem_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {i : Nat}
|
||||
(h : i < (xs.mapFinIdx f).size) :
|
||||
@@ -132,23 +132,20 @@ namespace Array
|
||||
(xs.zipIdx k)[i] = (xs[i]'(by simp_all), k + i) := by
|
||||
simp [zipIdx]
|
||||
|
||||
@[deprecated getElem_zipIdx (since := "2025-01-21")]
|
||||
abbrev getElem_zipWithIndex := @getElem_zipIdx
|
||||
|
||||
|
||||
@[simp, grind =] theorem zipIdx_toArray {l : List α} {k : Nat} :
|
||||
l.toArray.zipIdx k = (l.zipIdx k).toArray := by
|
||||
ext i hi₁ hi₂ <;> simp
|
||||
|
||||
@[deprecated zipIdx_toArray (since := "2025-01-21")]
|
||||
abbrev zipWithIndex_toArray := @zipIdx_toArray
|
||||
|
||||
|
||||
@[simp, grind =] theorem toList_zipIdx {xs : Array α} {k : Nat} :
|
||||
(xs.zipIdx k).toList = xs.toList.zipIdx k := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[deprecated toList_zipIdx (since := "2025-01-21")]
|
||||
abbrev toList_zipWithIndex := @toList_zipIdx
|
||||
|
||||
|
||||
theorem mk_mem_zipIdx_iff_le_and_getElem?_sub {k i : Nat} {x : α} {xs : Array α} :
|
||||
(x, i) ∈ xs.zipIdx k ↔ k ≤ i ∧ xs[i - k]? = some x := by
|
||||
@@ -173,11 +170,7 @@ theorem mem_zipIdx_iff_getElem? {x : α × Nat} {xs : Array α} :
|
||||
x ∈ xs.zipIdx ↔ xs[x.2]? = some x.1 := by
|
||||
rw [mk_mem_zipIdx_iff_getElem?]
|
||||
|
||||
@[deprecated mk_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
abbrev mk_mem_zipWithIndex_iff_getElem? := @mk_mem_zipIdx_iff_getElem?
|
||||
|
||||
@[deprecated mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
abbrev mem_zipWithIndex_iff_getElem? := @mem_zipIdx_iff_getElem?
|
||||
|
||||
/-! ### mapFinIdx -/
|
||||
|
||||
@@ -222,8 +215,7 @@ theorem mapFinIdx_eq_zipIdx_map {xs : Array α} {f : (i : Nat) → α → (h : i
|
||||
f i x (by simp [mk_mem_zipIdx_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1) := by
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated mapFinIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapFinIdx_eq_zipWithIndex_map := @mapFinIdx_eq_zipIdx_map
|
||||
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_eq_empty_iff {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
@@ -332,8 +324,7 @@ theorem mapIdx_eq_zipIdx_map {xs : Array α} {f : Nat → α → β} :
|
||||
xs.mapIdx f = xs.zipIdx.map fun ⟨a, i⟩ => f i a := by
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapIdx_eq_zipWithIndex_map := @mapIdx_eq_zipIdx_map
|
||||
|
||||
|
||||
@[grind =]
|
||||
theorem mapIdx_append {xs ys : Array α} :
|
||||
|
||||
@@ -18,11 +18,11 @@ set_option linter.indexVariables true -- Enforce naming conventions for index va
|
||||
namespace Array
|
||||
|
||||
theorem sizeOf_lt_of_mem [SizeOf α] {as : Array α} (h : a ∈ as) : sizeOf a < sizeOf as := by
|
||||
cases as with | _ as =>
|
||||
cases as with | _ as
|
||||
exact Nat.lt_trans (List.sizeOf_lt_of_mem h.val) (by simp +arith)
|
||||
|
||||
theorem sizeOf_get [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) : sizeOf as[i] < sizeOf as := by
|
||||
cases as with | _ as =>
|
||||
cases as with | _ as
|
||||
simpa using Nat.lt_trans (List.sizeOf_get _ ⟨i, h⟩) (by simp +arith)
|
||||
|
||||
@[simp] theorem sizeOf_getElem [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) :
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ theorem zipWith_foldl_eq_zip_foldl {f : α → β → γ} {i : δ} :
|
||||
theorem zipWith_eq_empty_iff {f : α → β → γ} {as : Array α} {bs : Array β} : zipWith f as bs = #[] ↔ as = #[] ∨ bs = #[] := by
|
||||
cases as <;> cases bs <;> simp
|
||||
|
||||
@[grind =]
|
||||
@[simp, grind =]
|
||||
theorem map_zipWith {δ : Type _} {f : α → β} {g : γ → δ → α} {cs : Array γ} {ds : Array δ} :
|
||||
map f (zipWith g cs ds) = zipWith (fun x y => f (g x y)) cs ds := by
|
||||
cases cs
|
||||
@@ -354,6 +354,15 @@ theorem map_zipWithAll {δ : Type _} {f : α → β} {g : Option γ → Option
|
||||
@[deprecated zipWithAll_replicate (since := "2025-03-18")]
|
||||
abbrev zipWithAll_mkArray := @zipWithAll_replicate
|
||||
|
||||
/-! ### zipWithM -/
|
||||
|
||||
@[simp, grind =]
|
||||
theorem zipWithM_eq_mapM_id_zipWith {m : Type v → Type w} [Monad m] [LawfulMonad m] {f : α → β → m γ} {as : Array α} {bs : Array β} :
|
||||
zipWithM f as bs = mapM id (zipWith f as bs) := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWithM_toArray, ← List.zipWithM'_eq_zipWithM]
|
||||
|
||||
/-! ### unzip -/
|
||||
|
||||
@[deprecated fst_unzip (since := "2025-05-26")]
|
||||
|
||||
@@ -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⟩
|
||||
|
||||
@@ -552,7 +552,7 @@ Example:
|
||||
@[expose]
|
||||
protected def xor (x y : BitVec n) : BitVec n :=
|
||||
(x.toNat ^^^ y.toNat)#'(Nat.xor_lt_two_pow x.isLt y.isLt)
|
||||
instance : Xor (BitVec w) := ⟨.xor⟩
|
||||
instance : XorOp (BitVec w) := ⟨.xor⟩
|
||||
|
||||
/--
|
||||
Bitwise complement for bitvectors. Usually accessed via the `~~~` prefix operator.
|
||||
|
||||
@@ -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}
|
||||
@@ -702,7 +705,7 @@ theorem eq_zero_or_eq_one (a : BitVec 1) : a = 0#1 ∨ a = 1#1 := by
|
||||
have acases : a = 0 ∨ a = 1 := by omega
|
||||
rcases acases with ⟨rfl | rfl⟩
|
||||
· simp
|
||||
· case inr h =>
|
||||
case inr h =>
|
||||
subst h
|
||||
simp
|
||||
|
||||
@@ -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
|
||||
@@ -1393,7 +1396,7 @@ theorem or_eq_zero_iff {x y : BitVec w} : (x ||| y) = 0#w ↔ x = 0#w ∧ y = 0#
|
||||
· intro h
|
||||
constructor
|
||||
all_goals
|
||||
· ext i ih
|
||||
ext i ih
|
||||
have := BitVec.eq_of_getElem_eq_iff.mp h i ih
|
||||
simp only [getElem_or, getElem_zero, Bool.or_eq_false_iff] at this
|
||||
simp [this]
|
||||
@@ -1493,7 +1496,7 @@ theorem and_eq_allOnes_iff {x y : BitVec w} :
|
||||
· intro h
|
||||
constructor
|
||||
all_goals
|
||||
· ext i ih
|
||||
ext i ih
|
||||
have := BitVec.eq_of_getElem_eq_iff.mp h i ih
|
||||
simp only [getElem_and, getElem_allOnes, Bool.and_eq_true] at this
|
||||
simp [this]
|
||||
@@ -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
|
||||
@@ -4419,8 +4432,8 @@ theorem neg_one_ediv_toInt_eq {w : Nat} {y : BitVec w} :
|
||||
rcases w with _|_|w
|
||||
· simp [of_length_zero]
|
||||
· cases eq_zero_or_eq_one y
|
||||
· case _ h => simp [h]
|
||||
· case _ h => simp [h]
|
||||
case _ h => simp [h]
|
||||
case _ h => simp [h]
|
||||
· by_cases 0 < y.toInt
|
||||
· simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
|
||||
omega
|
||||
@@ -5766,16 +5779,16 @@ theorem clzAuxRec_eq_clzAuxRec_of_le (x : BitVec w) (h : w - 1 ≤ n) :
|
||||
let k := n - (w - 1)
|
||||
rw [show n = (w - 1) + k by omega]
|
||||
induction k
|
||||
· case zero => simp
|
||||
· case succ k ihk =>
|
||||
case zero => simp
|
||||
case succ k ihk =>
|
||||
simp [show w - 1 + (k + 1) = (w - 1 + k) + 1 by omega, clzAuxRec_succ, ihk,
|
||||
show x.getLsbD (w - 1 + k + 1) = false by simp only [show w ≤ w - 1 + k + 1 by omega, getLsbD_of_ge]]
|
||||
|
||||
theorem clzAuxRec_eq_clzAuxRec_of_getLsbD_false {x : BitVec w} (h : ∀ i, n < i → x.getLsbD i = false) :
|
||||
x.clzAuxRec n = x.clzAuxRec (n + k) := by
|
||||
induction k
|
||||
· case zero => simp
|
||||
· case succ k ihk =>
|
||||
case zero => simp
|
||||
case succ k ihk =>
|
||||
simp only [show n + (k + 1) = (n + k) + 1 by omega, clzAuxRec_succ]
|
||||
by_cases hxn : x.getLsbD (n + k + 1)
|
||||
· have : ¬ ∀ (i : Nat), n < i → x.getLsbD i = false := by
|
||||
@@ -5842,13 +5855,8 @@ set_option linter.missingDocs false
|
||||
@[deprecated toFin_uShiftRight (since := "2025-02-18")]
|
||||
abbrev toFin_uShiftRight := @toFin_ushiftRight
|
||||
|
||||
@[deprecated signExtend_eq_setWidth_of_msb_false (since := "2024-12-08")]
|
||||
abbrev signExtend_eq_not_setWidth_not_of_msb_false := @signExtend_eq_setWidth_of_msb_false
|
||||
|
||||
@[deprecated replicate_zero (since := "2025-01-08")]
|
||||
abbrev replicate_zero_eq := @replicate_zero
|
||||
|
||||
@[deprecated replicate_succ (since := "2025-01-08")]
|
||||
abbrev replicate_succ_eq := @replicate_succ
|
||||
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -696,3 +696,23 @@ but may be used locally.
|
||||
|
||||
@[simp] theorem Subtype.beq_iff {α : Type u} [BEq α] {p : α → Prop} {x y : {a : α // p a}} :
|
||||
(x == y) = (x.1 == y.1) := rfl
|
||||
|
||||
/-! ### Proof by reflection support -/
|
||||
|
||||
@[expose] protected noncomputable def Bool.and' (a b : Bool) : Bool :=
|
||||
Bool.rec false b a
|
||||
|
||||
@[expose] protected noncomputable def Bool.or' (a b : Bool) : Bool :=
|
||||
Bool.rec b true a
|
||||
|
||||
@[expose] protected noncomputable def Bool.not' (a : Bool) : Bool :=
|
||||
Bool.rec true false a
|
||||
|
||||
@[simp] theorem Bool.and'_eq_and (a b : Bool) : a.and' b = a.and b := by
|
||||
cases a <;> simp [Bool.and']
|
||||
|
||||
@[simp] theorem Bool.or'_eq_or (a b : Bool) : a.or' b = a.or b := by
|
||||
cases a <;> simp [Bool.or']
|
||||
|
||||
@[simp] theorem Bool.not'_eq_not (a : Bool) : a.not' = a.not := by
|
||||
cases a <;> simp [Bool.not']
|
||||
|
||||
@@ -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
|
||||
@@ -221,7 +221,7 @@ instance : AndOp (Fin n) where
|
||||
and := Fin.land
|
||||
instance : OrOp (Fin n) where
|
||||
or := Fin.lor
|
||||
instance : Xor (Fin n) where
|
||||
instance : XorOp (Fin n) where
|
||||
xor := Fin.xor
|
||||
instance : ShiftLeft (Fin n) where
|
||||
shiftLeft := Fin.shiftLeft
|
||||
|
||||
@@ -107,14 +107,14 @@ Fin.foldrM n f xₙ = do
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldlM_loop_lt [Monad m] (f : α → Fin n → m α) (x) (h : i < n) :
|
||||
private theorem foldlM_loop_lt [Monad m] (f : α → Fin n → m α) (x) (h : i < n) :
|
||||
foldlM.loop n f x i = f x ⟨i, h⟩ >>= (foldlM.loop n f . (i+1)) := by
|
||||
rw [foldlM.loop, dif_pos h]
|
||||
|
||||
theorem foldlM_loop_eq [Monad m] (f : α → Fin n → m α) (x) : foldlM.loop n f x n = pure x := by
|
||||
private theorem foldlM_loop_eq [Monad m] (f : α → Fin n → m α) (x) : foldlM.loop n f x n = pure x := by
|
||||
rw [foldlM.loop, dif_neg (Nat.lt_irrefl _)]
|
||||
|
||||
theorem foldlM_loop [Monad m] (f : α → Fin (n+1) → m α) (x) (h : i < n+1) :
|
||||
private theorem foldlM_loop [Monad m] (f : α → Fin (n+1) → m α) (x) (h : i < n+1) :
|
||||
foldlM.loop (n+1) f x i = f x ⟨i, h⟩ >>= (foldlM.loop n (fun x j => f x j.succ) . i) := by
|
||||
if h' : i < n then
|
||||
rw [foldlM_loop_lt _ _ h]
|
||||
@@ -170,15 +170,15 @@ theorem foldlM_add [Monad m] [LawfulMonad m] (f : α → Fin (n + k) → m α) :
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldrM_loop_zero [Monad m] (f : Fin n → α → m α) (x) :
|
||||
private theorem foldrM_loop_zero [Monad m] (f : Fin n → α → m α) (x) :
|
||||
foldrM.loop n f ⟨0, Nat.zero_le _⟩ x = pure x := by
|
||||
rw [foldrM.loop]
|
||||
|
||||
theorem foldrM_loop_succ [Monad m] (f : Fin n → α → m α) (x) (h : i < n) :
|
||||
private theorem foldrM_loop_succ [Monad m] (f : Fin n → α → m α) (x) (h : i < n) :
|
||||
foldrM.loop n f ⟨i+1, h⟩ x = f ⟨i, h⟩ x >>= foldrM.loop n f ⟨i, Nat.le_of_lt h⟩ := by
|
||||
rw [foldrM.loop]
|
||||
|
||||
theorem foldrM_loop [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x) (h : i+1 ≤ n+1) :
|
||||
private theorem foldrM_loop [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x) (h : i+1 ≤ n+1) :
|
||||
foldrM.loop (n+1) f ⟨i+1, h⟩ x =
|
||||
foldrM.loop n (fun j => f j.succ) ⟨i, Nat.le_of_succ_le_succ h⟩ x >>= f 0 := by
|
||||
induction i generalizing x with
|
||||
@@ -228,14 +228,14 @@ theorem foldrM_add [Monad m] [LawfulMonad m] (f : Fin (n + k) → α → m α) :
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldl_loop_lt (f : α → Fin n → α) (x) (h : i < n) :
|
||||
private theorem foldl_loop_lt (f : α → Fin n → α) (x) (h : i < n) :
|
||||
foldl.loop n f x i = foldl.loop n f (f x ⟨i, h⟩) (i+1) := by
|
||||
rw [foldl.loop, dif_pos h]
|
||||
|
||||
theorem foldl_loop_eq (f : α → Fin n → α) (x) : foldl.loop n f x n = x := by
|
||||
private theorem foldl_loop_eq (f : α → Fin n → α) (x) : foldl.loop n f x n = x := by
|
||||
rw [foldl.loop, dif_neg (Nat.lt_irrefl _)]
|
||||
|
||||
theorem foldl_loop (f : α → Fin (n+1) → α) (x) (h : i < n+1) :
|
||||
private theorem foldl_loop (f : α → Fin (n+1) → α) (x) (h : i < n+1) :
|
||||
foldl.loop (n+1) f x i = foldl.loop n (fun x j => f x j.succ) (f x ⟨i, h⟩) i := by
|
||||
if h' : i < n then
|
||||
rw [foldl_loop_lt _ _ h]
|
||||
@@ -285,15 +285,15 @@ theorem foldlM_pure [Monad m] [LawfulMonad m] {n} {f : α → Fin n → α} :
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldr_loop_zero (f : Fin n → α → α) (x) :
|
||||
private theorem foldr_loop_zero (f : Fin n → α → α) (x) :
|
||||
foldr.loop n f 0 (Nat.zero_le _) x = x := by
|
||||
rw [foldr.loop]
|
||||
|
||||
theorem foldr_loop_succ (f : Fin n → α → α) (x) (h : i < n) :
|
||||
private theorem foldr_loop_succ (f : Fin n → α → α) (x) (h : i < n) :
|
||||
foldr.loop n f (i+1) h x = foldr.loop n f i (Nat.le_of_lt h) (f ⟨i, h⟩ x) := by
|
||||
rw [foldr.loop]
|
||||
|
||||
theorem foldr_loop (f : Fin (n+1) → α → α) (x) (h : i+1 ≤ n+1) :
|
||||
private theorem foldr_loop (f : Fin (n+1) → α → α) (x) (h : i+1 ≤ n+1) :
|
||||
foldr.loop (n+1) f (i+1) h x =
|
||||
f 0 (foldr.loop n (fun j => f j.succ) i (Nat.le_of_succ_le_succ h) x) := by
|
||||
induction i generalizing x with
|
||||
|
||||
@@ -12,9 +12,13 @@ public import Init.Ext
|
||||
public import Init.ByCases
|
||||
public import Init.Conv
|
||||
public import Init.Omega
|
||||
public import Init.Data.Order.Factories
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
|
||||
namespace Fin
|
||||
|
||||
@[simp] theorem ofNat_zero (n : Nat) [NeZero n] : Fin.ofNat n 0 = 0 := rfl
|
||||
@@ -251,6 +255,16 @@ protected theorem le_antisymm_iff {x y : Fin n} : x = y ↔ x ≤ y ∧ y ≤ x
|
||||
protected theorem le_antisymm {x y : Fin n} (h1 : x ≤ y) (h2 : y ≤ x) : x = y :=
|
||||
Fin.le_antisymm_iff.2 ⟨h1, h2⟩
|
||||
|
||||
instance instIsLinearOrder : IsLinearOrder (Fin n) := by
|
||||
apply IsLinearOrder.of_le
|
||||
case le_antisymm => constructor; apply Fin.le_antisymm
|
||||
case le_total => constructor; apply Fin.le_total
|
||||
case le_trans => constructor; apply Fin.le_trans
|
||||
|
||||
instance : LawfulOrderLT (Fin n) where
|
||||
lt_iff := by
|
||||
simp [← Fin.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
@[simp, grind =] theorem val_rev (i : Fin n) : rev i = n - (i + 1) := rfl
|
||||
|
||||
@[simp] theorem rev_rev (i : Fin n) : rev (rev i) = i := Fin.ext <| by
|
||||
@@ -938,7 +952,7 @@ For the induction:
|
||||
(reverseInduction zero succ (Fin.last n) : motive (Fin.last n)) = zero := by
|
||||
rw [reverseInduction, reverseInduction.go]; simp
|
||||
|
||||
@[simp] theorem reverseInduction_castSucc_aux {n : Nat} {motive : Fin (n + 1) → Sort _} {succ}
|
||||
private theorem reverseInduction_castSucc_aux {n : Nat} {motive : Fin (n + 1) → Sort _} {succ}
|
||||
(i : Fin n) (j : Nat) (h) (h2 : i.1 < j) (zero : motive ⟨j, h⟩) :
|
||||
reverseInduction.go (motive := motive) succ i.castSucc j h (Nat.le_of_lt h2) zero =
|
||||
succ i (reverseInduction.go succ i.succ j h h2 zero) := by
|
||||
|
||||
@@ -314,7 +314,7 @@ Examples:
|
||||
* `(0 : Int).natAbs = 0`
|
||||
* `((-11 : Int).natAbs = 11`
|
||||
-/
|
||||
@[extern "lean_nat_abs"]
|
||||
@[extern "lean_nat_abs", expose]
|
||||
def natAbs (m : @& Int) : Nat :=
|
||||
match m with
|
||||
| ofNat m => m
|
||||
@@ -404,6 +404,26 @@ instance : Min Int := minOfLe
|
||||
|
||||
instance : Max Int := maxOfLe
|
||||
|
||||
/-- Equality predicate for kernel reduction. -/
|
||||
@[expose] protected noncomputable def beq' (a b : Int) : Bool :=
|
||||
Int.rec
|
||||
(fun a => Int.rec (fun b => Nat.beq a b) (fun _ => false) b)
|
||||
(fun a => Int.rec (fun _ => false) (fun b => Nat.beq a b) b) a
|
||||
|
||||
/-- `x ≤ y` for kernel reduction. -/
|
||||
@[expose] protected noncomputable def ble' (a b : Int) : Bool :=
|
||||
Int.rec
|
||||
(fun a => Int.rec (fun b => Nat.ble a b) (fun _ => false) b)
|
||||
(fun a => Int.rec (fun _ => true) (fun b => Nat.ble b a) b)
|
||||
a
|
||||
|
||||
/-- `x < y` for kernel reduction. -/
|
||||
@[expose] protected noncomputable def blt' (a b : Int) : Bool :=
|
||||
Int.rec
|
||||
(fun a => Int.rec (fun b => Nat.blt a b) (fun _ => false) b)
|
||||
(fun a => Int.rec (fun _ => true) (fun b => Nat.blt b a) b)
|
||||
a
|
||||
|
||||
end Int
|
||||
|
||||
/--
|
||||
|
||||
@@ -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
|
||||
@@ -27,7 +27,7 @@ theorem compare_eq_ite_lt (a b : Int) :
|
||||
simp only [compare, compareOfLessAndEq]
|
||||
split
|
||||
· rfl
|
||||
· next h =>
|
||||
next h =>
|
||||
match Int.lt_or_eq_of_le (Int.not_lt.1 h) with
|
||||
| .inl h => simp [h, Int.ne_of_gt h]
|
||||
| .inr rfl => simp
|
||||
@@ -36,11 +36,11 @@ theorem compare_eq_ite_le (a b : Int) :
|
||||
compare a b = if a ≤ b then if b ≤ a then .eq else .lt else .gt := by
|
||||
rw [compare_eq_ite_lt]
|
||||
split
|
||||
· next hlt => simp [Int.le_of_lt hlt, Int.not_le.2 hlt]
|
||||
· next hge =>
|
||||
next hlt => simp [Int.le_of_lt hlt, Int.not_le.2 hlt]
|
||||
next hge =>
|
||||
split
|
||||
· next hgt => simp [Int.not_le.2 hgt]
|
||||
· next hle => simp [Int.not_lt.1 hge, Int.not_lt.1 hle]
|
||||
next hgt => simp [Int.not_le.2 hgt]
|
||||
next hle => simp [Int.not_lt.1 hge, Int.not_lt.1 hle]
|
||||
|
||||
protected theorem compare_swap (a b : Int) : (compare a b).swap = compare b a := by
|
||||
simp only [compare_eq_ite_le]; (repeat' split) <;> try rfl
|
||||
|
||||
@@ -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 ..
|
||||
|
||||
@@ -86,6 +86,17 @@ theorem negSucc_coe (n : Nat) : -[n+1] = -↑(n + 1) := rfl
|
||||
@[simp, norm_cast] theorem cast_ofNat_Int :
|
||||
(Nat.cast (no_index (OfNat.ofNat n)) : Int) = OfNat.ofNat n := rfl
|
||||
|
||||
@[simp] theorem beq'_eq (a b : Int) : Int.beq' a b = (a = b) := by
|
||||
cases a <;> cases b <;> simp [Int.beq', ofNat_inj]
|
||||
|
||||
@[simp] theorem beq'_ne (a b : Int) : (Int.beq' a b = false) = (a ≠ b) := by
|
||||
rw [Ne, ← beq'_eq, Bool.not_eq_true]
|
||||
|
||||
theorem beq'_eq_beq (a b : Int) : (Int.beq' a b) = (a == b) := by
|
||||
have h : (Int.beq' a b = true) = (a == b) := by simp
|
||||
have : ∀ {a b : Bool}, (a = true) = (b = true) → a = b := by intro a b; cases a <;> cases b <;> simp
|
||||
exact this h
|
||||
|
||||
/- ## neg -/
|
||||
|
||||
@[simp] protected theorem neg_neg : ∀ a : Int, -(-a) = a
|
||||
@@ -350,10 +361,10 @@ theorem negSucc_coe' (n : Nat) : -[n+1] = -↑n - 1 := by
|
||||
|
||||
protected theorem subNatNat_eq_coe {m n : Nat} : subNatNat m n = ↑m - ↑n := by
|
||||
apply subNatNat_elim m n fun m n i => i = m - n
|
||||
· intros i n
|
||||
· intro i n
|
||||
rw [Int.natCast_add, Int.sub_eq_add_neg, Int.add_assoc, Int.add_left_comm,
|
||||
Int.add_right_neg, Int.add_zero]
|
||||
· intros i n
|
||||
· intro i n
|
||||
simp only [negSucc_eq, natCast_add, ofNat_one, Int.sub_eq_add_neg, Int.neg_add, ← Int.add_assoc]
|
||||
rw [Int.add_neg_eq_sub (a := n), ← ofNat_sub, Nat.sub_self, ofNat_zero, Int.zero_add]
|
||||
apply Nat.le_refl
|
||||
|
||||
@@ -69,6 +69,18 @@ theorem natCast_succ_pos (n : Nat) : 0 < (n.succ : Int) := natCast_pos.2 n.succ_
|
||||
|
||||
@[simp, norm_cast] theorem cast_id {n : Int} : Int.cast n = n := rfl
|
||||
|
||||
@[simp] theorem ble'_eq_true (a b : Int) : (Int.ble' a b = true) = (a ≤ b) := by
|
||||
cases a <;> cases b <;> simp [Int.ble'] <;> omega
|
||||
|
||||
@[simp] theorem blt'_eq_true (a b : Int) : (Int.blt' a b = true) = (a < b) := by
|
||||
cases a <;> cases b <;> simp [Int.blt'] <;> omega
|
||||
|
||||
@[simp] theorem ble'_eq_false (a b : Int) : (Int.ble' a b = false) = ¬(a ≤ b) := by
|
||||
simp [← Bool.not_eq_true]
|
||||
|
||||
@[simp] theorem blt'_eq_false (a b : Int) : (Int.blt' a b = false) = ¬ (a < b) := by
|
||||
simp [← Bool.not_eq_true]
|
||||
|
||||
/-! ### toNat -/
|
||||
|
||||
@[simp] theorem toNat_sub' (a : Int) (b : Nat) : (a - b).toNat = a.toNat - b := by
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@ prelude
|
||||
public import Init.Data.Int.Lemmas
|
||||
public import Init.Data.Int.DivMod
|
||||
public import Init.Data.Int.Linear
|
||||
public import Init.GrindInstances.ToInt
|
||||
public import Init.Data.RArray
|
||||
|
||||
public section
|
||||
@@ -83,6 +84,10 @@ theorem mod_congr {a b : Nat} {a' b' : Int}
|
||||
(h₁ : NatCast.natCast a = a') (h₂ : NatCast.natCast b = b') : NatCast.natCast (a % b) = a' % b' := by
|
||||
simp_all [Int.natCast_emod]
|
||||
|
||||
theorem finVal {n : Nat} {a : Fin n} {a' : Int}
|
||||
(h₁ : Lean.Grind.ToInt.toInt a = a') : NatCast.natCast (a.val) = a' := by
|
||||
rw [← h₁, Lean.Grind.ToInt.toInt, Lean.Grind.instToIntFinCoOfNatIntCast]
|
||||
|
||||
end Nat.ToInt
|
||||
|
||||
namespace Int.Nonneg
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -10,6 +10,7 @@ public import all Init.Data.Iterators.Combinators.Attach
|
||||
public import all Init.Data.Iterators.Combinators.Monadic.Attach
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.Attach
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
public import Init.Data.Array.Attach
|
||||
|
||||
public section
|
||||
|
||||
@@ -68,4 +69,16 @@ theorem Iter.unattach_toArray_attachWith [Iterator α Id β]
|
||||
(it.attachWith P hP).toListRev.unattach = it.toListRev := by
|
||||
simp [toListRev_eq]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_attachWith [Iterator α Id β]
|
||||
{it : Iter (α := α) β} {hP}
|
||||
[Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] :
|
||||
(it.attachWith P hP).toArray = it.toArray.attachWith P
|
||||
(fun out h => hP out (isPlausibleIndirectOutput_of_mem_toArray h)) := by
|
||||
suffices (it.attachWith P hP).toArray.toList = (it.toArray.attachWith P
|
||||
(fun out h => hP out (isPlausibleIndirectOutput_of_mem_toArray h))).toList by
|
||||
simpa only [Array.toList_inj]
|
||||
simp [Iter.toList_toArray]
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -251,7 +251,7 @@ instance {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
simp only [LawfulIteratorCollect.toArrayMapped_eq]
|
||||
simp only [IteratorCollect.toArrayMapped]
|
||||
rw [LawfulIteratorCollect.toArrayMapped_eq]
|
||||
induction it using IterM.inductSteps with | step it ih_yield ih_skip =>
|
||||
induction it using IterM.inductSteps with | step it ih_yield ih_skip
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
simp only [bind_assoc]
|
||||
|
||||
@@ -97,7 +97,7 @@ theorem Iter.getElem?_toList_eq_atIdxSlow? {α β}
|
||||
[Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {k : Nat} :
|
||||
it.toList[k]? = it.atIdxSlow? k := by
|
||||
induction it using Iter.inductSteps generalizing k with | step it ihy ihs =>
|
||||
induction it using Iter.inductSteps generalizing k with | step it ihy ihs
|
||||
rw [toList_eq_match_step, atIdxSlow?]
|
||||
obtain ⟨step, h⟩ := it.step
|
||||
cases step
|
||||
@@ -117,7 +117,7 @@ theorem Iter.isPlausibleIndirectOutput_of_mem_toList
|
||||
[Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {b : β} :
|
||||
b ∈ it.toList → it.IsPlausibleIndirectOutput b := by
|
||||
induction it using Iter.inductSteps with | step it ihy ihs =>
|
||||
induction it using Iter.inductSteps with | step it ihy ihs
|
||||
rw [toList_eq_match_step]
|
||||
cases it.step using PlausibleIterStep.casesOn
|
||||
case yield it' out h =>
|
||||
@@ -144,4 +144,13 @@ theorem Iter.isPlausibleIndirectOutput_of_mem_toListRev
|
||||
apply isPlausibleIndirectOutput_of_mem_toList
|
||||
simpa [toListRev_eq] using h
|
||||
|
||||
theorem Iter.isPlausibleIndirectOutput_of_mem_toArray
|
||||
[Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {b : β} :
|
||||
b ∈ it.toArray → it.IsPlausibleIndirectOutput b := by
|
||||
intro h
|
||||
apply isPlausibleIndirectOutput_of_mem_toList
|
||||
rw [← Array.mem_toList_iff] at h
|
||||
simpa [toList_toArray] using h
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -143,7 +143,7 @@ theorem Iter.mem_toList_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β
|
||||
[LawfulIteratorCollect α Id Id] [LawfulDeterministicIterator α Id]
|
||||
{it : Iter (α := α) β} {out : β} :
|
||||
out ∈ it.toList ↔ it.IsPlausibleIndirectOutput out := by
|
||||
induction it using Iter.inductSteps with | step it ihy ihs =>
|
||||
induction it using Iter.inductSteps with | step it ihy ihs
|
||||
rw [toList_eq_match_step]
|
||||
constructor
|
||||
· intro h
|
||||
@@ -194,7 +194,7 @@ theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it.toList init f = ForIn'.forIn' it init (fun out h acc => f out (Iter.mem_toList_iff_isPlausibleIndirectOutput.mpr h) acc) := by
|
||||
induction it using Iter.inductSteps generalizing init with case step it ihy ihs =>
|
||||
induction it using Iter.inductSteps generalizing init with | step it ihy ihs
|
||||
have := it.toList_eq_match_step
|
||||
generalize hs : it.step = step at this
|
||||
rw [forIn'_toList.aux this]
|
||||
@@ -239,7 +239,7 @@ theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it.toList init f = ForIn.forIn it init f := by
|
||||
rw [List.forIn_eq_foldlM]
|
||||
induction it using Iter.inductSteps generalizing init with case step it ihy ihs =>
|
||||
induction it using Iter.inductSteps generalizing init with | step it ihy ihs
|
||||
rw [forIn_eq_match_step, Iter.toList_eq_match_step]
|
||||
simp only [map_eq_pure_bind]
|
||||
generalize it.step = step
|
||||
|
||||
@@ -21,8 +21,7 @@ theorem IterM.DefaultConsumers.toArrayMapped.go.aux₁ [Monad n] [LawfulMonad n]
|
||||
[Finite α m] {b : γ} {bs : Array γ} :
|
||||
IterM.DefaultConsumers.toArrayMapped.go lift f it (#[b] ++ bs) (m := m) =
|
||||
(#[b] ++ ·) <$> IterM.DefaultConsumers.toArrayMapped.go lift f it bs (m := m) := by
|
||||
induction it, bs using IterM.DefaultConsumers.toArrayMapped.go.induct
|
||||
next it bs ih₁ ih₂ =>
|
||||
induction it, bs using IterM.DefaultConsumers.toArrayMapped.go.induct with | _ it bs ih₁ ih₂
|
||||
rw [go, map_eq_pure_bind, go, bind_assoc]
|
||||
apply bind_congr
|
||||
intro step
|
||||
@@ -93,8 +92,7 @@ theorem IterM.toList_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
theorem IterM.toListRev.go.aux₁ [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
{it : IterM (α := α) m β} {b : β} {bs : List β} :
|
||||
IterM.toListRev.go it (bs ++ [b]) = (· ++ [b]) <$> IterM.toListRev.go it bs:= by
|
||||
induction it, bs using IterM.toListRev.go.induct
|
||||
next it bs ih₁ ih₂ =>
|
||||
induction it, bs using IterM.toListRev.go.induct with | _ it bs ih₁ ih₂
|
||||
rw [go, go, map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
intro step
|
||||
|
||||
@@ -208,7 +208,7 @@ theorem IterM.toList_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator
|
||||
it.fold (init := l') (fun l out => l ++ [out]) by
|
||||
specialize h []
|
||||
simpa using h
|
||||
induction it using IterM.inductSteps with | step it ihy ihs =>
|
||||
induction it using IterM.inductSteps with | step it ihy ihs
|
||||
intro l'
|
||||
rw [IterM.toList_eq_match_step, IterM.fold_eq_match_step]
|
||||
simp only [map_eq_pure_bind, bind_assoc]
|
||||
@@ -253,7 +253,7 @@ theorem IterM.drain_eq_map_toList {α β : Type w} {m : Type w → Type w'} [Ite
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.drain = (fun _ => .unit) <$> it.toList := by
|
||||
induction it using IterM.inductSteps with | step it ihy ihs =>
|
||||
induction it using IterM.inductSteps with | step it ihy ihs
|
||||
rw [IterM.drain_eq_match_step, IterM.toList_eq_match_step]
|
||||
simp only [map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Lawful.Basic
|
||||
public import Init.Data.Subtype
|
||||
public import Init.Data.Subtype.Basic
|
||||
public import Init.PropLemmas
|
||||
|
||||
public section
|
||||
|
||||
@@ -8,7 +8,7 @@ module
|
||||
prelude
|
||||
public import all Init.Data.List.Lemmas -- for dsimping with `getElem?_cons_succ`
|
||||
public import Init.Data.List.Count
|
||||
public import Init.Data.Subtype
|
||||
public import Init.Data.Subtype.Basic
|
||||
public import Init.BinderNameHint
|
||||
|
||||
public section
|
||||
@@ -123,7 +123,7 @@ theorem attachWith_congr {l₁ l₂ : List α} (w : l₁ = l₂) {P : α → Pro
|
||||
⟨x, mem_cons_self⟩ :: xs.attach.map fun ⟨y, h⟩ => ⟨y, mem_cons_of_mem x h⟩ := by
|
||||
simp only [attach, attachWith, pmap, map_pmap, cons.injEq, true_and]
|
||||
apply pmap_congr_left
|
||||
intros a _ m' _
|
||||
intro a _ m' _
|
||||
rfl
|
||||
|
||||
@[simp, grind =]
|
||||
|
||||
@@ -242,8 +242,7 @@ instance instLT [LT α] : LT (List α) := ⟨List.lt⟩
|
||||
instance decidableLT [DecidableEq α] [LT α] [DecidableLT α] (l₁ l₂ : List α) :
|
||||
Decidable (l₁ < l₂) := decidableLex (· < ·) l₁ l₂
|
||||
|
||||
@[deprecated decidableLT (since := "2024-12-13"), inherit_doc decidableLT]
|
||||
abbrev hasDecidableLt := @decidableLT
|
||||
|
||||
|
||||
/--
|
||||
Non-strict ordering of lists with respect to a strict ordering of their elements.
|
||||
@@ -1722,14 +1721,8 @@ Examples:
|
||||
-/
|
||||
def idxOf [BEq α] (a : α) : List α → Nat := findIdx (· == a)
|
||||
|
||||
/-- Returns the index of the first element equal to `a`, or the length of the list otherwise. -/
|
||||
@[deprecated idxOf (since := "2025-01-29")] abbrev indexOf := @idxOf
|
||||
|
||||
@[simp] theorem idxOf_nil [BEq α] : ([] : List α).idxOf x = 0 := rfl
|
||||
|
||||
@[deprecated idxOf_nil (since := "2025-01-29")]
|
||||
theorem indexOf_nil [BEq α] : ([] : List α).idxOf x = 0 := rfl
|
||||
|
||||
/-! ### findIdx? -/
|
||||
|
||||
/--
|
||||
@@ -1760,10 +1753,6 @@ Examples:
|
||||
-/
|
||||
@[inline] def idxOf? [BEq α] (a : α) : List α → Option Nat := findIdx? (· == a)
|
||||
|
||||
/-- Return the index of the first occurrence of `a` in the list. -/
|
||||
@[deprecated idxOf? (since := "2025-01-29")]
|
||||
abbrev indexOf? := @idxOf?
|
||||
|
||||
/-! ### findFinIdx? -/
|
||||
|
||||
/--
|
||||
@@ -2119,21 +2108,10 @@ def range' : (start len : Nat) → (step : Nat := 1) → List Nat
|
||||
| _, 0, _ => []
|
||||
| s, n+1, step => s :: range' (s+step) n step
|
||||
|
||||
/-! ### iota -/
|
||||
|
||||
/--
|
||||
`O(n)`. `iota n` is the numbers from `1` to `n` inclusive, in decreasing order.
|
||||
* `iota 5 = [5, 4, 3, 2, 1]`
|
||||
-/
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
def iota : Nat → List Nat
|
||||
| 0 => []
|
||||
| m@(n+1) => m :: iota n
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[simp] theorem iota_zero : iota 0 = [] := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[simp] theorem iota_succ : iota (i+1) = (i+1) :: iota i := rfl
|
||||
@[simp, grind =] theorem range'_zero : range' s 0 step = [] := rfl
|
||||
@[simp, grind =] theorem range'_one {s step : Nat} : range' s 1 step = [s] := rfl
|
||||
-- The following theorem is intentionally not a simp lemma.
|
||||
theorem range'_succ : range' s (n + 1) step = s :: range' (s + step) n step := rfl
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@@ -2153,38 +2131,6 @@ def zipIdx : (l : List α) → (n : Nat := 0) → List (α × Nat)
|
||||
@[simp] theorem zipIdx_nil : ([] : List α).zipIdx i = [] := rfl
|
||||
@[simp] theorem zipIdx_cons : (a::as).zipIdx i = (a, i) :: as.zipIdx (i+1) := rfl
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
/--
|
||||
`O(|l|)`. `enumFrom n l` is like `enum` but it allows you to specify the initial index.
|
||||
* `enumFrom 5 [a, b, c] = [(5, a), (6, b), (7, c)]`
|
||||
-/
|
||||
@[deprecated "Use `zipIdx` instead; note the signature change." (since := "2025-01-21")]
|
||||
def enumFrom : Nat → List α → List (Nat × α)
|
||||
| _, [] => nil
|
||||
| n, x :: xs => (n, x) :: enumFrom (n + 1) xs
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated zipIdx_nil (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_nil : ([] : List α).enumFrom i = [] := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated zipIdx_cons (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_cons : (a::as).enumFrom i = (i, a) :: as.enumFrom (i+1) := rfl
|
||||
|
||||
/-! ### enum -/
|
||||
|
||||
set_option linter.deprecated false in
|
||||
/--
|
||||
`O(|l|)`. `enum l` pairs up each element with its index in the list.
|
||||
* `enum [a, b, c] = [(0, a), (1, b), (2, c)]`
|
||||
-/
|
||||
@[deprecated "Use `zipIdx` instead; note the signature change." (since := "2025-01-21")]
|
||||
def enum : List α → List (Nat × α) := enumFrom 0
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated zipIdx_nil (since := "2025-01-21"), simp]
|
||||
theorem enum_nil : ([] : List α).enum = [] := rfl
|
||||
|
||||
/-! ## Minima and maxima -/
|
||||
|
||||
/-! ### min? -/
|
||||
@@ -2604,25 +2550,6 @@ Examples:
|
||||
exact go s n (m + 1)
|
||||
exact (go s n 0).symm
|
||||
|
||||
/-! ### iota -/
|
||||
|
||||
/-- Tail-recursive version of `List.iota`. -/
|
||||
@[deprecated "Use `List.range' 1 n` instead of `iota n`." (since := "2025-01-20")]
|
||||
def iotaTR (n : Nat) : List Nat :=
|
||||
let rec go : Nat → List Nat → List Nat
|
||||
| 0, r => r.reverse
|
||||
| m@(n+1), r => go n (m::r)
|
||||
go n []
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[csimp]
|
||||
theorem iota_eq_iotaTR : @iota = @iotaTR :=
|
||||
have aux (n : Nat) (r : List Nat) : iotaTR.go n r = r.reverse ++ iota n := by
|
||||
induction n generalizing r with
|
||||
| zero => simp [iota, iotaTR.go]
|
||||
| succ n ih => simp [iota, iotaTR.go, ih, append_assoc]
|
||||
funext fun n => by simp [iotaTR, aux]
|
||||
|
||||
/-! ## Other list operations -/
|
||||
|
||||
/-! ### intersperse -/
|
||||
|
||||
@@ -104,6 +104,20 @@ def forA {m : Type u → Type v} [Applicative m] {α : Type w} (as : List α) (f
|
||||
| [] => pure ⟨⟩
|
||||
| a :: as => f a *> forA as f
|
||||
|
||||
/--
|
||||
Applies the monadic action `f` to the corresponding elements of two lists, left-to-right, stopping
|
||||
at the end of the shorter list. `zipWithM f as bs` is equivalent to `mapM id (zipWith f as bs)`
|
||||
for lawful `Monad` instances.
|
||||
|
||||
This implementation is tail recursive. `List.zipWithM'` is a a non-tail-recursive variant that may
|
||||
be more convenient to reason about.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def zipWithM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type x} {γ : Type u} (f : α → β → m γ) (as : List α) (bs : List β) : m (List γ) :=
|
||||
let rec @[specialize] loop
|
||||
| a::as, b::bs, acc => do loop as bs (acc.push (← f a b))
|
||||
| _, _, acc => pure acc.toList
|
||||
loop as bs #[]
|
||||
|
||||
@[specialize]
|
||||
def filterAuxM {m : Type → Type v} [Monad m] {α : Type} (f : α → m Bool) : List α → List α → m (List α)
|
||||
|
||||
@@ -57,15 +57,9 @@ theorem eraseP_of_forall_not {l : List α} (h : ∀ a, a ∈ l → ¬p a) : l.er
|
||||
rintro x h' rfl
|
||||
simp_all
|
||||
|
||||
@[deprecated eraseP_eq_nil_iff (since := "2025-01-30")]
|
||||
abbrev eraseP_eq_nil := @eraseP_eq_nil_iff
|
||||
|
||||
theorem eraseP_ne_nil_iff {xs : List α} {p : α → Bool} : xs.eraseP p ≠ [] ↔ xs ≠ [] ∧ ∀ x, p x → xs ≠ [x] := by
|
||||
simp
|
||||
|
||||
@[deprecated eraseP_ne_nil_iff (since := "2025-01-30")]
|
||||
abbrev eraseP_ne_nil := @eraseP_ne_nil_iff
|
||||
|
||||
theorem exists_of_eraseP : ∀ {l : List α} {a} (_ : a ∈ l) (_ : p a),
|
||||
∃ a l₁ l₂, (∀ b ∈ l₁, ¬p b) ∧ p a ∧ l = l₁ ++ a :: l₂ ∧ l.eraseP p = l₁ ++ l₂
|
||||
| b :: l, _, al, pa =>
|
||||
@@ -337,7 +331,7 @@ theorem erase_of_not_mem [LawfulBEq α] {a : α} : ∀ {l : List α}, a ∉ l
|
||||
theorem erase_eq_eraseP' (a : α) (l : List α) : l.erase a = l.eraseP (· == a) := by
|
||||
induction l
|
||||
· simp
|
||||
· next b t ih =>
|
||||
next b t ih =>
|
||||
rw [erase_cons, eraseP_cons, ih]
|
||||
if h : b == a then simp [h] else simp [h]
|
||||
|
||||
@@ -352,17 +346,11 @@ theorem erase_eq_eraseP [LawfulBEq α] (a : α) : ∀ (l : List α), l.erase a =
|
||||
rw [erase_eq_eraseP]
|
||||
simp
|
||||
|
||||
@[deprecated erase_eq_nil_iff (since := "2025-01-30")]
|
||||
abbrev erase_eq_nil := @erase_eq_nil_iff
|
||||
|
||||
theorem erase_ne_nil_iff [LawfulBEq α] {xs : List α} {a : α} :
|
||||
xs.erase a ≠ [] ↔ xs ≠ [] ∧ xs ≠ [a] := by
|
||||
rw [erase_eq_eraseP]
|
||||
simp
|
||||
|
||||
@[deprecated erase_ne_nil_iff (since := "2025-01-30")]
|
||||
abbrev erase_ne_nil := @erase_ne_nil_iff
|
||||
|
||||
theorem exists_erase_eq [LawfulBEq α] {a : α} {l : List α} (h : a ∈ l) :
|
||||
∃ l₁ l₂, a ∉ l₁ ∧ l = l₁ ++ a :: l₂ ∧ l.erase a = l₁ ++ l₂ := by
|
||||
let ⟨_, l₁, l₂, h₁, e, h₂, h₃⟩ := exists_of_eraseP h (beq_self_eq_true _)
|
||||
@@ -439,7 +427,7 @@ theorem erase_append_left [LawfulBEq α] {l₁ : List α} (l₂) (h : a ∈ l₁
|
||||
theorem erase_append_right [LawfulBEq α] {a : α} {l₁ : List α} (l₂ : List α) (h : a ∉ l₁) :
|
||||
(l₁ ++ l₂).erase a = (l₁ ++ l₂.erase a) := by
|
||||
rw [erase_eq_eraseP, erase_eq_eraseP, eraseP_append_right]
|
||||
intros b h' h''; rw [eq_of_beq h''] at h; exact h h'
|
||||
intro b h' h''; rw [eq_of_beq h''] at h; exact h h'
|
||||
|
||||
@[grind =]
|
||||
theorem erase_append [LawfulBEq α] {a : α} {l₁ l₂ : List α} :
|
||||
@@ -582,8 +570,7 @@ theorem eraseIdx_eq_take_drop_succ :
|
||||
| a::l, 0
|
||||
| a::l, i + 1 => simp
|
||||
|
||||
@[deprecated eraseIdx_eq_nil_iff (since := "2025-01-30")]
|
||||
abbrev eraseIdx_eq_nil := @eraseIdx_eq_nil_iff
|
||||
|
||||
|
||||
theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2 ≤ l.length ∨ (l.length = 1 ∧ i ≠ 0) := by
|
||||
match l with
|
||||
@@ -591,8 +578,7 @@ theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2
|
||||
| [a]
|
||||
| a::b::l => simp
|
||||
|
||||
@[deprecated eraseIdx_ne_nil_iff (since := "2025-01-30")]
|
||||
abbrev eraseIdx_ne_nil := @eraseIdx_ne_nil_iff
|
||||
|
||||
|
||||
@[grind]
|
||||
theorem eraseIdx_sublist : ∀ (l : List α) (k : Nat), eraseIdx l k <+ l
|
||||
@@ -700,7 +686,6 @@ theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α]
|
||||
rw [eq_comm, eraseIdx_eq_self]
|
||||
exact Nat.le_of_eq (idxOf_eq_length h).symm
|
||||
|
||||
@[deprecated erase_eq_eraseIdx_of_idxOf (since := "2025-01-29")]
|
||||
abbrev erase_eq_eraseIdx_of_indexOf := @erase_eq_eraseIdx_of_idxOf
|
||||
|
||||
|
||||
end List
|
||||
|
||||
@@ -46,7 +46,7 @@ theorem finRange_succ_last {n} :
|
||||
getElem_map, Fin.castSucc_mk, getElem_singleton]
|
||||
split
|
||||
· rfl
|
||||
· next h => exact Fin.eq_last_of_not_lt h
|
||||
next h => exact Fin.eq_last_of_not_lt h
|
||||
|
||||
@[grind _=_]
|
||||
theorem finRange_reverse {n} : (finRange n).reverse = (finRange n).map Fin.rev := by
|
||||
|
||||
@@ -1098,15 +1098,9 @@ theorem idxOf_cons [BEq α] :
|
||||
dsimp [idxOf]
|
||||
simp [findIdx_cons]
|
||||
|
||||
@[deprecated idxOf_cons (since := "2025-01-29")]
|
||||
abbrev indexOf_cons := @idxOf_cons
|
||||
|
||||
@[simp] theorem idxOf_cons_self [BEq α] [ReflBEq α] {l : List α} : (a :: l).idxOf a = 0 := by
|
||||
simp [idxOf_cons]
|
||||
|
||||
@[deprecated idxOf_cons_self (since := "2025-01-29")]
|
||||
abbrev indexOf_cons_self := @idxOf_cons_self
|
||||
|
||||
@[grind =]
|
||||
theorem idxOf_append [BEq α] [LawfulBEq α] {l₁ l₂ : List α} {a : α} :
|
||||
(l₁ ++ l₂).idxOf a = if a ∈ l₁ then l₁.idxOf a else l₂.idxOf a + l₁.length := by
|
||||
@@ -1117,8 +1111,7 @@ theorem idxOf_append [BEq α] [LawfulBEq α] {l₁ l₂ : List α} {a : α} :
|
||||
· rw [if_neg]
|
||||
simpa using h
|
||||
|
||||
@[deprecated idxOf_append (since := "2025-01-29")]
|
||||
abbrev indexOf_append := @idxOf_append
|
||||
|
||||
|
||||
theorem idxOf_eq_length [BEq α] [LawfulBEq α] {l : List α} (h : a ∉ l) : l.idxOf a = l.length := by
|
||||
induction l with
|
||||
@@ -1128,8 +1121,7 @@ theorem idxOf_eq_length [BEq α] [LawfulBEq α] {l : List α} (h : a ∉ l) : l.
|
||||
simp only [idxOf_cons, cond_eq_if, beq_iff_eq]
|
||||
split <;> simp_all
|
||||
|
||||
@[deprecated idxOf_eq_length (since := "2025-01-29")]
|
||||
abbrev indexOf_eq_length := @idxOf_eq_length
|
||||
|
||||
|
||||
theorem idxOf_lt_length_of_mem [BEq α] [EquivBEq α] {l : List α} (h : a ∈ l) : l.idxOf a < l.length := by
|
||||
induction l with
|
||||
@@ -1159,8 +1151,7 @@ theorem idxOf_lt_length_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
|
||||
grind_pattern idxOf_lt_length_iff => l.idxOf a, l.length
|
||||
|
||||
@[deprecated idxOf_lt_length_of_mem (since := "2025-01-29")]
|
||||
abbrev indexOf_lt_length := @idxOf_lt_length_of_mem
|
||||
|
||||
|
||||
/-! ### finIdxOf?
|
||||
|
||||
@@ -1231,8 +1222,7 @@ The lemmas below should be made consistent with those for `findIdx?` (and proved
|
||||
· rintro w x h rfl
|
||||
contradiction
|
||||
|
||||
@[deprecated idxOf?_eq_none_iff (since := "2025-01-29")]
|
||||
abbrev indexOf?_eq_none_iff := @idxOf?_eq_none_iff
|
||||
|
||||
|
||||
@[simp, grind =]
|
||||
theorem isSome_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
@@ -1251,9 +1241,9 @@ theorem isNone_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
/-! ### lookup -/
|
||||
|
||||
section lookup
|
||||
variable [BEq α] [LawfulBEq α]
|
||||
variable [BEq α]
|
||||
|
||||
@[simp] theorem lookup_cons_self {k : α} : ((k,b) :: es).lookup k = some b := by
|
||||
@[simp] theorem lookup_cons_self [ReflBEq α] {k : α} : ((k,b) :: es).lookup k = some b := by
|
||||
simp [lookup_cons]
|
||||
|
||||
@[simp] theorem lookup_singleton {a b : α} : [(a,b)].lookup c = if c == a then some b else none := by
|
||||
@@ -1272,13 +1262,13 @@ theorem lookup_eq_findSome? {l : List (α × β)} {k : α} :
|
||||
|
||||
@[simp, grind =] theorem lookup_eq_none_iff {l : List (α × β)} {k : α} :
|
||||
l.lookup k = none ↔ ∀ p ∈ l, k != p.1 := by
|
||||
simp [lookup_eq_findSome?]
|
||||
simp [lookup_eq_findSome?, bne]
|
||||
|
||||
@[simp] theorem lookup_isSome_iff {l : List (α × β)} {k : α} :
|
||||
(l.lookup k).isSome ↔ ∃ p ∈ l, k == p.1 := by
|
||||
simp [lookup_eq_findSome?]
|
||||
|
||||
theorem lookup_eq_some_iff {l : List (α × β)} {k : α} {b : β} :
|
||||
theorem lookup_eq_some_iff [LawfulBEq α] {l : List (α × β)} {k : α} {b : β} :
|
||||
l.lookup k = some b ↔ ∃ l₁ l₂, l = l₁ ++ (k, b) :: l₂ ∧ ∀ p ∈ l₁, k != p.1 := by
|
||||
simp only [lookup_eq_findSome?, findSome?_eq_some_iff]
|
||||
constructor
|
||||
@@ -1308,11 +1298,11 @@ theorem lookup_replicate_of_pos {k : α} (h : 0 < n) :
|
||||
(replicate n (a, b)).lookup k = if k == a then some b else none := by
|
||||
simp [lookup_replicate, Nat.ne_of_gt h]
|
||||
|
||||
theorem lookup_replicate_self {a : α} :
|
||||
theorem lookup_replicate_self [ReflBEq α] {a : α} :
|
||||
(replicate n (a, b)).lookup a = if n = 0 then none else some b := by
|
||||
simp [lookup_replicate]
|
||||
|
||||
@[simp] theorem lookup_replicate_self_of_pos {a : α} (h : 0 < n) :
|
||||
@[simp] theorem lookup_replicate_self_of_pos [ReflBEq α] {a : α} (h : 0 < n) :
|
||||
(replicate n (a, b)).lookup a = some b := by
|
||||
simp [lookup_replicate_self, Nat.ne_of_gt h]
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ Example:
|
||||
[10, 14, 14]
|
||||
```
|
||||
-/
|
||||
@[inline] def filterMapTR (f : α → Option β) (l : List α) : List β := go l #[] where
|
||||
@[inline, expose] def filterMapTR (f : α → Option β) (l : List α) : List β := go l #[] where
|
||||
/-- Auxiliary for `filterMap`: `filterMap.go f l = acc.toList ++ filterMap f l` -/
|
||||
@[specialize] go : List α → Array β → List β
|
||||
| [], acc => acc.toList
|
||||
@@ -367,7 +367,7 @@ def modifyTR (l : List α) (i : Nat) (f : α → α) : List α := go l i #[] whe
|
||||
| a :: l, 0, acc => acc.toListAppend (f a :: l)
|
||||
| a :: l, i+1, acc => go l i (acc.push a)
|
||||
|
||||
theorem modifyTR_go_eq : ∀ l i, modifyTR.go f l i acc = acc.toList ++ modify l i f
|
||||
private theorem modifyTR_go_eq : ∀ l i, modifyTR.go f l i acc = acc.toList ++ modify l i f
|
||||
| [], i => by cases i <;> simp [modifyTR.go, modify]
|
||||
| a :: l, 0 => by simp [modifyTR.go, modify]
|
||||
| a :: l, i+1 => by simp [modifyTR.go, modify, modifyTR_go_eq l]
|
||||
@@ -399,7 +399,7 @@ Examples:
|
||||
| _, [], acc => acc.toList
|
||||
| n+1, a :: l, acc => go n l (acc.push a)
|
||||
|
||||
theorem insertIdxTR_go_eq : ∀ i l, insertIdxTR.go a i l acc = acc.toList ++ insertIdx l i a
|
||||
private theorem insertIdxTR_go_eq : ∀ i l, insertIdxTR.go a i l acc = acc.toList ++ insertIdx l i a
|
||||
| 0, l | _+1, [] => by simp [insertIdxTR.go, insertIdx]
|
||||
| n+1, a :: l => by simp [insertIdxTR.go, insertIdx, insertIdxTR_go_eq n l]
|
||||
|
||||
@@ -564,24 +564,7 @@ def zipIdxTR (l : List α) (n : Nat := 0) : List (α × Nat) :=
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
/-- Tail recursive version of `List.enumFrom`. -/
|
||||
@[deprecated zipIdxTR (since := "2025-01-21")]
|
||||
def enumFromTR (n : Nat) (l : List α) : List (Nat × α) :=
|
||||
let as := l.toArray
|
||||
(as.foldr (fun a (n, acc) => (n-1, (n-1, a) :: acc)) (n + as.size, [])).2
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated zipIdx_eq_zipIdxTR (since := "2025-01-21"), csimp]
|
||||
theorem enumFrom_eq_enumFromTR : @enumFrom = @enumFromTR := by
|
||||
funext α n l; simp only [enumFromTR]
|
||||
let f := fun (a : α) (n, acc) => (n-1, (n-1, a) :: acc)
|
||||
let rec go : ∀ l n, l.foldr f (n + l.length, []) = (n, enumFrom n l)
|
||||
| [], n => rfl
|
||||
| a::as, n => by
|
||||
rw [← show _ + as.length = n + (a::as).length from Nat.succ_add .., foldr, go as]
|
||||
simp [enumFrom, f]
|
||||
rw [← Array.foldr_toList]
|
||||
simp +zetaDelta [go]
|
||||
|
||||
/-! ## Other list operations -/
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ See also
|
||||
|
||||
Further results, which first require developing further automation around `Nat`, appear in
|
||||
* `Init.Data.List.Nat.Basic`: miscellaneous lemmas
|
||||
* `Init.Data.List.Nat.Range`: `List.range` and `List.enum`
|
||||
* `Init.Data.List.Nat.Range`: `List.range`, `List.range'` and `List.enum`
|
||||
* `Init.Data.List.Nat.TakeDrop`: `List.take` and `List.drop`
|
||||
|
||||
Also
|
||||
@@ -1084,6 +1084,12 @@ theorem getLast?_tail {l : List α} : (tail l).getLast? = if l.length = 1 then n
|
||||
rw [if_neg]
|
||||
rintro ⟨⟩
|
||||
|
||||
@[simp, grind =]
|
||||
theorem cons_head_tail (h : l ≠ []) : l.head h :: l.tail = l := by
|
||||
induction l with
|
||||
| nil => contradiction
|
||||
| cons ih => simp_all
|
||||
|
||||
/-! ## Basic operations -/
|
||||
|
||||
/-! ### map -/
|
||||
@@ -1429,12 +1435,12 @@ theorem filterMap_eq_map {f : α → β} : filterMap (some ∘ f) = map f := by
|
||||
theorem filterMap_eq_map' {f : α → β} : filterMap (fun x => some (f x)) = map f :=
|
||||
filterMap_eq_map
|
||||
|
||||
@[simp] theorem filterMap_some_fun : filterMap (some : α → Option α) = id := by
|
||||
theorem filterMap_some_fun : filterMap (some : α → Option α) = id := by
|
||||
funext l
|
||||
erw [filterMap_eq_map]
|
||||
simp
|
||||
|
||||
@[grind] theorem filterMap_some {l : List α} : filterMap some l = l := by
|
||||
@[simp, grind] theorem filterMap_some {l : List α} : filterMap some l = l := by
|
||||
rw [filterMap_some_fun, id]
|
||||
|
||||
theorem map_filterMap_some_eq_filter_map_isSome {f : α → Option β} {l : List α} :
|
||||
@@ -1586,9 +1592,7 @@ theorem filterMap_eq_cons_iff {l} {b} {bs} :
|
||||
theorem not_mem_append {a : α} {s t : List α} (h₁ : a ∉ s) (h₂ : a ∉ t) : a ∉ s ++ t :=
|
||||
mt mem_append.1 $ not_or.mpr ⟨h₁, h₂⟩
|
||||
|
||||
@[deprecated mem_append (since := "2025-01-13")]
|
||||
theorem mem_append_eq {a : α} {s t : List α} : (a ∈ s ++ t) = (a ∈ s ∨ a ∈ t) :=
|
||||
propext mem_append
|
||||
|
||||
|
||||
/--
|
||||
See also `eq_append_cons_of_mem`, which proves a stronger version
|
||||
@@ -1698,7 +1702,7 @@ theorem getLast_concat {a : α} : ∀ {l : List α}, getLast (l ++ [a]) (by simp
|
||||
@[simp] theorem append_eq_nil_iff : p ++ q = [] ↔ p = [] ∧ q = [] := by
|
||||
cases p <;> simp
|
||||
|
||||
@[deprecated append_eq_nil_iff (since := "2025-01-13")] abbrev append_eq_nil := @append_eq_nil_iff
|
||||
|
||||
|
||||
theorem nil_eq_append_iff : [] = a ++ b ↔ a = [] ∧ b = [] := by
|
||||
simp
|
||||
@@ -1849,6 +1853,14 @@ theorem append_eq_map_iff {f : α → β} :
|
||||
L₁ ++ L₂ = map f l ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ map f l₁ = L₁ ∧ map f l₂ = L₂ := by
|
||||
rw [eq_comm, map_eq_append_iff]
|
||||
|
||||
@[simp, grind =]
|
||||
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.
|
||||
@@ -2148,7 +2160,7 @@ theorem flatMap_eq_foldl {f : α → List β} {l : List α} :
|
||||
intro l'
|
||||
induction l generalizing l'
|
||||
· simp
|
||||
· next ih => rw [flatMap_cons, ← append_assoc, ih, foldl_cons]
|
||||
next ih => rw [flatMap_cons, ← append_assoc, ih, foldl_cons]
|
||||
|
||||
/-! ### replicate -/
|
||||
|
||||
@@ -2264,8 +2276,7 @@ theorem map_const' {l : List α} {b : β} : map (fun _ => b) l = replicate l.len
|
||||
simp only [mem_append, mem_replicate, ne_eq]
|
||||
rintro (⟨-, rfl⟩ | ⟨_, rfl⟩) <;> rfl
|
||||
|
||||
@[deprecated replicate_append_replicate (since := "2025-01-16")]
|
||||
abbrev append_replicate_replicate := @replicate_append_replicate
|
||||
|
||||
|
||||
theorem append_eq_replicate_iff {l₁ l₂ : List α} {a : α} :
|
||||
l₁ ++ l₂ = replicate n a ↔
|
||||
@@ -2653,8 +2664,6 @@ theorem foldl_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
· simp
|
||||
· simp [*]
|
||||
|
||||
@[deprecated foldl_map_hom (since := "2025-01-20")] abbrev foldl_map' := @foldl_map_hom
|
||||
|
||||
theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {l : List α}
|
||||
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
|
||||
(l.map g).foldr f' (g a) = g (l.foldr f a) := by
|
||||
@@ -2662,8 +2671,6 @@ theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
· simp
|
||||
· simp [*]
|
||||
|
||||
@[deprecated foldr_map_hom (since := "2025-01-20")] abbrev foldr_map' := @foldr_map_hom
|
||||
|
||||
@[simp] theorem foldrM_append [Monad m] [LawfulMonad m] {f : α → β → m β} {b : β} {l l' : List α} :
|
||||
(l ++ l').foldrM f b = l'.foldrM f b >>= l.foldrM f := by
|
||||
induction l <;> simp [*]
|
||||
@@ -3731,12 +3738,6 @@ theorem mem_iff_get? {a} {l : List α} : a ∈ l ↔ ∃ n, l.get? n = some a :=
|
||||
|
||||
/-! ### Deprecations -/
|
||||
|
||||
@[deprecated _root_.isSome_getElem? (since := "2024-12-09")]
|
||||
theorem isSome_getElem? {l : List α} {i : Nat} : l[i]?.isSome ↔ i < l.length := by
|
||||
simp
|
||||
|
||||
@[deprecated _root_.isNone_getElem? (since := "2024-12-09")]
|
||||
theorem isNone_getElem? {l : List α} {i : Nat} : l[i]?.isNone ↔ l.length ≤ i := by
|
||||
simp
|
||||
|
||||
end List
|
||||
|
||||
@@ -8,9 +8,13 @@ module
|
||||
prelude
|
||||
public import Init.Data.List.Lemmas
|
||||
public import Init.Data.List.Nat.TakeDrop
|
||||
public import Init.Data.Order.Factories
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
@@ -18,6 +22,11 @@ namespace List
|
||||
|
||||
/-! ### Lexicographic ordering -/
|
||||
|
||||
instance [LT α] [Std.Asymm (α := List α) (· < ·)] : LawfulOrderLT (List α) where
|
||||
lt_iff := by
|
||||
simp only [LE.le, List.le, Classical.not_not, iff_and_self]
|
||||
apply Std.Asymm.asymm
|
||||
|
||||
@[simp] theorem lex_lt [LT α] {l₁ l₂ : List α} : Lex (· < ·) l₁ l₂ ↔ l₁ < l₂ := Iff.rfl
|
||||
@[simp] theorem not_lex_lt [LT α] {l₁ l₂ : List α} : ¬ Lex (· < ·) l₁ l₂ ↔ l₂ ≤ l₁ := Iff.rfl
|
||||
|
||||
@@ -79,7 +88,6 @@ theorem not_cons_lex_cons_iff [DecidableEq α] [DecidableRel r] {a b} {l₁ l₂
|
||||
rw [cons_lex_cons_iff, not_or, Decidable.not_and_iff_or_not, and_or_left]
|
||||
|
||||
theorem cons_le_cons_iff [LT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{a b} {l₁ l₂ : List α} :
|
||||
@@ -101,19 +109,22 @@ theorem cons_le_cons_iff [LT α]
|
||||
exact ⟨i₂.antisymm _ _ h₃ h₁, h₂⟩
|
||||
· rintro (h | ⟨h₁, h₂⟩)
|
||||
· left
|
||||
exact ⟨i₁.asymm _ _ h, fun w => i₀.irrefl _ (w ▸ h)⟩
|
||||
exact ⟨i₁.asymm _ _ h, fun w => Irrefl.irrefl _ (w ▸ h)⟩
|
||||
· right
|
||||
exact ⟨fun w => i₀.irrefl _ (h₁ ▸ w), h₂⟩
|
||||
exact ⟨fun w => Irrefl.irrefl _ (h₁ ▸ w), h₂⟩
|
||||
|
||||
theorem not_lt_of_cons_le_cons [LT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{a b : α} {l₁ l₂ : List α} (h : a :: l₁ ≤ b :: l₂) : ¬ b < a := by
|
||||
rw [cons_le_cons_iff] at h
|
||||
rcases h with h | ⟨rfl, h⟩
|
||||
· exact i₁.asymm _ _ h
|
||||
· exact i₀.irrefl _
|
||||
· exact Irrefl.irrefl _
|
||||
|
||||
theorem left_le_left_of_cons_le_cons [LT α] [LE α] [IsLinearOrder α]
|
||||
[LawfulOrderLT α] {a b : α} {l₁ l₂ : List α} (h : a :: l₁ ≤ b :: l₂) : a ≤ b := by
|
||||
simpa [not_lt] using not_lt_of_cons_le_cons h
|
||||
|
||||
theorem le_of_cons_le_cons [LT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
@@ -163,14 +174,9 @@ instance [LT α] [Trans (· < · : α → α → Prop) (· < ·) (· < ·)] :
|
||||
Trans (· < · : List α → List α → Prop) (· < ·) (· < ·) where
|
||||
trans h₁ h₂ := List.lt_trans h₁ h₂
|
||||
|
||||
@[deprecated List.le_antisymm (since := "2024-12-13")]
|
||||
protected abbrev lt_antisymm := @List.le_antisymm
|
||||
|
||||
protected theorem lt_of_le_of_lt [LT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[i₃ : Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
|
||||
protected theorem lt_of_le_of_lt [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α]
|
||||
{l₁ l₂ l₃ : List α} (h₁ : l₁ ≤ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ := by
|
||||
induction h₂ generalizing l₁ with
|
||||
| nil => simp_all
|
||||
@@ -180,11 +186,8 @@ protected theorem lt_of_le_of_lt [LT α]
|
||||
| nil => simp_all
|
||||
| cons c l₁ =>
|
||||
apply Lex.rel
|
||||
replace h₁ := not_lt_of_cons_le_cons h₁
|
||||
apply Classical.byContradiction
|
||||
intro h₂
|
||||
have := i₃.trans h₁ h₂
|
||||
contradiction
|
||||
replace h₁ := left_le_left_of_cons_le_cons h₁
|
||||
exact lt_of_le_of_lt h₁ hab
|
||||
| cons w₃ ih =>
|
||||
rename_i a as bs
|
||||
cases l₁ with
|
||||
@@ -194,21 +197,34 @@ protected theorem lt_of_le_of_lt [LT α]
|
||||
by_cases w₅ : a = c
|
||||
· subst w₅
|
||||
exact Lex.cons (ih (le_of_cons_le_cons h₁))
|
||||
· exact Lex.rel (Classical.byContradiction fun w₆ => w₅ (i₂.antisymm _ _ w₄ w₆))
|
||||
· simp only [not_lt] at w₄
|
||||
exact Lex.rel (lt_of_le_of_ne w₄ (w₅.imp Eq.symm))
|
||||
|
||||
protected theorem le_trans [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
@[deprecated List.lt_of_le_of_lt (since := "2025-08-01")]
|
||||
protected theorem lt_of_le_of_lt' [LT α]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{l₁ l₂ l₃ : List α} (h₁ : l₁ ≤ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
|
||||
letI : LE α := .ofLT α
|
||||
haveI : IsLinearOrder α := IsLinearOrder.of_lt
|
||||
List.lt_of_le_of_lt h₁ h₂
|
||||
|
||||
protected theorem le_trans [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α]
|
||||
{l₁ l₂ l₃ : List α} (h₁ : l₁ ≤ l₂) (h₂ : l₂ ≤ l₃) : l₁ ≤ l₃ :=
|
||||
fun h₃ => h₁ (List.lt_of_le_of_lt h₂ h₃)
|
||||
|
||||
@[deprecated List.le_trans (since := "2025-08-01")]
|
||||
protected theorem le_trans' [LT α]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{l₁ l₂ l₃ : List α} (h₁ : l₁ ≤ l₂) (h₂ : l₂ ≤ l₃) : l₁ ≤ l₃ :=
|
||||
fun h₃ => h₁ (List.lt_of_le_of_lt h₂ h₃)
|
||||
letI := LE.ofLT α
|
||||
haveI : IsLinearOrder α := IsLinearOrder.of_lt
|
||||
List.le_trans h₁ h₂
|
||||
|
||||
instance [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)] :
|
||||
instance [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α] :
|
||||
Trans (· ≤ · : List α → List α → Prop) (· ≤ ·) (· ≤ ·) where
|
||||
trans h₁ h₂ := List.le_trans h₁ h₂
|
||||
|
||||
@@ -248,14 +264,21 @@ theorem not_lex_total {r : α → α → Prop}
|
||||
obtain (_ | _) := not_lex_total h l₁ l₂ <;> contradiction
|
||||
|
||||
protected theorem le_total [LT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)] (l₁ l₂ : List α) : l₁ ≤ l₂ ∨ l₂ ≤ l₁ :=
|
||||
not_lex_total i.total l₂ l₁
|
||||
[i : Std.Asymm (· < · : α → α → Prop)] (l₁ l₂ : List α) : l₁ ≤ l₂ ∨ l₂ ≤ l₁ :=
|
||||
not_lex_total i.total_not.total l₂ l₁
|
||||
|
||||
instance [LT α]
|
||||
[Std.Total (¬ · < · : α → α → Prop)] :
|
||||
protected theorem le_total_of_asymm [LT α]
|
||||
[i : Std.Asymm (· < · : α → α → Prop)] (l₁ l₂ : List α) : l₁ ≤ l₂ ∨ l₂ ≤ l₁ :=
|
||||
List.le_total l₁ l₂
|
||||
|
||||
instance [LT α] [Std.Asymm (· < · : α → α → Prop)] :
|
||||
Std.Total (· ≤ · : List α → List α → Prop) where
|
||||
total := List.le_total
|
||||
|
||||
@[no_expose]
|
||||
instance instIsLinearOrder [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α] :
|
||||
IsLinearOrder (List α) := IsLinearOrder.of_le
|
||||
|
||||
@[simp] protected theorem not_lt [LT α]
|
||||
{l₁ l₂ : List α} : ¬ l₁ < l₂ ↔ l₂ ≤ l₁ := Iff.rfl
|
||||
|
||||
@@ -263,7 +286,7 @@ instance [LT α]
|
||||
{l₁ l₂ : List α} : ¬ l₂ ≤ l₁ ↔ l₁ < l₂ := Classical.not_not
|
||||
|
||||
protected theorem le_of_lt [LT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)]
|
||||
[i : Std.Asymm (· < · : α → α → Prop)]
|
||||
{l₁ l₂ : List α} (h : l₁ < l₂) : l₁ ≤ l₂ := by
|
||||
obtain (h' | h') := List.le_total l₁ l₂
|
||||
· exact h'
|
||||
@@ -273,7 +296,7 @@ protected theorem le_of_lt [LT α]
|
||||
protected theorem le_iff_lt_or_eq [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Total (¬ · < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
{l₁ l₂ : List α} : l₁ ≤ l₂ ↔ l₁ < l₂ ∨ l₁ = l₂ := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -457,7 +480,6 @@ protected theorem lt_iff_exists [LT α] {l₁ l₂ : List α} :
|
||||
simp
|
||||
|
||||
protected theorem le_iff_exists [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)] {l₁ l₂ : List α} :
|
||||
l₁ ≤ l₂ ↔
|
||||
@@ -481,7 +503,6 @@ theorem append_left_lt [LT α] {l₁ l₂ l₃ : List α} (h : l₂ < l₃) :
|
||||
| cons a l₁ ih => simp [cons_lt_cons_iff, ih]
|
||||
|
||||
theorem append_left_le [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{l₁ l₂ l₃ : List α} (h : l₂ ≤ l₃) :
|
||||
@@ -515,10 +536,8 @@ protected theorem map_lt [LT α] [LT β]
|
||||
simp [cons_lt_cons_iff, w, h]
|
||||
|
||||
protected theorem map_le [LT α] [LT β]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Irrefl (· < · : β → β → Prop)]
|
||||
[Std.Asymm (· < · : β → β → Prop)]
|
||||
[Std.Antisymm (¬ · < · : β → β → Prop)]
|
||||
{l₁ l₂ : List α} {f : α → β} (w : ∀ x y, x < y → f x < f y) (h : l₁ ≤ l₂) :
|
||||
|
||||
@@ -61,7 +61,7 @@ proof that the index is valid.
|
||||
`List.mapIdxM` is a variant that does not provide the function with evidence that the index is
|
||||
valid.
|
||||
-/
|
||||
@[inline] def mapFinIdxM [Monad m] (as : List α) (f : (i : Nat) → α → (h : i < as.length) → m β) : m (List β) :=
|
||||
@[inline, expose] def mapFinIdxM [Monad m] (as : List α) (f : (i : Nat) → α → (h : i < as.length) → m β) : m (List β) :=
|
||||
go as #[] (by simp)
|
||||
where
|
||||
/-- Auxiliary for `mapFinIdxM`:
|
||||
@@ -78,7 +78,7 @@ found, returning the list of results.
|
||||
`List.mapFinIdxM` is a variant that additionally provides the function with a proof that the index
|
||||
is valid.
|
||||
-/
|
||||
@[inline] def mapIdxM [Monad m] (f : Nat → α → m β) (as : List α) : m (List β) := go as #[] where
|
||||
@[inline, expose] def mapIdxM [Monad m] (f : Nat → α → m β) (as : List α) : m (List β) := go as #[] where
|
||||
/-- Auxiliary for `mapIdxM`:
|
||||
`mapIdxM.go [a₀, a₁, ...] acc = acc.toList ++ [f acc.size a₀, f (acc.size + 1) a₁, ...]` -/
|
||||
@[specialize] go : List α → Array β → m (List β)
|
||||
@@ -182,8 +182,7 @@ theorem mapFinIdx_eq_zipIdx_map {l : List α} {f : (i : Nat) → α → (h : i <
|
||||
f i x (by rw [mk_mem_zipIdx_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1) := by
|
||||
apply ext_getElem <;> simp
|
||||
|
||||
@[deprecated mapFinIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapFinIdx_eq_zipWithIndex_map := @mapFinIdx_eq_zipIdx_map
|
||||
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_eq_nil_iff {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
@@ -220,7 +219,7 @@ theorem mapFinIdx_eq_cons_iff {l : List α} {b : β} {f : (i : Nat) → α → (
|
||||
cases l with
|
||||
| nil => simp
|
||||
| cons x l' =>
|
||||
simp only [mapFinIdx_cons, cons.injEq,
|
||||
simp only [mapFinIdx_cons, cons.injEq,
|
||||
]
|
||||
constructor
|
||||
· rintro ⟨rfl, rfl⟩
|
||||
@@ -384,8 +383,7 @@ theorem mapIdx_eq_zipIdx_map {l : List α} {f : Nat → α → β} :
|
||||
simp only [getElem?_mapIdx, Option.map, getElem?_map, getElem?_zipIdx]
|
||||
split <;> simp
|
||||
|
||||
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapIdx_eq_enum_map := @mapIdx_eq_zipIdx_map
|
||||
|
||||
|
||||
@[simp, grind =]
|
||||
theorem mapIdx_cons {l : List α} {a : α} :
|
||||
|
||||
@@ -8,9 +8,14 @@ module
|
||||
prelude
|
||||
public import Init.Data.List.Lemmas
|
||||
public import Init.Data.List.Pairwise
|
||||
public import Init.Data.Order.Factories
|
||||
public import Init.Data.Subtype.Order
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
|
||||
/-!
|
||||
# Lemmas about `List.min?` and `List.max?.
|
||||
-/
|
||||
@@ -55,7 +60,7 @@ theorem min?_eq_head? {α : Type u} [Min α] {l : List α}
|
||||
have hx : min x y = x := rel_of_pairwise_cons h mem_cons_self
|
||||
rw [foldl_cons, ih _ (hx.symm ▸ h.sublist (by simp)), hx]
|
||||
|
||||
theorem min?_mem [Min α] (min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b) :
|
||||
theorem min?_mem [Min α] [MinEqOr α] :
|
||||
{xs : List α} → xs.min? = some a → a ∈ xs := by
|
||||
intro xs
|
||||
match xs with
|
||||
@@ -72,13 +77,10 @@ theorem min?_mem [Min α] (min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b
|
||||
have p := ind _ eq
|
||||
cases p with
|
||||
| inl p =>
|
||||
cases min_eq_or x y with | _ q => simp [p, q]
|
||||
cases MinEqOr.min_eq_or x y with | _ q => simp [p, q]
|
||||
| inr p => simp [p, mem_cons]
|
||||
|
||||
-- See also `Init.Data.List.Nat.Basic` for specialisations of the next two results to `Nat`.
|
||||
|
||||
theorem le_min?_iff [Min α] [LE α]
|
||||
(le_min_iff : ∀ a b c : α, a ≤ min b c ↔ a ≤ b ∧ a ≤ c) :
|
||||
theorem le_min?_iff [Min α] [LE α] [LawfulOrderInf α] :
|
||||
{xs : List α} → xs.min? = some a → ∀ {x}, x ≤ a ↔ ∀ b, b ∈ xs → x ≤ b
|
||||
| nil => by simp
|
||||
| cons x xs => by
|
||||
@@ -93,34 +95,64 @@ theorem le_min?_iff [Min α] [LE α]
|
||||
simp at eq
|
||||
simp [ih _ eq, le_min_iff, and_assoc]
|
||||
|
||||
-- This could be refactored by designing appropriate typeclasses to replace `le_refl`, `min_eq_or`,
|
||||
-- and `le_min_iff`.
|
||||
theorem min?_eq_some_iff [Min α] [LE α]
|
||||
(le_refl : ∀ a : α, a ≤ a)
|
||||
(min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b)
|
||||
(le_min_iff : ∀ a b c : α, a ≤ min b c ↔ a ≤ b ∧ a ≤ c) {xs : List α}
|
||||
(anti : ∀ a b, a ∈ xs → b ∈ xs → a ≤ b → b ≤ a → a = b := by
|
||||
exact fun a b _ _ => Std.Antisymm.antisymm a b) :
|
||||
theorem min?_eq_some_iff [Min α] [LE α] {xs : List α} [IsLinearOrder α] [LawfulOrderMin α] :
|
||||
xs.min? = some a ↔ a ∈ xs ∧ ∀ b, b ∈ xs → a ≤ b := by
|
||||
refine ⟨fun h => ⟨min?_mem min_eq_or h, (le_min?_iff le_min_iff h).1 (le_refl _)⟩, ?_⟩
|
||||
refine ⟨fun h => ⟨min?_mem h, (le_min?_iff h).1 (le_refl _)⟩, ?_⟩
|
||||
intro ⟨h₁, h₂⟩
|
||||
cases xs with
|
||||
| nil => simp at h₁
|
||||
| cons x xs =>
|
||||
exact congrArg some <| anti _ _ (min?_mem min_eq_or rfl) h₁
|
||||
((le_min?_iff le_min_iff (xs := x::xs) rfl).1 (le_refl _) _ h₁)
|
||||
(h₂ _ (min?_mem min_eq_or (xs := x::xs) rfl))
|
||||
rw [List.min?]
|
||||
exact congrArg some <| le_antisymm
|
||||
((le_min?_iff (xs := x :: xs) rfl).1 (le_refl _) _ h₁)
|
||||
(h₂ _ (min?_mem (xs := x :: xs) rfl))
|
||||
|
||||
theorem min?_replicate [Min α] {n : Nat} {a : α} (w : min a a = a) :
|
||||
private theorem min?_attach [Min α] [MinEqOr α] {xs : List α} :
|
||||
xs.attach.min? = (xs.min?.pmap (fun m hm => ⟨m, min?_mem hm⟩) (fun _ => id)) := by
|
||||
cases xs with
|
||||
| nil => simp
|
||||
| cons x xs =>
|
||||
simp only [min?, attach_cons, Option.some.injEq, Option.pmap_some]
|
||||
rw [foldl_map]
|
||||
simp only [Subtype.ext_iff]
|
||||
rw [← foldl_attach (l := xs)]
|
||||
apply Eq.trans (foldl_hom (f := Subtype.val) ?_).symm
|
||||
· rfl
|
||||
· intros; rfl
|
||||
|
||||
theorem min?_eq_min?_attach [Min α] [MinEqOr α] {xs : List α} :
|
||||
xs.min? = (xs.attach.min?.map Subtype.val) := by
|
||||
simp [min?_attach, Option.map_pmap]
|
||||
|
||||
theorem min?_eq_some_iff_subtype [Min α] [LE α] {xs : List α}
|
||||
[MinEqOr α] [IsLinearOrder (Subtype (· ∈ xs))] [LawfulOrderMin (Subtype (· ∈ xs))] :
|
||||
xs.min? = some a ↔ a ∈ xs ∧ ∀ b, b ∈ xs → a ≤ b := by
|
||||
have := fun a => min?_eq_some_iff (xs := xs.attach) (a := a)
|
||||
rw [min?_eq_min?_attach]
|
||||
simp [min?_eq_some_iff]
|
||||
constructor
|
||||
· rintro ⟨ha, h⟩
|
||||
exact ⟨ha, h⟩
|
||||
· rintro ⟨ha, h⟩
|
||||
exact ⟨ha, h⟩
|
||||
|
||||
theorem min?_replicate [Min α] [Std.IdempotentOp (min : α → α → α)] {n : Nat} {a : α} :
|
||||
(replicate n a).min? = if n = 0 then none else some a := by
|
||||
induction n with
|
||||
| zero => rfl
|
||||
| succ n ih => cases n <;> simp_all [replicate_succ, min?_cons']
|
||||
| succ n ih => cases n <;> simp_all [replicate_succ, min?_cons', Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp] theorem min?_replicate_of_pos [Min α] {n : Nat} {a : α} (w : min a a = a) (h : 0 < n) :
|
||||
@[simp] theorem min?_replicate_of_pos [Min α] [MinEqOr α] {n : Nat} {a : α} (h : 0 < n) :
|
||||
(replicate n a).min? = some a := by
|
||||
simp [min?_replicate, Nat.ne_of_gt h, w]
|
||||
simp [min?_replicate, Nat.ne_of_gt h]
|
||||
|
||||
/--
|
||||
This lemma is also applicable given the following instances:
|
||||
|
||||
```
|
||||
[LE α] [Min α] [IsLinearOrder α] [LawfulOrderMin α]
|
||||
```
|
||||
-/
|
||||
theorem foldl_min [Min α] [Std.IdempotentOp (min : α → α → α)] [Std.Associative (min : α → α → α)]
|
||||
{l : List α} {a : α} : l.foldl (init := a) min = min a (l.min?.getD a) := by
|
||||
cases l <;> simp [min?, foldl_assoc, Std.IdempotentOp.idempotent]
|
||||
@@ -144,54 +176,124 @@ theorem isSome_max?_of_mem {l : List α} [Max α] {a : α} (h : a ∈ l) :
|
||||
l.max?.isSome := by
|
||||
cases l <;> simp_all [max?_cons']
|
||||
|
||||
theorem max?_mem [Max α] (min_eq_or : ∀ a b : α, max a b = a ∨ max a b = b) :
|
||||
{xs : List α} → xs.max? = some a → a ∈ xs
|
||||
| nil => by simp
|
||||
| cons x xs => by
|
||||
rw [max?]; rintro ⟨⟩
|
||||
induction xs generalizing x with simp at *
|
||||
| cons y xs ih =>
|
||||
rcases ih (max x y) with h | h <;> simp [h]
|
||||
simp [← or_assoc, min_eq_or x y]
|
||||
|
||||
-- See also `Init.Data.List.Nat.Basic` for specialisations of the next two results to `Nat`.
|
||||
|
||||
theorem max?_le_iff [Max α] [LE α]
|
||||
(max_le_iff : ∀ a b c : α, max b c ≤ a ↔ b ≤ a ∧ c ≤ a) :
|
||||
{xs : List α} → xs.max? = some a → ∀ {x}, a ≤ x ↔ ∀ b ∈ xs, b ≤ x
|
||||
| nil => by simp
|
||||
| cons x xs => by
|
||||
rw [max?]; rintro ⟨⟩ y
|
||||
induction xs generalizing x with
|
||||
theorem max?_eq_head? {α : Type u} [Max α] {l : List α}
|
||||
(h : l.Pairwise (fun a b => max a b = a)) : l.max? = l.head? := by
|
||||
cases l with
|
||||
| nil => rfl
|
||||
| cons x l =>
|
||||
rw [head?_cons, max?_cons', Option.some.injEq]
|
||||
induction l generalizing x with
|
||||
| nil => simp
|
||||
| cons y xs ih => simp [ih, max_le_iff, and_assoc]
|
||||
| cons y l ih =>
|
||||
have hx : max x y = x := rel_of_pairwise_cons h mem_cons_self
|
||||
rw [foldl_cons, ih _ (hx.symm ▸ h.sublist (by simp)), hx]
|
||||
|
||||
-- This could be refactored by designing appropriate typeclasses to replace `le_refl`, `max_eq_or`,
|
||||
-- and `le_min_iff`.
|
||||
theorem max?_eq_some_iff [Max α] [LE α] [anti : Std.Antisymm (· ≤ · : α → α → Prop)]
|
||||
(le_refl : ∀ a : α, a ≤ a)
|
||||
(max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b)
|
||||
(max_le_iff : ∀ a b c : α, max b c ≤ a ↔ b ≤ a ∧ c ≤ a) {xs : List α} :
|
||||
xs.max? = some a ↔ a ∈ xs ∧ ∀ b ∈ xs, b ≤ a := by
|
||||
refine ⟨fun h => ⟨max?_mem max_eq_or h, (max?_le_iff max_le_iff h).1 (le_refl _)⟩, ?_⟩
|
||||
theorem max?_mem [Max α] [MaxEqOr α] :
|
||||
{xs : List α} → xs.max? = some a → a ∈ xs := by
|
||||
intro xs
|
||||
match xs with
|
||||
| nil => simp
|
||||
| x :: xs =>
|
||||
simp only [max?_cons', Option.some.injEq, mem_cons]
|
||||
intro eq
|
||||
induction xs generalizing x with
|
||||
| nil =>
|
||||
simp at eq
|
||||
simp [eq]
|
||||
| cons y xs ind =>
|
||||
simp at eq
|
||||
have p := ind _ eq
|
||||
cases p with
|
||||
| inl p =>
|
||||
cases MaxEqOr.max_eq_or x y with | _ q => simp [p, q]
|
||||
| inr p => simp [p, mem_cons]
|
||||
|
||||
theorem max?_le_iff [Max α] [LE α] [LawfulOrderSup α] :
|
||||
{xs : List α} → xs.max? = some a → ∀ {x}, a ≤ x ↔ ∀ b, b ∈ xs → b ≤ x
|
||||
| nil => by simp
|
||||
| cons x xs => by
|
||||
rw [max?]
|
||||
intro eq y
|
||||
simp only [Option.some.injEq] at eq
|
||||
induction xs generalizing x with
|
||||
| nil =>
|
||||
simp at eq
|
||||
simp [eq]
|
||||
| cons z xs ih =>
|
||||
simp at eq
|
||||
simp [ih _ eq, max_le_iff, and_assoc]
|
||||
|
||||
theorem max?_eq_some_iff [Max α] [LE α] {xs : List α} [IsLinearOrder (α)]
|
||||
[LawfulOrderMax α] : xs.max? = some a ↔ a ∈ xs ∧ ∀ b, b ∈ xs → b ≤ a := by
|
||||
refine ⟨fun h => ⟨max?_mem h, (max?_le_iff h).1 (le_refl _)⟩, ?_⟩
|
||||
intro ⟨h₁, h₂⟩
|
||||
cases xs with
|
||||
| nil => simp at h₁
|
||||
| cons x xs =>
|
||||
exact congrArg some <| anti.1 _ _
|
||||
(h₂ _ (max?_mem max_eq_or (xs := x::xs) rfl))
|
||||
((max?_le_iff max_le_iff (xs := x::xs) rfl).1 (le_refl _) _ h₁)
|
||||
rw [List.max?]
|
||||
exact congrArg some <| le_antisymm
|
||||
(h₂ _ (max?_mem (xs := x :: xs) rfl))
|
||||
((max?_le_iff (xs := x :: xs) rfl).1 (le_refl _) _ h₁)
|
||||
|
||||
theorem max?_replicate [Max α] {n : Nat} {a : α} (w : max a a = a) :
|
||||
private theorem max?_attach [Max α] [MaxEqOr α] {xs : List α} :
|
||||
xs.attach.max? = (xs.max?.pmap (fun m hm => ⟨m, max?_mem hm⟩) (fun _ => id)) := by
|
||||
cases xs with
|
||||
| nil => simp
|
||||
| cons x xs =>
|
||||
simp only [max?, attach_cons, Option.some.injEq, Option.pmap_some]
|
||||
rw [foldl_map]
|
||||
simp only [Subtype.ext_iff]
|
||||
rw [← foldl_attach (l := xs)]
|
||||
apply Eq.trans (foldl_hom (f := Subtype.val) ?_).symm
|
||||
· rfl
|
||||
· intros; rfl
|
||||
|
||||
theorem max?_eq_max?_attach [Max α] [MaxEqOr α] {xs : List α} :
|
||||
xs.max? = (xs.attach.max?.map Subtype.val) := by
|
||||
simp [max?_attach, Option.map_pmap]
|
||||
|
||||
theorem max?_eq_some_iff_subtype [Max α] [LE α] {xs : List α}
|
||||
[MaxEqOr α] [IsLinearOrder (Subtype (· ∈ xs))]
|
||||
[LawfulOrderMax (Subtype (· ∈ xs))] :
|
||||
xs.max? = some a ↔ a ∈ xs ∧ ∀ b, b ∈ xs → b ≤ a := by
|
||||
have := fun a => max?_eq_some_iff (xs := xs.attach) (a := a)
|
||||
rw [max?_eq_max?_attach]
|
||||
simp [max?_eq_some_iff]
|
||||
constructor
|
||||
· rintro ⟨ha, h⟩
|
||||
exact ⟨ha, h⟩
|
||||
· rintro ⟨ha, h⟩
|
||||
exact ⟨ha, h⟩
|
||||
|
||||
@[deprecated max?_eq_some_iff (since := "2025-08-01")]
|
||||
theorem max?_eq_some_iff_legacy [Max α] [LE α] [anti : Std.Antisymm (· ≤ · : α → α → Prop)]
|
||||
(le_refl : ∀ a : α, a ≤ a)
|
||||
(max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b)
|
||||
(max_le_iff : ∀ a b c : α, max b c ≤ a ↔ b ≤ a ∧ c ≤ a) {xs : List α} :
|
||||
xs.max? = some a ↔ a ∈ xs ∧ ∀ b ∈ xs, b ≤ a := by
|
||||
haveI : MaxEqOr α := ⟨max_eq_or⟩
|
||||
haveI : LawfulOrderMax α := .of_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]
|
||||
|
||||
@@ -101,7 +101,7 @@ theorem mapM_eq_reverse_foldlM_cons [Monad m] [LawfulMonad m] {f : α → m β}
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
simp only [mapM'_cons, ih, bind_map_left, foldlM_cons,
|
||||
simp only [mapM'_cons, ih, bind_map_left, foldlM_cons,
|
||||
foldlM_cons_eq_append, _root_.map_bind, Functor.map_map, reverse_append,
|
||||
reverse_cons, reverse_nil, nil_append, singleton_append]
|
||||
simp [bind_pure_comp]
|
||||
@@ -137,6 +137,43 @@ theorem filterMapM_loop_eq [Monad m] [LawfulMonad m] {f : α → m (Option β)}
|
||||
rw [filterMapM_loop_eq, filterMapM]
|
||||
simp
|
||||
|
||||
/-! ### zipWithM -/
|
||||
|
||||
/--
|
||||
Applies the monadic action `f` to the corresponding elements of two lists, left-to-right, stopping
|
||||
at the end of the shorter list. `zipWithM' f as bs` is equivalent to `mapM id (zipWith f as bs)`
|
||||
for lawful `Monad` instances.
|
||||
-/
|
||||
@[expose]
|
||||
def zipWithM' {m : Type u → Type v} [Monad m] {α : Type w} {β : Type x} {γ : Type u} (f : α → β → m γ) : (xs : List α) → (ys : List β) → m (List γ)
|
||||
| x::xs, y::ys => do
|
||||
let z ← f x y
|
||||
let zs ← zipWithM' f xs ys
|
||||
pure (z :: zs)
|
||||
| _, _ => pure []
|
||||
|
||||
@[simp, grind =] theorem zipWithM'_nil_left [Monad m] {f : α → β → m γ} : zipWithM' f [] l = pure (f := m) [] := by simp only [zipWithM']
|
||||
@[simp, grind =] theorem zipWithM'_nil_right [Monad m] {f : α → β → m γ} : zipWithM' f l [] = pure (f := m) [] := by simp only [zipWithM']
|
||||
@[simp, grind =] theorem zipWithM'_cons_cons [Monad m] {f : α → β → m γ} :
|
||||
zipWithM' f (a :: as) (b :: bs) = do return (← f a b) :: (← zipWithM' f as bs) := by simp only [zipWithM']
|
||||
|
||||
@[grind =]
|
||||
theorem zipWithM'_eq_zipWithM [Monad m] [LawfulMonad m] {f : α → β → m γ} {l : List α} {l' : List β} :
|
||||
zipWithM' f l l' = zipWithM f l l' := by simp [zipWithM, go l l' #[]] where
|
||||
go l l' acc : zipWithM.loop f l l' acc = return acc.toList ++ (← zipWithM' f l l') := by
|
||||
fun_induction zipWithM.loop <;> simp [zipWithM', *]
|
||||
|
||||
@[simp, grind =] theorem zipWithM_nil_left [Monad m] {f : α → β → m γ} : zipWithM f [] l = pure (f := m) [] := rfl
|
||||
@[simp, grind =] theorem zipWithM_nil_right [Monad m] {f : α → β → m γ} : zipWithM f l [] = pure (f := m) [] := by simp only [zipWithM, zipWithM.loop]
|
||||
@[simp, grind =] theorem zipWithM_cons_cons [Monad m] [LawfulMonad m] {f : α → β → m γ} :
|
||||
zipWithM f (a :: as) (b :: bs) = do return (← f a b) :: (← zipWithM f as bs) := by
|
||||
simp [← zipWithM'_eq_zipWithM]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem zipWithM'_eq_mapM_id_zipWith {m : Type v → Type w} [Monad m] [LawfulMonad m] {f : α → β → m γ} {as : List α} {bs : List β} :
|
||||
zipWithM' f as bs = mapM id (zipWith f as bs) := by
|
||||
fun_induction zipWithM' <;> simp [zipWith, *]
|
||||
|
||||
/-! ### flatMapM -/
|
||||
|
||||
@[simp, grind =] theorem flatMapM_nil [Monad m] {f : α → m (List β)} : [].flatMapM f = pure [] := rfl
|
||||
@@ -224,13 +261,7 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] {p : α → Bool} {g : α → β
|
||||
|
||||
/-! ### forM -/
|
||||
|
||||
@[deprecated forM_nil (since := "2025-01-31")]
|
||||
theorem forM_nil' [Monad m] : ([] : List α).forM f = (pure .unit : m PUnit) := rfl
|
||||
|
||||
@[deprecated forM_cons (since := "2025-01-31")]
|
||||
theorem forM_cons' [Monad m] :
|
||||
(a::as).forM f = (f a >>= fun _ => as.forM f : m PUnit) :=
|
||||
List.forM_cons
|
||||
|
||||
@[simp, grind =] theorem forM_append [Monad m] [LawfulMonad m] {l₁ l₂ : List α} {f : α → m PUnit} :
|
||||
forM (l₁ ++ l₂) f = (do forM l₁ f; forM l₂ f) := by
|
||||
|
||||
@@ -10,6 +10,7 @@ public import Init.Data.List.Count
|
||||
public import Init.Data.List.Find
|
||||
public import Init.Data.List.MinMax
|
||||
public import Init.Data.Nat.Lemmas
|
||||
import Init.Data.Nat.Order
|
||||
|
||||
public section
|
||||
|
||||
@@ -210,12 +211,10 @@ theorem mem_eraseIdx_iff_getElem? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃
|
||||
/-! ### min? -/
|
||||
|
||||
-- A specialization of `min?_eq_some_iff` to Nat.
|
||||
@[deprecated min?_eq_some_iff (since := "2025-08-08")]
|
||||
theorem min?_eq_some_iff' {xs : List Nat} :
|
||||
xs.min? = some a ↔ (a ∈ xs ∧ ∀ b ∈ xs, a ≤ b) :=
|
||||
min?_eq_some_iff
|
||||
(le_refl := Nat.le_refl)
|
||||
(min_eq_or := fun _ _ => Nat.min_def .. ▸ by split <;> simp)
|
||||
(le_min_iff := fun _ _ _ => Nat.le_min)
|
||||
xs.min? = some a ↔ (a ∈ xs ∧ ∀ b ∈ xs, a ≤ b) := by
|
||||
exact min?_eq_some_iff
|
||||
|
||||
theorem min?_get_le_of_mem {l : List Nat} {a : Nat} (h : a ∈ l) :
|
||||
l.min?.get (isSome_min?_of_mem h) ≤ a := by
|
||||
@@ -237,12 +236,10 @@ theorem min?_getD_le_of_mem {l : List Nat} {a k : Nat} (h : a ∈ l) : l.min?.ge
|
||||
/-! ### max? -/
|
||||
|
||||
-- A specialization of `max?_eq_some_iff` to Nat.
|
||||
@[deprecated max?_eq_some_iff (since := "2025-08-08")]
|
||||
theorem max?_eq_some_iff' {xs : List Nat} :
|
||||
xs.max? = some a ↔ (a ∈ xs ∧ ∀ b ∈ xs, b ≤ a) :=
|
||||
max?_eq_some_iff
|
||||
(le_refl := Nat.le_refl)
|
||||
(max_eq_or := fun _ _ => Nat.max_def .. ▸ by split <;> simp)
|
||||
(max_le_iff := fun _ _ _ => Nat.max_le)
|
||||
|
||||
theorem le_max?_get_of_mem {l : List Nat} {a : Nat} (h : a ∈ l) :
|
||||
a ≤ l.max?.get (isSome_max?_of_mem h) := by
|
||||
|
||||
@@ -61,10 +61,10 @@ theorem pairwise_iff_getElem {l : List α} : Pairwise R l ↔
|
||||
∀ (i j : Nat) (_hi : i < l.length) (_hj : j < l.length) (_hij : i < j), R l[i] l[j] := by
|
||||
rw [pairwise_iff_forall_sublist]
|
||||
constructor <;> intro h
|
||||
· intros i j hi hj h'
|
||||
· intro i j hi hj h'
|
||||
apply h
|
||||
simpa [h'] using map_getElem_sublist (is := [⟨i, hi⟩, ⟨j, hj⟩])
|
||||
· intros a b h'
|
||||
· intro a b h'
|
||||
have ⟨is, h', hij⟩ := sublist_eq_map_getElem h'
|
||||
rcases is with ⟨⟩ | ⟨a', ⟨⟩ | ⟨b', ⟨⟩⟩⟩ <;> simp at h'
|
||||
rcases h' with ⟨rfl, rfl⟩
|
||||
|
||||
@@ -58,7 +58,7 @@ theorem pairwise_lt_range' {s n} (step := 1) (pos : 0 < step := by simp) :
|
||||
| s, n + 1, step, pos => by
|
||||
simp only [range'_succ, pairwise_cons]
|
||||
constructor
|
||||
· intros n m
|
||||
· intro n m
|
||||
rw [mem_range'] at m
|
||||
omega
|
||||
· exact pairwise_lt_range' (s := s + step) step pos
|
||||
@@ -70,7 +70,7 @@ theorem pairwise_le_range' {s n} (step := 1) :
|
||||
| s, n + 1, step => by
|
||||
simp only [range'_succ, pairwise_cons]
|
||||
constructor
|
||||
· intros n m
|
||||
· intro n m
|
||||
rw [mem_range'] at m
|
||||
omega
|
||||
· exact pairwise_le_range' (s := s + step) step
|
||||
@@ -90,31 +90,27 @@ theorem map_sub_range' {a s : Nat} (h : a ≤ s) (n : Nat) :
|
||||
rintro rfl
|
||||
omega
|
||||
|
||||
@[deprecated range'_eq_singleton_iff (since := "2025-01-29")]
|
||||
abbrev range'_eq_singleton := @range'_eq_singleton_iff
|
||||
|
||||
theorem range'_eq_append_iff : range' s n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs = range' s k ∧ ys = range' (s + k) (n - k) := by
|
||||
theorem range'_eq_append_iff : range' s n step = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs = range' s k step ∧ ys = range' (s + k * step) (n - k) step := by
|
||||
induction n generalizing s xs ys with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp only [range'_succ]
|
||||
rw [cons_eq_append_iff]
|
||||
have add_mul' (k n m : Nat) : (n + m) * k = m * k + n * k := by rw [Nat.add_mul]; omega
|
||||
constructor
|
||||
· rintro (⟨rfl, rfl⟩ | ⟨_, rfl, h⟩)
|
||||
· exact ⟨0, by simp [range'_succ]⟩
|
||||
· simp only [ih] at h
|
||||
obtain ⟨k, h, rfl, rfl⟩ := h
|
||||
refine ⟨k + 1, ?_⟩
|
||||
simp_all [range'_succ]
|
||||
omega
|
||||
simp_all [range'_succ, Nat.add_assoc]
|
||||
· rintro ⟨k, h, rfl, rfl⟩
|
||||
cases k with
|
||||
| zero => simp [range'_succ]
|
||||
| succ k =>
|
||||
simp only [range'_succ, reduceCtorEq, false_and, cons.injEq, true_and, ih, range'_inj, exists_eq_left', or_true, and_true, false_or]
|
||||
simp only [range'_succ, reduceCtorEq, false_and, cons.injEq, true_and, ih, exists_eq_left', false_or]
|
||||
refine ⟨k, ?_⟩
|
||||
simp_all
|
||||
omega
|
||||
simp_all [Nat.add_assoc]
|
||||
|
||||
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range' s n).find? p = some i ↔ p i ∧ i ∈ range' s n ∧ ∀ j, s ≤ j → j < i → !p j := by
|
||||
@@ -181,6 +177,46 @@ theorem count_range_1' {a s n} :
|
||||
specialize h (a - s)
|
||||
omega
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_range' : (range' start n step).sum = n * start + n * (n - 1) * step / 2 := by
|
||||
induction n generalizing start with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp_all only [List.range'_succ, List.sum_cons, Nat.mul_add, ← Nat.add_assoc,
|
||||
Nat.add_mul, Nat.one_mul, Nat.add_one_sub_one]
|
||||
have : n * step + n * (n - 1) * step / 2 = (n * n * step + n * step) / 2 := by
|
||||
apply Nat.eq_div_of_mul_eq_left (by omega)
|
||||
rw [Nat.add_mul, Nat.div_mul_cancel]
|
||||
· calc n * step * 2 + n * (n - 1) * step
|
||||
_ = n * step * 2 + n * step * (n - 1) := by simp [Nat.mul_comm, Nat.mul_assoc]
|
||||
_ = n * step + n * step * n := by cases n <;> simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm]
|
||||
_ = n * n * step + n * step := by simp [Nat.mul_comm, Nat.add_comm, Nat.mul_left_comm]
|
||||
· have : 2 ∣ n ∨ 2 ∣ (n - 1) := by omega
|
||||
apply Nat.dvd_mul_right_of_dvd
|
||||
apply Nat.dvd_mul.mpr
|
||||
cases this with
|
||||
| inl h => exists 2, 1; omega
|
||||
| inr h => exists 1, 2; omega
|
||||
omega
|
||||
|
||||
@[simp, grind =]
|
||||
theorem drop_range' : (List.range' start n step).drop k = List.range' (start + k * step) (n - k) step := by
|
||||
induction k generalizing start n with
|
||||
| zero => simp
|
||||
| succ => cases n <;> simp [*, List.range'_succ, Nat.add_mul, ← Nat.add_assoc, Nat.add_right_comm]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem take_range'_of_length_le (h : n ≤ k) : (List.range' start n step).take k = List.range' start n step := by
|
||||
induction n generalizing start k with
|
||||
| zero => simp
|
||||
| succ n ih => cases k <;> simp_all [List.range'_succ]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem take_range'_of_length_ge (h : n ≥ k) : (List.range' start n step).take k = List.range' start k step := by
|
||||
induction k generalizing start n with
|
||||
| zero => simp
|
||||
| succ k ih => cases n <;> simp_all [List.range'_succ]
|
||||
|
||||
/-! ### range -/
|
||||
|
||||
theorem reverse_range' : ∀ {s n : Nat}, reverse (range' s n) = map (s + n - 1 - ·) (range n)
|
||||
@@ -230,152 +266,6 @@ theorem count_range {a n} :
|
||||
rw [range_eq_range', count_range_1']
|
||||
simp
|
||||
|
||||
/-! ### iota -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem iota_eq_reverse_range' : ∀ n : Nat, iota n = reverse (range' 1 n)
|
||||
| 0 => rfl
|
||||
| n + 1 => by simp [iota, range'_concat, iota_eq_reverse_range' n, reverse_append, Nat.add_comm]
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem length_iota (n : Nat) : length (iota n) = n := by simp [iota_eq_reverse_range']
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem iota_eq_nil {n : Nat} : iota n = [] ↔ n = 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem iota_ne_nil {n : Nat} : iota n ≠ [] ↔ n ≠ 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem mem_iota {m n : Nat} : m ∈ iota n ↔ 0 < m ∧ m ≤ n := by
|
||||
simp [iota_eq_reverse_range', Nat.add_comm, Nat.lt_succ]
|
||||
omega
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem iota_inj : iota n = iota n' ↔ n = n' := by
|
||||
constructor
|
||||
· intro h
|
||||
have h' := congrArg List.length h
|
||||
simp at h'
|
||||
exact h'
|
||||
· rintro rfl
|
||||
simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem iota_eq_cons_iff : iota n = a :: xs ↔ n = a ∧ 0 < n ∧ xs = iota (n - 1) := by
|
||||
simp [iota_eq_reverse_range']
|
||||
simp [range'_eq_append_iff, reverse_eq_iff]
|
||||
constructor
|
||||
· rintro ⟨k, h, rfl, h'⟩
|
||||
rw [eq_comm, range'_eq_singleton] at h'
|
||||
simp only [reverse_inj, range'_inj, or_true, and_true]
|
||||
omega
|
||||
· rintro ⟨rfl, h, rfl⟩
|
||||
refine ⟨n - 1, by simp, rfl, ?_⟩
|
||||
rw [eq_comm, range'_eq_singleton]
|
||||
omega
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem iota_eq_append_iff : iota n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs = (range' (k + 1) (n - k)).reverse ∧ ys = iota k := by
|
||||
simp only [iota_eq_reverse_range']
|
||||
rw [reverse_eq_append_iff]
|
||||
rw [range'_eq_append_iff]
|
||||
simp only [reverse_eq_iff]
|
||||
constructor
|
||||
· rintro ⟨k, h, rfl, rfl⟩
|
||||
simp; omega
|
||||
· rintro ⟨k, h, rfl, rfl⟩
|
||||
exact ⟨k, by simp; omega⟩
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem pairwise_gt_iota (n : Nat) : Pairwise (· > ·) (iota n) := by
|
||||
simpa only [iota_eq_reverse_range', pairwise_reverse] using pairwise_lt_range'
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem nodup_iota (n : Nat) : Nodup (iota n) :=
|
||||
(pairwise_gt_iota n).imp Nat.ne_of_gt
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem head?_iota (n : Nat) : (iota n).head? = if n = 0 then none else some n := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem head_iota (n : Nat) (h) : (iota n).head h = n := by
|
||||
cases n with
|
||||
| zero => simp at h
|
||||
| succ n => simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem tail_iota (n : Nat) : (iota n).tail = iota (n - 1) := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem reverse_iota : reverse (iota n) = range' 1 n := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
rw [iota_succ, reverse_cons, ih, range'_1_concat, Nat.add_comm]
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem getLast?_iota (n : Nat) : (iota n).getLast? = if n = 0 then none else some 1 := by
|
||||
rw [getLast?_eq_head?_reverse]
|
||||
simp [head?_range']
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem getLast_iota (n : Nat) (h) : (iota n).getLast h = 1 := by
|
||||
rw [getLast_eq_head_reverse]
|
||||
simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem find?_iota_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
(iota n).find? p = none ↔ ∀ i, 0 < i → i ≤ n → !p i := by
|
||||
simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem find?_iota_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(iota n).find? p = some i ↔ p i ∧ i ∈ iota n ∧ ∀ j, i < j → j ≤ n → !p j := by
|
||||
rw [find?_eq_some_iff_append]
|
||||
simp only [iota_eq_reverse_range', reverse_eq_append_iff, reverse_cons, append_assoc, cons_append,
|
||||
nil_append, Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, mem_reverse, mem_range'_1,
|
||||
and_congr_right_iff]
|
||||
intro h
|
||||
constructor
|
||||
· rintro ⟨as, ⟨xs, h⟩, h'⟩
|
||||
constructor
|
||||
· replace h : i ∈ range' 1 n := by
|
||||
rw [h]
|
||||
exact mem_append_cons_self
|
||||
simpa using h
|
||||
· rw [range'_eq_append_iff] at h
|
||||
simp [reverse_eq_iff] at h
|
||||
obtain ⟨k, h₁, rfl, h₂⟩ := h
|
||||
rw [eq_comm, range'_eq_cons_iff, reverse_eq_iff] at h₂
|
||||
obtain ⟨rfl, -, rfl⟩ := h₂
|
||||
intro j j₁ j₂
|
||||
apply h'
|
||||
simp; omega
|
||||
· rintro ⟨⟨i₁, i₂⟩, h⟩
|
||||
refine ⟨(range' (i+1) (n-i)).reverse, ⟨(range' 1 (i-1)).reverse, ?_⟩, ?_⟩
|
||||
· simp [← range'_succ]
|
||||
rw [range'_eq_append_iff]
|
||||
refine ⟨i-1, ?_⟩
|
||||
constructor
|
||||
· omega
|
||||
· simp
|
||||
omega
|
||||
· simp
|
||||
intros a a₁ a₂
|
||||
apply h
|
||||
· omega
|
||||
· omega
|
||||
|
||||
end
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@[simp, grind =]
|
||||
@@ -504,245 +394,10 @@ theorem zipIdx_eq_append_iff {l : List α} {k : Nat} :
|
||||
simp only [length_range'] at h
|
||||
obtain rfl := h
|
||||
refine ⟨ws, xs, rfl, ?_⟩
|
||||
simp only [zipIdx_eq_zip_range', length_append, true_and]
|
||||
congr
|
||||
omega
|
||||
simp [zipIdx_eq_zip_range', length_append]
|
||||
· rintro ⟨l₁', l₂', rfl, rfl, rfl⟩
|
||||
simp only [zipIdx_eq_zip_range']
|
||||
refine ⟨l₁', l₂', range' k l₁'.length, range' (k + l₁'.length) l₂'.length, ?_⟩
|
||||
simp
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated zipIdx_singleton (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_singleton (x : α) (n : Nat) : enumFrom n [x] = [(n, x)] :=
|
||||
rfl
|
||||
|
||||
@[deprecated head?_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem head?_enumFrom (n : Nat) (l : List α) :
|
||||
(enumFrom n l).head? = l.head?.map fun a => (n, a) := by
|
||||
simp [head?_eq_getElem?]
|
||||
|
||||
@[deprecated getLast?_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getLast?_enumFrom (n : Nat) (l : List α) :
|
||||
(enumFrom n l).getLast? = l.getLast?.map fun a => (n + l.length - 1, a) := by
|
||||
simp [getLast?_eq_getElem?]
|
||||
cases l <;> simp
|
||||
|
||||
@[deprecated mk_add_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
theorem mk_add_mem_enumFrom_iff_getElem? {n i : Nat} {x : α} {l : List α} :
|
||||
(n + i, x) ∈ enumFrom n l ↔ l[i]? = some x := by
|
||||
simp [mem_iff_get?]
|
||||
|
||||
@[deprecated mk_mem_zipIdx_iff_le_and_getElem?_sub (since := "2025-01-21")]
|
||||
theorem mk_mem_enumFrom_iff_le_and_getElem?_sub {n i : Nat} {x : α} {l : List α} :
|
||||
(i, x) ∈ enumFrom n l ↔ n ≤ i ∧ l[i - n]? = some x := by
|
||||
if h : n ≤ i then
|
||||
rcases Nat.exists_eq_add_of_le h with ⟨i, rfl⟩
|
||||
simp [mk_add_mem_enumFrom_iff_getElem?, Nat.add_sub_cancel_left]
|
||||
else
|
||||
have : ∀ k, n + k ≠ i := by rintro k rfl; simp at h
|
||||
simp [h, mem_iff_get?, this]
|
||||
|
||||
@[deprecated le_snd_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem le_fst_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x ∈ enumFrom n l) :
|
||||
n ≤ x.1 :=
|
||||
(mk_mem_enumFrom_iff_le_and_getElem?_sub.1 h).1
|
||||
|
||||
@[deprecated snd_lt_add_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem fst_lt_add_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x ∈ enumFrom n l) :
|
||||
x.1 < n + length l := by
|
||||
rcases mem_iff_get.1 h with ⟨i, rfl⟩
|
||||
simpa using i.isLt
|
||||
|
||||
@[deprecated map_zipIdx (since := "2025-01-21")]
|
||||
theorem map_enumFrom (f : α → β) (n : Nat) (l : List α) :
|
||||
map (Prod.map id f) (enumFrom n l) = enumFrom n (map f l) := by
|
||||
induction l generalizing n <;> simp_all
|
||||
|
||||
@[deprecated fst_mem_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem snd_mem_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x ∈ enumFrom n l) : x.2 ∈ l :=
|
||||
enumFrom_map_snd n l ▸ mem_map_of_mem h
|
||||
|
||||
@[deprecated fst_eq_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem snd_eq_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x ∈ enumFrom n l) :
|
||||
x.2 = l[x.1 - n]'(by have := le_fst_of_mem_enumFrom h; have := fst_lt_add_of_mem_enumFrom h; omega) := by
|
||||
induction l generalizing n with
|
||||
| nil => cases h
|
||||
| cons hd tl ih =>
|
||||
cases h with
|
||||
| head _ => simp
|
||||
| tail h m =>
|
||||
specialize ih m
|
||||
have : x.1 - n = x.1 - (n + 1) + 1 := by
|
||||
have := le_fst_of_mem_enumFrom m
|
||||
omega
|
||||
simp [this, ih]
|
||||
|
||||
@[deprecated mem_zipIdx (since := "2025-01-21")]
|
||||
theorem mem_enumFrom {x : α} {i j : Nat} {xs : List α} (h : (i, x) ∈ xs.enumFrom j) :
|
||||
j ≤ i ∧ i < j + xs.length ∧
|
||||
x = xs[i - j]'(by have := le_fst_of_mem_enumFrom h; have := fst_lt_add_of_mem_enumFrom h; omega) :=
|
||||
⟨le_fst_of_mem_enumFrom h, fst_lt_add_of_mem_enumFrom h, snd_eq_of_mem_enumFrom h⟩
|
||||
|
||||
@[deprecated zipIdx_map (since := "2025-01-21")]
|
||||
theorem enumFrom_map (n : Nat) (l : List α) (f : α → β) :
|
||||
enumFrom n (l.map f) = (enumFrom n l).map (Prod.map id f) := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons hd tl IH =>
|
||||
rw [map_cons, enumFrom_cons', enumFrom_cons', map_cons, map_map, IH, map_map]
|
||||
rfl
|
||||
|
||||
@[deprecated zipIdx_append (since := "2025-01-21")]
|
||||
theorem enumFrom_append (xs ys : List α) (n : Nat) :
|
||||
enumFrom n (xs ++ ys) = enumFrom n xs ++ enumFrom (n + xs.length) ys := by
|
||||
induction xs generalizing ys n with
|
||||
| nil => simp
|
||||
| cons x xs IH =>
|
||||
rw [cons_append, enumFrom_cons, IH, ← cons_append, ← enumFrom_cons, length, Nat.add_right_comm,
|
||||
Nat.add_assoc]
|
||||
|
||||
@[deprecated zipIdx_eq_cons_iff (since := "2025-01-21")]
|
||||
theorem enumFrom_eq_cons_iff {l : List α} {n : Nat} :
|
||||
l.enumFrom n = x :: l' ↔ ∃ a as, l = a :: as ∧ x = (n, a) ∧ l' = enumFrom (n + 1) as := by
|
||||
rw [enumFrom_eq_zip_range', zip_eq_cons_iff]
|
||||
constructor
|
||||
· rintro ⟨l₁, l₂, h, rfl, rfl⟩
|
||||
rw [range'_eq_cons_iff] at h
|
||||
obtain ⟨rfl, -, rfl⟩ := h
|
||||
exact ⟨x.2, l₂, by simp [enumFrom_eq_zip_range']⟩
|
||||
· rintro ⟨a, as, rfl, rfl, rfl⟩
|
||||
refine ⟨range' (n+1) as.length, as, ?_⟩
|
||||
simp [enumFrom_eq_zip_range', range'_succ]
|
||||
|
||||
@[deprecated zipIdx_eq_append_iff (since := "2025-01-21")]
|
||||
theorem enumFrom_eq_append_iff {l : List α} {n : Nat} :
|
||||
l.enumFrom n = l₁ ++ l₂ ↔
|
||||
∃ l₁' l₂', l = l₁' ++ l₂' ∧ l₁ = l₁'.enumFrom n ∧ l₂ = l₂'.enumFrom (n + l₁'.length) := by
|
||||
rw [enumFrom_eq_zip_range', zip_eq_append_iff]
|
||||
constructor
|
||||
· rintro ⟨ws, xs, ys, zs, h, h', rfl, rfl, rfl⟩
|
||||
rw [range'_eq_append_iff] at h'
|
||||
obtain ⟨k, -, rfl, rfl⟩ := h'
|
||||
simp only [length_range'] at h
|
||||
obtain rfl := h
|
||||
refine ⟨ys, zs, rfl, ?_⟩
|
||||
simp only [enumFrom_eq_zip_range', length_append, true_and]
|
||||
congr
|
||||
omega
|
||||
· rintro ⟨l₁', l₂', rfl, rfl, rfl⟩
|
||||
simp only [enumFrom_eq_zip_range']
|
||||
refine ⟨range' n l₁'.length, range' (n + l₁'.length) l₂'.length, l₁', l₂', ?_⟩
|
||||
simp
|
||||
|
||||
end
|
||||
|
||||
/-! ### enum -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated zipIdx_eq_nil_iff (since := "2025-01-21"), simp]
|
||||
theorem enum_eq_nil_iff {l : List α} : List.enum l = [] ↔ l = [] := enumFrom_eq_nil
|
||||
|
||||
@[deprecated zipIdx_singleton (since := "2025-01-21"), simp]
|
||||
theorem enum_singleton (x : α) : enum [x] = [(0, x)] := rfl
|
||||
|
||||
@[deprecated length_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem enum_length : (enum l).length = l.length :=
|
||||
enumFrom_length
|
||||
|
||||
@[deprecated getElem?_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getElem?_enum (l : List α) (i : Nat) : (enum l)[i]? = l[i]?.map fun a => (i, a) := by
|
||||
rw [enum, getElem?_enumFrom, Nat.zero_add]
|
||||
|
||||
@[deprecated getElem_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getElem_enum (l : List α) (i : Nat) (h : i < l.enum.length) :
|
||||
l.enum[i] = (i, l[i]'(by simpa [enum_length] using h)) := by
|
||||
simp [enum]
|
||||
|
||||
@[deprecated head?_zipIdx (since := "2025-01-21"), simp] theorem head?_enum (l : List α) :
|
||||
l.enum.head? = l.head?.map fun a => (0, a) := by
|
||||
simp [head?_eq_getElem?]
|
||||
|
||||
@[deprecated getLast?_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getLast?_enum (l : List α) :
|
||||
l.enum.getLast? = l.getLast?.map fun a => (l.length - 1, a) := by
|
||||
simp [getLast?_eq_getElem?]
|
||||
|
||||
@[deprecated tail_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem tail_enum (l : List α) : (enum l).tail = enumFrom 1 l.tail := by
|
||||
simp [enum]
|
||||
|
||||
@[deprecated mk_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
theorem mk_mem_enum_iff_getElem? {i : Nat} {x : α} {l : List α} : (i, x) ∈ enum l ↔ l[i]? = some x := by
|
||||
simp [enum, mk_mem_enumFrom_iff_le_and_getElem?_sub]
|
||||
|
||||
@[deprecated mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
theorem mem_enum_iff_getElem? {x : Nat × α} {l : List α} : x ∈ enum l ↔ l[x.1]? = some x.2 :=
|
||||
mk_mem_enum_iff_getElem?
|
||||
|
||||
@[deprecated snd_lt_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem fst_lt_of_mem_enum {x : Nat × α} {l : List α} (h : x ∈ enum l) : x.1 < length l := by
|
||||
simpa using fst_lt_add_of_mem_enumFrom h
|
||||
|
||||
@[deprecated fst_mem_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem snd_mem_of_mem_enum {x : Nat × α} {l : List α} (h : x ∈ enum l) : x.2 ∈ l :=
|
||||
snd_mem_of_mem_enumFrom h
|
||||
|
||||
@[deprecated fst_eq_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem snd_eq_of_mem_enum {x : Nat × α} {l : List α} (h : x ∈ enum l) :
|
||||
x.2 = l[x.1]'(fst_lt_of_mem_enum h) :=
|
||||
snd_eq_of_mem_enumFrom h
|
||||
|
||||
@[deprecated mem_zipIdx (since := "2025-01-21")]
|
||||
theorem mem_enum {x : α} {i : Nat} {xs : List α} (h : (i, x) ∈ xs.enum) :
|
||||
i < xs.length ∧ x = xs[i]'(fst_lt_of_mem_enum h) :=
|
||||
by simpa using mem_enumFrom h
|
||||
|
||||
@[deprecated map_zipIdx (since := "2025-01-21")]
|
||||
theorem map_enum (f : α → β) (l : List α) : map (Prod.map id f) (enum l) = enum (map f l) :=
|
||||
map_enumFrom f 0 l
|
||||
|
||||
@[deprecated zipIdx_map_snd (since := "2025-01-21"), simp]
|
||||
theorem enum_map_fst (l : List α) : map Prod.fst (enum l) = range l.length := by
|
||||
simp only [enum, enumFrom_map_fst, range_eq_range']
|
||||
|
||||
@[deprecated zipIdx_map_fst (since := "2025-01-21"), simp]
|
||||
theorem enum_map_snd (l : List α) : map Prod.snd (enum l) = l :=
|
||||
enumFrom_map_snd _ _
|
||||
|
||||
@[deprecated zipIdx_map (since := "2025-01-21")]
|
||||
theorem enum_map (l : List α) (f : α → β) : (l.map f).enum = l.enum.map (Prod.map id f) :=
|
||||
enumFrom_map _ _ _
|
||||
|
||||
@[deprecated zipIdx_append (since := "2025-01-21")]
|
||||
theorem enum_append (xs ys : List α) : enum (xs ++ ys) = enum xs ++ enumFrom xs.length ys := by
|
||||
simp [enum, enumFrom_append]
|
||||
|
||||
@[deprecated zipIdx_eq_zip_range' (since := "2025-01-21")]
|
||||
theorem enum_eq_zip_range (l : List α) : l.enum = (range l.length).zip l :=
|
||||
zip_of_prod (enum_map_fst _) (enum_map_snd _)
|
||||
|
||||
@[deprecated unzip_zipIdx_eq_prod (since := "2025-01-21"), simp]
|
||||
theorem unzip_enum_eq_prod (l : List α) : l.enum.unzip = (range l.length, l) := by
|
||||
simp only [enum_eq_zip_range, unzip_zip, length_range]
|
||||
|
||||
@[deprecated zipIdx_eq_cons_iff (since := "2025-01-21")]
|
||||
theorem enum_eq_cons_iff {l : List α} :
|
||||
l.enum = x :: l' ↔ ∃ a as, l = a :: as ∧ x = (0, a) ∧ l' = enumFrom 1 as := by
|
||||
rw [enum, enumFrom_eq_cons_iff]
|
||||
|
||||
@[deprecated zipIdx_eq_append_iff (since := "2025-01-21")]
|
||||
theorem enum_eq_append_iff {l : List α} :
|
||||
l.enum = l₁ ++ l₂ ↔
|
||||
∃ l₁' l₂', l = l₁' ++ l₂' ∧ l₁ = l₁'.enum ∧ l₂ = l₂'.enumFrom l₁'.length := by
|
||||
simp [enum, enumFrom_eq_append_iff]
|
||||
|
||||
end
|
||||
|
||||
end List
|
||||
|
||||
@@ -61,8 +61,8 @@ theorem getElem?_take_eq_none {l : List α} {i j : Nat} (h : i ≤ j) :
|
||||
@[grind =] theorem getElem?_take {l : List α} {i j : Nat} :
|
||||
(l.take i)[j]? = if j < i then l[j]? else none := by
|
||||
split
|
||||
· next h => exact getElem?_take_of_lt h
|
||||
· next h => exact getElem?_take_eq_none (Nat.le_of_not_lt h)
|
||||
next h => exact getElem?_take_of_lt h
|
||||
next h => exact getElem?_take_eq_none (Nat.le_of_not_lt h)
|
||||
|
||||
theorem head?_take {l : List α} {i : Nat} :
|
||||
(l.take i).head? = if i = 0 then none else l.head? := by
|
||||
@@ -114,7 +114,7 @@ theorem take_set_of_le {a : α} {i j : Nat} {l : List α} (h : j ≤ i) :
|
||||
List.ext_getElem? fun i => by
|
||||
rw [getElem?_take, getElem?_take]
|
||||
split
|
||||
· next h' => rw [getElem?_set_ne (by omega)]
|
||||
next h' => rw [getElem?_set_ne (by omega)]
|
||||
· rfl
|
||||
|
||||
@[deprecated take_set_of_le (since := "2025-02-04")]
|
||||
@@ -384,7 +384,7 @@ theorem take_reverse {α} {xs : List α} {i : Nat} :
|
||||
by_cases h : i ≤ xs.length
|
||||
· induction xs generalizing i <;>
|
||||
simp only [reverse_cons, drop, reverse_nil, Nat.zero_sub, length, take_nil]
|
||||
next hd tl xs_ih =>
|
||||
rename_i hd tl xs_ih
|
||||
cases Nat.lt_or_eq_of_le h with
|
||||
| inl h' =>
|
||||
have h' := Nat.le_of_succ_le_succ h'
|
||||
|
||||
@@ -213,7 +213,7 @@ theorem pairwise_append_comm {R : α → α → Prop} (s : ∀ {x y}, R x y →
|
||||
@[grind] theorem Pairwise.take {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.take i) :=
|
||||
h.sublist (take_sublist _ _)
|
||||
|
||||
@[grind =]
|
||||
-- This theorem is not annotated with `grind` because it leads to a loop of instantiations with `Pairwise.sublist`.
|
||||
theorem pairwise_iff_forall_sublist : l.Pairwise R ↔ (∀ {a b}, [a,b] <+ l → R a b) := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
@@ -232,6 +232,10 @@ theorem pairwise_iff_forall_sublist : l.Pairwise R ↔ (∀ {a b}, [a,b] <+ l
|
||||
intro a b hab
|
||||
apply h; exact hab.cons _
|
||||
|
||||
theorem pairwise_of_forall_sublist (g : ∀ {a b}, [a,b] <+ l → R a b) : l.Pairwise R := pairwise_iff_forall_sublist.mpr g
|
||||
|
||||
theorem Pairwise.forall_sublist (h : l.Pairwise R) : ∀ {a b}, [a,b] <+ l → R a b := pairwise_iff_forall_sublist.mp h
|
||||
|
||||
theorem Pairwise.rel_of_mem_take_of_mem_drop
|
||||
{l : List α} (h : l.Pairwise R) (hx : x ∈ l.take i) (hy : y ∈ l.drop i) : R x y := by
|
||||
apply pairwise_iff_forall_sublist.mp h
|
||||
|
||||
@@ -29,34 +29,31 @@ open Nat
|
||||
|
||||
/-! ### range' -/
|
||||
|
||||
theorem range'_succ {s n step} : range' s (n + 1) step = s :: range' (s + step) n step := by
|
||||
simp [range']
|
||||
|
||||
@[simp] theorem length_range' {s step} : ∀ {n : Nat}, length (range' s n step) = n
|
||||
@[simp, grind =] theorem length_range' {s step} : ∀ {n : Nat}, length (range' s n step) = n
|
||||
| 0 => rfl
|
||||
| _ + 1 => congrArg succ length_range'
|
||||
|
||||
@[simp] theorem range'_eq_nil_iff : range' s n step = [] ↔ n = 0 := by
|
||||
@[simp, grind =] theorem range'_eq_nil_iff : range' s n step = [] ↔ n = 0 := by
|
||||
rw [← length_eq_zero_iff, length_range']
|
||||
|
||||
@[deprecated range'_eq_nil_iff (since := "2025-01-29")] abbrev range'_eq_nil := @range'_eq_nil_iff
|
||||
|
||||
theorem range'_ne_nil_iff (s : Nat) {n step : Nat} : range' s n step ≠ [] ↔ n ≠ 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated range'_ne_nil_iff (since := "2025-01-29")] abbrev range'_ne_nil := @range'_ne_nil_iff
|
||||
theorem range'_eq_cons_iff : range' s n step = a :: xs ↔ s = a ∧ 0 < n ∧ xs = range' (a + step) (n - 1) step := by
|
||||
induction n generalizing s with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp only [range'_succ]
|
||||
simp only [cons.injEq, and_congr_right_iff]
|
||||
rintro rfl
|
||||
simp [eq_comm]
|
||||
|
||||
@[simp] theorem range'_zero : range' s 0 step = [] := by
|
||||
simp
|
||||
|
||||
@[simp] theorem range'_one {s step : Nat} : range' s 1 step = [s] := rfl
|
||||
|
||||
@[simp] theorem tail_range' : (range' s n step).tail = range' (s + step) (n - 1) step := by
|
||||
@[simp, grind =] theorem tail_range' : (range' s n step).tail = range' (s + step) (n - 1) step := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n => simp [range'_succ]
|
||||
|
||||
@[simp] theorem range'_inj : range' s n = range' s' n' ↔ n = n' ∧ (n = 0 ∨ s = s') := by
|
||||
@[simp, grind =] theorem range'_inj : range' s n = range' s' n' ↔ n = n' ∧ (n = 0 ∨ s = s') := by
|
||||
constructor
|
||||
· intro h
|
||||
have h' := congrArg List.length h
|
||||
@@ -85,14 +82,14 @@ theorem getElem?_range' {s step} :
|
||||
exact (getElem?_range' (s := s + step) (by exact succ_lt_succ_iff.mp h)).trans <| by
|
||||
simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm]
|
||||
|
||||
@[simp] theorem getElem_range' {n m step} {i} (H : i < (range' n m step).length) :
|
||||
@[simp, grind =] theorem getElem_range' {n m step} {i} (H : i < (range' n m step).length) :
|
||||
(range' n m step)[i] = n + step * i :=
|
||||
(getElem?_eq_some_iff.1 <| getElem?_range' (by simpa using H)).2
|
||||
|
||||
theorem head?_range' : (range' s n).head? = if n = 0 then none else some s := by
|
||||
induction n <;> simp_all [range'_succ]
|
||||
|
||||
@[simp] theorem head_range' (h) : (range' s n).head h = s := by
|
||||
@[simp, grind =] theorem head_range' (h) : (range' s n).head h = s := by
|
||||
repeat simp_all [head?_range', head_eq_iff_head?_eq_some]
|
||||
|
||||
theorem map_add_range' {a} : ∀ s n step, map (a + ·) (range' s n step) = range' (a + s) n step
|
||||
@@ -111,7 +108,7 @@ theorem range'_append : ∀ {s m n step : Nat},
|
||||
simpa [range', Nat.mul_succ, Nat.add_assoc, Nat.add_comm]
|
||||
using range'_append (s := s + step)
|
||||
|
||||
@[simp] theorem range'_append_1 {s m n : Nat} :
|
||||
@[simp, grind =] theorem range'_append_1 {s m n : Nat} :
|
||||
range' s m ++ range' (s + m) n = range' s (m + n) := by simpa using range'_append (step := 1)
|
||||
|
||||
theorem range'_sublist_right {s m n : Nat} : range' s m step <+ range' s n step ↔ m ≤ n :=
|
||||
@@ -133,15 +130,6 @@ theorem range'_concat {s n : Nat} : range' s (n + 1) step = range' s n step ++ [
|
||||
theorem range'_1_concat {s n : Nat} : range' s (n + 1) = range' s n ++ [s + n] := by
|
||||
simp [range'_concat]
|
||||
|
||||
theorem range'_eq_cons_iff : range' s n = a :: xs ↔ s = a ∧ 0 < n ∧ xs = range' (a + 1) (n - 1) := by
|
||||
induction n generalizing s with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp only [range'_succ]
|
||||
simp only [cons.injEq, and_congr_right_iff]
|
||||
rintro rfl
|
||||
simp [eq_comm]
|
||||
|
||||
/-! ### range -/
|
||||
|
||||
@[simp, grind =] theorem range_one : range 1 = [0] := rfl
|
||||
@@ -156,7 +144,7 @@ theorem range_eq_range' {n : Nat} : range n = range' 0 n :=
|
||||
theorem getElem?_range {i n : Nat} (h : i < n) : (range n)[i]? = some i := by
|
||||
simp [range_eq_range', getElem?_range' h]
|
||||
|
||||
@[simp] theorem getElem_range (h : j < (range n).length) : (range n)[j] = j := by
|
||||
@[simp, grind =] theorem getElem_range (h : j < (range n).length) : (range n)[j] = j := by
|
||||
simp [range_eq_range']
|
||||
|
||||
theorem range_succ_eq_map {n : Nat} : range (n + 1) = 0 :: map succ (range n) := by
|
||||
@@ -166,23 +154,23 @@ theorem range_succ_eq_map {n : Nat} : range (n + 1) = 0 :: map succ (range n) :=
|
||||
theorem range'_eq_map_range {s n : Nat} : range' s n = map (s + ·) (range n) := by
|
||||
rw [range_eq_range', map_add_range']; rfl
|
||||
|
||||
@[simp] theorem length_range {n : Nat} : (range n).length = n := by
|
||||
@[simp, grind =] theorem length_range {n : Nat} : (range n).length = n := by
|
||||
simp only [range_eq_range', length_range']
|
||||
|
||||
@[simp] theorem range_eq_nil {n : Nat} : range n = [] ↔ n = 0 := by
|
||||
@[simp, grind =] theorem range_eq_nil {n : Nat} : range n = [] ↔ n = 0 := by
|
||||
rw [← length_eq_zero_iff, length_range]
|
||||
|
||||
theorem range_ne_nil {n : Nat} : range n ≠ [] ↔ n ≠ 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[simp] theorem tail_range : (range n).tail = range' 1 (n - 1) := by
|
||||
@[simp, grind =] theorem tail_range : (range n).tail = range' 1 (n - 1) := by
|
||||
rw [range_eq_range', tail_range']
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem range_sublist {m n : Nat} : range m <+ range n ↔ m ≤ n := by
|
||||
simp only [range_eq_range', range'_sublist_right]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem range_subset {m n : Nat} : range m ⊆ range n ↔ m ≤ n := by
|
||||
simp only [range_eq_range', range'_subset_right, lt_succ_self]
|
||||
|
||||
@@ -200,7 +188,7 @@ theorem head?_range {n : Nat} : (range n).head? = if n = 0 then none else some 0
|
||||
simp only [range_succ, head?_append, ih]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem head_range {n : Nat} (h) : (range n).head h = 0 := by
|
||||
@[simp, grind =] theorem head_range {n : Nat} (h) : (range n).head h = 0 := by
|
||||
cases n with
|
||||
| zero => simp at h
|
||||
| succ n => simp [head?_range, head_eq_iff_head?_eq_some]
|
||||
@@ -212,7 +200,7 @@ theorem getLast?_range {n : Nat} : (range n).getLast? = if n = 0 then none else
|
||||
simp only [range_succ, getLast?_append, ih]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem getLast_range {n : Nat} (h) : (range n).getLast h = n - 1 := by
|
||||
@[simp, grind =] theorem getLast_range {n : Nat} (h) : (range n).getLast h = n - 1 := by
|
||||
cases n with
|
||||
| zero => simp at h
|
||||
| succ n => simp [getLast?_range, getLast_eq_iff_getLast?_eq_some]
|
||||
@@ -295,107 +283,4 @@ theorem zipIdx_eq_map_add {l : List α} {i : Nat} :
|
||||
| nil => rfl
|
||||
| cons _ _ ih => simp [ih (i := i + 1), zipIdx_succ, Nat.add_assoc, Nat.add_comm 1]
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated zipIdx_eq_nil_iff (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_eq_nil {n : Nat} {l : List α} : List.enumFrom n l = [] ↔ l = [] := by
|
||||
cases l <;> simp
|
||||
|
||||
@[deprecated length_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_length : ∀ {n} {l : List α}, (enumFrom n l).length = l.length
|
||||
| _, [] => rfl
|
||||
| _, _ :: _ => congrArg Nat.succ enumFrom_length
|
||||
|
||||
@[deprecated getElem?_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getElem?_enumFrom :
|
||||
∀ i (l : List α) j, (enumFrom i l)[j]? = l[j]?.map fun a => (i + j, a)
|
||||
| _, [], _ => rfl
|
||||
| _, _ :: _, 0 => by simp
|
||||
| n, _ :: l, m + 1 => by
|
||||
simp only [enumFrom_cons, getElem?_cons_succ]
|
||||
exact (getElem?_enumFrom (n + 1) l m).trans <| by rw [Nat.add_right_comm]; rfl
|
||||
|
||||
@[deprecated getElem_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getElem_enumFrom (l : List α) (n) (i : Nat) (h : i < (l.enumFrom n).length) :
|
||||
(l.enumFrom n)[i] = (n + i, l[i]'(by simpa [enumFrom_length] using h)) := by
|
||||
simp only [enumFrom_length] at h
|
||||
rw [getElem_eq_getElem?_get]
|
||||
simp only [getElem?_enumFrom, getElem?_eq_getElem h]
|
||||
simp
|
||||
|
||||
@[deprecated tail_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem tail_enumFrom (l : List α) (n : Nat) : (enumFrom n l).tail = enumFrom (n + 1) l.tail := by
|
||||
induction l generalizing n with
|
||||
| nil => simp
|
||||
| cons _ l ih => simp [enumFrom_cons]
|
||||
|
||||
@[deprecated map_snd_add_zipIdx_eq_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem map_fst_add_enumFrom_eq_enumFrom (l : List α) (n k : Nat) :
|
||||
map (Prod.map (· + n) id) (enumFrom k l) = enumFrom (n + k) l :=
|
||||
ext_getElem? fun i ↦ by simp [Nat.add_comm, Nat.add_left_comm]; rfl
|
||||
|
||||
@[deprecated map_snd_add_zipIdx_eq_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem map_fst_add_enum_eq_enumFrom (l : List α) (n : Nat) :
|
||||
map (Prod.map (· + n) id) (enum l) = enumFrom n l :=
|
||||
map_fst_add_enumFrom_eq_enumFrom l _ _
|
||||
|
||||
@[deprecated zipIdx_cons' (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_cons' (n : Nat) (x : α) (xs : List α) :
|
||||
enumFrom n (x :: xs) = (n, x) :: (enumFrom n xs).map (Prod.map (· + 1) id) := by
|
||||
rw [enumFrom_cons, Nat.add_comm, ← map_fst_add_enumFrom_eq_enumFrom]
|
||||
|
||||
@[deprecated zipIdx_map_snd (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_map_fst (n) :
|
||||
∀ (l : List α), map Prod.fst (enumFrom n l) = range' n l.length
|
||||
| [] => rfl
|
||||
| _ :: _ => congrArg (cons _) (enumFrom_map_fst _ _)
|
||||
|
||||
@[deprecated zipIdx_map_fst (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_map_snd : ∀ (n) (l : List α), map Prod.snd (enumFrom n l) = l
|
||||
| _, [] => rfl
|
||||
| _, _ :: _ => congrArg (cons _) (enumFrom_map_snd _ _)
|
||||
|
||||
@[deprecated zipIdx_eq_zip_range' (since := "2025-01-21")]
|
||||
theorem enumFrom_eq_zip_range' (l : List α) {n : Nat} : l.enumFrom n = (range' n l.length).zip l :=
|
||||
zip_of_prod (enumFrom_map_fst _ _) (enumFrom_map_snd _ _)
|
||||
|
||||
@[deprecated unzip_zipIdx_eq_prod (since := "2025-01-21"), simp]
|
||||
theorem unzip_enumFrom_eq_prod (l : List α) {n : Nat} :
|
||||
(l.enumFrom n).unzip = (range' n l.length, l) := by
|
||||
simp only [enumFrom_eq_zip_range', unzip_zip, length_range']
|
||||
|
||||
end
|
||||
|
||||
/-! ### enum -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated zipIdx_cons (since := "2025-01-21")]
|
||||
theorem enum_cons : (a::as).enum = (0, a) :: as.enumFrom 1 := rfl
|
||||
|
||||
@[deprecated zipIdx_cons (since := "2025-01-21")]
|
||||
theorem enum_cons' (x : α) (xs : List α) :
|
||||
enum (x :: xs) = (0, x) :: (enum xs).map (Prod.map (· + 1) id) :=
|
||||
enumFrom_cons' _ _ _
|
||||
|
||||
@[deprecated "These are now both `l.zipIdx 0`" (since := "2025-01-21")]
|
||||
theorem enum_eq_enumFrom {l : List α} : l.enum = l.enumFrom 0 := rfl
|
||||
|
||||
@[deprecated "Use the reverse direction of `map_snd_add_zipIdx_eq_zipIdx` instead" (since := "2025-01-21")]
|
||||
theorem enumFrom_eq_map_enum (l : List α) (n : Nat) :
|
||||
enumFrom n l = (enum l).map (Prod.map (· + n) id) := by
|
||||
induction l generalizing n with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [enumFrom_cons, ih, enum_cons, map_cons, Prod.map_apply, Nat.zero_add, id_eq, map_map,
|
||||
cons.injEq, map_inj_left, Function.comp_apply, Prod.forall, Prod.mk.injEq, and_true, true_and]
|
||||
intro a b _
|
||||
exact (succ_add a n).symm
|
||||
|
||||
end
|
||||
|
||||
end List
|
||||
|
||||
@@ -57,7 +57,7 @@ where go : List α → List α → List α → List α
|
||||
else
|
||||
go (x :: xs) ys (y :: acc)
|
||||
|
||||
theorem mergeTR_go_eq : mergeTR.go le l₁ l₂ acc = acc.reverse ++ merge l₁ l₂ le := by
|
||||
private theorem mergeTR_go_eq : mergeTR.go le l₁ l₂ acc = acc.reverse ++ merge l₁ l₂ le := by
|
||||
induction l₁ generalizing l₂ acc with
|
||||
| nil => simp [mergeTR.go, reverseAux_eq]
|
||||
| cons x l₁ ih₁ =>
|
||||
@@ -84,7 +84,7 @@ def splitRevAt (n : Nat) (l : List α) : List α × List α := go l n [] where
|
||||
| x :: xs, n+1, acc => go xs n (x :: acc)
|
||||
| xs, _, acc => (acc, xs)
|
||||
|
||||
theorem splitRevAt_go (xs : List α) (i : Nat) (acc : List α) :
|
||||
private theorem splitRevAt_go (xs : List α) (i : Nat) (acc : List α) :
|
||||
splitRevAt.go xs i acc = ((take i xs).reverse ++ acc, drop i xs) := by
|
||||
induction xs generalizing i acc with
|
||||
| nil => simp [splitRevAt.go]
|
||||
@@ -172,7 +172,7 @@ theorem splitRevInTwo_snd (l : { l : List α // l.length = n }) :
|
||||
(splitRevInTwo l).2 = ⟨(splitInTwo l).2.1, by simp; omega⟩ := by
|
||||
simp only [splitRevInTwo, splitRevAt_eq, reverse_take, splitInTwo_snd]
|
||||
|
||||
theorem mergeSortTR_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → mergeSortTR.run le l = mergeSort l.1 le
|
||||
private theorem mergeSortTR_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → mergeSortTR.run le l = mergeSort l.1 le
|
||||
| 0, ⟨[], _⟩
|
||||
| 1, ⟨[a], _⟩ => by simp [mergeSortTR.run]
|
||||
| n+2, ⟨a :: b :: l, h⟩ => by
|
||||
@@ -189,7 +189,7 @@ theorem mergeSort_eq_mergeSortTR : @mergeSort = @mergeSortTR := by
|
||||
-- This mutual block is unfortunately quite slow to elaborate.
|
||||
set_option maxHeartbeats 400000 in
|
||||
mutual
|
||||
theorem mergeSortTR₂_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → mergeSortTR₂.run le l = mergeSort l.1 le
|
||||
private theorem mergeSortTR₂_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → mergeSortTR₂.run le l = mergeSort l.1 le
|
||||
| 0, ⟨[], _⟩
|
||||
| 1, ⟨[a], _⟩ => by simp [mergeSortTR₂.run]
|
||||
| n+2, ⟨a :: b :: l, h⟩ => by
|
||||
@@ -201,7 +201,7 @@ theorem mergeSortTR₂_run_eq_mergeSort : {n : Nat} → (l : { l : List α // l.
|
||||
rw [reverse_reverse]
|
||||
termination_by n => n
|
||||
|
||||
theorem mergeSortTR₂_run'_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → (w : l' = l.1.reverse) → mergeSortTR₂.run' le l = mergeSort l' le
|
||||
private theorem mergeSortTR₂_run'_eq_mergeSort : {n : Nat} → (l : { l : List α // l.length = n }) → (w : l' = l.1.reverse) → mergeSortTR₂.run' le l = mergeSort l' le
|
||||
| 0, ⟨[], _⟩, w
|
||||
| 1, ⟨[a], _⟩, w => by simp_all [mergeSortTR₂.run']
|
||||
| n+2, ⟨a :: b :: l, h⟩, w => by
|
||||
|
||||
@@ -352,14 +352,14 @@ where go : ∀ (i : Nat) (l : List α),
|
||||
rw [merge_stable]
|
||||
· rw [go, go]
|
||||
· simp only [mem_mergeSort, Prod.forall]
|
||||
intros j x k y mx my
|
||||
intro j x k y mx my
|
||||
have := mem_zipIdx mx
|
||||
have := mem_zipIdx my
|
||||
simp_all
|
||||
omega
|
||||
termination_by _ l => l.length
|
||||
|
||||
@[deprecated mergeSort_zipIdx (since := "2025-01-21")] abbrev mergeSort_enum := @mergeSort_zipIdx
|
||||
|
||||
|
||||
theorem mergeSort_cons {le : α → α → Bool}
|
||||
(trans : ∀ (a b c : α), le a b → le b c → le a c)
|
||||
|
||||
@@ -68,9 +68,9 @@ theorem take_of_length_le {l : List α} (h : l.length ≤ i) : take i l = l := b
|
||||
theorem lt_length_of_take_ne_self {l : List α} {i} (h : l.take i ≠ l) : i < l.length :=
|
||||
gt_of_not_le (mt take_of_length_le h)
|
||||
|
||||
@[simp] theorem drop_length {l : List α} : l.drop l.length = [] := drop_of_length_le (Nat.le_refl _)
|
||||
@[simp, grind =] theorem drop_length {l : List α} : l.drop l.length = [] := drop_of_length_le (Nat.le_refl _)
|
||||
|
||||
@[simp] theorem take_length {l : List α} : l.take l.length = l := take_of_length_le (Nat.le_refl _)
|
||||
@[simp, grind =] theorem take_length {l : List α} : l.take l.length = l := take_of_length_le (Nat.le_refl _)
|
||||
|
||||
@[simp]
|
||||
theorem getElem_cons_drop : ∀ {l : List α} {i : Nat} (h : i < l.length),
|
||||
|
||||
@@ -222,11 +222,11 @@ theorem forM_toArray [Monad m] (l : List α) (f : α → m PUnit) :
|
||||
congr
|
||||
ext1 (_|_) <;> simp [ih]
|
||||
|
||||
theorem findSomeRevM?_find_toArray [Monad m] [LawfulMonad m] (f : α → m (Option β)) (l : List α)
|
||||
private theorem findSomeRevM?_find_toArray [Monad m] [LawfulMonad m] (f : α → m (Option β)) (l : List α)
|
||||
(i : Nat) (h) :
|
||||
findSomeRevM?.find f l.toArray i h = (l.take i).reverse.findSomeM? f := by
|
||||
induction i generalizing l with
|
||||
| zero => simp [Array.findSomeRevM?.find.eq_def]
|
||||
| zero => simp [Array.findSomeRevM?.find]
|
||||
| succ i ih =>
|
||||
rw [size_toArray] at h
|
||||
rw [Array.findSomeRevM?.find, take_succ, getElem?_eq_getElem (by omega)]
|
||||
@@ -398,45 +398,46 @@ theorem isPrefixOfAux_toArray_zero [BEq α] (l₁ l₂ : List α) (hle : l₁.le
|
||||
rw [ih]
|
||||
simp_all
|
||||
|
||||
theorem zipWithAux_toArray_succ (as : List α) (bs : List β) (f : α → β → γ) (i : Nat) (xs : Array γ) :
|
||||
zipWithAux as.toArray bs.toArray f (i + 1) xs = zipWithAux as.tail.toArray bs.tail.toArray f i xs := by
|
||||
rw [zipWithAux]
|
||||
conv => rhs; rw [zipWithAux]
|
||||
theorem zipWithMAux_toArray_succ {m : Type u → Type v} [Monad m] (as : List α) (bs : List β) (f : α → β → m γ) (i : Nat) (xs : Array γ) :
|
||||
zipWithMAux as.toArray bs.toArray f (i + 1) xs = zipWithMAux as.tail.toArray bs.tail.toArray f i xs := by
|
||||
rw [zipWithMAux]
|
||||
conv => rhs; rw [zipWithMAux]
|
||||
simp only [size_toArray, getElem_toArray, length_tail, getElem_tail]
|
||||
split <;> rename_i h₁
|
||||
· split <;> rename_i h₂
|
||||
· rw [dif_pos (by omega), dif_pos (by omega), zipWithAux_toArray_succ]
|
||||
· rw [dif_pos (by omega), dif_pos (by omega)]
|
||||
simp only [zipWithMAux_toArray_succ as bs f (i+1)]
|
||||
· rw [dif_pos (by omega)]
|
||||
rw [dif_neg (by omega)]
|
||||
· rw [dif_neg (by omega)]
|
||||
|
||||
theorem zipWithAux_toArray_succ' (as : List α) (bs : List β) (f : α → β → γ) (i : Nat) (xs : Array γ) :
|
||||
zipWithAux as.toArray bs.toArray f (i + 1) xs = zipWithAux (as.drop (i+1)).toArray (bs.drop (i+1)).toArray f 0 xs := by
|
||||
theorem zipWithMAux_toArray_succ' {m : Type u → Type v} [Monad m] (as : List α) (bs : List β) (f : α → β → m γ) (i : Nat) (xs : Array γ) :
|
||||
zipWithMAux as.toArray bs.toArray f (i + 1) xs = zipWithMAux (as.drop (i+1)).toArray (bs.drop (i+1)).toArray f 0 xs := by
|
||||
induction i generalizing as bs xs with
|
||||
| zero => simp [zipWithAux_toArray_succ]
|
||||
| zero => simp [zipWithMAux_toArray_succ]
|
||||
| succ i ih =>
|
||||
rw [zipWithAux_toArray_succ, ih]
|
||||
rw [zipWithMAux_toArray_succ, ih]
|
||||
simp
|
||||
|
||||
theorem zipWithAux_toArray_zero (f : α → β → γ) (as : List α) (bs : List β) (xs : Array γ) :
|
||||
zipWithAux as.toArray bs.toArray f 0 xs = xs ++ (List.zipWith f as bs).toArray := by
|
||||
rw [Array.zipWithAux]
|
||||
theorem zipWithMAux_toArray_zero {m : Type u → Type v} [Monad m] [LawfulMonad m] (f : α → β → m γ) (as : List α) (bs : List β) (xs : Array γ) :
|
||||
zipWithMAux as.toArray bs.toArray f 0 xs = do return xs ++ (← List.zipWithM f as bs).toArray := by
|
||||
rw [Array.zipWithMAux]
|
||||
match as, bs with
|
||||
| [], _ => simp
|
||||
| _, [] => simp
|
||||
| a :: as, b :: bs =>
|
||||
simp [zipWith_cons_cons, zipWithAux_toArray_succ', zipWithAux_toArray_zero, push_append_toArray]
|
||||
simp [zipWithMAux_toArray_succ', zipWithMAux_toArray_zero, push_append_toArray]
|
||||
|
||||
@[simp, grind =] theorem zipWith_toArray (as : List α) (bs : List β) (f : α → β → γ) :
|
||||
Array.zipWith f as.toArray bs.toArray = (List.zipWith f as bs).toArray := by
|
||||
rw [Array.zipWith]
|
||||
simp [zipWithAux_toArray_zero]
|
||||
simp [zipWithMAux_toArray_zero, ← zipWithM'_eq_zipWithM]
|
||||
|
||||
@[simp, grind =] theorem zip_toArray (as : List α) (bs : List β) :
|
||||
Array.zip as.toArray bs.toArray = (List.zip as bs).toArray := by
|
||||
simp [Array.zip, zipWith_toArray, zip]
|
||||
|
||||
theorem zipWithAll_go_toArray (as : List α) (bs : List β) (f : Option α → Option β → γ) (i : Nat) (xs : Array γ) :
|
||||
private theorem zipWithAll_go_toArray (as : List α) (bs : List β) (f : Option α → Option β → γ) (i : Nat) (xs : Array γ) :
|
||||
zipWithAll.go f as.toArray bs.toArray i xs = xs ++ (List.zipWithAll f (as.drop i) (bs.drop i)).toArray := by
|
||||
unfold zipWithAll.go
|
||||
split <;> rename_i h
|
||||
@@ -474,6 +475,11 @@ theorem zipWithAll_go_toArray (as : List α) (bs : List β) (f : Option α → O
|
||||
Array.zipWithAll f as.toArray bs.toArray = (List.zipWithAll f as bs).toArray := by
|
||||
simp [Array.zipWithAll, zipWithAll_go_toArray]
|
||||
|
||||
@[simp, grind =] theorem zipWithM_toArray {m : Type u → Type v} [Monad m] [LawfulMonad m] (f : α → β → m γ) (as : List α) (bs : List β) :
|
||||
Array.zipWithM f as.toArray bs.toArray = do return (← List.zipWithM f as bs).toArray := by
|
||||
rw [Array.zipWithM]
|
||||
simp [zipWithMAux_toArray_zero]
|
||||
|
||||
@[simp, grind =] theorem toArray_appendList (l₁ l₂ : List α) :
|
||||
l₁.toArray ++ l₂ = (l₁ ++ l₂).toArray := by
|
||||
apply ext'
|
||||
@@ -483,7 +489,7 @@ theorem zipWithAll_go_toArray (as : List α) (bs : List β) (f : Option α → O
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
theorem takeWhile_go_succ (p : α → Bool) (a : α) (l : List α) (i : Nat) :
|
||||
private theorem takeWhile_go_succ (p : α → Bool) (a : α) (l : List α) (i : Nat) :
|
||||
takeWhile.go p (a :: l).toArray (i+1) r = takeWhile.go p l.toArray i r := by
|
||||
rw [takeWhile.go, takeWhile.go]
|
||||
simp only [size_toArray, length_cons, Nat.add_lt_add_iff_right,
|
||||
@@ -492,7 +498,7 @@ theorem takeWhile_go_succ (p : α → Bool) (a : α) (l : List α) (i : Nat) :
|
||||
rw [takeWhile_go_succ]
|
||||
rfl
|
||||
|
||||
theorem takeWhile_go_toArray (p : α → Bool) (l : List α) (i : Nat) :
|
||||
private theorem takeWhile_go_toArray (p : α → Bool) (l : List α) (i : Nat) :
|
||||
Array.takeWhile.go p l.toArray i r = r ++ (takeWhile p (l.drop i)).toArray := by
|
||||
induction l generalizing i r with
|
||||
| nil => simp [takeWhile.go]
|
||||
|
||||
@@ -31,6 +31,6 @@ both `List.toArray` and `Array.mk`.
|
||||
-/
|
||||
-- This function is exported to C, where it is called by `Array.mk`
|
||||
-- (the constructor) to implement this functionality.
|
||||
@[inline, match_pattern, pp_nodot, export lean_list_to_array]
|
||||
@[inline, expose, match_pattern, pp_nodot, export lean_list_to_array]
|
||||
def List.toArrayImpl (xs : List α) : Array α :=
|
||||
xs.toArrayAux (Array.mkEmpty xs.length)
|
||||
|
||||
@@ -42,7 +42,7 @@ theorem zipWith_self {f : α → α → δ} : ∀ {l : List α}, zipWith f l l =
|
||||
| [] => rfl
|
||||
| _ :: _ => congrArg _ zipWith_self
|
||||
|
||||
@[deprecated zipWith_self (since := "2025-01-29")] abbrev zipWith_same := @zipWith_self
|
||||
|
||||
|
||||
/--
|
||||
See also `getElem?_zipWith'` for a variant
|
||||
@@ -127,7 +127,7 @@ theorem zipWith_foldl_eq_zip_foldl {f : α → β → γ} {i : δ} {g : δ →
|
||||
theorem zipWith_eq_nil_iff {f : α → β → γ} {l l'} : zipWith f l l' = [] ↔ l = [] ∨ l' = [] := by
|
||||
cases l <;> cases l' <;> simp
|
||||
|
||||
@[grind =]
|
||||
@[simp, grind =]
|
||||
theorem map_zipWith {δ : Type _} {f : α → β} {g : γ → δ → α} {l : List γ} {l' : List δ} :
|
||||
map f (zipWith g l l') = zipWith (fun x y => f (g x y)) l l' := by
|
||||
induction l generalizing l' with
|
||||
@@ -306,7 +306,7 @@ theorem of_mem_zip {a b} : ∀ {l₁ : List α} {l₂ : List β}, (a, b) ∈ zip
|
||||
cases h
|
||||
case head => simp
|
||||
case tail h =>
|
||||
· have := of_mem_zip h
|
||||
have := of_mem_zip h
|
||||
exact ⟨Mem.tail _ this.1, Mem.tail _ this.2⟩
|
||||
|
||||
theorem map_fst_zip :
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -97,7 +97,7 @@ def shiftRight : @& Nat → @& Nat → Nat
|
||||
|
||||
instance : AndOp Nat := ⟨Nat.land⟩
|
||||
instance : OrOp Nat := ⟨Nat.lor⟩
|
||||
instance : Xor Nat := ⟨Nat.xor⟩
|
||||
instance : XorOp Nat := ⟨Nat.xor⟩
|
||||
instance : ShiftLeft Nat := ⟨Nat.shiftLeft⟩
|
||||
instance : ShiftRight Nat := ⟨Nat.shiftRight⟩
|
||||
|
||||
|
||||
@@ -78,8 +78,7 @@ noncomputable def div2Induction {motive : Nat → Sort u}
|
||||
simp only [HAnd.hAnd, AndOp.and, land] at andz
|
||||
simp only [HAnd.hAnd, AndOp.and, land]
|
||||
unfold bitwise
|
||||
cases mod_two_eq_zero_or_one x with | _ p =>
|
||||
simp [xz, p, andz]
|
||||
cases mod_two_eq_zero_or_one x with | _ p => simp [xz, p, andz]
|
||||
|
||||
/-! ### testBit -/
|
||||
|
||||
@@ -182,9 +181,8 @@ theorem exists_testBit_ne_of_ne {x y : Nat} (p : x ≠ y) : ∃ i, testBit x i
|
||||
apply Exists.intro 0
|
||||
simp only [testBit_zero]
|
||||
revert lsb_diff
|
||||
cases mod_two_eq_zero_or_one x with | _ p =>
|
||||
cases mod_two_eq_zero_or_one y with | _ q =>
|
||||
simp [p,q]
|
||||
cases mod_two_eq_zero_or_one x with
|
||||
| _ p => cases mod_two_eq_zero_or_one y with | _ q => simp [p,q]
|
||||
|
||||
@[deprecated exists_testBit_ne_of_ne (since := "2025-04-04")]
|
||||
abbrev ne_implies_bit_diff := @exists_testBit_ne_of_ne
|
||||
@@ -260,8 +258,7 @@ private theorem succ_mod_two : succ x % 2 = 1 - x % 2 := by
|
||||
|
||||
private theorem testBit_succ_zero : testBit (x + 1) 0 = !(testBit x 0) := by
|
||||
simp only [testBit_eq_decide_div_mod_eq, Nat.pow_zero, Nat.div_one, succ_mod_two]
|
||||
cases Nat.mod_two_eq_zero_or_one x with | _ p =>
|
||||
simp [p]
|
||||
cases Nat.mod_two_eq_zero_or_one x with | _ p => simp [p]
|
||||
|
||||
theorem testBit_two_pow_add_eq (x i : Nat) : testBit (2^i + x) i = !(testBit x i) := by
|
||||
simp only [testBit_eq_decide_div_mod_eq, add_div_left, Nat.two_pow_pos, succ_mod_two]
|
||||
@@ -277,8 +274,7 @@ theorem testBit_mul_two_pow_add_eq (a b i : Nat) :
|
||||
testBit_mul_two_pow_add_eq a,
|
||||
testBit_two_pow_add_eq,
|
||||
Nat.succ_mod_two]
|
||||
cases mod_two_eq_zero_or_one a with
|
||||
| _ p => simp [p]
|
||||
cases mod_two_eq_zero_or_one a with | _ p => simp [p]
|
||||
|
||||
theorem testBit_two_pow_add_gt {i j : Nat} (j_lt_i : j < i) (x : Nat) :
|
||||
testBit (2^i + x) j = testBit x j := by
|
||||
@@ -587,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]
|
||||
@@ -641,7 +635,7 @@ theorem or_mod_two_pow : (a ||| b) % 2 ^ n = a % 2 ^ n ||| b % 2 ^ n :=
|
||||
|
||||
@[simp, grind =] theorem testBit_xor (x y i : Nat) :
|
||||
(x ^^^ y).testBit i = ((x.testBit i) ^^ (y.testBit i)) := by
|
||||
simp [HXor.hXor, Xor.xor, xor, testBit_bitwise ]
|
||||
simp [HXor.hXor, XorOp.xor, xor, testBit_bitwise ]
|
||||
|
||||
@[simp, grind =] theorem zero_xor (x : Nat) : 0 ^^^ x = x := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
@@ -678,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]
|
||||
@@ -853,8 +847,7 @@ theorem shiftLeft_add_eq_or_of_lt {b : Nat} (b_lt : b < 2^i) (a : Nat) :
|
||||
/-! ### le -/
|
||||
|
||||
theorem le_of_testBit {n m : Nat} (h : ∀ i, n.testBit i = true → m.testBit i = true) : n ≤ m := by
|
||||
induction n using div2Induction generalizing m
|
||||
next n ih =>
|
||||
induction n using div2Induction generalizing m with | _ n ih
|
||||
have : n / 2 ≤ m / 2 := by
|
||||
rcases n with (_|n)
|
||||
· simp
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,7 +24,7 @@ theorem compare_eq_ite_lt (a b : Nat) :
|
||||
simp only [compare, compareOfLessAndEq]
|
||||
split
|
||||
· rfl
|
||||
· next h =>
|
||||
next h =>
|
||||
match Nat.lt_or_eq_of_le (Nat.not_lt.1 h) with
|
||||
| .inl h => simp [h, Nat.ne_of_gt h]
|
||||
| .inr rfl => simp
|
||||
@@ -36,11 +36,11 @@ theorem compare_eq_ite_le (a b : Nat) :
|
||||
compare a b = if a ≤ b then if b ≤ a then .eq else .lt else .gt := by
|
||||
rw [compare_eq_ite_lt]
|
||||
split
|
||||
· next hlt => simp [Nat.le_of_lt hlt, Nat.not_le.2 hlt]
|
||||
· next hge =>
|
||||
next hlt => simp [Nat.le_of_lt hlt, Nat.not_le.2 hlt]
|
||||
next hge =>
|
||||
split
|
||||
· next hgt => simp [Nat.not_le.2 hgt]
|
||||
· next hle => simp [Nat.not_lt.1 hge, Nat.not_lt.1 hle]
|
||||
next hgt => simp [Nat.not_le.2 hgt]
|
||||
next hle => simp [Nat.not_lt.1 hge, Nat.not_lt.1 hle]
|
||||
|
||||
@[deprecated compare_eq_ite_le (since := "2025-03_28")]
|
||||
def compare_def_le := compare_eq_ite_le
|
||||
|
||||
194
src/Init/Data/Nat/Coprime.lean
Normal file
194
src/Init/Data/Nat/Coprime.lean
Normal file
@@ -0,0 +1,194 @@
|
||||
/-
|
||||
Copyright (c) 2014 Jeremy Avigad. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
|
||||
public import Init.Data.Nat.Gcd
|
||||
|
||||
public section
|
||||
|
||||
/-!
|
||||
# Definitions and properties of `coprime`
|
||||
-/
|
||||
|
||||
namespace Nat
|
||||
|
||||
/-!
|
||||
### `coprime`
|
||||
-/
|
||||
|
||||
/-- `m` and `n` are coprime, or relatively prime, if their `gcd` is 1. -/
|
||||
@[reducible, expose] def Coprime (m n : Nat) : Prop := gcd m n = 1
|
||||
|
||||
-- if we don't inline this, then the compiler computes the GCD even if it already has it
|
||||
@[inline] instance (m n : Nat) : Decidable (Coprime m n) := inferInstanceAs (Decidable (_ = 1))
|
||||
|
||||
theorem coprime_iff_gcd_eq_one : Coprime m n ↔ gcd m n = 1 := .rfl
|
||||
|
||||
theorem Coprime.gcd_eq_one : Coprime m n → gcd m n = 1 := id
|
||||
|
||||
theorem Coprime.symm : Coprime n m → Coprime m n := (gcd_comm m n).trans
|
||||
|
||||
theorem coprime_comm : Coprime n m ↔ Coprime m n := ⟨Coprime.symm, Coprime.symm⟩
|
||||
|
||||
theorem Coprime.dvd_of_dvd_mul_right (H1 : Coprime k n) (H2 : k ∣ m * n) : k ∣ m := by
|
||||
have t := dvd_gcd (Nat.dvd_mul_left k m) H2
|
||||
rwa [gcd_mul_left, H1.gcd_eq_one, Nat.mul_one] at t
|
||||
|
||||
theorem Coprime.dvd_of_dvd_mul_left (H1 : Coprime k m) (H2 : k ∣ m * n) : k ∣ n :=
|
||||
H1.dvd_of_dvd_mul_right (by rwa [Nat.mul_comm])
|
||||
|
||||
theorem Coprime.gcd_mul_left_cancel (m : Nat) (H : Coprime k n) : gcd (k * m) n = gcd m n :=
|
||||
have H1 : Coprime (gcd (k * m) n) k := by
|
||||
rw [Coprime, Nat.gcd_assoc, H.symm.gcd_eq_one, gcd_one_right]
|
||||
Nat.dvd_antisymm
|
||||
(dvd_gcd (H1.dvd_of_dvd_mul_left (gcd_dvd_left _ _)) (gcd_dvd_right _ _))
|
||||
(gcd_dvd_gcd_mul_left_left _ _ _)
|
||||
|
||||
theorem Coprime.gcd_mul_right_cancel (m : Nat) (H : Coprime k n) : gcd (m * k) n = gcd m n := by
|
||||
rw [Nat.mul_comm m k, H.gcd_mul_left_cancel m]
|
||||
|
||||
theorem Coprime.gcd_mul_left_cancel_right (n : Nat)
|
||||
(H : Coprime k m) : gcd m (k * n) = gcd m n := by
|
||||
rw [gcd_comm m n, gcd_comm m (k * n), H.gcd_mul_left_cancel n]
|
||||
|
||||
theorem Coprime.gcd_mul_right_cancel_right (n : Nat)
|
||||
(H : Coprime k m) : gcd m (n * k) = gcd m n := by
|
||||
rw [Nat.mul_comm n k, H.gcd_mul_left_cancel_right n]
|
||||
|
||||
theorem coprime_div_gcd_div_gcd
|
||||
(H : 0 < gcd m n) : Coprime (m / gcd m n) (n / gcd m n) := by
|
||||
rw [coprime_iff_gcd_eq_one, gcd_div (gcd_dvd_left m n) (gcd_dvd_right m n), Nat.div_self H]
|
||||
|
||||
theorem not_coprime_of_dvd_of_dvd (dgt1 : 1 < d) (Hm : d ∣ m) (Hn : d ∣ n) : ¬ Coprime m n :=
|
||||
fun co => Nat.not_le_of_gt dgt1 <| Nat.le_of_dvd Nat.zero_lt_one <| by
|
||||
rw [← co.gcd_eq_one]; exact dvd_gcd Hm Hn
|
||||
|
||||
theorem exists_coprime (m n : Nat) :
|
||||
∃ m' n', Coprime m' n' ∧ m = m' * gcd m n ∧ n = n' * gcd m n := by
|
||||
cases eq_zero_or_pos (gcd m n) with
|
||||
| inl h0 =>
|
||||
rw [gcd_eq_zero_iff] at h0
|
||||
refine ⟨1, 1, gcd_one_left 1, ?_⟩
|
||||
simp [h0]
|
||||
| inr hpos =>
|
||||
exact ⟨_, _, coprime_div_gcd_div_gcd hpos,
|
||||
(Nat.div_mul_cancel (gcd_dvd_left m n)).symm,
|
||||
(Nat.div_mul_cancel (gcd_dvd_right m n)).symm⟩
|
||||
|
||||
theorem exists_coprime' (H : 0 < gcd m n) :
|
||||
∃ g m' n', 0 < g ∧ Coprime m' n' ∧ m = m' * g ∧ n = n' * g :=
|
||||
let ⟨m', n', h⟩ := exists_coprime m n; ⟨_, m', n', H, h⟩
|
||||
|
||||
theorem Coprime.mul_left (H1 : Coprime m k) (H2 : Coprime n k) : Coprime (m * n) k :=
|
||||
(H1.gcd_mul_left_cancel n).trans H2
|
||||
|
||||
theorem Coprime.mul_right (H1 : Coprime k m) (H2 : Coprime k n) : Coprime k (m * n) :=
|
||||
(H1.symm.mul_left H2.symm).symm
|
||||
|
||||
theorem Coprime.coprime_dvd_left (H1 : m ∣ k) (H2 : Coprime k n) : Coprime m n := by
|
||||
apply eq_one_of_dvd_one
|
||||
rw [Coprime] at H2
|
||||
have := Nat.gcd_dvd_gcd_of_dvd_left n H1
|
||||
rwa [← H2]
|
||||
|
||||
theorem Coprime.coprime_dvd_right (H1 : n ∣ m) (H2 : Coprime k m) : Coprime k n :=
|
||||
(H2.symm.coprime_dvd_left H1).symm
|
||||
|
||||
theorem Coprime.coprime_mul_left (H : Coprime (k * m) n) : Coprime m n :=
|
||||
H.coprime_dvd_left (Nat.dvd_mul_left _ _)
|
||||
|
||||
theorem Coprime.coprime_mul_right (H : Coprime (m * k) n) : Coprime m n :=
|
||||
H.coprime_dvd_left (Nat.dvd_mul_right _ _)
|
||||
|
||||
theorem Coprime.coprime_mul_left_right (H : Coprime m (k * n)) : Coprime m n :=
|
||||
H.coprime_dvd_right (Nat.dvd_mul_left _ _)
|
||||
|
||||
theorem Coprime.coprime_mul_right_right (H : Coprime m (n * k)) : Coprime m n :=
|
||||
H.coprime_dvd_right (Nat.dvd_mul_right _ _)
|
||||
|
||||
theorem Coprime.coprime_div_left (cmn : Coprime m n) (dvd : a ∣ m) : Coprime (m / a) n := by
|
||||
match eq_zero_or_pos a with
|
||||
| .inl h0 =>
|
||||
rw [h0] at dvd
|
||||
rw [Nat.eq_zero_of_zero_dvd dvd] at cmn ⊢
|
||||
simp; assumption
|
||||
| .inr hpos =>
|
||||
let ⟨k, hk⟩ := dvd
|
||||
rw [hk, Nat.mul_div_cancel_left _ hpos]
|
||||
rw [hk] at cmn
|
||||
exact cmn.coprime_mul_left
|
||||
|
||||
theorem Coprime.coprime_div_right (cmn : Coprime m n) (dvd : a ∣ n) : Coprime m (n / a) :=
|
||||
(cmn.symm.coprime_div_left dvd).symm
|
||||
|
||||
theorem coprime_mul_iff_left : Coprime (m * n) k ↔ Coprime m k ∧ Coprime n k :=
|
||||
⟨fun h => ⟨h.coprime_mul_right, h.coprime_mul_left⟩,
|
||||
fun ⟨h, _⟩ => by rwa [coprime_iff_gcd_eq_one, h.gcd_mul_left_cancel n]⟩
|
||||
|
||||
theorem coprime_mul_iff_right : Coprime k (m * n) ↔ Coprime k m ∧ Coprime k n := by
|
||||
rw [@coprime_comm k, @coprime_comm k, @coprime_comm k, coprime_mul_iff_left]
|
||||
|
||||
theorem Coprime.gcd_left (k : Nat) (hmn : Coprime m n) : Coprime (gcd k m) n :=
|
||||
hmn.coprime_dvd_left <| gcd_dvd_right k m
|
||||
|
||||
theorem Coprime.gcd_right (k : Nat) (hmn : Coprime m n) : Coprime m (gcd k n) :=
|
||||
hmn.coprime_dvd_right <| gcd_dvd_right k n
|
||||
|
||||
theorem Coprime.gcd_both (k l : Nat) (hmn : Coprime m n) : Coprime (gcd k m) (gcd l n) :=
|
||||
(hmn.gcd_left k).gcd_right l
|
||||
|
||||
theorem Coprime.mul_dvd_of_dvd_of_dvd (hmn : Coprime m n) (hm : m ∣ a) (hn : n ∣ a) : m * n ∣ a :=
|
||||
let ⟨_, hk⟩ := hm
|
||||
hk.symm ▸ Nat.mul_dvd_mul_left _ (hmn.symm.dvd_of_dvd_mul_left (hk ▸ hn))
|
||||
|
||||
@[simp] theorem coprime_zero_left (n : Nat) : Coprime 0 n ↔ n = 1 := by simp [Coprime]
|
||||
|
||||
@[simp] theorem coprime_zero_right (n : Nat) : Coprime n 0 ↔ n = 1 := by simp [Coprime]
|
||||
|
||||
theorem coprime_one_left : ∀ n, Coprime 1 n := gcd_one_left
|
||||
|
||||
theorem coprime_one_right : ∀ n, Coprime n 1 := gcd_one_right
|
||||
|
||||
@[simp] theorem coprime_one_left_eq_true (n) : Coprime 1 n = True := eq_true (coprime_one_left _)
|
||||
|
||||
@[simp] theorem coprime_one_right_eq_true (n) : Coprime n 1 = True := eq_true (coprime_one_right _)
|
||||
|
||||
@[simp] theorem coprime_self (n : Nat) : Coprime n n ↔ n = 1 := by simp [Coprime]
|
||||
|
||||
theorem Coprime.pow_left (n : Nat) (H1 : Coprime m k) : Coprime (m ^ n) k := by
|
||||
induction n with
|
||||
| zero => exact coprime_one_left _
|
||||
| succ n ih => have hm := H1.mul_left ih; rwa [Nat.pow_succ, Nat.mul_comm]
|
||||
|
||||
theorem Coprime.pow_right (n : Nat) (H1 : Coprime k m) : Coprime k (m ^ n) :=
|
||||
(H1.symm.pow_left n).symm
|
||||
|
||||
theorem Coprime.pow {k l : Nat} (m n : Nat) (H1 : Coprime k l) : Coprime (k ^ m) (l ^ n) :=
|
||||
(H1.pow_left _).pow_right _
|
||||
|
||||
theorem Coprime.eq_one_of_dvd {k m : Nat} (H : Coprime k m) (d : k ∣ m) : k = 1 := by
|
||||
rw [← H.gcd_eq_one, gcd_eq_left d]
|
||||
|
||||
theorem Coprime.gcd_mul (k : Nat) (h : Coprime m n) : gcd k (m * n) = gcd k m * gcd k n :=
|
||||
Nat.dvd_antisymm
|
||||
(gcd_mul_right_dvd_mul_gcd k m n)
|
||||
((h.gcd_both k k).mul_dvd_of_dvd_of_dvd
|
||||
(gcd_dvd_gcd_mul_right_right ..)
|
||||
(gcd_dvd_gcd_mul_left_right ..))
|
||||
|
||||
theorem Coprime.mul_gcd (h : Coprime m n) (k : Nat) : gcd (m * n) k = gcd m k * gcd n k := by
|
||||
rw [gcd_comm, h.gcd_mul, gcd_comm k, gcd_comm k]
|
||||
|
||||
theorem gcd_mul_gcd_of_coprime_of_mul_eq_mul
|
||||
(cop : Coprime c d) (h : a * b = c * d) : a.gcd c * b.gcd c = c := by
|
||||
apply Nat.dvd_antisymm
|
||||
· apply ((cop.gcd_left _).mul_left (cop.gcd_left _)).dvd_of_dvd_mul_right
|
||||
rw [← h]
|
||||
apply Nat.mul_dvd_mul (gcd_dvd ..).1 (gcd_dvd ..).1
|
||||
· rw [gcd_comm a, gcd_comm b]
|
||||
refine Nat.dvd_trans ?_ (gcd_mul_right_dvd_mul_gcd ..)
|
||||
rw [h, gcd_mul_right_right d c]; apply Nat.dvd_refl
|
||||
@@ -128,7 +128,7 @@ theorem fold_congr {α : Type u} {n m : Nat} (w : n = m)
|
||||
subst m
|
||||
rfl
|
||||
|
||||
theorem foldTR_loop_congr {α : Type u} {n m : Nat} (w : n = m)
|
||||
private theorem foldTR_loop_congr {α : Type u} {n m : Nat} (w : n = m)
|
||||
(f : (i : Nat) → i < n → α → α) (j : Nat) (h : j ≤ n) (init : α) :
|
||||
foldTR.loop n f j h init = foldTR.loop m (fun i h => f i (by omega)) j (by omega) init := by
|
||||
subst m
|
||||
@@ -154,7 +154,7 @@ theorem any_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) : a
|
||||
subst m
|
||||
rfl
|
||||
|
||||
theorem anyTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) (j : Nat) (h : j ≤ n) :
|
||||
private theorem anyTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) (j : Nat) (h : j ≤ n) :
|
||||
anyTR.loop n f j h = anyTR.loop m (fun i h => f i (by omega)) j (by omega) := by
|
||||
subst m
|
||||
rfl
|
||||
@@ -179,7 +179,7 @@ theorem all_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) : a
|
||||
subst m
|
||||
rfl
|
||||
|
||||
theorem allTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) (j : Nat) (h : j ≤ n) : allTR.loop n f j h = allTR.loop m (fun i h => f i (by omega)) j (by omega) := by
|
||||
private theorem allTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) (j : Nat) (h : j ≤ n) : allTR.loop n f j h = allTR.loop m (fun i h => f i (by omega)) j (by omega) := by
|
||||
subst m
|
||||
rfl
|
||||
|
||||
@@ -199,6 +199,62 @@ theorem allTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bo
|
||||
omega
|
||||
go n 0 f
|
||||
|
||||
/-! # `dfold` -/
|
||||
|
||||
private def dfoldCast {n : Nat} (α : (i : Nat) → (h : i ≤ n := by omega) → Type u)
|
||||
{i j : Nat} {hi : i ≤ n} (w : i = j) (x : α i hi) : α j (by omega) := by
|
||||
subst w
|
||||
exact x
|
||||
|
||||
@[local simp] private theorem dfoldCast_rfl (h : i ≤ n) (w : i = i) (x : α i h) : dfoldCast α w x = x := by
|
||||
simp [dfoldCast]
|
||||
|
||||
@[local simp] private theorem dfoldCast_trans (h : i ≤ n) (w₁ : i = j) (w₂ : j = k) (x : α i h) :
|
||||
dfoldCast @α w₂ (dfoldCast @α w₁ x) = dfoldCast @α (w₁.trans w₂) x := by
|
||||
cases w₁
|
||||
cases w₂
|
||||
simp [dfoldCast]
|
||||
|
||||
@[local simp] private theorem dfoldCast_eq_dfoldCast_iff {α : (i : Nat) → (h : i ≤ n := by omega) → Type u} {w₁ w₂ : i = j} {h : i ≤ n} {x : α i h} :
|
||||
dfoldCast @α w₁ x = dfoldCast (n := n) (fun i h => α i) (hi := hi) w₂ x ↔ w₁ = w₂ := by
|
||||
cases w₁
|
||||
cases w₂
|
||||
simp [dfoldCast]
|
||||
|
||||
private theorem apply_dfoldCast {α : (i : Nat) → (h : i ≤ n := by omega) → Type u}
|
||||
(f : (i : Nat) → (h : i < n) → α i → α (i + 1)) {i j : Nat} (h : i < n) {w : i = j} {x : α i (by omega)} :
|
||||
f j (by omega) (dfoldCast @α w x) = dfoldCast (n := n) (fun i h => α i) (hi := by omega) (by omega) (f i h x) := by
|
||||
subst w
|
||||
simp
|
||||
|
||||
/--
|
||||
`Nat.dfold` evaluates `f` on the numbers up to `n` exclusive, in increasing order:
|
||||
* `Nat.dfold f 3 init = init |> f 0 |> f 1 |> f 2`
|
||||
The input and output types of `f` are indexed by the current index, i.e. `f : (i : Nat) → (h : i < n) → α i → α (i + 1)`.
|
||||
-/
|
||||
@[specialize]
|
||||
def dfold (n : Nat) {α : (i : Nat) → (h : i ≤ n := by omega) → Type u}
|
||||
(f : (i : Nat) → (h : i < n) → α i → α (i + 1)) (init : α 0) : α n :=
|
||||
let rec @[specialize] loop : ∀ j, j ≤ n → α (n - j) → α n
|
||||
| 0, h, a => a
|
||||
| succ m, h, a =>
|
||||
loop m (by omega) (dfoldCast @α (by omega) (f (n - succ m) (by omega) a))
|
||||
loop n (by omega) (dfoldCast @α (by omega) init)
|
||||
|
||||
/--
|
||||
`Nat.dfoldRev` evaluates `f` on the numbers up to `n` exclusive, in decreasing order:
|
||||
* `Nat.dfoldRev f 3 init = f 0 <| f 1 <| f 2 <| init`
|
||||
The input and output types of `f` are indexed by the current index, i.e. `f : (i : Nat) → (h : i < n) → α (i + 1) → α i`.
|
||||
-/
|
||||
@[specialize]
|
||||
def dfoldRev (n : Nat) {α : (i : Nat) → (h : i ≤ n := by omega) → Type u}
|
||||
(f : (i : Nat) → (h : i < n) → α (i + 1) → α i) (init : α n) : α 0 :=
|
||||
match n with
|
||||
| 0 => init
|
||||
| (n + 1) => dfoldRev n (α := fun i h => α i) (fun i h => f i (by omega)) (f n (by omega) init)
|
||||
|
||||
/-! # Theorems -/
|
||||
|
||||
/-! ### `fold` -/
|
||||
|
||||
@[simp] theorem fold_zero {α : Type u} (f : (i : Nat) → i < 0 → α → α) (init : α) :
|
||||
@@ -255,6 +311,102 @@ theorem allTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bo
|
||||
| zero => simp
|
||||
| succ n ih => simp [ih, List.finRange_succ_last, List.all_map, Function.comp_def]
|
||||
|
||||
/-! ### `dfold` -/
|
||||
|
||||
@[simp]
|
||||
theorem dfold_zero
|
||||
{α : (i : Nat) → (h : i ≤ 0 := by omega) → Type u}
|
||||
(f : (i : Nat) → (h : i < 0) → α i → α (i + 1)) (init : α 0) :
|
||||
dfold 0 f init = init := by
|
||||
simp [dfold, dfold.loop]
|
||||
|
||||
private theorem dfold_loop_succ
|
||||
{α : (i : Nat) → (h : i ≤ n + 1 := by omega) → Type u}
|
||||
(f : (i : Nat) → (h : i < n + 1) → α i → α (i + 1))
|
||||
(a : α (n + 1 - (j + 1))) (w : j ≤ n):
|
||||
dfold.loop (n + 1) f (j + 1) (by omega) a =
|
||||
f n (by omega)
|
||||
(dfold.loop n (α := fun i h => α i) (fun i h => f i (by omega)) j w (dfoldCast @α (by omega) a)) := by
|
||||
induction j with
|
||||
| zero => simp [dfold.loop]
|
||||
| succ j ih =>
|
||||
rw [dfold.loop, ih _ (by omega)]
|
||||
congr 2
|
||||
simp only [succ_eq_add_one, dfoldCast_trans]
|
||||
rw [apply_dfoldCast (h := by omega) f]
|
||||
· erw [dfoldCast_trans (h := by omega)]
|
||||
erw [dfoldCast_eq_dfoldCast_iff]
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem dfold_succ
|
||||
{α : (i : Nat) → (h : i ≤ n + 1 := by omega) → Type u}
|
||||
(f : (i : Nat) → (h : i < n + 1) → α i → α (i + 1)) (init : α 0) :
|
||||
dfold (n + 1) f init =
|
||||
f n (by omega) (dfold n (α := fun i h => α i) (fun i h => f i (by omega)) init) := by
|
||||
simp [dfold]
|
||||
rw [dfold_loop_succ (w := Nat.le_refl _)]
|
||||
congr 2
|
||||
simp only [dfoldCast_trans]
|
||||
erw [dfoldCast_eq_dfoldCast_iff]
|
||||
exact le_add_left 0 (n + 1)
|
||||
|
||||
-- This isn't a proper `@[congr]` lemma, but it doesn't seem possible to state one.
|
||||
theorem dfold_congr
|
||||
{n m : Nat} (w : n = m)
|
||||
{α : (i : Nat) → (h : i ≤ n := by omega) → Type u}
|
||||
(f : (i : Nat) → (h : i < n) → α i → α (i + 1)) (init : α 0) :
|
||||
dfold n f init =
|
||||
cast (by subst w; rfl)
|
||||
(dfold m (α := fun i h => α i) (fun i h => f i (by omega)) init) := by
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem dfold_add
|
||||
{α : (i : Nat) → (h : i ≤ n + m := by omega) → Type u}
|
||||
(f : (i : Nat) → (h : i < n + m) → α i → α (i + 1)) (init : α 0) :
|
||||
dfold (n + m) f init =
|
||||
dfold m (α := fun i h => α (n + i)) (fun i h => f (n + i) (by omega))
|
||||
(dfold n (α := fun i h => α i) (fun i h => f i (by omega)) init) := by
|
||||
induction m with
|
||||
| zero => simp; rfl
|
||||
| succ m ih =>
|
||||
simp [dfold_congr (Nat.add_assoc n m 1).symm, ih]
|
||||
|
||||
@[simp] theorem dfoldRev_zero
|
||||
{α : (i : Nat) → (h : i ≤ 0 := by omega) → Type u}
|
||||
(f : (i : Nat) → (_ : i < 0) → α (i + 1) → α i) (init : α 0) :
|
||||
dfoldRev 0 f init = init := by
|
||||
simp [dfoldRev]
|
||||
|
||||
@[simp] theorem dfoldRev_succ
|
||||
{α : (i : Nat) → (h : i ≤ n + 1 := by omega) → Type u}
|
||||
(f : (i : Nat) → (h : i < n + 1) → α (i + 1) → α i) (init : α (n + 1)) :
|
||||
dfoldRev (n + 1) f init =
|
||||
dfoldRev n (α := fun i h => α i) (fun i h => f i (by omega)) (f n (by omega) init) := by
|
||||
simp [dfoldRev]
|
||||
|
||||
@[congr]
|
||||
theorem dfoldRev_congr
|
||||
{n m : Nat} (w : n = m)
|
||||
{α : (i : Nat) → (h : i ≤ n := by omega) → Type u}
|
||||
(f : (i : Nat) → (h : i < n) → α (i + 1) → α i) (init : α n) :
|
||||
dfoldRev n f init =
|
||||
dfoldRev m (α := fun i h => α i) (fun i h => f i (by omega))
|
||||
(cast (by subst w; rfl) init) := by
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem dfoldRev_add
|
||||
{α : (i : Nat) → (h : i ≤ n + m := by omega) → Type u}
|
||||
(f : (i : Nat) → (h : i < n + m) → α (i + 1) → α i) (init : α (n + m)) :
|
||||
dfoldRev (n + m) f init =
|
||||
dfoldRev n (α := fun i h => α i) (fun i h => f i (by omega))
|
||||
(dfoldRev m (α := fun i h => α (n + i)) (fun i h => f (n + i) (by omega)) init) := by
|
||||
induction m with
|
||||
| zero => simp; rfl
|
||||
| succ m ih => simp [← Nat.add_assoc, ih]
|
||||
|
||||
end Nat
|
||||
|
||||
namespace Prod
|
||||
|
||||
@@ -1145,8 +1145,7 @@ protected theorem pow_lt_pow_succ (h : 1 < a) : a ^ n < a ^ (n + 1) := by
|
||||
|
||||
protected theorem pow_lt_pow_of_lt {a n m : Nat} (h : 1 < a) (w : n < m) : a ^ n < a ^ m := by
|
||||
have := Nat.exists_eq_add_of_lt w
|
||||
cases this
|
||||
case intro k p =>
|
||||
cases this with | intro k p
|
||||
rw [Nat.add_right_comm] at p
|
||||
subst p
|
||||
rw [Nat.pow_add, ← Nat.mul_one (a^n)]
|
||||
@@ -1165,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)
|
||||
@@ -1178,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)
|
||||
@@ -1332,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]
|
||||
@@ -1561,7 +1579,7 @@ theorem mul_add_mod_of_lt {a b c : Nat} (h : c < b) : (a * b + c) % b = c := by
|
||||
@[simp] theorem mod_div_self (m n : Nat) : m % n / n = 0 := by
|
||||
cases n
|
||||
· exact (m % 0).div_zero
|
||||
· case succ n => exact Nat.div_eq_of_lt (m.mod_lt n.succ_pos)
|
||||
case succ n => exact Nat.div_eq_of_lt (m.mod_lt n.succ_pos)
|
||||
|
||||
theorem mod_eq_iff {a b c : Nat} :
|
||||
a % b = c ↔ (b = 0 ∧ a = c) ∨ (c < b ∧ Exists fun k => a = b * k + c) :=
|
||||
|
||||
@@ -42,7 +42,7 @@ decreasing_by exact log2_terminates _ ‹_›
|
||||
|
||||
theorem log2_le_self (n : Nat) : Nat.log2 n ≤ n := by
|
||||
unfold Nat.log2; split
|
||||
· next h =>
|
||||
next h =>
|
||||
have := log2_le_self (n / 2)
|
||||
exact Nat.lt_of_le_of_lt this (Nat.div_lt_self (Nat.le_of_lt h) (by decide))
|
||||
· apply Nat.zero_le
|
||||
|
||||
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,817 +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
|
||||
|
||||
/--
|
||||
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
|
||||
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user